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:
88
LittleShop/wwwroot/lib/hammerjs/src/input/pointerevent.js
Normal file
88
LittleShop/wwwroot/lib/hammerjs/src/input/pointerevent.js
Normal file
@@ -0,0 +1,88 @@
|
||||
var POINTER_INPUT_MAP = {
|
||||
pointerdown: INPUT_START,
|
||||
pointermove: INPUT_MOVE,
|
||||
pointerup: INPUT_END,
|
||||
pointercancel: INPUT_CANCEL,
|
||||
pointerout: INPUT_CANCEL
|
||||
};
|
||||
|
||||
// in IE10 the pointer types is defined as an enum
|
||||
var IE10_POINTER_TYPE_ENUM = {
|
||||
2: INPUT_TYPE_TOUCH,
|
||||
3: INPUT_TYPE_PEN,
|
||||
4: INPUT_TYPE_MOUSE,
|
||||
5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
|
||||
};
|
||||
|
||||
var POINTER_ELEMENT_EVENTS = 'pointerdown';
|
||||
var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
|
||||
|
||||
// IE10 has prefixed support, and case-sensitive
|
||||
if (window.MSPointerEvent && !window.PointerEvent) {
|
||||
POINTER_ELEMENT_EVENTS = 'MSPointerDown';
|
||||
POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pointer events input
|
||||
* @constructor
|
||||
* @extends Input
|
||||
*/
|
||||
function PointerEventInput() {
|
||||
this.evEl = POINTER_ELEMENT_EVENTS;
|
||||
this.evWin = POINTER_WINDOW_EVENTS;
|
||||
|
||||
Input.apply(this, arguments);
|
||||
|
||||
this.store = (this.manager.session.pointerEvents = []);
|
||||
}
|
||||
|
||||
inherit(PointerEventInput, Input, {
|
||||
/**
|
||||
* handle mouse events
|
||||
* @param {Object} ev
|
||||
*/
|
||||
handler: function PEhandler(ev) {
|
||||
var store = this.store;
|
||||
var removePointer = false;
|
||||
|
||||
var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
|
||||
var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
|
||||
var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
|
||||
|
||||
var isTouch = (pointerType == INPUT_TYPE_TOUCH);
|
||||
|
||||
// get index of the event in the store
|
||||
var storeIndex = inArray(store, ev.pointerId, 'pointerId');
|
||||
|
||||
// start and mouse must be down
|
||||
if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
|
||||
if (storeIndex < 0) {
|
||||
store.push(ev);
|
||||
storeIndex = store.length - 1;
|
||||
}
|
||||
} else if (eventType & (INPUT_END | INPUT_CANCEL)) {
|
||||
removePointer = true;
|
||||
}
|
||||
|
||||
// it not found, so the pointer hasn't been down (so it's probably a hover)
|
||||
if (storeIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update the event in the store
|
||||
store[storeIndex] = ev;
|
||||
|
||||
this.callback(this.manager, eventType, {
|
||||
pointers: store,
|
||||
changedPointers: [ev],
|
||||
pointerType: pointerType,
|
||||
srcEvent: ev
|
||||
});
|
||||
|
||||
if (removePointer) {
|
||||
// remove from the store
|
||||
store.splice(storeIndex, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user