##// END OF EJS Templates
rhodecode-toasts: allow removing single elements from toast queue.
marcink -
r1513:940ac693 default
parent child Browse files
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;
9 margin: 0;
10 .btn {
10 float: right;
11 margin: 0;
11 cursor: pointer;
12 }
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: 'This is a test notification. ' + new Date(),
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