bard-file_field 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/.nvmrc +1 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +98 -0
  7. data/LICENSE +21 -0
  8. data/README.md +29 -0
  9. data/Rakefile +4 -0
  10. data/app/assets/javascripts/bard-file.js +4913 -0
  11. data/app/controllers/bard/file_field/blobs_controller.rb +11 -0
  12. data/bard-file/.gitignore +1 -0
  13. data/bard-file/bun.lockb +0 -0
  14. data/bard-file/index.js +2 -0
  15. data/bard-file/package.json +20 -0
  16. data/bard-file/rollup.config.js +26 -0
  17. data/bard-file_field.gemspec +34 -0
  18. data/config/routes.rb +6 -0
  19. data/dummy/.gitattributes +7 -0
  20. data/dummy/.gitignore +36 -0
  21. data/dummy/Gemfile +29 -0
  22. data/dummy/Gemfile.lock +353 -0
  23. data/dummy/README.md +24 -0
  24. data/dummy/Rakefile +13 -0
  25. data/dummy/app/assets/config/manifest.js +3 -0
  26. data/dummy/app/assets/images/.keep +0 -0
  27. data/dummy/app/assets/stylesheets/application.css +22 -0
  28. data/dummy/app/controllers/application_controller.rb +2 -0
  29. data/dummy/app/controllers/concerns/.keep +0 -0
  30. data/dummy/app/controllers/edge_cases_controller.rb +23 -0
  31. data/dummy/app/controllers/posts_controller.rb +33 -0
  32. data/dummy/app/controllers/validations_controller.rb +18 -0
  33. data/dummy/app/helpers/application_helper.rb +2 -0
  34. data/dummy/app/javascript/application.js +2 -0
  35. data/dummy/app/javascript/controllers/application.js +9 -0
  36. data/dummy/app/javascript/controllers/index.js +11 -0
  37. data/dummy/app/models/application_record.rb +3 -0
  38. data/dummy/app/models/concerns/.keep +0 -0
  39. data/dummy/app/models/post.rb +9 -0
  40. data/dummy/app/views/edge_cases/rails_validation_error.html.erb +16 -0
  41. data/dummy/app/views/layouts/application.html.erb +18 -0
  42. data/dummy/app/views/layouts/mailer.html.erb +13 -0
  43. data/dummy/app/views/layouts/mailer.text.erb +1 -0
  44. data/dummy/app/views/posts/form.html.erb +39 -0
  45. data/dummy/app/views/posts/show.html.erb +16 -0
  46. data/dummy/app/views/validations/form.html.erb +19 -0
  47. data/dummy/app/views/validations/optional_file.html.erb +10 -0
  48. data/dummy/app/views/validations/optional_file_with_max_size.html.erb +10 -0
  49. data/dummy/app/views/validations/optional_image.html.erb +10 -0
  50. data/dummy/app/views/validations/required_file.html.erb +10 -0
  51. data/dummy/app/views/validations/required_media.html.erb +10 -0
  52. data/dummy/bin/bundle +114 -0
  53. data/dummy/bin/importmap +4 -0
  54. data/dummy/bin/rails +4 -0
  55. data/dummy/bin/rake +4 -0
  56. data/dummy/bin/setup +33 -0
  57. data/dummy/config/application.rb +22 -0
  58. data/dummy/config/boot.rb +4 -0
  59. data/dummy/config/cable.yml +10 -0
  60. data/dummy/config/credentials.yml.enc +1 -0
  61. data/dummy/config/cucumber.yml +2 -0
  62. data/dummy/config/database.yml +25 -0
  63. data/dummy/config/environment.rb +5 -0
  64. data/dummy/config/environments/development.rb +70 -0
  65. data/dummy/config/environments/production.rb +93 -0
  66. data/dummy/config/environments/test.rb +60 -0
  67. data/dummy/config/importmap.rb +4 -0
  68. data/dummy/config/initializers/assets.rb +12 -0
  69. data/dummy/config/initializers/content_security_policy.rb +25 -0
  70. data/dummy/config/initializers/filter_parameter_logging.rb +8 -0
  71. data/dummy/config/initializers/inflections.rb +16 -0
  72. data/dummy/config/initializers/permissions_policy.rb +11 -0
  73. data/dummy/config/locales/en.yml +33 -0
  74. data/dummy/config/puma.rb +43 -0
  75. data/dummy/config/routes.rb +7 -0
  76. data/dummy/config/storage.yml +34 -0
  77. data/dummy/config.ru +6 -0
  78. data/dummy/db/migrate/20231013175203_create_posts.rb +8 -0
  79. data/dummy/db/migrate/20231013175257_create_active_storage_tables.active_storage.rb +57 -0
  80. data/dummy/db/migrate/20231102131420_add_name_to_posts.rb +5 -0
  81. data/dummy/db/schema.rb +50 -0
  82. data/dummy/db/seeds.rb +7 -0
  83. data/dummy/features/edge_cases.feature +17 -0
  84. data/dummy/features/form-persistence.feature +40 -0
  85. data/dummy/features/form_bard_file_field_helper.feature +98 -0
  86. data/dummy/features/support/env.rb +21 -0
  87. data/dummy/features/support/fixtures/empty.3gpp +0 -0
  88. data/dummy/features/support/fixtures/empty.JPEG +0 -0
  89. data/dummy/features/support/fixtures/empty.M4V +0 -0
  90. data/dummy/features/support/fixtures/empty.avi +0 -0
  91. data/dummy/features/support/fixtures/empty.bmp +0 -0
  92. data/dummy/features/support/fixtures/empty.flv +0 -0
  93. data/dummy/features/support/fixtures/empty.gif +0 -0
  94. data/dummy/features/support/fixtures/empty.heic +0 -0
  95. data/dummy/features/support/fixtures/empty.jpeg +0 -0
  96. data/dummy/features/support/fixtures/empty.jpg +0 -0
  97. data/dummy/features/support/fixtures/empty.m4v +0 -0
  98. data/dummy/features/support/fixtures/empty.mkv +0 -0
  99. data/dummy/features/support/fixtures/empty.mov +0 -0
  100. data/dummy/features/support/fixtures/empty.mp4 +0 -0
  101. data/dummy/features/support/fixtures/empty.png +0 -0
  102. data/dummy/features/support/fixtures/empty.tiff +0 -0
  103. data/dummy/features/support/fixtures/empty.webm +0 -0
  104. data/dummy/features/support/fixtures/empty.wmv +0 -0
  105. data/dummy/features/support/fixtures/image.jpg +0 -0
  106. data/dummy/features/support/fixtures/image2.jpg +0 -0
  107. data/dummy/features/support/fixtures/video.mp4 +0 -0
  108. data/dummy/features/support/selectors.rb +63 -0
  109. data/dummy/features/support/step_definitions/download_steps.rb +4 -0
  110. data/dummy/features/support/step_definitions/web_steps.rb +94 -0
  111. data/dummy/features/validations.feature +71 -0
  112. data/dummy/lib/assets/.keep +0 -0
  113. data/dummy/lib/tasks/.keep +0 -0
  114. data/dummy/log/.keep +0 -0
  115. data/dummy/public/404.html +67 -0
  116. data/dummy/public/422.html +67 -0
  117. data/dummy/public/500.html +66 -0
  118. data/dummy/public/apple-touch-icon-precomposed.png +0 -0
  119. data/dummy/public/apple-touch-icon.png +0 -0
  120. data/dummy/public/favicon.ico +0 -0
  121. data/dummy/public/robots.txt +1 -0
  122. data/dummy/storage/.keep +0 -0
  123. data/dummy/test/application_system_test_case.rb +21 -0
  124. data/dummy/test/channels/application_cable/connection_test.rb +11 -0
  125. data/dummy/test/controllers/.keep +0 -0
  126. data/dummy/test/fixtures/files/.keep +0 -0
  127. data/dummy/test/helpers/.keep +0 -0
  128. data/dummy/test/integration/.keep +0 -0
  129. data/dummy/test/mailers/.keep +0 -0
  130. data/dummy/test/models/.keep +0 -0
  131. data/dummy/test/system/.keep +0 -0
  132. data/dummy/test/system/tests_test.rb +9 -0
  133. data/dummy/test/test_helper.rb +13 -0
  134. data/dummy/tmp/.keep +0 -0
  135. data/dummy/tmp/pids/.keep +0 -0
  136. data/dummy/tmp/storage/.keep +0 -0
  137. data/lib/bard/file_field/field.rb +27 -0
  138. data/lib/bard/file_field/form_builder.rb +12 -0
  139. data/lib/bard/file_field/version.rb +7 -0
  140. data/lib/bard/file_field.rb +20 -0
  141. metadata +197 -0
@@ -0,0 +1,4913 @@
1
+ /**
2
+ * A collection of default build flags for a Stencil project.
3
+ *
4
+ * This collection can be found throughout the Stencil codebase, often imported from the `@app-data` module like so:
5
+ * ```ts
6
+ * import { BUILD } from '@app-data';
7
+ * ```
8
+ * and is used to determine if a portion of the output of a Stencil _project_'s compilation step can be eliminated.
9
+ *
10
+ * e.g. When `BUILD.allRenderFn` evaluates to `false`, the compiler will eliminate conditional statements like:
11
+ * ```ts
12
+ * if (BUILD.allRenderFn) {
13
+ * // some code that will be eliminated if BUILD.allRenderFn is false
14
+ * }
15
+ * ```
16
+ *
17
+ * `@app-data`, the module that `BUILD` is imported from, is an alias for the `@stencil/core/internal/app-data`, and is
18
+ * partially referenced by {@link STENCIL_APP_DATA_ID}. The `src/compiler/bundle/app-data-plugin.ts` references
19
+ * `STENCIL_APP_DATA_ID` uses it to replace these defaults with {@link BuildConditionals} that are derived from a
20
+ * Stencil project's contents (i.e. metadata from the components). This replacement happens at a Stencil project's
21
+ * compile time. Such code can be found at `src/compiler/app-core/app-data.ts`.
22
+ */
23
+ const BUILD = {
24
+ allRenderFn: false,
25
+ cmpDidLoad: true,
26
+ cmpDidUnload: false,
27
+ cmpDidUpdate: true,
28
+ cmpDidRender: true,
29
+ cmpWillLoad: true,
30
+ cmpWillUpdate: true,
31
+ cmpWillRender: true,
32
+ connectedCallback: true,
33
+ disconnectedCallback: true,
34
+ element: true,
35
+ event: true,
36
+ hasRenderFn: true,
37
+ lifecycle: true,
38
+ hostListener: true,
39
+ hostListenerTargetWindow: true,
40
+ hostListenerTargetDocument: true,
41
+ hostListenerTargetBody: true,
42
+ hostListenerTargetParent: false,
43
+ hostListenerTarget: true,
44
+ member: true,
45
+ method: true,
46
+ mode: true,
47
+ observeAttribute: true,
48
+ prop: true,
49
+ propMutable: true,
50
+ reflect: true,
51
+ scoped: true,
52
+ shadowDom: true,
53
+ slot: true,
54
+ cssAnnotations: true,
55
+ state: true,
56
+ style: true,
57
+ formAssociated: false,
58
+ svg: true,
59
+ updatable: true,
60
+ vdomAttribute: true,
61
+ vdomXlink: true,
62
+ vdomClass: true,
63
+ vdomFunctional: true,
64
+ vdomKey: true,
65
+ vdomListener: true,
66
+ vdomRef: true,
67
+ vdomPropOrAttr: true,
68
+ vdomRender: true,
69
+ vdomStyle: true,
70
+ vdomText: true,
71
+ watchCallback: true,
72
+ taskQueue: true,
73
+ hotModuleReplacement: false,
74
+ isDebug: false,
75
+ isDev: false,
76
+ isTesting: false,
77
+ hydrateServerSide: false,
78
+ hydrateClientSide: false,
79
+ lifecycleDOMEvents: false,
80
+ lazyLoad: false,
81
+ profile: false,
82
+ slotRelocation: true,
83
+ // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
84
+ appendChildSlotFix: false,
85
+ // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
86
+ cloneNodeFix: false,
87
+ hydratedAttribute: false,
88
+ hydratedClass: true,
89
+ scriptDataOpts: false,
90
+ // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
91
+ scopedSlotTextContentFix: false,
92
+ // TODO(STENCIL-854): Remove code related to legacy shadowDomShim field
93
+ shadowDomShim: false,
94
+ // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
95
+ slotChildNodesFix: false,
96
+ invisiblePrehydration: true,
97
+ propBoolean: true,
98
+ propNumber: true,
99
+ propString: true,
100
+ constructableCSS: true,
101
+ cmpShouldUpdate: true,
102
+ devTools: false,
103
+ shadowDelegatesFocus: true,
104
+ initializeNextTick: false,
105
+ asyncLoading: false,
106
+ asyncQueue: false,
107
+ transformTagName: false,
108
+ attachStyles: true,
109
+ // TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
110
+ experimentalSlotFixes: false,
111
+ };
112
+
113
+ /**
114
+ * Virtual DOM patching algorithm based on Snabbdom by
115
+ * Simon Friis Vindum (@paldepind)
116
+ * Licensed under the MIT License
117
+ * https://github.com/snabbdom/snabbdom/blob/master/LICENSE
118
+ *
119
+ * Modified for Stencil's renderer and slot projection
120
+ */
121
+ let scopeId;
122
+ let contentRef;
123
+ let hostTagName;
124
+ let useNativeShadowDom = false;
125
+ let checkSlotFallbackVisibility = false;
126
+ let checkSlotRelocate = false;
127
+ let isSvgMode = false;
128
+ let renderingRef = null;
129
+ let queuePending = false;
130
+ const createTime = (fnName, tagName = '') => {
131
+ {
132
+ return () => {
133
+ return;
134
+ };
135
+ }
136
+ };
137
+ /**
138
+ * Constant for styles to be globally applied to `slot-fb` elements for pseudo-slot behavior.
139
+ *
140
+ * Two cascading rules must be used instead of a `:not()` selector due to Stencil browser
141
+ * support as of Stencil v4.
142
+ */
143
+ const SLOT_FB_CSS = 'slot-fb{display:contents}slot-fb[hidden]{display:none}';
144
+ const XLINK_NS = 'http://www.w3.org/1999/xlink';
145
+ /**
146
+ * Default style mode id
147
+ */
148
+ /**
149
+ * Reusable empty obj/array
150
+ * Don't add values to these!!
151
+ */
152
+ const EMPTY_OBJ = {};
153
+ /**
154
+ * Namespaces
155
+ */
156
+ const SVG_NS = 'http://www.w3.org/2000/svg';
157
+ const HTML_NS = 'http://www.w3.org/1999/xhtml';
158
+ const isDef = (v) => v != null;
159
+ /**
160
+ * Check whether a value is a 'complex type', defined here as an object or a
161
+ * function.
162
+ *
163
+ * @param o the value to check
164
+ * @returns whether it's a complex type or not
165
+ */
166
+ const isComplexType = (o) => {
167
+ // https://jsperf.com/typeof-fn-object/5
168
+ o = typeof o;
169
+ return o === 'object' || o === 'function';
170
+ };
171
+ /**
172
+ * Helper method for querying a `meta` tag that contains a nonce value
173
+ * out of a DOM's head.
174
+ *
175
+ * @param doc The DOM containing the `head` to query against
176
+ * @returns The content of the meta tag representing the nonce value, or `undefined` if no tag
177
+ * exists or the tag has no content.
178
+ */
179
+ function queryNonceMetaTagContent(doc) {
180
+ var _a, _b, _c;
181
+ return (_c = (_b = (_a = doc.head) === null || _a === void 0 ? void 0 : _a.querySelector('meta[name="csp-nonce"]')) === null || _b === void 0 ? void 0 : _b.getAttribute('content')) !== null && _c !== void 0 ? _c : undefined;
182
+ }
183
+ /**
184
+ * Production h() function based on Preact by
185
+ * Jason Miller (@developit)
186
+ * Licensed under the MIT License
187
+ * https://github.com/developit/preact/blob/master/LICENSE
188
+ *
189
+ * Modified for Stencil's compiler and vdom
190
+ */
191
+ // export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, child?: d.ChildType): d.VNode;
192
+ // export function h(nodeName: string | d.FunctionalComponent, vnodeData: d.PropsType, ...children: d.ChildType[]): d.VNode;
193
+ const h = (nodeName, vnodeData, ...children) => {
194
+ let child = null;
195
+ let key = null;
196
+ let slotName = null;
197
+ let simple = false;
198
+ let lastSimple = false;
199
+ const vNodeChildren = [];
200
+ const walk = (c) => {
201
+ for (let i = 0; i < c.length; i++) {
202
+ child = c[i];
203
+ if (Array.isArray(child)) {
204
+ walk(child);
205
+ }
206
+ else if (child != null && typeof child !== 'boolean') {
207
+ if ((simple = typeof nodeName !== 'function' && !isComplexType(child))) {
208
+ child = String(child);
209
+ }
210
+ if (simple && lastSimple) {
211
+ // If the previous child was simple (string), we merge both
212
+ vNodeChildren[vNodeChildren.length - 1].$text$ += child;
213
+ }
214
+ else {
215
+ // Append a new vNode, if it's text, we create a text vNode
216
+ vNodeChildren.push(simple ? newVNode(null, child) : child);
217
+ }
218
+ lastSimple = simple;
219
+ }
220
+ }
221
+ };
222
+ walk(children);
223
+ if (vnodeData) {
224
+ if (vnodeData.key) {
225
+ key = vnodeData.key;
226
+ }
227
+ if (vnodeData.name) {
228
+ slotName = vnodeData.name;
229
+ }
230
+ // normalize class / className attributes
231
+ {
232
+ const classData = vnodeData.className || vnodeData.class;
233
+ if (classData) {
234
+ vnodeData.class =
235
+ typeof classData !== 'object'
236
+ ? classData
237
+ : Object.keys(classData)
238
+ .filter((k) => classData[k])
239
+ .join(' ');
240
+ }
241
+ }
242
+ }
243
+ if (typeof nodeName === 'function') {
244
+ // nodeName is a functional component
245
+ return nodeName(vnodeData === null ? {} : vnodeData, vNodeChildren, vdomFnUtils);
246
+ }
247
+ const vnode = newVNode(nodeName, null);
248
+ vnode.$attrs$ = vnodeData;
249
+ if (vNodeChildren.length > 0) {
250
+ vnode.$children$ = vNodeChildren;
251
+ }
252
+ {
253
+ vnode.$key$ = key;
254
+ }
255
+ {
256
+ vnode.$name$ = slotName;
257
+ }
258
+ return vnode;
259
+ };
260
+ /**
261
+ * A utility function for creating a virtual DOM node from a tag and some
262
+ * possible text content.
263
+ *
264
+ * @param tag the tag for this element
265
+ * @param text possible text content for the node
266
+ * @returns a newly-minted virtual DOM node
267
+ */
268
+ const newVNode = (tag, text) => {
269
+ const vnode = {
270
+ $flags$: 0,
271
+ $tag$: tag,
272
+ $text$: text,
273
+ $elm$: null,
274
+ $children$: null,
275
+ };
276
+ {
277
+ vnode.$attrs$ = null;
278
+ }
279
+ {
280
+ vnode.$key$ = null;
281
+ }
282
+ {
283
+ vnode.$name$ = null;
284
+ }
285
+ return vnode;
286
+ };
287
+ const Host = {};
288
+ /**
289
+ * Check whether a given node is a Host node or not
290
+ *
291
+ * @param node the virtual DOM node to check
292
+ * @returns whether it's a Host node or not
293
+ */
294
+ const isHost = (node) => node && node.$tag$ === Host;
295
+ /**
296
+ * Implementation of {@link d.FunctionalUtilities} for Stencil's VDom.
297
+ *
298
+ * Note that these functions convert from {@link d.VNode} to
299
+ * {@link d.ChildNode} to give functional component developers a friendly
300
+ * interface.
301
+ */
302
+ const vdomFnUtils = {
303
+ forEach: (children, cb) => children.map(convertToPublic).forEach(cb),
304
+ map: (children, cb) => children.map(convertToPublic).map(cb).map(convertToPrivate),
305
+ };
306
+ /**
307
+ * Convert a {@link d.VNode} to a {@link d.ChildNode} in order to present a
308
+ * friendlier public interface (hence, 'convertToPublic').
309
+ *
310
+ * @param node the virtual DOM node to convert
311
+ * @returns a converted child node
312
+ */
313
+ const convertToPublic = (node) => ({
314
+ vattrs: node.$attrs$,
315
+ vchildren: node.$children$,
316
+ vkey: node.$key$,
317
+ vname: node.$name$,
318
+ vtag: node.$tag$,
319
+ vtext: node.$text$,
320
+ });
321
+ /**
322
+ * Convert a {@link d.ChildNode} back to an equivalent {@link d.VNode} in
323
+ * order to use the resulting object in the virtual DOM. The initial object was
324
+ * likely created as part of presenting a public API, so converting it back
325
+ * involved making it 'private' again (hence, `convertToPrivate`).
326
+ *
327
+ * @param node the child node to convert
328
+ * @returns a converted virtual DOM node
329
+ */
330
+ const convertToPrivate = (node) => {
331
+ if (typeof node.vtag === 'function') {
332
+ const vnodeData = Object.assign({}, node.vattrs);
333
+ if (node.vkey) {
334
+ vnodeData.key = node.vkey;
335
+ }
336
+ if (node.vname) {
337
+ vnodeData.name = node.vname;
338
+ }
339
+ return h(node.vtag, vnodeData, ...(node.vchildren || []));
340
+ }
341
+ const vnode = newVNode(node.vtag, node.vtext);
342
+ vnode.$attrs$ = node.vattrs;
343
+ vnode.$children$ = node.vchildren;
344
+ vnode.$key$ = node.vkey;
345
+ vnode.$name$ = node.vname;
346
+ return vnode;
347
+ };
348
+ // Private
349
+ const computeMode = (elm) => modeResolutionChain.map((h) => h(elm)).find((m) => !!m);
350
+ /**
351
+ * Parse a new property value for a given property type.
352
+ *
353
+ * While the prop value can reasonably be expected to be of `any` type as far as TypeScript's type checker is concerned,
354
+ * it is not safe to assume that the string returned by evaluating `typeof propValue` matches:
355
+ * 1. `any`, the type given to `propValue` in the function signature
356
+ * 2. the type stored from `propType`.
357
+ *
358
+ * This function provides the capability to parse/coerce a property's value to potentially any other JavaScript type.
359
+ *
360
+ * Property values represented in TSX preserve their type information. In the example below, the number 0 is passed to
361
+ * a component. This `propValue` will preserve its type information (`typeof propValue === 'number'`). Note that is
362
+ * based on the type of the value being passed in, not the type declared of the class member decorated with `@Prop`.
363
+ * ```tsx
364
+ * <my-cmp prop-val={0}></my-cmp>
365
+ * ```
366
+ *
367
+ * HTML prop values on the other hand, will always a string
368
+ *
369
+ * @param propValue the new value to coerce to some type
370
+ * @param propType the type of the prop, expressed as a binary number
371
+ * @returns the parsed/coerced value
372
+ */
373
+ const parsePropertyValue = (propValue, propType) => {
374
+ // ensure this value is of the correct prop type
375
+ if (propValue != null && !isComplexType(propValue)) {
376
+ if (propType & 4 /* MEMBER_FLAGS.Boolean */) {
377
+ // per the HTML spec, any string value means it is a boolean true value
378
+ // but we'll cheat here and say that the string "false" is the boolean false
379
+ return propValue === 'false' ? false : propValue === '' || !!propValue;
380
+ }
381
+ if (propType & 2 /* MEMBER_FLAGS.Number */) {
382
+ // force it to be a number
383
+ return parseFloat(propValue);
384
+ }
385
+ if (propType & 1 /* MEMBER_FLAGS.String */) {
386
+ // could have been passed as a number or boolean
387
+ // but we still want it as a string
388
+ return String(propValue);
389
+ }
390
+ // redundant return here for better minification
391
+ return propValue;
392
+ }
393
+ // not sure exactly what type we want
394
+ // so no need to change to a different type
395
+ return propValue;
396
+ };
397
+ const getElement = (ref) => (ref);
398
+ const createEvent = (ref, name, flags) => {
399
+ const elm = getElement(ref);
400
+ return {
401
+ emit: (detail) => {
402
+ return emitEvent(elm, name, {
403
+ bubbles: !!(flags & 4 /* EVENT_FLAGS.Bubbles */),
404
+ composed: !!(flags & 2 /* EVENT_FLAGS.Composed */),
405
+ cancelable: !!(flags & 1 /* EVENT_FLAGS.Cancellable */),
406
+ detail,
407
+ });
408
+ },
409
+ };
410
+ };
411
+ /**
412
+ * Helper function to create & dispatch a custom Event on a provided target
413
+ * @param elm the target of the Event
414
+ * @param name the name to give the custom Event
415
+ * @param opts options for configuring a custom Event
416
+ * @returns the custom Event
417
+ */
418
+ const emitEvent = (elm, name, opts) => {
419
+ const ev = plt.ce(name, opts);
420
+ elm.dispatchEvent(ev);
421
+ return ev;
422
+ };
423
+ const rootAppliedStyles = /*@__PURE__*/ new WeakMap();
424
+ const registerStyle = (scopeId, cssText, allowCS) => {
425
+ let style = styles.get(scopeId);
426
+ if (supportsConstructableStylesheets && allowCS) {
427
+ style = (style || new CSSStyleSheet());
428
+ if (typeof style === 'string') {
429
+ style = cssText;
430
+ }
431
+ else {
432
+ style.replaceSync(cssText);
433
+ }
434
+ }
435
+ else {
436
+ style = cssText;
437
+ }
438
+ styles.set(scopeId, style);
439
+ };
440
+ const addStyle = (styleContainerNode, cmpMeta, mode) => {
441
+ var _a;
442
+ const scopeId = getScopeId(cmpMeta, mode);
443
+ const style = styles.get(scopeId);
444
+ // if an element is NOT connected then getRootNode() will return the wrong root node
445
+ // so the fallback is to always use the document for the root node in those cases
446
+ styleContainerNode = styleContainerNode.nodeType === 11 /* NODE_TYPE.DocumentFragment */ ? styleContainerNode : doc$1;
447
+ if (style) {
448
+ if (typeof style === 'string') {
449
+ styleContainerNode = styleContainerNode.head || styleContainerNode;
450
+ let appliedStyles = rootAppliedStyles.get(styleContainerNode);
451
+ let styleElm;
452
+ if (!appliedStyles) {
453
+ rootAppliedStyles.set(styleContainerNode, (appliedStyles = new Set()));
454
+ }
455
+ if (!appliedStyles.has(scopeId)) {
456
+ {
457
+ styleElm = doc$1.createElement('style');
458
+ styleElm.innerHTML = style;
459
+ // Apply CSP nonce to the style tag if it exists
460
+ const nonce = (_a = plt.$nonce$) !== null && _a !== void 0 ? _a : queryNonceMetaTagContent(doc$1);
461
+ if (nonce != null) {
462
+ styleElm.setAttribute('nonce', nonce);
463
+ }
464
+ styleContainerNode.insertBefore(styleElm, styleContainerNode.querySelector('link'));
465
+ }
466
+ // Add styles for `slot-fb` elements if we're using slots outside the Shadow DOM
467
+ if (cmpMeta.$flags$ & 4 /* CMP_FLAGS.hasSlotRelocation */) {
468
+ styleElm.innerHTML += SLOT_FB_CSS;
469
+ }
470
+ if (appliedStyles) {
471
+ appliedStyles.add(scopeId);
472
+ }
473
+ }
474
+ }
475
+ else if (!styleContainerNode.adoptedStyleSheets.includes(style)) {
476
+ styleContainerNode.adoptedStyleSheets = [...styleContainerNode.adoptedStyleSheets, style];
477
+ }
478
+ }
479
+ return scopeId;
480
+ };
481
+ const attachStyles = (hostRef) => {
482
+ const cmpMeta = hostRef.$cmpMeta$;
483
+ const elm = hostRef.$hostElement$;
484
+ const flags = cmpMeta.$flags$;
485
+ const endAttachStyles = createTime('attachStyles', cmpMeta.$tagName$);
486
+ const scopeId = addStyle(elm.shadowRoot ? elm.shadowRoot : elm.getRootNode(), cmpMeta, hostRef.$modeName$);
487
+ if (flags & 10 /* CMP_FLAGS.needsScopedEncapsulation */) {
488
+ // only required when we're NOT using native shadow dom (slot)
489
+ // or this browser doesn't support native shadow dom
490
+ // and this host element was NOT created with SSR
491
+ // let's pick out the inner content for slot projection
492
+ // create a node to represent where the original
493
+ // content was first placed, which is useful later on
494
+ // DOM WRITE!!
495
+ elm['s-sc'] = scopeId;
496
+ elm.classList.add(scopeId + '-h');
497
+ if (flags & 2 /* CMP_FLAGS.scopedCssEncapsulation */) {
498
+ elm.classList.add(scopeId + '-s');
499
+ }
500
+ }
501
+ endAttachStyles();
502
+ };
503
+ const getScopeId = (cmp, mode) => 'sc-' + (mode && cmp.$flags$ & 32 /* CMP_FLAGS.hasMode */ ? cmp.$tagName$ + '-' + mode : cmp.$tagName$);
504
+ /**
505
+ * Production setAccessor() function based on Preact by
506
+ * Jason Miller (@developit)
507
+ * Licensed under the MIT License
508
+ * https://github.com/developit/preact/blob/master/LICENSE
509
+ *
510
+ * Modified for Stencil's compiler and vdom
511
+ */
512
+ /**
513
+ * When running a VDom render set properties present on a VDom node onto the
514
+ * corresponding HTML element.
515
+ *
516
+ * Note that this function has special functionality for the `class`,
517
+ * `style`, `key`, and `ref` attributes, as well as event handlers (like
518
+ * `onClick`, etc). All others are just passed through as-is.
519
+ *
520
+ * @param elm the HTMLElement onto which attributes should be set
521
+ * @param memberName the name of the attribute to set
522
+ * @param oldValue the old value for the attribute
523
+ * @param newValue the new value for the attribute
524
+ * @param isSvg whether we're in an svg context or not
525
+ * @param flags bitflags for Vdom variables
526
+ */
527
+ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
528
+ if (oldValue !== newValue) {
529
+ let isProp = isMemberInElement(elm, memberName);
530
+ let ln = memberName.toLowerCase();
531
+ if (memberName === 'class') {
532
+ const classList = elm.classList;
533
+ const oldClasses = parseClassList(oldValue);
534
+ const newClasses = parseClassList(newValue);
535
+ classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
536
+ classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
537
+ }
538
+ else if (memberName === 'style') {
539
+ // update style attribute, css properties and values
540
+ {
541
+ for (const prop in oldValue) {
542
+ if (!newValue || newValue[prop] == null) {
543
+ if (prop.includes('-')) {
544
+ elm.style.removeProperty(prop);
545
+ }
546
+ else {
547
+ elm.style[prop] = '';
548
+ }
549
+ }
550
+ }
551
+ }
552
+ for (const prop in newValue) {
553
+ if (!oldValue || newValue[prop] !== oldValue[prop]) {
554
+ if (prop.includes('-')) {
555
+ elm.style.setProperty(prop, newValue[prop]);
556
+ }
557
+ else {
558
+ elm.style[prop] = newValue[prop];
559
+ }
560
+ }
561
+ }
562
+ }
563
+ else if (memberName === 'key')
564
+ ;
565
+ else if (memberName === 'ref') {
566
+ // minifier will clean this up
567
+ if (newValue) {
568
+ newValue(elm);
569
+ }
570
+ }
571
+ else if ((!elm.__lookupSetter__(memberName)) &&
572
+ memberName[0] === 'o' &&
573
+ memberName[1] === 'n') {
574
+ // Event Handlers
575
+ // so if the member name starts with "on" and the 3rd characters is
576
+ // a capital letter, and it's not already a member on the element,
577
+ // then we're assuming it's an event listener
578
+ if (memberName[2] === '-') {
579
+ // on- prefixed events
580
+ // allows to be explicit about the dom event to listen without any magic
581
+ // under the hood:
582
+ // <my-cmp on-click> // listens for "click"
583
+ // <my-cmp on-Click> // listens for "Click"
584
+ // <my-cmp on-ionChange> // listens for "ionChange"
585
+ // <my-cmp on-EVENTS> // listens for "EVENTS"
586
+ memberName = memberName.slice(3);
587
+ }
588
+ else if (isMemberInElement(win, ln)) {
589
+ // standard event
590
+ // the JSX attribute could have been "onMouseOver" and the
591
+ // member name "onmouseover" is on the window's prototype
592
+ // so let's add the listener "mouseover", which is all lowercased
593
+ memberName = ln.slice(2);
594
+ }
595
+ else {
596
+ // custom event
597
+ // the JSX attribute could have been "onMyCustomEvent"
598
+ // so let's trim off the "on" prefix and lowercase the first character
599
+ // and add the listener "myCustomEvent"
600
+ // except for the first character, we keep the event name case
601
+ memberName = ln[2] + memberName.slice(3);
602
+ }
603
+ if (oldValue || newValue) {
604
+ // Need to account for "capture" events.
605
+ // If the event name ends with "Capture", we'll update the name to remove
606
+ // the "Capture" suffix and make sure the event listener is setup to handle the capture event.
607
+ const capture = memberName.endsWith(CAPTURE_EVENT_SUFFIX);
608
+ // Make sure we only replace the last instance of "Capture"
609
+ memberName = memberName.replace(CAPTURE_EVENT_REGEX, '');
610
+ if (oldValue) {
611
+ plt.rel(elm, memberName, oldValue, capture);
612
+ }
613
+ if (newValue) {
614
+ plt.ael(elm, memberName, newValue, capture);
615
+ }
616
+ }
617
+ }
618
+ else {
619
+ // Set property if it exists and it's not a SVG
620
+ const isComplex = isComplexType(newValue);
621
+ if ((isProp || (isComplex && newValue !== null)) && !isSvg) {
622
+ try {
623
+ if (!elm.tagName.includes('-')) {
624
+ const n = newValue == null ? '' : newValue;
625
+ // Workaround for Safari, moving the <input> caret when re-assigning the same valued
626
+ if (memberName === 'list') {
627
+ isProp = false;
628
+ }
629
+ else if (oldValue == null || elm[memberName] != n) {
630
+ elm[memberName] = n;
631
+ }
632
+ }
633
+ else {
634
+ elm[memberName] = newValue;
635
+ }
636
+ }
637
+ catch (e) {
638
+ /**
639
+ * in case someone tries to set a read-only property, e.g. "namespaceURI", we just ignore it
640
+ */
641
+ }
642
+ }
643
+ /**
644
+ * Need to manually update attribute if:
645
+ * - memberName is not an attribute
646
+ * - if we are rendering the host element in order to reflect attribute
647
+ * - if it's a SVG, since properties might not work in <svg>
648
+ * - if the newValue is null/undefined or 'false'.
649
+ */
650
+ let xlink = false;
651
+ {
652
+ if (ln !== (ln = ln.replace(/^xlink\:?/, ''))) {
653
+ memberName = ln;
654
+ xlink = true;
655
+ }
656
+ }
657
+ if (newValue == null || newValue === false) {
658
+ if (newValue !== false || elm.getAttribute(memberName) === '') {
659
+ if (xlink) {
660
+ elm.removeAttributeNS(XLINK_NS, memberName);
661
+ }
662
+ else {
663
+ elm.removeAttribute(memberName);
664
+ }
665
+ }
666
+ }
667
+ else if ((!isProp || flags & 4 /* VNODE_FLAGS.isHost */ || isSvg) && !isComplex) {
668
+ newValue = newValue === true ? '' : newValue;
669
+ if (xlink) {
670
+ elm.setAttributeNS(XLINK_NS, memberName, newValue);
671
+ }
672
+ else {
673
+ elm.setAttribute(memberName, newValue);
674
+ }
675
+ }
676
+ }
677
+ }
678
+ };
679
+ const parseClassListRegex = /\s/;
680
+ /**
681
+ * Parsed a string of classnames into an array
682
+ * @param value className string, e.g. "foo bar baz"
683
+ * @returns list of classes, e.g. ["foo", "bar", "baz"]
684
+ */
685
+ const parseClassList = (value) => (!value ? [] : value.split(parseClassListRegex));
686
+ const CAPTURE_EVENT_SUFFIX = 'Capture';
687
+ const CAPTURE_EVENT_REGEX = new RegExp(CAPTURE_EVENT_SUFFIX + '$');
688
+ const updateElement = (oldVnode, newVnode, isSvgMode, memberName) => {
689
+ // if the element passed in is a shadow root, which is a document fragment
690
+ // then we want to be adding attrs/props to the shadow root's "host" element
691
+ // if it's not a shadow root, then we add attrs/props to the same element
692
+ const elm = newVnode.$elm$.nodeType === 11 /* NODE_TYPE.DocumentFragment */ && newVnode.$elm$.host
693
+ ? newVnode.$elm$.host
694
+ : newVnode.$elm$;
695
+ const oldVnodeAttrs = (oldVnode && oldVnode.$attrs$) || EMPTY_OBJ;
696
+ const newVnodeAttrs = newVnode.$attrs$ || EMPTY_OBJ;
697
+ {
698
+ // remove attributes no longer present on the vnode by setting them to undefined
699
+ for (memberName in oldVnodeAttrs) {
700
+ if (!(memberName in newVnodeAttrs)) {
701
+ setAccessor(elm, memberName, oldVnodeAttrs[memberName], undefined, isSvgMode, newVnode.$flags$);
702
+ }
703
+ }
704
+ }
705
+ // add new & update changed attributes
706
+ for (memberName in newVnodeAttrs) {
707
+ setAccessor(elm, memberName, oldVnodeAttrs[memberName], newVnodeAttrs[memberName], isSvgMode, newVnode.$flags$);
708
+ }
709
+ };
710
+ /**
711
+ * Create a DOM Node corresponding to one of the children of a given VNode.
712
+ *
713
+ * @param oldParentVNode the parent VNode from the previous render
714
+ * @param newParentVNode the parent VNode from the current render
715
+ * @param childIndex the index of the VNode, in the _new_ parent node's
716
+ * children, for which we will create a new DOM node
717
+ * @param parentElm the parent DOM node which our new node will be a child of
718
+ * @returns the newly created node
719
+ */
720
+ const createElm = (oldParentVNode, newParentVNode, childIndex, parentElm) => {
721
+ var _a;
722
+ // tslint:disable-next-line: prefer-const
723
+ const newVNode = newParentVNode.$children$[childIndex];
724
+ let i = 0;
725
+ let elm;
726
+ let childNode;
727
+ let oldVNode;
728
+ if (!useNativeShadowDom) {
729
+ // remember for later we need to check to relocate nodes
730
+ checkSlotRelocate = true;
731
+ if (newVNode.$tag$ === 'slot') {
732
+ if (scopeId) {
733
+ // scoped css needs to add its scoped id to the parent element
734
+ parentElm.classList.add(scopeId + '-s');
735
+ }
736
+ newVNode.$flags$ |= newVNode.$children$
737
+ ? // slot element has fallback content
738
+ 2 /* VNODE_FLAGS.isSlotFallback */
739
+ : // slot element does not have fallback content
740
+ 1 /* VNODE_FLAGS.isSlotReference */;
741
+ }
742
+ }
743
+ if (newVNode.$text$ !== null) {
744
+ // create text node
745
+ elm = newVNode.$elm$ = doc$1.createTextNode(newVNode.$text$);
746
+ }
747
+ else if (newVNode.$flags$ & 1 /* VNODE_FLAGS.isSlotReference */) {
748
+ // create a slot reference node
749
+ elm = newVNode.$elm$ =
750
+ doc$1.createTextNode('');
751
+ }
752
+ else {
753
+ if (!isSvgMode) {
754
+ isSvgMode = newVNode.$tag$ === 'svg';
755
+ }
756
+ // create element
757
+ elm = newVNode.$elm$ = (doc$1.createElementNS(isSvgMode ? SVG_NS : HTML_NS, newVNode.$flags$ & 2 /* VNODE_FLAGS.isSlotFallback */
758
+ ? 'slot-fb'
759
+ : newVNode.$tag$)
760
+ );
761
+ if (isSvgMode && newVNode.$tag$ === 'foreignObject') {
762
+ isSvgMode = false;
763
+ }
764
+ // add css classes, attrs, props, listeners, etc.
765
+ {
766
+ updateElement(null, newVNode, isSvgMode);
767
+ }
768
+ if (isDef(scopeId) && elm['s-si'] !== scopeId) {
769
+ // if there is a scopeId and this is the initial render
770
+ // then let's add the scopeId as a css class
771
+ elm.classList.add((elm['s-si'] = scopeId));
772
+ }
773
+ if (newVNode.$children$) {
774
+ for (i = 0; i < newVNode.$children$.length; ++i) {
775
+ // create the node
776
+ childNode = createElm(oldParentVNode, newVNode, i, elm);
777
+ // return node could have been null
778
+ if (childNode) {
779
+ // append our new node
780
+ elm.appendChild(childNode);
781
+ }
782
+ }
783
+ }
784
+ {
785
+ if (newVNode.$tag$ === 'svg') {
786
+ // Only reset the SVG context when we're exiting <svg> element
787
+ isSvgMode = false;
788
+ }
789
+ else if (elm.tagName === 'foreignObject') {
790
+ // Reenter SVG context when we're exiting <foreignObject> element
791
+ isSvgMode = true;
792
+ }
793
+ }
794
+ }
795
+ {
796
+ elm['s-hn'] = hostTagName;
797
+ if (newVNode.$flags$ & (2 /* VNODE_FLAGS.isSlotFallback */ | 1 /* VNODE_FLAGS.isSlotReference */)) {
798
+ // remember the content reference comment
799
+ elm['s-sr'] = true;
800
+ // Persist the name of the slot that this slot was going to be projected into.
801
+ elm['s-fs'] = (_a = newVNode.$attrs$) === null || _a === void 0 ? void 0 : _a.slot;
802
+ // remember the content reference comment
803
+ elm['s-cr'] = contentRef;
804
+ // remember the slot name, or empty string for default slot
805
+ elm['s-sn'] = newVNode.$name$ || '';
806
+ // check if we've got an old vnode for this slot
807
+ oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];
808
+ if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) {
809
+ // we've got an old slot vnode and the wrapper is being replaced
810
+ // so let's move the old slot content back to it's original location
811
+ putBackInOriginalLocation(oldParentVNode.$elm$, false);
812
+ }
813
+ }
814
+ }
815
+ return elm;
816
+ };
817
+ const putBackInOriginalLocation = (parentElm, recursive) => {
818
+ var _a;
819
+ plt.$flags$ |= 1 /* PLATFORM_FLAGS.isTmpDisconnected */;
820
+ const oldSlotChildNodes = parentElm.childNodes;
821
+ for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) {
822
+ const childNode = oldSlotChildNodes[i];
823
+ if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) {
824
+ // // this child node in the old element is from another component
825
+ // // remove this node from the old slot's parent
826
+ // childNode.remove();
827
+ // and relocate it back to it's original location
828
+ parentReferenceNode(childNode).insertBefore(childNode, referenceNode(childNode));
829
+ // remove the old original location comment entirely
830
+ // later on the patch function will know what to do
831
+ // and move this to the correct spot if need be
832
+ childNode['s-ol'].remove();
833
+ childNode['s-ol'] = undefined;
834
+ // Reset so we can correctly move the node around again.
835
+ childNode['s-sh'] = undefined;
836
+ // When putting an element node back in its original location,
837
+ // we need to reset the `slot` attribute back to the value it originally had
838
+ // so we can correctly relocate it again in the future
839
+ if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
840
+ childNode.setAttribute('slot', (_a = childNode['s-sn']) !== null && _a !== void 0 ? _a : '');
841
+ }
842
+ checkSlotRelocate = true;
843
+ }
844
+ if (recursive) {
845
+ putBackInOriginalLocation(childNode, recursive);
846
+ }
847
+ }
848
+ plt.$flags$ &= ~1 /* PLATFORM_FLAGS.isTmpDisconnected */;
849
+ };
850
+ /**
851
+ * Create DOM nodes corresponding to a list of {@link d.Vnode} objects and
852
+ * add them to the DOM in the appropriate place.
853
+ *
854
+ * @param parentElm the DOM node which should be used as a parent for the new
855
+ * DOM nodes
856
+ * @param before a child of the `parentElm` which the new children should be
857
+ * inserted before (optional)
858
+ * @param parentVNode the parent virtual DOM node
859
+ * @param vnodes the new child virtual DOM nodes to produce DOM nodes for
860
+ * @param startIdx the index in the child virtual DOM nodes at which to start
861
+ * creating DOM nodes (inclusive)
862
+ * @param endIdx the index in the child virtual DOM nodes at which to stop
863
+ * creating DOM nodes (inclusive)
864
+ */
865
+ const addVnodes = (parentElm, before, parentVNode, vnodes, startIdx, endIdx) => {
866
+ let containerElm = ((parentElm['s-cr'] && parentElm['s-cr'].parentNode) || parentElm);
867
+ let childNode;
868
+ if (containerElm.shadowRoot && containerElm.tagName === hostTagName) {
869
+ containerElm = containerElm.shadowRoot;
870
+ }
871
+ for (; startIdx <= endIdx; ++startIdx) {
872
+ if (vnodes[startIdx]) {
873
+ childNode = createElm(null, parentVNode, startIdx, parentElm);
874
+ if (childNode) {
875
+ vnodes[startIdx].$elm$ = childNode;
876
+ containerElm.insertBefore(childNode, referenceNode(before) );
877
+ }
878
+ }
879
+ }
880
+ };
881
+ /**
882
+ * Remove the DOM elements corresponding to a list of {@link d.VNode} objects.
883
+ * This can be used to, for instance, clean up after a list of children which
884
+ * should no longer be shown.
885
+ *
886
+ * This function also handles some of Stencil's slot relocation logic.
887
+ *
888
+ * @param vnodes a list of virtual DOM nodes to remove
889
+ * @param startIdx the index at which to start removing nodes (inclusive)
890
+ * @param endIdx the index at which to stop removing nodes (inclusive)
891
+ */
892
+ const removeVnodes = (vnodes, startIdx, endIdx) => {
893
+ for (let index = startIdx; index <= endIdx; ++index) {
894
+ const vnode = vnodes[index];
895
+ if (vnode) {
896
+ const elm = vnode.$elm$;
897
+ nullifyVNodeRefs(vnode);
898
+ if (elm) {
899
+ {
900
+ // we're removing this element
901
+ // so it's possible we need to show slot fallback content now
902
+ checkSlotFallbackVisibility = true;
903
+ if (elm['s-ol']) {
904
+ // remove the original location comment
905
+ elm['s-ol'].remove();
906
+ }
907
+ else {
908
+ // it's possible that child nodes of the node
909
+ // that's being removed are slot nodes
910
+ putBackInOriginalLocation(elm, true);
911
+ }
912
+ }
913
+ // remove the vnode's element from the dom
914
+ elm.remove();
915
+ }
916
+ }
917
+ }
918
+ };
919
+ /**
920
+ * Reconcile the children of a new VNode with the children of an old VNode by
921
+ * traversing the two collections of children, identifying nodes that are
922
+ * conserved or changed, calling out to `patch` to make any necessary
923
+ * updates to the DOM, and rearranging DOM nodes as needed.
924
+ *
925
+ * The algorithm for reconciling children works by analyzing two 'windows' onto
926
+ * the two arrays of children (`oldCh` and `newCh`). We keep track of the
927
+ * 'windows' by storing start and end indices and references to the
928
+ * corresponding array entries. Initially the two 'windows' are basically equal
929
+ * to the entire array, but we progressively narrow the windows until there are
930
+ * no children left to update by doing the following:
931
+ *
932
+ * 1. Skip any `null` entries at the beginning or end of the two arrays, so
933
+ * that if we have an initial array like the following we'll end up dealing
934
+ * only with a window bounded by the highlighted elements:
935
+ *
936
+ * [null, null, VNode1 , ... , VNode2, null, null]
937
+ * ^^^^^^ ^^^^^^
938
+ *
939
+ * 2. Check to see if the elements at the head and tail positions are equal
940
+ * across the windows. This will basically detect elements which haven't
941
+ * been added, removed, or changed position, i.e. if you had the following
942
+ * VNode elements (represented as HTML):
943
+ *
944
+ * oldVNode: `<div><p><span>HEY</span></p></div>`
945
+ * newVNode: `<div><p><span>THERE</span></p></div>`
946
+ *
947
+ * Then when comparing the children of the `<div>` tag we check the equality
948
+ * of the VNodes corresponding to the `<p>` tags and, since they are the
949
+ * same tag in the same position, we'd be able to avoid completely
950
+ * re-rendering the subtree under them with a new DOM element and would just
951
+ * call out to `patch` to handle reconciling their children and so on.
952
+ *
953
+ * 3. Check, for both windows, to see if the element at the beginning of the
954
+ * window corresponds to the element at the end of the other window. This is
955
+ * a heuristic which will let us identify _some_ situations in which
956
+ * elements have changed position, for instance it _should_ detect that the
957
+ * children nodes themselves have not changed but merely moved in the
958
+ * following example:
959
+ *
960
+ * oldVNode: `<div><element-one /><element-two /></div>`
961
+ * newVNode: `<div><element-two /><element-one /></div>`
962
+ *
963
+ * If we find cases like this then we also need to move the concrete DOM
964
+ * elements corresponding to the moved children to write the re-order to the
965
+ * DOM.
966
+ *
967
+ * 4. Finally, if VNodes have the `key` attribute set on them we check for any
968
+ * nodes in the old children which have the same key as the first element in
969
+ * our window on the new children. If we find such a node we handle calling
970
+ * out to `patch`, moving relevant DOM nodes, and so on, in accordance with
971
+ * what we find.
972
+ *
973
+ * Finally, once we've narrowed our 'windows' to the point that either of them
974
+ * collapse (i.e. they have length 0) we then handle any remaining VNode
975
+ * insertion or deletion that needs to happen to get a DOM state that correctly
976
+ * reflects the new child VNodes. If, for instance, after our window on the old
977
+ * children has collapsed we still have more nodes on the new children that
978
+ * we haven't dealt with yet then we need to add them, or if the new children
979
+ * collapse but we still have unhandled _old_ children then we need to make
980
+ * sure the corresponding DOM nodes are removed.
981
+ *
982
+ * @param parentElm the node into which the parent VNode is rendered
983
+ * @param oldCh the old children of the parent node
984
+ * @param newVNode the new VNode which will replace the parent
985
+ * @param newCh the new children of the parent node
986
+ */
987
+ const updateChildren = (parentElm, oldCh, newVNode, newCh) => {
988
+ let oldStartIdx = 0;
989
+ let newStartIdx = 0;
990
+ let idxInOld = 0;
991
+ let i = 0;
992
+ let oldEndIdx = oldCh.length - 1;
993
+ let oldStartVnode = oldCh[0];
994
+ let oldEndVnode = oldCh[oldEndIdx];
995
+ let newEndIdx = newCh.length - 1;
996
+ let newStartVnode = newCh[0];
997
+ let newEndVnode = newCh[newEndIdx];
998
+ let node;
999
+ let elmToMove;
1000
+ while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
1001
+ if (oldStartVnode == null) {
1002
+ // VNode might have been moved left
1003
+ oldStartVnode = oldCh[++oldStartIdx];
1004
+ }
1005
+ else if (oldEndVnode == null) {
1006
+ oldEndVnode = oldCh[--oldEndIdx];
1007
+ }
1008
+ else if (newStartVnode == null) {
1009
+ newStartVnode = newCh[++newStartIdx];
1010
+ }
1011
+ else if (newEndVnode == null) {
1012
+ newEndVnode = newCh[--newEndIdx];
1013
+ }
1014
+ else if (isSameVnode(oldStartVnode, newStartVnode)) {
1015
+ // if the start nodes are the same then we should patch the new VNode
1016
+ // onto the old one, and increment our `newStartIdx` and `oldStartIdx`
1017
+ // indices to reflect that. We don't need to move any DOM Nodes around
1018
+ // since things are matched up in order.
1019
+ patch(oldStartVnode, newStartVnode);
1020
+ oldStartVnode = oldCh[++oldStartIdx];
1021
+ newStartVnode = newCh[++newStartIdx];
1022
+ }
1023
+ else if (isSameVnode(oldEndVnode, newEndVnode)) {
1024
+ // likewise, if the end nodes are the same we patch new onto old and
1025
+ // decrement our end indices, and also likewise in this case we don't
1026
+ // need to move any DOM Nodes.
1027
+ patch(oldEndVnode, newEndVnode);
1028
+ oldEndVnode = oldCh[--oldEndIdx];
1029
+ newEndVnode = newCh[--newEndIdx];
1030
+ }
1031
+ else if (isSameVnode(oldStartVnode, newEndVnode)) {
1032
+ // case: "Vnode moved right"
1033
+ //
1034
+ // We've found that the last node in our window on the new children is
1035
+ // the same VNode as the _first_ node in our window on the old children
1036
+ // we're dealing with now. Visually, this is the layout of these two
1037
+ // nodes:
1038
+ //
1039
+ // newCh: [..., newStartVnode , ... , newEndVnode , ...]
1040
+ // ^^^^^^^^^^^
1041
+ // oldCh: [..., oldStartVnode , ... , oldEndVnode , ...]
1042
+ // ^^^^^^^^^^^^^
1043
+ //
1044
+ // In this situation we need to patch `newEndVnode` onto `oldStartVnode`
1045
+ // and move the DOM element for `oldStartVnode`.
1046
+ if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
1047
+ putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);
1048
+ }
1049
+ patch(oldStartVnode, newEndVnode);
1050
+ // We need to move the element for `oldStartVnode` into a position which
1051
+ // will be appropriate for `newEndVnode`. For this we can use
1052
+ // `.insertBefore` and `oldEndVnode.$elm$.nextSibling`. If there is a
1053
+ // sibling for `oldEndVnode.$elm$` then we want to move the DOM node for
1054
+ // `oldStartVnode` between `oldEndVnode` and it's sibling, like so:
1055
+ //
1056
+ // <old-start-node />
1057
+ // <some-intervening-node />
1058
+ // <old-end-node />
1059
+ // <!-- -> <-- `oldStartVnode.$elm$` should be inserted here
1060
+ // <next-sibling />
1061
+ //
1062
+ // If instead `oldEndVnode.$elm$` has no sibling then we just want to put
1063
+ // the node for `oldStartVnode` at the end of the children of
1064
+ // `parentElm`. Luckily, `Node.nextSibling` will return `null` if there
1065
+ // aren't any siblings, and passing `null` to `Node.insertBefore` will
1066
+ // append it to the children of the parent element.
1067
+ parentElm.insertBefore(oldStartVnode.$elm$, oldEndVnode.$elm$.nextSibling);
1068
+ oldStartVnode = oldCh[++oldStartIdx];
1069
+ newEndVnode = newCh[--newEndIdx];
1070
+ }
1071
+ else if (isSameVnode(oldEndVnode, newStartVnode)) {
1072
+ // case: "Vnode moved left"
1073
+ //
1074
+ // We've found that the first node in our window on the new children is
1075
+ // the same VNode as the _last_ node in our window on the old children.
1076
+ // Visually, this is the layout of these two nodes:
1077
+ //
1078
+ // newCh: [..., newStartVnode , ... , newEndVnode , ...]
1079
+ // ^^^^^^^^^^^^^
1080
+ // oldCh: [..., oldStartVnode , ... , oldEndVnode , ...]
1081
+ // ^^^^^^^^^^^
1082
+ //
1083
+ // In this situation we need to patch `newStartVnode` onto `oldEndVnode`
1084
+ // (which will handle updating any changed attributes, reconciling their
1085
+ // children etc) but we also need to move the DOM node to which
1086
+ // `oldEndVnode` corresponds.
1087
+ if ((oldStartVnode.$tag$ === 'slot' || newEndVnode.$tag$ === 'slot')) {
1088
+ putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);
1089
+ }
1090
+ patch(oldEndVnode, newStartVnode);
1091
+ // We've already checked above if `oldStartVnode` and `newStartVnode` are
1092
+ // the same node, so since we're here we know that they are not. Thus we
1093
+ // can move the element for `oldEndVnode` _before_ the element for
1094
+ // `oldStartVnode`, leaving `oldStartVnode` to be reconciled in the
1095
+ // future.
1096
+ parentElm.insertBefore(oldEndVnode.$elm$, oldStartVnode.$elm$);
1097
+ oldEndVnode = oldCh[--oldEndIdx];
1098
+ newStartVnode = newCh[++newStartIdx];
1099
+ }
1100
+ else {
1101
+ // Here we do some checks to match up old and new nodes based on the
1102
+ // `$key$` attribute, which is set by putting a `key="my-key"` attribute
1103
+ // in the JSX for a DOM element in the implementation of a Stencil
1104
+ // component.
1105
+ //
1106
+ // First we check to see if there are any nodes in the array of old
1107
+ // children which have the same key as the first node in the new
1108
+ // children.
1109
+ idxInOld = -1;
1110
+ {
1111
+ for (i = oldStartIdx; i <= oldEndIdx; ++i) {
1112
+ if (oldCh[i] && oldCh[i].$key$ !== null && oldCh[i].$key$ === newStartVnode.$key$) {
1113
+ idxInOld = i;
1114
+ break;
1115
+ }
1116
+ }
1117
+ }
1118
+ if (idxInOld >= 0) {
1119
+ // We found a node in the old children which matches up with the first
1120
+ // node in the new children! So let's deal with that
1121
+ elmToMove = oldCh[idxInOld];
1122
+ if (elmToMove.$tag$ !== newStartVnode.$tag$) {
1123
+ // the tag doesn't match so we'll need a new DOM element
1124
+ node = createElm(oldCh && oldCh[newStartIdx], newVNode, idxInOld, parentElm);
1125
+ }
1126
+ else {
1127
+ patch(elmToMove, newStartVnode);
1128
+ // invalidate the matching old node so that we won't try to update it
1129
+ // again later on
1130
+ oldCh[idxInOld] = undefined;
1131
+ node = elmToMove.$elm$;
1132
+ }
1133
+ newStartVnode = newCh[++newStartIdx];
1134
+ }
1135
+ else {
1136
+ // We either didn't find an element in the old children that matches
1137
+ // the key of the first new child OR the build is not using `key`
1138
+ // attributes at all. In either case we need to create a new element
1139
+ // for the new node.
1140
+ node = createElm(oldCh && oldCh[newStartIdx], newVNode, newStartIdx, parentElm);
1141
+ newStartVnode = newCh[++newStartIdx];
1142
+ }
1143
+ if (node) {
1144
+ // if we created a new node then handle inserting it to the DOM
1145
+ {
1146
+ parentReferenceNode(oldStartVnode.$elm$).insertBefore(node, referenceNode(oldStartVnode.$elm$));
1147
+ }
1148
+ }
1149
+ }
1150
+ }
1151
+ if (oldStartIdx > oldEndIdx) {
1152
+ // we have some more new nodes to add which don't match up with old nodes
1153
+ addVnodes(parentElm, newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].$elm$, newVNode, newCh, newStartIdx, newEndIdx);
1154
+ }
1155
+ else if (newStartIdx > newEndIdx) {
1156
+ // there are nodes in the `oldCh` array which no longer correspond to nodes
1157
+ // in the new array, so lets remove them (which entails cleaning up the
1158
+ // relevant DOM nodes)
1159
+ removeVnodes(oldCh, oldStartIdx, oldEndIdx);
1160
+ }
1161
+ };
1162
+ /**
1163
+ * Compare two VNodes to determine if they are the same
1164
+ *
1165
+ * **NB**: This function is an equality _heuristic_ based on the available
1166
+ * information set on the two VNodes and can be misleading under certain
1167
+ * circumstances. In particular, if the two nodes do not have `key` attrs
1168
+ * (available under `$key$` on VNodes) then the function falls back on merely
1169
+ * checking that they have the same tag.
1170
+ *
1171
+ * So, in other words, if `key` attrs are not set on VNodes which may be
1172
+ * changing order within a `children` array or something along those lines then
1173
+ * we could obtain a false negative and then have to do needless re-rendering
1174
+ * (i.e. we'd say two VNodes aren't equal when in fact they should be).
1175
+ *
1176
+ * @param leftVNode the first VNode to check
1177
+ * @param rightVNode the second VNode to check
1178
+ * @returns whether they're equal or not
1179
+ */
1180
+ const isSameVnode = (leftVNode, rightVNode) => {
1181
+ // compare if two vnode to see if they're "technically" the same
1182
+ // need to have the same element tag, and same key to be the same
1183
+ if (leftVNode.$tag$ === rightVNode.$tag$) {
1184
+ if (leftVNode.$tag$ === 'slot') {
1185
+ return leftVNode.$name$ === rightVNode.$name$;
1186
+ }
1187
+ // this will be set if components in the build have `key` attrs set on them
1188
+ {
1189
+ return leftVNode.$key$ === rightVNode.$key$;
1190
+ }
1191
+ }
1192
+ return false;
1193
+ };
1194
+ const referenceNode = (node) => {
1195
+ // this node was relocated to a new location in the dom
1196
+ // because of some other component's slot
1197
+ // but we still have an html comment in place of where
1198
+ // it's original location was according to it's original vdom
1199
+ return (node && node['s-ol']) || node;
1200
+ };
1201
+ const parentReferenceNode = (node) => (node['s-ol'] ? node['s-ol'] : node).parentNode;
1202
+ /**
1203
+ * Handle reconciling an outdated VNode with a new one which corresponds to
1204
+ * it. This function handles flushing updates to the DOM and reconciling the
1205
+ * children of the two nodes (if any).
1206
+ *
1207
+ * @param oldVNode an old VNode whose DOM element and children we want to update
1208
+ * @param newVNode a new VNode representing an updated version of the old one
1209
+ */
1210
+ const patch = (oldVNode, newVNode) => {
1211
+ const elm = (newVNode.$elm$ = oldVNode.$elm$);
1212
+ const oldChildren = oldVNode.$children$;
1213
+ const newChildren = newVNode.$children$;
1214
+ const tag = newVNode.$tag$;
1215
+ const text = newVNode.$text$;
1216
+ let defaultHolder;
1217
+ if (text === null) {
1218
+ {
1219
+ // test if we're rendering an svg element, or still rendering nodes inside of one
1220
+ // only add this to the when the compiler sees we're using an svg somewhere
1221
+ isSvgMode = tag === 'svg' ? true : tag === 'foreignObject' ? false : isSvgMode;
1222
+ }
1223
+ {
1224
+ if (tag === 'slot')
1225
+ ;
1226
+ else {
1227
+ // either this is the first render of an element OR it's an update
1228
+ // AND we already know it's possible it could have changed
1229
+ // this updates the element's css classes, attrs, props, listeners, etc.
1230
+ updateElement(oldVNode, newVNode, isSvgMode);
1231
+ }
1232
+ }
1233
+ if (oldChildren !== null && newChildren !== null) {
1234
+ // looks like there's child vnodes for both the old and new vnodes
1235
+ // so we need to call `updateChildren` to reconcile them
1236
+ updateChildren(elm, oldChildren, newVNode, newChildren);
1237
+ }
1238
+ else if (newChildren !== null) {
1239
+ // no old child vnodes, but there are new child vnodes to add
1240
+ if (oldVNode.$text$ !== null) {
1241
+ // the old vnode was text, so be sure to clear it out
1242
+ elm.textContent = '';
1243
+ }
1244
+ // add the new vnode children
1245
+ addVnodes(elm, null, newVNode, newChildren, 0, newChildren.length - 1);
1246
+ }
1247
+ else if (oldChildren !== null) {
1248
+ // no new child vnodes, but there are old child vnodes to remove
1249
+ removeVnodes(oldChildren, 0, oldChildren.length - 1);
1250
+ }
1251
+ if (isSvgMode && tag === 'svg') {
1252
+ isSvgMode = false;
1253
+ }
1254
+ }
1255
+ else if ((defaultHolder = elm['s-cr'])) {
1256
+ // this element has slotted content
1257
+ defaultHolder.parentNode.textContent = text;
1258
+ }
1259
+ else if (oldVNode.$text$ !== text) {
1260
+ // update the text content for the text only vnode
1261
+ // and also only if the text is different than before
1262
+ elm.data = text;
1263
+ }
1264
+ };
1265
+ /**
1266
+ * Adjust the `.hidden` property as-needed on any nodes in a DOM subtree which
1267
+ * are slot fallbacks nodes.
1268
+ *
1269
+ * A slot fallback node should be visible by default. Then, it should be
1270
+ * conditionally hidden if:
1271
+ *
1272
+ * - it has a sibling with a `slot` property set to its slot name or if
1273
+ * - it is a default fallback slot node, in which case we hide if it has any
1274
+ * content
1275
+ *
1276
+ * @param elm the element of interest
1277
+ */
1278
+ const updateFallbackSlotVisibility = (elm) => {
1279
+ const childNodes = elm.childNodes;
1280
+ for (const childNode of childNodes) {
1281
+ if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1282
+ if (childNode['s-sr']) {
1283
+ // this is a slot fallback node
1284
+ // get the slot name for this slot reference node
1285
+ const slotName = childNode['s-sn'];
1286
+ // by default always show a fallback slot node
1287
+ // then hide it if there are other slots in the light dom
1288
+ childNode.hidden = false;
1289
+ // we need to check all of its sibling nodes in order to see if
1290
+ // `childNode` should be hidden
1291
+ for (const siblingNode of childNodes) {
1292
+ // Don't check the node against itself
1293
+ if (siblingNode !== childNode) {
1294
+ if (siblingNode['s-hn'] !== childNode['s-hn'] || slotName !== '') {
1295
+ // this sibling node is from a different component OR is a named
1296
+ // fallback slot node
1297
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ &&
1298
+ (slotName === siblingNode.getAttribute('slot') || slotName === siblingNode['s-sn'])) {
1299
+ childNode.hidden = true;
1300
+ break;
1301
+ }
1302
+ }
1303
+ else {
1304
+ // this is a default fallback slot node
1305
+ // any element or text node (with content)
1306
+ // should hide the default fallback slot node
1307
+ if (siblingNode.nodeType === 1 /* NODE_TYPE.ElementNode */ ||
1308
+ (siblingNode.nodeType === 3 /* NODE_TYPE.TextNode */ && siblingNode.textContent.trim() !== '')) {
1309
+ childNode.hidden = true;
1310
+ break;
1311
+ }
1312
+ }
1313
+ }
1314
+ }
1315
+ }
1316
+ // keep drilling down
1317
+ updateFallbackSlotVisibility(childNode);
1318
+ }
1319
+ }
1320
+ };
1321
+ /**
1322
+ * Component-global information about nodes which are either currently being
1323
+ * relocated or will be shortly.
1324
+ */
1325
+ const relocateNodes = [];
1326
+ /**
1327
+ * Mark the contents of a slot for relocation via adding references to them to
1328
+ * the {@link relocateNodes} data structure. The actual work of relocating them
1329
+ * will then be handled in {@link renderVdom}.
1330
+ *
1331
+ * @param elm a render node whose child nodes need to be relocated
1332
+ */
1333
+ const markSlotContentForRelocation = (elm) => {
1334
+ // tslint:disable-next-line: prefer-const
1335
+ let node;
1336
+ let hostContentNodes;
1337
+ let j;
1338
+ for (const childNode of elm.childNodes) {
1339
+ // we need to find child nodes which are slot references so we can then try
1340
+ // to match them up with nodes that need to be relocated
1341
+ if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) {
1342
+ // first get the content reference comment node ('s-cr'), then we get
1343
+ // its parent, which is where all the host content is now
1344
+ hostContentNodes = node.parentNode.childNodes;
1345
+ const slotName = childNode['s-sn'];
1346
+ // iterate through all the nodes under the location where the host was
1347
+ // originally rendered
1348
+ for (j = hostContentNodes.length - 1; j >= 0; j--) {
1349
+ node = hostContentNodes[j];
1350
+ // check that the node is not a content reference node or a node
1351
+ // reference and then check that the host name does not match that of
1352
+ // childNode.
1353
+ // In addition, check that the slot either has not already been relocated, or
1354
+ // that its current location's host is not childNode's host. This is essentially
1355
+ // a check so that we don't try to relocate (and then hide) a node that is already
1356
+ // where it should be.
1357
+ if (!node['s-cn'] &&
1358
+ !node['s-nr'] &&
1359
+ node['s-hn'] !== childNode['s-hn'] &&
1360
+ (!BUILD.experimentalSlotFixes )) {
1361
+ // if `node` is located in the slot that `childNode` refers to (via the
1362
+ // `'s-sn'` property) then we need to relocate it from it's current spot
1363
+ // (under the host element parent) to the right slot location
1364
+ if (isNodeLocatedInSlot(node, slotName)) {
1365
+ // it's possible we've already decided to relocate this node
1366
+ let relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
1367
+ // made some changes to slots
1368
+ // let's make sure we also double check
1369
+ // fallbacks are correctly hidden or shown
1370
+ checkSlotFallbackVisibility = true;
1371
+ // ensure that the slot-name attr is correct
1372
+ node['s-sn'] = node['s-sn'] || slotName;
1373
+ if (relocateNodeData) {
1374
+ relocateNodeData.$nodeToRelocate$['s-sh'] = childNode['s-hn'];
1375
+ // we marked this node for relocation previously but didn't find
1376
+ // out the slot reference node to which it needs to be relocated
1377
+ // so write it down now!
1378
+ relocateNodeData.$slotRefNode$ = childNode;
1379
+ }
1380
+ else {
1381
+ node['s-sh'] = childNode['s-hn'];
1382
+ // add to our list of nodes to relocate
1383
+ relocateNodes.push({
1384
+ $slotRefNode$: childNode,
1385
+ $nodeToRelocate$: node,
1386
+ });
1387
+ }
1388
+ if (node['s-sr']) {
1389
+ relocateNodes.map((relocateNode) => {
1390
+ if (isNodeLocatedInSlot(relocateNode.$nodeToRelocate$, node['s-sn'])) {
1391
+ relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
1392
+ if (relocateNodeData && !relocateNode.$slotRefNode$) {
1393
+ relocateNode.$slotRefNode$ = relocateNodeData.$slotRefNode$;
1394
+ }
1395
+ }
1396
+ });
1397
+ }
1398
+ }
1399
+ else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {
1400
+ // the node is not found within the slot (`childNode`) that we're
1401
+ // currently looking at, so we stick it into `relocateNodes` to
1402
+ // handle later. If we never find a home for this element then
1403
+ // we'll need to hide it
1404
+ relocateNodes.push({
1405
+ $nodeToRelocate$: node,
1406
+ });
1407
+ }
1408
+ }
1409
+ }
1410
+ }
1411
+ // if we're dealing with any type of element (capable of itself being a
1412
+ // slot reference or containing one) then we recur
1413
+ if (childNode.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1414
+ markSlotContentForRelocation(childNode);
1415
+ }
1416
+ }
1417
+ };
1418
+ /**
1419
+ * Check whether a node is located in a given named slot.
1420
+ *
1421
+ * @param nodeToRelocate the node of interest
1422
+ * @param slotName the slot name to check
1423
+ * @returns whether the node is located in the slot or not
1424
+ */
1425
+ const isNodeLocatedInSlot = (nodeToRelocate, slotName) => {
1426
+ if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1427
+ if (nodeToRelocate.getAttribute('slot') === null && slotName === '') {
1428
+ // if the node doesn't have a slot attribute, and the slot we're checking
1429
+ // is not a named slot, then we assume the node should be within the slot
1430
+ return true;
1431
+ }
1432
+ if (nodeToRelocate.getAttribute('slot') === slotName) {
1433
+ return true;
1434
+ }
1435
+ return false;
1436
+ }
1437
+ if (nodeToRelocate['s-sn'] === slotName) {
1438
+ return true;
1439
+ }
1440
+ return slotName === '';
1441
+ };
1442
+ /**
1443
+ * 'Nullify' any VDom `ref` callbacks on a VDom node or its children by calling
1444
+ * them with `null`. This signals that the DOM element corresponding to the VDom
1445
+ * node has been removed from the DOM.
1446
+ *
1447
+ * @param vNode a virtual DOM node
1448
+ */
1449
+ const nullifyVNodeRefs = (vNode) => {
1450
+ {
1451
+ vNode.$attrs$ && vNode.$attrs$.ref && vNode.$attrs$.ref(null);
1452
+ vNode.$children$ && vNode.$children$.map(nullifyVNodeRefs);
1453
+ }
1454
+ };
1455
+ /**
1456
+ * The main entry point for Stencil's virtual DOM-based rendering engine
1457
+ *
1458
+ * Given a {@link d.HostRef} container and some virtual DOM nodes, this
1459
+ * function will handle creating a virtual DOM tree with a single root, patching
1460
+ * the current virtual DOM tree onto an old one (if any), dealing with slot
1461
+ * relocation, and reflecting attributes.
1462
+ *
1463
+ * @param hostRef data needed to root and render the virtual DOM tree, such as
1464
+ * the DOM node into which it should be rendered.
1465
+ * @param renderFnResults the virtual DOM nodes to be rendered
1466
+ * @param isInitialLoad whether or not this is the first call after page load
1467
+ */
1468
+ const renderVdom = (hostRef, renderFnResults, isInitialLoad = false) => {
1469
+ var _a, _b;
1470
+ const hostElm = hostRef.$hostElement$;
1471
+ const cmpMeta = hostRef.$cmpMeta$;
1472
+ const oldVNode = hostRef.$vnode$ || newVNode(null, null);
1473
+ // if `renderFnResults` is a Host node then we can use it directly. If not,
1474
+ // we need to call `h` again to wrap the children of our component in a
1475
+ // 'dummy' Host node (well, an empty vnode) since `renderVdom` assumes
1476
+ // implicitly that the top-level vdom node is 1) an only child and 2)
1477
+ // contains attrs that need to be set on the host element.
1478
+ const rootVnode = isHost(renderFnResults) ? renderFnResults : h(null, null, renderFnResults);
1479
+ hostTagName = hostElm.tagName;
1480
+ if (cmpMeta.$attrsToReflect$) {
1481
+ rootVnode.$attrs$ = rootVnode.$attrs$ || {};
1482
+ cmpMeta.$attrsToReflect$.map(([propName, attribute]) => (rootVnode.$attrs$[attribute] = hostElm[propName]));
1483
+ }
1484
+ // On the first render and *only* on the first render we want to check for
1485
+ // any attributes set on the host element which are also set on the vdom
1486
+ // node. If we find them, we override the value on the VDom node attrs with
1487
+ // the value from the host element, which allows developers building apps
1488
+ // with Stencil components to override e.g. the `role` attribute on a
1489
+ // component even if it's already set on the `Host`.
1490
+ if (isInitialLoad && rootVnode.$attrs$) {
1491
+ for (const key of Object.keys(rootVnode.$attrs$)) {
1492
+ // We have a special implementation in `setAccessor` for `style` and
1493
+ // `class` which reconciles values coming from the VDom with values
1494
+ // already present on the DOM element, so we don't want to override those
1495
+ // attributes on the VDom tree with values from the host element if they
1496
+ // are present.
1497
+ //
1498
+ // Likewise, `ref` and `key` are special internal values for the Stencil
1499
+ // runtime and we don't want to override those either.
1500
+ if (hostElm.hasAttribute(key) && !['key', 'ref', 'style', 'class'].includes(key)) {
1501
+ rootVnode.$attrs$[key] = hostElm[key];
1502
+ }
1503
+ }
1504
+ }
1505
+ rootVnode.$tag$ = null;
1506
+ rootVnode.$flags$ |= 4 /* VNODE_FLAGS.isHost */;
1507
+ hostRef.$vnode$ = rootVnode;
1508
+ rootVnode.$elm$ = oldVNode.$elm$ = (hostElm.shadowRoot || hostElm );
1509
+ {
1510
+ scopeId = hostElm['s-sc'];
1511
+ }
1512
+ {
1513
+ contentRef = hostElm['s-cr'];
1514
+ useNativeShadowDom = (cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */) !== 0;
1515
+ // always reset
1516
+ checkSlotFallbackVisibility = false;
1517
+ }
1518
+ // synchronous patch
1519
+ patch(oldVNode, rootVnode);
1520
+ {
1521
+ // while we're moving nodes around existing nodes, temporarily disable
1522
+ // the disconnectCallback from working
1523
+ plt.$flags$ |= 1 /* PLATFORM_FLAGS.isTmpDisconnected */;
1524
+ if (checkSlotRelocate) {
1525
+ markSlotContentForRelocation(rootVnode.$elm$);
1526
+ for (const relocateData of relocateNodes) {
1527
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1528
+ if (!nodeToRelocate['s-ol']) {
1529
+ // add a reference node marking this node's original location
1530
+ // keep a reference to this node for later lookups
1531
+ const orgLocationNode = doc$1.createTextNode('');
1532
+ orgLocationNode['s-nr'] = nodeToRelocate;
1533
+ nodeToRelocate.parentNode.insertBefore((nodeToRelocate['s-ol'] = orgLocationNode), nodeToRelocate);
1534
+ }
1535
+ }
1536
+ for (const relocateData of relocateNodes) {
1537
+ const nodeToRelocate = relocateData.$nodeToRelocate$;
1538
+ const slotRefNode = relocateData.$slotRefNode$;
1539
+ if (slotRefNode) {
1540
+ const parentNodeRef = slotRefNode.parentNode;
1541
+ // When determining where to insert content, the most simple case would be
1542
+ // to relocate the node immediately following the slot reference node. We do this
1543
+ // by getting a reference to the node immediately following the slot reference node
1544
+ // since we will use `insertBefore` to manipulate the DOM.
1545
+ //
1546
+ // If there is no node immediately following the slot reference node, then we will just
1547
+ // end up appending the node as the last child of the parent.
1548
+ let insertBeforeNode = slotRefNode.nextSibling;
1549
+ // If the node we're currently planning on inserting the new node before is an element,
1550
+ // we need to do some additional checks to make sure we're inserting the node in the correct order.
1551
+ // The use case here would be that we have multiple nodes being relocated to the same slot. So, we want
1552
+ // to make sure they get inserted into their new how in the same order they were declared in their original location.
1553
+ //
1554
+ // TODO(STENCIL-914): Remove `experimentalSlotFixes` check
1555
+ {
1556
+ let orgLocationNode = (_a = nodeToRelocate['s-ol']) === null || _a === void 0 ? void 0 : _a.previousSibling;
1557
+ while (orgLocationNode) {
1558
+ let refNode = (_b = orgLocationNode['s-nr']) !== null && _b !== void 0 ? _b : null;
1559
+ if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) {
1560
+ refNode = refNode.nextSibling;
1561
+ if (!refNode || !refNode['s-nr']) {
1562
+ insertBeforeNode = refNode;
1563
+ break;
1564
+ }
1565
+ }
1566
+ orgLocationNode = orgLocationNode.previousSibling;
1567
+ }
1568
+ }
1569
+ if ((!insertBeforeNode && parentNodeRef !== nodeToRelocate.parentNode) ||
1570
+ nodeToRelocate.nextSibling !== insertBeforeNode) {
1571
+ // we've checked that it's worth while to relocate
1572
+ // since that the node to relocate
1573
+ // has a different next sibling or parent relocated
1574
+ if (nodeToRelocate !== insertBeforeNode) {
1575
+ if (!nodeToRelocate['s-hn'] && nodeToRelocate['s-ol']) {
1576
+ // probably a component in the index.html that doesn't have its hostname set
1577
+ nodeToRelocate['s-hn'] = nodeToRelocate['s-ol'].parentNode.nodeName;
1578
+ }
1579
+ // Add it back to the dom but in its new home
1580
+ // If we get to this point and `insertBeforeNode` is `null`, that means
1581
+ // we're just going to append the node as the last child of the parent. Passing
1582
+ // `null` as the second arg here will trigger that behavior.
1583
+ parentNodeRef.insertBefore(nodeToRelocate, insertBeforeNode);
1584
+ }
1585
+ }
1586
+ }
1587
+ else {
1588
+ // this node doesn't have a slot home to go to, so let's hide it
1589
+ if (nodeToRelocate.nodeType === 1 /* NODE_TYPE.ElementNode */) {
1590
+ nodeToRelocate.hidden = true;
1591
+ }
1592
+ }
1593
+ }
1594
+ }
1595
+ if (checkSlotFallbackVisibility) {
1596
+ updateFallbackSlotVisibility(rootVnode.$elm$);
1597
+ }
1598
+ // done moving nodes around
1599
+ // allow the disconnect callback to work again
1600
+ plt.$flags$ &= ~1 /* PLATFORM_FLAGS.isTmpDisconnected */;
1601
+ // always reset
1602
+ relocateNodes.length = 0;
1603
+ }
1604
+ };
1605
+ const attachToAncestor = (hostRef, ancestorComponent) => {
1606
+ };
1607
+ const scheduleUpdate = (hostRef, isInitialLoad) => {
1608
+ {
1609
+ hostRef.$flags$ |= 16 /* HOST_FLAGS.isQueuedForUpdate */;
1610
+ }
1611
+ attachToAncestor(hostRef, hostRef.$ancestorComponent$);
1612
+ // there is no ancestor component or the ancestor component
1613
+ // has already fired off its lifecycle update then
1614
+ // fire off the initial update
1615
+ const dispatch = () => dispatchHooks(hostRef, isInitialLoad);
1616
+ return writeTask(dispatch) ;
1617
+ };
1618
+ /**
1619
+ * Dispatch initial-render and update lifecycle hooks, enqueuing calls to
1620
+ * component lifecycle methods like `componentWillLoad` as well as
1621
+ * {@link updateComponent}, which will kick off the virtual DOM re-render.
1622
+ *
1623
+ * @param hostRef a reference to a host DOM node
1624
+ * @param isInitialLoad whether we're on the initial load or not
1625
+ * @returns an empty Promise which is used to enqueue a series of operations for
1626
+ * the component
1627
+ */
1628
+ const dispatchHooks = (hostRef, isInitialLoad) => {
1629
+ const elm = hostRef.$hostElement$;
1630
+ const endSchedule = createTime('scheduleUpdate', hostRef.$cmpMeta$.$tagName$);
1631
+ const instance = elm;
1632
+ // We're going to use this variable together with `enqueue` to implement a
1633
+ // little promise-based queue. We start out with it `undefined`. When we add
1634
+ // the first function to the queue we'll set this variable to be that
1635
+ // function's return value. When we attempt to add subsequent values to the
1636
+ // queue we'll check that value and, if it was a `Promise`, we'll then chain
1637
+ // the new function off of that `Promise` using `.then()`. This will give our
1638
+ // queue two nice properties:
1639
+ //
1640
+ // 1. If all functions added to the queue are synchronous they'll be called
1641
+ // synchronously right away.
1642
+ // 2. If all functions added to the queue are asynchronous they'll all be
1643
+ // called in order after `dispatchHooks` exits.
1644
+ let maybePromise;
1645
+ if (isInitialLoad) {
1646
+ {
1647
+ // If `componentWillLoad` returns a `Promise` then we want to wait on
1648
+ // whatever's going on in that `Promise` before we launch into
1649
+ // rendering the component, doing other lifecycle stuff, etc. So
1650
+ // in that case we assign the returned promise to the variable we
1651
+ // declared above to hold a possible 'queueing' Promise
1652
+ maybePromise = safeCall(instance, 'componentWillLoad');
1653
+ }
1654
+ }
1655
+ else {
1656
+ {
1657
+ // Like `componentWillLoad` above, we allow Stencil component
1658
+ // authors to return a `Promise` from this lifecycle callback, and
1659
+ // we specify that our runtime will wait for that `Promise` to
1660
+ // resolve before the component re-renders. So if the method
1661
+ // returns a `Promise` we need to keep it around!
1662
+ maybePromise = safeCall(instance, 'componentWillUpdate');
1663
+ }
1664
+ }
1665
+ {
1666
+ maybePromise = enqueue(maybePromise, () => safeCall(instance, 'componentWillRender'));
1667
+ }
1668
+ endSchedule();
1669
+ return enqueue(maybePromise, () => updateComponent(hostRef, instance, isInitialLoad));
1670
+ };
1671
+ /**
1672
+ * This function uses a Promise to implement a simple first-in, first-out queue
1673
+ * of functions to be called.
1674
+ *
1675
+ * The queue is ordered on the basis of the first argument. If it's
1676
+ * `undefined`, then nothing is on the queue yet, so the provided function can
1677
+ * be called synchronously (although note that this function may return a
1678
+ * `Promise`). The idea is that then the return value of that enqueueing
1679
+ * operation is kept around, so that if it was a `Promise` then subsequent
1680
+ * functions can be enqueued by calling this function again with that `Promise`
1681
+ * as the first argument.
1682
+ *
1683
+ * @param maybePromise either a `Promise` which should resolve before the next function is called or an 'empty' sentinel
1684
+ * @param fn a function to enqueue
1685
+ * @returns either a `Promise` or the return value of the provided function
1686
+ */
1687
+ const enqueue = (maybePromise, fn) => isPromisey(maybePromise) ? maybePromise.then(fn) : fn();
1688
+ /**
1689
+ * Check that a value is a `Promise`. To check, we first see if the value is an
1690
+ * instance of the `Promise` global. In a few circumstances, in particular if
1691
+ * the global has been overwritten, this is could be misleading, so we also do
1692
+ * a little 'duck typing' check to see if the `.then` property of the value is
1693
+ * defined and a function.
1694
+ *
1695
+ * @param maybePromise it might be a promise!
1696
+ * @returns whether it is or not
1697
+ */
1698
+ const isPromisey = (maybePromise) => maybePromise instanceof Promise ||
1699
+ (maybePromise && maybePromise.then && typeof maybePromise.then === 'function');
1700
+ /**
1701
+ * Update a component given reference to its host elements and so on.
1702
+ *
1703
+ * @param hostRef an object containing references to the element's host node,
1704
+ * VDom nodes, and other metadata
1705
+ * @param instance a reference to the underlying host element where it will be
1706
+ * rendered
1707
+ * @param isInitialLoad whether or not this function is being called as part of
1708
+ * the first render cycle
1709
+ */
1710
+ const updateComponent = async (hostRef, instance, isInitialLoad) => {
1711
+ const elm = hostRef.$hostElement$;
1712
+ const endUpdate = createTime('update', hostRef.$cmpMeta$.$tagName$);
1713
+ elm['s-rc'];
1714
+ if (isInitialLoad) {
1715
+ // DOM WRITE!
1716
+ attachStyles(hostRef);
1717
+ }
1718
+ const endRender = createTime('render', hostRef.$cmpMeta$.$tagName$);
1719
+ {
1720
+ callRender(hostRef, instance, elm, isInitialLoad);
1721
+ }
1722
+ endRender();
1723
+ endUpdate();
1724
+ {
1725
+ postUpdateComponent(hostRef);
1726
+ }
1727
+ };
1728
+ /**
1729
+ * Handle making the call to the VDom renderer with the proper context given
1730
+ * various build variables
1731
+ *
1732
+ * @param hostRef an object containing references to the element's host node,
1733
+ * VDom nodes, and other metadata
1734
+ * @param instance a reference to the underlying host element where it will be
1735
+ * rendered
1736
+ * @param elm the Host element for the component
1737
+ * @param isInitialLoad whether or not this function is being called as part of
1738
+ * @returns an empty promise
1739
+ */
1740
+ const callRender = (hostRef, instance, elm, isInitialLoad) => {
1741
+ // in order for bundlers to correctly tree-shake the BUILD object
1742
+ // we need to ensure BUILD is not deoptimized within a try/catch
1743
+ // https://rollupjs.org/guide/en/#treeshake tryCatchDeoptimization
1744
+ const allRenderFn = false;
1745
+ const lazyLoad = false;
1746
+ const taskQueue = true ;
1747
+ const updatable = true ;
1748
+ try {
1749
+ renderingRef = instance;
1750
+ /**
1751
+ * minification optimization: `allRenderFn` is `true` if all components have a `render`
1752
+ * method, so we can call the method immediately. If not, check before calling it.
1753
+ */
1754
+ instance = allRenderFn ? instance.render() : instance.render && instance.render();
1755
+ if (updatable && taskQueue) {
1756
+ hostRef.$flags$ &= ~16 /* HOST_FLAGS.isQueuedForUpdate */;
1757
+ }
1758
+ if (updatable || lazyLoad) {
1759
+ hostRef.$flags$ |= 2 /* HOST_FLAGS.hasRendered */;
1760
+ }
1761
+ if (BUILD.hasRenderFn || BUILD.reflect) {
1762
+ if (BUILD.vdomRender || BUILD.reflect) {
1763
+ // looks like we've got child nodes to render into this host element
1764
+ // or we need to update the css class/attrs on the host element
1765
+ // DOM WRITE!
1766
+ if (BUILD.hydrateServerSide) ;
1767
+ else {
1768
+ renderVdom(hostRef, instance, isInitialLoad);
1769
+ }
1770
+ }
1771
+ }
1772
+ }
1773
+ catch (e) {
1774
+ consoleError(e, hostRef.$hostElement$);
1775
+ }
1776
+ renderingRef = null;
1777
+ return null;
1778
+ };
1779
+ const postUpdateComponent = (hostRef) => {
1780
+ const tagName = hostRef.$cmpMeta$.$tagName$;
1781
+ const elm = hostRef.$hostElement$;
1782
+ const endPostUpdate = createTime('postUpdate', tagName);
1783
+ const instance = elm;
1784
+ hostRef.$ancestorComponent$;
1785
+ {
1786
+ safeCall(instance, 'componentDidRender');
1787
+ }
1788
+ if (!(hostRef.$flags$ & 64 /* HOST_FLAGS.hasLoadedComponent */)) {
1789
+ hostRef.$flags$ |= 64 /* HOST_FLAGS.hasLoadedComponent */;
1790
+ {
1791
+ safeCall(instance, 'componentDidLoad');
1792
+ }
1793
+ endPostUpdate();
1794
+ }
1795
+ else {
1796
+ {
1797
+ safeCall(instance, 'componentDidUpdate');
1798
+ }
1799
+ endPostUpdate();
1800
+ }
1801
+ // ( •_•)
1802
+ // ( •_•)>⌐■-■
1803
+ // (⌐■_■)
1804
+ };
1805
+ /**
1806
+ * Allows to safely call a method, e.g. `componentDidLoad`, on an instance,
1807
+ * e.g. custom element node. If a build figures out that e.g. no component
1808
+ * has a `componentDidLoad` method, the instance method gets removed from the
1809
+ * output bundle and this function returns `undefined`.
1810
+ * @param instance any object that may or may not contain methods
1811
+ * @param method method name
1812
+ * @param arg single arbitrary argument
1813
+ * @returns result of method call if it exists, otherwise `undefined`
1814
+ */
1815
+ const safeCall = (instance, method, arg) => {
1816
+ if (instance && instance[method]) {
1817
+ try {
1818
+ return instance[method](arg);
1819
+ }
1820
+ catch (e) {
1821
+ consoleError(e);
1822
+ }
1823
+ }
1824
+ return undefined;
1825
+ };
1826
+ const getValue = (ref, propName) => getHostRef(ref).$instanceValues$.get(propName);
1827
+ const setValue = (ref, propName, newVal, cmpMeta) => {
1828
+ // check our new property value against our internal value
1829
+ const hostRef = getHostRef(ref);
1830
+ const elm = ref;
1831
+ const oldVal = hostRef.$instanceValues$.get(propName);
1832
+ const flags = hostRef.$flags$;
1833
+ const instance = elm;
1834
+ newVal = parsePropertyValue(newVal, cmpMeta.$members$[propName][0]);
1835
+ // explicitly check for NaN on both sides, as `NaN === NaN` is always false
1836
+ const areBothNaN = Number.isNaN(oldVal) && Number.isNaN(newVal);
1837
+ const didValueChange = newVal !== oldVal && !areBothNaN;
1838
+ if (didValueChange) {
1839
+ // gadzooks! the property's value has changed!!
1840
+ // set our new value!
1841
+ hostRef.$instanceValues$.set(propName, newVal);
1842
+ {
1843
+ // get an array of method names of watch functions to call
1844
+ if (cmpMeta.$watchers$ && flags & 128 /* HOST_FLAGS.isWatchReady */) {
1845
+ const watchMethods = cmpMeta.$watchers$[propName];
1846
+ if (watchMethods) {
1847
+ // this instance is watching for when this property changed
1848
+ watchMethods.map((watchMethodName) => {
1849
+ try {
1850
+ // fire off each of the watch methods that are watching this property
1851
+ instance[watchMethodName](newVal, oldVal, propName);
1852
+ }
1853
+ catch (e) {
1854
+ consoleError(e, elm);
1855
+ }
1856
+ });
1857
+ }
1858
+ }
1859
+ if ((flags & (2 /* HOST_FLAGS.hasRendered */ | 16 /* HOST_FLAGS.isQueuedForUpdate */)) === 2 /* HOST_FLAGS.hasRendered */) {
1860
+ if (instance.componentShouldUpdate) {
1861
+ if (instance.componentShouldUpdate(newVal, oldVal, propName) === false) {
1862
+ return;
1863
+ }
1864
+ }
1865
+ // looks like this value actually changed, so we've got work to do!
1866
+ // but only if we've already rendered, otherwise just chill out
1867
+ // queue that we need to do an update, but don't worry about queuing
1868
+ // up millions cuz this function ensures it only runs once
1869
+ scheduleUpdate(hostRef, false);
1870
+ }
1871
+ }
1872
+ }
1873
+ };
1874
+ /**
1875
+ * Attach a series of runtime constructs to a compiled Stencil component
1876
+ * constructor, including getters and setters for the `@Prop` and `@State`
1877
+ * decorators, callbacks for when attributes change, and so on.
1878
+ *
1879
+ * @param Cstr the constructor for a component that we need to process
1880
+ * @param cmpMeta metadata collected previously about the component
1881
+ * @param flags a number used to store a series of bit flags
1882
+ * @returns a reference to the same constructor passed in (but now mutated)
1883
+ */
1884
+ const proxyComponent = (Cstr, cmpMeta, flags) => {
1885
+ var _a;
1886
+ const prototype = Cstr.prototype;
1887
+ if (cmpMeta.$members$) {
1888
+ if (Cstr.watchers) {
1889
+ cmpMeta.$watchers$ = Cstr.watchers;
1890
+ }
1891
+ // It's better to have a const than two Object.entries()
1892
+ const members = Object.entries(cmpMeta.$members$);
1893
+ members.map(([memberName, [memberFlags]]) => {
1894
+ if ((memberFlags & 31 /* MEMBER_FLAGS.Prop */ ||
1895
+ (memberFlags & 32 /* MEMBER_FLAGS.State */))) {
1896
+ // proxyComponent - prop
1897
+ Object.defineProperty(prototype, memberName, {
1898
+ get() {
1899
+ // proxyComponent, get value
1900
+ return getValue(this, memberName);
1901
+ },
1902
+ set(newValue) {
1903
+ // proxyComponent, set value
1904
+ setValue(this, memberName, newValue, cmpMeta);
1905
+ },
1906
+ configurable: true,
1907
+ enumerable: true,
1908
+ });
1909
+ }
1910
+ });
1911
+ {
1912
+ const attrNameToPropName = new Map();
1913
+ prototype.attributeChangedCallback = function (attrName, oldValue, newValue) {
1914
+ plt.jmp(() => {
1915
+ var _a;
1916
+ const propName = attrNameToPropName.get(attrName);
1917
+ // In a web component lifecycle the attributeChangedCallback runs prior to connectedCallback
1918
+ // in the case where an attribute was set inline.
1919
+ // ```html
1920
+ // <my-component some-attribute="some-value"></my-component>
1921
+ // ```
1922
+ //
1923
+ // There is an edge case where a developer sets the attribute inline on a custom element and then
1924
+ // programmatically changes it before it has been upgraded as shown below:
1925
+ //
1926
+ // ```html
1927
+ // <!-- this component has _not_ been upgraded yet -->
1928
+ // <my-component id="test" some-attribute="some-value"></my-component>
1929
+ // <script>
1930
+ // // grab non-upgraded component
1931
+ // el = document.querySelector("#test");
1932
+ // el.someAttribute = "another-value";
1933
+ // // upgrade component
1934
+ // customElements.define('my-component', MyComponent);
1935
+ // </script>
1936
+ // ```
1937
+ // In this case if we do not un-shadow here and use the value of the shadowing property, attributeChangedCallback
1938
+ // will be called with `newValue = "some-value"` and will set the shadowed property (this.someAttribute = "another-value")
1939
+ // to the value that was set inline i.e. "some-value" from above example. When
1940
+ // the connectedCallback attempts to un-shadow it will use "some-value" as the initial value rather than "another-value"
1941
+ //
1942
+ // The case where the attribute was NOT set inline but was not set programmatically shall be handled/un-shadowed
1943
+ // by connectedCallback as this attributeChangedCallback will not fire.
1944
+ //
1945
+ // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
1946
+ //
1947
+ // TODO(STENCIL-16) we should think about whether or not we actually want to be reflecting the attributes to
1948
+ // properties here given that this goes against best practices outlined here
1949
+ // https://developers.google.com/web/fundamentals/web-components/best-practices#avoid-reentrancy
1950
+ if (this.hasOwnProperty(propName)) {
1951
+ newValue = this[propName];
1952
+ delete this[propName];
1953
+ }
1954
+ else if (prototype.hasOwnProperty(propName) &&
1955
+ typeof this[propName] === 'number' &&
1956
+ this[propName] == newValue) {
1957
+ // if the propName exists on the prototype of `Cstr`, this update may be a result of Stencil using native
1958
+ // APIs to reflect props as attributes. Calls to `setAttribute(someElement, propName)` will result in
1959
+ // `propName` to be converted to a `DOMString`, which may not be what we want for other primitive props.
1960
+ return;
1961
+ }
1962
+ else if (propName == null) {
1963
+ // At this point we should know this is not a "member", so we can treat it like watching an attribute
1964
+ // on a vanilla web component
1965
+ const hostRef = getHostRef(this);
1966
+ const flags = hostRef === null || hostRef === void 0 ? void 0 : hostRef.$flags$;
1967
+ // We only want to trigger the callback(s) if:
1968
+ // 1. The instance is ready
1969
+ // 2. The watchers are ready
1970
+ // 3. The value has changed
1971
+ if (flags &&
1972
+ !(flags & 8 /* HOST_FLAGS.isConstructingInstance */) &&
1973
+ flags & 128 /* HOST_FLAGS.isWatchReady */ &&
1974
+ newValue !== oldValue) {
1975
+ const elm = this;
1976
+ const instance = elm;
1977
+ const entry = (_a = cmpMeta.$watchers$) === null || _a === void 0 ? void 0 : _a[attrName];
1978
+ entry === null || entry === void 0 ? void 0 : entry.forEach((callbackName) => {
1979
+ if (instance[callbackName] != null) {
1980
+ instance[callbackName].call(instance, newValue, oldValue, attrName);
1981
+ }
1982
+ });
1983
+ }
1984
+ return;
1985
+ }
1986
+ this[propName] = newValue === null && typeof this[propName] === 'boolean' ? false : newValue;
1987
+ });
1988
+ };
1989
+ // Create an array of attributes to observe
1990
+ // This list in comprised of all strings used within a `@Watch()` decorator
1991
+ // on a component as well as any Stencil-specific "members" (`@Prop()`s and `@State()`s).
1992
+ // As such, there is no way to guarantee type-safety here that a user hasn't entered
1993
+ // an invalid attribute.
1994
+ Cstr.observedAttributes = Array.from(new Set([
1995
+ ...Object.keys((_a = cmpMeta.$watchers$) !== null && _a !== void 0 ? _a : {}),
1996
+ ...members
1997
+ .filter(([_, m]) => m[0] & 15 /* MEMBER_FLAGS.HasAttribute */)
1998
+ .map(([propName, m]) => {
1999
+ var _a;
2000
+ const attrName = m[1] || propName;
2001
+ attrNameToPropName.set(attrName, propName);
2002
+ if (m[0] & 512 /* MEMBER_FLAGS.ReflectAttr */) {
2003
+ (_a = cmpMeta.$attrsToReflect$) === null || _a === void 0 ? void 0 : _a.push([propName, attrName]);
2004
+ }
2005
+ return attrName;
2006
+ }),
2007
+ ]));
2008
+ }
2009
+ }
2010
+ return Cstr;
2011
+ };
2012
+ /**
2013
+ * Initialize a Stencil component given a reference to its host element, its
2014
+ * runtime bookkeeping data structure, runtime metadata about the component,
2015
+ * and (optionally) an HMR version ID.
2016
+ *
2017
+ * @param elm a host element
2018
+ * @param hostRef the element's runtime bookkeeping object
2019
+ * @param cmpMeta runtime metadata for the Stencil component
2020
+ * @param hmrVersionId an (optional) HMR version ID
2021
+ */
2022
+ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId) => {
2023
+ let Cstr;
2024
+ // initializeComponent
2025
+ if ((hostRef.$flags$ & 32 /* HOST_FLAGS.hasInitializedComponent */) === 0) {
2026
+ // Let the runtime know that the component has been initialized
2027
+ hostRef.$flags$ |= 32 /* HOST_FLAGS.hasInitializedComponent */;
2028
+ {
2029
+ // sync constructor component
2030
+ Cstr = elm.constructor;
2031
+ // wait for the CustomElementRegistry to mark the component as ready before setting `isWatchReady`. Otherwise,
2032
+ // watchers may fire prematurely if `customElements.get()`/`customElements.whenDefined()` resolves _before_
2033
+ // Stencil has completed instantiating the component.
2034
+ customElements.whenDefined(cmpMeta.$tagName$).then(() => (hostRef.$flags$ |= 128 /* HOST_FLAGS.isWatchReady */));
2035
+ }
2036
+ if (Cstr.style) {
2037
+ // this component has styles but we haven't registered them yet
2038
+ let style = Cstr.style;
2039
+ if (typeof style !== 'string') {
2040
+ style = style[(hostRef.$modeName$ = computeMode(elm))];
2041
+ }
2042
+ const scopeId = getScopeId(cmpMeta, hostRef.$modeName$);
2043
+ if (!styles.has(scopeId)) {
2044
+ const endRegisterStyles = createTime('registerStyles', cmpMeta.$tagName$);
2045
+ registerStyle(scopeId, style, !!(cmpMeta.$flags$ & 1 /* CMP_FLAGS.shadowDomEncapsulation */));
2046
+ endRegisterStyles();
2047
+ }
2048
+ }
2049
+ }
2050
+ // we've successfully created a lazy instance
2051
+ hostRef.$ancestorComponent$;
2052
+ const schedule = () => scheduleUpdate(hostRef, true);
2053
+ {
2054
+ schedule();
2055
+ }
2056
+ };
2057
+ const fireConnectedCallback = (instance) => {
2058
+ };
2059
+ const connectedCallback = (elm) => {
2060
+ if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
2061
+ const hostRef = getHostRef(elm);
2062
+ const cmpMeta = hostRef.$cmpMeta$;
2063
+ const endConnected = createTime('connectedCallback', cmpMeta.$tagName$);
2064
+ if (!(hostRef.$flags$ & 1 /* HOST_FLAGS.hasConnected */)) {
2065
+ // first time this component has connected
2066
+ hostRef.$flags$ |= 1 /* HOST_FLAGS.hasConnected */;
2067
+ {
2068
+ // initUpdate
2069
+ // if the slot polyfill is required we'll need to put some nodes
2070
+ // in here to act as original content anchors as we move nodes around
2071
+ // host element has been connected to the DOM
2072
+ if ((// TODO(STENCIL-854): Remove code related to legacy shadowDomShim field
2073
+ cmpMeta.$flags$ & (4 /* CMP_FLAGS.hasSlotRelocation */ | 8 /* CMP_FLAGS.needsShadowDomShim */))) {
2074
+ setContentReference(elm);
2075
+ }
2076
+ }
2077
+ // Lazy properties
2078
+ // https://developers.google.com/web/fundamentals/web-components/best-practices#lazy-properties
2079
+ if (cmpMeta.$members$) {
2080
+ Object.entries(cmpMeta.$members$).map(([memberName, [memberFlags]]) => {
2081
+ if (memberFlags & 31 /* MEMBER_FLAGS.Prop */ && elm.hasOwnProperty(memberName)) {
2082
+ const value = elm[memberName];
2083
+ delete elm[memberName];
2084
+ elm[memberName] = value;
2085
+ }
2086
+ });
2087
+ }
2088
+ {
2089
+ initializeComponent(elm, hostRef, cmpMeta);
2090
+ }
2091
+ }
2092
+ else {
2093
+ // not the first time this has connected
2094
+ // reattach any event listeners to the host
2095
+ // since they would have been removed when disconnected
2096
+ addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
2097
+ // fire off connectedCallback() on component instance
2098
+ if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$lazyInstance$) {
2099
+ fireConnectedCallback(hostRef.$lazyInstance$);
2100
+ }
2101
+ else if (hostRef === null || hostRef === void 0 ? void 0 : hostRef.$onReadyPromise$) {
2102
+ hostRef.$onReadyPromise$.then(() => fireConnectedCallback(hostRef.$lazyInstance$));
2103
+ }
2104
+ }
2105
+ endConnected();
2106
+ }
2107
+ };
2108
+ const setContentReference = (elm) => {
2109
+ // only required when we're NOT using native shadow dom (slot)
2110
+ // or this browser doesn't support native shadow dom
2111
+ // and this host element was NOT created with SSR
2112
+ // let's pick out the inner content for slot projection
2113
+ // create a node to represent where the original
2114
+ // content was first placed, which is useful later on
2115
+ const contentRefElm = (elm['s-cr'] = doc$1.createComment(''));
2116
+ contentRefElm['s-cn'] = true;
2117
+ elm.insertBefore(contentRefElm, elm.firstChild);
2118
+ };
2119
+ const disconnectedCallback = async (elm) => {
2120
+ if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
2121
+ const hostRef = getHostRef(elm);
2122
+ {
2123
+ if (hostRef.$rmListeners$) {
2124
+ hostRef.$rmListeners$.map((rmListener) => rmListener());
2125
+ hostRef.$rmListeners$ = undefined;
2126
+ }
2127
+ }
2128
+ }
2129
+ };
2130
+ const proxyCustomElement = (Cstr, compactMeta) => {
2131
+ const cmpMeta = {
2132
+ $flags$: compactMeta[0],
2133
+ $tagName$: compactMeta[1],
2134
+ };
2135
+ {
2136
+ cmpMeta.$members$ = compactMeta[2];
2137
+ }
2138
+ {
2139
+ cmpMeta.$listeners$ = compactMeta[3];
2140
+ }
2141
+ {
2142
+ cmpMeta.$watchers$ = Cstr.$watchers$;
2143
+ }
2144
+ {
2145
+ cmpMeta.$attrsToReflect$ = [];
2146
+ }
2147
+ const originalConnectedCallback = Cstr.prototype.connectedCallback;
2148
+ const originalDisconnectedCallback = Cstr.prototype.disconnectedCallback;
2149
+ Object.assign(Cstr.prototype, {
2150
+ __registerHost() {
2151
+ registerHost(this, cmpMeta);
2152
+ },
2153
+ connectedCallback() {
2154
+ connectedCallback(this);
2155
+ if (originalConnectedCallback) {
2156
+ originalConnectedCallback.call(this);
2157
+ }
2158
+ },
2159
+ disconnectedCallback() {
2160
+ disconnectedCallback(this);
2161
+ if (originalDisconnectedCallback) {
2162
+ originalDisconnectedCallback.call(this);
2163
+ }
2164
+ },
2165
+ __attachShadow() {
2166
+ {
2167
+ {
2168
+ this.attachShadow({
2169
+ mode: 'open',
2170
+ delegatesFocus: !!(cmpMeta.$flags$ & 16 /* CMP_FLAGS.shadowDelegatesFocus */),
2171
+ });
2172
+ }
2173
+ }
2174
+ },
2175
+ });
2176
+ Cstr.is = cmpMeta.$tagName$;
2177
+ return proxyComponent(Cstr, cmpMeta);
2178
+ };
2179
+ const addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
2180
+ if (listeners) {
2181
+ listeners.map(([flags, name, method]) => {
2182
+ const target = getHostListenerTarget(elm, flags) ;
2183
+ const handler = hostListenerProxy(hostRef, method);
2184
+ const opts = hostListenerOpts(flags);
2185
+ plt.ael(target, name, handler, opts);
2186
+ (hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
2187
+ });
2188
+ }
2189
+ };
2190
+ const hostListenerProxy = (hostRef, methodName) => (ev) => {
2191
+ try {
2192
+ if (BUILD.lazyLoad) ;
2193
+ else {
2194
+ hostRef.$hostElement$[methodName](ev);
2195
+ }
2196
+ }
2197
+ catch (e) {
2198
+ consoleError(e);
2199
+ }
2200
+ };
2201
+ const getHostListenerTarget = (elm, flags) => {
2202
+ if (flags & 4 /* LISTENER_FLAGS.TargetDocument */)
2203
+ return doc$1;
2204
+ if (flags & 8 /* LISTENER_FLAGS.TargetWindow */)
2205
+ return win;
2206
+ if (flags & 16 /* LISTENER_FLAGS.TargetBody */)
2207
+ return doc$1.body;
2208
+ return elm;
2209
+ };
2210
+ // prettier-ignore
2211
+ const hostListenerOpts = (flags) => supportsListenerOptions
2212
+ ? ({
2213
+ passive: (flags & 1 /* LISTENER_FLAGS.Passive */) !== 0,
2214
+ capture: (flags & 2 /* LISTENER_FLAGS.Capture */) !== 0,
2215
+ })
2216
+ : (flags & 2 /* LISTENER_FLAGS.Capture */) !== 0;
2217
+ /**
2218
+ * A WeakMap mapping runtime component references to their corresponding host reference
2219
+ * instances.
2220
+ */
2221
+ const hostRefs = /*@__PURE__*/ new WeakMap();
2222
+ /**
2223
+ * Given a {@link d.RuntimeRef} retrieve the corresponding {@link d.HostRef}
2224
+ *
2225
+ * @param ref the runtime ref of interest
2226
+ * @returns the Host reference (if found) or undefined
2227
+ */
2228
+ const getHostRef = (ref) => hostRefs.get(ref);
2229
+ /**
2230
+ * Register a host element for a Stencil component, setting up various metadata
2231
+ * and callbacks based on {@link BUILD} flags as well as the component's runtime
2232
+ * metadata.
2233
+ *
2234
+ * @param hostElement the host element to register
2235
+ * @param cmpMeta runtime metadata for that component
2236
+ * @returns a reference to the host ref WeakMap
2237
+ */
2238
+ const registerHost = (hostElement, cmpMeta) => {
2239
+ const hostRef = {
2240
+ $flags$: 0,
2241
+ $hostElement$: hostElement,
2242
+ $cmpMeta$: cmpMeta,
2243
+ $instanceValues$: new Map(),
2244
+ };
2245
+ addHostEventListeners(hostElement, hostRef, cmpMeta.$listeners$);
2246
+ return hostRefs.set(hostElement, hostRef);
2247
+ };
2248
+ const isMemberInElement = (elm, memberName) => memberName in elm;
2249
+ const consoleError = (e, el) => (0, console.error)(e, el);
2250
+ const styles = /*@__PURE__*/ new Map();
2251
+ const modeResolutionChain = [];
2252
+ const win = typeof window !== 'undefined' ? window : {};
2253
+ const doc$1 = win.document || { head: {} };
2254
+ const H = (win.HTMLElement || class {
2255
+ });
2256
+ const plt = {
2257
+ $flags$: 0,
2258
+ $resourcesUrl$: '',
2259
+ jmp: (h) => h(),
2260
+ raf: (h) => requestAnimationFrame(h),
2261
+ ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),
2262
+ rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),
2263
+ ce: (eventName, opts) => new CustomEvent(eventName, opts),
2264
+ };
2265
+ const supportsListenerOptions = /*@__PURE__*/ (() => {
2266
+ let supportsListenerOptions = false;
2267
+ try {
2268
+ doc$1.addEventListener('e', null, Object.defineProperty({}, 'passive', {
2269
+ get() {
2270
+ supportsListenerOptions = true;
2271
+ },
2272
+ }));
2273
+ }
2274
+ catch (e) { }
2275
+ return supportsListenerOptions;
2276
+ })();
2277
+ const promiseResolve = (v) => Promise.resolve(v);
2278
+ const supportsConstructableStylesheets = /*@__PURE__*/ (() => {
2279
+ try {
2280
+ new CSSStyleSheet();
2281
+ return typeof new CSSStyleSheet().replaceSync === 'function';
2282
+ }
2283
+ catch (e) { }
2284
+ return false;
2285
+ })()
2286
+ ;
2287
+ const queueDomReads = [];
2288
+ const queueDomWrites = [];
2289
+ const queueTask = (queue, write) => (cb) => {
2290
+ queue.push(cb);
2291
+ if (!queuePending) {
2292
+ queuePending = true;
2293
+ if (write && plt.$flags$ & 4 /* PLATFORM_FLAGS.queueSync */) {
2294
+ nextTick(flush);
2295
+ }
2296
+ else {
2297
+ plt.raf(flush);
2298
+ }
2299
+ }
2300
+ };
2301
+ const consume = (queue) => {
2302
+ for (let i = 0; i < queue.length; i++) {
2303
+ try {
2304
+ queue[i](performance.now());
2305
+ }
2306
+ catch (e) {
2307
+ consoleError(e);
2308
+ }
2309
+ }
2310
+ queue.length = 0;
2311
+ };
2312
+ const flush = () => {
2313
+ // always force a bunch of medium callbacks to run, but still have
2314
+ // a throttle on how many can run in a certain time
2315
+ // DOM READS!!!
2316
+ consume(queueDomReads);
2317
+ // DOM WRITES!!!
2318
+ {
2319
+ consume(queueDomWrites);
2320
+ if ((queuePending = queueDomReads.length > 0)) {
2321
+ // still more to do yet, but we've run out of time
2322
+ // let's let this thing cool off and try again in the next tick
2323
+ plt.raf(flush);
2324
+ }
2325
+ }
2326
+ };
2327
+ const nextTick = (cb) => promiseResolve().then(cb);
2328
+ const writeTask = /*@__PURE__*/ queueTask(queueDomWrites, true);
2329
+
2330
+ const filePreviewCss = ":host{display:block;font-size:13px}img,video{max-width:100%;margin-top:10px}";
2331
+
2332
+ const FilePreview$1 = /*@__PURE__*/ proxyCustomElement(class FilePreview extends H {
2333
+ constructor() {
2334
+ super();
2335
+ this.__registerHost();
2336
+ this.__attachShadow();
2337
+ this.src = undefined;
2338
+ this.filetype = undefined;
2339
+ }
2340
+ render() {
2341
+ return (h(Host, { class: this.computeClass() }, this.isImage() && h("img", { src: this.src }), this.isVideo() && h("video", { src: this.src, onClick: toggle }), this.isOther() && "This file does not offer a preview", h("slot", null)));
2342
+ }
2343
+ computeClass() {
2344
+ if (this.isImage())
2345
+ return "image";
2346
+ if (this.isVideo())
2347
+ return "video";
2348
+ return "other";
2349
+ }
2350
+ isImage() {
2351
+ return this.filetype == "image";
2352
+ }
2353
+ isVideo() {
2354
+ return this.filetype == "video";
2355
+ }
2356
+ isOther() {
2357
+ return !this.isImage() && !this.isVideo();
2358
+ }
2359
+ static get style() { return filePreviewCss; }
2360
+ }, [1, "file-preview", {
2361
+ "src": [513],
2362
+ "filetype": [513]
2363
+ }]);
2364
+ const toggle = function () { this.paused ? this.play() : this.pause(); return false; };
2365
+
2366
+ const progressBarCss = ":host{display:block;position:relative;padding:0 20px;border:1px solid rgba(0, 0, 0, 0.3);border-radius:3px;line-height:2;flex:1 0;box-sizing:border-box;text-align:left;font-size:13px}.bar{position:absolute;top:0;left:0;bottom:0;background:rgba(57, 137, 39, 1);transition:width 120ms ease-out, opacity 60ms 60ms ease-in;transform:translate3d(0, 0, 0)}.content{position:relative;color:#fff;font-size:1em}";
2367
+
2368
+ const ProgressBar$1 = /*@__PURE__*/ proxyCustomElement(class ProgressBar extends H {
2369
+ constructor() {
2370
+ super();
2371
+ this.__registerHost();
2372
+ this.__attachShadow();
2373
+ this.percent = 0;
2374
+ }
2375
+ render() {
2376
+ return (h(Host, null, h("div", { class: "bar", style: { width: `${this.percent}%` } }), h("span", { class: "content" }, h("slot", null))));
2377
+ }
2378
+ static get style() { return progressBarCss; }
2379
+ }, [1, "progress-bar", {
2380
+ "percent": [514]
2381
+ }]);
2382
+
2383
+ var sparkMd5 = {
2384
+ exports: {}
2385
+ };
2386
+
2387
+ (function(module, exports) {
2388
+ (function(factory) {
2389
+ {
2390
+ module.exports = factory();
2391
+ }
2392
+ })((function(undefined$1) {
2393
+ var hex_chr = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" ];
2394
+ function md5cycle(x, k) {
2395
+ var a = x[0], b = x[1], c = x[2], d = x[3];
2396
+ a += (b & c | ~b & d) + k[0] - 680876936 | 0;
2397
+ a = (a << 7 | a >>> 25) + b | 0;
2398
+ d += (a & b | ~a & c) + k[1] - 389564586 | 0;
2399
+ d = (d << 12 | d >>> 20) + a | 0;
2400
+ c += (d & a | ~d & b) + k[2] + 606105819 | 0;
2401
+ c = (c << 17 | c >>> 15) + d | 0;
2402
+ b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
2403
+ b = (b << 22 | b >>> 10) + c | 0;
2404
+ a += (b & c | ~b & d) + k[4] - 176418897 | 0;
2405
+ a = (a << 7 | a >>> 25) + b | 0;
2406
+ d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
2407
+ d = (d << 12 | d >>> 20) + a | 0;
2408
+ c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
2409
+ c = (c << 17 | c >>> 15) + d | 0;
2410
+ b += (c & d | ~c & a) + k[7] - 45705983 | 0;
2411
+ b = (b << 22 | b >>> 10) + c | 0;
2412
+ a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
2413
+ a = (a << 7 | a >>> 25) + b | 0;
2414
+ d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
2415
+ d = (d << 12 | d >>> 20) + a | 0;
2416
+ c += (d & a | ~d & b) + k[10] - 42063 | 0;
2417
+ c = (c << 17 | c >>> 15) + d | 0;
2418
+ b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
2419
+ b = (b << 22 | b >>> 10) + c | 0;
2420
+ a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
2421
+ a = (a << 7 | a >>> 25) + b | 0;
2422
+ d += (a & b | ~a & c) + k[13] - 40341101 | 0;
2423
+ d = (d << 12 | d >>> 20) + a | 0;
2424
+ c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
2425
+ c = (c << 17 | c >>> 15) + d | 0;
2426
+ b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
2427
+ b = (b << 22 | b >>> 10) + c | 0;
2428
+ a += (b & d | c & ~d) + k[1] - 165796510 | 0;
2429
+ a = (a << 5 | a >>> 27) + b | 0;
2430
+ d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
2431
+ d = (d << 9 | d >>> 23) + a | 0;
2432
+ c += (d & b | a & ~b) + k[11] + 643717713 | 0;
2433
+ c = (c << 14 | c >>> 18) + d | 0;
2434
+ b += (c & a | d & ~a) + k[0] - 373897302 | 0;
2435
+ b = (b << 20 | b >>> 12) + c | 0;
2436
+ a += (b & d | c & ~d) + k[5] - 701558691 | 0;
2437
+ a = (a << 5 | a >>> 27) + b | 0;
2438
+ d += (a & c | b & ~c) + k[10] + 38016083 | 0;
2439
+ d = (d << 9 | d >>> 23) + a | 0;
2440
+ c += (d & b | a & ~b) + k[15] - 660478335 | 0;
2441
+ c = (c << 14 | c >>> 18) + d | 0;
2442
+ b += (c & a | d & ~a) + k[4] - 405537848 | 0;
2443
+ b = (b << 20 | b >>> 12) + c | 0;
2444
+ a += (b & d | c & ~d) + k[9] + 568446438 | 0;
2445
+ a = (a << 5 | a >>> 27) + b | 0;
2446
+ d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
2447
+ d = (d << 9 | d >>> 23) + a | 0;
2448
+ c += (d & b | a & ~b) + k[3] - 187363961 | 0;
2449
+ c = (c << 14 | c >>> 18) + d | 0;
2450
+ b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
2451
+ b = (b << 20 | b >>> 12) + c | 0;
2452
+ a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
2453
+ a = (a << 5 | a >>> 27) + b | 0;
2454
+ d += (a & c | b & ~c) + k[2] - 51403784 | 0;
2455
+ d = (d << 9 | d >>> 23) + a | 0;
2456
+ c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
2457
+ c = (c << 14 | c >>> 18) + d | 0;
2458
+ b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
2459
+ b = (b << 20 | b >>> 12) + c | 0;
2460
+ a += (b ^ c ^ d) + k[5] - 378558 | 0;
2461
+ a = (a << 4 | a >>> 28) + b | 0;
2462
+ d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
2463
+ d = (d << 11 | d >>> 21) + a | 0;
2464
+ c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
2465
+ c = (c << 16 | c >>> 16) + d | 0;
2466
+ b += (c ^ d ^ a) + k[14] - 35309556 | 0;
2467
+ b = (b << 23 | b >>> 9) + c | 0;
2468
+ a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
2469
+ a = (a << 4 | a >>> 28) + b | 0;
2470
+ d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
2471
+ d = (d << 11 | d >>> 21) + a | 0;
2472
+ c += (d ^ a ^ b) + k[7] - 155497632 | 0;
2473
+ c = (c << 16 | c >>> 16) + d | 0;
2474
+ b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
2475
+ b = (b << 23 | b >>> 9) + c | 0;
2476
+ a += (b ^ c ^ d) + k[13] + 681279174 | 0;
2477
+ a = (a << 4 | a >>> 28) + b | 0;
2478
+ d += (a ^ b ^ c) + k[0] - 358537222 | 0;
2479
+ d = (d << 11 | d >>> 21) + a | 0;
2480
+ c += (d ^ a ^ b) + k[3] - 722521979 | 0;
2481
+ c = (c << 16 | c >>> 16) + d | 0;
2482
+ b += (c ^ d ^ a) + k[6] + 76029189 | 0;
2483
+ b = (b << 23 | b >>> 9) + c | 0;
2484
+ a += (b ^ c ^ d) + k[9] - 640364487 | 0;
2485
+ a = (a << 4 | a >>> 28) + b | 0;
2486
+ d += (a ^ b ^ c) + k[12] - 421815835 | 0;
2487
+ d = (d << 11 | d >>> 21) + a | 0;
2488
+ c += (d ^ a ^ b) + k[15] + 530742520 | 0;
2489
+ c = (c << 16 | c >>> 16) + d | 0;
2490
+ b += (c ^ d ^ a) + k[2] - 995338651 | 0;
2491
+ b = (b << 23 | b >>> 9) + c | 0;
2492
+ a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
2493
+ a = (a << 6 | a >>> 26) + b | 0;
2494
+ d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
2495
+ d = (d << 10 | d >>> 22) + a | 0;
2496
+ c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
2497
+ c = (c << 15 | c >>> 17) + d | 0;
2498
+ b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
2499
+ b = (b << 21 | b >>> 11) + c | 0;
2500
+ a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
2501
+ a = (a << 6 | a >>> 26) + b | 0;
2502
+ d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
2503
+ d = (d << 10 | d >>> 22) + a | 0;
2504
+ c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
2505
+ c = (c << 15 | c >>> 17) + d | 0;
2506
+ b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
2507
+ b = (b << 21 | b >>> 11) + c | 0;
2508
+ a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
2509
+ a = (a << 6 | a >>> 26) + b | 0;
2510
+ d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
2511
+ d = (d << 10 | d >>> 22) + a | 0;
2512
+ c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
2513
+ c = (c << 15 | c >>> 17) + d | 0;
2514
+ b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
2515
+ b = (b << 21 | b >>> 11) + c | 0;
2516
+ a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
2517
+ a = (a << 6 | a >>> 26) + b | 0;
2518
+ d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
2519
+ d = (d << 10 | d >>> 22) + a | 0;
2520
+ c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
2521
+ c = (c << 15 | c >>> 17) + d | 0;
2522
+ b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
2523
+ b = (b << 21 | b >>> 11) + c | 0;
2524
+ x[0] = a + x[0] | 0;
2525
+ x[1] = b + x[1] | 0;
2526
+ x[2] = c + x[2] | 0;
2527
+ x[3] = d + x[3] | 0;
2528
+ }
2529
+ function md5blk(s) {
2530
+ var md5blks = [], i;
2531
+ for (i = 0; i < 64; i += 4) {
2532
+ md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
2533
+ }
2534
+ return md5blks;
2535
+ }
2536
+ function md5blk_array(a) {
2537
+ var md5blks = [], i;
2538
+ for (i = 0; i < 64; i += 4) {
2539
+ md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
2540
+ }
2541
+ return md5blks;
2542
+ }
2543
+ function md51(s) {
2544
+ var n = s.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
2545
+ for (i = 64; i <= n; i += 64) {
2546
+ md5cycle(state, md5blk(s.substring(i - 64, i)));
2547
+ }
2548
+ s = s.substring(i - 64);
2549
+ length = s.length;
2550
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2551
+ for (i = 0; i < length; i += 1) {
2552
+ tail[i >> 2] |= s.charCodeAt(i) << (i % 4 << 3);
2553
+ }
2554
+ tail[i >> 2] |= 128 << (i % 4 << 3);
2555
+ if (i > 55) {
2556
+ md5cycle(state, tail);
2557
+ for (i = 0; i < 16; i += 1) {
2558
+ tail[i] = 0;
2559
+ }
2560
+ }
2561
+ tmp = n * 8;
2562
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
2563
+ lo = parseInt(tmp[2], 16);
2564
+ hi = parseInt(tmp[1], 16) || 0;
2565
+ tail[14] = lo;
2566
+ tail[15] = hi;
2567
+ md5cycle(state, tail);
2568
+ return state;
2569
+ }
2570
+ function md51_array(a) {
2571
+ var n = a.length, state = [ 1732584193, -271733879, -1732584194, 271733878 ], i, length, tail, tmp, lo, hi;
2572
+ for (i = 64; i <= n; i += 64) {
2573
+ md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
2574
+ }
2575
+ a = i - 64 < n ? a.subarray(i - 64) : new Uint8Array(0);
2576
+ length = a.length;
2577
+ tail = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2578
+ for (i = 0; i < length; i += 1) {
2579
+ tail[i >> 2] |= a[i] << (i % 4 << 3);
2580
+ }
2581
+ tail[i >> 2] |= 128 << (i % 4 << 3);
2582
+ if (i > 55) {
2583
+ md5cycle(state, tail);
2584
+ for (i = 0; i < 16; i += 1) {
2585
+ tail[i] = 0;
2586
+ }
2587
+ }
2588
+ tmp = n * 8;
2589
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
2590
+ lo = parseInt(tmp[2], 16);
2591
+ hi = parseInt(tmp[1], 16) || 0;
2592
+ tail[14] = lo;
2593
+ tail[15] = hi;
2594
+ md5cycle(state, tail);
2595
+ return state;
2596
+ }
2597
+ function rhex(n) {
2598
+ var s = "", j;
2599
+ for (j = 0; j < 4; j += 1) {
2600
+ s += hex_chr[n >> j * 8 + 4 & 15] + hex_chr[n >> j * 8 & 15];
2601
+ }
2602
+ return s;
2603
+ }
2604
+ function hex(x) {
2605
+ var i;
2606
+ for (i = 0; i < x.length; i += 1) {
2607
+ x[i] = rhex(x[i]);
2608
+ }
2609
+ return x.join("");
2610
+ }
2611
+ if (hex(md51("hello")) !== "5d41402abc4b2a76b9719d911017c592") ;
2612
+ if (typeof ArrayBuffer !== "undefined" && !ArrayBuffer.prototype.slice) {
2613
+ (function() {
2614
+ function clamp(val, length) {
2615
+ val = val | 0 || 0;
2616
+ if (val < 0) {
2617
+ return Math.max(val + length, 0);
2618
+ }
2619
+ return Math.min(val, length);
2620
+ }
2621
+ ArrayBuffer.prototype.slice = function(from, to) {
2622
+ var length = this.byteLength, begin = clamp(from, length), end = length, num, target, targetArray, sourceArray;
2623
+ if (to !== undefined$1) {
2624
+ end = clamp(to, length);
2625
+ }
2626
+ if (begin > end) {
2627
+ return new ArrayBuffer(0);
2628
+ }
2629
+ num = end - begin;
2630
+ target = new ArrayBuffer(num);
2631
+ targetArray = new Uint8Array(target);
2632
+ sourceArray = new Uint8Array(this, begin, num);
2633
+ targetArray.set(sourceArray);
2634
+ return target;
2635
+ };
2636
+ })();
2637
+ }
2638
+ function toUtf8(str) {
2639
+ if (/[\u0080-\uFFFF]/.test(str)) {
2640
+ str = unescape(encodeURIComponent(str));
2641
+ }
2642
+ return str;
2643
+ }
2644
+ function utf8Str2ArrayBuffer(str, returnUInt8Array) {
2645
+ var length = str.length, buff = new ArrayBuffer(length), arr = new Uint8Array(buff), i;
2646
+ for (i = 0; i < length; i += 1) {
2647
+ arr[i] = str.charCodeAt(i);
2648
+ }
2649
+ return returnUInt8Array ? arr : buff;
2650
+ }
2651
+ function arrayBuffer2Utf8Str(buff) {
2652
+ return String.fromCharCode.apply(null, new Uint8Array(buff));
2653
+ }
2654
+ function concatenateArrayBuffers(first, second, returnUInt8Array) {
2655
+ var result = new Uint8Array(first.byteLength + second.byteLength);
2656
+ result.set(new Uint8Array(first));
2657
+ result.set(new Uint8Array(second), first.byteLength);
2658
+ return returnUInt8Array ? result : result.buffer;
2659
+ }
2660
+ function hexToBinaryString(hex) {
2661
+ var bytes = [], length = hex.length, x;
2662
+ for (x = 0; x < length - 1; x += 2) {
2663
+ bytes.push(parseInt(hex.substr(x, 2), 16));
2664
+ }
2665
+ return String.fromCharCode.apply(String, bytes);
2666
+ }
2667
+ function SparkMD5() {
2668
+ this.reset();
2669
+ }
2670
+ SparkMD5.prototype.append = function(str) {
2671
+ this.appendBinary(toUtf8(str));
2672
+ return this;
2673
+ };
2674
+ SparkMD5.prototype.appendBinary = function(contents) {
2675
+ this._buff += contents;
2676
+ this._length += contents.length;
2677
+ var length = this._buff.length, i;
2678
+ for (i = 64; i <= length; i += 64) {
2679
+ md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
2680
+ }
2681
+ this._buff = this._buff.substring(i - 64);
2682
+ return this;
2683
+ };
2684
+ SparkMD5.prototype.end = function(raw) {
2685
+ 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;
2686
+ for (i = 0; i < length; i += 1) {
2687
+ tail[i >> 2] |= buff.charCodeAt(i) << (i % 4 << 3);
2688
+ }
2689
+ this._finish(tail, length);
2690
+ ret = hex(this._hash);
2691
+ if (raw) {
2692
+ ret = hexToBinaryString(ret);
2693
+ }
2694
+ this.reset();
2695
+ return ret;
2696
+ };
2697
+ SparkMD5.prototype.reset = function() {
2698
+ this._buff = "";
2699
+ this._length = 0;
2700
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
2701
+ return this;
2702
+ };
2703
+ SparkMD5.prototype.getState = function() {
2704
+ return {
2705
+ buff: this._buff,
2706
+ length: this._length,
2707
+ hash: this._hash.slice()
2708
+ };
2709
+ };
2710
+ SparkMD5.prototype.setState = function(state) {
2711
+ this._buff = state.buff;
2712
+ this._length = state.length;
2713
+ this._hash = state.hash;
2714
+ return this;
2715
+ };
2716
+ SparkMD5.prototype.destroy = function() {
2717
+ delete this._hash;
2718
+ delete this._buff;
2719
+ delete this._length;
2720
+ };
2721
+ SparkMD5.prototype._finish = function(tail, length) {
2722
+ var i = length, tmp, lo, hi;
2723
+ tail[i >> 2] |= 128 << (i % 4 << 3);
2724
+ if (i > 55) {
2725
+ md5cycle(this._hash, tail);
2726
+ for (i = 0; i < 16; i += 1) {
2727
+ tail[i] = 0;
2728
+ }
2729
+ }
2730
+ tmp = this._length * 8;
2731
+ tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
2732
+ lo = parseInt(tmp[2], 16);
2733
+ hi = parseInt(tmp[1], 16) || 0;
2734
+ tail[14] = lo;
2735
+ tail[15] = hi;
2736
+ md5cycle(this._hash, tail);
2737
+ };
2738
+ SparkMD5.hash = function(str, raw) {
2739
+ return SparkMD5.hashBinary(toUtf8(str), raw);
2740
+ };
2741
+ SparkMD5.hashBinary = function(content, raw) {
2742
+ var hash = md51(content), ret = hex(hash);
2743
+ return raw ? hexToBinaryString(ret) : ret;
2744
+ };
2745
+ SparkMD5.ArrayBuffer = function() {
2746
+ this.reset();
2747
+ };
2748
+ SparkMD5.ArrayBuffer.prototype.append = function(arr) {
2749
+ var buff = concatenateArrayBuffers(this._buff.buffer, arr, true), length = buff.length, i;
2750
+ this._length += arr.byteLength;
2751
+ for (i = 64; i <= length; i += 64) {
2752
+ md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
2753
+ }
2754
+ this._buff = i - 64 < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);
2755
+ return this;
2756
+ };
2757
+ SparkMD5.ArrayBuffer.prototype.end = function(raw) {
2758
+ 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;
2759
+ for (i = 0; i < length; i += 1) {
2760
+ tail[i >> 2] |= buff[i] << (i % 4 << 3);
2761
+ }
2762
+ this._finish(tail, length);
2763
+ ret = hex(this._hash);
2764
+ if (raw) {
2765
+ ret = hexToBinaryString(ret);
2766
+ }
2767
+ this.reset();
2768
+ return ret;
2769
+ };
2770
+ SparkMD5.ArrayBuffer.prototype.reset = function() {
2771
+ this._buff = new Uint8Array(0);
2772
+ this._length = 0;
2773
+ this._hash = [ 1732584193, -271733879, -1732584194, 271733878 ];
2774
+ return this;
2775
+ };
2776
+ SparkMD5.ArrayBuffer.prototype.getState = function() {
2777
+ var state = SparkMD5.prototype.getState.call(this);
2778
+ state.buff = arrayBuffer2Utf8Str(state.buff);
2779
+ return state;
2780
+ };
2781
+ SparkMD5.ArrayBuffer.prototype.setState = function(state) {
2782
+ state.buff = utf8Str2ArrayBuffer(state.buff, true);
2783
+ return SparkMD5.prototype.setState.call(this, state);
2784
+ };
2785
+ SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
2786
+ SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
2787
+ SparkMD5.ArrayBuffer.hash = function(arr, raw) {
2788
+ var hash = md51_array(new Uint8Array(arr)), ret = hex(hash);
2789
+ return raw ? hexToBinaryString(ret) : ret;
2790
+ };
2791
+ return SparkMD5;
2792
+ }));
2793
+ })(sparkMd5);
2794
+
2795
+ var SparkMD5 = sparkMd5.exports;
2796
+
2797
+ const fileSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
2798
+
2799
+ class FileChecksum {
2800
+ static create(file, callback) {
2801
+ const instance = new FileChecksum(file);
2802
+ instance.create(callback);
2803
+ }
2804
+ constructor(file) {
2805
+ this.file = file;
2806
+ this.chunkSize = 2097152;
2807
+ this.chunkCount = Math.ceil(this.file.size / this.chunkSize);
2808
+ this.chunkIndex = 0;
2809
+ }
2810
+ create(callback) {
2811
+ this.callback = callback;
2812
+ this.md5Buffer = new SparkMD5.ArrayBuffer;
2813
+ this.fileReader = new FileReader;
2814
+ this.fileReader.addEventListener("load", (event => this.fileReaderDidLoad(event)));
2815
+ this.fileReader.addEventListener("error", (event => this.fileReaderDidError(event)));
2816
+ this.readNextChunk();
2817
+ }
2818
+ fileReaderDidLoad(event) {
2819
+ this.md5Buffer.append(event.target.result);
2820
+ if (!this.readNextChunk()) {
2821
+ const binaryDigest = this.md5Buffer.end(true);
2822
+ const base64digest = btoa(binaryDigest);
2823
+ this.callback(null, base64digest);
2824
+ }
2825
+ }
2826
+ fileReaderDidError(event) {
2827
+ this.callback(`Error reading ${this.file.name}`);
2828
+ }
2829
+ readNextChunk() {
2830
+ if (this.chunkIndex < this.chunkCount || this.chunkIndex == 0 && this.chunkCount == 0) {
2831
+ const start = this.chunkIndex * this.chunkSize;
2832
+ const end = Math.min(start + this.chunkSize, this.file.size);
2833
+ const bytes = fileSlice.call(this.file, start, end);
2834
+ this.fileReader.readAsArrayBuffer(bytes);
2835
+ this.chunkIndex++;
2836
+ return true;
2837
+ } else {
2838
+ return false;
2839
+ }
2840
+ }
2841
+ }
2842
+
2843
+ function getMetaValue(name) {
2844
+ const element = findElement(document.head, `meta[name="${name}"]`);
2845
+ if (element) {
2846
+ return element.getAttribute("content");
2847
+ }
2848
+ }
2849
+
2850
+ function findElements(root, selector) {
2851
+ if (typeof root == "string") {
2852
+ selector = root;
2853
+ root = document;
2854
+ }
2855
+ const elements = root.querySelectorAll(selector);
2856
+ return toArray(elements);
2857
+ }
2858
+
2859
+ function findElement(root, selector) {
2860
+ if (typeof root == "string") {
2861
+ selector = root;
2862
+ root = document;
2863
+ }
2864
+ return root.querySelector(selector);
2865
+ }
2866
+
2867
+ function dispatchEvent$1(element, type, eventInit = {}) {
2868
+ const {disabled: disabled} = element;
2869
+ const {bubbles: bubbles, cancelable: cancelable, detail: detail} = eventInit;
2870
+ const event = document.createEvent("Event");
2871
+ event.initEvent(type, bubbles || true, cancelable || true);
2872
+ event.detail = detail || {};
2873
+ try {
2874
+ element.disabled = false;
2875
+ element.dispatchEvent(event);
2876
+ } finally {
2877
+ element.disabled = disabled;
2878
+ }
2879
+ return event;
2880
+ }
2881
+
2882
+ function toArray(value) {
2883
+ if (Array.isArray(value)) {
2884
+ return value;
2885
+ } else if (Array.from) {
2886
+ return Array.from(value);
2887
+ } else {
2888
+ return [].slice.call(value);
2889
+ }
2890
+ }
2891
+
2892
+ class BlobRecord {
2893
+ constructor(file, checksum, url, customHeaders = {}) {
2894
+ this.file = file;
2895
+ this.attributes = {
2896
+ filename: file.name,
2897
+ content_type: file.type || "application/octet-stream",
2898
+ byte_size: file.size,
2899
+ checksum: checksum
2900
+ };
2901
+ this.xhr = new XMLHttpRequest;
2902
+ this.xhr.open("POST", url, true);
2903
+ this.xhr.responseType = "json";
2904
+ this.xhr.setRequestHeader("Content-Type", "application/json");
2905
+ this.xhr.setRequestHeader("Accept", "application/json");
2906
+ this.xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
2907
+ Object.keys(customHeaders).forEach((headerKey => {
2908
+ this.xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
2909
+ }));
2910
+ const csrfToken = getMetaValue("csrf-token");
2911
+ if (csrfToken != undefined) {
2912
+ this.xhr.setRequestHeader("X-CSRF-Token", csrfToken);
2913
+ }
2914
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
2915
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
2916
+ }
2917
+ get status() {
2918
+ return this.xhr.status;
2919
+ }
2920
+ get response() {
2921
+ const {responseType: responseType, response: response} = this.xhr;
2922
+ if (responseType == "json") {
2923
+ return response;
2924
+ } else {
2925
+ return JSON.parse(response);
2926
+ }
2927
+ }
2928
+ create(callback) {
2929
+ this.callback = callback;
2930
+ this.xhr.send(JSON.stringify({
2931
+ blob: this.attributes
2932
+ }));
2933
+ }
2934
+ requestDidLoad(event) {
2935
+ if (this.status >= 200 && this.status < 300) {
2936
+ const {response: response} = this;
2937
+ const {direct_upload: direct_upload} = response;
2938
+ delete response.direct_upload;
2939
+ this.attributes = response;
2940
+ this.directUploadData = direct_upload;
2941
+ this.callback(null, this.toJSON());
2942
+ } else {
2943
+ this.requestDidError(event);
2944
+ }
2945
+ }
2946
+ requestDidError(event) {
2947
+ this.callback(`Error creating Blob for "${this.file.name}". Status: ${this.status}`);
2948
+ }
2949
+ toJSON() {
2950
+ const result = {};
2951
+ for (const key in this.attributes) {
2952
+ result[key] = this.attributes[key];
2953
+ }
2954
+ return result;
2955
+ }
2956
+ }
2957
+
2958
+ class BlobUpload {
2959
+ constructor(blob) {
2960
+ this.blob = blob;
2961
+ this.file = blob.file;
2962
+ const {url: url, headers: headers} = blob.directUploadData;
2963
+ this.xhr = new XMLHttpRequest;
2964
+ this.xhr.open("PUT", url, true);
2965
+ this.xhr.responseType = "text";
2966
+ for (const key in headers) {
2967
+ this.xhr.setRequestHeader(key, headers[key]);
2968
+ }
2969
+ this.xhr.addEventListener("load", (event => this.requestDidLoad(event)));
2970
+ this.xhr.addEventListener("error", (event => this.requestDidError(event)));
2971
+ }
2972
+ create(callback) {
2973
+ this.callback = callback;
2974
+ this.xhr.send(this.file.slice());
2975
+ }
2976
+ requestDidLoad(event) {
2977
+ const {status: status, response: response} = this.xhr;
2978
+ if (status >= 200 && status < 300) {
2979
+ this.callback(null, response);
2980
+ } else {
2981
+ this.requestDidError(event);
2982
+ }
2983
+ }
2984
+ requestDidError(event) {
2985
+ this.callback(`Error storing "${this.file.name}". Status: ${this.xhr.status}`);
2986
+ }
2987
+ }
2988
+
2989
+ let id = 0;
2990
+
2991
+ class DirectUpload {
2992
+ constructor(file, url, delegate, customHeaders = {}) {
2993
+ this.id = ++id;
2994
+ this.file = file;
2995
+ this.url = url;
2996
+ this.delegate = delegate;
2997
+ this.customHeaders = customHeaders;
2998
+ }
2999
+ create(callback) {
3000
+ FileChecksum.create(this.file, ((error, checksum) => {
3001
+ if (error) {
3002
+ callback(error);
3003
+ return;
3004
+ }
3005
+ const blob = new BlobRecord(this.file, checksum, this.url, this.customHeaders);
3006
+ notify(this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr);
3007
+ blob.create((error => {
3008
+ if (error) {
3009
+ callback(error);
3010
+ } else {
3011
+ const upload = new BlobUpload(blob);
3012
+ notify(this.delegate, "directUploadWillStoreFileWithXHR", upload.xhr);
3013
+ upload.create((error => {
3014
+ if (error) {
3015
+ callback(error);
3016
+ } else {
3017
+ callback(null, blob.toJSON());
3018
+ }
3019
+ }));
3020
+ }
3021
+ }));
3022
+ }));
3023
+ }
3024
+ }
3025
+
3026
+ function notify(object, methodName, ...messages) {
3027
+ if (object && typeof object[methodName] == "function") {
3028
+ return object[methodName](...messages);
3029
+ }
3030
+ }
3031
+
3032
+ class DirectUploadController$1 {
3033
+ constructor(input, file) {
3034
+ this.input = input;
3035
+ this.file = file;
3036
+ this.directUpload = new DirectUpload(this.file, this.url, this);
3037
+ this.dispatch("initialize");
3038
+ }
3039
+ start(callback) {
3040
+ const hiddenInput = document.createElement("input");
3041
+ hiddenInput.type = "hidden";
3042
+ hiddenInput.name = this.input.name;
3043
+ this.input.insertAdjacentElement("beforebegin", hiddenInput);
3044
+ this.dispatch("start");
3045
+ this.directUpload.create(((error, attributes) => {
3046
+ if (error) {
3047
+ hiddenInput.parentNode.removeChild(hiddenInput);
3048
+ this.dispatchError(error);
3049
+ } else {
3050
+ hiddenInput.value = attributes.signed_id;
3051
+ }
3052
+ this.dispatch("end");
3053
+ callback(error);
3054
+ }));
3055
+ }
3056
+ uploadRequestDidProgress(event) {
3057
+ const progress = event.loaded / event.total * 100;
3058
+ if (progress) {
3059
+ this.dispatch("progress", {
3060
+ progress: progress
3061
+ });
3062
+ }
3063
+ }
3064
+ get url() {
3065
+ return this.input.getAttribute("data-direct-upload-url");
3066
+ }
3067
+ dispatch(name, detail = {}) {
3068
+ detail.file = this.file;
3069
+ detail.id = this.directUpload.id;
3070
+ return dispatchEvent$1(this.input, `direct-upload:${name}`, {
3071
+ detail: detail
3072
+ });
3073
+ }
3074
+ dispatchError(error) {
3075
+ const event = this.dispatch("error", {
3076
+ error: error
3077
+ });
3078
+ if (!event.defaultPrevented) {
3079
+ alert(error);
3080
+ }
3081
+ }
3082
+ directUploadWillCreateBlobWithXHR(xhr) {
3083
+ this.dispatch("before-blob-request", {
3084
+ xhr: xhr
3085
+ });
3086
+ }
3087
+ directUploadWillStoreFileWithXHR(xhr) {
3088
+ this.dispatch("before-storage-request", {
3089
+ xhr: xhr
3090
+ });
3091
+ xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
3092
+ }
3093
+ }
3094
+
3095
+ const inputSelector = "input[type=file][data-direct-upload-url]:not([disabled])";
3096
+
3097
+ class DirectUploadsController {
3098
+ constructor(form) {
3099
+ this.form = form;
3100
+ this.inputs = findElements(form, inputSelector).filter((input => input.files.length));
3101
+ }
3102
+ start(callback) {
3103
+ const controllers = this.createDirectUploadControllers();
3104
+ const startNextController = () => {
3105
+ const controller = controllers.shift();
3106
+ if (controller) {
3107
+ controller.start((error => {
3108
+ if (error) {
3109
+ callback(error);
3110
+ this.dispatch("end");
3111
+ } else {
3112
+ startNextController();
3113
+ }
3114
+ }));
3115
+ } else {
3116
+ callback();
3117
+ this.dispatch("end");
3118
+ }
3119
+ };
3120
+ this.dispatch("start");
3121
+ startNextController();
3122
+ }
3123
+ createDirectUploadControllers() {
3124
+ const controllers = [];
3125
+ this.inputs.forEach((input => {
3126
+ toArray(input.files).forEach((file => {
3127
+ const controller = new DirectUploadController$1(input, file);
3128
+ controllers.push(controller);
3129
+ }));
3130
+ }));
3131
+ return controllers;
3132
+ }
3133
+ dispatch(name, detail = {}) {
3134
+ return dispatchEvent$1(this.form, `direct-uploads:${name}`, {
3135
+ detail: detail
3136
+ });
3137
+ }
3138
+ }
3139
+
3140
+ const processingAttribute = "data-direct-uploads-processing";
3141
+
3142
+ const submitButtonsByForm = new WeakMap;
3143
+
3144
+ let started = false;
3145
+
3146
+ function start() {
3147
+ if (!started) {
3148
+ started = true;
3149
+ document.addEventListener("click", didClick, true);
3150
+ document.addEventListener("submit", didSubmitForm, true);
3151
+ document.addEventListener("ajax:before", didSubmitRemoteElement);
3152
+ }
3153
+ }
3154
+
3155
+ function didClick(event) {
3156
+ const {target: target} = event;
3157
+ if ((target.tagName == "INPUT" || target.tagName == "BUTTON") && target.type == "submit" && target.form) {
3158
+ submitButtonsByForm.set(target.form, target);
3159
+ }
3160
+ }
3161
+
3162
+ function didSubmitForm(event) {
3163
+ handleFormSubmissionEvent(event);
3164
+ }
3165
+
3166
+ function didSubmitRemoteElement(event) {
3167
+ if (event.target.tagName == "FORM") {
3168
+ handleFormSubmissionEvent(event);
3169
+ }
3170
+ }
3171
+
3172
+ function handleFormSubmissionEvent(event) {
3173
+ const form = event.target;
3174
+ if (form.hasAttribute(processingAttribute)) {
3175
+ event.preventDefault();
3176
+ return;
3177
+ }
3178
+ const controller = new DirectUploadsController(form);
3179
+ const {inputs: inputs} = controller;
3180
+ if (inputs.length) {
3181
+ event.preventDefault();
3182
+ form.setAttribute(processingAttribute, "");
3183
+ inputs.forEach(disable);
3184
+ controller.start((error => {
3185
+ form.removeAttribute(processingAttribute);
3186
+ if (error) {
3187
+ inputs.forEach(enable);
3188
+ } else {
3189
+ submitForm(form);
3190
+ }
3191
+ }));
3192
+ }
3193
+ }
3194
+
3195
+ function submitForm(form) {
3196
+ let button = submitButtonsByForm.get(form) || findElement(form, "input[type=submit], button[type=submit]");
3197
+ if (button) {
3198
+ const {disabled: disabled} = button;
3199
+ button.disabled = false;
3200
+ button.focus();
3201
+ button.click();
3202
+ button.disabled = disabled;
3203
+ } else {
3204
+ button = document.createElement("input");
3205
+ button.type = "submit";
3206
+ button.style.display = "none";
3207
+ form.appendChild(button);
3208
+ button.click();
3209
+ form.removeChild(button);
3210
+ }
3211
+ submitButtonsByForm.delete(form);
3212
+ }
3213
+
3214
+ function disable(input) {
3215
+ input.disabled = true;
3216
+ }
3217
+
3218
+ function enable(input) {
3219
+ input.disabled = false;
3220
+ }
3221
+
3222
+ function autostart() {
3223
+ if (window.ActiveStorage) {
3224
+ start();
3225
+ }
3226
+ }
3227
+
3228
+ setTimeout(autostart, 1);
3229
+
3230
+ class DirectUploadController {
3231
+ uploadedFile;
3232
+ file;
3233
+ directUpload;
3234
+ recordXHR;
3235
+ uploadXHR;
3236
+ callback = null;
3237
+ constructor(uploadedFile) {
3238
+ this.uploadedFile = uploadedFile;
3239
+ this.file = this.uploadedFile["file"];
3240
+ this.directUpload = new DirectUpload(this.file, this.uploadedFile.url, this);
3241
+ }
3242
+ cancel() {
3243
+ this.directUpload.url = null;
3244
+ this.abortXHR(this.recordXHR);
3245
+ this.abortXHR(this.uploadXHR);
3246
+ }
3247
+ abortXHR(xhr) {
3248
+ if (!xhr)
3249
+ return;
3250
+ xhr.addEventListener("abort", () => {
3251
+ this.complete("aborted", {});
3252
+ });
3253
+ xhr.abort();
3254
+ }
3255
+ start(callback) {
3256
+ this.callback = callback;
3257
+ this.dispatch("start");
3258
+ this.directUpload.create((error, attributes) => {
3259
+ this.complete(error, attributes);
3260
+ });
3261
+ }
3262
+ complete(error, _attributes) {
3263
+ if (error) {
3264
+ this.dispatchError(error);
3265
+ }
3266
+ this.dispatch("end");
3267
+ this.callback(error);
3268
+ }
3269
+ uploadRequestDidProgress(event) {
3270
+ const progress = event.loaded / event.total * 100;
3271
+ if (progress) {
3272
+ this.dispatch("progress", {
3273
+ progress: progress
3274
+ });
3275
+ }
3276
+ }
3277
+ dispatch(name, detail = {}) {
3278
+ return dispatchEvent(this.uploadedFile, `direct-upload:${name}`, {
3279
+ detail: {
3280
+ ...detail,
3281
+ file: this.file,
3282
+ id: this.directUpload.id,
3283
+ }
3284
+ });
3285
+ }
3286
+ dispatchError(error) {
3287
+ this.dispatch("error", {
3288
+ error: error
3289
+ });
3290
+ }
3291
+ directUploadWillCreateBlobWithXHR(xhr) {
3292
+ this.recordXHR = xhr;
3293
+ this.dispatch("before-blob-request", {
3294
+ xhr: xhr
3295
+ });
3296
+ }
3297
+ directUploadWillStoreFileWithXHR(xhr) {
3298
+ this.uploadXHR = xhr;
3299
+ this.uploadedFile.value = this.recordXHR.response.signed_id;
3300
+ this.dispatch("before-storage-request", {
3301
+ xhr: xhr
3302
+ });
3303
+ xhr.upload.addEventListener("progress", (event => this.uploadRequestDidProgress(event)));
3304
+ }
3305
+ }
3306
+ function dispatchEvent(element, type, eventInit = {}) {
3307
+ const { disabled: disabled } = element;
3308
+ const { bubbles: bubbles, cancelable: cancelable, detail: detail } = eventInit;
3309
+ const event = document.createEvent("Event");
3310
+ event.initEvent(type, bubbles || true, cancelable || true);
3311
+ event.detail = detail || {};
3312
+ try {
3313
+ element.disabled = false;
3314
+ element.dispatchEvent(event);
3315
+ }
3316
+ finally {
3317
+ element.disabled = disabled;
3318
+ }
3319
+ return event;
3320
+ }
3321
+
3322
+ class Max {
3323
+ uploadedFile;
3324
+ constructor(uploadedFile) {
3325
+ this.uploadedFile = uploadedFile;
3326
+ }
3327
+ get errors() {
3328
+ if (this.#errors)
3329
+ return this.#errors;
3330
+ this.#errors = [];
3331
+ if (!this.checkValidity()) {
3332
+ this.#errors.push(this.errorMessage);
3333
+ }
3334
+ return this.#errors;
3335
+ }
3336
+ #errors;
3337
+ checkValidity() {
3338
+ if (!this.uploadedFile.max)
3339
+ return true;
3340
+ return this.uploadedFile.size <= this.uploadedFile.max;
3341
+ }
3342
+ get errorMessage() {
3343
+ return [
3344
+ `Must be smaller than ${this.formatBytes(this.uploadedFile.max)},`,
3345
+ `and "${this.uploadedFile.filename}" is ${this.formatBytes(this.uploadedFile.size)}.`,
3346
+ `Please attach a smaller file.`,
3347
+ ].join(" ");
3348
+ }
3349
+ formatBytes(bytes, decimals = 2) {
3350
+ if (bytes === 0)
3351
+ return '0 Bytes';
3352
+ const k = 1024;
3353
+ const dm = decimals < 0 ? 0 : decimals;
3354
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
3355
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
3356
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i];
3357
+ }
3358
+ }
3359
+
3360
+ class Accepts {
3361
+ uploadedFile;
3362
+ constructor(uploadedFile) {
3363
+ this.uploadedFile = uploadedFile;
3364
+ }
3365
+ get errors() {
3366
+ if (this.#errors)
3367
+ return this.#errors;
3368
+ this.#errors = [];
3369
+ const accepts = this.uploadedFile.accepts ? this.uploadedFile.accepts.split(/,\s*/) : [];
3370
+ if (accepts.length > 0 && !accepts.includes(this.uploadedFile.filetype)) {
3371
+ this.#errors.push(`Must be a ${this.joinWords(accepts)}.`);
3372
+ }
3373
+ return this.#errors;
3374
+ }
3375
+ #errors;
3376
+ joinWords(words) {
3377
+ if (words.length >= 3) {
3378
+ return (words.slice(0, -1) + [`or ${words.at(-1)}`]).join(", ");
3379
+ }
3380
+ else {
3381
+ return words.join(" or ");
3382
+ }
3383
+ }
3384
+ }
3385
+
3386
+ const Extensions = {
3387
+ image: ["ase", "art", "bmp", "blp", "cd5", "cit", "cpt", "cr2", "cut", "dds", "dib", "djvu", "egt", "exif", "gif", "gpl", "grf", "icns", "ico", "iff", "jng", "jpeg", "jpg", "jfif", "jp2", "jps", "lbm", "max", "miff", "mng", "msp", "nef", "nitf", "ota", "pbm", "pc1", "pc2", "pc3", "pcf", "pcx", "pdn", "pgm", "PI1", "PI2", "PI3", "pict", "pct", "pnm", "pns", "ppm", "psb", "psd", "pdd", "psp", "px", "pxm", "pxr", "qfx", "raw", "rle", "sct", "sgi", "rgb", "int", "bw", "tga", "tiff", "tif", "vtf", "xbm", "xcf", "xpm", "3dv", "amf", "ai", "awg", "cgm", "cdr", "cmx", "dxf", "e2d", "egt", "eps", "fs", "gbr", "odg", "svg", "stl", "vrml", "x3d", "sxd", "v2d", "vnd", "wmf", "emf", "art", "xar", "png", "webp", "jxr", "hdp", "wdp", "cur", "ecw", "iff", "lbm", "liff", "nrrd", "pam", "pcx", "pgf", "sgi", "rgb", "rgba", "bw", "int", "inta", "sid", "ras", "sun", "tga", "heic", "heif"],
3388
+ video: ["3g2", "3gp", "3gpp", "aaf", "asf", "avchd", "avi", "drc", "flv", "m2v", "m3u8", "m4p", "m4v", "mkv", "mng", "mov", "mp2", "mp4", "mpe", "mpeg", "mpg", "mpv", "mxf", "nsv", "ogg", "ogv", "qt", "rm", "rmvb", "roq", "svi", "vob", "webm", "wmv", "yuv"],
3389
+ pdf: ["pdf"],
3390
+ getFileType: function (filename) {
3391
+ const normalized = filename.toString().split(".").at(-1).toLowerCase().trim();
3392
+ if (this.video.includes(normalized))
3393
+ return "video";
3394
+ if (this.image.includes(normalized))
3395
+ return "image";
3396
+ if (this.pdf.includes(normalized))
3397
+ return "pdf";
3398
+ return "unknown";
3399
+ }
3400
+ };
3401
+
3402
+ class FetchResponse {
3403
+ constructor (response) {
3404
+ this.response = response;
3405
+ }
3406
+
3407
+ get statusCode () {
3408
+ return this.response.status
3409
+ }
3410
+
3411
+ get redirected () {
3412
+ return this.response.redirected
3413
+ }
3414
+
3415
+ get ok () {
3416
+ return this.response.ok
3417
+ }
3418
+
3419
+ get unauthenticated () {
3420
+ return this.statusCode === 401
3421
+ }
3422
+
3423
+ get unprocessableEntity () {
3424
+ return this.statusCode === 422
3425
+ }
3426
+
3427
+ get authenticationURL () {
3428
+ return this.response.headers.get('WWW-Authenticate')
3429
+ }
3430
+
3431
+ get contentType () {
3432
+ const contentType = this.response.headers.get('Content-Type') || '';
3433
+
3434
+ return contentType.replace(/;.*$/, '')
3435
+ }
3436
+
3437
+ get headers () {
3438
+ return this.response.headers
3439
+ }
3440
+
3441
+ get html () {
3442
+ if (this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)) {
3443
+ return this.text
3444
+ }
3445
+
3446
+ return Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`))
3447
+ }
3448
+
3449
+ get json () {
3450
+ if (this.contentType.match(/^application\/.*json$/)) {
3451
+ return this.responseJson || (this.responseJson = this.response.json())
3452
+ }
3453
+
3454
+ return Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`))
3455
+ }
3456
+
3457
+ get text () {
3458
+ return this.responseText || (this.responseText = this.response.text())
3459
+ }
3460
+
3461
+ get isTurboStream () {
3462
+ return this.contentType.match(/^text\/vnd\.turbo-stream\.html/)
3463
+ }
3464
+
3465
+ async renderTurboStream () {
3466
+ if (this.isTurboStream) {
3467
+ if (window.Turbo) {
3468
+ await window.Turbo.renderStreamMessage(await this.text);
3469
+ } else {
3470
+ console.warn('You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js');
3471
+ }
3472
+ } else {
3473
+ return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`))
3474
+ }
3475
+ }
3476
+ }
3477
+
3478
+ class RequestInterceptor {
3479
+ static register (interceptor) {
3480
+ this.interceptor = interceptor;
3481
+ }
3482
+
3483
+ static get () {
3484
+ return this.interceptor
3485
+ }
3486
+
3487
+ static reset () {
3488
+ this.interceptor = undefined;
3489
+ }
3490
+ }
3491
+
3492
+ function getCookie (name) {
3493
+ const cookies = document.cookie ? document.cookie.split('; ') : [];
3494
+ const prefix = `${encodeURIComponent(name)}=`;
3495
+ const cookie = cookies.find(cookie => cookie.startsWith(prefix));
3496
+
3497
+ if (cookie) {
3498
+ const value = cookie.split('=').slice(1).join('=');
3499
+
3500
+ if (value) {
3501
+ return decodeURIComponent(value)
3502
+ }
3503
+ }
3504
+ }
3505
+
3506
+ function compact (object) {
3507
+ const result = {};
3508
+
3509
+ for (const key in object) {
3510
+ const value = object[key];
3511
+ if (value !== undefined) {
3512
+ result[key] = value;
3513
+ }
3514
+ }
3515
+
3516
+ return result
3517
+ }
3518
+
3519
+ function metaContent (name) {
3520
+ const element = document.head.querySelector(`meta[name="${name}"]`);
3521
+ return element && element.content
3522
+ }
3523
+
3524
+ function stringEntriesFromFormData (formData) {
3525
+ return [...formData].reduce((entries, [name, value]) => {
3526
+ return entries.concat(typeof value === 'string' ? [[name, value]] : [])
3527
+ }, [])
3528
+ }
3529
+
3530
+ function mergeEntries (searchParams, entries) {
3531
+ for (const [name, value] of entries) {
3532
+ if (value instanceof window.File) continue
3533
+
3534
+ if (searchParams.has(name)) {
3535
+ searchParams.delete(name);
3536
+ searchParams.set(name, value);
3537
+ } else {
3538
+ searchParams.append(name, value);
3539
+ }
3540
+ }
3541
+ }
3542
+
3543
+ class FetchRequest {
3544
+ constructor (method, url, options = {}) {
3545
+ this.method = method;
3546
+ this.options = options;
3547
+ this.originalUrl = url.toString();
3548
+ }
3549
+
3550
+ async perform () {
3551
+ try {
3552
+ const requestInterceptor = RequestInterceptor.get();
3553
+ if (requestInterceptor) {
3554
+ await requestInterceptor(this);
3555
+ }
3556
+ } catch (error) {
3557
+ console.error(error);
3558
+ }
3559
+
3560
+ const response = new FetchResponse(await window.fetch(this.url, this.fetchOptions));
3561
+
3562
+ if (response.unauthenticated && response.authenticationURL) {
3563
+ return Promise.reject(window.location.href = response.authenticationURL)
3564
+ }
3565
+
3566
+ if (response.ok && response.isTurboStream) {
3567
+ await response.renderTurboStream();
3568
+ }
3569
+
3570
+ return response
3571
+ }
3572
+
3573
+ addHeader (key, value) {
3574
+ const headers = this.additionalHeaders;
3575
+ headers[key] = value;
3576
+ this.options.headers = headers;
3577
+ }
3578
+
3579
+ get fetchOptions () {
3580
+ return {
3581
+ method: this.method.toUpperCase(),
3582
+ headers: this.headers,
3583
+ body: this.formattedBody,
3584
+ signal: this.signal,
3585
+ credentials: 'same-origin',
3586
+ redirect: this.redirect
3587
+ }
3588
+ }
3589
+
3590
+ get headers () {
3591
+ return compact(
3592
+ Object.assign({
3593
+ 'X-Requested-With': 'XMLHttpRequest',
3594
+ 'X-CSRF-Token': this.csrfToken,
3595
+ 'Content-Type': this.contentType,
3596
+ Accept: this.accept
3597
+ },
3598
+ this.additionalHeaders)
3599
+ )
3600
+ }
3601
+
3602
+ get csrfToken () {
3603
+ return getCookie(metaContent('csrf-param')) || metaContent('csrf-token')
3604
+ }
3605
+
3606
+ get contentType () {
3607
+ if (this.options.contentType) {
3608
+ return this.options.contentType
3609
+ } else if (this.body == null || this.body instanceof window.FormData) {
3610
+ return undefined
3611
+ } else if (this.body instanceof window.File) {
3612
+ return this.body.type
3613
+ }
3614
+
3615
+ return 'application/json'
3616
+ }
3617
+
3618
+ get accept () {
3619
+ switch (this.responseKind) {
3620
+ case 'html':
3621
+ return 'text/html, application/xhtml+xml'
3622
+ case 'turbo-stream':
3623
+ return 'text/vnd.turbo-stream.html, text/html, application/xhtml+xml'
3624
+ case 'json':
3625
+ return 'application/json, application/vnd.api+json'
3626
+ default:
3627
+ return '*/*'
3628
+ }
3629
+ }
3630
+
3631
+ get body () {
3632
+ return this.options.body
3633
+ }
3634
+
3635
+ get query () {
3636
+ const originalQuery = (this.originalUrl.split('?')[1] || '').split('#')[0];
3637
+ const params = new URLSearchParams(originalQuery);
3638
+
3639
+ let requestQuery = this.options.query;
3640
+ if (requestQuery instanceof window.FormData) {
3641
+ requestQuery = stringEntriesFromFormData(requestQuery);
3642
+ } else if (requestQuery instanceof window.URLSearchParams) {
3643
+ requestQuery = requestQuery.entries();
3644
+ } else {
3645
+ requestQuery = Object.entries(requestQuery || {});
3646
+ }
3647
+
3648
+ mergeEntries(params, requestQuery);
3649
+
3650
+ const query = params.toString();
3651
+ return (query.length > 0 ? `?${query}` : '')
3652
+ }
3653
+
3654
+ get url () {
3655
+ return (this.originalUrl.split('?')[0]).split('#')[0] + this.query
3656
+ }
3657
+
3658
+ get responseKind () {
3659
+ return this.options.responseKind || 'html'
3660
+ }
3661
+
3662
+ get signal () {
3663
+ return this.options.signal
3664
+ }
3665
+
3666
+ get redirect () {
3667
+ return this.options.redirect || 'follow'
3668
+ }
3669
+
3670
+ get additionalHeaders () {
3671
+ return this.options.headers || {}
3672
+ }
3673
+
3674
+ get formattedBody () {
3675
+ const bodyIsAString = Object.prototype.toString.call(this.body) === '[object String]';
3676
+ const contentTypeIsJson = this.headers['Content-Type'] === 'application/json';
3677
+
3678
+ if (contentTypeIsJson && !bodyIsAString) {
3679
+ return JSON.stringify(this.body)
3680
+ }
3681
+
3682
+ return this.body
3683
+ }
3684
+ }
3685
+
3686
+ const request = (verb, url, payload) => {
3687
+ const req = new FetchRequest(verb, url, {
3688
+ headers: { Accept: "application/json" },
3689
+ body: payload,
3690
+ });
3691
+ return req.perform().then(response => {
3692
+ if(response.response.ok) {
3693
+ return response.json
3694
+ } else {
3695
+ return response
3696
+ }
3697
+ })
3698
+ };
3699
+
3700
+ const get = (url, payload) => request('get', url, payload);
3701
+
3702
+ var DOCUMENT_FRAGMENT_NODE = 11;
3703
+
3704
+ function morphAttrs(fromNode, toNode) {
3705
+ var toNodeAttrs = toNode.attributes;
3706
+ var attr;
3707
+ var attrName;
3708
+ var attrNamespaceURI;
3709
+ var attrValue;
3710
+ var fromValue;
3711
+
3712
+ // document-fragments dont have attributes so lets not do anything
3713
+ if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE || fromNode.nodeType === DOCUMENT_FRAGMENT_NODE) {
3714
+ return;
3715
+ }
3716
+
3717
+ // update attributes on original DOM element
3718
+ for (var i = toNodeAttrs.length - 1; i >= 0; i--) {
3719
+ attr = toNodeAttrs[i];
3720
+ attrName = attr.name;
3721
+ attrNamespaceURI = attr.namespaceURI;
3722
+ attrValue = attr.value;
3723
+
3724
+ if (attrNamespaceURI) {
3725
+ attrName = attr.localName || attrName;
3726
+ fromValue = fromNode.getAttributeNS(attrNamespaceURI, attrName);
3727
+
3728
+ if (fromValue !== attrValue) {
3729
+ if (attr.prefix === 'xmlns'){
3730
+ attrName = attr.name; // It's not allowed to set an attribute with the XMLNS namespace without specifying the `xmlns` prefix
3731
+ }
3732
+ fromNode.setAttributeNS(attrNamespaceURI, attrName, attrValue);
3733
+ }
3734
+ } else {
3735
+ fromValue = fromNode.getAttribute(attrName);
3736
+
3737
+ if (fromValue !== attrValue) {
3738
+ fromNode.setAttribute(attrName, attrValue);
3739
+ }
3740
+ }
3741
+ }
3742
+
3743
+ // Remove any extra attributes found on the original DOM element that
3744
+ // weren't found on the target element.
3745
+ var fromNodeAttrs = fromNode.attributes;
3746
+
3747
+ for (var d = fromNodeAttrs.length - 1; d >= 0; d--) {
3748
+ attr = fromNodeAttrs[d];
3749
+ attrName = attr.name;
3750
+ attrNamespaceURI = attr.namespaceURI;
3751
+
3752
+ if (attrNamespaceURI) {
3753
+ attrName = attr.localName || attrName;
3754
+
3755
+ if (!toNode.hasAttributeNS(attrNamespaceURI, attrName)) {
3756
+ fromNode.removeAttributeNS(attrNamespaceURI, attrName);
3757
+ }
3758
+ } else {
3759
+ if (!toNode.hasAttribute(attrName)) {
3760
+ fromNode.removeAttribute(attrName);
3761
+ }
3762
+ }
3763
+ }
3764
+ }
3765
+
3766
+ var range; // Create a range object for efficently rendering strings to elements.
3767
+ var NS_XHTML = 'http://www.w3.org/1999/xhtml';
3768
+
3769
+ var doc = typeof document === 'undefined' ? undefined : document;
3770
+ var HAS_TEMPLATE_SUPPORT = !!doc && 'content' in doc.createElement('template');
3771
+ var HAS_RANGE_SUPPORT = !!doc && doc.createRange && 'createContextualFragment' in doc.createRange();
3772
+
3773
+ function createFragmentFromTemplate(str) {
3774
+ var template = doc.createElement('template');
3775
+ template.innerHTML = str;
3776
+ return template.content.childNodes[0];
3777
+ }
3778
+
3779
+ function createFragmentFromRange(str) {
3780
+ if (!range) {
3781
+ range = doc.createRange();
3782
+ range.selectNode(doc.body);
3783
+ }
3784
+
3785
+ var fragment = range.createContextualFragment(str);
3786
+ return fragment.childNodes[0];
3787
+ }
3788
+
3789
+ function createFragmentFromWrap(str) {
3790
+ var fragment = doc.createElement('body');
3791
+ fragment.innerHTML = str;
3792
+ return fragment.childNodes[0];
3793
+ }
3794
+
3795
+ /**
3796
+ * This is about the same
3797
+ * var html = new DOMParser().parseFromString(str, 'text/html');
3798
+ * return html.body.firstChild;
3799
+ *
3800
+ * @method toElement
3801
+ * @param {String} str
3802
+ */
3803
+ function toElement(str) {
3804
+ str = str.trim();
3805
+ if (HAS_TEMPLATE_SUPPORT) {
3806
+ // avoid restrictions on content for things like `<tr><th>Hi</th></tr>` which
3807
+ // createContextualFragment doesn't support
3808
+ // <template> support not available in IE
3809
+ return createFragmentFromTemplate(str);
3810
+ } else if (HAS_RANGE_SUPPORT) {
3811
+ return createFragmentFromRange(str);
3812
+ }
3813
+
3814
+ return createFragmentFromWrap(str);
3815
+ }
3816
+
3817
+ /**
3818
+ * Returns true if two node's names are the same.
3819
+ *
3820
+ * NOTE: We don't bother checking `namespaceURI` because you will never find two HTML elements with the same
3821
+ * nodeName and different namespace URIs.
3822
+ *
3823
+ * @param {Element} a
3824
+ * @param {Element} b The target element
3825
+ * @return {boolean}
3826
+ */
3827
+ function compareNodeNames(fromEl, toEl) {
3828
+ var fromNodeName = fromEl.nodeName;
3829
+ var toNodeName = toEl.nodeName;
3830
+ var fromCodeStart, toCodeStart;
3831
+
3832
+ if (fromNodeName === toNodeName) {
3833
+ return true;
3834
+ }
3835
+
3836
+ fromCodeStart = fromNodeName.charCodeAt(0);
3837
+ toCodeStart = toNodeName.charCodeAt(0);
3838
+
3839
+ // If the target element is a virtual DOM node or SVG node then we may
3840
+ // need to normalize the tag name before comparing. Normal HTML elements that are
3841
+ // in the "http://www.w3.org/1999/xhtml"
3842
+ // are converted to upper case
3843
+ if (fromCodeStart <= 90 && toCodeStart >= 97) { // from is upper and to is lower
3844
+ return fromNodeName === toNodeName.toUpperCase();
3845
+ } else if (toCodeStart <= 90 && fromCodeStart >= 97) { // to is upper and from is lower
3846
+ return toNodeName === fromNodeName.toUpperCase();
3847
+ } else {
3848
+ return false;
3849
+ }
3850
+ }
3851
+
3852
+ /**
3853
+ * Create an element, optionally with a known namespace URI.
3854
+ *
3855
+ * @param {string} name the element name, e.g. 'div' or 'svg'
3856
+ * @param {string} [namespaceURI] the element's namespace URI, i.e. the value of
3857
+ * its `xmlns` attribute or its inferred namespace.
3858
+ *
3859
+ * @return {Element}
3860
+ */
3861
+ function createElementNS(name, namespaceURI) {
3862
+ return !namespaceURI || namespaceURI === NS_XHTML ?
3863
+ doc.createElement(name) :
3864
+ doc.createElementNS(namespaceURI, name);
3865
+ }
3866
+
3867
+ /**
3868
+ * Copies the children of one DOM element to another DOM element
3869
+ */
3870
+ function moveChildren(fromEl, toEl) {
3871
+ var curChild = fromEl.firstChild;
3872
+ while (curChild) {
3873
+ var nextChild = curChild.nextSibling;
3874
+ toEl.appendChild(curChild);
3875
+ curChild = nextChild;
3876
+ }
3877
+ return toEl;
3878
+ }
3879
+
3880
+ function syncBooleanAttrProp(fromEl, toEl, name) {
3881
+ if (fromEl[name] !== toEl[name]) {
3882
+ fromEl[name] = toEl[name];
3883
+ if (fromEl[name]) {
3884
+ fromEl.setAttribute(name, '');
3885
+ } else {
3886
+ fromEl.removeAttribute(name);
3887
+ }
3888
+ }
3889
+ }
3890
+
3891
+ var specialElHandlers = {
3892
+ OPTION: function(fromEl, toEl) {
3893
+ var parentNode = fromEl.parentNode;
3894
+ if (parentNode) {
3895
+ var parentName = parentNode.nodeName.toUpperCase();
3896
+ if (parentName === 'OPTGROUP') {
3897
+ parentNode = parentNode.parentNode;
3898
+ parentName = parentNode && parentNode.nodeName.toUpperCase();
3899
+ }
3900
+ if (parentName === 'SELECT' && !parentNode.hasAttribute('multiple')) {
3901
+ if (fromEl.hasAttribute('selected') && !toEl.selected) {
3902
+ // Workaround for MS Edge bug where the 'selected' attribute can only be
3903
+ // removed if set to a non-empty value:
3904
+ // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12087679/
3905
+ fromEl.setAttribute('selected', 'selected');
3906
+ fromEl.removeAttribute('selected');
3907
+ }
3908
+ // We have to reset select element's selectedIndex to -1, otherwise setting
3909
+ // fromEl.selected using the syncBooleanAttrProp below has no effect.
3910
+ // The correct selectedIndex will be set in the SELECT special handler below.
3911
+ parentNode.selectedIndex = -1;
3912
+ }
3913
+ }
3914
+ syncBooleanAttrProp(fromEl, toEl, 'selected');
3915
+ },
3916
+ /**
3917
+ * The "value" attribute is special for the <input> element since it sets
3918
+ * the initial value. Changing the "value" attribute without changing the
3919
+ * "value" property will have no effect since it is only used to the set the
3920
+ * initial value. Similar for the "checked" attribute, and "disabled".
3921
+ */
3922
+ INPUT: function(fromEl, toEl) {
3923
+ syncBooleanAttrProp(fromEl, toEl, 'checked');
3924
+ syncBooleanAttrProp(fromEl, toEl, 'disabled');
3925
+
3926
+ if (fromEl.value !== toEl.value) {
3927
+ fromEl.value = toEl.value;
3928
+ }
3929
+
3930
+ if (!toEl.hasAttribute('value')) {
3931
+ fromEl.removeAttribute('value');
3932
+ }
3933
+ },
3934
+
3935
+ TEXTAREA: function(fromEl, toEl) {
3936
+ var newValue = toEl.value;
3937
+ if (fromEl.value !== newValue) {
3938
+ fromEl.value = newValue;
3939
+ }
3940
+
3941
+ var firstChild = fromEl.firstChild;
3942
+ if (firstChild) {
3943
+ // Needed for IE. Apparently IE sets the placeholder as the
3944
+ // node value and vise versa. This ignores an empty update.
3945
+ var oldValue = firstChild.nodeValue;
3946
+
3947
+ if (oldValue == newValue || (!newValue && oldValue == fromEl.placeholder)) {
3948
+ return;
3949
+ }
3950
+
3951
+ firstChild.nodeValue = newValue;
3952
+ }
3953
+ },
3954
+ SELECT: function(fromEl, toEl) {
3955
+ if (!toEl.hasAttribute('multiple')) {
3956
+ var selectedIndex = -1;
3957
+ var i = 0;
3958
+ // We have to loop through children of fromEl, not toEl since nodes can be moved
3959
+ // from toEl to fromEl directly when morphing.
3960
+ // At the time this special handler is invoked, all children have already been morphed
3961
+ // and appended to / removed from fromEl, so using fromEl here is safe and correct.
3962
+ var curChild = fromEl.firstChild;
3963
+ var optgroup;
3964
+ var nodeName;
3965
+ while(curChild) {
3966
+ nodeName = curChild.nodeName && curChild.nodeName.toUpperCase();
3967
+ if (nodeName === 'OPTGROUP') {
3968
+ optgroup = curChild;
3969
+ curChild = optgroup.firstChild;
3970
+ } else {
3971
+ if (nodeName === 'OPTION') {
3972
+ if (curChild.hasAttribute('selected')) {
3973
+ selectedIndex = i;
3974
+ break;
3975
+ }
3976
+ i++;
3977
+ }
3978
+ curChild = curChild.nextSibling;
3979
+ if (!curChild && optgroup) {
3980
+ curChild = optgroup.nextSibling;
3981
+ optgroup = null;
3982
+ }
3983
+ }
3984
+ }
3985
+
3986
+ fromEl.selectedIndex = selectedIndex;
3987
+ }
3988
+ }
3989
+ };
3990
+
3991
+ var ELEMENT_NODE = 1;
3992
+ var DOCUMENT_FRAGMENT_NODE$1 = 11;
3993
+ var TEXT_NODE = 3;
3994
+ var COMMENT_NODE = 8;
3995
+
3996
+ function noop() {}
3997
+
3998
+ function defaultGetNodeKey(node) {
3999
+ if (node) {
4000
+ return (node.getAttribute && node.getAttribute('id')) || node.id;
4001
+ }
4002
+ }
4003
+
4004
+ function morphdomFactory(morphAttrs) {
4005
+
4006
+ return function morphdom(fromNode, toNode, options) {
4007
+ if (!options) {
4008
+ options = {};
4009
+ }
4010
+
4011
+ if (typeof toNode === 'string') {
4012
+ if (fromNode.nodeName === '#document' || fromNode.nodeName === 'HTML' || fromNode.nodeName === 'BODY') {
4013
+ var toNodeHtml = toNode;
4014
+ toNode = doc.createElement('html');
4015
+ toNode.innerHTML = toNodeHtml;
4016
+ } else {
4017
+ toNode = toElement(toNode);
4018
+ }
4019
+ } else if (toNode.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
4020
+ toNode = toNode.firstElementChild;
4021
+ }
4022
+
4023
+ var getNodeKey = options.getNodeKey || defaultGetNodeKey;
4024
+ var onBeforeNodeAdded = options.onBeforeNodeAdded || noop;
4025
+ var onNodeAdded = options.onNodeAdded || noop;
4026
+ var onBeforeElUpdated = options.onBeforeElUpdated || noop;
4027
+ var onElUpdated = options.onElUpdated || noop;
4028
+ var onBeforeNodeDiscarded = options.onBeforeNodeDiscarded || noop;
4029
+ var onNodeDiscarded = options.onNodeDiscarded || noop;
4030
+ var onBeforeElChildrenUpdated = options.onBeforeElChildrenUpdated || noop;
4031
+ var skipFromChildren = options.skipFromChildren || noop;
4032
+ var addChild = options.addChild || function(parent, child){ return parent.appendChild(child); };
4033
+ var childrenOnly = options.childrenOnly === true;
4034
+
4035
+ // This object is used as a lookup to quickly find all keyed elements in the original DOM tree.
4036
+ var fromNodesLookup = Object.create(null);
4037
+ var keyedRemovalList = [];
4038
+
4039
+ function addKeyedRemoval(key) {
4040
+ keyedRemovalList.push(key);
4041
+ }
4042
+
4043
+ function walkDiscardedChildNodes(node, skipKeyedNodes) {
4044
+ if (node.nodeType === ELEMENT_NODE) {
4045
+ var curChild = node.firstChild;
4046
+ while (curChild) {
4047
+
4048
+ var key = undefined;
4049
+
4050
+ if (skipKeyedNodes && (key = getNodeKey(curChild))) {
4051
+ // If we are skipping keyed nodes then we add the key
4052
+ // to a list so that it can be handled at the very end.
4053
+ addKeyedRemoval(key);
4054
+ } else {
4055
+ // Only report the node as discarded if it is not keyed. We do this because
4056
+ // at the end we loop through all keyed elements that were unmatched
4057
+ // and then discard them in one final pass.
4058
+ onNodeDiscarded(curChild);
4059
+ if (curChild.firstChild) {
4060
+ walkDiscardedChildNodes(curChild, skipKeyedNodes);
4061
+ }
4062
+ }
4063
+
4064
+ curChild = curChild.nextSibling;
4065
+ }
4066
+ }
4067
+ }
4068
+
4069
+ /**
4070
+ * Removes a DOM node out of the original DOM
4071
+ *
4072
+ * @param {Node} node The node to remove
4073
+ * @param {Node} parentNode The nodes parent
4074
+ * @param {Boolean} skipKeyedNodes If true then elements with keys will be skipped and not discarded.
4075
+ * @return {undefined}
4076
+ */
4077
+ function removeNode(node, parentNode, skipKeyedNodes) {
4078
+ if (onBeforeNodeDiscarded(node) === false) {
4079
+ return;
4080
+ }
4081
+
4082
+ if (parentNode) {
4083
+ parentNode.removeChild(node);
4084
+ }
4085
+
4086
+ onNodeDiscarded(node);
4087
+ walkDiscardedChildNodes(node, skipKeyedNodes);
4088
+ }
4089
+
4090
+ // // TreeWalker implementation is no faster, but keeping this around in case this changes in the future
4091
+ // function indexTree(root) {
4092
+ // var treeWalker = document.createTreeWalker(
4093
+ // root,
4094
+ // NodeFilter.SHOW_ELEMENT);
4095
+ //
4096
+ // var el;
4097
+ // while((el = treeWalker.nextNode())) {
4098
+ // var key = getNodeKey(el);
4099
+ // if (key) {
4100
+ // fromNodesLookup[key] = el;
4101
+ // }
4102
+ // }
4103
+ // }
4104
+
4105
+ // // NodeIterator implementation is no faster, but keeping this around in case this changes in the future
4106
+ //
4107
+ // function indexTree(node) {
4108
+ // var nodeIterator = document.createNodeIterator(node, NodeFilter.SHOW_ELEMENT);
4109
+ // var el;
4110
+ // while((el = nodeIterator.nextNode())) {
4111
+ // var key = getNodeKey(el);
4112
+ // if (key) {
4113
+ // fromNodesLookup[key] = el;
4114
+ // }
4115
+ // }
4116
+ // }
4117
+
4118
+ function indexTree(node) {
4119
+ if (node.nodeType === ELEMENT_NODE || node.nodeType === DOCUMENT_FRAGMENT_NODE$1) {
4120
+ var curChild = node.firstChild;
4121
+ while (curChild) {
4122
+ var key = getNodeKey(curChild);
4123
+ if (key) {
4124
+ fromNodesLookup[key] = curChild;
4125
+ }
4126
+
4127
+ // Walk recursively
4128
+ indexTree(curChild);
4129
+
4130
+ curChild = curChild.nextSibling;
4131
+ }
4132
+ }
4133
+ }
4134
+
4135
+ indexTree(fromNode);
4136
+
4137
+ function handleNodeAdded(el) {
4138
+ onNodeAdded(el);
4139
+
4140
+ var curChild = el.firstChild;
4141
+ while (curChild) {
4142
+ var nextSibling = curChild.nextSibling;
4143
+
4144
+ var key = getNodeKey(curChild);
4145
+ if (key) {
4146
+ var unmatchedFromEl = fromNodesLookup[key];
4147
+ // if we find a duplicate #id node in cache, replace `el` with cache value
4148
+ // and morph it to the child node.
4149
+ if (unmatchedFromEl && compareNodeNames(curChild, unmatchedFromEl)) {
4150
+ curChild.parentNode.replaceChild(unmatchedFromEl, curChild);
4151
+ morphEl(unmatchedFromEl, curChild);
4152
+ } else {
4153
+ handleNodeAdded(curChild);
4154
+ }
4155
+ } else {
4156
+ // recursively call for curChild and it's children to see if we find something in
4157
+ // fromNodesLookup
4158
+ handleNodeAdded(curChild);
4159
+ }
4160
+
4161
+ curChild = nextSibling;
4162
+ }
4163
+ }
4164
+
4165
+ function cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey) {
4166
+ // We have processed all of the "to nodes". If curFromNodeChild is
4167
+ // non-null then we still have some from nodes left over that need
4168
+ // to be removed
4169
+ while (curFromNodeChild) {
4170
+ var fromNextSibling = curFromNodeChild.nextSibling;
4171
+ if ((curFromNodeKey = getNodeKey(curFromNodeChild))) {
4172
+ // Since the node is keyed it might be matched up later so we defer
4173
+ // the actual removal to later
4174
+ addKeyedRemoval(curFromNodeKey);
4175
+ } else {
4176
+ // NOTE: we skip nested keyed nodes from being removed since there is
4177
+ // still a chance they will be matched up later
4178
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
4179
+ }
4180
+ curFromNodeChild = fromNextSibling;
4181
+ }
4182
+ }
4183
+
4184
+ function morphEl(fromEl, toEl, childrenOnly) {
4185
+ var toElKey = getNodeKey(toEl);
4186
+
4187
+ if (toElKey) {
4188
+ // If an element with an ID is being morphed then it will be in the final
4189
+ // DOM so clear it out of the saved elements collection
4190
+ delete fromNodesLookup[toElKey];
4191
+ }
4192
+
4193
+ if (!childrenOnly) {
4194
+ // optional
4195
+ if (onBeforeElUpdated(fromEl, toEl) === false) {
4196
+ return;
4197
+ }
4198
+
4199
+ // update attributes on original DOM element first
4200
+ morphAttrs(fromEl, toEl);
4201
+ // optional
4202
+ onElUpdated(fromEl);
4203
+
4204
+ if (onBeforeElChildrenUpdated(fromEl, toEl) === false) {
4205
+ return;
4206
+ }
4207
+ }
4208
+
4209
+ if (fromEl.nodeName !== 'TEXTAREA') {
4210
+ morphChildren(fromEl, toEl);
4211
+ } else {
4212
+ specialElHandlers.TEXTAREA(fromEl, toEl);
4213
+ }
4214
+ }
4215
+
4216
+ function morphChildren(fromEl, toEl) {
4217
+ var skipFrom = skipFromChildren(fromEl, toEl);
4218
+ var curToNodeChild = toEl.firstChild;
4219
+ var curFromNodeChild = fromEl.firstChild;
4220
+ var curToNodeKey;
4221
+ var curFromNodeKey;
4222
+
4223
+ var fromNextSibling;
4224
+ var toNextSibling;
4225
+ var matchingFromEl;
4226
+
4227
+ // walk the children
4228
+ outer: while (curToNodeChild) {
4229
+ toNextSibling = curToNodeChild.nextSibling;
4230
+ curToNodeKey = getNodeKey(curToNodeChild);
4231
+
4232
+ // walk the fromNode children all the way through
4233
+ while (!skipFrom && curFromNodeChild) {
4234
+ fromNextSibling = curFromNodeChild.nextSibling;
4235
+
4236
+ if (curToNodeChild.isSameNode && curToNodeChild.isSameNode(curFromNodeChild)) {
4237
+ curToNodeChild = toNextSibling;
4238
+ curFromNodeChild = fromNextSibling;
4239
+ continue outer;
4240
+ }
4241
+
4242
+ curFromNodeKey = getNodeKey(curFromNodeChild);
4243
+
4244
+ var curFromNodeType = curFromNodeChild.nodeType;
4245
+
4246
+ // this means if the curFromNodeChild doesnt have a match with the curToNodeChild
4247
+ var isCompatible = undefined;
4248
+
4249
+ if (curFromNodeType === curToNodeChild.nodeType) {
4250
+ if (curFromNodeType === ELEMENT_NODE) {
4251
+ // Both nodes being compared are Element nodes
4252
+
4253
+ if (curToNodeKey) {
4254
+ // The target node has a key so we want to match it up with the correct element
4255
+ // in the original DOM tree
4256
+ if (curToNodeKey !== curFromNodeKey) {
4257
+ // The current element in the original DOM tree does not have a matching key so
4258
+ // let's check our lookup to see if there is a matching element in the original
4259
+ // DOM tree
4260
+ if ((matchingFromEl = fromNodesLookup[curToNodeKey])) {
4261
+ if (fromNextSibling === matchingFromEl) {
4262
+ // Special case for single element removals. To avoid removing the original
4263
+ // DOM node out of the tree (since that can break CSS transitions, etc.),
4264
+ // we will instead discard the current node and wait until the next
4265
+ // iteration to properly match up the keyed target element with its matching
4266
+ // element in the original tree
4267
+ isCompatible = false;
4268
+ } else {
4269
+ // We found a matching keyed element somewhere in the original DOM tree.
4270
+ // Let's move the original DOM node into the current position and morph
4271
+ // it.
4272
+
4273
+ // NOTE: We use insertBefore instead of replaceChild because we want to go through
4274
+ // the `removeNode()` function for the node that is being discarded so that
4275
+ // all lifecycle hooks are correctly invoked
4276
+ fromEl.insertBefore(matchingFromEl, curFromNodeChild);
4277
+
4278
+ // fromNextSibling = curFromNodeChild.nextSibling;
4279
+
4280
+ if (curFromNodeKey) {
4281
+ // Since the node is keyed it might be matched up later so we defer
4282
+ // the actual removal to later
4283
+ addKeyedRemoval(curFromNodeKey);
4284
+ } else {
4285
+ // NOTE: we skip nested keyed nodes from being removed since there is
4286
+ // still a chance they will be matched up later
4287
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
4288
+ }
4289
+
4290
+ curFromNodeChild = matchingFromEl;
4291
+ }
4292
+ } else {
4293
+ // The nodes are not compatible since the "to" node has a key and there
4294
+ // is no matching keyed node in the source tree
4295
+ isCompatible = false;
4296
+ }
4297
+ }
4298
+ } else if (curFromNodeKey) {
4299
+ // The original has a key
4300
+ isCompatible = false;
4301
+ }
4302
+
4303
+ isCompatible = isCompatible !== false && compareNodeNames(curFromNodeChild, curToNodeChild);
4304
+ if (isCompatible) {
4305
+ // We found compatible DOM elements so transform
4306
+ // the current "from" node to match the current
4307
+ // target DOM node.
4308
+ // MORPH
4309
+ morphEl(curFromNodeChild, curToNodeChild);
4310
+ }
4311
+
4312
+ } else if (curFromNodeType === TEXT_NODE || curFromNodeType == COMMENT_NODE) {
4313
+ // Both nodes being compared are Text or Comment nodes
4314
+ isCompatible = true;
4315
+ // Simply update nodeValue on the original node to
4316
+ // change the text value
4317
+ if (curFromNodeChild.nodeValue !== curToNodeChild.nodeValue) {
4318
+ curFromNodeChild.nodeValue = curToNodeChild.nodeValue;
4319
+ }
4320
+
4321
+ }
4322
+ }
4323
+
4324
+ if (isCompatible) {
4325
+ // Advance both the "to" child and the "from" child since we found a match
4326
+ // Nothing else to do as we already recursively called morphChildren above
4327
+ curToNodeChild = toNextSibling;
4328
+ curFromNodeChild = fromNextSibling;
4329
+ continue outer;
4330
+ }
4331
+
4332
+ // No compatible match so remove the old node from the DOM and continue trying to find a
4333
+ // match in the original DOM. However, we only do this if the from node is not keyed
4334
+ // since it is possible that a keyed node might match up with a node somewhere else in the
4335
+ // target tree and we don't want to discard it just yet since it still might find a
4336
+ // home in the final DOM tree. After everything is done we will remove any keyed nodes
4337
+ // that didn't find a home
4338
+ if (curFromNodeKey) {
4339
+ // Since the node is keyed it might be matched up later so we defer
4340
+ // the actual removal to later
4341
+ addKeyedRemoval(curFromNodeKey);
4342
+ } else {
4343
+ // NOTE: we skip nested keyed nodes from being removed since there is
4344
+ // still a chance they will be matched up later
4345
+ removeNode(curFromNodeChild, fromEl, true /* skip keyed nodes */);
4346
+ }
4347
+
4348
+ curFromNodeChild = fromNextSibling;
4349
+ } // END: while(curFromNodeChild) {}
4350
+
4351
+ // If we got this far then we did not find a candidate match for
4352
+ // our "to node" and we exhausted all of the children "from"
4353
+ // nodes. Therefore, we will just append the current "to" node
4354
+ // to the end
4355
+ if (curToNodeKey && (matchingFromEl = fromNodesLookup[curToNodeKey]) && compareNodeNames(matchingFromEl, curToNodeChild)) {
4356
+ // MORPH
4357
+ if(!skipFrom){ addChild(fromEl, matchingFromEl); }
4358
+ morphEl(matchingFromEl, curToNodeChild);
4359
+ } else {
4360
+ var onBeforeNodeAddedResult = onBeforeNodeAdded(curToNodeChild);
4361
+ if (onBeforeNodeAddedResult !== false) {
4362
+ if (onBeforeNodeAddedResult) {
4363
+ curToNodeChild = onBeforeNodeAddedResult;
4364
+ }
4365
+
4366
+ if (curToNodeChild.actualize) {
4367
+ curToNodeChild = curToNodeChild.actualize(fromEl.ownerDocument || doc);
4368
+ }
4369
+ addChild(fromEl, curToNodeChild);
4370
+ handleNodeAdded(curToNodeChild);
4371
+ }
4372
+ }
4373
+
4374
+ curToNodeChild = toNextSibling;
4375
+ curFromNodeChild = fromNextSibling;
4376
+ }
4377
+
4378
+ cleanupFromEl(fromEl, curFromNodeChild, curFromNodeKey);
4379
+
4380
+ var specialElHandler = specialElHandlers[fromEl.nodeName];
4381
+ if (specialElHandler) {
4382
+ specialElHandler(fromEl, toEl);
4383
+ }
4384
+ } // END: morphChildren(...)
4385
+
4386
+ var morphedNode = fromNode;
4387
+ var morphedNodeType = morphedNode.nodeType;
4388
+ var toNodeType = toNode.nodeType;
4389
+
4390
+ if (!childrenOnly) {
4391
+ // Handle the case where we are given two DOM nodes that are not
4392
+ // compatible (e.g. <div> --> <span> or <div> --> TEXT)
4393
+ if (morphedNodeType === ELEMENT_NODE) {
4394
+ if (toNodeType === ELEMENT_NODE) {
4395
+ if (!compareNodeNames(fromNode, toNode)) {
4396
+ onNodeDiscarded(fromNode);
4397
+ morphedNode = moveChildren(fromNode, createElementNS(toNode.nodeName, toNode.namespaceURI));
4398
+ }
4399
+ } else {
4400
+ // Going from an element node to a text node
4401
+ morphedNode = toNode;
4402
+ }
4403
+ } else if (morphedNodeType === TEXT_NODE || morphedNodeType === COMMENT_NODE) { // Text or comment node
4404
+ if (toNodeType === morphedNodeType) {
4405
+ if (morphedNode.nodeValue !== toNode.nodeValue) {
4406
+ morphedNode.nodeValue = toNode.nodeValue;
4407
+ }
4408
+
4409
+ return morphedNode;
4410
+ } else {
4411
+ // Text node to something else
4412
+ morphedNode = toNode;
4413
+ }
4414
+ }
4415
+ }
4416
+
4417
+ if (morphedNode === toNode) {
4418
+ // The "to node" was not compatible with the "from node" so we had to
4419
+ // toss out the "from node" and use the "to node"
4420
+ onNodeDiscarded(fromNode);
4421
+ } else {
4422
+ if (toNode.isSameNode && toNode.isSameNode(morphedNode)) {
4423
+ return;
4424
+ }
4425
+
4426
+ morphEl(morphedNode, toNode, childrenOnly);
4427
+
4428
+ // We now need to loop over any keyed nodes that might need to be
4429
+ // removed. We only do the removal if we know that the keyed node
4430
+ // never found a match. When a keyed node is matched up we remove
4431
+ // it out of fromNodesLookup and we use fromNodesLookup to determine
4432
+ // if a keyed node has been matched up or not
4433
+ if (keyedRemovalList) {
4434
+ for (var i=0, len=keyedRemovalList.length; i<len; i++) {
4435
+ var elToRemove = fromNodesLookup[keyedRemovalList[i]];
4436
+ if (elToRemove) {
4437
+ removeNode(elToRemove, elToRemove.parentNode, false);
4438
+ }
4439
+ }
4440
+ }
4441
+ }
4442
+
4443
+ if (!childrenOnly && morphedNode !== fromNode && fromNode.parentNode) {
4444
+ if (morphedNode.actualize) {
4445
+ morphedNode = morphedNode.actualize(fromNode.ownerDocument || doc);
4446
+ }
4447
+ // If we had to swap out the from node with a new node because the old
4448
+ // node was not compatible with the target node then we need to
4449
+ // replace the old DOM node in the original DOM tree. This is only
4450
+ // possible if the original DOM node was part of a DOM tree which
4451
+ // we know is the case if it has a parent node.
4452
+ fromNode.parentNode.replaceChild(morphedNode, fromNode);
4453
+ }
4454
+
4455
+ return morphedNode;
4456
+ };
4457
+ }
4458
+
4459
+ var morphdom = morphdomFactory(morphAttrs);
4460
+
4461
+ function html(html) {
4462
+ const el = document.createElement("div");
4463
+ morphdom(el, `<div>${html}</div>`);
4464
+ return el.children[0];
4465
+ }
4466
+ function arrayRemove(arr, e) {
4467
+ const index = arr.findIndex(x => x === e);
4468
+ if (index !== -1) {
4469
+ arr.splice(index, 1);
4470
+ }
4471
+ }
4472
+
4473
+ const uploadedFileCss = ":host{display:block;width:100%;max-width:100%;font-size:13px}figure{margin:0}.progress-details{position:relative;display:flex;align-items:center}progress-bar{flex:1 0;padding:0 10px}progress-bar.pending{opacity:0.5}progress-bar.complete{opacity:0.8}progress-bar:not(.complete)+.progress-icon{display:none}progress-bar.complete+.progress-icon{content:url('data:image/svg+xml;utf8,<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 20 20\" style=\"enable-background:new 0 0 20 20;\" xml:space=\"preserve\"><g><path d=\"M6.3,9.1c0.2,0,0.5,0.1,0.7,0.4c0.5,0.5,1,1,1.4,1.4c0.3,0.3,0.3,0.3,0.6,0c1.4-1.3,2.7-2.6,4-3.9c0.3-0.3,0.6-0.4,1-0.4 c0.5,0.1,0.9,0.6,0.7,1.1c-0.1,0.2-0.2,0.4-0.3,0.6c-1.6,1.6-3.2,3.2-4.8,4.8c-0.5,0.5-1,0.5-1.6,0c-0.8-0.7-1.5-1.5-2.3-2.3 c-0.3-0.3-0.5-0.6-0.3-1.1C5.5,9.3,5.8,9.1,6.3,9.1z\"/></g></svg>');filter:invert(100%)}.progress-icon{display:inline-block;flex:0 0 20px;width:28px;height:28px;background-size:contain;position:absolute;right:30px;z-index:1}progress-bar.error{background:#f8b3b1;background:rgba(74, 70, 70, 0.25);opacity:1}.progress-bar a{color:#fff}.download-link{padding-right:20px;color:#fff}.remove-media{display:inline-block;content:url('data:image/svg+xml;utf8,<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 40 40\" style=\"enable-background:new 0 0 40 40;\" xml:space=\"preserve\"><g><path d=\"M0,19.9C0.2,8.5,9.2-0.1,20.1,0C31.8,0.1,40.2,9.5,40,20.4c-0.2,11-8.9,19.7-20.1,19.6C8,39.9,0,30.5,0,19.9z M20,3.7 c-9,0-16.3,7-16.3,16.2C3.7,29,10.9,36.3,20,36.3c9,0,16.3-7.1,16.4-16.3C36.3,11,29.2,3.8,20,3.7z\"/><path d=\"M17.3,20c-0.2-0.2-0.3-0.4-0.5-0.6c-1-1-2-1.9-2.9-2.9c-0.5-0.5-0.8-1.1-0.7-1.9c0.1-0.7,0.5-1.2,1.2-1.4 c0.8-0.2,1.5,0,2.1,0.6c1,1,2,2,3,3.1c0.3,0.4,0.6,0.3,0.9,0c1-1,2-2,3-3c0.3-0.3,0.7-0.5,1.1-0.6c0.8-0.2,1.6,0.1,2,0.8 c0.4,0.8,0.3,1.7-0.4,2.4c-1,1-2,2-3,3c-0.2,0.2-0.3,0.4-0.5,0.6c1.2,1.2,2.3,2.3,3.4,3.4c0.6,0.6,0.9,1.3,0.6,2.2 c-0.4,1.1-1.7,1.6-2.6,1c-0.3-0.2-0.5-0.4-0.8-0.6c-1-1-1.9-1.9-2.9-2.9c-0.3-0.3-0.5-0.3-0.9,0c-1,1-2,2.1-3,3 c-0.4,0.4-1,0.6-1.5,0.8c-0.6,0.1-1.2-0.2-1.5-0.8c-0.4-0.6-0.5-1.3-0.1-1.9c0.2-0.3,0.4-0.5,0.6-0.7C15.1,22.3,16.2,21.2,17.3,20z \"/></g></svg>');flex:0 0 25px;width:25px;height:20px;align-items:center;opacity:0.25}.remove-media:hover{opacity:1;filter:invert(50%)sepia(100%)saturate(10000%)}.remove-media span{display:inline-block;text-indent:-9999px;color:transparent}";
4474
+
4475
+ let uid = 0;
4476
+ const UploadedFile$1 = /*@__PURE__*/ proxyCustomElement(class UploadedFile extends H {
4477
+ get el() { return this; }
4478
+ removeEvent;
4479
+ removeClicked = event => {
4480
+ event.stopPropagation();
4481
+ event.preventDefault();
4482
+ this.controller?.cancel();
4483
+ this.removeEvent.emit(this);
4484
+ };
4485
+ inputTarget;
4486
+ controller;
4487
+ _file;
4488
+ uid;
4489
+ constructor() {
4490
+ super();
4491
+ this.__registerHost();
4492
+ this.__attachShadow();
4493
+ this.removeEvent = createEvent(this, "uploaded-file:remove", 7);
4494
+ this.name = undefined;
4495
+ this.accepts = undefined;
4496
+ this.max = undefined;
4497
+ this.url = undefined;
4498
+ this.value = "";
4499
+ this.filename = undefined;
4500
+ this.src = undefined;
4501
+ this.filetype = undefined;
4502
+ this.size = undefined;
4503
+ this.state = "complete";
4504
+ this.percent = 100;
4505
+ this.preview = true;
4506
+ this.validationMessage = undefined;
4507
+ this.uid = uid++;
4508
+ this.inputTarget = html(`<input id="input-target-${this.uid}">`);
4509
+ }
4510
+ componentWillLoad() {
4511
+ this.el.appendChild(this.inputTarget);
4512
+ this.setMissingFiletype();
4513
+ }
4514
+ get file() {
4515
+ return this._file;
4516
+ }
4517
+ set file(file) {
4518
+ this.src = URL.createObjectURL(file);
4519
+ this.filename = file.name;
4520
+ this.size = file.size;
4521
+ this.state = "pending";
4522
+ this.percent = 0;
4523
+ this._file = file;
4524
+ }
4525
+ set signedId(val) {
4526
+ if (this.value !== val) {
4527
+ get(`/rails/active_storage/blobs/info/${val}`).then(blob => {
4528
+ this.src = `/rails/active_storage/blobs/redirect/${val}/${blob.filename}`;
4529
+ this.filename = blob.filename;
4530
+ this.size = blob.byte_size;
4531
+ this.state = "complete";
4532
+ this.percent = 100;
4533
+ this.value = val;
4534
+ });
4535
+ }
4536
+ }
4537
+ setMissingFiletype(_value, _previousValue) {
4538
+ if (!this.filetype && this.filename) {
4539
+ this.filetype = Extensions.getFileType(this.filename);
4540
+ }
4541
+ }
4542
+ start(_event) {
4543
+ this.state = "pending";
4544
+ this.percent = 0;
4545
+ }
4546
+ progress(event) {
4547
+ const { progress } = event.detail;
4548
+ this.percent = progress;
4549
+ }
4550
+ error(event) {
4551
+ event.preventDefault();
4552
+ const { error } = event.detail;
4553
+ this.state = "error";
4554
+ this.inputTarget.setCustomValidity(error);
4555
+ }
4556
+ end(_event) {
4557
+ if (this.state !== "error") {
4558
+ this.state = "complete";
4559
+ this.percent = 100;
4560
+ }
4561
+ }
4562
+ render() {
4563
+ return (h(Host, null, h("slot", null), h("figure", null, h("div", { class: "progress-details" }, h("progress-bar", { percent: this.percent, class: this.state }, h("a", { class: "download-link", href: this.src, download: this.filename, onClick: e => e.stopPropagation() }, this.filename)), h("span", { class: "progress-icon" }), h("a", { class: "remove-media", onClick: this.removeClicked, href: "#" }, h("span", null, "Remove media"))), this.preview ? h("file-preview", { src: this.src, filetype: this.filetype }) : '')));
4564
+ }
4565
+ componentDidRender() {
4566
+ morphdom(this.inputTarget, `
4567
+ <input
4568
+ id="input-target-${this.uid}"
4569
+ style="opacity: 0.01; width: 1px; height: 1px; z-index: -999; position: absolute;"
4570
+ name="${this.name}"
4571
+ value="${this.value}"
4572
+ >`);
4573
+ }
4574
+ componentDidLoad() {
4575
+ if (this.checkValidity() && this.state == "pending") {
4576
+ this.controller = new DirectUploadController(this.el);
4577
+ this.controller.dispatch("initialize", { controller: this.controller });
4578
+ }
4579
+ }
4580
+ checkValidity() {
4581
+ let errors = [];
4582
+ errors.push(...new Accepts(this).errors);
4583
+ errors.push(...new Max(this).errors);
4584
+ this.inputTarget.setCustomValidity(errors.join(" "));
4585
+ this.inputTarget.reportValidity();
4586
+ return errors.length === 0;
4587
+ }
4588
+ static get watchers() { return {
4589
+ "filename": ["setMissingFiletype"]
4590
+ }; }
4591
+ static get style() { return uploadedFileCss; }
4592
+ }, [1, "uploaded-file", {
4593
+ "name": [1537],
4594
+ "accepts": [1537],
4595
+ "max": [1538],
4596
+ "url": [1537],
4597
+ "value": [1537],
4598
+ "filename": [1537],
4599
+ "src": [1537],
4600
+ "filetype": [1537],
4601
+ "size": [1538],
4602
+ "state": [1537],
4603
+ "percent": [1538],
4604
+ "preview": [1540],
4605
+ "validationMessage": [1, "validation-message"]
4606
+ }, [[0, "direct-upload:initialize", "start"], [0, "direct-upload:start", "start"], [0, "direct-upload:progress", "progress"], [0, "direct-upload:error", "error"], [0, "direct-upload:end", "end"]], {
4607
+ "filename": ["setMissingFiletype"]
4608
+ }]);
4609
+
4610
+ const fileDropCss = "file-drop{display:flex;flex-direction:column;justify-content:center;align-items:center;box-sizing:border-box;min-height:60px;outline-offset:-10px;padding:20px;background:rgba(255, 255, 255, 0.25);text-align:center;transition:all 0.15s ease 0s;outline:rgba(0, 0, 0, 0.25) dashed 2px;font-size:13px}";
4611
+
4612
+ const FileDrop$1 = /*@__PURE__*/ proxyCustomElement(class FileDrop extends H {
4613
+ constructor() {
4614
+ super();
4615
+ this.__registerHost();
4616
+ this.for = undefined;
4617
+ }
4618
+ get el() { return this; }
4619
+ get fileTarget() {
4620
+ return document.querySelector(`#${this.for}`);
4621
+ }
4622
+ openFilePicker(_event) {
4623
+ this.fileTarget.click();
4624
+ }
4625
+ highlight(event) {
4626
+ event.preventDefault();
4627
+ this.el.classList.add("-dragover");
4628
+ }
4629
+ unhighlight(_event) {
4630
+ this.el.classList.remove("-dragover");
4631
+ }
4632
+ drop(event) {
4633
+ event.preventDefault();
4634
+ this.el.classList.remove("-dragover");
4635
+ this.fileTarget.files = event.dataTransfer.files;
4636
+ const changeEvent = new Event("change", { bubbles: true });
4637
+ this.fileTarget.dispatchEvent(changeEvent);
4638
+ }
4639
+ static get style() { return fileDropCss; }
4640
+ }, [0, "file-drop", {
4641
+ "for": [1537]
4642
+ }, [[0, "click", "openFilePicker"], [0, "dragover", "highlight"], [0, "dragleave", "unhighlight"], [0, "drop", "drop"]]]);
4643
+
4644
+ class FormController {
4645
+ static instance(form) {
4646
+ return form.bardFileFormController ||= new FormController(form);
4647
+ }
4648
+ progressContainerTarget;
4649
+ dialog;
4650
+ element;
4651
+ progressTargetMap;
4652
+ controllers;
4653
+ submitted;
4654
+ processing;
4655
+ errors;
4656
+ constructor(form) {
4657
+ this.element = form;
4658
+ this.progressTargetMap = {};
4659
+ this.controllers = [];
4660
+ this.submitted = false;
4661
+ this.processing = false;
4662
+ this.errors = false;
4663
+ this.element.insertAdjacentHTML("beforeend", `<dialog id="form-controller-dialog">
4664
+ <div class="direct-upload-wrapper">
4665
+ <div class="direct-upload-content">
4666
+ <h3>Uploading your media</h3>
4667
+ <div id="progress-container"></div>
4668
+ </div>
4669
+ </div>
4670
+ </dialog>`);
4671
+ this.dialog = this.element.querySelector("#form-controller-dialog");
4672
+ this.progressContainerTarget = this.dialog.querySelector("#progress-container");
4673
+ if (this.element.dataset.remote !== "true") {
4674
+ this.element.addEventListener("submit", event => this.submit(event));
4675
+ }
4676
+ window.addEventListener("beforeunload", event => this.beforeUnload(event));
4677
+ this.element.addEventListener("direct-upload:initialize", event => this.init(event));
4678
+ this.element.addEventListener("direct-upload:start", event => this.start(event));
4679
+ this.element.addEventListener("direct-upload:progress", event => this.progress(event));
4680
+ this.element.addEventListener("direct-upload:error", event => this.error(event));
4681
+ this.element.addEventListener("direct-upload:end", event => this.end(event));
4682
+ this.element.addEventListener("uploaded-file:remove", event => this.removeUploadedFile(event));
4683
+ }
4684
+ beforeUnload(event) {
4685
+ if (this.processing) {
4686
+ event.preventDefault();
4687
+ return (event.returnValue = "");
4688
+ }
4689
+ }
4690
+ submit(event) {
4691
+ event.preventDefault();
4692
+ this.submitted = true;
4693
+ this.startNextController();
4694
+ if (this.processing) {
4695
+ this.dialog.showModal();
4696
+ }
4697
+ }
4698
+ startNextController() {
4699
+ if (this.processing)
4700
+ return;
4701
+ const controller = this.controllers.shift();
4702
+ if (controller) {
4703
+ this.processing = true;
4704
+ controller.start(error => {
4705
+ if (error) {
4706
+ Array.from(this.element.querySelectorAll("input[type=file]"))
4707
+ .forEach((e) => e.disabled = false);
4708
+ }
4709
+ this.processing = false;
4710
+ this.startNextController();
4711
+ });
4712
+ }
4713
+ else {
4714
+ this.submitForm();
4715
+ }
4716
+ }
4717
+ submitForm() {
4718
+ if (this.submitted) {
4719
+ Array.from(this.element.querySelectorAll("input[type=file]"))
4720
+ .forEach((e) => e.disabled = true);
4721
+ window.setTimeout(() => {
4722
+ this.element.submit();
4723
+ }, 10);
4724
+ }
4725
+ }
4726
+ init(event) {
4727
+ const { id, file, controller } = event.detail;
4728
+ this.progressContainerTarget.insertAdjacentHTML("beforebegin", `
4729
+ <progress-bar id="direct-upload-${id}" class="direct-upload--pending">${file.name}</progress-bar>
4730
+ `);
4731
+ const progressTarget = document.getElementById(`direct-upload-${id}`);
4732
+ this.progressTargetMap[id] = progressTarget;
4733
+ this.controllers.push(controller);
4734
+ this.startNextController();
4735
+ }
4736
+ start(event) {
4737
+ this.progressTargetMap[event.detail.id].classList.remove("direct-upload--pending");
4738
+ }
4739
+ progress(event) {
4740
+ const { id, progress } = event.detail;
4741
+ this.progressTargetMap[id].percent = progress;
4742
+ }
4743
+ error(event) {
4744
+ event.preventDefault();
4745
+ const { id, error } = event.detail;
4746
+ const target = this.progressTargetMap[id];
4747
+ target.classList.add("direct-upload--error");
4748
+ target.title = error;
4749
+ }
4750
+ end(event) {
4751
+ this.progressTargetMap[event.detail.id].classList.add("direct-upload--complete");
4752
+ }
4753
+ removeUploadedFile(event) {
4754
+ const uploadedFile = event.detail;
4755
+ const id = uploadedFile.controller?.directUpload?.id;
4756
+ if (id) {
4757
+ document.getElementById(`direct-upload-${id}`).remove();
4758
+ delete this.progressTargetMap[id];
4759
+ }
4760
+ }
4761
+ }
4762
+
4763
+ const bardFileCss = ":host{display:block;padding:25px;color:var(--bard-file-text-color, #000);font-size:13px}:host *{box-sizing:border-box;position:relative}drag-and-drop{display:block;outline-offset:-10px;background:rgba(255,255,255, 0.25);margin:0;text-align:center;transition:all 0.15s;outline:2px dashed rgba(0,0,0,0.25);color:#444;font-size:14px}p{padding:10px 20px;margin:0}drag-and-drop.-full{width:100%}.-dragover{background:rgba(255,255,255,0.5);outline:2px dashed rgba(0,0,0,0.25)}.media-preview{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:center}// UPLOADER .direct-upload-wrapper{position:fixed;z-index:9999;top:0;left:0;width:100vw;height:100vh;display:flex;align-items:center;justify-content:center;background:rgba(#333, 0.9)}.direct-upload-content{display:block;background:#fcfcfc;padding:40px 60px 60px;border-radius:3px;width:60vw}.direct-upload-content h3{border-bottom:2px solid #1f1f1f;margin-bottom:20px}.separate-upload{padding:0 10px;margin-top:10px;font-size:0.9em}.direct-upload--pending{opacity:0.6}.direct-upload--complete{opacity:0.4}.direct-upload--error{border-color:red}input[type=file][data-direct-upload-url][disabled]{display:none}:host.separate-upload{padding:0 10px;margin-top:10px;font-size:0.9em}";
4764
+
4765
+ const BardFile$1 = /*@__PURE__*/ proxyCustomElement(class BardFile extends H {
4766
+ get el() { return this; }
4767
+ forceUpdate() { this._forceUpdate = !this._forceUpdate; }
4768
+ fileTargetId;
4769
+ fileTarget;
4770
+ hiddenTargetId;
4771
+ hiddenTarget;
4772
+ _files;
4773
+ constructor() {
4774
+ super();
4775
+ this.__registerHost();
4776
+ this.__attachShadow();
4777
+ this.name = undefined;
4778
+ this.directupload = undefined;
4779
+ this.multiple = false;
4780
+ this.required = false;
4781
+ this.accepts = undefined;
4782
+ this.max = undefined;
4783
+ this.preview = true;
4784
+ this._forceUpdate = false;
4785
+ this.fileTargetId = this.el.id;
4786
+ this.fileTarget = html(`<input id="${this.fileTargetId}">`);
4787
+ this.hiddenTargetId = `hidden-target-${this.el.getAttribute("name")}`;
4788
+ this.hiddenTarget = html(`<input id="${this.hiddenTargetId}">`);
4789
+ }
4790
+ componentWillLoad() {
4791
+ this.el.removeAttribute("id");
4792
+ FormController.instance(this.el.closest("form"));
4793
+ this.files = Array.from(this.el.children).filter(e => e.tagName == "UPLOADED-FILE");
4794
+ }
4795
+ // Methods
4796
+ get files() {
4797
+ return this._files;
4798
+ }
4799
+ set files(val) {
4800
+ this._files = val;
4801
+ if (!this.multiple)
4802
+ this._files = this._files.slice(-1);
4803
+ this.forceUpdate();
4804
+ this.fireChangeEvent();
4805
+ }
4806
+ get value() {
4807
+ return this.files.map(e => e.value);
4808
+ }
4809
+ set value(val) {
4810
+ const newValue = val || [];
4811
+ if (JSON.stringify(this.value) !== JSON.stringify(newValue)) { // this is insane. javascript is fucking garbage.
4812
+ this.files = newValue.map(signedId => Object.assign(new UploadedFile$1(), {
4813
+ name: this.name,
4814
+ preview: this.preview,
4815
+ signedId,
4816
+ }));
4817
+ }
4818
+ }
4819
+ fileTargetChanged(event) {
4820
+ if (event.target !== this.fileTarget)
4821
+ return;
4822
+ this.files.push(...Array.from(this.fileTarget.files).map(file => Object.assign(new UploadedFile$1(), {
4823
+ name: this.name,
4824
+ preview: this.preview,
4825
+ url: this.directupload,
4826
+ accepts: this.accepts,
4827
+ max: this.max,
4828
+ file,
4829
+ })));
4830
+ this.files = this.files;
4831
+ this.fileTarget.value = null;
4832
+ }
4833
+ removeUploadedFile(event) {
4834
+ arrayRemove(this.files, event.detail);
4835
+ this.files = this.files;
4836
+ }
4837
+ fireChangeEvent() {
4838
+ requestAnimationFrame(() => this.el.dispatchEvent(new Event("change", { bubbles: true })));
4839
+ }
4840
+ // Rendering
4841
+ render() {
4842
+ return (h(Host, null, h("file-drop", { for: this.fileTargetId }, h("p", { part: "title" }, h("strong", null, "Choose ", this.multiple ? "files" : "file", " "), h("span", null, "or drag ", this.multiple ? "them" : "it", " here.")), h("div", { class: `media-preview ${this.multiple ? '-stacked' : ''}` }, h("slot", null)))));
4843
+ }
4844
+ componentDidRender() {
4845
+ morphdom(this.fileTarget, `
4846
+ <input id="${this.fileTargetId}"
4847
+ type="file"
4848
+ ${this.multiple ? "multiple" : ""}
4849
+ ${this.required && this.files.length === 0 ? "required" : ""}
4850
+ style="opacity: 0.01; width: 1px; height: 1px; z-index: -999"
4851
+ >`);
4852
+ morphdom(this.hiddenTarget, `
4853
+ <input id="${this.hiddenTargetId}"
4854
+ type="hidden"
4855
+ name="${this.name}"
4856
+ ${this.files.length > 0 ? "disabled" : ""}
4857
+ >`);
4858
+ const wrapper = document.createElement("div");
4859
+ wrapper.replaceChildren(this.fileTarget, this.hiddenTarget, ...this.files);
4860
+ morphdom(this.el, wrapper, { childrenOnly: true });
4861
+ }
4862
+ // Validations
4863
+ checkValidity() {
4864
+ return this.fileTarget.checkValidity();
4865
+ }
4866
+ setCustomValidity(msg) {
4867
+ this.fileTarget.setCustomValidity(msg);
4868
+ }
4869
+ reportValidity() {
4870
+ this.fileTarget.reportValidity();
4871
+ }
4872
+ get validationMessage() {
4873
+ return this.fileTarget.validationMessage;
4874
+ }
4875
+ static get style() { return bardFileCss; }
4876
+ }, [1, "bard-file", {
4877
+ "name": [1],
4878
+ "directupload": [1],
4879
+ "multiple": [4],
4880
+ "required": [4],
4881
+ "accepts": [1],
4882
+ "max": [2],
4883
+ "preview": [4],
4884
+ "_forceUpdate": [32]
4885
+ }, [[0, "change", "fileTargetChanged"], [0, "uploaded-file:remove", "removeUploadedFile"], [0, "direct-upload:end", "fireChangeEvent"]]]);
4886
+
4887
+ const BardFile = BardFile$1;
4888
+
4889
+ const FileDrop = FileDrop$1;
4890
+
4891
+ const FilePreview = FilePreview$1;
4892
+
4893
+ const ProgressBar = ProgressBar$1;
4894
+
4895
+ const UploadedFile = UploadedFile$1;
4896
+
4897
+ const defineCustomElements = (opts) => {
4898
+ if (typeof customElements !== 'undefined') {
4899
+ [
4900
+ BardFile,
4901
+ FileDrop,
4902
+ FilePreview,
4903
+ ProgressBar,
4904
+ UploadedFile,
4905
+ ].forEach(cmp => {
4906
+ if (!customElements.get(cmp.is)) {
4907
+ customElements.define(cmp.is, cmp, opts);
4908
+ }
4909
+ });
4910
+ }
4911
+ };
4912
+
4913
+ defineCustomElements();