PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.4.2
Secure Custom Fields v6.4.2
6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / assets / src / js / _acf-screen.js
secure-custom-fields / assets / src / js Last commit date
pro 1 year ago _acf-compatibility.js 1 year ago _acf-condition-types.js 1 year ago _acf-condition.js 1 year ago _acf-conditions.js 1 year ago _acf-field-accordion.js 1 year ago _acf-field-button-group.js 1 year ago _acf-field-checkbox.js 1 year ago _acf-field-color-picker.js 1 year ago _acf-field-date-picker.js 1 year ago _acf-field-date-time-picker.js 1 year ago _acf-field-file.js 1 year ago _acf-field-google-map.js 1 year ago _acf-field-icon-picker.js 1 year ago _acf-field-image.js 1 year ago _acf-field-link.js 1 year ago _acf-field-oembed.js 1 year ago _acf-field-page-link.js 1 year ago _acf-field-post-object.js 1 year ago _acf-field-radio.js 1 year ago _acf-field-range.js 1 year ago _acf-field-relationship.js 1 year ago _acf-field-select.js 1 year ago _acf-field-tab.js 1 year ago _acf-field-taxonomy.js 1 year ago _acf-field-time-picker.js 1 year ago _acf-field-true-false.js 1 year ago _acf-field-url.js 1 year ago _acf-field-user.js 1 year ago _acf-field-wysiwyg.js 1 year ago _acf-field.js 1 year ago _acf-fields.js 1 year ago _acf-helpers.js 1 year ago _acf-hooks.js 1 year ago _acf-internal-post-type.js 1 year ago _acf-media.js 1 year ago _acf-modal.js 1 year ago _acf-model.js 1 year ago _acf-notice.js 1 year ago _acf-panel.js 1 year ago _acf-popup.js 1 year ago _acf-postbox.js 1 year ago _acf-screen.js 1 year ago _acf-select2.js 1 year ago _acf-tinymce.js 1 year ago _acf-tooltip.js 1 year ago _acf-unload.js 1 year ago _acf-validation.js 1 year ago _acf.js 1 year ago _browse-fields-modal.js 1 year ago _field-group-compatibility.js 1 year ago _field-group-conditions.js 1 year ago _field-group-field.js 1 year ago _field-group-fields.js 1 year ago _field-group-locations.js 1 year ago _field-group-settings.js 1 year ago _field-group.js 1 year ago acf-escaped-html-notice.js 1 year ago acf-field-group.js 1 year ago acf-input.js 1 year ago acf-internal-post-type.js 1 year ago acf.js 1 year ago
_acf-screen.js
667 lines
1 ( function ( $, undefined ) {
2 acf.screen = new acf.Model( {
3 active: true,
4
5 xhr: false,
6
7 timeout: false,
8
9 wait: 'load',
10
11 events: {
12 'change #page_template': 'onChange',
13 'change #parent_id': 'onChange',
14 'change #post-formats-select': 'onChange',
15 'change .categorychecklist': 'onChange',
16 'change .tagsdiv': 'onChange',
17 'change .acf-taxonomy-field[data-save="1"]': 'onChange',
18 'change #product-type': 'onChange',
19 },
20
21 isPost: function () {
22 return acf.get( 'screen' ) === 'post';
23 },
24
25 isUser: function () {
26 return acf.get( 'screen' ) === 'user';
27 },
28
29 isTaxonomy: function () {
30 return acf.get( 'screen' ) === 'taxonomy';
31 },
32
33 isAttachment: function () {
34 return acf.get( 'screen' ) === 'attachment';
35 },
36
37 isNavMenu: function () {
38 return acf.get( 'screen' ) === 'nav_menu';
39 },
40
41 isWidget: function () {
42 return acf.get( 'screen' ) === 'widget';
43 },
44
45 isComment: function () {
46 return acf.get( 'screen' ) === 'comment';
47 },
48
49 getPageTemplate: function () {
50 var $el = $( '#page_template' );
51 return $el.length ? $el.val() : null;
52 },
53
54 getPageParent: function ( e, $el ) {
55 var $el = $( '#parent_id' );
56 return $el.length ? $el.val() : null;
57 },
58
59 getPageType: function ( e, $el ) {
60 return this.getPageParent() ? 'child' : 'parent';
61 },
62
63 getPostType: function () {
64 return $( '#post_type' ).val();
65 },
66
67 getPostFormat: function ( e, $el ) {
68 var $el = $( '#post-formats-select input:checked' );
69 if ( $el.length ) {
70 var val = $el.val();
71 return val == '0' ? 'standard' : val;
72 }
73 return null;
74 },
75
76 getPostCoreTerms: function () {
77 // vars
78 var terms = {};
79
80 // serialize WP taxonomy postboxes
81 var data = acf.serialize( $( '.categorydiv, .tagsdiv' ) );
82
83 // use tax_input (tag, custom-taxonomy) when possible.
84 // this data is already formatted in taxonomy => [terms].
85 if ( data.tax_input ) {
86 terms = data.tax_input;
87 }
88
89 // append "category" which uses a different name
90 if ( data.post_category ) {
91 terms.category = data.post_category;
92 }
93
94 // convert any string values (tags) into array format
95 for ( var tax in terms ) {
96 if ( ! acf.isArray( terms[ tax ] ) ) {
97 terms[ tax ] = terms[ tax ].split( /,[\s]?/ );
98 }
99 }
100
101 // return
102 return terms;
103 },
104
105 getPostTerms: function () {
106 // Get core terms.
107 var terms = this.getPostCoreTerms();
108
109 // loop over taxonomy fields and add their values
110 acf.getFields( { type: 'taxonomy' } ).map( function ( field ) {
111 // ignore fields that don't save
112 if ( ! field.get( 'save' ) ) {
113 return;
114 }
115
116 // vars
117 var val = field.val();
118 var tax = field.get( 'taxonomy' );
119
120 // check val
121 if ( val ) {
122 // ensure terms exists
123 terms[ tax ] = terms[ tax ] || [];
124
125 // ensure val is an array
126 val = acf.isArray( val ) ? val : [ val ];
127
128 // append
129 terms[ tax ] = terms[ tax ].concat( val );
130 }
131 } );
132
133 // add WC product type
134 if ( ( productType = this.getProductType() ) !== null ) {
135 terms.product_type = [ productType ];
136 }
137
138 // remove duplicate values
139 for ( var tax in terms ) {
140 terms[ tax ] = acf.uniqueArray( terms[ tax ] );
141 }
142
143 // return
144 return terms;
145 },
146
147 getProductType: function () {
148 var $el = $( '#product-type' );
149 return $el.length ? $el.val() : null;
150 },
151
152 check: function () {
153 // bail early if not for post
154 if ( acf.get( 'screen' ) !== 'post' ) {
155 return;
156 }
157
158 // abort XHR if is already loading AJAX data
159 if ( this.xhr ) {
160 this.xhr.abort();
161 }
162
163 // vars
164 var ajaxData = acf.parseArgs( this.data, {
165 action: 'acf/ajax/check_screen',
166 screen: acf.get( 'screen' ),
167 exists: [],
168 } );
169
170 // post id
171 if ( this.isPost() ) {
172 ajaxData.post_id = acf.get( 'post_id' );
173 }
174
175 // post type
176 if ( ( postType = this.getPostType() ) !== null ) {
177 ajaxData.post_type = postType;
178 }
179
180 // page template
181 if ( ( pageTemplate = this.getPageTemplate() ) !== null ) {
182 ajaxData.page_template = pageTemplate;
183 }
184
185 // page parent
186 if ( ( pageParent = this.getPageParent() ) !== null ) {
187 ajaxData.page_parent = pageParent;
188 }
189
190 // page type
191 if ( ( pageType = this.getPageType() ) !== null ) {
192 ajaxData.page_type = pageType;
193 }
194
195 // post format
196 if ( ( postFormat = this.getPostFormat() ) !== null ) {
197 ajaxData.post_format = postFormat;
198 }
199
200 // post terms
201 if ( ( postTerms = this.getPostTerms() ) !== null ) {
202 ajaxData.post_terms = postTerms;
203 }
204
205 // add array of existing postboxes to increase performance and reduce JSON HTML
206 acf.getPostboxes().map( function ( postbox ) {
207 ajaxData.exists.push( postbox.get( 'key' ) );
208 } );
209
210 // filter
211 ajaxData = acf.applyFilters( 'check_screen_args', ajaxData );
212
213 // success
214 var onSuccess = function ( json ) {
215 // Render post screen.
216 if ( acf.get( 'screen' ) == 'post' ) {
217 this.renderPostScreen( json );
218
219 // Render user screen.
220 } else if ( acf.get( 'screen' ) == 'user' ) {
221 this.renderUserScreen( json );
222 }
223
224 // action
225 acf.doAction( 'check_screen_complete', json, ajaxData );
226 };
227
228 // ajax
229 this.xhr = $.ajax( {
230 url: acf.get( 'ajaxurl' ),
231 data: acf.prepareForAjax( ajaxData ),
232 type: 'post',
233 dataType: 'json',
234 context: this,
235 success: onSuccess,
236 } );
237 },
238
239 onChange: function ( e, $el ) {
240 this.setTimeout( this.check, 1 );
241 },
242
243 renderPostScreen: function ( data ) {
244 // Helper function to copy events
245 var copyEvents = function ( $from, $to ) {
246 var events = $._data( $from[ 0 ] ).events;
247 for ( var type in events ) {
248 for ( var i = 0; i < events[ type ].length; i++ ) {
249 $to.on( type, events[ type ][ i ].handler );
250 }
251 }
252 };
253
254 // Helper function to sort metabox.
255 var sortMetabox = function ( id, ids ) {
256 // Find position of id within ids.
257 var index = ids.indexOf( id );
258
259 // Bail early if index not found.
260 if ( index == -1 ) {
261 return false;
262 }
263
264 // Loop over metaboxes behind (in reverse order).
265 for ( var i = index - 1; i >= 0; i-- ) {
266 if ( $( '#' + ids[ i ] ).length ) {
267 return $( '#' + ids[ i ] ).after( $( '#' + id ) );
268 }
269 }
270
271 // Loop over metaboxes infront.
272 for ( var i = index + 1; i < ids.length; i++ ) {
273 if ( $( '#' + ids[ i ] ).length ) {
274 return $( '#' + ids[ i ] ).before( $( '#' + id ) );
275 }
276 }
277
278 // Return false if not sorted.
279 return false;
280 };
281
282 // Keep track of visible and hidden postboxes.
283 data.visible = [];
284 data.hidden = [];
285
286 // Show these postboxes.
287 data.results = data.results.map( function ( result, i ) {
288 // vars
289 var postbox = acf.getPostbox( result.id );
290
291 // Prevent "acf_after_title" position in Block Editor.
292 if (
293 acf.isGutenberg() &&
294 result.position == 'acf_after_title'
295 ) {
296 result.position = 'normal';
297 }
298
299 // Create postbox if doesn't exist.
300 if ( ! postbox ) {
301 var wpMinorVersion = parseFloat( acf.get( 'wp_version' ) );
302 if ( wpMinorVersion >= 5.5 ) {
303 var postboxHeader = [
304 '<div class="postbox-header">',
305 '<h2 class="hndle ui-sortable-handle">',
306 '<span>' + acf.escHtml( result.title ) + '</span>',
307 '</h2>',
308 '<div class="handle-actions hide-if-no-js">',
309 '<button type="button" class="handlediv" aria-expanded="true">',
310 '<span class="screen-reader-text">Toggle panel: ' +
311 acf.escHtml( result.title ) +
312 '</span>',
313 '<span class="toggle-indicator" aria-hidden="true"></span>',
314 '</button>',
315 '</div>',
316 '</div>',
317 ].join( '' );
318 } else {
319 var postboxHeader = [
320 '<button type="button" class="handlediv" aria-expanded="true">',
321 '<span class="screen-reader-text">Toggle panel: ' +
322 acf.escHtml( result.title ) +
323 '</span>',
324 '<span class="toggle-indicator" aria-hidden="true"></span>',
325 '</button>',
326 '<h2 class="hndle ui-sortable-handle">',
327 '<span>' + acf.escHtml( result.title ) + '</span>',
328 '</h2>',
329 ].join( '' );
330 }
331
332 // Ensure result.classes is set.
333 if ( ! result.classes ) result.classes = '';
334
335 // Create it.
336 var $postbox = $(
337 [
338 '<div id="' +
339 result.id +
340 '" class="postbox ' +
341 result.classes +
342 '">',
343 postboxHeader,
344 '<div class="inside">',
345 result.html,
346 '</div>',
347 '</div>',
348 ].join( '' )
349 );
350
351 // Create new hide toggle.
352 if ( $( '#adv-settings' ).length ) {
353 var $prefs = $( '#adv-settings .metabox-prefs' );
354 var $label = $(
355 [
356 '<label for="' + result.id + '-hide">',
357 '<input class="hide-postbox-tog" name="' +
358 result.id +
359 '-hide" type="checkbox" id="' +
360 result.id +
361 '-hide" value="' +
362 result.id +
363 '" checked="checked">',
364 ' ' + result.title,
365 '</label>',
366 ].join( '' )
367 );
368
369 // Copy default WP events onto checkbox.
370 copyEvents(
371 $prefs.find( 'input' ).first(),
372 $label.find( 'input' )
373 );
374
375 // Append hide label
376 $prefs.append( $label );
377 }
378
379 // Copy default WP events onto metabox.
380 if ( $( '.postbox' ).length ) {
381 copyEvents(
382 $( '.postbox .handlediv' ).first(),
383 $postbox.children( '.handlediv' )
384 );
385 copyEvents(
386 $( '.postbox .hndle' ).first(),
387 $postbox.children( '.hndle' )
388 );
389 }
390
391 // Append metabox to the bottom of "side-sortables".
392 if ( result.position === 'side' ) {
393 $( '#' + result.position + '-sortables' ).append(
394 $postbox
395 );
396
397 // Prepend metabox to the top of "normal-sortbables".
398 } else {
399 $( '#' + result.position + '-sortables' ).prepend(
400 $postbox
401 );
402 }
403
404 // Position metabox amongst existing ACF metaboxes within the same location.
405 var order = [];
406 data.results.map( function ( _result ) {
407 if (
408 result.position === _result.position &&
409 $(
410 '#' +
411 result.position +
412 '-sortables #' +
413 _result.id
414 ).length
415 ) {
416 order.push( _result.id );
417 }
418 } );
419 sortMetabox( result.id, order );
420
421 // Check 'sorted' for user preference.
422 if ( data.sorted ) {
423 // Loop over each position (acf_after_title, side, normal).
424 for ( var position in data.sorted ) {
425 let order = data.sorted[ position ];
426
427 if ( typeof order !== 'string' ) {
428 continue;
429 }
430
431 // Explode string into array of ids.
432 order = order.split( ',' );
433
434 // Position metabox relative to order.
435 if ( sortMetabox( result.id, order ) ) {
436 break;
437 }
438 }
439 }
440
441 // Initalize it (modifies HTML).
442 postbox = acf.newPostbox( result );
443
444 // Trigger action.
445 acf.doAction( 'append', $postbox );
446 acf.doAction( 'append_postbox', postbox );
447 }
448
449 // show postbox
450 postbox.showEnable();
451
452 // append
453 data.visible.push( result.id );
454
455 // Return result (may have changed).
456 return result;
457 } );
458
459 // Hide these postboxes.
460 acf.getPostboxes().map( function ( postbox ) {
461 if ( data.visible.indexOf( postbox.get( 'id' ) ) === -1 ) {
462 // Hide postbox.
463 postbox.hideDisable();
464
465 // Append to data.
466 data.hidden.push( postbox.get( 'id' ) );
467 }
468 } );
469
470 // Update style.
471 $( '#acf-style' ).html( data.style );
472
473 // Do action.
474 acf.doAction( 'refresh_post_screen', data );
475 },
476
477 renderUserScreen: function ( json ) {},
478 } );
479
480 /**
481 * gutenScreen
482 *
483 * Adds compatibility with the Gutenberg edit screen.
484 *
485 * @date 11/12/18
486 * @since ACF 5.8.0
487 *
488 * @param void
489 * @return void
490 */
491 var gutenScreen = new acf.Model( {
492 // Keep a reference to the most recent post attributes.
493 postEdits: {},
494
495 // Wait until assets have been loaded.
496 wait: 'prepare',
497
498 initialize: function () {
499 // Bail early if not Gutenberg.
500 if ( ! acf.isGutenbergPostEditor() ) {
501 return;
502 }
503
504 // Listen for changes (use debounced version as this can fires often).
505 wp.data.subscribe( acf.debounce( this.onChange ).bind( this ) );
506
507 // Customize "acf.screen.get" functions.
508 acf.screen.getPageTemplate = this.getPageTemplate;
509 acf.screen.getPageParent = this.getPageParent;
510 acf.screen.getPostType = this.getPostType;
511 acf.screen.getPostFormat = this.getPostFormat;
512 acf.screen.getPostCoreTerms = this.getPostCoreTerms;
513
514 // Disable unload
515 acf.unload.disable();
516
517 // Refresh metaboxes since WP 5.3.
518 var wpMinorVersion = parseFloat( acf.get( 'wp_version' ) );
519 if ( wpMinorVersion >= 5.3 ) {
520 this.addAction(
521 'refresh_post_screen',
522 this.onRefreshPostScreen
523 );
524 }
525
526 // Trigger "refresh" after WP has moved metaboxes into place.
527 wp.domReady( acf.refresh );
528 },
529
530 onChange: function () {
531 // Determine attributes that can trigger a refresh.
532 var attributes = [ 'template', 'parent', 'format' ];
533
534 // Append taxonomy attribute names to this list.
535 ( wp.data.select( 'core' ).getTaxonomies() || [] ).map( function (
536 taxonomy
537 ) {
538 attributes.push( taxonomy.rest_base );
539 } );
540
541 // Get relevant current post edits.
542 var _postEdits = wp.data.select( 'core/editor' ).getPostEdits();
543 var postEdits = {};
544 attributes.map( function ( k ) {
545 if ( _postEdits[ k ] !== undefined ) {
546 postEdits[ k ] = _postEdits[ k ];
547 }
548 } );
549
550 // Detect change.
551 if (
552 JSON.stringify( postEdits ) !== JSON.stringify( this.postEdits )
553 ) {
554 this.postEdits = postEdits;
555
556 // Check screen.
557 acf.screen.check();
558 }
559 },
560
561 getPageTemplate: function () {
562 return wp.data
563 .select( 'core/editor' )
564 .getEditedPostAttribute( 'template' );
565 },
566
567 getPageParent: function ( e, $el ) {
568 return wp.data
569 .select( 'core/editor' )
570 .getEditedPostAttribute( 'parent' );
571 },
572
573 getPostType: function () {
574 return wp.data
575 .select( 'core/editor' )
576 .getEditedPostAttribute( 'type' );
577 },
578
579 getPostFormat: function ( e, $el ) {
580 return wp.data
581 .select( 'core/editor' )
582 .getEditedPostAttribute( 'format' );
583 },
584
585 getPostCoreTerms: function () {
586 // vars
587 var terms = {};
588
589 // Loop over taxonomies.
590 var taxonomies = wp.data.select( 'core' ).getTaxonomies() || [];
591 taxonomies.map( function ( taxonomy ) {
592 // Append selected taxonomies to terms object.
593 var postTerms = wp.data
594 .select( 'core/editor' )
595 .getEditedPostAttribute( taxonomy.rest_base );
596 if ( postTerms ) {
597 terms[ taxonomy.slug ] = postTerms;
598 }
599 } );
600
601 // return
602 return terms;
603 },
604
605 /**
606 * onRefreshPostScreen
607 *
608 * Fires after the Post edit screen metaboxs are refreshed to update the Block Editor API state.
609 *
610 * @date 11/11/19
611 * @since ACF 5.8.7
612 *
613 * @param object data The "check_screen" JSON response data.
614 * @return void
615 */
616 onRefreshPostScreen: function ( data ) {
617
618 // Extract vars.
619 var select = wp.data.select( 'core/edit-post' );
620 var dispatch = wp.data.dispatch( 'core/edit-post' );
621
622 // Load current metabox locations and data.
623 var locations = {};
624 select.getActiveMetaBoxLocations().map( function ( location ) {
625 locations[ location ] = select.getMetaBoxesPerLocation(
626 location
627 );
628 } );
629
630 // Generate flat array of existing ids.
631 var ids = [];
632 for ( var k in locations ) {
633 locations[ k ].map( function ( m ) {
634 ids.push( m.id );
635 } );
636 }
637
638 // Append new ACF metaboxes (ignore those which already exist).
639 data.results
640 .filter( function ( r ) {
641 return ids.indexOf( r.id ) === -1;
642 } )
643 .map( function ( result, i ) {
644 // Ensure location exists.
645 var location = result.position;
646 locations[ location ] = locations[ location ] || [];
647
648 // Append.
649 locations[ location ].push( {
650 id: result.id,
651 title: result.title,
652 } );
653 } );
654
655 // Remove hidden ACF metaboxes.
656 for ( var k in locations ) {
657 locations[ k ] = locations[ k ].filter( function ( m ) {
658 return data.hidden.indexOf( m.id ) === -1;
659 } );
660 }
661
662 // Update state.
663 dispatch.setAvailableMetaBoxesPerLocation( locations );
664 },
665 } );
666 } )( jQuery );
667