PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / trunk
Secure Custom Fields vtrunk
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
bindings 6 months ago commands 2 weeks ago pro 2 weeks ago _acf-compatibility.js 1 year ago _acf-condition-types.js 7 months ago _acf-condition.js 1 year ago _acf-conditions.js 1 year ago _acf-field-accordion.js 6 months ago _acf-field-button-group.js 7 months ago _acf-field-checkbox.js 1 month ago _acf-field-color-picker.js 7 months ago _acf-field-date-picker.js 1 month ago _acf-field-date-time-picker.js 1 month ago _acf-field-file.js 1 month ago _acf-field-google-map.js 6 months ago _acf-field-icon-picker.js 1 month ago _acf-field-image.js 1 month ago _acf-field-link.js 1 year ago _acf-field-oembed.js 1 month ago _acf-field-page-link.js 1 year ago _acf-field-post-object.js 1 year ago _acf-field-radio.js 1 month ago _acf-field-range.js 1 year ago _acf-field-relationship.js 1 month ago _acf-field-select.js 1 month ago _acf-field-tab.js 3 weeks ago _acf-field-taxonomy.js 7 months ago _acf-field-time-picker.js 1 month ago _acf-field-true-false.js 1 month ago _acf-field-url.js 1 year ago _acf-field-user.js 1 year ago _acf-field-wysiwyg.js 1 month 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 7 months ago _acf-media.js 2 weeks ago _acf-modal.js 1 year ago _acf-model.js 1 year ago _acf-notice.js 7 months ago _acf-panel.js 1 year ago _acf-popup.js 7 months ago _acf-postbox.js 1 year ago _acf-screen.js 10 months ago _acf-select2.js 1 year ago _acf-tinymce.js 6 months ago _acf-tooltip.js 10 months ago _acf-unload.js 1 year ago _acf-validation.js 1 month ago _acf.js 7 months ago _browse-fields-modal.js 7 months ago _field-group-compatibility.js 1 year ago _field-group-conditions.js 1 year ago _field-group-field.js 3 months ago _field-group-fields.js 10 months ago _field-group-locations.js 1 year ago _field-group-settings.js 1 year ago _field-group.js 10 months 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
646 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 postboxHeader = [
302 '<div class="postbox-header">',
303 '<h2 class="hndle ui-sortable-handle">',
304 '<span>' + result.title + '</span>',
305 '</h2>',
306 '<div class="handle-actions hide-if-no-js">',
307 '<button type="button" class="handlediv" aria-expanded="true">',
308 '<span class="screen-reader-text">' +
309 acf.__( 'Toggle panel' ) +
310 ': ' +
311 result.title +
312 '</span>',
313 '<span class="toggle-indicator" aria-hidden="true"></span>',
314 '</button>',
315 '</div>',
316 '</div>',
317 ].join( '' );
318
319 // Ensure result.classes is set.
320 if ( ! result.classes ) result.classes = '';
321
322 // Create it.
323 var $postbox = $(
324 [
325 '<div id="' +
326 result.id +
327 '" class="postbox ' +
328 result.classes +
329 '">',
330 postboxHeader,
331 '<div class="inside">',
332 result.html,
333 '</div>',
334 '</div>',
335 ].join( '' )
336 );
337
338 // Create new hide toggle.
339 if ( $( '#adv-settings' ).length ) {
340 var $prefs = $( '#adv-settings .metabox-prefs' );
341 var $label = $(
342 [
343 '<label for="' + result.id + '-hide">',
344 '<input class="hide-postbox-tog" name="' +
345 result.id +
346 '-hide" type="checkbox" id="' +
347 result.id +
348 '-hide" value="' +
349 result.id +
350 '" checked="checked">',
351 ' ' + result.title,
352 '</label>',
353 ].join( '' )
354 );
355
356 // Copy default WP events onto checkbox.
357 copyEvents(
358 $prefs.find( 'input' ).first(),
359 $label.find( 'input' )
360 );
361
362 // Append hide label
363 $prefs.append( $label );
364 }
365
366 // Copy default WP events onto metabox.
367 if ( $( '.postbox' ).length ) {
368 copyEvents(
369 $( '.postbox .handlediv' ).first(),
370 $postbox.children( '.handlediv' )
371 );
372 copyEvents(
373 $( '.postbox .hndle' ).first(),
374 $postbox.children( '.hndle' )
375 );
376 }
377
378 // Append metabox to the bottom of "side-sortables".
379 if ( result.position === 'side' ) {
380 $( '#' + result.position + '-sortables' ).append(
381 $postbox
382 );
383
384 // Prepend metabox to the top of "normal-sortbables".
385 } else {
386 $( '#' + result.position + '-sortables' ).prepend(
387 $postbox
388 );
389 }
390
391 // Position metabox amongst existing ACF metaboxes within the same location.
392 var order = [];
393 data.results.map( function ( _result ) {
394 if (
395 result.position === _result.position &&
396 $(
397 '#' +
398 result.position +
399 '-sortables #' +
400 _result.id
401 ).length
402 ) {
403 order.push( _result.id );
404 }
405 } );
406 sortMetabox( result.id, order );
407
408 // Check 'sorted' for user preference.
409 if ( data.sorted ) {
410 // Loop over each position (acf_after_title, side, normal).
411 for ( var position in data.sorted ) {
412 let order = data.sorted[ position ];
413
414 if ( typeof order !== 'string' ) {
415 continue;
416 }
417
418 // Explode string into array of ids.
419 order = order.split( ',' );
420
421 // Position metabox relative to order.
422 if ( sortMetabox( result.id, order ) ) {
423 break;
424 }
425 }
426 }
427
428 // Initalize it (modifies HTML).
429 postbox = acf.newPostbox( result );
430
431 // Trigger action.
432 acf.doAction( 'append', $postbox );
433 acf.doAction( 'append_postbox', postbox );
434 }
435
436 // show postbox
437 postbox.showEnable();
438
439 // append
440 data.visible.push( result.id );
441
442 // Return result (may have changed).
443 return result;
444 } );
445
446 // Hide these postboxes.
447 acf.getPostboxes().map( function ( postbox ) {
448 if ( data.visible.indexOf( postbox.get( 'id' ) ) === -1 ) {
449 // Hide postbox.
450 postbox.hideDisable();
451
452 // Append to data.
453 data.hidden.push( postbox.get( 'id' ) );
454 }
455 } );
456
457 // Update style.
458 $( '#acf-style' ).html( data.style );
459
460 // Do action.
461 acf.doAction( 'refresh_post_screen', data );
462 },
463
464 renderUserScreen: function ( json ) {},
465 } );
466
467 /**
468 * gutenScreen
469 *
470 * Adds compatibility with the Gutenberg edit screen.
471 *
472 * @date 11/12/18
473 * @since ACF 5.8.0
474 *
475 * @param void
476 * @return void
477 */
478 var gutenScreen = new acf.Model( {
479 // Keep a reference to the most recent post attributes.
480 postEdits: {},
481
482 // Wait until assets have been loaded.
483 wait: 'prepare',
484
485 initialize: function () {
486 // Bail early if not Gutenberg.
487 if ( ! acf.isGutenbergPostEditor() ) {
488 return;
489 }
490
491 // Listen for changes (use debounced version as this can fires often).
492 wp.data.subscribe( acf.debounce( this.onChange ).bind( this ) );
493
494 // Customize "acf.screen.get" functions.
495 acf.screen.getPageTemplate = this.getPageTemplate;
496 acf.screen.getPageParent = this.getPageParent;
497 acf.screen.getPostType = this.getPostType;
498 acf.screen.getPostFormat = this.getPostFormat;
499 acf.screen.getPostCoreTerms = this.getPostCoreTerms;
500
501 // Disable unload
502 acf.unload.disable();
503
504 // Refresh metaboxes since WP 5.3.
505 this.addAction( 'refresh_post_screen', this.onRefreshPostScreen );
506
507 // Trigger "refresh" after WP has moved metaboxes into place.
508 wp.domReady( acf.refresh );
509 },
510
511 onChange: function () {
512 // Determine attributes that can trigger a refresh.
513 var attributes = [ 'template', 'parent', 'format' ];
514
515 // Append taxonomy attribute names to this list.
516 ( wp.data.select( 'core' ).getTaxonomies() || [] ).map(
517 function ( taxonomy ) {
518 attributes.push( taxonomy.rest_base );
519 }
520 );
521
522 // Get relevant current post edits.
523 var _postEdits = wp.data.select( 'core/editor' ).getPostEdits();
524 var postEdits = {};
525 attributes.map( function ( k ) {
526 if ( _postEdits[ k ] !== undefined ) {
527 postEdits[ k ] = _postEdits[ k ];
528 }
529 } );
530
531 // Detect change.
532 if (
533 JSON.stringify( postEdits ) !== JSON.stringify( this.postEdits )
534 ) {
535 this.postEdits = postEdits;
536
537 // Check screen.
538 acf.screen.check();
539 }
540 },
541
542 getPageTemplate: function () {
543 return wp.data
544 .select( 'core/editor' )
545 .getEditedPostAttribute( 'template' );
546 },
547
548 getPageParent: function ( e, $el ) {
549 return wp.data
550 .select( 'core/editor' )
551 .getEditedPostAttribute( 'parent' );
552 },
553
554 getPostType: function () {
555 return wp.data
556 .select( 'core/editor' )
557 .getEditedPostAttribute( 'type' );
558 },
559
560 getPostFormat: function ( e, $el ) {
561 return wp.data
562 .select( 'core/editor' )
563 .getEditedPostAttribute( 'format' );
564 },
565
566 getPostCoreTerms: function () {
567 // vars
568 var terms = {};
569
570 // Loop over taxonomies.
571 var taxonomies = wp.data.select( 'core' ).getTaxonomies() || [];
572 taxonomies.map( function ( taxonomy ) {
573 // Append selected taxonomies to terms object.
574 var postTerms = wp.data
575 .select( 'core/editor' )
576 .getEditedPostAttribute( taxonomy.rest_base );
577 if ( postTerms ) {
578 terms[ taxonomy.slug ] = postTerms;
579 }
580 } );
581
582 // return
583 return terms;
584 },
585
586 /**
587 * onRefreshPostScreen
588 *
589 * Fires after the Post edit screen metaboxs are refreshed to update the Block Editor API state.
590 *
591 * @date 11/11/19
592 * @since ACF 5.8.7
593 *
594 * @param object data The "check_screen" JSON response data.
595 * @return void
596 */
597 onRefreshPostScreen: function ( data ) {
598 // Extract vars.
599 var select = wp.data.select( 'core/edit-post' );
600 var dispatch = wp.data.dispatch( 'core/edit-post' );
601
602 // Load current metabox locations and data.
603 var locations = {};
604 select.getActiveMetaBoxLocations().map( function ( location ) {
605 locations[ location ] =
606 select.getMetaBoxesPerLocation( location );
607 } );
608
609 // Generate flat array of existing ids.
610 var ids = [];
611 for ( var k in locations ) {
612 locations[ k ].map( function ( m ) {
613 ids.push( m.id );
614 } );
615 }
616
617 // Append new ACF metaboxes (ignore those which already exist).
618 data.results
619 .filter( function ( r ) {
620 return ids.indexOf( r.id ) === -1;
621 } )
622 .map( function ( result, i ) {
623 // Ensure location exists.
624 var location = result.position;
625 locations[ location ] = locations[ location ] || [];
626
627 // Append.
628 locations[ location ].push( {
629 id: result.id,
630 title: result.title,
631 } );
632 } );
633
634 // Remove hidden ACF metaboxes.
635 for ( var k in locations ) {
636 locations[ k ] = locations[ k ].filter( function ( m ) {
637 return data.hidden.indexOf( m.id ) === -1;
638 } );
639 }
640
641 // Update state.
642 dispatch.setAvailableMetaBoxesPerLocation( locations );
643 },
644 } );
645 } )( jQuery );
646