PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.5
Advanced Ads – Ad Manager & AdSense v2.0.5
2.0.26 2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / assets / src / admin / notifications.js
advanced-ads / assets / src / admin Last commit date
common 1 year ago screen-ads-editing 1 year ago screen-ads-listing 1 year ago screen-dashboard 1 year ago screen-groups-listing 1 year ago screen-placements-listing 1 year ago screen-settings 1 year ago screen-tools 1 year ago shared-modules 1 year ago wp-dashboard 1 year ago admin-common.js 1 year ago notification-tester.js 1 year ago notifications.js 1 year ago page-quick-edit.js 1 year ago
notifications.js
318 lines
1 import notificationTester from './notification-tester';
2
3 let wrapper, innerWrapper;
4
5 // Notification markup template.
6 const template =
7 '<div class="item-inner"><div class="content"><p>__MSG__</p></div><div class="sep"></div><div class="dismiss"><span class="dashicons"></span></div></div>';
8
9 // Queue animations, so we keep animating one item at a time and keep things simple.
10 const queue = [],
11 SLIDE_DURATION = 500;
12
13 /**
14 * Animation class
15 *
16 * @type {{addItem: notification.addItem, unlockPositions: notification.unlockPositions, endOfDismiss: notification.endOfDismiss, busy: boolean, dismiss: notification.dismiss, moveOtherItems: notification.moveOtherItems, lockPositions: notification.lockPositions, checkQueue: notification.checkQueue}}
17 */
18 const notification = {
19 /**
20 * Animate one element at a time
21 */
22 busy: false,
23
24 /**
25 * Add a notification
26 *
27 * @param {string} htmlContent the content.
28 * @param {string} type the type of notification.
29 */
30 addItem: (htmlContent, type) => {
31 if (notification.busy) {
32 queue.push({
33 fn: notification.addItem,
34 args: [htmlContent, type],
35 });
36 return;
37 }
38
39 notification.busy = true;
40
41 const types = ['error', 'info', 'success'];
42
43 if (!types.includes(type)) {
44 type = 'info';
45 }
46
47 const item = document.createElement('div');
48 item.className = `item item-${type}`;
49 item.innerHTML = template.replace('__MSG__', htmlContent);
50 innerWrapper.append(item);
51 item.style.left = 'auto';
52
53 const anim = new Animation(
54 new KeyframeEffect(
55 item,
56 [{ right: `${-item.clientWidth - 30}px` }, { right: 0 }],
57 {
58 duration: SLIDE_DURATION,
59 easing: 'ease-in-out',
60 iterations: 1,
61 }
62 )
63 );
64
65 anim.onfinish = () => {
66 notification.unlockPositions();
67 if ('error' !== type) {
68 // Non-error types last only 5 seconds.
69 setTimeout(() => notification.dismiss(item), 5000);
70 }
71 notification.busy = false;
72 notification.checkQueue();
73 };
74
75 anim.play();
76 },
77
78 /**
79 * Go back to relative positioning
80 */
81 unlockPositions: () => {
82 innerWrapper.querySelectorAll('.item').forEach((item) => {
83 item.style = 'position:relative;left:0;top:0;margin:0;right:auto;';
84 });
85 },
86
87 /**
88 * Capture offsets then switch to absolute positioning with these offsets
89 */
90 lockPositions: () => {
91 const itemsOffsets = [],
92 items = innerWrapper.querySelectorAll('.item');
93 items.forEach((item) => {
94 itemsOffsets.push(item.offsetTop);
95 });
96 items.forEach((el, index) => {
97 el.style = `position:absolute;top:${itemsOffsets[index]}px;right:0;`;
98 });
99 },
100
101 /**
102 * If there's something queued, run the function one at a time
103 */
104 checkQueue: () => {
105 if (!queue.length) {
106 return;
107 }
108 const fn = queue.shift();
109 fn.fn.apply(null, fn.args);
110 },
111
112 /**
113 * Dismiss notification
114 *
115 * @param {Node} item the notification.
116 */
117 dismiss: (item) => {
118 if (notification.busy) {
119 queue.push({
120 fn: notification.dismiss,
121 args: [item],
122 });
123 return;
124 }
125
126 notification.busy = true;
127
128 if (!document.contains(item)) {
129 // The notification isn't in the DOM anymore (multiple clicks on the same icon).
130 notification.busy = false;
131 notification.checkQueue();
132 return;
133 }
134
135 // Collect all items that are below the one that is meing removed, then move them upward later.
136 const otherItems = [...innerWrapper.querySelectorAll('.item')].filter(
137 (elem) => {
138 return (
139 !elem.isEqualNode(item) && elem.offsetTop > item.offsetTop
140 );
141 }
142 );
143
144 notification.lockPositions();
145
146 const anim = new Animation(
147 new KeyframeEffect(
148 item,
149 [
150 {
151 right: `-${item.querySelector('.item-inner').clientWidth + 60}px`,
152 },
153 ],
154 {
155 duration: SLIDE_DURATION,
156 easing: 'ease-in-out',
157 iterations: 1,
158 fill: 'forwards',
159 }
160 )
161 );
162 anim.onfinish = () => {
163 if (otherItems.length) {
164 notification.moveOtherItems(
165 item.clientHeight,
166 otherItems,
167 notification.endOfDismiss,
168 item
169 );
170 } else {
171 notification.endOfDismiss(item);
172 }
173 };
174 anim.play();
175 },
176
177 /**
178 * Remove the item, switch to relative positioning, check queued functions.
179 *
180 * @param {Node} item the dismissed item
181 */
182 endOfDismiss: (item) => {
183 item.remove();
184 notification.unlockPositions();
185 notification.busy = false;
186 notification.checkQueue();
187 },
188
189 /**
190 * Move items up after dismissal of the one above them
191 *
192 * @param {number} height height of the removed item.
193 * @param {Array} items items that need to be moved.
194 * @param {Function} complete on complete callback.
195 * @param {Array} completeArgs arguments of the callback.
196 */
197 moveOtherItems: (height, items, complete, completeArgs) => {
198 let completed = 0;
199 const animate = (items, index) => {
200 const anim = new Animation(
201 new KeyframeEffect(
202 items[index],
203 [{ marginTop: `-${height}px` }],
204 {
205 duration: 200,
206 easing: 'ease-in-out',
207 iterations: 1,
208 }
209 )
210 );
211 anim.onfinish = () => {
212 if ('function' !== typeof complete) {
213 return;
214 }
215 completed++;
216 if (items.length === completed) {
217 complete.call(null, completeArgs);
218 }
219 };
220 anim.play();
221 };
222
223 items.forEach((elem, index) => {
224 animate(items, index);
225 });
226 },
227 };
228
229 // Bind notification dismiss event listener.
230 const bindListeners = () => {
231 document.addEventListener('click', (event) => {
232 const el = event.target;
233 if (
234 el.closest('#advads-notifications') &&
235 el.classList &&
236 (el.classList.contains('dismiss') ||
237 (el.parentNode.classList &&
238 el.parentNode.classList.contains('dismiss')))
239 ) {
240 notification.dismiss(el.closest('.item'));
241 }
242 });
243 };
244
245 /**
246 * Publicly available functions.
247 *
248 * @type {{addError: publicHelper.addError, addSuccess: publicHelper.addSuccess, addInfo: publicHelper.addInfo}}
249 */
250 const publicHelper = {
251 /**
252 * Add an error notification
253 *
254 * @param {string} htmlContent the content
255 */
256 addError: (htmlContent) => {
257 notification.addItem(htmlContent, 'error');
258 },
259
260 /**
261 * Add an info notification
262 *
263 * @param {string} htmlContent the content
264 */
265 addInfo: (htmlContent) => {
266 notification.addItem(htmlContent, 'info');
267 },
268
269 /**
270 * Add a success notification
271 *
272 * @param {string} htmlContent the content
273 */
274 addSuccess: (htmlContent) => {
275 notification.addItem(htmlContent, 'success');
276 },
277 };
278
279 /**
280 * Ads/Placements posts updated
281 */
282 const addPostUpdate = () => {
283 const msg = document.getElementById('message');
284 if (msg) {
285 publicHelper.addSuccess(msg.querySelector('p').innerHTML);
286 }
287 const updateMessage = localStorage.getItem('advadsUpdateMessage');
288 if (updateMessage) {
289 const notice = JSON.parse(updateMessage);
290 notification.addItem(notice.message, notice.type);
291 localStorage.removeItem('advadsUpdateMessage');
292 }
293 };
294
295 /**
296 * Settings updated
297 */
298 const addSettingsUpdate = () => {
299 const msg = document.getElementById('setting-error-settings_updated');
300 if (msg) {
301 publicHelper.addSuccess(msg.querySelector('p').innerHTML);
302 }
303 };
304
305 document.addEventListener('DOMContentLoaded', (event) => {
306 wrapper = document.createElement('div');
307 wrapper.id = 'advads-notifications';
308 innerWrapper = document.createElement('div');
309 wrapper.append(innerWrapper);
310 document.getElementById('wpwrap').append(wrapper);
311 bindListeners();
312 notificationTester();
313 addPostUpdate();
314 addSettingsUpdate();
315 // Make public function available.
316 window.advancedAds.notifications = publicHelper;
317 });
318