Show More
@@ -1,25 +1,24 b'' | |||||
1 | <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html"> |
|
1 | <link rel="import" href="../../../../../../bower_components/paper-button/paper-button.html"> | |
2 | <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html"> |
|
2 | <link rel="import" href="../../../../../../bower_components/paper-toast/paper-toast.html"> | |
3 | <link rel="import" href="../../../../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html"> |
|
3 | <link rel="import" href="../../../../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html"> | |
4 | <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html"> |
|
4 | <link rel="import" href="../rhodecode-unsafe-html/rhodecode-unsafe-html.html"> | |
5 | <dom-module id="rhodecode-toast"> |
|
5 | <dom-module id="rhodecode-toast"> | |
6 | <template> |
|
6 | <template> | |
7 | <style include="shared-styles"></style> |
|
7 | <style include="shared-styles"></style> | |
8 | <link rel="stylesheet" href="rhodecode-toast.css"> |
|
8 | <link rel="stylesheet" href="rhodecode-toast.css"> | |
9 | <template is="dom-if" if="[[hasToasts]]"> |
|
9 | <template is="dom-if" if="[[hasToasts]]"> | |
10 | <div class$="container toast-message-holder [[conditionalClass(isFixed)]]"> |
|
10 | <div class$="container toast-message-holder [[conditionalClass(isFixed)]]"> | |
11 | <template is="dom-repeat" items="[[toasts]]"> |
|
11 | <template is="dom-repeat" items="[[toasts]]"> | |
12 | <div class$="alert alert-[[item.level]]"> |
|
12 | <div class$="alert alert-[[item.level]]"> | |
|
13 | <div on-tap="dismissNotification" class="toast-close" index-pos="[[index]]"> | |||
|
14 | <span>[[_gettext('Close')]]</span> | |||
|
15 | </div> | |||
13 | <rhodecode-unsafe-html text="[[item.message]]"></rhodecode-unsafe-html> |
|
16 | <rhodecode-unsafe-html text="[[item.message]]"></rhodecode-unsafe-html> | |
14 | </div> |
|
17 | </div> | |
15 | </template> |
|
18 | </template> | |
16 |
|
||||
17 | <div class="toast-close"> |
|
|||
18 | <button on-tap="dismissNotifications" class="btn btn-default">[[_gettext('Close')]]</button> |
|
|||
19 | </div> |
|
|||
20 | </div> |
|
19 | </div> | |
21 | </template> |
|
20 | </template> | |
22 | </template> |
|
21 | </template> | |
23 |
|
22 | |||
24 | <script src="rhodecode-toast.js"></script> |
|
23 | <script src="rhodecode-toast.js"></script> | |
25 | </dom-module> |
|
24 | </dom-module> |
@@ -1,92 +1,98 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 | isFixed: { |
|
10 | isFixed: { | |
11 | type: Boolean, |
|
11 | type: Boolean, | |
12 | value: false |
|
12 | value: false | |
13 | }, |
|
13 | }, | |
14 | hasToasts: { |
|
14 | hasToasts: { | |
15 | type: Boolean, |
|
15 | type: Boolean, | |
16 | computed: '_computeHasToasts(toasts.*)' |
|
16 | computed: '_computeHasToasts(toasts.*)' | |
17 | }, |
|
17 | }, | |
18 | keyEventTarget: { |
|
18 | keyEventTarget: { | |
19 | type: Object, |
|
19 | type: Object, | |
20 | value: function() { |
|
20 | value: function() { | |
21 | return document.body; |
|
21 | return document.body; | |
22 | } |
|
22 | } | |
23 | } |
|
23 | } | |
24 | }, |
|
24 | }, | |
25 | behaviors: [ |
|
25 | behaviors: [ | |
26 | Polymer.IronA11yKeysBehavior |
|
26 | Polymer.IronA11yKeysBehavior | |
27 | ], |
|
27 | ], | |
28 | observers: [ |
|
28 | observers: [ | |
29 | '_changedToasts(toasts.splices)' |
|
29 | '_changedToasts(toasts.splices)' | |
30 | ], |
|
30 | ], | |
31 |
|
31 | |||
32 | keyBindings: { |
|
32 | keyBindings: { | |
33 | 'esc:keyup': '_hideOnEsc' |
|
33 | 'esc:keyup': '_hideOnEsc' | |
34 | }, |
|
34 | }, | |
35 |
|
35 | |||
36 | _hideOnEsc: function (event) { |
|
36 | _hideOnEsc: function (event) { | |
37 | return this.dismissNotifications(); |
|
37 | return this.dismissNotifications(); | |
38 | }, |
|
38 | }, | |
39 |
|
39 | |||
40 | _computeHasToasts: function(){ |
|
40 | _computeHasToasts: function(){ | |
41 | return this.toasts.length > 0; |
|
41 | return this.toasts.length > 0; | |
42 | }, |
|
42 | }, | |
43 |
|
43 | |||
44 | _debouncedCalc: function(){ |
|
44 | _debouncedCalc: function(){ | |
45 | // calculate once in a while |
|
45 | // calculate once in a while | |
46 | this.debounce('debouncedCalc', this.toastInWindow, 25); |
|
46 | this.debounce('debouncedCalc', this.toastInWindow, 25); | |
47 | }, |
|
47 | }, | |
48 |
|
48 | |||
49 | conditionalClass: function(){ |
|
49 | conditionalClass: function(){ | |
50 | return this.isFixed ? 'fixed': ''; |
|
50 | return this.isFixed ? 'fixed': ''; | |
51 | }, |
|
51 | }, | |
52 |
|
52 | |||
53 | toastInWindow: function() { |
|
53 | toastInWindow: function() { | |
54 | if (!this._headerNode){ |
|
54 | if (!this._headerNode){ | |
55 | return true |
|
55 | return true | |
56 | } |
|
56 | } | |
57 | var headerHeight = this._headerNode.offsetHeight; |
|
57 | var headerHeight = this._headerNode.offsetHeight; | |
58 | var scrollPosition = window.scrollY; |
|
58 | var scrollPosition = window.scrollY; | |
59 |
|
59 | |||
60 | if (this.isFixed){ |
|
60 | if (this.isFixed){ | |
61 | this.isFixed = 1 <= scrollPosition; |
|
61 | this.isFixed = 1 <= scrollPosition; | |
62 | } |
|
62 | } | |
63 | else{ |
|
63 | else{ | |
64 | this.isFixed = headerHeight <= scrollPosition; |
|
64 | this.isFixed = headerHeight <= scrollPosition; | |
65 | } |
|
65 | } | |
66 | }, |
|
66 | }, | |
67 |
|
67 | |||
68 | attached: function(){ |
|
68 | attached: function(){ | |
69 | this._headerNode = document.querySelector('.header', document); |
|
69 | this._headerNode = document.querySelector('.header', document); | |
70 | this.listen(window,'scroll', '_debouncedCalc'); |
|
70 | this.listen(window,'scroll', '_debouncedCalc'); | |
71 | this.listen(window,'resize', '_debouncedCalc'); |
|
71 | this.listen(window,'resize', '_debouncedCalc'); | |
72 | this._debouncedCalc(); |
|
72 | this._debouncedCalc(); | |
73 | }, |
|
73 | }, | |
74 | _changedToasts: function(newValue, oldValue){ |
|
74 | _changedToasts: function(newValue, oldValue){ | |
75 | $.Topic('/favicon/update').publish({count: this.toasts.length}); |
|
75 | $.Topic('/favicon/update').publish({count: this.toasts.length}); | |
76 | }, |
|
76 | }, | |
|
77 | dismissNotification: function(e) { | |||
|
78 | $.Topic('/favicon/update').publish({count: this.toasts.length-1}); | |||
|
79 | var idx = e.target.parentNode.indexPos | |||
|
80 | this.splice('toasts', idx, 1); | |||
|
81 | ||||
|
82 | }, | |||
77 | dismissNotifications: function(){ |
|
83 | dismissNotifications: function(){ | |
78 | $.Topic('/favicon/update').publish({count: 0}); |
|
84 | $.Topic('/favicon/update').publish({count: 0}); | |
79 | this.splice('toasts', 0); |
|
85 | this.splice('toasts', 0); | |
80 | }, |
|
86 | }, | |
81 | handleNotification: function(data){ |
|
87 | handleNotification: function(data){ | |
82 | if (!templateContext.rhodecode_user.notification_status && !data.message.force) { |
|
88 | if (!templateContext.rhodecode_user.notification_status && !data.message.force) { | |
83 | // do not act if notifications are disabled |
|
89 | // do not act if notifications are disabled | |
84 | return |
|
90 | return | |
85 | } |
|
91 | } | |
86 | this.push('toasts',{ |
|
92 | this.push('toasts',{ | |
87 | level: data.message.level, |
|
93 | level: data.message.level, | |
88 | message: data.message.message |
|
94 | message: data.message.message | |
89 | }); |
|
95 | }); | |
90 | }, |
|
96 | }, | |
91 | _gettext: _gettext |
|
97 | _gettext: _gettext | |
92 | }); |
|
98 | }); |
@@ -1,28 +1,27 b'' | |||||
1 | @import '../../../../css/variables'; |
|
1 | @import '../../../../css/variables'; | |
2 | @import '../../../../css/mixins'; |
|
2 | @import '../../../../css/mixins'; | |
3 |
|
3 | |||
4 | .alert{ |
|
4 | .alert{ | |
5 | margin: 10px 0; |
|
5 | margin: 10px 0; | |
6 | } |
|
6 | } | |
7 |
|
7 | |||
8 | .toast-close{ |
|
8 | .toast-close { | |
9 | text-align: right; |
|
|||
10 | .btn { |
|
|||
11 |
|
|
9 | margin: 0; | |
12 | } |
|
10 | float: right; | |
|
11 | cursor: pointer; | |||
13 | } |
|
12 | } | |
14 |
|
13 | |||
15 | .toast-message-holder{ |
|
14 | .toast-message-holder{ | |
16 | background: fade(#fff, 25%); |
|
15 | background: fade(#fff, 25%); | |
17 |
|
16 | |||
18 | &.fixed{ |
|
17 | &.fixed{ | |
19 | position: fixed; |
|
18 | position: fixed; | |
20 | padding: 10px 0; |
|
19 | padding: 10px 0; | |
21 | margin-left: 10px; |
|
20 | margin-left: 10px; | |
22 | margin-right: 10px; |
|
21 | margin-right: 10px; | |
23 | top: 0; |
|
22 | top: 0; | |
24 | left: 0; |
|
23 | left: 0; | |
25 | right:0; |
|
24 | right:0; | |
26 | z-index: 100; |
|
25 | z-index: 100; | |
27 | } |
|
26 | } | |
28 | } |
|
27 | } |
@@ -1,106 +1,130 b'' | |||||
1 | <template is="dom-bind" id="notificationsPage"> |
|
1 | <template is="dom-bind" id="notificationsPage"> | |
2 | <iron-ajax id="toggleNotifications" |
|
2 | <iron-ajax id="toggleNotifications" | |
3 | method="post" |
|
3 | method="post" | |
4 | url="${url('my_account_notifications_toggle_visibility')}" |
|
4 | url="${url('my_account_notifications_toggle_visibility')}" | |
5 | content-type="application/json" |
|
5 | content-type="application/json" | |
6 | loading="{{changeNotificationsLoading}}" |
|
6 | loading="{{changeNotificationsLoading}}" | |
7 | on-response="handleNotifications" |
|
7 | on-response="handleNotifications" | |
8 | handle-as="json"> |
|
8 | handle-as="json"> | |
9 | </iron-ajax> |
|
9 | </iron-ajax> | |
10 |
|
10 | |||
11 | <iron-ajax id="sendTestNotification" |
|
11 | <iron-ajax id="sendTestNotification" | |
12 | method="post" |
|
12 | method="post" | |
13 | url="${url('my_account_notifications_test_channelstream')}" |
|
13 | url="${url('my_account_notifications_test_channelstream')}" | |
14 | content-type="application/json" |
|
14 | content-type="application/json" | |
15 | on-response="handleTestNotification" |
|
15 | on-response="handleTestNotification" | |
16 | handle-as="json"> |
|
16 | handle-as="json"> | |
17 | </iron-ajax> |
|
17 | </iron-ajax> | |
18 |
|
18 | |||
19 | <div class="panel panel-default"> |
|
19 | <div class="panel panel-default"> | |
20 | <div class="panel-heading"> |
|
20 | <div class="panel-heading"> | |
21 | <h3 class="panel-title">${_('Your Live Notification Settings')}</h3> |
|
21 | <h3 class="panel-title">${_('Your Live Notification Settings')}</h3> | |
22 | </div> |
|
22 | </div> | |
23 | <div class="panel-body"> |
|
23 | <div class="panel-body"> | |
24 |
|
24 | |||
25 | <p><strong>IMPORTANT:</strong> This feature requires enabled channelstream websocket server to function correctly.</p> |
|
25 | <p><strong>IMPORTANT:</strong> This feature requires enabled channelstream websocket server to function correctly.</p> | |
26 |
|
26 | |||
27 | <p class="hidden">Status of browser notifications permission: <strong id="browser-notification-status"></strong></p> |
|
27 | <p class="hidden">Status of browser notifications permission: <strong id="browser-notification-status"></strong></p> | |
28 |
|
28 | |||
29 | <div class="form"> |
|
29 | <div class="form"> | |
30 | <div class="fields"> |
|
30 | <div class="fields"> | |
31 | <div class="field"> |
|
31 | <div class="field"> | |
32 | <div class="label"> |
|
32 | <div class="label"> | |
33 | <label for="new_email">${_('Notifications Status')}:</label> |
|
33 | <label for="new_email">${_('Notifications Status')}:</label> | |
34 | </div> |
|
34 | </div> | |
35 | <div class="checkboxes"> |
|
35 | <div class="checkboxes"> | |
36 | <rhodecode-toggle id="live-notifications" active="[[changeNotificationsLoading]]" on-change="toggleNotifications" ${'checked' if c.rhodecode_user.get_instance().user_data.get('notification_status') else ''}></rhodecode-toggle> |
|
36 | <rhodecode-toggle id="live-notifications" active="[[changeNotificationsLoading]]" on-change="toggleNotifications" ${'checked' if c.rhodecode_user.get_instance().user_data.get('notification_status') else ''}></rhodecode-toggle> | |
37 | </div> |
|
37 | </div> | |
38 | </div> |
|
38 | </div> | |
39 | </div> |
|
39 | </div> | |
40 | </div> |
|
40 | </div> | |
41 | </div> |
|
41 | </div> | |
42 | </div> |
|
42 | </div> | |
43 |
|
43 | |||
44 | <div class="panel panel-default"> |
|
44 | <div class="panel panel-default"> | |
45 | <div class="panel-heading"> |
|
45 | <div class="panel-heading"> | |
46 | <h3 class="panel-title">${_('Test Notifications')}</h3> |
|
46 | <h3 class="panel-title">${_('Test Notifications')}</h3> | |
47 | </div> |
|
47 | </div> | |
48 | <div class="panel-body"> |
|
48 | <div class="panel-body"> | |
49 |
|
49 | |||
50 |
|
50 | |||
51 | <div style="padding: 0px 0px 20px 0px"> |
|
51 | <div style="padding: 0px 0px 20px 0px"> | |
52 | <button class="btn" id="test-notification" on-tap="testNotifications">Test flash message</button> |
|
52 | <button class="btn" id="test-notification" on-tap="testNotifications">Test flash message</button> | |
53 | <button class="btn" id="test-notification-live" on-tap="testNotificationsLive">Test live notification</button> |
|
53 | <button class="btn" id="test-notification-live" on-tap="testNotificationsLive">Test live notification</button> | |
54 | </div> |
|
54 | </div> | |
55 | <h4 id="test-response"></h4> |
|
55 | <h4 id="test-response"></h4> | |
56 |
|
56 | |||
57 | </div> |
|
57 | </div> | |
58 |
|
58 | |||
59 |
|
59 | |||
60 |
|
60 | |||
61 | </div> |
|
61 | </div> | |
62 |
|
62 | |||
63 | <script type="text/javascript"> |
|
63 | <script type="text/javascript"> | |
64 | /** because im not creating a custom element for this page |
|
64 | /** because im not creating a custom element for this page | |
65 | * we need to push the function onto the dom-template |
|
65 | * we need to push the function onto the dom-template | |
66 | * ideally we turn this into notification-settings elements |
|
66 | * ideally we turn this into notification-settings elements | |
67 | * then it will be cleaner |
|
67 | * then it will be cleaner | |
68 | */ |
|
68 | */ | |
69 | var ctrlr = $('#notificationsPage')[0]; |
|
69 | var ctrlr = $('#notificationsPage')[0]; | |
70 | ctrlr.toggleNotifications = function(event){ |
|
70 | ctrlr.toggleNotifications = function(event){ | |
71 | var ajax = $('#toggleNotifications')[0]; |
|
71 | var ajax = $('#toggleNotifications')[0]; | |
72 | ajax.headers = {"X-CSRF-Token": CSRF_TOKEN}; |
|
72 | ajax.headers = {"X-CSRF-Token": CSRF_TOKEN}; | |
73 | ajax.body = {notification_status:event.target.active}; |
|
73 | ajax.body = {notification_status:event.target.active}; | |
74 | ajax.generateRequest(); |
|
74 | ajax.generateRequest(); | |
75 | }; |
|
75 | }; | |
76 | ctrlr.handleNotifications = function(event){ |
|
76 | ctrlr.handleNotifications = function(event){ | |
77 | $('#live-notifications')[0].checked = event.detail.response; |
|
77 | $('#live-notifications')[0].checked = event.detail.response; | |
78 | }; |
|
78 | }; | |
79 |
|
79 | |||
80 | ctrlr.testNotifications = function(event){ |
|
80 | ctrlr.testNotifications = function(event){ | |
81 | var levels = ['info', 'error', 'warning', 'success']; |
|
81 | var levels = ['info', 'error', 'warning', 'success']; | |
82 | var level = levels[Math.floor(Math.random()*levels.length)]; |
|
82 | var level = levels[Math.floor(Math.random()*levels.length)]; | |
|
83 | function getRandomArbitrary(min, max) { | |||
|
84 | return parseInt(Math.random() * (max - min) + min); | |||
|
85 | } | |||
|
86 | function shuffle(a) { | |||
|
87 | var j, x, i; | |||
|
88 | for (i = a.length; i; i--) { | |||
|
89 | j = Math.floor(Math.random() * i); | |||
|
90 | x = a[i - 1]; | |||
|
91 | a[i - 1] = a[j]; | |||
|
92 | a[j] = x; | |||
|
93 | } | |||
|
94 | } | |||
|
95 | var wordDb = [ | |||
|
96 | "Leela,", "Bender,", "we are", "going", "grave", "robbing.", | |||
|
97 | "Oh,", "I", "think", "we", "should", "just", "stay", "friends.", | |||
|
98 | "got", "to", "find", "a", "way", "to", "escape", "the", "horrible", | |||
|
99 | "ravages", "of", "youth.", "Suddenly,", "going", "to", | |||
|
100 | "the", "bathroom", "like", "clockwork,", "every", "three", | |||
|
101 | "hours.", "And", "those", "jerks", "at", "Social", "Security", | |||
|
102 | "stopped", "sending", "me", "checks.", "Now", "have", "to", "pay" | |||
|
103 | ]; | |||
|
104 | shuffle(wordDb); | |||
|
105 | wordDb = wordDb.slice(0, getRandomArbitrary(3, wordDb.length)); | |||
|
106 | var randomMessage = wordDb.join(" "); | |||
83 | var payload = { |
|
107 | var payload = { | |
84 | message: { |
|
108 | message: { | |
85 |
message: |
|
109 | message: randomMessage + " " + new Date(), | |
86 | level: level, |
|
110 | level: level, | |
87 | force: true |
|
111 | force: true | |
88 | } |
|
112 | } | |
89 | }; |
|
113 | }; | |
90 | $.Topic('/notifications').publish(payload); |
|
114 | $.Topic('/notifications').publish(payload); | |
91 | }; |
|
115 | }; | |
92 | ctrlr.testNotificationsLive = function(event){ |
|
116 | ctrlr.testNotificationsLive = function(event){ | |
93 | var ajax = $('#sendTestNotification')[0]; |
|
117 | var ajax = $('#sendTestNotification')[0]; | |
94 | ajax.headers = {"X-CSRF-Token": CSRF_TOKEN}; |
|
118 | ajax.headers = {"X-CSRF-Token": CSRF_TOKEN}; | |
95 | ajax.body = {test_msg: 'Hello !'}; |
|
119 | ajax.body = {test_msg: 'Hello !'}; | |
96 | ajax.generateRequest(); |
|
120 | ajax.generateRequest(); | |
97 | }; |
|
121 | }; | |
98 | ctrlr.handleTestNotification = function(event){ |
|
122 | ctrlr.handleTestNotification = function(event){ | |
99 | var reply = event.detail.response.response; |
|
123 | var reply = event.detail.response.response; | |
100 | reply = reply || 'no reply form server'; |
|
124 | reply = reply || 'no reply form server'; | |
101 | $('#test-response').html(reply); |
|
125 | $('#test-response').html(reply); | |
102 | }; |
|
126 | }; | |
103 |
|
127 | |||
104 | </script> |
|
128 | </script> | |
105 |
|
129 | |||
106 | </template> |
|
130 | </template> |
General Comments 0
You need to be logged in to leave comments.
Login now