@oat-sa/tao-core-ui 3.23.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/figure/FigureStateActive.js +64 -32
- package/dist/image/ImgStateActive/initHelper.js +64 -32
- package/dist/image/ImgStateActive.js +64 -32
- package/dist/previewer.js +1 -1
- package/dist/resourcemgr/assetSearch.js +793 -0
- package/dist/resourcemgr/assetSearchContract.js +477 -0
- package/dist/resourcemgr/css/resourcemgr.css +1230 -97
- package/dist/resourcemgr/css/resourcemgr.css.map +1 -1
- package/dist/resourcemgr/fileBrowser.js +815 -83
- package/dist/resourcemgr/filePreview.js +82 -7
- package/dist/resourcemgr/fileSelector.js +377 -92
- package/dist/resourcemgr.js +314 -57
- package/dist/searchModal/advancedSearch.js +233 -31
- package/package.json +15 -6
- package/src/image/ImgStateActive/initHelper.js +69 -31
- package/src/previewer.js +1 -1
- package/src/resourcemgr/assetSearch.js +847 -0
- package/src/resourcemgr/assetSearchContract.js +489 -0
- package/src/resourcemgr/css/resourcemgr.css +1230 -97
- package/src/resourcemgr/css/resourcemgr.css.map +1 -1
- package/src/resourcemgr/fileBrowser.js +872 -92
- package/src/resourcemgr/filePreview.js +89 -8
- package/src/resourcemgr/fileSelector.js +356 -46
- package/src/resourcemgr/scss/resourcemgr.scss +1450 -89
- package/src/resourcemgr/tpl/advanced-search.tpl +10 -0
- package/src/resourcemgr/tpl/fileSelect.tpl +25 -28
- package/src/resourcemgr/tpl/folder.tpl +4 -1
- package/src/resourcemgr/tpl/layout.tpl +125 -54
- package/src/resourcemgr/tpl/rootFolder.tpl +3 -1
- package/src/resourcemgr.js +294 -47
- package/src/searchModal/advancedSearch.js +242 -31
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib/handlebars/helpers', 'ui/feedback', 'context', 'ui/uploader', 'core/logger'], function ($$1, _, async, __, mimeType, Handlebars, Helpers0, feedback, context, uploader, loggerFactory) { 'use strict';
|
|
1
|
+
define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib/handlebars/helpers', 'ui/feedback', 'context', 'ui/uploader', 'core/logger', 'ui/resourcemgr/assetSearchContract'], function ($$1, _, async, __, mimeType, Handlebars, Helpers0, feedback, context, uploader, loggerFactory, assetSearchContract) { 'use strict';
|
|
2
2
|
|
|
3
3
|
$$1 = $$1 && Object.prototype.hasOwnProperty.call($$1, 'default') ? $$1['default'] : $$1;
|
|
4
4
|
_ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
|
|
@@ -18,12 +18,12 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
18
18
|
var Template = Handlebars.template(function (Handlebars,depth0,helpers,partials,data) {
|
|
19
19
|
this.compilerInfo = [4,'>= 1.0.0'];
|
|
20
20
|
helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
|
|
21
|
-
var buffer = "", stack1,
|
|
21
|
+
var buffer = "", stack1, functionType="function", escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing, self=this;
|
|
22
22
|
|
|
23
23
|
function program1(depth0,data) {
|
|
24
24
|
|
|
25
25
|
var buffer = "", stack1, helper;
|
|
26
|
-
buffer += "\n <
|
|
26
|
+
buffer += "\n <tr data-type=\"";
|
|
27
27
|
if (helper = helpers.type) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
28
28
|
else { helper = (depth0 && depth0.type); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
29
29
|
buffer += escapeExpression(stack1)
|
|
@@ -48,93 +48,98 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
48
48
|
else { helper = (depth0 && depth0.viewUrl); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
49
49
|
buffer += escapeExpression(stack1)
|
|
50
50
|
+ "\"\n ";
|
|
51
|
-
stack1 = helpers['if'].call(depth0, (
|
|
51
|
+
stack1 = helpers['if'].call(depth0, (depth0 && depth0.location), {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data});
|
|
52
52
|
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
53
53
|
buffer += "\n ";
|
|
54
|
-
stack1 = helpers['if'].call(depth0, (
|
|
54
|
+
stack1 = helpers['if'].call(depth0, (depth0 && depth0.updatedAt), {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
|
|
55
55
|
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
56
56
|
buffer += "\n ";
|
|
57
|
-
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.
|
|
57
|
+
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.download), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
|
|
58
|
+
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
59
|
+
buffer += "\n ";
|
|
60
|
+
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.preview), {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
|
|
61
|
+
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
62
|
+
buffer += "\n ";
|
|
63
|
+
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.read), {hash:{},inverse:self.noop,fn:self.program(10, program10, data),data:data});
|
|
58
64
|
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
59
65
|
buffer += "\n data-alt=\"";
|
|
60
66
|
if (helper = helpers.alt) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
61
67
|
else { helper = (depth0 && depth0.alt); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
62
68
|
buffer += escapeExpression(stack1)
|
|
63
|
-
+ "\">\n <span class=\"desc truncate\">";
|
|
69
|
+
+ "\">\n <td class=\"files-label\">\n <span class=\"files-label-inner\">\n <span class=\"file-icon\" aria-hidden=\"true\"></span>\n <span class=\"desc truncate\">";
|
|
64
70
|
if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
65
71
|
else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
66
72
|
buffer += escapeExpression(stack1)
|
|
67
|
-
+ "</span>\n
|
|
68
|
-
|
|
73
|
+
+ "</span>\n </span>\n </td>\n <td class=\"files-location\">\n <span class=\"meta location truncate\" title=\"";
|
|
74
|
+
if (helper = helpers.locationDisplay) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
75
|
+
else { helper = (depth0 && depth0.locationDisplay); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
76
|
+
buffer += escapeExpression(stack1)
|
|
77
|
+
+ "\">";
|
|
78
|
+
if (helper = helpers.locationDisplay) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
79
|
+
else { helper = (depth0 && depth0.locationDisplay); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
80
|
+
buffer += escapeExpression(stack1)
|
|
81
|
+
+ "</span>\n </td>\n <td class=\"files-updated\">\n <span class=\"files-updated-inner\">\n <span class=\"meta updated truncate\" title=\"";
|
|
82
|
+
if (helper = helpers.updatedAtDisplay) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
83
|
+
else { helper = (depth0 && depth0.updatedAtDisplay); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
84
|
+
buffer += escapeExpression(stack1)
|
|
85
|
+
+ "\">";
|
|
86
|
+
if (helper = helpers.updatedAtDisplay) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
87
|
+
else { helper = (depth0 && depth0.updatedAtDisplay); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
88
|
+
buffer += escapeExpression(stack1)
|
|
89
|
+
+ "</span>\n <span class=\"row-actions\">\n ";
|
|
90
|
+
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1['delete']), {hash:{},inverse:self.noop,fn:self.program(12, program12, data),data:data});
|
|
69
91
|
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
70
|
-
buffer += "\n
|
|
92
|
+
buffer += "\n </span>\n </span>\n </td>\n </tr>\n";
|
|
71
93
|
return buffer;
|
|
72
94
|
}
|
|
73
95
|
function program2(depth0,data) {
|
|
74
96
|
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
var buffer = "", stack1, helper;
|
|
98
|
+
buffer += " data-location=\"";
|
|
99
|
+
if (helper = helpers.location) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
100
|
+
else { helper = (depth0 && depth0.location); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
101
|
+
buffer += escapeExpression(stack1)
|
|
102
|
+
+ "\" ";
|
|
103
|
+
return buffer;
|
|
77
104
|
}
|
|
78
105
|
|
|
79
106
|
function program4(depth0,data) {
|
|
80
107
|
|
|
81
|
-
|
|
82
|
-
|
|
108
|
+
var buffer = "", stack1, helper;
|
|
109
|
+
buffer += " data-updated=\"";
|
|
110
|
+
if (helper = helpers.updatedAt) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
111
|
+
else { helper = (depth0 && depth0.updatedAt); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
112
|
+
buffer += escapeExpression(stack1)
|
|
113
|
+
+ "\" ";
|
|
114
|
+
return buffer;
|
|
83
115
|
}
|
|
84
116
|
|
|
85
117
|
function program6(depth0,data) {
|
|
86
118
|
|
|
87
119
|
|
|
88
|
-
return " data-
|
|
120
|
+
return " data-download=\"true\" ";
|
|
89
121
|
}
|
|
90
122
|
|
|
91
123
|
function program8(depth0,data) {
|
|
92
124
|
|
|
93
|
-
var buffer = "", stack1;
|
|
94
|
-
buffer += "\n <span class=\"tlb-group\">\n ";
|
|
95
|
-
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.read), {hash:{},inverse:self.noop,fn:self.program(9, program9, data),data:data});
|
|
96
|
-
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
97
|
-
buffer += "\n ";
|
|
98
|
-
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1.download), {hash:{},inverse:self.noop,fn:self.program(11, program11, data),data:data});
|
|
99
|
-
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
100
|
-
buffer += "\n ";
|
|
101
|
-
stack1 = helpers['if'].call(depth0, ((stack1 = (depth0 && depth0.permissions)),stack1 == null || stack1 === false ? stack1 : stack1['delete']), {hash:{},inverse:self.noop,fn:self.program(13, program13, data),data:data});
|
|
102
|
-
if(stack1 || stack1 === 0) { buffer += stack1; }
|
|
103
|
-
buffer += "\n </span>\n ";
|
|
104
|
-
return buffer;
|
|
105
|
-
}
|
|
106
|
-
function program9(depth0,data) {
|
|
107
125
|
|
|
108
|
-
|
|
109
|
-
buffer += "\n <a href=\"#\" class=\"tlb-button-off select\" title=\""
|
|
110
|
-
+ escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Select this file", options) : helperMissing.call(depth0, "__", "Select this file", options)))
|
|
111
|
-
+ "\"><span class=\"icon-move-item\"></span></a>\n ";
|
|
112
|
-
return buffer;
|
|
126
|
+
return " data-preview=\"true\" ";
|
|
113
127
|
}
|
|
114
128
|
|
|
115
|
-
function
|
|
129
|
+
function program10(depth0,data) {
|
|
116
130
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (helper = helpers.downloadUrl) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
120
|
-
else { helper = (depth0 && depth0.downloadUrl); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
121
|
-
buffer += escapeExpression(stack1)
|
|
122
|
-
+ "\" download=\"";
|
|
123
|
-
if (helper = helpers.name) { stack1 = helper.call(depth0, {hash:{},data:data}); }
|
|
124
|
-
else { helper = (depth0 && depth0.name); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
|
|
125
|
-
buffer += escapeExpression(stack1)
|
|
126
|
-
+ "\" target=\"_blank\" class=\"tlb-button-off download\" title=\""
|
|
127
|
-
+ escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Download this file", options) : helperMissing.call(depth0, "__", "Download this file", options)))
|
|
128
|
-
+ "\"><span class=\"icon-download\"></span></a>\n ";
|
|
129
|
-
return buffer;
|
|
131
|
+
|
|
132
|
+
return " data-select=\"true\" ";
|
|
130
133
|
}
|
|
131
134
|
|
|
132
|
-
function
|
|
135
|
+
function program12(depth0,data) {
|
|
133
136
|
|
|
134
137
|
var buffer = "", helper, options;
|
|
135
|
-
buffer += "\n
|
|
138
|
+
buffer += "\n <a href=\"#\" class=\"delete\" title=\""
|
|
139
|
+
+ escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Remove this file", options) : helperMissing.call(depth0, "__", "Remove this file", options)))
|
|
140
|
+
+ "\" aria-label=\""
|
|
136
141
|
+ escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Remove this file", options) : helperMissing.call(depth0, "__", "Remove this file", options)))
|
|
137
|
-
+ "\"
|
|
142
|
+
+ "\">\n <span class=\"icon-bin\" aria-hidden=\"true\"></span>\n </a>\n ";
|
|
138
143
|
return buffer;
|
|
139
144
|
}
|
|
140
145
|
|
|
@@ -213,13 +218,14 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
213
218
|
*
|
|
214
219
|
* You should have received a copy of the GNU General Public License
|
|
215
220
|
* along with this program; if not, write to the Free Software
|
|
216
|
-
* Foundation, Inc.,
|
|
221
|
+
* Foundation, Inc., 31 Milk St # 960789 Boston, MA 02196 USA.
|
|
217
222
|
*
|
|
218
|
-
* Copyright (c) 2015-
|
|
223
|
+
* Copyright (c) 2015-2026 (original work) Open Assessment Technologies SA;
|
|
219
224
|
*
|
|
220
225
|
*/
|
|
221
226
|
const ns = 'resourcemgr';
|
|
222
227
|
const logger = loggerFactory(`ui/${ns}`);
|
|
228
|
+
const ROW_SELECTOR = '.files-list tr';
|
|
223
229
|
function shortenPath(path) {
|
|
224
230
|
let tokens = path.replace(/\/$/, '').split('/');
|
|
225
231
|
let start = tokens.length - 3;
|
|
@@ -230,6 +236,65 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
230
236
|
title = title.filter(Boolean);
|
|
231
237
|
return title.join('/');
|
|
232
238
|
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Normalize a catalog folder path for the Location column.
|
|
242
|
+
* Strips URI schemes and media-root labels (Assets/Media); keeps directory path only.
|
|
243
|
+
* @param {String} location
|
|
244
|
+
* @returns {String}
|
|
245
|
+
*/
|
|
246
|
+
function formatLocationDisplay(location) {
|
|
247
|
+
if (location === null || typeof location === 'undefined' || location === '') {
|
|
248
|
+
return '';
|
|
249
|
+
}
|
|
250
|
+
let path = String(location).trim().replace(/\\/g, '/');
|
|
251
|
+
if (!path) {
|
|
252
|
+
return '';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Drop URI schemes (taomedia://…, https://…, asset://…)
|
|
256
|
+
path = path.replace(/^[a-z][a-z0-9+.-]*:\/\//i, '');
|
|
257
|
+
// Residual host/path from http(s) after scheme strip
|
|
258
|
+
if (path.indexOf('/') > 0 && /^[^/]+\.[^/]+\//.test(path)) {
|
|
259
|
+
path = path.slice(path.indexOf('/'));
|
|
260
|
+
}
|
|
261
|
+
const segments = path.replace(/^\/+|\/+$/g, '').split('/').filter(Boolean);
|
|
262
|
+
if (!segments.length) {
|
|
263
|
+
return '/';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Directory path only: drop trailing filename-like segment
|
|
267
|
+
const last = segments[segments.length - 1];
|
|
268
|
+
if (segments.length > 1 && /\.[a-z0-9]{1,8}$/i.test(last)) {
|
|
269
|
+
segments.pop();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Strip media-tree root label prefix (Assets, Media, …)
|
|
273
|
+
const rootLabels = ['assets', 'media', 'mediamanager'];
|
|
274
|
+
if (segments.length && rootLabels.indexOf(segments[0].toLowerCase()) !== -1) {
|
|
275
|
+
segments.shift();
|
|
276
|
+
}
|
|
277
|
+
return segments.length ? `/${segments.join('/')}` : '/';
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Format updatedAt as a fixed UTC date-time (YYYY-MM-DD HH:mm).
|
|
282
|
+
* @param {String} value
|
|
283
|
+
* @returns {String}
|
|
284
|
+
*/
|
|
285
|
+
function formatUpdatedAtUtc(value) {
|
|
286
|
+
if (!value) {
|
|
287
|
+
return '';
|
|
288
|
+
}
|
|
289
|
+
const date = new Date(value);
|
|
290
|
+
if (Number.isNaN(date.getTime()) || date.getTime() <= 0) {
|
|
291
|
+
return '—';
|
|
292
|
+
}
|
|
293
|
+
const pad = function (n) {
|
|
294
|
+
return String(n).padStart(2, '0');
|
|
295
|
+
};
|
|
296
|
+
return `${date.getUTCFullYear()}-${pad(date.getUTCMonth() + 1)}-${pad(date.getUTCDate())} ` + `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}`;
|
|
297
|
+
}
|
|
233
298
|
function isTextLarger($element, text) {
|
|
234
299
|
let $dummy = $element.clone().detach().css({
|
|
235
300
|
position: 'absolute',
|
|
@@ -246,12 +311,23 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
246
311
|
let disableUpload = options.disableUpload || false;
|
|
247
312
|
let $container = options.$target;
|
|
248
313
|
let $fileSelector = $$1('.file-selector', $container);
|
|
249
|
-
let $
|
|
314
|
+
let $filesWrapper = $$1('.files-wrapper', $fileSelector);
|
|
315
|
+
let $filesListLoading = $$1('.files-list-loading', $filesWrapper);
|
|
316
|
+
let $filesListLoadingStatus = $$1('.files-list-loading-status', $filesListLoading);
|
|
317
|
+
let $fileContainer = $$1('.files-list', $fileSelector);
|
|
250
318
|
let $placeholder = $$1('.empty', $fileSelector);
|
|
251
319
|
let $uploader = $$1('.file-upload-container', $fileSelector);
|
|
252
320
|
let parentSelector = `#${$container.attr('id')} .file-selector`;
|
|
253
321
|
let $pathTitle = $fileSelector.find('h1 > .title');
|
|
254
|
-
let $browserTitle = $$1('.file-browser > h1', $container);
|
|
322
|
+
let $browserTitle = $$1('.file-browser > h1.resources-title', $container);
|
|
323
|
+
if (!$browserTitle.length) {
|
|
324
|
+
$browserTitle = $$1('.file-browser > h1', $container);
|
|
325
|
+
}
|
|
326
|
+
let searchMode = false;
|
|
327
|
+
let initialSelectionApplied = false;
|
|
328
|
+
let pendingContextSelection = null;
|
|
329
|
+
let sort = Object.assign({}, assetSearchContract.DEFAULT_SORT);
|
|
330
|
+
let lastFiles = [];
|
|
255
331
|
|
|
256
332
|
//set up the uploader
|
|
257
333
|
if (disableUpload) {
|
|
@@ -260,15 +336,30 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
260
336
|
} else {
|
|
261
337
|
setUpUploader(root);
|
|
262
338
|
}
|
|
339
|
+
$container.on(`searchmode.${ns}`, function (e, enabled) {
|
|
340
|
+
searchMode = !!enabled;
|
|
341
|
+
$fileSelector.toggleClass('search-mode', searchMode);
|
|
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
|
+
});
|
|
355
|
+
|
|
263
356
|
//update current folder
|
|
264
357
|
$container.on(`folderselect.${ns}`, function (e, fullPath, data, activePath, content) {
|
|
265
358
|
let files;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return dataItem;
|
|
271
|
-
});
|
|
359
|
+
if (searchMode) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
applyFilesListLoading(false);
|
|
272
363
|
|
|
273
364
|
//update title
|
|
274
365
|
if ($container[0].querySelector('.upload')) {
|
|
@@ -282,37 +373,217 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
282
373
|
|
|
283
374
|
//update content here
|
|
284
375
|
if (_.isArray(data)) {
|
|
285
|
-
files = _.filter(data, function (item) {
|
|
376
|
+
files = _.filter(data.map(ensurePermissions), function (item) {
|
|
286
377
|
return !!item.uri;
|
|
287
378
|
}).map(function (file) {
|
|
288
|
-
file
|
|
289
|
-
if (typeof file.identifier === 'undefined') {
|
|
290
|
-
file.display = `${fullPath}/${file.name}`.replace('//', '/');
|
|
291
|
-
} else {
|
|
292
|
-
file.display = file.identifier + file.name;
|
|
293
|
-
}
|
|
294
|
-
file.viewUrl = `${options.downloadUrl}?${$$1.param(options.params)}&${options.pathParam}=${encodeURIComponent(file.uri)}`;
|
|
295
|
-
file.downloadUrl = `${file.viewUrl}&svgzsupport=true`;
|
|
296
|
-
return file;
|
|
379
|
+
return prepareFileForDisplay(file, fullPath, activePath);
|
|
297
380
|
});
|
|
298
|
-
updateFiles(
|
|
299
|
-
if (
|
|
300
|
-
|
|
381
|
+
updateFiles(files);
|
|
382
|
+
if (pendingContextSelection) {
|
|
383
|
+
const pending = pendingContextSelection;
|
|
384
|
+
initialSelectionApplied = false;
|
|
385
|
+
applyInitialSelection(pending, false);
|
|
386
|
+
if (initialSelectionApplied) {
|
|
387
|
+
pendingContextSelection = null;
|
|
388
|
+
}
|
|
389
|
+
return;
|
|
301
390
|
}
|
|
391
|
+
applyInitialSelection();
|
|
302
392
|
}
|
|
303
393
|
});
|
|
394
|
+
|
|
395
|
+
// Render scoped search results from the service as-is (no client MIME/auth filtering).
|
|
396
|
+
$container.on(`searchresults.${ns}`, function (e, result) {
|
|
397
|
+
const items = result && result.items || [];
|
|
398
|
+
const files = items.filter(function (item) {
|
|
399
|
+
return item && !!item.uri;
|
|
400
|
+
}).map(function (file) {
|
|
401
|
+
return prepareFileForDisplay(ensureSearchPermissions(file), result.path || '', result.path);
|
|
402
|
+
});
|
|
403
|
+
$pathTitle.text(__('Search results'));
|
|
404
|
+
updateFiles(files, {
|
|
405
|
+
emptyMessage: result && result.emptyMessage
|
|
406
|
+
});
|
|
407
|
+
if (!(result && result.error)) {
|
|
408
|
+
applyInitialSelection(result && result.initialSelection);
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Reopen resolve (AC3): defer preselect until folderselect loads the resolved parent folder.
|
|
413
|
+
$container.on(`applycontext.${ns}`, function (e, ctx) {
|
|
414
|
+
initialSelectionApplied = false;
|
|
415
|
+
options.initialSelection = ctx && ctx.selection ? ctx.selection : null;
|
|
416
|
+
options.currentAssetItem = ctx && ctx.currentAssetItem ? ctx.currentAssetItem : null;
|
|
417
|
+
pendingContextSelection = options.initialSelection || null;
|
|
418
|
+
$fileContainer.find('tr.active').removeClass('active');
|
|
419
|
+
});
|
|
304
420
|
function injectTranscriptionMetadata(transcriptionUrl, metadataUri, resourceUri) {
|
|
305
421
|
return `${transcriptionUrl}?metadataUri=${encodeURIComponent(metadataUri)}&resourceUri=${resourceUri.replace('taomedia://mediamanager/', '')}`;
|
|
306
422
|
}
|
|
307
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Normalize ACL flags unless they are already a boolean permission map.
|
|
426
|
+
* @param {Object} item
|
|
427
|
+
* @returns {Object}
|
|
428
|
+
*/
|
|
429
|
+
function ensurePermissions(item) {
|
|
430
|
+
if (item.permissions && !Array.isArray(item.permissions) && typeof item.permissions === 'object') {
|
|
431
|
+
return item;
|
|
432
|
+
}
|
|
433
|
+
return updatePermissions(item);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Search results often omit ACL (indexed gateway). Missing/empty ACL must stay pickable
|
|
438
|
+
* (read/preview/download) without inventing write/delete/upload. Explicit ACL arrays and
|
|
439
|
+
* boolean maps are preserved / mapped via updatePermissions.
|
|
440
|
+
* @param {Object} item
|
|
441
|
+
* @returns {Object}
|
|
442
|
+
*/
|
|
443
|
+
function ensureSearchPermissions(item) {
|
|
444
|
+
if (!item) {
|
|
445
|
+
return item;
|
|
446
|
+
}
|
|
447
|
+
if (item.permissions && !Array.isArray(item.permissions) && typeof item.permissions === 'object') {
|
|
448
|
+
return item;
|
|
449
|
+
}
|
|
450
|
+
if (!item.permissions || Array.isArray(item.permissions) && item.permissions.length === 0) {
|
|
451
|
+
item.permissions = {
|
|
452
|
+
read: true,
|
|
453
|
+
write: false,
|
|
454
|
+
preview: true,
|
|
455
|
+
download: true,
|
|
456
|
+
upload: false,
|
|
457
|
+
delete: false
|
|
458
|
+
};
|
|
459
|
+
return item;
|
|
460
|
+
}
|
|
461
|
+
return updatePermissions(item);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Map a service file record to the selector display model.
|
|
466
|
+
* @param {Object} file
|
|
467
|
+
* @param {String} fullPath
|
|
468
|
+
* @param {String} [folderPath]
|
|
469
|
+
* @returns {Object}
|
|
470
|
+
*/
|
|
471
|
+
function prepareFileForDisplay(file, fullPath, folderPath) {
|
|
472
|
+
file.type = mimeType.getFileType(file);
|
|
473
|
+
if (typeof file.identifier === 'undefined') {
|
|
474
|
+
file.display = `${fullPath}/${file.name}`.replace('//', '/');
|
|
475
|
+
} else {
|
|
476
|
+
file.display = file.identifier + file.name;
|
|
477
|
+
}
|
|
478
|
+
file.viewUrl = `${options.downloadUrl}?${$$1.param(options.params)}&${options.pathParam || 'path'}=${encodeURIComponent(file.uri)}`;
|
|
479
|
+
file.downloadUrl = `${file.viewUrl}&svgzsupport=true`;
|
|
480
|
+
if (!file.location) {
|
|
481
|
+
file.location = folderPath || fullPath || '';
|
|
482
|
+
}
|
|
483
|
+
if (!file.updatedAt && file.updated_at) {
|
|
484
|
+
file.updatedAt = file.updated_at;
|
|
485
|
+
}
|
|
486
|
+
file.locationDisplay = formatLocationDisplay(file.location);
|
|
487
|
+
file.updatedAtDisplay = formatUpdatedAtUtc(file.updatedAt);
|
|
488
|
+
return file;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Sync sort classes and aria-sort on table headers.
|
|
493
|
+
*/
|
|
494
|
+
function applySortHeader() {
|
|
495
|
+
$fileSelector.find('.files thead th[data-sort-by]').each(function () {
|
|
496
|
+
const $th = $$1(this);
|
|
497
|
+
const field = $th.attr('data-sort-by');
|
|
498
|
+
$th.removeClass('sorted sorted_asc sorted_desc');
|
|
499
|
+
if (field === sort.field) {
|
|
500
|
+
$th.addClass('sorted').addClass(sort.direction === 'desc' ? 'sorted_desc' : 'sorted_asc');
|
|
501
|
+
$th.attr('aria-sort', sort.direction === 'desc' ? 'descending' : 'ascending');
|
|
502
|
+
} else {
|
|
503
|
+
$th.attr('aria-sort', 'none');
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Apply a column click to sort state and notify listeners.
|
|
510
|
+
* Skip optimistic re-sort of lastFiles (current page only) — that flashed the
|
|
511
|
+
* wrong order before browse/search refetch; updateFiles still sorts the response.
|
|
512
|
+
* @param {String} field
|
|
513
|
+
*/
|
|
514
|
+
function changeSort(field) {
|
|
515
|
+
if (!field) {
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (field === sort.field) {
|
|
519
|
+
sort = {
|
|
520
|
+
field,
|
|
521
|
+
direction: sort.direction === 'asc' ? 'desc' : 'asc'
|
|
522
|
+
};
|
|
523
|
+
} else {
|
|
524
|
+
sort = {
|
|
525
|
+
field,
|
|
526
|
+
direction: 'asc'
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
applySortHeader();
|
|
530
|
+
$container.trigger(`sortchange.${ns}`, [Object.assign({}, sort)]);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Preselect initialSelection once when the matching row is present.
|
|
535
|
+
* When resolve returned a currentAssetItem missing from the page, inject it.
|
|
536
|
+
* @param {String} [selection]
|
|
537
|
+
* @param {Boolean} [allowInject=true] - inject currentAssetItem when missing (skip during pending reopen)
|
|
538
|
+
*/
|
|
539
|
+
function applyInitialSelection(selection, allowInject) {
|
|
540
|
+
const target = selection || options.initialSelection;
|
|
541
|
+
if (!target || initialSelectionApplied) {
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const mayInject = allowInject !== false;
|
|
545
|
+
let $item = $fileContainer.find('tr').filter(function () {
|
|
546
|
+
return $$1(this).attr('data-file') === String(target);
|
|
547
|
+
});
|
|
548
|
+
if (!$item.length && mayInject && options.currentAssetItem && String(options.currentAssetItem.uri) === String(target)) {
|
|
549
|
+
const injected = prepareFileForDisplay(ensurePermissions(Object.assign({}, options.currentAssetItem)), options.currentAssetItem.location || '', options.currentAssetItem.location || '');
|
|
550
|
+
updateFiles([injected].concat(lastFiles || []));
|
|
551
|
+
$item = $fileContainer.find('tr').filter(function () {
|
|
552
|
+
return $$1(this).attr('data-file') === String(target);
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
if ($item.length) {
|
|
556
|
+
initialSelectionApplied = true;
|
|
557
|
+
$item.first().trigger('click');
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
applySortHeader();
|
|
561
|
+
$$1(parentSelector).off('click.resourcemgr', '.files thead th[data-sort-by]').on('click.resourcemgr', '.files thead th[data-sort-by]', function (e) {
|
|
562
|
+
e.preventDefault();
|
|
563
|
+
e.stopImmediatePropagation();
|
|
564
|
+
changeSort($$1(this).attr('data-sort-by'));
|
|
565
|
+
}).off('keydown.resourcemgr', '.files thead th[data-sort-by]').on('keydown.resourcemgr', '.files thead th[data-sort-by]', function (e) {
|
|
566
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
567
|
+
e.preventDefault();
|
|
568
|
+
e.stopImmediatePropagation();
|
|
569
|
+
changeSort($$1(this).attr('data-sort-by'));
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
|
|
308
573
|
//listen for file activation
|
|
309
|
-
$$1(parentSelector).off('click',
|
|
574
|
+
$$1(parentSelector).off('click', ROW_SELECTOR).on('click', ROW_SELECTOR, function (e) {
|
|
575
|
+
if ($$1(e.target).closest('.row-actions').length) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if ($$1(e.target).closest('a.select, a.download, a.delete').length) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
310
581
|
const clickedItem = e.target;
|
|
311
582
|
if (clickedItem.hasAttribute('data-delete') || $$1(clickedItem).hasClass('icon-bin')) {
|
|
312
583
|
return;
|
|
313
584
|
}
|
|
314
585
|
let $selected = $$1(this);
|
|
315
|
-
let $files = $$1(
|
|
586
|
+
let $files = $$1(ROW_SELECTOR, $fileSelector);
|
|
316
587
|
let data = _.clone($selected.data());
|
|
317
588
|
if (options.resourceMetadataUrl && options.transcriptionMetadata && data.file.includes('taomedia://mediamanager/')) {
|
|
318
589
|
data.transcriptionUrl = injectTranscriptionMetadata(options.resourceMetadataUrl, options.transcriptionMetadata, data.file);
|
|
@@ -323,9 +594,9 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
323
594
|
});
|
|
324
595
|
|
|
325
596
|
//select a file
|
|
326
|
-
$$1(parentSelector).off('click',
|
|
597
|
+
$$1(parentSelector).off('click', `${ROW_SELECTOR} a.select`).on('click', `${ROW_SELECTOR} a.select`, function (e) {
|
|
327
598
|
e.preventDefault();
|
|
328
|
-
let data = _.pick($$1(this).
|
|
599
|
+
let data = _.pick($$1(this).closest('tr').data(), ['file', 'type', 'mime', 'size', 'alt']);
|
|
329
600
|
if (context.mediaSources && context.mediaSources.length === 0 && data.file.indexOf('local/') > -1) {
|
|
330
601
|
data.file = data.file.substring(6);
|
|
331
602
|
}
|
|
@@ -333,7 +604,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
333
604
|
});
|
|
334
605
|
|
|
335
606
|
//delete a file
|
|
336
|
-
$$1(parentSelector).off('click',
|
|
607
|
+
$$1(parentSelector).off('click', `${ROW_SELECTOR} a.delete`).on('click', `${ROW_SELECTOR} a.delete`, function (e) {
|
|
337
608
|
// This function replaces ui/deleter and must follow the same logic.
|
|
338
609
|
// The main difference is that it insert a confirmation dialog before deleting the file.
|
|
339
610
|
e.preventDefault();
|
|
@@ -341,7 +612,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
341
612
|
if ($elt.hasClass(options.disableClass)) {
|
|
342
613
|
return;
|
|
343
614
|
}
|
|
344
|
-
const $target = $elt.closest('
|
|
615
|
+
const $target = $elt.closest('tr');
|
|
345
616
|
const path = $target.data('file');
|
|
346
617
|
const hooks = [];
|
|
347
618
|
if (options.hooks && 'function' === typeof options.hooks.deleteFile) {
|
|
@@ -364,7 +635,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
364
635
|
params = {};
|
|
365
636
|
if (e.namespace === 'deleter' && $target.length) {
|
|
366
637
|
path = $target.data('file');
|
|
367
|
-
params[options.pathParam] = path;
|
|
638
|
+
params[options.pathParam || 'path'] = path;
|
|
368
639
|
$$1.getJSON(options.deleteUrl, _.merge(params, options.params), function (response) {
|
|
369
640
|
if (response.deleted) {
|
|
370
641
|
$container.trigger(`filedelete.${ns}`, [path]);
|
|
@@ -380,7 +651,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
380
651
|
$container.trigger(`filenew.${ns}`, [result, currentPath]);
|
|
381
652
|
});
|
|
382
653
|
$uploader.on('fail.uploader', function (e, file, err) {
|
|
383
|
-
errors.push(__('Unable to upload file %s : %s', file.name, err.message));
|
|
654
|
+
errors.push(__('Unable to upload file %s : %s', _.escape(file && file.name), _.escape(err && err.message)));
|
|
384
655
|
});
|
|
385
656
|
$uploader.on('end.uploader', function () {
|
|
386
657
|
if (errors.length === 0) {
|
|
@@ -396,11 +667,11 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
396
667
|
$uploader.uploader({
|
|
397
668
|
upload: true,
|
|
398
669
|
multiple: true,
|
|
399
|
-
uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam}=${currentPath}`,
|
|
670
|
+
uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam || 'path'}=${currentPath}`,
|
|
400
671
|
fileSelect: function (files, done) {
|
|
401
672
|
let givenLength = files.length;
|
|
402
673
|
let fileNames = [];
|
|
403
|
-
$fileContainer.find('
|
|
674
|
+
$fileContainer.find('.desc').each(function () {
|
|
404
675
|
fileNames.push($$1(this).text().toLowerCase());
|
|
405
676
|
});
|
|
406
677
|
|
|
@@ -434,7 +705,7 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
434
705
|
if (options.fileExistsUrl) {
|
|
435
706
|
let pathParam = `${currentPath}/${file.name}`;
|
|
436
707
|
pathParam.replace('//', '/');
|
|
437
|
-
$$1.getJSON(`${options.fileExistsUrl}?${$$1.param(options.params)}&${options.pathParam}=${pathParam}`, function (response) {
|
|
708
|
+
$$1.getJSON(`${options.fileExistsUrl}?${$$1.param(options.params)}&${options.pathParam || 'path'}=${pathParam}`, function (response) {
|
|
438
709
|
if (response && response.exists === true) {
|
|
439
710
|
//eslint-disable-next-line no-alert
|
|
440
711
|
result = window.confirm(__('Do you want to override "%s"?', file.name));
|
|
@@ -455,22 +726,26 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
455
726
|
$container.on(`folderselect.${ns}`, function (e, fullPath, data, uri) {
|
|
456
727
|
currentPath = uri;
|
|
457
728
|
$uploader.uploader('options', {
|
|
458
|
-
uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam}=${currentPath}&relPath=${currentPath}`
|
|
729
|
+
uploadUrl: `${options.uploadUrl}?${$$1.param(options.params)}&${options.pathParam || 'path'}=${currentPath}&relPath=${currentPath}`
|
|
459
730
|
});
|
|
460
731
|
});
|
|
461
732
|
function setUploadMode(enableUploadMode) {
|
|
462
733
|
if (!enableUploadMode) {
|
|
463
734
|
isUploadMode = false;
|
|
735
|
+
$fileSelector.removeClass('upload-mode');
|
|
464
736
|
$uploader.hide();
|
|
737
|
+
$filesWrapper.show();
|
|
465
738
|
$fileContainer.show();
|
|
466
739
|
// Note: show() would display as inline, not inline-block!
|
|
467
740
|
$switcher.filter('.upload').css({
|
|
468
741
|
display: 'inline-block'
|
|
469
742
|
});
|
|
470
743
|
$switcher.filter('.listing').hide();
|
|
471
|
-
$browserTitle.text(__('
|
|
744
|
+
$browserTitle.text(__('Resources'));
|
|
472
745
|
} else {
|
|
473
746
|
isUploadMode = true;
|
|
747
|
+
$fileSelector.addClass('upload-mode');
|
|
748
|
+
$filesWrapper.hide();
|
|
474
749
|
$fileContainer.hide();
|
|
475
750
|
$placeholder.hide();
|
|
476
751
|
$uploader.show();
|
|
@@ -494,15 +769,25 @@ define(['jquery', 'lodash', 'async', 'i18n', 'core/mimetype', 'handlebars', 'lib
|
|
|
494
769
|
});
|
|
495
770
|
setUploadMode(isUploadMode);
|
|
496
771
|
}
|
|
497
|
-
function updateFiles(
|
|
772
|
+
function updateFiles(files, updateOptions) {
|
|
773
|
+
const displayOptions = updateOptions || {};
|
|
774
|
+
const emptyLabel = displayOptions.emptyMessage || __('No files');
|
|
775
|
+
lastFiles = Array.isArray(files) ? files.slice() : [];
|
|
776
|
+
const sorted = assetSearchContract.sortAssetItems(lastFiles, sort);
|
|
498
777
|
$fileContainer.empty();
|
|
499
|
-
if (
|
|
778
|
+
if (sorted.length) {
|
|
500
779
|
$placeholder.hide();
|
|
780
|
+
$filesWrapper.show();
|
|
501
781
|
$fileContainer.append(fileSelectTpl({
|
|
502
|
-
files:
|
|
782
|
+
files: sorted
|
|
503
783
|
}));
|
|
504
|
-
} else if ($
|
|
505
|
-
$
|
|
784
|
+
} else if ($fileSelector.find('.asset-search-error:not([hidden])').length === 0) {
|
|
785
|
+
$filesWrapper.hide();
|
|
786
|
+
// Stylesheet defaults `.empty` to display:none; force visible for empty states.
|
|
787
|
+
$placeholder.text(emptyLabel).css('display', 'block');
|
|
788
|
+
} else {
|
|
789
|
+
$filesWrapper.hide();
|
|
790
|
+
$placeholder.hide();
|
|
506
791
|
}
|
|
507
792
|
}
|
|
508
793
|
}
|