10 changed files with 531 additions and 0 deletions
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"fieldTypes": { |
||||||
|
"dynamic-checklist": "Dynamic Checklist" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"fieldTypes": { |
||||||
|
"dynamic-checklist": "Dynamic Checklist" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"fieldTypes": { |
||||||
|
"dynamic-checklist": "Lista Interactiva" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"fieldTypes": { |
||||||
|
"dynamic-checklist": "Lista Interactiva" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
{ |
||||||
|
"developerModeScriptList": [ |
||||||
|
"__APPEND__", |
||||||
|
"client/modules/dynamic-checklist/lib/module-js-functions.js" |
||||||
|
], |
||||||
|
"scriptList": [ |
||||||
|
"__APPEND__", |
||||||
|
"client/modules/dynamic-checklist/lib/module-js-functions.js" |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
{ |
||||||
|
"view":"dynamic-checklist:views/fields/dynamic-checklist", |
||||||
|
|
||||||
|
"params":[ |
||||||
|
{ |
||||||
|
"name":"required", |
||||||
|
"type":"bool", |
||||||
|
"default":false |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "allowCustomOptions", |
||||||
|
"type": "bool", |
||||||
|
"hidden": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "noEmptyString", |
||||||
|
"type": "bool", |
||||||
|
"default": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "displayAsList", |
||||||
|
"type":"bool", |
||||||
|
"default": true |
||||||
|
} |
||||||
|
|
||||||
|
], |
||||||
|
"validationList": [ |
||||||
|
"required" |
||||||
|
], |
||||||
|
"filter": true, |
||||||
|
"notCreatable": false, |
||||||
|
"notSortable": true, |
||||||
|
"fieldDefs":{ |
||||||
|
"type":"jsonArray", |
||||||
|
"storeArrayValues": false |
||||||
|
}, |
||||||
|
"translatedOptions": true, |
||||||
|
"dynamicLogicOptions": true, |
||||||
|
"personalData": false |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
function decodeHTML(encodedHTML) { |
||||||
|
var workArea = document.createElement('textarea'); |
||||||
|
workArea.innerHTML = encodedHTML; |
||||||
|
return workArea.value;
|
||||||
|
} |
||||||
|
|
||||||
|
function replaceLabel(objArray,oldLabel,newLabel) { |
||||||
|
let obj = objArray.find((o,i) => { |
||||||
|
if(o.label === oldLabel) { |
||||||
|
objArray[i].label = newLabel; |
||||||
|
return true; // stop searching
|
||||||
|
} |
||||||
|
}); |
||||||
|
return objArray; |
||||||
|
} |
||||||
|
|
||||||
|
function replaceJsonObjectinArrayByReference(objArray,refName,refValue,newObject){ |
||||||
|
let obj = objArray.find((o, i) => { |
||||||
|
if (o.refName === refValue) { |
||||||
|
objArray[i] = newObject; |
||||||
|
return true; // stop searching
|
||||||
|
} |
||||||
|
}); |
||||||
|
return objArray; |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
<div class="link-container list-group"> |
||||||
|
{{#each itemHtmlList}} |
||||||
|
{{{./this}}} |
||||||
|
{{/each}} |
||||||
|
</div> |
||||||
|
<div class="array-control-container"> |
||||||
|
{{#if hasOptions}} |
||||||
|
<button class="btn btn-default btn-block" type="button" data-action="showAddModal">{{translate 'Add'}}</button> |
||||||
|
{{/if}} |
||||||
|
{{#if allowCustomOptions}} |
||||||
|
<div class="input-group addItem"> |
||||||
|
<input class="main-element form-control select addItem" type="text" autocomplete="espo-{{name}}" placeholder="{{#if this.options}}{{translate 'Select'}}{{else}}{{translate 'typeAndPressEnter' category='messages'}}{{/if}}"{{#if maxItemLength}} maxlength="{{maxItemLength}}"{{/if}}> |
||||||
|
<span class="input-group-btn"> |
||||||
|
<button data-action="addItem" class="btn btn-default btn-icon" type="button" tabindex="-1" title="{{translate 'Add Item'}}"><span class="fas fa-plus"></span></button> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="input-group updateItem" style="display:none;"> |
||||||
|
<input class="main-element form-control select updateItem" type="text" autocomplete="espo-{{name}}" placeholder="{{#if this.options}}{{translate 'Select'}}{{else}}{{translate 'typeAndPressEnter' category='messages'}}{{/if}}"{{#if maxItemLength}} maxlength="{{maxItemLength}}"{{/if}}> |
||||||
|
<span class="input-group-btn"> |
||||||
|
<button data-action="updateItem" class="btn btn-default btn-icon" type="button" tabindex="-1" title="{{translate 'Update Item'}}"><span class="fas fa-check"></span></button> |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
{{/if}} |
||||||
|
</div> |
@ -0,0 +1,402 @@ |
|||||||
|
/************************************************************************ |
||||||
|
* This file is part of EspoCRM. |
||||||
|
* |
||||||
|
* EspoCRM - Open Source CRM application. |
||||||
|
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko |
||||||
|
* Website: https://www.espocrm.com
|
||||||
|
* |
||||||
|
* EspoCRM is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* EspoCRM is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
||||||
|
* |
||||||
|
* The interactive user interfaces in modified source and object code versions |
||||||
|
* of this program must display Appropriate Legal Notices, as required under |
||||||
|
* Section 5 of the GNU General Public License version 3. |
||||||
|
* |
||||||
|
* In accordance with Section 7(b) of the GNU General Public License version 3, |
||||||
|
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word. |
||||||
|
************************************************************************/ |
||||||
|
|
||||||
|
define('dynamic-checklist:views/fields/dynamic-checklist', ['views/fields/array'], function (Dep) { |
||||||
|
|
||||||
|
return Dep.extend({ |
||||||
|
|
||||||
|
type: 'dynamic-checklist', |
||||||
|
|
||||||
|
listTemplate: 'fields/array/list', |
||||||
|
|
||||||
|
detailTemplate: 'fields/array/detail', |
||||||
|
|
||||||
|
editTemplate: 'dynamic-checklist:fields/dynamic-checklist/edit', |
||||||
|
|
||||||
|
searchTemplate: 'fields/array/search', |
||||||
|
|
||||||
|
searchTypeList: ['anyOf', 'noneOf', 'allOf', 'isEmpty', 'isNotEmpty'], |
||||||
|
|
||||||
|
maxItemLength: null, |
||||||
|
|
||||||
|
validations: ['required', 'maxCount'], |
||||||
|
|
||||||
|
isInversed: false, |
||||||
|
|
||||||
|
existingObj: null, |
||||||
|
|
||||||
|
displayAsList: true, |
||||||
|
|
||||||
|
data: function () { |
||||||
|
var itemHtmlList = []; |
||||||
|
(this.selected || []).forEach(function (jsonItem) { |
||||||
|
itemHtmlList.push(this.getItemHtml(jsonItem)); |
||||||
|
}, this); |
||||||
|
|
||||||
|
return _.extend({ |
||||||
|
selected: this.selected, |
||||||
|
translatedOptions: this.translatedOptions, |
||||||
|
hasOptions: this.params.options ? true : false, |
||||||
|
itemHtmlList: itemHtmlList, |
||||||
|
isEmpty: (this.selected || []).length === 0, |
||||||
|
valueIsSet: this.model.has(this.name), |
||||||
|
maxItemLength: this.maxItemLength, |
||||||
|
allowCustomOptions: this.allowCustomOptions |
||||||
|
}, Dep.prototype.data.call(this)); |
||||||
|
}, |
||||||
|
|
||||||
|
events: { |
||||||
|
'click [data-action="removeValue"]': function (e) { |
||||||
|
var value = $(e.currentTarget).data('value').toString(); |
||||||
|
this.removeValue(value); |
||||||
|
}, |
||||||
|
'click [data-action="editValue"]': function (e) { |
||||||
|
var existingValue = $(e.currentTarget).data('value').toString(); |
||||||
|
this.editLabel(existingValue); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
getItemHtml: function(jsonItem) { |
||||||
|
// breakdown a given checklist item into its components: label and checkbox value
|
||||||
|
var label = this.escapeValue(jsonItem.label); |
||||||
|
if (this.translatedOptions) { |
||||||
|
if ((label in this.translatedOptions)) { |
||||||
|
label = this.translatedOptions[label]; |
||||||
|
label = label.toString(); |
||||||
|
label = this.escapeValue(label); |
||||||
|
} |
||||||
|
} |
||||||
|
var dataName = 'checklistItem-'+this.name+'-'+label; |
||||||
|
var id = 'checklist-item-'+this.name+'-'+label; |
||||||
|
var isChecked = false; |
||||||
|
if( jsonItem.state == "1"){ |
||||||
|
isChecked = true; |
||||||
|
} |
||||||
|
if(this.isInversed){ |
||||||
|
isChecked = !isChecked; |
||||||
|
} |
||||||
|
var dataValue = this.escapeValue(JSON.stringify(jsonItem)); |
||||||
|
var itemHtml = '<div class="list-group-item" data-value="'+dataValue+'" data-label="'+label+'" style="cursor: default;">'; |
||||||
|
itemHtml += '<div style="float:left; margin-right:5px; vertical-align:top;"><input type="checkbox" style="vertical-align:top;" data-name="'+dataName+'" id="'+id+'"'; |
||||||
|
if(isChecked) { |
||||||
|
itemHtml += ' checked '; |
||||||
|
} |
||||||
|
itemHtml += '></div> '; |
||||||
|
//itemHtml += '<input class = "main-element form-control" type="text" class="checklist-label" value="'+label+'">';
|
||||||
|
itemHtml += '<div style="display:inline-block;max-width:85%;"><label for="'+id+'" class="checklist-label" style="overflow-y: auto !important;">'+label+'</label></div>'; |
||||||
|
itemHtml += '<div style="float:right; width:10%;"><a href="javascript:" class="pull-right" data-value="'+label+'" data-action="removeValue"><span class="fas fa-trash-alt"></span></a>'; |
||||||
|
itemHtml += '<a href="javascript:" class="pull-right" data-value="'+label+'" data-action="editValue" style="margin-right:10px;"><span class="fas fa-pencil-alt fa-sm"></span></a>'; |
||||||
|
itemHtml += '</div></div>'; |
||||||
|
return itemHtml; |
||||||
|
}, |
||||||
|
|
||||||
|
addValue: function (label) { |
||||||
|
var isNew = true; |
||||||
|
// convert the label into a JSON object with the default state value of zero
|
||||||
|
var jsonItem = {}; |
||||||
|
jsonItem.offVal = "0"; |
||||||
|
jsonItem.label = label; |
||||||
|
jsonItem.state = "0"; |
||||||
|
var targetObj = this.selected.find(o => o.label === label); |
||||||
|
if(targetObj) { |
||||||
|
Espo.Ui.error("Duplicate checklist labels are not allowed"); |
||||||
|
isNew = false; |
||||||
|
} |
||||||
|
// it it doesn't exist append to the "selected" array and to the list html
|
||||||
|
if(isNew) { |
||||||
|
// create the rendering html code
|
||||||
|
var html = this.getItemHtml(jsonItem); |
||||||
|
// append the html to the existing list of items
|
||||||
|
this.$list.append(html); |
||||||
|
// append the new dynamic checklist item to the "selected" array
|
||||||
|
this.selected.push(jsonItem); |
||||||
|
// trigger the "change" event
|
||||||
|
this.trigger('change'); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
editLabel: function (existingLabel) { |
||||||
|
var valueInternal = existingLabel.replace(/"/g, '\\"'); |
||||||
|
// remove the element from the DOM
|
||||||
|
this.$list.children('[data-label="' + valueInternal + '"]').remove(); |
||||||
|
// get the existing item object
|
||||||
|
this.existingObj = this.selected.find(o => o.label === existingLabel); |
||||||
|
// display the label on the "updateItem" input container for editing
|
||||||
|
var $inputContainer = $('input.updateItem'); |
||||||
|
$inputContainer.val(existingLabel); |
||||||
|
// hide the "addItem" input-group div and display instead the "updateItem" input-group div
|
||||||
|
this.$el.find('div.addItem').hide(); |
||||||
|
this.$el.find('div.updateItem').show(); |
||||||
|
// enable the "updateItem" button
|
||||||
|
this.controlUpdateItemButton(); |
||||||
|
}, |
||||||
|
|
||||||
|
updateLabel: function (newLabel) { |
||||||
|
// get the existing element json object position inside the array
|
||||||
|
var index = this.selected.indexOf(this.existingObj); |
||||||
|
// update the array of json objects
|
||||||
|
this.selected[index].label = newLabel; |
||||||
|
this.selected[index].state = this.existingObj.state; |
||||||
|
// create the updated element rendering html code
|
||||||
|
var html = this.getItemHtml(this.selected[index]); |
||||||
|
// append the html to the existing list of items
|
||||||
|
this.$list.append(html); |
||||||
|
// trigger the "change" event
|
||||||
|
this.trigger('change'); |
||||||
|
}, |
||||||
|
|
||||||
|
removeValue: function (label) { |
||||||
|
var valueInternal = label.replace(/"/g, '\\"'); |
||||||
|
// remove the element from the DOM
|
||||||
|
this.$list.children('[data-label="' + valueInternal + '"]').remove(); |
||||||
|
// find the element json object in the "selected" array
|
||||||
|
var targetObj = this.selected.find(o => o.label === label); |
||||||
|
// get the element json object position inside the array
|
||||||
|
var index = this.selected.indexOf(targetObj); |
||||||
|
// remove the element from the array of json objects
|
||||||
|
this.selected.splice(index, 1); |
||||||
|
// trigger the 'change' event
|
||||||
|
this.trigger('change'); |
||||||
|
}, |
||||||
|
|
||||||
|
getValueForDisplay: function () { |
||||||
|
var list = this.selected.map(function (jsonItem) { |
||||||
|
// get the checklist item label
|
||||||
|
var label = this.escapeValue(jsonItem.label); |
||||||
|
if (this.translatedOptions) { |
||||||
|
if ((label in this.translatedOptions)) { |
||||||
|
label = this.translatedOptions[label]; |
||||||
|
label = label.toString(); |
||||||
|
label = this.escapeValue(label); |
||||||
|
} |
||||||
|
} |
||||||
|
if (label === '') { |
||||||
|
label = this.translate('None'); |
||||||
|
} |
||||||
|
var style = this.styleMap[jsonItem.label] || 'default'; |
||||||
|
if (this.params.displayAsLabel) { |
||||||
|
label = '<span class="label label-md label-'+style+'">' + label + '</span>'; |
||||||
|
} else { |
||||||
|
if (style && style != 'default') { |
||||||
|
label = '<span class="text-'+style+'">' + label + '</span>'; |
||||||
|
} |
||||||
|
} |
||||||
|
var displayHtml = ''; |
||||||
|
// get the option checkbox boolean value and generate its html code
|
||||||
|
var dataName = 'checklistItem-'+this.name+'-'+label; |
||||||
|
var id = 'checklist-item-'+this.name+'-'+label; |
||||||
|
var isChecked = false; |
||||||
|
if( jsonItem.state == "1"){ |
||||||
|
isChecked = true; |
||||||
|
} |
||||||
|
if(this.isInversed){ |
||||||
|
isChecked = !isChecked; |
||||||
|
} |
||||||
|
displayHtml += '<div style="padding-top:2px;padding-bottom:3px;">'; |
||||||
|
displayHtml += '<div style="display:inline-block; margin-right:5px; vertical-align:top;">'; |
||||||
|
displayHtml += '<input type="checkbox" data-name="'+dataName+'" id="'+id+'"'; |
||||||
|
if(isChecked) { |
||||||
|
displayHtml += ' checked '; |
||||||
|
} |
||||||
|
// prevent the checkbox element from being editable in display mode
|
||||||
|
displayHtml += 'disabled = "disabled"'; |
||||||
|
displayHtml += '>'; |
||||||
|
displayHtml += '</div>'; |
||||||
|
displayHtml += '<div style="display:inline-block;max-width:95%;">'+label+'</div>'; |
||||||
|
displayHtml += '</div>'; |
||||||
|
//displayHtml += ' '+label;
|
||||||
|
return displayHtml; |
||||||
|
}, this); |
||||||
|
if (this.displayAsList) { |
||||||
|
if (!list.length) return ''; |
||||||
|
var itemClassName = 'multi-enum-item-container'; |
||||||
|
if (this.displayAsLabel) { |
||||||
|
itemClassName += ' multi-enum-item-label-container'; |
||||||
|
} |
||||||
|
return '<div class="'+itemClassName+'">' + |
||||||
|
list.join('</div><div class="'+itemClassName+'">') + '</div>'; |
||||||
|
} else if (this.displayAsLabel) { |
||||||
|
return list.join(' '); |
||||||
|
} else { |
||||||
|
return list.join(', '); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
fetchFromDom: function () { |
||||||
|
var selected = []; |
||||||
|
this.$el.find('.list-group .list-group-item').each(function (i, el) { |
||||||
|
var updatedValue = {}; |
||||||
|
// fetch the original data-value
|
||||||
|
var existingValue = $(el).data('value'); |
||||||
|
var label = existingValue.label; |
||||||
|
// fetch the current boolean value (0 or 1)
|
||||||
|
var currentState = $(el).find('input:checkbox:first:checked').length.toString(); |
||||||
|
// build the current item object
|
||||||
|
updatedValue.label = label; |
||||||
|
updatedValue.state = currentState; |
||||||
|
// update the element's data-value attribute
|
||||||
|
$(el).attr('data-value', updatedValue); |
||||||
|
// append the 'selected' array
|
||||||
|
selected.push(updatedValue); |
||||||
|
}); |
||||||
|
this.selected = selected; |
||||||
|
}, |
||||||
|
|
||||||
|
controlAddItemButton: function () { |
||||||
|
var $addItemInput = this.$addItemInput; |
||||||
|
if (!$addItemInput) return; |
||||||
|
if (!$addItemInput.get(0)) return; |
||||||
|
|
||||||
|
var value = $addItemInput.val().toString(); |
||||||
|
if (!value && this.params.noEmptyString) { |
||||||
|
this.$addButton.addClass('disabled').attr('disabled', 'disabled'); |
||||||
|
} else { |
||||||
|
this.$addButton.removeClass('disabled').removeAttr('disabled'); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
controlUpdateItemButton: function () { |
||||||
|
//alert("controlUpdateItemButton function invoked");
|
||||||
|
var $updateItemInput = this.$updateItemInput; |
||||||
|
if (!$updateItemInput) return; |
||||||
|
if (!$updateItemInput.get(0)) return; |
||||||
|
|
||||||
|
var value = $updateItemInput.val().toString(); |
||||||
|
if (!value && this.params.noEmptyString) { |
||||||
|
this.$updateButton.addClass('disabled').attr('disabled', 'disabled'); |
||||||
|
} else { |
||||||
|
this.$updateButton.removeClass('disabled').removeAttr('disabled'); |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
afterRender: function () { |
||||||
|
if (this.mode == 'edit') { |
||||||
|
this.$list = this.$el.find('.list-group'); |
||||||
|
|
||||||
|
// prepare the add item and update item inputs
|
||||||
|
var $addItemInput = this.$addItemInput = this.$el.find('input.addItem'); |
||||||
|
var $updateItemInput = this.$updateItemInput = this.$el.find('input.updateItem'); |
||||||
|
|
||||||
|
if (this.allowCustomOptions) { |
||||||
|
this.$addButton = this.$el.find('button[data-action="addItem"]'); |
||||||
|
this.$updateButton = this.$el.find('button[data-action="updateItem"]'); |
||||||
|
|
||||||
|
this.$addButton.on('click', function () { |
||||||
|
var label = this.$addItemInput.val().toString(); |
||||||
|
this.addValue(label); |
||||||
|
$addItemInput.val(''); |
||||||
|
this.controlAddItemButton(); |
||||||
|
// update the model
|
||||||
|
this.inlineEditSave(); |
||||||
|
// reinstate the inline edit mode
|
||||||
|
this.inlineEdit(); |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
this.$updateButton.on('click', function () { |
||||||
|
var label = this.$updateItemInput.val().toString(); |
||||||
|
this.updateLabel(label); |
||||||
|
$updateItemInput.val(''); |
||||||
|
this.controlUpdateItemButton(); |
||||||
|
// update the model
|
||||||
|
this.inlineEditSave(); |
||||||
|
// reinstate the inline edit mode
|
||||||
|
this.inlineEdit(); |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
$addItemInput.on('input', function () { |
||||||
|
this.controlAddItemButton(); |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
$updateItemInput.on('input', function () { |
||||||
|
this.controlUpdateItemButton(); |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
// add the new item and updated the list if user presses 'Enter' or "Tab"
|
||||||
|
$addItemInput.on('keypress', function (e) { |
||||||
|
if (e.keyCode === 13 || e.keyCode === 9) { |
||||||
|
var label = $addItemInput.val().toString(); |
||||||
|
if (this.params.noEmptyString) { |
||||||
|
if (label == '') { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
this.addValue(label); |
||||||
|
$addItemInput.val(''); |
||||||
|
this.controlAddItemButton(); |
||||||
|
// update the model
|
||||||
|
//this.inlineEditSave();
|
||||||
|
// reinstate the inline edit mode
|
||||||
|
//this.inlineEdit();
|
||||||
|
} |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
// update the item and update the list if the user presses 'Enter'
|
||||||
|
$updateItemInput.on('keypress', function (e) { |
||||||
|
if (e.keyCode === 13) { |
||||||
|
var label = $updateItemInput.val().toString(); |
||||||
|
if (this.params.noEmptyString) { |
||||||
|
if (label == '') { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
this.updateLabel(label); |
||||||
|
$updateItemInput.val(''); |
||||||
|
this.controlUpdateItemButton(); |
||||||
|
// update the model
|
||||||
|
//this.inlineEditSave();
|
||||||
|
// reinstate the inline edit mode
|
||||||
|
//this.inlineEdit();
|
||||||
|
} |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
this.controlAddItemButton(); |
||||||
|
} |
||||||
|
|
||||||
|
this.$list.sortable({ |
||||||
|
stop: function () { |
||||||
|
this.fetchFromDom(); |
||||||
|
this.trigger('change'); |
||||||
|
}.bind(this) |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (this.mode == 'search') { |
||||||
|
this.renderSearch(); |
||||||
|
} |
||||||
|
|
||||||
|
// whenever any checkbox changes, update the item data-value and trigger the change event
|
||||||
|
this.$el.find('input:checkbox').on('change', function () { |
||||||
|
this.fetchFromDom(); |
||||||
|
this.trigger('change'); |
||||||
|
}.bind(this)); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
}); |
||||||
|
}); |
Loading…
Reference in new issue