@knowark/componarkjs 1.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/Makefile +49 -0
  2. package/README.md +47 -0
  3. package/knowarkjs.code-workspace +29 -0
  4. package/lib/base/component/README.rst +113 -0
  5. package/lib/base/component/component.js +115 -0
  6. package/lib/base/component/component.test.js +327 -0
  7. package/lib/base/component/index.js +3 -0
  8. package/lib/base/index.js +1 -0
  9. package/lib/base/styles/index.js +3 -0
  10. package/lib/base/styles/styles.js +320 -0
  11. package/lib/base/utils/define.js +21 -0
  12. package/lib/base/utils/define.test.js +62 -0
  13. package/lib/base/utils/format.js +24 -0
  14. package/lib/base/utils/format.test.js +19 -0
  15. package/lib/base/utils/helpers.js +96 -0
  16. package/lib/base/utils/helpers.test.js +154 -0
  17. package/lib/base/utils/index.js +5 -0
  18. package/lib/base/utils/slots.js +18 -0
  19. package/lib/base/utils/slots.test.js +52 -0
  20. package/lib/base/utils/uuid.js +9 -0
  21. package/lib/base/utils/uuid.test.js +19 -0
  22. package/lib/components/audio/README.md +22 -0
  23. package/lib/components/audio/components/audio.js +103 -0
  24. package/lib/components/audio/components/audio.test.js +127 -0
  25. package/lib/components/audio/index.js +1 -0
  26. package/lib/components/audio/styles/ark.css.js +83 -0
  27. package/lib/components/audio/styles/index.js +2 -0
  28. package/lib/components/camera/README.md +64 -0
  29. package/lib/components/camera/components/camera.js +85 -0
  30. package/lib/components/camera/components/camera.test.js +104 -0
  31. package/lib/components/camera/index.js +1 -0
  32. package/lib/components/camera/styles/ark.css.js +17 -0
  33. package/lib/components/camera/styles/index.js +2 -0
  34. package/lib/components/capture/components/capture.js +54 -0
  35. package/lib/components/capture/components/capture.test.js +112 -0
  36. package/lib/components/capture/index.js +1 -0
  37. package/lib/components/droparea/README.md +51 -0
  38. package/lib/components/droparea/components/droparea-preview.js +159 -0
  39. package/lib/components/droparea/components/droparea-preview.test.js +105 -0
  40. package/lib/components/droparea/components/droparea.js +165 -0
  41. package/lib/components/droparea/components/droparea.test.js +320 -0
  42. package/lib/components/droparea/index.js +1 -0
  43. package/lib/components/droparea/styles/ark.css.js +235 -0
  44. package/lib/components/droparea/styles/index.js +3 -0
  45. package/lib/components/emit/components/emit.js +33 -0
  46. package/lib/components/emit/components/emit.test.js +138 -0
  47. package/lib/components/emit/index.js +1 -0
  48. package/lib/components/index.js +9 -0
  49. package/lib/components/list/README.md +103 -0
  50. package/lib/components/list/components/item.test.js +93 -0
  51. package/lib/components/list/components/list.item.js +22 -0
  52. package/lib/components/list/components/list.js +96 -0
  53. package/lib/components/list/components/list.test.js +267 -0
  54. package/lib/components/list/index.js +2 -0
  55. package/lib/components/paginator/README.md +32 -0
  56. package/lib/components/paginator/components/paginator.js +110 -0
  57. package/lib/components/paginator/components/paginator.test.js +131 -0
  58. package/lib/components/paginator/index.js +1 -0
  59. package/lib/components/paginator/styles/ark.css.js +196 -0
  60. package/lib/components/paginator/styles/index.js +2 -0
  61. package/lib/components/spinner/README.md +41 -0
  62. package/lib/components/spinner/components/spinner.js +105 -0
  63. package/lib/components/spinner/components/spinner.test.js +50 -0
  64. package/lib/components/spinner/index.js +1 -0
  65. package/lib/components/spinner/styles/ark.css.js +658 -0
  66. package/lib/components/spinner/styles/index.js +2 -0
  67. package/lib/components/splitview/README.md +63 -0
  68. package/lib/components/splitview/components/splitview.detail.js +46 -0
  69. package/lib/components/splitview/components/splitview.detail.test.js +92 -0
  70. package/lib/components/splitview/components/splitview.js +69 -0
  71. package/lib/components/splitview/components/splitview.master.js +26 -0
  72. package/lib/components/splitview/components/splitview.master.test.js +55 -0
  73. package/lib/components/splitview/components/splitview.test.js +76 -0
  74. package/lib/components/splitview/index.js +3 -0
  75. package/lib/components/translate/README.md +56 -0
  76. package/lib/components/translate/components/translate.js +100 -0
  77. package/lib/components/translate/components/translate.test.js +226 -0
  78. package/lib/components/translate/index.js +1 -0
  79. package/lib/index.js +2 -0
  80. package/package.json +68 -0
  81. package/showcase/design/.htaccess +8 -0
  82. package/showcase/design/core/factories/development/development.factory.js +5 -0
  83. package/showcase/design/core/factories/development/index.js +1 -0
  84. package/showcase/design/core/factories/index.js +11 -0
  85. package/showcase/design/core/factories/standard.factory.js +19 -0
  86. package/showcase/design/index.html +22 -0
  87. package/showcase/design/index.js +7 -0
  88. package/showcase/design/screens/base/audio/audioDemo.js +32 -0
  89. package/showcase/design/screens/base/audio/index.js +25 -0
  90. package/showcase/design/screens/base/camera/cameraDemo.js +83 -0
  91. package/showcase/design/screens/base/camera/index.js +25 -0
  92. package/showcase/design/screens/base/droparea/dropareaDemo.js +88 -0
  93. package/showcase/design/screens/base/droparea/index.js +25 -0
  94. package/showcase/design/screens/base/index.js +42 -0
  95. package/showcase/design/screens/base/list/index.js +25 -0
  96. package/showcase/design/screens/base/list/listDemo.js +89 -0
  97. package/showcase/design/screens/base/paginator/index.js +25 -0
  98. package/showcase/design/screens/base/paginator/paginatorDemo.js +82 -0
  99. package/showcase/design/screens/base/root.component.js +294 -0
  100. package/showcase/design/screens/base/root.routes.js +28 -0
  101. package/showcase/design/screens/base/spinner/index.js +25 -0
  102. package/showcase/design/screens/base/spinner/spinnerDemo.js +55 -0
  103. package/showcase/design/screens/base/splitview/detailDemo.js +40 -0
  104. package/showcase/design/screens/base/splitview/index.js +25 -0
  105. package/showcase/design/screens/base/splitview/splitViewDemo.js +58 -0
  106. package/showcase/design/screens/base/translate/index.js +20 -0
  107. package/showcase/design/screens/base/translate/translateDemo.js +43 -0
  108. package/showcase/design/screens/main.js +12 -0
  109. package/showcase/design/screens/screens.routes.js +23 -0
  110. package/showcase/index.html +86 -0
  111. package/showcase/index.js +5 -0
  112. package/showcase/locales/en/default.json +5 -0
  113. package/showcase/locales/es/default.json +5 -0
  114. package/showcase/locales/fr/default.json +5 -0
  115. package/tsconfig.json +23 -0
  116. package/webpack.config.cjs +118 -0
@@ -0,0 +1,17 @@
1
+ const css = String.raw; export default css`
2
+ .ark-camera {
3
+ display: grid;
4
+ width: fit-content;
5
+ height: fit-content;
6
+ overflow: hidden;
7
+ user-select: none;
8
+ }
9
+
10
+ .ark-camera__canvas {
11
+ display: none;
12
+ }
13
+
14
+ .ark-camera__video {
15
+ transform: rotateY(180deg);
16
+ }
17
+ `
@@ -0,0 +1,2 @@
1
+ import styles from './ark.css.js'
2
+ export default styles
@@ -0,0 +1,54 @@
1
+ import { Component } from '../../../base/component/index.js'
2
+
3
+ const tag = 'ark-capture'
4
+ export class Capture extends Component {
5
+ constructor () {
6
+ super()
7
+ const type = this['receive'] || 'emit'
8
+ this.addEventListener(type, this.handle.bind(this))
9
+ }
10
+
11
+ reflectedProperties () {
12
+ return ['receive']
13
+ }
14
+
15
+ /** @param {Object} context */
16
+ init (context = {}) {
17
+ const data = JSON.parse(this._pop(':scope > data')?.textContent || null)
18
+ this.source = /** @type {object} */ (
19
+ context.source) || data || this.source || {}
20
+ this.template = context.template || this.template || (
21
+ (data) => `${JSON.stringify(data)}`)
22
+
23
+ return super.init()
24
+ }
25
+
26
+ render () {
27
+ const outputTemplate = this._pop(':scope > template')?.innerHTML
28
+ this.template = (
29
+ outputTemplate ? this._format(outputTemplate) : this.template)
30
+
31
+ const output = this.querySelector(':scope > output')
32
+ if (this.template && output) {
33
+ output.innerHTML = this.template(this.source)
34
+ }
35
+
36
+ return super.render()
37
+ }
38
+
39
+ handle (event) {
40
+ const source = event.detail
41
+ this.init({ source }).render()
42
+ }
43
+
44
+ _format (template) {
45
+ return (data) => Function(`return \`${template}\``).call(data)
46
+ }
47
+
48
+ _pop (selector) {
49
+ const element = this.querySelector(selector)
50
+ element?.remove()
51
+ return element
52
+ }
53
+ }
54
+ Component.define(tag, Capture)
@@ -0,0 +1,112 @@
1
+ import './capture.js'
2
+
3
+ describe('Capture', () => {
4
+ let container = null
5
+
6
+ beforeEach(() => {
7
+ container = document.createElement('div')
8
+ document.body.appendChild(container)
9
+ })
10
+
11
+ afterEach(() => {
12
+ container.remove()
13
+ container = null
14
+ })
15
+
16
+ it('can be instantiated', () => {
17
+ container.innerHTML = `
18
+ <ark-capture></ark-capture>
19
+ `
20
+
21
+ const capture = container.querySelector('ark-capture')
22
+ expect(capture).toEqual(capture.init())
23
+ })
24
+
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
+ })
45
+
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')
71
+ })
72
+
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
+ }))
96
+
97
+ expect(capture.children.length).toEqual(2)
98
+ expect(output.children[0].innerHTML).toContain('Richard Roe')
99
+ expect(output.children[0].innerHTML).toContain('Analyst')
100
+
101
+ capture.dispatchEvent(new CustomEvent('custom', {
102
+ bubbles: true,
103
+ detail: {
104
+ name: 'Megan More', job: 'Manager'
105
+ }
106
+ }))
107
+
108
+ expect(capture.children.length).toEqual(2)
109
+ expect(output.children[0].innerHTML).toContain('Megan More')
110
+ expect(output.children[0].innerHTML).toContain('Manager')
111
+ })
112
+ })
@@ -0,0 +1 @@
1
+ export { Capture } from './components/capture.js'
@@ -0,0 +1,51 @@
1
+ DROPAREA
2
+ --------
3
+
4
+ The ``ark-droparea`` is an easy to use drag & drop component, that allows the user to upload multiple or single files,
5
+ defining the limit of size and the specific extension of the files.
6
+
7
+
8
+ Examples
9
+ ========
10
+
11
+ **Default droparea, multiple files**
12
+
13
+ ``` html
14
+
15
+ <ark-droparea></ark-droparea>
16
+ ```
17
+
18
+ **Single file droparea, use the single atribute**
19
+
20
+ ``` html
21
+
22
+ <ark-droparea single></ark-droparea>
23
+ ```
24
+
25
+ **With the attributes accept and max-size specified in megabytes**
26
+
27
+ ``` html
28
+ <ark-droparea accept="jpg, png, gif" max-size="10" ></ark-droparea>
29
+ ```
30
+
31
+
32
+
33
+ Attributes
34
+ ----------
35
+
36
+ | Name | Type | Default | Description |
37
+ | :------: | :-----: | :--------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
38
+ | single | boolean | (multiple) | Limits the number of files to a single one, if not set, recieves multiple files by default |
39
+ | max-size | string | (no limit) | Specifies the size of the file in megabytes |
40
+ | accept | string | (any) | Indicates the type of files, with values separated by commas: (png, jpeg, gif, etc.). It's also possible to specify general file types: (image, video, text, audio) |
41
+
42
+ Properties
43
+ ----------
44
+
45
+ | Name | Type | Default | Description |
46
+ | :-------: | :-----: | :--------: | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------: |
47
+ | single | boolean | (multiple) | Limits the number of files to a single one, if not set, recieves multiple files by default |
48
+ | maxSize | string | (no limit) | Specifies the size of the file in bytes |
49
+ | accept | string | (any) | Indicates the type of files, with values separated by commas: (png, jpeg, gif, etc.), It's also possible to specify general file types: (image, video, text, audio) |
50
+ | fileList | string | - | Returns the list of files droped |
51
+ | mediaList | string | - | Returns a list of media objects |
@@ -0,0 +1,159 @@
1
+ import { Component } from '../../../base/component/index.js'
2
+ import './droparea.js'
3
+ // @ts-ignore
4
+ const tag = 'ark-droparea-preview'
5
+
6
+ export class DropareaPreview extends Component {
7
+ init(_context = {}) {
8
+ return super.init()
9
+ }
10
+
11
+ render() {
12
+ this.content = /* html */ `
13
+ <ul data-preview-list class="ark-droparea-preview__list drag-sort-enable"></ul>
14
+ `
15
+ return super.render()
16
+ }
17
+
18
+ previewFile(file) {
19
+ const blobUrl = URL.createObjectURL(file)
20
+ const fileType = file.type.split('/')[0]
21
+ const previewZone = this.select('[data-preview-list]')
22
+ const picture = document.createElement('li')
23
+ picture.className = 'ark-droparea-preview__frame'
24
+ const removeButton = document.createElement('button')
25
+ removeButton.innerText = '⨯'
26
+ removeButton.className = 'ark-droparea__remove'
27
+
28
+ if (fileType != 'image') {
29
+ picture.innerHTML = `<p>${file.name}</p>`
30
+ picture.setAttribute('data', `${blobUrl}`)
31
+ } else {
32
+ picture.style.backgroundImage = `url('${blobUrl}')`
33
+ }
34
+
35
+ removeButton.addEventListener('click', this.removeFile.bind(this, file))
36
+ picture.appendChild(removeButton)
37
+ previewZone.appendChild(picture)
38
+ this.toggleVisibility()
39
+
40
+ if (!this.droparea.hasAttribute('single')) {
41
+ picture.setAttribute('index', this.fileIndex(file))
42
+ this.enableDragSort('drag-sort-enable')
43
+ }
44
+ }
45
+
46
+ toggleVisibility() {
47
+ const previewZone = this.select('[data-preview-list]')
48
+ this.files.length !== 0
49
+ ? (previewZone.style.display = 'grid')
50
+ : (previewZone.style.display = 'none')
51
+ }
52
+
53
+ /* DragSort Functionality */
54
+
55
+ enableDragSort(listClass) {
56
+ const sortableLists = this.getElementsByClassName(listClass)
57
+ Array.prototype.map.call(sortableLists, (list) => {
58
+ this.enableDragList(list)
59
+ })
60
+ }
61
+
62
+ enableDragList(list) {
63
+ Array.prototype.map.call(list.children, (item) => {
64
+ this.enableDragItem(item)
65
+ })
66
+ }
67
+
68
+ enableDragItem(item) {
69
+ item.setAttribute('draggable', true)
70
+ item.addEventListener('drag', this.handleDrag.bind(this, item))
71
+ item.addEventListener('dragend', this.handleDrop, false)
72
+ }
73
+
74
+ /* istanbul ignore next */
75
+ handleDrag(item, event) {
76
+ const selectedItem = item,
77
+ list = selectedItem.parentNode,
78
+ x = event.clientX,
79
+ y = event.clientY
80
+
81
+ selectedItem.classList.add('drag-sort-active')
82
+ let swapItem =
83
+ document.elementFromPoint(x, y) === null
84
+ ? selectedItem
85
+ : document.elementFromPoint(x, y)
86
+ if (list === swapItem.parentNode) {
87
+ swapItem = (
88
+ swapItem !== selectedItem.nextSibling ?
89
+ swapItem : swapItem.nextSibling)
90
+ list.insertBefore(selectedItem, swapItem)
91
+ }
92
+ }
93
+
94
+ handleDrop(item) {
95
+ const droparea = item.target.closest('ark-droparea')
96
+ droparea.preview.createNewFileList()
97
+ item.target.classList.remove('drag-sort-active')
98
+ droparea.preview.dispatchAlterEvent()
99
+ }
100
+ /*----------------------------------------------------*/
101
+
102
+ dispatchAlterEvent() {
103
+ this.emit('alter', this.mediaList)
104
+ }
105
+
106
+ createNewFileList() {
107
+ const nodeList = this.querySelectorAll('li')
108
+ const newList = []
109
+ nodeList.forEach((item, index) => {
110
+ newList.push(this.droparea.fileList[item.getAttribute('index')])
111
+ item.setAttribute('index', index)
112
+ })
113
+ this.droparea.fileList = newList
114
+ }
115
+
116
+ fileExists(file) {
117
+ const present = this.files.some((item) => item.name === file.name)
118
+ return present
119
+ }
120
+
121
+ removeFile(file, event) {
122
+ let element = event.target
123
+ const fileIndex = this.droparea.fileList.indexOf(file)
124
+ this.droparea.fileList.splice(fileIndex, 1)
125
+ element.parentNode.remove()
126
+ this.selectAll('li').forEach((item, index) =>
127
+ item.setAttribute('index', index)
128
+ )
129
+ this.toggleVisibility()
130
+ this.dispatchAlterEvent()
131
+ }
132
+
133
+ fileIndex(file) {
134
+ return this.droparea.fileList.indexOf(file)
135
+ }
136
+
137
+ get droparea() {
138
+ return this.closest('.ark-droparea')
139
+ }
140
+
141
+ get mediaList() {
142
+ const mediaList = []
143
+ this.droparea.fileList.map((file) => {
144
+ mediaList.push({
145
+ name: file.name,
146
+ type: file.type,
147
+ size: file.size,
148
+ url: URL.createObjectURL(file),
149
+ })
150
+ })
151
+ return mediaList
152
+ }
153
+
154
+ get files() {
155
+ return this.droparea.fileList
156
+ }
157
+ }
158
+
159
+ Component.define(tag, DropareaPreview)
@@ -0,0 +1,105 @@
1
+ import { jest } from '@jest/globals'
2
+ import './droparea-preview.js'
3
+
4
+ describe('Droparea', () => {
5
+ const createBubbledEvent = (type, props = {}) => {
6
+ const event = new Event(type, {
7
+ bubbles: true,
8
+ })
9
+ Object.assign(event, props)
10
+ return event
11
+ }
12
+
13
+ global.URL.createObjectURL = jest.fn()
14
+ global.document.elementFromPoint = jest.fn()
15
+
16
+ let container = null
17
+
18
+ beforeEach(() => {
19
+ container = document.createElement('div')
20
+ document.body.appendChild(container)
21
+ })
22
+
23
+ afterEach(() => {
24
+ container.remove()
25
+ container = null
26
+ })
27
+
28
+ it('can be instantiated', () => {
29
+ container.innerHTML = /* html */ `
30
+ <ark-droparea></ark-droparea>
31
+ `
32
+ const droparea = container.querySelector('ark-droparea')
33
+ const preview = droparea.querySelector('ark-droparea-preview')
34
+ expect(preview).toBe(preview.init())
35
+ })
36
+
37
+ it('Item can be removed', () => {
38
+ container.innerHTML = /* html */ `
39
+ <ark-droparea></ark-droparea>
40
+ `
41
+
42
+ const droparea = container.querySelector('ark-droparea')
43
+ const preview = droparea.querySelector('[data-preview-list]')
44
+ const dropZone = droparea.querySelector('.ark-droparea__form')
45
+ const myFile = new File(['image'], 'Doggy.png', {
46
+ type: 'image/png',
47
+ })
48
+ const myFile2 = new File(['image'], 'Scooby.png', {
49
+ type: 'image/png',
50
+ })
51
+ const dropEvent = createBubbledEvent('drop', {
52
+ clientX: 0,
53
+ clientY: 1,
54
+ dataTransfer: {
55
+ files: [myFile, myFile2],
56
+ },
57
+ })
58
+
59
+ dropZone.dispatchEvent(dropEvent)
60
+ preview.querySelector('button').click()
61
+ preview.querySelector('button').click()
62
+ })
63
+
64
+ it('Can drag previews and sort a new list', () => {
65
+ container.innerHTML = /* html */ `
66
+ <ark-droparea></ark-droparea>
67
+ `
68
+
69
+ const droparea = container.querySelector('ark-droparea')
70
+ const preview = droparea.querySelector('[data-preview-list]')
71
+ const dropZone = droparea.querySelector('.ark-droparea__form')
72
+ const myFile = new File(['image'], 'Doggy.png', {
73
+ type: 'image/png',
74
+ })
75
+ const myFile2 = new File(['image'], 'Scooby.png', {
76
+ type: 'image/png',
77
+ })
78
+ const dropEvent = createBubbledEvent('drop', {
79
+ clientX: 0,
80
+ clientY: 1,
81
+ dataTransfer: {
82
+ files: [myFile, myFile2],
83
+ },
84
+ })
85
+
86
+ dropZone.dispatchEvent(dropEvent)
87
+
88
+ preview.handleDrag = jest.fn()
89
+
90
+ const getThumbnails = () =>
91
+ Array.from(preview.querySelectorAll('.ark-droparea-preview__frame'))
92
+
93
+ const thumbnails = getThumbnails()
94
+
95
+ const startingNode = thumbnails[0]
96
+ const endingNode = thumbnails[1]
97
+
98
+ startingNode.dispatchEvent(
99
+ createBubbledEvent('dragstart', { clientX: 0, clientY: 0 })
100
+ )
101
+ endingNode.dispatchEvent(
102
+ createBubbledEvent('dragend', { clientX: 0, clientY: 1 })
103
+ )
104
+ })
105
+ })
@@ -0,0 +1,165 @@
1
+ import { Component } from '../../../base/component/index.js'
2
+ import './droparea-preview.js'
3
+ import styles from '../styles/index.js'
4
+ // @ts-ignore
5
+ const tag = 'ark-droparea'
6
+
7
+ export class Droparea extends Component {
8
+ init(context = {}) {
9
+ this.fileList = []
10
+ this.contextFiles = context.contextFiles || this.contextFiles || []
11
+ this.accept = context.accept || this.accept
12
+ this.single = this.hasAttribute('single')
13
+ this.maxSize = context.maxSize || this.maxSize || ''
14
+ return super.init()
15
+ }
16
+
17
+ render() {
18
+ this.content = /* html */ `
19
+ <form class="${tag}__form">
20
+ <div class="${tag}__header">
21
+ <div class="${tag}__open">${this.title || 'Upload'}</div>
22
+ <input id="fileElement"class="${tag}__input" type="file"
23
+ data-input multiple />
24
+ </div>
25
+ <ark-droparea-preview></ark-droparea-preview>
26
+ </form>
27
+ `
28
+ this.dragDropEvents = ['dragenter', 'dragover', 'dragleave', 'drop']
29
+ this.dragEvents = this.dragDropEvents.slice(0, 2)
30
+ this.dropEvents = this.dragDropEvents.slice(2)
31
+ this._input = this.select('.ark-droparea__input')
32
+ this.openButton = this.select('.ark-droparea__open')
33
+
34
+ return super.render()
35
+ }
36
+
37
+ reflectedProperties() {
38
+ return ['size', 'accept', 'maxSize', 'title']
39
+ }
40
+
41
+ async load() {
42
+ this.dragDropEvents.forEach((eventName) => {
43
+ this.addEventListener(eventName, this.preventDefaults, false)
44
+ })
45
+
46
+ this.dragEvents.forEach((eventName) => {
47
+ this.addEventListener(eventName, this.highlight, false)
48
+ })
49
+
50
+ this.dropEvents.forEach((eventName) => {
51
+ this.addEventListener(eventName, this.unhighlight, false)
52
+ })
53
+
54
+ this.addEventListener('drop', this.handleDrop, false)
55
+ this._input.addEventListener('change', this.onChange.bind(this))
56
+ this.openButton.addEventListener('click', this.openInput.bind(this))
57
+
58
+ /* istanbul ignore else */
59
+ if (this.contextFiles) {
60
+ await this.handleFiles(this.contextFiles)
61
+ }
62
+ }
63
+
64
+ openInput(event) {
65
+ event.stopPropagation()
66
+ const input = this.select('[data-input]')
67
+ input.click()
68
+ }
69
+
70
+ preventDefaults(event) {
71
+ event.preventDefault()
72
+ event.stopPropagation()
73
+ }
74
+
75
+ highlight(event) {
76
+ this.dropZone.classList.add('highlight')
77
+ }
78
+
79
+ unhighlight(event) {
80
+ this.dropZone.classList.remove('highlight')
81
+ }
82
+
83
+ handleDrop(event) {
84
+ event.stopPropagation()
85
+ let data = event.dataTransfer
86
+ let files = data.files
87
+ this.handleFiles(files)
88
+ }
89
+
90
+ onChange(event) {
91
+ event.stopPropagation()
92
+ const input = event.target
93
+ const files = input.files
94
+ this.handleFiles(files)
95
+ }
96
+
97
+ handleFiles(files) {
98
+ if (this.single) {
99
+ files = [files[0]]
100
+ if (
101
+ files[0] != undefined &&
102
+ this.validate(files) &&
103
+ !this.preview.fileExists(files[0]) &&
104
+ this.maxSizeValidate(files[0])
105
+ ) {
106
+ this.fileList[0] = files[0]
107
+ this.preview.querySelector('[data-preview-list]').innerHTML = ''
108
+ this.preview.previewFile(files[0])
109
+ }
110
+ } else {
111
+ files = [...files]
112
+ if (!files.includes(undefined) && this.validate(files)) {
113
+ files.forEach((file) => {
114
+ /*istanbul ignore else*/
115
+ if (!this.preview.fileExists(file) && this.maxSizeValidate(file)) {
116
+ this.fileList.push(file)
117
+ this.preview.previewFile(file)
118
+ }
119
+ })
120
+ }
121
+ }
122
+ this.preview.dispatchAlterEvent()
123
+ }
124
+
125
+ validate(fileList) {
126
+ if (!this.accept || this.accept.length === 0) return true
127
+ const acceptList = this.accept.split(',').map(
128
+ (s) => s.trim().toLowerCase())
129
+ const hasAudio = acceptList.indexOf('audio') >= 0
130
+ const hasVideo = acceptList.indexOf('video') >= 0
131
+ const hasImage = acceptList.indexOf('image') >= 0
132
+ const hasText = acceptList.indexOf('text') >= 0
133
+
134
+ for (let i = 0, len = fileList.length; i < len; ++i) {
135
+ let ext = '' + fileList[i].name.split('.').pop().toLowerCase()
136
+ if (acceptList.indexOf(ext) >= 0) continue
137
+ if (hasAudio && fileList[i].type.split('/')[0] === 'audio') continue
138
+ if (hasVideo && fileList[i].type.split('/')[0] === 'video') continue
139
+ if (hasImage && fileList[i].type.split('/')[0] === 'image') continue
140
+ if (hasText && fileList[i].type.split('/')[0] === 'text') continue
141
+
142
+ return false
143
+ }
144
+
145
+ return true
146
+ }
147
+
148
+ maxSizeValidate (file) {
149
+ return true
150
+ }
151
+
152
+ get dropZone() {
153
+ return this.select('.ark-droparea__form')
154
+ }
155
+
156
+ get preview() {
157
+ return this.select('ark-droparea-preview')
158
+ }
159
+
160
+ get mediaList() {
161
+ return this.preview.mediaList
162
+ }
163
+ }
164
+
165
+ Component.define(tag, Droparea, styles)