PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / 6.8.8
Secure Custom Fields v6.8.8
6.9.5 6.9.4 6.9.3 6.9.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 / pro / _acf-setting-flexible-content.js
secure-custom-fields / assets / src / js / pro Last commit date
blocks-v3 2 months ago _acf-blocks-v3.js 4 months ago _acf-blocks.js 4 months ago _acf-field-flexible-content.js 4 months ago _acf-field-gallery.js 3 months ago _acf-field-repeater.js 4 months ago _acf-jsx-names.js 1 year ago _acf-setting-clone.js 1 year ago _acf-setting-flexible-content.js 1 year ago _acf-setting-repeater.js 1 year ago _acf-ui-options-page.js 9 months ago acf-datastore.js 3 months ago acf-field-bindings.js 3 months ago acf-pro-blocks.js 9 months ago acf-pro-field-group.js 1 year ago acf-pro-input.js 1 year ago acf-pro-ui-options-page.js 1 year ago
_acf-setting-flexible-content.js
431 lines
1 ( function ( $ ) {
2 /**
3 * CloneDisplayFieldSetting
4 *
5 * Extra logic for this field setting
6 *
7 * @date 18/4/18
8 * @since ACF 5.6.9
9 *
10 * @param void
11 * @return void
12 */
13
14 var FlexibleContentLayoutFieldSetting = acf.FieldSetting.extend( {
15 type: 'flexible_content',
16 name: 'fc_layout',
17
18 events: {
19 'blur .layout-label': 'onChangeLabel',
20 'blur .layout-name': 'onChangeName',
21 'click .add-layout': 'onClickAdd',
22 'click .acf-field-settings-fc_head': 'onClickEdit',
23 'click .acf-field-setting-fc-duplicate': 'onClickDuplicate',
24 'click .acf-field-setting-fc-delete': 'onClickDelete',
25 'changed:layoutLabel': 'updateLayoutTitles',
26 'changed:layoutName': 'updateLayoutTitles',
27 },
28
29 $input: function ( name ) {
30 return $( '#' + this.getInputId() + '-' + name );
31 },
32
33 $list: function () {
34 return this.$( '.acf-field-list:first' );
35 },
36
37 getInputId: function () {
38 return (
39 this.fieldObject.getInputId() +
40 '-layouts-' +
41 this.field.get( 'id' )
42 );
43 },
44
45 // get all sub fields
46 getFields: function () {
47 return acf.getFieldObjects( { parent: this.$el } );
48 },
49
50 // get immediate children
51 getChildren: function () {
52 return acf.getFieldObjects( { list: this.$list() } );
53 },
54
55 initialize: function () {
56 // add sortable
57 var $tbody = this.$el.parent();
58 $tbody.css( 'position', 'relative' );
59
60 if ( ! $tbody.hasClass( 'ui-sortable' ) ) {
61 $tbody.sortable( {
62 items: '> .acf-field-setting-fc_layout',
63 handle: '.acf-fc_draggable',
64 zIndex: 9999,
65 forceHelperSize: true,
66 forcePlaceholderSize: true,
67 scroll: true,
68 stop: this.proxy( function ( event, ui ) {
69 this.fieldObject.save();
70 } ),
71 } );
72 }
73
74 // add meta to sub fields
75 this.updateFieldLayouts();
76 this.updateLayoutTitles();
77 },
78
79 updateFieldLayouts: function () {
80 this.getChildren().map( this.updateFieldLayout, this );
81 },
82
83 updateFieldLayout: function ( field ) {
84 field.prop( 'parent_layout', this.get( 'id' ) );
85 },
86
87 updateLayoutTitles: function () {
88 const label = this.get( 'layoutLabel' );
89 const name = this.get( 'layoutName' );
90
91 const $layoutHeaderLabelText = this.$el.find(
92 '> .acf-label .acf-fc-layout-label'
93 );
94
95 if ( label ) {
96 $layoutHeaderLabelText.text( acf.decode( label ) );
97 }
98
99 const $layoutHeaderNameText = this.$el.find(
100 '> .acf-label .acf-fc-layout-name span'
101 );
102
103 if ( name ) {
104 $layoutHeaderNameText.text( name );
105 $layoutHeaderNameText.parent().css( 'display', '' );
106 } else {
107 $layoutHeaderNameText.parent().css( 'display', 'none' );
108 }
109 },
110
111 onClickEdit: function ( e ) {
112 const $target = $( e.target );
113
114 if (
115 $target.hasClass( 'acf-btn' ) ||
116 $target.hasClass( 'copyable' ) ||
117 $target.parent().hasClass( 'acf-btn' ) ||
118 $target.parent().hasClass( 'copyable' )
119 ) {
120 return;
121 }
122
123 this.isOpen() ? this.close() : this.open();
124 },
125
126 isOpen: function ( e ) {
127 const $settings = this.$el.children( '.acf-field-layout-settings' );
128 return $settings.hasClass( 'open' );
129 },
130
131 open: function ( element, isAddingLayout ) {
132 const $header = element
133 ? element.children( '.acf-field-settings-fc_head' )
134 : this.$el.children( '.acf-field-settings-fc_head' );
135 const $settings = element
136 ? element.children( '.acf-field-layout-settings' )
137 : this.$el.children( '.acf-field-layout-settings' );
138 const toggle = element
139 ? element.find( '.toggle-indicator' ).first()
140 : this.$el.find( '.toggle-indicator' ).first();
141
142 // action (show)
143 acf.doAction( 'show', $settings );
144
145 // open
146 if ( isAddingLayout ) {
147 $settings.slideDown( {
148 complete: function () {
149 $settings.find( '.layout-label' ).trigger( 'focus' );
150 },
151 } );
152 } else {
153 $settings.slideDown();
154 }
155 toggle.addClass( 'open' );
156 if ( toggle.hasClass( 'closed' ) ) {
157 toggle.removeClass( 'closed' );
158 }
159 $settings.addClass( 'open' );
160 $header.addClass( 'open' );
161 },
162
163 close: function () {
164 const $header = this.$el.children( '.acf-field-settings-fc_head' );
165 const $settings = this.$el.children( '.acf-field-layout-settings' );
166 const toggle = this.$el.find( '.toggle-indicator' ).first();
167
168 // close
169 $settings.slideUp();
170 $settings.removeClass( 'open' );
171 toggle.removeClass( 'open' );
172 $header.removeClass( 'open' );
173 if ( ! toggle.hasClass( 'closed' ) ) {
174 toggle.addClass( 'closed' );
175 }
176
177 // action (hide)
178 acf.doAction( 'hide', $settings );
179 },
180
181 onChangeLabel: function ( e, $el ) {
182 let label = $el.val();
183 const safeLabel = acf.strEscape( label );
184
185 this.set( 'layoutLabel', safeLabel );
186 this.$el.attr( 'data-layout-label', safeLabel );
187
188 let $name = this.$input( 'name' );
189
190 // render name
191 if ( $name.val() == '' ) {
192 acf.val( $name, acf.strSanitize( label ) );
193 this.$el.find( '.layout-name' ).trigger( 'blur' );
194 }
195 },
196
197 onChangeName: function ( e, $el ) {
198 const sanitizedName = acf.strSanitize( $el.val(), false );
199
200 $el.val( sanitizedName );
201 this.set( 'layoutName', sanitizedName );
202
203 this.$el.attr( 'data-layout-name', sanitizedName );
204 },
205
206 onClickAdd: function ( e, $el ) {
207 e.preventDefault();
208 var prevKey = this.get( 'id' );
209 var newKey = acf.uniqid( 'layout_' );
210
211 // duplicate
212 $layout = acf.duplicate( {
213 $el: this.$el,
214 search: prevKey,
215 replace: newKey,
216 after: function ( $el, $el2 ) {
217 var $list = $el2.find( '.acf-field-list:first' );
218
219 // remove sub fields
220 $list.children( '.acf-field-object' ).remove();
221
222 // show empty
223 $list.addClass( '-empty' );
224
225 // reset layout meta values
226 $el2.attr( 'data-layout-label', '' );
227 $el2.attr( 'data-layout-name', '' );
228 $el2.find( '.acf-fc-meta input' ).val( '' );
229 $el2.find( 'label.acf-fc-layout-label' ).html(
230 acf.__( 'Layout' )
231 );
232 },
233 } );
234
235 // get layout
236 var layout = acf.getFieldSetting( $layout );
237
238 // update hidden input
239 layout.$input( 'key' ).val( newKey );
240 ! this.isOpen()
241 ? this.open( layout.$el, true )
242 : layout.$el.find( '.layout-label' ).trigger( 'focus' );
243
244 // save
245 this.fieldObject.save();
246 },
247
248 onClickDuplicate: function ( e, $el ) {
249 e.preventDefault();
250 var prevKey = this.get( 'id' );
251 var newKey = acf.uniqid( 'layout_' );
252
253 // duplicate
254 $layout = acf.duplicate( {
255 $el: this.$el,
256 search: prevKey,
257 replace: newKey,
258 } );
259
260 // get all fields in new layout similar to fieldManager.onDuplicateField().
261 // important to run field.wipe() before making any changes to the "parent_layout" prop
262 // to ensure the correct input is modified.
263 var children = acf.getFieldObjects( { parent: $layout } );
264 if ( children.length ) {
265 // loop
266 children.map( function ( child ) {
267 // wipe field
268 child.wipe();
269
270 // if the child is open, re-fire the open method to ensure it's initialised correctly.
271 if ( child.isOpen() ) {
272 child.open();
273 }
274
275 // update parent
276 child.updateParent();
277 } );
278
279 // action
280 acf.doAction(
281 'duplicate_field_objects',
282 children,
283 this.fieldObject,
284 this.fieldObject
285 );
286 }
287
288 // get layout
289 var layout = acf.getFieldSetting( $layout );
290
291 // get current label/names so we can prepare to append 'copy'
292 var label = layout.get( 'layoutLabel' );
293 var name = layout.get( 'layoutName' );
294 var end = name.split( '_' ).pop();
295 var copy = acf.__( 'copy' );
296
297 // increase suffix "1"
298 if ( acf.isNumeric( end ) ) {
299 var i = end * 1 + 1;
300 label = label.replace( end, i );
301 name = name.replace( end, i );
302
303 // increase suffix "(copy1)"
304 } else if ( end.indexOf( copy ) === 0 ) {
305 var i = end.replace( copy, '' ) * 1;
306 i = i ? i + 1 : 2;
307
308 // replace
309 label = label.replace( end, copy + i );
310 name = name.replace( end, copy + i );
311
312 // add default "(copy)"
313 } else {
314 label += ' (' + copy + ')';
315 name += '_' + copy;
316 }
317
318 // update inputs and data attributes which will trigger header label updates too.
319 layout.$input( 'label' ).val( label );
320 layout.set( 'layoutLabel', label );
321 layout.$el.attr( 'data-layout-label', label );
322 layout.$input( 'name' ).val( name );
323 layout.set( 'layoutName', name );
324 layout.$el.attr( 'data-layout-name', name );
325
326 // update hidden input
327 layout.$input( 'key' ).val( newKey );
328 ! this.isOpen()
329 ? this.open( layout.$el, true )
330 : layout.$el.find( '.layout-label' ).trigger( 'focus' );
331 // save
332 this.fieldObject.save();
333 },
334
335 onClickDelete: function ( e, $el ) {
336 e.preventDefault();
337 // Bypass confirmation when holding down "shift" key.
338 if ( e.shiftKey ) {
339 return this.delete();
340 }
341
342 // add class
343 this.$el.addClass( '-hover' );
344
345 // add tooltip
346 var tooltip = acf.newTooltip( {
347 confirmRemove: true,
348 target: $el,
349 context: this,
350 confirm: function () {
351 this.delete();
352 },
353 cancel: function () {
354 this.$el.removeClass( '-hover' );
355 },
356 } );
357 },
358
359 delete: function () {
360 var $siblings = this.$el.siblings( '.acf-field-setting-fc_layout' );
361
362 // validate
363 if ( ! $siblings.length ) {
364 alert(
365 acf.__( 'Flexible Content requires at least 1 layout' )
366 );
367 return false;
368 }
369
370 // delete sub fields
371 this.getFields().map( function ( child ) {
372 child.delete( {
373 animate: false,
374 } );
375 } );
376
377 // remove tr
378 acf.remove( this.$el );
379
380 // save
381 this.fieldObject.save();
382 },
383 } );
384
385 acf.registerFieldSetting( FlexibleContentLayoutFieldSetting );
386
387 /**
388 * flexibleContentHelper
389 *
390 * description
391 *
392 * @date 19/4/18
393 * @since ACF 5.6.9
394 *
395 * @param type $var Description. Default.
396 * @return type Description.
397 */
398
399 var flexibleContentHelper = new acf.Model( {
400 actions: {
401 sortstop_field_object: 'updateParentLayout',
402 change_field_object_parent: 'updateParentLayout',
403 },
404
405 updateParentLayout: function ( fieldObject ) {
406 var parent = fieldObject.getParent();
407
408 // delete meta
409 if ( ! parent || parent.prop( 'type' ) !== 'flexible_content' ) {
410 fieldObject.prop( 'parent_layout', null );
411 return;
412 }
413
414 // get layout
415 var $layout = fieldObject.$el.closest(
416 '.acf-field-setting-fc_layout'
417 );
418 var layout = acf.getFieldSetting( $layout );
419
420 // check if previous prop exists
421 // - if not, set prop to allow following code to trigger 'change' and save the field
422 if ( ! fieldObject.has( 'parent_layout' ) ) {
423 fieldObject.prop( 'parent_layout', 0 );
424 }
425
426 // update meta
427 fieldObject.prop( 'parent_layout', layout.get( 'id' ) );
428 },
429 } );
430 } )( jQuery );
431