@@ -318,6 +318,315 @@ var kirkiDependencies = {
318318 } ,
319319} ;
320320
321+
322+ /**
323+ * Enable [active_callback] for repeater's controls
324+ * This function MUST be here to use [kirkiControlDependencies] passed from [Field_Dependencies.php]
325+ *
326+ * @author : Kirki
327+ * @since 4.1.1
328+ */
329+ var KirkiRepeaterDependencies = {
330+
331+ repeatersControls : { } ,
332+
333+ repeatersActiveCallbackFields : { } ,
334+ listenTo : { } ,
335+
336+ init : function ( ) {
337+ var self = this ;
338+
339+ /* 1. Collect All Repeaters */
340+ _ . each ( window . kirkiRepeaterControlsAvailable , function ( repDetails , repeaterID ) {
341+
342+ var control = wp . customize . control ( repeaterID ) ;
343+
344+ if ( control && control . params && control . params . type && control . params . type === 'repeater' ) {
345+
346+ self . repeatersControls [ control . id ] = self . repeatersControls [ control . id ] || [ ] ;
347+
348+ self . repeatersControls [ control . id ] = {
349+ 'user_entries' : JSON . parse ( decodeURI ( control . setting . get ( ) ) ) /* @see function [getValue] in [wp.customize.controlConstructor.repeater] located in [controls/js/script.js] */
350+ } ;
351+
352+ }
353+
354+ } ) ;
355+
356+ /* 2. Collect Active Callbacks Arrays for each Available Repeater */
357+ _ . each ( self . repeatersControls , function ( repDetails , repID ) {
358+
359+ var repControl = wp . customize . control ( repID ) ,
360+ repUserEntries = ( ! _ . isUndefined ( repDetails ) && ! _ . isUndefined ( repDetails [ 'user_entries' ] ) && ! _ . isEmpty ( repDetails [ 'user_entries' ] ) ) ? repDetails [ 'user_entries' ] : null ;
361+
362+ if ( ! _ . isUndefined ( repControl ) && ! _ . isNull ( repUserEntries ) ) {
363+
364+ _ . each ( repUserEntries , function ( rowValue , rowIndex ) {
365+
366+ _ . each ( rowValue , function ( eleValue , eleID ) {
367+
368+ if ( ! _ . isUndefined ( repControl . params . fields [ eleID ] ) ) {
369+
370+ var eleDetails = repControl . params . fields [ eleID ] ;
371+
372+ self . showRepeaterControl ( repControl . id , eleDetails , rowValue ) ;
373+
374+ }
375+
376+ } ) ;
377+
378+ } ) ;
379+
380+ self . repeatersActiveCallbackFields [ repControl . id ] = self . repeatersActiveCallbackFields [ repControl . id ] || [ ] ;
381+ self . repeatersActiveCallbackFields [ repControl . id ] = self . listenTo ;
382+ /* Destroy it */
383+ self . listenTo = { } ;
384+
385+ }
386+
387+ } ) ;
388+
389+
390+ /* 3. Iterate inside every user entry and Apply [showRepeaterControl] on each slave element */
391+ _ . each ( self . repeatersActiveCallbackFields , function ( required_fields , repID ) {
392+
393+ objRepeaterControl = wp . customize . control ( repID ) ;
394+
395+ if ( ! _ . isUndefined ( objRepeaterControl ) ) {
396+
397+ var repUserEntries = JSON . parse ( decodeURI ( objRepeaterControl . setting . get ( ) ) ) , /* @see function [getValue] in [wp.customize.controlConstructor.repeater] located in [controls/js/script.js] */
398+ repFields = objRepeaterControl . params . fields ;
399+
400+ _ . each ( repUserEntries , function ( rowValue , rowIndex ) {
401+
402+ _ . each ( required_fields , function ( slaves , master ) {
403+
404+ _ . each ( slaves , function ( slave ) {
405+
406+ var objSlave = repFields [ slave ] ,
407+ setActiveState ,
408+ isDisplayed ;
409+
410+ isDisplayed = function ( ) {
411+ return self . showRepeaterControl ( repID , objSlave , rowValue ) ;
412+ } ;
413+
414+ setActiveState = function ( ) {
415+ if ( isDisplayed ( ) ) {
416+ jQuery ( objRepeaterControl . selector ) . find ( '[data-row="' + rowIndex + '"] .repeater-field-' + slave ) . removeClass ( 'inactive' ) . addClass ( 'active' ) . slideDown ( 'fast' ) ;
417+ }
418+ else {
419+ jQuery ( objRepeaterControl . selector ) . find ( '[data-row="' + rowIndex + '"] .repeater-field-' + slave ) . removeClass ( 'active' ) . addClass ( 'inactive' ) . slideUp ( 'fast' ) ;
420+ }
421+ } ;
422+
423+ setActiveState ( ) ;
424+
425+
426+ } ) ;
427+
428+ } ) ;
429+
430+ } ) ;
431+
432+ }
433+
434+ } ) ;
435+
436+ } ,
437+
438+
439+ /**
440+ * Should we show the control?
441+ *
442+ * @since 4.0.22
443+ *
444+ * @param {string } repeaterID - The repeater ID
445+ * @param {string|object } control - The control-id or the control object.
446+ * @param {object } rowEntries - The user entry for a repeater block
447+ * @returns {bool }
448+ */
449+ showRepeaterControl : function ( repeaterID , control , rowEntries ) {
450+
451+ var self = this ,
452+ show = true ,
453+
454+ isOption = (
455+ ! _ . isUndefined ( control ) && /* Fix: Multiple Repeaters with no active_callback */
456+ ! _ . isUndefined ( control . id ) && /* Fix: Multiple Repeaters with no active_callback */
457+ control . id && // Check if id exists.
458+ control . type && // Check if tpe exists.
459+ ! _ . isEmpty ( control . type ) // Check if control's type is not empty.
460+ ) ,
461+ i ;
462+
463+ // Exit early if control not found or if "required" argument is not defined.
464+ if ( 'undefined' === typeof control || 'undefined' === typeof control . active_callback || ( control . active_callback && _ . isEmpty ( control . active_callback ) ) ) {
465+ return true ;
466+ }
467+
468+ // Loop control requirements.
469+ for ( i = 0 ; i < control . active_callback . length ; i ++ ) {
470+ if ( ! self . checkCondition ( repeaterID , control . active_callback [ i ] , control , rowEntries , isOption , 'AND' ) ) {
471+ show = false ;
472+ }
473+ }
474+ return show ;
475+ } ,
476+
477+ /**
478+ * Check a condition.
479+ *
480+ * @param {string } repeaterID - The repeater ID
481+ * @param {Object } requirement - The requirement, inherited from showRepeaterControl - Represents the Active Callack Array.
482+ * @param {Object } control - The repeater's control object.
483+ * @param {object } rowEntries - The user entry for a repeater block
484+ * @param {bool } isOption - Whether it's an option or not.
485+ * @param {string } relation - Can be one of 'AND' or 'OR'.
486+ */
487+ checkCondition : function ( repeaterID , requirement , control , rowEntries , isOption , relation ) {
488+ var self = this ,
489+ childRelation = ( 'AND' === relation ) ? 'OR' : 'AND' ,
490+ nestedItems ,
491+ requirementSettingValue ,
492+ i ;
493+
494+
495+
496+ // If an array of other requirements nested, we need to process them separately.
497+ if ( 'undefined' !== typeof requirement [ 0 ] && 'undefined' === typeof requirement . setting ) {
498+
499+ nestedItems = [ ] ;
500+
501+ // Loop sub-requirements.
502+ for ( i = 0 ; i < requirement . length ; i ++ ) {
503+ nestedItems . push ( self . checkCondition ( repeaterID , requirement [ i ] , control , rowEntries , isOption , childRelation ) ) ;
504+ }
505+
506+
507+ // OR relation. Check that true is part of the array.
508+ if ( 'OR' === childRelation ) {
509+ return ( - 1 !== nestedItems . indexOf ( true ) ) ;
510+ }
511+
512+ // AND relation. Check that false is not part of the array.
513+ return ( - 1 === nestedItems . indexOf ( false ) ) ;
514+ }
515+
516+
517+ // Early exit if setting is not defined.
518+ if ( ! requirement . setting in rowEntries ) {
519+ return true ;
520+ }
521+
522+ /* Requirement Setting User Value */
523+ requirementSettingValue = rowEntries [ requirement . setting ] ;
524+
525+ // console.log( requirementSettingValue );
526+
527+ /**
528+ * Output: listenTo
529+ *
530+ * Master_#1 => array(
531+ * 0: Slave #1,
532+ * 1: Slave #2
533+ * )
534+ *
535+ */
536+ self . listenTo [ requirement . setting ] = self . listenTo [ requirement . setting ] || [ ] ;
537+
538+ if ( - 1 === self . listenTo [ requirement . setting ] . indexOf ( control . id ) ) {
539+
540+ self . listenTo [ requirement . setting ] . push ( control . id ) ;
541+
542+ }
543+
544+ return self . evaluate (
545+ requirement . value ,
546+ requirementSettingValue ,
547+ requirement . operator
548+ ) ;
549+
550+ } ,
551+
552+ /**
553+ * Figure out if the 2 values have the relation we want.
554+ *
555+ * @since 4.0.22
556+ * @param {mixed } value1 - The 1st value.
557+ * @param {mixed } value2 - The 2nd value.
558+ * @param {string } operator - The comparison to use.
559+ * @returns {bool }
560+ */
561+ evaluate : function ( value1 , value2 , operator ) {
562+ var found = false ;
563+
564+ if ( '===' === operator ) {
565+ return value1 === value2 ;
566+ }
567+ if ( '==' === operator || '=' === operator || 'equals' === operator || 'equal' === operator ) {
568+ return value1 == value2 ;
569+ }
570+ if ( '!==' === operator ) {
571+ return value1 !== value2 ;
572+ }
573+ if ( '!=' === operator || 'not equal' === operator ) {
574+ return value1 != value2 ;
575+ }
576+ if ( '>=' === operator || 'greater or equal' === operator || 'equal or greater' === operator ) {
577+ return value2 >= value1 ;
578+ }
579+ if ( '<=' === operator || 'smaller or equal' === operator || 'equal or smaller' === operator ) {
580+ return value2 <= value1 ;
581+ }
582+ if ( '>' === operator || 'greater' === operator ) {
583+ return value2 > value1 ;
584+ }
585+ if ( '<' === operator || 'smaller' === operator ) {
586+ return value2 < value1 ;
587+ }
588+ if ( 'contains' === operator || 'in' === operator ) {
589+ if ( _ . isArray ( value1 ) && _ . isArray ( value2 ) ) {
590+ _ . each ( value2 , function ( value ) {
591+ if ( value1 . includes ( value ) ) {
592+ found = true ;
593+ return false ;
594+ }
595+ } ) ;
596+ return found ;
597+ }
598+ if ( _ . isArray ( value2 ) ) {
599+ _ . each ( value2 , function ( value ) {
600+ if ( value == value1 ) { // jshint ignore:line
601+ found = true ;
602+ }
603+ } ) ;
604+ return found ;
605+ }
606+ if ( _ . isObject ( value2 ) ) {
607+ if ( ! _ . isUndefined ( value2 [ value1 ] ) ) {
608+ found = true ;
609+ }
610+ _ . each ( value2 , function ( subValue ) {
611+ if ( value1 === subValue ) {
612+ found = true ;
613+ }
614+ } ) ;
615+ return found ;
616+ }
617+ if ( _ . isString ( value2 ) ) {
618+ if ( _ . isString ( value1 ) ) {
619+ return ( - 1 < value1 . indexOf ( value2 ) && - 1 < value2 . indexOf ( value1 ) ) ;
620+ }
621+ return - 1 < value1 . indexOf ( value2 ) ;
622+ }
623+ }
624+ return value1 == value2 ;
625+ }
626+
627+ } ;
628+
321629jQuery ( document ) . ready ( function ( ) {
322630 kirkiDependencies . init ( ) ;
631+ KirkiRepeaterDependencies . init ( ) ;
323632} ) ;
0 commit comments