PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.24
Advanced Ads – Ad Manager & AdSense v2.0.24
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 / src / admin / notifications / notifications.js
advanced-ads / src / admin / notifications Last commit date
notification-tester.js 3 months ago notifications.css 3 months ago notifications.js 3 months ago
notifications.js
321 lines
1 import notificationTester from './notification-tester';
2 import './notifications.css';
3
4 let wrapper, innerWrapper;
5
6 // Notification markup template.
7 const template =
8 '<div class="item-inner"><div class="content"><p>__MSG__</p></div><div class="sep"></div><div class="dismiss"><span class="dashicons"></span></div></div>';
9
10 // Queue animations, so we keep animating one item at a time and keep things simple.
11 const queue = [],
12 SLIDE_DURATION = 500;
13
14 /**
15 * Animation class
16 *
17 * @type {{addItem: notification.addItem, unlockPositions: notification.unlockPositions, endOfDismiss: notification.endOfDismiss, busy: boolean, dismiss: notification.dismiss, moveOtherItems: notification.moveOtherItems, lockPositions: notification.lockPositions, checkQueue: notification.checkQueue}}
18 */
19 const notification = {
20 /**
21 * Animate one element at a time
22 */
23 busy: false,
24
25 /**
26 * Add a notification
27 *
28 * @param {string} htmlContent the content.
29 * @param {string} type the type of notification.
30 */
31 addItem: ( htmlContent, type ) => {
32 if ( notification.busy ) {
33 queue.push( {
34 fn: notification.addItem,
35 args: [ htmlContent, type ],
36 } );
37 return;
38 }
39
40 notification.busy = true;
41
42 const types = [ 'error', 'info', 'success' ];
43
44 if ( ! types.includes( type ) ) {
45 type = 'info';
46 }
47
48 const item = document.createElement( 'div' );
49 item.className = `item item-${ type }`;
50 item.innerHTML = template.replace( '__MSG__', htmlContent );
51 innerWrapper.append( item );
52 item.style.left = 'auto';
53
54 const anim = new window.Animation(
55 new window.KeyframeEffect(
56 item,
57 [ { right: `${ -item.clientWidth - 30 }px` }, { right: 0 } ],
58 {
59 duration: SLIDE_DURATION,
60 easing: 'ease-in-out',
61 iterations: 1,
62 }
63 )
64 );
65
66 anim.onfinish = () => {
67 notification.unlockPositions();
68 if ( 'error' !== type ) {
69 // Non-error types last only 5 seconds.
70 setTimeout( () => notification.dismiss( item ), 5000 );
71 }
72 notification.busy = false;
73 notification.checkQueue();
74 };
75
76 anim.play();
77 },
78
79 /**
80 * Go back to relative positioning
81 */
82 unlockPositions: () => {
83 innerWrapper.querySelectorAll( '.item' ).forEach( ( item ) => {
84 item.style = 'position:relative;left:0;top:0;margin:0;right:auto;';
85 } );
86 },
87
88 /**
89 * Capture offsets then switch to absolute positioning with these offsets
90 */
91 lockPositions: () => {
92 const itemsOffsets = [],
93 items = innerWrapper.querySelectorAll( '.item' );
94 items.forEach( ( item ) => {
95 itemsOffsets.push( item.offsetTop );
96 } );
97 items.forEach( ( el, index ) => {
98 el.style = `position:absolute;top:${ itemsOffsets[ index ] }px;right:0;`;
99 } );
100 },
101
102 /**
103 * If there's something queued, run the function one at a time
104 */
105 checkQueue: () => {
106 if ( ! queue.length ) {
107 return;
108 }
109 const fn = queue.shift();
110 fn.fn.apply( null, fn.args );
111 },
112
113 /**
114 * Dismiss notification
115 *
116 * @param {Node} item the notification.
117 */
118 dismiss: ( item ) => {
119 if ( notification.busy ) {
120 queue.push( {
121 fn: notification.dismiss,
122 args: [ item ],
123 } );
124 return;
125 }
126
127 notification.busy = true;
128
129 if ( ! document.contains( item ) ) {
130 // The notification isn't in the DOM anymore (multiple clicks on the same icon).
131 notification.busy = false;
132 notification.checkQueue();
133 return;
134 }
135
136 // Collect all items that are below the one that is meing removed, then move them upward later.
137 const otherItems = [
138 ...innerWrapper.querySelectorAll( '.item' ),
139 ].filter( ( elem ) => {
140 return (
141 ! elem.isEqualNode( item ) && elem.offsetTop > item.offsetTop
142 );
143 } );
144
145 notification.lockPositions();
146
147 const anim = new window.Animation(
148 new window.KeyframeEffect(
149 item,
150 [
151 {
152 right: `-${
153 item.querySelector( '.item-inner' ).clientWidth + 60
154 }px`,
155 },
156 ],
157 {
158 duration: SLIDE_DURATION,
159 easing: 'ease-in-out',
160 iterations: 1,
161 fill: 'forwards',
162 }
163 )
164 );
165 anim.onfinish = () => {
166 if ( otherItems.length ) {
167 notification.moveOtherItems(
168 item.clientHeight,
169 otherItems,
170 notification.endOfDismiss,
171 item
172 );
173 } else {
174 notification.endOfDismiss( item );
175 }
176 };
177 anim.play();
178 },
179
180 /**
181 * Remove the item, switch to relative positioning, check queued functions.
182 *
183 * @param {Node} item the dismissed item
184 */
185 endOfDismiss: ( item ) => {
186 item.remove();
187 notification.unlockPositions();
188 notification.busy = false;
189 notification.checkQueue();
190 },
191
192 /**
193 * Move items up after dismissal of the one above them
194 *
195 * @param {number} height height of the removed item.
196 * @param {Array} items items that need to be moved.
197 * @param {Function} complete on complete callback.
198 * @param {Array} completeArgs arguments of the callback.
199 */
200 moveOtherItems: ( height, items, complete, completeArgs ) => {
201 let completed = 0;
202 const animate = ( itemsToAnimate, index ) => {
203 const anim = new window.Animation(
204 new window.KeyframeEffect(
205 itemsToAnimate[ index ],
206 [ { marginTop: `-${ height }px` } ],
207 {
208 duration: 200,
209 easing: 'ease-in-out',
210 iterations: 1,
211 }
212 )
213 );
214 anim.onfinish = () => {
215 if ( 'function' !== typeof complete ) {
216 return;
217 }
218 completed++;
219 if ( itemsToAnimate.length === completed ) {
220 complete.call( null, completeArgs );
221 }
222 };
223 anim.play();
224 };
225
226 items.forEach( ( elem, index ) => {
227 animate( items, index );
228 } );
229 },
230 };
231
232 // Bind notification dismiss event listener.
233 const bindListeners = () => {
234 document.addEventListener( 'click', ( event ) => {
235 const el = event.target;
236 if (
237 el.closest( '#advads-notifications' ) &&
238 el.classList &&
239 ( el.classList.contains( 'dismiss' ) ||
240 ( el.parentNode.classList &&
241 el.parentNode.classList.contains( 'dismiss' ) ) )
242 ) {
243 notification.dismiss( el.closest( '.item' ) );
244 }
245 } );
246 };
247
248 /**
249 * Publicly available functions.
250 *
251 * @type {{addError: publicHelper.addError, addSuccess: publicHelper.addSuccess, addInfo: publicHelper.addInfo}}
252 */
253 const publicHelper = {
254 /**
255 * Add an error notification
256 *
257 * @param {string} htmlContent the content
258 */
259 addError: ( htmlContent ) => {
260 notification.addItem( htmlContent, 'error' );
261 },
262
263 /**
264 * Add an info notification
265 *
266 * @param {string} htmlContent the content
267 */
268 addInfo: ( htmlContent ) => {
269 notification.addItem( htmlContent, 'info' );
270 },
271
272 /**
273 * Add a success notification
274 *
275 * @param {string} htmlContent the content
276 */
277 addSuccess: ( htmlContent ) => {
278 notification.addItem( htmlContent, 'success' );
279 },
280 };
281
282 /**
283 * Ads/Placements posts updated
284 */
285 const addPostUpdate = () => {
286 const msg = document.getElementById( 'message' );
287 if ( msg ) {
288 publicHelper.addSuccess( msg.querySelector( 'p' ).innerHTML );
289 }
290 const updateMessage = window.localStorage.getItem( 'advadsUpdateMessage' );
291 if ( updateMessage ) {
292 const notice = JSON.parse( updateMessage );
293 notification.addItem( notice.message, notice.type );
294 window.localStorage.removeItem( 'advadsUpdateMessage' );
295 }
296 };
297
298 /**
299 * Settings updated
300 */
301 const addSettingsUpdate = () => {
302 const msg = document.getElementById( 'setting-error-settings_updated' );
303 if ( msg ) {
304 publicHelper.addSuccess( msg.querySelector( 'p' ).innerHTML );
305 }
306 };
307
308 document.addEventListener( 'DOMContentLoaded', () => {
309 wrapper = document.createElement( 'div' );
310 wrapper.id = 'advads-notifications';
311 innerWrapper = document.createElement( 'div' );
312 wrapper.append( innerWrapper );
313 document.getElementById( 'wpwrap' ).append( wrapper );
314 bindListeners();
315 notificationTester();
316 addPostUpdate();
317 addSettingsUpdate();
318 // Make public function available.
319 window.advancedAds.notifications = publicHelper;
320 } );
321