You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
9.4 KiB
289 lines
9.4 KiB
$.fn.repeaterVal = function () { |
|
var parse = function (raw) { |
|
var parsed = []; |
|
|
|
foreach(raw, function (val, key) { |
|
var parsedKey = []; |
|
if(key !== "undefined") { |
|
parsedKey.push(key.match(/^[^\[]*/)[0]); |
|
parsedKey = parsedKey.concat(map( |
|
key.match(/\[[^\]]*\]/g), |
|
function (bracketed) { |
|
return bracketed.replace(/[\[\]]/g, ''); |
|
} |
|
)); |
|
|
|
parsed.push({ |
|
val: val, |
|
key: parsedKey |
|
}); |
|
} |
|
}); |
|
|
|
return parsed; |
|
}; |
|
|
|
var build = function (parsed) { |
|
if( |
|
parsed.length === 1 && |
|
(parsed[0].key.length === 0 || parsed[0].key.length === 1 && !parsed[0].key[0]) |
|
) { |
|
return parsed[0].val; |
|
} |
|
|
|
foreach(parsed, function (p) { |
|
p.head = p.key.shift(); |
|
}); |
|
|
|
var grouped = (function () { |
|
var grouped = {}; |
|
|
|
foreach(parsed, function (p) { |
|
if(!grouped[p.head]) { |
|
grouped[p.head] = []; |
|
} |
|
grouped[p.head].push(p); |
|
}); |
|
|
|
return grouped; |
|
}()); |
|
|
|
var built; |
|
|
|
if(/^[0-9]+$/.test(parsed[0].head)) { |
|
built = []; |
|
foreach(grouped, function (group) { |
|
built.push(build(group)); |
|
}); |
|
} |
|
else { |
|
built = {}; |
|
foreach(grouped, function (group, key) { |
|
built[key] = build(group); |
|
}); |
|
} |
|
|
|
return built; |
|
}; |
|
|
|
return build(parse($(this).inputVal())); |
|
}; |
|
|
|
$.fn.repeater = function (fig) { |
|
fig = fig || {}; |
|
|
|
var setList; |
|
|
|
$(this).each(function () { |
|
|
|
var $self = $(this); |
|
|
|
var show = fig.show || function () { |
|
$(this).show(); |
|
}; |
|
|
|
var hide = fig.hide || function (removeElement) { |
|
removeElement(); |
|
}; |
|
|
|
var $list = $self.find('[data-repeater-list]').first(); |
|
|
|
var $filterNested = function ($items, repeaters) { |
|
return $items.filter(function () { |
|
return repeaters ? |
|
$(this).closest( |
|
pluck(repeaters, 'selector').join(',') |
|
).length === 0 : true; |
|
}); |
|
}; |
|
|
|
var $items = function () { |
|
return $filterNested($list.find('[data-repeater-item]'), fig.repeaters); |
|
}; |
|
|
|
var $itemTemplate = $list.find('[data-repeater-item]') |
|
.first().clone().hide(); |
|
|
|
var $firstDeleteButton = $filterNested( |
|
$filterNested($(this).find('[data-repeater-item]'), fig.repeaters) |
|
.first().find('[data-repeater-delete]'), |
|
fig.repeaters |
|
); |
|
|
|
if(fig.isFirstItemUndeletable && $firstDeleteButton) { |
|
$firstDeleteButton.remove(); |
|
} |
|
|
|
var getGroupName = function () { |
|
var groupName = $list.data('repeater-list'); |
|
return fig.$parent ? |
|
fig.$parent.data('item-name') + '[' + groupName + ']' : |
|
groupName; |
|
}; |
|
|
|
var initNested = function ($listItems) { |
|
if(fig.repeaters) { |
|
$listItems.each(function () { |
|
var $item = $(this); |
|
foreach(fig.repeaters, function (nestedFig) { |
|
$item.find(nestedFig.selector).repeater(extend( |
|
nestedFig, { $parent: $item } |
|
)); |
|
}); |
|
}); |
|
} |
|
}; |
|
|
|
var $foreachRepeaterInItem = function (repeaters, $item, cb) { |
|
if(repeaters) { |
|
foreach(repeaters, function (nestedFig) { |
|
cb.call($item.find(nestedFig.selector)[0], nestedFig); |
|
}); |
|
} |
|
}; |
|
|
|
var setIndexes = function ($items, groupName, repeaters) { |
|
$items.each(function (index) { |
|
var $item = $(this); |
|
$item.data('item-name', groupName + '[' + index + ']'); |
|
$filterNested($item.find('[name]'), repeaters) |
|
.each(function () { |
|
var $input = $(this); |
|
// match non empty brackets (ex: "[foo]") |
|
var matches = $input.attr('name').match(/\[[^\]]+\]/g); |
|
|
|
var name = matches ? |
|
// strip "[" and "]" characters |
|
last(matches).replace(/\[|\]/g, '') : |
|
$input.attr('name'); |
|
|
|
|
|
var newName = groupName + '[' + index + '][' + name + ']' + |
|
($input.is(':checkbox') || $input.attr('multiple') ? '[]' : ''); |
|
|
|
$input.attr('name', newName); |
|
|
|
$foreachRepeaterInItem(repeaters, $item, function (nestedFig) { |
|
var $repeater = $(this); |
|
setIndexes( |
|
$filterNested($repeater.find('[data-repeater-item]'), nestedFig.repeaters || []), |
|
groupName + '[' + index + ']' + |
|
'[' + $repeater.find('[data-repeater-list]').first().data('repeater-list') + ']', |
|
nestedFig.repeaters |
|
); |
|
}); |
|
}); |
|
}); |
|
|
|
$list.find('input[name][checked]') |
|
.removeAttr('checked') |
|
.prop('checked', true); |
|
}; |
|
|
|
setIndexes($items(), getGroupName(), fig.repeaters); |
|
initNested($items()); |
|
if(fig.initEmpty) { |
|
$items().remove(); |
|
} |
|
|
|
if(fig.ready) { |
|
fig.ready(function () { |
|
setIndexes($items(), getGroupName(), fig.repeaters); |
|
}); |
|
} |
|
|
|
var appendItem = (function () { |
|
var setItemsValues = function ($item, data, repeaters) { |
|
if(data || fig.defaultValues) { |
|
var inputNames = {}; |
|
$filterNested($item.find('[name]'), repeaters).each(function () { |
|
var key = $(this).attr('name').match(/\[([^\]]*)(\]|\]\[\])$/)[1]; |
|
inputNames[key] = $(this).attr('name'); |
|
}); |
|
|
|
$item.inputVal(map( |
|
filter(data || fig.defaultValues, function (val, name) { |
|
return inputNames[name]; |
|
}), |
|
identity, |
|
function (name) { |
|
return inputNames[name]; |
|
} |
|
)); |
|
} |
|
|
|
|
|
$foreachRepeaterInItem(repeaters, $item, function (nestedFig) { |
|
var $repeater = $(this); |
|
$filterNested( |
|
$repeater.find('[data-repeater-item]'), |
|
nestedFig.repeaters |
|
) |
|
.each(function () { |
|
var fieldName = $repeater.find('[data-repeater-list]').data('repeater-list'); |
|
if(data && data[fieldName]) { |
|
var $template = $(this).clone(); |
|
$repeater.find('[data-repeater-item]').remove(); |
|
foreach(data[fieldName], function (data) { |
|
var $item = $template.clone(); |
|
setItemsValues( |
|
$item, |
|
data, |
|
nestedFig.repeaters || [] |
|
); |
|
$repeater.find('[data-repeater-list]').append($item); |
|
}); |
|
} |
|
else { |
|
setItemsValues( |
|
$(this), |
|
nestedFig.defaultValues, |
|
nestedFig.repeaters || [] |
|
); |
|
} |
|
}); |
|
}); |
|
|
|
}; |
|
|
|
return function ($item, data) { |
|
$list.append($item); |
|
setIndexes($items(), getGroupName(), fig.repeaters); |
|
$item.find('[name]').each(function () { |
|
$(this).inputClear(); |
|
}); |
|
setItemsValues($item, data || fig.defaultValues, fig.repeaters); |
|
}; |
|
}()); |
|
|
|
var addItem = function (data) { |
|
var $item = $itemTemplate.clone(); |
|
appendItem($item, data); |
|
if(fig.repeaters) { |
|
initNested($item); |
|
} |
|
show.call($item.get(0)); |
|
}; |
|
|
|
setList = function (rows) { |
|
$items().remove(); |
|
foreach(rows, addItem); |
|
}; |
|
|
|
$filterNested($self.find('[data-repeater-create]'), fig.repeaters).click(function () { |
|
addItem(); |
|
}); |
|
|
|
$list.on('click', '[data-repeater-delete]', function () { |
|
var self = $(this).closest('[data-repeater-item]').get(0); |
|
hide.call(self, function () { |
|
$(self).remove(); |
|
setIndexes($items(), getGroupName(), fig.repeaters); |
|
}); |
|
}); |
|
}); |
|
|
|
this.setList = setList; |
|
|
|
return this; |
|
};
|
|
|