PluginProbe
Polylang / 3.8.10
Polylang v3.8.10
3.8.10 3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 All 234 releases
polylang / js / build / nav-menu.js

nav-menu.js in Polylang 3.8.10, at js/build/nav-menu.js

221 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Handles the options in the language switcher nav menu metabox.
3 *
4 * @package Polylang
5 */
6
7 const pllNavMenu = {
8 /**
9 * The element wrapping the menu elements.
10 *
11 * @member {HTMLElement|null}
12 */
13 wrapper: null,
14
15 /**
16 * Init.
17 */
18 init: () => {
19 if ( document.readyState !== 'loading' ) {
20 pllNavMenu.ready();
21 } else {
22 document.addEventListener( 'DOMContentLoaded', pllNavMenu.ready );
23 }
24 },
25
26 /**
27 * Called when the DOM is ready. Attaches the events to the wrapper.
28 */
29 ready: () => {
30 pllNavMenu.wrapper = document.getElementById( 'menu-to-edit' );
31
32 if ( ! pllNavMenu.wrapper ) {
33 return;
34 }
35
36 pllNavMenu.wrapper.addEventListener( 'click', pllNavMenu.printMetabox );
37 pllNavMenu.wrapper.addEventListener( 'change', pllNavMenu.ensureContent );
38 pllNavMenu.wrapper.addEventListener( 'change', pllNavMenu.showHideRows );
39 },
40
41 printMetabox: {
42 /**
43 * Event callback that prints our checkboxes in the language switcher.
44 *
45 * @param {Event} event The event.
46 */
47 handleEvent: ( event ) => {
48 if ( ! event.target.classList.contains( 'item-edit' ) ) {
49 // Not clicking on a Edit arrow button.
50 return;
51 }
52
53 const metabox = event.target.closest( '.menu-item' ).querySelector( '.menu-item-settings' );
54
55 if ( ! metabox?.id ) {
56 // Should not happen.
57 return;
58 }
59
60 if ( ! metabox.querySelectorAll( 'input[value="#pll_switcher"][type=text]' ).length ) {
61 // Not our metabox, or already replaced.
62 return;
63 }
64
65 // Remove default fields we don't need.
66 [ ...metabox.children ].forEach( ( el ) => {
67 if ( 'P' === el.nodeName && ! el.classList.contains( 'field-move' ) ) {
68 el.remove();
69 }
70 } );
71
72 const t = pllNavMenu.printMetabox;
73 const itemId = Number( metabox.id.replace( 'menu-item-settings-', '' ) );
74
75 metabox.append( t.createHiddenInput( 'title', itemId, pll_data.title ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
76 metabox.append( t.createHiddenInput( 'url', itemId, '#pll_switcher' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
77 metabox.append( t.createHiddenInput( 'pll-detect', itemId, 1 ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
78
79 const ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // Reverse order.
80 const isValDefined = typeof( pll_data.val[ itemId ] ) !== 'undefined';
81
82 ids.forEach( ( optionName ) => {
83 // Create the checkbox's wrapper.
84 const inputWrapper = t.createElement( 'p', { class: 'description' } );
85
86 if ( 'hide_current' === optionName && isValDefined && 1 === pll_data.val[ itemId ].dropdown ) {
87 // Hide the `hide_current` checkbox if `dropdown` is checked.
88 inputWrapper.classList.add( 'hidden' );
89 }
90
91 metabox.prepend( inputWrapper ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
92
93 // Create the checkbox's label.
94 const inputId = `edit-menu-item-${ optionName }-${ itemId }`;
95 const label = t.createElement( 'label', { 'for': inputId } );
96 label.innerText = ` ${ pll_data.strings[ optionName ] }`;
97
98 inputWrapper.append( label ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
99
100 // Create the checkbox.
101 const cb = t.createElement( 'input', {
102 type: 'checkbox',
103 id: inputId,
104 name: `menu-item-${ optionName }[${ itemId }]`,
105 value: 1,
106 } );
107
108 if ( ( isValDefined && 1 === pll_data.val[ itemId ][ optionName ] ) || ( ! isValDefined && 'show_names' === optionName ) ) { // `show_names` as default value.
109 cb.checked = true;
110 }
111
112 label.prepend( cb ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
113 } );
114 },
115
116 /**
117 * Creates and returns a `<input type=hidden"/>` element.
118 *
119 * @param {string} id An identifier for this input. It will be part of the final `id` attribute.
120 * @param {number} itemId The ID of the menu element (post ID).
121 * @param {string|number} value The input's value.
122 * @return {HTMLElement} The input element.
123 */
124 createHiddenInput: ( id, itemId, value ) => {
125 return pllNavMenu.printMetabox.createElement( 'input', {
126 type: 'hidden',
127 id: `edit-menu-item-${ id }-${ itemId }`,
128 name: `menu-item-${ id }[${ itemId }]`,
129 value: value,
130 } );
131 },
132
133 /**
134 * Creates and returns an element.
135 *
136 * @param {string} type Element's type.
137 * @param {Object} atts Element's attributes.
138 * @return {HTMLElement} The element.
139 */
140 createElement: ( type, atts ) => {
141 const el = document.createElement( type );
142 for ( const [ key, value ] of Object.entries( atts ) ) {
143 el.setAttribute( key, value );
144 }
145 return el;
146 },
147 },
148
149 ensureContent: {
150 regExpr: new RegExp( /^edit-menu-item-show_(names|flags)-(\d+)$/ ),
151
152 /**
153 * Event callback that disallows unchecking both `show_names` and `show_flags`.
154 *
155 * @param {Event} event The event.
156 */
157 handleEvent: ( event ) => {
158 if ( ! event.target.id || event.target.checked ) {
159 // Now checked, nothing to do.
160 return;
161 }
162
163 const matches = event.target.id.match( pllNavMenu.ensureContent.regExpr );
164
165 if ( ! matches ) {
166 // Not the checkbox we want.
167 return;
168 }
169
170 // Check the other checkbox.
171 const [ , type, id ] = matches;
172 const otherType = 'names' === type ? 'flags' : 'names';
173 document.getElementById( `edit-menu-item-show_${ otherType }-${ id }` ).checked = true;
174 },
175 },
176
177 showHideRows: {
178 regExpr: new RegExp( /^edit-menu-item-dropdown-(\d+)$/ ),
179
180 /**
181 * Event callback that shows or hides the `hide_current` checkbox when `dropdown` is checked.
182 *
183 * @param {Event} event The event.
184 */
185 handleEvent: ( event ) => {
186 if ( ! event.target.id ) {
187 // Not the checkbox we want.
188 return;
189 }
190
191 const matches = event.target.id.match( pllNavMenu.showHideRows.regExpr );
192
193 if ( ! matches ) {
194 // Not the checkbox we want.
195 return;
196 }
197
198 const hideCb = document.getElementById( `edit-menu-item-hide_current-${ matches[1] }` );
199
200 if ( ! hideCb ) {
201 // Should not happen.
202 return;
203 }
204
205 const description = hideCb.closest( '.description' );
206
207 // Hide or show.
208 description.classList.toggle( 'hidden', event.target.checked );
209
210 if ( event.target.checked ) {
211 // Uncheck after hiding.
212 hideCb.checked = false;
213 hideCb.dispatchEvent( new Event( 'change' ) );
214 }
215 },
216 },
217 };
218
219 pllNavMenu.init();
220
221