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
polylang / js / build / block-editor.js

block-editor.js in Polylang trunk, at js/build/block-editor.js

451 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ var __webpack_modules__ = ({
3
4 /***/ 631
5 (module) {
6
7 module.exports = (function() { return this["wp"]["apiFetch"]; }());
8
9 /***/ }
10
11 /******/ });
12 /************************************************************************/
13 /******/ // The module cache
14 /******/ const __webpack_module_cache__ = {};
15 /******/
16 /******/ // The require function
17 /******/ function __webpack_require__(moduleId) {
18 /******/ // Check if module is in cache
19 /******/ const cachedModule = __webpack_module_cache__[moduleId];
20 /******/ if (cachedModule !== undefined) {
21 /******/ return cachedModule.exports;
22 /******/ }
23 /******/ // Create a new module (and put it into the cache)
24 /******/ const module = __webpack_module_cache__[moduleId] = {
25 /******/ // no module.id needed
26 /******/ // no module.loaded needed
27 /******/ exports: {}
28 /******/ };
29 /******/
30 /******/ // Execute the module function
31 /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
32 /******/
33 /******/ // Return the exports of the module
34 /******/ return module.exports;
35 /******/ }
36 /******/
37 /************************************************************************/
38 /******/ /* webpack/runtime/compat get default export */
39 /******/ // getDefaultExport function for compatibility with non-harmony modules
40 /******/ __webpack_require__.n = (module) => {
41 /******/ const getter = module && module.__esModule ?
42 /******/ () => (module['default']) :
43 /******/ () => (module);
44 /******/ __webpack_require__.d(getter, { a: getter });
45 /******/ return getter;
46 /******/ };
47 /******/
48 /******/ /* webpack/runtime/define property getters */
49 /******/ // define getter/value functions for harmony exports
50 /******/ __webpack_require__.d = (exports, definition) => {
51 /******/ for(var key in definition) {
52 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
53 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
54 /******/ }
55 /******/ }
56 /******/ };
57 /******/
58 /******/ /* webpack/runtime/hasOwnProperty shorthand */
59 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop));
60 /******/
61 /************************************************************************/
62 let __webpack_exports__ = {};
63 // This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
64 (() => {
65 "use strict";
66
67 ;// ./js/src/lib/confirmation-modal.js
68 /**
69 * @package Polylang
70 */
71
72 const languagesList = jQuery('.post_lang_choice');
73
74 // Dialog box for alerting the user about a risky changing.
75 const initializeConfirmationModal = () => {
76 const {
77 __
78 } = wp.i18n;
79
80 // Create dialog container.
81 const dialogContainer = jQuery('<div/>', {
82 id: 'pll-dialog',
83 style: 'display:none;'
84 }).text(__('Are you sure you want to change the language of the current content?', 'polylang'));
85
86 // Put it after languages list dropdown.
87 // PHPCS ignore dialogContainer is a new safe HTML code generated above.
88 languagesList.after(dialogContainer);
89 const dialogResult = new Promise((confirm, cancel) => {
90 const confirmDialog = what => {
91 // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
92 switch (what) {
93 // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
94 case 'yes':
95 // Confirm the new language.
96 languagesList.data('old-value', languagesList.children(':selected').first().val());
97 confirm();
98 break;
99 case 'no':
100 // Revert to the old language.
101 languagesList.val(languagesList.data('old-value'));
102 cancel('Cancel');
103 break;
104 }
105 dialogContainer.dialog('close'); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
106 }; // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
107
108 // Initialize dialog box in the case a language is selected but not added in the list.
109 const dialogOptions = {
110 autoOpen: false,
111 modal: true,
112 draggable: false,
113 resizable: false,
114 title: __('Change language', 'polylang'),
115 minWidth: 600,
116 maxWidth: '100%',
117 open: function (event, ui) {
118 // Change dialog box position for rtl language
119 if (jQuery('body').hasClass('rtl')) {
120 jQuery(this).parent().css({
121 right: jQuery(this).parent().css('left'),
122 left: 'auto'
123 });
124 }
125 },
126 close: function (event, ui) {
127 // When we're closing the dialog box we need to cancel the language change as we click on Cancel button.
128 confirmDialog('no');
129 },
130 buttons: [{
131 text: __('OK', 'polylang'),
132 click: function (event) {
133 confirmDialog('yes');
134 }
135 }, {
136 text: __('Cancel', 'polylang'),
137 click: function (event) {
138 confirmDialog('no');
139 }
140 }]
141 };
142 if (jQuery.ui.version >= '1.12.0') {
143 Object.assign(dialogOptions, {
144 classes: {
145 'ui-dialog': 'pll-confirmation-modal'
146 }
147 });
148 } else {
149 Object.assign(dialogOptions, {
150 dialogClass: 'pll-confirmation-modal'
151 }); // jQuery UI 1.11.4 - WP < 5.6
152 }
153 dialogContainer.dialog(dialogOptions);
154 });
155 return {
156 dialogContainer,
157 dialogResult
158 };
159 };
160 const initializeLanguageOldValue = () => {
161 // Keep the old language value to be able to compare to the new one and revert to it if necessary.
162 languagesList.attr('data-old-value', languagesList.children(':selected').first().val());
163 };
164 ;// ./js/src/lib/metabox-autocomplete.js
165 /**
166 * @package Polylang
167 */
168
169 // Translations autocomplete input box.
170 function initMetaboxAutoComplete() {
171 jQuery('.tr_lang').each(function () {
172 var tr_lang = jQuery(this).attr('id').substring(8);
173 var td = jQuery(this).parent().parent().siblings('.pll-edit-column');
174 jQuery(this).autocomplete({
175 minLength: 0,
176 source: ajaxurl + '?action=pll_posts_not_translated' + '&post_language=' + jQuery('.post_lang_choice').val() + '&translation_language=' + tr_lang + '&post_type=' + jQuery('#post_type').val() + '&_pll_nonce=' + jQuery('#_pll_nonce').val(),
177 select: function (event, ui) {
178 jQuery('#htr_lang_' + tr_lang).val(ui.item.id);
179 // ui.item.link is built and come from server side and is well escaped when necessary
180 td.html(ui.item.link);
181 }
182 });
183
184 // when the input box is emptied
185 jQuery(this).on('blur', function () {
186 if (!jQuery(this).val()) {
187 jQuery('#htr_lang_' + tr_lang).val(0);
188 // Value is retrieved from HTML already generated server side
189 td.html(td.siblings('.hidden').children().clone());
190 }
191 });
192 });
193 }
194 // EXTERNAL MODULE: external {"this":["wp","apiFetch"]}
195 var external_this_wp_apiFetch_ = __webpack_require__(631);
196 var external_this_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_this_wp_apiFetch_);
197 ;// ./node_modules/@wpsyntex/polylang-react-library/build/middlewares/filter-path.js
198 /**
199 * Filters requests for translatable entities.
200 * This logic is shared across all Polylang plugins.
201 *
202 * @since 3.5
203 *
204 * @param {Object} options - API fetch options object.
205 * @param {Array} filteredRoutes - Array of route paths to filter.
206 * @param {Function} filter - Function to filter matching routes.
207 * @return {Object} Modified REST request options.
208 */
209 const filterPathMiddleware = (options, filteredRoutes, filter) => {
210 const cleanPath = options.path.split('?')[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'.
211
212 return Object.values(filteredRoutes).find(path => cleanPath === path) ? filter(options) : options;
213 };
214 /* harmony default export */ const filter_path = (filterPathMiddleware);
215 ;// ./node_modules/@wpsyntex/polylang-react-library/build/middlewares/editors-requests-filter.js
216 /**
217 * WordPress dependencies.
218 */
219
220
221 /*
222 * Internal dependencies.
223 */
224
225
226 /**
227 * Safely filters requests for translatable entities in block editor type screens.
228 * Ensures that `pllFilteredRoutes` has been well defined on server side and
229 * that the filtered request is a REST one.
230 *
231 * @param {Function} filterCallback - Function to filter API fetch options.
232 */
233 const editorsRequestsFilter = filterCallback => {
234 external_this_wp_apiFetch_default().use((options, next) => {
235 /*
236 * If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes.
237 * If `filteredRoutes` is not defined, return early.
238 */
239 if ('undefined' !== typeof options.url || 'undefined' === typeof window.pllFilteredRoutes) {
240 return next(options);
241 }
242 return next(filter_path(options, window.pllFilteredRoutes, filterCallback));
243 });
244 };
245 /* harmony default export */ const editors_requests_filter = (editorsRequestsFilter);
246 ;// ./js/src/block-editor.js
247 /**
248 * @package Polylang
249 */
250
251
252
253
254
255 /**
256 * Gets the language of the currently edited post, fallback to default language if none is found.
257 *
258 * @since 2.5
259 *
260 * @return {Element.value}
261 */
262 function getCurrentLanguage() {
263 const lang = document.querySelector('[name=post_lang_choice]');
264 if (null === lang) {
265 return pllDefaultLanguage;
266 }
267 return lang.value;
268 }
269
270 /**
271 * Adds language parameter according to the current one (query string for GET, body for PUT and POST).
272 *
273 * @since 3.5
274 *
275 * @param {APIFetchOptions} options
276 * @returns {APIFetchOptions}
277 */
278 function addLanguageParameter(options) {
279 if ('undefined' === typeof options.data || null === options.data) {
280 // GET
281 options.path += (options.path.indexOf('?') >= 0 ? '&lang=' : '?lang=') + getCurrentLanguage();
282 } else {
283 // PUT, POST
284 options.data.lang = getCurrentLanguage();
285 }
286 return options;
287 }
288
289 /**
290 * Filter REST API requests to add the language in the request
291 *
292 * @since 2.5
293 */
294 editors_requests_filter(addLanguageParameter);
295
296 /**
297 * Handles internals of the metabox:
298 * Language select, autocomplete input field.
299 *
300 * @since 1.5
301 *
302 * Save post after lang choice is done and redirect to the same page for refreshing all the data.
303 *
304 * @since 2.5
305 *
306 * Link post saving after refreshing the metabox.
307 *
308 * @since 3.0
309 */
310 jQuery(function ($) {
311 // Initialize current language to be able to compare if it changes.
312 initializeLanguageOldValue();
313
314 // Ajax for changing the post's language in the languages metabox
315 $('.post_lang_choice').on('change', function (event) {
316 const {
317 select,
318 dispatch,
319 subscribe
320 } = wp.data;
321 const emptyPost = isEmptyPost();
322 const {
323 addQueryArgs
324 } = wp.url;
325
326 // Initialize the confirmation dialog box.
327 const confirmationModal = initializeConfirmationModal();
328 const {
329 dialogContainer: dialog
330 } = confirmationModal;
331 let {
332 dialogResult
333 } = confirmationModal;
334 const selectedOption = event.target; // The selected option in the dropdown list.
335
336 // Specific case for empty posts.
337 // Place at the beginning because window.location change triggers automatically page reloading.
338 if (location.pathname.match(/post-new.php/gi) && emptyPost) {
339 reloadPageForEmptyPost(selectedOption.value);
340 }
341
342 // Otherwise send an ajax request to refresh the legacy metabox and set the post language with the new language.
343 // It needs a confirmation of the user before changing the language.
344 // Need to wait the ajax response before triggering the block editor post save action.
345 if ($(this).data('old-value') !== selectedOption.value && !emptyPost) {
346 dialog.dialog('open');
347 } else {
348 // Update the old language with the new one to be able to compare it in the next change.
349 // Because the page isn't reloaded in this case.
350 initializeLanguageOldValue();
351 dialogResult = Promise.resolve();
352 }
353 dialogResult.then(() => {
354 let data = {
355 // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
356 action: 'post_lang_choice',
357 lang: selectedOption.value,
358 post_type: $('#post_type').val(),
359 post_id: $('#post_ID').val(),
360 _pll_nonce: $('#_pll_nonce').val()
361 };
362
363 // Update post language in database as soon as possible.
364 // Because, in addition of the block editor save process, the legacy metabox uses a post.php process to update the language and is too late compared to the page reload.
365 $.post(ajaxurl, data, function () {
366 blockEditorSavePostAndReloadPage();
367 });
368 }, () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button.
369 );
370 function isEmptyPost() {
371 const editor = select('core/editor');
372 return !editor.getEditedPostAttribute('title')?.trim() && !editor.getEditedPostContent() && !editor.getEditedPostAttribute('excerpt')?.trim();
373 }
374
375 /**
376 * Reload the block editor page for empty posts.
377 *
378 * @param {string} lang The target language code.
379 */
380 function reloadPageForEmptyPost(lang) {
381 // Change the new_lang parameter with the new language value for reloading the page
382 // WPCS location.search is never written in the page, just used to reload page with the right value of new_lang
383 // new_lang input is controlled server side in PHP. The value come from the dropdown list of language returned and escaped server side.
384 // Notice that window.location changing triggers automatically page reloading.
385 if (-1 != location.search.indexOf('new_lang')) {
386 // use regexp non capturing group to replace new_lang parameter no matter where it is and capture other parameters which can be behind it
387 window.location.search = window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + lang + '$1$2');
388 } else {
389 window.location.search = window.location.search + (-1 != window.location.search.indexOf('?') ? '&' : '?') + 'new_lang=' + lang;
390 }
391 }
392 ;
393
394 /**
395 * Triggers block editor post save and reload the block editor page when everything is ok.
396 */
397 function blockEditorSavePostAndReloadPage() {
398 let unsubscribe = null;
399 const previousPost = select('core/editor').getCurrentPost();
400
401 // Listen if the savePost is completely done by subscribing to its events.
402 const savePostIsDone = new Promise(function (resolve, reject) {
403 unsubscribe = subscribe(function () {
404 const post = select('core/editor').getCurrentPost();
405 const {
406 id,
407 status,
408 type
409 } = post;
410 const error = select('core').getLastEntitySaveError('postType', type, id);
411 if (error) {
412 reject();
413 }
414 if (previousPost.modified !== post.modified) {
415 if (location.pathname.match(/post-new.php/gi) && status !== 'auto-draft' && id) {
416 window.history.replaceState({
417 id
418 }, 'Post ' + id, addQueryArgs('post.php', {
419 post: id,
420 action: 'edit'
421 }));
422 }
423 resolve();
424 }
425 });
426 });
427
428 // Triggers the post save.
429 dispatch('core/editor').savePost();
430
431 // Process
432 savePostIsDone.then(function () {
433 // If the post is well saved, we can reload the page
434 window.location.reload();
435 }, function () {
436 // If the post save failed
437 unsubscribe();
438 }).catch(function () {
439 // If an exception is thrown
440 unsubscribe();
441 });
442 }
443 ;
444 });
445 initMetaboxAutoComplete();
446 });
447 })();
448
449 this.polylang = __webpack_exports__;
450 /******/ })()
451 ;