Skip to content

Commit 9ad24ac

Browse files
landlogicitAndyButlandkjac
authored
[v13] Media Picker: implement paging using getPagedChildren (no server changes) (#20202)
* Avoid throwing an exception on getting references when migrating content with changed data types. * Revert and handle exception at the consumer side * Clean up * Fix issue 12364 fix bug for Media Picker is slow when you have a large number of images at the root folder #12364 * Revert "Fix issue 12364" This reverts commit 4d86734. * Media Picker: use getPagedChildren with paging & sorting Replaces folder view calls to entityResource.getChildren with entityResource.getPagedChildren in MediaPickerController. - Adds orderBy/Direction and increases default pageSize to 200 - Resets pagination when entering folders or clearing search - Updates changePagination to work for both search and folder views - Keeps legacy behaviour for searchMedia (no breaking server changes) * Update mediapicker.controller.js * Update mediapicker.controller.js * Update mediapicker.controller.js * Update mediapicker.controller.js * Fix default values for paging. * Refactor Media Picker controller: simplify pagination and clarify comments - Removed unnecessary helper methods (pickPositive / pickNonNegative) and assign pagination values directly, as backend always provides valid positive/ non-negative numbers. - Renamed or removed review-only comments to keep codebase clean. - Clarified purpose of resetting `vm.searchOptions.filter` to explain why the filter is cleared after loading items. - Adjusted indentation and minor formatting for consistency. * Media Picker: fix lost paging on reopen by chaining navigation promises Ensures the Media Picker always loads a paged result when restoring the last visited folder. - run(), ensureWithinStartNode(), gotoStartNode(), and gotoFolder() now return and chain the same promise flow. - gotoFolder() resolves path → sets current folder → resets pagination → calls getChildren() (which uses getPagedChildren). - Fixed cases where reopening the picker showed all items with no pager. - Kept existing UX: filter is cleared on folder navigation to start unfiltered. - Minor indentation/formatting cleanups. * Tidied up indentation. --------- Co-authored-by: Andy Butland <[email protected]> Co-authored-by: Kenn Jacobsen <[email protected]>
1 parent e504011 commit 9ad24ac

File tree

2 files changed

+72
-49
lines changed

2 files changed

+72
-49
lines changed

src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,10 +514,9 @@ function entityResource($q, $http, umbRequestHelper) {
514514
*
515515
*/
516516
getPagedChildren: function (parentId, type, options) {
517-
518517
var defaults = {
519-
pageSize: 1,
520-
pageNumber: 100,
518+
pageSize: 100,
519+
pageNumber: 1,
521520
filter: '',
522521
orderDirection: "Ascending",
523522
orderBy: "SortOrder",

src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -130,28 +130,24 @@ angular.module("umbraco")
130130
}
131131
}
132132

133-
134133
function onInit() {
135-
136-
137134
localizationService.localizeMany(["defaultdialogs_selectMedia", "mediaPicker_tabClipboard"])
138135
.then(function (localizationResult) {
139136
setTitle(localizationResult);
140137
setNavigation(localizationResult);
141138
});
142139

143-
144140
userService.getCurrentUser().then(function (userData) {
145141
userStartNodes = userData.startMediaIds;
146142

147143
if ($scope.startNodeId !== -1) {
148144
entityResource.getById($scope.startNodeId, "media")
149145
.then(function (ent) {
150146
$scope.startNodeId = ent.id;
151-
run();
147+
return run();
152148
});
153149
} else {
154-
run();
150+
return run();
155151
}
156152
});
157153
}
@@ -160,10 +156,11 @@ angular.module("umbraco")
160156
//default root item
161157
if (!$scope.target) {
162158
if ($scope.lastOpenedNode && $scope.lastOpenedNode !== -1) {
163-
entityResource.getById($scope.lastOpenedNode, "media")
164-
.then(ensureWithinStartNode, gotoStartNode);
159+
return entityResource.getById($scope.lastOpenedNode, "media")
160+
.then(ensureWithinStartNode)
161+
.catch(function () { return gotoStartNode(); });
165162
} else {
166-
gotoStartNode();
163+
return gotoStartNode();
167164
}
168165
} else {
169166
// if a target is specified, go look it up - generally this target will just contain ids not the actual full
@@ -176,11 +173,11 @@ angular.module("umbraco")
176173
// ID of a UDI or legacy int ID still could be null/undefinied here
177174
// As user may dragged in an image that has not been saved to media section yet
178175
if (id) {
179-
entityResource.getById(id, "Media")
176+
return entityResource.getById(id, "Media")
180177
.then(function (node) {
181178
$scope.target = node;
182-
// Moving directly to existing node's folder
183-
gotoFolder({ id: node.parentId }).then(function () {
179+
// Move directly to existing node's folder, then open details
180+
return gotoFolder({ id: node.parentId }).then(function () {
184181
selectMedia(node);
185182
$scope.target.url = mediaHelper.resolveFileFromEntity(node);
186183
$scope.target.thumbnail = mediaHelper.resolveFileFromEntity(node, true);
@@ -195,6 +192,7 @@ angular.module("umbraco")
195192
// No ID set - then this is going to be a tmpimg that has not been uploaded
196193
// User editing this will want to be changing the ALT text
197194
openDetailsDialog();
195+
return;
198196
}
199197
}
200198
}
@@ -257,22 +255,27 @@ angular.module("umbraco")
257255
folder = { id: -1, name: "Media", icon: "icon-folder" };
258256
}
259257

260-
if (folder.id > 0) {
261-
entityResource.getAncestors(folder.id, "media", null, { dataTypeKey: dataTypeKey })
262-
.then(function (anc) {
263-
$scope.path = _.filter(anc,
264-
function (f) {
265-
return f.path.indexOf($scope.startNodeId) !== -1;
266-
});
267-
folder.path = $scope.path[0].path;
268-
performGotoFolder(folder);
269-
});
270-
} else {
271-
$scope.path = [];
272-
performGotoFolder(folder);
273-
}
258+
var setPathPromise = (folder.id > 0)
259+
? entityResource.getAncestors(folder.id, "media", null, { dataTypeKey: dataTypeKey })
260+
.then(function (anc) {
261+
$scope.path = _.filter(anc, function (f) {
262+
return f.path.indexOf($scope.startNodeId) !== -1;
263+
});
264+
folder.path = $scope.path[0].path;
265+
})
266+
: Promise.resolve().then(function () {
267+
$scope.path = [];
268+
});
274269

275-
return getChildren(folder.id);
270+
// Chain: resolve path → set current folder → reset paging → fetch page
271+
return setPathPromise.then(function () {
272+
performGotoFolder(folder);
273+
// Reset pagination to the first page on folder change
274+
vm.searchOptions.pageNumber = 1;
275+
vm.searchOptions.totalItems = 0;
276+
vm.searchOptions.totalPages = 0;
277+
return getChildren(folder.id);
278+
});
276279
}
277280

278281
function performGotoFolder(folder) {
@@ -388,11 +391,9 @@ angular.module("umbraco")
388391

389392
// also make sure the node is not trashed
390393
if (nodePath.indexOf($scope.startNodeId.toString()) !== -1 && node.trashed === false) {
391-
gotoFolder({ id: $scope.lastOpenedNode || $scope.startNodeId, name: "Media", icon: "icon-folder", path: node.path });
392-
return true;
394+
return gotoFolder({ id: $scope.lastOpenedNode || $scope.startNodeId, name: "Media", icon: "icon-folder", path: node.path });
393395
} else {
394-
gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
395-
return false;
396+
return gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
396397
}
397398
}
398399

@@ -408,7 +409,7 @@ angular.module("umbraco")
408409
}
409410

410411
function gotoStartNode() {
411-
gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
412+
return gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
412413
}
413414

414415
function openDetailsDialog() {
@@ -484,8 +485,15 @@ angular.module("umbraco")
484485
function changePagination(pageNumber) {
485486
vm.loading = true;
486487
vm.searchOptions.pageNumber = pageNumber;
487-
searchMedia();
488-
};
488+
489+
if (vm.searchOptions.filter) {
490+
// search pagination (already present)
491+
searchMedia();
492+
} else {
493+
// pagination in folder view
494+
getChildren($scope.currentFolder.id);
495+
}
496+
}
489497

490498
function searchMedia() {
491499
vm.loading = true;
@@ -559,22 +567,38 @@ angular.module("umbraco")
559567

560568
function getChildren(id) {
561569
vm.loading = true;
562-
return entityResource.getChildren(id, "Media", vm.searchOptions).then(function (data) {
570+
return entityResource
571+
.getPagedChildren(id, "Media", vm.searchOptions)
572+
.then(handlePagedChildren)
573+
.finally(function () { vm.loading = false; });
574+
}
563575

564-
var allowedTypes = dialogOptions.filter ? dialogOptions.filter.split(",") : null;
576+
function handlePagedChildren(data) {
577+
var items = transformItems(data && data.items ? data.items : [], getAllowedTypes());
578+
$scope.images = items;
579+
syncPagination(vm.searchOptions, data);
580+
vm.searchOptions.filter = ""; // reset filter to ensure folder navigation always starts unfiltered
581+
preSelectMedia();
582+
}
565583

566-
for (var i = 0; i < data.length; i++) {
567-
setDefaultData(data[i]);
568-
data[i].filtered = allowedTypes && allowedTypes.indexOf(data[i].metaData.ContentTypeAlias) < 0;
569-
}
584+
function getAllowedTypes() {
585+
return dialogOptions.filter ? dialogOptions.filter.split(",") : null;
586+
}
570587

571-
vm.searchOptions.filter = "";
572-
$scope.images = data ? data : [];
588+
function transformItems(items, allowedTypes) {
589+
for (var i = 0; i < items.length; i++) {
590+
setDefaultData(items[i]);
591+
items[i].filtered = !!(allowedTypes && allowedTypes.indexOf(items[i].metaData.ContentTypeAlias) < 0);
592+
}
593+
return items;
594+
}
573595

574-
// set already selected medias to selected
575-
preSelectMedia();
576-
vm.loading = false;
577-
});
596+
function syncPagination(opts, data) {
597+
var d = data || {};
598+
opts.pageNumber = d.pageNumber;
599+
opts.pageSize = d.pageSize;
600+
opts.totalItems = d.totalItems;
601+
opts.totalPages = d.totalPages;
578602
}
579603

580604
function setDefaultData(item) {

0 commit comments

Comments
 (0)