ep_data_tables 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/static/js/client_hooks.js +35 -11
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ const ATTR_TABLE_JSON = 'tbljson';
|
|
|
17
17
|
const ATTR_CELL = 'td';
|
|
18
18
|
const ATTR_CLASS_PREFIX = 'tbljson-'; // For finding the class in DOM
|
|
19
19
|
const log = (...m) => console.debug('[ep_data_tables:client_hooks]', ...m);
|
|
20
|
+
log('version 0.0.6');
|
|
20
21
|
const DELIMITER = '\u241F'; // Internal column delimiter (␟)
|
|
21
22
|
// Use the same rare character inside the hidden span so acePostWriteDomLineHTML can
|
|
22
23
|
// still find delimiters when it splits node.innerHTML.
|
|
@@ -66,13 +67,14 @@ let isAndroidChromeComposition = false;
|
|
|
66
67
|
let handledCurrentComposition = false;
|
|
67
68
|
// Suppress all beforeinput insertText events during an Android Chrome IME composition
|
|
68
69
|
let suppressBeforeInputInsertTextDuringComposition = false;
|
|
69
|
-
// Helper to detect
|
|
70
|
-
function
|
|
70
|
+
// Helper to detect Android Chromium-family browsers (exclude iOS and Firefox)
|
|
71
|
+
function isAndroidChromiumUA() {
|
|
71
72
|
const ua = (navigator.userAgent || '').toLowerCase();
|
|
72
73
|
const isAndroid = ua.includes('android');
|
|
73
74
|
const isIOS = ua.includes('iphone') || ua.includes('ipad') || ua.includes('ipod') || ua.includes('crios');
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
const isFirefox = ua.includes('firefox');
|
|
76
|
+
const isChromiumFamily = ua.includes('chrome') || ua.includes('edg') || ua.includes('opr') || ua.includes('samsungbrowser') || ua.includes('vivaldi') || ua.includes('brave');
|
|
77
|
+
return isAndroid && !isIOS && !isFirefox && isChromiumFamily;
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// ─────────────────── Reusable Helper Functions ───────────────────
|
|
@@ -964,11 +966,33 @@ exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
|
|
|
964
966
|
// NEW: Remove all hidden-delimiter <span> wrappers **before** we split so
|
|
965
967
|
// the embedded delimiter character they carry doesn't inflate or shrink
|
|
966
968
|
// the segment count.
|
|
967
|
-
const spanDelimRegex = new RegExp('<span class="ep-data_tables-delim"[^>]*>' + DELIMITER + '
|
|
969
|
+
const spanDelimRegex = new RegExp('<span class="ep-data_tables-delim"[^>]*>' + DELIMITER + '</span>', 'ig');
|
|
970
|
+
// Safari-specific normalization: it may serialize the delimiter as entities and inject Apple spans
|
|
971
|
+
const delimiterEntityHexRE = /␟/ig; // hex entity for U+241F
|
|
972
|
+
const delimiterEntityDecRE = /␟/g; // decimal entity for U+241F
|
|
973
|
+
const appleConvertedSpaceRE = /<span class="Apple-converted-space">[\s\u00A0]*<\/span>/ig;
|
|
974
|
+
const zeroWidthCharsRE = /[\u200B\u200C\u200D\uFEFF]/g;
|
|
975
|
+
|
|
976
|
+
const hexMatches = ((delimitedTextFromLine || '').match(delimiterEntityHexRE) || []).length;
|
|
977
|
+
const decMatches = ((delimitedTextFromLine || '').match(delimiterEntityDecRE) || []).length;
|
|
978
|
+
const appleSpaceMatches = ((delimitedTextFromLine || '').match(appleConvertedSpaceRE) || []).length;
|
|
979
|
+
|
|
968
980
|
const sanitizedHTMLForSplit = (delimitedTextFromLine || '')
|
|
969
981
|
.replace(spanDelimRegex, '')
|
|
970
982
|
// strip caret anchors from raw line html before split
|
|
971
|
-
.replace(/<span class="ep-data_tables-caret-anchor"[^>]*><\/span>/ig, '')
|
|
983
|
+
.replace(/<span class="ep-data_tables-caret-anchor"[^>]*><\/span>/ig, '')
|
|
984
|
+
// Safari may serialize the delimiter as HTML entities – convert back to raw char
|
|
985
|
+
.replace(delimiterEntityHexRE, DELIMITER)
|
|
986
|
+
.replace(delimiterEntityDecRE, DELIMITER)
|
|
987
|
+
// Safari sometimes injects Apple-converted-space wrappers; collapse to a normal space
|
|
988
|
+
.replace(appleConvertedSpaceRE, ' ')
|
|
989
|
+
// Guard against invisible characters that can disturb splitting
|
|
990
|
+
.replace(zeroWidthCharsRE, '');
|
|
991
|
+
|
|
992
|
+
if ((hexMatches + decMatches + appleSpaceMatches) > 0) {
|
|
993
|
+
console.warn(`[ep_data_tables] ${funcName} NodeID#${nodeId}: Normalized Safari entities/spans before splitting: hex=${hexMatches}, dec=${decMatches}, appleSpaces=${appleSpaceMatches}`);
|
|
994
|
+
}
|
|
995
|
+
|
|
972
996
|
const htmlSegments = sanitizedHTMLForSplit.split(DELIMITER);
|
|
973
997
|
|
|
974
998
|
// log(`${logPrefix} NodeID#${nodeId}: *** SEGMENT ANALYSIS ***`);
|
|
@@ -2195,7 +2219,7 @@ exports.aceInitialized = (h, ctx) => {
|
|
|
2195
2219
|
// log(`${deleteLogPrefix} Current line number: ${lineNum}. Column start: ${selStart[1]}, Column end: ${selEnd[1]}.`);
|
|
2196
2220
|
|
|
2197
2221
|
// Android Chrome IME: collapsed backspace/forward-delete often comes via beforeinput
|
|
2198
|
-
const isAndroidChrome =
|
|
2222
|
+
const isAndroidChrome = isAndroidChromiumUA();
|
|
2199
2223
|
const inputType = (evt.originalEvent && evt.originalEvent.inputType) || '';
|
|
2200
2224
|
|
|
2201
2225
|
// Handle collapsed deletes on Android Chrome inside a table line to protect delimiters
|
|
@@ -2448,8 +2472,8 @@ exports.aceInitialized = (h, ctx) => {
|
|
|
2448
2472
|
// Only intercept insert types
|
|
2449
2473
|
if (!inputType || !inputType.startsWith('insert')) return;
|
|
2450
2474
|
|
|
2451
|
-
// Target only Android browsers (exclude iOS)
|
|
2452
|
-
if (!
|
|
2475
|
+
// Target only Android Chromium-family browsers (exclude iOS and Firefox)
|
|
2476
|
+
if (!isAndroidChromiumUA()) return;
|
|
2453
2477
|
|
|
2454
2478
|
// Get current selection and ensure we are inside a table line
|
|
2455
2479
|
const rep = ed.ace_getRep();
|
|
@@ -2614,7 +2638,7 @@ exports.aceInitialized = (h, ctx) => {
|
|
|
2614
2638
|
|
|
2615
2639
|
// Composition start marker (Android Chrome/table only)
|
|
2616
2640
|
$inner.on('compositionstart', (evt) => {
|
|
2617
|
-
if (!
|
|
2641
|
+
if (!isAndroidChromiumUA()) return;
|
|
2618
2642
|
const rep = ed.ace_getRep();
|
|
2619
2643
|
if (!rep || !rep.selStart) return;
|
|
2620
2644
|
const lineNum = rep.selStart[0];
|
|
@@ -2631,7 +2655,7 @@ exports.aceInitialized = (h, ctx) => {
|
|
|
2631
2655
|
$inner.on('compositionupdate', (evt) => {
|
|
2632
2656
|
const compLogPrefix = '[ep_data_tables:compositionHandler]';
|
|
2633
2657
|
|
|
2634
|
-
if (!
|
|
2658
|
+
if (!isAndroidChromiumUA()) return;
|
|
2635
2659
|
|
|
2636
2660
|
const rep = ed.ace_getRep();
|
|
2637
2661
|
if (!rep || !rep.selStart) return;
|