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