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