Initial commit,修正

This commit is contained in:
2025-07-13 19:37:38 +08:00
parent 38ce288e27
commit 65bbd06981
12384 changed files with 3985464 additions and 8 deletions
@@ -0,0 +1,374 @@
$.fn.editableTable = function(options) {
// Default options
let defaultOptions = {
cloneProperties: ['padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right',
'text-align', 'font', 'font-size', 'font-family', 'font-weight',
'border', 'border-top', 'border-bottom', 'border-left', 'border-right', 'color', 'background-color', 'border-radius'
],
columns: []
}
// Overlay default options on user options
options = $.extend({}, defaultOptions, options);
// The instance reference we'll pass to the user
let _instance;
// Class to put on the editor to denote an error
let errorClass = 'error';
// Something to tag the hidden input with
let identifierAttribute = 'table-editor-input';
// Keycodes
let ARROW_LEFT = 37,
ARROW_UP = 38,
ARROW_RIGHT = 39,
ARROW_DOWN = 40,
ENTER = 13,
ESC = 27,
TAB = 9,
CONTROL = 17,
LEFT_WINDOWS = 91,
SELECT_KEY = 93;
// The table element
let element = $(this);
// Show all columns and then hide any hidden ones
element.find('th').show();
options.columns.forEach((col, i) => {
if (col.isHidden !== undefined && col.isHidden) element.find('th').eq(i).hide();
});
// If there are actions, add a final blank table header
if (options.actions !== undefined && options.actions.length > 0) {
// Add header if we don't already have one
if (!element.find('thead tr th[actions]').length) {
element.find('thead tr').append($('<th actions=""></th>'));
}
}
// The textbox allowing user input. Only add if there's not already an editor input control around
let editor;
let existingEditor = element.parent().find(`input[${identifierAttribute}]`);
if (existingEditor.length) {
editor = existingEditor.first();
} else {
editor = $('<input>');
}
// Add it to the DOM
editor.attr(identifierAttribute, '')
.css('position', 'absolute')
.hide()
.appendTo(element.parent());
// The `td` being "edited"
let activeCell;
// Function to show the editor
function showEditor(select) {
// Set the active cell
activeCell = element.find('td:focus:not([action])');
if (activeCell.length) {
// Get column def
let currentColIndex = $(activeCell).parent().children('td').index($(activeCell));
let columnDef = options.columns[currentColIndex];
// Prepare input control
editor.val(activeCell.text()) // Throw the value in
.removeClass(errorClass) // remove any error classes
.show() // show it
.offset(activeCell.offset()) // position it
.css(activeCell.css(options.cloneProperties)) // make it look similar by cloning properties
.width(activeCell.width()) // size it
.height(activeCell.height()) // size it
.focus(); // focus user input into it
// Set max length, if it's specified
if (columnDef.maxLength !== undefined) editor.attr('maxlength', columnDef.maxLength);
else editor.removeAttr('maxlength');
if (select) {
editor.select();
}
}
};
function setActiveText() {
let text = editor.val(),
evt = $.Event('change'),
originalContent;
if (activeCell.text() === text || editor.hasClass(errorClass)) {
return true;
}
originalContent = activeCell.html();
activeCell.text(text).trigger(evt, text);
if (evt.result === false) {
activeCell.html(originalContent);
}
};
// For traversing the table up/down/left/right by returning the adjacent cell
function handleMovement(element, keycode) {
if (keycode === ARROW_RIGHT) {
return element.next('td');
} else if (keycode === ARROW_LEFT) {
return element.prev('td');
} else if (keycode === ARROW_UP) {
return element.parent().prev().children().eq(element.index());
} else if (keycode === ARROW_DOWN) {
return element.parent().next().children().eq(element.index());
}
return [];
};
// On the editor losing focus, hide the input
editor.blur(function() {
setActiveText();
editor.hide();
});
// Handle typing into the input
editor.keydown(function(e) {
if (e.which === ENTER) {
setActiveText();
editor.hide();
activeCell.focus();
e.preventDefault();
e.stopPropagation();
} else if (e.which === ESC) {
editor.val(activeCell.text());
e.preventDefault();
e.stopPropagation();
editor.hide();
activeCell.focus();
} else if (e.which === TAB) {
activeCell.focus();
} else if (this.selectionEnd - this.selectionStart === this.value.length) {
let possibleMove = handleMovement(activeCell, e.which);
if (possibleMove.length > 0) {
possibleMove.focus();
e.preventDefault();
e.stopPropagation();
}
}
});
// Validate cell input on typing or pasting
editor.on('input paste', function() {
let evt = $.Event('validate');
activeCell.trigger(evt, editor.val());
if (evt.result !== undefined) {
if (evt.result === false) {
editor.addClass(errorClass);
} else {
editor.removeClass(errorClass);
}
}
});
// On table clicking, move around cells
element.on('click keypress dblclick', showEditor);
element.keydown(function(e) {
let prevent = true,
possibleMove = handleMovement($(e.target), e.which);
if (possibleMove.length > 0) {
possibleMove.focus();
} else if (e.which === ENTER) {
showEditor(false);
} else if (e.which === CONTROL || e.which === LEFT_WINDOWS || e.which === SELECT_KEY) {
showEditor(true);
prevent = false;
} else {
prevent = false;
}
if (prevent) {
e.stopPropagation();
e.preventDefault();
}
});
element.find('td').prop('tabindex', 1);
$(window).on('resize', function() {
if (editor.is(':visible')) {
editor.offset(activeCell.offset())
.width(activeCell.width())
.height(activeCell.height());
}
});
function refresh() {
$(element).editableTable(options);
}
// Validate based on options
$('table td').on('validate', function(evt, newValue) {
let currentColIndex = $(evt.currentTarget).parent().children('td').index($(evt.currentTarget));
let columnDef = options.columns[currentColIndex];
let currentData = _instance.getData({
convert: false
}); // current data to allow user to validate based on existing data
let isValid = columnDef.isValid && columnDef.isValid(newValue, currentData);
return isValid;
});
$('table td').on('change', function(evt, newValue) {
let td = $(this);
let currentColIndex = $(evt.currentTarget).parent().children('td').index($(evt.currentTarget));
let columnDef = options.columns[currentColIndex];
if (columnDef.removeRowIfCleared && newValue == '') {
td.parent('tr').remove();
}
// Bind user-specified events if they exist
if (typeof columnDef.afterChange == 'function') {
columnDef.afterChange(newValue, td);
}
return true;
});
// Set up the instance reference
_instance = {
// Get table back out as JSON
getData: function(opts) {
opts = $.extend({}, {
convert: true
}, opts);
let rowData = [];
element.find('tbody tr').toArray().forEach(row => {
let newRow = {};
$(row).find('td:not([action])').toArray().forEach(col => {
let columnsDef = options.columns[
$(col).parent().children('td').index($(col)) // only index at cells, or "td"s
];
let value = $(col).text();
// Check if the cell was marked as having a null value, and if so, extract as null and not
// as a blank string
let isNull = $(col).attr('data-is-null');
if (typeof isNull !== 'undefined' && isNull !== false) {
value = null;
}
// Convert if requried
if (opts.convert && typeof columnsDef.convertOut == 'function') {
value = columnsDef.convertOut(value);
}
newRow[columnsDef.name] = value;
});
rowData.push(newRow);
});
return rowData;
},
// Add a new row with JSON
addRow: function(row) {
let newRow = $(`<tr></tr>`);
if (row !== undefined && row !== null) {
let props = Object.keys(row);
let columnsToAdd = [];
props.forEach(prop => {
let columnDef = options.columns.filter(col => col.name === prop);
if (columnDef.length) {
columnDef = columnDef[0];
columnsToAdd.push({
order: columnDef.index,
value: row[prop],
prop: prop,
def: columnDef
});
}
})
columnsToAdd.sort((a, b) => a.order - b.order).forEach((colToAdd, index) => {
let newCell;
if (colToAdd.value !== null)
newCell = $(`<td>${colToAdd.value}</td>`);
else
newCell = $(`<td data-is-null></td>`);
// Apply any classes
if (colToAdd.def.classes !== undefined && colToAdd.def.classes.length) {
colToAdd.def.classes.forEach(classToAdd => newCell.addClass(classToAdd));
}
// Apply any style
if (colToAdd.def.style !== undefined && colToAdd.def.style.length) {
newCell.attr("style", newCell.attr("style") + "; " + colToAdd.def.style);
}
// Hide if hidden
if (colToAdd.def.isHidden !== undefined && colToAdd.def.isHidden) {
newCell.hide();
}
// Add to the column
newRow.append(newCell);
// Trigger any events
let columnDef = options.columns.filter(col => col.name === colToAdd.prop)[0];
if (typeof columnDef.afterAdd == 'function') {
columnDef.afterAdd(colToAdd.value, newCell);
}
});
} else {
newRow = $(`<tr></tr>`);
activeOptions.columns.forEach(x => {
newRow.append(`<td></td>`);
});
}
// Add actions if any
if (options.actions !== undefined && options.actions.length > 0) {
let actionsCell = $(`<td action></td>`);
options.actions.forEach(a => {
let actionElement = $(a.label);
actionElement.css('cursor', 'pointer');
actionElement.click(e => a.action(e, newRow))
actionsCell.append(actionElement);
});
newRow.append(actionsCell);
}
// Add the new row
let lastRow = element.find('tbody tr:last');
if (lastRow.length > 0)
lastRow.after(newRow);
else
element.find('tbody').append(newRow);
refresh();
},
// Clear the table
clear: function() {
element.find('tbody tr').remove();
},
// Set the table's data with JSON
setData: function(data) {
if (data) {
this.clear();
data.forEach(datum => {
this.addRow(datum);
});
}
}
};
return _instance;
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,248 @@
/*! jquery.tablednd.js 20-11-2020 */ ! function(a, b, c, d) {
var e = "touchstart mousedown",
f = "touchmove mousemove",
g = "touchend mouseup";
a(c).ready(function() {
function b(a) {
for (var b = {}, c = a.match(/([^;:]+)/g) || []; c.length;) b[c.shift()] = c.shift().trim();
return b
}
a("table").each(function() {
"dnd" === a(this).data("table") && a(this).tableDnD({
onDragStyle: a(this).data("ondragstyle") && b(a(this).data("ondragstyle")) || null,
onDropStyle: a(this).data("ondropstyle") && b(a(this).data("ondropstyle")) || null,
onDragClass: a(this).data("ondragclass") === d && "tDnD_whileDrag" || a(this).data("ondragclass"),
onDrop: a(this).data("ondrop") && new Function("table", "row", a(this).data("ondrop")),
onDragStart: a(this).data("ondragstart") && new Function("table", "row", a(this).data("ondragstart")),
onDragStop: a(this).data("ondragstop") && new Function("table", "row", a(this).data("ondragstop")),
scrollAmount: a(this).data("scrollamount") || 5,
sensitivity: a(this).data("sensitivity") || 10,
hierarchyLevel: a(this).data("hierarchylevel") || 0,
indentArtifact: a(this).data("indentartifact") || '<div class="indent">&nbsp;</div>',
autoWidthAdjust: a(this).data("autowidthadjust") || !0,
autoCleanRelations: a(this).data("autocleanrelations") || !0,
jsonPretifySeparator: a(this).data("jsonpretifyseparator") || "\t",
serializeRegexp: a(this).data("serializeregexp") && new RegExp(a(this).data("serializeregexp")) || /[^\-]*$/,
serializeParamName: a(this).data("serializeparamname") || !1,
dragHandle: a(this).data("draghandle") || null
})
})
}), jQuery.tableDnD = {
currentTable: null,
dragObject: null,
mouseOffset: null,
oldX: 0,
oldY: 0,
build: function(b) {
return this.each(function() {
this.tableDnDConfig = a.extend({
onDragStyle: null,
onDropStyle: null,
onDragClass: "tDnD_whileDrag",
onDrop: null,
onDragStart: null,
onDragStop: null,
scrollAmount: 5,
sensitivity: 10,
hierarchyLevel: 0,
indentArtifact: '<div class="indent">&nbsp;</div>',
autoWidthAdjust: !0,
autoCleanRelations: !0,
jsonPretifySeparator: "\t",
serializeRegexp: /[^\-]*$/,
serializeParamName: !1,
dragHandle: null
}, b || {}), a.tableDnD.makeDraggable(this), this.tableDnDConfig.hierarchyLevel && a.tableDnD.makeIndented(this)
}), this
},
makeIndented: function(b) {
var c, d, e = b.tableDnDConfig,
f = b.rows,
g = a(f).first().find("td:first")[0],
h = 0,
i = 0;
if (a(b).hasClass("indtd")) return null;
d = a(b).addClass("indtd").attr("style"), a(b).css({
whiteSpace: "nowrap"
});
for (var j = 0; j < f.length; j++) i < a(f[j]).find("td:first").text().length && (i = a(f[j]).find("td:first").text().length, c = j);
for (a(g).css({
width: "auto"
}), j = 0; j < e.hierarchyLevel; j++) a(f[c]).find("td:first").prepend(e.indentArtifact);
for (g && a(g).css({
width: g.offsetWidth
}), d && a(b).css(d), j = 0; j < e.hierarchyLevel; j++) a(f[c]).find("td:first").children(":first").remove();
return e.hierarchyLevel && a(f).each(function() {
(h = a(this).data("level") || 0) <= e.hierarchyLevel && a(this).data("level", h) || a(this).data("level", 0);
for (var b = 0; b < a(this).data("level"); b++) a(this).find("td:first").prepend(e.indentArtifact)
}), this
},
makeDraggable: function(b) {
var c = b.tableDnDConfig;
c.dragHandle && a(c.dragHandle, b).each(function() {
a(this).bind(e, function(d) {
return a.tableDnD.initialiseDrag(a(this).parents("tr")[0], b, this, d, c), !1
})
}) || a(b.rows).each(function() {
a(this).hasClass("nodrag") ? a(this).css("cursor", "") : a(this).bind(e, function(d) {
if ("TD" === d.target.tagName) return a.tableDnD.initialiseDrag(this, b, this, d, c), !1
}).css("cursor", "move")
})
},
currentOrder: function() {
var b = this.currentTable.rows;
return a.map(b, function(b) {
return (a(b).data("level") + b.id).replace(/\s/g, "")
}).join("")
},
initialiseDrag: function(b, d, e, h, i) {
this.dragObject = b, this.currentTable = d, this.mouseOffset = this.getMouseOffset(e, h), this.originalOrder = this.currentOrder(), a(c).bind(f, this.mousemove).bind(g, this.mouseup), i.onDragStart && i.onDragStart(d, e)
},
updateTables: function() {
this.each(function() {
this.tableDnDConfig && a.tableDnD.makeDraggable(this)
})
},
mouseCoords: function(a) {
return a.originalEvent.changedTouches ? {
x: a.originalEvent.changedTouches[0].clientX,
y: a.originalEvent.changedTouches[0].clientY
} : a.pageX || a.pageY ? {
x: a.pageX,
y: a.pageY
} : {
x: a.clientX + c.body.scrollLeft - c.body.clientLeft,
y: a.clientY + c.body.scrollTop - c.body.clientTop
}
},
getMouseOffset: function(a, c) {
var d, e;
return c = c || b.event, e = this.getPosition(a), d = this.mouseCoords(c), {
x: d.x - e.x,
y: d.y - e.y
}
},
getPosition: function(a) {
for (var b = 0, c = 0; a.offsetParent;) b += a.offsetLeft, c += a.offsetTop, a = a.offsetParent;
return b += a.offsetLeft, c += a.offsetTop, {
x: b,
y: c
}
},
autoScroll: function(a) {
var d = this.currentTable.tableDnDConfig,
e = b.pageYOffset,
f = b.innerHeight ? b.innerHeight : c.documentElement.clientHeight ? c.documentElement.clientHeight : c.body.clientHeight;
c.all && (void 0 !== c.compatMode && "BackCompat" !== c.compatMode ? e = c.documentElement.scrollTop : void 0 !== c.body && (e = c.body.scrollTop)), a.y - e < d.scrollAmount && b.scrollBy(0, -d.scrollAmount) || f - (a.y - e) < d.scrollAmount && b.scrollBy(0, d.scrollAmount)
},
moveVerticle: function(a, b) {
0 !== a.vertical && b && this.dragObject !== b && this.dragObject.parentNode === b.parentNode && (0 > a.vertical && this.dragObject.parentNode.insertBefore(this.dragObject, b.nextSibling) || 0 < a.vertical && this.dragObject.parentNode.insertBefore(this.dragObject, b))
},
moveHorizontal: function(b, c) {
var d, e = this.currentTable.tableDnDConfig;
if (!e.hierarchyLevel || 0 === b.horizontal || !c || this.dragObject !== c) return null;
d = a(c).data("level"), 0 < b.horizontal && d > 0 && a(c).find("td:first").children(":first").remove() && a(c).data("level", --d), 0 > b.horizontal && d < e.hierarchyLevel && a(c).prev().data("level") >= d && a(c).children(":first").prepend(e.indentArtifact) && a(c).data("level", ++d)
},
mousemove: function(b) {
var c, d, e, f, g, h = a(a.tableDnD.dragObject),
i = a.tableDnD.currentTable.tableDnDConfig;
return b && b.preventDefault(), !!a.tableDnD.dragObject && ("touchmove" === b.type && event.preventDefault(), i.onDragClass && h.addClass(i.onDragClass) || h.css(i.onDragStyle), d = a.tableDnD.mouseCoords(b), f = d.x - a.tableDnD.mouseOffset.x, g = d.y - a.tableDnD.mouseOffset.y, a.tableDnD.autoScroll(d), c = a.tableDnD.findDropTargetRow(h, g), e = a.tableDnD.findDragDirection(f, g), a.tableDnD.moveVerticle(e, c), a.tableDnD.moveHorizontal(e, c), !1)
},
findDragDirection: function(a, b) {
var c = this.currentTable.tableDnDConfig.sensitivity,
d = this.oldX,
e = this.oldY,
f = d - c,
g = d + c,
h = e - c,
i = e + c,
j = {
horizontal: a >= f && a <= g ? 0 : a > d ? -1 : 1,
vertical: b >= h && b <= i ? 0 : b > e ? -1 : 1
};
return 0 !== j.horizontal && (this.oldX = a), 0 !== j.vertical && (this.oldY = b), j
},
findDropTargetRow: function(b, c) {
for (var d = 0, e = this.currentTable.rows, f = this.currentTable.tableDnDConfig, g = 0, h = null, i = 0; i < e.length; i++)
if (h = e[i], g = this.getPosition(h).y, d = parseInt(h.offsetHeight) / 2, 0 === h.offsetHeight && (g = this.getPosition(h.firstChild).y, d = parseInt(h.firstChild.offsetHeight) / 2), c > g - d && c < g + d) return b.is(h) || f.onAllowDrop && !f.onAllowDrop(b, h) || a(h).hasClass("nodrop") ? null : h;
return null
},
processMouseup: function() {
if (!this.currentTable || !this.dragObject) return null;
var b = this.currentTable.tableDnDConfig,
d = this.dragObject,
e = 0,
h = 0;
a(c).unbind(f, this.mousemove).unbind(g, this.mouseup), b.hierarchyLevel && b.autoCleanRelations && a(this.currentTable.rows).first().find("td:first").children().each(function() {
(h = a(this).parents("tr:first").data("level")) && a(this).parents("tr:first").data("level", --h) && a(this).remove()
}) && b.hierarchyLevel > 1 && a(this.currentTable.rows).each(function() {
if ((h = a(this).data("level")) > 1)
for (e = a(this).prev().data("level"); h > e + 1;) a(this).find("td:first").children(":first").remove(), a(this).data("level", --h)
}), b.onDragClass && a(d).removeClass(b.onDragClass) || a(d).css(b.onDropStyle), this.dragObject = null, b.onDrop && this.originalOrder !== this.currentOrder() && a(d).hide().fadeIn("fast") && b.onDrop(this.currentTable, d), b.onDragStop && b.onDragStop(this.currentTable, d), this.currentTable = null
},
mouseup: function(b) {
return b && b.preventDefault(), a.tableDnD.processMouseup(), !1
},
jsonize: function(a) {
var b = this.currentTable;
return a ? JSON.stringify(this.tableData(b), null, b.tableDnDConfig.jsonPretifySeparator) : JSON.stringify(this.tableData(b))
},
serialize: function() {
return a.param(this.tableData(this.currentTable))
},
serializeTable: function(a) {
for (var b = "", c = a.tableDnDConfig.serializeParamName || a.id, d = a.rows, e = 0; e < d.length; e++) {
b.length > 0 && (b += "&");
var f = d[e].id;
f && a.tableDnDConfig && a.tableDnDConfig.serializeRegexp && (f = f.match(a.tableDnDConfig.serializeRegexp)[0], b += c + "[]=" + f)
}
return b
},
serializeTables: function() {
var b = [];
return a("table").each(function() {
this.id && b.push(a.param(a.tableDnD.tableData(this)))
}), b.join("&")
},
tableData: function(b) {
var c, d, e, f, g = b.tableDnDConfig,
h = [],
i = 0,
j = 0,
k = null,
l = {};
if (b || (b = this.currentTable), !b || !b.rows || !b.rows.length) return {
error: {
code: 500,
message: "Not a valid table."
}
};
if (!b.id && !g.serializeParamName) return {
error: {
code: 500,
message: "No serializable unique id provided."
}
};
f = g.autoCleanRelations && b.rows || a.makeArray(b.rows), d = g.serializeParamName || b.id, e = d, c = function(a) {
return a && g && g.serializeRegexp ? a.match(g.serializeRegexp)[0] : a
}, l[e] = [], !g.autoCleanRelations && a(f[0]).data("level") && f.unshift({
id: "undefined"
});
for (var m = 0; m < f.length; m++)
if (g.hierarchyLevel) {
if (0 === (j = a(f[m]).data("level") || 0)) e = d, h = [];
else if (j > i) h.push([e, i]), e = c(f[m - 1].id);
else if (j < i)
for (var n = 0; n < h.length; n++) h[n][1] === j && (e = h[n][0]), h[n][1] >= i && (h[n][1] = 0);
i = j, a.isArray(l[e]) || (l[e] = []), k = c(f[m].id), k && l[e].push(k)
} else(k = c(f[m].id)) && l[e].push(k);
return l
}
}, jQuery.fn.extend({
tableDnD: a.tableDnD.build,
tableDnDUpdate: a.tableDnD.updateTables,
tableDnDSerialize: a.proxy(a.tableDnD.serialize, a.tableDnD),
tableDnDSerializeAll: a.tableDnD.serializeTables,
tableDnDData: a.proxy(a.tableDnD.tableData, a.tableDnD)
})
}(jQuery, window, window.document);