PluginProbe
Polylang / 3.0.1
Polylang v3.0.1
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / js / classic-editor.js

classic-editor.js in Polylang 3.0.1, at js/classic-editor.js

342 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * @package Polylang
3 */
4
5 import {
6 initializeLanguageOldValue,
7 initializeConfimationModal
8 } from './lib/confirmation-modal';
9
10 // tag suggest in metabox
11 jQuery(
12 function( $ ) {
13 $.ajaxPrefilter(
14 function( options, originalOptions, jqXHR ) {
15 var lang = $( '.post_lang_choice' ).val();
16 if ( 'string' === typeof options.data && -1 !== options.url.indexOf( 'action=ajax-tag-search' ) && lang ) {
17 options.data = 'lang=' + lang + '&' + options.data;
18 }
19 }
20 );
21 }
22 );
23
24 // overrides tagBox.get
25 jQuery(
26 function( $ ) {
27 // overrides function to add the language
28 tagBox.get = function( id ) {
29 var tax = id.substr( id.indexOf( '-' ) + 1 );
30
31 // add the language in the $_POST variable
32 var data = {
33 action: 'get-tagcloud',
34 lang: $( '.post_lang_choice' ).val(),
35 tax: tax
36 }
37
38 $.post(
39 ajaxurl,
40 data,
41 function( r, stat ) {
42 if ( 0 == r || 'success' != stat ) {
43 r = wpAjax.broken;
44 }
45
46 // @see code from WordPress core https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/js/tags-box.js#L291
47 // @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
48 r = $( '<div />' ).addClass( 'the-tagcloud' ).attr( 'id', 'tagcloud-' + tax ).html( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
49 $( 'a', r ).on(
50 'click',
51 function(){
52 tagBox.flushTags( $( this ).closest( '.inside' ).children( '.tagsdiv' ), this );
53 return false;
54 }
55 );
56
57 var tagCloud = $( '#tagcloud-' + tax );
58 // add an if else condition to allow modifying the tags outputed when switching the language
59 var v = tagCloud.css( 'display' );
60 if ( v ) {
61 // See the comment above when r variable is created.
62 $( '#tagcloud-' + tax ).replaceWith( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
63 $( '#tagcloud-' + tax ).css( 'display', v );
64 }
65 else {
66 // See the comment above when r variable is created.
67 $( '#' + id ).after( r ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.after
68 }
69 }
70 );
71 }
72 }
73 );
74
75 jQuery(
76 function( $ ) {
77 // collect taxonomies - code partly copied from WordPress
78 var taxonomies = new Array();
79 $( '.categorydiv' ).each(
80 function(){
81 var this_id = $( this ).attr( 'id' ), taxonomyParts, taxonomy;
82
83 taxonomyParts = this_id.split( '-' );
84 taxonomyParts.shift();
85 taxonomy = taxonomyParts.join( '-' );
86 taxonomies.push( taxonomy ); // store the taxonomy for future use
87
88 // add our hidden field in the new category form - for each hierarchical taxonomy
89 // to set the language when creating a new category
90 // html code inserted come from html code itself.
91 $( '#' + taxonomy + '-add-submit' ).before( // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.before
92 $( '<input />' ).attr( 'type', 'hidden' )
93 .attr( 'id', taxonomy + '-lang' )
94 .attr( 'name', 'term_lang_choice' )
95 .attr( 'value', $( '.post_lang_choice' ).val() )
96 );
97 }
98 );
99
100 // Initialize current language to be able to compare if it changes.
101 initializeLanguageOldValue();
102
103 // ajax for changing the post's language in the languages metabox
104 $( '.post_lang_choice' ).on(
105 'change',
106 function( event ) {
107 // Initialize the confirmation dialog box.
108 const confirmationModal = initializeConfimationModal();
109 const { dialogContainer: dialog } = confirmationModal;
110 let { dialogResult } = confirmationModal;
111 // The selected option in the dropdown list.
112 const selectedOption = event.target;
113
114 if ( $( this ).data( 'old-value' ) !== selectedOption.value && ! isEmptyPost() ) {
115 dialog.dialog( 'open' );
116 } else {
117 dialogResult = Promise.resolve();
118 }
119
120 // phpcs:disable PEAR.Functions.FunctionCallSignature.EmptyLine
121 dialogResult.then(
122 () => {
123 var lang = selectedOption.options[selectedOption.options.selectedIndex].lang; // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
124 var dir = $( '.pll-translation-column > span[lang="' + lang + '"]' ).attr( 'dir' ); // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
125
126 var data = { // phpcs:ignore PEAR.Functions.FunctionCallSignature.Indent
127 action: 'post_lang_choice',
128 lang: selectedOption.value,
129 post_type: $( '#post_type' ).val(),
130 taxonomies: taxonomies,
131 post_id: $( '#post_ID' ).val(),
132 _pll_nonce: $( '#_pll_nonce' ).val()
133 }
134
135 $.post(
136 ajaxurl,
137 data,
138 function( response ) {
139 var res = wpAjax.parseAjaxResponse( response, 'ajax-response' );
140 $.each(
141 res.responses,
142 function() {
143 switch ( this.what ) {
144 case 'translations': // translations fields
145 // Data is built and come from server side and is well escaped when necessary
146 $( '.translations' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
147 init_translations();
148 break;
149 case 'taxonomy': // categories metabox for posts
150 var tax = this.data;
151 // @see wp_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L175
152 // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/class-walker-category-checklist.php#L89-L111
153 $( '#' + tax + 'checklist' ).html( this.supplemental.all ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
154 // @see wp_popular_terms_checklist https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/template.php#L236
155 $( '#' + tax + 'checklist-pop' ).html( this.supplemental.populars ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
156 // @see wp_dropdown_categories https://github.com/WordPress/WordPress/blob/5.5.1/wp-includes/category-template.php#L336
157 // which is called by PLL_Admin_Classic_Editor::post_lang_choice to generate supplemental.dropdown
158 $( '#new' + tax + '_parent' ).replaceWith( this.supplemental.dropdown ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.replaceWith
159 $( '#' + tax + '-lang' ).val( $( '.post_lang_choice' ).val() ); // hidden field
160 break;
161 case 'pages': // parent dropdown list for pages
162 // @see wp_dropdown_pages https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/post-template.php#L1186-L1208
163 // @see https://github.com/WordPress/WordPress/blob/5.2.2/wp-includes/class-walker-page-dropdown.php#L88
164 $( '#parent_id' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
165 break;
166 case 'flag': // flag in front of the select dropdown
167 // Data is built and come from server side and is well escaped when necessary
168 $( '.pll-select-flag' ).html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
169 break;
170 case 'permalink': // Sample permalink
171 var div = $( '#edit-slug-box' );
172 if ( '-1' != this.data && div.children().length ) {
173 // @see get_sample_permalink_html https://github.com/WordPress/WordPress/blob/5.2.2/wp-admin/includes/post.php#L1425-L1454
174 div.html( this.data ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
175 }
176 break;
177 }
178 }
179 );
180
181 // Update the old language with the new one to be able to compare it in the next changing.
182 initializeLanguageOldValue();
183 // modifies the language in the tag cloud
184 $( '.tagcloud-link' ).each(
185 function() {
186 var id = $( this ).attr( 'id' );
187 tagBox.get( id );
188 }
189 );
190
191 // Modifies the text direction
192 $( 'body' ).removeClass( 'pll-dir-rtl' ).removeClass( 'pll-dir-ltr' ).addClass( 'pll-dir-' + dir );
193 $( '#content_ifr' ).contents().find( 'html' ).attr( 'lang', lang ).attr( 'dir', dir );
194 $( '#content_ifr' ).contents().find( 'body' ).attr( 'dir', dir );
195
196 pll.media.resetAllAttachmentsCollections();
197 }
198 )
199 },
200 () => {} // Do nothing when promise is rejected by clicking the Cancel dialog button.
201 );
202 // phpcs:enable PEAR.Functions.FunctionCallSignature.EmptyLine
203
204 function isEmptyPost() {
205 const title = $( 'input#title' ).val();
206 const content = $( 'textarea#content' ).val();
207 const excerpt = $( 'textarea#excerpt' ).val();
208
209 return ! title && ! content && ! excerpt;
210 }
211 }
212 );
213
214 // translations autocomplete input box
215 function init_translations() {
216 $( '.tr_lang' ).each(
217 function(){
218 var tr_lang = $( this ).attr( 'id' ).substring( 8 );
219 var td = $( this ).parent().parent().siblings( '.pll-edit-column' );
220
221 $( this ).autocomplete(
222 {
223 minLength: 0,
224 source: ajaxurl + '?action=pll_posts_not_translated' +
225 '&post_language=' + $( '.post_lang_choice' ).val() +
226 '&translation_language=' + tr_lang +
227 '&post_type=' + $( '#post_type' ).val() +
228 '&_pll_nonce=' + $( '#_pll_nonce' ).val(),
229 select: function( event, ui ) {
230 $( '#htr_lang_' + tr_lang ).val( ui.item.id );
231 // ui.item.link is built and come from server side and is well escaped when necessary
232 td.html( ui.item.link ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
233 },
234 }
235 );
236
237 // when the input box is emptied
238 $( this ).on(
239 'blur',
240 function() {
241 if ( ! $( this ).val() ) {
242 $( '#htr_lang_' + tr_lang ).val( 0 );
243 // Value is retrieved from HTML already generated server side
244 td.html( td.siblings( '.hidden' ).children().clone() ); // phpcs:ignore WordPressVIPMinimum.JS.HTMLExecutingFunctions.html
245 }
246 }
247 );
248 }
249 );
250 }
251
252 init_translations();
253 }
254 );
255
256 /**
257 * @since 3.0
258 *
259 * @namespace pll
260 */
261 var pll = window.pll || {};
262
263 /**
264 * @since 3.0
265 *
266 * @namespace pll.media
267 */
268 _.extend( pll, { media: {} } );
269
270 /**
271 * @since 3.0
272 *
273 * @alias pll.media
274 * @memberOf pll
275 * @namespace
276 */
277 var media = _.extend(
278 pll.media, /** @lends pll.media.prototype */
279 {
280 /**
281 * TODO: Find a way to delete references to Attachments collections that are not used anywhere else.
282 *
283 * @type {wp.media.model.Attachments}
284 */
285 attachmentsCollections : [],
286
287 /**
288 * Imitates { @see wp.media.query } but log all Attachments collections created.
289 *
290 * @param {Object} [props]
291 * @return {wp.media.model.Attachments}
292 */
293 query: function( props ) {
294 var attachments = pll.media.query.delegate( props );
295
296 pll.media.attachmentsCollections.push( attachments );
297
298 return attachments;
299 },
300
301 resetAllAttachmentsCollections: function() {
302 this.attachmentsCollections.forEach(
303 function( attachmentsCollection ) {
304 /**
305 * First reset the { @see wp.media.model.Attachments } collection.
306 * Then, if it is mirroring a { @see wp.media.model.Query } collection,
307 * refresh this one too, so it will fetch new data from the server,
308 * and then the wp.media.model.Attachments collection will syncrhonize with the new data.
309 */
310 attachmentsCollection.reset();
311 if (attachmentsCollection.mirroring) {
312 attachmentsCollection.mirroring._hasMore = true;
313 attachmentsCollection.mirroring.reset();
314 }
315 }
316 );
317 }
318 }
319 );
320
321 if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.media ) {
322
323 /**
324 * @since 3.0
325 *
326 * @memberOf pll.media
327 */
328 media.query = _.extend(
329 media.query, /** @lends pll.media.query prototype */
330 {
331 /**
332 * @type Function References WordPress { @see wp.media.query } constructor
333 */
334 delegate: wp.media.query
335 }
336 )
337
338 // Substitute WordPress media query shortcut with our decorated function.
339 wp.media.query = media.query
340
341 }
342