Files
yunkong2.admin/www/js/tableEditor.js
2018-09-14 21:27:03 +08:00

437 lines
18 KiB
JavaScript

/**
* Create edit table from javascript array.
*
* This function creates a html edit table.
*
* <pre><code>
* <div id="values" style="width: 100%; height: calc(100% - 205px)">
* <button class="table-button-add" style="margin-left: 10px"></button>
* <div style="width: 100%; height: calc(100% - 30px); overflow: auto;">
* <table class="table-values" style="width: 100%;">
* <thead>
* <tr>
* <th data-name="_index" style="30px" data-style="width: 100%; text-align: right">Context</th>
* <th data-name="regex" class="translate" style="width: 30%" data-style="text-align: right">Context</th>
* <th data-name="room" class="translate" data-type="select">Room</th>
* <th data-name="aaa" class="translate" data-options="1/A;2/B;3/C;4" data-type="select">Room</th>
* <th data-name="enabled" class="translate" data-type="checkbox">Enabled</th>
* <th data-buttons="delete up down" style="width: 32px"></th>
* </tr>
* </thead>
* </table>
* </div>
* </div>
* </pre></code>
*
* @param {string} divId name of the html element (or empty).
* @param {string} values data array
* @param {object} options settings
* <pre><code>
* {
* onChange: this function will be called if something changed. function (attr, index) {}
* onReady: called, when the table is ready (may be to modify some elements of it),
* maxRaw: maximal number of rows
* }
* </pre></code>
* @return {object} array with values
*/
function values2table(divId, values, options) {
if (typeof divId === 'object') {
options = values;
values = divId;
divId = '';
}
var maxRaw = (options && options.maxRaw) || null;
var onChange = (options && options.onChange) || null;
var onReady = (options && options.onReady) || null;
values = values || [];
var names = [];
var $div;
if (!divId) {
$div = $('body');
} else {
$div = $('#' + divId);
}
var $add = $div.find('.table-button-add');
$add.data('raw', values.length);
if (maxRaw) {
$add.data('maxRaw', maxRaw);
}
if (!$add.data('inited')) {
$add.data('inited', true);
// var addText = $add.text();
$add.on('click', function () {
if (!$add.data('maxRaw') || ($add.data('raw') < $add.data('maxRaw'))) {
var $table = $div.find('.table-values');
var values = $table.data('values');
var names = $table.data('names');
var maxRaw = $table.data('maxRaw');
var obj = {};
for (var i = 0; i < names.length; i++) {
if (!names[i]) continue;
obj[names[i].name] = names[i].def;
}
values.push(obj);
onChange && onChange();
setTimeout(function () {
values2table(divId, values, onChange, onReady, maxRaw);
}, 100);
$add.data('raw', $add.data('raw') + 1);
} else {
confirmMessage(_('maxTableRaw') + ': ' + $add.data('maxRaw'), _('maxTableRawInfo'), 'alert', ['Ok']);
}
});
}
if (values) {
var buttons = [];
var $table = $div.find('.table-values');
$table.data('values', values);
// load rooms
if (!$table.data('rooms') && $table.find('th[data-name="room"]').length) {
getEnums('rooms', function (err, list) {
var result = {};
var trRooms = _('nonerooms');
if (trRooms !== 'nonerooms') {
result[_('none')] = trRooms;
} else {
result[_('none')] = '';
}
var nnames = [];
for (var n in list) {
if (list.hasOwnProperty(n)) {
nnames.push(n);
}
}
nnames.sort(function (a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a > b) return 1;
if (a < b) return -1;
return 0;
});
for (var l = 0; l < nnames.length; l++) {
result[nnames[l]] = list[nnames[l]].common.name || l;
}
$table.data('rooms', result);
values2table(divId, values, onChange, onReady, maxRaw);
});
return;
}
// load functions
if (!$table.data('functions') && $table.find('th[data-name="func"]').length) {
getEnums('functions', function (err, list) {
var result = {};
var trFuncs = _('nonefunctions');
if (trFuncs !== 'nonefunctions') {
result[_('none')] = trFuncs;
} else {
result[_('none')] = '';
}
var nnames = [];
for (var n in list) {
if (list.hasOwnProperty(n)) {
nnames.push(n);
}
}
nnames.sort(function (a, b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a > b) return 1;
if (a < b) return -1;
return 0;
});
for (var l = 0; l < nnames.length; l++) {
result[nnames[l]] = list[nnames[l]].common.name || l;
}
$table.data('functions', result);
values2table(divId, values, onChange, onReady, maxRaw);
});
return;
}
$table.find('th').each(function () {
var name = $(this).data('name');
if (name) {
var obj = {
name: name,
type: $(this).data('type') || 'text',
def: $(this).data('default'),
'class': ($(this).attr('class') || '').replace('translate', ''),
style: $(this).data('style'),
readOnly: $(this).data('readOnly'),
tdstyle: $(this).data('tdstyle')
};
if (obj.type === 'checkbox') {
if (obj.def === 'false') obj.def = false;
if (obj.def === 'true') obj.def = true;
obj.def = !!obj.def;
} else if (obj.type === 'select' || obj.type === 'select multiple') {
var vals = ($(this).data('options') || '').split(';');
obj.options = {};
for (var v = 0; v < vals.length; v++) {
var parts = vals[v].split('/');
obj.options[parts[0]] = _(parts[1] || parts[0]);
if (v === 0) obj.def = (obj.def === undefined) ? parts[0] : obj.def;
}
} else {
obj.def = obj.def || '';
}
names.push(obj);
} else {
names.push(null);
}
name = $(this).data('buttons');
if (name) {
buttons.push({
btn: name.split(' '),
'class': ($(this).attr('class') || '').replace('translate', ''),
style: $(this).data('style'),
tdstyle: $(this).data('tdstyle')
});
} else {
buttons.push(null);
}
});
$table.data('names', names);
var text = '';
for (var v = 0; v < values.length; v++) {
var idName = values[v] && values[v].id;
if (!idName && values[v]) {
if (names[0] === '_index') {
idName = values[v][names[1]];
} else {
idName = values[v][names[0]];
}
}
text += '<tr data-id="' + idName + '" data-index="' + v + '">';
for (var i = 0; i < names.length; i++) {
text += '<td';
var line = '';
var style = '';
var tdstyle = '';
if (names[i]) {
if (names[i]['class']) {
text += ' class="' + names[i]['class'] + '" ';
}
if (names[i].name !== '_index') {
tdstyle = names[i].tdstyle || '';
if (tdstyle && tdstyle[0] !== ';') tdstyle = ';' + tdstyle;
}
if (names[i].name === '_index') {
style = (names[i].style ? names[i].style : 'text-align: right;');
line += (v + 1);
} else if (names[i].type === 'checkbox') {
line += '<input style="' + (names[i].style || '') + '" class="values-input" type="checkbox" data-index="' + v + '" data-name="' + names[i].name + '" ' + (values[v][names[i].name] ? 'checked' : '') + '" data-old-value="' + (values[v][names[i].name] === undefined ? '' : values[v][names[i].name]) + '"/>';
} else if (names[i].type.substring(0, 6) === 'select') {
line += (names[i].type.substring(7, 16) === 'multiple' ? '<select multiple style="' : '<select style="') + (names[i].style ? names[i].style : 'width: 100%') + '" class="values-input" data-index="' + v + '" data-name="' + names[i].name + '">';
var options;
if (names[i].name === 'room') {
options = $table.data('rooms');
} else if (names[i].name === 'func') {
options = $table.data('functions');
if (names[i].type === 'select multiple') delete options[_('none')];
} else {
options = names[i].options;
}
var val = (values[v][names[i].name] === undefined ? '' : values[v][names[i].name]);
if (typeof val !== 'object') val = [val];
for (var p in options) {
line += '<option value="' + p + '" ' + (val.indexOf(p) !== -1 ? ' selected' : '') + '>' + options[p] + '</option>';
}
line += '</select>';
} else {
line += '<input class="values-input" style="' + (names[i].style ? names[i].style : 'width: 100%') + '" type="' + names[i].type + '" data-index="' + v + '" data-name="' + names[i].name + '"/>';
}
}
if (buttons[i]) {
style = 'text-align: center; ' + (buttons[i].style || '') + (buttons[i].tdstyle || '');
for (var b = 0; b < buttons[i].btn.length; b++) {
if ((!v && buttons[i].btn[b] === 'up') || v === values.length - 1 && buttons[i].btn[b] === 'down') {
line += '<a class="btn-floating disabled" data-command="' + buttons[i].btn[b] + '" class="values-buttons"><i class="material-icons"></i></a>';
continue;
}
line += '<a class="btn-floating" data-index="' + v + '" data-command="' + buttons[i].btn[b] + '" class="values-buttons"><i class="material-icons"></i></a>';
}
if (buttons[i]['class']) {
text += ' class="' + buttons[i]['class'] + '" ';
}
}
if (style.length || tdstyle.length) {
text += ' style="' + style + tdstyle + '">' + line + '</td>';
} else {
text += '>' + line + '</td>';
}
}
text += '</tr>';
}
var $lines = $table.find('.table-lines');
if (!$lines.length) {
$table.append('<tbody class="table-lines"></tbody>');
$lines = $table.find('.table-lines');
}
$lines.html(text);
$lines.find('.values-input').each(function () {
var $this = $(this);
var type = $this.attr('type');
var name = $this.data('name');
var id = $this.data('index');
$this.data('old-value', values[id][name]);
if (type === 'checkbox') {
$this.prop('checked', values[id][name]);
} else {
$this.val(values[id][name]);
}
});
$lines.find('a[data-command]').each(function () {
var command = $(this).data('command');
if (command === 'delete') {
$(this).on('click', function () {
var id = $(this).data('index');
var elem = values[id];
values.splice(id, 1);
onChange && onChange();
setTimeout(function () {
if (typeof tableEvents === 'function') {
tableEvents(id, elem, 'delete');
}
values2table(divId, values, onChange, onReady, maxRaw);
}, 100);
if ($add.data('maxRaw')) {
$add.data('raw', $add.data('raw') - 1);
}
})
.addClass('red')
.find('.material-icons')
.html('delete');
} else if (command === 'up') {
$(this).on('click', function () {
var id = $(this).data('index');
var elem = values[id];
values.splice(id, 1);
values.splice(id - 1, 0, elem);
onChange && onChange();
setTimeout(function () {
values2table(id, values, onChange, onReady, maxRaw);
}, 100);
}).find('i').html('arrow_upward');
} else if (command === 'down') {
$(this).on('click', function () {
var id = $(this).data('index');
var elem = values[id];
values.splice(id, 1);
values.splice(id + 1, 0, elem);
onChange && onChange();
setTimeout(function () {
values2table(id, values, onChange, onReady, maxRaw);
}, 100);
}).find('i').html('arrow_downward');
} else if (command === 'pair') {
$(this).on('click', function () {
if (typeof tableEvents === 'function') {
var id = $(this).data('index');
var elem = values[id];
tableEvents(id, elem, 'pair');
}
}).attr('title', _('pair')).find('i').html('insert_link');
} else if (command === 'unpair') {
$(this).on('click', function () {
if (typeof tableEvents === 'function') {
var id = $(this).data('index');
var elem = values[id];
tableEvents(id, elem, 'unpair');
}
}).attr('title', _('unpair')).find('i').html('not_interested');
}
});
$lines.find('.values-input').on('change.adaptersettings', function () {
var index = $(this).data('index');
var name = $(this).data('name');
if ($(this).attr('type') === 'checkbox') {
if ($(this).prop('checked').toString() !== $(this).data('old-value') && onChange) onChange(name, index);
values[index][name] = $(this).prop('checked');
} else {
if ($(this).val() !== $(this).data('old-value') && onChange) onChange(name, index);
values[index][name] = $(this).val();
}
}).on('keyup', function () {
$(this).trigger('change.adaptersettings');
});
}
if (typeof onReady === 'function') onReady();
}
/**
* Extract the values from table.
*
* This function extracts the values from edit table, that was generated with values2table function.
*
* @param {string} divId name of the html element (or nothing).
* @return {object} array with values
*/
function table2values(divId) {
var $div;
if (!divId) {
$div = $('body');
} else {
$div = $('#' + divId);
}
var names = [];
$div.find('.table-values th').each(function () {
var name = $(this).data('name');
if (name) {
names.push(name);
} else {
names.push('___ignore___');
}
});
var values = [];
var j = 0;
$div.find('.table-lines tr').each(function () {
values[j] = {};
$(this).find('td').each(function () {
var $input = $(this).find('input');
if ($input.length) {
var name = $input.data('name');
if ($input.attr('type') === 'checkbox') {
values[j][name] = $input.prop('checked');
} else {
values[j][name] = $input.val();
}
}
var $select = $(this).find('select');
if ($select.length) {
var name = $select.data('name');
values[j][name] = $select.val() || '';
}
});
j++;
});
return values;
}