mirror of
https://github.com/processwire/processwire.git
synced 2025-08-09 16:26:59 +02:00
Repeater updates continued with a complete refactoring of the InputfieldRepeater.js file. This update also corrects the depth-dragging issues that were present in the last commit (issues were especially noticable dragging when using AdminThemeReno). Also adds a repeater open all/close all function per processwire/processwire-requests#33 - to use it, double click the "on/off" toggle icon that appears next to the trash icon.
This commit is contained in:
@@ -69,7 +69,7 @@
|
|||||||
* @property InputfieldWrapper|null $parent The parent InputfieldWrapper for this Inputfield or null if not set. #pw-internal
|
* @property InputfieldWrapper|null $parent The parent InputfieldWrapper for this Inputfield or null if not set. #pw-internal
|
||||||
* @property null|bool|Fieldtype $hasFieldtype The Fieldtype using this Inputfield, or boolean false when known not to have a Fieldtype, or null when not known. #pw-group-other
|
* @property null|bool|Fieldtype $hasFieldtype The Fieldtype using this Inputfield, or boolean false when known not to have a Fieldtype, or null when not known. #pw-group-other
|
||||||
* @property bool|null $useLanguages When multi-language support active, can be set to true to make it provide inputs for each language, where supported (default=false). #pw-group-behavior
|
* @property bool|null $useLanguages When multi-language support active, can be set to true to make it provide inputs for each language, where supported (default=false). #pw-group-behavior
|
||||||
* @property null|bool $entityEncodeLabel Set to boolean false to specifically disable entity encoding of field header/label (default=true). #pw-group-output
|
* @property null|bool|int $entityEncodeLabel Set to boolean false to specifically disable entity encoding of field header/label, or set to a Inputfield::textFormat constant. (default=true). #pw-group-output
|
||||||
* @property null|bool $entityEncodeText Set to boolean false to specifically disable entity encoding for other text: description, notes, etc. (default=true). #pw-group-output
|
* @property null|bool $entityEncodeText Set to boolean false to specifically disable entity encoding for other text: description, notes, etc. (default=true). #pw-group-output
|
||||||
* @property int $renderValueFlags Options that can be applied to renderValue mode, see "renderValue" constants (default=0). #pw-group-output
|
* @property int $renderValueFlags Options that can be applied to renderValue mode, see "renderValue" constants (default=0). #pw-group-output
|
||||||
* @property string $wrapClass Optional class name (CSS) to apply to the HTML element wrapping the Inputfield. #pw-group-other
|
* @property string $wrapClass Optional class name (CSS) to apply to the HTML element wrapping the Inputfield. #pw-group-other
|
||||||
|
@@ -504,7 +504,13 @@ class InputfieldWrapper extends Inputfield implements \Countable, \IteratorAggre
|
|||||||
if($label || $quietMode) {
|
if($label || $quietMode) {
|
||||||
$for = $inputfield->getSetting('skipLabel') || $quietMode ? '' : $inputfield->attr('id');
|
$for = $inputfield->getSetting('skipLabel') || $quietMode ? '' : $inputfield->attr('id');
|
||||||
// if $inputfield has a property of entityEncodeLabel with a value of boolean FALSE, we don't entity encode
|
// if $inputfield has a property of entityEncodeLabel with a value of boolean FALSE, we don't entity encode
|
||||||
if($inputfield->getSetting('entityEncodeLabel') !== false) $label = $inputfield->entityEncode($label);
|
$entityEncodeLabel = $inputfield->getSetting('entityEncodeLabel');
|
||||||
|
if(is_int($entityEncodeLabel) && $entityEncodeLabel >= Inputfield::textFormatBasic) {
|
||||||
|
// uses an Inputfield::textFormat constant
|
||||||
|
$label = $inputfield->entityEncode($label, $entityEncodeLabel);
|
||||||
|
} else if($entityEncodeLabel !== false) {
|
||||||
|
$label = $inputfield->entityEncode($label);
|
||||||
|
}
|
||||||
$icon = $inputfield->getSetting('icon');
|
$icon = $inputfield->getSetting('icon');
|
||||||
$icon = $icon ? str_replace('{name}', $this->wire('sanitizer')->name(str_replace(array('icon-', 'fa-'), '', $icon)), $markup['item_icon']) : '';
|
$icon = $icon ? str_replace('{name}', $this->wire('sanitizer')->name(str_replace(array('icon-', 'fa-'), '', $icon)), $markup['item_icon']) : '';
|
||||||
$toggle = $collapsed == Inputfield::collapsedNever ? '' : $markup['item_toggle'];
|
$toggle = $collapsed == Inputfield::collapsedNever ? '' : $markup['item_toggle'];
|
||||||
|
@@ -2,19 +2,39 @@
|
|||||||
margin-bottom: 1em; }
|
margin-bottom: 1em; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
padding: 0.5em; }
|
padding: 0.5em 0 0.5em 0.4em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemLabel {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 0.25em; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls {
|
||||||
|
padding-right: 0.5em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 100%; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterClone,
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterToggle,
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterTrash,
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .toggle-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
float: right; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterTrash {
|
||||||
|
padding-right: 3px; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterToggle {
|
||||||
|
margin-right: 1em; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .InputfieldRepeaterItemControls .InputfieldRepeaterClone {
|
||||||
|
margin-right: 1em; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .toggle-icon {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader .toggle-icon {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
margin-right: 0.5em; }
|
margin-right: 0.5em; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterClone, .Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterToggle, .Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterTrash {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right; }
|
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterTrash {
|
|
||||||
padding-right: 3px; }
|
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterToggle {
|
|
||||||
margin-right: 1em; }
|
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem > .InputfieldHeader > .InputfieldRepeaterClone {
|
|
||||||
margin-right: 1em; }
|
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldStateCollapsed > .InputfieldHeader {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldStateCollapsed > .InputfieldHeader {
|
||||||
opacity: 0.90; }
|
opacity: 0.90; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldStateCollapsed > .InputfieldHeader:hover {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldStateCollapsed > .InputfieldHeader:hover {
|
||||||
@@ -23,7 +43,9 @@
|
|||||||
opacity: 0.7; }
|
opacity: 0.7; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldRepeaterOff > .InputfieldHeader {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldRepeaterOff > .InputfieldHeader {
|
||||||
opacity: 0.5; }
|
opacity: 0.5; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldRepeaterOff > .InputfieldHeader:not(:hover) {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending).InputfieldRepeaterOff > .InputfieldHeader:not(:hover) > .InputfieldRepeaterItemLabel {
|
||||||
|
text-decoration: line-through; }
|
||||||
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem.InputfieldRepeaterDeletePending > .InputfieldHeader > .InputfieldRepeaterItemLabel {
|
||||||
text-decoration: line-through; }
|
text-decoration: line-through; }
|
||||||
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem.InputfieldRepeaterItemLoading {
|
.Inputfields .InputfieldRepeater .InputfieldRepeaterItem.InputfieldRepeaterItemLoading {
|
||||||
margin-bottom: 1em; }
|
margin-bottom: 1em; }
|
||||||
@@ -44,6 +66,7 @@
|
|||||||
.InputfieldRepeater ul.Inputfields + .InputfieldRepeaterAddItem {
|
.InputfieldRepeater ul.Inputfields + .InputfieldRepeaterAddItem {
|
||||||
margin-top: 0; }
|
margin-top: 0; }
|
||||||
.InputfieldRepeater .InputfieldRepeaterDrag {
|
.InputfieldRepeater .InputfieldRepeaterDrag {
|
||||||
|
display: inline-block;
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
line-height: 1em; }
|
line-height: 1em; }
|
||||||
|
@@ -3,62 +3,108 @@
|
|||||||
*
|
*
|
||||||
* Maintains a collection of fields that are repeated for any number of times.
|
* Maintains a collection of fields that are repeated for any number of times.
|
||||||
*
|
*
|
||||||
* ProcessWire 3.x (development), Copyright 2015 by Ryan Cramer
|
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var InputfieldRepeaterDepthSize = 50;
|
|
||||||
|
function InputfieldRepeater($) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete click event (single item)
|
* When depth is used, this indicates the indent (in pixels) used to show a single depth increment
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterDeleteClick(e) {
|
var depthSize = 50;
|
||||||
|
|
||||||
var $parent = $(this).parent('label').parent('li');
|
/**
|
||||||
|
* Whether or not AdminThemeReno is present
|
||||||
|
*
|
||||||
|
* @type {bool}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var isReno = $('body').hasClass('AdminThemeReno');
|
||||||
|
|
||||||
if($parent.is('.InputfieldRepeaterNewItem')) {
|
/*** EVENTS ********************************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for when an .InputfieldRepeater "reloaded" event is triggered
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @param source
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var eventReloaded = function(event, source) {
|
||||||
|
if(typeof source != "undefined") {
|
||||||
|
if(source == 'InputfieldRepeaterItemEdit' || source == 'InputfieldRepeaterItemAdd') {
|
||||||
|
event.stopPropagation();
|
||||||
|
var $r = $(this).find(".InputfieldRepeater");
|
||||||
|
if($r.length) initRepeater($r);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initRepeater($(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for when the "delete" action is clicked
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var eventDeleteClick = function(e) {
|
||||||
|
|
||||||
|
var $header = $(this).closest('.InputfieldHeader');
|
||||||
|
var $item = $header.parent();
|
||||||
|
|
||||||
|
if($item.hasClass('InputfieldRepeaterNewItem')) {
|
||||||
// delete new item (noAjaxAdd mode)
|
// delete new item (noAjaxAdd mode)
|
||||||
var $numAddInput = $parent.parent().parent().find('.InputfieldRepeaterAddItem').children('input');
|
var $numAddInput = $item.children('.InputfieldContent').children('.InputfieldRepeaterAddItem').children('input');
|
||||||
$numAddInput.attr('value', parseInt($numAddInput.attr('value')-1)); // total number of new items to add, minus 1
|
$numAddInput.attr('value', parseInt($numAddInput.attr('value')-1)); // total number of new items to add, minus 1
|
||||||
$parent.remove();
|
$item.remove();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// delete existing item
|
// delete existing item
|
||||||
var $checkbox = $parent.find('.InputfieldRepeaterDelete');
|
var pageID = $item.attr('data-page');
|
||||||
|
var $checkbox = $item.find('#delete_repeater' + pageID);
|
||||||
|
|
||||||
if($checkbox.is(":checked")) {
|
if($checkbox.is(":checked")) {
|
||||||
$checkbox.removeAttr('checked');
|
$checkbox.removeAttr('checked');
|
||||||
$parent.children('label').removeClass('ui-state-error').addClass('ui-state-default');
|
$header.removeClass('ui-state-error').addClass('ui-state-default');
|
||||||
//if($parent.is('.InputfieldStateCollapsed')) $parent.toggleClass('InputfieldStateCollapsed', 100);
|
//if($parent.is('.InputfieldStateCollapsed')) $parent.toggleClass('InputfieldStateCollapsed', 100);
|
||||||
$parent.removeClass('InputfieldRepeaterDeletePending');
|
$item.removeClass('InputfieldRepeaterDeletePending');
|
||||||
} else {
|
} else {
|
||||||
$checkbox.attr('checked', 'checked');
|
$checkbox.attr('checked', 'checked');
|
||||||
$parent.children('label').removeClass('ui-state-default').addClass('ui-state-error');
|
$header.removeClass('ui-state-default').addClass('ui-state-error');
|
||||||
if(!$parent.hasClass('InputfieldStateCollapsed')) $parent.toggleClass('InputfieldStateCollapsed', 100);
|
if(!$item.hasClass('InputfieldStateCollapsed')) {
|
||||||
$parent.addClass('InputfieldRepeaterDeletePending');
|
$header.find('.toggle-icon').click();
|
||||||
|
//$item.toggleClass('InputfieldStateCollapsed', 100);
|
||||||
}
|
}
|
||||||
|
$item.addClass('InputfieldRepeaterDeletePending');
|
||||||
|
}
|
||||||
|
$header.find('.InputfieldRepeaterItemControls').css('background-color', $header.css('background-color'));
|
||||||
}
|
}
|
||||||
|
|
||||||
InputfieldRepeaterCheckMax($parent.closest('.InputfieldRepeater'));
|
checkMax($item.closest('.InputfieldRepeater'));
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete double-click event (multi-item)
|
* Event handler for when the "delete" link is double clicked
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterDeleteDblClick(e) {
|
var eventDeleteDblClick = function(e) {
|
||||||
|
|
||||||
var $li = $(this).closest('li');
|
var $li = $(this).closest('li');
|
||||||
var undelete = $li.hasClass('InputfieldRepeaterDeletePending');
|
var undelete = $li.hasClass('InputfieldRepeaterDeletePending');
|
||||||
|
|
||||||
function selectAll() {
|
function selectAll() {
|
||||||
$li.parent().children('li').each(function() {
|
$li.parent().children('li').each(function() {
|
||||||
var $item = $(this);
|
var $item = $(this);
|
||||||
var $trashLink = $item.children('.InputfieldHeader').children('.InputfieldRepeaterTrash');
|
var $trashLink = $item.children('.InputfieldHeader').find('.InputfieldRepeaterTrash');
|
||||||
if($item.hasClass('InputfieldRepeaterDeletePending')) {
|
if($item.hasClass('InputfieldRepeaterDeletePending')) {
|
||||||
if(undelete) $trashLink.click();
|
if(undelete) $trashLink.click();
|
||||||
} else {
|
} else {
|
||||||
@@ -72,9 +118,16 @@ function InputfieldRepeaterDeleteDblClick(e) {
|
|||||||
} else {
|
} else {
|
||||||
ProcessWire.confirm(ProcessWire.config.InputfieldRepeater.labels.removeAll, selectAll);
|
ProcessWire.confirm(ProcessWire.config.InputfieldRepeater.labels.removeAll, selectAll);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function InputfieldRepeaterCloneClick(e) {
|
/**
|
||||||
|
* Event handler for when the "clone" repeater item action is clicked
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* @returns {boolean}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var eventCloneClick = function(e) {
|
||||||
var $item = $(this).closest('.InputfieldRepeaterItem');
|
var $item = $(this).closest('.InputfieldRepeaterItem');
|
||||||
ProcessWire.confirm(ProcessWire.config.InputfieldRepeater.labels.clone, function() {
|
ProcessWire.confirm(ProcessWire.config.InputfieldRepeater.labels.clone, function() {
|
||||||
var itemID = $item.attr('data-page');
|
var itemID = $item.attr('data-page');
|
||||||
@@ -84,18 +137,21 @@ function InputfieldRepeaterCloneClick(e) {
|
|||||||
$('html, body').animate({ scrollTop: $addLink.offset().top - 100}, 250, 'swing');
|
$('html, body').animate({ scrollTop: $addLink.offset().top - 100}, 250, 'swing');
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler for the "publish" toggle in the header of each repeater item
|
* Event handler for when the repeater item "on/off" toggle is clicked
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterToggleClick(e) {
|
var eventToggleClick = function(e) {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var toggleOn = $this.attr('data-on');
|
var toggleOn = $this.attr('data-on');
|
||||||
var toggleOff = $this.attr('data-off');
|
var toggleOff = $this.attr('data-off');
|
||||||
var $item = $this.closest('.InputfieldRepeaterItem');
|
var $item = $this.closest('.InputfieldRepeaterItem');
|
||||||
var $input = $item.find('.InputfieldRepeaterPublish');
|
var $input = $item.find('.InputfieldRepeaterPublish');
|
||||||
|
|
||||||
if($this.hasClass(toggleOn)) {
|
if($this.hasClass(toggleOn)) {
|
||||||
$this.removeClass(toggleOn).addClass(toggleOff);
|
$this.removeClass(toggleOn).addClass(toggleOff);
|
||||||
$item.addClass('InputfieldRepeaterUnpublished InputfieldRepeaterOff');
|
$item.addClass('InputfieldRepeaterUnpublished InputfieldRepeaterOff');
|
||||||
@@ -105,85 +161,34 @@ function InputfieldRepeaterToggleClick(e) {
|
|||||||
$item.removeClass('InputfieldRepeaterUnpublished InputfieldRepeaterOff');
|
$item.removeClass('InputfieldRepeaterUnpublished InputfieldRepeaterOff');
|
||||||
$input.val('1');
|
$input.val('1');
|
||||||
}
|
}
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares for open of ajax loaded item (Inputfields "openReady" event handler)
|
* Event handler for when a repeater item is about to be opened
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterItemOpenReady(e) {
|
var eventItemOpenReady = function(e) {
|
||||||
var $item = $(this);
|
var $item = $(this);
|
||||||
var $loaded = $item.find(".InputfieldRepeaterLoaded");
|
var $loaded = $item.find(".InputfieldRepeaterLoaded");
|
||||||
if(parseInt($loaded.val()) > 0) return; // item already loaded
|
if(parseInt($loaded.val()) > 0) return; // item already loaded
|
||||||
$item.addClass('InputfieldRepeaterItemLoading');
|
$item.addClass('InputfieldRepeaterItemLoading');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remember which repeater items are open
|
* Event handler for when a repeater item is opened (primarily focused on ajax loaded items)
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterUpdateState($item) {
|
var eventItemOpened = function(e) {
|
||||||
if($item.closest('.InputfieldRepeaterRememberOpen').length) {
|
|
||||||
var val = '';
|
|
||||||
$(".InputfieldRepeaterItem:not(.InputfieldStateCollapsed)").each(function() {
|
|
||||||
var id = parseInt($(this).attr('data-page'));
|
|
||||||
if(id > 0) {
|
|
||||||
val += id + '|';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
$.cookie('repeaters_open', val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function InputfieldRepeaterCheckMax($inputfield) {
|
|
||||||
if(!$inputfield.hasClass('InputfieldRepeaterMax')) return;
|
|
||||||
var max = parseInt($inputfield.attr('data-max'));
|
|
||||||
if(max <= 0) return;
|
|
||||||
var $content = $inputfield.children('.InputfieldContent');
|
|
||||||
var num = $content.children('.Inputfields').children('li:not(.InputfieldRepeaterDeletePending)').length;
|
|
||||||
var $addItem = $content.children('.InputfieldRepeaterAddItem');
|
|
||||||
if(num > max) {
|
|
||||||
$addItem.hide();
|
|
||||||
} else if(!$addItem.is(":visible")) {
|
|
||||||
$addItem.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function InputfieldRepeaterCheckDepths($inputfield) {
|
|
||||||
$inputfield.find('.InputfieldRepeaterDepth').each(function() {
|
|
||||||
var $depth = $(this);
|
|
||||||
var depth = $depth.val();
|
|
||||||
var $item = $depth.closest('.InputfieldRepeaterItem');
|
|
||||||
var currentLeft = $item.css('margin-left');
|
|
||||||
if(currentLeft == 'auto') currentLeft = 0;
|
|
||||||
currentLeft = parseInt(currentLeft);
|
|
||||||
var targetLeft = depth * InputfieldRepeaterDepthSize;
|
|
||||||
if(targetLeft != currentLeft) {
|
|
||||||
$item.css('margin-left', targetLeft + 'px');
|
|
||||||
$item.data('lastLeft', targetLeft);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event called when repeater item is collapsed
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function InputfieldRepeaterItemClosed(e) {
|
|
||||||
InputfieldRepeaterUpdateState($(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles load of ajax editable items (Inputfields "opened" event handler)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function InputfieldRepeaterItemOpened(e) {
|
|
||||||
|
|
||||||
var $item = $(this);
|
var $item = $(this);
|
||||||
var $loaded = $item.find(".InputfieldRepeaterLoaded");
|
var $loaded = $item.find(".InputfieldRepeaterLoaded");
|
||||||
|
|
||||||
InputfieldRepeaterUpdateState($item);
|
updateState($item);
|
||||||
|
|
||||||
if(parseInt($loaded.val()) > 0) return; // item already loaded
|
if(parseInt($loaded.val()) > 0) return; // item already loaded
|
||||||
|
|
||||||
@@ -213,7 +218,7 @@ function InputfieldRepeaterItemOpened(e) {
|
|||||||
|
|
||||||
var $repeaters = $inputs.filter('.InputfieldRepeater');
|
var $repeaters = $inputs.filter('.InputfieldRepeater');
|
||||||
if($repeaters.length) $repeaters.each(function() {
|
if($repeaters.length) $repeaters.each(function() {
|
||||||
InputfieldRepeaterInit($(this));
|
initRepeater($(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
$content.slideDown('fast', function() {
|
$content.slideDown('fast', function() {
|
||||||
@@ -224,206 +229,32 @@ function InputfieldRepeaterItemOpened(e) {
|
|||||||
}, 50);
|
}, 50);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a repeater label for the given repeater $item, optionally incrementing the index number
|
* Event handler for when a repeater item is closed
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterAdjustLabel($item, doIncrement) {
|
var eventItemClosed = function(e) {
|
||||||
|
updateState($(this));
|
||||||
var $label = $item.children('label');
|
};
|
||||||
var labelHTML = $label.html();
|
|
||||||
var _labelHTML = labelHTML;
|
|
||||||
|
|
||||||
if(doIncrement && labelHTML.indexOf('#') > -1) {
|
|
||||||
num = $item.siblings('.InputfieldRepeaterItem:visible').length + 1;
|
|
||||||
labelHTML = labelHTML.replace(/#[0-9]+/, '#' + num);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(labelHTML.indexOf('{') > -1) {
|
|
||||||
// parts of the label wrapped in {brackets} get different appearance
|
|
||||||
labelHTML = labelHTML.replace(/\{/, '<span class="ui-priority-secondary" style="font-weight:normal">');
|
|
||||||
labelHTML = labelHTML.replace(/}/, '</span>');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(labelHTML != _labelHTML) {
|
|
||||||
$label.html(labelHTML);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a repeater field
|
* Event handler for "add" link clicks
|
||||||
|
*
|
||||||
|
* Handles adding repeater items and initializing them
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* @returns {boolean}
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function InputfieldRepeaterInit($this) {
|
var eventAddLinkClick = function(e) {
|
||||||
|
|
||||||
if($this.hasClass('InputfieldRepeaterItem')) {
|
|
||||||
// single repeater item
|
|
||||||
var $inputfields = $this;
|
|
||||||
var $inputfieldRepeater = $this.closest('.InputfieldRepeater');
|
|
||||||
var isItem = true;
|
|
||||||
} else {
|
|
||||||
// enter repeater
|
|
||||||
var $inputfields = $this.find('.Inputfields:eq(0)');
|
|
||||||
var $inputfieldRepeater = $this;
|
|
||||||
var isItem = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(!$inputfields.length) return;
|
|
||||||
if($inputfields.hasClass('InputfieldRepeaterInit')) return;
|
|
||||||
$inputfields.addClass('InputfieldRepeaterInit');
|
|
||||||
|
|
||||||
var renderValueMode = $inputfields.closest('.InputfieldRenderValueMode').length > 0;
|
|
||||||
var $clone = $("<i class='fa fa-copy InputfieldRepeaterClone'></i>").css('display', 'block');
|
|
||||||
var $delete = $("<i class='fa fa-trash InputfieldRepeaterTrash'></i>");
|
|
||||||
var $toggle = $("<i class='fa InputfieldRepeaterToggle' data-on='fa-toggle-on' data-off='fa-toggle-off'></i>");
|
|
||||||
var cfg = ProcessWire.config.InputfieldRepeater;
|
|
||||||
var allowClone = !$inputfieldRepeater.hasClass('InputfieldRepeaterNoAjaxAdd');
|
|
||||||
|
|
||||||
if(cfg) {
|
|
||||||
$toggle.attr('title', cfg.labels.toggle);
|
|
||||||
$delete.attr('title', cfg.labels.remove);
|
|
||||||
$clone.attr('title', cfg.labels.clone);
|
|
||||||
}
|
|
||||||
|
|
||||||
$("input.InputfieldRepeaterDelete", $this).parents('.InputfieldCheckbox').hide();
|
|
||||||
|
|
||||||
function setupRepeaterHeaders($headers) {
|
|
||||||
$headers.each(function() {
|
|
||||||
var $t = $(this);
|
|
||||||
if($t.hasClass('InputfieldRepeaterHeaderInit')) return;
|
|
||||||
var icon = 'fa-arrows';
|
|
||||||
var $item = $t.parent();
|
|
||||||
if($item.hasClass('InputfieldRepeaterNewItem')) {
|
|
||||||
// noAjaxAdd mode
|
|
||||||
icon = 'fa-plus';
|
|
||||||
$t.addClass('ui-priority-secondary');
|
|
||||||
}
|
|
||||||
$t.addClass('ui-state-default InputfieldRepeaterHeaderInit');
|
|
||||||
$t.prepend("<i class='fa fa-fw " + icon + " InputfieldRepeaterDrag'></i>")
|
|
||||||
if(!renderValueMode) {
|
|
||||||
if(allowClone) $t.prepend($clone.clone(true));
|
|
||||||
$t.prepend($toggle.clone(true).addClass($t.parent().hasClass('InputfieldRepeaterOff') ? 'fa-toggle-off' : 'fa-toggle-on'));
|
|
||||||
$t.prepend($delete.clone(true));
|
|
||||||
}
|
|
||||||
InputfieldRepeaterAdjustLabel($item, false);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isItem) {
|
|
||||||
setupRepeaterHeaders($this.children('.InputfieldHeader'));
|
|
||||||
} else {
|
|
||||||
setupRepeaterHeaders($(".InputfieldRepeaterItem > .InputfieldHeader", $this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(renderValueMode) return;
|
|
||||||
|
|
||||||
$(".InputfieldRepeaterDrag", $this).hover(function() {
|
|
||||||
$(this).parent('label').addClass('ui-state-focus');
|
|
||||||
}, function() {
|
|
||||||
$(this).parent('label').removeClass('ui-state-focus');
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".InputfieldRepeaterTrash", $this).hover(function() {
|
|
||||||
var $label = $(this).parent('label');
|
|
||||||
if(!$label.parent().is('.InputfieldRepeaterDeletePending')) $label.addClass('ui-state-error');
|
|
||||||
}, function() {
|
|
||||||
var $label = $(this).parent('label');
|
|
||||||
if(!$label.parent().is('.InputfieldRepeaterDeletePending')) $label.removeClass('ui-state-error');
|
|
||||||
});
|
|
||||||
|
|
||||||
if(isItem) {
|
|
||||||
// if we only init'd a single item, now make $inputfields refer to all repeater items for sortable init
|
|
||||||
$inputfields = $this.closest('.InputfieldRepeater').find('.Inputfields:eq(0)');
|
|
||||||
}
|
|
||||||
|
|
||||||
var sortableOptions = {
|
|
||||||
items: '> li:not(.InputfieldRepeaterNewItem)',
|
|
||||||
handle: '.InputfieldRepeaterDrag',
|
|
||||||
start: function(e, ui) {
|
|
||||||
ui.item.find('.InputfieldHeader').addClass("ui-state-highlight");
|
|
||||||
|
|
||||||
// CKEditor doesn't like being sorted, do destroy when sort starts, and reload after sort
|
|
||||||
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'));
|
|
||||||
});
|
|
||||||
|
|
||||||
// TinyMCE instances don't like to be dragged, so we disable them temporarily
|
|
||||||
ui.item.find('.InputfieldTinyMCE textarea').each(function() {
|
|
||||||
tinyMCE.execCommand('mceRemoveControl', false, $(this).attr('id'));
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
stop: function(e, ui) {
|
|
||||||
|
|
||||||
ui.item.find('.InputfieldHeader').removeClass("ui-state-highlight");
|
|
||||||
$(this).children().each(function(n) {
|
|
||||||
$(this).find('.InputfieldRepeaterSort').slice(0,1).attr('value', n);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Re-enable CKEditor instances
|
|
||||||
ui.item.find('textarea.InputfieldCKEditorNormal:not(.InputfieldCKEditorLoaded)').each(function() {
|
|
||||||
$(this).closest('.InputfieldCKEditor').trigger('reloaded', [ 'InputfieldRepeaterSort' ]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Re-enable the TinyMCE instances
|
|
||||||
ui.item.find('.InputfieldTinyMCE textarea').each(function() {
|
|
||||||
tinyMCE.execCommand('mceAddControl', false, $(this).attr('id'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var maxDepth = parseInt($inputfieldRepeater.attr('data-depth'));
|
|
||||||
if(maxDepth > 0) {
|
|
||||||
InputfieldRepeaterCheckDepths($inputfieldRepeater);
|
|
||||||
sortableOptions.grid = [ InputfieldRepeaterDepthSize, 1 ];
|
|
||||||
sortableOptions.beforeStop = function(event, ui) {
|
|
||||||
var lastLeft = ui.item.data('lastLeft');
|
|
||||||
if(!lastLeft) lastLeft = 0;
|
|
||||||
var left = lastLeft + ui.position.left;
|
|
||||||
left -= InputfieldRepeaterDepthSize / 2;
|
|
||||||
if(left > 25 && left < InputfieldRepeaterDepthSize) left = InputfieldRepeaterDepthSize;
|
|
||||||
var depth = Math.round(left / InputfieldRepeaterDepthSize);
|
|
||||||
if(depth < 1) depth = 0;
|
|
||||||
if(depth > maxDepth) depth = maxDepth;
|
|
||||||
if(depth) {
|
|
||||||
ui.item.css('margin-left', (depth * InputfieldRepeaterDepthSize) + 'px');
|
|
||||||
} else {
|
|
||||||
ui.item.css('margin-left', 0);
|
|
||||||
}
|
|
||||||
ui.item.find('.InputfieldRepeaterDepth').val(depth);
|
|
||||||
ui.item.data('lastLeft', left);
|
|
||||||
ui.item.children('.InputfieldHeader').removeClass('ui-state-error');
|
|
||||||
};
|
|
||||||
sortableOptions.sort = function(event, ui) {
|
|
||||||
var lastLeft = ui.item.data('lastLeft');
|
|
||||||
if(!lastLeft) lastLeft = 0;
|
|
||||||
var left = lastLeft + ui.position.left;
|
|
||||||
var $header = ui.item.children('.InputfieldHeader');
|
|
||||||
if(left > (InputfieldRepeaterDepthSize * maxDepth) + (InputfieldRepeaterDepthSize / 2)) {
|
|
||||||
// beyond max depth allowed
|
|
||||||
$header.addClass('ui-state-error');
|
|
||||||
} else if($header.hasClass('ui-state-error')) {
|
|
||||||
$header.removeClass('ui-state-error');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
sortableOptions.axis = 'y';
|
|
||||||
}
|
|
||||||
|
|
||||||
$inputfields.sortable(sortableOptions);
|
|
||||||
|
|
||||||
var $addLinks = $(".InputfieldRepeaterAddLink:not(.InputfieldRepeaterAddLinkInit)", $this);
|
|
||||||
$addLinks.addClass('InputfieldRepeaterAddLinkInit');
|
|
||||||
$addLinks.click(function() {
|
|
||||||
|
|
||||||
var $addLink = $(this);
|
var $addLink = $(this);
|
||||||
var $inputfields = $(this).parent('p').prev('ul.Inputfields');
|
var $inputfields = $addLink.parent('p').prev('ul.Inputfields');
|
||||||
var $numAddInput = $(this).parent().children('input');
|
var $inputfieldRepeater = $addLink.closest('.InputfieldRepeater');
|
||||||
|
var $numAddInput = $addLink.parent().children('input');
|
||||||
var newItemTotal = 0; // for noAjaxAdd mode
|
var newItemTotal = 0; // for noAjaxAdd mode
|
||||||
var useAjax = $addLink.attr('data-noajax').length == 0;
|
var useAjax = $addLink.attr('data-noajax').length == 0;
|
||||||
var cloneID = $addLink.attr('data-clone');
|
var cloneID = $addLink.attr('data-clone');
|
||||||
@@ -435,8 +266,7 @@ function InputfieldRepeaterInit($this) {
|
|||||||
$addItem.attr('id', id);
|
$addItem.attr('id', id);
|
||||||
$inputfields.append($addItem);
|
$inputfields.append($addItem);
|
||||||
$addItem.css('display', 'block');
|
$addItem.css('display', 'block');
|
||||||
//$addItem.find('.InputfieldRepeaterTrash').click(InputfieldRepeaterDeleteClick);
|
adjustItemLabel($addItem, true);
|
||||||
InputfieldRepeaterAdjustLabel($addItem, true);
|
|
||||||
$addLink.trigger('repeateradd', [ $addItem ]);
|
$addLink.trigger('repeateradd', [ $addItem ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,13 +281,14 @@ function InputfieldRepeaterInit($this) {
|
|||||||
var $addItem = $newItem.clone(true)
|
var $addItem = $newItem.clone(true)
|
||||||
addRepeaterItem($addItem);
|
addRepeaterItem($addItem);
|
||||||
$numAddInput.attr('value', newItemTotal);
|
$numAddInput.attr('value', newItemTotal);
|
||||||
InputfieldRepeaterCheckMax($inputfieldRepeater);
|
checkMax($inputfieldRepeater);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
// get addItem from ajax
|
// get addItem from ajax
|
||||||
var pageID = $addLink.closest('.InputfieldRepeater').attr('data-page'); // $("#Inputfield_id").val();
|
var pageID = $inputfieldRepeater.attr('data-page');
|
||||||
var fieldName = $addLink.closest('.InputfieldRepeater').attr('id').replace('wrap_Inputfield_', '');
|
var fieldName = $inputfieldRepeater.attr('id').replace('wrap_Inputfield_', '');
|
||||||
var $spinner = $addLink.parent().find('.InputfieldRepeaterSpinner');
|
var $spinner = $addLink.parent().find('.InputfieldRepeaterSpinner');
|
||||||
var ajaxURL = ProcessWire.config.InputfieldRepeater.editorUrl + '?id=' + pageID + '&field=' + fieldName;
|
var ajaxURL = ProcessWire.config.InputfieldRepeater.editorUrl + '?id=' + pageID + '&field=' + fieldName;
|
||||||
|
|
||||||
@@ -484,65 +315,424 @@ function InputfieldRepeaterInit($this) {
|
|||||||
var $addItem = $(data).find(".InputfieldRepeaterItemRequested");
|
var $addItem = $(data).find(".InputfieldRepeaterItemRequested");
|
||||||
if(!$addItem.length) {
|
if(!$addItem.length) {
|
||||||
// error
|
// error
|
||||||
// console.log("Can't find item: .InputfieldRepeaterItem.InputfieldRepeaterUnpublished");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addRepeaterItem($addItem);
|
addRepeaterItem($addItem);
|
||||||
$addItem.wrap("<div />"); // wrap for inputfields.js $target
|
$addItem.wrap("<div />"); // wrap for inputfields.js $target
|
||||||
InputfieldsInit($addItem.parent());
|
InputfieldsInit($addItem.parent());
|
||||||
InputfieldRepeaterInit($addItem);
|
initRepeater($addItem);
|
||||||
$addItem.unwrap(); // unwrap div once item initialized
|
$addItem.unwrap(); // unwrap div once item initialized
|
||||||
//$addItem.find('input.InputfieldRepeaterPublish').attr('value', 1);
|
|
||||||
$addItem.find('.Inputfield').trigger('reloaded', [ 'InputfieldRepeaterItemAdd' ]);
|
$addItem.find('.Inputfield').trigger('reloaded', [ 'InputfieldRepeaterItemAdd' ]);
|
||||||
$addItem.find('.InputfieldRepeaterSort').val($inputfields.children().length);
|
$addItem.find('.InputfieldRepeaterSort').val($inputfields.children().length);
|
||||||
$('html, body').animate({
|
$('html, body').animate({
|
||||||
scrollTop: $addItem.offset().top
|
scrollTop: $addItem.offset().top
|
||||||
}, 500, 'swing');
|
}, 500, 'swing');
|
||||||
InputfieldRepeaterUpdateState($addItem);
|
updateState($addItem);
|
||||||
InputfieldRepeaterCheckMax($inputfieldRepeater);
|
checkMax($inputfieldRepeater);
|
||||||
$nestedRepeaters = $addItem.find('.InputfieldRepeater');
|
$nestedRepeaters = $addItem.find('.InputfieldRepeater');
|
||||||
if($nestedRepeaters.length) {
|
if($nestedRepeaters.length) {
|
||||||
$nestedRepeaters.each(function() {
|
$nestedRepeaters.each(function() {
|
||||||
InputfieldRepeaterInit($(this));
|
initRepeater($(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for the "open all" or "collapse all" functions
|
||||||
|
*
|
||||||
|
* @param e
|
||||||
|
* @returns {boolean}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
var eventOpenAllClick = function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var $repeater = $(this).closest('.InputfieldRepeater');
|
||||||
|
var $items = $repeater.children('.InputfieldContent').children('.Inputfields').children('.InputfieldRepeaterItem');
|
||||||
|
if(!$items.length) return false;
|
||||||
|
var $item = $items.eq(0);
|
||||||
|
|
||||||
|
if($item.hasClass('InputfieldStateCollapsed')) {
|
||||||
|
var label = ProcessWire.config.InputfieldRepeater.labels.openAll;
|
||||||
|
var selector = '.InputfieldStateCollapsed';
|
||||||
|
} else {
|
||||||
|
var label = ProcessWire.config.InputfieldRepeater.labels.collapseAll;
|
||||||
|
var selector = '.InputfieldRepeaterItem:not(.InputfieldStateCollapsed)';
|
||||||
|
}
|
||||||
|
ProcessWire.confirm(label, function() {
|
||||||
|
$items.filter(selector).each(function() {
|
||||||
|
$(this).children('.InputfieldHeader').find('.toggle-icon').click();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
//$(".InputfieldRepeaterUnpublished").children('.InputfieldHeader').addClass('ui-priority-secondary');
|
/*** GENERAL FUNCTIONS **********************************************************************************/
|
||||||
|
|
||||||
if($inputfieldRepeater.hasClass('InputfieldRepeaterMax')) InputfieldRepeaterCheckMax($inputfieldRepeater);
|
/**
|
||||||
|
* Given an InputfieldRepeaterItem update the label consistent with any present formatting sting
|
||||||
|
*
|
||||||
|
* Primarily adjusts item count(s) and allowed for {secondary} text appearance
|
||||||
|
*
|
||||||
|
* @param $item An .InputfieldRepeaterItem
|
||||||
|
* @param bool doIncrement Specify true to increment the item count value (like for new items)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function adjustItemLabel($item, doIncrement) {
|
||||||
|
|
||||||
|
var $label = $item.children('label');
|
||||||
|
var labelHTML = $label.html();
|
||||||
|
var _labelHTML = labelHTML;
|
||||||
|
|
||||||
|
if(doIncrement && labelHTML.indexOf('#') > -1) {
|
||||||
|
num = $item.siblings('.InputfieldRepeaterItem:visible').length + 1;
|
||||||
|
labelHTML = labelHTML.replace(/#[0-9]+/, '#' + num);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function() {
|
if(labelHTML.indexOf('{') > -1) {
|
||||||
|
// parts of the label wrapped in {brackets} get different appearance
|
||||||
|
labelHTML = labelHTML.replace(/\{/, '<span class="ui-priority-secondary" style="font-weight:normal">');
|
||||||
|
labelHTML = labelHTML.replace(/}/, '</span>');
|
||||||
|
}
|
||||||
|
|
||||||
$(".InputfieldRepeater").each(function() {
|
if(labelHTML != _labelHTML) {
|
||||||
InputfieldRepeaterInit($(this));
|
$label.html(labelHTML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the sortable depth of a repeater item and either return it or apply it
|
||||||
|
*
|
||||||
|
* @param ui The 'ui' argument provided to jQuery UI sortable events
|
||||||
|
* @param maxDepth Maximum allowed depth
|
||||||
|
* @param updateNow Specify true to apply the determined depth now or false to just return it.
|
||||||
|
* @returns {number} Depth integer value between 0 and maxDepth
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function sortableDepth(ui, maxDepth, updateNow) {
|
||||||
|
|
||||||
|
var $depth = ui.item.find('.InputfieldRepeaterDepth');
|
||||||
|
var depth = -1;
|
||||||
|
var prevDepth = parseInt($depth.val());
|
||||||
|
var left = ui.position.left;
|
||||||
|
|
||||||
|
// AdminThemeReno has something different going on with the left positions, so we adjust for that here
|
||||||
|
if(isReno) left -= depthSize;
|
||||||
|
|
||||||
|
if(left < 0) {
|
||||||
|
depth = prevDepth - Math.round(Math.abs(left) / depthSize);
|
||||||
|
// console.log('decrease depth to: ' + depth);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
depth = Math.round(left / depthSize) + prevDepth;
|
||||||
|
// console.log('increase depth to: ' + depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(depth < 1) {
|
||||||
|
depth = 0;
|
||||||
|
} else if(depth > maxDepth) {
|
||||||
|
depth = maxDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(updateNow) {
|
||||||
|
if(depth) {
|
||||||
|
ui.item.css('margin-left', (depth * depthSize) + 'px');
|
||||||
|
} else {
|
||||||
|
ui.item.css('margin-left', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$depth.val(depth);
|
||||||
|
ui.item.children('.InputfieldHeader').removeClass('ui-state-error');
|
||||||
|
}
|
||||||
|
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** INIT FUNCTIONS **********************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize repeater item depths
|
||||||
|
*
|
||||||
|
* Applies a left-margin to repeater items consistent with with value in
|
||||||
|
* each item's input.InputfieldRepeaterDepth hidden input.
|
||||||
|
*
|
||||||
|
* @param $inputfieldRepeater
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function initDepths($inputfieldRepeater) {
|
||||||
|
$inputfieldRepeater.find('.InputfieldRepeaterDepth').each(function() {
|
||||||
|
var $depth = $(this);
|
||||||
|
var depth = $depth.val();
|
||||||
|
var $item = $depth.closest('.InputfieldRepeaterItem');
|
||||||
|
var currentLeft = $item.css('margin-left');
|
||||||
|
if(currentLeft == 'auto') currentLeft = 0;
|
||||||
|
currentLeft = parseInt(currentLeft);
|
||||||
|
var targetLeft = depth * depthSize;
|
||||||
|
if(targetLeft != currentLeft) {
|
||||||
|
$item.css('margin-left', targetLeft + 'px');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 sortableOptions = {
|
||||||
|
items: '> li:not(.InputfieldRepeaterNewItem)',
|
||||||
|
handle: '.InputfieldRepeaterDrag',
|
||||||
|
start: function(e, ui) {
|
||||||
|
ui.item.find('.InputfieldHeader').addClass("ui-state-highlight");
|
||||||
|
|
||||||
|
// CKEditor doesn't like being sorted, do destroy when sort starts, and reload after sort
|
||||||
|
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'));
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('reloaded', '.InputfieldRepeater', function(event, source) {
|
// TinyMCE instances don't like to be dragged, so we disable them temporarily
|
||||||
if(typeof source != "undefined") {
|
ui.item.find('.InputfieldTinyMCE textarea').each(function() {
|
||||||
if(source == 'InputfieldRepeaterItemEdit' || source == 'InputfieldRepeaterItemAdd') {
|
tinyMCE.execCommand('mceRemoveControl', false, $(this).attr('id'));
|
||||||
event.stopPropagation();
|
});
|
||||||
var $r = $(this).find(".InputfieldRepeater");
|
},
|
||||||
if($r.length) InputfieldRepeaterInit($r);
|
|
||||||
|
stop: function(e, ui) {
|
||||||
|
if(maxDepth > 0) {
|
||||||
|
sortableDepth(ui, maxDepth, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.item.find('.InputfieldHeader').removeClass("ui-state-highlight");
|
||||||
|
$(this).children().each(function(n) {
|
||||||
|
$(this).find('.InputfieldRepeaterSort').slice(0,1).attr('value', n);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-enable CKEditor instances
|
||||||
|
ui.item.find('textarea.InputfieldCKEditorNormal:not(.InputfieldCKEditorLoaded)').each(function() {
|
||||||
|
$(this).closest('.InputfieldCKEditor').trigger('reloaded', [ 'InputfieldRepeaterSort' ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-enable the TinyMCE instances
|
||||||
|
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) {
|
||||||
|
// beyond max depth allowed
|
||||||
|
$header.addClass('ui-state-error');
|
||||||
|
} else if($header.hasClass('ui-state-error')) {
|
||||||
|
// no problems
|
||||||
|
$header.removeClass('ui-state-error');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
sortableOptions.axis = 'y';
|
||||||
|
}
|
||||||
|
// apply "ui-state-focus" class when an item is being dragged
|
||||||
|
$(".InputfieldRepeaterDrag", $inputfields).hover(function() {
|
||||||
|
$(this).parent('label').addClass('ui-state-focus');
|
||||||
|
}, function() {
|
||||||
|
$(this).parent('label').removeClass('ui-state-focus');
|
||||||
|
});
|
||||||
|
|
||||||
|
$inputfields.sortable(sortableOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a repeater
|
||||||
|
*
|
||||||
|
* @param $this Can be an .InputfieldRepeater or an .InputfieldRepeaterItem
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function initRepeater($this) {
|
||||||
|
|
||||||
|
if($this.hasClass('InputfieldRepeaterItem')) {
|
||||||
|
// single repeater item
|
||||||
|
var $inputfields = $this;
|
||||||
|
var $inputfieldRepeater = $this.closest('.InputfieldRepeater');
|
||||||
|
var isItem = true;
|
||||||
|
} else {
|
||||||
|
// enter repeater
|
||||||
|
var $inputfields = $this.find('.Inputfields:eq(0)');
|
||||||
|
var $inputfieldRepeater = $this;
|
||||||
|
var isItem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($inputfields.hasClass('InputfieldRepeaterInit')) return;
|
||||||
|
|
||||||
|
$inputfields.addClass('InputfieldRepeaterInit');
|
||||||
|
|
||||||
|
var renderValueMode = $inputfields.closest('.InputfieldRenderValueMode').length > 0;
|
||||||
|
var $clone = $("<i class='fa fa-copy InputfieldRepeaterClone'></i>").css('display', 'block');
|
||||||
|
var $delete = $("<i class='fa fa-trash InputfieldRepeaterTrash'></i>");
|
||||||
|
var $toggle = $("<i class='fa InputfieldRepeaterToggle' data-on='fa-toggle-on' data-off='fa-toggle-off'></i>");
|
||||||
|
var cfg = ProcessWire.config.InputfieldRepeater;
|
||||||
|
var allowClone = !$inputfieldRepeater.hasClass('InputfieldRepeaterNoAjaxAdd');
|
||||||
|
|
||||||
|
if(cfg) {
|
||||||
|
$toggle.attr('title', cfg.labels.toggle);
|
||||||
|
$delete.attr('title', cfg.labels.remove);
|
||||||
|
$clone.attr('title', cfg.labels.clone);
|
||||||
|
}
|
||||||
|
|
||||||
|
$("input.InputfieldRepeaterDelete", $this).parents('.InputfieldCheckbox').hide();
|
||||||
|
|
||||||
|
function initHeaders($headers) {
|
||||||
|
$headers.each(function() {
|
||||||
|
var $t = $(this);
|
||||||
|
if($t.hasClass('InputfieldRepeaterHeaderInit')) return;
|
||||||
|
var icon = 'fa-arrows';
|
||||||
|
var $item = $t.parent();
|
||||||
|
if($item.hasClass('InputfieldRepeaterNewItem')) {
|
||||||
|
// noAjaxAdd mode
|
||||||
|
icon = 'fa-plus';
|
||||||
|
$t.addClass('ui-priority-secondary');
|
||||||
|
}
|
||||||
|
$t.addClass('ui-state-default InputfieldRepeaterHeaderInit');
|
||||||
|
$t.prepend("<i class='fa fa-fw " + icon + " InputfieldRepeaterDrag'></i>")
|
||||||
|
if(!renderValueMode) {
|
||||||
|
//if(allowClone) $t.prepend($clone.clone(true));
|
||||||
|
var $controls = $("<span class='InputfieldRepeaterItemControls'></span>");
|
||||||
|
var $toggleControl = $toggle.clone(true).addClass($t.parent().hasClass('InputfieldRepeaterOff') ? 'fa-toggle-off' : 'fa-toggle-on');
|
||||||
|
var $deleteControl = $delete.clone(true);
|
||||||
|
var $collapseControl = $t.find('.toggle-icon');
|
||||||
|
//$collapseControl.addClass('InputfieldRepeaterCollapse').removeClass('toggle-icon');
|
||||||
|
$controls.prepend($collapseControl);
|
||||||
|
if(allowClone) $controls.prepend($clone.clone(true));
|
||||||
|
$controls.prepend($toggleControl).prepend($deleteControl);
|
||||||
|
$t.prepend($controls);
|
||||||
|
$controls.css('background-color', $t.css('background-color'));
|
||||||
|
}
|
||||||
|
adjustItemLabel($item, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isItem) {
|
||||||
|
initHeaders($this.children('.InputfieldHeader'));
|
||||||
|
} else {
|
||||||
|
initHeaders($(".InputfieldRepeaterItem > .InputfieldHeader", $this));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(renderValueMode) {
|
||||||
|
// nothing further needed if only rendering the value
|
||||||
|
initDepths($inputfieldRepeater);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hovering the trash gives a preview of what clicking it would do
|
||||||
|
$(".InputfieldRepeaterTrash", $this).hover(function() {
|
||||||
|
var $label = $(this).closest('label');
|
||||||
|
if(!$label.parents().hasClass('InputfieldRepeaterDeletePending')) $label.addClass('ui-state-error');
|
||||||
|
$label.find('.InputfieldRepeaterItemControls').css('background-color', $label.css('background-color'));
|
||||||
|
}, function() {
|
||||||
|
var $label = $(this).closest('label');
|
||||||
|
if(!$label.parent().hasClass('InputfieldRepeaterDeletePending')) $label.removeClass('ui-state-error');
|
||||||
|
$label.find('.InputfieldRepeaterItemControls').css('background-color', $label.css('background-color'));
|
||||||
|
});
|
||||||
|
|
||||||
|
// if we only init'd a single item, now make $inputfields refer to all repeater items for sortable init
|
||||||
|
if(isItem) $inputfields = $inputfieldRepeater.find('.Inputfields:eq(0)');
|
||||||
|
|
||||||
|
// setup the sortable
|
||||||
|
initSortable($inputfieldRepeater, $inputfields);
|
||||||
|
|
||||||
|
// setup the add links
|
||||||
|
$(".InputfieldRepeaterAddLink:not(.InputfieldRepeaterAddLinkInit)", $inputfieldRepeater)
|
||||||
|
.addClass('InputfieldRepeaterAddLinkInit')
|
||||||
|
.click(eventAddLinkClick);
|
||||||
|
|
||||||
|
// check for maximum items
|
||||||
|
if($inputfieldRepeater.hasClass('InputfieldRepeaterMax')) {
|
||||||
|
checkMax($inputfieldRepeater);
|
||||||
}
|
}
|
||||||
InputfieldRepeaterInit($(this));
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When "max items" setting is used, this toggles whether or not "add" links are visible
|
||||||
|
*
|
||||||
|
* @todo Make this toggle the clone links as well
|
||||||
|
* @param $inputfieldRepeater .InputfieldRepeater
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function checkMax($inputfieldRepeater) {
|
||||||
|
if(!$inputfieldRepeater.hasClass('InputfieldRepeaterMax')) return;
|
||||||
|
var max = parseInt($inputfieldRepeater.attr('data-max'));
|
||||||
|
if(max <= 0) return;
|
||||||
|
var $content = $inputfieldRepeater.children('.InputfieldContent');
|
||||||
|
var num = $content.children('.Inputfields').children('li:not(.InputfieldRepeaterDeletePending)').length;
|
||||||
|
var $addItem = $content.children('.InputfieldRepeaterAddItem');
|
||||||
|
if(num > max) {
|
||||||
|
$addItem.hide();
|
||||||
|
} else if(!$addItem.is(":visible")) {
|
||||||
|
$addItem.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update state of the remembered open repeaters
|
||||||
|
*
|
||||||
|
* Note: this records state for all repeaters on the page in cookie 'repeaters_open'
|
||||||
|
* that are configured to be remembered.
|
||||||
|
*
|
||||||
|
* @param $item .InputfieldRepeaterItem
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function updateState($item) {
|
||||||
|
if($item.closest('.InputfieldRepeaterRememberOpen').length < 1) return;
|
||||||
|
var val = '';
|
||||||
|
$(".InputfieldRepeaterItem:not(.InputfieldStateCollapsed)").each(function() {
|
||||||
|
var id = parseInt($(this).attr('data-page'));
|
||||||
|
if(id > 0) {
|
||||||
|
val += id + '|';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$.cookie('repeaters_open', val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization for document.ready
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function init() {
|
||||||
|
|
||||||
|
$('.InputfieldRepeater').each(function() {
|
||||||
|
initRepeater($(this));
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document)
|
$(document)
|
||||||
.on('click', '.InputfieldRepeaterTrash', InputfieldRepeaterDeleteClick)
|
.on('reloaded', '.InputfieldRepeater', eventReloaded)
|
||||||
.on('dblclick', '.InputfieldRepeaterTrash', InputfieldRepeaterDeleteDblClick)
|
.on('click', '.InputfieldRepeaterTrash', eventDeleteClick)
|
||||||
.on('click', '.InputfieldRepeaterClone', InputfieldRepeaterCloneClick)
|
.on('dblclick', '.InputfieldRepeaterTrash', eventDeleteDblClick)
|
||||||
.on('click', '.InputfieldRepeaterToggle', InputfieldRepeaterToggleClick)
|
.on('click', '.InputfieldRepeaterClone', eventCloneClick)
|
||||||
.on('opened', '.InputfieldRepeaterItem', InputfieldRepeaterItemOpened)
|
.on('dblclick', '.InputfieldRepeaterToggle', eventOpenAllClick)
|
||||||
.on('closed', '.InputfieldRepeaterItem', InputfieldRepeaterItemClosed)
|
.on('click', '.InputfieldRepeaterToggle', eventToggleClick)
|
||||||
.on('openReady', '.InputfieldRepeaterItem', InputfieldRepeaterItemOpenReady);
|
.on('opened', '.InputfieldRepeaterItem', eventItemOpened)
|
||||||
});
|
.on('closed', '.InputfieldRepeaterItem', eventItemClosed)
|
||||||
|
.on('openReady', '.InputfieldRepeaterItem', eventItemOpenReady);
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(document).ready(function($) {
|
||||||
|
InputfieldRepeater($);
|
||||||
|
});
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -335,8 +335,12 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
|
|||||||
$loaded->attr('value', $isLoaded ? 1 : 0);
|
$loaded->attr('value', $isLoaded ? 1 : 0);
|
||||||
|
|
||||||
$wrap = $this->wire('modules')->get('InputfieldFieldset');
|
$wrap = $this->wire('modules')->get('InputfieldFieldset');
|
||||||
$wrap->addClass('InputfieldRepeaterItem');
|
$wrap->addClass('InputfieldRepeaterItem InputfieldNoFocus');
|
||||||
$wrap->label = $this->renderRepeaterLabel($label, ++$cnt, $page);
|
$wrap->entityEncodeLabel = false;
|
||||||
|
$wrap->label =
|
||||||
|
"<span class='InputfieldRepeaterItemLabel'>" .
|
||||||
|
$this->entityEncode($this->renderRepeaterLabel($label, ++$cnt, $page)) .
|
||||||
|
"</span>";
|
||||||
$wrap->name = "repeater_item_{$page->id}";
|
$wrap->name = "repeater_item_{$page->id}";
|
||||||
$wrap->wrapAttr('data-page', $page->id);
|
$wrap->wrapAttr('data-page', $page->id);
|
||||||
$wrap->wrapAttr('data-type', $this->getRepeaterItemType($page));
|
$wrap->wrapAttr('data-type', $this->getRepeaterItemType($page));
|
||||||
@@ -400,6 +404,7 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
|
|||||||
|
|
||||||
// create a new/blank item to be used as a template for any new items added
|
// create a new/blank item to be used as a template for any new items added
|
||||||
if(!$itemID) {
|
if(!$itemID) {
|
||||||
|
/** @var InputfieldWrapper $wrap */
|
||||||
$wrap = $this->wire('modules')->get('InputfieldFieldset');
|
$wrap = $this->wire('modules')->get('InputfieldFieldset');
|
||||||
$wrap->label = $this->renderRepeaterLabel($label, ++$cnt, new NullPage());
|
$wrap->label = $this->renderRepeaterLabel($label, ++$cnt, new NullPage());
|
||||||
$wrap->class = 'InputfieldRepeaterItem InputfieldRepeaterNewItem';
|
$wrap->class = 'InputfieldRepeaterItem InputfieldRepeaterNewItem';
|
||||||
@@ -540,10 +545,12 @@ class InputfieldRepeater extends Inputfield implements InputfieldItemList {
|
|||||||
$this->wire('config')->js('InputfieldRepeater', array(
|
$this->wire('config')->js('InputfieldRepeater', array(
|
||||||
'editorUrl' => $editorUrl,
|
'editorUrl' => $editorUrl,
|
||||||
'labels' => array(
|
'labels' => array(
|
||||||
'remove' => $this->_x('Delete this item', 'repeater-item-action'),
|
'remove' => $this->_x('Click to delete this item, or double-click to delete all', 'repeater-item-action'),
|
||||||
'removeAll' => $this->_x('Delete all items?', 'repeater-item-action'),
|
'removeAll' => $this->_x('Delete all items?', 'repeater-item-action'),
|
||||||
'toggle' => $this->_x('Toggle published/unpublished', 'repeater-item-action'),
|
'toggle' => $this->_x('Click to turn item on/off, or double-click to open/collapse all items', 'repeater-item-action'),
|
||||||
'clone' => $this->_x('Clone this item?', 'repeater-item-action')
|
'clone' => $this->_x('Clone this item?', 'repeater-item-action'),
|
||||||
|
'openAll' => $this->_x('Open all items?', 'repeater-item-action'),
|
||||||
|
'collapseAll' => $this->_x('Collapse all items?', 'repeater-item-action')
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@@ -7,28 +7,50 @@
|
|||||||
|
|
||||||
.InputfieldRepeaterItem > .InputfieldHeader {
|
.InputfieldRepeaterItem > .InputfieldHeader {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
padding: 0.5em;
|
padding: 0.5em 0 0.5em 0.4em;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.InputfieldRepeaterItemLabel {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 0.25em;
|
||||||
|
}
|
||||||
|
.InputfieldRepeaterItemControls {
|
||||||
|
padding-right: 0.5em;
|
||||||
|
padding-left: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1;
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.InputfieldRepeaterClone,
|
||||||
|
.InputfieldRepeaterToggle,
|
||||||
|
.InputfieldRepeaterTrash,
|
||||||
|
.toggle-icon {
|
||||||
|
cursor: pointer;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.InputfieldRepeaterTrash {
|
||||||
|
padding-right: 3px;
|
||||||
|
}
|
||||||
|
.InputfieldRepeaterToggle {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
.InputfieldRepeaterClone {
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-icon {
|
.toggle-icon {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
& > .InputfieldRepeaterClone,
|
|
||||||
& > .InputfieldRepeaterToggle,
|
|
||||||
& > .InputfieldRepeaterTrash {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
& > .InputfieldRepeaterTrash {
|
|
||||||
padding-right: 3px;
|
|
||||||
}
|
|
||||||
& > .InputfieldRepeaterToggle {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
& > .InputfieldRepeaterClone {
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending) {
|
.InputfieldRepeaterItem:not(.InputfieldRepeaterDeletePending) {
|
||||||
@@ -48,12 +70,16 @@
|
|||||||
&.InputfieldRepeaterOff > .InputfieldHeader {
|
&.InputfieldRepeaterOff > .InputfieldHeader {
|
||||||
// off items faded yet even more
|
// off items faded yet even more
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
&:not(:hover) {
|
&:not(:hover) > .InputfieldRepeaterItemLabel {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.InputfieldRepeaterItem.InputfieldRepeaterDeletePending > .InputfieldHeader > .InputfieldRepeaterItemLabel {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
.InputfieldRepeaterItem.InputfieldRepeaterItemLoading {
|
.InputfieldRepeaterItem.InputfieldRepeaterItemLoading {
|
||||||
// override the margin-bottom 1.25em from admin theme stylesheet, so margin isn't showing while item is loading
|
// override the margin-bottom 1.25em from admin theme stylesheet, so margin isn't showing while item is loading
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
@@ -82,6 +108,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.InputfieldRepeaterAddItem input {
|
.InputfieldRepeaterAddItem input {
|
||||||
// count of added items hidden
|
// count of added items hidden
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -96,6 +123,7 @@
|
|||||||
|
|
||||||
.InputfieldRepeaterDrag {
|
.InputfieldRepeaterDrag {
|
||||||
// draggable icon for repeater items
|
// draggable icon for repeater items
|
||||||
|
display: inline-block;
|
||||||
cursor: ns-resize;
|
cursor: ns-resize;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
|
@@ -351,4 +351,11 @@
|
|||||||
top: -1.1em;
|
top: -1.1em;
|
||||||
bottom: auto; }
|
bottom: auto; }
|
||||||
|
|
||||||
|
.AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input textarea:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="date"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="datetime-local"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="email"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="month"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="number"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="password"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="search"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="tel"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="text"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="time"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="url"]:focus, .AdminThemeReno .vex.vex-theme-default .vex-dialog-form .vex-dialog-input input[type="week"]:focus {
|
||||||
|
-moz-box-shadow: inset 0 0 0 2px #86d7c1;
|
||||||
|
-webkit-box-shadow: inset 0 0 0 2px #86d7c1;
|
||||||
|
box-shadow: inset 0 0 0 2px #86d7c1; }
|
||||||
|
.AdminThemeReno .vex.vex-theme-default .vex-dialog-button.vex-dialog-button-primary {
|
||||||
|
background: #3eb998; }
|
||||||
|
|
||||||
/*# sourceMappingURL=vex-theme-default.css.map */
|
/*# sourceMappingURL=vex-theme-default.css.map */
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
$blue: #3288e6
|
$blue: #3288e6
|
||||||
$green: #93BF0D // RJC
|
$green: #93BF0D // RJC
|
||||||
|
$reno-green: #3eb998 // RJC
|
||||||
|
|
||||||
.vex.vex-theme-default
|
.vex.vex-theme-default
|
||||||
padding-top: 160px
|
padding-top: 160px
|
||||||
@@ -128,3 +129,16 @@ $green: #93BF0D // RJC
|
|||||||
border-top-color: #bbb
|
border-top-color: #bbb
|
||||||
top: -1.1em
|
top: -1.1em
|
||||||
bottom: auto
|
bottom: auto
|
||||||
|
|
||||||
|
.AdminThemeReno
|
||||||
|
.vex.vex-theme-default
|
||||||
|
.vex-dialog-form
|
||||||
|
.vex-dialog-input
|
||||||
|
textarea, input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="email"], input[type="month"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="time"], input[type="url"], input[type="week"]
|
||||||
|
&:focus
|
||||||
|
+box-shadow(inset 0 0 0 2px lighten($reno-green, 20%)) // RJC
|
||||||
|
|
||||||
|
.vex-dialog-button
|
||||||
|
&.vex-dialog-button-primary
|
||||||
|
background: $reno-green // RJC
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user