wire/modules/Fieldtype/FieldtypeRepeater/InputfieldRepeater.js
/**
	 * Make a repeater sortable
	 * 
	 * @param $inputfieldRepeater The parent .InputfieldRepeater 
	 * @param $inputfields The .Inputfields parent of the sortable items
	 * 
	 */
Make a repeater sortable

@param $inputfieldRepeater The parent .InputfieldRepeater
@param $inputfields The .Inputfields parent of the sortable items
Make a repeater sortable @param $inputfieldRepeater The parent . InputfieldRepeater @param $inputfields The . Inputfields parent of the sortable items
function initSortable($inputfieldRepeater, $inputfields) {
		var maxDepth = parseInt($inputfieldRepeater.attr('data-depth'));
		var depthChildren = [];
		var startDepth = 0;
		var familyFriendly = $inputfieldRepeater.hasClass('InputfieldRepeaterFamilyFriendly');
		var sortableOptions = {
			items: '> li:not(.InputfieldRepeaterNewItem)',
			handle: '.InputfieldRepeaterDrag',
			start: function(e, ui) {
				ui.item.find('.InputfieldHeader').addClass("ui-state-highlight");
				ui.item.find('textarea.InputfieldCKEditorNormal.InputfieldCKEditorLoaded').each(function() {
					$(this).removeClass('InputfieldCKEditorLoaded');
					var editor = CKEDITOR.instances[$(this).attr('id')];
					editor.destroy();
					CKEDITOR.remove($(this).attr('id'));
				});
				ui.item.find('.InputfieldTinyMCE textarea').each(function() {
					tinyMCE.execCommand('mceRemoveControl', false, $(this).attr('id'));
				});
				if(familyFriendly && maxDepth > 0) {
					startDepth = parseInt(ui.item.attr('data-depth'));
					depthChildren = getDepthChildren(ui.item);
					for(var n = 0; n < depthChildren.length; n++) {
						depthChildren[n].slideUp('fast');
					}
				}
			},
			stop: function(e, ui) {
				if(maxDepth > 0) {
					sortableDepth(ui, maxDepth, true);
				}
				if(maxDepth > 0 && familyFriendly && depthChildren.length) {
					var $item = ui.item;
					var stopDepth = parseInt($item.attr('data-depth'));
					var diffDepth = stopDepth - startDepth;
					for(var n = 0; n < depthChildren.length; n++) {
						var $child = depthChildren[n];
						if(diffDepth != 0) {
							var itemDepth = getItemDepth($child);
							setItemDepth($child, itemDepth + diffDepth, maxDepth, true);
						}
						$item.after($child);
						$child.slideDown('fast');
						$item = $child;
					}
					depthChildren = [];
				}
				ui.item.find('.InputfieldHeader').removeClass("ui-state-highlight");
				$(this).children().each(function(n) {
					$(this).find('.InputfieldRepeaterSort').slice(0,1).attr('value', n);
				});
				ui.item.find('textarea.InputfieldCKEditorNormal:not(.InputfieldCKEditorLoaded)').each(function() {
					$(this).closest('.InputfieldCKEditor').trigger('reloaded', [ 'InputfieldRepeaterSort' ]);
				});
				ui.item.find('.InputfieldTinyMCE textarea').each(function() {
					tinyMCE.execCommand('mceAddControl', false, $(this).attr('id'));
				});
			}
		};
		if(maxDepth > 0) {
			initDepths($inputfieldRepeater);
			sortableOptions.grid = [ depthSize, 1 ];
			sortableOptions.sort = function(event, ui) {
				var depth = sortableDepth(ui, 99, false);
				var $header = ui.item.children('.InputfieldHeader');
				if(depth > maxDepth) {
					$header.addClass('ui-state-error');
				} else if($header.hasClass('ui-state-error')) {
					$header.removeClass('ui-state-error');
				}
			};
		} else {
			sortableOptions.axis = 'y';
		}
		$(".InputfieldRepeaterDrag", $inputfields).hover(function() {
			$(this).parent('label').addClass('ui-state-focus');
		}, function() {
			$(this).parent('label').removeClass('ui-state-focus');
		});
		$inputfields.sortable(sortableOptions);
	}
function initSortable ( $inputfieldRepeater , $inputfields ) { var maxDepth = parseInt ( $inputfieldRepeater . attr ( 'data-depth' ) ) ; var depthChildren = [ ] ; var startDepth = 0 ; var familyFriendly = $inputfieldRepeater . hasClass ( 'InputfieldRepeaterFamilyFriendly' ) ; var sortableOptions = { items : '> li:not(.InputfieldRepeaterNewItem)' , handle : '.InputfieldRepeaterDrag' , start : function ( e , ui ) { ui . item . find ( '.InputfieldHeader' ) . addClass ( "ui-state-highlight" ) ; ui . item . find ( 'textarea.InputfieldCKEditorNormal.InputfieldCKEditorLoaded' ) . each ( function ( ) { $ ( this ) . removeClass ( 'InputfieldCKEditorLoaded' ) ; var editor = CKEDITOR . instances [ $ ( this ) . attr ( 'id' ) ] ; editor . destroy ( ) ; CKEDITOR . remove ( $ ( this ) . attr ( 'id' ) ) ; } ) ; ui . item . find ( '.InputfieldTinyMCE textarea' ) . each ( function ( ) { tinyMCE . execCommand ( 'mceRemoveControl' , false , $ ( this ) . attr ( 'id' ) ) ; } ) ; if ( familyFriendly && maxDepth > 0 ) { startDepth = parseInt ( ui . item . attr ( 'data-depth' ) ) ; depthChildren = getDepthChildren ( ui . item ) ; for ( var n = 0 ; n < depthChildren . length ; n ++ ) { depthChildren [ n ] . slideUp ( 'fast' ) ; } } } , stop : function ( e , ui ) { if ( maxDepth > 0 ) { sortableDepth ( ui , maxDepth , true ) ; } if ( maxDepth > 0 && familyFriendly && depthChildren . length ) { var $item = ui . item ; var stopDepth = parseInt ( $item . attr ( 'data-depth' ) ) ; var diffDepth = stopDepth - startDepth ; for ( var n = 0 ; n < depthChildren . length ; n ++ ) { var $child = depthChildren [ n ] ; if ( diffDepth != 0 ) { var itemDepth = getItemDepth ( $child ) ; setItemDepth ( $child , itemDepth + diffDepth , maxDepth , true ) ; } $item . after ( $child ) ; $child . slideDown ( 'fast' ) ; $item = $child ; } depthChildren = [ ] ; } ui . item . find ( '.InputfieldHeader' ) . removeClass ( "ui-state-highlight" ) ; $ ( this ) . children ( ) . each ( function ( n ) { $ ( this ) . find ( '.InputfieldRepeaterSort' ) . slice ( 0 , 1 ) . attr ( 'value' , n ) ; } ) ; ui . item . find ( 'textarea.InputfieldCKEditorNormal:not(.InputfieldCKEditorLoaded)' ) . each ( function ( ) { $ ( this ) . closest ( '.InputfieldCKEditor' ) . trigger ( 'reloaded' , [ 'InputfieldRepeaterSort' ] ) ; } ) ; ui . item . find ( '.InputfieldTinyMCE textarea' ) . each ( function ( ) { tinyMCE . execCommand ( 'mceAddControl' , false , $ ( this ) . attr ( 'id' ) ) ; } ) ; } } ; if ( maxDepth > 0 ) { initDepths ( $inputfieldRepeater ) ; sortableOptions . grid = [ depthSize , 1 ] ; sortableOptions . sort = function ( event , ui ) { var depth = sortableDepth ( ui , 99 , false ) ; var $header = ui . item . children ( '.InputfieldHeader' ) ; if ( depth > maxDepth ) { $header . addClass ( 'ui-state-error' ) ; } else if ( $header . hasClass ( 'ui-state-error' ) ) { $header . removeClass ( 'ui-state-error' ) ; } } ; } else { sortableOptions . axis = 'y' ; } $ ( ".InputfieldRepeaterDrag" , $inputfields ) . hover ( function ( ) { $ ( this ) . parent ( 'label' ) . addClass ( 'ui-state-focus' ) ; } , function ( ) { $ ( this ) . parent ( 'label' ) . removeClass ( 'ui-state-focus' ) ; } ) ; $inputfields . sortable ( sortableOptions ) ; }
Make a repeater sortable
Make a repeater sortable
// CKEditor doesn't like being sorted, do destroy when sort starts, and reload after sort // TinyMCE instances don't like to be dragged, so we disable them temporarily // remember and hide depth children // update/move and show depth children // Re-enable CKEditor instances // Re-enable the TinyMCE instances // beyond max depth allowed // no problems // apply "ui-state-focus" class when an item is being dragged