@knowark/componarkjs 1.13.3 → 1.14.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 (177) hide show
  1. package/lib/base/component/component.js +17 -1
  2. package/lib/base/component/component.test.js +475 -389
  3. package/lib/base/utils/define.js +28 -6
  4. package/lib/base/utils/define.test.js +129 -42
  5. package/lib/base/utils/format.test.js +16 -16
  6. package/lib/base/utils/helpers.js +11 -4
  7. package/lib/base/utils/helpers.test.js +134 -115
  8. package/lib/base/utils/slots.test.js +38 -38
  9. package/lib/base/utils/uuid.test.js +13 -13
  10. package/lib/components/audio/components/audio.js +22 -3
  11. package/lib/components/audio/components/audio.test.js +120 -90
  12. package/lib/components/camera/components/camera.js +8 -3
  13. package/lib/components/camera/components/camera.test.js +96 -91
  14. package/lib/components/capture/components/capture.js +33 -5
  15. package/lib/components/capture/components/capture.test.js +165 -97
  16. package/lib/components/droparea/components/droparea-preview.js +66 -15
  17. package/lib/components/droparea/components/droparea-preview.test.js +262 -78
  18. package/lib/components/droparea/components/droparea.js +47 -8
  19. package/lib/components/droparea/components/droparea.test.js +309 -298
  20. package/lib/components/emit/components/emit.js +24 -4
  21. package/lib/components/emit/components/emit.test.js +192 -134
  22. package/lib/components/index.js +1 -1
  23. package/lib/components/list/components/{list.item.js → item.js} +1 -1
  24. package/lib/components/list/components/item.test.js +70 -69
  25. package/lib/components/list/components/list.js +35 -5
  26. package/lib/components/list/components/list.test.js +358 -227
  27. package/lib/components/list/index.js +1 -1
  28. package/lib/components/paginator/components/paginator.js +3 -2
  29. package/lib/components/paginator/components/paginator.test.js +146 -143
  30. package/lib/components/spinner/components/spinner.js +1 -1
  31. package/lib/components/spinner/components/spinner.test.js +36 -41
  32. package/lib/components/splitview/components/splitview.detail.js +1 -1
  33. package/lib/components/splitview/components/splitview.detail.test.js +78 -74
  34. package/lib/components/splitview/components/splitview.js +40 -10
  35. package/lib/components/splitview/components/splitview.master.js +29 -3
  36. package/lib/components/splitview/components/splitview.master.test.js +52 -52
  37. package/lib/components/splitview/components/splitview.test.js +136 -32
  38. package/lib/components/translate/components/translate.js +32 -10
  39. package/lib/components/translate/components/translate.test.js +492 -133
  40. package/package.json +7 -27
  41. package/scripts/node-test-setup.js +94 -0
  42. package/showcase/components/index.html +1 -1
  43. package/{jsconfig.json → tsconfig.json} +6 -4
  44. package/types/base/component/component.d.ts +48 -0
  45. package/types/base/component/component.d.ts.map +1 -0
  46. package/types/base/component/component.test.d.ts +2 -0
  47. package/types/base/component/component.test.d.ts.map +1 -0
  48. package/types/base/component/index.d.ts +8 -0
  49. package/types/base/component/index.d.ts.map +1 -0
  50. package/types/base/index.d.ts +2 -0
  51. package/types/base/index.d.ts.map +1 -0
  52. package/types/base/styles/index.d.ts +3 -0
  53. package/types/base/styles/index.d.ts.map +1 -0
  54. package/types/base/styles/styles.d.ts +3 -0
  55. package/types/base/styles/styles.d.ts.map +1 -0
  56. package/types/base/utils/define.d.ts +5 -0
  57. package/types/base/utils/define.d.ts.map +1 -0
  58. package/types/base/utils/define.test.d.ts +2 -0
  59. package/types/base/utils/define.test.d.ts.map +1 -0
  60. package/types/base/utils/format.d.ts +13 -0
  61. package/types/base/utils/format.d.ts.map +1 -0
  62. package/types/base/utils/format.test.d.ts +2 -0
  63. package/types/base/utils/format.test.d.ts.map +1 -0
  64. package/types/base/utils/helpers.d.ts +11 -0
  65. package/types/base/utils/helpers.d.ts.map +1 -0
  66. package/types/base/utils/helpers.test.d.ts +2 -0
  67. package/types/base/utils/helpers.test.d.ts.map +1 -0
  68. package/types/base/utils/index.d.ts +6 -0
  69. package/types/base/utils/index.d.ts.map +1 -0
  70. package/types/base/utils/slots.d.ts +15 -0
  71. package/types/base/utils/slots.d.ts.map +1 -0
  72. package/types/base/utils/slots.test.d.ts +2 -0
  73. package/types/base/utils/slots.test.d.ts.map +1 -0
  74. package/types/base/utils/uuid.d.ts +3 -0
  75. package/types/base/utils/uuid.d.ts.map +1 -0
  76. package/types/base/utils/uuid.test.d.ts +2 -0
  77. package/types/base/utils/uuid.test.d.ts.map +1 -0
  78. package/types/components/audio/components/audio.d.ts +18 -0
  79. package/types/components/audio/components/audio.d.ts.map +1 -0
  80. package/types/components/audio/components/audio.test.d.ts +2 -0
  81. package/types/components/audio/components/audio.test.d.ts.map +1 -0
  82. package/types/components/audio/index.d.ts +2 -0
  83. package/types/components/audio/index.d.ts.map +1 -0
  84. package/types/components/audio/styles/ark.css.d.ts +3 -0
  85. package/types/components/audio/styles/ark.css.d.ts.map +1 -0
  86. package/types/components/audio/styles/index.d.ts +3 -0
  87. package/types/components/audio/styles/index.d.ts.map +1 -0
  88. package/types/components/camera/components/camera.d.ts +18 -0
  89. package/types/components/camera/components/camera.d.ts.map +1 -0
  90. package/types/components/camera/components/camera.test.d.ts +2 -0
  91. package/types/components/camera/components/camera.test.d.ts.map +1 -0
  92. package/types/components/camera/index.d.ts +2 -0
  93. package/types/components/camera/index.d.ts.map +1 -0
  94. package/types/components/camera/styles/ark.css.d.ts +3 -0
  95. package/types/components/camera/styles/ark.css.d.ts.map +1 -0
  96. package/types/components/camera/styles/index.d.ts +3 -0
  97. package/types/components/camera/styles/index.d.ts.map +1 -0
  98. package/types/components/capture/components/capture.d.ts +10 -0
  99. package/types/components/capture/components/capture.d.ts.map +1 -0
  100. package/types/components/capture/components/capture.test.d.ts +2 -0
  101. package/types/components/capture/components/capture.test.d.ts.map +1 -0
  102. package/types/components/capture/index.d.ts +2 -0
  103. package/types/components/capture/index.d.ts.map +1 -0
  104. package/types/components/droparea/components/droparea-preview.d.ts +21 -0
  105. package/types/components/droparea/components/droparea-preview.d.ts.map +1 -0
  106. package/types/components/droparea/components/droparea-preview.test.d.ts +2 -0
  107. package/types/components/droparea/components/droparea-preview.test.d.ts.map +1 -0
  108. package/types/components/droparea/components/droparea.d.ts +32 -0
  109. package/types/components/droparea/components/droparea.d.ts.map +1 -0
  110. package/types/components/droparea/components/droparea.test.d.ts +2 -0
  111. package/types/components/droparea/components/droparea.test.d.ts.map +1 -0
  112. package/types/components/droparea/index.d.ts +2 -0
  113. package/types/components/droparea/index.d.ts.map +1 -0
  114. package/types/components/droparea/styles/ark.css.d.ts +3 -0
  115. package/types/components/droparea/styles/ark.css.d.ts.map +1 -0
  116. package/types/components/droparea/styles/index.d.ts +3 -0
  117. package/types/components/droparea/styles/index.d.ts.map +1 -0
  118. package/types/components/emit/components/emit.d.ts +10 -0
  119. package/types/components/emit/components/emit.d.ts.map +1 -0
  120. package/types/components/emit/components/emit.test.d.ts +2 -0
  121. package/types/components/emit/components/emit.test.d.ts.map +1 -0
  122. package/types/components/emit/index.d.ts +2 -0
  123. package/types/components/emit/index.d.ts.map +1 -0
  124. package/types/components/index.d.ts +10 -0
  125. package/types/components/index.d.ts.map +1 -0
  126. package/types/components/list/components/item.d.ts +8 -0
  127. package/types/components/list/components/item.d.ts.map +1 -0
  128. package/types/components/list/components/item.test.d.ts +2 -0
  129. package/types/components/list/components/item.test.d.ts.map +1 -0
  130. package/types/components/list/components/list.d.ts +13 -0
  131. package/types/components/list/components/list.d.ts.map +1 -0
  132. package/types/components/list/components/list.test.d.ts +2 -0
  133. package/types/components/list/components/list.test.d.ts.map +1 -0
  134. package/types/components/list/index.d.ts +3 -0
  135. package/types/components/list/index.d.ts.map +1 -0
  136. package/types/components/paginator/components/paginator.d.ts +32 -0
  137. package/types/components/paginator/components/paginator.d.ts.map +1 -0
  138. package/types/components/paginator/components/paginator.test.d.ts +2 -0
  139. package/types/components/paginator/components/paginator.test.d.ts.map +1 -0
  140. package/types/components/paginator/index.d.ts +2 -0
  141. package/types/components/paginator/index.d.ts.map +1 -0
  142. package/types/components/paginator/styles/ark.css.d.ts +3 -0
  143. package/types/components/paginator/styles/ark.css.d.ts.map +1 -0
  144. package/types/components/paginator/styles/index.d.ts +3 -0
  145. package/types/components/paginator/styles/index.d.ts.map +1 -0
  146. package/types/components/spinner/components/spinner.d.ts +11 -0
  147. package/types/components/spinner/components/spinner.d.ts.map +1 -0
  148. package/types/components/spinner/components/spinner.test.d.ts +2 -0
  149. package/types/components/spinner/components/spinner.test.d.ts.map +1 -0
  150. package/types/components/spinner/index.d.ts +2 -0
  151. package/types/components/spinner/index.d.ts.map +1 -0
  152. package/types/components/spinner/styles/ark.css.d.ts +3 -0
  153. package/types/components/spinner/styles/ark.css.d.ts.map +1 -0
  154. package/types/components/spinner/styles/index.d.ts +3 -0
  155. package/types/components/spinner/styles/index.d.ts.map +1 -0
  156. package/types/components/splitview/components/splitview.d.ts +12 -0
  157. package/types/components/splitview/components/splitview.d.ts.map +1 -0
  158. package/types/components/splitview/components/splitview.detail.d.ts +10 -0
  159. package/types/components/splitview/components/splitview.detail.d.ts.map +1 -0
  160. package/types/components/splitview/components/splitview.detail.test.d.ts +2 -0
  161. package/types/components/splitview/components/splitview.detail.test.d.ts.map +1 -0
  162. package/types/components/splitview/components/splitview.master.d.ts +8 -0
  163. package/types/components/splitview/components/splitview.master.d.ts.map +1 -0
  164. package/types/components/splitview/components/splitview.master.test.d.ts +2 -0
  165. package/types/components/splitview/components/splitview.master.test.d.ts.map +1 -0
  166. package/types/components/splitview/components/splitview.test.d.ts +2 -0
  167. package/types/components/splitview/components/splitview.test.d.ts.map +1 -0
  168. package/types/components/splitview/index.d.ts +4 -0
  169. package/types/components/splitview/index.d.ts.map +1 -0
  170. package/types/components/translate/components/translate.d.ts +18 -0
  171. package/types/components/translate/components/translate.d.ts.map +1 -0
  172. package/types/components/translate/components/translate.test.d.ts +2 -0
  173. package/types/components/translate/components/translate.test.d.ts.map +1 -0
  174. package/types/components/translate/index.d.ts +2 -0
  175. package/types/components/translate/index.d.ts.map +1 -0
  176. package/types/index.d.ts +3 -0
  177. package/types/index.d.ts.map +1 -0
@@ -1,11 +1,11 @@
1
- import { Component } from '../../../base/component/index.js'
1
+ import { Component } from "#base/index.js"
2
2
 
3
3
  const tag = 'ark-capture'
4
4
  export class Capture extends Component {
5
5
  constructor () {
6
6
  super()
7
- const type = this.receive || 'emit'
8
- this.addEventListener(type, this.handle.bind(this))
7
+ this.receive = this.receive || 'emit'
8
+ this.addEventListener(this.receive, this.handle.bind(this))
9
9
  }
10
10
 
11
11
  reflectedProperties () {
@@ -14,7 +14,7 @@ export class Capture extends Component {
14
14
 
15
15
  /** @param {Object} context */
16
16
  init (context = {}) {
17
- const data = JSON.parse(this._pop(':scope > data')?.textContent || null)
17
+ const data = this._parseJSON(this._pop(':scope > data')?.textContent)
18
18
  this.source = /** @type {object} */ (
19
19
  context.source) || data || this.source || {}
20
20
  this.template = context.template || this.template || (
@@ -42,7 +42,24 @@ export class Capture extends Component {
42
42
  }
43
43
 
44
44
  _format (template) {
45
- return (data) => Function(`return \`${template}\``).call(data)
45
+ let render = null
46
+
47
+ try {
48
+ render = Function(`return \`${template}\``)
49
+ } catch (error) {
50
+ this.emit('error', error)
51
+ }
52
+
53
+ return (data) => {
54
+ if (!render) return ''
55
+
56
+ try {
57
+ return render.call(data)
58
+ } catch (error) {
59
+ this.emit('error', error)
60
+ return ''
61
+ }
62
+ }
46
63
  }
47
64
 
48
65
  _pop (selector) {
@@ -50,5 +67,16 @@ export class Capture extends Component {
50
67
  element?.remove()
51
68
  return element
52
69
  }
70
+
71
+ _parseJSON (source) {
72
+ if (!source) return null
73
+
74
+ try {
75
+ return JSON.parse(source)
76
+ } catch (error) {
77
+ this.emit('error', error)
78
+ return null
79
+ }
80
+ }
53
81
  }
54
82
  Component.define(tag, Capture)
@@ -1,112 +1,180 @@
1
+ import { it } from 'node:test'
2
+ import assert from 'node:assert/strict'
1
3
  import './capture.js'
2
4
 
3
- describe('Capture', () => {
4
- let container = null
5
+ let container = null
5
6
 
6
- beforeEach(() => {
7
- container = document.createElement('div')
8
- document.body.appendChild(container)
9
- })
7
+ const setup = () => {
8
+ document.body.innerHTML = ''
9
+ container = document.createElement('div')
10
+ document.body.appendChild(container)
11
+ }
10
12
 
11
- afterEach(() => {
12
- container.remove()
13
- container = null
14
- })
13
+ it('can be instantiated', () => {
14
+ setup()
15
+ container.innerHTML = `
16
+ <ark-capture></ark-capture>
17
+ `
15
18
 
16
- it('can be instantiated', () => {
17
- container.innerHTML = `
18
- <ark-capture></ark-capture>
19
- `
19
+ const capture = container.querySelector('ark-capture')
20
+ assert.deepStrictEqual(capture, capture.init())
21
+ })
20
22
 
21
- const capture = container.querySelector('ark-capture')
22
- expect(capture).toEqual(capture.init())
23
- })
23
+ it('renders the given data detail', () => {
24
+ setup()
25
+ container.innerHTML = `
26
+ <ark-capture>
27
+ <data>
28
+ {
29
+ "name": "John Doe",
30
+ "job": "Programmer"
31
+ }
32
+ </data>
33
+ <output></output>
34
+ </ark-capture>
35
+ `
36
+
37
+ const capture = container.querySelector('ark-capture')
38
+ capture.init().render()
39
+ const output = capture.querySelector('output')
40
+
41
+ assert.deepStrictEqual(capture.children.length, 1)
42
+ assert.ok(output.innerHTML.includes('John Doe'))
43
+ assert.ok(output.innerHTML.includes('Programmer'))
44
+ })
24
45
 
25
- it('renders the given data detail', () => {
26
- container.innerHTML = `
27
- <ark-capture>
28
- <data>
29
- {
30
- "name": "John Doe",
31
- "job": "Programmer"
32
- }
33
- </data>
34
- <output></output>
35
- </ark-capture>
36
- `
37
-
38
- const capture = container.querySelector('ark-capture')
39
- const output = capture.querySelector('output')
40
-
41
- expect(capture.children.length).toEqual(1)
42
- expect(output.innerHTML).toContain('John Doe')
43
- expect(output.innerHTML).toContain('Programmer')
44
- })
46
+ it('renders json data on the given template on the given output', () => {
47
+ setup()
48
+ container.innerHTML = `
49
+ <ark-capture>
50
+ <data>
51
+ {
52
+ "name": "John Doe",
53
+ "job": "Programmer"
54
+ }
55
+ </data>
56
+ <template>
57
+ <div id="output">
58
+ <strong>\${this.name}</strong>
59
+ <strong>\${this.job}</strong>
60
+ </div>
61
+ </template>
62
+ <output></output>
63
+ </ark-capture>
64
+ `
65
+
66
+ const capture = container.querySelector('ark-capture')
67
+ capture.init().render()
68
+ const output = capture.querySelector('output')
69
+
70
+ assert.deepStrictEqual(capture.children.length, 1)
71
+ assert.ok(output.children[0].innerHTML.includes('John Doe'))
72
+ assert.ok(output.children[0].innerHTML.includes('Programmer'))
73
+ })
74
+
75
+ it('captures specific custom events and renders its details', () => {
76
+ setup()
77
+ container.innerHTML = `
78
+ <ark-capture receive="custom">
79
+ <template>
80
+ <div id="output">
81
+ <strong>\${this.name}</strong>
82
+ <strong>\${this.job}</strong>
83
+ </div>
84
+ </template>
85
+ <output></output>
86
+ <p>Adjoint Element</p>
87
+ </ark-capture>
88
+ `
89
+
90
+ const capture = container.querySelector('ark-capture')
91
+ capture.init().render()
92
+ capture.addEventListener('custom', capture.handle.bind(capture))
93
+ const output = capture.querySelector('output')
94
+
95
+ capture.dispatchEvent(new CustomEvent('custom', {
96
+ bubbles: true,
97
+ detail: {
98
+ name: 'Richard Roe', job: 'Analyst'
99
+ }
100
+ }))
101
+
102
+ assert.deepStrictEqual(capture.children.length, 2)
103
+ assert.ok(output.children[0].innerHTML.includes('Richard Roe'))
104
+ assert.ok(output.children[0].innerHTML.includes('Analyst'))
105
+
106
+ capture.dispatchEvent(new CustomEvent('custom', {
107
+ bubbles: true,
108
+ detail: {
109
+ name: 'Megan More', job: 'Manager'
110
+ }
111
+ }))
112
+
113
+ assert.deepStrictEqual(capture.children.length, 2)
114
+ assert.ok(output.children[0].innerHTML.includes('Megan More'))
115
+ assert.ok(output.children[0].innerHTML.includes('Manager'))
116
+ })
45
117
 
46
- it('renders json data on the given template on the given output', () => {
47
- container.innerHTML = `
48
- <ark-capture>
49
- <data>
50
- {
51
- "name": "John Doe",
52
- "job": "Programmer"
53
- }
54
- </data>
55
- <template>
56
- <div id="output">
57
- <strong>\${this.name}</strong>
58
- <strong>\${this.job}</strong>
59
- </div>
60
- </template>
61
- <output></output>
62
- </ark-capture>
63
- `
64
-
65
- const capture = container.querySelector('ark-capture')
66
- const output = capture.querySelector('output')
67
-
68
- expect(capture.children.length).toEqual(1)
69
- expect(output.children[0].innerHTML).toContain('John Doe')
70
- expect(output.children[0].innerHTML).toContain('Programmer')
118
+ it('emits error when data JSON is invalid', () => {
119
+ setup()
120
+ const holder = document.createElement('div')
121
+ holder.innerHTML = `
122
+ <ark-capture>
123
+ <data>{ invalid json }</data>
124
+ <output></output>
125
+ </ark-capture>
126
+ `
127
+ const capture = holder.querySelector('ark-capture')
128
+ let errorEvent = null
129
+ capture.addEventListener('error', (event) => {
130
+ errorEvent = event
71
131
  })
72
132
 
73
- it('captures specific custom events and renders its details', () => {
74
- container.innerHTML = `
75
- <ark-capture receive="custom">
76
- <template>
77
- <div id="output">
78
- <strong>\${this.name}</strong>
79
- <strong>\${this.job}</strong>
80
- </div>
81
- </template>
82
- <output></output>
83
- <p>Adjoint Element</p>
84
- </ark-capture>
85
- `
86
-
87
- const capture = container.querySelector('ark-capture')
88
- const output = capture.querySelector('output')
89
-
90
- capture.dispatchEvent(new CustomEvent('custom', {
91
- bubbles: true,
92
- detail: {
93
- name: 'Richard Roe', job: 'Analyst'
94
- }
95
- }))
133
+ capture.init().render()
96
134
 
97
- expect(capture.children.length).toEqual(2)
98
- expect(output.children[0].innerHTML).toContain('Richard Roe')
99
- expect(output.children[0].innerHTML).toContain('Analyst')
135
+ assert.ok(errorEvent)
136
+ })
100
137
 
101
- capture.dispatchEvent(new CustomEvent('custom', {
102
- bubbles: true,
103
- detail: {
104
- name: 'Megan More', job: 'Manager'
105
- }
106
- }))
138
+ it('emits error when template cannot be compiled', () => {
139
+ setup()
140
+ const holder = document.createElement('div')
141
+ holder.innerHTML = `
142
+ <ark-capture>
143
+ <data>{"name":"John"}</data>
144
+ <template>\${this.name</template>
145
+ <output></output>
146
+ </ark-capture>
147
+ `
148
+ const capture = holder.querySelector('ark-capture')
149
+ let errorEvent = null
150
+ capture.addEventListener('error', (event) => {
151
+ errorEvent = event
152
+ })
107
153
 
108
- expect(capture.children.length).toEqual(2)
109
- expect(output.children[0].innerHTML).toContain('Megan More')
110
- expect(output.children[0].innerHTML).toContain('Manager')
154
+ capture.init().render()
155
+
156
+ assert.ok(errorEvent)
157
+ assert.deepStrictEqual(capture.querySelector('output').innerHTML, '')
158
+ })
159
+
160
+ it('emits error when template evaluation fails at runtime', () => {
161
+ setup()
162
+ const holder = document.createElement('div')
163
+ holder.innerHTML = `
164
+ <ark-capture>
165
+ <data>{"name":"John"}</data>
166
+ <template>\${this.profile.name}</template>
167
+ <output></output>
168
+ </ark-capture>
169
+ `
170
+ const capture = holder.querySelector('ark-capture')
171
+ let errorEvent = null
172
+ capture.addEventListener('error', (event) => {
173
+ errorEvent = event
111
174
  })
175
+
176
+ capture.init().render()
177
+
178
+ assert.ok(errorEvent)
179
+ assert.deepStrictEqual(capture.querySelector('output').innerHTML, '')
112
180
  })
@@ -1,13 +1,26 @@
1
- import { Component } from '../../../base/component/index.js'
1
+ import { Component } from '#base/index.js'
2
2
  import './droparea.js'
3
- // @ts-ignore
3
+
4
+ /** @import {Droparea} from './droparea.js' */
5
+
4
6
  const tag = 'ark-droparea-preview'
5
7
 
6
8
  export class DropareaPreview extends Component {
9
+ constructor () {
10
+ super()
11
+ this._objectUrls = new Map()
12
+ this._onDragEnd = this.handleDrop.bind(this)
13
+ }
14
+
7
15
  init (_context = {}) {
8
16
  return super.init()
9
17
  }
10
18
 
19
+ disconnectedCallback () {
20
+ this.revokeAllFiles()
21
+ super.disconnectedCallback()
22
+ }
23
+
11
24
  render () {
12
25
  this.content = /* html */ `
13
26
  <ul data-preview-list class="ark-droparea-preview__list drag-sort-enable"></ul>
@@ -16,7 +29,7 @@ export class DropareaPreview extends Component {
16
29
  }
17
30
 
18
31
  previewFile (file) {
19
- const blobUrl = URL.createObjectURL(file)
32
+ const blobUrl = this.getObjectURL(file)
20
33
  const fileType = file.type.split('/')[0]
21
34
  const previewZone = this.select('[data-preview-list]')
22
35
  const picture = document.createElement('li')
@@ -26,7 +39,9 @@ export class DropareaPreview extends Component {
26
39
  removeButton.className = 'ark-droparea__remove'
27
40
 
28
41
  if (fileType != 'image') {
29
- picture.innerHTML = `<p>${file.name}</p>`
42
+ const text = document.createElement('p')
43
+ text.textContent = file.name
44
+ picture.appendChild(text)
30
45
  picture.setAttribute('data', `${blobUrl}`)
31
46
  } else {
32
47
  picture.style.backgroundImage = `url('${blobUrl}')`
@@ -38,7 +53,7 @@ export class DropareaPreview extends Component {
38
53
  this.toggleVisibility()
39
54
 
40
55
  if (!this.droparea.hasAttribute('single')) {
41
- picture.setAttribute('index', this.fileIndex(file))
56
+ picture.setAttribute('index', String(this.fileIndex(file)))
42
57
  this.enableDragSort('drag-sort-enable')
43
58
  }
44
59
  }
@@ -66,9 +81,12 @@ export class DropareaPreview extends Component {
66
81
  }
67
82
 
68
83
  enableDragItem (item) {
84
+ if (item.hasAttribute('data-drag-enabled')) return
85
+
86
+ item.setAttribute('data-drag-enabled', '')
69
87
  item.setAttribute('draggable', true)
70
88
  item.addEventListener('drag', this.handleDrag.bind(this, item))
71
- item.addEventListener('dragend', this.handleDrop, false)
89
+ item.addEventListener('dragend', this._onDragEnd, false)
72
90
  }
73
91
 
74
92
  /* istanbul ignore next */
@@ -92,10 +110,12 @@ export class DropareaPreview extends Component {
92
110
  }
93
111
  }
94
112
 
95
- handleDrop (item) {
96
- const droparea = item.target.closest('ark-droparea')
113
+ handleDrop (event) {
114
+ const droparea = event.target.closest('ark-droparea')
115
+ if (!droparea) return
116
+
97
117
  droparea.preview.createNewFileList()
98
- item.target.classList.remove('drag-sort-active')
118
+ event.target.classList.remove('drag-sort-active')
99
119
  droparea.preview.dispatchAlterEvent()
100
120
  }
101
121
  /* ---------------------------------------------------- */
@@ -109,23 +129,54 @@ export class DropareaPreview extends Component {
109
129
  const newList = []
110
130
  nodeList.forEach((item, index) => {
111
131
  newList.push(this.droparea.fileList[item.getAttribute('index')])
112
- item.setAttribute('index', index)
132
+ item.setAttribute('index', String(index))
113
133
  })
114
134
  this.droparea.fileList = newList
115
135
  }
116
136
 
117
137
  fileExists (file) {
118
- const present = this.files.some((item) => item.name === file.name)
119
- return present
138
+ return this.files.some((item) => item.name === file.name)
139
+ }
140
+
141
+ getObjectURL (file) {
142
+ if (this._objectUrls.has(file)) return this._objectUrls.get(file)
143
+
144
+ const url = URL.createObjectURL(file)
145
+ this._objectUrls.set(file, url)
146
+ return url
147
+ }
148
+
149
+ revokeFile (file) {
150
+ const url = this._objectUrls.get(file)
151
+ if (!url) return
152
+
153
+ this._objectUrls.delete(file)
154
+ URL.revokeObjectURL?.(url)
155
+ }
156
+
157
+ revokeAllFiles () {
158
+ for (const url of this._objectUrls.values()) {
159
+ URL.revokeObjectURL?.(url)
160
+ }
161
+ this._objectUrls.clear()
162
+ }
163
+
164
+ clearPreview () {
165
+ const previewZone = this.select('[data-preview-list]')
166
+ previewZone && (previewZone.textContent = '')
167
+ this.toggleVisibility()
120
168
  }
121
169
 
122
170
  removeFile (file, event) {
123
171
  const element = event.target
124
172
  const fileIndex = this.droparea.fileList.indexOf(file)
173
+ if (fileIndex < 0) return
174
+
175
+ this.revokeFile(file)
125
176
  this.droparea.fileList.splice(fileIndex, 1)
126
177
  element.parentNode.remove()
127
178
  this.selectAll('li').forEach((item, index) =>
128
- item.setAttribute('index', index)
179
+ item.setAttribute('index', String(index))
129
180
  )
130
181
  this.toggleVisibility()
131
182
  this.dispatchAlterEvent()
@@ -136,7 +187,7 @@ export class DropareaPreview extends Component {
136
187
  }
137
188
 
138
189
  get droparea () {
139
- return this.closest('.ark-droparea')
190
+ return /** @type {Droparea} */ (this.closest('ark-droparea'))
140
191
  }
141
192
 
142
193
  get mediaList () {
@@ -146,7 +197,7 @@ export class DropareaPreview extends Component {
146
197
  name: file.name,
147
198
  type: file.type,
148
199
  size: file.size,
149
- url: URL.createObjectURL(file)
200
+ url: this.getObjectURL(file)
150
201
  })
151
202
  })
152
203
  return mediaList