##// END OF EJS Templates
notifications: different approach with fixed/standard container
ergo -
r1483:211476f5 default
parent child Browse files
Show More
@@ -1,18 +1,17 b''
1 1 <link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
2 2 <link rel="import" href="../channelstream-connection/channelstream-connection.html">
3 3 <link rel="import" href="../rhodecode-toast/rhodecode-toast.html">
4 4 <link rel="import" href="../rhodecode-favicon/rhodecode-favicon.html">
5 5
6 6 <dom-module id="rhodecode-app">
7 7 <template>
8 8 <channelstream-connection
9 9 id="channelstream-connection"
10 10 on-channelstream-listen-message="receivedMessage"
11 11 on-channelstream-connected="handleConnected"
12 12 on-channelstream-subscribed="handleSubscribed">
13 13 </channelstream-connection>
14 14 <rhodecode-favicon></rhodecode-favicon>
15 <rhodecode-toast id="notifications"></rhodecode-toast>
16 15 </template>
17 16 <script src="rhodecode-app.js"></script>
18 17 </dom-module>
@@ -1,137 +1,141 b''
1 1 ccLog = Logger.get('RhodeCodeApp');
2 2 ccLog.setLevel(Logger.OFF);
3 3
4 4 var rhodeCodeApp = Polymer({
5 5 is: 'rhodecode-app',
6 6 attached: function () {
7 7 ccLog.debug('rhodeCodeApp created');
8 8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
9 9 $.Topic('/favicon/update').subscribe(this.faviconUpdate.bind(this));
10 10 $.Topic('/connection_controller/subscribe').subscribe(
11 11 this.subscribeToChannelTopic.bind(this));
12 12 // this event can be used to coordinate plugins to do their
13 13 // initialization before channelstream is kicked off
14 14 $.Topic('/__MAIN_APP__').publish({});
15 15
16 16 for (var i = 0; i < alertMessagePayloads.length; i++) {
17 17 $.Topic('/notifications').publish(alertMessagePayloads[i]);
18 18 }
19 19 this.kickoffChannelstreamPlugin();
20 20 },
21 21
22 22 /** proxy to channelstream connection */
23 23 getChannelStreamConnection: function () {
24 24 return this.$['channelstream-connection'];
25 25 },
26 26
27 27 handleNotifications: function (data) {
28 this.$['notifications'].handleNotification(data);
28 var elem = document.getElementById('notifications');
29 if(elem){
30 elem.handleNotification(data);
31 }
32
29 33 },
30 34
31 35 faviconUpdate: function (data) {
32 36 this.$$('rhodecode-favicon').counter = data.count;
33 37 },
34 38
35 39 /** opens connection to ws server */
36 40 kickoffChannelstreamPlugin: function (data) {
37 41 ccLog.debug('kickoffChannelstreamPlugin');
38 42 var channels = ['broadcast'];
39 43 var addChannels = this.checkViewChannels();
40 44 for (var i = 0; i < addChannels.length; i++) {
41 45 channels.push(addChannels[i]);
42 46 }
43 47 if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
44 48 var channelstreamConnection = this.getChannelStreamConnection();
45 49 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
46 50 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
47 51 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
48 52 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
49 53 // some channels might already be registered by topic
50 54 for (var i = 0; i < channels.length; i++) {
51 55 channelstreamConnection.push('channels', channels[i]);
52 56 }
53 57 // append any additional channels registered in other plugins
54 58 $.Topic('/connection_controller/subscribe').processPrepared();
55 59 channelstreamConnection.connect();
56 60 }
57 61 },
58 62
59 63 checkViewChannels: function () {
60 64 var channels = []
61 65 // subscribe to PR repo channel for PR's'
62 66 if (templateContext.pull_request_data.pull_request_id) {
63 67 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
64 68 String(templateContext.pull_request_data.pull_request_id);
65 69 channels.push(channelName);
66 70 }
67 71 return channels;
68 72 },
69 73
70 74 /** subscribes users from channels in channelstream */
71 75 subscribeToChannelTopic: function (channels) {
72 76 var channelstreamConnection = this.getChannelStreamConnection();
73 77 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
74 78 ccLog.debug('subscribeToChannelTopic', toSubscribe);
75 79 if (toSubscribe.length > 0) {
76 80 // if we are connected then subscribe
77 81 if (channelstreamConnection.connected) {
78 82 channelstreamConnection.subscribe(toSubscribe);
79 83 }
80 84 // not connected? just push channels onto the stack
81 85 else {
82 86 for (var i = 0; i < toSubscribe.length; i++) {
83 87 channelstreamConnection.push('channels', toSubscribe[i]);
84 88 }
85 89 }
86 90 }
87 91 },
88 92
89 93 /** publish received messages into correct topic */
90 94 receivedMessage: function (event) {
91 95 for (var i = 0; i < event.detail.length; i++) {
92 96 var message = event.detail[i];
93 97 if (message.message.topic) {
94 98 ccLog.debug('publishing', message.message.topic);
95 99 $.Topic(message.message.topic).publish(message);
96 100 }
97 101 else if (message.type === 'presence'){
98 102 $.Topic('/connection_controller/presence').publish(message);
99 103 }
100 104 else {
101 105 ccLog.warn('unhandled message', message);
102 106 }
103 107 }
104 108 },
105 109
106 110 handleConnected: function (event) {
107 111 var channelstreamConnection = this.getChannelStreamConnection();
108 112 channelstreamConnection.set('channelsState',
109 113 event.detail.channels_info);
110 114 channelstreamConnection.set('userState', event.detail.state);
111 115 channelstreamConnection.set('channels', event.detail.channels);
112 116 this.propagageChannelsState();
113 117 },
114 118 handleSubscribed: function (event) {
115 119 var channelstreamConnection = this.getChannelStreamConnection();
116 120 var channelInfo = event.detail.channels_info;
117 121 var channelKeys = Object.keys(event.detail.channels_info);
118 122 for (var i = 0; i < channelKeys.length; i++) {
119 123 var key = channelKeys[i];
120 124 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
121 125 }
122 126 channelstreamConnection.set('channels', event.detail.channels);
123 127 this.propagageChannelsState();
124 128 },
125 129 /** propagates channel states on topics */
126 130 propagageChannelsState: function (event) {
127 131 var channelstreamConnection = this.getChannelStreamConnection();
128 132 var channel_data = channelstreamConnection.channelsState;
129 133 var channels = channelstreamConnection.channels;
130 134 for (var i = 0; i < channels.length; i++) {
131 135 var key = channels[i];
132 136 $.Topic('/connection_controller/channel_update').publish(
133 137 {channel: key, state: channel_data[key]}
134 138 );
135 139 }
136 140 }
137 141 });
@@ -1,30 +1,24 b''
1 1 <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html">
2 2 <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html">
3 3 <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html">
4 4 <dom-module id="rhodecode-toast">
5 5 <template>
6 6 <style include="shared-styles"></style>
7 7 <link rel="stylesheet" href="rhodecode-toast.css">
8
9 <paper-toast id="p-toast"
10 duration="0"
11 horizontal-offset="100"
12 horizontal-align="auto"
13 vertical-align="top"
14 on-iron-overlay-closed="handleClosed"
15 always-on-top>
16 <div class="toast-message-holder">
17 <template is="dom-repeat" items="{{toasts}}">
18 <div class$="alert alert-{{item.level}}">
19 <rhodecode-unsafe-html text="{{item.message}}"></rhodecode-unsafe-html>
8 <template is="dom-if" if="[[hasToasts]]">
9 <div class$="container toast-message-holder [[conditionalClass(isFixed)]]" >
10 <template is="dom-repeat" items="[[toasts]]">
11 <div class$="alert alert-[[item.level]]">
12 <rhodecode-unsafe-html text="[[item.message]]"></rhodecode-unsafe-html>
20 13 </div>
21 14 </template>
15
16 <div class="toast-close">
17 <button on-tap="dismissNotifications" class="btn btn-default">[[_gettext('Close')]]</button>
18 </div>
22 19 </div>
23 <div class="toast-close">
24 <button on-tap="dismissNotifications" class="btn btn-default">{{_gettext('Close')}}</button>
25 </div>
26 </paper-toast>
20 </template>
27 21 </template>
28 22
29 23 <script src="rhodecode-toast.js"></script>
30 24 </dom-module>
@@ -1,40 +1,75 b''
1 1 Polymer({
2 2 is: 'rhodecode-toast',
3 3 properties: {
4 4 toasts: {
5 5 type: Array,
6 6 value: function(){
7 7 return []
8 8 }
9 },
10 isFixed: {
11 type: Boolean,
12 value: false
13 },
14 hasToasts: {
15 type: Boolean,
16 computed: '_computeHasToasts(toasts.*)'
9 17 }
10 18 },
11 19 observers: [
12 20 '_changedToasts(toasts.splices)'
13 21 ],
22
23 _computeHasToasts: function(){
24 return this.toasts.length > 0;
25 },
26
27 _debouncedCalc: function(){
28 // calculate once in a while
29 this.debounce('debouncedCalc', this.toastInWindow, 25);
30 },
31
32 conditionalClass: function(){
33 return this.isFixed ? 'fixed': '';
34 },
35
36 toastInWindow: function() {
37 if (!this._headerNode){
38 return true
39 }
40 var headerHeight = this._headerNode.offsetHeight;
41 var scrollPosition = window.scrollY;
42
43 if (this.isFixed){
44 this.isFixed = 1 <= scrollPosition;
45 }
46 else{
47 this.isFixed = headerHeight <= scrollPosition;
48 }
49 },
50
51 attached: function(){
52 this._headerNode = document.querySelector('.header', document);
53 this.listen(window,'scroll', '_debouncedCalc');
54 this.listen(window,'resize', '_debouncedCalc');
55 this._debouncedCalc();
56 },
14 57 _changedToasts: function(newValue, oldValue){
15 this.$['p-toast'].notifyResize();
16 58 $.Topic('/favicon/update').publish({count: this.toasts.length});
17 59 },
18 60 dismissNotifications: function(){
19 this.$['p-toast'].close();
20 61 $.Topic('/favicon/update').publish({count: 0});
21 },
22 handleClosed: function(){
23 62 this.splice('toasts', 0);
24 63 },
25 open: function(){
26 this.$['p-toast'].open();
27 },
28 64 handleNotification: function(data){
29 65 if (!templateContext.rhodecode_user.notification_status && !data.message.force) {
30 66 // do not act if notifications are disabled
31 67 return
32 68 }
33 69 this.push('toasts',{
34 70 level: data.message.level,
35 71 message: data.message.message
36 72 });
37 this.open();
38 73 },
39 74 _gettext: _gettext
40 75 });
@@ -1,29 +1,22 b''
1 1 @import '../../../../css/variables';
2 2 @import '../../../../css/mixins';
3 3
4 paper-toast{
5 width: 100%;
6 min-width: 400px;
7 padding: 0px;
8 --paper-toast-background-color: transparent;
9 --paper-toast-color: #000000;
10 .box-shadow(none);
4 .alert{
5 margin: 10px 0;
11 6 }
12 paper-toast a{
13 font-weight: bold
7
8 .toast-close{
9 text-align: right;
14 10 }
15 11
16 .toast-message-holder {
17 }
18 .toast-close {
19 right: -5px;
20 position: absolute;
21 bottom: -45px;
22 paper-button{
23 .box-shadow(0 2px 5px 0 rgba(0, 0, 0, 0.15));
12 .toast-message-holder{
13 background-color: #ffffff;
14
15 &.fixed{
16 position: fixed;
17 padding: 10px;
18 top: 0;
19 width: 1200px;
20 z-index: 1;
24 21 }
25 22 }
26 paper-toast .alert{
27 margin: @padding 0 0 0;
28 .box-shadow(0 2px 5px 0 rgba(0, 0, 0, 0.15));
29 }
@@ -1,598 +1,601 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="root.mako"/>
3 3
4 4 <div class="outerwrapper">
5 5 <!-- HEADER -->
6 6 <div class="header">
7 7 <div id="header-inner" class="wrapper">
8 8 <div id="logo">
9 9 <div class="logo-wrapper">
10 10 <a href="${h.url('home')}"><img src="${h.asset('images/rhodecode-logo-white-216x60.png')}" alt="RhodeCode"/></a>
11 11 </div>
12 12 %if c.rhodecode_name:
13 13 <div class="branding">- ${h.branding(c.rhodecode_name)}</div>
14 14 %endif
15 15 </div>
16 16 <!-- MENU BAR NAV -->
17 17 ${self.menu_bar_nav()}
18 18 <!-- END MENU BAR NAV -->
19 19 </div>
20 20 </div>
21 21 ${self.menu_bar_subnav()}
22 22 <!-- END HEADER -->
23 23
24 24 <!-- CONTENT -->
25 25 <div id="content" class="wrapper">
26
27 <rhodecode-toast id="notifications"></rhodecode-toast>
28
26 29 <div class="main">
27 30 ${next.main()}
28 31 </div>
29 32 </div>
30 33 <!-- END CONTENT -->
31 34
32 35 </div>
33 36 <!-- FOOTER -->
34 37 <div id="footer">
35 38 <div id="footer-inner" class="title wrapper">
36 39 <div>
37 40 <p class="footer-link-right">
38 41 % if c.visual.show_version:
39 42 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
40 43 % endif
41 44 &copy; 2010-${h.datetime.today().year}, <a href="${h.url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
42 45 % if c.visual.rhodecode_support_url:
43 46 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
44 47 % endif
45 48 </p>
46 49 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
47 50 <p class="server-instance" style="display:${sid}">
48 51 ## display hidden instance ID if specially defined
49 52 % if c.rhodecode_instanceid:
50 53 ${_('RhodeCode instance id: %s') % c.rhodecode_instanceid}
51 54 % endif
52 55 </p>
53 56 </div>
54 57 </div>
55 58 </div>
56 59
57 60 <!-- END FOOTER -->
58 61
59 62 ### MAKO DEFS ###
60 63
61 64 <%def name="menu_bar_subnav()">
62 65 </%def>
63 66
64 67 <%def name="breadcrumbs(class_='breadcrumbs')">
65 68 <div class="${class_}">
66 69 ${self.breadcrumbs_links()}
67 70 </div>
68 71 </%def>
69 72
70 73 <%def name="admin_menu()">
71 74 <ul class="admin_menu submenu">
72 75 <li><a href="${h.url('admin_home')}">${_('Admin journal')}</a></li>
73 76 <li><a href="${h.url('repos')}">${_('Repositories')}</a></li>
74 77 <li><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
75 78 <li><a href="${h.url('users')}">${_('Users')}</a></li>
76 79 <li><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
77 80 <li><a href="${h.url('admin_permissions_application')}">${_('Permissions')}</a></li>
78 81 <li><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
79 82 <li><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
80 83 <li><a href="${h.url('admin_defaults_repositories')}">${_('Defaults')}</a></li>
81 84 <li class="last"><a href="${h.url('admin_settings')}">${_('Settings')}</a></li>
82 85 </ul>
83 86 </%def>
84 87
85 88
86 89 <%def name="dt_info_panel(elements)">
87 90 <dl class="dl-horizontal">
88 91 %for dt, dd, title, show_items in elements:
89 92 <dt>${dt}:</dt>
90 93 <dd title="${title}">
91 94 %if callable(dd):
92 95 ## allow lazy evaluation of elements
93 96 ${dd()}
94 97 %else:
95 98 ${dd}
96 99 %endif
97 100 %if show_items:
98 101 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
99 102 %endif
100 103 </dd>
101 104
102 105 %if show_items:
103 106 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
104 107 %for item in show_items:
105 108 <dt></dt>
106 109 <dd>${item}</dd>
107 110 %endfor
108 111 </div>
109 112 %endif
110 113
111 114 %endfor
112 115 </dl>
113 116 </%def>
114 117
115 118
116 119 <%def name="gravatar(email, size=16)">
117 120 <%
118 121 if (size > 16):
119 122 gravatar_class = 'gravatar gravatar-large'
120 123 else:
121 124 gravatar_class = 'gravatar'
122 125 %>
123 126 <%doc>
124 127 TODO: johbo: For now we serve double size images to make it smooth
125 128 for retina. This is how it worked until now. Should be replaced
126 129 with a better solution at some point.
127 130 </%doc>
128 131 <img class="${gravatar_class}" src="${h.gravatar_url(email, size * 2)}" height="${size}" width="${size}">
129 132 </%def>
130 133
131 134
132 135 <%def name="gravatar_with_user(contact, size=16, show_disabled=False)">
133 136 <% email = h.email_or_none(contact) %>
134 137 <div class="rc-user tooltip" title="${h.author_string(email)}">
135 138 ${self.gravatar(email, size)}
136 139 <span class="${'user user-disabled' if show_disabled else 'user'}"> ${h.link_to_user(contact)}</span>
137 140 </div>
138 141 </%def>
139 142
140 143
141 144 ## admin menu used for people that have some admin resources
142 145 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
143 146 <ul class="submenu">
144 147 %if repositories:
145 148 <li class="local-admin-repos"><a href="${h.url('repos')}">${_('Repositories')}</a></li>
146 149 %endif
147 150 %if repository_groups:
148 151 <li class="local-admin-repo-groups"><a href="${h.url('repo_groups')}">${_('Repository groups')}</a></li>
149 152 %endif
150 153 %if user_groups:
151 154 <li class="local-admin-user-groups"><a href="${h.url('users_groups')}">${_('User groups')}</a></li>
152 155 %endif
153 156 </ul>
154 157 </%def>
155 158
156 159 <%def name="repo_page_title(repo_instance)">
157 160 <div class="title-content">
158 161 <div class="title-main">
159 162 ## SVN/HG/GIT icons
160 163 %if h.is_hg(repo_instance):
161 164 <i class="icon-hg"></i>
162 165 %endif
163 166 %if h.is_git(repo_instance):
164 167 <i class="icon-git"></i>
165 168 %endif
166 169 %if h.is_svn(repo_instance):
167 170 <i class="icon-svn"></i>
168 171 %endif
169 172
170 173 ## public/private
171 174 %if repo_instance.private:
172 175 <i class="icon-repo-private"></i>
173 176 %else:
174 177 <i class="icon-repo-public"></i>
175 178 %endif
176 179
177 180 ## repo name with group name
178 181 ${h.breadcrumb_repo_link(c.rhodecode_db_repo)}
179 182
180 183 </div>
181 184
182 185 ## FORKED
183 186 %if repo_instance.fork:
184 187 <p>
185 188 <i class="icon-code-fork"></i> ${_('Fork of')}
186 189 <a href="${h.url('summary_home',repo_name=repo_instance.fork.repo_name)}">${repo_instance.fork.repo_name}</a>
187 190 </p>
188 191 %endif
189 192
190 193 ## IMPORTED FROM REMOTE
191 194 %if repo_instance.clone_uri:
192 195 <p>
193 196 <i class="icon-code-fork"></i> ${_('Clone from')}
194 197 <a href="${h.url(h.safe_str(h.hide_credentials(repo_instance.clone_uri)))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
195 198 </p>
196 199 %endif
197 200
198 201 ## LOCKING STATUS
199 202 %if repo_instance.locked[0]:
200 203 <p class="locking_locked">
201 204 <i class="icon-repo-lock"></i>
202 205 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
203 206 </p>
204 207 %elif repo_instance.enable_locking:
205 208 <p class="locking_unlocked">
206 209 <i class="icon-repo-unlock"></i>
207 210 ${_('Repository not locked. Pull repository to lock it.')}
208 211 </p>
209 212 %endif
210 213
211 214 </div>
212 215 </%def>
213 216
214 217 <%def name="repo_menu(active=None)">
215 218 <%
216 219 def is_active(selected):
217 220 if selected == active:
218 221 return "active"
219 222 %>
220 223
221 224 <!--- CONTEXT BAR -->
222 225 <div id="context-bar">
223 226 <div class="wrapper">
224 227 <ul id="context-pages" class="horizontal-list navigation">
225 228 <li class="${is_active('summary')}"><a class="menulink" href="${h.url('summary_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
226 229 <li class="${is_active('changelog')}"><a class="menulink" href="${h.url('changelog_home', repo_name=c.repo_name)}"><div class="menulabel">${_('Changelog')}</div></a></li>
227 230 <li class="${is_active('files')}"><a class="menulink" href="${h.url('files_home', repo_name=c.repo_name, revision=c.rhodecode_db_repo.landing_rev[1])}"><div class="menulabel">${_('Files')}</div></a></li>
228 231 <li class="${is_active('compare')}">
229 232 <a class="menulink" href="${h.url('compare_home',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a>
230 233 </li>
231 234 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
232 235 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
233 236 <li class="${is_active('showpullrequest')}">
234 237 <a class="menulink" href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}">
235 238 %if c.repository_pull_requests:
236 239 <span class="pr_notifications">${c.repository_pull_requests}</span>
237 240 %endif
238 241 <div class="menulabel">${_('Pull Requests')}</div>
239 242 </a>
240 243 </li>
241 244 %endif
242 245 <li class="${is_active('options')}">
243 246 <a class="menulink" href="#" class="dropdown"><div class="menulabel">${_('Options')} <div class="show_more"></div></div></a>
244 247 <ul class="submenu">
245 248 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
246 249 <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}">${_('Settings')}</a></li>
247 250 %endif
248 251 %if c.rhodecode_db_repo.fork:
249 252 <li><a href="${h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,source_ref_type=c.rhodecode_db_repo.landing_rev[0],source_ref=c.rhodecode_db_repo.landing_rev[1], target_repo=c.repo_name,target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1], merge=1)}">
250 253 ${_('Compare fork')}</a></li>
251 254 %endif
252 255
253 256 <li><a href="${h.url('search_repo_home',repo_name=c.repo_name)}">${_('Search')}</a></li>
254 257
255 258 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
256 259 %if c.rhodecode_db_repo.locked[0]:
257 260 <li><a class="locking_del" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Unlock')}</a></li>
258 261 %else:
259 262 <li><a class="locking_add" href="${h.url('toggle_locking',repo_name=c.repo_name)}">${_('Lock')}</a></li>
260 263 %endif
261 264 %endif
262 265 %if c.rhodecode_user.username != h.DEFAULT_USER:
263 266 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
264 267 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}">${_('Fork')}</a></li>
265 268 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}">${_('Create Pull Request')}</a></li>
266 269 %endif
267 270 %endif
268 271 </ul>
269 272 </li>
270 273 </ul>
271 274 </div>
272 275 <div class="clear"></div>
273 276 </div>
274 277 <!--- END CONTEXT BAR -->
275 278
276 279 </%def>
277 280
278 281 <%def name="usermenu(active=False)">
279 282 ## USER MENU
280 283 <li id="quick_login_li" class="${'active' if active else ''}">
281 284 <a id="quick_login_link" class="menulink childs">
282 285 ${gravatar(c.rhodecode_user.email, 20)}
283 286 <span class="user">
284 287 %if c.rhodecode_user.username != h.DEFAULT_USER:
285 288 <span class="menu_link_user">${c.rhodecode_user.username}</span><div class="show_more"></div>
286 289 %else:
287 290 <span>${_('Sign in')}</span>
288 291 %endif
289 292 </span>
290 293 </a>
291 294
292 295 <div class="user-menu submenu">
293 296 <div id="quick_login">
294 297 %if c.rhodecode_user.username == h.DEFAULT_USER:
295 298 <h4>${_('Sign in to your account')}</h4>
296 299 ${h.form(h.route_path('login', _query={'came_from': h.url.current()}), needs_csrf_token=False)}
297 300 <div class="form form-vertical">
298 301 <div class="fields">
299 302 <div class="field">
300 303 <div class="label">
301 304 <label for="username">${_('Username')}:</label>
302 305 </div>
303 306 <div class="input">
304 307 ${h.text('username',class_='focus',tabindex=1)}
305 308 </div>
306 309
307 310 </div>
308 311 <div class="field">
309 312 <div class="label">
310 313 <label for="password">${_('Password')}:</label>
311 314 %if h.HasPermissionAny('hg.password_reset.enabled')():
312 315 <span class="forgot_password">${h.link_to(_('(Forgot password?)'),h.route_path('reset_password'), class_='pwd_reset')}</span>
313 316 %endif
314 317 </div>
315 318 <div class="input">
316 319 ${h.password('password',class_='focus',tabindex=2)}
317 320 </div>
318 321 </div>
319 322 <div class="buttons">
320 323 <div class="register">
321 324 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
322 325 ${h.link_to(_("Don't have an account ?"),h.route_path('register'))}
323 326 %endif
324 327 </div>
325 328 <div class="submit">
326 329 ${h.submit('sign_in',_('Sign In'),class_="btn btn-small",tabindex=3)}
327 330 </div>
328 331 </div>
329 332 </div>
330 333 </div>
331 334 ${h.end_form()}
332 335 %else:
333 336 <div class="">
334 337 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
335 338 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
336 339 <div class="email">${c.rhodecode_user.email}</div>
337 340 </div>
338 341 <div class="">
339 342 <ol class="links">
340 343 <li>${h.link_to(_(u'My account'),h.url('my_account'))}</li>
341 344 % if c.rhodecode_user.personal_repo_group:
342 345 <li>${h.link_to(_(u'My personal group'), h.url('repo_group_home', group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
343 346 % endif
344 347 <li class="logout">
345 348 ${h.secure_form(h.route_path('logout'))}
346 349 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
347 350 ${h.end_form()}
348 351 </li>
349 352 </ol>
350 353 </div>
351 354 %endif
352 355 </div>
353 356 </div>
354 357 %if c.rhodecode_user.username != h.DEFAULT_USER:
355 358 <div class="pill_container">
356 359 % if c.unread_notifications == 0:
357 360 <a class="menu_link_notifications empty" href="${h.url('notifications')}">${c.unread_notifications}</a>
358 361 % else:
359 362 <a class="menu_link_notifications" href="${h.url('notifications')}">${c.unread_notifications}</a>
360 363 % endif
361 364 </div>
362 365 % endif
363 366 </li>
364 367 </%def>
365 368
366 369 <%def name="menu_items(active=None)">
367 370 <%
368 371 def is_active(selected):
369 372 if selected == active:
370 373 return "active"
371 374 return ""
372 375 %>
373 376 <ul id="quick" class="main_nav navigation horizontal-list">
374 377 <!-- repo switcher -->
375 378 <li class="${is_active('repositories')} repo_switcher_li has_select2">
376 379 <input id="repo_switcher" name="repo_switcher" type="hidden">
377 380 </li>
378 381
379 382 ## ROOT MENU
380 383 %if c.rhodecode_user.username != h.DEFAULT_USER:
381 384 <li class="${is_active('journal')}">
382 385 <a class="menulink" title="${_('Show activity journal')}" href="${h.url('journal')}">
383 386 <div class="menulabel">${_('Journal')}</div>
384 387 </a>
385 388 </li>
386 389 %else:
387 390 <li class="${is_active('journal')}">
388 391 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.url('public_journal')}">
389 392 <div class="menulabel">${_('Public journal')}</div>
390 393 </a>
391 394 </li>
392 395 %endif
393 396 <li class="${is_active('gists')}">
394 397 <a class="menulink childs" title="${_('Show Gists')}" href="${h.url('gists')}">
395 398 <div class="menulabel">${_('Gists')}</div>
396 399 </a>
397 400 </li>
398 401 <li class="${is_active('search')}">
399 402 <a class="menulink" title="${_('Search in repositories you have access to')}" href="${h.url('search')}">
400 403 <div class="menulabel">${_('Search')}</div>
401 404 </a>
402 405 </li>
403 406 % if h.HasPermissionAll('hg.admin')('access admin main page'):
404 407 <li class="${is_active('admin')}">
405 408 <a class="menulink childs" title="${_('Admin settings')}" href="#" onclick="return false;">
406 409 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
407 410 </a>
408 411 ${admin_menu()}
409 412 </li>
410 413 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
411 414 <li class="${is_active('admin')}">
412 415 <a class="menulink childs" title="${_('Delegated Admin settings')}">
413 416 <div class="menulabel">${_('Admin')} <div class="show_more"></div></div>
414 417 </a>
415 418 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
416 419 c.rhodecode_user.repository_groups_admin,
417 420 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
418 421 </li>
419 422 % endif
420 423 % if c.debug_style:
421 424 <li class="${is_active('debug_style')}">
422 425 <a class="menulink" title="${_('Style')}" href="${h.url('debug_style_home')}">
423 426 <div class="menulabel">${_('Style')}</div>
424 427 </a>
425 428 </li>
426 429 % endif
427 430 ## render extra user menu
428 431 ${usermenu(active=(active=='my_account'))}
429 432 </ul>
430 433
431 434 <script type="text/javascript">
432 435 var visual_show_public_icon = "${c.visual.show_public_icon}" == "True";
433 436
434 437 /*format the look of items in the list*/
435 438 var format = function(state, escapeMarkup){
436 439 if (!state.id){
437 440 return state.text; // optgroup
438 441 }
439 442 var obj_dict = state.obj;
440 443 var tmpl = '';
441 444
442 445 if(obj_dict && state.type == 'repo'){
443 446 if(obj_dict['repo_type'] === 'hg'){
444 447 tmpl += '<i class="icon-hg"></i> ';
445 448 }
446 449 else if(obj_dict['repo_type'] === 'git'){
447 450 tmpl += '<i class="icon-git"></i> ';
448 451 }
449 452 else if(obj_dict['repo_type'] === 'svn'){
450 453 tmpl += '<i class="icon-svn"></i> ';
451 454 }
452 455 if(obj_dict['private']){
453 456 tmpl += '<i class="icon-lock" ></i> ';
454 457 }
455 458 else if(visual_show_public_icon){
456 459 tmpl += '<i class="icon-unlock-alt"></i> ';
457 460 }
458 461 }
459 462 if(obj_dict && state.type == 'commit') {
460 463 tmpl += '<i class="icon-tag"></i>';
461 464 }
462 465 if(obj_dict && state.type == 'group'){
463 466 tmpl += '<i class="icon-folder-close"></i> ';
464 467 }
465 468 tmpl += escapeMarkup(state.text);
466 469 return tmpl;
467 470 };
468 471
469 472 var formatResult = function(result, container, query, escapeMarkup) {
470 473 return format(result, escapeMarkup);
471 474 };
472 475
473 476 var formatSelection = function(data, container, escapeMarkup) {
474 477 return format(data, escapeMarkup);
475 478 };
476 479
477 480 $("#repo_switcher").select2({
478 481 cachedDataSource: {},
479 482 minimumInputLength: 2,
480 483 placeholder: '<div class="menulabel">${_('Go to')} <div class="show_more"></div></div>',
481 484 dropdownAutoWidth: true,
482 485 formatResult: formatResult,
483 486 formatSelection: formatSelection,
484 487 containerCssClass: "repo-switcher",
485 488 dropdownCssClass: "repo-switcher-dropdown",
486 489 escapeMarkup: function(m){
487 490 // don't escape our custom placeholder
488 491 if(m.substr(0,23) == '<div class="menulabel">'){
489 492 return m;
490 493 }
491 494
492 495 return Select2.util.escapeMarkup(m);
493 496 },
494 497 query: $.debounce(250, function(query){
495 498 self = this;
496 499 var cacheKey = query.term;
497 500 var cachedData = self.cachedDataSource[cacheKey];
498 501
499 502 if (cachedData) {
500 503 query.callback({results: cachedData.results});
501 504 } else {
502 505 $.ajax({
503 506 url: "${h.url('goto_switcher_data')}",
504 507 data: {'query': query.term},
505 508 dataType: 'json',
506 509 type: 'GET',
507 510 success: function(data) {
508 511 self.cachedDataSource[cacheKey] = data;
509 512 query.callback({results: data.results});
510 513 },
511 514 error: function(data, textStatus, errorThrown) {
512 515 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
513 516 }
514 517 })
515 518 }
516 519 })
517 520 });
518 521
519 522 $("#repo_switcher").on('select2-selecting', function(e){
520 523 e.preventDefault();
521 524 window.location = e.choice.url;
522 525 });
523 526
524 527 </script>
525 528 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
526 529 </%def>
527 530
528 531 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
529 532 <div class="modal-dialog">
530 533 <div class="modal-content">
531 534 <div class="modal-header">
532 535 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
533 536 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
534 537 </div>
535 538 <div class="modal-body">
536 539 <div class="block-left">
537 540 <table class="keyboard-mappings">
538 541 <tbody>
539 542 <tr>
540 543 <th></th>
541 544 <th>${_('Site-wide shortcuts')}</th>
542 545 </tr>
543 546 <%
544 547 elems = [
545 548 ('/', 'Open quick search box'),
546 549 ('g h', 'Goto home page'),
547 550 ('g g', 'Goto my private gists page'),
548 551 ('g G', 'Goto my public gists page'),
549 552 ('n r', 'New repository page'),
550 553 ('n g', 'New gist page'),
551 554 ]
552 555 %>
553 556 %for key, desc in elems:
554 557 <tr>
555 558 <td class="keys">
556 559 <span class="key tag">${key}</span>
557 560 </td>
558 561 <td>${desc}</td>
559 562 </tr>
560 563 %endfor
561 564 </tbody>
562 565 </table>
563 566 </div>
564 567 <div class="block-left">
565 568 <table class="keyboard-mappings">
566 569 <tbody>
567 570 <tr>
568 571 <th></th>
569 572 <th>${_('Repositories')}</th>
570 573 </tr>
571 574 <%
572 575 elems = [
573 576 ('g s', 'Goto summary page'),
574 577 ('g c', 'Goto changelog page'),
575 578 ('g f', 'Goto files page'),
576 579 ('g F', 'Goto files page with file search activated'),
577 580 ('g p', 'Goto pull requests page'),
578 581 ('g o', 'Goto repository settings'),
579 582 ('g O', 'Goto repository permissions settings'),
580 583 ]
581 584 %>
582 585 %for key, desc in elems:
583 586 <tr>
584 587 <td class="keys">
585 588 <span class="key tag">${key}</span>
586 589 </td>
587 590 <td>${desc}</td>
588 591 </tr>
589 592 %endfor
590 593 </tbody>
591 594 </table>
592 595 </div>
593 596 </div>
594 597 <div class="modal-footer">
595 598 </div>
596 599 </div><!-- /.modal-content -->
597 600 </div><!-- /.modal-dialog -->
598 601 </div><!-- /.modal -->
General Comments 0
You need to be logged in to leave comments. Login now