balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

clone.js (7725B)


      1 ( function ( $, rwmb ) {
      2 	'use strict';
      3 
      4 	// Object holds all methods related to fields' index when clone
      5 	var cloneIndex = {
      6 		/**
      7 		 * Set index for fields in a .rwmb-clone
      8 		 * @param $inputs .rwmb-clone element
      9 		 * @param index Index value
     10 		 */
     11 		set: function ( $inputs, index ) {
     12 			$inputs.each( function () {
     13 				var $field = $( this );
     14 
     15 				// Name attribute
     16 				var name = this.name;
     17 				if ( name && ! $field.closest( '.rwmb-group-clone' ).length ) {
     18 					$field.attr( 'name', cloneIndex.replace( index, name, '[', ']', false ) );
     19 				}
     20 
     21 				// ID attribute
     22 				var id = this.id;
     23 				if ( id ) {
     24 					$field.attr( 'id', cloneIndex.replace( index, id, '_', '', true, true ) );
     25 				}
     26 
     27 				$field.trigger( 'update_index', index );
     28 			} );
     29 		},
     30 
     31 		/**
     32 		 * Replace an attribute of a field with updated index
     33 		 * @param index New index value
     34 		 * @param value Attribute value
     35 		 * @param before String before returned value
     36 		 * @param after String after returned value
     37 		 * @param alternative Check if attribute does not contain any integer, will reset the attribute?
     38 		 * @param isEnd Check if we find string at the end?
     39 		 * @return string
     40 		 */
     41 		replace: function ( index, value, before, after, alternative, isEnd ) {
     42 			before = before || '';
     43 			after = after || '';
     44 
     45 			if ( typeof alternative === 'undefined' ) {
     46 				alternative = true;
     47 			}
     48 
     49 			var end = isEnd ? '$' : '';
     50 
     51 			var regex = new RegExp( cloneIndex.escapeRegex( before ) + '(\\d+)' + cloneIndex.escapeRegex( after ) + end ),
     52 				newValue = before + index + after;
     53 
     54 			return regex.test( value ) ? value.replace( regex, newValue ) : (alternative ? value + newValue : value );
     55 		},
     56 
     57 		/**
     58 		 * Helper function to escape string in regular expression
     59 		 * @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
     60 		 * @param string
     61 		 * @return string
     62 		 */
     63 		escapeRegex: function ( string ) {
     64 			return string.replace( /[.*+?^${}()|[\]\\]/g, "\\$&" );
     65 		},
     66 
     67 		/**
     68 		 * Helper function to create next index for clones
     69 		 * @param $container .rwmb-input container
     70 		 * @return integer
     71 		 */
     72 		nextIndex: function ( $container ) {
     73 			var nextIndex = $container.data( 'next-index' );
     74 			$container.data( 'next-index', nextIndex + 1 );
     75 			return nextIndex;
     76 		}
     77 	};
     78 
     79 	// Object holds all method related to fields' value when clone.
     80 	var cloneValue = {
     81 		setDefault: function() {
     82 			var $field = $( this );
     83 
     84 			if ( true !== $field.data( 'clone-default' ) ) {
     85 				return;
     86 			}
     87 
     88 			var type = $field.attr( 'type' ),
     89 				defaultValue = $field.data( 'default' );
     90 
     91 			if ( 'radio' === type ) {
     92 				$field.prop( 'checked', $field.val() === defaultValue );
     93 			} else if ( $field.hasClass( 'rwmb-checkbox' ) || $field.hasClass( 'rwmb-switch' ) ) {
     94 				$field.prop( 'checked', !! defaultValue );
     95 			} else if ( $field.hasClass( 'rwmb-checkbox_list' ) ) {
     96 				var value = $field.val();
     97 				$field.prop( 'checked', Array.isArray( defaultValue ) ? -1 !== defaultValue.indexOf( value ) : value == defaultValue );
     98 			} else if ( 'select' === type ) {
     99 				$field.find( 'option[value="' + defaultValue + '"]' ).prop( 'selected', true );
    100 			} else if ( ! $field.hasClass( 'rwmb-hidden' ) ) {
    101 				$field.val( defaultValue );
    102 			}
    103 		},
    104 		clear: function() {
    105 			var $field = $( this ),
    106 				type = $field.attr( 'type' );
    107 
    108 			if ( 'radio' === type || 'checkbox' === type ) {
    109 				$field.prop( 'checked', false );
    110 			} else if ( 'select' === type ) {
    111 				$field.prop( 'selectedIndex', - 1 );
    112 			} else if ( ! $field.hasClass( 'rwmb-hidden' ) ) {
    113 				$field.val( '' );
    114 			}
    115 		}
    116 	};
    117 
    118 	/**
    119 	 * Clone fields
    120 	 * @param $container A div container which has all fields
    121 	 */
    122 	function clone( $container ) {
    123 		var $last = $container.children( '.rwmb-clone' ).last(),
    124 			$clone = $last.clone(),
    125 			nextIndex = cloneIndex.nextIndex( $container );
    126 
    127 		// Clear fields' values.
    128 		var $inputs = $clone.find( rwmb.inputSelectors );
    129 		$inputs.each( cloneValue.clear );
    130 
    131 		// Insert clone.
    132 		$clone.insertAfter( $last );
    133 
    134 		// Trigger custom event for the clone instance. Required for Group extension to update sub fields.
    135 		$clone.trigger( 'clone_instance', nextIndex );
    136 
    137 		// Set fields index. Must run before trigger clone event.
    138 		cloneIndex.set( $inputs, nextIndex );
    139 
    140 		// Set fields' default values: do after index is set to prevent previous radio fields from unchecking.
    141 		$inputs.each( cloneValue.setDefault );
    142 
    143 		// Trigger custom clone event.
    144 		$inputs.trigger( 'clone', nextIndex );
    145 
    146 		// After cloning fields.
    147 		$inputs.trigger( 'after_clone', nextIndex );
    148 
    149 		// Trigger custom change event for MB Blocks to update block attributes.
    150 		$inputs.first().trigger( 'mb_change' );
    151 	}
    152 
    153 	/**
    154 	 * Hide remove buttons when there's only 1 of them
    155 	 *
    156 	 * @param $container .rwmb-input container
    157 	 */
    158 	function toggleRemoveButtons( $container ) {
    159 		var $clones = $container.children( '.rwmb-clone' );
    160 		$clones.children( '.remove-clone' ).toggle( $clones.length > 1 );
    161 
    162 		// Recursive for nested groups.
    163 		$container.find( '.rwmb-input' ).each( function () {
    164 			toggleRemoveButtons( $( this ) );
    165 		} );
    166 	}
    167 
    168 	/**
    169 	 * Toggle add button
    170 	 * Used with [data-max-clone] attribute. When max clone is reached, the add button is hid and vice versa
    171 	 *
    172 	 * @param $container .rwmb-input container
    173 	 */
    174 	function toggleAddButton( $container ) {
    175 		var $button = $container.children( '.add-clone' ),
    176 			maxClone = parseInt( $container.data( 'max-clone' ) ),
    177 			numClone = $container.children( '.rwmb-clone' ).length;
    178 
    179 		$button.toggle( isNaN( maxClone ) || ( maxClone && numClone < maxClone ) );
    180 	}
    181 
    182 	function addClone( e ) {
    183 		e.preventDefault();
    184 
    185 		var $container = $( this ).closest( '.rwmb-input' );
    186 		clone( $container );
    187 
    188 		toggleRemoveButtons( $container );
    189 		toggleAddButton( $container );
    190 		sortClones.apply( $container[0] );
    191 	}
    192 
    193 	function removeClone( e ) {
    194 		e.preventDefault();
    195 
    196 		var $this = $( this ),
    197 			$container = $this.closest( '.rwmb-input' );
    198 
    199 		// Remove clone only if there are 2 or more of them
    200 		if ( $container.children( '.rwmb-clone' ).length < 2 ) {
    201 			return;
    202 		}
    203 
    204 		$this.parent().trigger( 'remove' ).remove();
    205 		toggleRemoveButtons( $container );
    206 		toggleAddButton( $container );
    207 
    208 		// Trigger custom change event for MB Blocks to update block attributes.
    209 		$container.find( rwmb.inputSelectors ).first().trigger( 'mb_change' );
    210 	}
    211 
    212 	/**
    213 	 * Sort clones.
    214 	 * Expect this = .rwmb-input element.
    215 	 */
    216 	function sortClones() {
    217 		var $container = $( this );
    218 
    219 		if ( undefined !== $container.sortable( 'instance' ) ) {
    220 			return;
    221 		}
    222 		if ( 0 === $container.children( '.rwmb-clone' ).length ) {
    223 			return;
    224 		}
    225 
    226 		$container.sortable( {
    227 			handle: '.rwmb-clone-icon',
    228 			placeholder: ' rwmb-clone rwmb-sortable-placeholder',
    229 			items: '> .rwmb-clone',
    230 			start: function ( event, ui ) {
    231 				// Make the placeholder has the same height as dragged item
    232 				ui.placeholder.height( ui.item.outerHeight() );
    233 			},
    234 			stop: function( event, ui ) {
    235 				ui.item.trigger( 'mb_init_editors' );
    236 				ui.item.find( rwmb.inputSelectors ).first().trigger( 'mb_change' );
    237 			}
    238 		} );
    239 	}
    240 
    241 	function start() {
    242 		var $container = $( this );
    243 		toggleRemoveButtons( $container );
    244 		toggleAddButton( $container );
    245 
    246 		$container.data( 'next-index', $container.children( '.rwmb-clone' ).length );
    247 		sortClones.apply( this );
    248 	}
    249 
    250 	function init( e ) {
    251 		$( e.target ).find( '.rwmb-input' ).each( start );
    252 	}
    253 
    254 	rwmb.$document
    255 		.on( 'mb_ready', init )
    256 		.on( 'click', '.add-clone', addClone )
    257 		.on( 'click', '.remove-clone', removeClone );
    258 
    259 	// Export for use outside.
    260 	rwmb.cloneIndex = cloneIndex;
    261 	rwmb.cloneValue = cloneValue;
    262 	rwmb.sortClones = sortClones;
    263 	rwmb.toggleRemoveButtons = toggleRemoveButtons;
    264 	rwmb.toggleAddButton = toggleAddButton;
    265 } )( jQuery, rwmb );