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 +204 -103 3.0.3 → trunk View file →
@@ -1,133 +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, widgets_selector, flags;
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 + }
10 41
11 - if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
12 - flags = pll_widgets.flags;
13 - }
42 + if (
43 + ! pllWidget.displayFlags.flags.length ||
44 + 'customize-theme-controls' === wrapper.id
45 + ) {
46 + // No flags for the customizer.
47 + return;
48 + }
14 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: {
15 93 /**
16 - * 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.
17 95 *
18 - * @param {object} widget The widget element.
19 - * @return {void} Nothing.
96 + * @param {Event} event The event.
20 97 */
21 - function add_flag( widget ) {
22 - if ( ! flags ) {
98 + handleEvent: ( event ) => {
99 + let value = '';
100 +
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;
108 + } else {
23 109 return;
24 110 }
25 - widget = $( widget );
26 - var title = $( '.widget-top .widget-title h3', widget ),
27 - locale = $( '.pll-lang-choice option:selected', widget ).val(),
28 - // Icon is HTML built and come from server side and is well escaped when necessary
29 - icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
30 111
31 - if ( icon ) {
32 - icon += '   ';
33 - var current = $( '.pll-lang', title );
34 - if ( current.length ) {
35 - current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
36 - } else {
37 - flag = $( '<span />' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
38 - // See the comment above about the icon which is safe. So it is also safe to prepend flag which uses icon.
39 - title.prepend( flag ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
40 - }
41 - } else {
42 - $( '.pll-lang', title ).remove();
112 + const wrapper = event.target.closest(
113 + '.polylang-language-switcher-widget-content'
114 + );
115 +
116 + if ( ! wrapper ) {
117 + return;
43 118 }
44 - }
45 119
46 - if ( 'undefined' !== typeof wp.customize ) {
120 + const key = event.target.getAttribute( 'data-key' );
47 121
48 - widgets_container = $( '#customize-controls' );
49 - widgets_selector = '.customize-control .widget';
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 + } );
50 135
51 - /**
52 - * WP Customizer add control listener.
53 - *
54 - * @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading
55 - *
56 - * @param {object} control The control type.
57 - * @return {void} Nothing.
58 - */
59 - function customize_add_flag( control ) {
60 - if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) {
61 - return;
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 + );
141 +
142 + if ( true !== otherInput.checked ) {
143 + otherInput.checked = true;
144 + otherInput.dispatchEvent(
145 + new Event( 'change', { bubbles: true } )
146 + );
62 147 }
148 + } else if ( 'show_flags' === key && false === value ) {
149 + const otherInput = wrapper.querySelector(
150 + '[data-key="show_labels"]'
151 + );
63 152
64 - /*
65 - * Make sure the widget's contents are embedded; normally this is done
66 - * when the control is expanded, for DOM performance reasons.
67 - */
68 - control.embedWidgetContent();
69 -
70 - // Now we know for sure the widget is fully embedded.
71 - add_flag( control.container.find( '.widget' ) );
153 + if ( '' === otherInput.value ) {
154 + otherInput.value = 'names';
155 + otherInput.dispatchEvent(
156 + new Event( 'change', { bubbles: true } )
157 + );
158 + }
72 159 }
73 - wp.customize.control.each( customize_add_flag );
74 - wp.customize.control.bind( 'add', customize_add_flag );
160 + },
161 + },
75 162
76 - } 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: {},
77 173
78 - widgets_container = $( '#widgets-right' );
79 - 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 );
80 183
81 - }
184 + if ( ! wrapper ) {
185 + return;
186 + }
82 187
83 - // Add flags on load.
84 - $( widgets_selector, widgets_container ).each(
85 - function() {
86 - add_flag( this );
87 - }
88 - );
188 + const title = wrapper.querySelector( titleSelector );
89 189
90 - // Update flags.
91 - widgets_container.on(
92 - 'change',
93 - '.pll-lang-choice',
94 - function() {
95 - add_flag( $( this ).parents( '.widget' ) );
190 + if ( ! title ) {
191 + return;
96 192 }
97 - );
98 193
99 - function pll_toggle( a, test ) {
100 - test ? a.show() : a.hide();
101 - }
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' );
102 201
103 - // Remove all options if dropdown is checked.
104 - $( '.widgets-sortables,.control-section-sidebar' ).on(
105 - 'change',
106 - '.pll-dropdown',
107 - function() {
108 - var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
109 - 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();
110 213 }
111 - );
214 + },
112 215
113 - // Disallow unchecking both show names and show flags.
114 - var options = ['-show_flags', '-show_names'];
115 - $.each(
116 - options,
117 - function( i, v ) {
118 - $( '.widgets-sortables,.control-section-sidebar' ).on(
119 - 'change',
120 - '.pll' + v,
121 - function() {
122 - var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
123 - if ( true != $( this ).prop( 'checked' ) ) {
124 - $( '#widget-' + this_id + options[ 1 - i ] ).prop( 'checked', true );
125 - }
126 - }
127 - );
128 - }
129 - );
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 +};
130 232
131 - }
132 -);
233 +pllWidget.init();
133 234