@oat-sa/tao-core-ui 3.24.0 → 3.24.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/dist/resourcemgr/assetSearch.js +3 -3
- package/dist/resourcemgr/assetSearchContract.js +1 -1
- package/dist/resourcemgr/css/resourcemgr.css +96 -3
- package/dist/resourcemgr/css/resourcemgr.css.map +1 -1
- package/dist/resourcemgr/fileBrowser.js +370 -15
- package/dist/resourcemgr/filePreview.js +42 -3
- package/dist/resourcemgr/fileSelector.js +15 -0
- package/dist/resourcemgr.js +15 -10
- package/package.json +1 -1
- package/src/resourcemgr/assetSearch.js +3 -3
- package/src/resourcemgr/assetSearchContract.js +1 -1
- package/src/resourcemgr/css/resourcemgr.css +96 -3
- package/src/resourcemgr/css/resourcemgr.css.map +1 -1
- package/src/resourcemgr/fileBrowser.js +434 -33
- package/src/resourcemgr/filePreview.js +43 -4
- package/src/resourcemgr/fileSelector.js +18 -0
- package/src/resourcemgr/scss/resourcemgr.scss +103 -5
- package/src/resourcemgr/tpl/layout.tpl +30 -18
- package/src/resourcemgr.js +9 -4
|
@@ -204,7 +204,18 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
204
204
|
*/
|
|
205
205
|
const NS = 'resourcemgr';
|
|
206
206
|
const LOGGER = loggerFactory(`ui/${NS}`);
|
|
207
|
-
const DEFAULT_AJAX_TIMEOUT_MS =
|
|
207
|
+
const DEFAULT_AJAX_TIMEOUT_MS = 30000;
|
|
208
|
+
const TREE_LOADING_REF_KEY = `${NS}TreeLoadingRefCount`;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {Object} data
|
|
212
|
+
* @returns {Array}
|
|
213
|
+
*/
|
|
214
|
+
function folderChildrenOnly(data) {
|
|
215
|
+
return _.filter(data && data.children, function (child) {
|
|
216
|
+
return child && child.path && !child.uri;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
208
219
|
function fileBrowser (options) {
|
|
209
220
|
if (!options.browseUrl && options.url) {
|
|
210
221
|
options.browseUrl = options.url;
|
|
@@ -221,15 +232,50 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
221
232
|
// for pagination
|
|
222
233
|
let selectedClass = {
|
|
223
234
|
path: rootPath,
|
|
224
|
-
childrenLimit:
|
|
235
|
+
childrenLimit: 11,
|
|
225
236
|
total: 0,
|
|
226
237
|
page: 1
|
|
227
238
|
};
|
|
228
239
|
let searchMode = false;
|
|
229
240
|
let sort = Object.assign({}, assetSearchContract.DEFAULT_SORT);
|
|
241
|
+
const splitBrowse = options.splitBrowse !== false;
|
|
230
242
|
const ajaxTimeoutMs = Number.isFinite(Number(options.ajaxTimeoutMs)) && Number(options.ajaxTimeoutMs) > 0 ? Number(options.ajaxTimeoutMs) : DEFAULT_AJAX_TIMEOUT_MS;
|
|
243
|
+
const $treeLoadingOverlay = $$1('.file-browser-tree-loading', $fileBrowser);
|
|
244
|
+
const $treeLoadingStatus = $$1('.file-browser-tree-loading-status', $treeLoadingOverlay);
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Ref-count in-flight browse requests and toggle the tree loading overlay.
|
|
248
|
+
* @param {Boolean} increment - true when a load starts, false when it finishes
|
|
249
|
+
*/
|
|
250
|
+
function setTreeLoading(increment) {
|
|
251
|
+
let treeLoadingRefCount = Number($fileBrowser.data(TREE_LOADING_REF_KEY)) || 0;
|
|
252
|
+
treeLoadingRefCount += increment ? 1 : -1;
|
|
253
|
+
if (treeLoadingRefCount < 0) {
|
|
254
|
+
treeLoadingRefCount = 0;
|
|
255
|
+
}
|
|
256
|
+
$fileBrowser.data(TREE_LOADING_REF_KEY, treeLoadingRefCount);
|
|
257
|
+
const loading = treeLoadingRefCount > 0;
|
|
258
|
+
$fileBrowser.toggleClass('is-tree-loading', loading);
|
|
259
|
+
$fileBrowser.attr('aria-busy', loading ? 'true' : 'false');
|
|
260
|
+
$treeLoadingOverlay.toggleClass('hidden', !loading).attr('aria-hidden', loading ? 'false' : 'true');
|
|
261
|
+
$treeLoadingStatus.attr('aria-busy', loading ? 'true' : 'false');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Show or hide the asset table loading overlay (browse mode only).
|
|
266
|
+
* @param {Boolean} loading
|
|
267
|
+
*/
|
|
268
|
+
function setFilesLoading(loading) {
|
|
269
|
+
if (searchMode) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
$container.trigger(`filesloading.${NS}`, [!!loading]);
|
|
273
|
+
}
|
|
231
274
|
$container.on(`searchmode.${NS}`, function (e, enabled) {
|
|
232
275
|
searchMode = !!enabled;
|
|
276
|
+
if (searchMode) {
|
|
277
|
+
$container.trigger(`filesloading.${NS}`, [false]);
|
|
278
|
+
}
|
|
233
279
|
});
|
|
234
280
|
$container.on(`sortchange.${NS}`, function (e, nextSort) {
|
|
235
281
|
sort = Object.assign({}, assetSearchContract.DEFAULT_SORT, nextSort || {});
|
|
@@ -248,9 +294,14 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
248
294
|
return;
|
|
249
295
|
}
|
|
250
296
|
const subTree = getByExactPath(fileTree, targetPath) || getByPath(fileTree, targetPath) || fileTree;
|
|
297
|
+
if (!searchMode) {
|
|
298
|
+
setFilesLoading(true);
|
|
299
|
+
}
|
|
251
300
|
getFolderContent(subTree, targetPath, function (content) {
|
|
252
301
|
if (content) {
|
|
253
302
|
selectFolder(content, targetPath);
|
|
303
|
+
} else {
|
|
304
|
+
setFilesLoading(false);
|
|
254
305
|
}
|
|
255
306
|
});
|
|
256
307
|
});
|
|
@@ -274,8 +325,15 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
274
325
|
});
|
|
275
326
|
|
|
276
327
|
//load the content of the ROOT
|
|
328
|
+
const showInitialListLoading = !searchMode && root === 'local';
|
|
329
|
+
if (showInitialListLoading) {
|
|
330
|
+
setFilesLoading(true);
|
|
331
|
+
}
|
|
277
332
|
getFolderContent(fileTree, rootPath, function (content) {
|
|
278
333
|
if (!content) {
|
|
334
|
+
if (showInitialListLoading) {
|
|
335
|
+
setFilesLoading(false);
|
|
336
|
+
}
|
|
279
337
|
return;
|
|
280
338
|
}
|
|
281
339
|
indexTree(content);
|
|
@@ -303,6 +361,8 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
303
361
|
if (root !== 'local') {
|
|
304
362
|
options.hasAlreadySelected = true;
|
|
305
363
|
}
|
|
364
|
+
} else if (showInitialListLoading) {
|
|
365
|
+
setFilesLoading(false);
|
|
306
366
|
}
|
|
307
367
|
});
|
|
308
368
|
|
|
@@ -312,6 +372,14 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
312
372
|
const $selected = $$1(this);
|
|
313
373
|
const fullPath = $selected.data('path');
|
|
314
374
|
const subTree = getByExactPath(fileTree, fullPath);
|
|
375
|
+
const openingFolder = !searchMode && fullPath !== selectedClass.path;
|
|
376
|
+
if (openingFolder) {
|
|
377
|
+
selectedClass.page = 1;
|
|
378
|
+
}
|
|
379
|
+
if (!searchMode) {
|
|
380
|
+
setFilesLoading(true);
|
|
381
|
+
}
|
|
382
|
+
invalidateFolderFiles(fullPath);
|
|
315
383
|
|
|
316
384
|
//get the folder content
|
|
317
385
|
getFolderContent(subTree, fullPath, function (content) {
|
|
@@ -341,6 +409,8 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
341
409
|
|
|
342
410
|
//internal event to set the file-selector content
|
|
343
411
|
selectFolder(content, fullPath);
|
|
412
|
+
} else if (!searchMode) {
|
|
413
|
+
setFilesLoading(false);
|
|
344
414
|
}
|
|
345
415
|
});
|
|
346
416
|
});
|
|
@@ -361,10 +431,11 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
361
431
|
}
|
|
362
432
|
if (targetPath !== selectedClass.path) {
|
|
363
433
|
selectedClass.path = targetPath;
|
|
364
|
-
selectedClass.page = 1;
|
|
365
434
|
}
|
|
435
|
+
selectedClass.page = 1;
|
|
366
436
|
invalidateFolderFiles(targetPath);
|
|
367
|
-
|
|
437
|
+
const pendingUpload = file && !file.error && (file.uri || file.name) ? file : null;
|
|
438
|
+
reloadSortedFolder(pendingUpload ? [pendingUpload] : []);
|
|
368
439
|
});
|
|
369
440
|
$container.on(`filedelete.${NS}`, function (e, path) {
|
|
370
441
|
if (searchMode) {
|
|
@@ -494,13 +565,16 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
494
565
|
$container.data('activeFileBrowserRoot', root);
|
|
495
566
|
if (searchMode) {
|
|
496
567
|
$container.trigger(`folderpath.${NS}`, [path, content.label]);
|
|
497
|
-
$container.trigger(`folderselect.${NS}`, [content.label,
|
|
568
|
+
$container.trigger(`folderselect.${NS}`, [content.label, getFilesForDisplay(content), path, content]);
|
|
498
569
|
return;
|
|
499
570
|
}
|
|
500
571
|
updateSelectedClass(path, content.total, content.childrenLimit);
|
|
501
572
|
$container.trigger(`folderpath.${NS}`, [path, content.label]);
|
|
502
|
-
$container.trigger(`folderselect.${NS}`, [content.label,
|
|
573
|
+
$container.trigger(`folderselect.${NS}`, [content.label, getFilesForDisplay(content), path, content]);
|
|
503
574
|
renderPagination();
|
|
575
|
+
if (!searchMode) {
|
|
576
|
+
setFilesLoading(false);
|
|
577
|
+
}
|
|
504
578
|
}
|
|
505
579
|
|
|
506
580
|
/**
|
|
@@ -517,6 +591,172 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
517
591
|
}
|
|
518
592
|
return files;
|
|
519
593
|
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Files for the table (split list payload or legacy children slice).
|
|
597
|
+
* @param {Object} content
|
|
598
|
+
* @returns {Array}
|
|
599
|
+
*/
|
|
600
|
+
function getFilesForDisplay(content) {
|
|
601
|
+
if (!content) {
|
|
602
|
+
return [];
|
|
603
|
+
}
|
|
604
|
+
if (splitBrowse) {
|
|
605
|
+
return content.listItems || [];
|
|
606
|
+
}
|
|
607
|
+
return getPage(content.children || []);
|
|
608
|
+
}
|
|
609
|
+
function listCacheKey() {
|
|
610
|
+
return `${sort.field}:${sort.direction}:${selectedClass.page}`;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Snapshot list request identity (folder + page/sort) when a browse starts.
|
|
615
|
+
* @returns {{path: String, cacheKey: String}}
|
|
616
|
+
*/
|
|
617
|
+
function captureListRequestContext() {
|
|
618
|
+
return {
|
|
619
|
+
path: selectedClass.path,
|
|
620
|
+
cacheKey: listCacheKey()
|
|
621
|
+
};
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Whether navigation changed before an in-flight list response should apply.
|
|
626
|
+
* @param {{path: String, cacheKey: String}} captured
|
|
627
|
+
* @returns {Boolean}
|
|
628
|
+
*/
|
|
629
|
+
function isListRequestStale(captured) {
|
|
630
|
+
return !captured || captured.path !== selectedClass.path || captured.cacheKey !== listCacheKey();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* @param {Object} response
|
|
635
|
+
* @returns {Object}
|
|
636
|
+
*/
|
|
637
|
+
function unwrapBrowseResponse(response) {
|
|
638
|
+
if (response && response.success === false) {
|
|
639
|
+
return Promise.reject(response);
|
|
640
|
+
}
|
|
641
|
+
let data = response && response.data ? response.data : response;
|
|
642
|
+
data = updatePermissions(data);
|
|
643
|
+
if (data.children && data.children.length > 0) {
|
|
644
|
+
data.children = data.children.map(function (child) {
|
|
645
|
+
return updatePermissions(child);
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
if (data.items && data.items.length > 0) {
|
|
649
|
+
data.items = data.items.map(function (item) {
|
|
650
|
+
return updatePermissions(item);
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return data;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* @param {String} path
|
|
658
|
+
* @param {Object} extraData
|
|
659
|
+
* @returns {Promise}
|
|
660
|
+
*/
|
|
661
|
+
function browseRequest(path, extraData) {
|
|
662
|
+
const parameters = {};
|
|
663
|
+
parameters[options.pathParam || 'path'] = path;
|
|
664
|
+
return Promise.resolve($$1.ajax({
|
|
665
|
+
url: options.browseUrl,
|
|
666
|
+
method: 'GET',
|
|
667
|
+
dataType: 'json',
|
|
668
|
+
timeout: ajaxTimeoutMs,
|
|
669
|
+
data: _.merge(parameters, options.params, extraData)
|
|
670
|
+
})).then(unwrapBrowseResponse);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* @param {Object} tree
|
|
675
|
+
* @param {String} path
|
|
676
|
+
* @param {Object} data
|
|
677
|
+
*/
|
|
678
|
+
function applyTreePayload(tree, path, data) {
|
|
679
|
+
const folderData = Object.assign({}, data, {
|
|
680
|
+
children: folderChildrenOnly(data)
|
|
681
|
+
});
|
|
682
|
+
if (!tree.path) {
|
|
683
|
+
_.merge(tree, folderData);
|
|
684
|
+
} else if (folderData.children) {
|
|
685
|
+
setToPath(tree, path, folderData);
|
|
686
|
+
if (!_.find(folderData.children, 'path')) {
|
|
687
|
+
markFolderEmptyAtPath(tree, path);
|
|
688
|
+
}
|
|
689
|
+
} else {
|
|
690
|
+
setToPath(tree, path, folderData);
|
|
691
|
+
markFolderEmptyAtPath(tree, path);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* @param {Object} tree
|
|
697
|
+
* @param {String} path
|
|
698
|
+
* @param {Object} listData
|
|
699
|
+
* @param {String} cacheKey
|
|
700
|
+
*/
|
|
701
|
+
function applyListPayload(tree, path, listData, cacheKey) {
|
|
702
|
+
const node = getByExactPath(tree, path) || getByPath(tree, path);
|
|
703
|
+
if (!node || !listData) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
node.listItems = listData.items || [];
|
|
707
|
+
node.total = listData.total;
|
|
708
|
+
node.childrenLimit = listData.pageSize || listData.childrenLimit || selectedClass.childrenLimit;
|
|
709
|
+
node.listPage = listData.page;
|
|
710
|
+
node.totalIsApproximate = listData.totalIsApproximate;
|
|
711
|
+
node.listCacheKey = cacheKey;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Ensure upload responses appear in the table before Elasticsearch catches up.
|
|
716
|
+
* @param {String} path
|
|
717
|
+
* @param {Array<Object>} uploads
|
|
718
|
+
*/
|
|
719
|
+
function mergePendingUploads(path, uploads) {
|
|
720
|
+
if (!uploads || !uploads.length) {
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
const node = getByExactPath(fileTree, path) || getByPath(fileTree, path);
|
|
724
|
+
if (!node) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (!Array.isArray(node.listItems)) {
|
|
728
|
+
node.listItems = [];
|
|
729
|
+
}
|
|
730
|
+
let added = 0;
|
|
731
|
+
uploads.forEach(function (uploaded) {
|
|
732
|
+
if (!uploaded || uploaded.error) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const normalized = updatePermissions(uploaded);
|
|
736
|
+
if (!normalized.uri && !normalized.name) {
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
const exists = _.some(node.listItems, function (item) {
|
|
740
|
+
return normalized.uri && item.uri === normalized.uri || normalized.name && item.name === normalized.name;
|
|
741
|
+
});
|
|
742
|
+
if (exists) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
node.listItems.push(normalized);
|
|
746
|
+
added++;
|
|
747
|
+
});
|
|
748
|
+
if (!added) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (splitBrowse) {
|
|
752
|
+
node.listItems = assetSearchContract.sortAssetItems(node.listItems, sort);
|
|
753
|
+
}
|
|
754
|
+
const total = Number(node.total);
|
|
755
|
+
if (Number.isFinite(total) && total >= 0) {
|
|
756
|
+
node.total = total + added;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
520
760
|
/**
|
|
521
761
|
* Get the content of a folder, either in the model or load it
|
|
522
762
|
* @param {Object} tree - the tree model
|
|
@@ -530,6 +770,44 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
530
770
|
}
|
|
531
771
|
}
|
|
532
772
|
function getFolderContent(tree, path, cb) {
|
|
773
|
+
if (splitBrowse) {
|
|
774
|
+
const existing = getByExactPath(tree, path) || getByPath(tree, path);
|
|
775
|
+
const needTree = !existing || !existing.children && !existing.empty;
|
|
776
|
+
const cacheKey = listCacheKey();
|
|
777
|
+
const needList = !existing || existing.listCacheKey !== cacheKey;
|
|
778
|
+
const treePromise = needTree ? (setTreeLoading(true), browseRequest(path, {
|
|
779
|
+
part: 'tree',
|
|
780
|
+
depth: 1,
|
|
781
|
+
sortBy: sort.field,
|
|
782
|
+
sortDir: sort.direction
|
|
783
|
+
}).then(function (data) {
|
|
784
|
+
setTreeLoading(false);
|
|
785
|
+
return data;
|
|
786
|
+
}, function (error) {
|
|
787
|
+
setTreeLoading(false);
|
|
788
|
+
return Promise.reject(error);
|
|
789
|
+
})) : Promise.resolve(null);
|
|
790
|
+
const listPromise = needList ? browseRequest(path, {
|
|
791
|
+
part: 'list',
|
|
792
|
+
page: selectedClass.page,
|
|
793
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
794
|
+
sortBy: sort.field,
|
|
795
|
+
sortDir: sort.direction
|
|
796
|
+
}) : Promise.resolve(null);
|
|
797
|
+
Promise.all([treePromise, listPromise]).then(function (_ref) {
|
|
798
|
+
let [treeData, listData] = _ref;
|
|
799
|
+
if (treeData) {
|
|
800
|
+
applyTreePayload(tree, path, treeData);
|
|
801
|
+
}
|
|
802
|
+
if (listData) {
|
|
803
|
+
applyListPayload(tree, path, listData, cacheKey);
|
|
804
|
+
}
|
|
805
|
+
cb(getByExactPath(tree, path) || getByPath(tree, path));
|
|
806
|
+
}).catch(function () {
|
|
807
|
+
cb(null);
|
|
808
|
+
});
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
533
811
|
let content = getByPath(tree, path);
|
|
534
812
|
if (!content || !content.children && !content.empty) {
|
|
535
813
|
loadContent(path).then(function (data) {
|
|
@@ -555,7 +833,7 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
555
833
|
});
|
|
556
834
|
// Use folder total (not selectedClass): openInitialPath runs before selectFolder.
|
|
557
835
|
const expectedTotal = Number(content.total);
|
|
558
|
-
const pageSize = Number(content.childrenLimit) || selectedClass.childrenLimit ||
|
|
836
|
+
const pageSize = Number(content.childrenLimit) || selectedClass.childrenLimit || 11;
|
|
559
837
|
const page = selectedClass.page || 1;
|
|
560
838
|
// Missing/NaN total → unknown size; refetch so invalidated cache is not treated as complete.
|
|
561
839
|
if (!Number.isFinite(expectedTotal) || files.length < expectedTotal && files.length < page * pageSize) {
|
|
@@ -715,7 +993,16 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
715
993
|
*/
|
|
716
994
|
function invalidateFolderFiles(path) {
|
|
717
995
|
const content = getByExactPath(fileTree, path);
|
|
718
|
-
if (content
|
|
996
|
+
if (!content) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
if (splitBrowse) {
|
|
1000
|
+
delete content.listItems;
|
|
1001
|
+
delete content.listCacheKey;
|
|
1002
|
+
delete content.listPage;
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (Array.isArray(content.children)) {
|
|
719
1006
|
content.children = content.children.filter(function (child) {
|
|
720
1007
|
return child.path && !child.uri;
|
|
721
1008
|
});
|
|
@@ -727,11 +1014,15 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
727
1014
|
* @param {String} path
|
|
728
1015
|
* @param {Object} data
|
|
729
1016
|
*/
|
|
730
|
-
function replaceFolderContent(path, data) {
|
|
1017
|
+
function replaceFolderContent(path, data, cacheKey) {
|
|
731
1018
|
const content = getByExactPath(fileTree, path);
|
|
732
1019
|
if (!content || !data) {
|
|
733
1020
|
return;
|
|
734
1021
|
}
|
|
1022
|
+
if (splitBrowse && Object.prototype.hasOwnProperty.call(data, 'items')) {
|
|
1023
|
+
applyListPayload(fileTree, path, data, cacheKey || listCacheKey());
|
|
1024
|
+
return;
|
|
1025
|
+
}
|
|
735
1026
|
if (Object.prototype.hasOwnProperty.call(data, 'children')) {
|
|
736
1027
|
content.children = data.children;
|
|
737
1028
|
} else {
|
|
@@ -761,6 +1052,7 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
761
1052
|
function loadContent(path) {
|
|
762
1053
|
const parameters = {};
|
|
763
1054
|
parameters[options.pathParam || 'path'] = path;
|
|
1055
|
+
setTreeLoading(true);
|
|
764
1056
|
return Promise.resolve($$1.ajax({
|
|
765
1057
|
url: options.browseUrl,
|
|
766
1058
|
method: 'GET',
|
|
@@ -784,6 +1076,12 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
784
1076
|
data.children.map(responseChildren => updatePermissions(responseChildren));
|
|
785
1077
|
}
|
|
786
1078
|
return data;
|
|
1079
|
+
}).then(function (data) {
|
|
1080
|
+
setTreeLoading(false);
|
|
1081
|
+
return data;
|
|
1082
|
+
}, function (error) {
|
|
1083
|
+
setTreeLoading(false);
|
|
1084
|
+
return Promise.reject(error);
|
|
787
1085
|
});
|
|
788
1086
|
}
|
|
789
1087
|
|
|
@@ -853,7 +1151,7 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
853
1151
|
selectedClass = {
|
|
854
1152
|
path,
|
|
855
1153
|
total: Number.isFinite(normalizedTotal) && normalizedTotal >= 0 ? normalizedTotal : 0,
|
|
856
|
-
childrenLimit: Number.isFinite(normalizedChildrenLimit) && normalizedChildrenLimit > 0 ? normalizedChildrenLimit : selectedClass.childrenLimit ||
|
|
1154
|
+
childrenLimit: Number.isFinite(normalizedChildrenLimit) && normalizedChildrenLimit > 0 ? normalizedChildrenLimit : selectedClass.childrenLimit || 11,
|
|
857
1155
|
page: 1
|
|
858
1156
|
};
|
|
859
1157
|
}
|
|
@@ -890,17 +1188,35 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
890
1188
|
/**
|
|
891
1189
|
* Re-fetch the current folder with the active sort and publish files.
|
|
892
1190
|
*/
|
|
893
|
-
function reloadSortedFolder() {
|
|
894
|
-
const
|
|
895
|
-
|
|
1191
|
+
function reloadSortedFolder(pendingUploads) {
|
|
1192
|
+
const listRequest = captureListRequestContext();
|
|
1193
|
+
const path = listRequest.path;
|
|
1194
|
+
if (!searchMode && isActiveBrowser()) {
|
|
1195
|
+
setFilesLoading(true);
|
|
1196
|
+
}
|
|
1197
|
+
const loadPromise = splitBrowse ? browseRequest(path, {
|
|
1198
|
+
part: 'list',
|
|
1199
|
+
page: selectedClass.page,
|
|
1200
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
1201
|
+
sortBy: sort.field,
|
|
1202
|
+
sortDir: sort.direction
|
|
1203
|
+
}) : loadContent(path);
|
|
1204
|
+
loadPromise.then(function (data) {
|
|
896
1205
|
if (!data) {
|
|
1206
|
+
setFilesLoading(false);
|
|
897
1207
|
return;
|
|
898
1208
|
}
|
|
899
|
-
|
|
1209
|
+
if (isListRequestStale(listRequest)) {
|
|
1210
|
+
setFilesLoading(false);
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
replaceFolderContent(path, data, listRequest.cacheKey);
|
|
1214
|
+
mergePendingUploads(path, pendingUploads);
|
|
900
1215
|
const content = getByExactPath(fileTree, path) || data;
|
|
901
1216
|
selectFolder(content, content.path || path);
|
|
902
1217
|
}).catch(function (error) {
|
|
903
1218
|
LOGGER.error(error);
|
|
1219
|
+
setFilesLoading(false);
|
|
904
1220
|
});
|
|
905
1221
|
}
|
|
906
1222
|
|
|
@@ -908,14 +1224,53 @@ define(['jquery', 'lodash', 'ui/pagination', 'handlebars', 'lib/handlebars/helpe
|
|
|
908
1224
|
* Load page
|
|
909
1225
|
*/
|
|
910
1226
|
function loadPage() {
|
|
1227
|
+
const listRequest = captureListRequestContext();
|
|
1228
|
+
if (!searchMode && isActiveBrowser()) {
|
|
1229
|
+
setFilesLoading(true);
|
|
1230
|
+
}
|
|
1231
|
+
if (splitBrowse) {
|
|
1232
|
+
const path = listRequest.path;
|
|
1233
|
+
browseRequest(path, {
|
|
1234
|
+
part: 'list',
|
|
1235
|
+
page: selectedClass.page,
|
|
1236
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
1237
|
+
sortBy: sort.field,
|
|
1238
|
+
sortDir: sort.direction
|
|
1239
|
+
}).then(function (data) {
|
|
1240
|
+
if (isListRequestStale(listRequest)) {
|
|
1241
|
+
setFilesLoading(false);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
applyListPayload(fileTree, path, data, listRequest.cacheKey);
|
|
1245
|
+
const content = getByExactPath(fileTree, path);
|
|
1246
|
+
if (content) {
|
|
1247
|
+
$container.trigger(`folderselect.${NS}`, [content.label, getFilesForDisplay(content), content.path, content]);
|
|
1248
|
+
renderPagination();
|
|
1249
|
+
}
|
|
1250
|
+
setFilesLoading(false);
|
|
1251
|
+
}).catch(function (error) {
|
|
1252
|
+
LOGGER.error(error);
|
|
1253
|
+
setFilesLoading(false);
|
|
1254
|
+
});
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
911
1257
|
const subTree = getByPath(fileTree, selectedClass.path) || fileTree;
|
|
912
1258
|
|
|
913
1259
|
//get the folder content
|
|
914
1260
|
getFolderContent(subTree, selectedClass.path, function (content) {
|
|
1261
|
+
if (isListRequestStale(listRequest)) {
|
|
1262
|
+
if (!searchMode) {
|
|
1263
|
+
setFilesLoading(false);
|
|
1264
|
+
}
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
915
1267
|
indexTree(fileTree);
|
|
916
1268
|
if (content) {
|
|
917
1269
|
//internal event to set the file-selector content
|
|
918
|
-
$container.trigger(`folderselect.${NS}`, [content.label,
|
|
1270
|
+
$container.trigger(`folderselect.${NS}`, [content.label, getFilesForDisplay(content), content.path, content]);
|
|
1271
|
+
}
|
|
1272
|
+
if (!searchMode) {
|
|
1273
|
+
setFilesLoading(false);
|
|
919
1274
|
}
|
|
920
1275
|
});
|
|
921
1276
|
}
|
|
@@ -67,6 +67,39 @@ define(['jquery', 'lodash', 'util/bytes', 'context', 'ui/previewer'], function (
|
|
|
67
67
|
}
|
|
68
68
|
return String(value);
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Row markup uses data-download for permission flag (boolean), not the URL.
|
|
73
|
+
* @param {*} file
|
|
74
|
+
* @returns {string}
|
|
75
|
+
*/
|
|
76
|
+
function downloadHref(file) {
|
|
77
|
+
if (typeof file.downloadUrl === 'string' && file.downloadUrl) {
|
|
78
|
+
return file.downloadUrl;
|
|
79
|
+
}
|
|
80
|
+
if (typeof file.url === 'string' && file.url) {
|
|
81
|
+
const query = file.url.split('#')[0].split('?')[1] || '';
|
|
82
|
+
const hasSvgzSupport = query.split('&').some(param => param.split('=')[0] === 'svgzsupport');
|
|
83
|
+
return hasSvgzSupport ? file.url : `${file.url}&svgzsupport=true`;
|
|
84
|
+
}
|
|
85
|
+
if (typeof file.download === 'string' && file.download) {
|
|
86
|
+
return file.download;
|
|
87
|
+
}
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {*} file
|
|
93
|
+
* @returns {string}
|
|
94
|
+
*/
|
|
95
|
+
function downloadFilename(file) {
|
|
96
|
+
if (typeof file.display === 'string' && file.display) {
|
|
97
|
+
return file.display;
|
|
98
|
+
}
|
|
99
|
+
const path = file.file || '';
|
|
100
|
+
const idx = path.lastIndexOf('/');
|
|
101
|
+
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
102
|
+
}
|
|
70
103
|
function startPreview(file, preview, download, select) {
|
|
71
104
|
if (preview) {
|
|
72
105
|
$previewer.previewer(file);
|
|
@@ -81,9 +114,15 @@ define(['jquery', 'lodash', 'util/bytes', 'context', 'ui/previewer'], function (
|
|
|
81
114
|
$propSize.text(EMPTY_META);
|
|
82
115
|
}
|
|
83
116
|
if (download) {
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
$link.
|
|
117
|
+
const href = downloadHref(file);
|
|
118
|
+
if (href) {
|
|
119
|
+
$link.attr('href', href).attr('download', downloadFilename(file));
|
|
120
|
+
if ($link.hasClass('hidden')) {
|
|
121
|
+
$link.removeClass('hidden');
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
$link.attr('href', '#').removeAttr('download');
|
|
125
|
+
$link.addClass('hidden');
|
|
87
126
|
}
|
|
88
127
|
} else {
|
|
89
128
|
$link.attr('href', '#').attr('download', '#');
|
|
@@ -312,6 +312,8 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
312
312
|
let $container = options.$target;
|
|
313
313
|
let $fileSelector = $$1('.file-selector', $container);
|
|
314
314
|
let $filesWrapper = $$1('.files-wrapper', $fileSelector);
|
|
315
|
+
let $filesListLoading = $$1('.files-list-loading', $filesWrapper);
|
|
316
|
+
let $filesListLoadingStatus = $$1('.files-list-loading-status', $filesListLoading);
|
|
315
317
|
let $fileContainer = $$1('.files-list', $fileSelector);
|
|
316
318
|
let $placeholder = $$1('.empty', $fileSelector);
|
|
317
319
|
let $uploader = $$1('.file-upload-container', $fileSelector);
|
|
@@ -338,6 +340,18 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
338
340
|
searchMode = !!enabled;
|
|
339
341
|
$fileSelector.toggleClass('search-mode', searchMode);
|
|
340
342
|
});
|
|
343
|
+
function applyFilesListLoading(loading) {
|
|
344
|
+
$filesWrapper.toggleClass('is-files-loading', !!loading);
|
|
345
|
+
$filesWrapper.attr('aria-busy', loading ? 'true' : 'false');
|
|
346
|
+
$filesListLoading.toggleClass('hidden', !loading).attr('aria-hidden', loading ? 'false' : 'true');
|
|
347
|
+
$filesListLoadingStatus.attr('aria-busy', loading ? 'true' : 'false');
|
|
348
|
+
}
|
|
349
|
+
$container.on(`filesloading.${ns}`, function (e, loading) {
|
|
350
|
+
if (searchMode) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
applyFilesListLoading(loading);
|
|
354
|
+
});
|
|
341
355
|
|
|
342
356
|
//update current folder
|
|
343
357
|
$container.on(`folderselect.${ns}`, function (e, fullPath, data, activePath, content) {
|
|
@@ -345,6 +359,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
345
359
|
if (searchMode) {
|
|
346
360
|
return;
|
|
347
361
|
}
|
|
362
|
+
applyFilesListLoading(false);
|
|
348
363
|
|
|
349
364
|
//update title
|
|
350
365
|
if ($container[0].querySelector('.upload')) {
|