PluginProbe
Polylang / 3.8.4
Polylang v3.8.4
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
polylang / src / modules / wizard / js / languages-step.js

languages-step.js in Polylang 3.8.4, at src/modules/wizard/js/languages-step.js

303 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * @package Polylang
3 */
4
5 jQuery(
6 function ( $ ) {
7 var addLanguageForm = $( '.languages-step' ); // Form element.
8 var languageFields = $( '#language-fields' ); // Element where to append hidden fields for creating language.
9 var languagesTable = $( '#languages' ); // Table element contains languages list to create.
10 var languagesListTable = $( '#languages tbody' ); // Table rows with languages list to create.
11 var definedLanguagesListTable = $( '#defined-languages tbody' ); // Table rows with already defined languages list.
12 var languagesList = $( '#lang_list' ); // Select form element with predefined languages without already created languages.
13 var nextStepButton = $( '[name="save_step"]' ); // The button for continuing to the next step.
14 var messagesContainer = $( '#messages' ); // Element where to display error messages.
15 var languagesMap = new Map(); // Languages map object for managing the languages to create.
16 var dialog = $( '#dialog' ); // Dialog box for alerting the language selected has not been added to the list.
17
18 /**
19 * Add a language in the list to create it in Polylang settings
20 *
21 * @param {object} language The language object
22 */
23 function addLanguage( language ) {
24 // language properties come from the select dropdown which is built server side and well escaped.
25 // see template view-wizard-step-languages.php.
26 var languageValueHtml = $( '<td />' ).text( language.text ).prepend( language.flagUrl ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
27 var languageTrashIconHtml = $( '<td />' )
28 .append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
29 $( '<span />' )
30 .addClass( 'dashicons dashicons-trash' )
31 .attr( 'data-language', language.locale )
32 .append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
33 $( '<span />' )
34 .addClass( 'screen-reader-text' )
35 .text( pll_wizard_params.i18n_remove_language_icon )
36 )
37 );
38 // see the comment and the hardcoded code above. languageTrashIconHtml and languageValueHtml are safe.
39 var languageLineHtml = $( '<tr />' ).prepend( languageTrashIconHtml ).prepend( languageValueHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
40 var languageFieldHtml = $( '<input />' ).attr(
41 {
42 type: 'hidden',
43 name: 'languages[]'
44 }
45 ).val( language.locale );
46
47 languagesList.val( '' );
48 languagesList.selectmenu( 'refresh' ); // Refresh jQuery selectmenu widget after changing the value.
49
50 languagesMap.set( language.locale, language );
51
52 // see above how languageLineHtml is built.
53 languagesListTable.append( languageLineHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
54 // Bind click event on trash icon.
55 languagesListTable.on(
56 'click',
57 'span[data-language=' + language.locale + ']',
58 function ( event ) {
59 event.preventDefault();
60 // Remove line in languages table.
61 $( this ).parents( 'tr' ).remove();
62 // Remove input field.
63 var languageField = languageFields.children( 'input[value=' + $( this ).data( 'language' ) + ']' ).remove();
64 // If there is no more languages hide languages table.
65 if ( languagesListTable.children().length <= 0 ) {
66 languagesTable.hide();
67 }
68 // Remove language from the Map.
69 languagesMap.delete( $( this ).data( 'language' ) );
70 // Hide error message.
71 hideError();
72 }
73 );
74 // see above how languageFieldHtml is built.
75 // Add hidden input field for posting the form.
76 languageFields.append( languageFieldHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
77
78 }
79
80 /**
81 * Display an error message
82 *
83 * @param {string} message The message to display
84 */
85 function showError( message ) {
86 messagesContainer.empty();
87 // html is hardcoded and use of jQuery text method which is safe to add message value.
88 // In addition message is i18n value which is initialized server side in PLL_Wizard::add_step_languages and correctly escaped.
89 messagesContainer.prepend( $( '<p/>' ).addClass( 'error' ).text( message ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
90 }
91
92 /**
93 * Hide all error messages and fields in error
94 */
95 function hideError() {
96 messagesContainer.empty();
97 addLanguageForm.find( '.error' ).removeClass( 'error field-in-error' );
98 }
99
100 /**
101 * Style the field to indicate where the error is
102 *
103 * @param {object} field The jQuery element which is in error
104 */
105 function showFieldInError( field ) {
106 field.addClass( 'error field-in-error' );
107 }
108
109 /**
110 * Focus on a specific element
111 *
112 * @param {object} field The jQuery element which will be focused
113 */
114 function focusOnField( field ) {
115 field.trigger( 'focus' );
116 }
117
118 /**
119 * Disable a specific button
120 *
121 * @param {object} button
122 */
123 function disableButton( button ){
124 button.prop( 'disabled', true );
125 // Because the button is disabled we need to add the value of the button to ensure it will pass in the request.
126 addLanguageForm.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
127 $( '<input />' ).prop(
128 {
129 type: 'hidden',
130 name: button.prop( 'name' ),
131 value: button.prop( 'value' )
132 }
133 )
134 );
135 }
136
137 /**
138 * Remove error when a new selection is done in languages list.
139 */
140 languagesList.on(
141 'selectmenuchange',
142 function () {
143 hideError();;
144 }
145 );
146 /**
147 * Bind click event on "Add language" button
148 */
149 $( '#add-language' ).on(
150 'click',
151 function ( event ) {
152 hideError();
153 var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex];
154 if ( '' !== selectedOption.value && ! languagesMap.has( selectedOption.value ) ) {
155 addLanguage(
156 {
157 locale: selectedOption.value,
158 text: selectedOption.innerText,
159 name: $( selectedOption ).data( 'language-name' ),
160 flagUrl: $( selectedOption ).data( 'flag-html' )
161 }
162 );
163 // Show table of languages.
164 languagesTable.show();
165 // Put back the focus on the select language field after clicking on "Add language button".
166 focusOnField( $( '#lang_list-button' ) );
167 } else {
168 var message = pll_wizard_params.i18n_no_language_selected;
169 if ( languagesMap.has( selectedOption.value ) ) {
170 message = pll_wizard_params.i18n_language_already_added;
171 }
172 showError( message );
173 showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
174 focusOnField( $( '#lang_list-button' ) );
175
176 }
177 }
178 );
179
180 /**
181 * Bind submit event on "add_lang" form
182 */
183 addLanguageForm.on(
184 'submit',
185 function ( event ) {
186 // Verify if there is at least one language.
187 var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0;
188 var selectedLanguage = $( '#lang_list' ).val();
189 if ( languagesMap.size <= 0 && ! isLanguagesAlreadyDefined ) {
190 if ( '' === selectedLanguage ) {
191 showError( pll_wizard_params.i18n_no_language_added );
192 showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
193 focusOnField( $( '#lang_list-button' ) );
194 } else {
195 showError( pll_wizard_params.i18n_add_language_needed );
196 showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
197 focusOnField( $( '#add-language' ) ); // Put the focus on the "Add language" button.
198 }
199 return false;
200 }
201 // Verify if the language has been added in the list otherwise display a dialog box to confirm what to do.
202 if ( '' !== selectedLanguage ) {
203 // Verify we don't add a duplicate language before opening the dialog box otherwise display an error message.
204 if ( ! languagesMap.has( selectedLanguage ) ) {
205 dialog.dialog( 'open' );
206 } else {
207 showError( pll_wizard_params.i18n_language_already_added );
208 showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
209 focusOnField( $( '#lang_list-button' ) );
210 }
211 return false;
212 }
213 disableButton( nextStepButton );
214 }
215 );
216
217 // Is there an error return by PHP ?
218 var searchParams = new URLSearchParams( document.location.search );
219 if ( searchParams.has( 'activate_error' ) ) {
220 // If the error code exists, display it.
221 if ( undefined !== pll_wizard_params[ searchParams.get( 'activate_error' ) ] ) {
222 showError( pll_wizard_params[ searchParams.get( 'activate_error' ) ] );
223 }
224 }
225
226 function confirmDialog( what ) {
227 switch ( what ) {
228 case 'yes':
229 var selectedOption = $( '#lang_list' ).children( ':selected' );
230 addLanguage(
231 {
232 locale: selectedOption[0].value,
233 text: selectedOption[0].innerText,
234 name: $( selectedOption ).data( 'language-name' ),
235 flagUrl: $( selectedOption ).data( 'flag-html' )
236 }
237 );
238 break;
239 case 'no':
240 // Empty select form field and submit again the form.
241 languagesList.val( '' );
242 break;
243 case 'ignore':
244 }
245 dialog.dialog( 'close' );
246 if ( 'ignore' === what ) {
247 focusOnField( $( '#lang_list-button' ) );
248 } else {
249 addLanguageForm.submit();
250 }
251 }
252
253 // Initialize dialog box in the case a language is selected but not added in the list.
254 dialog.dialog(
255 {
256 autoOpen: false,
257 modal: true,
258 draggable: false,
259 resizable: false,
260 title: pll_wizard_params.i18n_dialog_title,
261 minWidth: 600,
262 maxWidth: '100%',
263 open: function ( event, ui ) {
264 // Change dialog box position for rtl language
265 if ( $( 'body' ).hasClass( 'rtl' ) ) {
266 $( this ).parent().css(
267 {
268 right: $( this ).parent().css( 'left' ),
269 left: 'auto'
270 }
271 );
272 }
273 // Display language name and flag information in dialog box.
274 $( this ).find( '#dialog-language' ).text( $( '#lang_list' ).children( ':selected' ).first().text() );
275 // language properties come from the select dropdown #lang_list which is built server side and well escaped.
276 // see template view-wizard-step-languages.php.
277 $( this ).find( '#dialog-language-flag' ).empty().prepend( $( '#lang_list' ).children( ':selected' ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
278 },
279 buttons: [
280 {
281 text: pll_wizard_params.i18n_dialog_yes_button,
282 click: function ( event ) {
283 confirmDialog( 'yes' );
284 }
285 },
286 {
287 text: pll_wizard_params.i18n_dialog_no_button,
288 click: function ( event ) {
289 confirmDialog( 'no' );
290 }
291 },
292 {
293 text: pll_wizard_params.i18n_dialog_ignore_button,
294 click: function ( event ) {
295 confirmDialog( 'ignore' );
296 }
297 }
298 ]
299 }
300 )
301 }
302 );
303