@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
|
@@ -26,7 +26,18 @@ import { DEFAULT_SORT, sortAssetItems } from 'ui/resourcemgr/assetSearchContract
|
|
|
26
26
|
|
|
27
27
|
const NS = 'resourcemgr';
|
|
28
28
|
const LOGGER = loggerFactory(`ui/${NS}`);
|
|
29
|
-
const DEFAULT_AJAX_TIMEOUT_MS =
|
|
29
|
+
const DEFAULT_AJAX_TIMEOUT_MS = 30000;
|
|
30
|
+
const TREE_LOADING_REF_KEY = `${NS}TreeLoadingRefCount`;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} data
|
|
34
|
+
* @returns {Array}
|
|
35
|
+
*/
|
|
36
|
+
function folderChildrenOnly(data) {
|
|
37
|
+
return _.filter(data && data.children, function (child) {
|
|
38
|
+
return child && child.path && !child.uri;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
30
41
|
|
|
31
42
|
export default function (options) {
|
|
32
43
|
if (!options.browseUrl && options.url) {
|
|
@@ -45,18 +56,53 @@ export default function (options) {
|
|
|
45
56
|
// for pagination
|
|
46
57
|
let selectedClass = {
|
|
47
58
|
path: rootPath,
|
|
48
|
-
childrenLimit:
|
|
59
|
+
childrenLimit: 11,
|
|
49
60
|
total: 0,
|
|
50
61
|
page: 1
|
|
51
62
|
};
|
|
52
63
|
let searchMode = false;
|
|
53
64
|
let sort = Object.assign({}, DEFAULT_SORT);
|
|
65
|
+
const splitBrowse = options.splitBrowse !== false;
|
|
54
66
|
const ajaxTimeoutMs = Number.isFinite(Number(options.ajaxTimeoutMs)) && Number(options.ajaxTimeoutMs) > 0
|
|
55
67
|
? Number(options.ajaxTimeoutMs)
|
|
56
68
|
: DEFAULT_AJAX_TIMEOUT_MS;
|
|
69
|
+
const $treeLoadingOverlay = $('.file-browser-tree-loading', $fileBrowser);
|
|
70
|
+
const $treeLoadingStatus = $('.file-browser-tree-loading-status', $treeLoadingOverlay);
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Ref-count in-flight browse requests and toggle the tree loading overlay.
|
|
74
|
+
* @param {Boolean} increment - true when a load starts, false when it finishes
|
|
75
|
+
*/
|
|
76
|
+
function setTreeLoading(increment) {
|
|
77
|
+
let treeLoadingRefCount = Number($fileBrowser.data(TREE_LOADING_REF_KEY)) || 0;
|
|
78
|
+
treeLoadingRefCount += increment ? 1 : -1;
|
|
79
|
+
if (treeLoadingRefCount < 0) {
|
|
80
|
+
treeLoadingRefCount = 0;
|
|
81
|
+
}
|
|
82
|
+
$fileBrowser.data(TREE_LOADING_REF_KEY, treeLoadingRefCount);
|
|
83
|
+
const loading = treeLoadingRefCount > 0;
|
|
84
|
+
$fileBrowser.toggleClass('is-tree-loading', loading);
|
|
85
|
+
$fileBrowser.attr('aria-busy', loading ? 'true' : 'false');
|
|
86
|
+
$treeLoadingOverlay.toggleClass('hidden', !loading).attr('aria-hidden', loading ? 'false' : 'true');
|
|
87
|
+
$treeLoadingStatus.attr('aria-busy', loading ? 'true' : 'false');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Show or hide the asset table loading overlay (browse mode only).
|
|
92
|
+
* @param {Boolean} loading
|
|
93
|
+
*/
|
|
94
|
+
function setFilesLoading(loading) {
|
|
95
|
+
if (searchMode) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
$container.trigger(`filesloading.${NS}`, [!!loading]);
|
|
99
|
+
}
|
|
57
100
|
|
|
58
101
|
$container.on(`searchmode.${NS}`, function (e, enabled) {
|
|
59
102
|
searchMode = !!enabled;
|
|
103
|
+
if (searchMode) {
|
|
104
|
+
$container.trigger(`filesloading.${NS}`, [false]);
|
|
105
|
+
}
|
|
60
106
|
});
|
|
61
107
|
|
|
62
108
|
$container.on(`sortchange.${NS}`, function (e, nextSort) {
|
|
@@ -77,9 +123,14 @@ export default function (options) {
|
|
|
77
123
|
return;
|
|
78
124
|
}
|
|
79
125
|
const subTree = getByExactPath(fileTree, targetPath) || getByPath(fileTree, targetPath) || fileTree;
|
|
126
|
+
if (!searchMode) {
|
|
127
|
+
setFilesLoading(true);
|
|
128
|
+
}
|
|
80
129
|
getFolderContent(subTree, targetPath, function (content) {
|
|
81
130
|
if (content) {
|
|
82
131
|
selectFolder(content, targetPath);
|
|
132
|
+
} else {
|
|
133
|
+
setFilesLoading(false);
|
|
83
134
|
}
|
|
84
135
|
});
|
|
85
136
|
});
|
|
@@ -103,8 +154,15 @@ export default function (options) {
|
|
|
103
154
|
});
|
|
104
155
|
|
|
105
156
|
//load the content of the ROOT
|
|
157
|
+
const showInitialListLoading = !searchMode && root === 'local';
|
|
158
|
+
if (showInitialListLoading) {
|
|
159
|
+
setFilesLoading(true);
|
|
160
|
+
}
|
|
106
161
|
getFolderContent(fileTree, rootPath, function (content) {
|
|
107
162
|
if (!content) {
|
|
163
|
+
if (showInitialListLoading) {
|
|
164
|
+
setFilesLoading(false);
|
|
165
|
+
}
|
|
108
166
|
return;
|
|
109
167
|
}
|
|
110
168
|
indexTree(content);
|
|
@@ -139,6 +197,8 @@ export default function (options) {
|
|
|
139
197
|
if (root !== 'local') {
|
|
140
198
|
options.hasAlreadySelected = true;
|
|
141
199
|
}
|
|
200
|
+
} else if (showInitialListLoading) {
|
|
201
|
+
setFilesLoading(false);
|
|
142
202
|
}
|
|
143
203
|
});
|
|
144
204
|
|
|
@@ -148,6 +208,15 @@ export default function (options) {
|
|
|
148
208
|
const $selected = $(this);
|
|
149
209
|
const fullPath = $selected.data('path');
|
|
150
210
|
const subTree = getByExactPath(fileTree, fullPath);
|
|
211
|
+
const openingFolder = !searchMode && fullPath !== selectedClass.path;
|
|
212
|
+
|
|
213
|
+
if (openingFolder) {
|
|
214
|
+
selectedClass.page = 1;
|
|
215
|
+
}
|
|
216
|
+
if (!searchMode) {
|
|
217
|
+
setFilesLoading(true);
|
|
218
|
+
}
|
|
219
|
+
invalidateFolderFiles(fullPath);
|
|
151
220
|
|
|
152
221
|
//get the folder content
|
|
153
222
|
getFolderContent(subTree, fullPath, function (content) {
|
|
@@ -179,6 +248,8 @@ export default function (options) {
|
|
|
179
248
|
|
|
180
249
|
//internal event to set the file-selector content
|
|
181
250
|
selectFolder(content, fullPath);
|
|
251
|
+
} else if (!searchMode) {
|
|
252
|
+
setFilesLoading(false);
|
|
182
253
|
}
|
|
183
254
|
});
|
|
184
255
|
});
|
|
@@ -201,11 +272,13 @@ export default function (options) {
|
|
|
201
272
|
|
|
202
273
|
if (targetPath !== selectedClass.path) {
|
|
203
274
|
selectedClass.path = targetPath;
|
|
204
|
-
selectedClass.page = 1;
|
|
205
275
|
}
|
|
276
|
+
selectedClass.page = 1;
|
|
206
277
|
|
|
207
278
|
invalidateFolderFiles(targetPath);
|
|
208
|
-
|
|
279
|
+
const pendingUpload =
|
|
280
|
+
file && !file.error && (file.uri || file.name) ? file : null;
|
|
281
|
+
reloadSortedFolder(pendingUpload ? [pendingUpload] : []);
|
|
209
282
|
});
|
|
210
283
|
|
|
211
284
|
$container.on(`filedelete.${NS}`, function (e, path) {
|
|
@@ -348,23 +421,26 @@ export default function (options) {
|
|
|
348
421
|
$container.data('activeFileBrowserRoot', root);
|
|
349
422
|
if (searchMode) {
|
|
350
423
|
$container.trigger(`folderpath.${NS}`, [path, content.label]);
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
424
|
+
$container.trigger(`folderselect.${NS}`, [
|
|
425
|
+
content.label,
|
|
426
|
+
getFilesForDisplay(content),
|
|
427
|
+
path,
|
|
428
|
+
content
|
|
429
|
+
]);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
359
432
|
updateSelectedClass(path, content.total, content.childrenLimit);
|
|
360
433
|
$container.trigger(`folderpath.${NS}`, [path, content.label]);
|
|
361
434
|
$container.trigger(`folderselect.${NS}`, [
|
|
362
435
|
content.label,
|
|
363
|
-
|
|
436
|
+
getFilesForDisplay(content),
|
|
364
437
|
path,
|
|
365
438
|
content
|
|
366
439
|
]);
|
|
367
440
|
renderPagination();
|
|
441
|
+
if (!searchMode) {
|
|
442
|
+
setFilesLoading(false);
|
|
443
|
+
}
|
|
368
444
|
}
|
|
369
445
|
|
|
370
446
|
/**
|
|
@@ -387,6 +463,180 @@ export default function (options) {
|
|
|
387
463
|
}
|
|
388
464
|
return files;
|
|
389
465
|
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Files for the table (split list payload or legacy children slice).
|
|
469
|
+
* @param {Object} content
|
|
470
|
+
* @returns {Array}
|
|
471
|
+
*/
|
|
472
|
+
function getFilesForDisplay(content) {
|
|
473
|
+
if (!content) {
|
|
474
|
+
return [];
|
|
475
|
+
}
|
|
476
|
+
if (splitBrowse) {
|
|
477
|
+
return content.listItems || [];
|
|
478
|
+
}
|
|
479
|
+
return getPage(content.children || []);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function listCacheKey() {
|
|
483
|
+
return `${sort.field}:${sort.direction}:${selectedClass.page}`;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Snapshot list request identity (folder + page/sort) when a browse starts.
|
|
488
|
+
* @returns {{path: String, cacheKey: String}}
|
|
489
|
+
*/
|
|
490
|
+
function captureListRequestContext() {
|
|
491
|
+
return {
|
|
492
|
+
path: selectedClass.path,
|
|
493
|
+
cacheKey: listCacheKey()
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Whether navigation changed before an in-flight list response should apply.
|
|
499
|
+
* @param {{path: String, cacheKey: String}} captured
|
|
500
|
+
* @returns {Boolean}
|
|
501
|
+
*/
|
|
502
|
+
function isListRequestStale(captured) {
|
|
503
|
+
return (
|
|
504
|
+
!captured ||
|
|
505
|
+
captured.path !== selectedClass.path ||
|
|
506
|
+
captured.cacheKey !== listCacheKey()
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* @param {Object} response
|
|
512
|
+
* @returns {Object}
|
|
513
|
+
*/
|
|
514
|
+
function unwrapBrowseResponse(response) {
|
|
515
|
+
if (response && response.success === false) {
|
|
516
|
+
return Promise.reject(response);
|
|
517
|
+
}
|
|
518
|
+
let data = response && response.data ? response.data : response;
|
|
519
|
+
data = updatePermissions(data);
|
|
520
|
+
if (data.children && data.children.length > 0) {
|
|
521
|
+
data.children = data.children.map(function (child) {
|
|
522
|
+
return updatePermissions(child);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
if (data.items && data.items.length > 0) {
|
|
526
|
+
data.items = data.items.map(function (item) {
|
|
527
|
+
return updatePermissions(item);
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
return data;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* @param {String} path
|
|
535
|
+
* @param {Object} extraData
|
|
536
|
+
* @returns {Promise}
|
|
537
|
+
*/
|
|
538
|
+
function browseRequest(path, extraData) {
|
|
539
|
+
const parameters = {};
|
|
540
|
+
parameters[options.pathParam || 'path'] = path;
|
|
541
|
+
return Promise.resolve(
|
|
542
|
+
$.ajax({
|
|
543
|
+
url: options.browseUrl,
|
|
544
|
+
method: 'GET',
|
|
545
|
+
dataType: 'json',
|
|
546
|
+
timeout: ajaxTimeoutMs,
|
|
547
|
+
data: _.merge(parameters, options.params, extraData)
|
|
548
|
+
})
|
|
549
|
+
).then(unwrapBrowseResponse);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* @param {Object} tree
|
|
554
|
+
* @param {String} path
|
|
555
|
+
* @param {Object} data
|
|
556
|
+
*/
|
|
557
|
+
function applyTreePayload(tree, path, data) {
|
|
558
|
+
const folderData = Object.assign({}, data, { children: folderChildrenOnly(data) });
|
|
559
|
+
if (!tree.path) {
|
|
560
|
+
_.merge(tree, folderData);
|
|
561
|
+
} else if (folderData.children) {
|
|
562
|
+
setToPath(tree, path, folderData);
|
|
563
|
+
if (!_.find(folderData.children, 'path')) {
|
|
564
|
+
markFolderEmptyAtPath(tree, path);
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
setToPath(tree, path, folderData);
|
|
568
|
+
markFolderEmptyAtPath(tree, path);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* @param {Object} tree
|
|
574
|
+
* @param {String} path
|
|
575
|
+
* @param {Object} listData
|
|
576
|
+
* @param {String} cacheKey
|
|
577
|
+
*/
|
|
578
|
+
function applyListPayload(tree, path, listData, cacheKey) {
|
|
579
|
+
const node = getByExactPath(tree, path) || getByPath(tree, path);
|
|
580
|
+
if (!node || !listData) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
node.listItems = listData.items || [];
|
|
584
|
+
node.total = listData.total;
|
|
585
|
+
node.childrenLimit = listData.pageSize || listData.childrenLimit || selectedClass.childrenLimit;
|
|
586
|
+
node.listPage = listData.page;
|
|
587
|
+
node.totalIsApproximate = listData.totalIsApproximate;
|
|
588
|
+
node.listCacheKey = cacheKey;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Ensure upload responses appear in the table before Elasticsearch catches up.
|
|
593
|
+
* @param {String} path
|
|
594
|
+
* @param {Array<Object>} uploads
|
|
595
|
+
*/
|
|
596
|
+
function mergePendingUploads(path, uploads) {
|
|
597
|
+
if (!uploads || !uploads.length) {
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
const node = getByExactPath(fileTree, path) || getByPath(fileTree, path);
|
|
601
|
+
if (!node) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (!Array.isArray(node.listItems)) {
|
|
605
|
+
node.listItems = [];
|
|
606
|
+
}
|
|
607
|
+
let added = 0;
|
|
608
|
+
uploads.forEach(function (uploaded) {
|
|
609
|
+
if (!uploaded || uploaded.error) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const normalized = updatePermissions(uploaded);
|
|
613
|
+
if (!normalized.uri && !normalized.name) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const exists = _.some(node.listItems, function (item) {
|
|
617
|
+
return (
|
|
618
|
+
(normalized.uri && item.uri === normalized.uri) ||
|
|
619
|
+
(normalized.name && item.name === normalized.name)
|
|
620
|
+
);
|
|
621
|
+
});
|
|
622
|
+
if (exists) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
node.listItems.push(normalized);
|
|
626
|
+
added++;
|
|
627
|
+
});
|
|
628
|
+
if (!added) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (splitBrowse) {
|
|
632
|
+
node.listItems = sortAssetItems(node.listItems, sort);
|
|
633
|
+
}
|
|
634
|
+
const total = Number(node.total);
|
|
635
|
+
if (Number.isFinite(total) && total >= 0) {
|
|
636
|
+
node.total = total + added;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
390
640
|
/**
|
|
391
641
|
* Get the content of a folder, either in the model or load it
|
|
392
642
|
* @param {Object} tree - the tree model
|
|
@@ -401,6 +651,57 @@ export default function (options) {
|
|
|
401
651
|
}
|
|
402
652
|
|
|
403
653
|
function getFolderContent(tree, path, cb) {
|
|
654
|
+
if (splitBrowse) {
|
|
655
|
+
const existing = getByExactPath(tree, path) || getByPath(tree, path);
|
|
656
|
+
const needTree = !existing || (!existing.children && !existing.empty);
|
|
657
|
+
const cacheKey = listCacheKey();
|
|
658
|
+
const needList = !existing || existing.listCacheKey !== cacheKey;
|
|
659
|
+
|
|
660
|
+
const treePromise = needTree
|
|
661
|
+
? (setTreeLoading(true),
|
|
662
|
+
browseRequest(path, {
|
|
663
|
+
part: 'tree',
|
|
664
|
+
depth: 1,
|
|
665
|
+
sortBy: sort.field,
|
|
666
|
+
sortDir: sort.direction
|
|
667
|
+
}).then(
|
|
668
|
+
function (data) {
|
|
669
|
+
setTreeLoading(false);
|
|
670
|
+
return data;
|
|
671
|
+
},
|
|
672
|
+
function (error) {
|
|
673
|
+
setTreeLoading(false);
|
|
674
|
+
return Promise.reject(error);
|
|
675
|
+
}
|
|
676
|
+
))
|
|
677
|
+
: Promise.resolve(null);
|
|
678
|
+
|
|
679
|
+
const listPromise = needList
|
|
680
|
+
? browseRequest(path, {
|
|
681
|
+
part: 'list',
|
|
682
|
+
page: selectedClass.page,
|
|
683
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
684
|
+
sortBy: sort.field,
|
|
685
|
+
sortDir: sort.direction
|
|
686
|
+
})
|
|
687
|
+
: Promise.resolve(null);
|
|
688
|
+
|
|
689
|
+
Promise.all([treePromise, listPromise])
|
|
690
|
+
.then(function ([treeData, listData]) {
|
|
691
|
+
if (treeData) {
|
|
692
|
+
applyTreePayload(tree, path, treeData);
|
|
693
|
+
}
|
|
694
|
+
if (listData) {
|
|
695
|
+
applyListPayload(tree, path, listData, cacheKey);
|
|
696
|
+
}
|
|
697
|
+
cb(getByExactPath(tree, path) || getByPath(tree, path));
|
|
698
|
+
})
|
|
699
|
+
.catch(function () {
|
|
700
|
+
cb(null);
|
|
701
|
+
});
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
|
|
404
705
|
let content = getByPath(tree, path);
|
|
405
706
|
if (!content || (!content.children && !content.empty)) {
|
|
406
707
|
loadContent(path).then(function (data) {
|
|
@@ -426,7 +727,7 @@ export default function (options) {
|
|
|
426
727
|
});
|
|
427
728
|
// Use folder total (not selectedClass): openInitialPath runs before selectFolder.
|
|
428
729
|
const expectedTotal = Number(content.total);
|
|
429
|
-
const pageSize = Number(content.childrenLimit) || selectedClass.childrenLimit ||
|
|
730
|
+
const pageSize = Number(content.childrenLimit) || selectedClass.childrenLimit || 11;
|
|
430
731
|
const page = selectedClass.page || 1;
|
|
431
732
|
// Missing/NaN total → unknown size; refetch so invalidated cache is not treated as complete.
|
|
432
733
|
if (
|
|
@@ -588,7 +889,16 @@ export default function (options) {
|
|
|
588
889
|
*/
|
|
589
890
|
function invalidateFolderFiles(path) {
|
|
590
891
|
const content = getByExactPath(fileTree, path);
|
|
591
|
-
if (content
|
|
892
|
+
if (!content) {
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (splitBrowse) {
|
|
896
|
+
delete content.listItems;
|
|
897
|
+
delete content.listCacheKey;
|
|
898
|
+
delete content.listPage;
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
if (Array.isArray(content.children)) {
|
|
592
902
|
content.children = content.children.filter(function (child) {
|
|
593
903
|
return child.path && !child.uri;
|
|
594
904
|
});
|
|
@@ -600,11 +910,15 @@ export default function (options) {
|
|
|
600
910
|
* @param {String} path
|
|
601
911
|
* @param {Object} data
|
|
602
912
|
*/
|
|
603
|
-
function replaceFolderContent(path, data) {
|
|
913
|
+
function replaceFolderContent(path, data, cacheKey) {
|
|
604
914
|
const content = getByExactPath(fileTree, path);
|
|
605
915
|
if (!content || !data) {
|
|
606
916
|
return;
|
|
607
917
|
}
|
|
918
|
+
if (splitBrowse && Object.prototype.hasOwnProperty.call(data, 'items')) {
|
|
919
|
+
applyListPayload(fileTree, path, data, cacheKey || listCacheKey());
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
608
922
|
if (Object.prototype.hasOwnProperty.call(data, 'children')) {
|
|
609
923
|
content.children = data.children;
|
|
610
924
|
} else {
|
|
@@ -634,6 +948,7 @@ export default function (options) {
|
|
|
634
948
|
function loadContent(path) {
|
|
635
949
|
const parameters = {};
|
|
636
950
|
parameters[options.pathParam || 'path'] = path;
|
|
951
|
+
setTreeLoading(true);
|
|
637
952
|
return Promise.resolve(
|
|
638
953
|
$.ajax({
|
|
639
954
|
url: options.browseUrl,
|
|
@@ -649,17 +964,28 @@ export default function (options) {
|
|
|
649
964
|
sortDir: sort.direction
|
|
650
965
|
})
|
|
651
966
|
})
|
|
652
|
-
)
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
data.children.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
967
|
+
)
|
|
968
|
+
.then(function (response) {
|
|
969
|
+
if (response && response.success === false) {
|
|
970
|
+
return Promise.reject(response);
|
|
971
|
+
}
|
|
972
|
+
let data = response && response.data ? response.data : response;
|
|
973
|
+
data = updatePermissions(data);
|
|
974
|
+
if (data.children && data.children.length > 0) {
|
|
975
|
+
data.children.map(responseChildren => updatePermissions(responseChildren));
|
|
976
|
+
}
|
|
977
|
+
return data;
|
|
978
|
+
})
|
|
979
|
+
.then(
|
|
980
|
+
function (data) {
|
|
981
|
+
setTreeLoading(false);
|
|
982
|
+
return data;
|
|
983
|
+
},
|
|
984
|
+
function (error) {
|
|
985
|
+
setTreeLoading(false);
|
|
986
|
+
return Promise.reject(error);
|
|
987
|
+
}
|
|
988
|
+
);
|
|
663
989
|
}
|
|
664
990
|
|
|
665
991
|
/**
|
|
@@ -732,7 +1058,7 @@ export default function (options) {
|
|
|
732
1058
|
childrenLimit:
|
|
733
1059
|
Number.isFinite(normalizedChildrenLimit) && normalizedChildrenLimit > 0
|
|
734
1060
|
? normalizedChildrenLimit
|
|
735
|
-
: selectedClass.childrenLimit ||
|
|
1061
|
+
: selectedClass.childrenLimit || 11,
|
|
736
1062
|
page: 1
|
|
737
1063
|
};
|
|
738
1064
|
}
|
|
@@ -776,19 +1102,40 @@ export default function (options) {
|
|
|
776
1102
|
/**
|
|
777
1103
|
* Re-fetch the current folder with the active sort and publish files.
|
|
778
1104
|
*/
|
|
779
|
-
function reloadSortedFolder() {
|
|
780
|
-
const
|
|
781
|
-
|
|
1105
|
+
function reloadSortedFolder(pendingUploads) {
|
|
1106
|
+
const listRequest = captureListRequestContext();
|
|
1107
|
+
const path = listRequest.path;
|
|
1108
|
+
if (!searchMode && isActiveBrowser()) {
|
|
1109
|
+
setFilesLoading(true);
|
|
1110
|
+
}
|
|
1111
|
+
const loadPromise = splitBrowse
|
|
1112
|
+
? browseRequest(path, {
|
|
1113
|
+
part: 'list',
|
|
1114
|
+
page: selectedClass.page,
|
|
1115
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
1116
|
+
sortBy: sort.field,
|
|
1117
|
+
sortDir: sort.direction
|
|
1118
|
+
})
|
|
1119
|
+
: loadContent(path);
|
|
1120
|
+
|
|
1121
|
+
loadPromise
|
|
782
1122
|
.then(function (data) {
|
|
783
1123
|
if (!data) {
|
|
1124
|
+
setFilesLoading(false);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (isListRequestStale(listRequest)) {
|
|
1128
|
+
setFilesLoading(false);
|
|
784
1129
|
return;
|
|
785
1130
|
}
|
|
786
|
-
replaceFolderContent(path, data);
|
|
1131
|
+
replaceFolderContent(path, data, listRequest.cacheKey);
|
|
1132
|
+
mergePendingUploads(path, pendingUploads);
|
|
787
1133
|
const content = getByExactPath(fileTree, path) || data;
|
|
788
1134
|
selectFolder(content, content.path || path);
|
|
789
1135
|
})
|
|
790
1136
|
.catch(function (error) {
|
|
791
1137
|
LOGGER.error(error);
|
|
1138
|
+
setFilesLoading(false);
|
|
792
1139
|
});
|
|
793
1140
|
}
|
|
794
1141
|
|
|
@@ -796,15 +1143,69 @@ export default function (options) {
|
|
|
796
1143
|
* Load page
|
|
797
1144
|
*/
|
|
798
1145
|
function loadPage() {
|
|
1146
|
+
const listRequest = captureListRequestContext();
|
|
1147
|
+
|
|
1148
|
+
if (!searchMode && isActiveBrowser()) {
|
|
1149
|
+
setFilesLoading(true);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
if (splitBrowse) {
|
|
1153
|
+
const path = listRequest.path;
|
|
1154
|
+
browseRequest(path, {
|
|
1155
|
+
part: 'list',
|
|
1156
|
+
page: selectedClass.page,
|
|
1157
|
+
pageSize: selectedClass.childrenLimit || 11,
|
|
1158
|
+
sortBy: sort.field,
|
|
1159
|
+
sortDir: sort.direction
|
|
1160
|
+
})
|
|
1161
|
+
.then(function (data) {
|
|
1162
|
+
if (isListRequestStale(listRequest)) {
|
|
1163
|
+
setFilesLoading(false);
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
applyListPayload(fileTree, path, data, listRequest.cacheKey);
|
|
1167
|
+
const content = getByExactPath(fileTree, path);
|
|
1168
|
+
if (content) {
|
|
1169
|
+
$container.trigger(`folderselect.${NS}`, [
|
|
1170
|
+
content.label,
|
|
1171
|
+
getFilesForDisplay(content),
|
|
1172
|
+
content.path,
|
|
1173
|
+
content
|
|
1174
|
+
]);
|
|
1175
|
+
renderPagination();
|
|
1176
|
+
}
|
|
1177
|
+
setFilesLoading(false);
|
|
1178
|
+
})
|
|
1179
|
+
.catch(function (error) {
|
|
1180
|
+
LOGGER.error(error);
|
|
1181
|
+
setFilesLoading(false);
|
|
1182
|
+
});
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
799
1186
|
const subTree = getByPath(fileTree, selectedClass.path) || fileTree;
|
|
800
1187
|
|
|
801
1188
|
//get the folder content
|
|
802
1189
|
getFolderContent(subTree, selectedClass.path, function (content) {
|
|
1190
|
+
if (isListRequestStale(listRequest)) {
|
|
1191
|
+
if (!searchMode) {
|
|
1192
|
+
setFilesLoading(false);
|
|
1193
|
+
}
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
803
1196
|
indexTree(fileTree);
|
|
804
1197
|
|
|
805
1198
|
if (content) {
|
|
806
1199
|
//internal event to set the file-selector content
|
|
807
|
-
$container.trigger(`folderselect.${NS}`, [
|
|
1200
|
+
$container.trigger(`folderselect.${NS}`, [
|
|
1201
|
+
content.label,
|
|
1202
|
+
getFilesForDisplay(content),
|
|
1203
|
+
content.path,
|
|
1204
|
+
content
|
|
1205
|
+
]);
|
|
1206
|
+
}
|
|
1207
|
+
if (!searchMode) {
|
|
1208
|
+
setFilesLoading(false);
|
|
808
1209
|
}
|
|
809
1210
|
});
|
|
810
1211
|
}
|
|
@@ -72,6 +72,39 @@ export default function(options) {
|
|
|
72
72
|
return String(value);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Row markup uses data-download for permission flag (boolean), not the URL.
|
|
77
|
+
* @param {*} file
|
|
78
|
+
* @returns {string}
|
|
79
|
+
*/
|
|
80
|
+
function downloadHref(file) {
|
|
81
|
+
if (typeof file.downloadUrl === 'string' && file.downloadUrl) {
|
|
82
|
+
return file.downloadUrl;
|
|
83
|
+
}
|
|
84
|
+
if (typeof file.url === 'string' && file.url) {
|
|
85
|
+
const query = file.url.split('#')[0].split('?')[1] || '';
|
|
86
|
+
const hasSvgzSupport = query.split('&').some(param => param.split('=')[0] === 'svgzsupport');
|
|
87
|
+
return hasSvgzSupport ? file.url : `${file.url}&svgzsupport=true`;
|
|
88
|
+
}
|
|
89
|
+
if (typeof file.download === 'string' && file.download) {
|
|
90
|
+
return file.download;
|
|
91
|
+
}
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {*} file
|
|
97
|
+
* @returns {string}
|
|
98
|
+
*/
|
|
99
|
+
function downloadFilename(file) {
|
|
100
|
+
if (typeof file.display === 'string' && file.display) {
|
|
101
|
+
return file.display;
|
|
102
|
+
}
|
|
103
|
+
const path = file.file || '';
|
|
104
|
+
const idx = path.lastIndexOf('/');
|
|
105
|
+
return idx >= 0 ? path.slice(idx + 1) : path;
|
|
106
|
+
}
|
|
107
|
+
|
|
75
108
|
function startPreview(file, preview, download, select) {
|
|
76
109
|
if (preview) {
|
|
77
110
|
$previewer.previewer(file);
|
|
@@ -91,10 +124,16 @@ export default function(options) {
|
|
|
91
124
|
$propType.text(EMPTY_META);
|
|
92
125
|
$propSize.text(EMPTY_META);
|
|
93
126
|
}
|
|
94
|
-
if(download) {
|
|
95
|
-
|
|
96
|
-
if (
|
|
97
|
-
$link.
|
|
127
|
+
if (download) {
|
|
128
|
+
const href = downloadHref(file);
|
|
129
|
+
if (href) {
|
|
130
|
+
$link.attr('href', href).attr('download', downloadFilename(file));
|
|
131
|
+
if ($link.hasClass('hidden')) {
|
|
132
|
+
$link.removeClass('hidden');
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
$link.attr('href', '#').removeAttr('download');
|
|
136
|
+
$link.addClass('hidden');
|
|
98
137
|
}
|
|
99
138
|
} else {
|
|
100
139
|
$link.attr('href', '#').attr('download', '#');
|