@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.
Files changed (31) hide show
  1. package/dist/figure/FigureStateActive.js +64 -32
  2. package/dist/image/ImgStateActive/initHelper.js +64 -32
  3. package/dist/image/ImgStateActive.js +64 -32
  4. package/dist/previewer.js +1 -1
  5. package/dist/resourcemgr/assetSearch.js +793 -0
  6. package/dist/resourcemgr/assetSearchContract.js +477 -0
  7. package/dist/resourcemgr/css/resourcemgr.css +1230 -97
  8. package/dist/resourcemgr/css/resourcemgr.css.map +1 -1
  9. package/dist/resourcemgr/fileBrowser.js +815 -83
  10. package/dist/resourcemgr/filePreview.js +82 -7
  11. package/dist/resourcemgr/fileSelector.js +377 -92
  12. package/dist/resourcemgr.js +314 -57
  13. package/dist/searchModal/advancedSearch.js +233 -31
  14. package/package.json +15 -6
  15. package/src/image/ImgStateActive/initHelper.js +69 -31
  16. package/src/previewer.js +1 -1
  17. package/src/resourcemgr/assetSearch.js +847 -0
  18. package/src/resourcemgr/assetSearchContract.js +489 -0
  19. package/src/resourcemgr/css/resourcemgr.css +1230 -97
  20. package/src/resourcemgr/css/resourcemgr.css.map +1 -1
  21. package/src/resourcemgr/fileBrowser.js +872 -92
  22. package/src/resourcemgr/filePreview.js +89 -8
  23. package/src/resourcemgr/fileSelector.js +356 -46
  24. package/src/resourcemgr/scss/resourcemgr.scss +1450 -89
  25. package/src/resourcemgr/tpl/advanced-search.tpl +10 -0
  26. package/src/resourcemgr/tpl/fileSelect.tpl +25 -28
  27. package/src/resourcemgr/tpl/folder.tpl +4 -1
  28. package/src/resourcemgr/tpl/layout.tpl +125 -54
  29. package/src/resourcemgr/tpl/rootFolder.tpl +3 -1
  30. package/src/resourcemgr.js +294 -47
  31. package/src/searchModal/advancedSearch.js +242 -31
@@ -1,10 +1,14 @@
1
1
  import $ from 'jquery';
2
2
  import _ from 'lodash';
3
3
  import Pluginifier from 'core/pluginifier';
4
+ import assetSearch from 'ui/resourcemgr/assetSearch';
4
5
  import fileBrowser from 'ui/resourcemgr/fileBrowser';
5
6
  import filePreview from 'ui/resourcemgr/filePreview';
6
7
  import fileSelector from 'ui/resourcemgr/fileSelector';
8
+ import feedback from 'ui/feedback';
7
9
  import layout from 'ui/resourcemgr/tpl/layout';
10
+ import urlUtil from 'util/url';
11
+ import __ from 'i18n';
8
12
  import 'ui/modal';
9
13
  import 'ui/resourcemgr/css/resourcemgr.css';
10
14
 
@@ -15,7 +19,14 @@ var defaults = {
15
19
  mediaSources: [{ root: 'local', path: '/' }],
16
20
  open: true,
17
21
  appendContainer: '.tao-scope:first',
18
- title: ''
22
+ title: '',
23
+ pathParam: 'path',
24
+ // Advanced Search metadata filters (same endpoints as ui/searchModal)
25
+ rootClassUri: 'http://www.tao.lu/Ontologies/TAOMedia.rdf#Media',
26
+ classMappingUrl: urlUtil.route('getWithMapping', 'ClassMetadata', 'tao'),
27
+ statusUrl: urlUtil.route('status', 'AdvancedSearch', 'tao'),
28
+ maxListSize: 5,
29
+ ajaxTimeoutMs: 30000
19
30
  };
20
31
 
21
32
  /**
@@ -34,7 +45,18 @@ var resourceMgr = {
34
45
  * @constructor
35
46
  * @param {Object} options - the plugin options
36
47
  * @param {Sring|Boolean} [options.bindEvent = 'click'] - the event that trigger the toggling
37
- * @param {String} options.url - the URL of the service used to retrieve the resources.
48
+ * @param {String} [options.browseUrl] - folder browse endpoint (legacy alias: options.url)
49
+ * @param {String} [options.url] - legacy alias for browseUrl
50
+ * @param {String} [options.searchUrl] - scoped asset-search endpoint; omit for browse-only
51
+ * @param {Boolean} [options.browseSearchFallback=false] - client filter when searchUrl returns browse-shaped `{ children }`
52
+ * @param {String} [options.initialPath] - folder to open on start (within the media source tree)
53
+ * @param {String} [options.initialSelection] - asset URI to preselect when present in results
54
+ * @param {String} [options.currentAsset] - asset URI/path to resolve to parent folder + selection
55
+ * @param {String} [options.pathParam='path'] - query parameter name for folder/asset path
56
+ * @param {String} [options.rootClassUri=TAOMedia#Media] - Assets class URI for Advanced Search criteria (metadata filters)
57
+ * @param {String} [options.classMappingUrl] - ClassMetadata mapping endpoint for criteria list
58
+ * @param {String} [options.statusUrl] - Advanced Search status endpoint
59
+ * @param {Number} [options.maxListSize=5] - max list values per criterion in filters UI
38
60
  * @fires ResourceMgr#create.resourcemgr
39
61
  * @returns {jQueryElement} for chaining
40
62
  */
@@ -43,6 +65,9 @@ var resourceMgr = {
43
65
 
44
66
  //get options using default
45
67
  options = _.defaults(options, defaults);
68
+ if (!options.browseUrl && options.url) {
69
+ options.browseUrl = options.url;
70
+ }
46
71
 
47
72
  return this.each(function() {
48
73
  var $elt = $(this);
@@ -55,7 +80,10 @@ var resourceMgr = {
55
80
  //auto bind events configured in options
56
81
  _.functions(options).forEach(function(eventName) {
57
82
  $elt.on(eventName + '.' + ns, function() {
58
- options[eventName].apply($elt, arguments);
83
+ const live = $elt.data(dataNs);
84
+ if (live && typeof live[eventName] === 'function') {
85
+ live[eventName].apply($elt, arguments);
86
+ }
59
87
  });
60
88
  });
61
89
 
@@ -74,56 +102,273 @@ var resourceMgr = {
74
102
  $target.on('closed.modal', function() {
75
103
  $elt.trigger('close.' + ns);
76
104
  });
77
- //initialize the components
78
- const $fileBrowser = $('.file-browser .file-browser-wrapper', $target);
79
- if (options.mediaSourcesUrl) {
80
- $.getJSON(options.mediaSourcesUrl)
81
- .done(function(data) {
82
- const mediaSources = data || defaults.mediaSources;
83
- for (let i = 0; i < mediaSources.length; i++) {
84
- options.root = mediaSources[i].root;
85
- options.path = mediaSources[i].path;
86
- $fileBrowser.append(
87
- '<div class="' + options.root + '"><ul class="folders"></ul></div>'
88
- );
89
- fileBrowser(options);
90
- }
91
- })
92
- .fail(function() {
93
- for (let i = 0; i < defaults.mediaSources.length; i++) {
94
- options.root = defaults.mediaSources[i].root;
95
- options.path = defaults.mediaSources[i].path;
96
- $fileBrowser.append(
97
- '<div class="' + options.root + '"><ul class="folders"></ul></div>'
98
- );
99
- fileBrowser(options);
100
- }
101
- });
102
- } else if (options.path && options.root) {
103
- $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
104
- fileBrowser(options);
105
+
106
+ options.contextToken = 1;
107
+ const initToken = options.contextToken;
108
+ $elt.data(dataNs, options);
109
+
110
+ that._resolveCurrentAssetContext(options, initToken).always(function(resolvedOptions) {
111
+ const current = $elt.data(dataNs);
112
+ if (!current) {
113
+ return;
114
+ }
115
+ const ownsOpen = current.contextToken === initToken;
116
+ if (!ownsOpen) {
117
+ return;
118
+ }
119
+ $elt.data(dataNs, resolvedOptions);
120
+
121
+ that._ensureBrowsersStarted($elt, resolvedOptions).always(function() {
122
+ const latest = $elt.data(dataNs) || resolvedOptions;
123
+ if (!latest._createEventEmitted) {
124
+ latest._createEventEmitted = true;
125
+ $elt.data(dataNs, latest);
126
+ /**
127
+ * The plugin have been created.
128
+ * @event ResourceMgr#create.resourcemgr
129
+ */
130
+ $elt.trigger('create.' + ns, [latest.$target[0]]);
131
+ }
132
+
133
+ if (ownsOpen && latest.open) {
134
+ that._open($elt);
135
+ }
136
+ });
137
+ });
138
+ } else {
139
+ // Reopen: consumer may pass a new currentAsset (edit/change after create).
140
+ that._reopenWithContext($elt, options);
141
+ }
142
+ });
143
+ },
144
+
145
+ /**
146
+ * Merge reopen options, re-resolve currentAsset, re-apply folder/selection, then open.
147
+ * @param {jQuery} $elt
148
+ * @param {Object} incoming - options from the latest .resourcemgr(…) call
149
+ */
150
+ _reopenWithContext: function($elt, incoming) {
151
+ const that = resourceMgr;
152
+ const stored = $elt.data(dataNs);
153
+ if (!stored) {
154
+ return;
155
+ }
156
+
157
+ if (Object.prototype.hasOwnProperty.call(incoming, 'currentAsset')) {
158
+ stored.currentAsset = incoming.currentAsset;
159
+ stored.initialPath = null;
160
+ stored.initialSelection = null;
161
+ stored.currentAssetItem = null;
162
+ }
163
+ if (incoming.params && typeof incoming.params === 'object') {
164
+ stored.params = Object.assign({}, stored.params || {}, incoming.params);
165
+ }
166
+ ['select', 'open', 'close'].forEach(function(key) {
167
+ if (typeof incoming[key] === 'function') {
168
+ stored[key] = incoming[key];
169
+ }
170
+ });
171
+
172
+ stored.contextToken = (stored.contextToken || 0) + 1;
173
+ const token = stored.contextToken;
174
+ $elt.data(dataNs, stored);
175
+
176
+ that._resolveCurrentAssetContext(stored, token).always(function(resolved) {
177
+ const current = $elt.data(dataNs);
178
+ if (!current || current.contextToken !== token) {
179
+ return;
180
+ }
181
+ $elt.data(dataNs, resolved);
182
+ that._ensureBrowsersStarted($elt, resolved).always(function() {
183
+ that._applyResolvedContext($elt, resolved);
184
+ that._open($elt);
185
+ });
186
+ });
187
+ },
188
+
189
+ /**
190
+ * Notify mounted browser/selector to open parent folder and (re)preselect.
191
+ * @param {jQuery} $elt
192
+ * @param {Object} options
193
+ */
194
+ _applyResolvedContext: function($elt, options) {
195
+ if (!options || !options.$target) {
196
+ return;
197
+ }
198
+ options.$target.trigger('applycontext.' + ns, [
199
+ {
200
+ path: options.initialPath || options.path || '/',
201
+ selection: options.initialSelection || null,
202
+ currentAssetItem: options.currentAssetItem || null
203
+ }
204
+ ]);
205
+ },
206
+
207
+ /**
208
+ * Resolve currentAsset via browse/search endpoint into initialPath/initialSelection.
209
+ * @param {Object} options
210
+ * @param {number} [expectedToken] - contextToken that must still match before mutating options
211
+ * @returns {Promise}
212
+ */
213
+ _resolveCurrentAssetContext: function(options, expectedToken) {
214
+ const deferred = $.Deferred();
215
+ const isStale = function() {
216
+ return typeof expectedToken !== 'undefined' && expectedToken !== null && options.contextToken !== expectedToken;
217
+ };
218
+ if (!options.currentAsset || (!options.browseUrl && !options.searchUrl)) {
219
+ deferred.resolve(options);
220
+ return deferred.promise();
221
+ }
222
+
223
+ const endpoint = options.browseUrl || options.searchUrl;
224
+ const pathParam = options.pathParam || 'path';
225
+ const params = Object.assign({}, options.params || {}, {
226
+ currentAsset: options.currentAsset
227
+ });
228
+ params[pathParam] = options.path || '/';
229
+
230
+ $.ajax({
231
+ url: endpoint,
232
+ method: 'GET',
233
+ dataType: 'json',
234
+ timeout: Number(options.ajaxTimeoutMs) > 0 ? Number(options.ajaxTimeoutMs) : defaults.ajaxTimeoutMs,
235
+ data: params
236
+ })
237
+ .done(function(response) {
238
+ if (isStale()) {
239
+ deferred.resolve(options);
240
+ return;
241
+ }
242
+ const payload = response && response.data ? response.data : response;
243
+ if (payload && payload.parentPath) {
244
+ options.initialPath = payload.parentPath;
105
245
  }
246
+ if (payload && payload.currentAsset && payload.currentAsset.uri) {
247
+ options.initialSelection = payload.currentAsset.uri;
248
+ options.currentAssetItem = payload.currentAsset;
249
+ } else {
250
+ options.initialSelection = null;
251
+ options.currentAssetItem = null;
252
+ }
253
+ deferred.resolve(options);
254
+ })
255
+ .fail(function() {
256
+ if (isStale()) {
257
+ deferred.resolve(options);
258
+ return;
259
+ }
260
+ // AC6: keep RM usable without selection; surface recoverable feedback.
261
+ options.initialSelection = null;
262
+ options.currentAssetItem = null;
263
+ if (options.$target && options.$target.length) {
264
+ feedback(options.$target).warning(
265
+ __('Unable to resolve the current asset. You can still browse and select another file.')
266
+ );
267
+ }
268
+ deferred.resolve(options);
269
+ });
270
+
271
+ return deferred.promise();
272
+ },
106
273
 
107
- $fileBrowser.find('li.root:last').addClass('active');
108
- fileSelector(options);
109
- filePreview(options);
274
+ /**
275
+ * Start browsers once and resolve when the tree wrapper is mounted.
276
+ * @param {jQuery} $elt
277
+ * @param {Object} options
278
+ * @returns {Promise}
279
+ */
280
+ _ensureBrowsersStarted: function($elt, options) {
281
+ const stored = $elt.data(dataNs) || options;
282
+ if (stored._browsersStartPromise) {
283
+ return stored._browsersStartPromise;
284
+ }
110
285
 
111
- /**
112
- * The plugin have been created.
113
- * @event ResourceMgr#create.resourcemgr
114
- */
115
- $elt.trigger('create.' + ns, [$target[0]]);
286
+ stored._browsersStartPromise = this._startBrowsers($elt, stored);
287
+ $elt.data(dataNs, stored);
288
+ return stored._browsersStartPromise;
289
+ },
116
290
 
117
- if (options.open) {
118
- that._open($elt);
291
+ /**
292
+ * Mount file browser / selector / search after options are ready.
293
+ * @param {jQuery} $elt
294
+ * @param {Object} options
295
+ */
296
+ _startBrowsers: function($elt, options) {
297
+ const $fileBrowser = $('.file-browser .file-browser-wrapper', options.$target);
298
+
299
+ const waitForTreeWrapper = function() {
300
+ const deferred = $.Deferred();
301
+ const isMounted = function() {
302
+ return $fileBrowser.children().length > 0;
303
+ };
304
+
305
+ if (isMounted()) {
306
+ deferred.resolve();
307
+ return deferred.promise();
308
+ }
309
+
310
+ let attempts = 200;
311
+ const poll = function() {
312
+ if (isMounted()) {
313
+ deferred.resolve();
314
+ return;
119
315
  }
120
- } else {
121
- options = $elt.data(dataNs);
122
- if (options.open) {
123
- that._open($elt);
316
+ attempts -= 1;
317
+ if (attempts <= 0) {
318
+ deferred.reject();
319
+ return;
124
320
  }
321
+ window.setTimeout(poll, 50);
322
+ };
323
+ poll();
324
+ return deferred.promise();
325
+ };
326
+
327
+ const finishMount = function() {
328
+ $fileBrowser.find('li.root:last').addClass('active');
329
+ fileSelector(options);
330
+ filePreview(options);
331
+ assetSearch(options);
332
+ };
333
+
334
+ const mountFromSources = function(mediaSources) {
335
+ const sources = mediaSources || defaults.mediaSources;
336
+ for (let i = 0; i < sources.length; i++) {
337
+ options.root = sources[i].root;
338
+ options.path = sources[i].path;
339
+ $fileBrowser.children('.file-browser-scroll').append(
340
+ '<div class="' + options.root + '"><ul class="folders"></ul></div>'
341
+ );
342
+ fileBrowser(options);
125
343
  }
126
- });
344
+ };
345
+
346
+ const afterComponentsMounted = function() {
347
+ finishMount();
348
+ return waitForTreeWrapper();
349
+ };
350
+
351
+ if (options.mediaSourcesUrl) {
352
+ return $.getJSON(options.mediaSourcesUrl).then(
353
+ function(data) {
354
+ mountFromSources(data || defaults.mediaSources);
355
+ return afterComponentsMounted();
356
+ },
357
+ function() {
358
+ mountFromSources(defaults.mediaSources);
359
+ return afterComponentsMounted();
360
+ }
361
+ );
362
+ }
363
+
364
+ if (options.path && options.root) {
365
+ $fileBrowser.children('.file-browser-scroll').append(
366
+ '<div class="' + options.root + '"><ul class="folders"></ul></div>'
367
+ );
368
+ fileBrowser(options);
369
+ }
370
+
371
+ return afterComponentsMounted();
127
372
  },
128
373
 
129
374
  _createTarget: function($elt) {
@@ -136,7 +381,9 @@ var resourceMgr = {
136
381
  options.$target = $(
137
382
  layout({
138
383
  title: options.title || '',
139
- className: options.className || ''
384
+ className: options.className || '',
385
+ assetSearchInputId: options.targetId + '-asset-search',
386
+ assetSearchBodyId: options.targetId + '-asset-search-body'
140
387
  })
141
388
  );
142
389