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-field-tab.js
secure-custom-fields / assets / src / js Last commit date
bindings 6 months ago commands 3 weeks ago pro 3 weeks ago _acf-compatibility.js 1 year ago _acf-condition-types.js 8 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 8 months ago _acf-field-checkbox.js 1 month ago _acf-field-color-picker.js 8 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 1 month ago _acf-field-taxonomy.js 8 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 8 months ago _acf-media.js 3 weeks ago _acf-modal.js 1 year ago _acf-model.js 1 year ago _acf-notice.js 8 months ago _acf-panel.js 1 year ago _acf-popup.js 8 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 8 months ago _field-group-compatibility.js 1 year ago _field-group-conditions.js 1 year ago _field-group-field.js 4 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-field-tab.js
591 lines
1 ( function ( $, undefined ) {
2 // vars
3 var CONTEXT = 'tab';
4
5 var Field = acf.Field.extend( {
6 type: 'tab',
7
8 wait: '',
9
10 tabs: false,
11
12 tab: false,
13
14 events: {
15 duplicateField: 'onDuplicate',
16 },
17
18 findFields: function () {
19 let filter;
20
21 /**
22 * Tabs in the admin UI that can be extended by third
23 * parties have the child settings wrapped inside an extra div,
24 * so we need to look for that instead of an adjacent .acf-field.
25 */
26 switch ( this.get( 'key' ) ) {
27 case 'acf_field_settings_tabs':
28 filter = '.acf-field-settings-main';
29 break;
30 case 'acf_field_group_settings_tabs':
31 filter = '.field-group-settings-tab';
32 break;
33 case 'acf_browse_fields_tabs':
34 filter = '.acf-field-types-tab';
35 break;
36 case 'acf_icon_picker_tabs':
37 filter = '.acf-icon-picker-tabs';
38 break;
39 case 'acf_post_type_tabs':
40 filter = '.acf-post-type-advanced-settings';
41 break;
42 case 'acf_taxonomy_tabs':
43 filter = '.acf-taxonomy-advanced-settings';
44 break;
45 case 'acf_ui_options_page_tabs':
46 filter = '.acf-ui-options-page-advanced-settings';
47 break;
48 default:
49 filter = '.acf-field';
50 }
51
52 return this.$el.nextUntil( '.acf-field-tab', filter );
53 },
54
55 getFields: function () {
56 return acf.getFields( this.findFields() );
57 },
58
59 findTabs: function () {
60 return this.$el.prevAll( '.acf-tab-wrap:first' );
61 },
62
63 findTab: function () {
64 return this.$( '.acf-tab-button' );
65 },
66
67 initialize: function () {
68 // bail early if is td
69 if ( this.$el.is( 'td' ) ) {
70 this.events = {};
71 return false;
72 }
73
74 // vars
75 var $tabs = this.findTabs();
76 var $tab = this.findTab();
77 var settings = acf.parseArgs( $tab.data(), {
78 endpoint: false,
79 placement: '',
80 before: this.$el,
81 } );
82
83 // create wrap
84 if ( ! $tabs.length || settings.endpoint ) {
85 this.tabs = new Tabs( settings );
86 } else {
87 this.tabs = $tabs.data( 'acf' );
88 }
89
90 // add tab
91 this.tab = this.tabs.addTab( $tab, this );
92 },
93
94 isActive: function () {
95 return this.tab.isActive();
96 },
97
98 showFields: function () {
99 // show fields
100 this.getFields().map( function ( field ) {
101 field.show( this.cid, CONTEXT );
102 field.hiddenByTab = false;
103 }, this );
104 },
105
106 hideFields: function () {
107 // hide fields
108 this.getFields().map( function ( field ) {
109 field.hide( this.cid, CONTEXT );
110 field.hiddenByTab = this.tab;
111 }, this );
112 },
113
114 show: function ( lockKey ) {
115 // show field and store result
116 var visible = acf.Field.prototype.show.apply( this, arguments );
117
118 // check if now visible
119 if ( visible ) {
120 // show tab
121 this.tab.show();
122
123 // check active tabs
124 this.tabs.refresh();
125 }
126
127 // return
128 return visible;
129 },
130
131 hide: function ( lockKey ) {
132 // hide field and store result
133 var hidden = acf.Field.prototype.hide.apply( this, arguments );
134
135 // check if now hidden
136 if ( hidden ) {
137 // hide tab
138 this.tab.hide();
139
140 // reset tabs if this was active
141 if ( this.isActive() ) {
142 this.tabs.reset();
143 }
144 }
145
146 // return
147 return hidden;
148 },
149
150 enable: function ( lockKey ) {
151 // enable fields
152 this.getFields().map( function ( field ) {
153 field.enable( CONTEXT );
154 } );
155 },
156
157 disable: function ( lockKey ) {
158 // disable fields
159 this.getFields().map( function ( field ) {
160 field.disable( CONTEXT );
161 } );
162 },
163
164 onDuplicate: function ( e, $el, $duplicate ) {
165 if ( this.isActive() ) {
166 $duplicate.prevAll( '.acf-tab-wrap:first' ).remove();
167 }
168 },
169 } );
170
171 acf.registerFieldType( Field );
172
173 /**
174 * tabs
175 *
176 * description
177 *
178 * @date 8/2/18
179 * @since ACF 5.6.5
180 *
181 * @param type $var Description. Default.
182 * @return type Description.
183 */
184
185 var i = 0;
186 var Tabs = acf.Model.extend( {
187 tabs: [],
188
189 active: false,
190
191 actions: {
192 refresh: 'onRefresh',
193 close_field_object: 'onCloseFieldObject',
194 },
195
196 data: {
197 before: false,
198 placement: 'top',
199 index: 0,
200 initialized: false,
201 },
202
203 setup: function ( settings ) {
204 // data
205 $.extend( this.data, settings );
206
207 // define this prop to avoid scope issues
208 this.tabs = [];
209 this.active = false;
210
211 // vars
212 var placement = this.get( 'placement' );
213 var $before = this.get( 'before' );
214 var $parent = $before.parent();
215
216 // add sidebar for left placement
217 if ( placement == 'left' && $parent.hasClass( 'acf-fields' ) ) {
218 $parent.addClass( '-sidebar' );
219 }
220
221 // create wrap
222 if ( $before.is( 'tr' ) ) {
223 this.$el = $(
224 '<tr class="acf-tab-wrap"><td colspan="2"><ul class="acf-hl acf-tab-group"></ul></td></tr>'
225 );
226 } else {
227 let ulClass = 'acf-hl acf-tab-group';
228
229 if ( this.get( 'key' ) === 'acf_field_settings_tabs' ) {
230 ulClass = 'acf-field-settings-tab-bar';
231 }
232
233 this.$el = $(
234 '<div class="acf-tab-wrap -' +
235 placement +
236 '"><ul class="' +
237 ulClass +
238 '"></ul></div>'
239 );
240 }
241
242 // append
243 $before.before( this.$el );
244
245 // set index
246 this.set( 'index', i, true );
247 i++;
248 },
249
250 initializeTabs: function () {
251 // Bail if tabs are disabled.
252 if (
253 'acf_field_settings_tabs' === this.get( 'key' ) &&
254 $( '#acf-field-group-fields' ).hasClass( 'hide-tabs' )
255 ) {
256 return;
257 }
258
259 var tab = false;
260
261 // check if we've got a saved default tab.
262 var order = acf.getPreference( 'this.tabs' ) || false;
263 if ( order ) {
264 var groupIndex = this.get( 'index' );
265 var tabIndex = order[ groupIndex ];
266 if (
267 this.tabs[ tabIndex ] &&
268 this.tabs[ tabIndex ].isVisible()
269 ) {
270 tab = this.tabs[ tabIndex ];
271 }
272 }
273
274 // If we've got a defaultTab provided by configuration, use that.
275 if (
276 ! tab &&
277 this.data.defaultTab &&
278 this.data.defaultTab.isVisible()
279 ) {
280 tab = this.data.defaultTab;
281 }
282
283 // find first visible tab as our default.
284 if ( ! tab ) {
285 tab = this.getVisible().shift();
286 }
287
288 if ( tab ) {
289 this.selectTab( tab );
290 } else {
291 this.closeTabs();
292 }
293
294 // set local variable used by tabsManager
295 this.set( 'initialized', true );
296 },
297
298 getVisible: function () {
299 return this.tabs.filter( function ( tab ) {
300 return tab.isVisible();
301 } );
302 },
303
304 getActive: function () {
305 return this.active;
306 },
307
308 setActive: function ( tab ) {
309 return ( this.active = tab );
310 },
311
312 hasActive: function () {
313 return this.active !== false;
314 },
315
316 isActive: function ( tab ) {
317 var active = this.getActive();
318 return active && active.cid === tab.cid;
319 },
320
321 closeActive: function () {
322 if ( this.hasActive() ) {
323 this.closeTab( this.getActive() );
324 }
325 },
326
327 openTab: function ( tab ) {
328 // close existing tab
329 this.closeActive();
330
331 // open
332 tab.open();
333
334 // set active
335 this.setActive( tab );
336
337 // Recalculate admin menu pinning so a previously taller tab (e.g. one
338 // containing WYSIWYG fields) doesn't leave the menu pinned against a
339 // shorter page, which can lock page scroll.
340 $( document ).trigger( 'wp-pin-menu' );
341 },
342
343 closeTab: function ( tab ) {
344 // close
345 tab.close();
346
347 // set active
348 this.setActive( false );
349 },
350
351 closeTabs: function () {
352 this.tabs.map( this.closeTab, this );
353 },
354
355 selectTab: function ( tab ) {
356 // close other tabs
357 this.tabs.map( function ( t ) {
358 if ( tab.cid !== t.cid ) {
359 this.closeTab( t );
360 }
361 }, this );
362
363 // open
364 this.openTab( tab );
365 },
366
367 addTab: function ( $a, field ) {
368 // create <li>
369 var $li = $( '<li>' + $a.outerHTML() + '</li>' );
370
371 // add settings type class.
372 var settingsType = $a.data( 'settings-type' );
373 if ( settingsType ) {
374 $li.addClass( 'acf-settings-type-' + settingsType );
375 }
376
377
378 // append
379 this.$( 'ul' ).append( $li );
380
381 // initialize
382 var tab = new Tab( {
383 $el: $li,
384 field: field,
385 group: this,
386 } );
387
388 // store
389 this.tabs.push( tab );
390
391 if ( $a.data( 'selected' ) ) {
392 this.data.defaultTab = tab;
393 }
394
395 // return
396 return tab;
397 },
398
399 reset: function () {
400 // close existing tab
401 this.closeActive();
402
403 // find and active a tab
404 return this.refresh();
405 },
406
407 refresh: function () {
408 // bail early if active already exists
409 if ( this.hasActive() ) {
410 return false;
411 }
412 // find next active tab
413 var tab = this.getVisible().shift();
414 // open tab
415 if ( tab ) {
416 this.openTab( tab );
417 }
418
419 // return
420 return tab;
421 },
422
423 onRefresh: function () {
424 // only for left placements
425 if ( this.get( 'placement' ) !== 'left' ) {
426 return;
427 }
428
429 // vars
430 var $parent = this.$el.parent();
431 var $list = this.$el.children( 'ul' );
432 var attribute = $parent.is( 'td' ) ? 'height' : 'min-height';
433
434 // find height (minus 1 for border-bottom)
435 var height = $list.position().top + $list.outerHeight( true ) - 1;
436
437 // add css
438 $parent.css( attribute, height );
439 },
440
441 onCloseFieldObject: function ( fieldObject ) {
442 const tab = this.getVisible().find( ( item ) => {
443 const id = item.$el.closest( 'div[data-id]' ).data( 'id' );
444 if ( fieldObject.data.id === id ) {
445 return item;
446 }
447 } );
448
449 if ( tab ) {
450 // Wait for field group drawer to close
451 setTimeout( () => {
452 this.openTab( tab );
453 }, 300 );
454 }
455 },
456 } );
457
458 var Tab = acf.Model.extend( {
459 group: false,
460
461 field: false,
462
463 events: {
464 'click a': 'onClick',
465 },
466
467 index: function () {
468 return this.$el.index();
469 },
470
471 isVisible: function () {
472 return acf.isVisible( this.$el );
473 },
474
475 isActive: function () {
476 return this.$el.hasClass( 'active' );
477 },
478
479 open: function () {
480 // add class
481 this.$el.addClass( 'active' );
482
483 // show field
484 this.field.showFields();
485 },
486
487 close: function () {
488 // remove class
489 this.$el.removeClass( 'active' );
490
491 // hide field
492 this.field.hideFields();
493 },
494
495 onClick: function ( e, $el ) {
496 // prevent default
497 e.preventDefault();
498
499 // toggle
500 this.toggle();
501 },
502
503 toggle: function () {
504 // bail early if already active
505 if ( this.isActive() ) {
506 return;
507 }
508
509 // toggle this tab
510 this.group.openTab( this );
511 },
512 } );
513
514 var tabsManager = new acf.Model( {
515 priority: 50,
516
517 actions: {
518 prepare: 'render',
519 append: 'render',
520 unload: 'onUnload',
521 show: 'render',
522 invalid_field: 'onInvalidField',
523 },
524
525 findTabs: function () {
526 return $( '.acf-tab-wrap' );
527 },
528
529 getTabs: function () {
530 return acf.getInstances( this.findTabs() );
531 },
532
533 render: function ( $el ) {
534 this.getTabs().map( function ( tabs ) {
535 if ( ! tabs.get( 'initialized' ) ) {
536 tabs.initializeTabs();
537 }
538 } );
539 },
540
541 onInvalidField: function ( field ) {
542 // bail early if busy
543 if ( this.busy ) {
544 return;
545 }
546
547 // ignore if not hidden by tab
548 if ( ! field.hiddenByTab ) {
549 return;
550 }
551
552 // toggle tab
553 field.hiddenByTab.toggle();
554
555 // ignore other invalid fields
556 this.busy = true;
557 this.setTimeout( function () {
558 this.busy = false;
559 }, 100 );
560 },
561
562 onUnload: function () {
563 // vars
564 var order = [];
565
566 // loop
567 this.getTabs().map( function ( group ) {
568 // Do not save selected tab on field settings, or an acf-advanced-settings when unloading
569 if (
570 group.$el.children( '.acf-field-settings-tab-bar' )
571 .length ||
572 group.$el.parents( '#acf-advanced-settings.postbox' ).length
573 ) {
574 return true;
575 }
576
577 var active = group.hasActive() ? group.getActive().index() : 0;
578 order.push( active );
579 } );
580
581 // bail if no tabs
582 if ( ! order.length ) {
583 return;
584 }
585
586 // update
587 acf.setPreference( 'this.tabs', order );
588 },
589 } );
590 } )( jQuery );
591