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,2449 @@
1
+ /*!
2
+ Marksmith 0.0.15
3
+ */
4
+ var MarksmithController = (function (stimulus) {
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
+ var sparkMd5 = {
690
+ exports: {}
691
+ };
692
+
693
+ (function(module, exports) {
694
+ (function(factory) {
695
+ {
696
+ module.exports = factory();
697
+ }
698
+ })((function(undefined$1) {
699
+ var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ];
700
+ function md5cycle(x, k) {
701
+ var a = x[0], b = x[1], c = x[2], d = x[3];
702
+ a += (b & c | ~b & d) + k[0] - 680876936 | 0;
703
+ a = (a << 7 | a >>> 25) + b | 0;
704
+ d += (a & b | ~a & c) + k[1] - 389564586 | 0;
705
+ d = (d << 12 | d >>> 20) + a | 0;
706
+ c += (d & a | ~d & b) + k[2] + 606105819 | 0;
707
+ c = (c << 17 | c >>> 15) + d | 0;
708
+ b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
709
+ b = (b << 22 | b >>> 10) + c | 0;
710
+ a += (b & c | ~b & d) + k[4] - 176418897 | 0;
711
+ a = (a << 7 | a >>> 25) + b | 0;
712
+ d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
713
+ d = (d << 12 | d >>> 20) + a | 0;
714
+ c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
715
+ c = (c << 17 | c >>> 15) + d | 0;
716
+ b += (c & d | ~c & a) + k[7] - 45705983 | 0;
717
+ b = (b << 22 | b >>> 10) + c | 0;
718
+ a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
719
+ a = (a << 7 | a >>> 25) + b | 0;
720
+ d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
721
+ d = (d << 12 | d >>> 20) + a | 0;
722
+ c += (d & a | ~d & b) + k[10] - 42063 | 0;
723
+ c = (c << 17 | c >>> 15) + d | 0;
724
+ b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
725
+ b = (b << 22 | b >>> 10) + c | 0;
726
+ a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
727
+ a = (a << 7 | a >>> 25) + b | 0;
728
+ d += (a & b | ~a & c) + k[13] - 40341101 | 0;
729
+ d = (d << 12 | d >>> 20) + a | 0;
730
+ c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
731
+ c = (c << 17 | c >>> 15) + d | 0;
732
+ b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
733
+ b = (b << 22 | b >>> 10) + c | 0;
734
+ a += (b & d | c & ~d) + k[1] - 165796510 | 0;
735
+ a = (a << 5 | a >>> 27) + b | 0;
736
+ d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
737
+ d = (d << 9 | d >>> 23) + a | 0;
738
+ c += (d & b | a & ~b) + k[11] + 643717713 | 0;
739
+ c = (c << 14 | c >>> 18) + d | 0;
740
+ b += (c & a | d & ~a) + k[0] - 373897302 | 0;
741
+ b = (b << 20 | b >>> 12) + c | 0;
742
+ a += (b & d | c & ~d) + k[5] - 701558691 | 0;
743
+ a = (a << 5 | a >>> 27) + b | 0;
744
+ d += (a & c | b & ~c) + k[10] + 38016083 | 0;
745
+ d = (d << 9 | d >>> 23) + a | 0;
746
+ c += (d & b | a & ~b) + k[15] - 660478335 | 0;
747
+ c = (c << 14 | c >>> 18) + d | 0;
748
+ b += (c & a | d & ~a) + k[4] - 405537848 | 0;
749
+ b = (b << 20 | b >>> 12) + c | 0;
750
+ a += (b & d | c & ~d) + k[9] + 568446438 | 0;
751
+ a = (a << 5 | a >>> 27) + b | 0;
752
+ d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
753
+ d = (d << 9 | d >>> 23) + a | 0;
754
+ c += (d & b | a & ~b) + k[3] - 187363961 | 0;
755
+ c = (c << 14 | c >>> 18) + d | 0;
756
+ b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
757
+ b = (b << 20 | b >>> 12) + c | 0;
758
+ a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
759
+ a = (a << 5 | a >>> 27) + b | 0;
760
+ d += (a & c | b & ~c) + k[2] - 51403784 | 0;
761
+ d = (d << 9 | d >>> 23) + a | 0;
762
+ c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
763
+ c = (c << 14 | c >>> 18) + d | 0;
764
+ b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
765
+ b = (b << 20 | b >>> 12) + c | 0;
766
+ a += (b ^ c ^ d) + k[5] - 378558 | 0;
767
+ a = (a << 4 | a >>> 28) + b | 0;
768
+ d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
769
+ d = (d << 11 | d >>> 21) + a | 0;
770
+ c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
771
+ c = (c << 16 | c >>> 16) + d | 0;
772
+ b += (c ^ d ^ a) + k[14] - 35309556 | 0;
773
+ b = (b << 23 | b >>> 9) + c | 0;
774
+ a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
775
+ a = (a << 4 | a >>> 28) + b | 0;
776
+ d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
777
+ d = (d << 11 | d >>> 21) + a | 0;
778
+ c += (d ^ a ^ b) + k[7] - 155497632 | 0;
779
+ c = (c << 16 | c >>> 16) + d | 0;
780
+ b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
781
+ b = (b << 23 | b >>> 9) + c | 0;
782
+ a += (b ^ c ^ d) + k[13] + 681279174 | 0;
783
+ a = (a << 4 | a >>> 28) + b | 0;
784
+ d += (a ^ b ^ c) + k[0] - 358537222 | 0;
785
+ d = (d << 11 | d >>> 21) + a | 0;
786
+ c += (d ^ a ^ b) + k[3] - 722521979 | 0;
787
+ c = (c << 16 | c >>> 16) + d | 0;
788
+ b += (c ^ d ^ a) + k[6] + 76029189 | 0;
789
+ b = (b << 23 | b >>> 9) + c | 0;
790
+ a += (b ^ c ^ d) + k[9] - 640364487 | 0;
791
+ a = (a << 4 | a >>> 28) + b | 0;
792
+ d += (a ^ b ^ c) + k[12] - 421815835 | 0;
793
+ d = (d << 11 | d >>> 21) + a | 0;
794
+ c += (d ^ a ^ b) + k[15] + 530742520 | 0;
795
+ c = (c << 16 | c >>> 16) + d | 0;
796
+ b += (c ^ d ^ a) + k[2] - 995338651 | 0;
797
+ b = (b << 23 | b >>> 9) + c | 0;
798
+ a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
799
+ a = (a << 6 | a >>> 26) + b | 0;
800
+ d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
801
+ d = (d << 10 | d >>> 22) + a | 0;
802
+ c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
803
+ c = (c << 15 | c >>> 17) + d | 0;
804
+ b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
805
+ b = (b << 21 | b >>> 11) + c | 0;
806
+ a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
807
+ a = (a << 6 | a >>> 26) + b | 0;
808
+ d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
809
+ d = (d << 10 | d >>> 22) + a | 0;
810
+ c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
811
+ c = (c << 15 | c >>> 17) + d | 0;
812
+ b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
813
+ b = (b << 21 | b >>> 11) + c | 0;
814
+ a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
815
+ a = (a << 6 | a >>> 26) + b | 0;
816
+ d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
817
+ d = (d << 10 | d >>> 22) + a | 0;
818
+ c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
819
+ c = (c << 15 | c >>> 17) + d | 0;
820
+ b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
821
+ b = (b << 21 | b >>> 11) + c | 0;
822
+ a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
823
+ a = (a << 6 | a >>> 26) + b | 0;
824
+ d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
825
+ d = (d << 10 | d >>> 22) + a | 0;
826
+ c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
827
+ c = (c << 15 | c >>> 17) + d | 0;
828
+ b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
829
+ b = (b << 21 | b >>> 11) + c | 0;
830
+ x[0] = a + x[0] | 0;
831
+ x[1] = b + x[1] | 0;
832
+ x[2] = c + x[2] | 0;
833
+ x[3] = d + x[3] | 0;
834
+ }
835
+ function md5blk(s) {
836
+ var md5blks = [], i;
837
+ for (i = 0; i < 64; i += 4) {
838
+ md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
839
+ }
840
+ return md5blks;
841
+ }
842
+ function md5blk_array(a) {
843
+ var md5blks = [], i;
844
+ for (i = 0; i < 64; i += 4) {
845
+ md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
846
+ }
847
+ return md5blks;
848
+ }
849
+ function md51(s) {
850
+ var n = s.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
851
+ for (i = 64; i <= n; i += 64) {
852
+ md5cycle(state, md5blk(s.substring(i - 64, i)));
853
+ }
854
+ s = s.substring(i - 64);
855
+ length = s.length;
856
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
857
+ for (i = 0; i < length; i += 1) {
858
+ tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
859
+ }
860
+ tail[i >> 2] |= 128 << (i % 4 << 3);
861
+ if (i > 55) {
862
+ md5cycle(state, tail);
863
+ for (i = 0; i < 16; i += 1) {
864
+ tail[i] = 0;
865
+ }
866
+ }
867
+ tmp = n * 8;
868
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
869
+ lo = parseInt(tmp[2], 16);
870
+ hi = parseInt(tmp[1], 16) || 0;
871
+ tail[14] = lo;
872
+ tail[15] = hi;
873
+ md5cycle(state, tail);
874
+ return state;
875
+ }
876
+ function md51_array(a) {
877
+ var n = a.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
878
+ for (i = 64; i <= n; i += 64) {
879
+ md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
880
+ }
881
+ a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0);
882
+ length = a.length;
883
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
884
+ for (i = 0; i < length; i += 1) {
885
+ tail[i >> 2] |= a[i] << (i % 4 << 3);
886
+ }
887
+ tail[i >> 2] |= 128 << (i % 4 << 3);
888
+ if (i > 55) {
889
+ md5cycle(state, tail);
890
+ for (i = 0; i < 16; i += 1) {
891
+ tail[i] = 0;
892
+ }
893
+ }
894
+ tmp = n * 8;
895
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
896
+ lo = parseInt(tmp[2], 16);
897
+ hi = parseInt(tmp[1], 16) || 0;
898
+ tail[14] = lo;
899
+ tail[15] = hi;
900
+ md5cycle(state, tail);
901
+ return state;
902
+ }
903
+ function rhex(n) {
904
+ var s = "", j;
905
+ for (j = 0; j < 4; j += 1) {
906
+ s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
907
+ }
908
+ return s;
909
+ }
910
+ function hex(x) {
911
+ var i;
912
+ for (i = 0; i < x.length; i += 1) {
913
+ x[i] = rhex(x[i]);
914
+ }
915
+ return x.join("");
916
+ }
917
+ if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ;
918
+ if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) {
919
+ (function() {
920
+ function clamp(val, length) {
921
+ val = val | 0 || 0;
922
+ if (val < 0) {
923
+ return Math.max(val + length, 0);
924
+ }
925
+ return Math.min(val, length);
926
+ }
927
+ ArrayBuffer.prototype.slice = function(from, to) {
928
+ var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray;
929
+ if (to !== undefined$1) {
930
+ end = clamp(to, length);
931
+ }
932
+ if (begin > end) {
933
+ return new ArrayBuffer(0);
934
+ }
935
+ num = end - begin;
936
+ target = new ArrayBuffer(num);
937
+ targetArray = new Uint8Array(target);
938
+ sourceArray = new Uint8Array(this, begin, num);
939
+ targetArray.set(sourceArray);
940
+ return target;
941
+ };
942
+ })();
943
+ }
944
+ function toUtf8(str) {
945
+ if (/[\u0080-\uFFFF]/.test(str)) {
946
+ str = unescape(encodeURIComponent(str));
947
+ }
948
+ return str;
949
+ }
950
+ function utf8Str2ArrayBuffer(str, returnUInt8Array) {
951
+ var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i;
952
+ for (i = 0; i < length; i += 1) {
953
+ arr[i] = str.charCodeAt(i);
954
+ }
955
+ return returnUInt8Array ? arr : buff;
956
+ }
957
+ function arrayBuffer2Utf8Str(buff) {
958
+ return String.fromCharCode.apply(null, new Uint8Array(buff));
959
+ }
960
+ function concatenateArrayBuffers(first, second, returnUInt8Array) {
961
+ var result = new Uint8Array(first.byteLength + second.byteLength);
962
+ result.set(new Uint8Array(first));
963
+ result.set(new Uint8Array(second), first.byteLength);
964
+ return result ;
965
+ }
966
+ function hexToBinaryString(hex) {
967
+ var bytes = [], length = hex.length, x;
968
+ for (x = 0; x < length - 1; x += 2) {
969
+ bytes.push(parseInt(hex.substr(x, 2), 16));
970
+ }
971
+ return String.fromCharCode.apply(String, bytes);
972
+ }
973
+ function SparkMD5() {
974
+ this.reset();
975
+ }
976
+ SparkMD5.prototype.append = function(str) {
977
+ this.appendBinary(toUtf8(str));
978
+ return this;
979
+ };
980
+ SparkMD5.prototype.appendBinary = function(contents) {
981
+ this._buff += contents;
982
+ this._length += contents.length;
983
+ var length = this._buff.length, i;
984
+ for (i = 64; i <= length; i += 64) {
985
+ md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
986
+ }
987
+ this._buff = this._buff.substring(i - 64);
988
+ return this;
989
+ };
990
+ SparkMD5.prototype.end = function(raw) {
991
+ 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;
992
+ for (i = 0; i < length; i += 1) {
993
+ tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3);
994
+ }
995
+ this._finish(tail, length);
996
+ ret = hex(this._hash);
997
+ if (raw) {
998
+ ret = hexToBinaryString(ret);
999
+ }
1000
+ this.reset();
1001
+ return ret;
1002
+ };
1003
+ SparkMD5.prototype.reset = function() {
1004
+ this._buff = "";
1005
+ this._length = 0;
1006
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
1007
+ return this;
1008
+ };
1009
+ SparkMD5.prototype.getState = function() {
1010
+ return {
1011
+ buff: this._buff,
1012
+ length: this._length,
1013
+ hash: this._hash.slice()
1014
+ };
1015
+ };
1016
+ SparkMD5.prototype.setState = function(state) {
1017
+ this._buff = state.buff;
1018
+ this._length = state.length;
1019
+ this._hash = state.hash;
1020
+ return this;
1021
+ };
1022
+ SparkMD5.prototype.destroy = function() {
1023
+ delete this._hash;
1024
+ delete this._buff;
1025
+ delete this._length;
1026
+ };
1027
+ SparkMD5.prototype._finish = function(tail, length) {
1028
+ var i = length, tmp, lo, hi;
1029
+ tail[i >> 2] |= 128 << (i % 4 << 3);
1030
+ if (i > 55) {
1031
+ md5cycle(this._hash, tail);
1032
+ for (i = 0; i < 16; i += 1) {
1033
+ tail[i] = 0;
1034
+ }
1035
+ }
1036
+ tmp = this._length * 8;
1037
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
1038
+ lo = parseInt(tmp[2], 16);
1039
+ hi = parseInt(tmp[1], 16) || 0;
1040
+ tail[14] = lo;
1041
+ tail[15] = hi;
1042
+ md5cycle(this._hash, tail);
1043
+ };
1044
+ SparkMD5.hash = function(str, raw) {
1045
+ return SparkMD5.hashBinary(toUtf8(str), raw);
1046
+ };
1047
+ SparkMD5.hashBinary = function(content, raw) {
1048
+ var hash = md51(content), ret = hex(hash);
1049
+ return raw ? hexToBinaryString(ret) : ret;
1050
+ };
1051
+ SparkMD5.ArrayBuffer = function() {
1052
+ this.reset();
1053
+ };
1054
+ SparkMD5.ArrayBuffer.prototype.append = function(arr) {
1055
+ var buff = concatenateArrayBuffers(this._buff.buffer, arr), length = buff.length, i;
1056
+ this._length += arr.byteLength;
1057
+ for (i = 64; i <= length; i += 64) {
1058
+ md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
1059
+ }
1060
+ this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
1061
+ return this;
1062
+ };
1063
+ SparkMD5.ArrayBuffer.prototype.end = function(raw) {
1064
+ 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;
1065
+ for (i = 0; i < length; i += 1) {
1066
+ tail[i >> 2] |= buff[i] << (i % 4 << 3);
1067
+ }
1068
+ this._finish(tail, length);
1069
+ ret = hex(this._hash);
1070
+ if (raw) {
1071
+ ret = hexToBinaryString(ret);
1072
+ }
1073
+ this.reset();
1074
+ return ret;
1075
+ };
1076
+ SparkMD5.ArrayBuffer.prototype.reset = function() {
1077
+ this._buff = new Uint8Array(0);
1078
+ this._length = 0;
1079
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
1080
+ return this;
1081
+ };
1082
+ SparkMD5.ArrayBuffer.prototype.getState = function() {
1083
+ var state = SparkMD5.prototype.getState.call(this);
1084
+ state.buff = arrayBuffer2Utf8Str(state.buff);
1085
+ return state;
1086
+ };
1087
+ SparkMD5.ArrayBuffer.prototype.setState = function(state) {
1088
+ state.buff = utf8Str2ArrayBuffer(state.buff, true);
1089
+ return SparkMD5.prototype.setState.call(this, state);
1090
+ };
1091
+ SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
1092
+ SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
1093
+ SparkMD5.ArrayBuffer.hash = function(arr, raw) {
1094
+ var hash = md51_array(new Uint8Array(arr)), ret = hex(hash);
1095
+ return raw ? hexToBinaryString(ret) : ret;
1096
+ };
1097
+ return SparkMD5;
1098
+ }));
1099
+ })(sparkMd5);
1100
+
1101
+ var SparkMD5 = sparkMd5.exports;
1102
+
1103
+ const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
1104
+
1105
+ class FileChecksum {
1106
+ static create(file, callback) {
1107
+ const instance = new FileChecksum(file);
1108
+ instance.create(callback);
1109
+ }
1110
+ constructor(file) {
1111
+ this.file = file;
1112
+ this.chunkSize = 2097152;
1113
+ this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
1114
+ this.chunkIndex = 0;
1115
+ }
1116
+ create(callback) {
1117
+ this.callback = callback;
1118
+ this.md5Buffer = new SparkMD5.ArrayBuffer;
1119
+ this.fileReader = new FileReader;
1120
+ this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event)));
1121
+ this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event)));
1122
+ this.readNextChunk();
1123
+ }
1124
+ fileReaderDidLoad(event) {
1125
+ this.md5Buffer.append(event.target.result);
1126
+ if (!this.readNextChunk()) {
1127
+ const binaryDigest = this.md5Buffer.end(true);
1128
+ const base64digest = btoa(binaryDigest);
1129
+ this.callback(null, base64digest);
1130
+ }
1131
+ }
1132
+ fileReaderDidError(event) {
1133
+ this.callback(`Error reading ${this.file.name}`);
1134
+ }
1135
+ readNextChunk() {
1136
+ if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) {
1137
+ const start = this.chunkIndex * this.chunkSize;
1138
+ const end = Math.min(start + this.chunkSize, this.file.size);
1139
+ const bytes = fileSlice.call(this.file, start, end);
1140
+ this.fileReader.readAsArrayBuffer(bytes);
1141
+ this.chunkIndex++;
1142
+ return true;
1143
+ } else {
1144
+ return false;
1145
+ }
1146
+ }
1147
+ }
1148
+
1149
+ function getMetaValue(name) {
1150
+ const element = findElement(document.head, `meta[name="${name}"]`);
1151
+ if (element) {
1152
+ return element.getAttribute("content");
1153
+ }
1154
+ }
1155
+
1156
+ function findElements(root, selector) {
1157
+ if (typeof root == "string") {
1158
+ selector = root;
1159
+ root = document;
1160
+ }
1161
+ const elements = root.querySelectorAll(selector);
1162
+ return toArray(elements);
1163
+ }
1164
+
1165
+ function findElement(root, selector) {
1166
+ if (typeof root == "string") {
1167
+ selector = root;
1168
+ root = document;
1169
+ }
1170
+ return root.querySelector(selector);
1171
+ }
1172
+
1173
+ function dispatchEvent(element, type, eventInit = {}) {
1174
+ const {disabled: disabled} = element;
1175
+ const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit;
1176
+ const event = document.createEvent("Event");
1177
+ event.initEvent(type, bubbles || true, cancelable || true);
1178
+ event.detail = detail || {};
1179
+ try {
1180
+ element.disabled = false;
1181
+ element.dispatchEvent(event);
1182
+ } finally {
1183
+ element.disabled = disabled;
1184
+ }
1185
+ return event;
1186
+ }
1187
+
1188
+ function toArray(value) {
1189
+ if (Array.isArray(value)) {
1190
+ return value;
1191
+ } else if (Array.from) {
1192
+ return Array.from(value);
1193
+ } else {
1194
+ return [].slice.call(value);
1195
+ }
1196
+ }
1197
+
1198
+ class BlobRecord {
1199
+ constructor(file, checksum, url, customHeaders = {}) {
1200
+ this.file = file;
1201
+ this.attributes = {
1202
+ filename: file.name,
1203
+ content_type: file.type || "application/octet-stream",
1204
+ byte_size: file.size,
1205
+ checksum: checksum
1206
+ };
1207
+ this.xhr = new XMLHttpRequest;
1208
+ this.xhr.open("POST", url, true);
1209
+ this.xhr.responseType = "json";
1210
+ this.xhr.setRequestHeader("Content-Type", "application/json");
1211
+ this.xhr.setRequestHeader("Accept", "application/json");
1212
+ this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
1213
+ Object.keys(customHeaders).forEach((headerKey => {
1214
+ this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
1215
+ }));
1216
+ const csrfToken = getMetaValue("csrf-token");
1217
+ if (csrfToken != undefined) {
1218
+ this.xhr.setRequestHeader("X-CSRF-Token", csrfToken);
1219
+ }
1220
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
1221
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
1222
+ }
1223
+ get status() {
1224
+ return this.xhr.status;
1225
+ }
1226
+ get response() {
1227
+ const {responseType: responseType, response: response} = this.xhr;
1228
+ if (responseType == "json") {
1229
+ return response;
1230
+ } else {
1231
+ return JSON.parse(response);
1232
+ }
1233
+ }
1234
+ create(callback) {
1235
+ this.callback = callback;
1236
+ this.xhr.send(JSON.stringify({
1237
+ blob: this.attributes
1238
+ }));
1239
+ }
1240
+ requestDidLoad(event) {
1241
+ if (this.status >= 200 && this.status < 300) {
1242
+ const {response: response} = this;
1243
+ const {direct_upload: direct_upload} = response;
1244
+ delete response.direct_upload;
1245
+ this.attributes = response;
1246
+ this.directUploadData = direct_upload;
1247
+ this.callback(null, this.toJSON());
1248
+ } else {
1249
+ this.requestDidError(event);
1250
+ }
1251
+ }
1252
+ requestDidError(event) {
1253
+ this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`);
1254
+ }
1255
+ toJSON() {
1256
+ const result = {};
1257
+ for (const key in this.attributes) {
1258
+ result[key] = this.attributes[key];
1259
+ }
1260
+ return result;
1261
+ }
1262
+ }
1263
+
1264
+ class BlobUpload {
1265
+ constructor(blob) {
1266
+ this.blob = blob;
1267
+ this.file = blob.file;
1268
+ const {url: url, headers: headers} = blob.directUploadData;
1269
+ this.xhr = new XMLHttpRequest;
1270
+ this.xhr.open("PUT", url, true);
1271
+ this.xhr.responseType = "text";
1272
+ for (const key in headers) {
1273
+ this.xhr.setRequestHeader(key, headers[key]);
1274
+ }
1275
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
1276
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
1277
+ }
1278
+ create(callback) {
1279
+ this.callback = callback;
1280
+ this.xhr.send(this.file.slice());
1281
+ }
1282
+ requestDidLoad(event) {
1283
+ const {status: status, response: response} = this.xhr;
1284
+ if (status >= 200 && status < 300) {
1285
+ this.callback(null, response);
1286
+ } else {
1287
+ this.requestDidError(event);
1288
+ }
1289
+ }
1290
+ requestDidError(event) {
1291
+ this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`);
1292
+ }
1293
+ }
1294
+
1295
+ let id = 0;
1296
+
1297
+ class DirectUpload {
1298
+ constructor(file, url, delegate, customHeaders = {}) {
1299
+ this.id = ++id;
1300
+ this.file = file;
1301
+ this.url = url;
1302
+ this.delegate = delegate;
1303
+ this.customHeaders = customHeaders;
1304
+ }
1305
+ create(callback) {
1306
+ FileChecksum.create(this.file, ((error, checksum) => {
1307
+ if (error) {
1308
+ callback(error);
1309
+ return;
1310
+ }
1311
+ const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders);
1312
+ notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr);
1313
+ blob.create((error => {
1314
+ if (error) {
1315
+ callback(error);
1316
+ } else {
1317
+ const upload = new BlobUpload(blob);
1318
+ notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr);
1319
+ upload.create((error => {
1320
+ if (error) {
1321
+ callback(error);
1322
+ } else {
1323
+ callback(null, blob.toJSON());
1324
+ }
1325
+ }));
1326
+ }
1327
+ }));
1328
+ }));
1329
+ }
1330
+ }
1331
+
1332
+ function notify(object, methodName, ...messages) {
1333
+ if (object && typeof object[methodName] == "function") {
1334
+ return object[methodName](...messages);
1335
+ }
1336
+ }
1337
+
1338
+ class DirectUploadController {
1339
+ constructor(input, file) {
1340
+ this.input = input;
1341
+ this.file = file;
1342
+ this.directUpload = new DirectUpload(this.file, this.url, this);
1343
+ this.dispatch("initialize");
1344
+ }
1345
+ start(callback) {
1346
+ const hiddenInput = document.createElement("input");
1347
+ hiddenInput.type = "hidden";
1348
+ hiddenInput.name = this.input.name;
1349
+ this.input.insertAdjacentElement("beforebegin", hiddenInput);
1350
+ this.dispatch("start");
1351
+ this.directUpload.create(((error, attributes) => {
1352
+ if (error) {
1353
+ hiddenInput.parentNode.removeChild(hiddenInput);
1354
+ this.dispatchError(error);
1355
+ } else {
1356
+ hiddenInput.value = attributes.signed_id;
1357
+ }
1358
+ this.dispatch("end");
1359
+ callback(error);
1360
+ }));
1361
+ }
1362
+ uploadRequestDidProgress(event) {
1363
+ const progress = event.loaded / event.total * 100;
1364
+ if (progress) {
1365
+ this.dispatch("progress", {
1366
+ progress: progress
1367
+ });
1368
+ }
1369
+ }
1370
+ get url() {
1371
+ return this.input.getAttribute("data-direct-upload-url");
1372
+ }
1373
+ dispatch(name, detail = {}) {
1374
+ detail.file = this.file;
1375
+ detail.id = this.directUpload.id;
1376
+ return dispatchEvent(this.input, `direct-upload:${name}`, {
1377
+ detail: detail
1378
+ });
1379
+ }
1380
+ dispatchError(error) {
1381
+ const event = this.dispatch("error", {
1382
+ error: error
1383
+ });
1384
+ if (!event.defaultPrevented) {
1385
+ alert(error);
1386
+ }
1387
+ }
1388
+ directUploadWillCreateBlobWithXHR(xhr) {
1389
+ this.dispatch("before-blob-request", {
1390
+ xhr: xhr
1391
+ });
1392
+ }
1393
+ directUploadWillStoreFileWithXHR(xhr) {
1394
+ this.dispatch("before-storage-request", {
1395
+ xhr: xhr
1396
+ });
1397
+ xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
1398
+ }
1399
+ }
1400
+
1401
+ const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])";
1402
+
1403
+ class DirectUploadsController {
1404
+ constructor(form) {
1405
+ this.form = form;
1406
+ this.inputs = findElements(form, inputSelector).filter((input => input.files.length));
1407
+ }
1408
+ start(callback) {
1409
+ const controllers = this.createDirectUploadControllers();
1410
+ const startNextController = () => {
1411
+ const controller = controllers.shift();
1412
+ if (controller) {
1413
+ controller.start((error => {
1414
+ if (error) {
1415
+ callback(error);
1416
+ this.dispatch("end");
1417
+ } else {
1418
+ startNextController();
1419
+ }
1420
+ }));
1421
+ } else {
1422
+ callback();
1423
+ this.dispatch("end");
1424
+ }
1425
+ };
1426
+ this.dispatch("start");
1427
+ startNextController();
1428
+ }
1429
+ createDirectUploadControllers() {
1430
+ const controllers = [];
1431
+ this.inputs.forEach((input => {
1432
+ toArray(input.files).forEach((file => {
1433
+ const controller = new DirectUploadController(input, file);
1434
+ controllers.push(controller);
1435
+ }));
1436
+ }));
1437
+ return controllers;
1438
+ }
1439
+ dispatch(name, detail = {}) {
1440
+ return dispatchEvent(this.form, `direct-uploads:${name}`, {
1441
+ detail: detail
1442
+ });
1443
+ }
1444
+ }
1445
+
1446
+ const processingAttribute = "data-direct-uploads-processing";
1447
+
1448
+ const submitButtonsByForm = new WeakMap;
1449
+
1450
+ let started = false;
1451
+
1452
+ function start() {
1453
+ if (!started) {
1454
+ started = true;
1455
+ document.addEventListener("click", didClick, true);
1456
+ document.addEventListener("submit", didSubmitForm, true);
1457
+ document.addEventListener("ajax:before", didSubmitRemoteElement);
1458
+ }
1459
+ }
1460
+
1461
+ function didClick(event) {
1462
+ const button = event.target.closest("button, input");
1463
+ if (button && button.type === "submit" && button.form) {
1464
+ submitButtonsByForm.set(button.form, button);
1465
+ }
1466
+ }
1467
+
1468
+ function didSubmitForm(event) {
1469
+ handleFormSubmissionEvent(event);
1470
+ }
1471
+
1472
+ function didSubmitRemoteElement(event) {
1473
+ if (event.target.tagName == "FORM") {
1474
+ handleFormSubmissionEvent(event);
1475
+ }
1476
+ }
1477
+
1478
+ function handleFormSubmissionEvent(event) {
1479
+ const form = event.target;
1480
+ if (form.hasAttribute(processingAttribute)) {
1481
+ event.preventDefault();
1482
+ return;
1483
+ }
1484
+ const controller = new DirectUploadsController(form);
1485
+ const {inputs: inputs} = controller;
1486
+ if (inputs.length) {
1487
+ event.preventDefault();
1488
+ form.setAttribute(processingAttribute, "");
1489
+ inputs.forEach(disable);
1490
+ controller.start((error => {
1491
+ form.removeAttribute(processingAttribute);
1492
+ if (error) {
1493
+ inputs.forEach(enable);
1494
+ } else {
1495
+ submitForm(form);
1496
+ }
1497
+ }));
1498
+ }
1499
+ }
1500
+
1501
+ function submitForm(form) {
1502
+ let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]");
1503
+ if (button) {
1504
+ const {disabled: disabled} = button;
1505
+ button.disabled = false;
1506
+ button.focus();
1507
+ button.click();
1508
+ button.disabled = disabled;
1509
+ } else {
1510
+ button = document.createElement("input");
1511
+ button.type = "submit";
1512
+ button.style.display = "none";
1513
+ form.appendChild(button);
1514
+ button.click();
1515
+ form.removeChild(button);
1516
+ }
1517
+ submitButtonsByForm.delete(form);
1518
+ }
1519
+
1520
+ function disable(input) {
1521
+ input.disabled = true;
1522
+ }
1523
+
1524
+ function enable(input) {
1525
+ input.disabled = false;
1526
+ }
1527
+
1528
+ function autostart() {
1529
+ if (window.ActiveStorage) {
1530
+ start();
1531
+ }
1532
+ }
1533
+
1534
+ setTimeout(autostart, 1);
1535
+
1536
+ class FetchResponse {
1537
+ constructor (response) {
1538
+ this.response = response;
1539
+ }
1540
+
1541
+ get statusCode () {
1542
+ return this.response.status
1543
+ }
1544
+
1545
+ get redirected () {
1546
+ return this.response.redirected
1547
+ }
1548
+
1549
+ get ok () {
1550
+ return this.response.ok
1551
+ }
1552
+
1553
+ get unauthenticated () {
1554
+ return this.statusCode === 401
1555
+ }
1556
+
1557
+ get unprocessableEntity () {
1558
+ return this.statusCode === 422
1559
+ }
1560
+
1561
+ get authenticationURL () {
1562
+ return this.response.headers.get('WWW-Authenticate')
1563
+ }
1564
+
1565
+ get contentType () {
1566
+ const contentType = this.response.headers.get('Content-Type') || '';
1567
+
1568
+ return contentType.replace(/;.*$/, '')
1569
+ }
1570
+
1571
+ get headers () {
1572
+ return this.response.headers
1573
+ }
1574
+
1575
+ get html () {
1576
+ if (this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)) {
1577
+ return this.text
1578
+ }
1579
+
1580
+ return Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`))
1581
+ }
1582
+
1583
+ get json () {
1584
+ if (this.contentType.match(/^application\/.*json$/)) {
1585
+ return this.responseJson || (this.responseJson = this.response.json())
1586
+ }
1587
+
1588
+ return Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`))
1589
+ }
1590
+
1591
+ get text () {
1592
+ return this.responseText || (this.responseText = this.response.text())
1593
+ }
1594
+
1595
+ get isTurboStream () {
1596
+ return this.contentType.match(/^text\/vnd\.turbo-stream\.html/)
1597
+ }
1598
+
1599
+ get isScript () {
1600
+ return this.contentType.match(/\b(?:java|ecma)script\b/)
1601
+ }
1602
+
1603
+ async renderTurboStream () {
1604
+ if (this.isTurboStream) {
1605
+ if (window.Turbo) {
1606
+ await window.Turbo.renderStreamMessage(await this.text);
1607
+ } else {
1608
+ console.warn('You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js');
1609
+ }
1610
+ } else {
1611
+ return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`))
1612
+ }
1613
+ }
1614
+
1615
+ async activeScript () {
1616
+ if (this.isScript) {
1617
+ const script = document.createElement('script');
1618
+ const metaTag = document.querySelector('meta[name=csp-nonce]');
1619
+ const nonce = metaTag && metaTag.content;
1620
+ if (nonce) { script.setAttribute('nonce', nonce); }
1621
+ script.innerHTML = await this.text;
1622
+ document.body.appendChild(script);
1623
+ } else {
1624
+ return Promise.reject(new Error(`Expected a Script response but got "${this.contentType}" instead`))
1625
+ }
1626
+ }
1627
+ }
1628
+
1629
+ class RequestInterceptor {
1630
+ static register (interceptor) {
1631
+ this.interceptor = interceptor;
1632
+ }
1633
+
1634
+ static get () {
1635
+ return this.interceptor
1636
+ }
1637
+
1638
+ static reset () {
1639
+ this.interceptor = undefined;
1640
+ }
1641
+ }
1642
+
1643
+ function getCookie (name) {
1644
+ const cookies = document.cookie ? document.cookie.split('; ') : [];
1645
+ const prefix = `${encodeURIComponent(name)}=`;
1646
+ const cookie = cookies.find(cookie => cookie.startsWith(prefix));
1647
+
1648
+ if (cookie) {
1649
+ const value = cookie.split('=').slice(1).join('=');
1650
+
1651
+ if (value) {
1652
+ return decodeURIComponent(value)
1653
+ }
1654
+ }
1655
+ }
1656
+
1657
+ function compact (object) {
1658
+ const result = {};
1659
+
1660
+ for (const key in object) {
1661
+ const value = object[key];
1662
+ if (value !== undefined) {
1663
+ result[key] = value;
1664
+ }
1665
+ }
1666
+
1667
+ return result
1668
+ }
1669
+
1670
+ function metaContent (name) {
1671
+ const element = document.head.querySelector(`meta[name="${name}"]`);
1672
+ return element && element.content
1673
+ }
1674
+
1675
+ function stringEntriesFromFormData (formData) {
1676
+ return [...formData].reduce((entries, [name, value]) => {
1677
+ return entries.concat(typeof value === 'string' ? [[name, value]] : [])
1678
+ }, [])
1679
+ }
1680
+
1681
+ function mergeEntries (searchParams, entries) {
1682
+ for (const [name, value] of entries) {
1683
+ if (value instanceof window.File) continue
1684
+
1685
+ if (searchParams.has(name) && !name.includes('[]')) {
1686
+ searchParams.delete(name);
1687
+ searchParams.set(name, value);
1688
+ } else {
1689
+ searchParams.append(name, value);
1690
+ }
1691
+ }
1692
+ }
1693
+
1694
+ class FetchRequest {
1695
+ constructor (method, url, options = {}) {
1696
+ this.method = method;
1697
+ this.options = options;
1698
+ this.originalUrl = url.toString();
1699
+ }
1700
+
1701
+ async perform () {
1702
+ try {
1703
+ const requestInterceptor = RequestInterceptor.get();
1704
+ if (requestInterceptor) {
1705
+ await requestInterceptor(this);
1706
+ }
1707
+ } catch (error) {
1708
+ console.error(error);
1709
+ }
1710
+
1711
+ const fetch = (this.responseKind === 'turbo-stream' && window.Turbo)
1712
+ ? window.Turbo.fetch
1713
+ : window.fetch;
1714
+
1715
+ const response = new FetchResponse(await fetch(this.url, this.fetchOptions));
1716
+
1717
+ if (response.unauthenticated && response.authenticationURL) {
1718
+ return Promise.reject(window.location.href = response.authenticationURL)
1719
+ }
1720
+
1721
+ if (response.isScript) {
1722
+ await response.activeScript();
1723
+ }
1724
+
1725
+ const responseStatusIsTurboStreamable = response.ok || response.unprocessableEntity;
1726
+
1727
+ if (responseStatusIsTurboStreamable && response.isTurboStream) {
1728
+ await response.renderTurboStream();
1729
+ }
1730
+
1731
+ return response
1732
+ }
1733
+
1734
+ addHeader (key, value) {
1735
+ const headers = this.additionalHeaders;
1736
+ headers[key] = value;
1737
+ this.options.headers = headers;
1738
+ }
1739
+
1740
+ sameHostname () {
1741
+ if (!this.originalUrl.startsWith('http:')) {
1742
+ return true
1743
+ }
1744
+
1745
+ try {
1746
+ return new URL(this.originalUrl).hostname === window.location.hostname
1747
+ } catch (_) {
1748
+ return true
1749
+ }
1750
+ }
1751
+
1752
+ get fetchOptions () {
1753
+ return {
1754
+ method: this.method.toUpperCase(),
1755
+ headers: this.headers,
1756
+ body: this.formattedBody,
1757
+ signal: this.signal,
1758
+ credentials: this.credentials,
1759
+ redirect: this.redirect
1760
+ }
1761
+ }
1762
+
1763
+ get headers () {
1764
+ const baseHeaders = {
1765
+ 'X-Requested-With': 'XMLHttpRequest',
1766
+ 'Content-Type': this.contentType,
1767
+ Accept: this.accept
1768
+ };
1769
+
1770
+ if (this.sameHostname()) {
1771
+ baseHeaders['X-CSRF-Token'] = this.csrfToken;
1772
+ }
1773
+
1774
+ return compact(
1775
+ Object.assign(baseHeaders, this.additionalHeaders)
1776
+ )
1777
+ }
1778
+
1779
+ get csrfToken () {
1780
+ return getCookie(metaContent('csrf-param')) || metaContent('csrf-token')
1781
+ }
1782
+
1783
+ get contentType () {
1784
+ if (this.options.contentType) {
1785
+ return this.options.contentType
1786
+ } else if (this.body == null || this.body instanceof window.FormData) {
1787
+ return undefined
1788
+ } else if (this.body instanceof window.File) {
1789
+ return this.body.type
1790
+ }
1791
+
1792
+ return 'application/json'
1793
+ }
1794
+
1795
+ get accept () {
1796
+ switch (this.responseKind) {
1797
+ case 'html':
1798
+ return 'text/html, application/xhtml+xml'
1799
+ case 'turbo-stream':
1800
+ return 'text/vnd.turbo-stream.html, text/html, application/xhtml+xml'
1801
+ case 'json':
1802
+ return 'application/json, application/vnd.api+json'
1803
+ case 'script':
1804
+ return 'text/javascript, application/javascript'
1805
+ default:
1806
+ return '*/*'
1807
+ }
1808
+ }
1809
+
1810
+ get body () {
1811
+ return this.options.body
1812
+ }
1813
+
1814
+ get query () {
1815
+ const originalQuery = (this.originalUrl.split('?')[1] || '').split('#')[0];
1816
+ const params = new URLSearchParams(originalQuery);
1817
+
1818
+ let requestQuery = this.options.query;
1819
+ if (requestQuery instanceof window.FormData) {
1820
+ requestQuery = stringEntriesFromFormData(requestQuery);
1821
+ } else if (requestQuery instanceof window.URLSearchParams) {
1822
+ requestQuery = requestQuery.entries();
1823
+ } else {
1824
+ requestQuery = Object.entries(requestQuery || {});
1825
+ }
1826
+
1827
+ mergeEntries(params, requestQuery);
1828
+
1829
+ const query = params.toString();
1830
+ return (query.length > 0 ? `?${query}` : '')
1831
+ }
1832
+
1833
+ get url () {
1834
+ return (this.originalUrl.split('?')[0]).split('#')[0] + this.query
1835
+ }
1836
+
1837
+ get responseKind () {
1838
+ return this.options.responseKind || 'html'
1839
+ }
1840
+
1841
+ get signal () {
1842
+ return this.options.signal
1843
+ }
1844
+
1845
+ get redirect () {
1846
+ return this.options.redirect || 'follow'
1847
+ }
1848
+
1849
+ get credentials () {
1850
+ return this.options.credentials || 'same-origin'
1851
+ }
1852
+
1853
+ get additionalHeaders () {
1854
+ return this.options.headers || {}
1855
+ }
1856
+
1857
+ get formattedBody () {
1858
+ const bodyIsAString = Object.prototype.toString.call(this.body) === '[object String]';
1859
+ const contentTypeIsJson = this.headers['Content-Type'] === 'application/json';
1860
+
1861
+ if (contentTypeIsJson && !bodyIsAString) {
1862
+ return JSON.stringify(this.body)
1863
+ }
1864
+
1865
+ return this.body
1866
+ }
1867
+ }
1868
+
1869
+ async function post (url, options) {
1870
+ const request = new FetchRequest('post', url, options);
1871
+ return request.perform()
1872
+ }
1873
+
1874
+ function insertText(textarea, text) {
1875
+ var _a, _b, _c;
1876
+ const before = textarea.value.slice(0, (_a = textarea.selectionStart) !== null && _a !== undefined ? _a : undefined);
1877
+ const after = textarea.value.slice((_b = textarea.selectionEnd) !== null && _b !== undefined ? _b : undefined);
1878
+ let canInsertText = true;
1879
+ textarea.contentEditable = 'true';
1880
+ try {
1881
+ canInsertText = document.execCommand('insertText', false, text);
1882
+ }
1883
+ catch (error) {
1884
+ canInsertText = false;
1885
+ }
1886
+ textarea.contentEditable = 'false';
1887
+ if (canInsertText && !textarea.value.slice(0, (_c = textarea.selectionStart) !== null && _c !== undefined ? _c : undefined).endsWith(text)) {
1888
+ canInsertText = false;
1889
+ }
1890
+ if (!canInsertText) {
1891
+ try {
1892
+ document.execCommand('ms-beginUndoUnit');
1893
+ }
1894
+ catch (e) {
1895
+ }
1896
+ textarea.value = before + text + after;
1897
+ try {
1898
+ document.execCommand('ms-endUndoUnit');
1899
+ }
1900
+ catch (e) {
1901
+ }
1902
+ textarea.dispatchEvent(new CustomEvent('change', { bubbles: true, cancelable: true }));
1903
+ }
1904
+ }
1905
+
1906
+ const skipFormattingMap = new WeakMap();
1907
+ function setSkipFormattingFlag(event) {
1908
+ const { currentTarget: el } = event;
1909
+ const isSkipFormattingKeys = event.code === 'KeyV' && (event.ctrlKey || event.metaKey) && event.shiftKey;
1910
+ if (isSkipFormattingKeys || (isSkipFormattingKeys && event.altKey)) {
1911
+ skipFormattingMap.set(el, true);
1912
+ }
1913
+ }
1914
+ function unsetSkipFormattedFlag(event) {
1915
+ const { currentTarget: el } = event;
1916
+ skipFormattingMap.delete(el);
1917
+ }
1918
+ function shouldSkipFormatting(el) {
1919
+ var _a;
1920
+ const shouldSkipFormattingState = (_a = skipFormattingMap.get(el)) !== null && _a !== undefined ? _a : false;
1921
+ return shouldSkipFormattingState;
1922
+ }
1923
+ function installAround(el, installCallbacks, optionConfig) {
1924
+ el.addEventListener('keydown', setSkipFormattingFlag);
1925
+ for (const installCallback of installCallbacks) {
1926
+ installCallback(el, optionConfig);
1927
+ }
1928
+ el.addEventListener('paste', unsetSkipFormattedFlag);
1929
+ }
1930
+ function uninstall$5(el) {
1931
+ el.removeEventListener('keydown', setSkipFormattingFlag);
1932
+ el.removeEventListener('paste', unsetSkipFormattedFlag);
1933
+ }
1934
+
1935
+ function install$4(el) {
1936
+ el.addEventListener('paste', onPaste$4);
1937
+ }
1938
+ function uninstall$4(el) {
1939
+ el.removeEventListener('paste', onPaste$4);
1940
+ }
1941
+ function onPaste$4(event) {
1942
+ const transfer = event.clipboardData;
1943
+ const { currentTarget: el } = event;
1944
+ if (shouldSkipFormatting(el))
1945
+ return;
1946
+ if (!transfer || !hasHTML(transfer))
1947
+ return;
1948
+ const field = event.currentTarget;
1949
+ if (!(field instanceof HTMLTextAreaElement))
1950
+ return;
1951
+ if (isWithinUserMention(field)) {
1952
+ return;
1953
+ }
1954
+ let plaintext = transfer.getData('text/plain');
1955
+ const textHTML = transfer.getData('text/html');
1956
+ const textHTMLClean = textHTML.replace(/\u00A0/g, ' ').replace(/\uC2A0/g, ' ');
1957
+ if (!textHTML)
1958
+ return;
1959
+ plaintext = plaintext.trim();
1960
+ if (!plaintext)
1961
+ return;
1962
+ const parser = new DOMParser();
1963
+ const doc = parser.parseFromString(textHTMLClean, 'text/html');
1964
+ const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ALL, node => node.parentNode && isLink(node.parentNode) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT);
1965
+ const markdown = convertToMarkdown(plaintext, walker);
1966
+ if (markdown === plaintext)
1967
+ return;
1968
+ event.stopPropagation();
1969
+ event.preventDefault();
1970
+ insertText(field, markdown);
1971
+ }
1972
+ function convertToMarkdown(plaintext, walker) {
1973
+ let currentNode = walker.firstChild();
1974
+ let markdown = plaintext;
1975
+ let markdownIgnoreBeforeIndex = 0;
1976
+ let index = 0;
1977
+ const NODE_LIMIT = 10000;
1978
+ while (currentNode && index < NODE_LIMIT) {
1979
+ index++;
1980
+ const text = isLink(currentNode)
1981
+ ? (currentNode.textContent || '').replace(/[\t\n\r ]+/g, ' ')
1982
+ : (currentNode === null || currentNode === undefined ? undefined : currentNode.wholeText) || '';
1983
+ if (isEmptyString(text)) {
1984
+ currentNode = walker.nextNode();
1985
+ continue;
1986
+ }
1987
+ if (!isLink(currentNode)) {
1988
+ markdownIgnoreBeforeIndex += text.replace(/[\t\n\r ]+/g, ' ').trimStart().length;
1989
+ currentNode = walker.nextNode();
1990
+ continue;
1991
+ }
1992
+ const markdownFoundIndex = markdown.indexOf(text, markdownIgnoreBeforeIndex);
1993
+ if (markdownFoundIndex >= 0) {
1994
+ const markdownLink = linkify$2(currentNode, text);
1995
+ markdown = markdown.slice(0, markdownFoundIndex) + markdownLink + markdown.slice(markdownFoundIndex + text.length);
1996
+ markdownIgnoreBeforeIndex = markdownFoundIndex + markdownLink.length;
1997
+ }
1998
+ currentNode = walker.nextNode();
1999
+ }
2000
+ return index === NODE_LIMIT ? plaintext : markdown;
2001
+ }
2002
+ function isWithinUserMention(textarea) {
2003
+ const selectionStart = textarea.selectionStart || 0;
2004
+ if (selectionStart === 0) {
2005
+ return false;
2006
+ }
2007
+ const previousChar = textarea.value.substring(selectionStart - 1, selectionStart);
2008
+ return previousChar === '@';
2009
+ }
2010
+ function isEmptyString(text) {
2011
+ return !text || (text === null || text === undefined ? undefined : text.trim().length) === 0;
2012
+ }
2013
+ function isLink(node) {
2014
+ var _a;
2015
+ return ((_a = node.tagName) === null || _a === undefined ? undefined : _a.toLowerCase()) === 'a' && node.hasAttribute('href');
2016
+ }
2017
+ function hasHTML(transfer) {
2018
+ return transfer.types.includes('text/html');
2019
+ }
2020
+ function linkify$2(element, label) {
2021
+ const url = element.href || '';
2022
+ let markdown = '';
2023
+ if (isUserMention(element) || isTeamMention(element)) {
2024
+ markdown = label;
2025
+ }
2026
+ else if (isSpecialLink(element) || areEqualLinks(url, label)) {
2027
+ markdown = url;
2028
+ }
2029
+ else {
2030
+ markdown = `[${label}](${url})`;
2031
+ }
2032
+ return markdown;
2033
+ }
2034
+ function isSpecialLink(link) {
2035
+ return (link.className.indexOf('commit-link') >= 0 ||
2036
+ (!!link.getAttribute('data-hovercard-type') && link.getAttribute('data-hovercard-type') !== 'user'));
2037
+ }
2038
+ function areEqualLinks(link1, link2) {
2039
+ link1 = link1.slice(-1) === '/' ? link1.slice(0, -1) : link1;
2040
+ link2 = link2.slice(-1) === '/' ? link2.slice(0, -1) : link2;
2041
+ return link1.toLowerCase() === link2.toLowerCase();
2042
+ }
2043
+ function isUserMention(link) {
2044
+ var _a;
2045
+ return ((_a = link.textContent) === null || _a === undefined ? undefined : _a.slice(0, 1)) === '@' && link.getAttribute('data-hovercard-type') === 'user';
2046
+ }
2047
+ function isTeamMention(link) {
2048
+ var _a;
2049
+ return ((_a = link.textContent) === null || _a === undefined ? undefined : _a.slice(0, 1)) === '@' && link.getAttribute('data-hovercard-type') === 'team';
2050
+ }
2051
+
2052
+ function install$3(el) {
2053
+ el.addEventListener('dragover', onDragover$1);
2054
+ el.addEventListener('drop', onDrop$1);
2055
+ el.addEventListener('paste', onPaste$3);
2056
+ }
2057
+ function uninstall$3(el) {
2058
+ el.removeEventListener('dragover', onDragover$1);
2059
+ el.removeEventListener('drop', onDrop$1);
2060
+ el.removeEventListener('paste', onPaste$3);
2061
+ }
2062
+ function onDrop$1(event) {
2063
+ const transfer = event.dataTransfer;
2064
+ if (!transfer)
2065
+ return;
2066
+ if (hasFile$1(transfer))
2067
+ return;
2068
+ if (!hasLink(transfer))
2069
+ return;
2070
+ const links = extractLinks(transfer);
2071
+ if (!links.some(isImageLink))
2072
+ return;
2073
+ event.stopPropagation();
2074
+ event.preventDefault();
2075
+ const field = event.currentTarget;
2076
+ if (!(field instanceof HTMLTextAreaElement))
2077
+ return;
2078
+ insertText(field, links.map(linkify$1).join(''));
2079
+ }
2080
+ function onDragover$1(event) {
2081
+ const transfer = event.dataTransfer;
2082
+ if (transfer)
2083
+ transfer.dropEffect = 'link';
2084
+ }
2085
+ function onPaste$3(event) {
2086
+ const { currentTarget: el } = event;
2087
+ if (shouldSkipFormatting(el))
2088
+ return;
2089
+ const transfer = event.clipboardData;
2090
+ if (!transfer || !hasLink(transfer))
2091
+ return;
2092
+ const links = extractLinks(transfer);
2093
+ if (!links.some(isImageLink))
2094
+ return;
2095
+ event.stopPropagation();
2096
+ event.preventDefault();
2097
+ const field = event.currentTarget;
2098
+ if (!(field instanceof HTMLTextAreaElement))
2099
+ return;
2100
+ insertText(field, links.map(linkify$1).join(''));
2101
+ }
2102
+ function linkify$1(link) {
2103
+ return isImageLink(link) ? `\n![](${link})\n` : link;
2104
+ }
2105
+ function hasFile$1(transfer) {
2106
+ return Array.from(transfer.types).indexOf('Files') >= 0;
2107
+ }
2108
+ function hasLink(transfer) {
2109
+ return Array.from(transfer.types).indexOf('text/uri-list') >= 0;
2110
+ }
2111
+ function extractLinks(transfer) {
2112
+ return (transfer.getData('text/uri-list') || '').split('\r\n');
2113
+ }
2114
+ const IMAGE_RE = /\.(gif|png|jpe?g)$/i;
2115
+ function isImageLink(url) {
2116
+ return IMAGE_RE.test(url);
2117
+ }
2118
+
2119
+ const pasteLinkAsPlainTextOverSelectedTextMap = new WeakMap();
2120
+ function install$2(el, optionConfig) {
2121
+ var _a;
2122
+ pasteLinkAsPlainTextOverSelectedTextMap.set(el, ((_a = optionConfig === null || optionConfig === undefined ? undefined : optionConfig.defaultPlainTextPaste) === null || _a === undefined ? undefined : _a.urlLinks) === true);
2123
+ el.addEventListener('paste', onPaste$2);
2124
+ }
2125
+ function uninstall$2(el) {
2126
+ el.removeEventListener('paste', onPaste$2);
2127
+ }
2128
+ function onPaste$2(event) {
2129
+ var _a;
2130
+ const { currentTarget: el } = event;
2131
+ const element = el;
2132
+ const shouldPasteAsPlainText = (_a = pasteLinkAsPlainTextOverSelectedTextMap.get(element)) !== null && _a !== undefined ? _a : false;
2133
+ const shouldSkipDefaultBehavior = shouldSkipFormatting(element);
2134
+ if ((!shouldPasteAsPlainText && shouldSkipDefaultBehavior) ||
2135
+ (shouldPasteAsPlainText && !shouldSkipDefaultBehavior)) {
2136
+ return;
2137
+ }
2138
+ const transfer = event.clipboardData;
2139
+ if (!transfer || !hasPlainText(transfer))
2140
+ return;
2141
+ const field = event.currentTarget;
2142
+ if (!(field instanceof HTMLTextAreaElement))
2143
+ return;
2144
+ const text = transfer.getData('text/plain');
2145
+ if (!text)
2146
+ return;
2147
+ if (!isURL(text))
2148
+ return;
2149
+ if (isWithinLink(field))
2150
+ return;
2151
+ const selectedText = field.value.substring(field.selectionStart, field.selectionEnd);
2152
+ if (!selectedText.length)
2153
+ return;
2154
+ if (isURL(selectedText.trim()))
2155
+ return;
2156
+ event.stopPropagation();
2157
+ event.preventDefault();
2158
+ insertText(field, linkify(selectedText, text.trim()));
2159
+ }
2160
+ function hasPlainText(transfer) {
2161
+ return Array.from(transfer.types).includes('text/plain');
2162
+ }
2163
+ function isWithinLink(textarea) {
2164
+ const selectionStart = textarea.selectionStart || 0;
2165
+ if (selectionStart > 1) {
2166
+ const previousChars = textarea.value.substring(selectionStart - 2, selectionStart);
2167
+ return previousChars === '](';
2168
+ }
2169
+ else {
2170
+ return false;
2171
+ }
2172
+ }
2173
+ function linkify(selectedText, text) {
2174
+ return `[${selectedText}](${text})`;
2175
+ }
2176
+ function isURL(url) {
2177
+ try {
2178
+ const parsedURL = new URL(url);
2179
+ return removeTrailingSlash(parsedURL.href).trim() === removeTrailingSlash(url).trim();
2180
+ }
2181
+ catch (_a) {
2182
+ return false;
2183
+ }
2184
+ }
2185
+ function removeTrailingSlash(url) {
2186
+ return url.endsWith('/') ? url.slice(0, url.length - 1) : url;
2187
+ }
2188
+
2189
+ function install$1(el) {
2190
+ el.addEventListener('dragover', onDragover);
2191
+ el.addEventListener('drop', onDrop);
2192
+ el.addEventListener('paste', onPaste$1);
2193
+ }
2194
+ function uninstall$1(el) {
2195
+ el.removeEventListener('dragover', onDragover);
2196
+ el.removeEventListener('drop', onDrop);
2197
+ el.removeEventListener('paste', onPaste$1);
2198
+ }
2199
+ function onDrop(event) {
2200
+ const transfer = event.dataTransfer;
2201
+ if (!transfer)
2202
+ return;
2203
+ if (hasFile(transfer))
2204
+ return;
2205
+ const textToPaste = generateText(transfer);
2206
+ if (!textToPaste)
2207
+ return;
2208
+ event.stopPropagation();
2209
+ event.preventDefault();
2210
+ const field = event.currentTarget;
2211
+ if (field instanceof HTMLTextAreaElement) {
2212
+ insertText(field, textToPaste);
2213
+ }
2214
+ }
2215
+ function onDragover(event) {
2216
+ const transfer = event.dataTransfer;
2217
+ if (transfer)
2218
+ transfer.dropEffect = 'copy';
2219
+ }
2220
+ function onPaste$1(event) {
2221
+ const { currentTarget: el } = event;
2222
+ if (shouldSkipFormatting(el))
2223
+ return;
2224
+ if (!event.clipboardData)
2225
+ return;
2226
+ const textToPaste = generateText(event.clipboardData);
2227
+ if (!textToPaste)
2228
+ return;
2229
+ event.stopPropagation();
2230
+ event.preventDefault();
2231
+ const field = event.currentTarget;
2232
+ if (field instanceof HTMLTextAreaElement) {
2233
+ insertText(field, textToPaste);
2234
+ }
2235
+ }
2236
+ function hasFile(transfer) {
2237
+ return Array.from(transfer.types).indexOf('Files') >= 0;
2238
+ }
2239
+ function columnText(column) {
2240
+ const noBreakSpace = '\u00A0';
2241
+ const text = (column.textContent || '').trim().replace(/\|/g, '\\|').replace(/\n/g, ' ');
2242
+ return text || noBreakSpace;
2243
+ }
2244
+ function tableHeaders(row) {
2245
+ return Array.from(row.querySelectorAll('td, th')).map(columnText);
2246
+ }
2247
+ function tableMarkdown(node) {
2248
+ const rows = Array.from(node.querySelectorAll('tr'));
2249
+ const firstRow = rows.shift();
2250
+ if (!firstRow)
2251
+ return '';
2252
+ const headers = tableHeaders(firstRow);
2253
+ const spacers = headers.map(() => '--');
2254
+ const header = `${headers.join(' | ')}\n${spacers.join(' | ')}\n`;
2255
+ const body = rows
2256
+ .map(row => {
2257
+ return Array.from(row.querySelectorAll('td')).map(columnText).join(' | ');
2258
+ })
2259
+ .join('\n');
2260
+ return `\n${header}${body}\n\n`;
2261
+ }
2262
+ function generateText(transfer) {
2263
+ if (Array.from(transfer.types).indexOf('text/html') === -1)
2264
+ return;
2265
+ const html = transfer.getData('text/html');
2266
+ if (!/<table/i.test(html))
2267
+ return;
2268
+ const start = html.substring(0, html.indexOf('<table'));
2269
+ const tableCloseIndex = html.lastIndexOf('</table>');
2270
+ if (!start || !tableCloseIndex)
2271
+ return;
2272
+ const end = html.substring(tableCloseIndex + 8);
2273
+ const parser = new DOMParser();
2274
+ const parsedDocument = parser.parseFromString(html, 'text/html');
2275
+ let table = parsedDocument.querySelector('table');
2276
+ table = !table || table.closest('[data-paste-markdown-skip]') ? null : table;
2277
+ if (!table)
2278
+ return;
2279
+ const formattedTable = tableMarkdown(table);
2280
+ if (!formattedTable)
2281
+ return;
2282
+ return [start, formattedTable, end].join('').replace(/<meta.*?>/, '');
2283
+ }
2284
+
2285
+ function install(el) {
2286
+ el.addEventListener('paste', onPaste);
2287
+ }
2288
+ function uninstall(el) {
2289
+ el.removeEventListener('paste', onPaste);
2290
+ }
2291
+ function onPaste(event) {
2292
+ const { currentTarget: el } = event;
2293
+ if (shouldSkipFormatting(el))
2294
+ return;
2295
+ const transfer = event.clipboardData;
2296
+ if (!transfer || !hasMarkdown(transfer))
2297
+ return;
2298
+ const field = event.currentTarget;
2299
+ if (!(field instanceof HTMLTextAreaElement))
2300
+ return;
2301
+ const text = transfer.getData('text/x-gfm');
2302
+ if (!text)
2303
+ return;
2304
+ event.stopPropagation();
2305
+ event.preventDefault();
2306
+ insertText(field, text);
2307
+ }
2308
+ function hasMarkdown(transfer) {
2309
+ return Array.from(transfer.types).indexOf('text/x-gfm') >= 0;
2310
+ }
2311
+
2312
+ function subscribe(el, optionConfig) {
2313
+ installAround(el, [install$1, install$3, install$2, install, install$4], optionConfig);
2314
+ return {
2315
+ unsubscribe: () => {
2316
+ uninstall$5(el);
2317
+ uninstall$1(el);
2318
+ uninstall$4(el);
2319
+ uninstall$3(el);
2320
+ uninstall$2(el);
2321
+ uninstall(el);
2322
+ },
2323
+ };
2324
+ }
2325
+
2326
+ /* eslint-disable camelcase */
2327
+
2328
+ // upload code from Jeremy Smith's blog post
2329
+ // https://hybrd.co/posts/github-issue-style-file-uploader-using-stimulus-and-active-storage
2330
+
2331
+ // Connects to data-controller="marksmith"
2332
+ class marksmith_controller extends stimulus.Controller {
2333
+ static values = {
2334
+ attachUrl: String,
2335
+ previewUrl: String,
2336
+ extraPreviewParams: { type: Object, default: {} },
2337
+ fieldId: String,
2338
+ }
2339
+
2340
+ static targets = ['fieldContainer', 'fieldElement', 'previewElement', 'writeTabButton', 'previewTabButton', 'toolbar']
2341
+
2342
+ connect() {
2343
+ subscribe(this.fieldContainerTarget, { defaultPlainTextPaste: { urlLinks: true } });
2344
+ }
2345
+
2346
+ switchToWrite(event) {
2347
+ event.preventDefault();
2348
+
2349
+ // toggle buttons
2350
+ this.writeTabButtonTarget.classList.add('ms:hidden');
2351
+ this.previewTabButtonTarget.classList.remove('ms:hidden');
2352
+
2353
+ // toggle write/preview buttons
2354
+ this.fieldContainerTarget.classList.remove('ms:hidden');
2355
+ this.previewElementTarget.classList.add('ms:hidden');
2356
+
2357
+ // toggle the toolbar back
2358
+ this.toolbarTarget.classList.remove('ms:hidden');
2359
+ }
2360
+
2361
+ switchToPreview(event) {
2362
+ event.preventDefault();
2363
+
2364
+ post(this.previewUrlValue, {
2365
+ body: {
2366
+ body: this.fieldElementTarget.value,
2367
+ element_id: this.previewElementTarget.id,
2368
+ extra_params: this.extraPreviewParamsValue,
2369
+ },
2370
+ responseKind: 'turbo-stream',
2371
+ });
2372
+
2373
+ // set the min height to the field element height
2374
+ this.previewElementTarget.style.minHeight = `${this.fieldElementTarget.offsetHeight}px`;
2375
+
2376
+ // toggle buttons
2377
+ this.writeTabButtonTarget.classList.remove('ms:hidden');
2378
+ this.previewTabButtonTarget.classList.add('ms:hidden');
2379
+
2380
+ // toggle elements
2381
+ this.fieldContainerTarget.classList.add('ms:hidden');
2382
+ this.previewElementTarget.classList.remove('ms:hidden');
2383
+
2384
+ // toggle the toolbar
2385
+ this.toolbarTarget.classList.add('ms:hidden');
2386
+ }
2387
+
2388
+ dropUpload(event) {
2389
+ event.preventDefault();
2390
+ this.uploadFiles(event.dataTransfer.files);
2391
+ }
2392
+
2393
+ pasteUpload(event) {
2394
+ if (!event.clipboardData.files.length) return
2395
+
2396
+ event.preventDefault();
2397
+ this.uploadFiles(event.clipboardData.files);
2398
+ }
2399
+
2400
+ buttonUpload(event) {
2401
+ event.preventDefault();
2402
+ // Create a hidden file input and trigger it
2403
+ const fileInput = document.createElement('input');
2404
+ fileInput.type = 'file';
2405
+ fileInput.multiple = true;
2406
+ fileInput.accept = 'image/*,.pdf,.doc,.docx,.txt';
2407
+
2408
+ fileInput.addEventListener('change', (e) => {
2409
+ this.uploadFiles(e.target.files);
2410
+ });
2411
+
2412
+ fileInput.click();
2413
+ }
2414
+
2415
+ uploadFiles(files) {
2416
+ Array.from(files).forEach((file) => this.uploadFile(file));
2417
+ }
2418
+
2419
+ uploadFile(file) {
2420
+ const upload = new DirectUpload(file, this.attachUrlValue);
2421
+
2422
+ upload.create((error, blob) => {
2423
+ if (error) {
2424
+ console.log('Error', error);
2425
+ } else {
2426
+ const text = this.markdownLink(blob);
2427
+ const start = this.fieldElementTarget.selectionStart;
2428
+ const end = this.fieldElementTarget.selectionEnd;
2429
+ this.fieldElementTarget.setRangeText(text, start, end);
2430
+ }
2431
+ });
2432
+ }
2433
+
2434
+ markdownLink(blob) {
2435
+ const { filename } = blob;
2436
+ const url = `/rails/active_storage/blobs/${blob.signed_id}/${filename}`;
2437
+ const prefix = (this.isImage(blob.content_type) ? '!' : '');
2438
+
2439
+ return `${prefix}[${filename}](${url})\n`
2440
+ }
2441
+
2442
+ isImage(contentType) {
2443
+ return ['image/jpeg', 'image/gif', 'image/png'].includes(contentType)
2444
+ }
2445
+ }
2446
+
2447
+ return marksmith_controller;
2448
+
2449
+ })(FakeStimulus);