PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.24
Advanced Ads – Ad Manager & AdSense v2.0.24
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 / common / modal.js
advanced-ads / src / admin / common Last commit date
accordion.css 3 months ago button.css 4 weeks ago card.css 3 months ago common.css 3 months ago common.js 3 months ago deprecated.css 3 months ago form.css 3 months ago header.css 3 months ago modal-new.css 3 months ago modal.css 3 months ago modal.js 3 months ago screen-options.js 3 months ago tabs.js 3 months ago toast.css 3 months ago toaster.js 3 months ago toggles.js 3 months ago
modal.js
190 lines
1 // ── Scroll Lock ───────────────────────────────────────────────────────────────
2
3 let _openCount = 0;
4 let _scrollbarWidth = 0;
5
6 function _measureScrollbar() {
7 return window.innerWidth - document.documentElement.clientWidth;
8 }
9
10 function lockScroll() {
11 if ( ++_openCount !== 1 ) {
12 return;
13 }
14
15 _scrollbarWidth = _measureScrollbar();
16 const { style } = document.body;
17 style.overflow = 'hidden';
18 if ( _scrollbarWidth > 0 ) {
19 style.paddingRight = `${ _scrollbarWidth }px`;
20 }
21 }
22
23 function unlockScroll() {
24 if ( _openCount === 0 || --_openCount !== 0 ) {
25 return;
26 }
27
28 const { style } = document.body;
29 style.overflow = '';
30 style.paddingRight = '';
31 }
32
33 // ── Core open / close ─────────────────────────────────────────────────────────
34
35 /**
36 * Opens a `<dialog>` element with an enter animation.
37 *
38 * @param {HTMLDialogElement} dialog The dialog element to open.
39 * @param {Element|null} [opener] The opener element that triggered the open.
40 */
41 function openDialog( dialog, opener ) {
42 if ( dialog.open ) {
43 return;
44 }
45
46 // Dispatch global event so external code can hook in
47 window.dispatchEvent(
48 new CustomEvent( 'advanced-ads-dialog-open', {
49 detail: { dialog, opener },
50 } )
51 );
52
53 dialog.dataset.state = 'closed';
54 dialog.showModal();
55 lockScroll();
56
57 // Trigger enter animation on the next frame so the browser has painted
58 // the initial "closed" state first.
59 window.requestAnimationFrame( () => {
60 dialog.dataset.state = 'enter';
61 } );
62
63 // Move focus inside the dialog — fall back to the dialog itself.
64 const focusTarget =
65 dialog.querySelector( '.advads-dialog-frame' ) ?? dialog;
66
67 // Ensure the fallback target is programmatically focusable
68 if ( focusTarget === dialog && ! dialog.hasAttribute( 'tabindex' ) ) {
69 dialog.setAttribute( 'tabindex', '-1' );
70 }
71
72 focusTarget.focus();
73 }
74
75 /**
76 * Closes a `<dialog>` element with a leave animation, then cleans up.
77 *
78 * @param {HTMLDialogElement} dialog The dialog element to close.
79 */
80 function closeDialog( dialog ) {
81 if ( ! dialog.open || dialog.dataset.state === 'leave' ) {
82 return;
83 }
84
85 window.dispatchEvent(
86 new CustomEvent( 'advanced-ads-dialog-close', {
87 detail: { dialog },
88 } )
89 );
90
91 dialog.dataset.state = 'leave';
92
93 dialog.addEventListener(
94 'transitionend',
95 () => {
96 dialog.dataset.state = 'closed';
97 dialog.close();
98 unlockScroll();
99
100 if ( window.location.hash === `#${ dialog.id }` ) {
101 window.history.replaceState(
102 '',
103 document.title,
104 window.location.pathname + window.location.search
105 );
106 }
107 },
108 { once: true }
109 );
110 }
111
112 // ── Hash routing ──────────────────────────────────────────────────────────────
113
114 /**
115 * Opens a dialog whose opener has `data-dialog="<hash>"`.
116 *
117 * @param {string} hash — without the leading `#`
118 */
119 function openDialogByHash( hash ) {
120 if ( ! hash ) {
121 return;
122 }
123
124 const opener = document.querySelector(
125 `[data-dialog="${ window.CSS.escape( hash ) }"]`
126 );
127 opener?.click();
128 }
129
130 // ── init ──────────────────────────────────────────────────────────────────────
131
132 /**
133 * Bootstraps all dialog behaviour.
134 * Call once per page after the DOM is ready.
135 */
136 export function modal() {
137 // Use event delegation on document to handle dynamically added elements.
138
139 // Single delegated click handler covers openers, close buttons, and backdrop.
140 document.addEventListener( 'click', ( { target } ) => {
141 // Opener: [data-dialog="id"]
142 const opener = target.closest( '[data-dialog]' );
143 if ( opener ) {
144 const dialog = document.querySelector(
145 `#${ window.CSS.escape( opener.dataset.dialog ) }`
146 );
147 if ( dialog ) {
148 openDialog( dialog, opener );
149 }
150 return;
151 }
152
153 // Close button: [data-dialog-close]
154 const closer = target.closest( '[data-dialog-close]' );
155 if ( closer ) {
156 const dialog = closer.closest( 'dialog' );
157 if ( dialog ) {
158 closeDialog( dialog );
159 }
160 return;
161 }
162
163 // Backdrop: click fell outside .advads-dialog-frame
164 const dialog = target.closest( 'dialog.advads-dialog' );
165 if (
166 dialog &&
167 ! dialog.classList.contains( 'manual' ) &&
168 ! dialog.querySelector( '.advads-dialog-frame' )?.contains( target )
169 ) {
170 closeDialog( dialog );
171 }
172 } );
173
174 // ── Native Escape key ─────────────────────────────────────────────────────
175 // The browser fires `cancel` on the dialog before closing it natively.
176 // We intercept to apply our animated close and prevent the native close.
177 document.addEventListener( 'cancel', ( event ) => {
178 event.preventDefault();
179 closeDialog( event.target );
180 } );
181
182 // ── Hash-based deep linking ───────────────────────────────────────────────
183 // Hash-based deep linking.
184 const openByHash = () =>
185 window.location.hash &&
186 openDialogByHash( window.location.hash.slice( 1 ) );
187 openByHash();
188 window.addEventListener( 'hashchange', openByHash );
189 }
190