PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.26
Advanced Ads – Ad Manager & AdSense v2.0.26
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 / src / admin / common / modal.js
advanced-ads / src / admin / common Last commit date
accordion.css 5 months ago button.css 2 months ago card.css 5 months ago common.css 5 months ago common.js 5 months ago deprecated.css 5 months ago form.css 5 months ago header.css 5 months ago modal-new.css 5 months ago modal.css 5 months ago modal.js 3 weeks ago screen-options.js 5 months ago tabs.js 5 months ago toast.css 5 months ago toaster.js 5 months ago toggles.js 5 months ago
modal.js
198 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 if ( opener ) {
128 opener.click();
129 return;
130 }
131
132 const dialog = document.getElementById( hash );
133 if ( dialog?.tagName === 'DIALOG' ) {
134 openDialog( dialog );
135 }
136 }
137
138 // ── init ──────────────────────────────────────────────────────────────────────
139
140 /**
141 * Bootstraps all dialog behaviour.
142 * Call once per page after the DOM is ready.
143 */
144 export function modal() {
145 // Use event delegation on document to handle dynamically added elements.
146
147 // Single delegated click handler covers openers, close buttons, and backdrop.
148 document.addEventListener( 'click', ( { target } ) => {
149 // Opener: [data-dialog="id"]
150 const opener = target.closest( '[data-dialog]' );
151 if ( opener ) {
152 const dialog = document.querySelector(
153 `#${ window.CSS.escape( opener.dataset.dialog ) }`
154 );
155 if ( dialog ) {
156 openDialog( dialog, opener );
157 }
158 return;
159 }
160
161 // Close button: [data-dialog-close]
162 const closer = target.closest( '[data-dialog-close]' );
163 if ( closer ) {
164 const dialog = closer.closest( 'dialog' );
165 if ( dialog ) {
166 closeDialog( dialog );
167 }
168 return;
169 }
170
171 // Backdrop: click fell outside .advads-dialog-frame
172 const dialog = target.closest( 'dialog.advads-dialog' );
173 if (
174 dialog &&
175 ! dialog.classList.contains( 'manual' ) &&
176 ! dialog.querySelector( '.advads-dialog-frame' )?.contains( target )
177 ) {
178 closeDialog( dialog );
179 }
180 } );
181
182 // ── Native Escape key ─────────────────────────────────────────────────────
183 // The browser fires `cancel` on the dialog before closing it natively.
184 // We intercept to apply our animated close and prevent the native close.
185 document.addEventListener( 'cancel', ( event ) => {
186 event.preventDefault();
187 closeDialog( event.target );
188 } );
189
190 // ── Hash-based deep linking ───────────────────────────────────────────────
191 // Hash-based deep linking.
192 const openByHash = () =>
193 window.location.hash &&
194 openDialogByHash( window.location.hash.slice( 1 ) );
195 openByHash();
196 window.addEventListener( 'hashchange', openByHash );
197 }
198