PluginProbe
Polylang / trunk
Polylang vtrunk
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 3.0.3 All 233 releases
← All changes | js/build/widgets.js +202 -120 3.8.4 → trunk View file →
@@ -1,152 +1,234 @@
1 1 /**
2 - * Adds a flag to the widgets filtered by a language.
3 - *
4 - * @package Polylang
2 + * Handles the options in the language switcher widget.
5 3 */
4 +const pllWidget = {
5 + /**
6 + * Init.
7 + */
8 + init: () => {
9 + if ( document.readyState !== 'loading' ) {
10 + pllWidget.ready();
11 + } else {
12 + document.addEventListener( 'DOMContentLoaded', pllWidget.ready );
13 + }
14 + },
6 15
7 -jQuery(
8 - function ( $ ) {
9 - var widgets_container,
10 - widgets_selector,
11 - flags,
12 - isBlockEditor = 'undefined' !== typeof wp.blockEditor;
16 + /**
17 + * Called when the DOM is ready. Attaches the events to the wrapper.
18 + */
19 + ready: () => {
20 + if (
21 + window.pll_widgets?.flags &&
22 + 'object' === typeof window.pll_widgets.flags
23 + ) {
24 + pllWidget.displayFlags.flags = window.pll_widgets.flags;
25 + }
26 + document
27 + .querySelectorAll(
28 + // Widgets page without Classic Widgets, Widgets page with Classic Widgets, Customizer page.
29 + '#widgets-editor, .widget-liquid-right #widgets-right, #customize-theme-controls'
30 + )
31 + .forEach( ( wrapper ) => {
32 + wrapper.addEventListener( 'change', ( event ) => {
33 + if (
34 + event.target.closest(
35 + '.polylang-language-switcher-widget-content select, .polylang-language-switcher-widget-content input'
36 + )
37 + ) {
38 + pllWidget.manageRowsAndValues.handleEvent( event );
39 + return;
40 + }
13 41
14 - if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
15 - flags = pll_widgets.flags;
16 - }
42 + if (
43 + ! pllWidget.displayFlags.flags.length ||
44 + 'customize-theme-controls' === wrapper.id
45 + ) {
46 + // No flags for the customizer.
47 + return;
48 + }
17 49
50 + if (
51 + event.target.closest(
52 + '.wp-block-legacy-widget__edit-form .pll-lang-choice'
53 + )
54 + ) {
55 + // Without Classic Widgets.
56 + pllWidget.displayFlags.handleEvent(
57 + event,
58 + '.wp-block-legacy-widget__edit-form',
59 + '.wp-block-legacy-widget__edit-form-title'
60 + );
61 + } else if (
62 + event.target.closest( '.widget .pll-lang-choice' )
63 + ) {
64 + // With Classic Widgets.
65 + pllWidget.displayFlags.handleEvent(
66 + event,
67 + '.widget',
68 + '.widget-top .widget-title h3'
69 + );
70 + }
71 + } );
72 +
73 + if ( 'customize-theme-controls' !== wrapper.id ) {
74 + // No flags for the customizer.
75 + if (
76 + wrapper.classList.contains( 'blocks-widgets-container' )
77 + ) {
78 + // Without Classic Widgets: wait a second that everything is inserted into the page by WP.
79 + setTimeout( () => {
80 + pllWidget.displayFlags.triggerChange( wrapper );
81 + }, 1000 );
82 + } else {
83 + pllWidget.displayFlags.triggerChange( wrapper );
84 + }
85 + }
86 + } );
87 + },
88 +
89 + /**
90 + * Display or hide rows, depending on the value of other settings.
91 + */
92 + manageRowsAndValues: {
18 93 /**
19 - * Prepend widget titles with a flag once a language is selected.
94 + * Event callback that hides rows and forbids disabling both flag and name/code.
20 95 *
21 - * @param {object} widget The widget element.
22 - * @return {void} Nothing.
96 + * @param {Event} event The event.
23 97 */
24 - function add_flag( widget ) {
25 - if ( ! flags ) {
26 - return;
27 - }
28 - widget = $( widget );
29 - var title = isBlockEditor ? widget.prev('h3') : $( '.widget-top .widget-title h3', widget ),
30 - locale = $( '.pll-lang-choice option:selected', widget ).val(),
31 - // Icon is HTML built and come from server side and is well escaped when necessary
32 - icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
98 + handleEvent: ( event ) => {
99 + let value = '';
33 100
34 - if ( icon ) {
35 - icon += '   ';
36 - var current = $( '.pll-lang', title );
37 - if ( current.length ) {
38 - current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
39 - } else {
40 - flag = $( '<span />' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
41 - // See the comment above about the icon which is safe. So it is also safe to prepend flag which uses icon.
42 - title.prepend( flag ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
43 - }
101 + if ( 'SELECT' === event.target.nodeName ) {
102 + value = event.target.value;
103 + } else if (
104 + 'INPUT' === event.target.nodeName &&
105 + 'checkbox' === event.target.type
106 + ) {
107 + value = event.target.checked;
44 108 } else {
45 - $( '.pll-lang', title ).remove();
109 + return;
46 110 }
47 - }
48 111
49 - if ( isBlockEditor ) {
112 + const wrapper = event.target.closest(
113 + '.polylang-language-switcher-widget-content'
114 + );
50 115
51 - widgets_container = $( '.edit-widgets-main-block-list' );
52 - widgets_selector = '.widget';
116 + if ( ! wrapper ) {
117 + return;
118 + }
53 119
54 - // Update flags when we click on the legacy widget to display its form.
55 - widgets_container.on(
56 - 'click',
57 - '.wp-block-legacy-widget',
58 - function () {
59 - add_flag( $( this ).find( '.widget' ) );
60 - }
61 - );
120 + const key = event.target.getAttribute( 'data-key' );
62 121
63 - } else {
64 - if ( 'undefined' !== typeof wp.customize ) {
122 + // Show/Hide rows.
123 + wrapper
124 + .querySelectorAll(
125 + `:scope [class*="pll-hidden-if-${ key }-"]:not(.pll-hidden-if-${ key }-${ value })`
126 + )
127 + .forEach( ( row ) => {
128 + row.classList.remove( `pll-hidden-by-${ key }` );
129 + } );
130 + wrapper
131 + .querySelectorAll( `:scope .pll-hidden-if-${ key }-${ value }` )
132 + .forEach( ( row ) => {
133 + row.classList.add( `pll-hidden-by-${ key }` );
134 + } );
65 135
66 - widgets_container = $( '#customize-controls' );
67 - widgets_selector = '.customize-control .widget';
136 + // Forbid disabling both flag and name/code.
137 + if ( 'show_labels' === key && '' === value ) {
138 + const otherInput = wrapper.querySelector(
139 + '[data-key="show_flags"]'
140 + );
68 141
69 - /**
70 - * WP Customizer add control listener.
71 - *
72 - * @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading
73 - *
74 - * @param {object} control The control type.
75 - * @return {void} Nothing.
76 - */
77 - function customize_add_flag( control ) {
78 - if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) {
79 - return;
80 - }
142 + if ( true !== otherInput.checked ) {
143 + otherInput.checked = true;
144 + otherInput.dispatchEvent(
145 + new Event( 'change', { bubbles: true } )
146 + );
147 + }
148 + } else if ( 'show_flags' === key && false === value ) {
149 + const otherInput = wrapper.querySelector(
150 + '[data-key="show_labels"]'
151 + );
81 152
82 - /*
83 - * Make sure the widget's contents are embedded; normally this is done
84 - * when the control is expanded, for DOM performance reasons.
85 - */
86 - control.embedWidgetContent();
87 -
88 - // Now we know for sure the widget is fully embedded.
89 - add_flag( control.container.find( '.widget' ) );
153 + if ( '' === otherInput.value ) {
154 + otherInput.value = 'names';
155 + otherInput.dispatchEvent(
156 + new Event( 'change', { bubbles: true } )
157 + );
90 158 }
91 - wp.customize.control.each( customize_add_flag );
92 - wp.customize.control.bind( 'add', customize_add_flag );
159 + }
160 + },
161 + },
93 162
94 - } else {
163 + /**
164 + * Display a flag in front of a widget title, depending on the language the widget should be displayed for.
165 + */
166 + displayFlags: {
167 + /**
168 + * Flags (markup), with language slug as property names.
169 + *
170 + * @member {Object}
171 + */
172 + flags: {},
95 173
96 - widgets_container = $( '#widgets-right' );
97 - widgets_selector = '.widget';
174 + /**
175 + * Event callback that adds or removes the flag.
176 + *
177 + * @param {Event} event The event.
178 + * @param {string} widgetSelector Selector for the widget wrapper, relative to the event target.
179 + * @param {string} titleSelector Selector for the title, relative to the wrapper.
180 + */
181 + handleEvent: ( event, widgetSelector, titleSelector ) => {
182 + const wrapper = event.target.closest( widgetSelector );
98 183
184 + if ( ! wrapper ) {
185 + return;
99 186 }
100 187
101 - // Add flags on load.
102 - $( widgets_selector, widgets_container ).each(
103 - function () {
104 - add_flag( this );
105 - }
106 - );
107 - }
188 + const title = wrapper.querySelector( titleSelector );
108 189
109 - // Update flags.
110 - widgets_container.on(
111 - 'change',
112 - '.pll-lang-choice',
113 - function () {
114 - add_flag( $( this ).parents( '.widget' ) );
190 + if ( ! title ) {
191 + return;
115 192 }
116 - );
117 193
118 - function pll_toggle( a, test ) {
119 - test ? a.show() : a.hide();
120 - }
194 + const langSlug = event.target.value;
195 + const icon =
196 + langSlug &&
197 + pllWidget.displayFlags.flags.hasOwnProperty( langSlug )
198 + ? pllWidget.displayFlags.flags[ langSlug ]
199 + : null;
200 + const currentFlag = title.querySelector( '.pll-lang' );
121 201
122 - // Remove all options if dropdown is checked.
123 - $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on(
124 - 'change',
125 - '.pll-dropdown',
126 - function () {
127 - var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
128 - pll_toggle( $( '.no-dropdown-' + this_id ), true != $( this ).prop( 'checked' ) );
202 + if ( icon ) {
203 + if ( currentFlag ) {
204 + currentFlag.innerHTML = `${ icon } &nbsp; `; // `icon` comes from `PLL_Admin_Base::add_inline_scripts()`.
205 + } else {
206 + const newFlag = document.createElement( 'span' );
207 + newFlag.classList.add( 'pll-lang' );
208 + newFlag.innerHTML = `${ icon } &nbsp; `; // `icon` comes from `PLL_Admin_Base::add_inline_scripts()`.
209 + title.prepend( newFlag ); // `newFlag` is a new element we just created with safe data.
210 + }
211 + } else if ( currentFlag ) {
212 + currentFlag.remove();
129 213 }
130 - );
214 + },
131 215
132 - // Disallow unchecking both show names and show flags.
133 - var options = ['-show_flags', '-show_names'];
134 - $.each(
135 - options,
136 - function ( i, v ) {
137 - $( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on(
138 - 'change',
139 - '.pll' + v,
140 - function () {
141 - var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
142 - if ( true != $( this ).prop( 'checked' ) ) {
143 - $( '#widget-' + this_id + options[ 1 - i ] ).prop( 'checked', true );
144 - }
145 - }
146 - );
147 - }
148 - );
216 + /**
217 + * Triggers a language selection.
218 + *
219 + * @param {HTMLElement} wrapper Wrapper.
220 + */
221 + triggerChange: ( wrapper ) => {
222 + wrapper
223 + .querySelectorAll( ':scope .pll-lang-choice' )
224 + .forEach( ( select ) => {
225 + select.dispatchEvent(
226 + new Event( 'change', { bubbles: true } )
227 + );
228 + } );
229 + },
230 + },
231 +};
149 232
150 - }
151 -);
233 +pllWidget.init();
152 234