@componyx/ui 0.0.0-stage → 1.0.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 (169) hide show
  1. package/AppSkin/AppSkin.css +1268 -0
  2. package/AppSkin/AppSkin.js +2748 -0
  3. package/AppSkin/Themes/Default.css +241 -0
  4. package/Base/Base.js +3407 -0
  5. package/Base/ComponentIcons.css +66 -0
  6. package/Base/Font/ComponentIcons.woff +0 -0
  7. package/Base/Font/UI.woff +0 -0
  8. package/Base/Library.js +8432 -0
  9. package/Base/NavigationManager.js +462 -0
  10. package/Base/ResponsiveTemplates.js +371 -0
  11. package/Base/Sanitizer.js +288 -0
  12. package/Base/Themes/Default.css +255 -0
  13. package/Base/UI.css +618 -0
  14. package/Base/UIResourcePath.js +6 -0
  15. package/Bindary/Bindary.js +2011 -0
  16. package/Bindary/Modules/Connection.js +216 -0
  17. package/Bindary/Modules/Core.js +854 -0
  18. package/Bindary/Modules/DataUpdater.js +351 -0
  19. package/Bindary/Modules/ExpressionEngine.js +347 -0
  20. package/Bindary/Modules/ProxyManager.js +482 -0
  21. package/Bindary/Modules/Renderer.js +605 -0
  22. package/Bindary/Modules/Router.js +291 -0
  23. package/Bindary/Modules/Scroller.js +89 -0
  24. package/Bindary/Modules/Template.js +1273 -0
  25. package/BookmarkSpy/BookmarkSpy.js +430 -0
  26. package/Box/Box.css +36 -0
  27. package/Box/Box.js +1685 -0
  28. package/Button/Button.css +470 -0
  29. package/Button/Button.js +1398 -0
  30. package/Button/Themes/Default.css +200 -0
  31. package/Carousel/Carousel.css +273 -0
  32. package/Carousel/Carousel.js +607 -0
  33. package/ColorButton/ColorButton.css +39 -0
  34. package/ColorButton/ColorButton.js +336 -0
  35. package/ColorPicker/ColorPicker.css +359 -0
  36. package/ColorPicker/ColorPicker.js +972 -0
  37. package/ComboBox/ComboBox.css +357 -0
  38. package/ComboBox/ComboBox.js +2342 -0
  39. package/ComboBox/Themes/Default.css +23 -0
  40. package/DataPager/DataPager.css +72 -0
  41. package/DataPager/DataPager.js +674 -0
  42. package/DatePicker/DatePicker.css +227 -0
  43. package/DatePicker/DatePicker.js +1531 -0
  44. package/DatePicker/Themes/Default.css +26 -0
  45. package/Dialog/Dialog.css +106 -0
  46. package/Dialog/Dialog.js +572 -0
  47. package/Dialog/Themes/Default.css +10 -0
  48. package/Editor/Data/Emoji.json +8285 -0
  49. package/Editor/Data/Special.json +1042 -0
  50. package/Editor/Editor.css +1562 -0
  51. package/Editor/Editor.js +4058 -0
  52. package/Editor/Font/Editor.woff +0 -0
  53. package/Editor/Modules/ComponentFactory.js +565 -0
  54. package/Editor/Modules/ContentManager.js +748 -0
  55. package/Editor/Modules/DialogManager.js +1234 -0
  56. package/Editor/Modules/EventManager.js +458 -0
  57. package/Editor/Modules/Format.js +950 -0
  58. package/Editor/Modules/History.js +191 -0
  59. package/Editor/Modules/LayoutState.js +379 -0
  60. package/Editor/Modules/ListManager.js +296 -0
  61. package/Editor/Modules/MenuManager.js +388 -0
  62. package/Editor/Modules/NodeManager.js +681 -0
  63. package/Editor/Modules/ParagraphButtons.js +122 -0
  64. package/Editor/Modules/Resizer.js +176 -0
  65. package/Editor/Modules/SelectionRange.js +564 -0
  66. package/Editor/Modules/SourceViewBuilder.js +212 -0
  67. package/Editor/Modules/SymbolPicker.js +208 -0
  68. package/Editor/Modules/Table.js +2327 -0
  69. package/Editor/Modules/TableDialog.js +757 -0
  70. package/Editor/Modules/Toolbar.js +375 -0
  71. package/Editor/Modules/TooltipMenu.js +125 -0
  72. package/Editor/Modules/Utility.js +131 -0
  73. package/Editor/Themes/Default.css +204 -0
  74. package/FileUpload/FileUpload.css +156 -0
  75. package/FileUpload/FileUpload.js +898 -0
  76. package/FileUpload/Themes/Default.css +17 -0
  77. package/Form/Form.css +1934 -0
  78. package/Form/Form.js +4943 -0
  79. package/Form/Modules/ActionManager.js +368 -0
  80. package/Form/Modules/BuildPanelManager.js +319 -0
  81. package/Form/Modules/ComponentFactory.js +468 -0
  82. package/Form/Modules/ComponentPanel.js +265 -0
  83. package/Form/Modules/ConfigPanelManager.js +685 -0
  84. package/Form/Modules/DataObserver.js +717 -0
  85. package/Form/Modules/Databinder.js +602 -0
  86. package/Form/Modules/Draggable.js +756 -0
  87. package/Form/Modules/OptionsPanel.js +342 -0
  88. package/Form/Modules/Renderer.js +1889 -0
  89. package/Form/Modules/RuleEngine.js +585 -0
  90. package/Form/Modules/RulesPanel.js +1158 -0
  91. package/Form/Modules/Types.js +1709 -0
  92. package/Form/Modules/ValidationManager.js +194 -0
  93. package/Form/Themes/Default.css +216 -0
  94. package/FormField/FormField.css +468 -0
  95. package/FormField/FormField.js +576 -0
  96. package/FormField/Themes/Default.css +99 -0
  97. package/Grid/Grid.css +544 -0
  98. package/Grid/Grid.js +3761 -0
  99. package/Grid/Themes/Default.css +43 -0
  100. package/LICENSE +126 -0
  101. package/MaskedTextBox/MaskedTextBox.css +28 -0
  102. package/MaskedTextBox/MaskedTextBox.js +642 -0
  103. package/MaskedTextBox/Themes/Default.css +6 -0
  104. package/Menu/Menu.css +328 -0
  105. package/Menu/Menu.js +2386 -0
  106. package/Menu/Themes/Default.css +24 -0
  107. package/NumericBox/NumericBox.css +120 -0
  108. package/NumericBox/NumericBox.js +984 -0
  109. package/PanelBar/PanelBar.css +123 -0
  110. package/PanelBar/PanelBar.js +505 -0
  111. package/PanelBar/Themes/Default.css +51 -0
  112. package/PieChart/PieChart.css +95 -0
  113. package/PieChart/PieChart.js +820 -0
  114. package/PieChart/Themes/Default.css +9 -0
  115. package/README.md +178 -3
  116. package/Slider/Slider.css +348 -0
  117. package/Slider/Slider.js +1306 -0
  118. package/Slider/Themes/Default.css +44 -0
  119. package/TabStrip/TabStrip.css +52 -0
  120. package/TabStrip/TabStrip.js +362 -0
  121. package/TabStrip/Themes/Default.css +35 -0
  122. package/TimePicker/Themes/Default.css +30 -0
  123. package/TimePicker/TimePicker.css +253 -0
  124. package/TimePicker/TimePicker.js +1485 -0
  125. package/TooltipManager/Themes/Default.css +21 -0
  126. package/TooltipManager/TooltipManager.css +227 -0
  127. package/TooltipManager/TooltipManager.js +791 -0
  128. package/Validator/Validator.css +54 -0
  129. package/Validator/Validator.js +2508 -0
  130. package/componyx.html-data.json +619 -0
  131. package/index.js +27 -0
  132. package/package.json +43 -4
  133. package/types/AppSkin.d.ts +842 -0
  134. package/types/Base.d.ts +1034 -0
  135. package/types/Bindary.d.ts +1196 -0
  136. package/types/BookmarkSpy.d.ts +112 -0
  137. package/types/Box.d.ts +374 -0
  138. package/types/Button.d.ts +455 -0
  139. package/types/Carousel.d.ts +136 -0
  140. package/types/ColorButton.d.ts +120 -0
  141. package/types/ColorPicker.d.ts +225 -0
  142. package/types/ComboBox.d.ts +507 -0
  143. package/types/DataPager.d.ts +152 -0
  144. package/types/DatePicker.d.ts +354 -0
  145. package/types/Dialog.d.ts +160 -0
  146. package/types/Editor.d.ts +1289 -0
  147. package/types/FileUpload.d.ts +206 -0
  148. package/types/Form.d.ts +3078 -0
  149. package/types/FormField.d.ts +204 -0
  150. package/types/Grid.d.ts +911 -0
  151. package/types/Library.d.ts +1899 -0
  152. package/types/MaskedTextBox.d.ts +91 -0
  153. package/types/Menu.d.ts +577 -0
  154. package/types/NumericBox.d.ts +310 -0
  155. package/types/PanelBar.d.ts +223 -0
  156. package/types/PieChart.d.ts +224 -0
  157. package/types/ResponsiveTemplates.d.ts +108 -0
  158. package/types/Slider.d.ts +227 -0
  159. package/types/TabStrip.d.ts +185 -0
  160. package/types/TimePicker.d.ts +265 -0
  161. package/types/TooltipManager.d.ts +178 -0
  162. package/types/UI.d.ts +29 -0
  163. package/types/Validator.d.ts +653 -0
  164. package/types/index.d.ts +59 -0
  165. package/ui.css +11783 -0
  166. package/ui.js +79477 -0
  167. package/ui.min.css +138 -0
  168. package/ui.min.js +264 -0
  169. package/ui.min.js.map +1 -0
@@ -0,0 +1,898 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ import '../Base/Base.js';
3
+ import '../Base/Library.js';
4
+ import '../Button/Button.js';
5
+ import '../Dialog/Dialog.js';
6
+
7
+ (function (window)
8
+ {
9
+ /**
10
+ * FileUpload class.
11
+ * @class
12
+ * @memberof componyx.UI
13
+ * @augments componyx.UI.base.Component
14
+ * @mixes componyx.UI.base.methods
15
+ * @param {String} id The id of the component.
16
+ * @param {Object|HTMLElement} properties The properties used to initialize the component or the container element.
17
+ * @property {componyx.UI.base.AjaxMethod} ajax.upload - AJAX method used to upload data to the server.
18
+ * @returns {componyx.UI.FileUpload} An instance of the component.
19
+ */
20
+ componyx.UI.FileUpload = function FileUpload(id, properties)
21
+ {
22
+ // define private properties
23
+ var _instance = this,
24
+ _input, _selectButton, _uploadButton, _dropzone, _list, _progressBar, _accept,
25
+ _xhr = [], _files = [], _uploadedFiles = [],
26
+ _uploading = false, _complete = false,
27
+ _suffix = ["B", "KB", "MB", "GB", "TB"], _cancelButtons,
28
+ _classOption =
29
+ {
30
+ SELECTBUTTON: 'button select',
31
+ UPLOADBUTTON: 'button upload',
32
+ CANCELBUTTON: 'button cancel',
33
+ DROPZONE: 'drop-zone',
34
+ LIST: 'list',
35
+ NAME: 'name',
36
+ PROGRESSBAR: 'progress',
37
+ STATE: 'state',
38
+ SUCCESS: 'success',
39
+ ERROR: 'error',
40
+ ABORT: 'error'
41
+ };
42
+ $base.static.ThemeOption;
43
+
44
+ /**
45
+ * Gets or sets the css class of the select button.
46
+ * @type {String}
47
+ */
48
+ this.cssClassSelectButton = '';
49
+
50
+ /**
51
+ * Gets or sets the css class of the upload button.
52
+ * @type {String}
53
+ */
54
+ this.cssClassUploadButton = '';
55
+
56
+ /**
57
+ * Gets or sets the css class of the cancel buttons.
58
+ * @type {String}
59
+ */
60
+ this.cssClassCancelButton = '';
61
+
62
+ /**
63
+ * Gets or sets the css class of the drop-zone.
64
+ * @type {String}
65
+ */
66
+ this.cssClassDropzone = '';
67
+
68
+ /**
69
+ * Gets or sets the css class of the list.
70
+ * @type {String}
71
+ */
72
+ this.cssClassList = '';
73
+
74
+ /**
75
+ * Gets or sets the css class of the name container in the list.
76
+ * @type {String}
77
+ */
78
+ this.cssClassName = '';
79
+
80
+ /**
81
+ * Gets or sets the css class of the progress bar.
82
+ * @type {String}
83
+ */
84
+ this.cssClassProgressBar = '';
85
+
86
+ /**
87
+ * Gets or sets the css class of the list-item state container.
88
+ * @type {String}
89
+ */
90
+ this.cssClassState = '';
91
+
92
+ /**
93
+ * Gets or sets the css class applied to the state container when the upload was successful.
94
+ * @type {String}
95
+ */
96
+ this.cssClassSuccess = '';
97
+
98
+ /**
99
+ * Gets or sets the css class applied to the state container when the upload failed.
100
+ * @type {String}
101
+ */
102
+ this.cssClassError = '';
103
+
104
+ /**
105
+ * Gets or sets the css class applied to the state container when the upload was aborted.
106
+ * @type {String}
107
+ */
108
+ this.cssClassAbort = '';
109
+
110
+ /**
111
+ * Gets or sets the comma-separated list of allowed file extensions (.png, .jpg, .jpeg) or MIME types (image/png or image/*).
112
+ * @type {String}
113
+ */
114
+ this.accept = '';
115
+
116
+ /**
117
+ * Gets or sets the max allowed file size in KB.
118
+ * @type {Number|null}
119
+ */
120
+ this.maxFileSize = null;
121
+
122
+ /**
123
+ * Gets or sets the max allowed file count.
124
+ * @type {Number|null}
125
+ */
126
+ this.maxFiles = null;
127
+
128
+ /**
129
+ * Gets or sets a value indicating if duplicate files (matched by name, size, and last modified date) are prevented from being added again.
130
+ * @type {Boolean}
131
+ */
132
+ this.preventDuplicates = false;
133
+
134
+ /**
135
+ * Gets or sets a value indicating if drag & drop of files is enabled.
136
+ * @type {Boolean}
137
+ */
138
+ this.dragAndDrop = true;
139
+
140
+ /**
141
+ * Gets or sets the label displayed in the drop-zone.
142
+ * @type {String}
143
+ */
144
+ this.dropLabel = 'Drag & Drop files here';
145
+
146
+ /**
147
+ * Gets or sets the label displayed when the upload was successful.
148
+ * @type {String}
149
+ */
150
+ this.successLabel = '';
151
+
152
+ /**
153
+ * Gets or sets the label displayed when the upload failed.
154
+ * @type {String}
155
+ */
156
+ this.errorLabel = 'failed';
157
+
158
+ /**
159
+ * Gets or sets the label displayed when the upload was aborted.
160
+ * @type {String}
161
+ */
162
+ this.abortLabel = 'aborted';
163
+
164
+ /**
165
+ * Gets or sets the label of the file select button.
166
+ * @type {String}
167
+ */
168
+ this.selectButtonLabel = "Select files";
169
+
170
+ /**
171
+ * Gets or sets the id of the component from which the settings are cloned for the select button.
172
+ * @type {String}
173
+ */
174
+ this.selectButtonId = '';
175
+
176
+ /**
177
+ * Gets or sets the label of the upload button.
178
+ * @type {String}
179
+ */
180
+ this.uploadButtonLabel = "Upload";
181
+
182
+ /**
183
+ * Gets or sets the id of the component from which the settings are cloned for the upload button.
184
+ * @type {String}
185
+ */
186
+ this.uploadButtonId = '';
187
+
188
+ /**
189
+ * Gets or sets the label of the cancel button.
190
+ * @type {String}
191
+ */
192
+ this.cancelButtonLabel = '';
193
+
194
+ /**
195
+ * Gets or sets the id of the component from which the settings are cloned for the cancel button.
196
+ * @type {String}
197
+ */
198
+ this.cancelButtonId = '';
199
+
200
+ /**
201
+ * Gets or sets the header label of the rejected files dialog.
202
+ * @type {String}
203
+ */
204
+ this.rejectedDialogHeader = 'Rejected Files';
205
+
206
+ /**
207
+ * Gets or sets the id of the component from which the settings are cloned for the rejected files dialog.
208
+ * @type {String}
209
+ */
210
+ this.rejectedDialogId = '';
211
+
212
+
213
+ /**
214
+ * A readonly snapshot of the current files in the queue.
215
+ * @type {File[]}
216
+ * @readonly
217
+ */
218
+ Object.defineProperty(this, "files",
219
+ {
220
+ get: function () { return _files.slice(0); }
221
+ });
222
+
223
+ /**
224
+ * Indicates whether an upload is currently in progress.
225
+ * @type {boolean}
226
+ * @readonly
227
+ */
228
+ Object.defineProperty(this, "uploading",
229
+ {
230
+ get: function () { return _uploading; }
231
+ });
232
+
233
+
234
+ /**
235
+ * @typedef {Object} AcceptEventArgs
236
+ * @memberof componyx.UI.FileUpload
237
+ * @property {File} file - The file to accept.
238
+ * @property {Boolean} [cancel=false] - A value indicating if the default action of accepting the file should be canceled (reject).
239
+ */
240
+
241
+ /**
242
+ * @typedef {Object} CancelEventArgs
243
+ * @memberof componyx.UI.FileUpload
244
+ * @property {String} id - The id of the list item.
245
+ * @property {File} file - The file that was canceled.
246
+ * @property {Number} fileIndex - The index of the file in the file list.
247
+ */
248
+
249
+ /**
250
+ * @typedef {Object} PreUploadFileEventArgs
251
+ * @memberof componyx.UI.FileUpload
252
+ * @property {Number} fileIndex - The index of the file being uploaded.
253
+ * @property {FormData} formData - The form data object used for the upload request.
254
+ */
255
+
256
+ /**
257
+ * @typedef {Object} UploadProgressEventArgs
258
+ * @memberof componyx.UI.FileUpload
259
+ * @property {Number} fileIndex - The index of the file being uploaded.
260
+ * @property {componyx.library.XhrWrappedResult} xhr - The wrapped XHR request for this upload.
261
+ * @property {Number} percentage - The upload transfer progress as a percentage (0-100).
262
+ */
263
+
264
+ /**
265
+ * @typedef {Object} PostUploadFileEventArgs
266
+ * @memberof componyx.UI.FileUpload
267
+ * @property {Number} fileIndex - The index of the file that was uploaded.
268
+ * @property {componyx.library.XhrWrappedResult} xhr - The wrapped XHR request for this upload.
269
+ * @property {Object} file - The uploaded file info; either the server response object or an object with the file name.
270
+ */
271
+
272
+ /**
273
+ * @class
274
+ * @augments componyx.UI.base.Events
275
+ * @memberof componyx.UI.FileUpload
276
+ * @property {componyx.UI.base.Event} onChange - Fires when the file input selection has changed.
277
+ * @property {componyx.UI.base.Event} onDragOver - Fires repeatedly while the (mouse) pointer drags over the drop-zone. The event arguments are the native DragEvent.
278
+ * @property {componyx.UI.base.Event} onDragLeave - Fires when the (mouse) pointer drags out of the drop-zone. The event arguments are the native DragEvent.
279
+ * @property {componyx.UI.base.Event} onDrop - Fires when files are dropped onto the drop-zone. The event arguments are the native DragEvent.
280
+ * @property {componyx.UI.base.Event} onAccept - Fires when files are selected through drag & drop or the file input. @see {@link componyx.UI.FileUpload.AcceptEventArgs}
281
+ * @property {componyx.UI.base.Event} onCancel - Fires when a file is canceled before being uploaded. @see {@link componyx.UI.FileUpload.CancelEventArgs}
282
+ * @property {componyx.UI.base.Event} onPreUploadFile - Fires before a file upload starts. @see {@link componyx.UI.FileUpload.PreUploadFileEventArgs}
283
+ * @property {componyx.UI.base.Event} onUploadProgress - Fires during the upload transfer, providing progress updates. @see {@link componyx.UI.FileUpload.UploadProgressEventArgs}
284
+ * @property {componyx.UI.base.Event} onPostUploadFile - Fires after a file upload completes and the server has responded. @see {@link componyx.UI.FileUpload.PostUploadFileEventArgs}
285
+ * @property {componyx.UI.base.Event} onUploadComplete - Fires when all files have been uploaded.
286
+ * @see {@link componyx.UI.base.Events}
287
+ */
288
+ function FileUploadEvents(events)
289
+ {
290
+ Object.assign(this, events);
291
+
292
+ this.onChange = $base.static.createEvent('onChange');
293
+ this.onDragOver = $base.static.createEvent('onDragOver');
294
+ this.onDragLeave = $base.static.createEvent('onDragLeave');
295
+ this.onDrop = $base.static.createEvent('onDrop');
296
+ this.onAccept = $base.static.createEvent('onAccept');
297
+ this.onCancel = $base.static.createEvent('onCancel');
298
+ this.onPreUploadFile = $base.static.createEvent('onPreUploadFile');
299
+ this.onUploadProgress = $base.static.createEvent('onUploadProgress');
300
+ this.onPostUploadFile = $base.static.createEvent('onPostUploadFile');
301
+ this.onUploadComplete = $base.static.createEvent('onUploadComplete');
302
+ }
303
+ /**
304
+ * FileUpload events
305
+ * @type {componyx.UI.FileUpload.FileUploadEvents}
306
+ */
307
+ this.events = new FileUploadEvents(this.events);
308
+
309
+ // inherit base and box members
310
+ $base.Component.apply(this, [id, properties]);
311
+
312
+ this.ajax.addMethod('upload');
313
+
314
+ /**
315
+ * Uploads the selected file(s).
316
+ */
317
+ this.upload = function ()
318
+ {
319
+ upload();
320
+ };
321
+
322
+ /**
323
+ * Gets the list of successfully uploaded files.
324
+ * Each entry is either the server response object, or if no JSON data response, an object with the file name.
325
+ * @returns {Object[]} An array of objects holding the uploaded file information.
326
+ */
327
+ this.getValue = function ()
328
+ {
329
+ return _uploadedFiles;
330
+ };
331
+
332
+ /**
333
+ * Clears the upload progression info.
334
+ */
335
+ this.clear = function ()
336
+ {
337
+ if (_instance.renderState != 2)
338
+ return;
339
+
340
+ $lib.each(_cancelButtons, function (button)
341
+ {
342
+ button.destroy();
343
+ });
344
+
345
+ _list.innerHTML = '';
346
+ _list.style.display = 'none';
347
+ _progressBar.style.visibility = 'hidden';
348
+ _progressBar.firstChild.style.width = '0%';
349
+ _input.value = '';
350
+ _complete = false;
351
+ };
352
+
353
+ /**
354
+ * Cancels the upload.
355
+ * @param {File} [file] The file to cancel. All files are canceled if omitted.
356
+ */
357
+ this.cancel = function (file)
358
+ {
359
+ $lib.each(_cancelButtons, function (button)
360
+ {
361
+ if (!file || button.__file === file)
362
+ button.commandClick();
363
+ });
364
+ };
365
+
366
+ /**
367
+ * Renders the component.
368
+ */
369
+ this.render = function ()
370
+ {
371
+ if (_instance.renderState != $base.static.RenderState.RENDERING)
372
+ {
373
+ // call base render and return
374
+ $base.methods.render.call(_instance, preRender, 'file-upload');
375
+ return;
376
+ }
377
+
378
+ _complete = false;
379
+ draw();
380
+ };
381
+
382
+ /**
383
+ * Destroys the component.
384
+ * @see {@link componyx.UI.base.methods#destroy}
385
+ */
386
+ this.destroy = function (...args)
387
+ {
388
+ dispose();
389
+ $base.methods.destroy.call(this, ...args);
390
+ };
391
+
392
+ function preRender()
393
+ {
394
+ // initialize script and css
395
+ return ['FileUpload', ['Button', 'Dialog']];
396
+ }
397
+
398
+ function draw()
399
+ {
400
+ var content = document.createElement('span'),
401
+ uploadContainer = document.createElement('div');
402
+
403
+ content.innerHTML = _instance.selectButtonLabel;
404
+
405
+ _dropzone = document.createElement('div');
406
+ _dropzone.className = _instance.cssClassDropzone || _classOption.DROPZONE;
407
+
408
+ if (_instance.dragAndDrop)
409
+ _dropzone.setAttribute('data-drop-text', _instance.dropLabel);
410
+ else
411
+ $lib.addClass(_dropzone, 'disabled');
412
+
413
+ _input = createFileInput();
414
+
415
+ _list = document.createElement('div');
416
+ _list.className = _instance.cssClassList || _classOption.LIST;
417
+ _list.style.display = 'none';
418
+
419
+ _selectButton = createButton(_instance.selectButtonId, _dropzone, _instance.cssClassSelectButton || _classOption.SELECTBUTTON);
420
+ _selectButton.setContentTemplate([content, _input]);
421
+ _selectButton.render();
422
+
423
+ _uploadButton = createButton(_instance.uploadButtonId, uploadContainer, _instance.cssClassUploadButton || _classOption.UPLOADBUTTON, _instance.uploadButtonLabel);
424
+ _uploadButton.disabled = true;
425
+ _uploadButton.command = upload;
426
+ _uploadButton.render();
427
+
428
+ _progressBar = createProgressBar(uploadContainer, true);
429
+
430
+ _instance.element.appendChild(_dropzone);
431
+ _instance.element.appendChild(_list);
432
+ _instance.element.appendChild(uploadContainer);
433
+
434
+ if (_instance.accept)
435
+ _accept = _instance.accept.replace(/ /g, "").split(',');
436
+
437
+ bindEvents();
438
+ _instance.renderChildren();
439
+ }
440
+
441
+ function bindEvents()
442
+ {
443
+ if (_instance.dragAndDrop)
444
+ {
445
+ $lib.on(_dropzone, 'ondrop', drop);
446
+ $lib.on(_dropzone, 'ondragover', dragOver);
447
+ $lib.on(_dropzone, 'ondragleave', dragLeave);
448
+ }
449
+
450
+ $lib.on(_input, 'onchange', change);
451
+ }
452
+
453
+ function createFileInput()
454
+ {
455
+ var input = document.createElement('input');
456
+
457
+ input.type = 'file';
458
+ input.multiple = (_instance.maxFiles == 1) ? false : true;
459
+ input.accept = _instance.accept;
460
+ return input;
461
+ }
462
+
463
+ function createButton(cloneId, container, cssClass, text, postRenderCallback)
464
+ {
465
+ var id = _instance.id + '_' + $lib.guid(),
466
+ button = $UI.createComponent(componyx.UI.Button, { id: id, containerElement: container });
467
+
468
+ button.clone($UI.store[cloneId], _instance);
469
+ button.cssClass = cssClass;
470
+ button.showing = true;
471
+ button.text = text;
472
+
473
+ if (postRenderCallback != false)
474
+ button.events.onPostRender.priorityAdd(function () { _instance.isReady.apply(_instance); }, null);
475
+
476
+ return button;
477
+ }
478
+
479
+ function change()
480
+ {
481
+ if (!_input.value)
482
+ return;
483
+
484
+ filesSelected(_input.files);
485
+ _instance.events.onChange.fire(_instance);
486
+ }
487
+
488
+ function dragOver(e)
489
+ {
490
+ e.preventDefault();
491
+
492
+ if (_instance.uploading)
493
+ return;
494
+
495
+ $lib.addClass(_dropzone, 'active');
496
+ _instance.events.onDragOver.fire(_instance, e);
497
+ }
498
+
499
+ function drop(e)
500
+ {
501
+ if (!e.dataTransfer.files)
502
+ return;
503
+
504
+ e.preventDefault();
505
+ $lib.removeClass(_dropzone, 'active'); // the drag is over, also while uploading
506
+
507
+ if (_instance.uploading)
508
+ return;
509
+
510
+ filesSelected(e.dataTransfer.files);
511
+ _instance.events.onDrop.fire(_instance, e);
512
+ }
513
+
514
+ function dragLeave(e)
515
+ {
516
+ if (_dropzone.contains(e.relatedTarget))
517
+ return; // moved onto a child element of the drop-zone, still inside
518
+
519
+ if (_instance.uploading)
520
+ return;
521
+
522
+ $lib.removeClass(_dropzone, 'active');
523
+ _instance.events.onDragLeave.fire(_instance, e);
524
+ }
525
+
526
+ function filesSelected(files)
527
+ {
528
+ let result = accept(files);
529
+ _files = _files.concat(result.accept);
530
+
531
+ if (result.reject.length)
532
+ showRejected(result.reject);
533
+
534
+ toggleUploadButton();
535
+ toggleList();
536
+ _progressBar.style.visibility = 'hidden';
537
+
538
+ if (_files.length == 0)
539
+ return;
540
+
541
+ _input.value = '';
542
+ drawItemList();
543
+ }
544
+
545
+ function accept(files)
546
+ {
547
+ let accept = [], reject = [], size;
548
+ let seen = _files.slice();
549
+
550
+ $lib.each(files, function (file)
551
+ {
552
+ if ((!$lib.isEmpty(_instance.maxFiles) && seen.length >= _instance.maxFiles)
553
+ || _instance.preventDuplicates && seen.some(item => filesMatch(item, file)))
554
+ {
555
+ reject.push(file);
556
+ return;
557
+ }
558
+
559
+ size = (file.size / 1024); // KB
560
+
561
+ if ((!_instance.maxFileSize || size <= _instance.maxFileSize) && acceptType(file))
562
+ {
563
+ const args = { cancel: false, file: file };
564
+ _instance.events.onAccept.fire(_instance, args);
565
+
566
+ if (!args.cancel)
567
+ {
568
+ accept.push(file);
569
+ seen.push(file);
570
+ }
571
+ else
572
+ reject.push(file);
573
+ }
574
+ else
575
+ reject.push(file);
576
+ });
577
+
578
+ return { accept, reject };
579
+ }
580
+
581
+ function filesMatch(a, b)
582
+ {
583
+ return a.name === b.name && a.size === b.size && a.lastModified === b.lastModified;
584
+ }
585
+
586
+ function filesMatch(a, b)
587
+ {
588
+ return a.name === b.name && a.size === b.size && a.lastModified === b.lastModified;
589
+ }
590
+
591
+ function acceptType(file)
592
+ {
593
+ if (!_accept)
594
+ return true;
595
+
596
+ var accept = false,
597
+ type = file.type.split('/'),
598
+ ext = file.name.substr(file.name.lastIndexOf('.'));
599
+
600
+ $lib.indexOf(_accept, function (item)
601
+ {
602
+ if (($lib.startsWith(item, '.')))
603
+ accept = item?.toLowerCase() == ext?.toLowerCase();
604
+ else
605
+ {
606
+ item = item.split('/');
607
+ accept = (item[0]?.toLowerCase() == type[0]?.toLowerCase() && (item[1] == '*' || item[1]?.toLowerCase() == type[1]?.toLowerCase()));
608
+ }
609
+
610
+ return accept;
611
+ });
612
+
613
+ return accept;
614
+ }
615
+
616
+ function showRejected(files)
617
+ {
618
+ const id = `${_instance.id}_rejected`,
619
+ dialog = $UI.createComponent(componyx.UI.Dialog, { id: id, containerElement: _instance.element }),
620
+ content = [];
621
+
622
+ dialog.clone($UI.store[_instance.rejectedDialogId], _instance);
623
+
624
+ files.forEach((file) =>
625
+ {
626
+ content.push($lib.element({ content: `${file.name} (${printSize(file.size)})` }));
627
+ });
628
+
629
+ dialog.alert(null, _instance.rejectedDialogHeader, content);
630
+ }
631
+
632
+ function toggleUploadButton()
633
+ {
634
+ if (_files.length > 0)
635
+ _uploadButton.enable();
636
+ else
637
+ _uploadButton.disable();
638
+ }
639
+
640
+ function toggleList()
641
+ {
642
+ if (_files.length > 0)
643
+ _list.style.display = '';
644
+ else
645
+ _list.style.display = 'none';
646
+ }
647
+
648
+ function drawItemList()
649
+ {
650
+ var ul = document.createElement('ul'), li, div, i, cancel;
651
+
652
+ _list.innerHTML = '';
653
+ _list.appendChild(ul);
654
+ _cancelButtons = [];
655
+ _complete = false;
656
+
657
+ $lib.each(_files, function (file, index)
658
+ {
659
+ li = ul.appendChild(document.createElement('li'));
660
+ li.id = _instance.id + '_' + $lib.guid();
661
+
662
+ div = li.appendChild(document.createElement('div'));
663
+ div.className = _instance.cssClassName || _classOption.NAME;
664
+
665
+ var span = div.appendChild(document.createElement('span'));
666
+ span.textContent = file.name;
667
+ span = div.appendChild(document.createElement('span'));
668
+ span.textContent = printSize(file.size);
669
+
670
+ createProgressBar(li);
671
+
672
+ div = li.appendChild(document.createElement('div'));
673
+ div.className = _instance.cssClassState || _classOption.STATE;
674
+
675
+ div = li.appendChild(document.createElement('div'));
676
+ i = document.createElement('i');
677
+ i.className = 'ico-cross';
678
+
679
+ cancel = createButton(_instance.cancelButtonId, div, _instance.cssClassCancelButton || _classOption.CANCELBUTTON, _instance.cancelButtonLabel, false);
680
+ cancel.hasIcon = true;
681
+ cancel.transparent = true;
682
+ cancel.cssClassIcon = 'icon ico-cross';
683
+ cancel.command = cancelFile.bind(this, cancel);
684
+ cancel.__file = file;
685
+ cancel.__itemId = li.id;
686
+ cancel.show();
687
+ _cancelButtons.push(cancel);
688
+ });
689
+ }
690
+
691
+ function createProgressBar(container, total)
692
+ {
693
+ var div = container.appendChild(document.createElement('div'));
694
+ div.className = _instance.cssClassProgressBar || _classOption.PROGRESSBAR;
695
+ div.style.visibility = 'hidden';
696
+ div.appendChild(document.createElement('b'));
697
+
698
+ if (total)
699
+ $lib.addClass(div, 'total');
700
+
701
+ return div;
702
+ }
703
+
704
+ function printSize(bytes)
705
+ {
706
+ var count = 0;
707
+
708
+ if (bytes <= 0)
709
+ return bytes + _suffix[0];
710
+
711
+ while ($lib.roundNumber(bytes, 2) >= 1000 && count < _suffix.length)
712
+ {
713
+ bytes /= 1024;
714
+ count++;
715
+ }
716
+
717
+ return $lib.roundNumber(bytes, 2) + _suffix[count];
718
+ }
719
+
720
+ function cancelFile(button)
721
+ {
722
+ var id = button.__itemId,
723
+ file = button.__file,
724
+ index = (_files.length > 0) ? getFileIndex(file) : -1;
725
+
726
+ if (_xhr[index])
727
+ {
728
+ _xhr[index].abort(); // fires complete eventually
729
+ }
730
+ else
731
+ {
732
+ $lib.remove($lib('#' + id));
733
+
734
+ if (_files.length > 0)
735
+ {
736
+ _files.splice(index, 1);
737
+ }
738
+
739
+ if (!_complete || _list.firstElementChild?.childNodes?.length == 0)
740
+ {
741
+ toggleUploadButton();
742
+ toggleList();
743
+ }
744
+ }
745
+
746
+ if (!complete)
747
+ _instance.events.onCancel.fire(_instance, { id: id, file: file, fileIndex: index });
748
+ }
749
+
750
+ function upload()
751
+ {
752
+ var formData;
753
+
754
+ _uploading = true;
755
+ _uploadButton.disable();
756
+ _selectButton.disable();
757
+
758
+ $lib.each(_files, function (file, index)
759
+ {
760
+ if (!file)
761
+ return; // cancelled
762
+
763
+ formData = new FormData();
764
+ formData.append(_instance.name || file.name, file);
765
+
766
+ _instance.events.onPreUploadFile.fire(_instance, { fileIndex: index, formData: formData });
767
+ _xhr.push(_instance.ajaxCall('upload', formData,
768
+ {
769
+ onStart: function (args) { start(args, index); },
770
+ onUploadProgress: function (args) { progress(args, index); },
771
+ onSuccess: function (args) { success(args, index); },
772
+ onUploadError: function (args) { error(args, index); },
773
+ onError: function (args) { error(args, index); },
774
+ onAbort: function (args) { abort(args, index); }
775
+ }, [index]));
776
+ });
777
+ }
778
+
779
+ function getFileIndex(file)
780
+ {
781
+ return $lib.indexOf(_files, function (item) { return (file == item); })
782
+ }
783
+
784
+ function getItem(index)
785
+ {
786
+ return $lib(null, _list, 'li')[index];
787
+ }
788
+
789
+ function getProgressBar(li)
790
+ {
791
+ return $lib('progress', li, 'div', true).firstChild;
792
+ }
793
+
794
+ function getStatusLabel(li)
795
+ {
796
+ return $lib('state', li, 'div', true);
797
+ }
798
+
799
+ function start(args, index)
800
+ {
801
+ var li = getItem(index);
802
+ getProgressBar(li).parentNode.style.visibility = '';
803
+ }
804
+
805
+ function progress(args, index)
806
+ {
807
+ var e = args.event,
808
+ percentage = (e.lengthComputable) ? Math.floor((e.loaded / e.total) * 100) : 0,
809
+ progress = getProgressBar(getItem(index));
810
+
811
+ progress.style.width = percentage + '%';
812
+ _xhr[index].__progress = percentage / 100;
813
+ setTotalProgress();
814
+
815
+ _instance.events.onUploadProgress.fire(_instance, { fileIndex: index, xhr: _xhr[index], percentage: percentage });
816
+ }
817
+
818
+ function setTotalProgress(percentage)
819
+ {
820
+ var total = 0;
821
+
822
+ $lib.each(_xhr, function (item)
823
+ {
824
+ if (item.__progress)
825
+ total += item.__progress;
826
+ });
827
+
828
+ _progressBar.style.visibility = '';
829
+ _progressBar.firstChild.style.width = (total / _xhr.length) * 100 + '%';
830
+ }
831
+
832
+ function success(args, index)
833
+ {
834
+ let li = getItem(index),
835
+ uploadedInfo = (args.data && typeof args.data === 'object') ? args.data : { name: _files[index].name };
836
+
837
+ getProgressBar(li).style.width = '100%';
838
+ $lib.addClass(li, _input.cssClassSuccess || _classOption.SUCCESS);
839
+ getStatusLabel(li).innerHTML = _instance.successLabel;
840
+ _uploadedFiles.push(uploadedInfo);
841
+
842
+ _instance.events.onPostUploadFile.fire(_instance, { fileIndex: index, xhr: _xhr[index], file: uploadedInfo });
843
+ complete(index);
844
+ }
845
+
846
+ function error(args, index)
847
+ {
848
+ var li = getItem(index);
849
+ $lib.addClass(li, _input.cssClassError || _classOption.ERROR);
850
+ getStatusLabel(li).innerHTML = _instance.errorLabel;
851
+ complete(index);
852
+ }
853
+
854
+ function abort(args, index)
855
+ {
856
+ var li = getItem(index);
857
+
858
+ $lib.addClass(li, _input.cssClassAbort || _classOption.ABORT);
859
+ getStatusLabel(li).innerHTML = _instance.abortLabel;
860
+ complete(index);
861
+ }
862
+
863
+ function complete(index)
864
+ {
865
+ _xhr[index].__ready = true;
866
+ _xhr[index].__progress = 1;
867
+ setTotalProgress();
868
+
869
+ if ($lib.indexOf(_xhr, function (xhr) { return (!xhr.__ready); }) == -1)
870
+ {
871
+ _instance.events.onUploadComplete.fire(_instance);
872
+ _uploading = false;
873
+ _files = [];
874
+ _xhr = [];
875
+ _complete = true;
876
+ _selectButton.enable();
877
+ _uploadButton.disable();
878
+ }
879
+ }
880
+
881
+ function dispose()
882
+ {
883
+ _uploadedFiles = [];
884
+ _files = [];
885
+ _xhr = [];
886
+ }
887
+ };
888
+
889
+ /**
890
+ * @see {@link componyx.UI.base.methods}
891
+ */
892
+ componyx.UI.FileUpload.prototype = Object.create($base.methods);
893
+ componyx.UI.FileUpload.prototype.constructor = componyx.UI.FileUpload;
894
+ })();
895
+
896
+ const FileUpload = componyx.UI.FileUpload;
897
+
898
+ export { FileUpload };