@scaleflex/widget-core 4.4.0 → 4.5.1

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.
package/lib/index.js ADDED
@@ -0,0 +1,1932 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
3
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
6
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
7
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
8
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
9
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
10
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
11
+ function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
12
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
13
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
14
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
15
+ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
16
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
17
+ function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
18
+ function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
19
+ function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
20
+ function _wrapNativeSuper(t) { var r = "function" == typeof Map ? new Map() : void 0; return _wrapNativeSuper = function _wrapNativeSuper(t) { if (null === t || !_isNativeFunction(t)) return t; if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function"); if (void 0 !== r) { if (r.has(t)) return r.get(t); r.set(t, Wrapper); } function Wrapper() { return _construct(t, arguments, _getPrototypeOf(this).constructor); } return Wrapper.prototype = Object.create(t.prototype, { constructor: { value: Wrapper, enumerable: !1, writable: !0, configurable: !0 } }), _setPrototypeOf(Wrapper, t); }, _wrapNativeSuper(t); }
21
+ function _construct(t, e, r) { if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments); var o = [null]; o.push.apply(o, e); var p = new (t.bind.apply(t, o))(); return r && _setPrototypeOf(p, r.prototype), p; }
22
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
23
+ function _isNativeFunction(t) { try { return -1 !== Function.toString.call(t).indexOf("[native code]"); } catch (n) { return "function" == typeof t; } }
24
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
25
+ function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
26
+ import React from 'react';
27
+ import ReactDOM from 'react-dom';
28
+ import ee from 'namespace-emitter';
29
+ import cuid from 'cuid';
30
+ import prettierBytes from '@transloadit/prettier-bytes';
31
+ import match from 'mime-match';
32
+ import getFileType from '@scaleflex/widget-utils/lib/getFileType';
33
+ import Translator from '@scaleflex/widget-utils/lib/Translator';
34
+ import getFileNameAndExtension from '@scaleflex/widget-utils/lib/getFileNameAndExtension';
35
+ import generateFileId from '@scaleflex/widget-utils/lib/generateFileId';
36
+ import checkConnection from '@scaleflex/widget-utils/lib/checkConnection';
37
+ import handlePromise from '@scaleflex/widget-utils/lib/handlePromise';
38
+ import { PERMISSIONS, RESTRICTED_FILES_EXTENISONS, PLUGINS_IDS, FILE_UPLOAD_STATUS, PROGRESS_PANEL_ACTIVITY, ABORTED_ERROR } from '@scaleflex/widget-utils/lib/constants';
39
+ import { getBackendTranslations } from '@scaleflex/widget-utils/lib/i18n.client';
40
+ import extractFileDataNoBlob from '@scaleflex/widget-utils/lib/extractFileDataNoBlob';
41
+ import getFileExtension from '@scaleflex/widget-utils/lib/getFileExtension';
42
+ import convertBytesToMb from '@scaleflex/widget-utils/lib/convertBytesToMb';
43
+ import { justErrorsLogger, debugLogger } from './loggers';
44
+ import Plugin from './Plugin'; // Exported from here.
45
+ import defaultLocale from './defaultLocale';
46
+ import createStore from './createStore';
47
+ import { uploadUpdated, selectUploadById, selectUploads, selectUploadsArray, selectUploadCapabilities, uploadCapabilitiesUpdated, updateUploadInfoMetaTags, uploadsAdded, uploadsRemoved, allUploadsCancelled, allUploadsRemoved } from './slices/uploads.slice';
48
+ import { fetchUserAuthState, generateUserKey as _generateUserKey, saveUserSassKey, selectUserPermissions, selectUserSassKey, selectUserSecurityData, userInfoUpdated } from './slices/user.slice';
49
+ import { infoHid, infoSet } from './slices/info.slice';
50
+ import { coreCommonStateUpdated, selectCommonState, selectCoreLoading, selectCurrentFolderPath } from './slices/common.slice';
51
+ import Client from './Client';
52
+ import SassKeyRenewer from './SassKeyRenewer';
53
+
54
+ // TODO: find a way to show version of the current plugin
55
+ // why solution below isn't good?
56
+ // first import doesn't work with webpack 5 as it was deprecated
57
+ // second import fixes webpack 5 issue as it was mentioned in their docs
58
+ // but it exposes our package.json to the client and it is mentioned as security rist in mutiple places
59
+ // https://github.com/axelpale/genversion
60
+ // https://stackoverflow.com/questions/64993118/error-should-not-import-the-named-export-version-imported-as-version
61
+ // https://stackoverflow.com/questions/9153571/is-there-a-way-to-get-version-from-package-json-in-nodejs-code/10855054#10855054
62
+ // import { version } from '../package.json'
63
+ // import packageInfo from '../package.json'
64
+
65
+ // HACK until this issue fixed -- https://scaleflexhq.atlassian.net/browse/FRA-1673
66
+ window.React = React;
67
+ window.ReactDOM = ReactDOM;
68
+ var RestrictionError = /*#__PURE__*/function (_Error) {
69
+ function RestrictionError() {
70
+ var _this;
71
+ _classCallCheck(this, RestrictionError);
72
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
73
+ args[_key] = arguments[_key];
74
+ }
75
+ _this = _callSuper(this, RestrictionError, [].concat(args));
76
+ _this.isRestriction = true;
77
+ return _this;
78
+ }
79
+ _inherits(RestrictionError, _Error);
80
+ return _createClass(RestrictionError);
81
+ }(/*#__PURE__*/_wrapNativeSuper(Error));
82
+ /**
83
+ * filerobot Core module.
84
+ * Manages plugins, state updates, acts as an event bus,
85
+ * adds/removes files and metadata.
86
+ */
87
+ var ScaleflexWidget = /*#__PURE__*/function () {
88
+ /**
89
+ * Instantiate filerobot
90
+ *
91
+ * @param {object} opts — filerobot options
92
+ */
93
+ function ScaleflexWidget(opts) {
94
+ var _this2 = this;
95
+ _classCallCheck(this, ScaleflexWidget);
96
+ _defineProperty(this, "loadBackendTranslations", function () {
97
+ if (!_this2.backendTranslations) {
98
+ handlePromise(getBackendTranslations({
99
+ i18nFetchApiEndpoint: _this2.opts.i18nFetchApiEndpoint
100
+ }), function (translations) {
101
+ var _this2$currLngBackend;
102
+ if (!((_this2$currLngBackend = _this2.currLngBackendTranslations) !== null && _this2$currLngBackend !== void 0 && _this2$currLngBackend.strings)) {
103
+ _this2.currLngBackendTranslations = {
104
+ strings: {}
105
+ };
106
+ }
107
+ _this2.backendTranslations = translations;
108
+ _this2.updateCurrLngBackendTranslations();
109
+ }, function () {
110
+ var _this2$currLngBackend2;
111
+ if (!((_this2$currLngBackend2 = _this2.currLngBackendTranslations) !== null && _this2$currLngBackend2 !== void 0 && _this2$currLngBackend2.strings)) {
112
+ _this2.currLngBackendTranslations = {
113
+ strings: {}
114
+ };
115
+ }
116
+ _this2.updateCurrLngBackendTranslations();
117
+ _this2.info.apply(_this2, arguments);
118
+ });
119
+ }
120
+ });
121
+ _defineProperty(this, "updateCurrLngBackendTranslations", function () {
122
+ var _ref = _this2.opts || {},
123
+ language = _ref.language;
124
+ if (!language) return;
125
+ var currentLanguage = language.toLowerCase();
126
+ Translator.LANGUAGE = currentLanguage;
127
+ var backendTranslations = _this2.backendTranslations || [];
128
+ backendTranslations.forEach(function (translation) {
129
+ _this2.currLngBackendTranslations.strings[translation.translation_key] = translation.translations[currentLanguage];
130
+ });
131
+ _this2.i18nInit();
132
+ _this2.updateAllPluginsI18n();
133
+ _this2.refreshPluginsOptions();
134
+ });
135
+ _defineProperty(this, "updateAllPluginsI18n", function () {
136
+ _this2.iteratePlugins(function (plugin) {
137
+ if (typeof plugin.i18nInit === 'function') {
138
+ plugin.i18nInit();
139
+ }
140
+ });
141
+ });
142
+ _defineProperty(this, "_getInstalledPkgs", function () {
143
+ // We are always returning a new reference from plugins object, incase of using memoized value for the reference of the object
144
+ // So that we guarantee a rerender in all cases whether memoized or not.
145
+ return {
146
+ filerobot: _this2,
147
+ plugins: _objectSpread({}, _this2.plugins)
148
+ };
149
+ });
150
+ _defineProperty(this, "refreshPluginsOptions", function () {
151
+ _this2.emit('opts-updated', _this2._getInstalledPkgs());
152
+ });
153
+ // TODO: [Relevance] remove show/hide relevance when BE is done
154
+ _defineProperty(this, "showRelevance", function () {
155
+ _this2.setCoreCommonState({
156
+ isRelevanceAvailable: true
157
+ });
158
+ localStorage.setItem('show-relevance', 'true');
159
+ return 'Relevance activated, search by something to view relevance badge';
160
+ });
161
+ _defineProperty(this, "hideRelevance", function () {
162
+ _this2.setCoreCommonState({
163
+ isRelevanceAvailable: false
164
+ });
165
+ localStorage.removeItem('show-relevance');
166
+ return 'Relevance deactivated, search by something to hide relevance badge';
167
+ });
168
+ _defineProperty(this, "enableSearchDebugging", function () {
169
+ localStorage.setItem('debug_search', true);
170
+ return 'Search debugging enabled, hover on any asset to show debug info';
171
+ });
172
+ _defineProperty(this, "disableSearchDebugging", function () {
173
+ localStorage.setItem('debug_search', false);
174
+ return 'Search debugging disabled';
175
+ });
176
+ this.defaultLocale = {
177
+ strings: defaultLocale
178
+ };
179
+ this.timeoutNoPermissionsInfoId = null;
180
+ var defaultOptions = {
181
+ id: 'scaleflexWidget',
182
+ autoProceed: false,
183
+ allowMultipleUploads: true,
184
+ debug: false,
185
+ restrictions: {
186
+ maxFileSize: null,
187
+ maxTotalFilesSize: null,
188
+ maxNumberOfFiles: null,
189
+ minNumberOfFiles: null,
190
+ allowedFileTypes: null,
191
+ maxItemsSizeForCompression: null,
192
+ hideRestrictionsInformer: false,
193
+ // Folder import restrictions in remote uploads (GoogleDrive...etc.)
194
+ remoteMaxFolderImportCount: 500,
195
+ remoteMaxFolderImportSize: 10737418240,
196
+ // 10 GB in bytes
197
+ remoteMaxFolderDepth: 5,
198
+ remoteMaxFolderCount: 100
199
+ },
200
+ customUploadedFilesSizeInMb: 0,
201
+ onBeforeFileAdded: function onBeforeFileAdded(currentFile, files) {
202
+ return currentFile;
203
+ },
204
+ onBeforeUpload: function onBeforeUpload(files) {
205
+ return files;
206
+ },
207
+ logger: justErrorsLogger,
208
+ dev: false,
209
+ container: undefined,
210
+ securityTemplateId: undefined,
211
+ akamaiMode: false,
212
+ userPermissions: [],
213
+ userFoldersScope: [],
214
+ apiEndpoint: '',
215
+ skipApiEndpointToken: false,
216
+ apiEndpointVersion: 'v5',
217
+ adminApiEndpoint: '',
218
+ i18nFetchApiEndpoint: 'https://i18n-fastly.ultrafast.io/api',
219
+ shareApiEndpoint: '',
220
+ videoApiEndpoint: '',
221
+ language: 'en',
222
+ theme: {
223
+ breakpoints: {
224
+ values: {
225
+ xs: 0,
226
+ sm: 576,
227
+ md: 768,
228
+ lg: 1084,
229
+ xl: 1342,
230
+ xxl: 1600,
231
+ xxxl: 1920
232
+ }
233
+ }
234
+ },
235
+ userInfo: {
236
+ email: '',
237
+ name: '',
238
+ photo_uri: '',
239
+ uuid: ''
240
+ },
241
+ sassKeyRenewerEnabled: true
242
+ };
243
+
244
+ // Merge default options with the ones set by user,
245
+ // making sure to merge restrictions too
246
+ this.opts = _objectSpread(_objectSpread(_objectSpread({}, defaultOptions), opts), {}, {
247
+ securityTemplateId: opts.securityTemplateId || opts.securityTemplateID || defaultOptions.securityTemplateId,
248
+ // Old config name alias securityTemplateID->securityTemplateId. DEPRECATE SOON!
249
+ restrictions: _objectSpread(_objectSpread({}, defaultOptions.restrictions), opts && opts.restrictions),
250
+ userInfo: _objectSpread(_objectSpread({}, defaultOptions.userInfo), (opts === null || opts === void 0 ? void 0 : opts.userInfo) || {})
251
+ });
252
+ this.opts.apiEndpoint = (this.opts.apiEndpoint || '').trim().replace(/\/$/, '');
253
+ this.opts.adminApiEndpoint = (this.opts.adminApiEndpoint || '').trim().replace(/\/$/, '');
254
+ this.opts.shareApiEndpoint = (this.opts.shareApiEndpoint || '').trim().replace(/\/$/, '');
255
+ this.opts.videoApiEndpoint = (this.opts.videoApiEndpoint || '').trim().replace(/\/$/, '');
256
+ this.opts.i18nFetchApiEndpoint = (this.opts.i18nFetchApiEndpoint || '').trim().replace(/\/$/, '');
257
+ if (!this.opts.apiEndpoint) {
258
+ this.opts.apiEndpoint = this.opts.dev ? 'https://api-dev.filerobot.com' : 'https://api.filerobot.com';
259
+ }
260
+ if (!this.opts.adminApiEndpoint) {
261
+ this.opts.adminApiEndpoint = this.opts.dev ? 'https://hub-dev.filerobot.com/api' : 'https://hub.filerobot.com/api';
262
+ }
263
+ if (!this.opts.shareApiEndpoint) {
264
+ this.opts.shareApiEndpoint = this.opts.dev ? 'https://share-dev.filerobot.com' : 'https://share.filerobot.com';
265
+ }
266
+ if (!this.opts.videoApiEndpoint) {
267
+ this.opts.videoApiEndpoint = 'https://api.filerobot.com/videos/v2';
268
+ }
269
+
270
+ // Separate option for easier usage as it respects skipApiEndpointToken (no need to check in each use case)
271
+ this.opts.apiEndpointWithContainer = "".concat(this.opts.apiEndpoint).concat(!this.opts.skipApiEndpointToken && this.opts.container ? "/".concat(this.opts.container) : '');
272
+
273
+ // opts instead of this.opts to avoid comparing objects — we set logger: justErrorsLogger in defaultOptions
274
+ if (opts && opts.logger && opts.debug) {
275
+ this.log('You are using a custom `logger`, but also set `debug: true`, which uses built-in logger to output logs to console. Ignoring `debug: true` and using your custom `logger`.', 'warning');
276
+ } else if (opts && opts.debug) {
277
+ this.opts.logger = debugLogger;
278
+ }
279
+ if (!opts.container) {
280
+ throw new Error('`container` is required for having the widget works properly.');
281
+ }
282
+ if (this.log) {
283
+ this.log("Using Core v".concat(this.constructor.VERSION));
284
+ }
285
+ if (this.opts.restrictions.allowedFileTypes && this.opts.restrictions.allowedFileTypes !== null && !Array.isArray(this.opts.restrictions.allowedFileTypes)) {
286
+ throw new TypeError('`restrictions.allowedFileTypes` must be an array');
287
+ }
288
+
289
+ /**
290
+ * saveMissing translations is temporary disabled. Until we find a good solution how to improve automation.
291
+ * Previous approach doesn't work thus we switched to manual translations adding to Wordplex directly by developers.
292
+ */
293
+ // Translator.IS_DEV = this.opts.dev
294
+
295
+ this.i18nInit();
296
+
297
+ // Container for different types of plugins
298
+ this.plugins = {};
299
+ /*
300
+ * Container for the current uploads operations
301
+ * (not files but the upload process/operation itself that can contain multiple files)
302
+ * made as a property in the class as it doesn't need to cause a render or accessed externally.
303
+ */
304
+ this.uploadOperations = {};
305
+ this.getGlobalState = this.getGlobalState.bind(this);
306
+ this.getPlugin = this.getPlugin.bind(this);
307
+ this.removePlugin = this.removePlugin.bind(this);
308
+ this.getPreProcessors = this.getPreProcessors.bind(this);
309
+ this.getPostProcessors = this.getPostProcessors.bind(this);
310
+ this.setFilesInfoMetaTags = this.setFilesInfoMetaTags.bind(this);
311
+ this.showRelevance = this.showRelevance.bind(this);
312
+ this.hideRelevance = this.hideRelevance.bind(this);
313
+ this.setFileStateBeforeUpload = this.setFileStateBeforeUpload.bind(this);
314
+ this.getFileUploading = this.getFileUploading.bind(this);
315
+ this.setFileUploadingState = this.setFileUploadingState.bind(this);
316
+ this.setUploadPanelFileState = this.setUploadPanelFileState.bind(this);
317
+ this.setFileState = this.setFileState.bind(this);
318
+ this.setProgressPanelFileState = this.setProgressPanelFileState.bind(this);
319
+ this.log = this.log.bind(this);
320
+ this.use = this.use.bind(this);
321
+ this.info = this.info.bind(this);
322
+ this.hideInfo = this.hideInfo.bind(this);
323
+ this.addFile = this.addFile.bind(this);
324
+ this.removeFile = this.removeFile.bind(this);
325
+ this.removeUploads = this.removeUploads.bind(this);
326
+ this.pauseResume = this.pauseResume.bind(this);
327
+ this.checkUserPermissions = this.checkUserPermissions.bind(this);
328
+ this.generateUserKey = this.generateUserKey.bind(this);
329
+ this.checkPluginTypeExistence = this.checkPluginTypeExistence.bind(this);
330
+ this.initUserAuthState = this.initUserAuthState.bind(this);
331
+ this.enableSearchDebugging = this.enableSearchDebugging.bind(this);
332
+ this.disableSearchDebugging = this.disableSearchDebugging.bind(this);
333
+ this.isFileRestrictedToGetAdded = this.isFileRestrictedToGetAdded.bind(this);
334
+ window.enableSearchDebugging = this.enableSearchDebugging;
335
+ window.disableSearchDebugging = this.disableSearchDebugging;
336
+ this.updateOnlineStatus = this.updateOnlineStatus.bind(this);
337
+ this.cancelUploads = this.cancelUploads.bind(this);
338
+ this.retryUpload = this.retryUpload.bind(this);
339
+ this.upload = this.upload.bind(this);
340
+ this.pauseAll = this.pauseAll.bind(this);
341
+ this.resumeAll = this.resumeAll.bind(this);
342
+ this.retryAll = this.retryAll.bind(this);
343
+ this.cancelAll = this.cancelAll.bind(this);
344
+ this.emitter = ee();
345
+ this.on = this.on.bind(this);
346
+ this.off = this.off.bind(this);
347
+ this.once = this.emitter.once.bind(this.emitter);
348
+ this.emit = this.emitter.emit.bind(this.emitter);
349
+
350
+ // { process: processingFn, render: renderingFn }
351
+ this.preProcessors = [];
352
+ this.filerobots = [];
353
+ // { process: processingFn, render: renderingFn }
354
+ this.postProcessors = [];
355
+ this._storeInit();
356
+ this._storeUnsubscribe = this.store.subscribe(function () {});
357
+ if (this.opts.sassKeyRenewerEnabled) {
358
+ this._sassKeyRenewerUnsubscribe = this.sassKeyRenewer.subscribe();
359
+ }
360
+
361
+ // Exposing filerobot object on window for debugging and testing
362
+ if (this.opts.debug && typeof window !== 'undefined') {
363
+ window[this.opts.id] = this;
364
+ }
365
+ this.loadBackendTranslations();
366
+ this._addListeners();
367
+ if (!this.opts.sassKey) {
368
+ if (this.opts.securityTemplateId) {
369
+ this.generateUserKey();
370
+ } else {
371
+ if (this.opts.dev) {
372
+ console.warn('Core: `securityTemplateId` property is required if you don\'t want to use login (email&pass) mode. (this warning is shown in development mode only)');
373
+ }
374
+ this.initUserAuthState();
375
+ }
376
+ } else {
377
+ this.initUserAuthState(this.opts.sassKey);
378
+ }
379
+ }
380
+ return _createClass(ScaleflexWidget, [{
381
+ key: "on",
382
+ value: function on(event, callback) {
383
+ this.emitter.on(event, callback);
384
+ return this;
385
+ }
386
+ }, {
387
+ key: "off",
388
+ value: function off(event, callback) {
389
+ this.emitter.off(event, callback);
390
+ return this;
391
+ }
392
+ }, {
393
+ key: "initUserAuthState",
394
+ value: function initUserAuthState(sassKey) {
395
+ if (!sassKey) return this.setCoreCommonState({
396
+ loading: false
397
+ });
398
+ this.dispatch(userInfoUpdated(_objectSpread(_objectSpread({}, this.opts.userInfo), {}, {
399
+ sessionUuid: this.opts.sessionToken
400
+ })));
401
+ return this.dispatch(fetchUserAuthState({
402
+ userSassKey: sassKey
403
+ }));
404
+ }
405
+
406
+ /**
407
+ * Iterate on all plugins and run `update` on them.
408
+ * Called each time state changes.
409
+ *
410
+ */
411
+ }, {
412
+ key: "updateAll",
413
+ value: function updateAll(state) {
414
+ this.iteratePlugins(function (plugin) {
415
+ plugin.update(state);
416
+ });
417
+ }
418
+
419
+ /**
420
+ * creates & assigns the redux store
421
+ *
422
+ */
423
+ }, {
424
+ key: "_storeInit",
425
+ value: function _storeInit() {
426
+ var client = new Client(this, this.opts);
427
+ this.store = createStore(client, [], this);
428
+ this.setCoreCommonState({
429
+ isDevEnv: this.opts.dev
430
+ });
431
+ if (this.opts.sassKeyRenewerEnabled) {
432
+ this.sassKeyRenewer = new SassKeyRenewer(this, client);
433
+ }
434
+ }
435
+
436
+ /**
437
+ * injects a sub-reducer into the root reducer (mostly used for injecting a plugin's reducer)
438
+ *
439
+ */
440
+ }, {
441
+ key: "_injectReducer",
442
+ value: function _injectReducer(key, reducerFn) {
443
+ this.store.injectReducer(key, reducerFn);
444
+ }
445
+
446
+ /**
447
+ * injects a sub-reducer into the root reducer (mostly used for injecting a plugin's reducer)
448
+ *
449
+ */
450
+ }, {
451
+ key: "_removeReducer",
452
+ value: function _removeReducer(key) {
453
+ this.store.removeReducer(key);
454
+ }
455
+
456
+ /**
457
+ * Triggers the action to call store's reducers
458
+ * @param {Function} actionCreator
459
+ */
460
+ }, {
461
+ key: "dispatch",
462
+ value: function dispatch(actionCreator) {
463
+ return this.store.dispatch(actionCreator);
464
+ }
465
+
466
+ /**
467
+ * Updates common state with a patch
468
+ * any state that not organized in a sub-reducer/slice
469
+ *
470
+ * @param {object} patch {foo: 'bar'}
471
+ // * TODO: To check it
472
+ */
473
+ }, {
474
+ key: "setCoreCommonState",
475
+ value: function setCoreCommonState(patch) {
476
+ this.dispatch(coreCommonStateUpdated(patch));
477
+ }
478
+
479
+ /**
480
+ * Returns current state of whole redux's store (global state).
481
+ *
482
+ * @returns {object}
483
+ */
484
+ }, {
485
+ key: "getGlobalState",
486
+ value: function getGlobalState() {
487
+ return this.store.getState();
488
+ }
489
+
490
+ /**
491
+ * Returns current core's slice state.
492
+ *
493
+ * @returns {object}
494
+ */
495
+ }, {
496
+ key: "getCoreState",
497
+ value: function getCoreState() {
498
+ return this.getGlobalState()[PLUGINS_IDS.CORE];
499
+ }
500
+
501
+ /**
502
+ * Returns current core's slice state.
503
+ *
504
+ * @returns {object}
505
+ */
506
+ }, {
507
+ key: "getCoreCommonState",
508
+ value: function getCoreCommonState() {
509
+ return selectCommonState(this.getGlobalState());
510
+ }
511
+
512
+ /**
513
+ * Returns current uploads
514
+ *
515
+ * @returns {object}
516
+ */
517
+ }, {
518
+ key: "getUploadOperations",
519
+ value: function getUploadOperations() {
520
+ return this.uploadOperations;
521
+ }
522
+
523
+ /**
524
+ * Returns current uploads' meta
525
+ *
526
+ * @returns {object}
527
+ */
528
+ }, {
529
+ key: "getUploadCapabilities",
530
+ value: function getUploadCapabilities() {
531
+ return selectUploadCapabilities(this.getGlobalState());
532
+ }
533
+
534
+ /**
535
+ * Returns the current files that will get uploaded
536
+ *
537
+ * @returns {object}
538
+ */
539
+ }, {
540
+ key: "getUploads",
541
+ value: function getUploads() {
542
+ var files = _objectSpread({}, selectUploads(this.getGlobalState()));
543
+ Object.keys(files).forEach(function (fileId) {
544
+ files[fileId] = _objectSpread(_objectSpread({}, files[fileId]), {}, {
545
+ data: ScaleflexWidget.uploadFilesData[fileId]
546
+ });
547
+ });
548
+ return files;
549
+ }
550
+
551
+ /**
552
+ * Returns the current files that will get uploaded in a type of array
553
+ *
554
+ * @returns {Array}
555
+ */
556
+ }, {
557
+ key: "getUploadsArray",
558
+ value: function getUploadsArray() {
559
+ return selectUploadsArray(this.getGlobalState());
560
+ }
561
+ }, {
562
+ key: "setUploadPanelFileState",
563
+ value: function setUploadPanelFileState() {
564
+ // This method is deprecated
565
+ // TODO: remove completely after a while
566
+ this.log('This method is deprecated, please use setFileStateBeforeUpload instead');
567
+ }
568
+ }, {
569
+ key: "setFileState",
570
+ value: function setFileState() {
571
+ // This method is deprecated
572
+ // TODO: remove completely after a while
573
+ this.log('This method is deprecated, please use setFileStateBeforeUpload instead');
574
+ this.setFileStateBeforeUpload.apply(this, arguments);
575
+ }
576
+
577
+ /**
578
+ * Shorthand to set state for a specific file.
579
+ */
580
+ }, {
581
+ key: "setFileStateBeforeUpload",
582
+ value: function setFileStateBeforeUpload(fileId, state) {
583
+ if (!this.getFileBeforeUpload(fileId)) {
584
+ if (this.opts.autoProceed) {
585
+ return;
586
+ }
587
+ throw new Error("Can\u2019t set state for ".concat(fileId, " (the file could have been removed)"));
588
+ }
589
+ var fileState = _objectSpread(_objectSpread({}, state), {}, {
590
+ id: fileId
591
+ });
592
+ if (state.data) {
593
+ ScaleflexWidget.uploadFilesData[fileId] = state.data;
594
+ fileState.data = extractFileDataNoBlob(state.data);
595
+ }
596
+ this.dispatch(uploadUpdated(_objectSpread(_objectSpread({}, fileState), {}, {
597
+ id: fileId
598
+ })));
599
+ }
600
+ }, {
601
+ key: "i18nInit",
602
+ value: function i18nInit() {
603
+ if (!Translator.BACKEND_TRANSLATIONS) {
604
+ var _this$currLngBackendT;
605
+ Translator.BACKEND_TRANSLATIONS = (_this$currLngBackendT = this.currLngBackendTranslations) === null || _this$currLngBackendT === void 0 ? void 0 : _this$currLngBackendT.strings;
606
+ }
607
+ this.translator = new Translator([this.defaultLocale, this.currLngBackendTranslations, this.opts.locale]);
608
+ this.locale = this.translator.locale;
609
+ this.i18n = this.translator.translate.bind(this.translator);
610
+ this.i18nArray = this.translator.translateArray.bind(this.translator);
611
+ }
612
+ }, {
613
+ key: "setOptions",
614
+ value: function setOptions() {
615
+ var newOpts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
616
+ if (typeof newOpts.sassKey !== 'undefined' && newOpts.sassKey !== this.opts.sassKey) {
617
+ var _explorerPlugin$opts;
618
+ var explorerPlugin = this.getPlugin(PLUGINS_IDS.EXPLORER);
619
+ if (!explorerPlugin || !((_explorerPlugin$opts = explorerPlugin.opts) !== null && _explorerPlugin$opts !== void 0 && _explorerPlugin$opts.ExploreViewComponent)) {
620
+ this.dispatch(saveUserSassKey(newOpts.sassKey));
621
+ } else {
622
+ this.initUserAuthState(newOpts.sassKey);
623
+ }
624
+ }
625
+ this.opts = _objectSpread(_objectSpread(_objectSpread({}, this.opts), newOpts), {}, {
626
+ restrictions: _objectSpread(_objectSpread({}, this.opts.restrictions), newOpts && newOpts.restrictions)
627
+ });
628
+ if (newOpts.locale) {
629
+ this.i18nInit();
630
+ }
631
+ if (newOpts.language) {
632
+ this.updateCurrLngBackendTranslations();
633
+ }
634
+ if (typeof newOpts.dev !== 'undefined') {
635
+ this.setCoreCommonState({
636
+ isDevEnv: this.opts.dev
637
+ });
638
+ }
639
+
640
+ // Already the opts object of the plugin is updated, so we need only to emit a new object's reference
641
+ // and handle rerendering in the plugins' providers so that it causes rerender.
642
+ this.emit('opts-updated', this._getInstalledPkgs());
643
+ }
644
+ }, {
645
+ key: "addPreProcessor",
646
+ value: function addPreProcessor(processor) {
647
+ this.preProcessors.push(processor);
648
+ }
649
+ }, {
650
+ key: "removePreProcessor",
651
+ value: function removePreProcessor(processor) {
652
+ var i = this.preProcessors.indexOf(processor);
653
+ if (i !== -1) {
654
+ this.preProcessors.splice(i, 1);
655
+ }
656
+ }
657
+ }, {
658
+ key: "addPostProcessor",
659
+ value: function addPostProcessor(processor) {
660
+ this.postProcessors.push(processor);
661
+ }
662
+ }, {
663
+ key: "removePostProcessor",
664
+ value: function removePostProcessor(processor) {
665
+ var i = this.postProcessors.indexOf(processor);
666
+ if (i !== -1) {
667
+ this.postProcessors.splice(i, 1);
668
+ }
669
+ }
670
+ }, {
671
+ key: "addFilerobot",
672
+ value: function addFilerobot(fn) {
673
+ this.filerobots.push(fn);
674
+ }
675
+ }, {
676
+ key: "removeFilerobot",
677
+ value: function removeFilerobot(fn) {
678
+ var i = this.filerobots.indexOf(fn);
679
+ if (i !== -1) {
680
+ this.filerobots.splice(i, 1);
681
+ }
682
+ }
683
+ }, {
684
+ key: "setFilesInfoMetaTags",
685
+ value: function setFilesInfoMetaTags(_ref2) {
686
+ var filesIds = _ref2.filesIds,
687
+ meta = _ref2.meta,
688
+ tags = _ref2.tags,
689
+ info = _ref2.info,
690
+ tagsForceUpdate = _ref2.tagsForceUpdate;
691
+ return this.dispatch(updateUploadInfoMetaTags({
692
+ filesIds: filesIds,
693
+ meta: meta,
694
+ tags: tags,
695
+ info: info,
696
+ tagsForceUpdate: tagsForceUpdate
697
+ }));
698
+ }
699
+
700
+ /**
701
+ * Get file uploading object.
702
+ *
703
+ * @param {string} fileId The ID of the file object to return.
704
+ */
705
+ }, {
706
+ key: "getFileUploading",
707
+ value: function getFileUploading(fileId) {
708
+ var uploadOperations = this.getUploadOperations();
709
+ var uploadOperationId = Object.keys(uploadOperations).find(function (uploadId) {
710
+ return uploadOperations[uploadId].files[fileId];
711
+ });
712
+ if (!uploadOperationId) {
713
+ return;
714
+ }
715
+ return _objectSpread(_objectSpread({}, uploadOperations[uploadOperationId].files[fileId]), {}, {
716
+ uploadId: uploadOperationId,
717
+ data: ScaleflexWidget.uploadFilesData[fileId]
718
+ });
719
+ }
720
+
721
+ /**
722
+ * Get a file object before upload.
723
+ *
724
+ * @param {string} fileId The ID of the file object to return.
725
+ */
726
+ }, {
727
+ key: "getFileBeforeUpload",
728
+ value: function getFileBeforeUpload(fileId) {
729
+ return selectUploadById(this.getGlobalState(), fileId);
730
+ }
731
+
732
+ /**
733
+ * Check if minNumberOfFiles restriction is reached before uploading.
734
+ *
735
+ * @private
736
+ */
737
+ }, {
738
+ key: "_checkMinNumberOfFiles",
739
+ value: function _checkMinNumberOfFiles(files) {
740
+ var minNumberOfFiles = this.opts.restrictions.minNumberOfFiles;
741
+ if (Object.keys(files).length < minNumberOfFiles) {
742
+ throw new RestrictionError("".concat(this.i18n('filerobotYouHaveToAtLeastSelectXError', {
743
+ smart_count: minNumberOfFiles
744
+ })));
745
+ }
746
+ }
747
+
748
+ /**
749
+ * Check if file passes a set of restrictions set in options: maxFileSize,
750
+ * maxNumberOfFiles and allowedFileTypes.
751
+ *
752
+ * @param {object} files Object of files already added
753
+ * @param {object} file object to check
754
+ * @private
755
+ */
756
+ }, {
757
+ key: "_checkRestrictions",
758
+ value: function _checkRestrictions(files, file) {
759
+ var _this3 = this,
760
+ _file$data;
761
+ var dontCheckFileType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
762
+ var customUploadedFilesSizeInMb = this.opts.customUploadedFilesSizeInMb;
763
+ var _this$opts$restrictio = this.opts.restrictions,
764
+ maxFileSize = _this$opts$restrictio.maxFileSize,
765
+ maxNumberOfFiles = _this$opts$restrictio.maxNumberOfFiles,
766
+ allowedFileTypes = _this$opts$restrictio.allowedFileTypes,
767
+ maxTotalFilesSize = _this$opts$restrictio.maxTotalFilesSize;
768
+ var _selectUserSecurityDa = selectUserSecurityData(this.getGlobalState()),
769
+ _selectUserSecurityDa2 = _selectUserSecurityDa.upload_scope,
770
+ allowedFoldersToUploadTo = _selectUserSecurityDa2 === void 0 ? this.opts.userFoldersScope : _selectUserSecurityDa2;
771
+ if (allowedFoldersToUploadTo && allowedFoldersToUploadTo.length > 0) {
772
+ this.plugins.uploader.forEach(function (plugin) {
773
+ var folderPath = (file.toFolder || plugin.opts.uploadToFolderPath || selectCurrentFolderPath(_this3.getGlobalState()) || '').toLowerCase().replace(/\/$/, '') || '/';
774
+ var foundAllowedFolderScope = allowedFoldersToUploadTo.some(function (f) {
775
+ var folderNameWithNoSlashStar = f.toLowerCase().replace(/\/\*?$/, '');
776
+ if (folderPath === folderNameWithNoSlashStar || f.endsWith('/*') && folderPath.includes("".concat(folderNameWithNoSlashStar, "/"))) {
777
+ return true;
778
+ }
779
+ return false;
780
+ });
781
+ if (!foundAllowedFolderScope) {
782
+ throw new RestrictionError("".concat(_this3.i18n('filerobotFolderUploadingNotAllowedError', {
783
+ folder: folderPath
784
+ })));
785
+ }
786
+ });
787
+ }
788
+ if (!this.checkUserPermissions([PERMISSIONS.UPLOAD])) {
789
+ throw new Error("".concat(this.i18n('filerobotInvalidPermissionError')));
790
+ }
791
+ if (typeof maxNumberOfFiles === 'number') {
792
+ if (Object.keys(files).length + 1 > maxNumberOfFiles) {
793
+ throw new RestrictionError("".concat(this.i18n('filerobotYouCanOnlyUploadXError', {
794
+ smart_count: maxNumberOfFiles
795
+ })));
796
+ }
797
+ }
798
+ if (!dontCheckFileType && allowedFileTypes) {
799
+ var fileType = file.type || file.mimeType;
800
+ var isCorrectFileType = allowedFileTypes.some(function (type) {
801
+ var _file$extension;
802
+ // is this is a mime-type
803
+ if (type.indexOf('/') > -1) {
804
+ if (!fileType) return false;
805
+ return match(fileType.replace(/;.*?$/, ''), type);
806
+ }
807
+
808
+ // otherwise this is likely an extension
809
+ var fileExtension = type[0] === '.' && ((_file$extension = file.extension) !== null && _file$extension !== void 0 ? _file$extension : getFileExtension(file));
810
+ if (fileExtension) {
811
+ return fileExtension.toLowerCase() === type.substr(1).toLowerCase();
812
+ }
813
+ return false;
814
+ });
815
+ if (!isCorrectFileType) {
816
+ var allowedFileTypesString = allowedFileTypes.join(', ');
817
+ throw new RestrictionError(this.i18n('filerobotYouCanOnlyUploadFileTypesError', {
818
+ types: allowedFileTypesString
819
+ }));
820
+ }
821
+ }
822
+
823
+ // We can't check maxFileSize if the size is unknown.
824
+ var fileSize = ((_file$data = file.data) === null || _file$data === void 0 ? void 0 : _file$data.size) || file.size;
825
+ if (maxTotalFilesSize) {
826
+ var totalFilesSize = [].concat(_toConsumableArray(Object.values(files)), [file]).reduce(function (totalSize, file) {
827
+ var _file$data2;
828
+ totalSize += ((_file$data2 = file.data) === null || _file$data2 === void 0 ? void 0 : _file$data2.size) || file.size || 0;
829
+ return totalSize;
830
+ }, 0);
831
+ if (convertBytesToMb(totalFilesSize) + customUploadedFilesSizeInMb > maxTotalFilesSize) {
832
+ throw new RestrictionError(this.i18n('filerobotFilesExceedsSizeError', {
833
+ size: maxTotalFilesSize
834
+ }));
835
+ }
836
+ }
837
+ if (maxFileSize && fileSize != null) {
838
+ if (fileSize > maxFileSize) {
839
+ throw new RestrictionError(this.i18n('filerobotExceedsSizeError', {
840
+ size: prettierBytes(maxFileSize)
841
+ }));
842
+ }
843
+ }
844
+ }
845
+
846
+ /**
847
+ * Logs an error, sets Informer message, then throws the error.
848
+ * Emits a 'restriction-failed' event if it’s a restriction error
849
+ *
850
+ * @param {object | string} err — Error object or plain string message
851
+ * @param {object} [options]
852
+ * @param {boolean} [options.showInformer=true] — Sometimes developer might want to show Informer manually
853
+ * @param {object} [options.file=null] — File object used to emit the restriction error
854
+ * @param {boolean} [options.throwErr=true] — Errors shouldn’t be thrown, for example, in `upload-error` event
855
+ * @private
856
+ */
857
+ }, {
858
+ key: "_showOrLogErrorAndThrow",
859
+ value: function _showOrLogErrorAndThrow(err) {
860
+ var _ref3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
861
+ _ref3$showInformer = _ref3.showInformer,
862
+ showInformer = _ref3$showInformer === void 0 ? true : _ref3$showInformer,
863
+ _ref3$file = _ref3.file,
864
+ file = _ref3$file === void 0 ? null : _ref3$file,
865
+ _ref3$throwErr = _ref3.throwErr,
866
+ throwErr = _ref3$throwErr === void 0 ? true : _ref3$throwErr;
867
+ var message = _typeof(err) === 'object' ? err.message : err;
868
+ var details = _typeof(err) === 'object' && err.details ? err.details : '';
869
+ var hideRestrictionsInformer = this.opts.restrictions.hideRestrictionsInformer;
870
+
871
+ // Restriction errors should be logged, but not as errors,
872
+ // as they are expected and shown in the UI.
873
+ var logMessageWithDetails = message;
874
+ if (details) {
875
+ logMessageWithDetails += ' ' + details;
876
+ }
877
+ if (err.isRestriction) {
878
+ this.log(logMessageWithDetails);
879
+ this.emit('restriction-failed', file, err);
880
+ } else {
881
+ this.log(logMessageWithDetails, 'error');
882
+ }
883
+
884
+ // Sometimes informer has to be shown manually by the developer,
885
+ // for example, in `onBeforeFileAdded`.
886
+ if (showInformer && !hideRestrictionsInformer) {
887
+ this.info({
888
+ message: message,
889
+ details: details
890
+ }, 'error', 5000);
891
+ }
892
+ if (throwErr) {
893
+ throw _typeof(err) === 'object' ? err : new Error(err);
894
+ }
895
+ }
896
+ }, {
897
+ key: "_assertNewUploadAllowed",
898
+ value: function _assertNewUploadAllowed(file) {
899
+ var _this$getUploadCapabi = this.getUploadCapabilities(),
900
+ allowNewUpload = _this$getUploadCapabi.allowNewUpload;
901
+ if (allowNewUpload === false) {
902
+ this._showOrLogErrorAndThrow(new RestrictionError(this.i18n('filerobotNoNewAlreadyUploadingError')), {
903
+ file: file
904
+ });
905
+ }
906
+ }
907
+
908
+ /**
909
+ * Create a file state object based on user-provided `addFile()` options.
910
+ *
911
+ * Note this is extremely side-effectful and should only be done when a file state object will be added to state immediately afterward!
912
+ *
913
+ * The `files` value is passed in because it may be updated by the caller without updating the store.
914
+ */
915
+ }, {
916
+ key: "_checkAndCreateFileStateObject",
917
+ value: function _checkAndCreateFileStateObject(files, checkedFile) {
918
+ var _file$data3, _file$data4;
919
+ var fileType = getFileType(checkedFile);
920
+ var file = _objectSpread(_objectSpread({}, checkedFile), {}, {
921
+ type: fileType
922
+ });
923
+ var onBeforeFileAddedResult = this.opts.onBeforeFileAdded(file, files);
924
+ if (onBeforeFileAddedResult === false) {
925
+ // Don’t show UI info for this error, as it should be done by the developer
926
+ this._showOrLogErrorAndThrow(new RestrictionError('Cannot add the file because onBeforeFileAdded returned false.'), {
927
+ showInformer: false,
928
+ file: file
929
+ });
930
+ }
931
+ if (_typeof(onBeforeFileAddedResult) === 'object' && onBeforeFileAddedResult) {
932
+ file = onBeforeFileAddedResult;
933
+ }
934
+ var fileName;
935
+ if (file.name) {
936
+ fileName = file.name;
937
+ } else if (fileType.split('/')[0] === 'image') {
938
+ fileName = fileType.split('/')[0] + '.' + fileType.split('/')[1];
939
+ } else {
940
+ fileName = 'noname';
941
+ }
942
+ var fileExtension = getFileNameAndExtension(fileName, fileType).extension;
943
+ var isRemote = file.isRemote || false;
944
+ var fileId = generateFileId(file);
945
+ if (files[fileId]) {
946
+ this._showOrLogErrorAndThrow(new RestrictionError(this.i18n('filerobotNoDuplicatesError', {
947
+ fileName: fileName
948
+ })), {
949
+ file: file
950
+ });
951
+ }
952
+ var fileInfo = file.info || {};
953
+ fileInfo.name = fileName;
954
+ fileInfo.type = fileType;
955
+ // `null` means the size is unknown.
956
+ var size = isFinite((_file$data3 = file.data) === null || _file$data3 === void 0 ? void 0 : _file$data3.size) ? (_file$data4 = file.data) === null || _file$data4 === void 0 ? void 0 : _file$data4.size : null;
957
+ var newFile = {
958
+ source: file.source || '',
959
+ id: fileId,
960
+ name: fileName,
961
+ extension: fileExtension || '',
962
+ info: fileInfo,
963
+ meta: file.meta || {},
964
+ product: file.product || {},
965
+ type: fileType,
966
+ blob: file.data instanceof File || file.data instanceof Blob ? URL.createObjectURL(file.data) : null,
967
+ data: extractFileDataNoBlob(file.data),
968
+ progress: {
969
+ type: PROGRESS_PANEL_ACTIVITY.UPLOAD,
970
+ percentage: 0,
971
+ bytesFinished: 0,
972
+ bytesTotal: size,
973
+ startedAt: null,
974
+ status: FILE_UPLOAD_STATUS.PREPARING
975
+ },
976
+ size: size,
977
+ isRemote: isRemote,
978
+ remote: file.remote || '',
979
+ preview: file.preview,
980
+ toFolder: file.toFolder || selectCurrentFolderPath(this.getGlobalState()),
981
+ xhrQueryParams: file.xhrQueryParams,
982
+ xhrHeaders: file.xhrHeaders,
983
+ uploadStep: true,
984
+ visibility: file.visibility,
985
+ uploadUrl: file.uploadUrl,
986
+ currentUploadId: file.currentUploadId
987
+ };
988
+ try {
989
+ this._checkRestrictions(files, newFile);
990
+ } catch (err) {
991
+ this._showOrLogErrorAndThrow(err, {
992
+ file: newFile
993
+ });
994
+ }
995
+ if (file.data) {
996
+ ScaleflexWidget.uploadFilesData[newFile.id] = file.data;
997
+ }
998
+ return newFile;
999
+ }
1000
+
1001
+ /**
1002
+ * check if file is available and if not it will throw an error
1003
+ *
1004
+ * @param {string} error — Error message
1005
+ * @param {object} file — File object
1006
+ * @private
1007
+ */
1008
+ }, {
1009
+ key: "_checkIfFileIsAvailable",
1010
+ value: function _checkIfFileIsAvailable(file, error) {
1011
+ if (!file) {
1012
+ throw new Error(error);
1013
+ }
1014
+ }
1015
+ }, {
1016
+ key: "isFileRestrictedToGetAdded",
1017
+ value: function isFileRestrictedToGetAdded(files, file) {
1018
+ var dontCheckFileType = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
1019
+ try {
1020
+ this._checkRestrictions(files, file, dontCheckFileType);
1021
+ return false;
1022
+ } catch (err) {
1023
+ this._showOrLogErrorAndThrow(err, {
1024
+ file: file,
1025
+ throwErr: false
1026
+ });
1027
+ return true;
1028
+ }
1029
+ }
1030
+
1031
+ // Schedule an upload if `autoProceed` is enabled.
1032
+ }, {
1033
+ key: "_startIfAutoProceed",
1034
+ value: function _startIfAutoProceed() {
1035
+ var _this4 = this;
1036
+ var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
1037
+ _ref4$forceAutoProcee = _ref4.forceAutoProceed,
1038
+ forceAutoProceed = _ref4$forceAutoProcee === void 0 ? false : _ref4$forceAutoProcee,
1039
+ onUpload = _ref4.onUpload,
1040
+ newFile = _ref4.newFile,
1041
+ newFiles = _ref4.newFiles;
1042
+ if ((this.opts.autoProceed || forceAutoProceed) && !this.scheduledAutoProceed) {
1043
+ this.scheduledAutoProceed = setTimeout(function () {
1044
+ _this4.scheduledAutoProceed = null;
1045
+ _this4.upload()["catch"](function (err) {
1046
+ if (!err.isRestriction) {
1047
+ _this4.log(err.stack || err.message || err);
1048
+ }
1049
+ });
1050
+ if (typeof onUpload === 'function') {
1051
+ onUpload(newFile);
1052
+ }
1053
+ if (_this4.opts.autoProceed && Array.isArray(newFiles) && newFiles.length > 0) {
1054
+ var explorerInstance = _this4.getPlugin(PLUGINS_IDS.EXPLORER);
1055
+ if (explorerInstance) {
1056
+ explorerInstance.triggerProgressPanelActivities(newFiles);
1057
+ }
1058
+ }
1059
+ }, 4);
1060
+ }
1061
+ }
1062
+
1063
+ /**
1064
+ * Add a new file to `state.files`. This will run `onBeforeFileAdded`,
1065
+ * try to guess file type in a clever way, check file against restrictions,
1066
+ * and start an upload if `autoProceed === true`.
1067
+ *
1068
+ * @param {object} file object to add
1069
+ * @returns {string} id for the added file
1070
+ */
1071
+ }, {
1072
+ key: "addFile",
1073
+ value: function addFile(file) {
1074
+ var forceAutoProceed = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1075
+ var onUpload = arguments.length > 2 ? arguments[2] : undefined;
1076
+ var fileExtension = getFileNameAndExtension(file.name, file.type).extension;
1077
+ var isRestrictedFileExtension = RESTRICTED_FILES_EXTENISONS.includes(fileExtension);
1078
+ if (isRestrictedFileExtension) {
1079
+ return this.info({
1080
+ message: this.i18n('filerobotRestrictedFileError', {
1081
+ file_extension: fileExtension
1082
+ })
1083
+ }, 'error', 5000);
1084
+ }
1085
+ this._assertNewUploadAllowed(file);
1086
+ var files = this.getUploads();
1087
+ var newFile = this._checkAndCreateFileStateObject(files, file);
1088
+ this.dispatch(uploadsAdded({
1089
+ files: [newFile],
1090
+ skipOpenUploadsPanel: forceAutoProceed
1091
+ }));
1092
+ this.emit('file-added', _objectSpread(_objectSpread({}, newFile), {}, {
1093
+ data: ScaleflexWidget.uploadFilesData[newFile.id]
1094
+ }));
1095
+ this.log("Added file: ".concat(newFile.name, ", ").concat(newFile.id, ", mime type: ").concat(newFile.type));
1096
+ this._startIfAutoProceed({
1097
+ forceAutoProceed: forceAutoProceed,
1098
+ onUpload: onUpload,
1099
+ newFile: newFile
1100
+ });
1101
+ return newFile.id;
1102
+ }
1103
+
1104
+ /**
1105
+ * Add multiple files to `state.files`. See the `addFile()` documentation.
1106
+ *
1107
+ * This cuts some corners for performance, so should typically only be used in cases where there may be a lot of files.
1108
+ *
1109
+ * If an error occurs while adding a file, it is logged and the user is notified. This is good for UI plugins, but not for programmatic use. Programmatic users should usually still use `addFile()` on individual files.
1110
+ */
1111
+ }, {
1112
+ key: "addFiles",
1113
+ value: function addFiles(fileDescriptors, forceAutoProceed, _onUpload) {
1114
+ var _this5 = this;
1115
+ var _fileDescriptors = fileDescriptors.filter(function (_ref5) {
1116
+ var name = _ref5.name;
1117
+ return !RESTRICTED_FILES_EXTENISONS.includes(getFileNameAndExtension(name).extension);
1118
+ });
1119
+ this._assertNewUploadAllowed();
1120
+
1121
+ // create a copy of the files object only once
1122
+ var currentAndNewPassedFiles = this.getUploads();
1123
+ var newFiles = [];
1124
+ var errors = [];
1125
+ for (var i = 0; i < _fileDescriptors.length; i++) {
1126
+ try {
1127
+ var newFile = this._checkAndCreateFileStateObject(currentAndNewPassedFiles, _fileDescriptors[i]);
1128
+ newFiles.push(newFile);
1129
+ // We are adding the passed files into the object in every loop step, for considering them in the restrictions counts.
1130
+ currentAndNewPassedFiles[newFile.id] = newFile;
1131
+ } catch (err) {
1132
+ if (!err.isRestriction) {
1133
+ errors.push(err);
1134
+ }
1135
+ }
1136
+ }
1137
+ this.dispatch(uploadsAdded({
1138
+ files: newFiles,
1139
+ skipOpenUploadsPanel: forceAutoProceed
1140
+ }));
1141
+ newFiles.forEach(function (newFile) {
1142
+ _this5.emit('file-added', _objectSpread(_objectSpread({}, newFile), {}, {
1143
+ data: ScaleflexWidget.uploadFilesData[newFile.id]
1144
+ }));
1145
+ });
1146
+ if (newFiles.length > 5) {
1147
+ this.log("Added batch of ".concat(newFiles.length, " files"));
1148
+ } else {
1149
+ newFiles.forEach(function (file) {
1150
+ _this5.log("Added file: ".concat(file.name, "\n id: ").concat(file.id, "\n type: ").concat(file.type));
1151
+ });
1152
+ }
1153
+ if (newFiles.length > 0) {
1154
+ this._startIfAutoProceed({
1155
+ forceAutoProceed: forceAutoProceed,
1156
+ onUpload: function onUpload() {
1157
+ return _onUpload && _onUpload(newFiles);
1158
+ },
1159
+ newFiles: newFiles
1160
+ });
1161
+ }
1162
+ if (errors.length > 0) {
1163
+ var message = 'Multiple errors occurred while adding files:\n';
1164
+ errors.forEach(function (subError) {
1165
+ message += "\n * ".concat(subError.message);
1166
+ });
1167
+ this.info({
1168
+ message: this.i18n('addBulkFilesFailedMessage', {
1169
+ smart_count: errors.length
1170
+ }),
1171
+ details: message
1172
+ }, 'error', 5000);
1173
+ var err = new Error(message);
1174
+ err.errors = errors;
1175
+ throw err;
1176
+ }
1177
+ }
1178
+ }, {
1179
+ key: "removeUploads",
1180
+ value: function removeUploads(filesIds) {
1181
+ this.dispatch(uploadsRemoved(filesIds));
1182
+ }
1183
+ }, {
1184
+ key: "removeFile",
1185
+ value: function removeFile(fileId) {
1186
+ var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
1187
+ var fileBeforeRemove = this.getFileUploading(fileId);
1188
+ if (!fileBeforeRemove) {
1189
+ throw new Error("Can\u2019t remove ".concat(fileId, " (the file could have been removed)"));
1190
+ }
1191
+ var uploadOperationId = fileBeforeRemove.uploadId;
1192
+ var currentUploadOperation = this.uploadOperations[uploadOperationId];
1193
+ var notRemovedFileIds = function notRemovedFileIds(uploadFileId) {
1194
+ return uploadFileId !== fileId;
1195
+ };
1196
+ if (currentUploadOperation && uploadOperationId) {
1197
+ var newFileIds = currentUploadOperation.filesIds.filter(notRemovedFileIds);
1198
+ delete currentUploadOperation.files[fileId];
1199
+ delete ScaleflexWidget.uploadFilesData[fileId];
1200
+ this.emit('file-removed', fileBeforeRemove, reason);
1201
+ this.log("Removed file: ".concat(fileId));
1202
+ if (newFileIds.length === 0) {
1203
+ delete this.uploadOperations[uploadOperationId];
1204
+ return;
1205
+ }
1206
+ this.uploadOperations[uploadOperationId] = _objectSpread(_objectSpread({}, currentUploadOperation), {}, {
1207
+ filesIds: newFileIds
1208
+ });
1209
+ }
1210
+ }
1211
+ }, {
1212
+ key: "pauseResume",
1213
+ value: function pauseResume(fileId) {
1214
+ if (!this.getUploadCapabilities().allowResumableUploads) {
1215
+ return;
1216
+ }
1217
+ var file = this.getFileUploading(fileId);
1218
+ this._checkIfFileIsAvailable(file, "can't pause or resume for a file that has been removed: ".concat(fileId));
1219
+ var wasPaused = file.progress.status === FILE_UPLOAD_STATUS.PAUSED || false;
1220
+ var isPaused = !wasPaused;
1221
+ var status = isPaused ? FILE_UPLOAD_STATUS.PAUSED : FILE_UPLOAD_STATUS.PROGRESSING;
1222
+ this.emit('activity-update', {
1223
+ id: file.id,
1224
+ progress: {
1225
+ status: status
1226
+ }
1227
+ });
1228
+ this.setFileUploadingState(fileId, file.uploadId, {
1229
+ progress: _objectSpread(_objectSpread({}, file.progress), {}, {
1230
+ status: status
1231
+ })
1232
+ });
1233
+ this.emit('upload-pause', fileId, isPaused);
1234
+ }
1235
+ }, {
1236
+ key: "pauseAll",
1237
+ value: function pauseAll() {
1238
+ // This method is deprecated
1239
+ // TODO: remove completely after a while
1240
+ this.log('This method is deprecated');
1241
+ }
1242
+ }, {
1243
+ key: "resumeAll",
1244
+ value: function resumeAll() {
1245
+ // This method is deprecated
1246
+ // TODO: remove completely after a while
1247
+ this.log('This method is deprecated');
1248
+ }
1249
+ }, {
1250
+ key: "retryAll",
1251
+ value: function retryAll() {
1252
+ // This method is deprecated
1253
+ // TODO: remove completely after a while
1254
+ this.log('This method is deprecated');
1255
+ }
1256
+ }, {
1257
+ key: "cancelAll",
1258
+ value: function cancelAll() {
1259
+ // This method is deprecated
1260
+ // TODO: remove completely after a while
1261
+ this.log('This method is deprecated');
1262
+ }
1263
+ }, {
1264
+ key: "cancelUploads",
1265
+ value: function cancelUploads() {
1266
+ this.emit('cancel-uploads');
1267
+ this.uploadOperations = {};
1268
+ this.dispatch(allUploadsCancelled({
1269
+ capabilities: {
1270
+ allowResumableUploads: Boolean(this.getPlugin(PLUGINS_IDS.TUS))
1271
+ }
1272
+ }));
1273
+ }
1274
+ }, {
1275
+ key: "retryUpload",
1276
+ value: function retryUpload(fileId, fallbackFile) {
1277
+ var file = this.getFileUploading(fileId);
1278
+ if (!file && fallbackFile) {
1279
+ return this.retryRemovedUpload(fallbackFile);
1280
+ }
1281
+ this._checkIfFileIsAvailable(file, "can't retry a file that has been removed: ".concat(fileId));
1282
+ this.setFileUploadingState(fileId, file.uploadId, {
1283
+ error: null
1284
+ });
1285
+ this.emit('upload-retry', fileId);
1286
+ return this._runUploadOperation(file.uploadId);
1287
+ }
1288
+ }, {
1289
+ key: "retryRemovedUpload",
1290
+ value: function retryRemovedUpload(file) {
1291
+ if (!file || _typeof(file) !== 'object') {
1292
+ return;
1293
+ }
1294
+ this.emit('upload-retry', file.id);
1295
+ return this.upload(_defineProperty({}, file.id, file));
1296
+ }
1297
+
1298
+ /**
1299
+ * Registers listeners for all global actions, like:
1300
+ * `error`, `file-removed`, `upload-progress`
1301
+ */
1302
+ }, {
1303
+ key: "_addListeners",
1304
+ value: function _addListeners() {
1305
+ var _this6 = this;
1306
+ this.on('error', function (filesIds, error, _ref6) {
1307
+ var uploadId = _ref6.uploadId;
1308
+ var errorMsg = 'Unknown error';
1309
+ if (error.message) {
1310
+ errorMsg = error.message;
1311
+ }
1312
+ if (error.details) {
1313
+ errorMsg += ' ' + error.details;
1314
+ }
1315
+ filesIds.forEach(function (fileId) {
1316
+ var file = _this6.getFileUploading(fileId);
1317
+ _this6.setFileUploadingState(fileId, uploadId, {
1318
+ progress: _objectSpread(_objectSpread({}, file.progress), {}, {
1319
+ status: FILE_UPLOAD_STATUS.ERROR
1320
+ }),
1321
+ error: errorMsg
1322
+ });
1323
+ _this6.emit('activity-error', {
1324
+ id: file.id,
1325
+ error: errorMsg
1326
+ });
1327
+ });
1328
+ });
1329
+
1330
+ // show informer if offline
1331
+ if (typeof window !== 'undefined' && window.addEventListener) {
1332
+ window.addEventListener('online', function () {
1333
+ return _this6.updateOnlineStatus();
1334
+ });
1335
+ window.addEventListener('offline', function () {
1336
+ return _this6.updateOnlineStatus();
1337
+ });
1338
+ setTimeout(function () {
1339
+ return _this6.updateOnlineStatus();
1340
+ }, 3000);
1341
+ }
1342
+ }
1343
+ }, {
1344
+ key: "updateOnlineStatus",
1345
+ value: function updateOnlineStatus() {
1346
+ var isOnline = checkConnection();
1347
+ if (!isOnline) {
1348
+ this.emit('is-offline');
1349
+ this.info(this.i18n('filerobotNoInternetConnectionInfo'), 'error', 5000);
1350
+ this.wasOffline = true;
1351
+ } else {
1352
+ this.emit('is-online');
1353
+ if (this.wasOffline) {
1354
+ this.emit('back-online');
1355
+ this.info(this.i18n('filerobotConnectedToInternetInfo'), 'success', 3000);
1356
+ this.wasOffline = false;
1357
+ }
1358
+ }
1359
+ }
1360
+ }, {
1361
+ key: "generateUserKey",
1362
+ value: function generateUserKey() {
1363
+ return this.dispatch(_generateUserKey());
1364
+ }
1365
+ }, {
1366
+ key: "checkUserPermissions",
1367
+ value: function checkUserPermissions() {
1368
+ var _this7 = this;
1369
+ var permissionsToCheck = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
1370
+ var showMsg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1371
+ var state = this.getGlobalState();
1372
+ var permissions = selectUserPermissions(state);
1373
+ var loading = selectCoreLoading(state);
1374
+ var isSasskeyGenerated = !!selectUserSassKey(state);
1375
+ if (Object.keys(permissions).length === 0 && isSasskeyGenerated) {
1376
+ if (!loading) {
1377
+ // Show warning only when permissions are missing after core loading
1378
+ setTimeout(function () {
1379
+ _this7.info(_this7.i18n('filerobotNoPermissionsInfo'), 'error', 5000);
1380
+ }, 0);
1381
+ }
1382
+ return false;
1383
+ }
1384
+ var areAllPermissionsValid = !permissionsToCheck.some(function (permission) {
1385
+ return permission && !permissions[permission];
1386
+ });
1387
+ if (showMsg && !areAllPermissionsValid) {
1388
+ this.info(this.i18n('filerobotInvalidPermissionError'), 'error', 4000);
1389
+ return false;
1390
+ }
1391
+ return areAllPermissionsValid;
1392
+ }
1393
+ }, {
1394
+ key: "getId",
1395
+ value: function getId() {
1396
+ return this.opts.id;
1397
+ }
1398
+
1399
+ /**
1400
+ * Registers a plugin with Core.
1401
+ *
1402
+ * @param {object} Plugin object
1403
+ * @param {object} [opts] object with options to be passed to Plugin
1404
+ * @returns {object} self for chaining
1405
+ */
1406
+ }, {
1407
+ key: "use",
1408
+ value: function use(Plugin, opts) {
1409
+ if (typeof Plugin !== 'function') {
1410
+ var msg = "Expected a plugin class, but got ".concat(Plugin === null ? 'null' : _typeof(Plugin), ".") + ' Please verify that the plugin was imported and spelled correctly.';
1411
+ throw new TypeError(msg);
1412
+ }
1413
+
1414
+ // Instantiate
1415
+ var plugin = new Plugin(this, opts);
1416
+ var pluginId = plugin.id;
1417
+ this.plugins[plugin.type] = this.plugins[plugin.type] || [];
1418
+ if (!pluginId) {
1419
+ throw new Error('Your plugin must have an id');
1420
+ }
1421
+ if (!plugin.type) {
1422
+ throw new Error('Your plugin must have a type');
1423
+ }
1424
+ var existsPluginAlready = this.getPlugin(pluginId);
1425
+ if (existsPluginAlready) {
1426
+ var _msg = "Already found a plugin named '".concat(existsPluginAlready.id, "'. ") + "Tried to use: '".concat(pluginId, "'.\n") + 'filerobot plugins must have unique `id` options.';
1427
+ throw new Error(_msg);
1428
+ }
1429
+ if (Plugin.VERSION) {
1430
+ this.log("Using ".concat(pluginId, " v").concat(Plugin.VERSION));
1431
+ }
1432
+ var pluginReducer = plugin.getPluginReducer();
1433
+ if (typeof pluginReducer === 'function') {
1434
+ this._injectReducer(pluginId, pluginReducer);
1435
+ }
1436
+ this.plugins[plugin.type].push(plugin);
1437
+ plugin.install();
1438
+ this.emit('plugins-updated', this._getInstalledPkgs());
1439
+ return this;
1440
+ }
1441
+
1442
+ /**
1443
+ * Find one Plugin by name.
1444
+ *
1445
+ * @param {string} id plugin id
1446
+ * @returns {object|boolean}
1447
+ */
1448
+ }, {
1449
+ key: "getPlugin",
1450
+ value: function getPlugin(id) {
1451
+ var foundPlugin = null;
1452
+ this.iteratePlugins(function (plugin) {
1453
+ if (plugin.id === id) {
1454
+ foundPlugin = plugin;
1455
+ return false;
1456
+ }
1457
+ });
1458
+ return foundPlugin;
1459
+ }
1460
+
1461
+ /**
1462
+ * Get all the pre-processor plugins
1463
+ *
1464
+ * @returns array
1465
+ */
1466
+ }, {
1467
+ key: "getPreProcessors",
1468
+ value: function getPreProcessors() {
1469
+ return this.preProcessors;
1470
+ }
1471
+
1472
+ /**
1473
+ * Get all the post-processor plugins
1474
+ *
1475
+ * @returns array
1476
+ */
1477
+ }, {
1478
+ key: "getPostProcessors",
1479
+ value: function getPostProcessors() {
1480
+ return this.postProcessors;
1481
+ }
1482
+
1483
+ /**
1484
+ * Iterate through all `use`d plugins.
1485
+ *
1486
+ * @param {Function} method that will be run on each plugin
1487
+ */
1488
+ }, {
1489
+ key: "iteratePlugins",
1490
+ value: function iteratePlugins(method) {
1491
+ var _this8 = this;
1492
+ Object.keys(this.plugins).forEach(function (pluginType) {
1493
+ _this8.plugins[pluginType].forEach(method);
1494
+ });
1495
+ }
1496
+ }, {
1497
+ key: "checkPluginTypeExistence",
1498
+ value: function checkPluginTypeExistence() {
1499
+ var pluginTypeToCheck = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
1500
+ var pluginTypeLoweredCase = pluginTypeToCheck.toLowerCase();
1501
+ if (!pluginTypeLoweredCase) {
1502
+ return;
1503
+ }
1504
+ return Object.keys(this.plugins).includes(pluginTypeLoweredCase) && this.plugins[pluginTypeLoweredCase].length > 0;
1505
+ }
1506
+ }, {
1507
+ key: "checkPluginExistence",
1508
+ value: function checkPluginExistence() {
1509
+ var pluginIdToCheck = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
1510
+ if (!pluginIdToCheck) {
1511
+ return;
1512
+ }
1513
+ return Boolean(this.getPlugin(pluginIdToCheck));
1514
+ }
1515
+
1516
+ /**
1517
+ * Uninstall and remove a plugin.
1518
+ *
1519
+ * @param {object} instance The plugin instance to remove.
1520
+ */
1521
+ }, {
1522
+ key: "removePlugin",
1523
+ value: function removePlugin(instance) {
1524
+ this.log("Removing plugin ".concat(instance.id));
1525
+ if (instance.uninstall) {
1526
+ instance.uninstall();
1527
+ }
1528
+ var list = this.plugins[instance.type].slice();
1529
+ var index = list.indexOf(instance);
1530
+ if (index !== -1) {
1531
+ list.splice(index, 1);
1532
+ this._removeReducer(instance.id);
1533
+ this.plugins[instance.type] = list;
1534
+ }
1535
+ this.emit('plugin-remove', instance);
1536
+ this.emit('plugins-updated', this._getInstalledPkgs());
1537
+ }
1538
+
1539
+ /**
1540
+ * Uninstall all plugins and close down this filerobot instance.
1541
+ */
1542
+ }, {
1543
+ key: "close",
1544
+ value: function close() {
1545
+ var _this9 = this;
1546
+ this.log("Closing filerobot instance ".concat(this.opts.id, ": removing all files and uninstalling plugins"));
1547
+ this._storeUnsubscribe();
1548
+ if (this.opts.sassKeyRenewerEnabled) {
1549
+ this._sassKeyRenewerUnsubscribe();
1550
+ }
1551
+ this.iteratePlugins(function (plugin) {
1552
+ _this9.removePlugin(plugin);
1553
+ });
1554
+ }
1555
+
1556
+ /**
1557
+ * Set info message in `state.info`, so that UI plugins like `Informer`
1558
+ * can display the message.
1559
+ *
1560
+ * @param {string | object} message Message to be displayed by the informer
1561
+ * @param {string} [type]
1562
+ * @param {number} [duration]
1563
+ */
1564
+ }, {
1565
+ key: "info",
1566
+ value: function info(message) {
1567
+ var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'info';
1568
+ var duration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3000;
1569
+ // Avoid showing aborted/cancelled request feedback to the user.
1570
+ if (message === ABORTED_ERROR || message === (ABORTED_ERROR === null || ABORTED_ERROR === void 0 ? void 0 : ABORTED_ERROR.message)) {
1571
+ return;
1572
+ }
1573
+ var isComplexMessage = _typeof(message) === 'object';
1574
+ var toStringIfObj = function toStringIfObj(data) {
1575
+ return _typeof(data) === 'object' ? data.toString() : data;
1576
+ };
1577
+ this.dispatch(infoSet({
1578
+ isHidden: false,
1579
+ type: type,
1580
+ message: isComplexMessage ? toStringIfObj(message.message) : message,
1581
+ details: isComplexMessage ? toStringIfObj(message.details) : null,
1582
+ errors: message.errors
1583
+ }));
1584
+ this.emit('info-visible');
1585
+ clearTimeout(this.infoTimeoutId);
1586
+ if (duration === 0) {
1587
+ this.infoTimeoutId = undefined;
1588
+ return;
1589
+ }
1590
+
1591
+ // hide the informer after `duration` milliseconds
1592
+ this.infoTimeoutId = setTimeout(this.hideInfo, duration);
1593
+ }
1594
+ }, {
1595
+ key: "hideInfo",
1596
+ value: function hideInfo() {
1597
+ this.dispatch(infoHid());
1598
+ this.emit('info-hidden');
1599
+ }
1600
+
1601
+ /**
1602
+ * Passes messages to a function, provided in `opts.logger`.
1603
+ * If `opts.logger: filerobot.debugLogger` or `opts.debug: true`, logs to the browser console.
1604
+ *
1605
+ * @param {string|object} message to log
1606
+ * @param {string} [type] optional `error` or `warning`
1607
+ */
1608
+ }, {
1609
+ key: "log",
1610
+ value: function log(message, type) {
1611
+ var logger = this.opts.logger;
1612
+ if (!logger) {
1613
+ return;
1614
+ }
1615
+ switch (type) {
1616
+ case 'error':
1617
+ logger.error(message);
1618
+ break;
1619
+ case 'warning':
1620
+ logger.warn(message);
1621
+ break;
1622
+ default:
1623
+ logger.debug(message);
1624
+ break;
1625
+ }
1626
+ }
1627
+
1628
+ /**
1629
+ * Obsolete, event listeners are now added in the constructor.
1630
+ */
1631
+ }, {
1632
+ key: "run",
1633
+ value: function run() {
1634
+ this.log('Calling run() is no longer necessary.', 'warning');
1635
+ return this;
1636
+ }
1637
+
1638
+ /**
1639
+ * Restore an upload by its ID.
1640
+ */
1641
+ }, {
1642
+ key: "restore",
1643
+ value: function restore(uploadId) {
1644
+ this.log("Core: attempting to restore upload \"".concat(uploadId, "\""));
1645
+ if (!this.getUploadOperation(uploadId)) {
1646
+ this._removeUploadOperation(uploadId);
1647
+ return Promise.reject(new Error('Nonexistent upload'));
1648
+ }
1649
+ return this._runUploadOperation(uploadId);
1650
+ }
1651
+
1652
+ /**
1653
+ * Create an upload for a bunch of files.
1654
+ *
1655
+ * @param {Object} files Files to include in this upload.
1656
+ * @returns {string} ID of this upload.
1657
+ */
1658
+ }, {
1659
+ key: "_createUploadOperation",
1660
+ value: function _createUploadOperation(files) {
1661
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1662
+ var _opts$forceAllowNewUp = opts.forceAllowNewUpload,
1663
+ forceAllowNewUpload = _opts$forceAllowNewUp === void 0 ? false : _opts$forceAllowNewUp;
1664
+ var _this$getUploadCapabi2 = this.getUploadCapabilities(),
1665
+ allowNewUpload = _this$getUploadCapabi2.allowNewUpload;
1666
+ if (!allowNewUpload && !forceAllowNewUpload) {
1667
+ throw new Error('Cannot create a new upload: already uploading.');
1668
+ }
1669
+ var uploadId = cuid();
1670
+ var filesIds = Object.keys(files);
1671
+ this.emit('upload', {
1672
+ id: uploadId,
1673
+ filesIds: filesIds,
1674
+ files: files
1675
+ });
1676
+ this.dispatch(uploadCapabilitiesUpdated({
1677
+ allowMultipleUploads: this.opts.allowMultipleUploads,
1678
+ allowNewUpload: this.opts.allowMultipleUploads !== false
1679
+ }));
1680
+ this.uploadOperations[uploadId] = {
1681
+ id: uploadId,
1682
+ filesIds: filesIds,
1683
+ files: files,
1684
+ step: 0,
1685
+ result: {}
1686
+ };
1687
+ return uploadId;
1688
+ }
1689
+ }, {
1690
+ key: "getUploadOperation",
1691
+ value: function getUploadOperation(uploadId) {
1692
+ return this.getUploadOperations()[uploadId];
1693
+ }
1694
+
1695
+ /**
1696
+ * Add data to an upload's result object.
1697
+ *
1698
+ * @param {string} uploadId The ID of the upload.
1699
+ * @param {object} data Data properties to add to the result object.
1700
+ */
1701
+ }, {
1702
+ key: "addResultData",
1703
+ value: function addResultData(uploadId, data) {
1704
+ if (!this.getUploadOperation(uploadId)) {
1705
+ this.log("Not setting result for an upload that has been removed: ".concat(uploadId));
1706
+ return;
1707
+ }
1708
+ var currentUploadOperation = this.getUploadOperation(uploadId);
1709
+ this._updateUploadOperation({
1710
+ id: uploadId,
1711
+ result: _objectSpread(_objectSpread({}, currentUploadOperation.result), data)
1712
+ });
1713
+ }
1714
+
1715
+ /**
1716
+ * Remove an upload, eg. if it has been canceled or completed.
1717
+ *
1718
+ * @param {string} uploadId The ID of the upload.
1719
+ */
1720
+ }, {
1721
+ key: "_removeUploadOperation",
1722
+ value: function _removeUploadOperation(uploadId) {
1723
+ delete this.uploadOperations[uploadId];
1724
+ }
1725
+
1726
+ /**
1727
+ * Edit an upload, eg. if its step/phase is being updated.
1728
+ *
1729
+ * @param {string} updatedUpload - the updated/changed upload operation must contain `id` for the upload's id to be changed.
1730
+ */
1731
+ }, {
1732
+ key: "_updateUploadOperation",
1733
+ value: function _updateUploadOperation(updatedUpload) {
1734
+ this.uploadOperations[updatedUpload.id] = _objectSpread(_objectSpread({}, this.uploadOperations[updatedUpload.id]), updatedUpload);
1735
+ }
1736
+ }, {
1737
+ key: "setProgressPanelFileState",
1738
+ value: function setProgressPanelFileState() {
1739
+ // This method is deprecated
1740
+ // TODO: remove completely after a while
1741
+ this.log('This method is deprecated, please use setFileUploadingState instead');
1742
+ }
1743
+ }, {
1744
+ key: "setFileUploadingState",
1745
+ value: function setFileUploadingState(fileId, uploadId, state) {
1746
+ var _this$uploadOperation;
1747
+ if (!this.getFileUploading(fileId)) {
1748
+ throw new Error("Can\u2019t set state for ".concat(fileId, " (the file could have been removed)"));
1749
+ }
1750
+ var fileState = _objectSpread(_objectSpread({}, state), {}, {
1751
+ id: fileId
1752
+ });
1753
+ var currentFiles = (_this$uploadOperation = this.uploadOperations[uploadId]) === null || _this$uploadOperation === void 0 ? void 0 : _this$uploadOperation.files;
1754
+ var currentFile = currentFiles === null || currentFiles === void 0 ? void 0 : currentFiles[fileId];
1755
+ this._updateUploadOperation({
1756
+ id: uploadId,
1757
+ files: _objectSpread(_objectSpread({}, currentFiles), {}, _defineProperty({}, fileId, _objectSpread(_objectSpread({}, currentFile), fileState)))
1758
+ });
1759
+ }
1760
+
1761
+ /**
1762
+ * Run an upload. This picks up where it left off in case the upload is being restored.
1763
+ *
1764
+ * @private
1765
+ */
1766
+ }, {
1767
+ key: "_runUploadOperation",
1768
+ value: function _runUploadOperation(uploadId) {
1769
+ var _this10 = this;
1770
+ var uploadData = this.getUploadOperation(uploadId);
1771
+ var restoreStep = uploadData.step;
1772
+ var steps = [].concat(_toConsumableArray(this.preProcessors), _toConsumableArray(this.filerobots), _toConsumableArray(this.postProcessors));
1773
+ var lastStep = Promise.resolve();
1774
+ steps.forEach(function (fn, step) {
1775
+ // Skip this step if we are restoring and have already completed this step before.
1776
+ if (step < restoreStep) {
1777
+ return;
1778
+ }
1779
+ lastStep = lastStep.then(function () {
1780
+ var currentUploadOperation = _this10.getUploadOperation(uploadId);
1781
+ if (!currentUploadOperation) {
1782
+ return;
1783
+ }
1784
+ var updatedUploadSlice = {
1785
+ id: uploadId,
1786
+ step: step
1787
+ };
1788
+ _this10._updateUploadOperation(updatedUploadSlice);
1789
+ // The processor is an object { process: fn, render: fn } which contains process function
1790
+ // otherwise would be the uploading process function.
1791
+ return fn ? (fn.process || fn)(currentUploadOperation.filesIds, uploadId) : Promise.resolve();
1792
+ }).then(function (result) {
1793
+ return null;
1794
+ });
1795
+ });
1796
+
1797
+ // Not returning the `catch`ed promise, because we still want to return a rejected
1798
+ // promise from this method if the upload failed.
1799
+ lastStep["catch"](function (error) {
1800
+ var currentUploadOperation = _this10.getUploadOperation(uploadId);
1801
+ var filesIds = currentUploadOperation.filesIds;
1802
+ _this10.emit('error', filesIds, error, {
1803
+ uploadId: uploadId
1804
+ });
1805
+ _this10._removeUploadOperation(uploadId);
1806
+ });
1807
+ return lastStep.then(function () {
1808
+ // Set result data.
1809
+ var currentUploadOperation = _this10.getUploadOperation(uploadId);
1810
+ if (!currentUploadOperation) {
1811
+ return;
1812
+ }
1813
+ var files = currentUploadOperation.filesIds.map(function (fileId) {
1814
+ return _this10.getFileUploading(fileId);
1815
+ });
1816
+ var successful = files.filter(function (file) {
1817
+ return (file === null || file === void 0 ? void 0 : file.progress.status) !== FILE_UPLOAD_STATUS.ERROR;
1818
+ });
1819
+ var failed = files.filter(function (file) {
1820
+ return (file === null || file === void 0 ? void 0 : file.progress.status) === FILE_UPLOAD_STATUS.ERROR;
1821
+ });
1822
+ _this10.addResultData(uploadId, {
1823
+ successful: successful,
1824
+ failed: failed,
1825
+ uploadId: uploadId
1826
+ });
1827
+ }).then(function () {
1828
+ // Emit completion events.
1829
+ // This is in a separate function so that the `currentUploadOperations` variable
1830
+ // always refers to the latest state. In the handler right above it refers
1831
+ // to an outdated object without the `.result` property.
1832
+ var currentUploadOperation = _this10.getUploadOperation(uploadId);
1833
+ if (!currentUploadOperation) {
1834
+ return;
1835
+ }
1836
+ var result = currentUploadOperation.result;
1837
+ _this10.emit('complete', result);
1838
+ _this10._removeUploadOperation(uploadId);
1839
+ return result;
1840
+ }).then(function (result) {
1841
+ if (result == null) {
1842
+ _this10.log("Not setting result for an upload that has been removed: ".concat(uploadId));
1843
+ }
1844
+ return result;
1845
+ });
1846
+ }
1847
+
1848
+ /**
1849
+ * Start an upload for all the files that are not currently being uploaded.
1850
+ *
1851
+ * @returns {Promise}
1852
+ */
1853
+ }, {
1854
+ key: "upload",
1855
+ value: function upload(files, callback) {
1856
+ var _this11 = this;
1857
+ if (!this.plugins.uploader) {
1858
+ this.log('No filerobot type plugins are used', 'warning');
1859
+ }
1860
+ var filesToUpload = files || selectUploads(this.getGlobalState());
1861
+ var onBeforeUploadResult = this.opts.onBeforeUpload(filesToUpload);
1862
+ if (onBeforeUploadResult === false) {
1863
+ return Promise.reject(new Error('Not starting the upload because onBeforeUpload returned false'));
1864
+ }
1865
+ if (onBeforeUploadResult && _typeof(onBeforeUploadResult) === 'object') {
1866
+ filesToUpload = onBeforeUploadResult;
1867
+ }
1868
+ return Promise.resolve().then(function () {
1869
+ return _this11._checkMinNumberOfFiles(filesToUpload);
1870
+ })["catch"](function (err) {
1871
+ _this11._showOrLogErrorAndThrow(err);
1872
+ }).then(function () {
1873
+ if (typeof callback === 'function') {
1874
+ callback(filesToUpload);
1875
+ }
1876
+ _this11.dispatch(allUploadsRemoved());
1877
+ var currentUploadOperations = _this11.getUploadOperations();
1878
+ // get a list of files that are currently assigned to uploads
1879
+ var currentlyUploadingFiles = Object.keys(currentUploadOperations).reduce(function (prev, curr) {
1880
+ return prev.concat(currentUploadOperations[curr].filesIds);
1881
+ }, []);
1882
+ var waitingFiles = {};
1883
+ Object.keys(filesToUpload).forEach(function (fileId) {
1884
+ // if the file hasn't started uploading
1885
+ if (currentlyUploadingFiles.indexOf(fileId) === -1) {
1886
+ waitingFiles[fileId] = _objectSpread({}, filesToUpload[fileId]);
1887
+ }
1888
+ });
1889
+ var uploadId = _this11._createUploadOperation(waitingFiles);
1890
+ return _this11._runUploadOperation(uploadId);
1891
+ })["catch"](function (err) {
1892
+ _this11._showOrLogErrorAndThrow(err, {
1893
+ showInformer: false
1894
+ });
1895
+ });
1896
+ }
1897
+ }, {
1898
+ key: "getRemoteUploadFolder",
1899
+ value: function getRemoteUploadFolder() {
1900
+ var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
1901
+ _ref7$file = _ref7.file,
1902
+ file = _ref7$file === void 0 ? {} : _ref7$file,
1903
+ opts = _ref7.opts;
1904
+ var _this$getCoreCommonSt = this.getCoreCommonState(),
1905
+ dndTargetFolderPath = _this$getCoreCommonSt.dndTargetFolderPath,
1906
+ _this$getCoreCommonSt2 = _this$getCoreCommonSt.isDragging,
1907
+ isDragging = _this$getCoreCommonSt2 === void 0 ? false : _this$getCoreCommonSt2,
1908
+ _this$getCoreCommonSt3 = _this$getCoreCommonSt.xhrUpload,
1909
+ xhrUpload = _this$getCoreCommonSt3 === void 0 ? {} : _this$getCoreCommonSt3;
1910
+ var _ref8 = opts || _objectSpread(_objectSpread(_objectSpread({}, this.opts), xhrUpload), file === null || file === void 0 ? void 0 : file.xhrUpload),
1911
+ uploadToFolderPath = _ref8.uploadToFolderPath,
1912
+ _ref8$uploadQueryPara = _ref8.uploadQueryParams,
1913
+ uploadQueryParams = _ref8$uploadQueryPara === void 0 ? '' : _ref8$uploadQueryPara;
1914
+ var isFolderInUploadParams = (uploadQueryParams === null || uploadQueryParams === void 0 ? void 0 : uploadQueryParams.search('(^|&)folder=')) > -1;
1915
+ var path = '/';
1916
+ if (isFolderInUploadParams) path = uploadQueryParams.match(/folder=([^&]*)/)[1];else if (uploadToFolderPath) path = uploadToFolderPath;else if (isDragging) path = dndTargetFolderPath;else if (file !== null && file !== void 0 && file.toFolder) path = file.toFolder;
1917
+ return decodeURIComponent(path);
1918
+ }
1919
+ }]);
1920
+ }();
1921
+ // static VERSION = version
1922
+ // This property contains the data File class instance of the uploads' files, mapped through the file id,
1923
+ // as `File` class is not serializable data type so we are not saving it into redux, and keeping it in sync with related upload/file object.
1924
+ _defineProperty(ScaleflexWidget, "uploadFilesData", {
1925
+ // [fileId]: { [File/Blob instance] }
1926
+ });
1927
+ export default function (opts) {
1928
+ return new ScaleflexWidget(opts);
1929
+ }
1930
+
1931
+ // Expose class constructor.
1932
+ export { ScaleflexWidget, Plugin, debugLogger };