##// END OF EJS Templates
frontend: introduce rhodecode-app for more complex cross element wiring
ergo -
r787:048ecbf3 default
parent child Browse files
Show More
@@ -0,0 +1,106 b''
1 <link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
2 <link rel="import" href="../../../../../../bower_components/iron-ajax/iron-ajax.html">
3
4 <!--
5
6 `<channelstream-connection>` allows you to connect and interact with channelstream server
7 abstracting websocket/long-polling connections from you.
8
9 In typical use, just slap some `<channelstream-connection>` at the top of your body:
10
11 <body>
12 <channelstream-connection
13 username="{{user.username}}"
14 connect-url="http://127.0.0.1:8000/demo/connect"
15 disconnect-url="http://127.0.0.1:8000/disconnect"
16 subscribe-url="http://127.0.0.1:8000/demo/subscribe"
17 message-url="http://127.0.0.1:8000/demo/message"
18 long-poll-url="http://127.0.0.1:8000/listen"
19 websocket-url="http://127.0.0.1:8000/ws"
20 channels-url='["channel1", "channel2"]' />
21
22 Then you can do `channelstreamElem.connect()` to kick off your connection.
23 This element also handles automatic reconnections.
24
25 ## Default handlers
26
27 By default element has a listener attached that will fire `startListening()` handler on `channelstream-connected` event.
28
29 By default element has a listener attached that will fire `retryConnection()` handler on `channelstream-connect-error` event,
30 this handler will forever try to re-establish connection to the server incrementing intervals between retries up to 1 minute.
31
32 -->
33 <dom-module id="channelstream-connection">
34 <template>
35
36 <iron-ajax
37 id="ajaxConnect"
38 url=""
39 handle-as="json"
40 method="post"
41 content-type="application/json"
42 loading="{{loadingConnect}}"
43 last-response="{{connectLastResponse}}"
44 on-response="_handleConnect"
45 on-error="_handleConnectError"
46 debounce-duration="100"></iron-ajax>
47
48 <iron-ajax
49 id="ajaxDisconnect"
50 url=""
51 handle-as="json"
52 method="post"
53 content-type="application/json"
54 loading="{{loadingDisconnect}}"
55 last-response="{{_disconnectLastResponse}}"
56 on-response="_handleDisconnect"
57 debounce-duration="100"></iron-ajax>
58
59 <iron-ajax
60 id="ajaxSubscribe"
61 url=""
62 handle-as="json"
63 method="post"
64 content-type="application/json"
65 loading="{{loadingSubscribe}}"
66 last-response="{{subscribeLastResponse}}"
67 on-response="_handleSubscribe"
68 debounce-duration="100"></iron-ajax>
69
70 <iron-ajax
71 id="ajaxUnsubscribe"
72 url=""
73 handle-as="json"
74 method="post"
75 content-type="application/json"
76 loading="{{loadingUnsubscribe}}"
77 last-response="{{unsubscribeLastResponse}}"
78 on-response="_handleUnsubscribe"
79 debounce-duration="100"></iron-ajax>
80
81 <iron-ajax
82 id="ajaxMessage"
83 url=""
84 handle-as="json"
85 method="post"
86 content-type="application/json"
87 loading="{{loadingMessage}}"
88 last-response="{{messageLastResponse}}"
89 on-response="_handleMessage"
90 on-error="_handleMessageError"
91 debounce-duration="100"></iron-ajax>
92
93 <iron-ajax
94 id="ajaxListen"
95 url=""
96 handle-as="text"
97 loading="{{loadingListen}}"
98 last-response="{{listenLastResponse}}"
99 on-request="_handleListenOpen"
100 on-error="_handleListenError"
101 on-response="_handleListenMessageEvent"
102 debounce-duration="100"></iron-ajax>
103
104 </template>
105 <script src="channelstream-connection.js"></script>
106 </dom-module>
This diff has been collapsed as it changes many lines, (502 lines changed) Show them Hide them
@@ -0,0 +1,502 b''
1 Polymer({
2 is: 'channelstream-connection',
3
4 /**
5 * Fired when `channels` array changes.
6 *
7 * @event channelstream-channels-changed
8 */
9
10 /**
11 * Fired when `connect()` method succeeds.
12 *
13 * @event channelstream-connected
14 */
15
16 /**
17 * Fired when `connect` fails.
18 *
19 * @event channelstream-connect-error
20 */
21
22 /**
23 * Fired when `disconnect()` succeeds.
24 *
25 * @event channelstream-disconnected
26 */
27
28 /**
29 * Fired when `message()` succeeds.
30 *
31 * @event channelstream-message-sent
32 */
33
34 /**
35 * Fired when `message()` fails.
36 *
37 * @event channelstream-message-error
38 */
39
40 /**
41 * Fired when `subscribe()` succeeds.
42 *
43 * @event channelstream-subscribed
44 */
45
46 /**
47 * Fired when `subscribe()` fails.
48 *
49 * @event channelstream-subscribe-error
50 */
51
52 /**
53 * Fired when `unsubscribe()` succeeds.
54 *
55 * @event channelstream-unsubscribed
56 */
57
58 /**
59 * Fired when `unsubscribe()` fails.
60 *
61 * @event channelstream-unsubscribe-error
62 */
63
64 /**
65 * Fired when listening connection receives a message.
66 *
67 * @event channelstream-listen-message
68 */
69
70 /**
71 * Fired when listening connection is opened.
72 *
73 * @event channelstream-listen-opened
74 */
75
76 /**
77 * Fired when listening connection is closed.
78 *
79 * @event channelstream-listen-closed
80 */
81
82 /**
83 * Fired when listening connection suffers an error.
84 *
85 * @event channelstream-listen-error
86 */
87
88 properties: {
89 isReady: Boolean,
90 /** List of channels user should be subscribed to. */
91 channels: {
92 type: Array,
93 value: function () {
94 return []
95 },
96 notify: true
97 },
98 /** Username of connecting user. */
99 username: {
100 type: String,
101 value: 'Anonymous',
102 reflectToAttribute: true
103 },
104 /** Connection identifier. */
105 connectionId: {
106 type: String,
107 reflectToAttribute: true
108 },
109 /** Websocket instance. */
110 websocket: {
111 type: Object,
112 value: null
113 },
114 /** Websocket connection url. */
115 websocketUrl: {
116 type: String,
117 value: ''
118 },
119 /** URL used in `connect()`. */
120 connectUrl: {
121 type: String,
122 value: ''
123 },
124 /** URL used in `disconnect()`. */
125 disconnectUrl: {
126 type: String,
127 value: ''
128 },
129 /** URL used in `subscribe()`. */
130 subscribeUrl: {
131 type: String,
132 value: ''
133 },
134 /** URL used in `unsubscribe()`. */
135 unsubscribeUrl: {
136 type: String,
137 value: ''
138 },
139 /** URL used in `message()`. */
140 messageUrl: {
141 type: String,
142 value: ''
143 },
144 /** Long-polling connection url. */
145 longPollUrl: {
146 type: String,
147 value: ''
148 },
149 /** Long-polling connection url. */
150 shouldReconnect: {
151 type: Boolean,
152 value: true
153 },
154 /** Should send heartbeats. */
155 heartbeats: {
156 type: Boolean,
157 value: true
158 },
159 /** How much should every retry interval increase (in milliseconds) */
160 increaseBounceIv: {
161 type: Number,
162 value: 2000
163 },
164 _currentBounceIv: {
165 type: Number,
166 reflectToAttribute: true,
167 value: 0
168 },
169 /** Should use websockets or long-polling by default */
170 useWebsocket: {
171 type: Boolean,
172 reflectToAttribute: true,
173 value: true
174 },
175 connected: {
176 type: Boolean,
177 reflectToAttribute: true,
178 value: false
179 }
180 },
181
182 observers: [
183 '_handleChannelsChange(channels.splices)'
184 ],
185
186 listeners: {
187 'channelstream-connected': 'startListening',
188 'channelstream-connect-error': 'retryConnection',
189 },
190
191 /**
192 * Mutators hold functions that you can set locally to change the data
193 * that the client is sending to all endpoints
194 * you can call it like `elem.mutators('connect', yourFunc())`
195 * mutators will be executed in order they were pushed onto arrays
196 *
197 */
198 mutators: {
199 connect: function () {
200 return []
201 }(),
202 message: function () {
203 return []
204 }(),
205 subscribe: function () {
206 return []
207 }(),
208 unsubscribe: function () {
209 return []
210 }(),
211 disconnect: function () {
212 return []
213 }()
214 },
215 ready: function () {
216 this.isReady = true;
217 },
218
219 /**
220 * Connects user and fetches connection id from the server.
221 *
222 */
223 connect: function () {
224 var request = this.$['ajaxConnect'];
225 request.url = this.connectUrl;
226 request.body = {
227 username: this.username,
228 channels: this.channels
229 };
230 for (var i = 0; i < this.mutators.connect.length; i++) {
231 this.mutators.connect[i](request);
232 }
233 request.generateRequest()
234 },
235 /**
236 * Overwrite with custom function that will
237 */
238 addMutator: function (type, func) {
239 this.mutators[type].push(func);
240 },
241 /**
242 * Subscribes user to channels.
243 *
244 */
245 subscribe: function (channels) {
246 var request = this.$['ajaxSubscribe'];
247 request.url = this.subscribeUrl;
248 request.body = {
249 channels: channels,
250 conn_id: this.connectionId
251 };
252 for (var i = 0; i < this.mutators.subscribe.length; i++) {
253 this.mutators.subscribe[i](request);
254 }
255 if (request.body.channels.length) {
256 request.generateRequest();
257 }
258 },
259 /**
260 * Unsubscribes user from channels.
261 *
262 */
263 unsubscribe: function (unsubscribe) {
264 var request = this.$['ajaxUnsubscribe'];
265
266 request.url = this.unsubscribeUrl;
267 request.body = {
268 channels: unsubscribe,
269 conn_id: this.connectionId
270 };
271 for (var i = 0; i < this.mutators.unsubscribe.length; i++) {
272 this.mutators.unsubscribe[i](request);
273 }
274 request.generateRequest()
275 },
276
277 /**
278 * calculates list of channels we should add user to based on difference
279 * between channels property and passed channel list
280 */
281 calculateSubscribe: function (channels) {
282 var currentlySubscribed = this.channels;
283 var toSubscribe = [];
284 for (var i = 0; i < channels.length; i++) {
285 if (currentlySubscribed.indexOf(channels[i]) === -1) {
286 toSubscribe.push(channels[i]);
287 }
288 }
289 return toSubscribe
290 },
291 /**
292 * calculates list of channels we should remove user from based difference
293 * between channels property and passed channel list
294 */
295 calculateUnsubscribe: function (channels) {
296 var currentlySubscribed = this.channels;
297 var toUnsubscribe = [];
298 for (var i = 0; i < channels.length; i++) {
299 if (currentlySubscribed.indexOf(channels[i]) !== -1) {
300 toUnsubscribe.push(channels[i]);
301 }
302 }
303 return toUnsubscribe
304 },
305 /**
306 * Marks the connection as expired.
307 *
308 */
309 disconnect: function () {
310 var request = this.$['ajaxDisconnect'];
311 request.url = this.disconnectUrl;
312 request.params = {
313 conn_id: this.connectionId
314 };
315 for (var i = 0; i < this.mutators.disconnect.length; i++) {
316 this.mutators.disconnect[i](request);
317 }
318 // mark connection as expired
319 request.generateRequest();
320 // disconnect existing connection
321 this.closeConnection();
322 },
323
324 /**
325 * Sends a message to the server.
326 *
327 */
328 message: function (message) {
329 var request = this.$['ajaxMessage'];
330 request.url = this.messageUrl;
331 request.body = message;
332 for (var i = 0; i < this.mutators.message.length; i++) {
333 this.mutators.message[i](request)
334 }
335 request.generateRequest();
336 },
337 /**
338 * Opens "long lived" (websocket/longpoll) connection to the channelstream server.
339 *
340 */
341 startListening: function (event) {
342 this.fire('start-listening', {});
343 if (this.useWebsocket) {
344 this.useWebsocket = window.WebSocket ? true : false;
345 }
346 if (this.useWebsocket) {
347 this.openWebsocket();
348 }
349 else {
350 this.openLongPoll();
351 }
352 },
353 /**
354 * Opens websocket connection.
355 *
356 */
357 openWebsocket: function () {
358 var url = this.websocketUrl + '?conn_id=' + this.connectionId;
359 this.websocket = new WebSocket(url);
360 this.websocket.onopen = this._handleListenOpen.bind(this);
361 this.websocket.onclose = this._handleListenCloseEvent.bind(this);
362 this.websocket.onerror = this._handleListenErrorEvent.bind(this);
363 this.websocket.onmessage = this._handleListenMessageEvent.bind(this);
364 },
365 /**
366 * Opens long-poll connection.
367 *
368 */
369 openLongPoll: function () {
370 var request = this.$['ajaxListen'];
371 request.url = this.longPollUrl + '?conn_id=' + this.connectionId;
372 request.generateRequest()
373 },
374 /**
375 * Retries `connect()` call while incrementing interval between tries up to 1 minute.
376 *
377 */
378 retryConnection: function () {
379 if (!this.shouldReconnect) {
380 return;
381 }
382 if (this._currentBounceIv < 60000) {
383 this._currentBounceIv = this._currentBounceIv + this.increaseBounceIv;
384 }
385 else {
386 this._currentBounceIv = 60000;
387 }
388 setTimeout(this.connect.bind(this), this._currentBounceIv);
389 },
390 /**
391 * Closes listening connection.
392 *
393 */
394 closeConnection: function () {
395 var request = this.$['ajaxListen'];
396 if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
397 this.websocket.onclose = null;
398 this.websocket.onerror = null;
399 this.websocket.close();
400 }
401 if (request.loading) {
402 request.lastRequest.abort();
403 }
404 this.connected = false;
405 },
406
407 _handleChannelsChange: function (event) {
408 // do not fire the event if set() didn't mutate anything
409 // is this a reliable way to do it?
410 if (!this.isReady || event === undefined) {
411 return
412 }
413 this.fire('channelstream-channels-changed', event)
414 },
415
416 _handleListenOpen: function (event) {
417 this.connected = true;
418 this.fire('channelstream-listen-opened', event);
419 this.createHeartBeats();
420 },
421
422 createHeartBeats: function () {
423 if (typeof self._heartbeat === 'undefined' && this.websocket !== null
424 && this.heartbeats) {
425 self._heartbeat = setInterval(this._sendHeartBeat.bind(this), 10000);
426 }
427 },
428
429 _sendHeartBeat: function () {
430 if (this.websocket.readyState === WebSocket.OPEN && this.heartbeats) {
431 this.websocket.send(JSON.stringify({type: 'heartbeat'}));
432 }
433 },
434
435 _handleListenError: function (event) {
436 this.connected = false;
437 this.retryConnection();
438 },
439 _handleConnectError: function (event) {
440 this.connected = false;
441 this.fire('channelstream-connect-error', event.detail);
442 },
443
444 _handleListenMessageEvent: function (event) {
445 var data = null;
446 // comes from iron-ajax
447 if (event.detail) {
448 data = JSON.parse(event.detail.response)
449 // comes from websocket
450 setTimeout(this.openLongPoll.bind(this), 0);
451 } else {
452 data = JSON.parse(event.data)
453 }
454 this.fire('channelstream-listen-message', data);
455
456 },
457
458 _handleListenCloseEvent: function (event) {
459 this.connected = false;
460 this.fire('channelstream-listen-closed', event.detail);
461 this.retryConnection();
462 },
463
464 _handleListenErrorEvent: function (event) {
465 this.connected = false;
466 this.fire('channelstream-listen-error', {})
467 },
468
469 _handleConnect: function (event) {
470 this.currentBounceIv = 0;
471 this.connectionId = event.detail.response.conn_id;
472 this.fire('channelstream-connected', event.detail.response);
473 },
474
475 _handleDisconnect: function (event) {
476 this.connected = false;
477 this.fire('channelstream-disconnected', {});
478 },
479
480 _handleMessage: function (event) {
481 this.fire('channelstream-message-sent', event.detail.response);
482 },
483 _handleMessageError: function (event) {
484 this.fire('channelstream-message-error', event.detail);
485 },
486
487 _handleSubscribe: function (event) {
488 this.fire('channelstream-subscribed', event.detail.response);
489 },
490
491 _handleSubscribeError: function (event) {
492 this.fire('channelstream-subscribe-error', event.detail);
493 },
494
495 _handleUnsubscribe: function (event) {
496 this.fire('channelstream-unsubscribed', event.detail.response);
497 },
498
499 _handleUnsubscribeError: function (event) {
500 this.fire('channelstream-unsubscribe-error', event.detail);
501 }
502 });
@@ -0,0 +1,15 b''
1 <link rel="import" href="../../../../../../bower_components/polymer/polymer.html">
2 <link rel="import" href="../channelstream-connection/channelstream-connection.html">
3
4 <dom-module id="rhodecode-app">
5 <template>
6 <rhodecode-toast id="notifications"></rhodecode-toast>
7 <channelstream-connection
8 id="channelstream-connection"
9 on-channelstream-listen-message="receivedMessage"
10 on-channelstream-connected="handleConnected"
11 on-channelstream-subscribed="handleSubscribed">
12 </channelstream-connection>
13 </template>
14 <script src="rhodecode-app.js"></script>
15 </dom-module>
@@ -0,0 +1,127 b''
1 ccLog = Logger.get('RhodeCodeApp');
2 ccLog.setLevel(Logger.OFF);
3
4 var rhodeCodeApp = Polymer({
5 is: 'rhodecode-app',
6 created: function () {
7 ccLog.debug('rhodeCodeApp created');
8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
9
10 $.Topic('/plugins/__REGISTER__').subscribe(
11 this.kickoffChannelstreamPlugin.bind(this)
12 );
13
14 $.Topic('/connection_controller/subscribe').subscribe(
15 this.subscribeToChannelTopic.bind(this));
16 },
17
18 /** proxy to channelstream connection */
19 getChannelStreamConnection: function () {
20 return this.$['channelstream-connection'];
21 },
22
23 handleNotifications: function (data) {
24 this.$['notifications'].handleNotification(data);
25 },
26
27 /** opens connection to ws server */
28 kickoffChannelstreamPlugin: function (data) {
29 ccLog.debug('kickoffChannelstreamPlugin');
30 var channels = ['broadcast'];
31 var addChannels = this.checkViewChannels();
32 for (var i = 0; i < addChannels.length; i++) {
33 channels.push(addChannels[i]);
34 }
35 var channelstreamConnection = this.$['channelstream-connection'];
36 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
37 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
38 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
39 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
40 // some channels might already be registered by topic
41 for (var i = 0; i < channels.length; i++) {
42 channelstreamConnection.push('channels', channels[i]);
43 }
44 // append any additional channels registered in other plugins
45 $.Topic('/connection_controller/subscribe').processPrepared();
46 channelstreamConnection.connect();
47 },
48
49 checkViewChannels: function () {
50 var channels = []
51 // subscribe to PR repo channel for PR's'
52 if (templateContext.pull_request_data.pull_request_id) {
53 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
54 String(templateContext.pull_request_data.pull_request_id);
55 channels.push(channelName);
56 }
57 return channels;
58 },
59
60 /** subscribes users from channels in channelstream */
61 subscribeToChannelTopic: function (channels) {
62 var channelstreamConnection = this.$['channelstream-connection'];
63 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
64 ccLog.debug('subscribeToChannelTopic', toSubscribe);
65 if (toSubscribe.length > 0) {
66 // if we are connected then subscribe
67 if (channelstreamConnection.connected) {
68 channelstreamConnection.subscribe(toSubscribe);
69 }
70 // not connected? just push channels onto the stack
71 else {
72 for (var i = 0; i < toSubscribe.length; i++) {
73 channelstreamConnection.push('channels', toSubscribe[i]);
74 }
75 }
76 }
77 },
78
79 /** publish received messages into correct topic */
80 receivedMessage: function (event) {
81 for (var i = 0; i < event.detail.length; i++) {
82 var message = event.detail[i];
83 if (message.message.topic) {
84 ccLog.debug('publishing', message.message.topic);
85 $.Topic(message.message.topic).publish(message);
86 }
87 else if (message.type === 'presence'){
88 $.Topic('/connection_controller/presence').publish(message);
89 }
90 else {
91 ccLog.warn('unhandled message', message);
92 }
93 }
94 },
95
96 handleConnected: function (event) {
97 var channelstreamConnection = this.$['channelstream-connection'];
98 channelstreamConnection.set('channelsState',
99 event.detail.channels_info);
100 channelstreamConnection.set('userState', event.detail.state);
101 channelstreamConnection.set('channels', event.detail.channels);
102 this.propagageChannelsState();
103 },
104 handleSubscribed: function (event) {
105 var channelstreamConnection = this.$['channelstream-connection'];
106 var channelInfo = event.detail.channels_info;
107 var channelKeys = Object.keys(event.detail.channels_info);
108 for (var i = 0; i < channelKeys.length; i++) {
109 var key = channelKeys[i];
110 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
111 }
112 channelstreamConnection.set('channels', event.detail.channels);
113 this.propagageChannelsState();
114 },
115 /** propagates channel states on topics */
116 propagageChannelsState: function (event) {
117 var channelstreamConnection = this.$['channelstream-connection'];
118 var channel_data = channelstreamConnection.channelsState;
119 var channels = channelstreamConnection.channels;
120 for (var i = 0; i < channels.length; i++) {
121 var key = channels[i];
122 $.Topic('/connection_controller/channel_update').publish(
123 {channel: key, state: channel_data[key]}
124 );
125 }
126 }
127 });
@@ -1,188 +1,186 b''
1 {
1 {
2 "dirs": {
2 "dirs": {
3 "css": {
3 "css": {
4 "src":"rhodecode/public/css",
4 "src":"rhodecode/public/css",
5 "dest":"rhodecode/public/css"
5 "dest":"rhodecode/public/css"
6 },
6 },
7 "js": {
7 "js": {
8 "src": "rhodecode/public/js/src",
8 "src": "rhodecode/public/js/src",
9 "dest": "rhodecode/public/js"
9 "dest": "rhodecode/public/js"
10 }
10 }
11 },
11 },
12 "copy": {
12 "copy": {
13 "main": {
13 "main": {
14 "expand": true,
14 "expand": true,
15 "cwd": "bower_components",
15 "cwd": "bower_components",
16 "src": "webcomponentsjs/webcomponents-lite.js",
16 "src": "webcomponentsjs/webcomponents-lite.js",
17 "dest": "<%= dirs.js.dest %>/vendors"
17 "dest": "<%= dirs.js.dest %>/vendors"
18 }
18 }
19 },
19 },
20 "concat": {
20 "concat": {
21 "polymercss": {
21 "polymercss": {
22 "src": [
22 "src": [
23 "<%= dirs.js.src %>/components/root-styles-prefix.html",
23 "<%= dirs.js.src %>/components/root-styles-prefix.html",
24 "<%= dirs.css.src %>/style-polymer.css",
24 "<%= dirs.css.src %>/style-polymer.css",
25 "<%= dirs.js.src %>/components/root-styles-suffix.html"
25 "<%= dirs.js.src %>/components/root-styles-suffix.html"
26 ],
26 ],
27 "dest": "<%= dirs.js.dest %>/src/components/root-styles.gen.html",
27 "dest": "<%= dirs.js.dest %>/src/components/root-styles.gen.html",
28 "nonull": true
28 "nonull": true
29 },
29 },
30 "dist": {
30 "dist": {
31 "src": [
31 "src": [
32 "<%= dirs.js.src %>/jquery-1.11.1.min.js",
32 "<%= dirs.js.src %>/jquery-1.11.1.min.js",
33 "<%= dirs.js.src %>/logging.js",
33 "<%= dirs.js.src %>/logging.js",
34 "<%= dirs.js.src %>/bootstrap.js",
34 "<%= dirs.js.src %>/bootstrap.js",
35 "<%= dirs.js.src %>/mousetrap.js",
35 "<%= dirs.js.src %>/mousetrap.js",
36 "<%= dirs.js.src %>/moment.js",
36 "<%= dirs.js.src %>/moment.js",
37 "<%= dirs.js.src %>/appenlight-client-0.4.1.min.js",
37 "<%= dirs.js.src %>/appenlight-client-0.4.1.min.js",
38 "<%= dirs.js.src %>/i18n_utils.js",
38 "<%= dirs.js.src %>/i18n_utils.js",
39 "<%= dirs.js.src %>/deform.js",
39 "<%= dirs.js.src %>/deform.js",
40 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
40 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
41 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
41 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
42 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
42 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
43 "<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js",
43 "<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js",
44 "<%= dirs.js.src %>/plugins/jquery.autocomplete.js",
44 "<%= dirs.js.src %>/plugins/jquery.autocomplete.js",
45 "<%= dirs.js.src %>/plugins/jquery.debounce.js",
45 "<%= dirs.js.src %>/plugins/jquery.debounce.js",
46 "<%= dirs.js.src %>/plugins/jquery.mark.js",
46 "<%= dirs.js.src %>/plugins/jquery.mark.js",
47 "<%= dirs.js.src %>/plugins/jquery.timeago.js",
47 "<%= dirs.js.src %>/plugins/jquery.timeago.js",
48 "<%= dirs.js.src %>/plugins/jquery.timeago-extension.js",
48 "<%= dirs.js.src %>/plugins/jquery.timeago-extension.js",
49 "<%= dirs.js.src %>/select2/select2.js",
49 "<%= dirs.js.src %>/select2/select2.js",
50 "<%= dirs.js.src %>/codemirror/codemirror.js",
50 "<%= dirs.js.src %>/codemirror/codemirror.js",
51 "<%= dirs.js.src %>/codemirror/codemirror_loadmode.js",
51 "<%= dirs.js.src %>/codemirror/codemirror_loadmode.js",
52 "<%= dirs.js.src %>/codemirror/codemirror_hint.js",
52 "<%= dirs.js.src %>/codemirror/codemirror_hint.js",
53 "<%= dirs.js.src %>/codemirror/codemirror_overlay.js",
53 "<%= dirs.js.src %>/codemirror/codemirror_overlay.js",
54 "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js",
54 "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js",
55 "<%= dirs.js.dest %>/mode/meta.js",
55 "<%= dirs.js.dest %>/mode/meta.js",
56 "<%= dirs.js.dest %>/mode/meta_ext.js",
56 "<%= dirs.js.dest %>/mode/meta_ext.js",
57 "<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js",
57 "<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js",
58 "<%= dirs.js.src %>/rhodecode/utils/array.js",
58 "<%= dirs.js.src %>/rhodecode/utils/array.js",
59 "<%= dirs.js.src %>/rhodecode/utils/string.js",
59 "<%= dirs.js.src %>/rhodecode/utils/string.js",
60 "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js",
60 "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js",
61 "<%= dirs.js.src %>/rhodecode/utils/ajax.js",
61 "<%= dirs.js.src %>/rhodecode/utils/ajax.js",
62 "<%= dirs.js.src %>/rhodecode/utils/autocomplete.js",
62 "<%= dirs.js.src %>/rhodecode/utils/autocomplete.js",
63 "<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js",
63 "<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js",
64 "<%= dirs.js.src %>/rhodecode/utils/ie.js",
64 "<%= dirs.js.src %>/rhodecode/utils/ie.js",
65 "<%= dirs.js.src %>/rhodecode/utils/os.js",
65 "<%= dirs.js.src %>/rhodecode/utils/os.js",
66 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
66 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
67 "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js",
67 "<%= dirs.js.src %>/rhodecode/widgets/multiselect.js",
68 "<%= dirs.js.src %>/rhodecode/init.js",
68 "<%= dirs.js.src %>/rhodecode/init.js",
69 "<%= dirs.js.src %>/rhodecode/connection_controller.js",
70 "<%= dirs.js.src %>/rhodecode/codemirror.js",
69 "<%= dirs.js.src %>/rhodecode/codemirror.js",
71 "<%= dirs.js.src %>/rhodecode/comments.js",
70 "<%= dirs.js.src %>/rhodecode/comments.js",
72 "<%= dirs.js.src %>/rhodecode/constants.js",
71 "<%= dirs.js.src %>/rhodecode/constants.js",
73 "<%= dirs.js.src %>/rhodecode/files.js",
72 "<%= dirs.js.src %>/rhodecode/files.js",
74 "<%= dirs.js.src %>/rhodecode/followers.js",
73 "<%= dirs.js.src %>/rhodecode/followers.js",
75 "<%= dirs.js.src %>/rhodecode/menus.js",
74 "<%= dirs.js.src %>/rhodecode/menus.js",
76 "<%= dirs.js.src %>/rhodecode/notifications.js",
75 "<%= dirs.js.src %>/rhodecode/notifications.js",
77 "<%= dirs.js.src %>/rhodecode/permissions.js",
76 "<%= dirs.js.src %>/rhodecode/permissions.js",
78 "<%= dirs.js.src %>/rhodecode/pjax.js",
77 "<%= dirs.js.src %>/rhodecode/pjax.js",
79 "<%= dirs.js.src %>/rhodecode/pullrequests.js",
78 "<%= dirs.js.src %>/rhodecode/pullrequests.js",
80 "<%= dirs.js.src %>/rhodecode/settings.js",
79 "<%= dirs.js.src %>/rhodecode/settings.js",
81 "<%= dirs.js.src %>/rhodecode/select2_widgets.js",
80 "<%= dirs.js.src %>/rhodecode/select2_widgets.js",
82 "<%= dirs.js.src %>/rhodecode/tooltips.js",
81 "<%= dirs.js.src %>/rhodecode/tooltips.js",
83 "<%= dirs.js.src %>/rhodecode/users.js",
82 "<%= dirs.js.src %>/rhodecode/users.js",
84 "<%= dirs.js.src %>/rhodecode/utils/notifications.js",
85 "<%= dirs.js.src %>/rhodecode/appenlight.js",
83 "<%= dirs.js.src %>/rhodecode/appenlight.js",
86 "<%= dirs.js.src %>/rhodecode.js"
84 "<%= dirs.js.src %>/rhodecode.js"
87 ],
85 ],
88 "dest": "<%= dirs.js.dest %>/scripts.js",
86 "dest": "<%= dirs.js.dest %>/scripts.js",
89 "nonull": true
87 "nonull": true
90 }
88 }
91 },
89 },
92 "crisper": {
90 "crisper": {
93 "dist": {
91 "dist": {
94 "options": {
92 "options": {
95 "cleanup": false,
93 "cleanup": false,
96 "onlySplit": true
94 "onlySplit": true
97 },
95 },
98 "src": "<%= dirs.js.dest %>/rhodecode-components.html",
96 "src": "<%= dirs.js.dest %>/rhodecode-components.html",
99 "dest": "<%= dirs.js.dest %>/rhodecode-components.js"
97 "dest": "<%= dirs.js.dest %>/rhodecode-components.js"
100 }
98 }
101 },
99 },
102 "less": {
100 "less": {
103 "development": {
101 "development": {
104 "options": {
102 "options": {
105 "compress": false,
103 "compress": false,
106 "yuicompress": false,
104 "yuicompress": false,
107 "optimization": 0
105 "optimization": 0
108 },
106 },
109 "files": {
107 "files": {
110 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
108 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
111 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
109 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
112 }
110 }
113 },
111 },
114 "production": {
112 "production": {
115 "options": {
113 "options": {
116 "compress": true,
114 "compress": true,
117 "yuicompress": true,
115 "yuicompress": true,
118 "optimization": 2
116 "optimization": 2
119 },
117 },
120 "files": {
118 "files": {
121 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
119 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
122 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
120 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
123 }
121 }
124 },
122 },
125 "components": {
123 "components": {
126 "files": [
124 "files": [
127 {
125 {
128 "cwd": "<%= dirs.js.src %>/components/",
126 "cwd": "<%= dirs.js.src %>/components/",
129 "dest": "<%= dirs.js.src %>/components/",
127 "dest": "<%= dirs.js.src %>/components/",
130 "src": [
128 "src": [
131 "**/*.less"
129 "**/*.less"
132 ],
130 ],
133 "expand": true,
131 "expand": true,
134 "ext": ".css"
132 "ext": ".css"
135 }
133 }
136 ]
134 ]
137 }
135 }
138 },
136 },
139 "watch": {
137 "watch": {
140 "less": {
138 "less": {
141 "files": [
139 "files": [
142 "<%= dirs.css.src %>/**/*.less",
140 "<%= dirs.css.src %>/**/*.less",
143 "<%= dirs.js.src %>/components/**/*.less"
141 "<%= dirs.js.src %>/components/**/*.less"
144 ],
142 ],
145 "tasks": [
143 "tasks": [
146 "less:development",
144 "less:development",
147 "less:components",
145 "less:components",
148 "concat:polymercss",
146 "concat:polymercss",
149 "vulcanize"
147 "vulcanize"
150 ]
148 ]
151 },
149 },
152 "js": {
150 "js": {
153 "files": [
151 "files": [
154 "!<%= dirs.js.src %>/components/root-styles.gen.html",
152 "!<%= dirs.js.src %>/components/root-styles.gen.html",
155 "<%= dirs.js.src %>/**/*.js",
153 "<%= dirs.js.src %>/**/*.js",
156 "<%= dirs.js.src %>/components/**/*.html"
154 "<%= dirs.js.src %>/components/**/*.html"
157 ],
155 ],
158 "tasks": [
156 "tasks": [
159 "less:components",
157 "less:components",
160 "concat:polymercss",
158 "concat:polymercss",
161 "vulcanize",
159 "vulcanize",
162 "crisper",
160 "crisper",
163 "concat:dist"
161 "concat:dist"
164 ]
162 ]
165 }
163 }
166 },
164 },
167 "jshint": {
165 "jshint": {
168 "rhodecode": {
166 "rhodecode": {
169 "src": "<%= dirs.js.src %>/rhodecode/**/*.js",
167 "src": "<%= dirs.js.src %>/rhodecode/**/*.js",
170 "options": {
168 "options": {
171 "jshintrc": ".jshintrc"
169 "jshintrc": ".jshintrc"
172 }
170 }
173 }
171 }
174 },
172 },
175 "vulcanize": {
173 "vulcanize": {
176 "default": {
174 "default": {
177 "options": {
175 "options": {
178 "abspath": "",
176 "abspath": "",
179 "inlineScripts": true,
177 "inlineScripts": true,
180 "inlineCss": true,
178 "inlineCss": true,
181 "stripComments": true
179 "stripComments": true
182 },
180 },
183 "files": {
181 "files": {
184 "<%= dirs.js.dest %>/rhodecode-components.html": "<%= dirs.js.src %>/components/shared-components.html"
182 "<%= dirs.js.dest %>/rhodecode-components.html": "<%= dirs.js.src %>/components/shared-components.html"
185 }
183 }
186 }
184 }
187 }
185 }
188 }
186 }
@@ -1,79 +1,81 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22
22
23 from pyramid.settings import asbool
23 from pyramid.settings import asbool
24
24
25 from rhodecode.config.routing import ADMIN_PREFIX
25 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.lib.ext_json import json
26 from rhodecode.lib.ext_json import json
27
27
28
28
29 def url_gen(request):
29 def url_gen(request):
30 urls = {
30 urls = {
31 'connect': request.route_url('channelstream_connect'),
31 'connect': request.route_url('channelstream_connect'),
32 'subscribe': request.route_url('channelstream_subscribe')
32 'subscribe': request.route_url('channelstream_subscribe'),
33 'longpoll': request.registry.settings.get('channelstream.longpoll_url', ''),
34 'ws': request.registry.settings.get('channelstream.ws_url', '')
33 }
35 }
34 return json.dumps(urls)
36 return json.dumps(urls)
35
37
36
38
37 PLUGIN_DEFINITION = {
39 PLUGIN_DEFINITION = {
38 'name': 'channelstream',
40 'name': 'channelstream',
39 'config': {
41 'config': {
40 'javascript': [],
42 'javascript': [],
41 'css': [],
43 'css': [],
42 'template_hooks': {
44 'template_hooks': {
43 'plugin_init_template': 'rhodecode:templates/channelstream/plugin_init.html'
45 'plugin_init_template': 'rhodecode:templates/channelstream/plugin_init.html'
44 },
46 },
45 'url_gen': url_gen,
47 'url_gen': url_gen,
46 'static': None,
48 'static': None,
47 'enabled': False,
49 'enabled': False,
48 'server': '',
50 'server': '',
49 'secret': ''
51 'secret': ''
50 }
52 }
51 }
53 }
52
54
53
55
54 def includeme(config):
56 def includeme(config):
55 settings = config.registry.settings
57 settings = config.registry.settings
56 PLUGIN_DEFINITION['config']['enabled'] = asbool(
58 PLUGIN_DEFINITION['config']['enabled'] = asbool(
57 settings.get('channelstream.enabled'))
59 settings.get('channelstream.enabled'))
58 PLUGIN_DEFINITION['config']['server'] = settings.get(
60 PLUGIN_DEFINITION['config']['server'] = settings.get(
59 'channelstream.server', '')
61 'channelstream.server', '')
60 PLUGIN_DEFINITION['config']['secret'] = settings.get(
62 PLUGIN_DEFINITION['config']['secret'] = settings.get(
61 'channelstream.secret', '')
63 'channelstream.secret', '')
62 PLUGIN_DEFINITION['config']['history.location'] = settings.get(
64 PLUGIN_DEFINITION['config']['history.location'] = settings.get(
63 'channelstream.history.location', '')
65 'channelstream.history.location', '')
64 config.register_rhodecode_plugin(
66 config.register_rhodecode_plugin(
65 PLUGIN_DEFINITION['name'],
67 PLUGIN_DEFINITION['name'],
66 PLUGIN_DEFINITION['config']
68 PLUGIN_DEFINITION['config']
67 )
69 )
68 # create plugin history location
70 # create plugin history location
69 history_dir = PLUGIN_DEFINITION['config']['history.location']
71 history_dir = PLUGIN_DEFINITION['config']['history.location']
70 if history_dir and not os.path.exists(history_dir):
72 if history_dir and not os.path.exists(history_dir):
71 os.makedirs(history_dir, 0750)
73 os.makedirs(history_dir, 0750)
72
74
73 config.add_route(
75 config.add_route(
74 name='channelstream_connect',
76 name='channelstream_connect',
75 pattern=ADMIN_PREFIX + '/channelstream/connect')
77 pattern=ADMIN_PREFIX + '/channelstream/connect')
76 config.add_route(
78 config.add_route(
77 name='channelstream_subscribe',
79 name='channelstream_subscribe',
78 pattern=ADMIN_PREFIX + '/channelstream/subscribe')
80 pattern=ADMIN_PREFIX + '/channelstream/subscribe')
79 config.scan('rhodecode.channelstream')
81 config.scan('rhodecode.channelstream')
@@ -1,31 +1,38 b''
1 Polymer({
1 Polymer({
2 is: 'rhodecode-toast',
2 is: 'rhodecode-toast',
3 properties: {
3 properties: {
4 toasts: {
4 toasts: {
5 type: Array,
5 type: Array,
6 value: function(){
6 value: function(){
7 return []
7 return []
8 }
8 }
9 }
9 }
10 },
10 },
11 observers: [
11 observers: [
12 '_changedToasts(toasts.splices)'
12 '_changedToasts(toasts.splices)'
13 ],
13 ],
14 ready: function(){
15
16 },
17
18 _changedToasts: function(newValue, oldValue){
14 _changedToasts: function(newValue, oldValue){
19 this.$['p-toast'].notifyResize();
15 this.$['p-toast'].notifyResize();
20 },
16 },
21 dismissNotifications: function(){
17 dismissNotifications: function(){
22 this.$['p-toast'].close();
18 this.$['p-toast'].close();
23 },
19 },
24 handleClosed: function(){
20 handleClosed: function(){
25 this.splice('toasts', 0);
21 this.splice('toasts', 0);
26 },
22 },
27 open: function(){
23 open: function(){
28 this.$['p-toast'].open();
24 this.$['p-toast'].open();
29 },
25 },
26 handleNotification: function(data){
27 if (!templateContext.rhodecode_user.notification_status && !data.message.force) {
28 // do not act if notifications are disabled
29 return
30 }
31 this.push('toasts',{
32 level: data.message.level,
33 message: data.message.message
34 });
35 this.open();
36 },
30 _gettext: _gettext
37 _gettext: _gettext
31 });
38 });
@@ -1,6 +1,8 b''
1 <!-- required for stamped out templates that might use common elements -->
1 <!-- required for stamped out templates that might use common elements -->
2 <link rel="import" href="../../../../../bower_components/iron-ajax/iron-ajax.html">
2 <link rel="import" href="../../../../../bower_components/iron-ajax/iron-ajax.html">
3 <link rel="import" href="shared-styles.html">
3 <link rel="import" href="shared-styles.html">
4 <link rel="import" href="channelstream-connection/channelstream-connection.html">
5 <link rel="import" href="rhodecode-app/rhodecode-app.html">
4 <link rel="import" href="rhodecode-toast/rhodecode-toast.html">
6 <link rel="import" href="rhodecode-toast/rhodecode-toast.html">
5 <link rel="import" href="rhodecode-toggle/rhodecode-toggle.html">
7 <link rel="import" href="rhodecode-toggle/rhodecode-toggle.html">
6 <link rel="import" href="rhodecode-unsafe-html/rhodecode-unsafe-html.html">
8 <link rel="import" href="rhodecode-unsafe-html/rhodecode-unsafe-html.html">
@@ -1,4 +1,7 b''
1 /plugins/__REGISTER__ - launched after the onDomReady() code from rhodecode.js is executed
1 /plugins/__REGISTER__ - launched after the onDomReady() code from rhodecode.js is executed
2 /ui/plugins/code/anchor_focus - launched when rc starts to scroll on load to anchor on PR/Codeview
2 /ui/plugins/code/anchor_focus - launched when rc starts to scroll on load to anchor on PR/Codeview
3 /ui/plugins/code/comment_form_built - launched when injectInlineForm() is executed and the form object is created
3 /ui/plugins/code/comment_form_built - launched when injectInlineForm() is executed and the form object is created
4 /notifications - shows new event notifications No newline at end of file
4 /notifications - shows new event notifications
5 /connection_controller/subscribe - subscribes user to new channels
6 /connection_controller/presence - receives presence change messages
7 /connection_controller/channel_update - receives channel states
@@ -1,179 +1,181 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html>
2 <!DOCTYPE html>
3
3
4 <%
4 <%
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
5 c.template_context['repo_name'] = getattr(c, 'repo_name', '')
6
6
7 if hasattr(c, 'rhodecode_db_repo'):
7 if hasattr(c, 'rhodecode_db_repo'):
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
8 c.template_context['repo_type'] = c.rhodecode_db_repo.repo_type
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
9 c.template_context['repo_landing_commit'] = c.rhodecode_db_repo.landing_rev[1]
10
10
11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
11 if getattr(c, 'rhodecode_user', None) and c.rhodecode_user.user_id:
12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
12 c.template_context['rhodecode_user']['username'] = c.rhodecode_user.username
13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
13 c.template_context['rhodecode_user']['email'] = c.rhodecode_user.email
14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
14 c.template_context['rhodecode_user']['notification_status'] = c.rhodecode_user.get_instance().user_data.get('notification_status', True)
15
15
16 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
16 c.template_context['visual']['default_renderer'] = h.get_visual_attr(c, 'default_renderer')
17 %>
17 %>
18 <html xmlns="http://www.w3.org/1999/xhtml">
18 <html xmlns="http://www.w3.org/1999/xhtml">
19 <head>
19 <head>
20 <title>${self.title()}</title>
20 <title>${self.title()}</title>
21 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
21 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
22 <%def name="robots()">
22 <%def name="robots()">
23 <meta name="robots" content="index, nofollow"/>
23 <meta name="robots" content="index, nofollow"/>
24 </%def>
24 </%def>
25 ${self.robots()}
25 ${self.robots()}
26 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
26 <link rel="icon" href="${h.asset('images/favicon.ico', ver=c.rhodecode_version_hash)}" sizes="16x16 32x32" type="image/png" />
27
27
28 ## CSS definitions
28 ## CSS definitions
29 <%def name="css()">
29 <%def name="css()">
30 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
30 <link rel="stylesheet" type="text/css" href="${h.asset('css/style.css', ver=c.rhodecode_version_hash)}" media="screen"/>
31 <!--[if lt IE 9]>
31 <!--[if lt IE 9]>
32 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
32 <link rel="stylesheet" type="text/css" href="${h.asset('css/ie.css', ver=c.rhodecode_version_hash)}" media="screen"/>
33 <![endif]-->
33 <![endif]-->
34 ## EXTRA FOR CSS
34 ## EXTRA FOR CSS
35 ${self.css_extra()}
35 ${self.css_extra()}
36 </%def>
36 </%def>
37 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
37 ## CSS EXTRA - optionally inject some extra CSS stuff needed for specific websites
38 <%def name="css_extra()">
38 <%def name="css_extra()">
39 </%def>
39 </%def>
40
40
41 ${self.css()}
41 ${self.css()}
42
42
43 ## JAVASCRIPT
43 ## JAVASCRIPT
44 <%def name="js()">
44 <%def name="js()">
45 <script>
45 <script>
46 // setup Polymer options
46 // setup Polymer options
47 window.Polymer = {lazyRegister: true, dom: 'shadow'};
47 window.Polymer = {lazyRegister: true, dom: 'shadow'};
48
48
49 // Load webcomponentsjs polyfill if browser does not support native Web Components
49 // Load webcomponentsjs polyfill if browser does not support native Web Components
50 (function() {
50 (function() {
51 'use strict';
51 'use strict';
52 var onload = function() {
52 var onload = function() {
53 // For native Imports, manually fire WebComponentsReady so user code
53 // For native Imports, manually fire WebComponentsReady so user code
54 // can use the same code path for native and polyfill'd imports.
54 // can use the same code path for native and polyfill'd imports.
55 if (!window.HTMLImports) {
55 if (!window.HTMLImports) {
56 document.dispatchEvent(
56 document.dispatchEvent(
57 new CustomEvent('WebComponentsReady', {bubbles: true})
57 new CustomEvent('WebComponentsReady', {bubbles: true})
58 );
58 );
59 }
59 }
60 };
60 };
61 var webComponentsSupported = (
61 var webComponentsSupported = (
62 'registerElement' in document
62 'registerElement' in document
63 && 'import' in document.createElement('link')
63 && 'import' in document.createElement('link')
64 && 'content' in document.createElement('template')
64 && 'content' in document.createElement('template')
65 );
65 );
66 if (!webComponentsSupported) {
66 if (!webComponentsSupported) {
67 var e = document.createElement('script');
67 var e = document.createElement('script');
68 e.async = true;
68 e.async = true;
69 e.src = '${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}';
69 e.src = '${h.asset('js/vendors/webcomponentsjs/webcomponents-lite.min.js', ver=c.rhodecode_version_hash)}';
70 document.head.appendChild(e);
70 document.head.appendChild(e);
71 } else {
71 } else {
72 onload();
72 onload();
73 }
73 }
74 })();
74 })();
75 </script>
75 </script>
76
76
77 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
77 <script src="${h.asset('js/rhodecode/i18n/%s.js' % c.language, ver=c.rhodecode_version_hash)}"></script>
78 <script type="text/javascript">
78 <script type="text/javascript">
79 // register templateContext to pass template variables to JS
79 // register templateContext to pass template variables to JS
80 var templateContext = ${h.json.dumps(c.template_context)|n};
80 var templateContext = ${h.json.dumps(c.template_context)|n};
81
81
82 var REPO_NAME = "${getattr(c, 'repo_name', '')}";
82 var REPO_NAME = "${getattr(c, 'repo_name', '')}";
83 %if hasattr(c, 'rhodecode_db_repo'):
83 %if hasattr(c, 'rhodecode_db_repo'):
84 var REPO_LANDING_REV = '${c.rhodecode_db_repo.landing_rev[1]}';
84 var REPO_LANDING_REV = '${c.rhodecode_db_repo.landing_rev[1]}';
85 var REPO_TYPE = '${c.rhodecode_db_repo.repo_type}';
85 var REPO_TYPE = '${c.rhodecode_db_repo.repo_type}';
86 %else:
86 %else:
87 var REPO_LANDING_REV = '';
87 var REPO_LANDING_REV = '';
88 var REPO_TYPE = '';
88 var REPO_TYPE = '';
89 %endif
89 %endif
90 var APPLICATION_URL = "${h.url('home').rstrip('/')}";
90 var APPLICATION_URL = "${h.url('home').rstrip('/')}";
91 var ASSET_URL = "${h.asset('')}";
91 var ASSET_URL = "${h.asset('')}";
92 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
92 var DEFAULT_RENDERER = "${h.get_visual_attr(c, 'default_renderer')}";
93 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
93 var CSRF_TOKEN = "${getattr(c, 'csrf_token', '')}";
94 % if getattr(c, 'rhodecode_user', None):
94 % if getattr(c, 'rhodecode_user', None):
95 var USER = {name:'${c.rhodecode_user.username}'};
95 var USER = {name:'${c.rhodecode_user.username}'};
96 % else:
96 % else:
97 var USER = {name:null};
97 var USER = {name:null};
98 % endif
98 % endif
99
99
100 var APPENLIGHT = {
100 var APPENLIGHT = {
101 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
101 enabled: ${'true' if getattr(c, 'appenlight_enabled', False) else 'false'},
102 key: '${getattr(c, "appenlight_api_public_key", "")}',
102 key: '${getattr(c, "appenlight_api_public_key", "")}',
103 % if getattr(c, 'appenlight_server_url', None):
103 % if getattr(c, 'appenlight_server_url', None):
104 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
104 serverUrl: '${getattr(c, "appenlight_server_url", "")}',
105 % endif
105 % endif
106 requestInfo: {
106 requestInfo: {
107 % if getattr(c, 'rhodecode_user', None):
107 % if getattr(c, 'rhodecode_user', None):
108 ip: '${c.rhodecode_user.ip_addr}',
108 ip: '${c.rhodecode_user.ip_addr}',
109 username: '${c.rhodecode_user.username}'
109 username: '${c.rhodecode_user.username}'
110 % endif
110 % endif
111 }
111 }
112 };
112 };
113 </script>
113 </script>
114 <%include file="/base/plugins_base.html"/>
114 <%include file="/base/plugins_base.html"/>
115 <!--[if lt IE 9]>
115 <!--[if lt IE 9]>
116 <script language="javascript" type="text/javascript" src="${h.asset('js/excanvas.min.js')}"></script>
116 <script language="javascript" type="text/javascript" src="${h.asset('js/excanvas.min.js')}"></script>
117 <![endif]-->
117 <![endif]-->
118 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
118 <script language="javascript" type="text/javascript" src="${h.asset('js/rhodecode/routes.js', ver=c.rhodecode_version_hash)}"></script>
119 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
119 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
120 <script>
120 <script>
121 var e = document.createElement('script');
121 var e = document.createElement('script');
122 e.src = '${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}';
122 e.src = '${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}';
123 document.head.appendChild(e);
123 document.head.appendChild(e);
124 </script>
124 </script>
125 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
125 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
126 ## avoide escaping the %N
126 ## avoide escaping the %N
127 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
127 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
128
128
129
129
130 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
130 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
131 ${self.js_extra()}
131 ${self.js_extra()}
132
132
133 <script type="text/javascript">
133 <script type="text/javascript">
134 $(document).ready(function(){
134 $(document).ready(function(){
135 show_more_event();
135 show_more_event();
136 timeagoActivate();
136 timeagoActivate();
137 })
137 })
138 </script>
138 </script>
139
139
140 </%def>
140 </%def>
141
141
142 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
142 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
143 <%def name="js_extra()"></%def>
143 <%def name="js_extra()"></%def>
144 ${self.js()}
144 ${self.js()}
145
145
146 <%def name="head_extra()"></%def>
146 <%def name="head_extra()"></%def>
147 ${self.head_extra()}
147 ${self.head_extra()}
148 <script>
148 <script>
149 $.Topic('/plugins/__REGISTER__').prepareOrPublish({});
149 window.addEventListener("load", function(event) {
150 $.Topic('/plugins/__REGISTER__').prepareOrPublish({});
151 });
150 </script>
152 </script>
151 ## extra stuff
153 ## extra stuff
152 %if c.pre_code:
154 %if c.pre_code:
153 ${c.pre_code|n}
155 ${c.pre_code|n}
154 %endif
156 %endif
155 </head>
157 </head>
156 <body id="body">
158 <body id="body">
157 <noscript>
159 <noscript>
158 <div class="noscript-error">
160 <div class="noscript-error">
159 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
161 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
160 </div>
162 </div>
161 </noscript>
163 </noscript>
162 ## IE hacks
164 ## IE hacks
163 <!--[if IE 7]>
165 <!--[if IE 7]>
164 <script>$(document.body).addClass('ie7')</script>
166 <script>$(document.body).addClass('ie7')</script>
165 <![endif]-->
167 <![endif]-->
166 <!--[if IE 8]>
168 <!--[if IE 8]>
167 <script>$(document.body).addClass('ie8')</script>
169 <script>$(document.body).addClass('ie8')</script>
168 <![endif]-->
170 <![endif]-->
169 <!--[if IE 9]>
171 <!--[if IE 9]>
170 <script>$(document.body).addClass('ie9')</script>
172 <script>$(document.body).addClass('ie9')</script>
171 <![endif]-->
173 <![endif]-->
172
174
173 ${next.body()}
175 ${next.body()}
174 %if c.post_code:
176 %if c.post_code:
175 ${c.post_code|n}
177 ${c.post_code|n}
176 %endif
178 %endif
177 <rhodecode-toast id="notifications"></rhodecode-toast>
179 <rhodecode-app></rhodecode-app>
178 </body>
180 </body>
179 </html>
181 </html>
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now