unicode-input-toolconverter 0.2.0 → 0.2.3

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.
Files changed (143) hide show
  1. package/.nyc_output/out.json +8980 -1849
  2. package/CHANGES.md +15 -1
  3. package/README.md +6 -11
  4. package/_locales/en-US/messages.json +153 -6
  5. package/_locales/hu-HU/messages.json +153 -6
  6. package/_locales/pt-BR/messages.json +153 -6
  7. package/_locales/sv-SE/messages.json +153 -6
  8. package/babel.config.json +0 -1
  9. package/browser_action/characterSelection.js +18 -11
  10. package/browser_action/charrefConverters.js +286 -79
  11. package/browser_action/chartBuild.js +97 -27
  12. package/browser_action/encodingBehaviors.js +10 -7
  13. package/browser_action/entityBehaviors.js +42 -16
  14. package/browser_action/index-es.html +13 -1
  15. package/browser_action/index-instrumented.html +13 -1
  16. package/browser_action/index-pages.html +13 -1
  17. package/browser_action/index.html +13 -1
  18. package/browser_action/index.iife.min.js +9 -1
  19. package/browser_action/index.iife.min.js.map +1 -1
  20. package/browser_action/index.instrumented.iife.min.js +1 -1
  21. package/browser_action/index.instrumented.iife.min.js.map +1 -1
  22. package/browser_action/index.js +5 -5
  23. package/browser_action/preferences/prefDefaults.js +12 -3
  24. package/browser_action/service-worker/sw-activateCallback.js +1 -2
  25. package/browser_action/service-worker/sw-resources.json +6 -4
  26. package/browser_action/templateUtils/elements.js +12 -1
  27. package/browser_action/templateUtils/fill.js +6 -0
  28. package/browser_action/templateUtils/validation.js +4 -1
  29. package/browser_action/templates/chartBuild.js +167 -102
  30. package/browser_action/templates/index.js +227 -53
  31. package/browser_action/templatesElementCustomization/widgets.js +40 -15
  32. package/browser_action/unicode/UnicodeConverter.js +99 -73
  33. package/browser_action/unicode/charrefunicodeDb.js +100 -50
  34. package/browser_action/unicode/getScriptInfoForCodePoint.js +13 -4
  35. package/browser_action/unicode/hangul.js +27 -20
  36. package/browser_action/unicode/lastScriptNames.json +1 -1
  37. package/browser_action/unicode/parseUnihanFromTextFileStrings.js +44 -25
  38. package/browser_action/unicode/unicodeFieldInfo.js +112 -90
  39. package/browser_action/unicode/unicodeScripts.js +409 -35
  40. package/browser_action/unicode/unihan.js +4 -3
  41. package/browser_action/unicode/unihanDbPopulate.js +7 -2
  42. package/browser_action/unicode/unihanFields.js +34 -0
  43. package/browser_action/unicodecharref.js +353 -190
  44. package/browser_action/utils/DOMUtils.js +95 -34
  45. package/browser_action/utils/FetchUtils.js +7 -6
  46. package/browser_action/utils/TextUtils.js +4 -4
  47. package/browser_action/utils/TypedArrayUtils.js +9 -5
  48. package/browser_action/utils/semicolonSeparatedToArray.js +3 -3
  49. package/browser_action/utils/setupServiceWorker.js +2 -2
  50. package/eslint.config.js +11 -0
  51. package/icons/openWindow16.png +0 -0
  52. package/icons/openWindow24.png +0 -0
  53. package/lib/background.html +7 -0
  54. package/lib/background.js +2 -2
  55. package/package.json +80 -70
  56. package/pnpm-workspace.yaml +8 -0
  57. package/server.js +66 -51
  58. package/sw.js +97 -56
  59. package/tools/entities-import.js +4 -1
  60. package/tools/findEsResources.js +33 -10
  61. package/tools/fix-sw-resources-vendor-paths.js +60 -0
  62. package/tools/list-locales.js +2 -2
  63. package/tools/parseUnicodeCharts.js +126 -60
  64. package/tools/ucd-import.js +1 -10
  65. package/tools/unicode-charts.html +49 -20
  66. package/tools/unihan-import.js +45 -15
  67. package/tools/write-sw-version.js +16 -0
  68. package/tsconfig.json +23 -0
  69. package/typings/__coverage__.d.ts +5 -0
  70. package/typings/apple-system-profiler.d.ts +17 -0
  71. package/typings/commands.d.ts +19 -0
  72. package/typings/json-6.d.ts +4 -0
  73. package/typings/rollup-plugin-istanbul.d.ts +3 -0
  74. package/vendor/camelcase/index.d.ts +154 -0
  75. package/vendor/camelcase/index.js +137 -23
  76. package/vendor/fflate/esm/browser.d.ts +1539 -0
  77. package/vendor/fflate/esm/browser.js +82 -55
  78. package/vendor/intl-dom/dist/Formatter.d.ts +120 -0
  79. package/vendor/intl-dom/dist/Formatter.d.ts.map +1 -0
  80. package/vendor/intl-dom/dist/collation.d.ts +42 -0
  81. package/vendor/intl-dom/dist/collation.d.ts.map +1 -0
  82. package/vendor/intl-dom/dist/defaultAllSubstitutions.d.ts +52 -0
  83. package/vendor/intl-dom/dist/defaultAllSubstitutions.d.ts.map +1 -0
  84. package/vendor/intl-dom/dist/defaultInsertNodes.d.ts +96 -0
  85. package/vendor/intl-dom/dist/defaultInsertNodes.d.ts.map +1 -0
  86. package/vendor/intl-dom/dist/defaultKeyCheckerConverter.d.ts +17 -0
  87. package/vendor/intl-dom/dist/defaultKeyCheckerConverter.d.ts.map +1 -0
  88. package/vendor/intl-dom/dist/defaultLocaleResolver.d.ts +285 -0
  89. package/vendor/intl-dom/dist/defaultLocaleResolver.d.ts.map +1 -0
  90. package/vendor/intl-dom/dist/findLocaleStrings.d.ts +88 -0
  91. package/vendor/intl-dom/dist/findLocaleStrings.d.ts.map +1 -0
  92. package/vendor/intl-dom/dist/getDOMForLocaleString.d.ts +67 -0
  93. package/vendor/intl-dom/dist/getDOMForLocaleString.d.ts.map +1 -0
  94. package/vendor/intl-dom/dist/getMessageForKeyByStyle.d.ts +73 -0
  95. package/vendor/intl-dom/dist/getMessageForKeyByStyle.d.ts.map +1 -0
  96. package/vendor/intl-dom/dist/getStringFromMessageAndDefaults.d.ts +26 -0
  97. package/vendor/intl-dom/dist/getStringFromMessageAndDefaults.d.ts.map +1 -0
  98. package/vendor/intl-dom/dist/i18n.d.ts +113 -0
  99. package/vendor/intl-dom/dist/i18n.d.ts.map +1 -0
  100. package/vendor/intl-dom/dist/index.d.ts +92 -0
  101. package/vendor/intl-dom/dist/index.d.ts.map +1 -0
  102. package/vendor/intl-dom/dist/index.esm.d.ts +34 -0
  103. package/vendor/intl-dom/dist/index.esm.js +854 -896
  104. package/vendor/intl-dom/dist/index.esm.min.js +4 -0
  105. package/vendor/intl-dom/dist/index.esm.min.js.map +1 -0
  106. package/vendor/intl-dom/dist/index.umd.js +2953 -0
  107. package/vendor/intl-dom/dist/index.umd.min.js +4 -0
  108. package/vendor/intl-dom/dist/index.umd.min.js.map +1 -0
  109. package/vendor/intl-dom/dist/promiseChainForValues.d.ts +34 -0
  110. package/vendor/intl-dom/dist/promiseChainForValues.d.ts.map +1 -0
  111. package/vendor/intl-dom/dist/shared.d.ts +20 -0
  112. package/vendor/intl-dom/dist/shared.d.ts.map +1 -0
  113. package/vendor/intl-dom/dist/utils.d.ts +53 -0
  114. package/vendor/intl-dom/dist/utils.d.ts.map +1 -0
  115. package/vendor/jamilih/dist/jml.d.mts +468 -0
  116. package/vendor/jamilih/dist/{jml-es.js → jml.mjs} +1489 -343
  117. package/vendor/jquery/dist/jquery.js +1677 -2713
  118. package/vendor/json-6/dist/index.mjs +2 -0
  119. package/vendor/miller-columns/CHANGES.md +185 -0
  120. package/vendor/miller-columns/LICENSE-MIT.txt +21 -0
  121. package/vendor/miller-columns/README.md +249 -0
  122. package/vendor/miller-columns/demos/index.html +69 -0
  123. package/vendor/miller-columns/demos/index.js +72 -0
  124. package/vendor/miller-columns/dist/index-es.js +748 -0
  125. package/vendor/miller-columns/dist/index-es.min.d.ts +25 -0
  126. package/vendor/miller-columns/dist/index-es.min.js +7 -1
  127. package/vendor/miller-columns/dist/index-umd.js +757 -0
  128. package/vendor/miller-columns/dist/index-umd.min.js +7 -0
  129. package/vendor/miller-columns/dist/index.d.ts +25 -0
  130. package/vendor/miller-columns/dist/millerColumns.d.ts +10 -0
  131. package/vendor/miller-columns/eslint.config.js +46 -0
  132. package/vendor/miller-columns/fix-declarations.js +18 -0
  133. package/vendor/miller-columns/miller-columns.css +24 -1
  134. package/vendor/miller-columns/package.json +73 -0
  135. package/vendor/miller-columns/pnpm-workspace.yaml +2 -0
  136. package/vendor/miller-columns/src/index.js +642 -0
  137. package/vendor/miller-columns/src/millerColumns.ts +12 -0
  138. package/vendor/miller-columns/tsconfig-prod.json +23 -0
  139. package/vendor/miller-columns/tsconfig.json +21 -0
  140. package/vendor/simple-prefs/dist/index.esm.d.ts +1 -0
  141. package/vendor/simple-prefs/dist/index.esm.js +164 -216
  142. package/vendor/simple-prefs/dist/simple-prefs.d.ts +117 -0
  143. package/lgtm.yml +0 -5
@@ -0,0 +1,642 @@
1
+
2
+ /* eslint-disable no-unused-vars -- Convenient */
3
+ /**
4
+ * MIT License.
5
+ *
6
+ * @copyright 2014 White Magic Software, Inc.
7
+ * @copyright 2018 Brett Zamir
8
+ */
9
+
10
+ import loadStylesheets from 'load-stylesheets';
11
+
12
+ /**
13
+ * @typedef {{
14
+ * delay: JQuery.Duration | string,
15
+ * outsideClickBehavior: "reset"|"select-parent"|"none",
16
+ * breadcrumbRoot: string,
17
+ * breadcrumb: (this: HTMLElement, $columns?: JQuery<HTMLElement>) => void,
18
+ * current: (li: JQuery<HTMLLIElement>, $columns: JQuery<HTMLElement>) => void,
19
+ * preview: null|((li: JQuery<HTMLLIElement>, $columns: JQuery<HTMLElement>) => void),
20
+ * onPreview: null|((
21
+ * ev: JQuery.ClickEvent<HTMLUListElement, undefined, HTMLUListElement, HTMLUListElement>,
22
+ * li: JQuery<HTMLUListElement>,
23
+ * $columns: JQuery<HTMLElement>
24
+ * ) => void),
25
+ * animation: (li: JQuery<HTMLLIElement>, $columns: JQuery<HTMLElement>) => void,
26
+ * reset: ($columns: JQuery<HTMLElement>, resetByUser: boolean) => void,
27
+ * scroll?: ($column: JQuery<HTMLElement>|null, $columns: JQuery<HTMLElement>) => void
28
+ * }} Settings
29
+ */
30
+
31
+ const defaultCSSURL = new URL('../miller-columns.css', import.meta.url).href;
32
+
33
+ /**
34
+ * @param {string} s
35
+ * @returns {string}
36
+ */
37
+ function escapeRegex (s) {
38
+ return s.replaceAll(/[\-\[\]\{\}\(\)*+?.,\\^$\|#\s]/gv, String.raw`\$&`);
39
+ }
40
+
41
+ /**
42
+ * @param {jQuery} $
43
+ * @param {object} cfg
44
+ * @param {string} [cfg.namespace]
45
+ * @param {Exclude<import('load-stylesheets').Stylesheets, string>} [cfg.stylesheets]
46
+ * @returns {Promise<jQuery>}
47
+ */
48
+ async function addMillerColumnPlugin ($, {namespace = 'miller', stylesheets = ['@default']} = {}) {
49
+ /** @type {Settings} */
50
+ let settings;
51
+ const columnSelector = `ul:not(.${namespace}-no-columns),ol:not(.${namespace}-no-columns)`;
52
+ const itemSelector = 'li';
53
+ if (stylesheets) {
54
+ await loadStylesheets(stylesheets.map((s) => {
55
+ return s === '@default' ? defaultCSSURL : s;
56
+ }));
57
+ }
58
+
59
+ /**
60
+ * Returns a list of the currently selected items.
61
+ * @returns {JQuery<HTMLElement>}
62
+ */
63
+ function chain () {
64
+ return $(`.${namespace}-column > .${namespace}-selected`);
65
+ }
66
+
67
+ /**
68
+ * Add the breadcrumb path using the chain of selected items.
69
+ * @param {JQuery<HTMLElement>} [$columns] - Optional columns element for root link
70
+ * @returns {void}
71
+ */
72
+ function breadcrumb ($columns) {
73
+ const $breadcrumb = $(`.${namespace}-breadcrumbs`).empty();
74
+
75
+ // Add root link if breadcrumbRoot option is set
76
+ if (settings.breadcrumbRoot) {
77
+ $(`<span class="${namespace}-breadcrumb ${namespace}-breadcrumb-root">`).
78
+ text(settings.breadcrumbRoot).
79
+ on('click', function () {
80
+ if ($columns) {
81
+ userReset($columns);
82
+ }
83
+ }).appendTo($breadcrumb);
84
+ }
85
+
86
+ chain().each(function () {
87
+ const $crumb = $(this);
88
+ $(`<span class="${namespace}-breadcrumb">`).
89
+ text($crumb.text().trim()).
90
+ on('click', function () {
91
+ $crumb.trigger('click');
92
+ }).appendTo($breadcrumb);
93
+ });
94
+ }
95
+
96
+ /**
97
+ * Ensure the viewport shows the entire newly expanded item.
98
+ *
99
+ * @param {JQuery<HTMLElement>|null} $column
100
+ * @param {JQuery<HTMLElement>} $columns
101
+ * @returns {void}
102
+ */
103
+ function animation ($column, $columns) {
104
+ let width = 0;
105
+ ($column ? chain().not($column) : chain()).each(function () {
106
+ width += /** @type {number} */ ($(this).outerWidth(true));
107
+ });
108
+ $columns.stop().animate({
109
+ scrollLeft: width
110
+ }, settings.delay, function () {
111
+ // Why isn't this working when we instead use this `last` on the `animate` above?
112
+ const last = $columns.find(`.${namespace}-column:not(.${namespace}-collapse)`).last();
113
+ // last[0].scrollIntoView(); // Scrolls vertically also unfortunately
114
+ last[0].scrollLeft = width;
115
+ if (settings.scroll) {
116
+ settings.scroll.call(this, $column, $columns);
117
+ }
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Convert nested lists into columns using breadth-first traversal.
123
+ *
124
+ * @param {JQuery<HTMLElement>} $columns
125
+ * @param {JQuery<HTMLElement>} [$startNode] - Optional starting node for partial unnesting
126
+ * @returns {void}
127
+ */
128
+ function unnest ($columns, $startNode) {
129
+ const queue = [];
130
+ let $node;
131
+
132
+ // Push the root unordered list item into the queue.
133
+ queue.push($startNode || $columns.children());
134
+
135
+ while (queue.length) {
136
+ $node = /** @type {JQuery<HTMLElement>} */ (queue.shift());
137
+
138
+ $node.children(itemSelector).each(function () {
139
+ const $this = $(this);
140
+ const $child = $this.children(columnSelector);
141
+ const $ancestor = $this.parent().parent();
142
+
143
+ // Retain item hierarchy (because it is lost after flattening).
144
+ // Only set ancestor if it's actually a list item and not already set
145
+ // eslint-disable-next-line eqeqeq, no-eq-null -- Check either without duplication
146
+ if ($ancestor.length && $ancestor.is(itemSelector) && ($this.data(`${namespace}-ancestor`) == null)) {
147
+ // Use addBack to reset all selection chains.
148
+ $(this).siblings().addBack().data(`${namespace}-ancestor`, $ancestor);
149
+ }
150
+
151
+ if ($child.length) {
152
+ queue.push($child);
153
+ $(this).data(`${namespace}-child`, $child).addClass(`${namespace}-parent`);
154
+ }
155
+
156
+ // Causes item siblings to have a flattened DOM lineage.
157
+ $(this).parent(columnSelector).appendTo($columns).addClass(`${namespace}-column`);
158
+ });
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Hide columns (not the first).
164
+ * @returns {void}
165
+ */
166
+ function collapse () {
167
+ $(`.${namespace}-column:gt(0)`).addClass(`${namespace}-collapse`);
168
+ }
169
+
170
+ /**
171
+ * Returns the last selected item (i.e., the current cursor).
172
+ * @returns {JQuery<HTMLElement>}
173
+ */
174
+ function current () {
175
+ return chain().last();
176
+ }
177
+
178
+ /**
179
+ * @param {JQuery<HTMLElement>} $columns
180
+ * @returns {void}
181
+ */
182
+ function scrollIntoView ($columns) {
183
+ animation(null, $columns);
184
+ }
185
+
186
+ /**
187
+ * @param {JQuery<HTMLElement>} $columns
188
+ * @returns {void}
189
+ */
190
+ function userReset ($columns) {
191
+ reset($columns, true);
192
+ scrollIntoView($columns);
193
+ }
194
+
195
+ /**
196
+ * Hide columns (not the first), remove selections, update breadcrumb.
197
+ *
198
+ * @param {JQuery<HTMLElement>} $columns
199
+ * @param {boolean} resetByUser
200
+ * @returns {void}
201
+ */
202
+ function reset ($columns, resetByUser) {
203
+ collapse();
204
+ chain().removeClass(`${namespace}-selected`);
205
+ breadcrumb($columns);
206
+
207
+ // Upon reset ensure no value is returned to the calling code.
208
+ settings.reset($columns, resetByUser);
209
+ if (settings.preview) {
210
+ $(`.${namespace}-preview`).remove();
211
+ }
212
+ }
213
+
214
+ /**
215
+ * Select item above current selection.
216
+ * @returns {void}
217
+ */
218
+ function moveU () {
219
+ const elem = current().prev();
220
+ elem[0]?.scrollIntoView({block: 'nearest'});
221
+ elem.trigger('click');
222
+ }
223
+
224
+ /**
225
+ * Select item below current selection.
226
+ * @returns {void}
227
+ */
228
+ function moveD () {
229
+ const elem = current().next();
230
+ elem[0]?.scrollIntoView({block: 'nearest', inline: 'start'});
231
+ elem.trigger('click');
232
+ }
233
+
234
+ /**
235
+ * Select item left of the current selection.
236
+ * @returns {void}
237
+ */
238
+ function moveL () {
239
+ const $current = current();
240
+ const $ancestor = $current.data(`${namespace}-ancestor`);
241
+ const $child = $current.data(`${namespace}-child`);
242
+
243
+ // If current item has children and they are visible, but we're at root level,
244
+ // do nothing - we're already on the parent and just expanded it
245
+ if ($child && !$child.hasClass(`${namespace}-collapse`) && !$ancestor) {
246
+ return;
247
+ }
248
+
249
+ // Move to ancestor if it exists
250
+ if ($ancestor) {
251
+ $ancestor[0]?.scrollIntoView({block: 'nearest'});
252
+ $ancestor.trigger('click');
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Select item right of the current selection, or down if no right item.
258
+ * @returns {void}
259
+ */
260
+ function moveR () {
261
+ const $child = current().data(`${namespace}-child`);
262
+
263
+ if ($child) {
264
+ const elem = $child.children(itemSelector).first();
265
+ elem[0]?.scrollIntoView({block: 'nearest'});
266
+ elem.trigger('click');
267
+ } else {
268
+ moveD();
269
+ }
270
+ }
271
+
272
+ /**
273
+ * @callback MillerColumnsKeyPress
274
+ * @param {KeyboardEvent} e
275
+ * @returns {void}
276
+ */
277
+
278
+ /**
279
+ * @param {JQuery<HTMLElement>} $columns
280
+ * @returns {MillerColumnsKeyPress}
281
+ */
282
+ function getKeyPress ($columns) {
283
+ let buffer = '';
284
+ /** @type {number} */
285
+ let lastTime;
286
+
287
+ /**
288
+ * @param {string} key
289
+ * @returns {void}
290
+ */
291
+ function checkLastPressed (key) {
292
+ const currTime = Date.now();
293
+ if (!lastTime || currTime - lastTime < 500) {
294
+ buffer += key;
295
+ } else {
296
+ buffer = key;
297
+ }
298
+ lastTime = currTime;
299
+ }
300
+
301
+ return function keypress (ev) {
302
+ // eslint-disable-next-line prefer-destructuring -- TS
303
+ const key = /** @type {Event & {key: string}} */ (ev).key;
304
+ // Was an attempt made to move the currently selected item (the cursor)?
305
+ let moved = false;
306
+
307
+ switch (key) {
308
+ case 'Escape':
309
+ userReset($columns);
310
+ break;
311
+ case 'ArrowUp':
312
+ moveU();
313
+ moved = true;
314
+ break;
315
+ case 'ArrowDown':
316
+ moveD();
317
+ moved = true;
318
+ break;
319
+ case 'ArrowLeft':
320
+ moveL();
321
+ moved = true;
322
+ break;
323
+ case 'ArrowRight':
324
+ moveR();
325
+ moved = true;
326
+ break;
327
+ default:
328
+ if (!ev.metaKey && !ev.altKey) {
329
+ if (key.length === 1) {
330
+ checkLastPressed(key);
331
+ const matching = $columns.
332
+ find(`${itemSelector}.${namespace}-selected`).
333
+ last().
334
+ siblings().
335
+ filter(function () {
336
+ return new RegExp('^' + escapeRegex(buffer), 'iv').
337
+ test($(this).text().trim());
338
+ });
339
+ const elem = matching.first();
340
+ elem[0]?.scrollIntoView({block: 'nearest'});
341
+ elem.trigger('click');
342
+ }
343
+ moved = true;
344
+ }
345
+ break;
346
+ }
347
+
348
+ // If no item is selected, then jump to the first item.
349
+ if (moved && (current().length === 0)) {
350
+ $(`.${namespace}-column`).first().children().first().trigger('click');
351
+ }
352
+
353
+ if (moved) {
354
+ ev.preventDefault();
355
+ }
356
+ };
357
+ }
358
+
359
+ /**
360
+ * @param {Partial<Settings>} options
361
+ */
362
+ $.fn.millerColumns = function (options) {
363
+ /** @type {Settings} */
364
+ const defaults = {
365
+ current ($item) { /* noop */ },
366
+ reset ($columns) { /* noop */ },
367
+ preview: null,
368
+ onPreview: null,
369
+ breadcrumbRoot: 'Root',
370
+ breadcrumb,
371
+ animation,
372
+ delay: 500,
373
+ outsideClickBehavior: 'select-parent'
374
+ };
375
+
376
+ settings = $.extend(defaults, options);
377
+
378
+ const $result = this.each(function () {
379
+ const $columns = $(this);
380
+
381
+ // Store original HTML for restoration
382
+ const originalHTML = $columns.html();
383
+ $columns.data(`${namespace}-original-html`, originalHTML);
384
+
385
+ unnest($columns);
386
+ collapse();
387
+ breadcrumb($columns); // Initialize breadcrumbs with Root link
388
+
389
+ // Store keypress handler for later removal
390
+ const keypressHandler = getKeyPress($columns);
391
+
392
+ // Expand the requested child node on click.
393
+ // Use event delegation to handle dynamically added items
394
+ $columns.on('click', itemSelector, function (ev) {
395
+ const $this = $(this);
396
+ reset($columns, false);
397
+
398
+ const $child = $this.data(`${namespace}-child`);
399
+ let $ancestor = $this;
400
+
401
+ if ($child) {
402
+ $child[0]?.scrollIntoView({block: 'nearest'});
403
+ $child.removeClass(`${namespace}-collapse`).
404
+ children().
405
+ removeClass(`${namespace}-selected`);
406
+ }
407
+
408
+ // Reveal all ancestors
409
+ while ($ancestor) {
410
+ $ancestor.
411
+ addClass(`${namespace}-selected`).
412
+ parent().
413
+ removeClass(`${namespace}-collapse`);
414
+ $ancestor = $ancestor.data(`${namespace}-ancestor`);
415
+ }
416
+
417
+ settings.animation.call(this, $this, $columns);
418
+ settings.breadcrumb.call(this, $columns);
419
+ settings.current.call(this, $this, $columns);
420
+
421
+ if (settings.preview) {
422
+ const isFinalCol = $this.hasClass(`${namespace}-selected`) &&
423
+ !$this.hasClass(`${namespace}-parent`);
424
+ if (isFinalCol) {
425
+ const content = settings.preview.call(this, $this, $columns);
426
+ const ul = /** @type {JQuery<HTMLUListElement>} */ (
427
+ $(`<ul class="${namespace}-column ${namespace}-preview">
428
+ <li>${content}</li>
429
+ </ul>`)
430
+ );
431
+ $this.parent().parent().append(ul);
432
+ ul[0].scrollIntoView({
433
+ block: 'nearest',
434
+ inline: 'start'
435
+ });
436
+ ul.on('click', (e) => {
437
+ e.stopPropagation();
438
+ settings.onPreview?.call(this, e, ul, $columns);
439
+ });
440
+ }
441
+ }
442
+
443
+ // Don't allow the underlying element
444
+ // to receive the click event.
445
+ ev.stopPropagation();
446
+ });
447
+
448
+ $columns[0].addEventListener('keydown', keypressHandler);
449
+
450
+ $columns.on('click', (e) => {
451
+ switch (settings.outsideClickBehavior) {
452
+ case 'reset':
453
+ userReset($columns);
454
+ break;
455
+ case 'select-parent': {
456
+ const caretPosition = document.caretPositionFromPoint(e.clientX, e.clientY);
457
+ const node = caretPosition?.offsetNode;
458
+ let elem = /** @type {Element|null} */ (node?.nodeType === 1 ? node : node?.parentElement);
459
+ while (elem) {
460
+ if (elem.matches(`ul.${namespace}-column:not(.${namespace}-collapse)`)) {
461
+ $(elem).prevAll(
462
+ `ul.${namespace}-column:not(.${namespace}-collapse)`
463
+ ).first().find(`li.${namespace}-selected`).trigger('click');
464
+ break;
465
+ }
466
+ elem = elem.parentElement;
467
+ }
468
+ break;
469
+ }
470
+ default:
471
+ break;
472
+ }
473
+ });
474
+
475
+ // Store handler reference for cleanup
476
+ $columns.data(`${namespace}-keypress-handler`, keypressHandler);
477
+
478
+ // The last set of columns on the page receives focus.
479
+ // $columns.focus();
480
+ });
481
+
482
+ /**
483
+ * Add a new item dynamically to the miller columns structure.
484
+ * The item can contain nested lists which will be automatically unnested.
485
+ *
486
+ * @param {string|JQuery<HTMLLIElement>} item - HTML string or jQuery element for the new list item
487
+ * @param {JQuery<HTMLLIElement>} [$parent] - Optional parent item to add this as a child.
488
+ * If not provided, adds to root level.
489
+ * @returns {JQuery<HTMLLIElement>} The newly added item
490
+ */
491
+ $result.addItem = function (item, $parent) {
492
+ const $item = /** @type {JQuery<HTMLLIElement>} */ (typeof item === 'string' ? $(item) : item);
493
+ const $columns = $result;
494
+
495
+ if (!$parent) {
496
+ // Add to root level (first column)
497
+ const $rootColumn = $columns.find(`.${namespace}-column`).first();
498
+
499
+ if ($rootColumn.length) {
500
+ // Append to existing root column
501
+ $rootColumn.append($item);
502
+
503
+ // If the item has nested children, process them
504
+ const $child = $item.children(columnSelector);
505
+ if ($child.length) {
506
+ // Set up the parent-child relationship
507
+ $item.data(`${namespace}-child`, $child).addClass(`${namespace}-parent`);
508
+ // Process the child list to unnest it
509
+ unnest($columns, $child);
510
+ }
511
+ } else {
512
+ // No columns exist yet, create initial structure
513
+ const $tempWrapper = $('<ul>').append($item);
514
+ $columns.append($tempWrapper);
515
+ unnest($columns, $tempWrapper);
516
+ }
517
+ } else {
518
+ // Add as child of existing parent
519
+ let $childList = $parent.data(`${namespace}-child`);
520
+
521
+ if (!$childList) {
522
+ // Parent doesn't have children yet, create a new list with the item
523
+ $childList = $('<ul>').append($item);
524
+ $parent.append($childList);
525
+ $parent.data(`${namespace}-child`, $childList).addClass(`${namespace}-parent`);
526
+
527
+ // Set the ancestor relationship for the new item
528
+ $item.data(`${namespace}-ancestor`, $parent);
529
+
530
+ // The new list needs to be processed by unnest to become a column
531
+ unnest($columns, $childList);
532
+
533
+ // After unnesting, get the updated reference to the child list
534
+ $childList = $parent.data(`${namespace}-child`);
535
+ } else {
536
+ // Parent already has children - $childList is already a column
537
+ // Just append the new item directly to it
538
+ $childList.append($item);
539
+
540
+ // Set the ancestor relationship for the new item
541
+ $item.data(`${namespace}-ancestor`, $parent);
542
+ }
543
+
544
+ // If the new item has nested children, process them
545
+ const $child = $item.children(columnSelector);
546
+ if ($child.length) {
547
+ // Set up the parent-child relationship
548
+ $item.data(`${namespace}-child`, $child).addClass(`${namespace}-parent`);
549
+ // Process the child list to unnest it
550
+ unnest($columns, $child);
551
+ }
552
+ }
553
+
554
+ return $item;
555
+ };
556
+
557
+ /**
558
+ * Rebuild children for a parent item after external changes.
559
+ * @param {JQuery<HTMLLIElement>} $parent
560
+ * @param {(string|JQuery<HTMLLIElement>)[]} newItems
561
+ * @returns {JQuery<HTMLLIElement>}
562
+ */
563
+ $result.refreshChildren = function ($parent, newItems) {
564
+ if (!$parent || !$parent.length) {
565
+ return $parent;
566
+ }
567
+ const $existing = $parent.data(`${namespace}-child`);
568
+ if ($existing && $existing.length) {
569
+ $existing.remove();
570
+ $parent.removeData(`${namespace}-child`).removeClass(`${namespace}-parent`);
571
+ }
572
+ const $liItems = newItems.map((it) => (typeof it === 'string' ? $(it) : it));
573
+ const $newList = $('<ul>').append($liItems);
574
+ $parent.append($newList);
575
+ unnest($result, $newList);
576
+ $parent.trigger('click');
577
+ return $parent;
578
+ };
579
+
580
+ /**
581
+ * Destroy and restore original structure.
582
+ * @returns {JQuery<HTMLElement>}
583
+ */
584
+ $result.destroy = function () {
585
+ const $columns = $result;
586
+
587
+ $columns.each(function () {
588
+ const $col = $(this);
589
+ // Remove keydown event listener
590
+ const keypressHandler = $col.data(`${namespace}-keypress-handler`);
591
+ if (keypressHandler) {
592
+ this.removeEventListener('keydown', keypressHandler);
593
+ }
594
+
595
+ // Remove click event handlers
596
+ $col.off('click');
597
+
598
+ // Remove all miller-columns CSS classes from columns
599
+ $col.find(`.${namespace}-column`).removeClass(`${namespace}-column ${namespace}-collapse`);
600
+
601
+ // Remove all miller-parent classes and miller-selected classes
602
+ $col.find(`.${namespace}-parent`).removeClass(`${namespace}-parent`);
603
+ $col.find(`.${namespace}-selected`).removeClass(`${namespace}-selected`);
604
+
605
+ // Remove all data attributes
606
+ $col.find('li').each(function () {
607
+ const $item = $(this);
608
+ $item.removeData(`${namespace}-ancestor`);
609
+ $item.removeData(`${namespace}-child`);
610
+ });
611
+
612
+ // Remove preview columns
613
+ $col.find(`.${namespace}-preview`).remove();
614
+
615
+ // Restore original HTML structure
616
+ const originalHTML = $col.data(`${namespace}-original-html`);
617
+ if (originalHTML) {
618
+ $col.html(originalHTML);
619
+ $col.removeData(`${namespace}-original-html`);
620
+ }
621
+
622
+ $col.removeData(`${namespace}-keypress-handler`);
623
+ });
624
+
625
+ delete $result.addItem;
626
+ delete $result.destroy;
627
+ delete $result.refreshChildren;
628
+
629
+ return $result;
630
+ };
631
+
632
+ return $result;
633
+ };
634
+
635
+ return $;
636
+ }
637
+
638
+ /**
639
+ * @typedef {import('./millerColumns.ts').millerColumns} millerColumns
640
+ */
641
+
642
+ export default addMillerColumnPlugin;
@@ -0,0 +1,12 @@
1
+ declare global {
2
+ interface JQuery {
3
+ millerColumns(options: Partial<import('./index.js').Settings>): JQuery;
4
+ addItem?(item: string | JQuery<HTMLLIElement>, $parent?: JQuery<HTMLLIElement>): JQuery<HTMLLIElement>;
5
+ refreshChildren?($parent: JQuery<HTMLLIElement>, newItems: Array<string | JQuery<HTMLLIElement>>): JQuery<HTMLLIElement>;
6
+ destroy?(): JQuery<HTMLElement>;
7
+ }
8
+ }
9
+
10
+ export type millerColumns = JQuery['millerColumns'];
11
+
12
+ export {};
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["es2024", "DOM"],
4
+ "moduleResolution": "NodeNext",
5
+ "module": "NodeNext",
6
+ "allowJs": true,
7
+ "checkJs": true,
8
+ "noEmit": false,
9
+ "emitDeclarationOnly": true,
10
+ "declaration": true,
11
+ "strict": true,
12
+ "skipLibCheck": true,
13
+ "target": "es2024",
14
+ "outDir": "dist",
15
+ "declarationDir": "dist",
16
+ "rootDir": "src"
17
+ },
18
+ "include": [
19
+ "src/**/*.js",
20
+ "src/**/*.ts"
21
+ ],
22
+ "exclude": ["node_modules"]
23
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["es2024", "DOM"],
4
+ "moduleResolution": "NodeNext",
5
+ "module": "NodeNext",
6
+ "allowJs": true,
7
+ "checkJs": true,
8
+ "noEmit": true,
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "target": "es2024"
12
+ },
13
+ "include": [
14
+ "*.js",
15
+ "demos/**/*.js",
16
+ "src/**/*.js",
17
+ "tests/**/*.js",
18
+ "src/**/*.ts"
19
+ ],
20
+ "exclude": ["node_modules"]
21
+ }
@@ -0,0 +1 @@
1
+ export * from './simple-prefs.js';