UNPKG

43.3 kBJavaScriptView Raw
1var _class, _temp;
2
3function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
4
5function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
6
7function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }
8
9var _require = require('preact'),
10 h = _require.h;
11
12var _require2 = require('@uppy/core'),
13 Plugin = _require2.Plugin;
14
15var Translator = require('@uppy/utils/lib/Translator');
16
17var DashboardUI = require('./components/Dashboard');
18
19var StatusBar = require('@uppy/status-bar');
20
21var Informer = require('@uppy/informer');
22
23var ThumbnailGenerator = require('@uppy/thumbnail-generator');
24
25var findAllDOMElements = require('@uppy/utils/lib/findAllDOMElements');
26
27var toArray = require('@uppy/utils/lib/toArray');
28
29var getDroppedFiles = require('@uppy/utils/lib/getDroppedFiles');
30
31var getTextDirection = require('@uppy/utils/lib/getTextDirection');
32
33var trapFocus = require('./utils/trapFocus');
34
35var cuid = require('cuid');
36
37var ResizeObserver = require('resize-observer-polyfill').default || require('resize-observer-polyfill');
38
39var createSuperFocus = require('./utils/createSuperFocus');
40
41var memoize = require('memoize-one').default || require('memoize-one');
42
43var FOCUSABLE_ELEMENTS = require('@uppy/utils/lib/FOCUSABLE_ELEMENTS');
44
45var TAB_KEY = 9;
46var ESC_KEY = 27;
47
48function createPromise() {
49 var o = {};
50 o.promise = new Promise(function (resolve, reject) {
51 o.resolve = resolve;
52 o.reject = reject;
53 });
54 return o;
55}
56
57function defaultPickerIcon() {
58 return h("svg", {
59 "aria-hidden": "true",
60 focusable: "false",
61 width: "30",
62 height: "30",
63 viewBox: "0 0 30 30"
64 }, h("path", {
65 d: "M15 30c8.284 0 15-6.716 15-15 0-8.284-6.716-15-15-15C6.716 0 0 6.716 0 15c0 8.284 6.716 15 15 15zm4.258-12.676v6.846h-8.426v-6.846H5.204l9.82-12.364 9.82 12.364H19.26z"
66 }));
67}
68/**
69 * Dashboard UI with previews, metadata editing, tabs for various services and more
70 */
71
72
73module.exports = (_temp = _class = /*#__PURE__*/function (_Plugin) {
74 _inheritsLoose(Dashboard, _Plugin);
75
76 function Dashboard(uppy, _opts) {
77 var _this;
78
79 _this = _Plugin.call(this, uppy, _opts) || this;
80
81 _this.setOptions = function (newOpts) {
82 _Plugin.prototype.setOptions.call(_assertThisInitialized(_this), newOpts);
83
84 _this.i18nInit();
85 };
86
87 _this.i18nInit = function () {
88 _this.translator = new Translator([_this.defaultLocale, _this.uppy.locale, _this.opts.locale]);
89 _this.i18n = _this.translator.translate.bind(_this.translator);
90 _this.i18nArray = _this.translator.translateArray.bind(_this.translator);
91
92 _this.setPluginState(); // so that UI re-renders and we see the updated locale
93
94 };
95
96 _this.removeTarget = function (plugin) {
97 var pluginState = _this.getPluginState(); // filter out the one we want to remove
98
99
100 var newTargets = pluginState.targets.filter(function (target) {
101 return target.id !== plugin.id;
102 });
103
104 _this.setPluginState({
105 targets: newTargets
106 });
107 };
108
109 _this.addTarget = function (plugin) {
110 var callerPluginId = plugin.id || plugin.constructor.name;
111 var callerPluginName = plugin.title || callerPluginId;
112 var callerPluginType = plugin.type;
113
114 if (callerPluginType !== 'acquirer' && callerPluginType !== 'progressindicator' && callerPluginType !== 'editor') {
115 var msg = 'Dashboard: can only be targeted by plugins of types: acquirer, progressindicator, editor';
116
117 _this.uppy.log(msg, 'error');
118
119 return;
120 }
121
122 var target = {
123 id: callerPluginId,
124 name: callerPluginName,
125 type: callerPluginType
126 };
127
128 var state = _this.getPluginState();
129
130 var newTargets = state.targets.slice();
131 newTargets.push(target);
132
133 _this.setPluginState({
134 targets: newTargets
135 });
136
137 return _this.el;
138 };
139
140 _this.hideAllPanels = function () {
141 var update = {
142 activePickerPanel: false,
143 showAddFilesPanel: false,
144 activeOverlayType: null,
145 fileCardFor: null,
146 showFileEditor: false
147 };
148
149 var current = _this.getPluginState();
150
151 if (current.activePickerPanel === update.activePickerPanel && current.showAddFilesPanel === update.showAddFilesPanel && current.showFileEditor === update.showFileEditor && current.activeOverlayType === update.activeOverlayType) {
152 // avoid doing a state update if nothing changed
153 return;
154 }
155
156 _this.setPluginState(update);
157 };
158
159 _this.showPanel = function (id) {
160 var _this$getPluginState = _this.getPluginState(),
161 targets = _this$getPluginState.targets;
162
163 var activePickerPanel = targets.filter(function (target) {
164 return target.type === 'acquirer' && target.id === id;
165 })[0];
166
167 _this.setPluginState({
168 activePickerPanel: activePickerPanel,
169 activeOverlayType: 'PickerPanel'
170 });
171 };
172
173 _this.canEditFile = function (file) {
174 var _this$getPluginState2 = _this.getPluginState(),
175 targets = _this$getPluginState2.targets;
176
177 var editors = _this._getEditors(targets);
178
179 return editors.some(function (target) {
180 return _this.uppy.getPlugin(target.id).canEditFile(file);
181 });
182 };
183
184 _this.openFileEditor = function (file) {
185 var _this$getPluginState3 = _this.getPluginState(),
186 targets = _this$getPluginState3.targets;
187
188 var editors = _this._getEditors(targets);
189
190 _this.setPluginState({
191 showFileEditor: true,
192 fileCardFor: file.id || null,
193 activeOverlayType: 'FileEditor'
194 });
195
196 editors.forEach(function (editor) {
197 _this.uppy.getPlugin(editor.id).selectFile(file);
198 });
199 };
200
201 _this.openModal = function () {
202 var _createPromise = createPromise(),
203 promise = _createPromise.promise,
204 resolve = _createPromise.resolve; // save scroll position
205
206
207 _this.savedScrollPosition = window.pageYOffset; // save active element, so we can restore focus when modal is closed
208
209 _this.savedActiveElement = document.activeElement;
210
211 if (_this.opts.disablePageScrollWhenModalOpen) {
212 document.body.classList.add('uppy-Dashboard-isFixed');
213 }
214
215 if (_this.opts.animateOpenClose && _this.getPluginState().isClosing) {
216 var handler = function handler() {
217 _this.setPluginState({
218 isHidden: false
219 });
220
221 _this.el.removeEventListener('animationend', handler, false);
222
223 resolve();
224 };
225
226 _this.el.addEventListener('animationend', handler, false);
227 } else {
228 _this.setPluginState({
229 isHidden: false
230 });
231
232 resolve();
233 }
234
235 if (_this.opts.browserBackButtonClose) {
236 _this.updateBrowserHistory();
237 } // handle ESC and TAB keys in modal dialog
238
239
240 document.addEventListener('keydown', _this.handleKeyDownInModal);
241
242 _this.uppy.emit('dashboard:modal-open');
243
244 return promise;
245 };
246
247 _this.closeModal = function (opts) {
248 if (opts === void 0) {
249 opts = {};
250 }
251
252 var _opts2 = opts,
253 _opts2$manualClose = _opts2.manualClose,
254 manualClose = _opts2$manualClose === void 0 ? true : _opts2$manualClose;
255
256 var _this$getPluginState4 = _this.getPluginState(),
257 isHidden = _this$getPluginState4.isHidden,
258 isClosing = _this$getPluginState4.isClosing;
259
260 if (isHidden || isClosing) {
261 // short-circuit if animation is ongoing
262 return;
263 }
264
265 var _createPromise2 = createPromise(),
266 promise = _createPromise2.promise,
267 resolve = _createPromise2.resolve;
268
269 if (_this.opts.disablePageScrollWhenModalOpen) {
270 document.body.classList.remove('uppy-Dashboard-isFixed');
271 }
272
273 if (_this.opts.animateOpenClose) {
274 _this.setPluginState({
275 isClosing: true
276 });
277
278 var handler = function handler() {
279 _this.setPluginState({
280 isHidden: true,
281 isClosing: false
282 });
283
284 _this.superFocus.cancel();
285
286 _this.savedActiveElement.focus();
287
288 _this.el.removeEventListener('animationend', handler, false);
289
290 resolve();
291 };
292
293 _this.el.addEventListener('animationend', handler, false);
294 } else {
295 _this.setPluginState({
296 isHidden: true
297 });
298
299 _this.superFocus.cancel();
300
301 _this.savedActiveElement.focus();
302
303 resolve();
304 } // handle ESC and TAB keys in modal dialog
305
306
307 document.removeEventListener('keydown', _this.handleKeyDownInModal);
308
309 if (manualClose) {
310 if (_this.opts.browserBackButtonClose) {
311 // Make sure that the latest entry in the history state is our modal name
312 if (history.state && history.state[_this.modalName]) {
313 // Go back in history to clear out the entry we created (ultimately closing the modal)
314 history.go(-1);
315 }
316 }
317 }
318
319 _this.uppy.emit('dashboard:modal-closed');
320
321 return promise;
322 };
323
324 _this.isModalOpen = function () {
325 return !_this.getPluginState().isHidden || false;
326 };
327
328 _this.requestCloseModal = function () {
329 if (_this.opts.onRequestCloseModal) {
330 return _this.opts.onRequestCloseModal();
331 }
332
333 return _this.closeModal();
334 };
335
336 _this.setDarkModeCapability = function (isDarkModeOn) {
337 var _this$uppy$getState = _this.uppy.getState(),
338 capabilities = _this$uppy$getState.capabilities;
339
340 _this.uppy.setState({
341 capabilities: _extends({}, capabilities, {
342 darkMode: isDarkModeOn
343 })
344 });
345 };
346
347 _this.handleSystemDarkModeChange = function (event) {
348 var isDarkModeOnNow = event.matches;
349
350 _this.uppy.log("[Dashboard] Dark mode is " + (isDarkModeOnNow ? 'on' : 'off'));
351
352 _this.setDarkModeCapability(isDarkModeOnNow);
353 };
354
355 _this.toggleFileCard = function (show, fileID) {
356 var file = _this.uppy.getFile(fileID);
357
358 if (show) {
359 _this.uppy.emit('dashboard:file-edit-start', file);
360 } else {
361 _this.uppy.emit('dashboard:file-edit-complete', file);
362 }
363
364 _this.setPluginState({
365 fileCardFor: show ? fileID : null,
366 activeOverlayType: show ? 'FileCard' : null
367 });
368 };
369
370 _this.toggleAddFilesPanel = function (show) {
371 _this.setPluginState({
372 showAddFilesPanel: show,
373 activeOverlayType: show ? 'AddFiles' : null
374 });
375 };
376
377 _this.addFiles = function (files) {
378 var descriptors = files.map(function (file) {
379 return {
380 source: _this.id,
381 name: file.name,
382 type: file.type,
383 data: file,
384 meta: {
385 // path of the file relative to the ancestor directory the user selected.
386 // e.g. 'docs/Old Prague/airbnb.pdf'
387 relativePath: file.relativePath || null
388 }
389 };
390 });
391
392 try {
393 _this.uppy.addFiles(descriptors);
394 } catch (err) {
395 _this.uppy.log(err);
396 }
397 };
398
399 _this.startListeningToResize = function () {
400 // Watch for Dashboard container (`.uppy-Dashboard-inner`) resize
401 // and update containerWidth/containerHeight in plugin state accordingly.
402 // Emits first event on initialization.
403 _this.resizeObserver = new ResizeObserver(function (entries, observer) {
404 var uppyDashboardInnerEl = entries[0];
405 var _uppyDashboardInnerEl = uppyDashboardInnerEl.contentRect,
406 width = _uppyDashboardInnerEl.width,
407 height = _uppyDashboardInnerEl.height;
408
409 _this.uppy.log("[Dashboard] resized: " + width + " / " + height, 'debug');
410
411 _this.setPluginState({
412 containerWidth: width,
413 containerHeight: height,
414 areInsidesReadyToBeVisible: true
415 });
416 });
417
418 _this.resizeObserver.observe(_this.el.querySelector('.uppy-Dashboard-inner')); // If ResizeObserver fails to emit an event telling us what size to use - default to the mobile view
419
420
421 _this.makeDashboardInsidesVisibleAnywayTimeout = setTimeout(function () {
422 var pluginState = _this.getPluginState();
423
424 var isModalAndClosed = !_this.opts.inline && pluginState.isHidden;
425
426 if ( // if ResizeObserver hasn't yet fired,
427 !pluginState.areInsidesReadyToBeVisible && // and it's not due to the modal being closed
428 !isModalAndClosed) {
429 _this.uppy.log("[Dashboard] resize event didn't fire on time: defaulted to mobile layout", 'debug');
430
431 _this.setPluginState({
432 areInsidesReadyToBeVisible: true
433 });
434 }
435 }, 1000);
436 };
437
438 _this.stopListeningToResize = function () {
439 _this.resizeObserver.disconnect();
440
441 clearTimeout(_this.makeDashboardInsidesVisibleAnywayTimeout);
442 };
443
444 _this.recordIfFocusedOnUppyRecently = function (event) {
445 if (_this.el.contains(event.target)) {
446 _this.ifFocusedOnUppyRecently = true;
447 } else {
448 _this.ifFocusedOnUppyRecently = false; // ___Why run this.superFocus.cancel here when it already runs in superFocusOnEachUpdate?
449 // Because superFocus is debounced, when we move from Uppy to some other element on the page,
450 // previously run superFocus sometimes hits and moves focus back to Uppy.
451
452 _this.superFocus.cancel();
453 }
454 };
455
456 _this.disableAllFocusableElements = function (disable) {
457 var focusableNodes = toArray(_this.el.querySelectorAll(FOCUSABLE_ELEMENTS));
458
459 if (disable) {
460 focusableNodes.forEach(function (node) {
461 // save previous tabindex in a data-attribute, to restore when enabling
462 var currentTabIndex = node.getAttribute('tabindex');
463
464 if (currentTabIndex) {
465 node.dataset.inertTabindex = currentTabIndex;
466 }
467
468 node.setAttribute('tabindex', '-1');
469 });
470 } else {
471 focusableNodes.forEach(function (node) {
472 if ('inertTabindex' in node.dataset) {
473 node.setAttribute('tabindex', node.dataset.inertTabindex);
474 } else {
475 node.removeAttribute('tabindex');
476 }
477 });
478 }
479
480 _this.dashboardIsDisabled = disable;
481 };
482
483 _this.updateBrowserHistory = function () {
484 // Ensure history state does not already contain our modal name to avoid double-pushing
485 if (!history.state || !history.state[_this.modalName]) {
486 var _extends2;
487
488 // Push to history so that the page is not lost on browser back button press
489 history.pushState(_extends({}, history.state, (_extends2 = {}, _extends2[_this.modalName] = true, _extends2)), '');
490 } // Listen for back button presses
491
492
493 window.addEventListener('popstate', _this.handlePopState, false);
494 };
495
496 _this.handlePopState = function (event) {
497 // Close the modal if the history state no longer contains our modal name
498 if (_this.isModalOpen() && (!event.state || !event.state[_this.modalName])) {
499 _this.closeModal({
500 manualClose: false
501 });
502 } // When the browser back button is pressed and uppy is now the latest entry in the history but the modal is closed, fix the history by removing the uppy history entry
503 // This occurs when another entry is added into the history state while the modal is open, and then the modal gets manually closed
504 // Solves PR #575 (https://github.com/transloadit/uppy/pull/575)
505
506
507 if (!_this.isModalOpen() && event.state && event.state[_this.modalName]) {
508 history.go(-1);
509 }
510 };
511
512 _this.handleKeyDownInModal = function (event) {
513 // close modal on esc key press
514 if (event.keyCode === ESC_KEY) _this.requestCloseModal(event); // trap focus on tab key press
515
516 if (event.keyCode === TAB_KEY) trapFocus.forModal(event, _this.getPluginState().activeOverlayType, _this.el);
517 };
518
519 _this.handleClickOutside = function () {
520 if (_this.opts.closeModalOnClickOutside) _this.requestCloseModal();
521 };
522
523 _this.handlePaste = function (event) {
524 // 1. Let any acquirer plugin (Url/Webcam/etc.) handle pastes to the root
525 _this.uppy.iteratePlugins(function (plugin) {
526 if (plugin.type === 'acquirer') {
527 // Every Plugin with .type acquirer can define handleRootPaste(event)
528 plugin.handleRootPaste && plugin.handleRootPaste(event);
529 }
530 }); // 2. Add all dropped files
531
532
533 var files = toArray(event.clipboardData.files);
534
535 _this.addFiles(files);
536 };
537
538 _this.handleInputChange = function (event) {
539 event.preventDefault();
540 var files = toArray(event.target.files);
541
542 _this.addFiles(files);
543 };
544
545 _this.handleDragOver = function (event) {
546 event.preventDefault();
547 event.stopPropagation();
548
549 if (_this.opts.disabled) {
550 return;
551 } // 1. Add a small (+) icon on drop
552 // (and prevent browsers from interpreting this as files being _moved_ into the browser, https://github.com/transloadit/uppy/issues/1978)
553
554
555 event.dataTransfer.dropEffect = 'copy';
556 clearTimeout(_this.removeDragOverClassTimeout);
557
558 _this.setPluginState({
559 isDraggingOver: true
560 });
561 };
562
563 _this.handleDragLeave = function (event) {
564 event.preventDefault();
565 event.stopPropagation();
566
567 if (_this.opts.disabled) {
568 return;
569 }
570
571 clearTimeout(_this.removeDragOverClassTimeout); // Timeout against flickering, this solution is taken from drag-drop library. Solution with 'pointer-events: none' didn't work across browsers.
572
573 _this.removeDragOverClassTimeout = setTimeout(function () {
574 _this.setPluginState({
575 isDraggingOver: false
576 });
577 }, 50);
578 };
579
580 _this.handleDrop = function (event, dropCategory) {
581 event.preventDefault();
582 event.stopPropagation();
583
584 if (_this.opts.disabled) {
585 return;
586 }
587
588 clearTimeout(_this.removeDragOverClassTimeout); // 2. Remove dragover class
589
590 _this.setPluginState({
591 isDraggingOver: false
592 }); // 3. Let any acquirer plugin (Url/Webcam/etc.) handle drops to the root
593
594
595 _this.uppy.iteratePlugins(function (plugin) {
596 if (plugin.type === 'acquirer') {
597 // Every Plugin with .type acquirer can define handleRootDrop(event)
598 plugin.handleRootDrop && plugin.handleRootDrop(event);
599 }
600 }); // 4. Add all dropped files
601
602
603 var executedDropErrorOnce = false;
604
605 var logDropError = function logDropError(error) {
606 _this.uppy.log(error, 'error'); // In practice all drop errors are most likely the same, so let's just show one to avoid overwhelming the user
607
608
609 if (!executedDropErrorOnce) {
610 _this.uppy.info(error.message, 'error');
611
612 executedDropErrorOnce = true;
613 }
614 };
615
616 getDroppedFiles(event.dataTransfer, {
617 logDropError: logDropError
618 }).then(function (files) {
619 if (files.length > 0) {
620 _this.uppy.log('[Dashboard] Files were dropped');
621
622 _this.addFiles(files);
623 }
624 });
625 };
626
627 _this.handleRequestThumbnail = function (file) {
628 if (!_this.opts.waitForThumbnailsBeforeUpload) {
629 _this.uppy.emit('thumbnail:request', file);
630 }
631 };
632
633 _this.handleCancelThumbnail = function (file) {
634 if (!_this.opts.waitForThumbnailsBeforeUpload) {
635 _this.uppy.emit('thumbnail:cancel', file);
636 }
637 };
638
639 _this.handleKeyDownInInline = function (event) {
640 // Trap focus on tab key press.
641 if (event.keyCode === TAB_KEY) trapFocus.forInline(event, _this.getPluginState().activeOverlayType, _this.el);
642 };
643
644 _this.handlePasteOnBody = function (event) {
645 var isFocusInOverlay = _this.el.contains(document.activeElement);
646
647 if (isFocusInOverlay) {
648 _this.handlePaste(event);
649 }
650 };
651
652 _this.handleComplete = function (_ref) {
653 var failed = _ref.failed;
654
655 if (_this.opts.closeAfterFinish && failed.length === 0) {
656 // All uploads are done
657 _this.requestCloseModal();
658 }
659 };
660
661 _this._openFileEditorWhenFilesAdded = function (files) {
662 var firstFile = files[0];
663
664 if (_this.canEditFile(firstFile)) {
665 _this.openFileEditor(firstFile);
666 }
667 };
668
669 _this.initEvents = function () {
670 // Modal open button
671 if (_this.opts.trigger && !_this.opts.inline) {
672 var showModalTrigger = findAllDOMElements(_this.opts.trigger);
673
674 if (showModalTrigger) {
675 showModalTrigger.forEach(function (trigger) {
676 return trigger.addEventListener('click', _this.openModal);
677 });
678 } else {
679 _this.uppy.log('Dashboard modal trigger not found. Make sure `trigger` is set in Dashboard options, unless you are planning to call `dashboard.openModal()` method yourself', 'warning');
680 }
681 }
682
683 _this.startListeningToResize();
684
685 document.addEventListener('paste', _this.handlePasteOnBody);
686
687 _this.uppy.on('plugin-remove', _this.removeTarget);
688
689 _this.uppy.on('file-added', _this.hideAllPanels);
690
691 _this.uppy.on('dashboard:modal-closed', _this.hideAllPanels);
692
693 _this.uppy.on('file-editor:complete', _this.hideAllPanels);
694
695 _this.uppy.on('complete', _this.handleComplete); // ___Why fire on capture?
696 // Because this.ifFocusedOnUppyRecently needs to change before onUpdate() fires.
697
698
699 document.addEventListener('focus', _this.recordIfFocusedOnUppyRecently, true);
700 document.addEventListener('click', _this.recordIfFocusedOnUppyRecently, true);
701
702 if (_this.opts.inline) {
703 _this.el.addEventListener('keydown', _this.handleKeyDownInInline);
704 }
705
706 if (_this.opts.autoOpenFileEditor) {
707 _this.uppy.on('files-added', _this._openFileEditorWhenFilesAdded);
708 }
709 };
710
711 _this.removeEvents = function () {
712 var showModalTrigger = findAllDOMElements(_this.opts.trigger);
713
714 if (!_this.opts.inline && showModalTrigger) {
715 showModalTrigger.forEach(function (trigger) {
716 return trigger.removeEventListener('click', _this.openModal);
717 });
718 }
719
720 _this.stopListeningToResize();
721
722 document.removeEventListener('paste', _this.handlePasteOnBody);
723 window.removeEventListener('popstate', _this.handlePopState, false);
724
725 _this.uppy.off('plugin-remove', _this.removeTarget);
726
727 _this.uppy.off('file-added', _this.hideAllPanels);
728
729 _this.uppy.off('dashboard:modal-closed', _this.hideAllPanels);
730
731 _this.uppy.off('complete', _this.handleComplete);
732
733 document.removeEventListener('focus', _this.recordIfFocusedOnUppyRecently);
734 document.removeEventListener('click', _this.recordIfFocusedOnUppyRecently);
735
736 if (_this.opts.inline) {
737 _this.el.removeEventListener('keydown', _this.handleKeyDownInInline);
738 }
739
740 if (_this.opts.autoOpenFileEditor) {
741 _this.uppy.off('files-added', _this._openFileEditorWhenFilesAdded);
742 }
743 };
744
745 _this.superFocusOnEachUpdate = function () {
746 var isFocusInUppy = _this.el.contains(document.activeElement); // When focus is lost on the page (== focus is on body for most browsers, or focus is null for IE11)
747
748
749 var isFocusNowhere = document.activeElement === document.body || document.activeElement === null;
750
751 var isInformerHidden = _this.uppy.getState().info.isHidden;
752
753 var isModal = !_this.opts.inline;
754
755 if ( // If update is connected to showing the Informer - let the screen reader calmly read it.
756 isInformerHidden && ( // If we are in a modal - always superfocus without concern for other elements on the page (user is unlikely to want to interact with the rest of the page)
757 isModal || // If we are already inside of Uppy, or
758 isFocusInUppy || // If we are not focused on anything BUT we have already, at least once, focused on uppy
759 // 1. We focus when isFocusNowhere, because when the element we were focused on disappears (e.g. an overlay), - focus gets lost. If user is typing something somewhere else on the page, - focus won't be 'nowhere'.
760 // 2. We only focus when focus is nowhere AND this.ifFocusedOnUppyRecently, to avoid focus jumps if we do something else on the page.
761 // [Practical check] Without '&& this.ifFocusedOnUppyRecently', in Safari, in inline mode, when file is uploading, - navigate via tab to the checkbox, try to press space multiple times. Focus will jump to Uppy.
762 isFocusNowhere && _this.ifFocusedOnUppyRecently)) {
763 _this.superFocus(_this.el, _this.getPluginState().activeOverlayType);
764 } else {
765 _this.superFocus.cancel();
766 }
767 };
768
769 _this.afterUpdate = function () {
770 if (_this.opts.disabled && !_this.dashboardIsDisabled) {
771 _this.disableAllFocusableElements(true);
772
773 return;
774 }
775
776 if (!_this.opts.disabled && _this.dashboardIsDisabled) {
777 _this.disableAllFocusableElements(false);
778 }
779
780 _this.superFocusOnEachUpdate();
781 };
782
783 _this.cancelUpload = function (fileID) {
784 _this.uppy.removeFile(fileID);
785 };
786
787 _this.saveFileCard = function (meta, fileID) {
788 _this.uppy.setFileMeta(fileID, meta);
789
790 _this.toggleFileCard(false, fileID);
791 };
792
793 _this._attachRenderFunctionToTarget = function (target) {
794 var plugin = _this.uppy.getPlugin(target.id);
795
796 return _extends({}, target, {
797 icon: plugin.icon || _this.opts.defaultPickerIcon,
798 render: plugin.render
799 });
800 };
801
802 _this._isTargetSupported = function (target) {
803 var plugin = _this.uppy.getPlugin(target.id); // If the plugin does not provide a `supported` check, assume the plugin works everywhere.
804
805
806 if (typeof plugin.isSupported !== 'function') {
807 return true;
808 }
809
810 return plugin.isSupported();
811 };
812
813 _this._getAcquirers = memoize(function (targets) {
814 return targets.filter(function (target) {
815 return target.type === 'acquirer' && _this._isTargetSupported(target);
816 }).map(_this._attachRenderFunctionToTarget);
817 });
818 _this._getProgressIndicators = memoize(function (targets) {
819 return targets.filter(function (target) {
820 return target.type === 'progressindicator';
821 }).map(_this._attachRenderFunctionToTarget);
822 });
823 _this._getEditors = memoize(function (targets) {
824 return targets.filter(function (target) {
825 return target.type === 'editor';
826 }).map(_this._attachRenderFunctionToTarget);
827 });
828
829 _this.render = function (state) {
830 var pluginState = _this.getPluginState();
831
832 var files = state.files,
833 capabilities = state.capabilities,
834 allowNewUpload = state.allowNewUpload; // TODO: move this to Core, to share between Status Bar and Dashboard
835 // (and any other plugin that might need it, too)
836
837 var newFiles = Object.keys(files).filter(function (file) {
838 return !files[file].progress.uploadStarted;
839 });
840 var uploadStartedFiles = Object.keys(files).filter(function (file) {
841 return files[file].progress.uploadStarted;
842 });
843 var pausedFiles = Object.keys(files).filter(function (file) {
844 return files[file].isPaused;
845 });
846 var completeFiles = Object.keys(files).filter(function (file) {
847 return files[file].progress.uploadComplete;
848 });
849 var erroredFiles = Object.keys(files).filter(function (file) {
850 return files[file].error;
851 });
852 var inProgressFiles = Object.keys(files).filter(function (file) {
853 return !files[file].progress.uploadComplete && files[file].progress.uploadStarted;
854 });
855 var inProgressNotPausedFiles = inProgressFiles.filter(function (file) {
856 return !files[file].isPaused;
857 });
858 var processingFiles = Object.keys(files).filter(function (file) {
859 return files[file].progress.preprocess || files[file].progress.postprocess;
860 });
861 var isUploadStarted = uploadStartedFiles.length > 0;
862 var isAllComplete = state.totalProgress === 100 && completeFiles.length === Object.keys(files).length && processingFiles.length === 0;
863 var isAllErrored = isUploadStarted && erroredFiles.length === uploadStartedFiles.length;
864 var isAllPaused = inProgressFiles.length !== 0 && pausedFiles.length === inProgressFiles.length;
865
866 var acquirers = _this._getAcquirers(pluginState.targets);
867
868 var progressindicators = _this._getProgressIndicators(pluginState.targets);
869
870 var editors = _this._getEditors(pluginState.targets);
871
872 var theme;
873
874 if (_this.opts.theme === 'auto') {
875 theme = capabilities.darkMode ? 'dark' : 'light';
876 } else {
877 theme = _this.opts.theme;
878 }
879
880 if (['files', 'folders', 'both'].indexOf(_this.opts.fileManagerSelectionType) < 0) {
881 _this.opts.fileManagerSelectionType = 'files';
882 console.error("Unsupported option for \"fileManagerSelectionType\". Using default of \"" + _this.opts.fileManagerSelectionType + "\".");
883 }
884
885 return DashboardUI({
886 state: state,
887 isHidden: pluginState.isHidden,
888 files: files,
889 newFiles: newFiles,
890 uploadStartedFiles: uploadStartedFiles,
891 completeFiles: completeFiles,
892 erroredFiles: erroredFiles,
893 inProgressFiles: inProgressFiles,
894 inProgressNotPausedFiles: inProgressNotPausedFiles,
895 processingFiles: processingFiles,
896 isUploadStarted: isUploadStarted,
897 isAllComplete: isAllComplete,
898 isAllErrored: isAllErrored,
899 isAllPaused: isAllPaused,
900 totalFileCount: Object.keys(files).length,
901 totalProgress: state.totalProgress,
902 allowNewUpload: allowNewUpload,
903 acquirers: acquirers,
904 theme: theme,
905 disabled: _this.opts.disabled,
906 direction: _this.opts.direction,
907 activePickerPanel: pluginState.activePickerPanel,
908 showFileEditor: pluginState.showFileEditor,
909 disableAllFocusableElements: _this.disableAllFocusableElements,
910 animateOpenClose: _this.opts.animateOpenClose,
911 isClosing: pluginState.isClosing,
912 getPlugin: _this.uppy.getPlugin,
913 progressindicators: progressindicators,
914 editors: editors,
915 autoProceed: _this.uppy.opts.autoProceed,
916 id: _this.id,
917 closeModal: _this.requestCloseModal,
918 handleClickOutside: _this.handleClickOutside,
919 handleInputChange: _this.handleInputChange,
920 handlePaste: _this.handlePaste,
921 inline: _this.opts.inline,
922 showPanel: _this.showPanel,
923 hideAllPanels: _this.hideAllPanels,
924 log: _this.uppy.log,
925 i18n: _this.i18n,
926 i18nArray: _this.i18nArray,
927 removeFile: _this.uppy.removeFile,
928 uppy: _this.uppy,
929 info: _this.uppy.info,
930 note: _this.opts.note,
931 metaFields: pluginState.metaFields,
932 resumableUploads: capabilities.resumableUploads || false,
933 individualCancellation: capabilities.individualCancellation,
934 isMobileDevice: capabilities.isMobileDevice,
935 pauseUpload: _this.uppy.pauseResume,
936 retryUpload: _this.uppy.retryUpload,
937 cancelUpload: _this.cancelUpload,
938 cancelAll: _this.uppy.cancelAll,
939 fileCardFor: pluginState.fileCardFor,
940 toggleFileCard: _this.toggleFileCard,
941 toggleAddFilesPanel: _this.toggleAddFilesPanel,
942 showAddFilesPanel: pluginState.showAddFilesPanel,
943 saveFileCard: _this.saveFileCard,
944 openFileEditor: _this.openFileEditor,
945 canEditFile: _this.canEditFile,
946 width: _this.opts.width,
947 height: _this.opts.height,
948 showLinkToFileUploadResult: _this.opts.showLinkToFileUploadResult,
949 fileManagerSelectionType: _this.opts.fileManagerSelectionType,
950 proudlyDisplayPoweredByUppy: _this.opts.proudlyDisplayPoweredByUppy,
951 hideCancelButton: _this.opts.hideCancelButton,
952 hideRetryButton: _this.opts.hideRetryButton,
953 hidePauseResumeButton: _this.opts.hidePauseResumeButton,
954 showRemoveButtonAfterComplete: _this.opts.showRemoveButtonAfterComplete,
955 containerWidth: pluginState.containerWidth,
956 containerHeight: pluginState.containerHeight,
957 areInsidesReadyToBeVisible: pluginState.areInsidesReadyToBeVisible,
958 isTargetDOMEl: _this.isTargetDOMEl,
959 parentElement: _this.el,
960 allowedFileTypes: _this.uppy.opts.restrictions.allowedFileTypes,
961 maxNumberOfFiles: _this.uppy.opts.restrictions.maxNumberOfFiles,
962 showSelectedFiles: _this.opts.showSelectedFiles,
963 handleRequestThumbnail: _this.handleRequestThumbnail,
964 handleCancelThumbnail: _this.handleCancelThumbnail,
965 // drag props
966 isDraggingOver: pluginState.isDraggingOver,
967 handleDragOver: _this.handleDragOver,
968 handleDragLeave: _this.handleDragLeave,
969 handleDrop: _this.handleDrop
970 });
971 };
972
973 _this.discoverProviderPlugins = function () {
974 _this.uppy.iteratePlugins(function (plugin) {
975 if (plugin && !plugin.target && plugin.opts && plugin.opts.target === _this.constructor) {
976 _this.addTarget(plugin);
977 }
978 });
979 };
980
981 _this.install = function () {
982 // Set default state for Dashboard
983 _this.setPluginState({
984 isHidden: true,
985 fileCardFor: null,
986 activeOverlayType: null,
987 showAddFilesPanel: false,
988 activePickerPanel: false,
989 showFileEditor: false,
990 metaFields: _this.opts.metaFields,
991 targets: [],
992 // We'll make them visible once .containerWidth is determined
993 areInsidesReadyToBeVisible: false,
994 isDraggingOver: false
995 });
996
997 var _this$opts = _this.opts,
998 inline = _this$opts.inline,
999 closeAfterFinish = _this$opts.closeAfterFinish;
1000
1001 if (inline && closeAfterFinish) {
1002 throw new Error('[Dashboard] `closeAfterFinish: true` cannot be used on an inline Dashboard, because an inline Dashboard cannot be closed at all. Either set `inline: false`, or disable the `closeAfterFinish` option.');
1003 }
1004
1005 var allowMultipleUploads = _this.uppy.opts.allowMultipleUploads;
1006
1007 if (allowMultipleUploads && closeAfterFinish) {
1008 _this.uppy.log('[Dashboard] When using `closeAfterFinish`, we recommended setting the `allowMultipleUploads` option to `false` in the Uppy constructor. See https://uppy.io/docs/uppy/#allowMultipleUploads-true', 'warning');
1009 }
1010
1011 var target = _this.opts.target;
1012
1013 if (target) {
1014 _this.mount(target, _assertThisInitialized(_this));
1015 }
1016
1017 var plugins = _this.opts.plugins || [];
1018 plugins.forEach(function (pluginID) {
1019 var plugin = _this.uppy.getPlugin(pluginID);
1020
1021 if (plugin) {
1022 plugin.mount(_assertThisInitialized(_this), plugin);
1023 }
1024 });
1025
1026 if (!_this.opts.disableStatusBar) {
1027 _this.uppy.use(StatusBar, {
1028 id: _this.id + ":StatusBar",
1029 target: _assertThisInitialized(_this),
1030 hideUploadButton: _this.opts.hideUploadButton,
1031 hideRetryButton: _this.opts.hideRetryButton,
1032 hidePauseResumeButton: _this.opts.hidePauseResumeButton,
1033 hideCancelButton: _this.opts.hideCancelButton,
1034 showProgressDetails: _this.opts.showProgressDetails,
1035 hideAfterFinish: _this.opts.hideProgressAfterFinish,
1036 locale: _this.opts.locale,
1037 doneButtonHandler: _this.opts.doneButtonHandler
1038 });
1039 }
1040
1041 if (!_this.opts.disableInformer) {
1042 _this.uppy.use(Informer, {
1043 id: _this.id + ":Informer",
1044 target: _assertThisInitialized(_this)
1045 });
1046 }
1047
1048 if (!_this.opts.disableThumbnailGenerator) {
1049 _this.uppy.use(ThumbnailGenerator, {
1050 id: _this.id + ":ThumbnailGenerator",
1051 thumbnailWidth: _this.opts.thumbnailWidth,
1052 thumbnailType: _this.opts.thumbnailType,
1053 waitForThumbnailsBeforeUpload: _this.opts.waitForThumbnailsBeforeUpload,
1054 // If we don't block on thumbnails, we can lazily generate them
1055 lazy: !_this.opts.waitForThumbnailsBeforeUpload
1056 });
1057 } // Dark Mode / theme
1058
1059
1060 _this.darkModeMediaQuery = typeof window !== 'undefined' && window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
1061 var isDarkModeOnFromTheStart = _this.darkModeMediaQuery ? _this.darkModeMediaQuery.matches : false;
1062
1063 _this.uppy.log("[Dashboard] Dark mode is " + (isDarkModeOnFromTheStart ? 'on' : 'off'));
1064
1065 _this.setDarkModeCapability(isDarkModeOnFromTheStart);
1066
1067 if (_this.opts.theme === 'auto') {
1068 _this.darkModeMediaQuery.addListener(_this.handleSystemDarkModeChange);
1069 }
1070
1071 _this.discoverProviderPlugins();
1072
1073 _this.initEvents();
1074 };
1075
1076 _this.uninstall = function () {
1077 if (!_this.opts.disableInformer) {
1078 var informer = _this.uppy.getPlugin(_this.id + ":Informer"); // Checking if this plugin exists, in case it was removed by uppy-core
1079 // before the Dashboard was.
1080
1081
1082 if (informer) _this.uppy.removePlugin(informer);
1083 }
1084
1085 if (!_this.opts.disableStatusBar) {
1086 var statusBar = _this.uppy.getPlugin(_this.id + ":StatusBar");
1087
1088 if (statusBar) _this.uppy.removePlugin(statusBar);
1089 }
1090
1091 if (!_this.opts.disableThumbnailGenerator) {
1092 var thumbnail = _this.uppy.getPlugin(_this.id + ":ThumbnailGenerator");
1093
1094 if (thumbnail) _this.uppy.removePlugin(thumbnail);
1095 }
1096
1097 var plugins = _this.opts.plugins || [];
1098 plugins.forEach(function (pluginID) {
1099 var plugin = _this.uppy.getPlugin(pluginID);
1100
1101 if (plugin) plugin.unmount();
1102 });
1103
1104 if (_this.opts.theme === 'auto') {
1105 _this.darkModeMediaQuery.removeListener(_this.handleSystemDarkModeChange);
1106 }
1107
1108 _this.unmount();
1109
1110 _this.removeEvents();
1111 };
1112
1113 _this.id = _this.opts.id || 'Dashboard';
1114 _this.title = 'Dashboard';
1115 _this.type = 'orchestrator';
1116 _this.modalName = "uppy-Dashboard-" + cuid();
1117 _this.defaultLocale = {
1118 strings: {
1119 closeModal: 'Close Modal',
1120 importFrom: 'Import from %{name}',
1121 addingMoreFiles: 'Adding more files',
1122 addMoreFiles: 'Add more files',
1123 dashboardWindowTitle: 'File Uploader Window (Press escape to close)',
1124 dashboardTitle: 'File Uploader',
1125 copyLinkToClipboardSuccess: 'Link copied to clipboard',
1126 copyLinkToClipboardFallback: 'Copy the URL below',
1127 copyLink: 'Copy link',
1128 fileSource: 'File source: %{name}',
1129 done: 'Done',
1130 back: 'Back',
1131 addMore: 'Add more',
1132 removeFile: 'Remove file',
1133 editFile: 'Edit file',
1134 editing: 'Editing %{file}',
1135 finishEditingFile: 'Finish editing file',
1136 saveChanges: 'Save changes',
1137 cancel: 'Cancel',
1138 myDevice: 'My Device',
1139 dropPasteFiles: 'Drop files here, paste or %{browseFiles}',
1140 dropPasteFolders: 'Drop files here, paste or %{browseFolders}',
1141 dropPasteBoth: 'Drop files here, paste, %{browseFiles} or %{browseFolders}',
1142 dropPasteImportFiles: 'Drop files here, paste, %{browseFiles} or import from:',
1143 dropPasteImportFolders: 'Drop files here, paste, %{browseFolders} or import from:',
1144 dropPasteImportBoth: 'Drop files here, paste, %{browseFiles}, %{browseFolders} or import from:',
1145 dropHint: 'Drop your files here',
1146 browseFiles: 'browse files',
1147 browseFolders: 'browse folders',
1148 uploadComplete: 'Upload complete',
1149 uploadPaused: 'Upload paused',
1150 resumeUpload: 'Resume upload',
1151 pauseUpload: 'Pause upload',
1152 retryUpload: 'Retry upload',
1153 cancelUpload: 'Cancel upload',
1154 xFilesSelected: {
1155 0: '%{smart_count} file selected',
1156 1: '%{smart_count} files selected'
1157 },
1158 uploadingXFiles: {
1159 0: 'Uploading %{smart_count} file',
1160 1: 'Uploading %{smart_count} files'
1161 },
1162 processingXFiles: {
1163 0: 'Processing %{smart_count} file',
1164 1: 'Processing %{smart_count} files'
1165 },
1166 // The default `poweredBy2` string only combines the `poweredBy` string (%{backwardsCompat}) with the size.
1167 // Locales can override `poweredBy2` to specify a different word order. This is for backwards compat with
1168 // Uppy 1.9.x and below which did a naive concatenation of `poweredBy2 + size` instead of using a locale-specific
1169 // substitution.
1170 // TODO: In 2.0 `poweredBy2` should be removed in and `poweredBy` updated to use substitution.
1171 poweredBy2: '%{backwardsCompat} %{uppy}',
1172 poweredBy: 'Powered by'
1173 }
1174 }; // set default options
1175
1176 var defaultOptions = {
1177 target: 'body',
1178 metaFields: [],
1179 trigger: '#uppy-select-files',
1180 inline: false,
1181 width: 750,
1182 height: 550,
1183 thumbnailWidth: 280,
1184 thumbnailType: 'image/jpeg',
1185 waitForThumbnailsBeforeUpload: false,
1186 defaultPickerIcon: defaultPickerIcon,
1187 showLinkToFileUploadResult: true,
1188 showProgressDetails: false,
1189 hideUploadButton: false,
1190 hideCancelButton: false,
1191 hideRetryButton: false,
1192 hidePauseResumeButton: false,
1193 hideProgressAfterFinish: false,
1194 doneButtonHandler: function doneButtonHandler() {
1195 _this.uppy.reset();
1196
1197 _this.requestCloseModal();
1198 },
1199 note: null,
1200 closeModalOnClickOutside: false,
1201 closeAfterFinish: false,
1202 disableStatusBar: false,
1203 disableInformer: false,
1204 disableThumbnailGenerator: false,
1205 disablePageScrollWhenModalOpen: true,
1206 animateOpenClose: true,
1207 fileManagerSelectionType: 'files',
1208 proudlyDisplayPoweredByUppy: true,
1209 onRequestCloseModal: function onRequestCloseModal() {
1210 return _this.closeModal();
1211 },
1212 showSelectedFiles: true,
1213 showRemoveButtonAfterComplete: false,
1214 browserBackButtonClose: false,
1215 theme: 'light',
1216 autoOpenFileEditor: false,
1217 disabled: false
1218 }; // merge default options with the ones set by user
1219
1220 _this.opts = _extends({}, defaultOptions, _opts);
1221
1222 _this.i18nInit();
1223
1224 _this.superFocus = createSuperFocus();
1225 _this.ifFocusedOnUppyRecently = false; // Timeouts
1226
1227 _this.makeDashboardInsidesVisibleAnywayTimeout = null;
1228 _this.removeDragOverClassTimeout = null;
1229 return _this;
1230 }
1231
1232 var _proto = Dashboard.prototype;
1233
1234 _proto.onMount = function onMount() {
1235 // Set the text direction if the page has not defined one.
1236 var element = this.el;
1237 var direction = getTextDirection(element);
1238
1239 if (!direction) {
1240 element.dir = 'ltr';
1241 }
1242 };
1243
1244 return Dashboard;
1245}(Plugin), _class.VERSION = "1.17.0", _temp);
\No newline at end of file