diff --git a/wire/modules/Fieldtype/FieldtypeRepeater/config.php b/wire/modules/Fieldtype/FieldtypeRepeater/config.php index 7916caf3..dace2cac 100644 --- a/wire/modules/Fieldtype/FieldtypeRepeater/config.php +++ b/wire/modules/Fieldtype/FieldtypeRepeater/config.php @@ -77,6 +77,7 @@ class FieldtypeRepeaterConfigHelper extends Wire { $select->attr('id', 'repeaterFields'); $select->attr('title', $this->_('Add Field')); $select->setAsmSelectOption('sortable', true); + $select->setAsmSelectOption('fieldset', true); $select->setAsmSelectOption('editLink', $this->wire('config')->urls->admin . "setup/field/edit?id={value}&fieldgroup_id={$template->fieldgroup->id}&modal=1&process_template=1"); $select->setAsmSelectOption('hideDeleted', false); diff --git a/wire/modules/Inputfield/InputfieldAsmSelect/InputfieldAsmSelect.module b/wire/modules/Inputfield/InputfieldAsmSelect/InputfieldAsmSelect.module index 84ddb0c1..0db7dfb1 100644 --- a/wire/modules/Inputfield/InputfieldAsmSelect/InputfieldAsmSelect.module +++ b/wire/modules/Inputfield/InputfieldAsmSelect/InputfieldAsmSelect.module @@ -13,7 +13,7 @@ class InputfieldAsmSelect extends InputfieldSelectMultiple implements Inputfield public static function getModuleInfo() { return array( 'title' => __('asmSelect', __FILE__), - 'version' => 120, + 'version' => 121, 'summary' => __('Multiple selection, progressive enhancement to select multiple', __FILE__), // Module Summary 'permanent' => true, ); @@ -32,7 +32,8 @@ class InputfieldAsmSelect extends InputfieldSelectMultiple implements Inputfield parent::init(); - $this->setAsmSelectOption('sortable', true); + $this->setAsmSelectOption('sortable', true); + $this->setAsmSelectOption('fieldset', false); // an optional edit or detail link where items can be modified or viewed // i.e. /path/to/page/?id={value} where {value} is replaced with option value diff --git a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.css b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.css index 174714e8..9826f140 100644 --- a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.css +++ b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.css @@ -130,3 +130,16 @@ span.asmListItemDesc { .asmListItemDeleted span { text-decoration: line-through; } + +span.asmFieldsetIndent { + float: left; + width: 15px; + height: 5px; +} + +.asmFieldset, +.pw-content .asmFieldset, +#content .asmFieldset { + font-weight: bold; +} + diff --git a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.js b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.js index fcaf9dad..01db3408 100644 --- a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.js +++ b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.js @@ -17,6 +17,7 @@ listType: 'ol', // Ordered list 'ol', or unordered list 'ul' sortable: false, // Should the list be sortable? highlight: false, // Use the highlight feature? + fieldset: false, // Use fieldset support? (for PW Fieldset types) animate: false, // Animate the the adding/removing of items in the list? addItemTarget: 'bottom', // Where to place new selected items in list: top or bottom hideWhenAdded: false, // Hide the option when added to the list? works only in FF @@ -68,6 +69,7 @@ var buildingSelect = false; // is the new select being constructed right now? var ieClick = false; // in IE, has a click event occurred? ignore if not var ignoreOriginalChangeEvent = false; // originalChangeEvent bypassed when this is true + var fieldsetCloseItems = {}; var msie = 0; function init() { @@ -75,7 +77,7 @@ // initialize the alternate select multiple // this loop ensures uniqueness, in case of existing asmSelects placed by ajax (1.0.3) - while($("#" + options.containerClass + index).size() > 0) index++; + while($("#" + options.containerClass + index).length > 0) index++; $select = $("") .addClass(options.selectClass) @@ -108,9 +110,19 @@ } if(msie > 0 && msie < 8) $ol.css('display', 'inline-block'); // Thanks Matthew Hutton + + if(options.fieldset) { + setupFieldsets(); + $original.children('option').each(function() { + var name = $(this).text(); + if(name.indexOf('_END') > 0 && name.substring(name.length - 4) == '_END') { + fieldsetCloseItems[name] = $(this); + } + }); + } $original.trigger('init'); - + if(options.editLinkModal === 'longclick') { $ol.on('longclick', 'a.asmEditLinkModalLongclick', clickEditLink); } @@ -120,6 +132,8 @@ // make any items in the selected list sortable // requires jQuery UI sortables, draggables, droppables + + var fieldsetItems = []; $ol.sortable({ items: 'li.' + options.listItemClass, @@ -133,26 +147,41 @@ updatedOptionId = $option.attr('id'); $(this).children("li").each(function(n) { - $option = $('#' + $(this).attr('rel')); $original.append($option); - - /* this doesn't seem to work in newer versions of jquery - if($(this).is(".ui-sortable-helper")) { - updatedOptionId = $option.attr('id'); - return; - } - */ - }); if(updatedOptionId) triggerOriginalChange(updatedOptionId, 'sort'); }, start: function(e, data) { if(options.jQueryUI) data.item.addClass('ui-state-highlight'); + if(data.item.hasClass('asmFieldsetStart')) { + var $next = data.item; + var stopName = data.item.find('.asmListItemLabel').text() + '_END'; + do { + if($next.find('.asmListItemLabel').text() == stopName) break; + $next = $next.next('li'); + if($next.length && !$next.hasClass('ui-sortable-placeholder')) { + $next.fadeTo(50, 0.7).slideUp('fast'); + fieldsetItems.push($next); + } + } while($next.length); + } }, stop: function(e, data) { if(options.jQueryUI) data.item.removeClass('ui-state-highlight'); + if(data.item.hasClass('asmFieldsetStart')) { + var $lastItem = data.item; + + for(var n = 0; n < fieldsetItems.length; n++) { + var $item = fieldsetItems[n]; + $lastItem.after($item); + $lastItem = $item; + $item.slideDown('fast').fadeTo('fast', 1.0); + } + fieldsetItems = []; + } + setupFieldsets(); } }).addClass(options.listSortableClass); @@ -198,6 +227,8 @@ if(typeof $.browser != "undefined") { if ($.browser.opera) $ol.hide().fadeIn("fast"); } + + if(options.fieldset) setupFieldsets(); } function buildSelect() { @@ -275,7 +306,7 @@ .attr("disabled", true); if(options.hideWhenEmpty) { - if($option.siblings('[disabled!=true]').size() < 2) $select.hide(); + if($option.siblings('[disabled!=true]').length < 2) $select.hide(); } if(options.hideWhenAdded) $option.hide(); @@ -297,7 +328,6 @@ function addListItem(optionId) { // add a new item to the html list - var $O = $('#' + optionId); if(!$O) return; // this is the first item, selectLabel @@ -400,6 +430,18 @@ setHighlight($item, options.highlightAddedLabel); selectFirstItem(); if(options.sortable) $ol.sortable("refresh"); + if(options.fieldset) { + var itemName = $O.text(); + if(itemName.indexOf('_END') > 0 && itemName.substring(itemName.length - 4) == '_END') { + $item.addClass('asmFieldset asmFieldsetEnd'); + } else { + var fieldsetCloseName = itemName + '_END'; + if(typeof fieldsetCloseItems[fieldsetCloseName] != "undefined") { + $item.addClass('asmFieldset asmFieldsetStart'); + addListItem(fieldsetCloseItems[fieldsetCloseName].attr('id')); + } + } + } } } @@ -571,16 +613,16 @@ $asmItem.effect('highlight', {}, 500); var $asmSetStatus = $icontents.find('#' + options.listItemStatusClass); // first try to find by ID - if($asmSetStatus.size() == 0) $asmSetStatus = $icontents.find(':input.' + options.listItemStatusClass); // then by class, if not ID - if($asmSetStatus.size() > 0) $asmItem.find('.' + options.listItemStatusClass).html($asmSetStatus.eq(0).val()); + if($asmSetStatus.length == 0) $asmSetStatus = $icontents.find(':input.' + options.listItemStatusClass); // then by class, if not ID + if($asmSetStatus.length > 0) $asmItem.find('.' + options.listItemStatusClass).html($asmSetStatus.eq(0).val()); var $asmSetDesc = $icontents.find('#' + options.listItemDescClass); // first try to find by ID - if($asmSetDesc.size() == 0) $asmSetDesc = $icontents.find(':input.' + options.listItemDescClass); // then by class, if not ID - if($asmSetDesc.size() > 0) { + if($asmSetDesc.length == 0) $asmSetDesc = $icontents.find(':input.' + options.listItemDescClass); // then by class, if not ID + if($asmSetDesc.length > 0) { $asmSetDesc = $asmSetDesc.eq(0); var $desc = $asmItem.find('.' + options.listItemDescClass); var $descA = $desc.find('a'); // does it have an in there? - if($descA.size() > 0) $descA.html($asmSetDesc.val()); + if($descA.length > 0) $descA.html($asmSetDesc.val()); else $desc.html($asmSetDesc.val()); } } @@ -595,6 +637,31 @@ }); return false; } + + function setupFieldsets() { + $ol.find('span.asmFieldsetIndent').remove(); + var $items = $ol.children('li'); + + $ol.children('li').children('span.asmListItemLabel').each(function() { + var $t = $(this); + var label = $t.text(); + if(label.substring(label.length-4) != '_END') return; + label = label.substring(0, label.length-4); + var $li = $(this).closest('li.asmListItem'); + $li.addClass('asmFieldset asmFieldsetEnd'); + while(1) { + $li = $li.prev('li.asmListItem'); + if($li.length < 1) break; + var $span = $li.children('span.asmListItemLabel'); + var label2 = $span.text(); + if(label2 == label) { + $li.addClass('asmFieldset asmFieldsetStart'); + break; + } + $span.prepend($('')); + } + }); + } init(); }); diff --git a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.min.js b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.min.js index 74343ba0..0e04c030 100644 --- a/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.min.js +++ b/wire/modules/Inputfield/InputfieldAsmSelect/asmselect/jquery.asmselect.min.js @@ -1 +1 @@ -(function(a){a.fn.asmSelect=function(b){var c={listType:"ol",sortable:false,highlight:false,animate:false,addItemTarget:"bottom",hideWhenAdded:false,hideWhenEmpty:false,debugMode:false,jQueryUI:true,hideDeleted:true,deletedOpacity:0.5,deletedPrepend:"-",sortLabel:'↕',removeLabel:'×',highlightAddedLabel:"Added: ",highlightRemovedLabel:"Removed: ",containerClass:"asmContainer",selectClass:"asmSelect",optionDisabledClass:"asmOptionDisabled",listClass:"asmList",listSortableClass:"asmListSortable",listItemClass:"asmListItem",listItemLabelClass:"asmListItemLabel",listItemDescClass:"asmListItemDesc",listItemStatusClass:"asmListItemStatus",listItemHandleClass:"asmListItemHandle",removeClass:"asmListItemRemove",editClass:"asmListItemEdit",highlightClass:"asmHighlight",deletedClass:"asmListItemDeleted",editLink:"",editLabel:'',editLinkOnlySelected:true,editLinkModal:true,editLinkButtonSelector:"form button.ui-button:visible"};a.extend(c,b);return this.each(function(l){var B=a(this);var t;var y;var n;var p=false;var e=false;var h=false;var o=0;function v(){while(a("#"+c.containerClass+l).size()>0){l++}y=a("").addClass(c.selectClass).addClass(B.attr("class")).attr("name",c.selectClass+l).attr("id",c.selectClass+l);$selectRemoved=a("");n=a("<"+c.listType+">"+c.listType+">").addClass(c.listClass).attr("id",c.listClass+l);t=a("").addClass(c.containerClass).attr("id",c.containerClass+l);x();y.change(m).click(C);B.change(r).wrap(t).before(y).before(n);if(c.sortable){z()}if(typeof a.browser!="undefined"&&typeof a.browser.msie!="undefined"){o=a.browser.msie?a.browser.version:0}if(o>0&&o<8){n.css("display","inline-block")}B.trigger("init");if(c.editLinkModal==="longclick"){n.on("longclick","a.asmEditLinkModalLongclick",w)}}function z(){n.sortable({items:"li."+c.listItemClass,axis:"y",cancel:"a.asmEditLinkModalLongclick",update:function(F,E){var D;$option=a("#"+E.item.attr("rel"));D=$option.attr("id");a(this).children("li").each(function(G){$option=a("#"+a(this).attr("rel"));B.append($option)});if(D){u(D,"sort")}},start:function(E,D){if(c.jQueryUI){D.item.addClass("ui-state-highlight")}},stop:function(E,D){if(c.jQueryUI){D.item.removeClass("ui-state-highlight")}}}).addClass(c.listSortableClass)}function m(D){if(o>0&&o<7&&!e){return}var E=a(this).children("option:selected").slice(0,1).attr("rel");s(E);e=false;u(E,"add")}function C(){e=true}function r(D){if(h){h=false;return}y.empty();n.empty();x();if(typeof a.browser!="undefined"){if(a.browser.opera){n.hide().fadeIn("fast")}}}function x(){p=true;var E=B.attr("title");var D=0;if(E===undefined){E=""}y.prepend("");B.children("option").each(function(H){var G=a(this);var F;if(!G.attr("id")){G.attr("id","asm"+l+"option"+H)}F=G.attr("id");if(G.is(":selected")){s(F);i(F,true)}else{D++;i(F)}});if(!c.debugMode){B.hide()}g();if(c.hideWhenEmpty){if(D>0){y.show()}else{y.hide()}}p=false}function i(F,E){if(E==undefined){var E=false}var D=a("#"+F);var G=a("").val(D.val()).attr("rel",F);if(E){q(G)}y.append(G)}function g(){y.children(":eq(0)").attr("selected",true)}function q(D){D.addClass(c.optionDisabledClass).attr("selected",false).attr("disabled",true);if(c.hideWhenEmpty){if(D.siblings("[disabled!=true]").size()<2){y.hide()}}if(c.hideWhenAdded){D.hide()}if(o){y.hide().show()}}function f(D){D.removeClass(c.optionDisabledClass).attr("disabled",false);if(c.hideWhenEmpty){y.show()}if(c.hideWhenAdded){D.show()}if(o){y.hide().show()}}function s(I){var D=a("#"+I);if(!D){return}var G=a("").attr("href","#").addClass(c.removeClass).prepend(c.removeLabel).click(function(){k(a(this).parent("li").attr("rel"));return false});var E=a("").addClass(c.listItemLabelClass);var H=a("").addClass(c.listItemStatusClass);if(D.attr("data-status")){H.html(D.attr("data-status"))}var F=a("").addClass(c.listItemDescClass);if(c.editLink.length>0&&(D.is(":selected")||!c.editLinkOnlySelected)){var L=a("").html(D.html()).attr("href",c.editLink.replace(/\{value\}/,D.val())).append(c.editLabel);if(c.editLinkModal==="longclick"){L.addClass("asmEditLinkModalLongclick")}else{if(c.editLinkModal){L.click(w)}}E.addClass(c.editClass).append(L);if(D.attr("data-desc")){var J=a("").html(D.attr("data-desc")).attr("href",L.attr("href")).append(c.editLabel);F.addClass(c.editClass).append(J);if(c.editLinkModal==="longclick"){J.addClass("asmEditLinkModalLongclick")}else{if(c.editLinkModal){J.click(w)}}}}else{E.html(D.html());if(D.attr("data-desc")){F.html(D.attr("data-desc"))}}var K=a("
").attr("rel",I).addClass(c.listItemClass).append(E).append(F).append(H).append(G).hide();if(c.jQueryUI){K.addClass("ui-state-default").hover(function(){a(this).addClass("ui-state-hover").removeClass("ui-state-default")},function(){a(this).addClass("ui-state-default").removeClass("ui-state-hover")});if(c.sortable){if(D.attr("data-handle")){K.prepend(a(D.attr("data-handle")).addClass(c.listItemHandleClass))}else{K.prepend(a(c.sortLabel).addClass(c.listItemHandleClass))}}}if(!p){if(D.is(":selected")){return}D.attr("selected",true)}if(c.addItemTarget=="top"&&!p){n.prepend(K);if(c.sortable){B.prepend(D)}}else{n.append(K);if(c.sortable){B.append(D)}}d(K);q(a("[rel="+I+"]",y));if(!p){A(K,c.highlightAddedLabel);g();if(c.sortable){n.sortable("refresh")}}}function d(D){if(c.animate&&!p){D.animate({opacity:"show",height:"show"},100,"swing",function(){D.animate({height:"+=2px"},50,"swing",function(){D.animate({height:"-=2px"},25,"swing")})})}else{D.show()}}function k(G,D){var E=a("#"+G);if(c.hideDeleted){if(D==undefined){var D=true}E.attr("selected",false);$item=n.children("li[rel="+G+"]");j($item);f(a("[rel="+G+"]",c.removeWhenAdded?$selectRemoved:y));if(D){A($item,c.highlightRemovedLabel)}}else{$item=n.children("li[rel="+G+"]");var F=E.attr("value");if(F=="undefined"){F=E.text()}if($item.hasClass(c.deletedClass)){$item.removeClass(c.deletedClass);if(c.deletedOpacity!=1){$item.css("opacity",1)}E.attr("value",F.substring(c.deletedPrepend.length))}else{$item.addClass(c.deletedClass);if(c.deletedOpacity!=1){$item.css("opacity",c.deletedOpacity)}E.attr("value",c.deletedPrepend+F)}}u(G,"drop")}function j(D){if(c.animate&&!p){$prevItem=D.prev("li");D.animate({opacity:"hide",height:"hide"},100,"linear",function(){$prevItem.animate({height:"-=2px"},50,"swing",function(){$prevItem.animate({height:"+=2px"},100,"swing")});D.remove()})}else{D.remove()}}function A(D,E){if(!c.highlight){return}y.next("#"+c.highlightClass+l).remove();var F=a("").hide().addClass(c.highlightClass).attr("id",c.highlightClass+l).html(E+D.children("."+c.listItemLabelClass).slice(0,1).text());y.after(F);F.fadeIn("fast",function(){setTimeout(function(){F.fadeOut("slow",function(){a(this).remove()})},50)})}function u(E,D){h=true;$option=a("#"+E);B.trigger("change",[{option:$option,value:$option.val(),id:E,item:n.children("[rel="+E+"]"),type:D}])}function w(G){if(!c.editLinkModal){return true}var D=a(this).parents("."+c.listItemClass);var E=a(this).attr("href");var F=pwModalWindow(E,{},"medium");F.load(function(){var J=F.contents();var I=[];var H=0;J.find(c.editLinkButtonSelector).each(function(P){var O=a(this);var L=O.text();var N=true;var K=O.is(".ui-priority-secondary");for(var M=0;M