bindings
6 months ago
commands
1 week ago
pro
1 week 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
1 week 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
_field-group-conditions.js
411 lines
| 1 | ( function ( $, undefined ) { |
| 2 | /** |
| 3 | * ConditionalLogicFieldSetting |
| 4 | * |
| 5 | * description |
| 6 | * |
| 7 | * @date 3/2/18 |
| 8 | * @since ACF 5.6.5 |
| 9 | * |
| 10 | * @param type $var Description. Default. |
| 11 | * @return type Description. |
| 12 | */ |
| 13 | |
| 14 | var ConditionalLogicFieldSetting = acf.FieldSetting.extend( { |
| 15 | type: '', |
| 16 | name: 'conditional_logic', |
| 17 | events: { |
| 18 | 'change .conditions-toggle': 'onChangeToggle', |
| 19 | 'click .add-conditional-group': 'onClickAddGroup', |
| 20 | 'focus .condition-rule-field': 'onFocusField', |
| 21 | 'change .condition-rule-field': 'onChangeField', |
| 22 | 'change .condition-rule-operator': 'onChangeOperator', |
| 23 | 'click .add-conditional-rule': 'onClickAdd', |
| 24 | 'click .remove-conditional-rule': 'onClickRemove', |
| 25 | }, |
| 26 | |
| 27 | $rule: false, |
| 28 | scope: function ( $rule ) { |
| 29 | this.$rule = $rule; |
| 30 | return this; |
| 31 | }, |
| 32 | |
| 33 | ruleData: function ( name, value ) { |
| 34 | return this.$rule.data.apply( this.$rule, arguments ); |
| 35 | }, |
| 36 | |
| 37 | $input: function ( name ) { |
| 38 | return this.$rule.find( '.condition-rule-' + name ); |
| 39 | }, |
| 40 | |
| 41 | $td: function ( name ) { |
| 42 | return this.$rule.find( 'td.' + name ); |
| 43 | }, |
| 44 | |
| 45 | $toggle: function () { |
| 46 | return this.$( '.conditions-toggle' ); |
| 47 | }, |
| 48 | |
| 49 | $control: function () { |
| 50 | return this.$( '.rule-groups' ); |
| 51 | }, |
| 52 | |
| 53 | $groups: function () { |
| 54 | return this.$( '.rule-group' ); |
| 55 | }, |
| 56 | |
| 57 | $rules: function () { |
| 58 | return this.$( '.rule' ); |
| 59 | }, |
| 60 | |
| 61 | $tabLabel: function () { |
| 62 | return this.fieldObject.$el.find('.conditional-logic-badge'); |
| 63 | }, |
| 64 | |
| 65 | $conditionalValueSelect: function () { |
| 66 | return this.$( '.condition-rule-value' ); |
| 67 | }, |
| 68 | |
| 69 | open: function () { |
| 70 | var $div = this.$control(); |
| 71 | $div.show(); |
| 72 | acf.enable( $div ); |
| 73 | }, |
| 74 | |
| 75 | close: function () { |
| 76 | var $div = this.$control(); |
| 77 | $div.hide(); |
| 78 | acf.disable( $div ); |
| 79 | }, |
| 80 | |
| 81 | render: function () { |
| 82 | // show |
| 83 | if ( this.$toggle().prop( 'checked' ) ) { |
| 84 | this.$tabLabel().addClass('is-enabled'); |
| 85 | this.renderRules(); |
| 86 | this.open(); |
| 87 | |
| 88 | // hide |
| 89 | } else { |
| 90 | this.$tabLabel().removeClass('is-enabled'); |
| 91 | this.close(); |
| 92 | } |
| 93 | }, |
| 94 | |
| 95 | renderRules: function () { |
| 96 | // vars |
| 97 | var self = this; |
| 98 | |
| 99 | // loop |
| 100 | this.$rules().each( function () { |
| 101 | self.renderRule( $( this ) ); |
| 102 | } ); |
| 103 | }, |
| 104 | |
| 105 | renderRule: function ( $rule ) { |
| 106 | this.scope( $rule ); |
| 107 | this.renderField(); |
| 108 | this.renderOperator(); |
| 109 | this.renderValue(); |
| 110 | }, |
| 111 | |
| 112 | renderField: function () { |
| 113 | // vars |
| 114 | var choices = []; |
| 115 | var validFieldTypes = []; |
| 116 | var cid = this.fieldObject.cid; |
| 117 | var $select = this.$input( 'field' ); |
| 118 | |
| 119 | // loop |
| 120 | acf.getFieldObjects().map( function ( fieldObject ) { |
| 121 | // vars |
| 122 | var choice = { |
| 123 | id: fieldObject.getKey(), |
| 124 | text: fieldObject.getLabel(), |
| 125 | }; |
| 126 | |
| 127 | // bail early if is self |
| 128 | if ( fieldObject.cid === cid ) { |
| 129 | choice.text += ' ' + acf.__( '(this field)' ); |
| 130 | choice.disabled = true; |
| 131 | } |
| 132 | |
| 133 | // get selected field conditions |
| 134 | var conditionTypes = acf.getConditionTypes( { |
| 135 | fieldType: fieldObject.getType(), |
| 136 | } ); |
| 137 | |
| 138 | // bail early if no types |
| 139 | if ( ! conditionTypes.length ) { |
| 140 | choice.disabled = true; |
| 141 | } |
| 142 | |
| 143 | // calculate indents |
| 144 | var indents = fieldObject.getParents().length; |
| 145 | choice.text = '- '.repeat( indents ) + choice.text; |
| 146 | |
| 147 | // append |
| 148 | choices.push( choice ); |
| 149 | } ); |
| 150 | |
| 151 | // allow for scenario where only one field exists |
| 152 | if ( ! choices.length ) { |
| 153 | choices.push( { |
| 154 | id: '', |
| 155 | text: acf.__( 'No toggle fields available' ), |
| 156 | } ); |
| 157 | } |
| 158 | |
| 159 | // render |
| 160 | acf.renderSelect( $select, choices ); |
| 161 | |
| 162 | // set |
| 163 | this.ruleData( 'field', $select.val() ); |
| 164 | }, |
| 165 | |
| 166 | renderOperator: function () { |
| 167 | // bail early if no field selected |
| 168 | if ( ! this.ruleData( 'field' ) ) { |
| 169 | return; |
| 170 | } |
| 171 | |
| 172 | // vars |
| 173 | var $select = this.$input( 'operator' ); |
| 174 | var val = $select.val(); |
| 175 | var choices = []; |
| 176 | |
| 177 | // set saved value on first render |
| 178 | // - this allows the 2nd render to correctly select an option |
| 179 | if ( $select.val() === null ) { |
| 180 | acf.renderSelect( $select, [ |
| 181 | { |
| 182 | id: this.ruleData( 'operator' ), |
| 183 | text: '', |
| 184 | }, |
| 185 | ] ); |
| 186 | } |
| 187 | |
| 188 | // get selected field |
| 189 | var $field = acf.findFieldObject( this.ruleData( 'field' ) ); |
| 190 | var field = acf.getFieldObject( $field ); |
| 191 | |
| 192 | // get selected field conditions |
| 193 | var conditionTypes = acf.getConditionTypes( { |
| 194 | fieldType: field.getType(), |
| 195 | } ); |
| 196 | |
| 197 | // html |
| 198 | conditionTypes.map( function ( model ) { |
| 199 | choices.push( { |
| 200 | id: model.prototype.operator, |
| 201 | text: model.prototype.label, |
| 202 | } ); |
| 203 | } ); |
| 204 | |
| 205 | // render |
| 206 | acf.renderSelect( $select, choices ); |
| 207 | |
| 208 | // set |
| 209 | this.ruleData( 'operator', $select.val() ); |
| 210 | }, |
| 211 | |
| 212 | renderValue: function () { |
| 213 | // bail early if no field selected |
| 214 | if ( ! this.ruleData( 'field' ) || ! this.ruleData( 'operator' ) ) { |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | var $select = this.$input( 'value' ); |
| 219 | var $td = this.$td( 'value' ); |
| 220 | var currentVal = $select.val(); |
| 221 | var savedValue = this.$rule[0].getAttribute( 'data-value' ); |
| 222 | |
| 223 | // get selected field |
| 224 | var $field = acf.findFieldObject( this.ruleData( 'field' ) ); |
| 225 | var field = acf.getFieldObject( $field ); |
| 226 | // get selected field conditions |
| 227 | var conditionTypes = acf.getConditionTypes( { |
| 228 | fieldType: field.getType(), |
| 229 | operator: this.ruleData( 'operator' ), |
| 230 | } ); |
| 231 | |
| 232 | var conditionType = conditionTypes[ 0 ].prototype; |
| 233 | var choices = conditionType.choices( field ); |
| 234 | let $newSelect; |
| 235 | if ( choices instanceof jQuery && !! choices.data( 'acfSelect2Props' ) ) { |
| 236 | $newSelect = $select.clone(); |
| 237 | // If converting from a disabled input, we need to convert it to an active select. |
| 238 | if ( $newSelect.is( 'input' ) ) { |
| 239 | var classes = $select.attr( 'class' ); |
| 240 | const $rebuiltSelect = $( '<select></select>' ).addClass( classes ).val( savedValue ); |
| 241 | $newSelect = $rebuiltSelect; |
| 242 | } |
| 243 | |
| 244 | acf.addAction( 'acf_conditional_value_rendered', function() { |
| 245 | acf.newSelect2( $newSelect, choices.data( 'acfSelect2Props' ) ); |
| 246 | }); |
| 247 | } else if ( choices instanceof Array ) { |
| 248 | this.$conditionalValueSelect().removeClass( 'select2-hidden-accessible' ); |
| 249 | $newSelect = $( '<select></select>' ); |
| 250 | acf.renderSelect( $newSelect, choices ); |
| 251 | } else { |
| 252 | this.$conditionalValueSelect().removeClass( 'select2-hidden-accessible' ); |
| 253 | $newSelect = $( choices ); |
| 254 | } |
| 255 | |
| 256 | // append |
| 257 | $select.detach(); |
| 258 | $td.html( $newSelect ); |
| 259 | |
| 260 | // timeout needed to avoid browser bug where "disabled" attribute is not applied |
| 261 | setTimeout( function () { |
| 262 | [ 'class', 'name', 'id' ].map( function ( attr ) { |
| 263 | $newSelect.attr( attr, $select.attr( attr ) ); |
| 264 | } ); |
| 265 | $select.val( savedValue ); |
| 266 | acf.doAction( 'acf_conditional_value_rendered' ); |
| 267 | }, 0 ); |
| 268 | // select existing value (if not a disabled input) |
| 269 | if ( ! $newSelect.prop( 'disabled' ) ) { |
| 270 | acf.val( $newSelect, currentVal, true ); |
| 271 | } |
| 272 | |
| 273 | // set |
| 274 | this.ruleData( 'value', $newSelect.val() ); |
| 275 | }, |
| 276 | |
| 277 | onChangeToggle: function () { |
| 278 | this.render(); |
| 279 | }, |
| 280 | |
| 281 | onClickAddGroup: function ( e, $el ) { |
| 282 | this.addGroup(); |
| 283 | }, |
| 284 | |
| 285 | addGroup: function () { |
| 286 | // vars |
| 287 | var $group = this.$( '.rule-group:last' ); |
| 288 | |
| 289 | // duplicate |
| 290 | var $group2 = acf.duplicate( $group ); |
| 291 | |
| 292 | // update h4 |
| 293 | $group2.find( 'h4' ).text( acf.__( 'or' ) ); |
| 294 | |
| 295 | // remove all tr's except the first one |
| 296 | $group2.find( 'tr' ).not( ':first' ).remove(); |
| 297 | |
| 298 | // Find the remaining tr and render |
| 299 | var $tr = $group2.find( 'tr' ); |
| 300 | this.renderRule( $tr ); |
| 301 | |
| 302 | // save field |
| 303 | this.fieldObject.save(); |
| 304 | }, |
| 305 | |
| 306 | onFocusField: function ( e, $el ) { |
| 307 | this.renderField(); |
| 308 | }, |
| 309 | |
| 310 | onChangeField: function ( e, $el ) { |
| 311 | // scope |
| 312 | this.scope( $el.closest( '.rule' ) ); |
| 313 | |
| 314 | // set data |
| 315 | this.ruleData( 'field', $el.val() ); |
| 316 | |
| 317 | // render |
| 318 | this.renderOperator(); |
| 319 | this.renderValue(); |
| 320 | }, |
| 321 | |
| 322 | onChangeOperator: function ( e, $el ) { |
| 323 | // scope |
| 324 | this.scope( $el.closest( '.rule' ) ); |
| 325 | |
| 326 | // set data |
| 327 | this.ruleData( 'operator', $el.val() ); |
| 328 | |
| 329 | // render |
| 330 | this.renderValue(); |
| 331 | }, |
| 332 | |
| 333 | onClickAdd: function ( e, $el ) { |
| 334 | // duplicate |
| 335 | var $rule = acf.duplicate( $el.closest( '.rule' ) ); |
| 336 | |
| 337 | // render |
| 338 | this.renderRule( $rule ); |
| 339 | }, |
| 340 | |
| 341 | onClickRemove: function ( e, $el ) { |
| 342 | // vars |
| 343 | var $rule = $el.closest( '.rule' ); |
| 344 | |
| 345 | // save field |
| 346 | this.fieldObject.save(); |
| 347 | |
| 348 | // remove group |
| 349 | if ( $rule.siblings( '.rule' ).length == 0 ) { |
| 350 | $rule.closest( '.rule-group' ).remove(); |
| 351 | } |
| 352 | |
| 353 | // remove |
| 354 | $rule.remove(); |
| 355 | }, |
| 356 | } ); |
| 357 | |
| 358 | acf.registerFieldSetting( ConditionalLogicFieldSetting ); |
| 359 | |
| 360 | /** |
| 361 | * conditionalLogicHelper |
| 362 | * |
| 363 | * description |
| 364 | * |
| 365 | * @date 20/4/18 |
| 366 | * @since ACF 5.6.9 |
| 367 | * |
| 368 | * @param type $var Description. Default. |
| 369 | * @return type Description. |
| 370 | */ |
| 371 | |
| 372 | var conditionalLogicHelper = new acf.Model( { |
| 373 | actions: { |
| 374 | duplicate_field_objects: 'onDuplicateFieldObjects', |
| 375 | }, |
| 376 | |
| 377 | onDuplicateFieldObjects: function ( children, newField, prevField ) { |
| 378 | // vars |
| 379 | var data = {}; |
| 380 | var $selects = $(); |
| 381 | |
| 382 | // reference change in key |
| 383 | children.map( function ( child ) { |
| 384 | // store reference of changed key |
| 385 | data[ child.get( 'prevKey' ) ] = child.get( 'key' ); |
| 386 | |
| 387 | // append condition select |
| 388 | $selects = $selects.add( child.$( '.condition-rule-field' ) ); |
| 389 | } ); |
| 390 | |
| 391 | // loop |
| 392 | $selects.each( function () { |
| 393 | // vars |
| 394 | var $select = $( this ); |
| 395 | var val = $select.val(); |
| 396 | |
| 397 | // bail early if val is not a ref key |
| 398 | if ( ! val || ! data[ val ] ) { |
| 399 | return; |
| 400 | } |
| 401 | |
| 402 | // modify selected option |
| 403 | $select.find( 'option:selected' ).attr( 'value', data[ val ] ); |
| 404 | |
| 405 | // set new val |
| 406 | $select.val( data[ val ] ); |
| 407 | } ); |
| 408 | }, |
| 409 | } ); |
| 410 | } )( jQuery ); |
| 411 |