marksmith 0.0.13 → 0.0.15

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.
@@ -0,0 +1,2939 @@
1
+ /*!
2
+ Marksmith 0.0.15
3
+ */
4
+ var MarksmithController = (function () {
5
+ 'use strict';
6
+
7
+ var __classPrivateFieldGet = (undefined && undefined.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _MarkdownHeaderButtonElement_instances, _MarkdownHeaderButtonElement_setLevelStyle;
13
+ const buttonSelectors = [
14
+ '[data-md-button]',
15
+ 'md-header',
16
+ 'md-bold',
17
+ 'md-italic',
18
+ 'md-quote',
19
+ 'md-code',
20
+ 'md-link',
21
+ 'md-image',
22
+ 'md-unordered-list',
23
+ 'md-ordered-list',
24
+ 'md-task-list',
25
+ 'md-mention',
26
+ 'md-ref',
27
+ 'md-strikethrough'
28
+ ];
29
+ function getButtons(toolbar) {
30
+ const els = [];
31
+ for (const button of toolbar.querySelectorAll(buttonSelectors.join(', '))) {
32
+ if (button.hidden || (button.offsetWidth <= 0 && button.offsetHeight <= 0))
33
+ continue;
34
+ if (button.closest('markdown-toolbar') === toolbar)
35
+ els.push(button);
36
+ }
37
+ return els;
38
+ }
39
+ function keydown(fn) {
40
+ return function (event) {
41
+ if (event.key === ' ' || event.key === 'Enter') {
42
+ fn(event);
43
+ }
44
+ };
45
+ }
46
+ const styles = new WeakMap();
47
+ const manualStyles = {
48
+ 'header-1': { prefix: '# ' },
49
+ 'header-2': { prefix: '## ' },
50
+ 'header-3': { prefix: '### ' },
51
+ 'header-4': { prefix: '#### ' },
52
+ 'header-5': { prefix: '##### ' },
53
+ 'header-6': { prefix: '###### ' },
54
+ bold: { prefix: '**', suffix: '**', trimFirst: true },
55
+ italic: { prefix: '_', suffix: '_', trimFirst: true },
56
+ quote: { prefix: '> ', multiline: true, surroundWithNewlines: true },
57
+ code: {
58
+ prefix: '`',
59
+ suffix: '`',
60
+ blockPrefix: '```',
61
+ blockSuffix: '```'
62
+ },
63
+ link: { prefix: '[', suffix: '](url)', replaceNext: 'url', scanFor: 'https?://' },
64
+ image: { prefix: '![', suffix: '](url)', replaceNext: 'url', scanFor: 'https?://' },
65
+ 'unordered-list': {
66
+ prefix: '- ',
67
+ multiline: true,
68
+ unorderedList: true
69
+ },
70
+ 'ordered-list': {
71
+ prefix: '1. ',
72
+ multiline: true,
73
+ orderedList: true
74
+ },
75
+ 'task-list': { prefix: '- [ ] ', multiline: true, surroundWithNewlines: true },
76
+ mention: { prefix: '@', prefixSpace: true },
77
+ ref: { prefix: '#', prefixSpace: true },
78
+ strikethrough: { prefix: '~~', suffix: '~~', trimFirst: true }
79
+ };
80
+ class MarkdownButtonElement extends HTMLElement {
81
+ constructor() {
82
+ super();
83
+ const apply = (event) => {
84
+ const style = styles.get(this);
85
+ if (!style)
86
+ return;
87
+ event.preventDefault();
88
+ applyStyle(this, style);
89
+ };
90
+ this.addEventListener('keydown', keydown(apply));
91
+ this.addEventListener('click', apply);
92
+ }
93
+ connectedCallback() {
94
+ if (!this.hasAttribute('role')) {
95
+ this.setAttribute('role', 'button');
96
+ }
97
+ }
98
+ click() {
99
+ const style = styles.get(this);
100
+ if (!style)
101
+ return;
102
+ applyStyle(this, style);
103
+ }
104
+ }
105
+ class MarkdownHeaderButtonElement extends MarkdownButtonElement {
106
+ constructor() {
107
+ super(...arguments);
108
+ _MarkdownHeaderButtonElement_instances.add(this);
109
+ }
110
+ connectedCallback() {
111
+ const level = parseInt(this.getAttribute('level') || '3', 10);
112
+ __classPrivateFieldGet(this, _MarkdownHeaderButtonElement_instances, "m", _MarkdownHeaderButtonElement_setLevelStyle).call(this, level);
113
+ }
114
+ static get observedAttributes() {
115
+ return ['level'];
116
+ }
117
+ attributeChangedCallback(name, oldValue, newValue) {
118
+ if (name !== 'level')
119
+ return;
120
+ const level = parseInt(newValue || '3', 10);
121
+ __classPrivateFieldGet(this, _MarkdownHeaderButtonElement_instances, "m", _MarkdownHeaderButtonElement_setLevelStyle).call(this, level);
122
+ }
123
+ }
124
+ _MarkdownHeaderButtonElement_instances = new WeakSet(), _MarkdownHeaderButtonElement_setLevelStyle = function _MarkdownHeaderButtonElement_setLevelStyle(level) {
125
+ if (level < 1 || level > 6) {
126
+ return;
127
+ }
128
+ const prefix = `${'#'.repeat(level)} `;
129
+ styles.set(this, {
130
+ prefix
131
+ });
132
+ };
133
+ if (!window.customElements.get('md-header')) {
134
+ window.MarkdownHeaderButtonElement = MarkdownHeaderButtonElement;
135
+ window.customElements.define('md-header', MarkdownHeaderButtonElement);
136
+ }
137
+ class MarkdownBoldButtonElement extends MarkdownButtonElement {
138
+ connectedCallback() {
139
+ styles.set(this, { prefix: '**', suffix: '**', trimFirst: true });
140
+ }
141
+ }
142
+ if (!window.customElements.get('md-bold')) {
143
+ window.MarkdownBoldButtonElement = MarkdownBoldButtonElement;
144
+ window.customElements.define('md-bold', MarkdownBoldButtonElement);
145
+ }
146
+ class MarkdownItalicButtonElement extends MarkdownButtonElement {
147
+ connectedCallback() {
148
+ styles.set(this, { prefix: '_', suffix: '_', trimFirst: true });
149
+ }
150
+ }
151
+ if (!window.customElements.get('md-italic')) {
152
+ window.MarkdownItalicButtonElement = MarkdownItalicButtonElement;
153
+ window.customElements.define('md-italic', MarkdownItalicButtonElement);
154
+ }
155
+ class MarkdownQuoteButtonElement extends MarkdownButtonElement {
156
+ connectedCallback() {
157
+ styles.set(this, { prefix: '> ', multiline: true, surroundWithNewlines: true });
158
+ }
159
+ }
160
+ if (!window.customElements.get('md-quote')) {
161
+ window.MarkdownQuoteButtonElement = MarkdownQuoteButtonElement;
162
+ window.customElements.define('md-quote', MarkdownQuoteButtonElement);
163
+ }
164
+ class MarkdownCodeButtonElement extends MarkdownButtonElement {
165
+ connectedCallback() {
166
+ styles.set(this, { prefix: '`', suffix: '`', blockPrefix: '```', blockSuffix: '```' });
167
+ }
168
+ }
169
+ if (!window.customElements.get('md-code')) {
170
+ window.MarkdownCodeButtonElement = MarkdownCodeButtonElement;
171
+ window.customElements.define('md-code', MarkdownCodeButtonElement);
172
+ }
173
+ class MarkdownLinkButtonElement extends MarkdownButtonElement {
174
+ connectedCallback() {
175
+ styles.set(this, { prefix: '[', suffix: '](url)', replaceNext: 'url', scanFor: 'https?://' });
176
+ }
177
+ }
178
+ if (!window.customElements.get('md-link')) {
179
+ window.MarkdownLinkButtonElement = MarkdownLinkButtonElement;
180
+ window.customElements.define('md-link', MarkdownLinkButtonElement);
181
+ }
182
+ class MarkdownImageButtonElement extends MarkdownButtonElement {
183
+ connectedCallback() {
184
+ styles.set(this, { prefix: '![', suffix: '](url)', replaceNext: 'url', scanFor: 'https?://' });
185
+ }
186
+ }
187
+ if (!window.customElements.get('md-image')) {
188
+ window.MarkdownImageButtonElement = MarkdownImageButtonElement;
189
+ window.customElements.define('md-image', MarkdownImageButtonElement);
190
+ }
191
+ class MarkdownUnorderedListButtonElement extends MarkdownButtonElement {
192
+ connectedCallback() {
193
+ styles.set(this, { prefix: '- ', multiline: true, unorderedList: true });
194
+ }
195
+ }
196
+ if (!window.customElements.get('md-unordered-list')) {
197
+ window.MarkdownUnorderedListButtonElement = MarkdownUnorderedListButtonElement;
198
+ window.customElements.define('md-unordered-list', MarkdownUnorderedListButtonElement);
199
+ }
200
+ class MarkdownOrderedListButtonElement extends MarkdownButtonElement {
201
+ connectedCallback() {
202
+ styles.set(this, { prefix: '1. ', multiline: true, orderedList: true });
203
+ }
204
+ }
205
+ if (!window.customElements.get('md-ordered-list')) {
206
+ window.MarkdownOrderedListButtonElement = MarkdownOrderedListButtonElement;
207
+ window.customElements.define('md-ordered-list', MarkdownOrderedListButtonElement);
208
+ }
209
+ class MarkdownTaskListButtonElement extends MarkdownButtonElement {
210
+ connectedCallback() {
211
+ styles.set(this, { prefix: '- [ ] ', multiline: true, surroundWithNewlines: true });
212
+ }
213
+ }
214
+ if (!window.customElements.get('md-task-list')) {
215
+ window.MarkdownTaskListButtonElement = MarkdownTaskListButtonElement;
216
+ window.customElements.define('md-task-list', MarkdownTaskListButtonElement);
217
+ }
218
+ class MarkdownMentionButtonElement extends MarkdownButtonElement {
219
+ connectedCallback() {
220
+ styles.set(this, { prefix: '@', prefixSpace: true });
221
+ }
222
+ }
223
+ if (!window.customElements.get('md-mention')) {
224
+ window.MarkdownMentionButtonElement = MarkdownMentionButtonElement;
225
+ window.customElements.define('md-mention', MarkdownMentionButtonElement);
226
+ }
227
+ class MarkdownRefButtonElement extends MarkdownButtonElement {
228
+ connectedCallback() {
229
+ styles.set(this, { prefix: '#', prefixSpace: true });
230
+ }
231
+ }
232
+ if (!window.customElements.get('md-ref')) {
233
+ window.MarkdownRefButtonElement = MarkdownRefButtonElement;
234
+ window.customElements.define('md-ref', MarkdownRefButtonElement);
235
+ }
236
+ class MarkdownStrikethroughButtonElement extends MarkdownButtonElement {
237
+ connectedCallback() {
238
+ styles.set(this, { prefix: '~~', suffix: '~~', trimFirst: true });
239
+ }
240
+ }
241
+ if (!window.customElements.get('md-strikethrough')) {
242
+ window.MarkdownStrikethroughButtonElement = MarkdownStrikethroughButtonElement;
243
+ window.customElements.define('md-strikethrough', MarkdownStrikethroughButtonElement);
244
+ }
245
+ function applyFromToolbar(event) {
246
+ const { target, currentTarget } = event;
247
+ if (!(target instanceof Element))
248
+ return;
249
+ const mdButton = target.closest('[data-md-button]');
250
+ if (!mdButton || mdButton.closest('markdown-toolbar') !== currentTarget)
251
+ return;
252
+ const mdButtonStyle = mdButton.getAttribute('data-md-button');
253
+ const style = manualStyles[mdButtonStyle];
254
+ if (!style)
255
+ return;
256
+ event.preventDefault();
257
+ applyStyle(target, style);
258
+ }
259
+ function setFocusManagement(toolbar) {
260
+ toolbar.addEventListener('keydown', focusKeydown);
261
+ toolbar.setAttribute('tabindex', '0');
262
+ toolbar.addEventListener('focus', onToolbarFocus, { once: true });
263
+ }
264
+ function unsetFocusManagement(toolbar) {
265
+ toolbar.removeEventListener('keydown', focusKeydown);
266
+ toolbar.removeAttribute('tabindex');
267
+ toolbar.removeEventListener('focus', onToolbarFocus);
268
+ }
269
+ class MarkdownToolbarElement extends HTMLElement {
270
+ connectedCallback() {
271
+ if (!this.hasAttribute('role')) {
272
+ this.setAttribute('role', 'toolbar');
273
+ }
274
+ if (!this.hasAttribute('data-no-focus')) {
275
+ setFocusManagement(this);
276
+ }
277
+ this.addEventListener('keydown', keydown(applyFromToolbar));
278
+ this.addEventListener('click', applyFromToolbar);
279
+ }
280
+ attributeChangedCallback(name, oldValue, newValue) {
281
+ if (name !== 'data-no-focus')
282
+ return;
283
+ if (newValue === null) {
284
+ setFocusManagement(this);
285
+ }
286
+ else {
287
+ unsetFocusManagement(this);
288
+ }
289
+ }
290
+ disconnectedCallback() {
291
+ unsetFocusManagement(this);
292
+ }
293
+ get field() {
294
+ const id = this.getAttribute('for');
295
+ if (!id)
296
+ return null;
297
+ const root = 'getRootNode' in this ? this.getRootNode() : document;
298
+ let field;
299
+ if (root instanceof Document || root instanceof ShadowRoot) {
300
+ field = root.getElementById(id);
301
+ }
302
+ return field instanceof HTMLTextAreaElement ? field : null;
303
+ }
304
+ }
305
+ MarkdownToolbarElement.observedAttributes = ['data-no-focus'];
306
+ function onToolbarFocus({ target }) {
307
+ if (!(target instanceof Element))
308
+ return;
309
+ target.removeAttribute('tabindex');
310
+ let tabindex = '0';
311
+ for (const button of getButtons(target)) {
312
+ button.setAttribute('tabindex', tabindex);
313
+ if (tabindex === '0') {
314
+ button.focus();
315
+ tabindex = '-1';
316
+ }
317
+ }
318
+ }
319
+ function focusKeydown(event) {
320
+ const key = event.key;
321
+ if (key !== 'ArrowRight' && key !== 'ArrowLeft' && key !== 'Home' && key !== 'End')
322
+ return;
323
+ const toolbar = event.currentTarget;
324
+ if (!(toolbar instanceof HTMLElement))
325
+ return;
326
+ const buttons = getButtons(toolbar);
327
+ const index = buttons.indexOf(event.target);
328
+ const length = buttons.length;
329
+ if (index === -1)
330
+ return;
331
+ let n = 0;
332
+ if (key === 'ArrowLeft')
333
+ n = index - 1;
334
+ if (key === 'ArrowRight')
335
+ n = index + 1;
336
+ if (key === 'End')
337
+ n = length - 1;
338
+ if (n < 0)
339
+ n = length - 1;
340
+ if (n > length - 1)
341
+ n = 0;
342
+ for (let i = 0; i < length; i += 1) {
343
+ buttons[i].setAttribute('tabindex', i === n ? '0' : '-1');
344
+ }
345
+ event.preventDefault();
346
+ buttons[n].focus();
347
+ }
348
+ if (!window.customElements.get('markdown-toolbar')) {
349
+ window.MarkdownToolbarElement = MarkdownToolbarElement;
350
+ window.customElements.define('markdown-toolbar', MarkdownToolbarElement);
351
+ }
352
+ function isMultipleLines(string) {
353
+ return string.trim().split('\n').length > 1;
354
+ }
355
+ function repeat(string, n) {
356
+ return Array(n + 1).join(string);
357
+ }
358
+ function wordSelectionStart(text, i) {
359
+ let index = i;
360
+ while (text[index] && text[index - 1] != null && !text[index - 1].match(/\s/)) {
361
+ index--;
362
+ }
363
+ return index;
364
+ }
365
+ function wordSelectionEnd(text, i, multiline) {
366
+ let index = i;
367
+ const breakpoint = multiline ? /\n/ : /\s/;
368
+ while (text[index] && !text[index].match(breakpoint)) {
369
+ index++;
370
+ }
371
+ return index;
372
+ }
373
+ let canInsertText = null;
374
+ function insertText$1(textarea, { text, selectionStart, selectionEnd }) {
375
+ const originalSelectionStart = textarea.selectionStart;
376
+ const before = textarea.value.slice(0, originalSelectionStart);
377
+ const after = textarea.value.slice(textarea.selectionEnd);
378
+ if (canInsertText === null || canInsertText === true) {
379
+ textarea.contentEditable = 'true';
380
+ try {
381
+ canInsertText = document.execCommand('insertText', false, text);
382
+ }
383
+ catch (error) {
384
+ canInsertText = false;
385
+ }
386
+ textarea.contentEditable = 'false';
387
+ }
388
+ if (canInsertText && !textarea.value.slice(0, textarea.selectionStart).endsWith(text)) {
389
+ canInsertText = false;
390
+ }
391
+ if (!canInsertText) {
392
+ try {
393
+ document.execCommand('ms-beginUndoUnit');
394
+ }
395
+ catch (e) {
396
+ }
397
+ textarea.value = before + text + after;
398
+ try {
399
+ document.execCommand('ms-endUndoUnit');
400
+ }
401
+ catch (e) {
402
+ }
403
+ textarea.dispatchEvent(new CustomEvent('input', { bubbles: true, cancelable: true }));
404
+ }
405
+ if (selectionStart != null && selectionEnd != null) {
406
+ textarea.setSelectionRange(selectionStart, selectionEnd);
407
+ }
408
+ else {
409
+ textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd);
410
+ }
411
+ }
412
+ function styleSelectedText(textarea, styleArgs) {
413
+ const text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
414
+ let result;
415
+ if (styleArgs.orderedList || styleArgs.unorderedList) {
416
+ result = listStyle(textarea, styleArgs);
417
+ }
418
+ else if (styleArgs.multiline && isMultipleLines(text)) {
419
+ result = multilineStyle(textarea, styleArgs);
420
+ }
421
+ else {
422
+ result = blockStyle(textarea, styleArgs);
423
+ }
424
+ insertText$1(textarea, result);
425
+ }
426
+ function expandSelectionToLine(textarea) {
427
+ const lines = textarea.value.split('\n');
428
+ let counter = 0;
429
+ for (let index = 0; index < lines.length; index++) {
430
+ const lineLength = lines[index].length + 1;
431
+ if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {
432
+ textarea.selectionStart = counter;
433
+ }
434
+ if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
435
+ textarea.selectionEnd = counter + lineLength - 1;
436
+ }
437
+ counter += lineLength;
438
+ }
439
+ }
440
+ function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {
441
+ if (textarea.selectionStart === textarea.selectionEnd) {
442
+ textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart);
443
+ textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline);
444
+ }
445
+ else {
446
+ const expandedSelectionStart = textarea.selectionStart - prefixToUse.length;
447
+ const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length;
448
+ const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse;
449
+ const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse;
450
+ if (beginsWithPrefix && endsWithSuffix) {
451
+ textarea.selectionStart = expandedSelectionStart;
452
+ textarea.selectionEnd = expandedSelectionEnd;
453
+ }
454
+ }
455
+ return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
456
+ }
457
+ function newlinesToSurroundSelectedText(textarea) {
458
+ const beforeSelection = textarea.value.slice(0, textarea.selectionStart);
459
+ const afterSelection = textarea.value.slice(textarea.selectionEnd);
460
+ const breaksBefore = beforeSelection.match(/\n*$/);
461
+ const breaksAfter = afterSelection.match(/^\n*/);
462
+ const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0;
463
+ const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0;
464
+ let newlinesToAppend;
465
+ let newlinesToPrepend;
466
+ if (beforeSelection.match(/\S/) && newlinesBeforeSelection < 2) {
467
+ newlinesToAppend = repeat('\n', 2 - newlinesBeforeSelection);
468
+ }
469
+ if (afterSelection.match(/\S/) && newlinesAfterSelection < 2) {
470
+ newlinesToPrepend = repeat('\n', 2 - newlinesAfterSelection);
471
+ }
472
+ if (newlinesToAppend == null) {
473
+ newlinesToAppend = '';
474
+ }
475
+ if (newlinesToPrepend == null) {
476
+ newlinesToPrepend = '';
477
+ }
478
+ return { newlinesToAppend, newlinesToPrepend };
479
+ }
480
+ function blockStyle(textarea, arg) {
481
+ let newlinesToAppend;
482
+ let newlinesToPrepend;
483
+ const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines } = arg;
484
+ const originalSelectionStart = textarea.selectionStart;
485
+ const originalSelectionEnd = textarea.selectionEnd;
486
+ let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
487
+ let prefixToUse = isMultipleLines(selectedText) && blockPrefix.length > 0 ? `${blockPrefix}\n` : prefix;
488
+ let suffixToUse = isMultipleLines(selectedText) && blockSuffix.length > 0 ? `\n${blockSuffix}` : suffix;
489
+ if (prefixSpace) {
490
+ const beforeSelection = textarea.value[textarea.selectionStart - 1];
491
+ if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\s/)) {
492
+ prefixToUse = ` ${prefixToUse}`;
493
+ }
494
+ }
495
+ selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, arg.multiline);
496
+ let selectionStart = textarea.selectionStart;
497
+ let selectionEnd = textarea.selectionEnd;
498
+ const hasReplaceNext = replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
499
+ if (surroundWithNewlines) {
500
+ const ref = newlinesToSurroundSelectedText(textarea);
501
+ newlinesToAppend = ref.newlinesToAppend;
502
+ newlinesToPrepend = ref.newlinesToPrepend;
503
+ prefixToUse = newlinesToAppend + prefix;
504
+ suffixToUse += newlinesToPrepend;
505
+ }
506
+ if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {
507
+ const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length);
508
+ if (originalSelectionStart === originalSelectionEnd) {
509
+ let position = originalSelectionStart - prefixToUse.length;
510
+ position = Math.max(position, selectionStart);
511
+ position = Math.min(position, selectionStart + replacementText.length);
512
+ selectionStart = selectionEnd = position;
513
+ }
514
+ else {
515
+ selectionEnd = selectionStart + replacementText.length;
516
+ }
517
+ return { text: replacementText, selectionStart, selectionEnd };
518
+ }
519
+ else if (!hasReplaceNext) {
520
+ let replacementText = prefixToUse + selectedText + suffixToUse;
521
+ selectionStart = originalSelectionStart + prefixToUse.length;
522
+ selectionEnd = originalSelectionEnd + prefixToUse.length;
523
+ const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
524
+ if (arg.trimFirst && whitespaceEdges) {
525
+ const leadingWhitespace = whitespaceEdges[0] || '';
526
+ const trailingWhitespace = whitespaceEdges[1] || '';
527
+ replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
528
+ selectionStart += leadingWhitespace.length;
529
+ selectionEnd -= trailingWhitespace.length;
530
+ }
531
+ return { text: replacementText, selectionStart, selectionEnd };
532
+ }
533
+ else if (scanFor.length > 0 && selectedText.match(scanFor)) {
534
+ suffixToUse = suffixToUse.replace(replaceNext, selectedText);
535
+ const replacementText = prefixToUse + suffixToUse;
536
+ selectionStart = selectionEnd = selectionStart + prefixToUse.length;
537
+ return { text: replacementText, selectionStart, selectionEnd };
538
+ }
539
+ else {
540
+ const replacementText = prefixToUse + selectedText + suffixToUse;
541
+ selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext);
542
+ selectionEnd = selectionStart + replaceNext.length;
543
+ return { text: replacementText, selectionStart, selectionEnd };
544
+ }
545
+ }
546
+ function multilineStyle(textarea, arg) {
547
+ const { prefix, suffix, surroundWithNewlines } = arg;
548
+ let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
549
+ let selectionStart = textarea.selectionStart;
550
+ let selectionEnd = textarea.selectionEnd;
551
+ const lines = text.split('\n');
552
+ const undoStyle = lines.every(line => line.startsWith(prefix) && line.endsWith(suffix));
553
+ if (undoStyle) {
554
+ text = lines.map(line => line.slice(prefix.length, line.length - suffix.length)).join('\n');
555
+ selectionEnd = selectionStart + text.length;
556
+ }
557
+ else {
558
+ text = lines.map(line => prefix + line + suffix).join('\n');
559
+ if (surroundWithNewlines) {
560
+ const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
561
+ selectionStart += newlinesToAppend.length;
562
+ selectionEnd = selectionStart + text.length;
563
+ text = newlinesToAppend + text + newlinesToPrepend;
564
+ }
565
+ }
566
+ return { text, selectionStart, selectionEnd };
567
+ }
568
+ function undoOrderedListStyle(text) {
569
+ const lines = text.split('\n');
570
+ const orderedListRegex = /^\d+\.\s+/;
571
+ const shouldUndoOrderedList = lines.every(line => orderedListRegex.test(line));
572
+ let result = lines;
573
+ if (shouldUndoOrderedList) {
574
+ result = lines.map(line => line.replace(orderedListRegex, ''));
575
+ }
576
+ return {
577
+ text: result.join('\n'),
578
+ processed: shouldUndoOrderedList
579
+ };
580
+ }
581
+ function undoUnorderedListStyle(text) {
582
+ const lines = text.split('\n');
583
+ const unorderedListPrefix = '- ';
584
+ const shouldUndoUnorderedList = lines.every(line => line.startsWith(unorderedListPrefix));
585
+ let result = lines;
586
+ if (shouldUndoUnorderedList) {
587
+ result = lines.map(line => line.slice(unorderedListPrefix.length, line.length));
588
+ }
589
+ return {
590
+ text: result.join('\n'),
591
+ processed: shouldUndoUnorderedList
592
+ };
593
+ }
594
+ function makePrefix(index, unorderedList) {
595
+ if (unorderedList) {
596
+ return '- ';
597
+ }
598
+ else {
599
+ return `${index + 1}. `;
600
+ }
601
+ }
602
+ function clearExistingListStyle(style, selectedText) {
603
+ let undoResultOpositeList;
604
+ let undoResult;
605
+ let pristineText;
606
+ if (style.orderedList) {
607
+ undoResult = undoOrderedListStyle(selectedText);
608
+ undoResultOpositeList = undoUnorderedListStyle(undoResult.text);
609
+ pristineText = undoResultOpositeList.text;
610
+ }
611
+ else {
612
+ undoResult = undoUnorderedListStyle(selectedText);
613
+ undoResultOpositeList = undoOrderedListStyle(undoResult.text);
614
+ pristineText = undoResultOpositeList.text;
615
+ }
616
+ return [undoResult, undoResultOpositeList, pristineText];
617
+ }
618
+ function listStyle(textarea, style) {
619
+ const noInitialSelection = textarea.selectionStart === textarea.selectionEnd;
620
+ let selectionStart = textarea.selectionStart;
621
+ let selectionEnd = textarea.selectionEnd;
622
+ expandSelectionToLine(textarea);
623
+ const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
624
+ const [undoResult, undoResultOpositeList, pristineText] = clearExistingListStyle(style, selectedText);
625
+ const prefixedLines = pristineText.split('\n').map((value, index) => {
626
+ return `${makePrefix(index, style.unorderedList)}${value}`;
627
+ });
628
+ const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
629
+ return previousValue + makePrefix(currentIndex, style.unorderedList).length;
630
+ }, 0);
631
+ const totalPrefixLengthOpositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
632
+ return previousValue + makePrefix(currentIndex, !style.unorderedList).length;
633
+ }, 0);
634
+ if (undoResult.processed) {
635
+ if (noInitialSelection) {
636
+ selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0);
637
+ selectionEnd = selectionStart;
638
+ }
639
+ else {
640
+ selectionStart = textarea.selectionStart;
641
+ selectionEnd = textarea.selectionEnd - totalPrefixLength;
642
+ }
643
+ return { text: pristineText, selectionStart, selectionEnd };
644
+ }
645
+ const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
646
+ const text = newlinesToAppend + prefixedLines.join('\n') + newlinesToPrepend;
647
+ if (noInitialSelection) {
648
+ selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0);
649
+ selectionEnd = selectionStart;
650
+ }
651
+ else {
652
+ if (undoResultOpositeList.processed) {
653
+ selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
654
+ selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOpositeList;
655
+ }
656
+ else {
657
+ selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
658
+ selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength;
659
+ }
660
+ }
661
+ return { text, selectionStart, selectionEnd };
662
+ }
663
+ function applyStyle(button, stylesToApply) {
664
+ const toolbar = button.closest('markdown-toolbar');
665
+ if (!(toolbar instanceof MarkdownToolbarElement))
666
+ return;
667
+ const defaults = {
668
+ prefix: '',
669
+ suffix: '',
670
+ blockPrefix: '',
671
+ blockSuffix: '',
672
+ multiline: false,
673
+ replaceNext: '',
674
+ prefixSpace: false,
675
+ scanFor: '',
676
+ surroundWithNewlines: false,
677
+ orderedList: false,
678
+ unorderedList: false,
679
+ trimFirst: false
680
+ };
681
+ const style = Object.assign(Object.assign({}, defaults), stylesToApply);
682
+ const field = toolbar.field;
683
+ if (field) {
684
+ field.focus();
685
+ styleSelectedText(field, style);
686
+ }
687
+ }
688
+
689
+ /*
690
+ Stimulus 3.2.1
691
+ Copyright © 2023 Basecamp, LLC
692
+ */
693
+
694
+ function camelize(value) {
695
+ return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase());
696
+ }
697
+ function namespaceCamelize(value) {
698
+ return camelize(value.replace(/--/g, "-").replace(/__/g, "_"));
699
+ }
700
+ function capitalize(value) {
701
+ return value.charAt(0).toUpperCase() + value.slice(1);
702
+ }
703
+ function dasherize(value) {
704
+ return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`);
705
+ }
706
+
707
+ function isSomething(object) {
708
+ return object !== null && object !== undefined;
709
+ }
710
+ function hasProperty(object, property) {
711
+ return Object.prototype.hasOwnProperty.call(object, property);
712
+ }
713
+
714
+ function readInheritableStaticArrayValues(constructor, propertyName) {
715
+ const ancestors = getAncestorsForConstructor(constructor);
716
+ return Array.from(ancestors.reduce((values, constructor) => {
717
+ getOwnStaticArrayValues(constructor, propertyName).forEach((name) => values.add(name));
718
+ return values;
719
+ }, new Set()));
720
+ }
721
+ function readInheritableStaticObjectPairs(constructor, propertyName) {
722
+ const ancestors = getAncestorsForConstructor(constructor);
723
+ return ancestors.reduce((pairs, constructor) => {
724
+ pairs.push(...getOwnStaticObjectPairs(constructor, propertyName));
725
+ return pairs;
726
+ }, []);
727
+ }
728
+ function getAncestorsForConstructor(constructor) {
729
+ const ancestors = [];
730
+ while (constructor) {
731
+ ancestors.push(constructor);
732
+ constructor = Object.getPrototypeOf(constructor);
733
+ }
734
+ return ancestors.reverse();
735
+ }
736
+ function getOwnStaticArrayValues(constructor, propertyName) {
737
+ const definition = constructor[propertyName];
738
+ return Array.isArray(definition) ? definition : [];
739
+ }
740
+ function getOwnStaticObjectPairs(constructor, propertyName) {
741
+ const definition = constructor[propertyName];
742
+ return definition ? Object.keys(definition).map((key) => [key, definition[key]]) : [];
743
+ }
744
+ (() => {
745
+ function extendWithReflect(constructor) {
746
+ function extended() {
747
+ return Reflect.construct(constructor, arguments, new.target);
748
+ }
749
+ extended.prototype = Object.create(constructor.prototype, {
750
+ constructor: { value: extended },
751
+ });
752
+ Reflect.setPrototypeOf(extended, constructor);
753
+ return extended;
754
+ }
755
+ function testReflectExtension() {
756
+ const a = function () {
757
+ this.a.call(this);
758
+ };
759
+ const b = extendWithReflect(a);
760
+ b.prototype.a = function () { };
761
+ return new b();
762
+ }
763
+ try {
764
+ testReflectExtension();
765
+ return extendWithReflect;
766
+ }
767
+ catch (error) {
768
+ return (constructor) => class extended extends constructor {
769
+ };
770
+ }
771
+ })();
772
+
773
+ ({
774
+ controllerAttribute: "data-controller",
775
+ actionAttribute: "data-action",
776
+ targetAttribute: "data-target",
777
+ targetAttributeForScope: (identifier) => `data-${identifier}-target`,
778
+ outletAttributeForScope: (identifier, outlet) => `data-${identifier}-${outlet}-outlet`,
779
+ keyMappings: Object.assign(Object.assign({ enter: "Enter", tab: "Tab", esc: "Escape", space: " ", up: "ArrowUp", down: "ArrowDown", left: "ArrowLeft", right: "ArrowRight", home: "Home", end: "End", page_up: "PageUp", page_down: "PageDown" }, objectFromEntries("abcdefghijklmnopqrstuvwxyz".split("").map((c) => [c, c]))), objectFromEntries("0123456789".split("").map((n) => [n, n]))),
780
+ });
781
+ function objectFromEntries(array) {
782
+ return array.reduce((memo, [k, v]) => (Object.assign(Object.assign({}, memo), { [k]: v })), {});
783
+ }
784
+
785
+ function ClassPropertiesBlessing(constructor) {
786
+ const classes = readInheritableStaticArrayValues(constructor, "classes");
787
+ return classes.reduce((properties, classDefinition) => {
788
+ return Object.assign(properties, propertiesForClassDefinition(classDefinition));
789
+ }, {});
790
+ }
791
+ function propertiesForClassDefinition(key) {
792
+ return {
793
+ [`${key}Class`]: {
794
+ get() {
795
+ const { classes } = this;
796
+ if (classes.has(key)) {
797
+ return classes.get(key);
798
+ }
799
+ else {
800
+ const attribute = classes.getAttributeName(key);
801
+ throw new Error(`Missing attribute "${attribute}"`);
802
+ }
803
+ },
804
+ },
805
+ [`${key}Classes`]: {
806
+ get() {
807
+ return this.classes.getAll(key);
808
+ },
809
+ },
810
+ [`has${capitalize(key)}Class`]: {
811
+ get() {
812
+ return this.classes.has(key);
813
+ },
814
+ },
815
+ };
816
+ }
817
+
818
+ function OutletPropertiesBlessing(constructor) {
819
+ const outlets = readInheritableStaticArrayValues(constructor, "outlets");
820
+ return outlets.reduce((properties, outletDefinition) => {
821
+ return Object.assign(properties, propertiesForOutletDefinition(outletDefinition));
822
+ }, {});
823
+ }
824
+ function getOutletController(controller, element, identifier) {
825
+ return controller.application.getControllerForElementAndIdentifier(element, identifier);
826
+ }
827
+ function getControllerAndEnsureConnectedScope(controller, element, outletName) {
828
+ let outletController = getOutletController(controller, element, outletName);
829
+ if (outletController)
830
+ return outletController;
831
+ controller.application.router.proposeToConnectScopeForElementAndIdentifier(element, outletName);
832
+ outletController = getOutletController(controller, element, outletName);
833
+ if (outletController)
834
+ return outletController;
835
+ }
836
+ function propertiesForOutletDefinition(name) {
837
+ const camelizedName = namespaceCamelize(name);
838
+ return {
839
+ [`${camelizedName}Outlet`]: {
840
+ get() {
841
+ const outletElement = this.outlets.find(name);
842
+ const selector = this.outlets.getSelectorForOutletName(name);
843
+ if (outletElement) {
844
+ const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name);
845
+ if (outletController)
846
+ return outletController;
847
+ throw new Error(`The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`);
848
+ }
849
+ throw new Error(`Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`);
850
+ },
851
+ },
852
+ [`${camelizedName}Outlets`]: {
853
+ get() {
854
+ const outlets = this.outlets.findAll(name);
855
+ if (outlets.length > 0) {
856
+ return outlets
857
+ .map((outletElement) => {
858
+ const outletController = getControllerAndEnsureConnectedScope(this, outletElement, name);
859
+ if (outletController)
860
+ return outletController;
861
+ console.warn(`The provided outlet element is missing an outlet controller "${name}" instance for host controller "${this.identifier}"`, outletElement);
862
+ })
863
+ .filter((controller) => controller);
864
+ }
865
+ return [];
866
+ },
867
+ },
868
+ [`${camelizedName}OutletElement`]: {
869
+ get() {
870
+ const outletElement = this.outlets.find(name);
871
+ const selector = this.outlets.getSelectorForOutletName(name);
872
+ if (outletElement) {
873
+ return outletElement;
874
+ }
875
+ else {
876
+ throw new Error(`Missing outlet element "${name}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${selector}".`);
877
+ }
878
+ },
879
+ },
880
+ [`${camelizedName}OutletElements`]: {
881
+ get() {
882
+ return this.outlets.findAll(name);
883
+ },
884
+ },
885
+ [`has${capitalize(camelizedName)}Outlet`]: {
886
+ get() {
887
+ return this.outlets.has(name);
888
+ },
889
+ },
890
+ };
891
+ }
892
+
893
+ function TargetPropertiesBlessing(constructor) {
894
+ const targets = readInheritableStaticArrayValues(constructor, "targets");
895
+ return targets.reduce((properties, targetDefinition) => {
896
+ return Object.assign(properties, propertiesForTargetDefinition(targetDefinition));
897
+ }, {});
898
+ }
899
+ function propertiesForTargetDefinition(name) {
900
+ return {
901
+ [`${name}Target`]: {
902
+ get() {
903
+ const target = this.targets.find(name);
904
+ if (target) {
905
+ return target;
906
+ }
907
+ else {
908
+ throw new Error(`Missing target element "${name}" for "${this.identifier}" controller`);
909
+ }
910
+ },
911
+ },
912
+ [`${name}Targets`]: {
913
+ get() {
914
+ return this.targets.findAll(name);
915
+ },
916
+ },
917
+ [`has${capitalize(name)}Target`]: {
918
+ get() {
919
+ return this.targets.has(name);
920
+ },
921
+ },
922
+ };
923
+ }
924
+
925
+ function ValuePropertiesBlessing(constructor) {
926
+ const valueDefinitionPairs = readInheritableStaticObjectPairs(constructor, "values");
927
+ const propertyDescriptorMap = {
928
+ valueDescriptorMap: {
929
+ get() {
930
+ return valueDefinitionPairs.reduce((result, valueDefinitionPair) => {
931
+ const valueDescriptor = parseValueDefinitionPair(valueDefinitionPair, this.identifier);
932
+ const attributeName = this.data.getAttributeNameForKey(valueDescriptor.key);
933
+ return Object.assign(result, { [attributeName]: valueDescriptor });
934
+ }, {});
935
+ },
936
+ },
937
+ };
938
+ return valueDefinitionPairs.reduce((properties, valueDefinitionPair) => {
939
+ return Object.assign(properties, propertiesForValueDefinitionPair(valueDefinitionPair));
940
+ }, propertyDescriptorMap);
941
+ }
942
+ function propertiesForValueDefinitionPair(valueDefinitionPair, controller) {
943
+ const definition = parseValueDefinitionPair(valueDefinitionPair, controller);
944
+ const { key, name, reader: read, writer: write } = definition;
945
+ return {
946
+ [name]: {
947
+ get() {
948
+ const value = this.data.get(key);
949
+ if (value !== null) {
950
+ return read(value);
951
+ }
952
+ else {
953
+ return definition.defaultValue;
954
+ }
955
+ },
956
+ set(value) {
957
+ if (value === undefined) {
958
+ this.data.delete(key);
959
+ }
960
+ else {
961
+ this.data.set(key, write(value));
962
+ }
963
+ },
964
+ },
965
+ [`has${capitalize(name)}`]: {
966
+ get() {
967
+ return this.data.has(key) || definition.hasCustomDefaultValue;
968
+ },
969
+ },
970
+ };
971
+ }
972
+ function parseValueDefinitionPair([token, typeDefinition], controller) {
973
+ return valueDescriptorForTokenAndTypeDefinition({
974
+ controller,
975
+ token,
976
+ typeDefinition,
977
+ });
978
+ }
979
+ function parseValueTypeConstant(constant) {
980
+ switch (constant) {
981
+ case Array:
982
+ return "array";
983
+ case Boolean:
984
+ return "boolean";
985
+ case Number:
986
+ return "number";
987
+ case Object:
988
+ return "object";
989
+ case String:
990
+ return "string";
991
+ }
992
+ }
993
+ function parseValueTypeDefault(defaultValue) {
994
+ switch (typeof defaultValue) {
995
+ case "boolean":
996
+ return "boolean";
997
+ case "number":
998
+ return "number";
999
+ case "string":
1000
+ return "string";
1001
+ }
1002
+ if (Array.isArray(defaultValue))
1003
+ return "array";
1004
+ if (Object.prototype.toString.call(defaultValue) === "[object Object]")
1005
+ return "object";
1006
+ }
1007
+ function parseValueTypeObject(payload) {
1008
+ const { controller, token, typeObject } = payload;
1009
+ const hasType = isSomething(typeObject.type);
1010
+ const hasDefault = isSomething(typeObject.default);
1011
+ const fullObject = hasType && hasDefault;
1012
+ const onlyType = hasType && !hasDefault;
1013
+ const onlyDefault = !hasType && hasDefault;
1014
+ const typeFromObject = parseValueTypeConstant(typeObject.type);
1015
+ const typeFromDefaultValue = parseValueTypeDefault(payload.typeObject.default);
1016
+ if (onlyType)
1017
+ return typeFromObject;
1018
+ if (onlyDefault)
1019
+ return typeFromDefaultValue;
1020
+ if (typeFromObject !== typeFromDefaultValue) {
1021
+ const propertyPath = controller ? `${controller}.${token}` : token;
1022
+ throw new Error(`The specified default value for the Stimulus Value "${propertyPath}" must match the defined type "${typeFromObject}". The provided default value of "${typeObject.default}" is of type "${typeFromDefaultValue}".`);
1023
+ }
1024
+ if (fullObject)
1025
+ return typeFromObject;
1026
+ }
1027
+ function parseValueTypeDefinition(payload) {
1028
+ const { controller, token, typeDefinition } = payload;
1029
+ const typeObject = { controller, token, typeObject: typeDefinition };
1030
+ const typeFromObject = parseValueTypeObject(typeObject);
1031
+ const typeFromDefaultValue = parseValueTypeDefault(typeDefinition);
1032
+ const typeFromConstant = parseValueTypeConstant(typeDefinition);
1033
+ const type = typeFromObject || typeFromDefaultValue || typeFromConstant;
1034
+ if (type)
1035
+ return type;
1036
+ const propertyPath = controller ? `${controller}.${typeDefinition}` : token;
1037
+ throw new Error(`Unknown value type "${propertyPath}" for "${token}" value`);
1038
+ }
1039
+ function defaultValueForDefinition(typeDefinition) {
1040
+ const constant = parseValueTypeConstant(typeDefinition);
1041
+ if (constant)
1042
+ return defaultValuesByType[constant];
1043
+ const hasDefault = hasProperty(typeDefinition, "default");
1044
+ const hasType = hasProperty(typeDefinition, "type");
1045
+ const typeObject = typeDefinition;
1046
+ if (hasDefault)
1047
+ return typeObject.default;
1048
+ if (hasType) {
1049
+ const { type } = typeObject;
1050
+ const constantFromType = parseValueTypeConstant(type);
1051
+ if (constantFromType)
1052
+ return defaultValuesByType[constantFromType];
1053
+ }
1054
+ return typeDefinition;
1055
+ }
1056
+ function valueDescriptorForTokenAndTypeDefinition(payload) {
1057
+ const { token, typeDefinition } = payload;
1058
+ const key = `${dasherize(token)}-value`;
1059
+ const type = parseValueTypeDefinition(payload);
1060
+ return {
1061
+ type,
1062
+ key,
1063
+ name: camelize(key),
1064
+ get defaultValue() {
1065
+ return defaultValueForDefinition(typeDefinition);
1066
+ },
1067
+ get hasCustomDefaultValue() {
1068
+ return parseValueTypeDefault(typeDefinition) !== undefined;
1069
+ },
1070
+ reader: readers[type],
1071
+ writer: writers[type] || writers.default,
1072
+ };
1073
+ }
1074
+ const defaultValuesByType = {
1075
+ get array() {
1076
+ return [];
1077
+ },
1078
+ boolean: false,
1079
+ number: 0,
1080
+ get object() {
1081
+ return {};
1082
+ },
1083
+ string: "",
1084
+ };
1085
+ const readers = {
1086
+ array(value) {
1087
+ const array = JSON.parse(value);
1088
+ if (!Array.isArray(array)) {
1089
+ throw new TypeError(`expected value of type "array" but instead got value "${value}" of type "${parseValueTypeDefault(array)}"`);
1090
+ }
1091
+ return array;
1092
+ },
1093
+ boolean(value) {
1094
+ return !(value == "0" || String(value).toLowerCase() == "false");
1095
+ },
1096
+ number(value) {
1097
+ return Number(value.replace(/_/g, ""));
1098
+ },
1099
+ object(value) {
1100
+ const object = JSON.parse(value);
1101
+ if (object === null || typeof object != "object" || Array.isArray(object)) {
1102
+ throw new TypeError(`expected value of type "object" but instead got value "${value}" of type "${parseValueTypeDefault(object)}"`);
1103
+ }
1104
+ return object;
1105
+ },
1106
+ string(value) {
1107
+ return value;
1108
+ },
1109
+ };
1110
+ const writers = {
1111
+ default: writeString,
1112
+ array: writeJSON,
1113
+ object: writeJSON,
1114
+ };
1115
+ function writeJSON(value) {
1116
+ return JSON.stringify(value);
1117
+ }
1118
+ function writeString(value) {
1119
+ return `${value}`;
1120
+ }
1121
+
1122
+ class Controller {
1123
+ constructor(context) {
1124
+ this.context = context;
1125
+ }
1126
+ static get shouldLoad() {
1127
+ return true;
1128
+ }
1129
+ static afterLoad(_identifier, _application) {
1130
+ return;
1131
+ }
1132
+ get application() {
1133
+ return this.context.application;
1134
+ }
1135
+ get scope() {
1136
+ return this.context.scope;
1137
+ }
1138
+ get element() {
1139
+ return this.scope.element;
1140
+ }
1141
+ get identifier() {
1142
+ return this.scope.identifier;
1143
+ }
1144
+ get targets() {
1145
+ return this.scope.targets;
1146
+ }
1147
+ get outlets() {
1148
+ return this.scope.outlets;
1149
+ }
1150
+ get classes() {
1151
+ return this.scope.classes;
1152
+ }
1153
+ get data() {
1154
+ return this.scope.data;
1155
+ }
1156
+ initialize() {
1157
+ }
1158
+ connect() {
1159
+ }
1160
+ disconnect() {
1161
+ }
1162
+ dispatch(eventName, { target = this.element, detail = {}, prefix = this.identifier, bubbles = true, cancelable = true, } = {}) {
1163
+ const type = prefix ? `${prefix}:${eventName}` : eventName;
1164
+ const event = new CustomEvent(type, { detail, bubbles, cancelable });
1165
+ target.dispatchEvent(event);
1166
+ return event;
1167
+ }
1168
+ }
1169
+ Controller.blessings = [
1170
+ ClassPropertiesBlessing,
1171
+ TargetPropertiesBlessing,
1172
+ ValuePropertiesBlessing,
1173
+ OutletPropertiesBlessing,
1174
+ ];
1175
+ Controller.targets = [];
1176
+ Controller.outlets = [];
1177
+ Controller.values = {};
1178
+
1179
+ var sparkMd5 = {
1180
+ exports: {}
1181
+ };
1182
+
1183
+ (function(module, exports) {
1184
+ (function(factory) {
1185
+ {
1186
+ module.exports = factory();
1187
+ }
1188
+ })((function(undefined$1) {
1189
+ var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ];
1190
+ function md5cycle(x, k) {
1191
+ var a = x[0], b = x[1], c = x[2], d = x[3];
1192
+ a += (b & c | ~b & d) + k[0] - 680876936 | 0;
1193
+ a = (a << 7 | a >>> 25) + b | 0;
1194
+ d += (a & b | ~a & c) + k[1] - 389564586 | 0;
1195
+ d = (d << 12 | d >>> 20) + a | 0;
1196
+ c += (d & a | ~d & b) + k[2] + 606105819 | 0;
1197
+ c = (c << 17 | c >>> 15) + d | 0;
1198
+ b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
1199
+ b = (b << 22 | b >>> 10) + c | 0;
1200
+ a += (b & c | ~b & d) + k[4] - 176418897 | 0;
1201
+ a = (a << 7 | a >>> 25) + b | 0;
1202
+ d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
1203
+ d = (d << 12 | d >>> 20) + a | 0;
1204
+ c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
1205
+ c = (c << 17 | c >>> 15) + d | 0;
1206
+ b += (c & d | ~c & a) + k[7] - 45705983 | 0;
1207
+ b = (b << 22 | b >>> 10) + c | 0;
1208
+ a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
1209
+ a = (a << 7 | a >>> 25) + b | 0;
1210
+ d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
1211
+ d = (d << 12 | d >>> 20) + a | 0;
1212
+ c += (d & a | ~d & b) + k[10] - 42063 | 0;
1213
+ c = (c << 17 | c >>> 15) + d | 0;
1214
+ b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
1215
+ b = (b << 22 | b >>> 10) + c | 0;
1216
+ a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
1217
+ a = (a << 7 | a >>> 25) + b | 0;
1218
+ d += (a & b | ~a & c) + k[13] - 40341101 | 0;
1219
+ d = (d << 12 | d >>> 20) + a | 0;
1220
+ c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
1221
+ c = (c << 17 | c >>> 15) + d | 0;
1222
+ b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
1223
+ b = (b << 22 | b >>> 10) + c | 0;
1224
+ a += (b & d | c & ~d) + k[1] - 165796510 | 0;
1225
+ a = (a << 5 | a >>> 27) + b | 0;
1226
+ d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
1227
+ d = (d << 9 | d >>> 23) + a | 0;
1228
+ c += (d & b | a & ~b) + k[11] + 643717713 | 0;
1229
+ c = (c << 14 | c >>> 18) + d | 0;
1230
+ b += (c & a | d & ~a) + k[0] - 373897302 | 0;
1231
+ b = (b << 20 | b >>> 12) + c | 0;
1232
+ a += (b & d | c & ~d) + k[5] - 701558691 | 0;
1233
+ a = (a << 5 | a >>> 27) + b | 0;
1234
+ d += (a & c | b & ~c) + k[10] + 38016083 | 0;
1235
+ d = (d << 9 | d >>> 23) + a | 0;
1236
+ c += (d & b | a & ~b) + k[15] - 660478335 | 0;
1237
+ c = (c << 14 | c >>> 18) + d | 0;
1238
+ b += (c & a | d & ~a) + k[4] - 405537848 | 0;
1239
+ b = (b << 20 | b >>> 12) + c | 0;
1240
+ a += (b & d | c & ~d) + k[9] + 568446438 | 0;
1241
+ a = (a << 5 | a >>> 27) + b | 0;
1242
+ d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
1243
+ d = (d << 9 | d >>> 23) + a | 0;
1244
+ c += (d & b | a & ~b) + k[3] - 187363961 | 0;
1245
+ c = (c << 14 | c >>> 18) + d | 0;
1246
+ b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
1247
+ b = (b << 20 | b >>> 12) + c | 0;
1248
+ a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
1249
+ a = (a << 5 | a >>> 27) + b | 0;
1250
+ d += (a & c | b & ~c) + k[2] - 51403784 | 0;
1251
+ d = (d << 9 | d >>> 23) + a | 0;
1252
+ c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
1253
+ c = (c << 14 | c >>> 18) + d | 0;
1254
+ b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
1255
+ b = (b << 20 | b >>> 12) + c | 0;
1256
+ a += (b ^ c ^ d) + k[5] - 378558 | 0;
1257
+ a = (a << 4 | a >>> 28) + b | 0;
1258
+ d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
1259
+ d = (d << 11 | d >>> 21) + a | 0;
1260
+ c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
1261
+ c = (c << 16 | c >>> 16) + d | 0;
1262
+ b += (c ^ d ^ a) + k[14] - 35309556 | 0;
1263
+ b = (b << 23 | b >>> 9) + c | 0;
1264
+ a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
1265
+ a = (a << 4 | a >>> 28) + b | 0;
1266
+ d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
1267
+ d = (d << 11 | d >>> 21) + a | 0;
1268
+ c += (d ^ a ^ b) + k[7] - 155497632 | 0;
1269
+ c = (c << 16 | c >>> 16) + d | 0;
1270
+ b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
1271
+ b = (b << 23 | b >>> 9) + c | 0;
1272
+ a += (b ^ c ^ d) + k[13] + 681279174 | 0;
1273
+ a = (a << 4 | a >>> 28) + b | 0;
1274
+ d += (a ^ b ^ c) + k[0] - 358537222 | 0;
1275
+ d = (d << 11 | d >>> 21) + a | 0;
1276
+ c += (d ^ a ^ b) + k[3] - 722521979 | 0;
1277
+ c = (c << 16 | c >>> 16) + d | 0;
1278
+ b += (c ^ d ^ a) + k[6] + 76029189 | 0;
1279
+ b = (b << 23 | b >>> 9) + c | 0;
1280
+ a += (b ^ c ^ d) + k[9] - 640364487 | 0;
1281
+ a = (a << 4 | a >>> 28) + b | 0;
1282
+ d += (a ^ b ^ c) + k[12] - 421815835 | 0;
1283
+ d = (d << 11 | d >>> 21) + a | 0;
1284
+ c += (d ^ a ^ b) + k[15] + 530742520 | 0;
1285
+ c = (c << 16 | c >>> 16) + d | 0;
1286
+ b += (c ^ d ^ a) + k[2] - 995338651 | 0;
1287
+ b = (b << 23 | b >>> 9) + c | 0;
1288
+ a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
1289
+ a = (a << 6 | a >>> 26) + b | 0;
1290
+ d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
1291
+ d = (d << 10 | d >>> 22) + a | 0;
1292
+ c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
1293
+ c = (c << 15 | c >>> 17) + d | 0;
1294
+ b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
1295
+ b = (b << 21 | b >>> 11) + c | 0;
1296
+ a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
1297
+ a = (a << 6 | a >>> 26) + b | 0;
1298
+ d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
1299
+ d = (d << 10 | d >>> 22) + a | 0;
1300
+ c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
1301
+ c = (c << 15 | c >>> 17) + d | 0;
1302
+ b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
1303
+ b = (b << 21 | b >>> 11) + c | 0;
1304
+ a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
1305
+ a = (a << 6 | a >>> 26) + b | 0;
1306
+ d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
1307
+ d = (d << 10 | d >>> 22) + a | 0;
1308
+ c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
1309
+ c = (c << 15 | c >>> 17) + d | 0;
1310
+ b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
1311
+ b = (b << 21 | b >>> 11) + c | 0;
1312
+ a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
1313
+ a = (a << 6 | a >>> 26) + b | 0;
1314
+ d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
1315
+ d = (d << 10 | d >>> 22) + a | 0;
1316
+ c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
1317
+ c = (c << 15 | c >>> 17) + d | 0;
1318
+ b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
1319
+ b = (b << 21 | b >>> 11) + c | 0;
1320
+ x[0] = a + x[0] | 0;
1321
+ x[1] = b + x[1] | 0;
1322
+ x[2] = c + x[2] | 0;
1323
+ x[3] = d + x[3] | 0;
1324
+ }
1325
+ function md5blk(s) {
1326
+ var md5blks = [], i;
1327
+ for (i = 0; i < 64; i += 4) {
1328
+ md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
1329
+ }
1330
+ return md5blks;
1331
+ }
1332
+ function md5blk_array(a) {
1333
+ var md5blks = [], i;
1334
+ for (i = 0; i < 64; i += 4) {
1335
+ md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
1336
+ }
1337
+ return md5blks;
1338
+ }
1339
+ function md51(s) {
1340
+ var n = s.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
1341
+ for (i = 64; i <= n; i += 64) {
1342
+ md5cycle(state, md5blk(s.substring(i - 64, i)));
1343
+ }
1344
+ s = s.substring(i - 64);
1345
+ length = s.length;
1346
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
1347
+ for (i = 0; i < length; i += 1) {
1348
+ tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
1349
+ }
1350
+ tail[i >> 2] |= 128 << (i % 4 << 3);
1351
+ if (i > 55) {
1352
+ md5cycle(state, tail);
1353
+ for (i = 0; i < 16; i += 1) {
1354
+ tail[i] = 0;
1355
+ }
1356
+ }
1357
+ tmp = n * 8;
1358
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1359
+ lo = parseInt(tmp[2], 16);
1360
+ hi = parseInt(tmp[1], 16) || 0;
1361
+ tail[14] = lo;
1362
+ tail[15] = hi;
1363
+ md5cycle(state, tail);
1364
+ return state;
1365
+ }
1366
+ function md51_array(a) {
1367
+ var n = a.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
1368
+ for (i = 64; i <= n; i += 64) {
1369
+ md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
1370
+ }
1371
+ a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0);
1372
+ length = a.length;
1373
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
1374
+ for (i = 0; i < length; i += 1) {
1375
+ tail[i >> 2] |= a[i] << (i % 4 << 3);
1376
+ }
1377
+ tail[i >> 2] |= 128 << (i % 4 << 3);
1378
+ if (i > 55) {
1379
+ md5cycle(state, tail);
1380
+ for (i = 0; i < 16; i += 1) {
1381
+ tail[i] = 0;
1382
+ }
1383
+ }
1384
+ tmp = n * 8;
1385
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1386
+ lo = parseInt(tmp[2], 16);
1387
+ hi = parseInt(tmp[1], 16) || 0;
1388
+ tail[14] = lo;
1389
+ tail[15] = hi;
1390
+ md5cycle(state, tail);
1391
+ return state;
1392
+ }
1393
+ function rhex(n) {
1394
+ var s = "", j;
1395
+ for (j = 0; j < 4; j += 1) {
1396
+ s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
1397
+ }
1398
+ return s;
1399
+ }
1400
+ function hex(x) {
1401
+ var i;
1402
+ for (i = 0; i < x.length; i += 1) {
1403
+ x[i] = rhex(x[i]);
1404
+ }
1405
+ return x.join("");
1406
+ }
1407
+ if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ;
1408
+ if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) {
1409
+ (function() {
1410
+ function clamp(val, length) {
1411
+ val = val | 0 || 0;
1412
+ if (val < 0) {
1413
+ return Math.max(val + length, 0);
1414
+ }
1415
+ return Math.min(val, length);
1416
+ }
1417
+ ArrayBuffer.prototype.slice = function(from, to) {
1418
+ var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray;
1419
+ if (to !== undefined$1) {
1420
+ end = clamp(to, length);
1421
+ }
1422
+ if (begin > end) {
1423
+ return new ArrayBuffer(0);
1424
+ }
1425
+ num = end - begin;
1426
+ target = new ArrayBuffer(num);
1427
+ targetArray = new Uint8Array(target);
1428
+ sourceArray = new Uint8Array(this, begin, num);
1429
+ targetArray.set(sourceArray);
1430
+ return target;
1431
+ };
1432
+ })();
1433
+ }
1434
+ function toUtf8(str) {
1435
+ if (/[\u0080-\uFFFF]/.test(str)) {
1436
+ str = unescape(encodeURIComponent(str));
1437
+ }
1438
+ return str;
1439
+ }
1440
+ function utf8Str2ArrayBuffer(str, returnUInt8Array) {
1441
+ var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i;
1442
+ for (i = 0; i < length; i += 1) {
1443
+ arr[i] = str.charCodeAt(i);
1444
+ }
1445
+ return returnUInt8Array ? arr : buff;
1446
+ }
1447
+ function arrayBuffer2Utf8Str(buff) {
1448
+ return String.fromCharCode.apply(null, new Uint8Array(buff));
1449
+ }
1450
+ function concatenateArrayBuffers(first, second, returnUInt8Array) {
1451
+ var result = new Uint8Array(first.byteLength + second.byteLength);
1452
+ result.set(new Uint8Array(first));
1453
+ result.set(new Uint8Array(second), first.byteLength);
1454
+ return result ;
1455
+ }
1456
+ function hexToBinaryString(hex) {
1457
+ var bytes = [], length = hex.length, x;
1458
+ for (x = 0; x < length - 1; x += 2) {
1459
+ bytes.push(parseInt(hex.substr(x, 2), 16));
1460
+ }
1461
+ return String.fromCharCode.apply(String, bytes);
1462
+ }
1463
+ function SparkMD5() {
1464
+ this.reset();
1465
+ }
1466
+ SparkMD5.prototype.append = function(str) {
1467
+ this.appendBinary(toUtf8(str));
1468
+ return this;
1469
+ };
1470
+ SparkMD5.prototype.appendBinary = function(contents) {
1471
+ this._buff += contents;
1472
+ this._length += contents.length;
1473
+ var length = this._buff.length, i;
1474
+ for (i = 64; i <= length; i += 64) {
1475
+ md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
1476
+ }
1477
+ this._buff = this._buff.substring(i - 64);
1478
+ return this;
1479
+ };
1480
+ SparkMD5.prototype.end = function(raw) {
1481
+ var buff = this._buff, length = buff.length, i, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], ret;
1482
+ for (i = 0; i < length; i += 1) {
1483
+ tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3);
1484
+ }
1485
+ this._finish(tail, length);
1486
+ ret = hex(this._hash);
1487
+ if (raw) {
1488
+ ret = hexToBinaryString(ret);
1489
+ }
1490
+ this.reset();
1491
+ return ret;
1492
+ };
1493
+ SparkMD5.prototype.reset = function() {
1494
+ this._buff = "";
1495
+ this._length = 0;
1496
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
1497
+ return this;
1498
+ };
1499
+ SparkMD5.prototype.getState = function() {
1500
+ return {
1501
+ buff: this._buff,
1502
+ length: this._length,
1503
+ hash: this._hash.slice()
1504
+ };
1505
+ };
1506
+ SparkMD5.prototype.setState = function(state) {
1507
+ this._buff = state.buff;
1508
+ this._length = state.length;
1509
+ this._hash = state.hash;
1510
+ return this;
1511
+ };
1512
+ SparkMD5.prototype.destroy = function() {
1513
+ delete this._hash;
1514
+ delete this._buff;
1515
+ delete this._length;
1516
+ };
1517
+ SparkMD5.prototype._finish = function(tail, length) {
1518
+ var i = length, tmp, lo, hi;
1519
+ tail[i >> 2] |= 128 << (i % 4 << 3);
1520
+ if (i > 55) {
1521
+ md5cycle(this._hash, tail);
1522
+ for (i = 0; i < 16; i += 1) {
1523
+ tail[i] = 0;
1524
+ }
1525
+ }
1526
+ tmp = this._length * 8;
1527
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1528
+ lo = parseInt(tmp[2], 16);
1529
+ hi = parseInt(tmp[1], 16) || 0;
1530
+ tail[14] = lo;
1531
+ tail[15] = hi;
1532
+ md5cycle(this._hash, tail);
1533
+ };
1534
+ SparkMD5.hash = function(str, raw) {
1535
+ return SparkMD5.hashBinary(toUtf8(str), raw);
1536
+ };
1537
+ SparkMD5.hashBinary = function(content, raw) {
1538
+ var hash = md51(content), ret = hex(hash);
1539
+ return raw ? hexToBinaryString(ret) : ret;
1540
+ };
1541
+ SparkMD5.ArrayBuffer = function() {
1542
+ this.reset();
1543
+ };
1544
+ SparkMD5.ArrayBuffer.prototype.append = function(arr) {
1545
+ var buff = concatenateArrayBuffers(this._buff.buffer, arr), length = buff.length, i;
1546
+ this._length += arr.byteLength;
1547
+ for (i = 64; i <= length; i += 64) {
1548
+ md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
1549
+ }
1550
+ this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
1551
+ return this;
1552
+ };
1553
+ SparkMD5.ArrayBuffer.prototype.end = function(raw) {
1554
+ var buff = this._buff, length = buff.length, tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], i, ret;
1555
+ for (i = 0; i < length; i += 1) {
1556
+ tail[i >> 2] |= buff[i] << (i % 4 << 3);
1557
+ }
1558
+ this._finish(tail, length);
1559
+ ret = hex(this._hash);
1560
+ if (raw) {
1561
+ ret = hexToBinaryString(ret);
1562
+ }
1563
+ this.reset();
1564
+ return ret;
1565
+ };
1566
+ SparkMD5.ArrayBuffer.prototype.reset = function() {
1567
+ this._buff = new Uint8Array(0);
1568
+ this._length = 0;
1569
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
1570
+ return this;
1571
+ };
1572
+ SparkMD5.ArrayBuffer.prototype.getState = function() {
1573
+ var state = SparkMD5.prototype.getState.call(this);
1574
+ state.buff = arrayBuffer2Utf8Str(state.buff);
1575
+ return state;
1576
+ };
1577
+ SparkMD5.ArrayBuffer.prototype.setState = function(state) {
1578
+ state.buff = utf8Str2ArrayBuffer(state.buff, true);
1579
+ return SparkMD5.prototype.setState.call(this, state);
1580
+ };
1581
+ SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
1582
+ SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
1583
+ SparkMD5.ArrayBuffer.hash = function(arr, raw) {
1584
+ var hash = md51_array(new Uint8Array(arr)), ret = hex(hash);
1585
+ return raw ? hexToBinaryString(ret) : ret;
1586
+ };
1587
+ return SparkMD5;
1588
+ }));
1589
+ })(sparkMd5);
1590
+
1591
+ var SparkMD5 = sparkMd5.exports;
1592
+
1593
+ const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
1594
+
1595
+ class FileChecksum {
1596
+ static create(file, callback) {
1597
+ const instance = new FileChecksum(file);
1598
+ instance.create(callback);
1599
+ }
1600
+ constructor(file) {
1601
+ this.file = file;
1602
+ this.chunkSize = 2097152;
1603
+ this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
1604
+ this.chunkIndex = 0;
1605
+ }
1606
+ create(callback) {
1607
+ this.callback = callback;
1608
+ this.md5Buffer = new SparkMD5.ArrayBuffer;
1609
+ this.fileReader = new FileReader;
1610
+ this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event)));
1611
+ this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event)));
1612
+ this.readNextChunk();
1613
+ }
1614
+ fileReaderDidLoad(event) {
1615
+ this.md5Buffer.append(event.target.result);
1616
+ if (!this.readNextChunk()) {
1617
+ const binaryDigest = this.md5Buffer.end(true);
1618
+ const base64digest = btoa(binaryDigest);
1619
+ this.callback(null, base64digest);
1620
+ }
1621
+ }
1622
+ fileReaderDidError(event) {
1623
+ this.callback(`Error reading ${this.file.name}`);
1624
+ }
1625
+ readNextChunk() {
1626
+ if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) {
1627
+ const start = this.chunkIndex * this.chunkSize;
1628
+ const end = Math.min(start + this.chunkSize, this.file.size);
1629
+ const bytes = fileSlice.call(this.file, start, end);
1630
+ this.fileReader.readAsArrayBuffer(bytes);
1631
+ this.chunkIndex++;
1632
+ return true;
1633
+ } else {
1634
+ return false;
1635
+ }
1636
+ }
1637
+ }
1638
+
1639
+ function getMetaValue(name) {
1640
+ const element = findElement(document.head, `meta[name="${name}"]`);
1641
+ if (element) {
1642
+ return element.getAttribute("content");
1643
+ }
1644
+ }
1645
+
1646
+ function findElements(root, selector) {
1647
+ if (typeof root == "string") {
1648
+ selector = root;
1649
+ root = document;
1650
+ }
1651
+ const elements = root.querySelectorAll(selector);
1652
+ return toArray(elements);
1653
+ }
1654
+
1655
+ function findElement(root, selector) {
1656
+ if (typeof root == "string") {
1657
+ selector = root;
1658
+ root = document;
1659
+ }
1660
+ return root.querySelector(selector);
1661
+ }
1662
+
1663
+ function dispatchEvent(element, type, eventInit = {}) {
1664
+ const {disabled: disabled} = element;
1665
+ const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit;
1666
+ const event = document.createEvent("Event");
1667
+ event.initEvent(type, bubbles || true, cancelable || true);
1668
+ event.detail = detail || {};
1669
+ try {
1670
+ element.disabled = false;
1671
+ element.dispatchEvent(event);
1672
+ } finally {
1673
+ element.disabled = disabled;
1674
+ }
1675
+ return event;
1676
+ }
1677
+
1678
+ function toArray(value) {
1679
+ if (Array.isArray(value)) {
1680
+ return value;
1681
+ } else if (Array.from) {
1682
+ return Array.from(value);
1683
+ } else {
1684
+ return [].slice.call(value);
1685
+ }
1686
+ }
1687
+
1688
+ class BlobRecord {
1689
+ constructor(file, checksum, url, customHeaders = {}) {
1690
+ this.file = file;
1691
+ this.attributes = {
1692
+ filename: file.name,
1693
+ content_type: file.type || "application/octet-stream",
1694
+ byte_size: file.size,
1695
+ checksum: checksum
1696
+ };
1697
+ this.xhr = new XMLHttpRequest;
1698
+ this.xhr.open("POST", url, true);
1699
+ this.xhr.responseType = "json";
1700
+ this.xhr.setRequestHeader("Content-Type", "application/json");
1701
+ this.xhr.setRequestHeader("Accept", "application/json");
1702
+ this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
1703
+ Object.keys(customHeaders).forEach((headerKey => {
1704
+ this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
1705
+ }));
1706
+ const csrfToken = getMetaValue("csrf-token");
1707
+ if (csrfToken != undefined) {
1708
+ this.xhr.setRequestHeader("X-CSRF-Token", csrfToken);
1709
+ }
1710
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
1711
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
1712
+ }
1713
+ get status() {
1714
+ return this.xhr.status;
1715
+ }
1716
+ get response() {
1717
+ const {responseType: responseType, response: response} = this.xhr;
1718
+ if (responseType == "json") {
1719
+ return response;
1720
+ } else {
1721
+ return JSON.parse(response);
1722
+ }
1723
+ }
1724
+ create(callback) {
1725
+ this.callback = callback;
1726
+ this.xhr.send(JSON.stringify({
1727
+ blob: this.attributes
1728
+ }));
1729
+ }
1730
+ requestDidLoad(event) {
1731
+ if (this.status >= 200 && this.status < 300) {
1732
+ const {response: response} = this;
1733
+ const {direct_upload: direct_upload} = response;
1734
+ delete response.direct_upload;
1735
+ this.attributes = response;
1736
+ this.directUploadData = direct_upload;
1737
+ this.callback(null, this.toJSON());
1738
+ } else {
1739
+ this.requestDidError(event);
1740
+ }
1741
+ }
1742
+ requestDidError(event) {
1743
+ this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`);
1744
+ }
1745
+ toJSON() {
1746
+ const result = {};
1747
+ for (const key in this.attributes) {
1748
+ result[key] = this.attributes[key];
1749
+ }
1750
+ return result;
1751
+ }
1752
+ }
1753
+
1754
+ class BlobUpload {
1755
+ constructor(blob) {
1756
+ this.blob = blob;
1757
+ this.file = blob.file;
1758
+ const {url: url, headers: headers} = blob.directUploadData;
1759
+ this.xhr = new XMLHttpRequest;
1760
+ this.xhr.open("PUT", url, true);
1761
+ this.xhr.responseType = "text";
1762
+ for (const key in headers) {
1763
+ this.xhr.setRequestHeader(key, headers[key]);
1764
+ }
1765
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
1766
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
1767
+ }
1768
+ create(callback) {
1769
+ this.callback = callback;
1770
+ this.xhr.send(this.file.slice());
1771
+ }
1772
+ requestDidLoad(event) {
1773
+ const {status: status, response: response} = this.xhr;
1774
+ if (status >= 200 && status < 300) {
1775
+ this.callback(null, response);
1776
+ } else {
1777
+ this.requestDidError(event);
1778
+ }
1779
+ }
1780
+ requestDidError(event) {
1781
+ this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`);
1782
+ }
1783
+ }
1784
+
1785
+ let id = 0;
1786
+
1787
+ class DirectUpload {
1788
+ constructor(file, url, delegate, customHeaders = {}) {
1789
+ this.id = ++id;
1790
+ this.file = file;
1791
+ this.url = url;
1792
+ this.delegate = delegate;
1793
+ this.customHeaders = customHeaders;
1794
+ }
1795
+ create(callback) {
1796
+ FileChecksum.create(this.file, ((error, checksum) => {
1797
+ if (error) {
1798
+ callback(error);
1799
+ return;
1800
+ }
1801
+ const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders);
1802
+ notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr);
1803
+ blob.create((error => {
1804
+ if (error) {
1805
+ callback(error);
1806
+ } else {
1807
+ const upload = new BlobUpload(blob);
1808
+ notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr);
1809
+ upload.create((error => {
1810
+ if (error) {
1811
+ callback(error);
1812
+ } else {
1813
+ callback(null, blob.toJSON());
1814
+ }
1815
+ }));
1816
+ }
1817
+ }));
1818
+ }));
1819
+ }
1820
+ }
1821
+
1822
+ function notify(object, methodName, ...messages) {
1823
+ if (object && typeof object[methodName] == "function") {
1824
+ return object[methodName](...messages);
1825
+ }
1826
+ }
1827
+
1828
+ class DirectUploadController {
1829
+ constructor(input, file) {
1830
+ this.input = input;
1831
+ this.file = file;
1832
+ this.directUpload = new DirectUpload(this.file, this.url, this);
1833
+ this.dispatch("initialize");
1834
+ }
1835
+ start(callback) {
1836
+ const hiddenInput = document.createElement("input");
1837
+ hiddenInput.type = "hidden";
1838
+ hiddenInput.name = this.input.name;
1839
+ this.input.insertAdjacentElement("beforebegin", hiddenInput);
1840
+ this.dispatch("start");
1841
+ this.directUpload.create(((error, attributes) => {
1842
+ if (error) {
1843
+ hiddenInput.parentNode.removeChild(hiddenInput);
1844
+ this.dispatchError(error);
1845
+ } else {
1846
+ hiddenInput.value = attributes.signed_id;
1847
+ }
1848
+ this.dispatch("end");
1849
+ callback(error);
1850
+ }));
1851
+ }
1852
+ uploadRequestDidProgress(event) {
1853
+ const progress = event.loaded / event.total * 100;
1854
+ if (progress) {
1855
+ this.dispatch("progress", {
1856
+ progress: progress
1857
+ });
1858
+ }
1859
+ }
1860
+ get url() {
1861
+ return this.input.getAttribute("data-direct-upload-url");
1862
+ }
1863
+ dispatch(name, detail = {}) {
1864
+ detail.file = this.file;
1865
+ detail.id = this.directUpload.id;
1866
+ return dispatchEvent(this.input, `direct-upload:${name}`, {
1867
+ detail: detail
1868
+ });
1869
+ }
1870
+ dispatchError(error) {
1871
+ const event = this.dispatch("error", {
1872
+ error: error
1873
+ });
1874
+ if (!event.defaultPrevented) {
1875
+ alert(error);
1876
+ }
1877
+ }
1878
+ directUploadWillCreateBlobWithXHR(xhr) {
1879
+ this.dispatch("before-blob-request", {
1880
+ xhr: xhr
1881
+ });
1882
+ }
1883
+ directUploadWillStoreFileWithXHR(xhr) {
1884
+ this.dispatch("before-storage-request", {
1885
+ xhr: xhr
1886
+ });
1887
+ xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
1888
+ }
1889
+ }
1890
+
1891
+ const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])";
1892
+
1893
+ class DirectUploadsController {
1894
+ constructor(form) {
1895
+ this.form = form;
1896
+ this.inputs = findElements(form, inputSelector).filter((input => input.files.length));
1897
+ }
1898
+ start(callback) {
1899
+ const controllers = this.createDirectUploadControllers();
1900
+ const startNextController = () => {
1901
+ const controller = controllers.shift();
1902
+ if (controller) {
1903
+ controller.start((error => {
1904
+ if (error) {
1905
+ callback(error);
1906
+ this.dispatch("end");
1907
+ } else {
1908
+ startNextController();
1909
+ }
1910
+ }));
1911
+ } else {
1912
+ callback();
1913
+ this.dispatch("end");
1914
+ }
1915
+ };
1916
+ this.dispatch("start");
1917
+ startNextController();
1918
+ }
1919
+ createDirectUploadControllers() {
1920
+ const controllers = [];
1921
+ this.inputs.forEach((input => {
1922
+ toArray(input.files).forEach((file => {
1923
+ const controller = new DirectUploadController(input, file);
1924
+ controllers.push(controller);
1925
+ }));
1926
+ }));
1927
+ return controllers;
1928
+ }
1929
+ dispatch(name, detail = {}) {
1930
+ return dispatchEvent(this.form, `direct-uploads:${name}`, {
1931
+ detail: detail
1932
+ });
1933
+ }
1934
+ }
1935
+
1936
+ const processingAttribute = "data-direct-uploads-processing";
1937
+
1938
+ const submitButtonsByForm = new WeakMap;
1939
+
1940
+ let started = false;
1941
+
1942
+ function start() {
1943
+ if (!started) {
1944
+ started = true;
1945
+ document.addEventListener("click", didClick, true);
1946
+ document.addEventListener("submit", didSubmitForm, true);
1947
+ document.addEventListener("ajax:before", didSubmitRemoteElement);
1948
+ }
1949
+ }
1950
+
1951
+ function didClick(event) {
1952
+ const button = event.target.closest("button, input");
1953
+ if (button && button.type === "submit" && button.form) {
1954
+ submitButtonsByForm.set(button.form, button);
1955
+ }
1956
+ }
1957
+
1958
+ function didSubmitForm(event) {
1959
+ handleFormSubmissionEvent(event);
1960
+ }
1961
+
1962
+ function didSubmitRemoteElement(event) {
1963
+ if (event.target.tagName == "FORM") {
1964
+ handleFormSubmissionEvent(event);
1965
+ }
1966
+ }
1967
+
1968
+ function handleFormSubmissionEvent(event) {
1969
+ const form = event.target;
1970
+ if (form.hasAttribute(processingAttribute)) {
1971
+ event.preventDefault();
1972
+ return;
1973
+ }
1974
+ const controller = new DirectUploadsController(form);
1975
+ const {inputs: inputs} = controller;
1976
+ if (inputs.length) {
1977
+ event.preventDefault();
1978
+ form.setAttribute(processingAttribute, "");
1979
+ inputs.forEach(disable);
1980
+ controller.start((error => {
1981
+ form.removeAttribute(processingAttribute);
1982
+ if (error) {
1983
+ inputs.forEach(enable);
1984
+ } else {
1985
+ submitForm(form);
1986
+ }
1987
+ }));
1988
+ }
1989
+ }
1990
+
1991
+ function submitForm(form) {
1992
+ let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]");
1993
+ if (button) {
1994
+ const {disabled: disabled} = button;
1995
+ button.disabled = false;
1996
+ button.focus();
1997
+ button.click();
1998
+ button.disabled = disabled;
1999
+ } else {
2000
+ button = document.createElement("input");
2001
+ button.type = "submit";
2002
+ button.style.display = "none";
2003
+ form.appendChild(button);
2004
+ button.click();
2005
+ form.removeChild(button);
2006
+ }
2007
+ submitButtonsByForm.delete(form);
2008
+ }
2009
+
2010
+ function disable(input) {
2011
+ input.disabled = true;
2012
+ }
2013
+
2014
+ function enable(input) {
2015
+ input.disabled = false;
2016
+ }
2017
+
2018
+ function autostart() {
2019
+ if (window.ActiveStorage) {
2020
+ start();
2021
+ }
2022
+ }
2023
+
2024
+ setTimeout(autostart, 1);
2025
+
2026
+ class FetchResponse {
2027
+ constructor (response) {
2028
+ this.response = response;
2029
+ }
2030
+
2031
+ get statusCode () {
2032
+ return this.response.status
2033
+ }
2034
+
2035
+ get redirected () {
2036
+ return this.response.redirected
2037
+ }
2038
+
2039
+ get ok () {
2040
+ return this.response.ok
2041
+ }
2042
+
2043
+ get unauthenticated () {
2044
+ return this.statusCode === 401
2045
+ }
2046
+
2047
+ get unprocessableEntity () {
2048
+ return this.statusCode === 422
2049
+ }
2050
+
2051
+ get authenticationURL () {
2052
+ return this.response.headers.get('WWW-Authenticate')
2053
+ }
2054
+
2055
+ get contentType () {
2056
+ const contentType = this.response.headers.get('Content-Type') || '';
2057
+
2058
+ return contentType.replace(/;.*$/, '')
2059
+ }
2060
+
2061
+ get headers () {
2062
+ return this.response.headers
2063
+ }
2064
+
2065
+ get html () {
2066
+ if (this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)) {
2067
+ return this.text
2068
+ }
2069
+
2070
+ return Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`))
2071
+ }
2072
+
2073
+ get json () {
2074
+ if (this.contentType.match(/^application\/.*json$/)) {
2075
+ return this.responseJson || (this.responseJson = this.response.json())
2076
+ }
2077
+
2078
+ return Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`))
2079
+ }
2080
+
2081
+ get text () {
2082
+ return this.responseText || (this.responseText = this.response.text())
2083
+ }
2084
+
2085
+ get isTurboStream () {
2086
+ return this.contentType.match(/^text\/vnd\.turbo-stream\.html/)
2087
+ }
2088
+
2089
+ get isScript () {
2090
+ return this.contentType.match(/\b(?:java|ecma)script\b/)
2091
+ }
2092
+
2093
+ async renderTurboStream () {
2094
+ if (this.isTurboStream) {
2095
+ if (window.Turbo) {
2096
+ await window.Turbo.renderStreamMessage(await this.text);
2097
+ } else {
2098
+ console.warn('You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js');
2099
+ }
2100
+ } else {
2101
+ return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`))
2102
+ }
2103
+ }
2104
+
2105
+ async activeScript () {
2106
+ if (this.isScript) {
2107
+ const script = document.createElement('script');
2108
+ const metaTag = document.querySelector('meta[name=csp-nonce]');
2109
+ const nonce = metaTag && metaTag.content;
2110
+ if (nonce) { script.setAttribute('nonce', nonce); }
2111
+ script.innerHTML = await this.text;
2112
+ document.body.appendChild(script);
2113
+ } else {
2114
+ return Promise.reject(new Error(`Expected a Script response but got "${this.contentType}" instead`))
2115
+ }
2116
+ }
2117
+ }
2118
+
2119
+ class RequestInterceptor {
2120
+ static register (interceptor) {
2121
+ this.interceptor = interceptor;
2122
+ }
2123
+
2124
+ static get () {
2125
+ return this.interceptor
2126
+ }
2127
+
2128
+ static reset () {
2129
+ this.interceptor = undefined;
2130
+ }
2131
+ }
2132
+
2133
+ function getCookie (name) {
2134
+ const cookies = document.cookie ? document.cookie.split('; ') : [];
2135
+ const prefix = `${encodeURIComponent(name)}=`;
2136
+ const cookie = cookies.find(cookie => cookie.startsWith(prefix));
2137
+
2138
+ if (cookie) {
2139
+ const value = cookie.split('=').slice(1).join('=');
2140
+
2141
+ if (value) {
2142
+ return decodeURIComponent(value)
2143
+ }
2144
+ }
2145
+ }
2146
+
2147
+ function compact (object) {
2148
+ const result = {};
2149
+
2150
+ for (const key in object) {
2151
+ const value = object[key];
2152
+ if (value !== undefined) {
2153
+ result[key] = value;
2154
+ }
2155
+ }
2156
+
2157
+ return result
2158
+ }
2159
+
2160
+ function metaContent (name) {
2161
+ const element = document.head.querySelector(`meta[name="${name}"]`);
2162
+ return element && element.content
2163
+ }
2164
+
2165
+ function stringEntriesFromFormData (formData) {
2166
+ return [...formData].reduce((entries, [name, value]) => {
2167
+ return entries.concat(typeof value === 'string' ? [[name, value]] : [])
2168
+ }, [])
2169
+ }
2170
+
2171
+ function mergeEntries (searchParams, entries) {
2172
+ for (const [name, value] of entries) {
2173
+ if (value instanceof window.File) continue
2174
+
2175
+ if (searchParams.has(name) && !name.includes('[]')) {
2176
+ searchParams.delete(name);
2177
+ searchParams.set(name, value);
2178
+ } else {
2179
+ searchParams.append(name, value);
2180
+ }
2181
+ }
2182
+ }
2183
+
2184
+ class FetchRequest {
2185
+ constructor (method, url, options = {}) {
2186
+ this.method = method;
2187
+ this.options = options;
2188
+ this.originalUrl = url.toString();
2189
+ }
2190
+
2191
+ async perform () {
2192
+ try {
2193
+ const requestInterceptor = RequestInterceptor.get();
2194
+ if (requestInterceptor) {
2195
+ await requestInterceptor(this);
2196
+ }
2197
+ } catch (error) {
2198
+ console.error(error);
2199
+ }
2200
+
2201
+ const fetch = (this.responseKind === 'turbo-stream' && window.Turbo)
2202
+ ? window.Turbo.fetch
2203
+ : window.fetch;
2204
+
2205
+ const response = new FetchResponse(await fetch(this.url, this.fetchOptions));
2206
+
2207
+ if (response.unauthenticated && response.authenticationURL) {
2208
+ return Promise.reject(window.location.href = response.authenticationURL)
2209
+ }
2210
+
2211
+ if (response.isScript) {
2212
+ await response.activeScript();
2213
+ }
2214
+
2215
+ const responseStatusIsTurboStreamable = response.ok || response.unprocessableEntity;
2216
+
2217
+ if (responseStatusIsTurboStreamable && response.isTurboStream) {
2218
+ await response.renderTurboStream();
2219
+ }
2220
+
2221
+ return response
2222
+ }
2223
+
2224
+ addHeader (key, value) {
2225
+ const headers = this.additionalHeaders;
2226
+ headers[key] = value;
2227
+ this.options.headers = headers;
2228
+ }
2229
+
2230
+ sameHostname () {
2231
+ if (!this.originalUrl.startsWith('http:')) {
2232
+ return true
2233
+ }
2234
+
2235
+ try {
2236
+ return new URL(this.originalUrl).hostname === window.location.hostname
2237
+ } catch (_) {
2238
+ return true
2239
+ }
2240
+ }
2241
+
2242
+ get fetchOptions () {
2243
+ return {
2244
+ method: this.method.toUpperCase(),
2245
+ headers: this.headers,
2246
+ body: this.formattedBody,
2247
+ signal: this.signal,
2248
+ credentials: this.credentials,
2249
+ redirect: this.redirect
2250
+ }
2251
+ }
2252
+
2253
+ get headers () {
2254
+ const baseHeaders = {
2255
+ 'X-Requested-With': 'XMLHttpRequest',
2256
+ 'Content-Type': this.contentType,
2257
+ Accept: this.accept
2258
+ };
2259
+
2260
+ if (this.sameHostname()) {
2261
+ baseHeaders['X-CSRF-Token'] = this.csrfToken;
2262
+ }
2263
+
2264
+ return compact(
2265
+ Object.assign(baseHeaders, this.additionalHeaders)
2266
+ )
2267
+ }
2268
+
2269
+ get csrfToken () {
2270
+ return getCookie(metaContent('csrf-param')) || metaContent('csrf-token')
2271
+ }
2272
+
2273
+ get contentType () {
2274
+ if (this.options.contentType) {
2275
+ return this.options.contentType
2276
+ } else if (this.body == null || this.body instanceof window.FormData) {
2277
+ return undefined
2278
+ } else if (this.body instanceof window.File) {
2279
+ return this.body.type
2280
+ }
2281
+
2282
+ return 'application/json'
2283
+ }
2284
+
2285
+ get accept () {
2286
+ switch (this.responseKind) {
2287
+ case 'html':
2288
+ return 'text/html, application/xhtml+xml'
2289
+ case 'turbo-stream':
2290
+ return 'text/vnd.turbo-stream.html, text/html, application/xhtml+xml'
2291
+ case 'json':
2292
+ return 'application/json, application/vnd.api+json'
2293
+ case 'script':
2294
+ return 'text/javascript, application/javascript'
2295
+ default:
2296
+ return '*/*'
2297
+ }
2298
+ }
2299
+
2300
+ get body () {
2301
+ return this.options.body
2302
+ }
2303
+
2304
+ get query () {
2305
+ const originalQuery = (this.originalUrl.split('?')[1] || '').split('#')[0];
2306
+ const params = new URLSearchParams(originalQuery);
2307
+
2308
+ let requestQuery = this.options.query;
2309
+ if (requestQuery instanceof window.FormData) {
2310
+ requestQuery = stringEntriesFromFormData(requestQuery);
2311
+ } else if (requestQuery instanceof window.URLSearchParams) {
2312
+ requestQuery = requestQuery.entries();
2313
+ } else {
2314
+ requestQuery = Object.entries(requestQuery || {});
2315
+ }
2316
+
2317
+ mergeEntries(params, requestQuery);
2318
+
2319
+ const query = params.toString();
2320
+ return (query.length > 0 ? `?${query}` : '')
2321
+ }
2322
+
2323
+ get url () {
2324
+ return (this.originalUrl.split('?')[0]).split('#')[0] + this.query
2325
+ }
2326
+
2327
+ get responseKind () {
2328
+ return this.options.responseKind || 'html'
2329
+ }
2330
+
2331
+ get signal () {
2332
+ return this.options.signal
2333
+ }
2334
+
2335
+ get redirect () {
2336
+ return this.options.redirect || 'follow'
2337
+ }
2338
+
2339
+ get credentials () {
2340
+ return this.options.credentials || 'same-origin'
2341
+ }
2342
+
2343
+ get additionalHeaders () {
2344
+ return this.options.headers || {}
2345
+ }
2346
+
2347
+ get formattedBody () {
2348
+ const bodyIsAString = Object.prototype.toString.call(this.body) === '[object String]';
2349
+ const contentTypeIsJson = this.headers['Content-Type'] === 'application/json';
2350
+
2351
+ if (contentTypeIsJson && !bodyIsAString) {
2352
+ return JSON.stringify(this.body)
2353
+ }
2354
+
2355
+ return this.body
2356
+ }
2357
+ }
2358
+
2359
+ async function post (url, options) {
2360
+ const request = new FetchRequest('post', url, options);
2361
+ return request.perform()
2362
+ }
2363
+
2364
+ function insertText(textarea, text) {
2365
+ var _a, _b, _c;
2366
+ const before = textarea.value.slice(0, (_a = textarea.selectionStart) !== null && _a !== undefined ? _a : undefined);
2367
+ const after = textarea.value.slice((_b = textarea.selectionEnd) !== null && _b !== undefined ? _b : undefined);
2368
+ let canInsertText = true;
2369
+ textarea.contentEditable = 'true';
2370
+ try {
2371
+ canInsertText = document.execCommand('insertText', false, text);
2372
+ }
2373
+ catch (error) {
2374
+ canInsertText = false;
2375
+ }
2376
+ textarea.contentEditable = 'false';
2377
+ if (canInsertText && !textarea.value.slice(0, (_c = textarea.selectionStart) !== null && _c !== undefined ? _c : undefined).endsWith(text)) {
2378
+ canInsertText = false;
2379
+ }
2380
+ if (!canInsertText) {
2381
+ try {
2382
+ document.execCommand('ms-beginUndoUnit');
2383
+ }
2384
+ catch (e) {
2385
+ }
2386
+ textarea.value = before + text + after;
2387
+ try {
2388
+ document.execCommand('ms-endUndoUnit');
2389
+ }
2390
+ catch (e) {
2391
+ }
2392
+ textarea.dispatchEvent(new CustomEvent('change', { bubbles: true, cancelable: true }));
2393
+ }
2394
+ }
2395
+
2396
+ const skipFormattingMap = new WeakMap();
2397
+ function setSkipFormattingFlag(event) {
2398
+ const { currentTarget: el } = event;
2399
+ const isSkipFormattingKeys = event.code === 'KeyV' && (event.ctrlKey || event.metaKey) && event.shiftKey;
2400
+ if (isSkipFormattingKeys || (isSkipFormattingKeys && event.altKey)) {
2401
+ skipFormattingMap.set(el, true);
2402
+ }
2403
+ }
2404
+ function unsetSkipFormattedFlag(event) {
2405
+ const { currentTarget: el } = event;
2406
+ skipFormattingMap.delete(el);
2407
+ }
2408
+ function shouldSkipFormatting(el) {
2409
+ var _a;
2410
+ const shouldSkipFormattingState = (_a = skipFormattingMap.get(el)) !== null && _a !== undefined ? _a : false;
2411
+ return shouldSkipFormattingState;
2412
+ }
2413
+ function installAround(el, installCallbacks, optionConfig) {
2414
+ el.addEventListener('keydown', setSkipFormattingFlag);
2415
+ for (const installCallback of installCallbacks) {
2416
+ installCallback(el, optionConfig);
2417
+ }
2418
+ el.addEventListener('paste', unsetSkipFormattedFlag);
2419
+ }
2420
+ function uninstall$5(el) {
2421
+ el.removeEventListener('keydown', setSkipFormattingFlag);
2422
+ el.removeEventListener('paste', unsetSkipFormattedFlag);
2423
+ }
2424
+
2425
+ function install$4(el) {
2426
+ el.addEventListener('paste', onPaste$4);
2427
+ }
2428
+ function uninstall$4(el) {
2429
+ el.removeEventListener('paste', onPaste$4);
2430
+ }
2431
+ function onPaste$4(event) {
2432
+ const transfer = event.clipboardData;
2433
+ const { currentTarget: el } = event;
2434
+ if (shouldSkipFormatting(el))
2435
+ return;
2436
+ if (!transfer || !hasHTML(transfer))
2437
+ return;
2438
+ const field = event.currentTarget;
2439
+ if (!(field instanceof HTMLTextAreaElement))
2440
+ return;
2441
+ if (isWithinUserMention(field)) {
2442
+ return;
2443
+ }
2444
+ let plaintext = transfer.getData('text/plain');
2445
+ const textHTML = transfer.getData('text/html');
2446
+ const textHTMLClean = textHTML.replace(/\u00A0/g, ' ').replace(/\uC2A0/g, ' ');
2447
+ if (!textHTML)
2448
+ return;
2449
+ plaintext = plaintext.trim();
2450
+ if (!plaintext)
2451
+ return;
2452
+ const parser = new DOMParser();
2453
+ const doc = parser.parseFromString(textHTMLClean, 'text/html');
2454
+ const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ALL, node => node.parentNode && isLink(node.parentNode) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT);
2455
+ const markdown = convertToMarkdown(plaintext, walker);
2456
+ if (markdown === plaintext)
2457
+ return;
2458
+ event.stopPropagation();
2459
+ event.preventDefault();
2460
+ insertText(field, markdown);
2461
+ }
2462
+ function convertToMarkdown(plaintext, walker) {
2463
+ let currentNode = walker.firstChild();
2464
+ let markdown = plaintext;
2465
+ let markdownIgnoreBeforeIndex = 0;
2466
+ let index = 0;
2467
+ const NODE_LIMIT = 10000;
2468
+ while (currentNode && index < NODE_LIMIT) {
2469
+ index++;
2470
+ const text = isLink(currentNode)
2471
+ ? (currentNode.textContent || '').replace(/[\t\n\r ]+/g, ' ')
2472
+ : (currentNode === null || currentNode === undefined ? undefined : currentNode.wholeText) || '';
2473
+ if (isEmptyString(text)) {
2474
+ currentNode = walker.nextNode();
2475
+ continue;
2476
+ }
2477
+ if (!isLink(currentNode)) {
2478
+ markdownIgnoreBeforeIndex += text.replace(/[\t\n\r ]+/g, ' ').trimStart().length;
2479
+ currentNode = walker.nextNode();
2480
+ continue;
2481
+ }
2482
+ const markdownFoundIndex = markdown.indexOf(text, markdownIgnoreBeforeIndex);
2483
+ if (markdownFoundIndex >= 0) {
2484
+ const markdownLink = linkify$2(currentNode, text);
2485
+ markdown = markdown.slice(0, markdownFoundIndex) + markdownLink + markdown.slice(markdownFoundIndex + text.length);
2486
+ markdownIgnoreBeforeIndex = markdownFoundIndex + markdownLink.length;
2487
+ }
2488
+ currentNode = walker.nextNode();
2489
+ }
2490
+ return index === NODE_LIMIT ? plaintext : markdown;
2491
+ }
2492
+ function isWithinUserMention(textarea) {
2493
+ const selectionStart = textarea.selectionStart || 0;
2494
+ if (selectionStart === 0) {
2495
+ return false;
2496
+ }
2497
+ const previousChar = textarea.value.substring(selectionStart - 1, selectionStart);
2498
+ return previousChar === '@';
2499
+ }
2500
+ function isEmptyString(text) {
2501
+ return !text || (text === null || text === undefined ? undefined : text.trim().length) === 0;
2502
+ }
2503
+ function isLink(node) {
2504
+ var _a;
2505
+ return ((_a = node.tagName) === null || _a === undefined ? undefined : _a.toLowerCase()) === 'a' && node.hasAttribute('href');
2506
+ }
2507
+ function hasHTML(transfer) {
2508
+ return transfer.types.includes('text/html');
2509
+ }
2510
+ function linkify$2(element, label) {
2511
+ const url = element.href || '';
2512
+ let markdown = '';
2513
+ if (isUserMention(element) || isTeamMention(element)) {
2514
+ markdown = label;
2515
+ }
2516
+ else if (isSpecialLink(element) || areEqualLinks(url, label)) {
2517
+ markdown = url;
2518
+ }
2519
+ else {
2520
+ markdown = `[${label}](${url})`;
2521
+ }
2522
+ return markdown;
2523
+ }
2524
+ function isSpecialLink(link) {
2525
+ return (link.className.indexOf('commit-link') >= 0 ||
2526
+ (!!link.getAttribute('data-hovercard-type') && link.getAttribute('data-hovercard-type') !== 'user'));
2527
+ }
2528
+ function areEqualLinks(link1, link2) {
2529
+ link1 = link1.slice(-1) === '/' ? link1.slice(0, -1) : link1;
2530
+ link2 = link2.slice(-1) === '/' ? link2.slice(0, -1) : link2;
2531
+ return link1.toLowerCase() === link2.toLowerCase();
2532
+ }
2533
+ function isUserMention(link) {
2534
+ var _a;
2535
+ return ((_a = link.textContent) === null || _a === undefined ? undefined : _a.slice(0, 1)) === '@' && link.getAttribute('data-hovercard-type') === 'user';
2536
+ }
2537
+ function isTeamMention(link) {
2538
+ var _a;
2539
+ return ((_a = link.textContent) === null || _a === undefined ? undefined : _a.slice(0, 1)) === '@' && link.getAttribute('data-hovercard-type') === 'team';
2540
+ }
2541
+
2542
+ function install$3(el) {
2543
+ el.addEventListener('dragover', onDragover$1);
2544
+ el.addEventListener('drop', onDrop$1);
2545
+ el.addEventListener('paste', onPaste$3);
2546
+ }
2547
+ function uninstall$3(el) {
2548
+ el.removeEventListener('dragover', onDragover$1);
2549
+ el.removeEventListener('drop', onDrop$1);
2550
+ el.removeEventListener('paste', onPaste$3);
2551
+ }
2552
+ function onDrop$1(event) {
2553
+ const transfer = event.dataTransfer;
2554
+ if (!transfer)
2555
+ return;
2556
+ if (hasFile$1(transfer))
2557
+ return;
2558
+ if (!hasLink(transfer))
2559
+ return;
2560
+ const links = extractLinks(transfer);
2561
+ if (!links.some(isImageLink))
2562
+ return;
2563
+ event.stopPropagation();
2564
+ event.preventDefault();
2565
+ const field = event.currentTarget;
2566
+ if (!(field instanceof HTMLTextAreaElement))
2567
+ return;
2568
+ insertText(field, links.map(linkify$1).join(''));
2569
+ }
2570
+ function onDragover$1(event) {
2571
+ const transfer = event.dataTransfer;
2572
+ if (transfer)
2573
+ transfer.dropEffect = 'link';
2574
+ }
2575
+ function onPaste$3(event) {
2576
+ const { currentTarget: el } = event;
2577
+ if (shouldSkipFormatting(el))
2578
+ return;
2579
+ const transfer = event.clipboardData;
2580
+ if (!transfer || !hasLink(transfer))
2581
+ return;
2582
+ const links = extractLinks(transfer);
2583
+ if (!links.some(isImageLink))
2584
+ return;
2585
+ event.stopPropagation();
2586
+ event.preventDefault();
2587
+ const field = event.currentTarget;
2588
+ if (!(field instanceof HTMLTextAreaElement))
2589
+ return;
2590
+ insertText(field, links.map(linkify$1).join(''));
2591
+ }
2592
+ function linkify$1(link) {
2593
+ return isImageLink(link) ? `\n![](${link})\n` : link;
2594
+ }
2595
+ function hasFile$1(transfer) {
2596
+ return Array.from(transfer.types).indexOf('Files') >= 0;
2597
+ }
2598
+ function hasLink(transfer) {
2599
+ return Array.from(transfer.types).indexOf('text/uri-list') >= 0;
2600
+ }
2601
+ function extractLinks(transfer) {
2602
+ return (transfer.getData('text/uri-list') || '').split('\r\n');
2603
+ }
2604
+ const IMAGE_RE = /\.(gif|png|jpe?g)$/i;
2605
+ function isImageLink(url) {
2606
+ return IMAGE_RE.test(url);
2607
+ }
2608
+
2609
+ const pasteLinkAsPlainTextOverSelectedTextMap = new WeakMap();
2610
+ function install$2(el, optionConfig) {
2611
+ var _a;
2612
+ pasteLinkAsPlainTextOverSelectedTextMap.set(el, ((_a = optionConfig === null || optionConfig === undefined ? undefined : optionConfig.defaultPlainTextPaste) === null || _a === undefined ? undefined : _a.urlLinks) === true);
2613
+ el.addEventListener('paste', onPaste$2);
2614
+ }
2615
+ function uninstall$2(el) {
2616
+ el.removeEventListener('paste', onPaste$2);
2617
+ }
2618
+ function onPaste$2(event) {
2619
+ var _a;
2620
+ const { currentTarget: el } = event;
2621
+ const element = el;
2622
+ const shouldPasteAsPlainText = (_a = pasteLinkAsPlainTextOverSelectedTextMap.get(element)) !== null && _a !== undefined ? _a : false;
2623
+ const shouldSkipDefaultBehavior = shouldSkipFormatting(element);
2624
+ if ((!shouldPasteAsPlainText && shouldSkipDefaultBehavior) ||
2625
+ (shouldPasteAsPlainText && !shouldSkipDefaultBehavior)) {
2626
+ return;
2627
+ }
2628
+ const transfer = event.clipboardData;
2629
+ if (!transfer || !hasPlainText(transfer))
2630
+ return;
2631
+ const field = event.currentTarget;
2632
+ if (!(field instanceof HTMLTextAreaElement))
2633
+ return;
2634
+ const text = transfer.getData('text/plain');
2635
+ if (!text)
2636
+ return;
2637
+ if (!isURL(text))
2638
+ return;
2639
+ if (isWithinLink(field))
2640
+ return;
2641
+ const selectedText = field.value.substring(field.selectionStart, field.selectionEnd);
2642
+ if (!selectedText.length)
2643
+ return;
2644
+ if (isURL(selectedText.trim()))
2645
+ return;
2646
+ event.stopPropagation();
2647
+ event.preventDefault();
2648
+ insertText(field, linkify(selectedText, text.trim()));
2649
+ }
2650
+ function hasPlainText(transfer) {
2651
+ return Array.from(transfer.types).includes('text/plain');
2652
+ }
2653
+ function isWithinLink(textarea) {
2654
+ const selectionStart = textarea.selectionStart || 0;
2655
+ if (selectionStart > 1) {
2656
+ const previousChars = textarea.value.substring(selectionStart - 2, selectionStart);
2657
+ return previousChars === '](';
2658
+ }
2659
+ else {
2660
+ return false;
2661
+ }
2662
+ }
2663
+ function linkify(selectedText, text) {
2664
+ return `[${selectedText}](${text})`;
2665
+ }
2666
+ function isURL(url) {
2667
+ try {
2668
+ const parsedURL = new URL(url);
2669
+ return removeTrailingSlash(parsedURL.href).trim() === removeTrailingSlash(url).trim();
2670
+ }
2671
+ catch (_a) {
2672
+ return false;
2673
+ }
2674
+ }
2675
+ function removeTrailingSlash(url) {
2676
+ return url.endsWith('/') ? url.slice(0, url.length - 1) : url;
2677
+ }
2678
+
2679
+ function install$1(el) {
2680
+ el.addEventListener('dragover', onDragover);
2681
+ el.addEventListener('drop', onDrop);
2682
+ el.addEventListener('paste', onPaste$1);
2683
+ }
2684
+ function uninstall$1(el) {
2685
+ el.removeEventListener('dragover', onDragover);
2686
+ el.removeEventListener('drop', onDrop);
2687
+ el.removeEventListener('paste', onPaste$1);
2688
+ }
2689
+ function onDrop(event) {
2690
+ const transfer = event.dataTransfer;
2691
+ if (!transfer)
2692
+ return;
2693
+ if (hasFile(transfer))
2694
+ return;
2695
+ const textToPaste = generateText(transfer);
2696
+ if (!textToPaste)
2697
+ return;
2698
+ event.stopPropagation();
2699
+ event.preventDefault();
2700
+ const field = event.currentTarget;
2701
+ if (field instanceof HTMLTextAreaElement) {
2702
+ insertText(field, textToPaste);
2703
+ }
2704
+ }
2705
+ function onDragover(event) {
2706
+ const transfer = event.dataTransfer;
2707
+ if (transfer)
2708
+ transfer.dropEffect = 'copy';
2709
+ }
2710
+ function onPaste$1(event) {
2711
+ const { currentTarget: el } = event;
2712
+ if (shouldSkipFormatting(el))
2713
+ return;
2714
+ if (!event.clipboardData)
2715
+ return;
2716
+ const textToPaste = generateText(event.clipboardData);
2717
+ if (!textToPaste)
2718
+ return;
2719
+ event.stopPropagation();
2720
+ event.preventDefault();
2721
+ const field = event.currentTarget;
2722
+ if (field instanceof HTMLTextAreaElement) {
2723
+ insertText(field, textToPaste);
2724
+ }
2725
+ }
2726
+ function hasFile(transfer) {
2727
+ return Array.from(transfer.types).indexOf('Files') >= 0;
2728
+ }
2729
+ function columnText(column) {
2730
+ const noBreakSpace = '\u00A0';
2731
+ const text = (column.textContent || '').trim().replace(/\|/g, '\\|').replace(/\n/g, ' ');
2732
+ return text || noBreakSpace;
2733
+ }
2734
+ function tableHeaders(row) {
2735
+ return Array.from(row.querySelectorAll('td, th')).map(columnText);
2736
+ }
2737
+ function tableMarkdown(node) {
2738
+ const rows = Array.from(node.querySelectorAll('tr'));
2739
+ const firstRow = rows.shift();
2740
+ if (!firstRow)
2741
+ return '';
2742
+ const headers = tableHeaders(firstRow);
2743
+ const spacers = headers.map(() => '--');
2744
+ const header = `${headers.join(' | ')}\n${spacers.join(' | ')}\n`;
2745
+ const body = rows
2746
+ .map(row => {
2747
+ return Array.from(row.querySelectorAll('td')).map(columnText).join(' | ');
2748
+ })
2749
+ .join('\n');
2750
+ return `\n${header}${body}\n\n`;
2751
+ }
2752
+ function generateText(transfer) {
2753
+ if (Array.from(transfer.types).indexOf('text/html') === -1)
2754
+ return;
2755
+ const html = transfer.getData('text/html');
2756
+ if (!/<table/i.test(html))
2757
+ return;
2758
+ const start = html.substring(0, html.indexOf('<table'));
2759
+ const tableCloseIndex = html.lastIndexOf('</table>');
2760
+ if (!start || !tableCloseIndex)
2761
+ return;
2762
+ const end = html.substring(tableCloseIndex + 8);
2763
+ const parser = new DOMParser();
2764
+ const parsedDocument = parser.parseFromString(html, 'text/html');
2765
+ let table = parsedDocument.querySelector('table');
2766
+ table = !table || table.closest('[data-paste-markdown-skip]') ? null : table;
2767
+ if (!table)
2768
+ return;
2769
+ const formattedTable = tableMarkdown(table);
2770
+ if (!formattedTable)
2771
+ return;
2772
+ return [start, formattedTable, end].join('').replace(/<meta.*?>/, '');
2773
+ }
2774
+
2775
+ function install(el) {
2776
+ el.addEventListener('paste', onPaste);
2777
+ }
2778
+ function uninstall(el) {
2779
+ el.removeEventListener('paste', onPaste);
2780
+ }
2781
+ function onPaste(event) {
2782
+ const { currentTarget: el } = event;
2783
+ if (shouldSkipFormatting(el))
2784
+ return;
2785
+ const transfer = event.clipboardData;
2786
+ if (!transfer || !hasMarkdown(transfer))
2787
+ return;
2788
+ const field = event.currentTarget;
2789
+ if (!(field instanceof HTMLTextAreaElement))
2790
+ return;
2791
+ const text = transfer.getData('text/x-gfm');
2792
+ if (!text)
2793
+ return;
2794
+ event.stopPropagation();
2795
+ event.preventDefault();
2796
+ insertText(field, text);
2797
+ }
2798
+ function hasMarkdown(transfer) {
2799
+ return Array.from(transfer.types).indexOf('text/x-gfm') >= 0;
2800
+ }
2801
+
2802
+ function subscribe(el, optionConfig) {
2803
+ installAround(el, [install$1, install$3, install$2, install, install$4], optionConfig);
2804
+ return {
2805
+ unsubscribe: () => {
2806
+ uninstall$5(el);
2807
+ uninstall$1(el);
2808
+ uninstall$4(el);
2809
+ uninstall$3(el);
2810
+ uninstall$2(el);
2811
+ uninstall(el);
2812
+ },
2813
+ };
2814
+ }
2815
+
2816
+ /* eslint-disable camelcase */
2817
+
2818
+ // upload code from Jeremy Smith's blog post
2819
+ // https://hybrd.co/posts/github-issue-style-file-uploader-using-stimulus-and-active-storage
2820
+
2821
+ // Connects to data-controller="marksmith"
2822
+ class marksmith_controller extends Controller {
2823
+ static values = {
2824
+ attachUrl: String,
2825
+ previewUrl: String,
2826
+ extraPreviewParams: { type: Object, default: {} },
2827
+ fieldId: String,
2828
+ }
2829
+
2830
+ static targets = ['fieldContainer', 'fieldElement', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
2831
+
2832
+ connect() {
2833
+ subscribe(this.fieldContainerTarget, { defaultPlainTextPaste: { urlLinks: true } });
2834
+ }
2835
+
2836
+ switchToWrite(event) {
2837
+ event.preventDefault();
2838
+
2839
+ // toggle buttons
2840
+ this.writeTabButtonTarget.classList.add('ms:hidden');
2841
+ this.previewTabButtonTarget.classList.remove('ms:hidden');
2842
+
2843
+ // toggle write/preview buttons
2844
+ this.fieldContainerTarget.classList.remove('ms:hidden');
2845
+ this.previewElementTarget.classList.add('ms:hidden');
2846
+
2847
+ // toggle the toolbar back
2848
+ this.toolbarTarget.classList.remove('ms:hidden');
2849
+ }
2850
+
2851
+ switchToPreview(event) {
2852
+ event.preventDefault();
2853
+
2854
+ post(this.previewUrlValue, {
2855
+ body: {
2856
+ body: this.fieldElementTarget.value,
2857
+ element_id: this.previewElementTarget.id,
2858
+ extra_params: this.extraPreviewParamsValue,
2859
+ },
2860
+ responseKind: 'turbo-stream',
2861
+ });
2862
+
2863
+ // set the min height to the field element height
2864
+ this.previewElementTarget.style.minHeight = `${this.fieldElementTarget.offsetHeight}px`;
2865
+
2866
+ // toggle buttons
2867
+ this.writeTabButtonTarget.classList.remove('ms:hidden');
2868
+ this.previewTabButtonTarget.classList.add('ms:hidden');
2869
+
2870
+ // toggle elements
2871
+ this.fieldContainerTarget.classList.add('ms:hidden');
2872
+ this.previewElementTarget.classList.remove('ms:hidden');
2873
+
2874
+ // toggle the toolbar
2875
+ this.toolbarTarget.classList.add('ms:hidden');
2876
+ }
2877
+
2878
+ dropUpload(event) {
2879
+ event.preventDefault();
2880
+ this.uploadFiles(event.dataTransfer.files);
2881
+ }
2882
+
2883
+ pasteUpload(event) {
2884
+ if (!event.clipboardData.files.length) return
2885
+
2886
+ event.preventDefault();
2887
+ this.uploadFiles(event.clipboardData.files);
2888
+ }
2889
+
2890
+ buttonUpload(event) {
2891
+ event.preventDefault();
2892
+ // Create a hidden file input and trigger it
2893
+ const fileInput = document.createElement('input');
2894
+ fileInput.type = 'file';
2895
+ fileInput.multiple = true;
2896
+ fileInput.accept = 'image/*,.pdf,.doc,.docx,.txt';
2897
+
2898
+ fileInput.addEventListener('change', (e) => {
2899
+ this.uploadFiles(e.target.files);
2900
+ });
2901
+
2902
+ fileInput.click();
2903
+ }
2904
+
2905
+ uploadFiles(files) {
2906
+ Array.from(files).forEach((file) => this.uploadFile(file));
2907
+ }
2908
+
2909
+ uploadFile(file) {
2910
+ const upload = new DirectUpload(file, this.attachUrlValue);
2911
+
2912
+ upload.create((error, blob) => {
2913
+ if (error) {
2914
+ console.log('Error', error);
2915
+ } else {
2916
+ const text = this.markdownLink(blob);
2917
+ const start = this.fieldElementTarget.selectionStart;
2918
+ const end = this.fieldElementTarget.selectionEnd;
2919
+ this.fieldElementTarget.setRangeText(text, start, end);
2920
+ }
2921
+ });
2922
+ }
2923
+
2924
+ markdownLink(blob) {
2925
+ const { filename } = blob;
2926
+ const url = `/rails/active_storage/blobs/${blob.signed_id}/${filename}`;
2927
+ const prefix = (this.isImage(blob.content_type) ? '!' : '');
2928
+
2929
+ return `${prefix}[${filename}](${url})\n`
2930
+ }
2931
+
2932
+ isImage(contentType) {
2933
+ return ['image/jpeg', 'image/gif', 'image/png'].includes(contentType)
2934
+ }
2935
+ }
2936
+
2937
+ return marksmith_controller;
2938
+
2939
+ })();