feat: Phase 2.5 - Variant Collections Spreadsheet Editor
Replaces JSON textarea with professional Excel-like spreadsheet interface for managing product variant properties. Features: - Handsontable 14.6.1 spreadsheet component - Property presets (Size, Color, Material, Storage, Custom) - Inline cell editing with Tab/Enter navigation - Context menu for add/remove rows and columns - Keyboard shortcuts (Ctrl+D delete, Ctrl+Enter save, Ctrl+Z undo) - Mobile touch gestures (swipe to delete rows) - Automatic JSON serialization on form submit - Form validation before saving - Comprehensive user guide documentation Files Changed: - LittleShop/package.json: NPM package management setup - LittleShop/wwwroot/js/variant-editor.js: 400-line spreadsheet editor module - LittleShop/wwwroot/lib/handsontable/: Handsontable library (Community Edition) - LittleShop/wwwroot/lib/hammerjs/: Hammer.js touch gesture library - LittleShop/Areas/Admin/Views/VariantCollections/Edit.cshtml: Spreadsheet UI integration - VARIANT_COLLECTIONS_USER_GUIDE.md: Complete user guide (18+ pages) Technical Details: - Excel-like editing experience (no more manual JSON editing) - Mobile-first responsive design - Browser compatibility: Chrome 90+, Firefox 88+, Edge 90+, Safari 14+ - Touch-optimized for mobile administration - Automatic data validation and error handling
This commit is contained in:
68
LittleShop/wwwroot/lib/hammerjs/src/input/singletouch.js
Normal file
68
LittleShop/wwwroot/lib/hammerjs/src/input/singletouch.js
Normal file
@@ -0,0 +1,68 @@
|
||||
var SINGLE_TOUCH_INPUT_MAP = {
|
||||
touchstart: INPUT_START,
|
||||
touchmove: INPUT_MOVE,
|
||||
touchend: INPUT_END,
|
||||
touchcancel: INPUT_CANCEL
|
||||
};
|
||||
|
||||
var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
|
||||
var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
|
||||
|
||||
/**
|
||||
* Touch events input
|
||||
* @constructor
|
||||
* @extends Input
|
||||
*/
|
||||
function SingleTouchInput() {
|
||||
this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
|
||||
this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
|
||||
this.started = false;
|
||||
|
||||
Input.apply(this, arguments);
|
||||
}
|
||||
|
||||
inherit(SingleTouchInput, Input, {
|
||||
handler: function TEhandler(ev) {
|
||||
var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
|
||||
|
||||
// should we handle the touch events?
|
||||
if (type === INPUT_START) {
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
if (!this.started) {
|
||||
return;
|
||||
}
|
||||
|
||||
var touches = normalizeSingleTouches.call(this, ev, type);
|
||||
|
||||
// when done, reset the started state
|
||||
if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
this.callback(this.manager, type, {
|
||||
pointers: touches[0],
|
||||
changedPointers: touches[1],
|
||||
pointerType: INPUT_TYPE_TOUCH,
|
||||
srcEvent: ev
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @this {TouchInput}
|
||||
* @param {Object} ev
|
||||
* @param {Number} type flag
|
||||
* @returns {undefined|Array} [all, changed]
|
||||
*/
|
||||
function normalizeSingleTouches(ev, type) {
|
||||
var all = toArray(ev.touches);
|
||||
var changed = toArray(ev.changedTouches);
|
||||
|
||||
if (type & (INPUT_END | INPUT_CANCEL)) {
|
||||
all = uniqueArray(all.concat(changed), 'identifier', true);
|
||||
}
|
||||
|
||||
return [all, changed];
|
||||
}
|
||||
Reference in New Issue
Block a user