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