From 991f2d0f42f7b22a1c181e6b1838b1440d4f4ec9 Mon Sep 17 00:00:00 2001 From: Marc Goodson Date: Mon, 27 Jul 2020 15:13:07 +0100 Subject: [PATCH] V8: Add alternate 'List View' to Media Picker - Take 2 (#7912) --- .../Implement/EntityRepository.cs | 6 +- .../components/umbmediagrid.directive.js | 38 ++++- .../src/less/components/umb-media-grid.less | 16 +++ .../mediapicker/mediapicker.controller.js | 44 +++++- .../mediapicker/mediapicker.html | 129 ++++++++++------- .../src/views/components/umb-media-grid.html | 134 ++++++++++++------ .../Models/ContentEditing/EntityBasic.cs | 3 +- .../Models/Mapping/EntityMapDefinition.cs | 3 + 8 files changed, 270 insertions(+), 103 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs index 24040bf393..a7502a338a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityRepository.cs @@ -369,7 +369,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (isContent || isMedia || isMember) sql - .AndSelect(x => Alias(x.Id, "versionId")) + .AndSelect(x => Alias(x.Id, "versionId"), x=>x.VersionDate) .AndSelect(x => x.Alias, x => x.Icon, x => x.Thumbnail, x => x.IsContainer, x => x.Variations); if (isContent) @@ -490,7 +490,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (isContent || isMedia || isMember) sql - .AndBy(x => x.Id) + .AndBy(x => x.Id, x => x.VersionDate) .AndBy(x => x.Alias, x => x.Icon, x => x.Thumbnail, x => x.IsContainer, x => x.Variations); if (defaultSort) @@ -594,6 +594,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public string Text { get; set; } public Guid NodeObjectType { get; set; } public DateTime CreateDate { get; set; } + public DateTime VersionDate { get; set; } public int Children { get; set; } public int VersionId { get; set; } public string Alias { get; set; } @@ -627,6 +628,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { entity.Trashed = dto.Trashed; entity.CreateDate = dto.CreateDate; + entity.UpdateDate = dto.VersionDate; entity.CreatorId = dto.UserId ?? Constants.Security.UnknownUserId; entity.Id = dto.NodeId; entity.Key = dto.UniqueId; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js index aa28d49c4a..241f1e80e8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbmediagrid.directive.js @@ -322,6 +322,41 @@ Use this directive to generate a thumbnail grid of media items. scope.$on('$destroy', function() { unbindItemsWatcher(); }); + //determine if sort is current + scope.sortColumn = "name"; + scope.sortReverse = false; + scope.sortDirection = "asc"; + //check sort status + scope.isSortDirection = function (col, direction) { + return col === scope.sortColumn && direction === scope.sortDirection; + }; + //change sort + scope.setSort = function (col) { + if (scope.sortColumn === col) { + scope.sortReverse = !scope.sortReverse; + } + else { + scope.sortColumn = col; + if (col === "updateDate") { + scope.sortReverse = true; + } + else { + scope.sortReverse = false; + } + } + scope.sortDirection = scope.sortReverse ? "desc" : "asc"; + + } + // sort function + scope.sortBy = function (item) { + if (scope.sortColumn === "updateDate") { + return [-item['isFolder'],item['updateDate']]; + } + else { + return [-item['isFolder'],item['name']]; + } + }; + } @@ -345,7 +380,8 @@ Use this directive to generate a thumbnail grid of media items. onlyImages: "@", onlyFolders: "@", includeSubFolders: "@", - currentFolderId: "@" + currentFolderId: "@", + showMediaList: "=" }, link: link }; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less index 5d6b7ad962..abd1bfd047 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-media-grid.less @@ -217,3 +217,19 @@ text-decoration: none; box-shadow: 0 1px 2px rgba(0,0,0,.2); } + +/*for the listview*/ + +.umb-media-grid__list-item.selected, .umb-media-grid__list-item.selected:hover, .umb-media-grid__list-item.selected:focus { + border: 2px solid #f5c1bc !important; +} + +.umb-media-grid__list-view .umb-table-cell.umb-table__name { + flex: 1 1 25%; + max-width: none; + white-space: normal; +} + +.umb-media-grid__list-view .umb-table-cell.umb-table__name .item-name { + white-space:normal; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js index 097ccd9437..26c2eee3a4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js @@ -22,6 +22,10 @@ angular.module("umbraco") vm.clickHandler = clickHandler; vm.clickItemName = clickItemName; vm.gotoFolder = gotoFolder; + vm.shouldShowUrl = shouldShowUrl; + vm.toggleListView = toggleListView; + vm.selectLayout = selectLayout; + vm.showMediaList = false; var dialogOptions = $scope.model; @@ -81,6 +85,11 @@ angular.module("umbraco") filter: '', dataTypeKey: dataTypeKey }; + vm.layout = { + layouts: [{ name: "Grid", icon: "icon-thumbnails-small", path: "gridpath", selected: true }, + { name: "List", icon: "icon-list", path: "listpath", selected: true }], + activeLayout: { name: "Grid", icon: "icon-thumbnails-small", path: "gridpath", selected: true } + }; // preload selected item $scope.target = null; @@ -232,6 +241,33 @@ angular.module("umbraco") return getChildren(folder.id); } + function shouldShowUrl() { + if (!$scope.model.target) { + return false; + } + if ($scope.model.target.id) { + return false; + } + if ($scope.model.target.url && $scope.model.target.url.toLower().indexOf("blob:") === 0) { + return false; + } + return true; + } + + function toggleListView() { + vm.showMediaList = !vm.showMediaList; + } + + function selectLayout(layout) { + //this somehow doesn't set the 'active=true' property for the chosen layout + vm.layout.activeLayout = layout; + //workaround + vm.layout.layouts.forEach(element => element.active = false); + layout.active = true; + //set whether to toggle the list + vm.showMediaList = (layout.name === "List"); + } + function clickHandler(media, event, index) { if (media.isFolder) { @@ -445,7 +481,6 @@ angular.module("umbraco") // set thumbnail and src mediaItem.thumbnail = mediaHelper.resolveFileFromEntity(mediaItem, true); mediaItem.image = mediaHelper.resolveFileFromEntity(mediaItem, false); - // set properties to match a media object if (mediaItem.metaData) { mediaItem.properties = []; @@ -473,6 +508,9 @@ angular.module("umbraco") } ); } + if (mediaItem.metaData.UpdateDate !== null) { + mediaItem.updateDate = mediaItem.metaData.UpdateDate; + } } } @@ -487,7 +525,9 @@ angular.module("umbraco") data[i].thumbnail = mediaHelper.resolveFileFromEntity(data[i], true); data[i].image = mediaHelper.resolveFileFromEntity(data[i], false); } - + if (data[i].metaData.UpdateDate !== null){ + data[i].updateDate = data[i].metaData.UpdateDate; + } data[i].filtered = allowedTypes && allowedTypes.indexOf(data[i].metaData.ContentTypeAlias) < 0; } diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html index 64c711928d..ab51949dfb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.html @@ -22,37 +22,52 @@
+ model="filterOptions.excludeSubFolders" + on-change="vm.toggle()" + text="Include subfolders in search" + label-key="general_excludeFromSubFolders">
+ type="button" + label-key="general_upload" + action="vm.upload()" + disabled="lockedFolder" + button-style="action">
- - +
+
+ + +
+
+
+ + +
+
  • - + -
@@ -85,44 +100,45 @@
+ ng-if="vm.acceptedMediatypes.length > 0 && !vm.loading && !lockedFolder" + accepted-mediatypes="vm.acceptedMediatypes" + parent-id="{{currentFolder.id}}" + files-uploaded="vm.onUploadComplete" + files-queued="vm.onFilesQueue" + accept="{{vm.acceptedFileTypes}}" + max-file-size="{{vm.maxFileSize}}" + hide-dropzone="{{ !activeDrag && (images.length > 0 || vm.searchOptions.filter !== '') }}" + compact="{{ images.length > 0 }}"> + ng-if="!vm.loading" + items="images" + on-click="vm.clickHandler" + on-click-name="vm.clickItemName" + item-max-width="150" + item-max-height="150" + item-min-width="100" + item-min-height="100" + disable-folder-select={{disableFolderSelect}} + only-images={{onlyImages}} + only-folders={{onlyFolders}} + include-sub-folders={{!filterOptions.excludeSubFolders}} + current-folder-id="{{currentFolder.id}}" + show-media-list=vm.showMediaList> + ng-if="vm.loading">
+ ng-if="vm.searchOptions.totalPages > 0 && !vm.loading" + page-number="vm.searchOptions.pageNumber" + total-pages="vm.searchOptions.totalPages" + on-change="vm.changePagination(pageNumber)">
@@ -132,8 +148,11 @@ + + + diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html index d347fecb2d..211c501e53 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-media-grid.html @@ -1,44 +1,96 @@ -
-
-
- -
- -
{{item.name}}
+
+
+
+
+ +
+ +
{{item.name}}
+
+ + +
+ + + {{item.name}} + + + {{item.name}} + + + {{item.name}} + + + + +
- - -
- - - {{item.name}} - - - {{item.name}} - - - {{item.name}} - - - - -
-
+ + +
+
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+ +
+ + +
+
+ + {{item.name}} +
+
+ {{item.updateDate | date:'medium'}} +
+
+
+
+
+
+ diff --git a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs index 6cb2ccffaf..502b603be6 100644 --- a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs @@ -63,8 +63,7 @@ namespace Umbraco.Web.Models.ContentEditing /// The path of the entity /// [DataMember(Name = "path")] - public string Path { get; set; } - + public string Path { get; set; } /// /// A collection of extra data that is available for this specific entity/entity type /// diff --git a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs index ddff093aab..d14d63ca0e 100644 --- a/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs +++ b/src/Umbraco.Web/Models/Mapping/EntityMapDefinition.cs @@ -41,6 +41,7 @@ namespace Umbraco.Web.Models.Mapping target.Path = source.Path; target.Trashed = source.Trashed; target.Udi = Udi.Create(ObjectTypes.GetUdiType(source.NodeObjectType), source.Key); + if (source is IContentEntitySlim contentSlim) { @@ -54,6 +55,8 @@ namespace Umbraco.Web.Models.Mapping if (source is IMediaEntitySlim mediaSlim) { + //pass UpdateDate for MediaPicker ListView ordering + source.AdditionalData["UpdateDate"] = mediaSlim.UpdateDate; source.AdditionalData["MediaPath"] = mediaSlim.MediaPath; }