jqueryui
4 years ago
select2
6 years ago
validation
2 years ago
wp-color-picker-alpha
5 years ago
autocomplete.js
6 years ago
autosave.js
7 years ago
button-group.js
3 years ago
clone.js
2 years ago
color.js
3 years ago
date.js
1 year ago
datetime.js
1 year ago
file-input.js
4 years ago
file-upload.js
2 years ago
file.js
3 years ago
icon.js
2 years ago
image-advanced.js
4 years ago
image-select.js
6 years ago
image-upload.js
4 years ago
input-list.js
1 year ago
map-frontend.js
4 years ago
map.js
2 years ago
media.js
3 years ago
modal.js
1 year ago
oembed.js
2 years ago
osm-frontend.js
5 years ago
osm.js
2 years ago
post.js
1 year ago
range.js
4 years ago
script.js
3 years ago
select-advanced.js
2 years ago
select-tree.js
5 years ago
select.js
3 years ago
slider.js
6 years ago
taxonomy.js
1 year ago
time.js
1 year ago
user.js
1 year ago
video.js
6 years ago
wysiwyg.js
2 years ago
clone.js
282 lines
| 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 | |
| 75 | // If we render cloneable fields via AJAX, the mb_ready event is not fired. |
| 76 | // so nextIndex is undefined. In this case, we get the next index from the number of existing clones. |
| 77 | if ( nextIndex === undefined ) { |
| 78 | nextIndex = $container.children( '.rwmb-clone' ).length; |
| 79 | } |
| 80 | |
| 81 | $container.data( 'next-index', nextIndex + 1 ); |
| 82 | return nextIndex; |
| 83 | } |
| 84 | }; |
| 85 | |
| 86 | // Object holds all method related to fields' value when clone. |
| 87 | var cloneValue = { |
| 88 | setDefault: function() { |
| 89 | var $field = $( this ); |
| 90 | |
| 91 | if ( true !== $field.data( 'clone-default' ) ) { |
| 92 | return; |
| 93 | } |
| 94 | |
| 95 | var type = $field.attr( 'type' ), |
| 96 | defaultValue = $field.data( 'default' ); |
| 97 | |
| 98 | if ( 'radio' === type ) { |
| 99 | $field.prop( 'checked', $field.val() === defaultValue ); |
| 100 | } else if ( $field.hasClass( 'rwmb-checkbox' ) || $field.hasClass( 'rwmb-switch' ) ) { |
| 101 | $field.prop( 'checked', !! defaultValue ); |
| 102 | } else if ( $field.hasClass( 'rwmb-checkbox_list' ) ) { |
| 103 | var value = $field.val(); |
| 104 | $field.prop( 'checked', Array.isArray( defaultValue ) ? -1 !== defaultValue.indexOf( value ) : value == defaultValue ); |
| 105 | } else if ( $field.is( 'select' ) ) { |
| 106 | $field.find( 'option[value="' + defaultValue + '"]' ).prop( 'selected', true ); |
| 107 | } else if ( ! $field.hasClass( 'rwmb-hidden' ) ) { |
| 108 | $field.val( defaultValue ); |
| 109 | } |
| 110 | }, |
| 111 | clear: function() { |
| 112 | const $field = $( this ), |
| 113 | type = $field.attr( 'type' ); |
| 114 | |
| 115 | if ( 'radio' === type || 'checkbox' === type ) { |
| 116 | $field.prop( 'checked', false ); |
| 117 | } else if ( $field.is( 'select' ) ) { |
| 118 | $field.prop( 'selectedIndex', 0 ); |
| 119 | } else if ( ! $field.hasClass( 'rwmb-hidden' ) ) { |
| 120 | $field.val( '' ); |
| 121 | } |
| 122 | } |
| 123 | }; |
| 124 | |
| 125 | /** |
| 126 | * Clone fields |
| 127 | * @param $container A div container which has all fields |
| 128 | */ |
| 129 | function clone( $container ) { |
| 130 | var $last = $container.children( '.rwmb-clone' ).last(), |
| 131 | $clone = $last.clone(), |
| 132 | nextIndex = cloneIndex.nextIndex( $container ); |
| 133 | |
| 134 | // Clear fields' values. |
| 135 | var $inputs = $clone.find( rwmb.inputSelectors ); |
| 136 | $inputs.each( cloneValue.clear ); |
| 137 | |
| 138 | // Remove validation errors. |
| 139 | $clone.find( 'p.rwmb-error' ).remove(); |
| 140 | |
| 141 | // Insert clone. |
| 142 | $clone.insertAfter( $last ); |
| 143 | |
| 144 | // Trigger custom event for the clone instance. Required for Group extension to update sub fields. |
| 145 | $clone.trigger( 'clone_instance', nextIndex ); |
| 146 | |
| 147 | // Set fields index. Must run before trigger clone event. |
| 148 | cloneIndex.set( $inputs, nextIndex ); |
| 149 | |
| 150 | // Set fields' default values: do after index is set to prevent previous radio fields from unchecking. |
| 151 | $inputs.each( cloneValue.setDefault ); |
| 152 | |
| 153 | // Trigger custom clone event. |
| 154 | $inputs.trigger( 'clone', nextIndex ); |
| 155 | |
| 156 | // After cloning fields. |
| 157 | $inputs.trigger( 'after_clone', nextIndex ); |
| 158 | |
| 159 | // Trigger custom change event for MB Blocks to update block attributes. |
| 160 | $inputs.first().trigger( 'mb_change' ); |
| 161 | } |
| 162 | |
| 163 | /** |
| 164 | * Hide remove buttons when there's only 1 of them |
| 165 | * |
| 166 | * @param $container .rwmb-input container |
| 167 | */ |
| 168 | function toggleRemoveButtons( $container ) { |
| 169 | |
| 170 | var $clones = $container.children( '.rwmb-clone' ), |
| 171 | minClone = 1; |
| 172 | |
| 173 | if ( $container.data( 'min-clone' ) ) { |
| 174 | minClone = parseInt( $container.data( 'min-clone' ) ); |
| 175 | } |
| 176 | $clones.children( '.remove-clone' ).toggle( $clones.length > minClone ); |
| 177 | |
| 178 | // Recursive for nested groups. |
| 179 | $container.find( '.rwmb-input' ).each( function () { |
| 180 | toggleRemoveButtons( $( this ) ); |
| 181 | } ); |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * Toggle add button |
| 186 | * Used with [data-max-clone] attribute. When max clone is reached, the add button is hid and vice versa |
| 187 | * |
| 188 | * @param $container .rwmb-input container |
| 189 | */ |
| 190 | function toggleAddButton( $container ) { |
| 191 | var $button = $container.children( '.add-clone' ), |
| 192 | maxClone = parseInt( $container.data( 'max-clone' ) ), |
| 193 | numClone = $container.children( '.rwmb-clone' ).length; |
| 194 | |
| 195 | $button.toggle( isNaN( maxClone ) || ( maxClone && numClone < maxClone ) ); |
| 196 | } |
| 197 | |
| 198 | function addClone( e ) { |
| 199 | e.preventDefault(); |
| 200 | |
| 201 | var $container = $( this ).closest( '.rwmb-input' ); |
| 202 | clone( $container ); |
| 203 | |
| 204 | toggleRemoveButtons( $container ); |
| 205 | toggleAddButton( $container ); |
| 206 | sortClones.apply( $container[0] ); |
| 207 | } |
| 208 | |
| 209 | function removeClone( e ) { |
| 210 | e.preventDefault(); |
| 211 | |
| 212 | var $this = $( this ), |
| 213 | $container = $this.closest( '.rwmb-input' ); |
| 214 | |
| 215 | // Remove clone only if there are 2 or more of them |
| 216 | if ( $container.children( '.rwmb-clone' ).length < 2 ) { |
| 217 | return; |
| 218 | } |
| 219 | |
| 220 | $this.parent().trigger( 'remove' ).remove(); |
| 221 | toggleRemoveButtons( $container ); |
| 222 | toggleAddButton( $container ); |
| 223 | |
| 224 | // Trigger custom change event for MB Blocks to update block attributes. |
| 225 | $container.find( rwmb.inputSelectors ).first().trigger( 'mb_change' ); |
| 226 | } |
| 227 | |
| 228 | /** |
| 229 | * Sort clones. |
| 230 | * Expect this = .rwmb-input element. |
| 231 | */ |
| 232 | function sortClones() { |
| 233 | var $container = $( this ); |
| 234 | |
| 235 | if ( undefined !== $container.sortable( 'instance' ) ) { |
| 236 | return; |
| 237 | } |
| 238 | if ( 0 === $container.children( '.rwmb-clone' ).length ) { |
| 239 | return; |
| 240 | } |
| 241 | |
| 242 | $container.sortable( { |
| 243 | handle: '.rwmb-clone-icon', |
| 244 | placeholder: ' rwmb-clone rwmb-sortable-placeholder', |
| 245 | items: '> .rwmb-clone', |
| 246 | start: function ( event, ui ) { |
| 247 | // Make the placeholder has the same height as dragged item |
| 248 | ui.placeholder.height( ui.item.outerHeight() ); |
| 249 | }, |
| 250 | stop: function( event, ui ) { |
| 251 | ui.item.trigger( 'mb_init_editors' ); |
| 252 | ui.item.find( rwmb.inputSelectors ).first().trigger( 'mb_change' ); |
| 253 | } |
| 254 | } ); |
| 255 | } |
| 256 | |
| 257 | function start() { |
| 258 | var $container = $( this ); |
| 259 | toggleRemoveButtons( $container ); |
| 260 | toggleAddButton( $container ); |
| 261 | |
| 262 | $container.data( 'next-index', $container.children( '.rwmb-clone' ).length ); |
| 263 | sortClones.apply( this ); |
| 264 | } |
| 265 | |
| 266 | function init( e ) { |
| 267 | $( e.target ).find( '.rwmb-input' ).each( start ); |
| 268 | } |
| 269 | |
| 270 | rwmb.$document |
| 271 | .on( 'mb_ready', init ) |
| 272 | .on( 'click', '.add-clone', addClone ) |
| 273 | .on( 'click', '.remove-clone', removeClone ); |
| 274 | |
| 275 | // Export for use outside. |
| 276 | rwmb.cloneIndex = cloneIndex; |
| 277 | rwmb.cloneValue = cloneValue; |
| 278 | rwmb.sortClones = sortClones; |
| 279 | rwmb.toggleRemoveButtons = toggleRemoveButtons; |
| 280 | rwmb.toggleAddButton = toggleAddButton; |
| 281 | } )( jQuery, rwmb ); |
| 282 |