Initial geladen: WP App Portal
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/******/ "use strict";
|
||||
|
||||
;// ./js/src/lib/ajax-filter/index.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds data to all ajax requests made with jQuery.
|
||||
*
|
||||
* @since 3.7
|
||||
*
|
||||
* @param {Object} data The data to add.
|
||||
* @returns {void}
|
||||
*/
|
||||
function ajaxFilter( data ) {
|
||||
if ( 'undefined' === typeof jQuery || ! data ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataStr = jQuery.param( data );
|
||||
|
||||
jQuery.ajaxPrefilter( function ( options ) {
|
||||
if ( -1 === options.url.indexOf( ajaxurl ) && -1 === ajaxurl.indexOf( options.url ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
'undefined' === typeof options.data ||
|
||||
null === options.data ||
|
||||
'string' === typeof options.data && '' === options.data.trim()
|
||||
) {
|
||||
// An empty string or null/undefined.
|
||||
options.data = dataStr;
|
||||
} else if ( 'string' === typeof options.data ) {
|
||||
// A non-empty string: can be a JSON string or a query string.
|
||||
try {
|
||||
options.data = JSON.stringify( Object.assign( JSON.parse( options.data ), data ) );
|
||||
} catch ( exception ) {
|
||||
// A non-empty non-JSON string is considered a query string.
|
||||
options.data = `${ options.data }&${ dataStr }`;
|
||||
}
|
||||
} else if ( jQuery.isPlainObject( options.data ) ) {
|
||||
// An object.
|
||||
options.data = Object.assign( options.data, data );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
;// ./js/src/admin.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
|
||||
|
||||
ajaxFilter( pll_admin?.ajax_filter );
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";function ajaxFilter(a){if("undefined"==typeof jQuery||!a)return;const t=jQuery.param(a);jQuery.ajaxPrefilter(function(e){if(-1!==e.url.indexOf(ajaxurl)||-1!==ajaxurl.indexOf(e.url))if(void 0===e.data||null===e.data||"string"==typeof e.data&&""===e.data.trim())e.data=t;else if("string"==typeof e.data)try{e.data=JSON.stringify(Object.assign(JSON.parse(e.data),a))}catch(a){e.data=`${e.data}&${t}`}else jQuery.isPlainObject(e.data)&&(e.data=Object.assign(e.data,a))})}ajaxFilter(pll_admin?.ajax_filter);
|
||||
@@ -0,0 +1,460 @@
|
||||
/******/ (() => { // webpackBootstrap
|
||||
/******/ var __webpack_modules__ = ({
|
||||
|
||||
/***/ 631
|
||||
(module) {
|
||||
|
||||
module.exports = (function() { return this["wp"]["apiFetch"]; }());
|
||||
|
||||
/***/ }
|
||||
|
||||
/******/ });
|
||||
/************************************************************************/
|
||||
/******/ // The module cache
|
||||
/******/ var __webpack_module_cache__ = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/ // Check if module is in cache
|
||||
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
||||
/******/ if (cachedModule !== undefined) {
|
||||
/******/ return cachedModule.exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = __webpack_module_cache__[moduleId] = {
|
||||
/******/ // no module.id needed
|
||||
/******/ // no module.loaded needed
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/************************************************************************/
|
||||
/******/ /* webpack/runtime/compat get default export */
|
||||
/******/ (() => {
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = (module) => {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ () => (module['default']) :
|
||||
/******/ () => (module);
|
||||
/******/ __webpack_require__.d(getter, { a: getter });
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/define property getters */
|
||||
/******/ (() => {
|
||||
/******/ // define getter functions for harmony exports
|
||||
/******/ __webpack_require__.d = (exports, definition) => {
|
||||
/******/ for(var key in definition) {
|
||||
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
||||
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
||||
/******/ }
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/ })();
|
||||
/******/
|
||||
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
||||
/******/ (() => {
|
||||
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
||||
/******/ })();
|
||||
/******/
|
||||
/************************************************************************/
|
||||
var __webpack_exports__ = {};
|
||||
// This entry needs to be wrapped in an IIFE because it needs to be in strict mode.
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
;// ./js/src/lib/confirmation-modal.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
const languagesList = jQuery('.post_lang_choice');
|
||||
|
||||
// Dialog box for alerting the user about a risky changing.
|
||||
const initializeConfirmationModal = () => {
|
||||
// We can't use underscore or lodash in this common code because it depends of the context classic or block editor.
|
||||
// Classic editor underscore is loaded, Block editor lodash is loaded.
|
||||
const {
|
||||
__
|
||||
} = wp.i18n;
|
||||
|
||||
// Create dialog container.
|
||||
const dialogContainer = jQuery('<div/>', {
|
||||
id: 'pll-dialog',
|
||||
style: 'display:none;'
|
||||
}).text(__('Are you sure you want to change the language of the current content?', 'polylang'));
|
||||
|
||||
// Put it after languages list dropdown.
|
||||
// PHPCS ignore dialogContainer is a new safe HTML code generated above.
|
||||
languagesList.after(dialogContainer); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after
|
||||
|
||||
const dialogResult = new Promise((confirm, cancel) => {
|
||||
const confirmDialog = what => {
|
||||
// phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
switch (what) {
|
||||
// phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
case 'yes':
|
||||
// Confirm the new language.
|
||||
languagesList.data('old-value', languagesList.children(':selected').first().val());
|
||||
confirm();
|
||||
break;
|
||||
case 'no':
|
||||
// Revert to the old language.
|
||||
languagesList.val(languagesList.data('old-value'));
|
||||
cancel('Cancel');
|
||||
break;
|
||||
}
|
||||
dialogContainer.dialog('close'); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
}; // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
|
||||
// Initialize dialog box in the case a language is selected but not added in the list.
|
||||
const dialogOptions = {
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
draggable: false,
|
||||
resizable: false,
|
||||
title: __('Change language', 'polylang'),
|
||||
minWidth: 600,
|
||||
maxWidth: '100%',
|
||||
open: function (event, ui) {
|
||||
// Change dialog box position for rtl language
|
||||
if (jQuery('body').hasClass('rtl')) {
|
||||
jQuery(this).parent().css({
|
||||
right: jQuery(this).parent().css('left'),
|
||||
left: 'auto'
|
||||
});
|
||||
}
|
||||
},
|
||||
close: function (event, ui) {
|
||||
// When we're closing the dialog box we need to cancel the language change as we click on Cancel button.
|
||||
confirmDialog('no');
|
||||
},
|
||||
buttons: [{
|
||||
text: __('OK', 'polylang'),
|
||||
click: function (event) {
|
||||
confirmDialog('yes');
|
||||
}
|
||||
}, {
|
||||
text: __('Cancel', 'polylang'),
|
||||
click: function (event) {
|
||||
confirmDialog('no');
|
||||
}
|
||||
}]
|
||||
};
|
||||
if (jQuery.ui.version >= '1.12.0') {
|
||||
Object.assign(dialogOptions, {
|
||||
classes: {
|
||||
'ui-dialog': 'pll-confirmation-modal'
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Object.assign(dialogOptions, {
|
||||
dialogClass: 'pll-confirmation-modal'
|
||||
}); // jQuery UI 1.11.4 - WP < 5.6
|
||||
}
|
||||
dialogContainer.dialog(dialogOptions);
|
||||
});
|
||||
return {
|
||||
dialogContainer,
|
||||
dialogResult
|
||||
};
|
||||
};
|
||||
const initializeLanguageOldValue = () => {
|
||||
// Keep the old language value to be able to compare to the new one and revert to it if necessary.
|
||||
languagesList.attr('data-old-value', languagesList.children(':selected').first().val());
|
||||
};
|
||||
;// ./js/src/lib/metabox-autocomplete.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
// Translations autocomplete input box.
|
||||
function initMetaboxAutoComplete() {
|
||||
jQuery('.tr_lang').each(function () {
|
||||
var tr_lang = jQuery(this).attr('id').substring(8);
|
||||
var td = jQuery(this).parent().parent().siblings('.pll-edit-column');
|
||||
jQuery(this).autocomplete({
|
||||
minLength: 0,
|
||||
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(),
|
||||
select: function (event, ui) {
|
||||
jQuery('#htr_lang_' + tr_lang).val(ui.item.id);
|
||||
// ui.item.link is built and come from server side and is well escaped when necessary
|
||||
td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
}
|
||||
});
|
||||
|
||||
// when the input box is emptied
|
||||
jQuery(this).on('blur', function () {
|
||||
if (!jQuery(this).val()) {
|
||||
jQuery('#htr_lang_' + tr_lang).val(0);
|
||||
// Value is retrieved from HTML already generated server side
|
||||
td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// EXTERNAL MODULE: external {"this":["wp","apiFetch"]}
|
||||
var external_this_wp_apiFetch_ = __webpack_require__(631);
|
||||
var external_this_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_this_wp_apiFetch_);
|
||||
;// ./node_modules/@wpsyntex/polylang-react-library/build/middlewares/filter-path.js
|
||||
/**
|
||||
* Filters requests for translatable entities.
|
||||
* This logic is shared across all Polylang plugins.
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param {Object} options - API fetch options object.
|
||||
* @param {Array} filteredRoutes - Array of route paths to filter.
|
||||
* @param {Function} filter - Function to filter matching routes.
|
||||
* @return {Object} Modified REST request options.
|
||||
*/
|
||||
const filterPathMiddleware = (options, filteredRoutes, filter) => {
|
||||
const cleanPath = options.path.split('?')[0].replace(/^\/+|\/+$/g, ''); // Get path without query parameters and trim '/'.
|
||||
|
||||
return Object.values(filteredRoutes).find(path => cleanPath === path) ? filter(options) : options;
|
||||
};
|
||||
/* harmony default export */ const filter_path = (filterPathMiddleware);
|
||||
;// ./node_modules/@wpsyntex/polylang-react-library/build/middlewares/editors-requests-filter.js
|
||||
/**
|
||||
* WordPress dependencies.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Internal dependencies.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Safely filters requests for translatable entities in block editor type screens.
|
||||
* Ensures that `pllFilteredRoutes` has been well defined on server side and
|
||||
* that the filtered request is a REST one.
|
||||
*
|
||||
* @param {Function} filterCallback - Function to filter API fetch options.
|
||||
*/
|
||||
const editorsRequestsFilter = filterCallback => {
|
||||
external_this_wp_apiFetch_default().use((options, next) => {
|
||||
/*
|
||||
* If options.url is defined, this is not a REST request but a direct call to post.php for legacy metaboxes.
|
||||
* If `filteredRoutes` is not defined, return early.
|
||||
*/
|
||||
if ('undefined' !== typeof options.url || 'undefined' === typeof window.pllFilteredRoutes) {
|
||||
return next(options);
|
||||
}
|
||||
return next(filter_path(options, window.pllFilteredRoutes, filterCallback));
|
||||
});
|
||||
};
|
||||
/* harmony default export */ const editors_requests_filter = (editorsRequestsFilter);
|
||||
;// ./js/src/block-editor.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the language of the currently edited post, fallback to default language if none is found.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* @return {Element.value}
|
||||
*/
|
||||
function getCurrentLanguage() {
|
||||
const lang = document.querySelector('[name=post_lang_choice]');
|
||||
if (null === lang) {
|
||||
return pllDefaultLanguage;
|
||||
}
|
||||
return lang.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds language parameter according to the current one (query string for GET, body for PUT and POST).
|
||||
*
|
||||
* @since 3.5
|
||||
*
|
||||
* @param {APIFetchOptions} options
|
||||
* @returns {APIFetchOptions}
|
||||
*/
|
||||
function addLanguageParameter(options) {
|
||||
if ('undefined' === typeof options.data || null === options.data) {
|
||||
// GET
|
||||
options.path += (options.path.indexOf('?') >= 0 ? '&lang=' : '?lang=') + getCurrentLanguage();
|
||||
} else {
|
||||
// PUT, POST
|
||||
options.data.lang = getCurrentLanguage();
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter REST API requests to add the language in the request
|
||||
*
|
||||
* @since 2.5
|
||||
*/
|
||||
editors_requests_filter(addLanguageParameter);
|
||||
|
||||
/**
|
||||
* Handles internals of the metabox:
|
||||
* Language select, autocomplete input field.
|
||||
*
|
||||
* @since 1.5
|
||||
*
|
||||
* Save post after lang choice is done and redirect to the same page for refreshing all the data.
|
||||
*
|
||||
* @since 2.5
|
||||
*
|
||||
* Link post saving after refreshing the metabox.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
jQuery(function ($) {
|
||||
// Initialize current language to be able to compare if it changes.
|
||||
initializeLanguageOldValue();
|
||||
|
||||
// Ajax for changing the post's language in the languages metabox
|
||||
$('.post_lang_choice').on('change', function (event) {
|
||||
const {
|
||||
select,
|
||||
dispatch,
|
||||
subscribe
|
||||
} = wp.data;
|
||||
const emptyPost = isEmptyPost();
|
||||
const {
|
||||
addQueryArgs
|
||||
} = wp.url;
|
||||
|
||||
// Initialize the confirmation dialog box.
|
||||
const confirmationModal = initializeConfirmationModal();
|
||||
const {
|
||||
dialogContainer: dialog
|
||||
} = confirmationModal;
|
||||
let {
|
||||
dialogResult
|
||||
} = confirmationModal;
|
||||
const selectedOption = event.target; // The selected option in the dropdown list.
|
||||
|
||||
// Specific case for empty posts.
|
||||
// Place at the beginning because window.location change triggers automatically page reloading.
|
||||
if (location.pathname.match(/post-new.php/gi) && emptyPost) {
|
||||
reloadPageForEmptyPost(selectedOption.value);
|
||||
}
|
||||
|
||||
// Otherwise send an ajax request to refresh the legacy metabox and set the post language with the new language.
|
||||
// It needs a confirmation of the user before changing the language.
|
||||
// Need to wait the ajax response before triggering the block editor post save action.
|
||||
if ($(this).data('old-value') !== selectedOption.value && !emptyPost) {
|
||||
dialog.dialog('open');
|
||||
} else {
|
||||
// Update the old language with the new one to be able to compare it in the next change.
|
||||
// Because the page isn't reloaded in this case.
|
||||
initializeLanguageOldValue();
|
||||
dialogResult = Promise.resolve();
|
||||
}
|
||||
dialogResult.then(() => {
|
||||
let data = {
|
||||
// phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
action: 'post_lang_choice',
|
||||
lang: selectedOption.value,
|
||||
post_type: $('#post_type').val(),
|
||||
post_id: $('#post_ID').val(),
|
||||
_pll_nonce: $('#_pll_nonce').val()
|
||||
};
|
||||
|
||||
// Update post language in database as soon as possible.
|
||||
// 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.
|
||||
$.post(ajaxurl, data, function () {
|
||||
blockEditorSavePostAndReloadPage();
|
||||
});
|
||||
}, () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button.
|
||||
);
|
||||
function isEmptyPost() {
|
||||
const editor = select('core/editor');
|
||||
return !editor.getEditedPostAttribute('title')?.trim() && !editor.getEditedPostContent() && !editor.getEditedPostAttribute('excerpt')?.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the block editor page for empty posts.
|
||||
*
|
||||
* @param {string} lang The target language code.
|
||||
*/
|
||||
function reloadPageForEmptyPost(lang) {
|
||||
// Change the new_lang parameter with the new language value for reloading the page
|
||||
// WPCS location.search is never written in the page, just used to reload page with the right value of new_lang
|
||||
// new_lang input is controlled server side in PHP. The value come from the dropdown list of language returned and escaped server side.
|
||||
// Notice that window.location changing triggers automatically page reloading.
|
||||
if (-1 != location.search.indexOf('new_lang')) {
|
||||
// use regexp non capturing group to replace new_lang parameter no matter where it is and capture other parameters which can be behind it
|
||||
window.location.search = window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/, 'new_lang=' + lang + '$1$2'); // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment
|
||||
} else {
|
||||
window.location.search = window.location.search + (-1 != window.location.search.indexOf('?') ? '&' : '?') + 'new_lang=' + lang; // phpcs:ignore WordPressVIPMinimum.JS.Window.location, WordPressVIPMinimum.JS.Window.VarAssignment
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
/**
|
||||
* Triggers block editor post save and reload the block editor page when everything is ok.
|
||||
*/
|
||||
function blockEditorSavePostAndReloadPage() {
|
||||
let unsubscribe = null;
|
||||
const previousPost = select('core/editor').getCurrentPost();
|
||||
|
||||
// Listen if the savePost is completely done by subscribing to its events.
|
||||
const savePostIsDone = new Promise(function (resolve, reject) {
|
||||
unsubscribe = subscribe(function () {
|
||||
const post = select('core/editor').getCurrentPost();
|
||||
const {
|
||||
id,
|
||||
status,
|
||||
type
|
||||
} = post;
|
||||
const error = select('core').getLastEntitySaveError('postType', type, id);
|
||||
if (error) {
|
||||
reject();
|
||||
}
|
||||
if (previousPost.modified !== post.modified) {
|
||||
if (location.pathname.match(/post-new.php/gi) && status !== 'auto-draft' && id) {
|
||||
window.history.replaceState({
|
||||
id
|
||||
}, 'Post ' + id, addQueryArgs('post.php', {
|
||||
post: id,
|
||||
action: 'edit'
|
||||
}));
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Triggers the post save.
|
||||
dispatch('core/editor').savePost();
|
||||
|
||||
// Process
|
||||
savePostIsDone.then(function () {
|
||||
// If the post is well saved, we can reload the page
|
||||
window.location.reload();
|
||||
}, function () {
|
||||
// If the post save failed
|
||||
unsubscribe();
|
||||
}).catch(function () {
|
||||
// If an exception is thrown
|
||||
unsubscribe();
|
||||
});
|
||||
}
|
||||
;
|
||||
});
|
||||
initMetaboxAutoComplete();
|
||||
});
|
||||
})();
|
||||
|
||||
this.polylang = __webpack_exports__;
|
||||
/******/ })()
|
||||
;
|
||||
@@ -0,0 +1 @@
|
||||
(()=>{var t={631(t){t.exports=function(){return this.wp.apiFetch}()}},e={};function n(o){var a=e[o];if(void 0!==a)return a.exports;var l=e[o]={exports:{}};return t[o](l,l.exports,n),l.exports}n.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return n.d(e,{a:e}),e},n.d=(t,e)=>{for(var o in e)n.o(e,o)&&!n.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);(()=>{"use strict";const t=jQuery(".post_lang_choice"),e=()=>{const{__:e}=wp.i18n,n=jQuery("<div/>",{id:"pll-dialog",style:"display:none;"}).text(e("Are you sure you want to change the language of the current content?","polylang"));t.after(n);const o=new Promise((o,a)=>{const l=e=>{switch(e){case"yes":t.data("old-value",t.children(":selected").first().val()),o();break;case"no":t.val(t.data("old-value")),a("Cancel")}n.dialog("close")},i={autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:e("Change language","polylang"),minWidth:600,maxWidth:"100%",open:function(t,e){jQuery("body").hasClass("rtl")&&jQuery(this).parent().css({right:jQuery(this).parent().css("left"),left:"auto"})},close:function(t,e){l("no")},buttons:[{text:e("OK","polylang"),click:function(t){l("yes")}},{text:e("Cancel","polylang"),click:function(t){l("no")}}]};jQuery.ui.version>="1.12.0"?Object.assign(i,{classes:{"ui-dialog":"pll-confirmation-modal"}}):Object.assign(i,{dialogClass:"pll-confirmation-modal"}),n.dialog(i)});return{dialogContainer:n,dialogResult:o}},o=()=>{t.attr("data-old-value",t.children(":selected").first().val())};var a=n(631),l=n.n(a);const i=(t,e,n)=>{const o=t.path.split("?")[0].replace(/^\/+|\/+$/g,"");return Object.values(e).find(t=>o===t)?n(t):t};function r(){const t=document.querySelector("[name=post_lang_choice]");return null===t?pllDefaultLanguage:t.value}(t=>{l().use((e,n)=>void 0!==e.url||void 0===window.pllFilteredRoutes?n(e):n(i(e,window.pllFilteredRoutes,t)))})(function(t){return void 0===t.data||null===t.data?t.path+=(t.path.indexOf("?")>=0?"&lang=":"?lang=")+r():t.data.lang=r(),t}),jQuery(function(t){o(),t(".post_lang_choice").on("change",function(n){const{select:a,dispatch:l,subscribe:i}=wp.data,r=function(){const t=a("core/editor");return!t.getEditedPostAttribute("title")?.trim()&&!t.getEditedPostContent()&&!t.getEditedPostAttribute("excerpt")?.trim()}(),{addQueryArgs:s}=wp.url,c=e(),{dialogContainer:u}=c;let{dialogResult:d}=c;const p=n.target;var g;location.pathname.match(/post-new.php/gi)&&r&&(g=p.value,-1!=location.search.indexOf("new_lang")?window.location.search=window.location.search.replace(/(?:new_lang=[^&]*)(&)?(.*)/,"new_lang="+g+"$1$2"):window.location.search=window.location.search+(-1!=window.location.search.indexOf("?")?"&":"?")+"new_lang="+g),t(this).data("old-value")===p.value||r?(o(),d=Promise.resolve()):u.dialog("open"),d.then(()=>{let e={action:"post_lang_choice",lang:p.value,post_type:t("#post_type").val(),post_id:t("#post_ID").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,e,function(){!function(){let t=null;const e=a("core/editor").getCurrentPost(),n=new Promise(function(n,o){t=i(function(){const t=a("core/editor").getCurrentPost(),{id:l,status:i,type:r}=t;a("core").getLastEntitySaveError("postType",r,l)&&o(),e.modified!==t.modified&&(location.pathname.match(/post-new.php/gi)&&"auto-draft"!==i&&l&&window.history.replaceState({id:l},"Post "+l,s("post.php",{post:l,action:"edit"})),n())})});l("core/editor").savePost(),n.then(function(){window.location.reload()},function(){t()}).catch(function(){t()})}()})},()=>{})}),jQuery(".tr_lang").each(function(){var t=jQuery(this).attr("id").substring(8),e=jQuery(this).parent().parent().siblings(".pll-edit-column");jQuery(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_posts_not_translated&post_language="+jQuery(".post_lang_choice").val()+"&translation_language="+t+"&post_type="+jQuery("#post_type").val()+"&_pll_nonce="+jQuery("#_pll_nonce").val(),select:function(n,o){jQuery("#htr_lang_"+t).val(o.item.id),e.html(o.item.link)}}),jQuery(this).on("blur",function(){jQuery(this).val()||(jQuery("#htr_lang_"+t).val(0),e.html(e.siblings(".hidden").children().clone()))})})})})(),this.polylang={}})();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,466 @@
|
||||
/******/ "use strict";
|
||||
|
||||
;// ./js/src/lib/confirmation-modal.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
const languagesList = jQuery( '.post_lang_choice' );
|
||||
|
||||
// Dialog box for alerting the user about a risky changing.
|
||||
const initializeConfirmationModal = () => {
|
||||
// We can't use underscore or lodash in this common code because it depends of the context classic or block editor.
|
||||
// Classic editor underscore is loaded, Block editor lodash is loaded.
|
||||
const { __ } = wp.i18n;
|
||||
|
||||
// Create dialog container.
|
||||
const dialogContainer = jQuery(
|
||||
'<div/>',
|
||||
{
|
||||
id: 'pll-dialog',
|
||||
style: 'display:none;'
|
||||
}
|
||||
).text( __( 'Are you sure you want to change the language of the current content?', 'polylang' ) );
|
||||
|
||||
// Put it after languages list dropdown.
|
||||
// PHPCS ignore dialogContainer is a new safe HTML code generated above.
|
||||
languagesList.after( dialogContainer ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after
|
||||
|
||||
const dialogResult = new Promise(
|
||||
( confirm, cancel ) => {
|
||||
const confirmDialog = ( what ) => { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
switch ( what ) { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
case 'yes':
|
||||
// Confirm the new language.
|
||||
languagesList.data( 'old-value', languagesList.children( ':selected' ).first().val() );
|
||||
confirm();
|
||||
break;
|
||||
case 'no':
|
||||
// Revert to the old language.
|
||||
languagesList.val( languagesList.data( 'old-value' ) );
|
||||
cancel( 'Cancel' );
|
||||
break;
|
||||
}
|
||||
dialogContainer.dialog( 'close' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
} // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
|
||||
|
||||
// Initialize dialog box in the case a language is selected but not added in the list.
|
||||
const dialogOptions = {
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
draggable: false,
|
||||
resizable: false,
|
||||
title: __( 'Change language', 'polylang' ),
|
||||
minWidth: 600,
|
||||
maxWidth: '100%',
|
||||
open: function ( event, ui ) {
|
||||
// Change dialog box position for rtl language
|
||||
if ( jQuery( 'body' ).hasClass( 'rtl' ) ) {
|
||||
jQuery( this ).parent().css(
|
||||
{
|
||||
right: jQuery( this ).parent().css( 'left' ),
|
||||
left: 'auto'
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
close: function ( event, ui ) {
|
||||
// When we're closing the dialog box we need to cancel the language change as we click on Cancel button.
|
||||
confirmDialog( 'no' );
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: __( 'OK', 'polylang' ),
|
||||
click: function ( event ) {
|
||||
confirmDialog( 'yes' );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: __( 'Cancel', 'polylang' ),
|
||||
click: function ( event ) {
|
||||
confirmDialog( 'no' );
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
if ( jQuery.ui.version >= '1.12.0' ) {
|
||||
Object.assign( dialogOptions, { classes: { 'ui-dialog': 'pll-confirmation-modal' } } );
|
||||
} else {
|
||||
Object.assign( dialogOptions, { dialogClass: 'pll-confirmation-modal' } ); // jQuery UI 1.11.4 - WP < 5.6
|
||||
}
|
||||
|
||||
dialogContainer.dialog( dialogOptions );
|
||||
}
|
||||
);
|
||||
return { dialogContainer, dialogResult };
|
||||
}
|
||||
|
||||
const initializeLanguageOldValue = () => {
|
||||
// Keep the old language value to be able to compare to the new one and revert to it if necessary.
|
||||
languagesList.attr( 'data-old-value', languagesList.children( ':selected' ).first().val() );
|
||||
};
|
||||
|
||||
;// ./js/src/lib/metabox-autocomplete.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
// Translations autocomplete input box.
|
||||
function initMetaboxAutoComplete() {
|
||||
jQuery('.tr_lang').each(
|
||||
function () {
|
||||
var tr_lang = jQuery(this).attr('id').substring(8);
|
||||
var td = jQuery(this).parent().parent().siblings('.pll-edit-column');
|
||||
|
||||
jQuery(this).autocomplete(
|
||||
{
|
||||
minLength: 0,
|
||||
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(),
|
||||
select: function (event, ui) {
|
||||
jQuery('#htr_lang_' + tr_lang).val(ui.item.id);
|
||||
// ui.item.link is built and come from server side and is well escaped when necessary
|
||||
td.html(ui.item.link); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// when the input box is emptied
|
||||
jQuery(this).on(
|
||||
'blur',
|
||||
function () {
|
||||
if ( ! jQuery(this).val() ) {
|
||||
jQuery('#htr_lang_' + tr_lang).val(0);
|
||||
// Value is retrieved from HTML already generated server side
|
||||
td.html(td.siblings('.hidden').children().clone()); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
;// ./js/src/classic-editor.js
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tag suggest in metabox
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
$.ajaxPrefilter(
|
||||
function ( options, originalOptions, jqXHR ) {
|
||||
var lang = $( '.post_lang_choice' ).val();
|
||||
if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && lang ) {
|
||||
options.data = 'lang=' + lang + '&' + options.data;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// overrides tagBox.get
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
// overrides function to add the language
|
||||
tagBox.get = function ( id ) {
|
||||
var tax = id.substr( id.indexOf( '-' ) + 1 );
|
||||
|
||||
// add the language in the $_POST variable
|
||||
var data = {
|
||||
action: 'get-tagcloud',
|
||||
lang: $( '.post_lang_choice' ).val(),
|
||||
tax: tax
|
||||
}
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( r, stat ) {
|
||||
if ( 0 == r || 'success' != stat ) {
|
||||
r = wpAjax.broken;
|
||||
}
|
||||
|
||||
// @see code from WordPress core https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/js/tags-box.js#L291
|
||||
// @see wp_generate_tag_cloud function which generate the escaped HTML https://github.com/WordPress/WordPress/blob/a02b5cc2a8eecb8e076fbb7cf4de7bd2ec8a8eb1/wp-includes/category-template.php#L966-L975
|
||||
r = $( '<div />' ).addClass( 'the-tagcloud' ).attr( 'id', 'tagcloud-' + tax ).html( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
$( 'a', r ).on(
|
||||
'click',
|
||||
function () {
|
||||
tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this );
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
var tagCloud = $( '#tagcloud-' + tax );
|
||||
// add an if else condition to allow modifying the tags outputted when switching the language
|
||||
var v = tagCloud.css( 'display' );
|
||||
if ( v ) {
|
||||
// See the comment above when r variable is created.
|
||||
$( '#tagcloud-' + tax ).replaceWith( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
$( '#tagcloud-' + tax ).css( 'display', v );
|
||||
}
|
||||
else {
|
||||
// See the comment above when r variable is created.
|
||||
$( '#' + id ).after( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
// collect taxonomies - code partly copied from WordPress
|
||||
var taxonomies = new Array();
|
||||
$( '.categorydiv' ).each(
|
||||
function () {
|
||||
var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy;
|
||||
|
||||
taxonomyParts = this_id.split( '-' );
|
||||
taxonomyParts.shift();
|
||||
taxonomy = taxonomyParts.join( '-' );
|
||||
taxonomies.push( taxonomy ); // store the taxonomy for future use
|
||||
|
||||
// add our hidden field in the new category form - for each hierarchical taxonomy
|
||||
// to set the language when creating a new category
|
||||
// html code inserted come from html code itself.
|
||||
$( '#' + taxonomy + '-add-submit' ).before( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.before
|
||||
$( '<input />' ).attr( 'type', 'hidden' )
|
||||
.attr( 'id', taxonomy + '-lang' )
|
||||
.attr( 'name', 'term_lang_choice' )
|
||||
.attr( 'value', $( '.post_lang_choice' ).val() )
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Initialize current language to be able to compare if it changes.
|
||||
initializeLanguageOldValue();
|
||||
|
||||
// ajax for changing the post's language in the languages metabox
|
||||
$( '.post_lang_choice' ).on(
|
||||
'change',
|
||||
function ( event ) {
|
||||
// Initialize the confirmation dialog box.
|
||||
const confirmationModal = initializeConfirmationModal();
|
||||
const { dialogContainer: dialog } = confirmationModal;
|
||||
let { dialogResult } = confirmationModal;
|
||||
// The selected option in the dropdown list.
|
||||
const selectedOption = event.target;
|
||||
|
||||
if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! isEmptyPost() ) {
|
||||
dialog.dialog( 'open' );
|
||||
} else {
|
||||
dialogResult = Promise.resolve();
|
||||
}
|
||||
|
||||
dialogResult.then(
|
||||
() => {
|
||||
var data = {
|
||||
action: 'post_lang_choice',
|
||||
lang: selectedOption.value,
|
||||
post_type: $( '#post_type' ).val(),
|
||||
taxonomies: taxonomies,
|
||||
post_id: $( '#post_ID' ).val(),
|
||||
_pll_nonce: $( '#_pll_nonce' ).val()
|
||||
}
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
// Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
|
||||
var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
switch ( this.what ) {
|
||||
case 'translations': // translations fields
|
||||
// Data is built and come from server side and is well escaped when necessary
|
||||
$( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
initMetaboxAutoComplete();
|
||||
break;
|
||||
case 'taxonomy': // categories metabox for posts
|
||||
var tax = this.data;
|
||||
// @see wp_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L175
|
||||
// @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/class-walker-category-checklist.php#L89-L111
|
||||
$( '#' + tax + 'checklist' ).html( this.supplemental.all ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
// @see wp_popular_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L236
|
||||
$( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
// @see wp_dropdown_categories https://github.com/WordPress/WordPress/blob/5.5.1/wp-includes/category-template.php#L336
|
||||
// which is called by PLL_Admin_Classic_Editor::post_lang_choice to generate supplemental.dropdown
|
||||
$( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
$( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field
|
||||
break;
|
||||
case 'pages': // parent dropdown list for pages
|
||||
// @see wp_dropdown_pages https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/post-template.php#L1186-L1208
|
||||
// @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/class-walker-page-dropdown.php#L88
|
||||
$( '#parent_id' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
break;
|
||||
case 'flag': // flag in front of the select dropdown
|
||||
// Data is built and come from server side and is well escaped when necessary
|
||||
$( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
break;
|
||||
case 'permalink': // Sample permalink
|
||||
var div = $( '#edit-slug-box' );
|
||||
if ( '-1' != this.data && div.children().length ) {
|
||||
// @see get_sample_permalink_html https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/post.php#L1425-L1454
|
||||
div.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Creates an event once the language has been successfully changed.
|
||||
const onPostLangChoice = new CustomEvent(
|
||||
"onPostLangChoice",
|
||||
{
|
||||
detail: {
|
||||
lang: JSON.parse( selectedOption.options[selectedOption.options.selectedIndex].getAttribute( 'data-lang' ) )
|
||||
},
|
||||
}
|
||||
);
|
||||
document.dispatchEvent( onPostLangChoice );
|
||||
}
|
||||
)
|
||||
},
|
||||
() => {} // Do nothing when promise is rejected by clicking the Cancel dialog button.
|
||||
);
|
||||
|
||||
function isEmptyPost() {
|
||||
const title = $( 'input#title' ).val();
|
||||
const content = $( 'textarea#content' ).val();
|
||||
const excerpt = $( 'textarea#excerpt' ).val();
|
||||
|
||||
return ! title && ! content && ! excerpt;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to `onPostLangChoice` to perform actions after the language has been changed.
|
||||
document.addEventListener(
|
||||
'onPostLangChoice',
|
||||
( e ) => {
|
||||
// Update the old language with the new one to be able to compare it in the next changing.
|
||||
initializeLanguageOldValue();
|
||||
|
||||
// Modifies the language in the tag cloud.
|
||||
$( '.tagcloud-link' ).each(
|
||||
function () {
|
||||
var id = $( this ).attr( 'id' );
|
||||
tagBox.get( id );
|
||||
}
|
||||
);
|
||||
|
||||
// Modifies the text direction.
|
||||
let dir = e.detail.lang.is_rtl ? 'rtl' : 'ltr'
|
||||
$( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
|
||||
$( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', e.detail.lang.locale ).attr( 'dir', dir );
|
||||
$( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
|
||||
|
||||
// Refresh media libraries.
|
||||
pll.media.resetAllAttachmentsCollections();
|
||||
}
|
||||
);
|
||||
|
||||
initMetaboxAutoComplete();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
*
|
||||
* @namespace pll
|
||||
*/
|
||||
var pll = window.pll || {};
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
*
|
||||
* @namespace pll.media
|
||||
*/
|
||||
_.extend( pll, { media: {} } );
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
*
|
||||
* @alias pll.media
|
||||
* @memberOf pll
|
||||
* @namespace
|
||||
*/
|
||||
var media = _.extend(
|
||||
pll.media, /** @lends pll.media.prototype */
|
||||
{
|
||||
/**
|
||||
* TODO: Find a way to delete references to Attachments collections that are not used anywhere else.
|
||||
*
|
||||
* @type {wp.media.model.Attachments}
|
||||
*/
|
||||
attachmentsCollections : [],
|
||||
|
||||
/**
|
||||
* Imitates { @see wp.media.query } but log all Attachments collections created.
|
||||
*
|
||||
* @param {Object} [props]
|
||||
* @return {wp.media.model.Attachments}
|
||||
*/
|
||||
query: function ( props ) {
|
||||
var attachments = pll.media.query.delegate( props );
|
||||
|
||||
pll.media.attachmentsCollections.push( attachments );
|
||||
|
||||
return attachments;
|
||||
},
|
||||
|
||||
resetAllAttachmentsCollections: function () {
|
||||
this.attachmentsCollections.forEach(
|
||||
function ( attachmentsCollection ) {
|
||||
/**
|
||||
* First reset the { @see wp.media.model.Attachments } collection.
|
||||
* Then, if it is mirroring a { @see wp.media.model.Query } collection,
|
||||
* refresh this one too, so it will fetch new data from the server,
|
||||
* and then the wp.media.model.Attachments collection will synchronize with the new data.
|
||||
*/
|
||||
attachmentsCollection.reset();
|
||||
if (attachmentsCollection.mirroring) {
|
||||
attachmentsCollection.mirroring._hasMore = true;
|
||||
attachmentsCollection.mirroring.reset();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.media ) {
|
||||
|
||||
/**
|
||||
* @since 3.0
|
||||
*
|
||||
* @memberOf pll.media
|
||||
*/
|
||||
media.query = _.extend(
|
||||
media.query, /** @lends pll.media.query prototype */
|
||||
{
|
||||
/**
|
||||
* @type Function References WordPress { @see wp.media.query } constructor
|
||||
*/
|
||||
delegate: wp.media.query
|
||||
}
|
||||
)
|
||||
|
||||
// Substitute WordPress media query shortcut with our decorated function.
|
||||
wp.media.query = media.query
|
||||
|
||||
}
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
var addLanguageForm = $( '.languages-step' ); // Form element.
|
||||
var languageFields = $( '#language-fields' ); // Element where to append hidden fields for creating language.
|
||||
var languagesTable = $( '#languages' ); // Table element contains languages list to create.
|
||||
var languagesListTable = $( '#languages tbody' ); // Table rows with languages list to create.
|
||||
var definedLanguagesListTable = $( '#defined-languages tbody' ); // Table rows with already defined languages list.
|
||||
var languagesList = $( '#lang_list' ); // Select form element with predefined languages without already created languages.
|
||||
var nextStepButton = $( '[name="save_step"]' ); // The button for continuing to the next step.
|
||||
var messagesContainer = $( '#messages' ); // Element where to display error messages.
|
||||
var languagesMap = new Map(); // Languages map object for managing the languages to create.
|
||||
var dialog = $( '#dialog' ); // Dialog box for alerting the language selected has not been added to the list.
|
||||
|
||||
/**
|
||||
* Add a language in the list to create it in Polylang settings
|
||||
*
|
||||
* @param {object} language The language object
|
||||
*/
|
||||
function addLanguage( language ) {
|
||||
// language properties come from the select dropdown which is built server side and well escaped.
|
||||
// see template view-wizard-step-languages.php.
|
||||
var languageValueHtml = $( '<td />' ).text( language.text ).prepend( language.flagUrl ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
var languageTrashIconHtml = $( '<td />' )
|
||||
.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
$( '<span />' )
|
||||
.addClass( 'dashicons dashicons-trash' )
|
||||
.attr( 'data-language', language.locale )
|
||||
.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
$( '<span />' )
|
||||
.addClass( 'screen-reader-text' )
|
||||
.text( pll_wizard_params.i18n_remove_language_icon )
|
||||
)
|
||||
);
|
||||
// see the comment and the hardcoded code above. languageTrashIconHtml and languageValueHtml are safe.
|
||||
var languageLineHtml = $( '<tr />' ).prepend( languageTrashIconHtml ).prepend( languageValueHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
var languageFieldHtml = $( '<input />' ).attr(
|
||||
{
|
||||
type: 'hidden',
|
||||
name: 'languages[]'
|
||||
}
|
||||
).val( language.locale );
|
||||
|
||||
languagesList.val( '' );
|
||||
languagesList.selectmenu( 'refresh' ); // Refresh jQuery selectmenu widget after changing the value.
|
||||
|
||||
languagesMap.set( language.locale, language );
|
||||
|
||||
// see above how languageLineHtml is built.
|
||||
languagesListTable.append( languageLineHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
// Bind click event on trash icon.
|
||||
languagesListTable.on(
|
||||
'click',
|
||||
'span[data-language=' + language.locale + ']',
|
||||
function ( event ) {
|
||||
event.preventDefault();
|
||||
// Remove line in languages table.
|
||||
$( this ).parents( 'tr' ).remove();
|
||||
// Remove input field.
|
||||
var languageField = languageFields.children( 'input[value=' + $( this ).data( 'language' ) + ']' ).remove();
|
||||
// If there is no more languages hide languages table.
|
||||
if ( languagesListTable.children().length <= 0 ) {
|
||||
languagesTable.hide();
|
||||
}
|
||||
// Remove language from the Map.
|
||||
languagesMap.delete( $( this ).data( 'language' ) );
|
||||
// Hide error message.
|
||||
hideError();
|
||||
}
|
||||
);
|
||||
// see above how languageFieldHtml is built.
|
||||
// Add hidden input field for posting the form.
|
||||
languageFields.append( languageFieldHtml ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display an error message
|
||||
*
|
||||
* @param {string} message The message to display
|
||||
*/
|
||||
function showError( message ) {
|
||||
messagesContainer.empty();
|
||||
// html is hardcoded and use of jQuery text method which is safe to add message value.
|
||||
// In addition message is i18n value which is initialized server side in PLL_Wizard::add_step_languages and correctly escaped.
|
||||
messagesContainer.prepend( $( '<p/>' ).addClass( 'error' ).text( message ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide all error messages and fields in error
|
||||
*/
|
||||
function hideError() {
|
||||
messagesContainer.empty();
|
||||
addLanguageForm.find( '.error' ).removeClass( 'error field-in-error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Style the field to indicate where the error is
|
||||
*
|
||||
* @param {object} field The jQuery element which is in error
|
||||
*/
|
||||
function showFieldInError( field ) {
|
||||
field.addClass( 'error field-in-error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus on a specific element
|
||||
*
|
||||
* @param {object} field The jQuery element which will be focused
|
||||
*/
|
||||
function focusOnField( field ) {
|
||||
field.trigger( 'focus' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a specific button
|
||||
*
|
||||
* @param {object} button
|
||||
*/
|
||||
function disableButton( button ){
|
||||
button.prop( 'disabled', true );
|
||||
// Because the button is disabled we need to add the value of the button to ensure it will pass in the request.
|
||||
addLanguageForm.append( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
$( '<input />' ).prop(
|
||||
{
|
||||
type: 'hidden',
|
||||
name: button.prop( 'name' ),
|
||||
value: button.prop( 'value' )
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove error when a new selection is done in languages list.
|
||||
*/
|
||||
languagesList.on(
|
||||
'selectmenuchange',
|
||||
function () {
|
||||
hideError();;
|
||||
}
|
||||
);
|
||||
/**
|
||||
* Bind click event on "Add language" button
|
||||
*/
|
||||
$( '#add-language' ).on(
|
||||
'click',
|
||||
function ( event ) {
|
||||
hideError();
|
||||
var selectedOption = event.currentTarget.form.lang_list.options[event.currentTarget.form.lang_list.selectedIndex];
|
||||
if ( '' !== selectedOption.value && ! languagesMap.has( selectedOption.value ) ) {
|
||||
addLanguage(
|
||||
{
|
||||
locale: selectedOption.value,
|
||||
text: selectedOption.innerText,
|
||||
name: $( selectedOption ).data( 'language-name' ),
|
||||
flagUrl: $( selectedOption ).data( 'flag-html' )
|
||||
}
|
||||
);
|
||||
// Show table of languages.
|
||||
languagesTable.show();
|
||||
// Put back the focus on the select language field after clicking on "Add language button".
|
||||
focusOnField( $( '#lang_list-button' ) );
|
||||
} else {
|
||||
var message = pll_wizard_params.i18n_no_language_selected;
|
||||
if ( languagesMap.has( selectedOption.value ) ) {
|
||||
message = pll_wizard_params.i18n_language_already_added;
|
||||
}
|
||||
showError( message );
|
||||
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
|
||||
focusOnField( $( '#lang_list-button' ) );
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Bind submit event on "add_lang" form
|
||||
*/
|
||||
addLanguageForm.on(
|
||||
'submit',
|
||||
function ( event ) {
|
||||
// Verify if there is at least one language.
|
||||
var isLanguagesAlreadyDefined = definedLanguagesListTable.children().length > 0;
|
||||
var selectedLanguage = $( '#lang_list' ).val();
|
||||
if ( languagesMap.size <= 0 && ! isLanguagesAlreadyDefined ) {
|
||||
if ( '' === selectedLanguage ) {
|
||||
showError( pll_wizard_params.i18n_no_language_added );
|
||||
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
|
||||
focusOnField( $( '#lang_list-button' ) );
|
||||
} else {
|
||||
showError( pll_wizard_params.i18n_add_language_needed );
|
||||
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
|
||||
focusOnField( $( '#add-language' ) ); // Put the focus on the "Add language" button.
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Verify if the language has been added in the list otherwise display a dialog box to confirm what to do.
|
||||
if ( '' !== selectedLanguage ) {
|
||||
// Verify we don't add a duplicate language before opening the dialog box otherwise display an error message.
|
||||
if ( ! languagesMap.has( selectedLanguage ) ) {
|
||||
dialog.dialog( 'open' );
|
||||
} else {
|
||||
showError( pll_wizard_params.i18n_language_already_added );
|
||||
showFieldInError( languagesList.next( 'span.ui-selectmenu-button' ) );
|
||||
focusOnField( $( '#lang_list-button' ) );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
disableButton( nextStepButton );
|
||||
}
|
||||
);
|
||||
|
||||
// Is there an error return by PHP ?
|
||||
var searchParams = new URLSearchParams( document.location.search );
|
||||
if ( searchParams.has( 'activate_error' ) ) {
|
||||
// If the error code exists, display it.
|
||||
if ( undefined !== pll_wizard_params[ searchParams.get( 'activate_error' ) ] ) {
|
||||
showError( pll_wizard_params[ searchParams.get( 'activate_error' ) ] );
|
||||
}
|
||||
}
|
||||
|
||||
function confirmDialog( what ) {
|
||||
switch ( what ) {
|
||||
case 'yes':
|
||||
var selectedOption = $( '#lang_list' ).children( ':selected' );
|
||||
addLanguage(
|
||||
{
|
||||
locale: selectedOption[0].value,
|
||||
text: selectedOption[0].innerText,
|
||||
name: $( selectedOption ).data( 'language-name' ),
|
||||
flagUrl: $( selectedOption ).data( 'flag-html' )
|
||||
}
|
||||
);
|
||||
break;
|
||||
case 'no':
|
||||
// Empty select form field and submit again the form.
|
||||
languagesList.val( '' );
|
||||
break;
|
||||
case 'ignore':
|
||||
}
|
||||
dialog.dialog( 'close' );
|
||||
if ( 'ignore' === what ) {
|
||||
focusOnField( $( '#lang_list-button' ) );
|
||||
} else {
|
||||
addLanguageForm.submit();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize dialog box in the case a language is selected but not added in the list.
|
||||
dialog.dialog(
|
||||
{
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
draggable: false,
|
||||
resizable: false,
|
||||
title: pll_wizard_params.i18n_dialog_title,
|
||||
minWidth: 600,
|
||||
maxWidth: '100%',
|
||||
open: function ( event, ui ) {
|
||||
// Change dialog box position for rtl language
|
||||
if ( $( 'body' ).hasClass( 'rtl' ) ) {
|
||||
$( this ).parent().css(
|
||||
{
|
||||
right: $( this ).parent().css( 'left' ),
|
||||
left: 'auto'
|
||||
}
|
||||
);
|
||||
}
|
||||
// Display language name and flag information in dialog box.
|
||||
$( this ).find( '#dialog-language' ).text( $( '#lang_list' ).children( ':selected' ).first().text() );
|
||||
// language properties come from the select dropdown #lang_list which is built server side and well escaped.
|
||||
// see template view-wizard-step-languages.php.
|
||||
$( this ).find( '#dialog-language-flag' ).empty().prepend( $( '#lang_list' ).children( ':selected' ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: pll_wizard_params.i18n_dialog_yes_button,
|
||||
click: function ( event ) {
|
||||
confirmDialog( 'yes' );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: pll_wizard_params.i18n_dialog_no_button,
|
||||
click: function ( event ) {
|
||||
confirmDialog( 'no' );
|
||||
}
|
||||
},
|
||||
{
|
||||
text: pll_wizard_params.i18n_dialog_ignore_button,
|
||||
click: function ( event ) {
|
||||
confirmDialog( 'ignore' );
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
jQuery(function(a){var e=a(".languages-step"),n=a("#language-fields"),t=a("#languages"),l=a("#languages tbody"),i=a("#defined-languages tbody"),r=a("#lang_list"),d=a('[name="save_step"]'),s=a("#messages"),o=new Map,g=a("#dialog");function u(e){var i=a("<td />").text(e.text).prepend(e.flagUrl),d=a("<td />").append(a("<span />").addClass("dashicons dashicons-trash").attr("data-language",e.locale).append(a("<span />").addClass("screen-reader-text").text(pll_wizard_params.i18n_remove_language_icon))),s=a("<tr />").prepend(d).prepend(i),g=a("<input />").attr({type:"hidden",name:"languages[]"}).val(e.locale);r.val(""),r.selectmenu("refresh"),o.set(e.locale,e),l.append(s),l.on("click","span[data-language="+e.locale+"]",function(e){e.preventDefault(),a(this).parents("tr").remove();n.children("input[value="+a(this).data("language")+"]").remove();l.children().length<=0&&t.hide(),o.delete(a(this).data("language")),c()}),n.append(g)}function p(e){s.empty(),s.prepend(a("<p/>").addClass("error").text(e))}function c(){s.empty(),e.find(".error").removeClass("error field-in-error")}function _(a){a.addClass("error field-in-error")}function m(a){a.trigger("focus")}r.on("selectmenuchange",function(){c()}),a("#add-language").on("click",function(e){c();var n=e.currentTarget.form.lang_list.options[e.currentTarget.form.lang_list.selectedIndex];if(""===n.value||o.has(n.value)){var l=pll_wizard_params.i18n_no_language_selected;o.has(n.value)&&(l=pll_wizard_params.i18n_language_already_added),p(l),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))}else u({locale:n.value,text:n.innerText,name:a(n).data("language-name"),flagUrl:a(n).data("flag-html")}),t.show(),m(a("#lang_list-button"))}),e.on("submit",function(n){var t,l=i.children().length>0,s=a("#lang_list").val();return o.size<=0&&!l?(""===s?(p(pll_wizard_params.i18n_no_language_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):(p(pll_wizard_params.i18n_add_language_needed),_(r.next("span.ui-selectmenu-button")),m(a("#add-language"))),!1):""!==s?(o.has(s)?(p(pll_wizard_params.i18n_language_already_added),_(r.next("span.ui-selectmenu-button")),m(a("#lang_list-button"))):g.dialog("open"),!1):((t=d).prop("disabled",!0),void e.append(a("<input />").prop({type:"hidden",name:t.prop("name"),value:t.prop("value")})))});var f=new URLSearchParams(document.location.search);function h(n){switch(n){case"yes":var t=a("#lang_list").children(":selected");u({locale:t[0].value,text:t[0].innerText,name:a(t).data("language-name"),flagUrl:a(t).data("flag-html")});break;case"no":r.val("")}g.dialog("close"),"ignore"===n?m(a("#lang_list-button")):e.submit()}f.has("activate_error")&&void 0!==pll_wizard_params[f.get("activate_error")]&&p(pll_wizard_params[f.get("activate_error")]),g.dialog({autoOpen:!1,modal:!0,draggable:!1,resizable:!1,title:pll_wizard_params.i18n_dialog_title,minWidth:600,maxWidth:"100%",open:function(e,n){a("body").hasClass("rtl")&&a(this).parent().css({right:a(this).parent().css("left"),left:"auto"}),a(this).find("#dialog-language").text(a("#lang_list").children(":selected").first().text()),a(this).find("#dialog-language-flag").empty().prepend(a("#lang_list").children(":selected").data("flag-html"))},buttons:[{text:pll_wizard_params.i18n_dialog_yes_button,click:function(a){h("yes")}},{text:pll_wizard_params.i18n_dialog_no_button,click:function(a){h("no")}},{text:pll_wizard_params.i18n_dialog_ignore_button,click:function(a){h("ignore")}}]})});
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
/**
|
||||
* Media list table
|
||||
* When clicking on attach link, filters find post list per media language
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
$.ajaxPrefilter(
|
||||
function ( options, originalOptions, jqXHR ) {
|
||||
if ( 'string' === typeof options.data && -1 !== options.data.indexOf( 'action=find_posts' ) ) {
|
||||
options.data = 'pll_post_id=' + $( '#affected' ).val() + '&' + options.data;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(a){a.ajaxPrefilter(function(t,d,f){"string"==typeof t.data&&-1!==t.data.indexOf("action=find_posts")&&(t.data="pll_post_id="+a("#affected").val()+"&"+t.data)})});
|
||||
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Handles the options in the language switcher nav menu metabox.
|
||||
*
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
const pllNavMenu = {
|
||||
/**
|
||||
* The element wrapping the menu elements.
|
||||
*
|
||||
* @member {HTMLElement|null}
|
||||
*/
|
||||
wrapper: null,
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
init: () => {
|
||||
if ( document.readyState !== 'loading' ) {
|
||||
pllNavMenu.ready();
|
||||
} else {
|
||||
document.addEventListener( 'DOMContentLoaded', pllNavMenu.ready );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the DOM is ready. Attaches the events to the wrapper.
|
||||
*/
|
||||
ready: () => {
|
||||
pllNavMenu.wrapper = document.getElementById( 'menu-to-edit' );
|
||||
|
||||
if ( ! pllNavMenu.wrapper ) {
|
||||
return;
|
||||
}
|
||||
|
||||
pllNavMenu.wrapper.addEventListener( 'click', pllNavMenu.printMetabox );
|
||||
pllNavMenu.wrapper.addEventListener( 'change', pllNavMenu.ensureContent );
|
||||
pllNavMenu.wrapper.addEventListener( 'change', pllNavMenu.showHideRows );
|
||||
},
|
||||
|
||||
printMetabox: {
|
||||
/**
|
||||
* Event callback that prints our checkboxes in the language switcher.
|
||||
*
|
||||
* @param {Event} event The event.
|
||||
*/
|
||||
handleEvent: ( event ) => {
|
||||
if ( ! event.target.classList.contains( 'item-edit' ) ) {
|
||||
// Not clicking on a Edit arrow button.
|
||||
return;
|
||||
}
|
||||
|
||||
const metabox = event.target.closest( '.menu-item' ).querySelector( '.menu-item-settings' );
|
||||
|
||||
if ( ! metabox?.id ) {
|
||||
// Should not happen.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! metabox.querySelectorAll( 'input[value="#pll_switcher"][type=text]' ).length ) {
|
||||
// Not our metabox, or already replaced.
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove default fields we don't need.
|
||||
[ ...metabox.children ].forEach( ( el ) => {
|
||||
if ( 'P' === el.nodeName && ! el.classList.contains( 'field-move' ) ) {
|
||||
el.remove();
|
||||
}
|
||||
} );
|
||||
|
||||
const t = pllNavMenu.printMetabox;
|
||||
const itemId = Number( metabox.id.replace( 'menu-item-settings-', '' ) );
|
||||
|
||||
metabox.append( t.createHiddenInput( 'title', itemId, pll_data.title ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
metabox.append( t.createHiddenInput( 'url', itemId, '#pll_switcher' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
metabox.append( t.createHiddenInput( 'pll-detect', itemId, 1 ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
|
||||
const ids = Array( 'hide_if_no_translation', 'hide_current', 'force_home', 'show_flags', 'show_names', 'dropdown' ); // Reverse order.
|
||||
const isValDefined = typeof( pll_data.val[ itemId ] ) !== 'undefined';
|
||||
|
||||
ids.forEach( ( optionName ) => {
|
||||
// Create the checkbox's wrapper.
|
||||
const inputWrapper = t.createElement( 'p', { class: 'description' } );
|
||||
|
||||
if ( 'hide_current' === optionName && isValDefined && 1 === pll_data.val[ itemId ].dropdown ) {
|
||||
// Hide the `hide_current` checkbox if `dropdown` is checked.
|
||||
inputWrapper.classList.add( 'hidden' );
|
||||
}
|
||||
|
||||
metabox.prepend( inputWrapper ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
|
||||
// Create the checkbox's label.
|
||||
const inputId = `edit-menu-item-${ optionName }-${ itemId }`;
|
||||
const label = t.createElement( 'label', { 'for': inputId } );
|
||||
label.innerText = ` ${ pll_data.strings[ optionName ] }`;
|
||||
|
||||
inputWrapper.append( label ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
|
||||
// Create the checkbox.
|
||||
const cb = t.createElement( 'input', {
|
||||
type: 'checkbox',
|
||||
id: inputId,
|
||||
name: `menu-item-${ optionName }[${ itemId }]`,
|
||||
value: 1,
|
||||
} );
|
||||
|
||||
if ( ( isValDefined && 1 === pll_data.val[ itemId ][ optionName ] ) || ( ! isValDefined && 'show_names' === optionName ) ) { // `show_names` as default value.
|
||||
cb.checked = true;
|
||||
}
|
||||
|
||||
label.prepend( cb ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates and returns a `<input type=hidden"/>` element.
|
||||
*
|
||||
* @param {string} id An identifier for this input. It will be part of the final `id` attribute.
|
||||
* @param {number} itemId The ID of the menu element (post ID).
|
||||
* @param {string|number} value The input's value.
|
||||
* @return {HTMLElement} The input element.
|
||||
*/
|
||||
createHiddenInput: ( id, itemId, value ) => {
|
||||
return pllNavMenu.printMetabox.createElement( 'input', {
|
||||
type: 'hidden',
|
||||
id: `edit-menu-item-${ id }-${ itemId }`,
|
||||
name: `menu-item-${ id }[${ itemId }]`,
|
||||
value: value,
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates and returns an element.
|
||||
*
|
||||
* @param {string} type Element's type.
|
||||
* @param {Object} atts Element's attributes.
|
||||
* @return {HTMLElement} The element.
|
||||
*/
|
||||
createElement: ( type, atts ) => {
|
||||
const el = document.createElement( type );
|
||||
for ( const [ key, value ] of Object.entries( atts ) ) {
|
||||
el.setAttribute( key, value );
|
||||
}
|
||||
return el;
|
||||
},
|
||||
},
|
||||
|
||||
ensureContent: {
|
||||
regExpr: new RegExp( /^edit-menu-item-show_(names|flags)-(\d+)$/ ),
|
||||
|
||||
/**
|
||||
* Event callback that disallows unchecking both `show_names` and `show_flags`.
|
||||
*
|
||||
* @param {Event} event The event.
|
||||
*/
|
||||
handleEvent: ( event ) => {
|
||||
if ( ! event.target.id || event.target.checked ) {
|
||||
// Now checked, nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = event.target.id.match( pllNavMenu.ensureContent.regExpr );
|
||||
|
||||
if ( ! matches ) {
|
||||
// Not the checkbox we want.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the other checkbox.
|
||||
const [ , type, id ] = matches;
|
||||
const otherType = 'names' === type ? 'flags' : 'names';
|
||||
document.getElementById( `edit-menu-item-show_${ otherType }-${ id }` ).checked = true;
|
||||
},
|
||||
},
|
||||
|
||||
showHideRows: {
|
||||
regExpr: new RegExp( /^edit-menu-item-dropdown-(\d+)$/ ),
|
||||
|
||||
/**
|
||||
* Event callback that shows or hides the `hide_current` checkbox when `dropdown` is checked.
|
||||
*
|
||||
* @param {Event} event The event.
|
||||
*/
|
||||
handleEvent: ( event ) => {
|
||||
if ( ! event.target.id ) {
|
||||
// Not the checkbox we want.
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = event.target.id.match( pllNavMenu.showHideRows.regExpr );
|
||||
|
||||
if ( ! matches ) {
|
||||
// Not the checkbox we want.
|
||||
return;
|
||||
}
|
||||
|
||||
const hideCb = document.getElementById( `edit-menu-item-hide_current-${ matches[1] }` );
|
||||
|
||||
if ( ! hideCb ) {
|
||||
// Should not happen.
|
||||
return;
|
||||
}
|
||||
|
||||
const description = hideCb.closest( '.description' );
|
||||
|
||||
// Hide or show.
|
||||
description.classList.toggle( 'hidden', event.target.checked );
|
||||
|
||||
if ( event.target.checked ) {
|
||||
// Uncheck after hiding.
|
||||
hideCb.checked = false;
|
||||
hideCb.dispatchEvent( new Event( 'change' ) );
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pllNavMenu.init();
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
const pllNavMenu={wrapper:null,init:()=>{"loading"!==document.readyState?pllNavMenu.ready():document.addEventListener("DOMContentLoaded",pllNavMenu.ready)},ready:()=>{pllNavMenu.wrapper=document.getElementById("menu-to-edit"),pllNavMenu.wrapper&&(pllNavMenu.wrapper.addEventListener("click",pllNavMenu.printMetabox),pllNavMenu.wrapper.addEventListener("change",pllNavMenu.ensureContent),pllNavMenu.wrapper.addEventListener("change",pllNavMenu.showHideRows))},printMetabox:{handleEvent:e=>{if(!e.target.classList.contains("item-edit"))return;const t=e.target.closest(".menu-item").querySelector(".menu-item-settings");if(!t?.id)return;if(!t.querySelectorAll('input[value="#pll_switcher"][type=text]').length)return;[...t.children].forEach(e=>{"P"!==e.nodeName||e.classList.contains("field-move")||e.remove()});const n=pllNavMenu.printMetabox,a=Number(t.id.replace("menu-item-settings-",""));t.append(n.createHiddenInput("title",a,pll_data.title)),t.append(n.createHiddenInput("url",a,"#pll_switcher")),t.append(n.createHiddenInput("pll-detect",a,1));const r=Array("hide_if_no_translation","hide_current","force_home","show_flags","show_names","dropdown"),d=void 0!==pll_data.val[a];r.forEach(e=>{const r=n.createElement("p",{class:"description"});"hide_current"===e&&d&&1===pll_data.val[a].dropdown&&r.classList.add("hidden"),t.prepend(r);const l=`edit-menu-item-${e}-${a}`,i=n.createElement("label",{for:l});i.innerText=` ${pll_data.strings[e]}`,r.append(i);const c=n.createElement("input",{type:"checkbox",id:l,name:`menu-item-${e}[${a}]`,value:1});(d&&1===pll_data.val[a][e]||!d&&"show_names"===e)&&(c.checked=!0),i.prepend(c)})},createHiddenInput:(e,t,n)=>pllNavMenu.printMetabox.createElement("input",{type:"hidden",id:`edit-menu-item-${e}-${t}`,name:`menu-item-${e}[${t}]`,value:n}),createElement:(e,t)=>{const n=document.createElement(e);for(const[e,a]of Object.entries(t))n.setAttribute(e,a);return n}},ensureContent:{regExpr:new RegExp(/^edit-menu-item-show_(names|flags)-(\d+)$/),handleEvent:e=>{if(!e.target.id||e.target.checked)return;const t=e.target.id.match(pllNavMenu.ensureContent.regExpr);if(!t)return;const[,n,a]=t,r="names"===n?"flags":"names";document.getElementById(`edit-menu-item-show_${r}-${a}`).checked=!0}},showHideRows:{regExpr:new RegExp(/^edit-menu-item-dropdown-(\d+)$/),handleEvent:e=>{if(!e.target.id)return;const t=e.target.id.match(pllNavMenu.showHideRows.regExpr);if(!t)return;const n=document.getElementById(`edit-menu-item-hide_current-${t[1]}`);if(!n)return;n.closest(".description").classList.toggle("hidden",e.target.checked),e.target.checked&&(n.checked=!1,n.dispatchEvent(new Event("change")))}}};pllNavMenu.init();
|
||||
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tag suggest in quick edit
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
$.ajaxPrefilter(
|
||||
function ( options, originalOptions, jqXHR ) {
|
||||
if ( 'string' === typeof options.data && -1 !== options.data.indexOf( 'action=ajax-tag-search' ) && ( lang = $( ':input[name="inline_lang_choice"]' ).val() ) ) {
|
||||
options.data = 'lang=' + lang + '&' + options.data;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Quick edit
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
const handleQuickEditInsertion = ( mutationsList ) => {
|
||||
for ( const mutation of mutationsList ) {
|
||||
const addedNodes = Array.from( mutation.addedNodes ).filter( el => el.nodeType === Node.ELEMENT_NODE )
|
||||
const form = addedNodes[0];
|
||||
if ( 0 < mutation.addedNodes.length && form.classList.contains( 'inline-editor' ) ) {
|
||||
// WordPress has inserted the quick edit form.
|
||||
const post_id = Number( form.id.substring( 5 ) );
|
||||
|
||||
if ( post_id > 0 ) {
|
||||
// Get the language dropdown.
|
||||
const select = form.querySelector( 'select[name="inline_lang_choice"]' );
|
||||
const lang = document.querySelector( '#lang_' + String( post_id ) ).innerHTML;
|
||||
select.value = lang; // Populates the dropdown with the post language.
|
||||
|
||||
filter_terms( lang ); // Initial filter for category checklist.
|
||||
filter_pages( lang ); // Initial filter for parent dropdown.
|
||||
|
||||
// Modify category checklist and parent dropdown on language change.
|
||||
select.addEventListener(
|
||||
'change',
|
||||
function ( event ) {
|
||||
const newLang = event.target.value;
|
||||
filter_terms( newLang );
|
||||
filter_pages( newLang );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Filters the category checklist.
|
||||
*/
|
||||
function filter_terms( lang ) {
|
||||
if ( "undefined" != typeof( pll_term_languages ) ) {
|
||||
$.each(
|
||||
pll_term_languages,
|
||||
function ( lg, term_tax ) {
|
||||
$.each(
|
||||
term_tax,
|
||||
function ( tax, terms ) {
|
||||
$.each(
|
||||
terms,
|
||||
function ( i ) {
|
||||
// Backward compatibility with WordPress < 6.7.
|
||||
// Support both old (WP < 6.7) and new (WP >= 6.7) ID formats.
|
||||
// Old format: category-123 (WordPress < 6.7).
|
||||
// New format: in-category-123-1 (WordPress >= 6.7).
|
||||
const termId = pll_term_languages[ lg ][ tax ][ i ];
|
||||
const selector = `#${tax}-${termId}, [id^="in-${tax}-${termId}-"]`;
|
||||
$( selector ).toggle( lang === lg );
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the parent page dropdown list.
|
||||
*/
|
||||
function filter_pages( lang ) {
|
||||
if ( "undefined" != typeof( pll_page_languages ) ) {
|
||||
$.each(
|
||||
pll_page_languages,
|
||||
function ( lg, pages ) {
|
||||
$.each(
|
||||
pages,
|
||||
function ( i ) {
|
||||
v = $( '#post_parent option[value="' + pll_page_languages[ lg ][ i ] + '"]' );
|
||||
lang == lg ? v.show() : v.hide();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const table = document.getElementById( 'the-list' );
|
||||
|
||||
if ( ! table ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const config = { childList: true, subtree: true };
|
||||
const observer = new MutationObserver( handleQuickEditInsertion );
|
||||
|
||||
observer.observe( table, config);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Update rows of translated posts when the language is modified in quick edit
|
||||
* Acts on ajaxSuccess event
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
$( document ).ajaxSuccess(
|
||||
function ( event, xhr, settings ) {
|
||||
function update_rows( post_id ) {
|
||||
// collect old translations
|
||||
var translations = new Array();
|
||||
$( '.translation_' + post_id ).each(
|
||||
function () {
|
||||
translations.push( $( this ).parent().parent().attr( 'id' ).substring( 5 ) );
|
||||
}
|
||||
);
|
||||
|
||||
var data = {
|
||||
action: 'pll_update_post_rows',
|
||||
post_id: post_id,
|
||||
translations: translations.join( ',' ),
|
||||
post_type: $( "input[name='post_type']" ).val(),
|
||||
screen: $( "input[name='screen']" ).val(),
|
||||
_pll_nonce: $( "input[name='_inline_edit']" ).val() // reuse quick edit nonce
|
||||
};
|
||||
|
||||
// get the modified rows in ajax and update them
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
if ( response ) {
|
||||
// Since WP changeset #52710 parseAjaxResponse() return content to notice the user in a HTML tag with ajax-response id.
|
||||
// Not to disturb this behaviour by executing another ajax request in the ajaxSuccess event, we need to target another unexisting id.
|
||||
var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
if ( 'row' == this.what ) {
|
||||
// data is built with a call to WP_Posts_List_Table::single_row method
|
||||
// which uses internally other WordPress methods which escape correctly values.
|
||||
// For Polylang language columns the HTML code is correctly escaped in PLL_Admin_Filters_Columns::post_column method.
|
||||
$( "#post-" + this.supplemental.post_id ).replaceWith( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'string' == typeof( settings.data ) ) { // Need to check the type due to block editor sometime sending FormData objects
|
||||
var data = wpAjax.unserialize( settings.data ); // what were the data sent by the ajax request?
|
||||
if ( 'undefined' != typeof( data['action'] ) && 'inline-save' == data['action'] ) {
|
||||
update_rows( data['post_ID'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(n){n.ajaxPrefilter(function(e,t,a){"string"==typeof e.data&&-1!==e.data.indexOf("action=ajax-tag-search")&&(lang=n(':input[name="inline_lang_choice"]').val())&&(e.data="lang="+lang+"&"+e.data)})}),jQuery(function(n){const e=document.getElementById("the-list");if(!e)return;new MutationObserver(e=>{for(const i of e){const o=Array.from(i.addedNodes).filter(n=>n.nodeType===Node.ELEMENT_NODE)[0];if(0<i.addedNodes.length&&o.classList.contains("inline-editor")){const s=Number(o.id.substring(5));if(s>0){const l=o.querySelector('select[name="inline_lang_choice"]'),c=document.querySelector("#lang_"+String(s)).innerHTML;l.value=c,t(c),a(c),l.addEventListener("change",function(n){const e=n.target.value;t(e),a(e)})}}function t(e){"undefined"!=typeof pll_term_languages&&n.each(pll_term_languages,function(t,a){n.each(a,function(a,i){n.each(i,function(i){const o=pll_term_languages[t][a][i];n(`#${a}-${o}, [id^="in-${a}-${o}-"]`).toggle(e===t)})})})}function a(e){"undefined"!=typeof pll_page_languages&&n.each(pll_page_languages,function(t,a){n.each(a,function(a){v=n('#post_parent option[value="'+pll_page_languages[t][a]+'"]'),e==t?v.show():v.hide()})})}}}).observe(e,{childList:!0,subtree:!0})}),jQuery(function(n){n(document).ajaxSuccess(function(e,t,a){if("string"==typeof a.data){var i=wpAjax.unserialize(a.data);void 0!==i.action&&"inline-save"==i.action&&function(e){var t=new Array;n(".translation_"+e).each(function(){t.push(n(this).parent().parent().attr("id").substring(5))});var a={action:"pll_update_post_rows",post_id:e,translations:t.join(","),post_type:n("input[name='post_type']").val(),screen:n("input[name='screen']").val(),_pll_nonce:n("input[name='_inline_edit']").val()};n.post(ajaxurl,a,function(e){if(e){var t=wpAjax.parseAjaxResponse(e,"pll-ajax-response");n.each(t.responses,function(){"row"==this.what&&n("#post-"+this.supplemental.post_id).replaceWith(this.data)})}})}(i.post_ID)}})});
|
||||
@@ -0,0 +1,395 @@
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
|
||||
// languages list table
|
||||
// accessibility to row actions on focus
|
||||
// mainly copy paste of WP code from common.js
|
||||
var transitionTimeout;
|
||||
$( 'table.languages' ).on(
|
||||
{ // restricted to languages list table
|
||||
focusin: function () {
|
||||
clearTimeout( transitionTimeout );
|
||||
var focusedRowActions = $( this ).find( '.row-actions' );
|
||||
// transitionTimeout is necessary for Firefox, but Chrome won't remove the CSS class without a little help.
|
||||
$( '.row-actions' ).not( this ).removeClass( 'visible' );
|
||||
focusedRowActions.addClass( 'visible' );
|
||||
},
|
||||
focusout: function () {
|
||||
// Tabbing between post title and .row-actions links needs a brief pause, otherwise
|
||||
// the .row-actions div gets hidden in transit in some browsers ( ahem, Firefox ).
|
||||
transitionTimeout = setTimeout(
|
||||
function () {
|
||||
focusedRowActions.removeClass( 'visible' );
|
||||
},
|
||||
30
|
||||
);
|
||||
}
|
||||
},
|
||||
'tr'
|
||||
); // acts on the whole tr instead of single td as we have actions links in several columns
|
||||
|
||||
/**
|
||||
* Common functions and variables for overriding languages and flags dropdown list by a jQuery UI selectmenu widget.
|
||||
*/
|
||||
|
||||
// Allow to check if a flag list dropdown is present. Not present in the Wizard steps or other settings page.
|
||||
var flagListExist = $( "#flag_list" ).length;
|
||||
// Allow to check if a language list dropdown is present. Not present in other settings page.
|
||||
var langListExist = $( "#lang_list" ).length;
|
||||
// jQuery UI selectmenu widget width option
|
||||
var defaultSelectmenuWidth = '95%';
|
||||
var wizardSelectmenuWidth = '100%';
|
||||
|
||||
// Inject flag image when jQuery UI selectmenu is created or an item is selected.
|
||||
// jQuery UI 1.12 introduces a wrapper inside de li tag which is necessary to selectmenu widget to work correctly.
|
||||
// Mainly copy from the original jQuery UI 1.12 selectmenu widget _renderItem method.
|
||||
var selectmenuRenderItem = function ( ul, item ) {
|
||||
var li = $( '<li>' );
|
||||
var wrapper = $( '<div>');
|
||||
|
||||
if ( item.disabled ) {
|
||||
this._addClass( li, null, "ui-state-disabled" );
|
||||
}
|
||||
// `item.label` is the original `<option>`'s label.
|
||||
this._setText( wrapper, item.label );
|
||||
|
||||
// Add the flag from the data attribute in the selected element.
|
||||
// `item.element` is the original `<option>` element, the data to prepend comes from a `data-html-flag` HTML attribute, filled by a method from `PLL_Language`.
|
||||
wrapper.prepend( $( item.element ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
wrapper.children( 'img' ).addClass( 'ui-icon' );
|
||||
|
||||
// `wrapper` and `ul` are safe, see above.
|
||||
return li.append( wrapper ).appendTo( ul ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append, WordPressVIPMinimum.JS.HTMLExecutingFunctions.appendTo
|
||||
};
|
||||
// Override selected item since jQuery UI 1.12 which introduces extension point method _renderButtonItem.
|
||||
// @see https://api.jqueryui.com/1.12/selectmenu/#method-_renderButtonItem _renderButtonItem documentation.
|
||||
var selectmenuRenderButtonItem = function ( selectElement ) {
|
||||
var buttonItem = $( '<span>' );
|
||||
this._setText( buttonItem, selectElement.label );
|
||||
this._addClass( buttonItem, "ui-selectmenu-text" );
|
||||
|
||||
// Add the flag from the data attribute in the selected element.
|
||||
// The data to prepend comes from a `data-html-flag` HTML attribute, filled by a method from `PLL_Language`.
|
||||
buttonItem.prepend( $( selectElement.element ).data( 'flag-html' ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
buttonItem.children( 'img' ).addClass( 'ui-icon' );
|
||||
|
||||
return buttonItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a jQuery UI selectmenu widget on a DOM element
|
||||
*
|
||||
* @param {*} element - The jQuery object representing the DOM element to attach the widget with.
|
||||
* @param {*} config - All the parameters - options and callbacks - necessary to configure the jQuery UI selectmenu widget.
|
||||
* @return {Object} - The jQuery UI selectmenu widget object instance.
|
||||
*/
|
||||
function initializeSelectmenuWidget( element, config ) {
|
||||
// Create the jQuery UI selectmenu widget for flags list dropdown and return its instance.
|
||||
var selectmenuWidgetInstance = element.selectmenu( config ).selectmenu( 'instance' );
|
||||
// Overrides each item in the jQuery UI selectmenu list by injecting flag image.
|
||||
selectmenuWidgetInstance._renderItem = selectmenuRenderItem;
|
||||
// Override the selected item rendering.
|
||||
selectmenuWidgetInstance._renderButtonItem = selectmenuRenderButtonItem;
|
||||
// Need to refresh to take in account the new button item rendering method after the selectmenu widget instanciaion.
|
||||
selectmenuWidgetInstance.refresh();
|
||||
return selectmenuWidgetInstance
|
||||
}
|
||||
/**
|
||||
* Selectmenu widget common parameters for its configuration: options and callbacks.
|
||||
*/
|
||||
|
||||
// Selectmenu widget options
|
||||
var selectmenuOptions = {
|
||||
width: defaultSelectmenuWidth,
|
||||
classes: {
|
||||
'ui-selectmenu-menu': 'pll-selectmenu-menu',
|
||||
'ui-selectmenu-button': 'pll-selectmenu-button',
|
||||
}
|
||||
};
|
||||
|
||||
// Selectmenu widget callbacks
|
||||
var selectmenuFlagListCallbacks = {};
|
||||
|
||||
/**
|
||||
* Overrides the flag dropdown list with our customized jquery ui selectmenu.
|
||||
*/
|
||||
|
||||
// Callbacks when Selectmenu widget change or open event is triggered.
|
||||
// Needed to correctly refresh the selected element in the list when editing an existing language or when the value change is triggered by the language choice.
|
||||
var changeOpenCallback = function ( event, ui ) {
|
||||
// Just a refresh of the menu is needed with jQuery UI 1.12 because _renderButtonItem is triggered and then inject correctly the flag.
|
||||
$( event.target ).selectmenu( 'refresh' );
|
||||
}
|
||||
selectmenuFlagListCallbacks =
|
||||
{
|
||||
change: changeOpenCallback,
|
||||
open: changeOpenCallback,
|
||||
};
|
||||
|
||||
// Create the selectmenu widget only if the field is present.
|
||||
if ( flagListExist ) {
|
||||
// Create the jQuery UI selectmenu widget for flags list dropdown and return its instance.
|
||||
var selectmenuFlagList = initializeSelectmenuWidget( $( '#flag_list' ), Object.assign( {}, selectmenuOptions, selectmenuFlagListCallbacks ) );
|
||||
$( '#lang_list' ).on(
|
||||
'languageChanged',
|
||||
function ( event, flag ) {
|
||||
// Refresh the flag field
|
||||
selectmenuFlagList.element.val( flag );
|
||||
selectmenuFlagList._trigger( 'change' );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Language choice in predefined languages in Polylang Languages settings page and wizard.
|
||||
* Overrides the predefined language dropdown list with our customized jQuery ui selectmenu widget.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fill the other language form fields from the language element selected in the language list dropdown.
|
||||
*
|
||||
* @param {Object} language - language object of the selected element in the language list dropdown.
|
||||
*/
|
||||
function fillLanguageFields( language ) {
|
||||
$( '#lang_slug' ).val( language.slug );
|
||||
$( '#lang_locale' ).val( language.locale );
|
||||
$( 'input[name="rtl"]' ).val( language.rtl );
|
||||
$( '#lang_name' ).val( language.name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse selected language element in the language list dropdown.
|
||||
*
|
||||
* @param {object} event - jQuery triggered event.
|
||||
* @return {object} The language object with its named properties.
|
||||
*/
|
||||
function parseSelectedLanguage( event ) {
|
||||
var selectedElement = $('option:selected', event.target);
|
||||
var values = selectedElement.val().split(':')
|
||||
return {
|
||||
slug: values[0],
|
||||
locale: values[1],
|
||||
rtl: [values[2]],
|
||||
flag: values[3],
|
||||
name: selectedElement.text().split(' - ')[0] // At the moment there is no need of the 2nd part because it corresponds on the locale which is already known by splitting the selected element value
|
||||
};
|
||||
}
|
||||
|
||||
// Callback when selectmenu widget change event is triggered.
|
||||
var changeCallback = function ( event, ui ) {
|
||||
var language = parseSelectedLanguage( event );
|
||||
|
||||
fillLanguageFields( language );
|
||||
|
||||
$( event.target ).trigger( 'languageChanged', language.flag );
|
||||
};
|
||||
|
||||
// Create the jQuery UI selectmenu widget languages list dropdown and return its instance.
|
||||
var selectmenuLangListCallbacks = {};
|
||||
// For the wizard we need a 100% width. So we override the previous defined value of selectmenuOptions.
|
||||
if ( $( '#lang_list' ).closest( '.pll-wizard-content' ).length > 0 ) {
|
||||
selectmenuOptions = Object.assign( selectmenuOptions, { width: wizardSelectmenuWidth } );
|
||||
}
|
||||
|
||||
selectmenuLangListCallbacks = {
|
||||
change: changeCallback,
|
||||
};
|
||||
|
||||
if ( langListExist ) {
|
||||
initializeSelectmenuWidget( $( '#lang_list' ), Object.assign( {}, selectmenuOptions, selectmenuLangListCallbacks ) );
|
||||
}
|
||||
|
||||
// strings translations
|
||||
// save translations when pressing enter
|
||||
$( '.translation input' ).on(
|
||||
'keydown',
|
||||
function ( event ) {
|
||||
if ( 'Enter' === event.key ) {
|
||||
event.preventDefault();
|
||||
$( '#submit' ).trigger( 'click' );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// settings page
|
||||
// click on configure link
|
||||
$( '#the-list' ).on(
|
||||
'click',
|
||||
'.configure>a',
|
||||
function () {
|
||||
$( '.pll-configure' ).hide().prev().show();
|
||||
$( this ).closest( 'tr' ).hide().next().show();
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
// cancel
|
||||
$( '#the-list' ).on(
|
||||
'click',
|
||||
'.cancel',
|
||||
function () {
|
||||
$( this ).closest( 'tr' ).hide().prev().show();
|
||||
}
|
||||
);
|
||||
|
||||
// save settings
|
||||
$( '#the-list' ).on(
|
||||
'click',
|
||||
'.save',
|
||||
function () {
|
||||
var tr = $( this ).closest( 'tr' );
|
||||
var parts = tr.attr( 'id' ).split( '-' );
|
||||
|
||||
var data = {
|
||||
action: 'pll_save_options',
|
||||
pll_ajax_settings: true,
|
||||
module: parts[parts.length - 1],
|
||||
_pll_nonce: $( '#_pll_nonce' ).val()
|
||||
};
|
||||
|
||||
data = tr.find( ':input' ).serialize() + '&' + $.param( data );
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
// Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
|
||||
var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
/**
|
||||
* Fires after saving the settings, before applying changes to the DOM.
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param {Object} response The response from the AJAX call.
|
||||
* @param {HTMLElement} tr The HTML element containing the fields.
|
||||
*/
|
||||
wp.hooks.doAction( 'pll_settings_saved', this, tr.get( 0 ) );
|
||||
|
||||
switch ( this.what ) {
|
||||
case 'license-update':
|
||||
// Data comes from `PLL_License::get_form_field()`, where everything is escaped.
|
||||
$( '#pll-license-' + this.data ).replaceWith( this.supplemental.html ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
break;
|
||||
case 'success':
|
||||
tr.hide().prev().show(); // close only if there is no error
|
||||
case 'error':
|
||||
$( '.settings-error' ).remove(); // remove previous messages if any
|
||||
// The data comes from `pll_add_notice()`, where message are passed through `wp_kses()`.
|
||||
$( 'h1' ).after( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after
|
||||
|
||||
// Make notices dismissible
|
||||
// copy paste of common.js from WP 4.2.2
|
||||
$( '.notice.is-dismissible' ).each(
|
||||
function () {
|
||||
var $this = $( this ),
|
||||
$button = $( '<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>' ),
|
||||
btnText = pll_settings.dismiss_notice || '';
|
||||
|
||||
// Ensure plain text
|
||||
$button.find( '.screen-reader-text' ).text( btnText );
|
||||
|
||||
// Whitelist because of how the button is built. See above
|
||||
$this.append( $button ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
|
||||
$button.on(
|
||||
'click.wp-dismiss-notice',
|
||||
function ( event ) {
|
||||
event.preventDefault();
|
||||
$this.fadeTo(
|
||||
100,
|
||||
0,
|
||||
function () {
|
||||
$( this ).slideUp(
|
||||
100,
|
||||
function () {
|
||||
$( this ).remove();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// act when pressing enter or esc in configurations
|
||||
$( '.pll-configure' ).on(
|
||||
'keydown',
|
||||
function ( event ) {
|
||||
if ( 'Enter' === event.key ) {
|
||||
event.preventDefault();
|
||||
$( this ).find( '.save' ).trigger( 'click' );
|
||||
}
|
||||
|
||||
if ( 'Escape' === event.key ) {
|
||||
event.preventDefault();
|
||||
$( this ).find( '.cancel' ).trigger( 'click' );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// settings URL modifications
|
||||
// manages visibility of fields
|
||||
$( "input[name='force_lang']" ).on(
|
||||
'change',
|
||||
function () {
|
||||
function pll_toggle( a, test ) {
|
||||
test ? a.show() : a.hide();
|
||||
}
|
||||
|
||||
var value = $( this ).val();
|
||||
pll_toggle( $( '#pll-domains-table' ), 3 == value );
|
||||
pll_toggle( $( "#pll-hide-default" ), 3 > value );
|
||||
pll_toggle( $( "#pll-rewrite" ), 2 > value );
|
||||
pll_toggle( $( "#pll-redirect-lang" ), 2 > value );
|
||||
}
|
||||
);
|
||||
|
||||
// settings license
|
||||
// deactivate button
|
||||
$( '.pll-deactivate-license' ).on(
|
||||
'click',
|
||||
function () {
|
||||
var data = {
|
||||
action: 'pll_deactivate_license',
|
||||
pll_ajax_settings: true,
|
||||
id: $( this ).attr( 'id' ),
|
||||
_pll_nonce: $( '#_pll_nonce' ).val()
|
||||
};
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
// Data comes from `PLL_License::get_form_field()`, where everything is escaped.
|
||||
$( '#pll-license-' + response.id ).replaceWith( response.html ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Manage closing the metabox.
|
||||
// close postboxes that should be closed
|
||||
$( '.if-js-closed' ).removeClass( 'if-js-closed' ).addClass( 'closed' );
|
||||
// postboxes setup
|
||||
if ( 'undefined' !== typeof postboxes ) {
|
||||
postboxes.add_postbox_toggles( pagenow );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(e){var t;e("table.languages").on({focusin:function(){clearTimeout(t);var n=e(this).find(".row-actions");e(".row-actions").not(this).removeClass("visible"),n.addClass("visible")},focusout:function(){t=setTimeout(function(){focusedRowActions.removeClass("visible")},30)}},"tr");var n=e("#flag_list").length,l=e("#lang_list").length,s=function(t,n){var l=e("<li>"),s=e("<div>");return n.disabled&&this._addClass(l,null,"ui-state-disabled"),this._setText(s,n.label),s.prepend(e(n.element).data("flag-html")),s.children("img").addClass("ui-icon"),l.append(s).appendTo(t)},i=function(t){var n=e("<span>");return this._setText(n,t.label),this._addClass(n,"ui-selectmenu-text"),n.prepend(e(t.element).data("flag-html")),n.children("img").addClass("ui-icon"),n};function a(e,t){var n=e.selectmenu(t).selectmenu("instance");return n._renderItem=s,n._renderButtonItem=i,n.refresh(),n}var c,o={width:"95%",classes:{"ui-selectmenu-menu":"pll-selectmenu-menu","ui-selectmenu-button":"pll-selectmenu-button"}},r=function(t,n){e(t.target).selectmenu("refresh")};if(c={change:r,open:r},n){var u=a(e("#flag_list"),Object.assign({},o,c));e("#lang_list").on("languageChanged",function(e,t){u.element.val(t),u._trigger("change")})}var d;e("#lang_list").closest(".pll-wizard-content").length>0&&(o=Object.assign(o,{width:"100%"})),d={change:function(t,n){var l=function(t){var n=e("option:selected",t.target),l=n.val().split(":");return{slug:l[0],locale:l[1],rtl:[l[2]],flag:l[3],name:n.text().split(" - ")[0]}}(t);!function(t){e("#lang_slug").val(t.slug),e("#lang_locale").val(t.locale),e('input[name="rtl"]').val(t.rtl),e("#lang_name").val(t.name)}(l),e(t.target).trigger("languageChanged",l.flag)}},l&&a(e("#lang_list"),Object.assign({},o,d)),e(".translation input").on("keydown",function(t){"Enter"===t.key&&(t.preventDefault(),e("#submit").trigger("click"))}),e("#the-list").on("click",".configure>a",function(){return e(".pll-configure").hide().prev().show(),e(this).closest("tr").hide().next().show(),!1}),e("#the-list").on("click",".cancel",function(){e(this).closest("tr").hide().prev().show()}),e("#the-list").on("click",".save",function(){var t=e(this).closest("tr"),n=t.attr("id").split("-"),l={action:"pll_save_options",pll_ajax_settings:!0,module:n[n.length-1],_pll_nonce:e("#_pll_nonce").val()};l=t.find(":input").serialize()+"&"+e.param(l),e.post(ajaxurl,l,function(n){var l=wpAjax.parseAjaxResponse(n,"pll-ajax-response");e.each(l.responses,function(){switch(wp.hooks.doAction("pll_settings_saved",this,t.get(0)),this.what){case"license-update":e("#pll-license-"+this.data).replaceWith(this.supplemental.html);break;case"success":t.hide().prev().show();case"error":e(".settings-error").remove(),e("h1").after(this.data),e(".notice.is-dismissible").each(function(){var t=e(this),n=e('<button type="button" class="notice-dismiss"><span class="screen-reader-text"></span></button>'),l=pll_settings.dismiss_notice||"";n.find(".screen-reader-text").text(l),t.append(n),n.on("click.wp-dismiss-notice",function(n){n.preventDefault(),t.fadeTo(100,0,function(){e(this).slideUp(100,function(){e(this).remove()})})})})}})})}),e(".pll-configure").on("keydown",function(t){"Enter"===t.key&&(t.preventDefault(),e(this).find(".save").trigger("click")),"Escape"===t.key&&(t.preventDefault(),e(this).find(".cancel").trigger("click"))}),e("input[name='force_lang']").on("change",function(){function t(e,t){t?e.show():e.hide()}var n=e(this).val();t(e("#pll-domains-table"),3==n),t(e("#pll-hide-default"),3>n),t(e("#pll-rewrite"),2>n),t(e("#pll-redirect-lang"),2>n)}),e(".pll-deactivate-license").on("click",function(){var t={action:"pll_deactivate_license",pll_ajax_settings:!0,id:e(this).attr("id"),_pll_nonce:e("#_pll_nonce").val()};e.post(ajaxurl,t,function(t){e("#pll-license-"+t.id).replaceWith(t.html)})}),e(".if-js-closed").removeClass("if-js-closed").addClass("closed"),"undefined"!=typeof postboxes&&postboxes.add_postbox_toggles(pagenow)});
|
||||
@@ -0,0 +1,250 @@
|
||||
/**
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
/**
|
||||
* Quick edit
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
const handleQuickEditInsertion = ( mutationsList ) => {
|
||||
for ( const mutation of mutationsList ) {
|
||||
const addedNodes = Array.from( mutation.addedNodes ).filter( el => el.nodeType === Node.ELEMENT_NODE )
|
||||
const form = addedNodes[0];
|
||||
if ( 0 < mutation.addedNodes.length && form.classList.contains( 'inline-edit-row' ) ) {
|
||||
// WordPress has inserted the quick edit form.
|
||||
const term_id = Number( form.id.substring( 5 ) );
|
||||
|
||||
if ( term_id > 0 ) {
|
||||
// Get the language dropdown.
|
||||
const select = form.querySelector( 'select[name="inline_lang_choice"]' );
|
||||
const lang = document.querySelector( '#lang_' + String( term_id ) ).innerHTML;
|
||||
select.value = lang; // Populates the dropdown with the post language.
|
||||
|
||||
// Disable the language dropdown for default categories.
|
||||
const default_cat = document.querySelector( `#default_cat_${term_id}` )?.innerHTML;
|
||||
if ( term_id == default_cat ) {
|
||||
select.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const table = document.getElementById( 'the-list' );
|
||||
if ( null !== table ) {
|
||||
// Ensure the table is displayed before listening to any change.
|
||||
const config = { childList: true, subtree: true };
|
||||
const observer = new MutationObserver( handleQuickEditInsertion );
|
||||
|
||||
observer.observe( table, config);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Update rows of translated terms when adding / deleting a translation or when the language is modified in quick edit.
|
||||
* Acts on ajaxSuccess event.
|
||||
*/
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
$( document ).ajaxSuccess(
|
||||
function ( event, xhr, settings ) {
|
||||
function update_rows( term_id ) {
|
||||
// collect old translations
|
||||
var translations = new Array();
|
||||
$( '.translation_' + term_id ).each(
|
||||
function () {
|
||||
translations.push( $( this ).parent().parent().attr( 'id' ).substring( 4 ) );
|
||||
}
|
||||
);
|
||||
|
||||
var data = {
|
||||
action: 'pll_update_term_rows',
|
||||
term_id: term_id,
|
||||
translations: translations.join( ',' ),
|
||||
taxonomy: $( "input[name='taxonomy']" ).val(),
|
||||
post_type: $( "input[name='post_type']" ).val(),
|
||||
screen: $( "input[name='screen']" ).val(),
|
||||
_pll_nonce: $( '#_pll_nonce' ).val()
|
||||
};
|
||||
|
||||
// get the modified rows in ajax and update them
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
if ( response ) {
|
||||
// Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
|
||||
var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
if ( 'row' == this.what ) {
|
||||
// data is built with a call to WP_Terms_List_Table::single_row method
|
||||
// which uses internally other WordPress methods which escape correctly values.
|
||||
// For Polylang language columns the HTML code is correctly escaped in PLL_Admin_Filters_Columns::term_column method.
|
||||
$( "#tag-" + this.supplemental.term_id ).replaceWith( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var data = wpAjax.unserialize( settings.data ); // what were the data sent by the ajax request?
|
||||
if ( 'undefined' != typeof( data['action'] ) ) {
|
||||
switch ( data['action'] ) {
|
||||
// when adding a term, the new term_id is in the ajax response
|
||||
case 'add-tag':
|
||||
// Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
|
||||
res = wpAjax.parseAjaxResponse( xhr.responseXML, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
if ( 'term' == this.what ) {
|
||||
update_rows( this.supplemental.term_id );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// and also reset translations hidden input fields
|
||||
$( '.htr_lang' ).val( 0 );
|
||||
break;
|
||||
|
||||
// when deleting a term
|
||||
case 'delete-tag':
|
||||
update_rows( data['tag_ID'] );
|
||||
break;
|
||||
|
||||
// in case the language is modified in quick edit and breaks translations
|
||||
case 'inline-save-tax':
|
||||
update_rows( data['tax_ID'] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
// translations autocomplete input box
|
||||
function init_translations() {
|
||||
$( '.tr_lang' ).each(
|
||||
function () {
|
||||
var tr_lang = $( this ).attr( 'id' ).substring( 8 );
|
||||
var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
|
||||
|
||||
$( this ).autocomplete(
|
||||
{
|
||||
minLength: 0,
|
||||
source: ajaxurl + '?action=pll_terms_not_translated' +
|
||||
'&term_language=' + $( '#term_lang_choice' ).val() +
|
||||
'&term_id=' + $( "input[name='tag_ID']" ).val() +
|
||||
'&taxonomy=' + $( "input[name='taxonomy']" ).val() +
|
||||
'&translation_language=' + tr_lang +
|
||||
'&post_type=' + typenow +
|
||||
'&_pll_nonce=' + $( '#_pll_nonce' ).val(),
|
||||
select: function ( event, ui ) {
|
||||
$( '#htr_lang_' + tr_lang ).val( ui.item.id );
|
||||
// ui.item.link is built and come from server side and is well escaped when necessary
|
||||
td.html( ui.item.link ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// when the input box is emptied
|
||||
$( this ).on(
|
||||
'blur',
|
||||
function () {
|
||||
if ( ! $( this ).val() ) {
|
||||
$( '#htr_lang_' + tr_lang ).val( 0 );
|
||||
// Value is retrieved from HTML already generated server side
|
||||
td.html( td.siblings( '.hidden' ).children().clone() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
init_translations();
|
||||
|
||||
// ajax for changing the term's language
|
||||
$( '#term_lang_choice' ).on(
|
||||
'change',
|
||||
function () {
|
||||
var value = $( this ).val();
|
||||
// The selected option in the dropdown list.
|
||||
const selectedOption = event.target;
|
||||
|
||||
var data = {
|
||||
action: 'term_lang_choice',
|
||||
lang: value,
|
||||
from_tag: $( "input[name='from_tag']" ).val(),
|
||||
term_id: $( "input[name='tag_ID']" ).val(),
|
||||
taxonomy: $( "input[name='taxonomy']" ).val(),
|
||||
post_type: typenow,
|
||||
_pll_nonce: $( '#_pll_nonce' ).val()
|
||||
};
|
||||
|
||||
$.post(
|
||||
ajaxurl,
|
||||
data,
|
||||
function ( response ) {
|
||||
// Target a non existing WP HTML id to avoid a conflict with WP ajax requests.
|
||||
var res = wpAjax.parseAjaxResponse( response, 'pll-ajax-response' );
|
||||
$.each(
|
||||
res.responses,
|
||||
function () {
|
||||
switch ( this.what ) {
|
||||
case 'translations': // translations fields
|
||||
// Data is built and come from server side and is well escaped when necessary
|
||||
$( "#term-translations" ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
init_translations();
|
||||
break;
|
||||
case 'parent': // parent dropdown list for hierarchical taxonomies
|
||||
// data correctly escaped in PLL_Admin_Filters_Term::term_lang_choice method which uses wp_dropdown_categories function.
|
||||
$( '#parent' ).replaceWith( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
break;
|
||||
case 'tag_cloud': // popular items
|
||||
// data correctly escaped in PLL_Admin_Filters_Term::term_lang_choice method which uses wp_tag_cloud and wp_generate_tag_cloud functions.
|
||||
$( '.tagcloud' ).replaceWith( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
|
||||
break;
|
||||
case 'flag': // flag in front of the select dropdown
|
||||
// Data is built and come from server side and is well escaped when necessary
|
||||
$( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Creates an event once the language has been successfully changed.
|
||||
const onTermLangChoice = new CustomEvent(
|
||||
"onTermLangChoice",
|
||||
{
|
||||
detail: {
|
||||
lang: JSON.parse( selectedOption.options[selectedOption.options.selectedIndex].getAttribute( 'data-lang' ) )
|
||||
},
|
||||
}
|
||||
);
|
||||
document.dispatchEvent( onTermLangChoice );
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to `onTermLangChoice` to perform actions after the language has been changed.
|
||||
document.addEventListener(
|
||||
'onTermLangChoice',
|
||||
( e ) => {
|
||||
// Modifies the text direction.
|
||||
let dir = e.detail.lang.is_rtl ? 'rtl' : 'ltr'
|
||||
$( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(t){const e=t=>{for(const e of t){const t=Array.from(e.addedNodes).filter(t=>t.nodeType===Node.ELEMENT_NODE)[0];if(0<e.addedNodes.length&&t.classList.contains("inline-edit-row")){const e=Number(t.id.substring(5));if(e>0){const a=t.querySelector('select[name="inline_lang_choice"]'),n=document.querySelector("#lang_"+String(e)).innerHTML;a.value=n;const l=document.querySelector(`#default_cat_${e}`)?.innerHTML;e==l&&(a.disabled=!0)}}}},a=document.getElementById("the-list");if(null!==a){const t={childList:!0,subtree:!0};new MutationObserver(e).observe(a,t)}}),jQuery(function(t){t(document).ajaxSuccess(function(e,a,n){function l(e){var a=new Array;t(".translation_"+e).each(function(){a.push(t(this).parent().parent().attr("id").substring(4))});var n={action:"pll_update_term_rows",term_id:e,translations:a.join(","),taxonomy:t("input[name='taxonomy']").val(),post_type:t("input[name='post_type']").val(),screen:t("input[name='screen']").val(),_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,n,function(e){if(e){var a=wpAjax.parseAjaxResponse(e,"pll-ajax-response");t.each(a.responses,function(){"row"==this.what&&t("#tag-"+this.supplemental.term_id).replaceWith(this.data)})}})}var s=wpAjax.unserialize(n.data);if(void 0!==s.action)switch(s.action){case"add-tag":res=wpAjax.parseAjaxResponse(a.responseXML,"pll-ajax-response"),t.each(res.responses,function(){"term"==this.what&&l(this.supplemental.term_id)}),t(".htr_lang").val(0);break;case"delete-tag":l(s.tag_ID);break;case"inline-save-tax":l(s.tax_ID)}})}),jQuery(function(t){function e(){t(".tr_lang").each(function(){var e=t(this).attr("id").substring(8),a=t(this).parent().parent().siblings(".pll-edit-column");t(this).autocomplete({minLength:0,source:ajaxurl+"?action=pll_terms_not_translated&term_language="+t("#term_lang_choice").val()+"&term_id="+t("input[name='tag_ID']").val()+"&taxonomy="+t("input[name='taxonomy']").val()+"&translation_language="+e+"&post_type="+typenow+"&_pll_nonce="+t("#_pll_nonce").val(),select:function(n,l){t("#htr_lang_"+e).val(l.item.id),a.html(l.item.link)}}),t(this).on("blur",function(){t(this).val()||(t("#htr_lang_"+e).val(0),a.html(a.siblings(".hidden").children().clone()))})})}e(),t("#term_lang_choice").on("change",function(){var a=t(this).val();const n=event.target;var l={action:"term_lang_choice",lang:a,from_tag:t("input[name='from_tag']").val(),term_id:t("input[name='tag_ID']").val(),taxonomy:t("input[name='taxonomy']").val(),post_type:typenow,_pll_nonce:t("#_pll_nonce").val()};t.post(ajaxurl,l,function(a){var l=wpAjax.parseAjaxResponse(a,"pll-ajax-response");t.each(l.responses,function(){switch(this.what){case"translations":t("#term-translations").html(this.data),e();break;case"parent":t("#parent").replaceWith(this.data);break;case"tag_cloud":t(".tagcloud").replaceWith(this.data);break;case"flag":t(".pll-select-flag").html(this.data)}});const s=new CustomEvent("onTermLangChoice",{detail:{lang:JSON.parse(n.options[n.options.selectedIndex].getAttribute("data-lang"))}});document.dispatchEvent(s)})}),document.addEventListener("onTermLangChoice",e=>{let a=e.detail.lang.is_rtl?"rtl":"ltr";t("body").removeClass("pll-dir-rtl").removeClass("pll-dir-ltr").addClass("pll-dir-"+a)})});
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Adds one biography input field per language in the user profile.
|
||||
*
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
// biography
|
||||
// FIXME there is probably a more efficient way to do this
|
||||
var td = $( '#description' ).parent();
|
||||
var d = $( '#description' ).clone();
|
||||
var span = td.children( '.description' ).clone();
|
||||
td.children().remove();
|
||||
|
||||
$( '.biography' ).each(
|
||||
function () {
|
||||
lang = $( this ).attr( 'name' ).split( '___' );
|
||||
desc = d.clone();
|
||||
desc.attr( 'name', 'description_' + lang[0] );
|
||||
desc.attr( 'id', 'description_' + lang[0] );
|
||||
// Whitelist because description and lang value is already escaped by the side of PHP
|
||||
desc.html( $( this ).val() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
td.append( $( '<div></div>' ).text( lang[1] ) ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
td.append( desc ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
}
|
||||
);
|
||||
|
||||
td.append( '<br />' );
|
||||
// Whitelist because description come from html code generated by WordPress
|
||||
td.append( span ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.append
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(e){var n=e("#description").parent(),i=e("#description").clone(),t=n.children(".description").clone();n.children().remove(),e(".biography").each(function(){lang=e(this).attr("name").split("___"),desc=i.clone(),desc.attr("name","description_"+lang[0]),desc.attr("id","description_"+lang[0]),desc.html(e(this).val()),n.append(e("<div></div>").text(lang[1])),n.append(desc)}),n.append("<br />"),n.append(t)});
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Adds a flag to the widgets filtered by a language.
|
||||
*
|
||||
* @package Polylang
|
||||
*/
|
||||
|
||||
jQuery(
|
||||
function ( $ ) {
|
||||
var widgets_container,
|
||||
widgets_selector,
|
||||
flags,
|
||||
isBlockEditor = 'undefined' !== typeof wp.blockEditor;
|
||||
|
||||
if ( 'undefined' !== typeof pll_widgets && pll_widgets.hasOwnProperty( 'flags' ) ) {
|
||||
flags = pll_widgets.flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend widget titles with a flag once a language is selected.
|
||||
*
|
||||
* @param {object} widget The widget element.
|
||||
* @return {void} Nothing.
|
||||
*/
|
||||
function add_flag( widget ) {
|
||||
if ( ! flags ) {
|
||||
return;
|
||||
}
|
||||
widget = $( widget );
|
||||
var title = isBlockEditor ? widget.prev('h3') : $( '.widget-top .widget-title h3', widget ),
|
||||
locale = $( '.pll-lang-choice option:selected', widget ).val(),
|
||||
// Icon is HTML built and come from server side and is well escaped when necessary
|
||||
icon = ( locale && flags.hasOwnProperty( locale ) ) ? flags[ locale ] : null;
|
||||
|
||||
if ( icon ) {
|
||||
icon += ' ';
|
||||
var current = $( '.pll-lang', title );
|
||||
if ( current.length ) {
|
||||
current.html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
} else {
|
||||
flag = $( '<span />' ).addClass( 'pll-lang' ).html( icon ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
|
||||
// See the comment above about the icon which is safe. So it is also safe to prepend flag which uses icon.
|
||||
title.prepend( flag ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.prepend
|
||||
}
|
||||
} else {
|
||||
$( '.pll-lang', title ).remove();
|
||||
}
|
||||
}
|
||||
|
||||
if ( isBlockEditor ) {
|
||||
|
||||
widgets_container = $( '.edit-widgets-main-block-list' );
|
||||
widgets_selector = '.widget';
|
||||
|
||||
// Update flags when we click on the legacy widget to display its form.
|
||||
widgets_container.on(
|
||||
'click',
|
||||
'.wp-block-legacy-widget',
|
||||
function () {
|
||||
add_flag( $( this ).find( '.widget' ) );
|
||||
}
|
||||
);
|
||||
|
||||
} else {
|
||||
if ( 'undefined' !== typeof wp.customize ) {
|
||||
|
||||
widgets_container = $( '#customize-controls' );
|
||||
widgets_selector = '.customize-control .widget';
|
||||
|
||||
/**
|
||||
* WP Customizer add control listener.
|
||||
*
|
||||
* @link https://wordpress.stackexchange.com/questions/256536/callback-after-wordpress-customizer-complete-loading
|
||||
*
|
||||
* @param {object} control The control type.
|
||||
* @return {void} Nothing.
|
||||
*/
|
||||
function customize_add_flag( control ) {
|
||||
if ( ! control.extended( wp.customize.Widgets.WidgetControl ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure the widget's contents are embedded; normally this is done
|
||||
* when the control is expanded, for DOM performance reasons.
|
||||
*/
|
||||
control.embedWidgetContent();
|
||||
|
||||
// Now we know for sure the widget is fully embedded.
|
||||
add_flag( control.container.find( '.widget' ) );
|
||||
}
|
||||
wp.customize.control.each( customize_add_flag );
|
||||
wp.customize.control.bind( 'add', customize_add_flag );
|
||||
|
||||
} else {
|
||||
|
||||
widgets_container = $( '#widgets-right' );
|
||||
widgets_selector = '.widget';
|
||||
|
||||
}
|
||||
|
||||
// Add flags on load.
|
||||
$( widgets_selector, widgets_container ).each(
|
||||
function () {
|
||||
add_flag( this );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Update flags.
|
||||
widgets_container.on(
|
||||
'change',
|
||||
'.pll-lang-choice',
|
||||
function () {
|
||||
add_flag( $( this ).parents( '.widget' ) );
|
||||
}
|
||||
);
|
||||
|
||||
function pll_toggle( a, test ) {
|
||||
test ? a.show() : a.hide();
|
||||
}
|
||||
|
||||
// Remove all options if dropdown is checked.
|
||||
$( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on(
|
||||
'change',
|
||||
'.pll-dropdown',
|
||||
function () {
|
||||
var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
|
||||
pll_toggle( $( '.no-dropdown-' + this_id ), true != $( this ).prop( 'checked' ) );
|
||||
}
|
||||
);
|
||||
|
||||
// Disallow unchecking both show names and show flags.
|
||||
var options = ['-show_flags', '-show_names'];
|
||||
$.each(
|
||||
options,
|
||||
function ( i, v ) {
|
||||
$( '.widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list' ).on(
|
||||
'change',
|
||||
'.pll' + v,
|
||||
function () {
|
||||
var this_id = $( this ).parent().parent().parent().children( '.widget-id' ).attr( 'value' );
|
||||
if ( true != $( this ).prop( 'checked' ) ) {
|
||||
$( '#widget-' + this_id + options[ 1 - i ] ).prop( 'checked', true );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jQuery(function(e){var t,i,n,o=void 0!==wp.blockEditor;function l(t){if(n){t=e(t);var i=o?t.prev("h3"):e(".widget-top .widget-title h3",t),l=e(".pll-lang-choice option:selected",t).val(),d=l&&n.hasOwnProperty(l)?n[l]:null;if(d){d+=" ";var s=e(".pll-lang",i);s.length?s.html(d):(flag=e("<span />").addClass("pll-lang").html(d),i.prepend(flag))}else e(".pll-lang",i).remove()}}if("undefined"!=typeof pll_widgets&&pll_widgets.hasOwnProperty("flags")&&(n=pll_widgets.flags),o)i=".widget",(t=e(".edit-widgets-main-block-list")).on("click",".wp-block-legacy-widget",function(){l(e(this).find(".widget"))});else{if(void 0!==wp.customize){function d(e){e.extended(wp.customize.Widgets.WidgetControl)&&(e.embedWidgetContent(),l(e.container.find(".widget")))}t=e("#customize-controls"),i=".customize-control .widget",wp.customize.control.each(d),wp.customize.control.bind("add",d)}else t=e("#widgets-right"),i=".widget";e(i,t).each(function(){l(this)})}t.on("change",".pll-lang-choice",function(){l(e(this).parents(".widget"))}),e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll-dropdown",function(){var t,i=e(this).parent().parent().parent().children(".widget-id").attr("value");t=e(".no-dropdown-"+i),1!=e(this).prop("checked")?t.show():t.hide()});var s=["-show_flags","-show_names"];e.each(s,function(t,i){e(".widgets-sortables,.control-section-sidebar,.edit-widgets-main-block-list").on("change",".pll"+i,function(){var i=e(this).parent().parent().parent().children(".widget-id").attr("value");1!=e(this).prop("checked")&&e("#widget-"+i+s[1-t]).prop("checked",!0)})})});
|
||||
Reference in New Issue
Block a user