@widgetic/editor 3.10.54 → 3.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widgetic/editor",
3
- "version": "3.10.54",
3
+ "version": "3.11.1",
4
4
  "scripts": {
5
5
  "start": "webpack --config webpack.config.js --watch --progress",
6
6
  "build": "webpack --config webpack.config.js",
@@ -58,7 +58,7 @@
58
58
  "svelte": "^1.22.5",
59
59
  "svelte-loader": "^1.3.0",
60
60
  "uglify-js": "^2.8.7",
61
- "uglifyjs-webpack-plugin": "^0.3.0",
61
+ "uglifyjs-webpack-plugin": "^1.3.0",
62
62
  "virtual-dom": "^2.1.1",
63
63
  "webpack": "^3.0.0",
64
64
  "webpack-bundle-analyzer": "^2.3.0",
@@ -67,7 +67,8 @@
67
67
  "dependencies": {
68
68
  "http-server": "^0.11.1",
69
69
  "json-logic-js": "^1.2.2",
70
- "soundcloud": "^3.3.2"
70
+ "soundcloud": "^3.3.2",
71
+ "tus-js-client": "^4.1.0"
71
72
  },
72
73
  "volta": {
73
74
  "node": "12.22.2"
@@ -24,8 +24,10 @@ File.defaults = {
24
24
  };
25
25
  File.guid = 0;
26
26
 
27
- const parseType = type =>
28
- type.indexOf('/') > 0 ? type.slice(0, type.indexOf('/')) : type;
27
+ const parseType = type => type.indexOf('/') > 0 ? type.slice(0, type.indexOf('/')) : type;
28
+
29
+ // const root = "http://127.0.0.1:8091"; // for local development
30
+ const root = ''; // (empty) for running on https://widgetic.com/upload
29
31
 
30
32
  export default class UploadService extends EventsMixin(Service) {
31
33
  constructor(user, token) {
@@ -41,6 +43,9 @@ export default class UploadService extends EventsMixin(Service) {
41
43
  // max file size in MB
42
44
  this.maxFilesize = user.premium ? 250 : 25; // MB limit / file for premium / free plan
43
45
 
46
+ // chunk size in MB
47
+ this.chunkSize = 90; // MB to go over Cloudflare's 100MB limit
48
+
44
49
  // max quota in bytes
45
50
  this.quota = (user.premium ? 10000 : 250) * 1000 * 1000; // total quota for premium / free plan
46
51
 
@@ -54,8 +59,16 @@ export default class UploadService extends EventsMixin(Service) {
54
59
  return this.maxFilesize;
55
60
  }
56
61
 
62
+ getChunkSize() {
63
+ return this.chunkSize;
64
+ }
65
+
57
66
  getUploadURL() {
58
- return '/upload?user=' + this.user;
67
+ let url = root + '/upload?user=' + this.user;
68
+
69
+ // console.log("getUploadURL:", url);
70
+
71
+ return url;
59
72
  }
60
73
 
61
74
  getAuthHeaders() {
@@ -63,10 +76,15 @@ export default class UploadService extends EventsMixin(Service) {
63
76
  }
64
77
 
65
78
  getFiles(type) {
79
+ // console.log("getting files:", this.files);
66
80
  type = parseType(type);
81
+
82
+ // if files for this type were already fetched, return them
67
83
  if (this.refreshed[type])
68
84
  return Promise.resolve(this.files.filter(f => f.type === type));
69
85
 
86
+ // otherwise fetch them
87
+ // console.log("fetching files for type:", type);
70
88
  return this._fetch(type)
71
89
  .then(files => {
72
90
  // console.log('fetched files:', files)
@@ -80,8 +98,13 @@ export default class UploadService extends EventsMixin(Service) {
80
98
  return this.files.filter(file => file.id === id)[0];
81
99
  }
82
100
 
101
+ getUser() {
102
+ return this.user;
103
+ }
104
+
105
+ // when the upload starts: create a new File instance and push it to the files array
83
106
  upload(uploadFile) {
84
- // console.log("on upload file:", uploadFile);
107
+ console.log("Uploads Service onUploadStart:", uploadFile);
85
108
 
86
109
  // create a new File instance from the uploadFile
87
110
  let file = new File({
@@ -104,29 +127,37 @@ export default class UploadService extends EventsMixin(Service) {
104
127
  this._broadcast.update();
105
128
  }
106
129
 
130
+ // when the upload is complete: update the file in the files array with the data from the server
107
131
  uploadComplete(uploadFile, instanceId) {
108
- // console.log("uploadComplete file:", uploadFile);
132
+ // console.log("Uploads Service uploadComplete:", uploadFile);
109
133
 
134
+ // if the upload failed, show an error
110
135
  if (uploadFile.status === 'error') return;
111
136
 
112
- // read metadata from the file that's on the server
113
- const response = JSON.parse(uploadFile.xhr.response);
114
- // console.log("uploadComplete server response:", response);
115
-
116
- // read file from the response
137
+ // read the response string from the request
138
+ let responseText = uploadFile.xhr && uploadFile.xhr.response ? uploadFile.xhr.response : "";
139
+ if(!responseText) {
140
+ console.error("Error parsing uploadComplete response:", error);
141
+ return this.setError(uploadFile, 'Error uploading file!');
142
+ }
143
+
144
+ // read server file from the response
145
+ const response = JSON.parse(responseText);
117
146
  let serverFile = response.files.data[0];
118
147
  // console.log("uploadComplete file on the server:", serverFile);
119
148
 
120
- // read quota from response
149
+ // read quota from response to update the used quota in dropzone
121
150
  // this.quota = response.quota.max;
122
151
  this.used = response.quota.used;
123
152
 
153
+ // console.log("Upload Service uploadComplete update file to complete:", uploadFile, serverFile);
154
+
124
155
  // update the file in the files array with the data from the server
125
156
  this._update(uploadFile, f => {
126
157
  f.state = 'complete';
127
158
  f.id = serverFile.id;
128
159
  f.path = serverFile.path;
129
- f.url = response.hostUrl + f.path;
160
+ f.url = response.hostUrl + serverFile.path;
130
161
  f.lastModified = serverFile.lastModified;
131
162
  });
132
163
 
@@ -135,10 +166,15 @@ export default class UploadService extends EventsMixin(Service) {
135
166
  }
136
167
 
137
168
  accept(file, done) {
169
+ // console.log("Editor accept file:", file, done);
170
+
171
+ // if with the file size the quota is not exceeded, accept the file
138
172
  // this.used was increased by adding file.size in the `upload` method
139
173
  if (this.used < this.quota) {
140
174
  return done();
141
175
  }
176
+
177
+ // if the file exceeds the quota show an error
142
178
  done(
143
179
  `The file exceeds the quota by ${prettyBytes(this.used - this.quota)}.`
144
180
  );
@@ -155,29 +191,49 @@ export default class UploadService extends EventsMixin(Service) {
155
191
  }
156
192
 
157
193
  setThumbnail(file, thumbnail) {
194
+ console.log("Uploads Service setThumbnail:", file, thumbnail);
158
195
  this._update(file, f => f.thumbnail = thumbnail);
159
196
  }
160
197
 
161
198
  setError(file, error) {
162
199
  this.used -= file.size;
163
- this._update(file, f => {
164
- f.error = error;
165
- f.size = 0;
166
- });
200
+
201
+ this._update(file, f => { f.error = error; f.size = 0; });
167
202
  }
168
203
 
169
204
  setUploadProgress(file, percentage, size) {
170
205
  this._update(file, f => f.progress = percentage);
206
+ // console.log("Uploads Service setUploadProgress:", percentage, file.state);
171
207
  }
172
208
 
173
209
  setUploadState(file, state) {
210
+ // console.log("Uploads Service setUploadState:", state);
174
211
  this._update(file, f => f.state = state);
175
212
  }
176
213
 
177
214
  _update(file, transform) {
215
+
216
+ // console.log("Uploads Service _update file:", transform);
217
+
178
218
  // apply the transform function to the file in the array
179
219
  this.files = this.files.map(f => {
180
- if (f.uploadFile === file) transform(f);
220
+ let fl = f.uploadFile ? f.uploadFile : f;
221
+
222
+ let equal = fl.name === file.name &&
223
+ fl.size === file.size &&
224
+ fl.lastModified === file.lastModified;
225
+
226
+ // console.log("Uploads Service _update compare:", equal, file, fl);
227
+
228
+ // if the file is the one to update, apply the transform function
229
+ // if (f.uploadFile === file)
230
+ if(equal)
231
+ {
232
+ // console.log("Uploads Service _update file found:", file, fl);
233
+ transform(f);
234
+ // console.log("Uploads Service _update file found:", f);
235
+ }
236
+
181
237
  return f;
182
238
  });
183
239
 
@@ -185,10 +241,12 @@ export default class UploadService extends EventsMixin(Service) {
185
241
  this._broadcast.update();
186
242
  }
187
243
 
244
+ // fetch files from the server for the user
188
245
  _fetch(type) {
246
+ // console.log("fetching files for type:", type);
189
247
  return jQuery
190
248
  .ajax({
191
- url: `/upload/?user=${this.user}&type=${type}`,
249
+ url: root + `/upload/?user=${this.user}&type=${type}`,
192
250
  headers: this.getAuthHeaders(),
193
251
  })
194
252
  .then(response => {
@@ -73,6 +73,9 @@ import Dropzone from 'dropzone';
73
73
  import Service from './service.html';
74
74
  import prettyBytes from 'pretty-bytes';
75
75
 
76
+ // Third party libraries imports
77
+ import * as tus from 'tus-js-client';
78
+
76
79
  export default {
77
80
  components: { Service },
78
81
  data() {
@@ -82,7 +85,8 @@ export default {
82
85
  quota: 0,
83
86
  uploading: { total: 0, now: 0 },
84
87
  dragging: false,
85
- maxFilesize: 10,
88
+ maxFilesize: 10, // in MB default
89
+ chunkSize: 0, // 0 by default, so no chunking
86
90
  instanceId: 0,
87
91
  };
88
92
  },
@@ -92,22 +96,31 @@ export default {
92
96
  },
93
97
  oncreate() {
94
98
  this.Uploads = this.refs.Uploads.instance();
99
+
100
+ // read the quota and used space from the Uploads service
95
101
  this.set({ quota: this.Uploads.quota, used: this.Uploads.used });
96
102
 
103
+ // check if should process uploads with XHR depending on the chunkSize
104
+ const autoProcessQueue = !this.get('chunkSize');
105
+ // console.log("Dropzone oncreate autoProcessQueue:", autoProcessQueue);
106
+
107
+ // Initialize Dropzone component
97
108
  this.dropzone = new Dropzone(this.refs.dropzone, {
98
- acceptedFiles: this.get('filetypes'),
109
+ acceptedFiles: this.get('filetypes') || 'application/offset+octet',
99
110
  url: this.Uploads.getUploadURL(),
100
111
  headers: this.Uploads.getAuthHeaders(),
101
112
  accept: this.Uploads.accept.bind(this.Uploads),
102
113
  uploadMultiple: false,
103
114
  maxFilesize: this.get('maxFilesize'),
115
+ // Disable the default XHR upload handler to use TUS instead
116
+ autoProcessQueue: autoProcessQueue,
104
117
  });
105
118
 
106
119
  const events = {
107
120
  dragenter: this._onDragEnter.bind(this),
108
121
  dragleave: this._onDragLeave.bind(this),
109
122
  drop: this._onDragLeave.bind(this),
110
- addedfile: this._onAddedFile.bind(this),
123
+ addedfile: this._onUploadStart.bind(this),
111
124
  thumbnail: this._onThumbnail.bind(this),
112
125
  error: this._onError.bind(this),
113
126
  uploadprogress: this._onUploadProgress.bind(this),
@@ -116,7 +129,7 @@ export default {
116
129
  success: this._updateFileState.bind(this, 'success'),
117
130
  complete: this._updateFileState.bind(this, 'complete'),
118
131
  canceled: this._updateFileState.bind(this, 'canceled'),
119
- complete: this._onComplete.bind(this),
132
+ complete: this._onUploadComplete.bind(this),
120
133
  totaluploadprogress: this._onTotalUploadProgress.bind(this),
121
134
  queuecomplete: this._onQueueComplete.bind(this),
122
135
  };
@@ -135,25 +148,94 @@ export default {
135
148
  this.set({ dragging: false });
136
149
  this.fire('dragging', false);
137
150
  },
138
- _onAddedFile(file) {
139
- this.fire('new');
151
+ _onUploadStart(file) {
152
+ console.log("Dropzone _onUploadStart file:", file);
153
+
154
+ // get the chunk size from the component
155
+ const chunkSize = this.get('chunkSize');
156
+ console.log("Dropzone _onUploadStart chunkSize:", chunkSize);
157
+
158
+ /* Initialize TUS upload */
159
+ if(chunkSize) {
160
+ const upload = new tus.Upload(file, {
161
+ endpoint: this.Uploads.getUploadURL(),
162
+ headers: this.Uploads.getAuthHeaders(),
163
+ retryDelays: [0, 3000, 5000, 10000, 20000],
164
+ chunkSize: chunkSize * 1024 * 1024, // in MB
165
+ metadata: {
166
+ filename: file.name,
167
+ filetype: file.type,
168
+ },
169
+ onError: (error) => {
170
+ // console.error("Failed because: " + error);
171
+ this._onError(file, error);
172
+ },
173
+ onProgress: (bytesUploaded, bytesTotal) => {
174
+ const percentage = (bytesUploaded / bytesTotal * 100);//.toFixed(2);
175
+ // console.log("Dropzone TUS Client Progress:", percentage);
176
+ this._onUploadProgress(file, percentage, bytesUploaded);
177
+ },
178
+ onSuccess: (payload) => {
179
+ // console.log("Dropzone TUS Client onSuccess:", upload);
180
+
181
+ // if the response is not empty, then the upload to widgetic server finished
182
+ if(upload._req._xhr.response == "") {
183
+
184
+ console.log("Dropzone TUS Client Upload Complete to server for file:", upload);
185
+
186
+ // update the file thumbnail to processing state
187
+ this._updateFileState('sending', file);
188
+ }
189
+
190
+ else {
191
+ console.log("Dropzone TUS Client Upload Complete to B2 with response:", upload._req._xhr.response);
192
+
193
+ // create uploadFile object
194
+ let uploadFile = upload.file;
195
+
196
+ // add the request to the file object for later use in Uploads.uploadComplete method
197
+ uploadFile.xhr = upload._req._xhr;
198
+
199
+ // call upload complete method from here that calls the Uploads.uploadComplete method
200
+ this._onUploadComplete(uploadFile);
201
+ }
202
+ }
203
+ });
204
+
205
+ // Start the TUS upload
206
+ upload.start();
207
+ }
208
+
209
+ // fire new event in the editor
210
+ this.fire('new', file);
211
+
212
+ // call uploadStart method on Uploads service
140
213
  this.Uploads.upload(file);
214
+
215
+ // change the file state to uploading
216
+ this._updateFileState('sending', file);
141
217
  },
142
218
  _onThumbnail(file, thumbnail) {
143
219
  this.Uploads.setThumbnail(file, thumbnail);
144
220
  },
145
221
  _onError(file, error) {
146
- console.error(error);
222
+ // console.error(error);
223
+
224
+ // Fire an error event in the editor
147
225
  this.fire('error', { message: error });
226
+
227
+ // Set the error on the file object in the Uploads service
148
228
  this.Uploads.setError(file, error);
149
229
  },
150
230
  _onUploadProgress(file, percentage, size) {
151
231
  this.Uploads.setUploadProgress(file, percentage, size);
152
232
  },
153
- _onComplete(file) {
233
+ _onUploadComplete(file) {
234
+ // console.log("Dropzone Component cploadComplete for file:", file);
154
235
  this.Uploads.uploadComplete(file, this.get('instanceId'));
155
236
  },
156
237
  _updateFileState(state, file) {
238
+ // console.log("Dropzone Component _updateFileState:", state);
157
239
  this.Uploads.setUploadState(file, state);
158
240
  },
159
241
  _onTotalUploadProgress() {
@@ -168,6 +250,10 @@ export default {
168
250
  this.dropzone.removeAllFiles();
169
251
  },
170
252
  _onUploadsUpdate() {
253
+
254
+ // console.log("Dropzone _onUploadsUpdate:", this.Uploads.quota, this.Uploads.used);
255
+
256
+ // Update the quota and used space so it updates in the dropzone UI
171
257
  this.set({
172
258
  quota: this.Uploads.quota,
173
259
  used: this.Uploads.used,
@@ -12,6 +12,7 @@
12
12
  {{#if file.thumbnail}}
13
13
  <div class="browser-image-prew_img" style="background-image: url('{{ file.thumbnail }}')" width="112" height="71"/>
14
14
  {{/if}}
15
+
15
16
  <div class="progress-bar">
16
17
  {{#if file.progress === 100 && file.state === 'sending'}}
17
18
  <div style="width: 100%">Processing...</div>
@@ -19,6 +20,7 @@
19
20
  <div class="progress-bar_fill" style="width: {{ file.progress }}%"></div>
20
21
  {{/if}}
21
22
  </div>
23
+
22
24
  </div>
23
25
  <div class="browser-entry-info" on:click="togglePlay()">{{ file.name }}</div>
24
26
  </div>