##// END OF EJS Templates
topics: remove dependency on __REGISTER__ so we avoid race condition
ergo -
r838:80501835 default
parent child Browse files
Show More
@@ -1,133 +1,129 b''
1 ccLog = Logger.get('RhodeCodeApp');
1 ccLog = Logger.get('RhodeCodeApp');
2 ccLog.setLevel(Logger.OFF);
2 ccLog.setLevel(Logger.OFF);
3
3
4 var rhodeCodeApp = Polymer({
4 var rhodeCodeApp = Polymer({
5 is: 'rhodecode-app',
5 is: 'rhodecode-app',
6 attached: function () {
6 attached: function () {
7 ccLog.debug('rhodeCodeApp created');
7 ccLog.debug('rhodeCodeApp created');
8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
8 $.Topic('/notifications').subscribe(this.handleNotifications.bind(this));
9
9
10 for (var i = 0; i < alertMessagePayloads.length; i++) {
10 for (var i = 0; i < alertMessagePayloads.length; i++) {
11 $.Topic('/notifications').publish(alertMessagePayloads[i]);
11 $.Topic('/notifications').publish(alertMessagePayloads[i]);
12 }
12 }
13
14 $.Topic('/plugins/__REGISTER__').subscribe(
15 this.kickoffChannelstreamPlugin.bind(this)
16 );
17
18 $.Topic('/connection_controller/subscribe').subscribe(
13 $.Topic('/connection_controller/subscribe').subscribe(
19 this.subscribeToChannelTopic.bind(this));
14 this.subscribeToChannelTopic.bind(this));
15 this.kickoffChannelstreamPlugin();
20 },
16 },
21
17
22 /** proxy to channelstream connection */
18 /** proxy to channelstream connection */
23 getChannelStreamConnection: function () {
19 getChannelStreamConnection: function () {
24 return this.$['channelstream-connection'];
20 return this.$['channelstream-connection'];
25 },
21 },
26
22
27 handleNotifications: function (data) {
23 handleNotifications: function (data) {
28 this.$['notifications'].handleNotification(data);
24 this.$['notifications'].handleNotification(data);
29 },
25 },
30
26
31 /** opens connection to ws server */
27 /** opens connection to ws server */
32 kickoffChannelstreamPlugin: function (data) {
28 kickoffChannelstreamPlugin: function (data) {
33 ccLog.debug('kickoffChannelstreamPlugin');
29 ccLog.debug('kickoffChannelstreamPlugin');
34 var channels = ['broadcast'];
30 var channels = ['broadcast'];
35 var addChannels = this.checkViewChannels();
31 var addChannels = this.checkViewChannels();
36 for (var i = 0; i < addChannels.length; i++) {
32 for (var i = 0; i < addChannels.length; i++) {
37 channels.push(addChannels[i]);
33 channels.push(addChannels[i]);
38 }
34 }
39 if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
35 if (window.CHANNELSTREAM_SETTINGS && CHANNELSTREAM_SETTINGS.enabled){
40 var channelstreamConnection = this.$['channelstream-connection'];
36 var channelstreamConnection = this.$['channelstream-connection'];
41 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
37 channelstreamConnection.connectUrl = CHANNELSTREAM_URLS.connect;
42 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
38 channelstreamConnection.subscribeUrl = CHANNELSTREAM_URLS.subscribe;
43 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
39 channelstreamConnection.websocketUrl = CHANNELSTREAM_URLS.ws + '/ws';
44 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
40 channelstreamConnection.longPollUrl = CHANNELSTREAM_URLS.longpoll + '/listen';
45 // some channels might already be registered by topic
41 // some channels might already be registered by topic
46 for (var i = 0; i < channels.length; i++) {
42 for (var i = 0; i < channels.length; i++) {
47 channelstreamConnection.push('channels', channels[i]);
43 channelstreamConnection.push('channels', channels[i]);
48 }
44 }
49 // append any additional channels registered in other plugins
45 // append any additional channels registered in other plugins
50 $.Topic('/connection_controller/subscribe').processPrepared();
46 $.Topic('/connection_controller/subscribe').processPrepared();
51 channelstreamConnection.connect();
47 channelstreamConnection.connect();
52 }
48 }
53 },
49 },
54
50
55 checkViewChannels: function () {
51 checkViewChannels: function () {
56 var channels = []
52 var channels = []
57 // subscribe to PR repo channel for PR's'
53 // subscribe to PR repo channel for PR's'
58 if (templateContext.pull_request_data.pull_request_id) {
54 if (templateContext.pull_request_data.pull_request_id) {
59 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
55 var channelName = '/repo$' + templateContext.repo_name + '$/pr/' +
60 String(templateContext.pull_request_data.pull_request_id);
56 String(templateContext.pull_request_data.pull_request_id);
61 channels.push(channelName);
57 channels.push(channelName);
62 }
58 }
63 return channels;
59 return channels;
64 },
60 },
65
61
66 /** subscribes users from channels in channelstream */
62 /** subscribes users from channels in channelstream */
67 subscribeToChannelTopic: function (channels) {
63 subscribeToChannelTopic: function (channels) {
68 var channelstreamConnection = this.$['channelstream-connection'];
64 var channelstreamConnection = this.$['channelstream-connection'];
69 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
65 var toSubscribe = channelstreamConnection.calculateSubscribe(channels);
70 ccLog.debug('subscribeToChannelTopic', toSubscribe);
66 ccLog.debug('subscribeToChannelTopic', toSubscribe);
71 if (toSubscribe.length > 0) {
67 if (toSubscribe.length > 0) {
72 // if we are connected then subscribe
68 // if we are connected then subscribe
73 if (channelstreamConnection.connected) {
69 if (channelstreamConnection.connected) {
74 channelstreamConnection.subscribe(toSubscribe);
70 channelstreamConnection.subscribe(toSubscribe);
75 }
71 }
76 // not connected? just push channels onto the stack
72 // not connected? just push channels onto the stack
77 else {
73 else {
78 for (var i = 0; i < toSubscribe.length; i++) {
74 for (var i = 0; i < toSubscribe.length; i++) {
79 channelstreamConnection.push('channels', toSubscribe[i]);
75 channelstreamConnection.push('channels', toSubscribe[i]);
80 }
76 }
81 }
77 }
82 }
78 }
83 },
79 },
84
80
85 /** publish received messages into correct topic */
81 /** publish received messages into correct topic */
86 receivedMessage: function (event) {
82 receivedMessage: function (event) {
87 for (var i = 0; i < event.detail.length; i++) {
83 for (var i = 0; i < event.detail.length; i++) {
88 var message = event.detail[i];
84 var message = event.detail[i];
89 if (message.message.topic) {
85 if (message.message.topic) {
90 ccLog.debug('publishing', message.message.topic);
86 ccLog.debug('publishing', message.message.topic);
91 $.Topic(message.message.topic).publish(message);
87 $.Topic(message.message.topic).publish(message);
92 }
88 }
93 else if (message.type === 'presence'){
89 else if (message.type === 'presence'){
94 $.Topic('/connection_controller/presence').publish(message);
90 $.Topic('/connection_controller/presence').publish(message);
95 }
91 }
96 else {
92 else {
97 ccLog.warn('unhandled message', message);
93 ccLog.warn('unhandled message', message);
98 }
94 }
99 }
95 }
100 },
96 },
101
97
102 handleConnected: function (event) {
98 handleConnected: function (event) {
103 var channelstreamConnection = this.$['channelstream-connection'];
99 var channelstreamConnection = this.$['channelstream-connection'];
104 channelstreamConnection.set('channelsState',
100 channelstreamConnection.set('channelsState',
105 event.detail.channels_info);
101 event.detail.channels_info);
106 channelstreamConnection.set('userState', event.detail.state);
102 channelstreamConnection.set('userState', event.detail.state);
107 channelstreamConnection.set('channels', event.detail.channels);
103 channelstreamConnection.set('channels', event.detail.channels);
108 this.propagageChannelsState();
104 this.propagageChannelsState();
109 },
105 },
110 handleSubscribed: function (event) {
106 handleSubscribed: function (event) {
111 var channelstreamConnection = this.$['channelstream-connection'];
107 var channelstreamConnection = this.$['channelstream-connection'];
112 var channelInfo = event.detail.channels_info;
108 var channelInfo = event.detail.channels_info;
113 var channelKeys = Object.keys(event.detail.channels_info);
109 var channelKeys = Object.keys(event.detail.channels_info);
114 for (var i = 0; i < channelKeys.length; i++) {
110 for (var i = 0; i < channelKeys.length; i++) {
115 var key = channelKeys[i];
111 var key = channelKeys[i];
116 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
112 channelstreamConnection.set(['channelsState', key], channelInfo[key]);
117 }
113 }
118 channelstreamConnection.set('channels', event.detail.channels);
114 channelstreamConnection.set('channels', event.detail.channels);
119 this.propagageChannelsState();
115 this.propagageChannelsState();
120 },
116 },
121 /** propagates channel states on topics */
117 /** propagates channel states on topics */
122 propagageChannelsState: function (event) {
118 propagageChannelsState: function (event) {
123 var channelstreamConnection = this.$['channelstream-connection'];
119 var channelstreamConnection = this.$['channelstream-connection'];
124 var channel_data = channelstreamConnection.channelsState;
120 var channel_data = channelstreamConnection.channelsState;
125 var channels = channelstreamConnection.channels;
121 var channels = channelstreamConnection.channels;
126 for (var i = 0; i < channels.length; i++) {
122 for (var i = 0; i < channels.length; i++) {
127 var key = channels[i];
123 var key = channels[i];
128 $.Topic('/connection_controller/channel_update').publish(
124 $.Topic('/connection_controller/channel_update').publish(
129 {channel: key, state: channel_data[key]}
125 {channel: key, state: channel_data[key]}
130 );
126 );
131 }
127 }
132 }
128 }
133 });
129 });
@@ -1,182 +1,177 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> var alertMessagePayloads = ${h.flash.json_alerts()|n}; </script>
119 <script> var alertMessagePayloads = ${h.flash.json_alerts()|n}; </script>
120 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
120 <script language="javascript" type="text/javascript" src="${h.asset('js/scripts.js', ver=c.rhodecode_version_hash)}"></script>
121 <script>
121 <script>
122 var e = document.createElement('script');
122 var e = document.createElement('script');
123 e.src = '${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}';
123 e.src = '${h.asset('js/rhodecode-components.js', ver=c.rhodecode_version_hash)}';
124 document.head.appendChild(e);
124 document.head.appendChild(e);
125 </script>
125 </script>
126 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
126 <link rel="import" href="${h.asset('js/rhodecode-components.html', ver=c.rhodecode_version_hash)}">
127 ## avoide escaping the %N
127 ## avoide escaping the %N
128 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
128 <script>CodeMirror.modeURL = "${h.asset('') + 'js/mode/%N/%N.js?ver='+c.rhodecode_version_hash}";</script>
129
129
130
130
131 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
131 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
132 ${self.js_extra()}
132 ${self.js_extra()}
133
133
134 <script type="text/javascript">
134 <script type="text/javascript">
135 $(document).ready(function(){
135 $(document).ready(function(){
136 show_more_event();
136 show_more_event();
137 timeagoActivate();
137 timeagoActivate();
138 })
138 })
139 </script>
139 </script>
140
140
141 </%def>
141 </%def>
142
142
143 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
143 ## JAVASCRIPT EXTRA - optionally inject some extra JS for specificed templates
144 <%def name="js_extra()"></%def>
144 <%def name="js_extra()"></%def>
145 ${self.js()}
145 ${self.js()}
146
146
147 <%def name="head_extra()"></%def>
147 <%def name="head_extra()"></%def>
148 ${self.head_extra()}
148 ${self.head_extra()}
149 <script>
150 window.addEventListener("load", function(event) {
151 $.Topic('/plugins/__REGISTER__').prepareOrPublish({});
152 });
153 </script>
154 ## extra stuff
149 ## extra stuff
155 %if c.pre_code:
150 %if c.pre_code:
156 ${c.pre_code|n}
151 ${c.pre_code|n}
157 %endif
152 %endif
158 </head>
153 </head>
159 <body id="body">
154 <body id="body">
160 <noscript>
155 <noscript>
161 <div class="noscript-error">
156 <div class="noscript-error">
162 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
157 ${_('Please enable JavaScript to use RhodeCode Enterprise')}
163 </div>
158 </div>
164 </noscript>
159 </noscript>
165 ## IE hacks
160 ## IE hacks
166 <!--[if IE 7]>
161 <!--[if IE 7]>
167 <script>$(document.body).addClass('ie7')</script>
162 <script>$(document.body).addClass('ie7')</script>
168 <![endif]-->
163 <![endif]-->
169 <!--[if IE 8]>
164 <!--[if IE 8]>
170 <script>$(document.body).addClass('ie8')</script>
165 <script>$(document.body).addClass('ie8')</script>
171 <![endif]-->
166 <![endif]-->
172 <!--[if IE 9]>
167 <!--[if IE 9]>
173 <script>$(document.body).addClass('ie9')</script>
168 <script>$(document.body).addClass('ie9')</script>
174 <![endif]-->
169 <![endif]-->
175
170
176 ${next.body()}
171 ${next.body()}
177 %if c.post_code:
172 %if c.post_code:
178 ${c.post_code|n}
173 ${c.post_code|n}
179 %endif
174 %endif
180 <rhodecode-app></rhodecode-app>
175 <rhodecode-app></rhodecode-app>
181 </body>
176 </body>
182 </html>
177 </html>
General Comments 0
You need to be logged in to leave comments. Login now