@oat-sa/tao-core-ui 3.23.0 → 3.24.0

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 +1137 -97
  8. package/dist/resourcemgr/css/resourcemgr.css.map +1 -1
  9. package/dist/resourcemgr/fileBrowser.js +456 -79
  10. package/dist/resourcemgr/filePreview.js +40 -4
  11. package/dist/resourcemgr/fileSelector.js +362 -92
  12. package/dist/resourcemgr.js +309 -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 +1137 -97
  20. package/src/resourcemgr/css/resourcemgr.css.map +1 -1
  21. package/src/resourcemgr/fileBrowser.js +470 -91
  22. package/src/resourcemgr/filePreview.js +46 -4
  23. package/src/resourcemgr/fileSelector.js +338 -46
  24. package/src/resourcemgr/scss/resourcemgr.scss +1351 -88
  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 +113 -54
  29. package/src/resourcemgr/tpl/rootFolder.tpl +3 -1
  30. package/src/resourcemgr.js +289 -47
  31. package/src/searchModal/advancedSearch.js +242 -31
@@ -1,13 +1,17 @@
1
- define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'ui/resourcemgr/filePreview', 'ui/resourcemgr/fileSelector', 'handlebars', 'lib/handlebars/helpers', 'ui/modal', 'css!ui/resourcemgr/css/resourcemgr.css'], function ($$1, _, Pluginifier, fileBrowser, filePreview, fileSelector, Handlebars, Helpers0, modal, resourcemgr_css) { 'use strict';
1
+ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/assetSearch', 'ui/resourcemgr/fileBrowser', 'ui/resourcemgr/filePreview', 'ui/resourcemgr/fileSelector', 'ui/feedback', 'handlebars', 'lib/handlebars/helpers', 'util/url', 'i18n', 'ui/modal', 'css!ui/resourcemgr/css/resourcemgr.css'], function ($$1, _, Pluginifier, assetSearch, fileBrowser, filePreview, fileSelector, feedback, Handlebars, Helpers0, urlUtil, __, modal, resourcemgr_css) { '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'] : _;
5
5
  Pluginifier = Pluginifier && Object.prototype.hasOwnProperty.call(Pluginifier, 'default') ? Pluginifier['default'] : Pluginifier;
6
+ assetSearch = assetSearch && Object.prototype.hasOwnProperty.call(assetSearch, 'default') ? assetSearch['default'] : assetSearch;
6
7
  fileBrowser = fileBrowser && Object.prototype.hasOwnProperty.call(fileBrowser, 'default') ? fileBrowser['default'] : fileBrowser;
7
8
  filePreview = filePreview && Object.prototype.hasOwnProperty.call(filePreview, 'default') ? filePreview['default'] : filePreview;
8
9
  fileSelector = fileSelector && Object.prototype.hasOwnProperty.call(fileSelector, 'default') ? fileSelector['default'] : fileSelector;
10
+ feedback = feedback && Object.prototype.hasOwnProperty.call(feedback, 'default') ? feedback['default'] : feedback;
9
11
  Handlebars = Handlebars && Object.prototype.hasOwnProperty.call(Handlebars, 'default') ? Handlebars['default'] : Handlebars;
10
12
  Helpers0 = Helpers0 && Object.prototype.hasOwnProperty.call(Helpers0, 'default') ? Helpers0['default'] : Helpers0;
13
+ urlUtil = urlUtil && Object.prototype.hasOwnProperty.call(urlUtil, 'default') ? urlUtil['default'] : urlUtil;
14
+ __ = __ && Object.prototype.hasOwnProperty.call(__, 'default') ? __['default'] : __;
11
15
 
12
16
  if (!Helpers0.__initialized) {
13
17
  Helpers0(Handlebars);
@@ -33,31 +37,67 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
33
37
  if (helper = helpers.title) { stack1 = helper.call(depth0, {hash:{},data:data}); }
34
38
  else { helper = (depth0 && depth0.title); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
35
39
  if(stack1 || stack1 === 0) { buffer += stack1; }
36
- buffer += "</h2>\n\n <div class=\"file-wrapper\">\n\n <!-- left section: items selection -->\n <section class=\"file-browser\">\n <h1>"
37
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Browse resources", options) : helperMissing.call(depth0, "__", "Browse resources", options)))
38
- + "</h1>\n <div class=\"file-browser-wrapper\"></div>\n </section>\n\n <!-- test editor -->\n <section class=\"file-selector\">\n\n <h1>\n <div class=\"title lft\"></div>\n <div class=\"upload-switcher rgt\">\n <a href=\"#\" class=\"btn-info small upload hidden\"><span class=\"icon-add\"></span>"
40
+ buffer += "</h2>\n\n <div class=\"file-wrapper\">\n\n <div class=\"file-panels\">\n <!-- left section: search, filters, folder tree -->\n <section class=\"file-browser\">\n <div class=\"asset-search hidden\" hidden>\n <div class=\"asset-search-header\">\n <button\n type=\"button\"\n class=\"asset-search-toggle\"\n aria-expanded=\"true\"\n aria-controls=\"";
41
+ if (helper = helpers.assetSearchBodyId) { stack1 = helper.call(depth0, {hash:{},data:data}); }
42
+ else { helper = (depth0 && depth0.assetSearchBodyId); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
43
+ buffer += escapeExpression(stack1)
44
+ + "\"\n >\n <span class=\"asset-search-title\">"
45
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Search", options) : helperMissing.call(depth0, "__", "Search", options)))
46
+ + "</span>\n <span class=\"asset-search-applied-count hidden\" hidden></span>\n <span class=\"asset-search-scope\" aria-live=\"polite\">\n <span class=\"asset-search-scope-prefix\">"
47
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Searching in:", options) : helperMissing.call(depth0, "__", "Searching in:", options)))
48
+ + "</span>\n <span class=\"asset-search-scope-name\"></span>\n <span class=\"asset-search-scope-subfolders hidden\" hidden>"
49
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "and its subfolders", options) : helperMissing.call(depth0, "__", "and its subfolders", options)))
50
+ + "</span>\n </span>\n <span class=\"asset-search-chevron icon-up\" aria-hidden=\"true\"></span>\n </button>\n </div>\n <div class=\"asset-search-body\" id=\"";
51
+ if (helper = helpers.assetSearchBodyId) { stack1 = helper.call(depth0, {hash:{},data:data}); }
52
+ else { helper = (depth0 && depth0.assetSearchBodyId); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
53
+ buffer += escapeExpression(stack1)
54
+ + "\">\n <div class=\"asset-search-field\">\n <span class=\"icon-find\" aria-hidden=\"true\"></span>\n <label class=\"asset-search-label\" for=\"";
55
+ if (helper = helpers.assetSearchInputId) { stack1 = helper.call(depth0, {hash:{},data:data}); }
56
+ else { helper = (depth0 && depth0.assetSearchInputId); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
57
+ buffer += escapeExpression(stack1)
58
+ + "\">"
59
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Search by name or label", options) : helperMissing.call(depth0, "__", "Search by name or label", options)))
60
+ + "</label>\n <input\n id=\"";
61
+ if (helper = helpers.assetSearchInputId) { stack1 = helper.call(depth0, {hash:{},data:data}); }
62
+ else { helper = (depth0 && depth0.assetSearchInputId); stack1 = typeof helper === functionType ? helper.call(depth0, {hash:{},data:data}) : helper; }
63
+ buffer += escapeExpression(stack1)
64
+ + "\"\n type=\"search\"\n class=\"asset-search-input\"\n placeholder=\""
65
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Search by name or label", options) : helperMissing.call(depth0, "__", "Search by name or label", options)))
66
+ + "\"\n autocomplete=\"off\"\n />\n </div>\n <div class=\"asset-search-filters\"></div>\n <div class=\"asset-search-actions\">\n <button type=\"button\" class=\"asset-search-clear hidden\" hidden>"
67
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Clear all", options) : helperMissing.call(depth0, "__", "Clear all", options)))
68
+ + "</button>\n <button type=\"button\" class=\"btn-info small asset-search-submit\" disabled>\n <span class=\"asset-search-submit-spinner icon-loop\" aria-hidden=\"true\" hidden></span>\n <span class=\"asset-search-submit-label\">"
69
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Search", options) : helperMissing.call(depth0, "__", "Search", options)))
70
+ + "</span>\n </button>\n </div>\n </div>\n </div>\n\n <h1 class=\"resources-title\">"
71
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Resources", options) : helperMissing.call(depth0, "__", "Resources", options)))
72
+ + "</h1>\n <div class=\"file-browser-wrapper\"></div>\n </section>\n\n <!-- center: asset listing -->\n <section class=\"file-selector\">\n\n <h1>\n <div class=\"title lft\">"
73
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Assets", options) : helperMissing.call(depth0, "__", "Assets", options)))
74
+ + "</div>\n <div class=\"upload-switcher rgt\">\n <a href=\"#\" class=\"btn-info small upload hidden\"><span class=\"icon-add\"></span>"
39
75
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Add file(s)", options) : helperMissing.call(depth0, "__", "Add file(s)", options)))
40
- + "</a>\n <a href=\"#\" class=\"btn-info small listing\"><span class=\"icon-undo\"></span>"
76
+ + "</a>\n <a href=\"#\" class=\"btn-info small listing\"><span class=\"icon-undo\"></span>"
41
77
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Back to listing", options) : helperMissing.call(depth0, "__", "Back to listing", options)))
42
- + "</a>\n </div>\n </h1>\n\n <div class=\"empty\">\n "
78
+ + "</a>\n </div>\n </h1>\n\n <div class=\"asset-search-error hidden\" hidden role=\"alert\">\n <p class=\"asset-search-error-message\"></p>\n <button type=\"button\" class=\"btn-info small asset-search-retry\">"
79
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Retry", options) : helperMissing.call(depth0, "__", "Retry", options)))
80
+ + "</button>\n </div>\n\n <div class=\"empty\">\n "
43
81
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "No files", options) : helperMissing.call(depth0, "__", "No files", options)))
44
- + "\n </div>\n\n <ul class=\"files\"></ul>\n\n <div class=\"file-upload-container\"></div>\n\n <div class=\"pagination-bottom\"></div>\n\n </section>\n\n <section class=\"file-preview\">\n\n <h1>"
82
+ + "\n </div>\n\n <div class=\"files-wrapper\" aria-busy=\"false\">\n <table class=\"files\">\n <thead>\n <tr>\n <th class=\"files-label sortable sorted sorted_asc\" data-sort-by=\"label\" aria-sort=\"ascending\" tabindex=\"0\">\n <span class=\"sort-label\">"
83
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Label", options) : helperMissing.call(depth0, "__", "Label", options)))
84
+ + "</span>\n </th>\n <th class=\"files-location sortable\" data-sort-by=\"location\" aria-sort=\"none\" tabindex=\"0\">\n <span class=\"sort-label\">"
85
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Location", options) : helperMissing.call(depth0, "__", "Location", options)))
86
+ + "</span>\n </th>\n <th class=\"files-updated sortable\" data-sort-by=\"updatedAt\" aria-sort=\"none\" tabindex=\"0\">\n <span class=\"sort-label\">"
87
+ + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Last modified on", options) : helperMissing.call(depth0, "__", "Last modified on", options)))
88
+ + "</span>\n </th>\n </tr>\n </thead>\n <tbody class=\"files-list\"></tbody>\n </table>\n </div>\n\n <div class=\"file-upload-container\"></div>\n\n <div class=\"pagination-bottom\"></div>\n\n </section>\n\n <section class=\"file-preview\">\n\n <h1>"
45
89
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Preview", options) : helperMissing.call(depth0, "__", "Preview", options)))
46
- + "</h1>\n\n <div class=\"previewer\">\n <p class=\"nopreview\"></p>\n </div>\n\n <h2 class=\"toggler\" data-toggle=\"~ .file-properties\">"
47
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "File Properties", options) : helperMissing.call(depth0, "__", "File Properties", options)))
48
- + "</h2>\n\n <div class=\"file-properties\">\n\n <div class=\"grid-row\">\n <div class=\"col-2\">\n "
90
+ + "</h1>\n\n <div class=\"previewer\">\n <p class=\"nopreview\"></p>\n </div>\n\n <div class=\"file-properties\">\n\n <div class=\"grid-row\">\n <div class=\"col-2\">\n "
49
91
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Type", options) : helperMissing.call(depth0, "__", "Type", options)))
50
- + "\n </div>\n <div class=\"col-10 prop-type\"></div>\n </div>\n\n <div class=\"grid-row\">\n <div class=\"col-2\">\n "
92
+ + "\n </div>\n <div class=\"col-10 prop-type\">—</div>\n </div>\n\n <div class=\"grid-row\">\n <div class=\"col-2\">\n "
51
93
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Size", options) : helperMissing.call(depth0, "__", "Size", options)))
52
- + "\n </div>\n <div class=\"col-10 prop-size\"></div>\n </div>\n\n <div class=\"grid-row prop-url\">\n <div class=\"actions\">\n <a href=\"#\" download=\"\" target=\"_blank\" class=\"tlb-button-off download hidden\" title=\""
94
+ + "\n </div>\n <div class=\"col-10 prop-size\">—</div>\n </div>\n\n <div class=\"grid-row prop-url\">\n <div class=\"actions\">\n <a href=\"#\" download=\"\" target=\"_blank\" class=\"tlb-button-off download hidden\" title=\""
53
95
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Download this file", options) : helperMissing.call(depth0, "__", "Download this file", options)))
54
- + "\">\n <button class=\"btn-info small\">\n <span class=\"icon-download\"></span>"
96
+ + "\">\n <span class=\"icon-download\"></span>"
55
97
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Download this file", options) : helperMissing.call(depth0, "__", "Download this file", options)))
56
- + "\n </button>\n </a>\n </div>\n </div>\n </div>\n\n <h2 class=\"toggler\" data-toggle=\"~ .actions\">"
57
- + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Actions", options) : helperMissing.call(depth0, "__", "Actions", options)))
58
- + "</h2>\n\n <div class=\"actions\">\n <button class=\"btn-success select-action small\" disabled>\n <span class=\"icon-move-item\"></span>"
98
+ + "\n </a>\n </div>\n </div>\n </div>\n\n <div class=\"actions select-actions\">\n <button class=\"btn-success select-action small\" disabled>\n <span class=\"icon-move-item\"></span>"
59
99
  + escapeExpression((helper = helpers.__ || (depth0 && depth0.__),options={hash:{},data:data},helper ? helper.call(depth0, "Select", options) : helperMissing.call(depth0, "__", "Select", options)))
60
- + "\n </button>\n </div>\n\n </section>\n\n </div>\n</div>\n";
100
+ + "\n </button>\n </div>\n\n </section>\n </div>\n\n </div>\n</div>\n";
61
101
  return buffer;
62
102
  });
63
103
  function layout(data, options, asString) {
@@ -74,7 +114,13 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
74
114
  }],
75
115
  open: true,
76
116
  appendContainer: '.tao-scope:first',
77
- title: ''
117
+ title: '',
118
+ pathParam: 'path',
119
+ // Advanced Search metadata filters (same endpoints as ui/searchModal)
120
+ rootClassUri: 'http://www.tao.lu/Ontologies/TAOMedia.rdf#Media',
121
+ classMappingUrl: urlUtil.route('getWithMapping', 'ClassMetadata', 'tao'),
122
+ statusUrl: urlUtil.route('status', 'AdvancedSearch', 'tao'),
123
+ maxListSize: 5
78
124
  };
79
125
 
80
126
  /**
@@ -93,7 +139,18 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
93
139
  * @constructor
94
140
  * @param {Object} options - the plugin options
95
141
  * @param {Sring|Boolean} [options.bindEvent = 'click'] - the event that trigger the toggling
96
- * @param {String} options.url - the URL of the service used to retrieve the resources.
142
+ * @param {String} [options.browseUrl] - folder browse endpoint (legacy alias: options.url)
143
+ * @param {String} [options.url] - legacy alias for browseUrl
144
+ * @param {String} [options.searchUrl] - scoped asset-search endpoint; omit for browse-only
145
+ * @param {Boolean} [options.browseSearchFallback=false] - client filter when searchUrl returns browse-shaped `{ children }`
146
+ * @param {String} [options.initialPath] - folder to open on start (within the media source tree)
147
+ * @param {String} [options.initialSelection] - asset URI to preselect when present in results
148
+ * @param {String} [options.currentAsset] - asset URI/path to resolve to parent folder + selection
149
+ * @param {String} [options.pathParam='path'] - query parameter name for folder/asset path
150
+ * @param {String} [options.rootClassUri=TAOMedia#Media] - Assets class URI for Advanced Search criteria (metadata filters)
151
+ * @param {String} [options.classMappingUrl] - ClassMetadata mapping endpoint for criteria list
152
+ * @param {String} [options.statusUrl] - Advanced Search status endpoint
153
+ * @param {Number} [options.maxListSize=5] - max list values per criterion in filters UI
97
154
  * @fires ResourceMgr#create.resourcemgr
98
155
  * @returns {jQueryElement} for chaining
99
156
  */
@@ -102,6 +159,9 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
102
159
 
103
160
  //get options using default
104
161
  options = _.defaults(options, defaults);
162
+ if (!options.browseUrl && options.url) {
163
+ options.browseUrl = options.url;
164
+ }
105
165
  return this.each(function () {
106
166
  var $elt = $$1(this);
107
167
  var $target;
@@ -112,7 +172,10 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
112
172
  //auto bind events configured in options
113
173
  _.functions(options).forEach(function (eventName) {
114
174
  $elt.on(eventName + '.' + ns, function () {
115
- options[eventName].apply($elt, arguments);
175
+ const live = $elt.data(dataNs);
176
+ if (live && typeof live[eventName] === 'function') {
177
+ live[eventName].apply($elt, arguments);
178
+ }
116
179
  });
117
180
  });
118
181
  $target = options.$target || that._createTarget($elt);
@@ -129,49 +192,236 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
129
192
  $target.on('closed.modal', function () {
130
193
  $elt.trigger('close.' + ns);
131
194
  });
132
- //initialize the components
133
- const $fileBrowser = $$1('.file-browser .file-browser-wrapper', $target);
134
- if (options.mediaSourcesUrl) {
135
- $$1.getJSON(options.mediaSourcesUrl).done(function (data) {
136
- const mediaSources = data || defaults.mediaSources;
137
- for (let i = 0; i < mediaSources.length; i++) {
138
- options.root = mediaSources[i].root;
139
- options.path = mediaSources[i].path;
140
- $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
141
- fileBrowser(options);
195
+ options.contextToken = 1;
196
+ const initToken = options.contextToken;
197
+ $elt.data(dataNs, options);
198
+ that._resolveCurrentAssetContext(options, initToken).always(function (resolvedOptions) {
199
+ const current = $elt.data(dataNs);
200
+ if (!current) {
201
+ return;
202
+ }
203
+ const ownsOpen = current.contextToken === initToken;
204
+ if (!ownsOpen) {
205
+ return;
206
+ }
207
+ $elt.data(dataNs, resolvedOptions);
208
+ that._ensureBrowsersStarted($elt, resolvedOptions).always(function () {
209
+ const latest = $elt.data(dataNs) || resolvedOptions;
210
+ if (!latest._createEventEmitted) {
211
+ latest._createEventEmitted = true;
212
+ $elt.data(dataNs, latest);
213
+ /**
214
+ * The plugin have been created.
215
+ * @event ResourceMgr#create.resourcemgr
216
+ */
217
+ $elt.trigger('create.' + ns, [latest.$target[0]]);
142
218
  }
143
- }).fail(function () {
144
- for (let i = 0; i < defaults.mediaSources.length; i++) {
145
- options.root = defaults.mediaSources[i].root;
146
- options.path = defaults.mediaSources[i].path;
147
- $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
148
- fileBrowser(options);
219
+ if (ownsOpen && latest.open) {
220
+ that._open($elt);
149
221
  }
150
222
  });
151
- } else if (options.path && options.root) {
152
- $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
153
- fileBrowser(options);
154
- }
155
- $fileBrowser.find('li.root:last').addClass('active');
156
- fileSelector(options);
157
- filePreview(options);
158
-
159
- /**
160
- * The plugin have been created.
161
- * @event ResourceMgr#create.resourcemgr
162
- */
163
- $elt.trigger('create.' + ns, [$target[0]]);
164
- if (options.open) {
165
- that._open($elt);
166
- }
223
+ });
167
224
  } else {
168
- options = $elt.data(dataNs);
169
- if (options.open) {
170
- that._open($elt);
171
- }
225
+ // Reopen: consumer may pass a new currentAsset (edit/change after create).
226
+ that._reopenWithContext($elt, options);
172
227
  }
173
228
  });
174
229
  },
230
+ /**
231
+ * Merge reopen options, re-resolve currentAsset, re-apply folder/selection, then open.
232
+ * @param {jQuery} $elt
233
+ * @param {Object} incoming - options from the latest .resourcemgr(…) call
234
+ */
235
+ _reopenWithContext: function ($elt, incoming) {
236
+ const that = resourceMgr;
237
+ const stored = $elt.data(dataNs);
238
+ if (!stored) {
239
+ return;
240
+ }
241
+ if (Object.prototype.hasOwnProperty.call(incoming, 'currentAsset')) {
242
+ stored.currentAsset = incoming.currentAsset;
243
+ stored.initialPath = null;
244
+ stored.initialSelection = null;
245
+ stored.currentAssetItem = null;
246
+ }
247
+ if (incoming.params && typeof incoming.params === 'object') {
248
+ stored.params = Object.assign({}, stored.params || {}, incoming.params);
249
+ }
250
+ ['select', 'open', 'close'].forEach(function (key) {
251
+ if (typeof incoming[key] === 'function') {
252
+ stored[key] = incoming[key];
253
+ }
254
+ });
255
+ stored.contextToken = (stored.contextToken || 0) + 1;
256
+ const token = stored.contextToken;
257
+ $elt.data(dataNs, stored);
258
+ that._resolveCurrentAssetContext(stored, token).always(function (resolved) {
259
+ const current = $elt.data(dataNs);
260
+ if (!current || current.contextToken !== token) {
261
+ return;
262
+ }
263
+ $elt.data(dataNs, resolved);
264
+ that._ensureBrowsersStarted($elt, resolved).always(function () {
265
+ that._applyResolvedContext($elt, resolved);
266
+ that._open($elt);
267
+ });
268
+ });
269
+ },
270
+ /**
271
+ * Notify mounted browser/selector to open parent folder and (re)preselect.
272
+ * @param {jQuery} $elt
273
+ * @param {Object} options
274
+ */
275
+ _applyResolvedContext: function ($elt, options) {
276
+ if (!options || !options.$target) {
277
+ return;
278
+ }
279
+ options.$target.trigger('applycontext.' + ns, [{
280
+ path: options.initialPath || options.path || '/',
281
+ selection: options.initialSelection || null,
282
+ currentAssetItem: options.currentAssetItem || null
283
+ }]);
284
+ },
285
+ /**
286
+ * Resolve currentAsset via browse/search endpoint into initialPath/initialSelection.
287
+ * @param {Object} options
288
+ * @param {number} [expectedToken] - contextToken that must still match before mutating options
289
+ * @returns {Promise}
290
+ */
291
+ _resolveCurrentAssetContext: function (options, expectedToken) {
292
+ const deferred = $$1.Deferred();
293
+ const isStale = function () {
294
+ return typeof expectedToken !== 'undefined' && expectedToken !== null && options.contextToken !== expectedToken;
295
+ };
296
+ if (!options.currentAsset || !options.browseUrl && !options.searchUrl) {
297
+ deferred.resolve(options);
298
+ return deferred.promise();
299
+ }
300
+ const endpoint = options.browseUrl || options.searchUrl;
301
+ const pathParam = options.pathParam || 'path';
302
+ const params = Object.assign({}, options.params || {}, {
303
+ currentAsset: options.currentAsset
304
+ });
305
+ params[pathParam] = options.path || '/';
306
+ $$1.ajax({
307
+ url: endpoint,
308
+ method: 'GET',
309
+ dataType: 'json',
310
+ timeout: Number(options.ajaxTimeoutMs) > 0 ? Number(options.ajaxTimeoutMs) : 10000,
311
+ data: params
312
+ }).done(function (response) {
313
+ if (isStale()) {
314
+ deferred.resolve(options);
315
+ return;
316
+ }
317
+ const payload = response && response.data ? response.data : response;
318
+ if (payload && payload.parentPath) {
319
+ options.initialPath = payload.parentPath;
320
+ }
321
+ if (payload && payload.currentAsset && payload.currentAsset.uri) {
322
+ options.initialSelection = payload.currentAsset.uri;
323
+ options.currentAssetItem = payload.currentAsset;
324
+ } else {
325
+ options.initialSelection = null;
326
+ options.currentAssetItem = null;
327
+ }
328
+ deferred.resolve(options);
329
+ }).fail(function () {
330
+ if (isStale()) {
331
+ deferred.resolve(options);
332
+ return;
333
+ }
334
+ // AC6: keep RM usable without selection; surface recoverable feedback.
335
+ options.initialSelection = null;
336
+ options.currentAssetItem = null;
337
+ if (options.$target && options.$target.length) {
338
+ feedback(options.$target).warning(__('Unable to resolve the current asset. You can still browse and select another file.'));
339
+ }
340
+ deferred.resolve(options);
341
+ });
342
+ return deferred.promise();
343
+ },
344
+ /**
345
+ * Start browsers once and resolve when the tree wrapper is mounted.
346
+ * @param {jQuery} $elt
347
+ * @param {Object} options
348
+ * @returns {Promise}
349
+ */
350
+ _ensureBrowsersStarted: function ($elt, options) {
351
+ const stored = $elt.data(dataNs) || options;
352
+ if (stored._browsersStartPromise) {
353
+ return stored._browsersStartPromise;
354
+ }
355
+ stored._browsersStartPromise = this._startBrowsers($elt, stored);
356
+ $elt.data(dataNs, stored);
357
+ return stored._browsersStartPromise;
358
+ },
359
+ /**
360
+ * Mount file browser / selector / search after options are ready.
361
+ * @param {jQuery} $elt
362
+ * @param {Object} options
363
+ */
364
+ _startBrowsers: function ($elt, options) {
365
+ const $fileBrowser = $$1('.file-browser .file-browser-wrapper', options.$target);
366
+ const waitForTreeWrapper = function () {
367
+ const deferred = $$1.Deferred();
368
+ const isMounted = function () {
369
+ return $fileBrowser.children().length > 0;
370
+ };
371
+ if (isMounted()) {
372
+ deferred.resolve();
373
+ return deferred.promise();
374
+ }
375
+ let attempts = 200;
376
+ const poll = function () {
377
+ if (isMounted()) {
378
+ deferred.resolve();
379
+ return;
380
+ }
381
+ attempts -= 1;
382
+ if (attempts <= 0) {
383
+ deferred.reject();
384
+ return;
385
+ }
386
+ window.setTimeout(poll, 50);
387
+ };
388
+ poll();
389
+ return deferred.promise();
390
+ };
391
+ const finishMount = function () {
392
+ $fileBrowser.find('li.root:last').addClass('active');
393
+ fileSelector(options);
394
+ filePreview(options);
395
+ assetSearch(options);
396
+ };
397
+ const mountFromSources = function (mediaSources) {
398
+ const sources = mediaSources || defaults.mediaSources;
399
+ for (let i = 0; i < sources.length; i++) {
400
+ options.root = sources[i].root;
401
+ options.path = sources[i].path;
402
+ $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
403
+ fileBrowser(options);
404
+ }
405
+ };
406
+ const afterComponentsMounted = function () {
407
+ finishMount();
408
+ return waitForTreeWrapper();
409
+ };
410
+ if (options.mediaSourcesUrl) {
411
+ return $$1.getJSON(options.mediaSourcesUrl).then(function (data) {
412
+ mountFromSources(data || defaults.mediaSources);
413
+ return afterComponentsMounted();
414
+ }, function () {
415
+ mountFromSources(defaults.mediaSources);
416
+ return afterComponentsMounted();
417
+ });
418
+ }
419
+ if (options.path && options.root) {
420
+ $fileBrowser.append('<div class="' + options.root + '"><ul class="folders"></ul></div>');
421
+ fileBrowser(options);
422
+ }
423
+ return afterComponentsMounted();
424
+ },
175
425
  _createTarget: function ($elt) {
176
426
  var options = $elt.data(dataNs);
177
427
  if (options) {
@@ -181,7 +431,9 @@ define(['jquery', 'lodash', 'core/pluginifier', 'ui/resourcemgr/fileBrowser', 'u
181
431
  //generate
182
432
  options.$target = $$1(layout({
183
433
  title: options.title || '',
184
- className: options.className || ''
434
+ className: options.className || '',
435
+ assetSearchInputId: options.targetId + '-asset-search',
436
+ assetSearchBodyId: options.targetId + '-asset-search-body'
185
437
  }));
186
438
  options.$target.attr('id', options.targetId).css('display', 'none').appendTo(options.appendContainer);
187
439
  $elt.data(dataNs, options);