diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index fbe7675836..b15b3f778c 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -117,8 +117,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -42, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-42", SortOrder = 2, UniqueId = new Guid("0b6a45e7-44ba-430d-9da5-4e46060b9e03"), Text = "Dropdown", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -41, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-41", SortOrder = 2, UniqueId = new Guid("5046194e-4237-453c-a547-15db3a07c4e1"), Text = "Date Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -40, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-40", SortOrder = 2, UniqueId = new Guid("bb5f57c9-ce2b-4bb9-b697-4caca783a805"), Text = "Radiobox", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -39, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-39", SortOrder = 2, UniqueId = new Guid("f38f0ac7-1d27-439c-9f3f-089cd8825a53"), Text = "Dropdown multiple", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -38, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-38", SortOrder = 2, UniqueId = new Guid("fd9f1447-6c61-4a7c-9595-5aa39147d318"), Text = "Folder Browser", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -39, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-39", SortOrder = 2, UniqueId = new Guid("f38f0ac7-1d27-439c-9f3f-089cd8825a53"), Text = "Dropdown multiple", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -37, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-37", SortOrder = 2, UniqueId = new Guid("0225af17-b302-49cb-9176-b9f35cab9c17"), Text = "Approved Color", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = -36, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-36", SortOrder = 2, UniqueId = new Guid("e4d66c0f-b935-4200-81f0-025f7256b89a"), Text = "Date Picker with time", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.DefaultContentListViewDataTypeId, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,-95", SortOrder = 2, UniqueId = new Guid("C0808DD3-8133-4E4B-8CE8-E2BEA84A96A4"), Text = Constants.Conventions.DataTypes.ListViewPrefix + "Content", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); @@ -196,7 +195,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 24, UniqueId = 24.ToGuid(), DataTypeId = -90, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.File, Name = "Upload file", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 25, UniqueId = 25.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Extension, Name = "Type", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 26, UniqueId = 26.ToGuid(), DataTypeId = -92, ContentTypeId = 1033, PropertyTypeGroupId = 4, Alias = Constants.Conventions.Media.Bytes, Name = "Size", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); - _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 27, UniqueId = 27.ToGuid(), DataTypeId = -38, ContentTypeId = 1031, PropertyTypeGroupId = 5, Alias = "contents", Name = "Contents:", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); + _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 27, UniqueId = 27.ToGuid(), DataTypeId = Constants.System.DefaultMediaListViewDataTypeId, ContentTypeId = 1031, PropertyTypeGroupId = 5, Alias = "contents", Name = "Contents:", SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); //membership property types _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 28, UniqueId = 28.ToGuid(), DataTypeId = -89, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.Comments, Name = Constants.Conventions.Member.CommentsLabel, SortOrder = 0, Mandatory = false, ValidationRegExp = null, Description = null }); _database.Insert("cmsPropertyType", "id", false, new PropertyTypeDto { Id = 29, UniqueId = 29.ToGuid(), DataTypeId = -92, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.FailedPasswordAttempts, Name = Constants.Conventions.Member.FailedPasswordAttemptsLabel, SortOrder = 1, Mandatory = false, ValidationRegExp = null, Description = null }); @@ -231,8 +230,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 6, DataTypeId = -90, PropertyEditorAlias = Constants.PropertyEditors.UploadFieldAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 7, DataTypeId = -92, PropertyEditorAlias = Constants.PropertyEditors.NoEditAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 8, DataTypeId = -36, PropertyEditorAlias = Constants.PropertyEditors.DateTimeAlias, DbType = "Date" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 9, DataTypeId = -37, PropertyEditorAlias = Constants.PropertyEditors.ColorPickerAlias, DbType = "Nvarchar" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 10, DataTypeId = -38, PropertyEditorAlias = Constants.PropertyEditors.FolderBrowserAlias, DbType = "Nvarchar" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 9, DataTypeId = -37, PropertyEditorAlias = Constants.PropertyEditors.ColorPickerAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 11, DataTypeId = -39, PropertyEditorAlias = Constants.PropertyEditors.DropDownListMultipleAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 12, DataTypeId = -40, PropertyEditorAlias = Constants.PropertyEditors.RadioButtonListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 13, DataTypeId = -41, PropertyEditorAlias = Constants.PropertyEditors.DateAlias, DbType = "Date" }); @@ -253,7 +251,6 @@ namespace Umbraco.Core.Persistence.Migrations.Initial //_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 19, DataTypeId = 1038, PropertyEditorAlias = Constants.PropertyEditors.MarkdownEditorAlias, DbType = "Ntext" }); //_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 20, DataTypeId = 1039, PropertyEditorAlias = Constants.PropertyEditors.UltimatePickerAlias, DbType = "Ntext" }); //_database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 23, DataTypeId = 1042, PropertyEditorAlias = Constants.PropertyEditors.MacroContainerAlias, DbType = "Ntext" }); - } private void CreateCmsDataTypePreValuesData() @@ -269,6 +266,17 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -2, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "Name" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -3, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "asc" }); _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -4, Alias = "includeProperties", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMembersListViewDataTypeId, Value = "[{\"alias\":\"email\",\"isSystem\":1},{\"alias\":\"username\",\"isSystem\":1},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1}]" }); + + //layouts for the list view + var cardLayout = "{\"name\": \"Grid\",\"path\": \"views/propertyeditors/listview/layouts/grid/grid.html\", \"icon\": \"icon-thumbnails-small\", \"isSystem\": 1, \"selected\": true}"; + var listLayout = "{\"name\": \"List\",\"path\": \"views/propertyeditors/listview/layouts/list/list.html\",\"icon\": \"icon-list\", \"isSystem\": 1,\"selected\": true}"; + + //defaults for the media list + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -5, Alias = "pageSize", SortOrder = 1, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "100" }); + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -6, Alias = "orderBy", SortOrder = 2, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "VersionDate" }); + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -7, Alias = "orderDirection", SortOrder = 3, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "desc" }); + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -8, Alias = "layouts", SortOrder = 4, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[" + cardLayout + "," + listLayout + "]" }); + _database.Insert("cmsDataTypePreValues", "id", false, new DataTypePreValueDto { Id = -9, Alias = "includeProperties", SortOrder = 5, DataTypeNodeId = Constants.System.DefaultMediaListViewDataTypeId, Value = "[{\"alias\":\"sort\",\"isSystem\":1, \"header\": \"Sort order\"},{\"alias\":\"updateDate\",\"header\":\"Last edited\",\"isSystem\":1},{\"alias\":\"owner\",\"header\":\"Updated by\",\"isSystem\":1}]" }); } private void CreateUmbracoRelationTypeData() diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 990b0a84d5..3bc97c60bc 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -394,12 +394,8 @@ namespace Umbraco.Core.Services using (var repository = RepositoryFactory.CreateMediaRepository(UowProvider.GetUnitOfWork())) { var query = Query.Builder; - //if the id is -1, then just get all - if (id != -1) - { - query.Where(x => x.ParentId == id); - } - + query.Where(x => x.ParentId == id); + long total; var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out total, orderBy, orderDirection, filter); @@ -427,11 +423,8 @@ namespace Umbraco.Core.Services using (var repository = RepositoryFactory.CreateMediaRepository(UowProvider.GetUnitOfWork())) { var query = Query.Builder; - //if the id is -1, then just get all - if (id != -1) - { - query.Where(x => x.ParentId == id); - } + query.Where(x => x.ParentId == id); + var medias = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, filter); return medias; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbbutton.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbbutton.directive.js index 4df813f429..1bb70e2b6c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbbutton.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/buttons/umbbutton.directive.js @@ -51,7 +51,9 @@ state: "=?", shortcut: "@?", label: "@?", - labelKey: "@?" + labelKey: "@?", + icon: "@?", + disabled: "=" } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheader.directive.js new file mode 100644 index 0000000000..b03d289a44 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheader.directive.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + function EditorSubHeaderDirective() { + + var directive = { + transclude: true, + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/subheader/umb-editor-sub-header.html' + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbEditorSubHeader', EditorSubHeaderDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentleft.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentleft.directive.js new file mode 100644 index 0000000000..d1c5bca923 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentleft.directive.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + function EditorSubHeaderContentLeftDirective() { + + var directive = { + transclude: true, + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/subheader/umb-editor-sub-header-content-left.html' + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbEditorSubHeaderContentLeft', EditorSubHeaderContentLeftDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentright.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentright.directive.js new file mode 100644 index 0000000000..819d7e30a6 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadercontentright.directive.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + function EditorSubHeaderContentRightDirective() { + + var directive = { + transclude: true, + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/subheader/umb-editor-sub-header-content-right.html' + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbEditorSubHeaderContentRight', EditorSubHeaderContentRightDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadersection.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadersection.directive.js new file mode 100644 index 0000000000..4ea2de83f1 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/subheader/umbeditorsubheadersection.directive.js @@ -0,0 +1,18 @@ +(function() { + 'use strict'; + + function EditorSubHeaderSectionDirective() { + + var directive = { + transclude: true, + restrict: 'E', + replace: true, + templateUrl: 'views/components/editor/subheader/umb-editor-sub-header-section.html' + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbEditorSubHeaderSection', EditorSubHeaderSectionDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbbreadcrumbs.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbbreadcrumbs.directive.js index 65894198ff..a200022f34 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbbreadcrumbs.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbbreadcrumbs.directive.js @@ -8,7 +8,8 @@ replace: true, templateUrl: 'views/components/umb-breadcrumbs.html', scope: { - ancestors: "=" + ancestors: "=", + entityType: "@" } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcontentgrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcontentgrid.directive.js new file mode 100644 index 0000000000..0d8ddc2170 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbcontentgrid.directive.js @@ -0,0 +1,41 @@ +(function() { + 'use strict'; + + function ContentGridDirective() { + + function link(scope, el, attr, ctrl) { + + scope.clickItem = function(item) { + if(scope.onClick) { + scope.onClick(item); + } + }; + + scope.selectItem = function(item, $event, $index) { + if(scope.onSelect) { + scope.onSelect(item, $event, $index); + $event.stopPropagation(); + } + }; + + } + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/umb-content-grid.html', + scope: { + content: '=', + contentProperties: "=", + onSelect: '=', + onClick: "=" + }, + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbContentGrid', ContentGridDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbfoldergrid.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbfoldergrid.directive.js new file mode 100644 index 0000000000..06475e9c45 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbfoldergrid.directive.js @@ -0,0 +1,40 @@ +(function() { + 'use strict'; + + function FolderGridDirective() { + + function link(scope, el, attr, ctrl) { + + scope.clickFolder = function(folder) { + if(scope.onClick) { + scope.onClick(folder); + } + }; + + scope.selectFolder = function(folder, $event, $index) { + if(scope.onSelect) { + scope.onSelect(folder, $event, $index); + } + $event.stopPropagation(); + }; + + } + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/umb-folder-grid.html', + scope: { + folders: '=', + onSelect: '=', + onClick: "=" + }, + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbFolderGrid', FolderGridDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umblistviewlayout.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblistviewlayout.directive.js new file mode 100644 index 0000000000..d026a3f4e5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblistviewlayout.directive.js @@ -0,0 +1,37 @@ +(function() { + 'use strict'; + + function ListViewLayoutDirective() { + + function link(scope, el, attr, ctrl) { + + scope.getContent = function(contentId) { + if(scope.onGetContent) { + scope.onGetContent(contentId); + } + }; + + } + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/umb-list-view-layout.html', + scope: { + contentId: '=', + folders: '=', + items: '=', + selection: '=', + options: '=', + entityType: '@', + onGetContent: '=' + }, + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbListViewLayout', ListViewLayoutDirective); + +})(); 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 c7858df500..fa639b6225 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 @@ -5,29 +5,21 @@ function link(scope, el, attr, ctrl) { - scope.folders = []; - scope.mediaItems = []; - var itemMaxHeight = 200; + var itemDefaultHeight = 200; + var itemDefaultWidth = 200; + var itemMaxWidth = 300; + var itemMaxHeight = 300; function activate() { - scope.folders = []; - scope.mediaItems = []; - for (var i = 0; scope.items.length > i; i++) { - var item = scope.items[i]; - setItemData(item); - setOriginalSize(item, itemMaxHeight); - - seperateFolderAndMediaItems(item); - } - if(scope.mediaItems.length > 0) { - setFlexValues(scope.mediaItems); + if(scope.items.length > 0) { + setFlexValues(scope.items); } } @@ -35,6 +27,7 @@ function setItemData(item) { item.isFolder = !mediaHelper.hasFilePropertyType(item); + item.hidden = item.isFolder; if(!item.isFolder){ item.thumbnail = mediaHelper.resolveFile(item, true); @@ -45,39 +38,40 @@ function setOriginalSize(item, maxHeight) { //set to a square by default - item.originalWidth = maxHeight; - item.originalHeight = maxHeight; + item.width = itemDefaultWidth; + item.height = itemDefaultHeight; item.aspectRatio = 1; var widthProp = _.find(item.properties, function(v) { return (v.alias === "umbracoWidth"); }); if (widthProp && widthProp.value) { - item.originalWidth = parseInt(widthProp.value, 10); - if (isNaN(item.originalWidth)) { - item.originalWidth = maxHeight; + item.width = parseInt(widthProp.value, 10); + if (isNaN(item.width)) { + item.width = itemDefaultWidth; } } var heightProp = _.find(item.properties, function(v) { return (v.alias === "umbracoHeight"); }); if (heightProp && heightProp.value) { - item.originalHeight = parseInt(heightProp.value, 10); - if (isNaN(item.originalHeight)) { - item.originalHeight = maxHeight; + item.height = parseInt(heightProp.value, 10); + if (isNaN(item.height)) { + item.height = itemDefaultWidth; } } - item.aspectRatio = item.originalWidth / item.originalHeight; + item.aspectRatio = item.width / item.height; - } + // set max width and height + if(item.width > itemMaxWidth) { + item.width = itemMaxWidth; + item.height = itemMaxWidth / item.aspectRatio; + } - function seperateFolderAndMediaItems(item) { - - if(item.isFolder){ - scope.folders.push(item); - } else { - scope.mediaItems.push(item); - } + if(item.height > itemMaxHeight) { + item.height = itemMaxHeight; + item.width = itemMaxHeight * item.aspectRatio; + } } @@ -88,13 +82,13 @@ var widestImageAspectRatio = null; // sort array after image width with the widest image first - flexSortArray = $filter('orderBy')(flexSortArray, 'originalWidth', true); + flexSortArray = $filter('orderBy')(flexSortArray, 'width', true); // find widest image aspect ratio widestImageAspectRatio = flexSortArray[0].aspectRatio; // find smallest image width - smallestImageWidth = flexSortArray[flexSortArray.length - 1].originalWidth; + smallestImageWidth = flexSortArray[flexSortArray.length - 1].width; for (var i = 0; flexSortArray.length > i; i++) { @@ -109,7 +103,7 @@ var flexStyle = { "flex": flex + " 1 " + imageMinWidth + "px", - "max-width": mediaItem.originalWidth + "px" + "max-width": mediaItem.width + "px" }; mediaItem.flexStyle = flexStyle; @@ -118,12 +112,29 @@ } - scope.toggleSelectItem = function(item) { - item.selected = !item.selected; + scope.selectItem = function(item, $event, $index) { + if(scope.onSelect) { + scope.onSelect(item, $event, $index); + $event.stopPropagation(); + } + }; + + scope.clickItem = function(item) { + if(scope.onClick) { + scope.onClick(item); + } + }; + + scope.hoverItemDetails = function(item, $event, hover) { + if(scope.onDetailsHover) { + scope.onDetailsHover(item, $event, hover); + } }; var unbindItemsWatcher = scope.$watch('items', function(newValue, oldValue){ - activate(); + if(angular.isArray(newValue)) { + activate(); + } }); scope.$on('$destroy', function(){ @@ -137,7 +148,10 @@ replace: true, templateUrl: 'views/components/umb-media-grid.html', scope: { - items: '=' + items: '=', + onDetailsHover: "=", + onSelect: '=', + onClick: '=' }, link: link }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js new file mode 100644 index 0000000000..18dd616f75 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js @@ -0,0 +1,105 @@ +(function() { + 'use strict'; + + function PaginationDirective() { + + function link(scope, el, attr, ctrl) { + + function activate() { + + scope.pagination = []; + + var i = 0; + + if (scope.totalPages <= 10) { + for (i = 0; i < scope.totalPages; i++) { + scope.pagination.push({ + val: (i + 1), + isActive: scope.pageNumber === (i + 1) + }); + } + } + else { + //if there is more than 10 pages, we need to do some fancy bits + + //get the max index to start + var maxIndex = scope.totalPages - 10; + //set the start, but it can't be below zero + var start = Math.max(scope.pageNumber - 5, 0); + //ensure that it's not too far either + start = Math.min(maxIndex, start); + + for (i = start; i < (10 + start) ; i++) { + scope.pagination.push({ + val: (i + 1), + isActive: scope.pageNumber === (i + 1) + }); + } + + //now, if the start is greater than 0 then '1' will not be displayed, so do the elipses thing + if (start > 0) { + scope.pagination.unshift({ name: "First", val: 1, isActive: false }, {val: "...",isActive: false}); + } + + //same for the end + if (start < maxIndex) { + scope.pagination.push({ val: "...", isActive: false }, { name: "Last", val: scope.totalPages, isActive: false }); + } + } + + } + + scope.next = function() { + if (scope.onNext && scope.pageNumber < scope.totalPages) { + scope.pageNumber++; + scope.onNext(scope.pageNumber); + } + }; + + scope.prev = function(pageNumber) { + if (scope.onPrev && scope.pageNumber > 1) { + scope.pageNumber--; + scope.onPrev(scope.pageNumber); + } + }; + + scope.goToPage = function(pageNumber) { + if(scope.onGoToPage) { + scope.pageNumber = pageNumber + 1; + scope.onGoToPage(scope.pageNumber); + } + }; + + var unbindPageNumberWatcher = scope.$watch('pageNumber', function(newValue, oldValue){ + activate(); + }); + + scope.$on('$destroy', function(){ + unbindPageNumberWatcher(); + }); + + activate(); + + } + + var directive = { + restrict: 'E', + replace: true, + templateUrl: 'views/components/umb-pagination.html', + scope: { + pageNumber: "=", + totalPages: "=", + onNext: "=", + onPrev: "=", + onGoToPage: "=" + }, + link: link + }; + + return directive; + + } + + angular.module('umbraco.directives').directive('umbPagination', PaginationDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbstickybar.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbstickybar.directive.js new file mode 100644 index 0000000000..727dc5ec94 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbstickybar.directive.js @@ -0,0 +1,116 @@ +(function() { + 'use strict'; + + function StickyBarDirective($rootScope) { + + function link(scope, el, attr, ctrl) { + + var bar = $(el); + var scrollableContainer = null; + var clonedBar = null; + var cloneIsMade = false; + var barTop = bar.context.offsetTop; + + function activate() { + + if (attr.scrollableContainer) { + scrollableContainer = $(attr.scrollableContainer); + } else { + scrollableContainer = $(window); + } + + scrollableContainer.on('scroll.umbStickyBar', determineVisibility).trigger("scroll"); + $(window).on('resize.umbStickyBar', determineVisibility); + + scope.$on('$destroy', function() { + scrollableContainer.off('.umbStickyBar'); + $(window).off('.umbStickyBar'); + }); + + } + + function determineVisibility() { + + var scrollTop = scrollableContainer.scrollTop(); + + if (scrollTop > barTop) { + + if (!cloneIsMade) { + + createClone(); + + clonedBar.css({ + 'visibility': 'visible' + }); + + } else { + + calculateSize(); + + } + + } else { + + if (cloneIsMade) { + + //remove cloned element (switched places with original on creation) + bar.remove(); + bar = clonedBar; + clonedBar = null; + + bar.removeClass('-umb-sticky-bar'); + bar.css({ + position: 'relative', + 'width': 'auto', + 'height': 'auto', + 'z-index': 'auto', + 'visibility': 'visible' + }); + + cloneIsMade = false; + + } + + } + + } + + function calculateSize() { + clonedBar.css({ + width: bar.outerWidth(), + height: bar.height() + }); + } + + function createClone() { + //switch place with cloned element, to keep binding intact + clonedBar = bar; + bar = clonedBar.clone(); + clonedBar.after(bar); + clonedBar.addClass('-umb-sticky-bar'); + clonedBar.css({ + 'position': 'fixed', + 'z-index': 500, + 'visibility': 'hidden' + }); + + cloneIsMade = true; + calculateSize(); + + } + + activate(); + + } + + var directive = { + restrict: 'A', + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbStickyBar', StickyBarDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtooltip.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtooltip.directive.js new file mode 100644 index 0000000000..4dd539d147 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbtooltip.directive.js @@ -0,0 +1,82 @@ +(function() { + 'use strict'; + + function TooltipDirective($timeout) { + + function link(scope, el, attr, ctrl) { + + scope.tooltipStyles = {}; + scope.tooltipStyles.left = 0; + scope.tooltipStyles.top = 0; + + function activate() { + + $timeout(function() { + setTooltipPosition(scope.event); + }); + + } + + function setTooltipPosition(event) { + + var viewportWidth = null; + var viewportHeight = null; + var elementHeight = null; + var elementWidth = null; + + var position = { + right: "inherit", + left: "inherit", + top: "inherit", + bottom: "inherit" + }; + + // viewport size + viewportWidth = $(window).innerWidth(); + viewportHeight = $(window).innerHeight(); + + // element size + elementHeight = el.context.clientHeight; + elementWidth = el.context.clientWidth; + + position.left = event.pageX - (elementWidth / 2); + position.top = event.pageY; + + // check to see if element is outside screen + // outside right + if (position.left + elementWidth > viewportWidth) { + position.right = 0; + position.left = "inherit"; + } + + // outside bottom + if (position.top + elementHeight > viewportHeight) { + position.bottom = 0; + position.top = "inherit"; + } + + scope.tooltipStyles = position; + + } + + activate(); + + } + + var directive = { + restrict: 'E', + transclude: true, + replace: true, + templateUrl: 'views/components/umb-tooltip.html', + scope: { + event: "=" + }, + link: link + }; + + return directive; + } + + angular.module('umbraco.directives').directive('umbTooltip', TooltipDirective); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/events/events.directive.js index 8d42e2a983..02da7bba7f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/events/events.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/events/events.directive.js @@ -10,7 +10,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onKeyup); }; elm.on("keyup", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("keyup", f);} ); } }; }) @@ -22,7 +22,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onKeydown); }; elm.on("keydown", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("keydown", f);} ); } }; }) @@ -34,7 +34,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onBlur); }; elm.on("blur", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("blur", f);} ); } }; }) @@ -46,7 +46,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onFocus); }; elm.on("focus", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("focus", f);} ); } }; }) @@ -58,7 +58,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onDragEnter); }; elm.on("dragenter", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("dragenter", f);} ); } }; }) @@ -91,7 +91,7 @@ angular.module('umbraco.directives') }; elm.on("dragleave", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("dragleave", f);} ); }; }) @@ -102,7 +102,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onDragOver); }; elm.on("dragover", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("dragover", f);} ); } }; }) @@ -114,7 +114,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onDragStart); }; elm.on("dragstart", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("dragstart", f);} ); } }; }) @@ -126,7 +126,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onDragEnd); }; elm.on("dragend", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("dragend", f);} ); } }; }) @@ -138,7 +138,7 @@ angular.module('umbraco.directives') scope.$apply(attrs.onDrop); }; elm.on("drop", f); - scope.$on("$destroy", function(){ elm.off(f);} ); + scope.$on("$destroy", function(){ elm.off("drop", f);} ); } }; }) @@ -236,8 +236,8 @@ angular.module('umbraco.directives') //unsub events scope.$on("$destroy", function(){ - element.off(leave_f); - element.off(enter_f); + element.off("mouseleave", leave_f); + element.off("mouseenter", enter_f); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js index 6c2fc5da4d..a1263a6126 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/datatype.resource.js @@ -17,7 +17,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) { * * ##usage *
-         * dataTypeResource.getPrevalyes("Umbraco.MediaPicker", 1234)
+         * dataTypeResource.getPreValues("Umbraco.MediaPicker", 1234)
          *    .then(function(prevalues) {
          *        alert('its gone!');
          *    });
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
index a8eda14161..f6443735cf 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
@@ -392,7 +392,45 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
                     }),
                 'Failed to add folder');
         },
-
+        
+        /**
+         * @ngdoc method
+         * @name umbraco.resources.mediaResource#getChildFolders
+         * @methodOf umbraco.resources.mediaResource
+         *
+         * @description
+         * Retrieves all media children with types used as folders.
+         * Uses the convention of looking for media items with mediaTypes ending in
+         * *Folder so will match "Folder", "bannerFolder", "secureFolder" etc,
+         *
+         * ##usage
+         * 
+         * mediaResource.getChildFolders(1234)
+         *    .then(function(data) {
+         *        alert('folders');
+         *    });
+         * 
+ * + * @param {int} parentId Id of the media item to query for child folders + * @returns {Promise} resourcePromise object. + * + */ + getChildFolders: function(parentId){ + if(!parentId){ + parentId = -1; + } + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "mediaApiBaseUrl", + "GetChildFolders", + [ + { id: parentId } + ])), + 'Failed to retrieve child folders for media item ' + parentId); + }, + /** * @ngdoc method * @name umbraco.resources.mediaResource#emptyRecycleBin diff --git a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js new file mode 100644 index 0000000000..41d1d62b69 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js @@ -0,0 +1,112 @@ +(function() { + 'use strict'; + + function listViewHelper() { + + var firstSelectedIndex = 0; + + function selectHandler(selectedItem, selectedIndex, items, selection, $event) { + + var start = 0; + var end = 0; + var item = null; + + if ($event.shiftKey === true) { + + if(selectedIndex > firstSelectedIndex) { + + start = firstSelectedIndex; + end = selectedIndex; + + for (; end >= start; start++) { + item = items[start]; + selectItem(item, selection); + } + + } else { + + start = firstSelectedIndex; + end = selectedIndex; + + for (; end <= start; start--) { + item = items[start]; + selectItem(item, selection); + } + + } + + } else { + + if(selectedItem.selected) { + deselectItem(selectedItem, selection); + } else { + selectItem(selectedItem, selection); + } + + firstSelectedIndex = selectedIndex; + + } + + } + + function selectItem(item, selection) { + var isSelected = false; + for (var i = 0; selection.length > i; i++) { + var selectedItem = selection[i]; + if (item.id === selectedItem.id) { + isSelected = true; + } + } + if(!isSelected && !item.hidden) { + selection.push({id: item.id}); + item.selected = true; + } + } + + function deselectItem(item, selection) { + for (var i = 0; selection.length > i; i++) { + var selectedItem = selection[i]; + if (item.id === selectedItem.id) { + selection.splice(i, 1); + item.selected = false; + } + } + } + + function clearSelection(items, folders, selection) { + + var i = 0; + + selection.length = 0; + + if(angular.isArray(items)) { + for(i = 0; items.length > i; i++) { + var item = items[i]; + item.selected = false; + } + } + + if(angular.isArray(items)) { + for(i = 0; folders.length > i; i++) { + var folder = folders[i]; + folder.selected = false; + } + } + } + + var service = { + selectHandler: selectHandler, + selectItem: selectItem, + deselectItem: deselectItem, + clearSelection: clearSelection + }; + + return service; + + } + + + angular.module('umbraco.services').factory('listViewHelper', listViewHelper); + + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index b6f4536b95..6cd3726c8f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -84,6 +84,7 @@ @import "components/umb-editor-navigation.less"; @import "components/umb-editor-sub-views.less"; @import "components/umb-editor-toolbar.less"; +@import "components/editor/subheader/umb-editor-sub-header.less"; @import "components/umb-grid-selector.less"; @import "components/umb-child-selector.less"; @import "components/umb-group-builder.less"; @@ -96,7 +97,11 @@ @import "components/umb-load-indicator.less"; @import "components/umb-breadcrumbs.less"; @import "components/umb-media-grid.less"; +@import "components/umb-folder-grid.less"; +@import "components/umb-content-grid.less"; @import "components/umb-layout-selector.less"; +@import "components/tooltip/umb-tooltip.less"; +@import "components/tooltip/umb-tooltip-list.less"; @import "components/overlays/umb-overlay-backdrop.less"; @import "components/buttons/umb-button.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less new file mode 100644 index 0000000000..5f6b91f4e9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less @@ -0,0 +1,53 @@ +.umb-editor-sub-header { + padding: 15px 0; + margin-bottom: 30px; + background: #ffffff; + display: flex; + justify-content: space-between; + margin-top: -30px; + position: relative; +} + +.umb-editor-sub-header.-umb-sticky-bar { + box-shadow: + 0 5px 0 rgba(0, 0, 0, 0.08), + 0 1px 0 rgba(0, 0, 0, 0.16); + transition: box-shadow 1s; +} + +.umb-editor-sub-header__content-left { + margin-right: auto; +} + +.umb-editor-sub-header__content-right { + margin-left: auto; +} + +.umb-editor-sub-header__content-left, +.umb-editor-sub-header__content-right { + display: flex; + align-items: stretch; +} + +.umb-editor-sub-header__section { + border-left: 1px solid @grayLight; + display: flex; + align-items: center; + padding-left: 20px; + padding-right: 20px; +} + +.umb-editor-sub-header__content-left .umb-editor-sub-header__section:first-child { + border-left: none; + padding-left: 0; +} + +.umb-editor-sub-header__content-right .umb-editor-sub-header__section { + border-left: none; + border-right: 1px solid @grayLight; +} + +.umb-editor-sub-header__content-right .umb-editor-sub-header__section:last-child { + border-right: none; + padding-right: 0; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip-list.less b/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip-list.less new file mode 100644 index 0000000000..4f704be511 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip-list.less @@ -0,0 +1,19 @@ +.umb-tooltip-list { + list-style: none; + margin-left: 0; + margin-bottom: 0; + padding: 10px; +} + +.umb-tooltip-list__item { + margin-bottom: 5px; +} + +.umb-tooltip-list__item:last-child { + margin-bottom: 0; +} + +.umb-tooltip-list__item-label { + font-weight: bold; + margin-bottom: -3px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip.less b/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip.less new file mode 100644 index 0000000000..b058cd1b4e --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/tooltip/umb-tooltip.less @@ -0,0 +1,13 @@ +.umb-tooltip { + position: fixed; + display: flex; + background: #ffffff; + padding: 10px; + z-index: 1000; + max-width: 200px; + font-size: 12px; + animation-duration: 0.1s; + animation-timing-function: ease-in; + animation: fadeIn; + margin-top: 15px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less new file mode 100644 index 0000000000..a4e18abb20 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-content-grid.less @@ -0,0 +1,124 @@ +.umb-content-grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; +} + +.umb-content-grid__item { + background: @grayLighter; + flex: 0 1 200px; + cursor: pointer; + position: relative; + margin: 10px; + border: 1px solid #ffffff; + user-select: none; +} + +.umb-content-grid__item:hover { + border: 1px solid @blue; +} + +.umb-content-grid__item:hover .umb-content-grid__action { + opacity: 1; +} + +.umb-content-grid__icon-container { + background: lighten(@grayLight, 7%); + height: 75px; + display: flex; + align-items: center; + justify-content: center; +} + +.umb-content-grid__icon { + font-size: 40px; + color: lighten(@gray, 20%); +} + +.umb-content-grid__icon.-light { + color: @grayLight; +} + + +.umb-content-grid__content { + box-sizing: border-box; + padding: 15px; +} + +.umb-content-grid__item-name { + font-weight: bold; + color: @grayDark; + margin-bottom: 10px; + color: black; + padding-bottom: 10px; + line-height: 1.4em; + border-bottom: 1px solid @grayLight; +} + +.umb-content-grid__item-name.-light { + color: @grayLight; +} + +.umb-content-grid__details-list { + list-style: none; + margin-bottom: 0; + margin-left: 0; + font-size: 11px; +} + +.umb-content-grid__details-list.-light { + color: @grayLight; +} + +.umb-content-grid__details-label { + font-weight: bold; + display: inline-block; +} + +.umb-content-grid__details-value { + display: inline-block; +} + +.umb-content-grid__action { + position: absolute; + opacity: 0; + top: 10px; + right: 10px; + border: 1px solid #ffffff; + width: 25px; + height: 25px; + background: rgba(0, 0, 0, 0.4); + border-radius: 50px; + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; + color: #ffffff; + cursor: pointer; +} + +.umb-content-grid__action:hover { + background: @blue; + transition: background 0.1s; +} + +.umb-content-grid__action.-selected { + opacity: 1; + background: @blue; +} + +.umb-content-grid__item:hover .umb-content-grid__action:not(.-selected) { + opacity: 1; + animation: fadeIn; + animation-duration: 0.2s; + animation-timing-function: ease-in-out; +} + +.umb-content-grid__no-items { + font-size: 16px; + font-weight: bold; + color: @grayLight; + padding-top: 50px; + padding-bottom: 50px; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-folder-grid.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-folder-grid.less new file mode 100644 index 0000000000..b82a18e3bb --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-folder-grid.less @@ -0,0 +1,81 @@ +.umb-folder-grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + margin-bottom: 30px; +} + +.umb-folder-grid__folder { + background: @grayLighter; + margin: 5px; + display: flex; + align-items: center; + padding: 10px 20px; + box-sizing: border-box; + flex: 1 1 200px; + border: 1px solid transparent; + transition: border 0.2s; + position: relative; + justify-content: space-between; + cursor: pointer; + user-select: none; +} + +.umb-folder-grid__folder:focus, +.umb-folder-grid__folder:active { + text-decoration: none; +} + +.umb-folder-grid__folder:hover { + text-decoration: none; + border: 1px solid @blue; +} + +.umb-folder-grid__folder-description { + display: flex; + align-items: center; +} + +.umb-folder-grid__folder-icon { + font-size: 20px; + color: @gray; + margin-right: 20px; +} + +.umb-folder-grid__folder-name { + font-size: 13px; +} + +.umb-folder-grid__action { + opacity: 0; + border: 1px solid #ffffff; + width: 25px; + height: 25px; + background: rgba(0, 0, 0, 0.4); + border-radius: 50px; + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; + color: #ffffff; + margin-left: 7px; + cursor: pointer; +} + +.umb-folder-grid__action:hover { + background: @blue; + transition: background 0.1s; +} + +.umb-folder-grid__action.-selected { + opacity: 1; + background: @blue; +} + +.umb-folder-grid__folder:hover .umb-folder-grid__action:not(.-selected) { + opacity: 1; + animation: fadeIn; + animation-duration: 0.2s; + animation-timing-function: ease-in-out; +} diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-layout-selector.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-layout-selector.less index 43e0c5ae52..122107f88c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-layout-selector.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-layout-selector.less @@ -9,7 +9,6 @@ cursor: pointer; height: 30px; width: 30px; - margin: 0 8px; font-size: 20px; display: flex; justify-content: center; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-list-view.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-list-view.less index c8fdcf6c3a..aadcd9dc89 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-list-view.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-list-view.less @@ -6,11 +6,10 @@ animation: fadeIn 0.5s; padding: 15px; position: relative; - z-index: 1; } .umb-list-view__trigger { - margin-bottom: 20px; + margin-bottom: 20px; } .umb-list-view__box.-open { @@ -47,9 +46,7 @@ .umb-list-view__settings { border: 1px dashed #d9d9d9; + border-top: none; border-radius: 0 0 5px 5px; - padding: 50px 20px 20px 20px; - position: relative; - top: -20px; - z-index: 0; + padding: 20px; } 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 66e1885042..03283ac0c3 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 @@ -2,83 +2,23 @@ display: flex; flex-wrap: wrap; flex-direction: row; + flex-wrap: wrap; + align-items: center; width: 100%; margin-bottom: 30px; } -/* ---------- FOLDERS --------- */ - -.umb-media-grid__folders { - display: flex; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - margin-bottom: 20px; -} - -.umb-media-grid__folder { - background: @grayLighter; - margin: 5px; - display: flex; - align-items: center; - padding: 10px 30px 10px 20px; - box-sizing: border-box; - flex: 1 1 200px; - border: 1px solid transparent; - transition: border 0.2s; - position: relative; -} - -.umb-media-grid__folder.-selected { - background: rgba(255, 255, 255, 0.6); -} - -.umb-media-grid__folder:focus, -.umb-media-grid__folder:active { - text-decoration: none; -} - -.umb-media-grid__folder:hover { - text-decoration: none; - border: 1px solid @blue; -} - -.umb-media-grid__folder-icon { - font-size: 20px; - color: @gray; - margin-right: 20px; -} - -.umb-media-grid__folder-name { - font-size: 13px; -} - -/* ---------- MEDIA ---------- */ - -.umb-media-grid__media { - display: flex; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - align-items: center; -} - .umb-media-grid__item { - margin: 7px; + margin: 2px; position: relative; background: @grayLighter; + overflow: hidden; } .umb-media-grid__item:hover { text-decoration: none; } -.umb-media-grid__item-image-placeholder { - width: 200px; - height: 200px; - display: inline-block; -} - .umb-media-grid__item-image { width: 100%; max-width: 100%; @@ -91,33 +31,36 @@ } .umb-media-grid__item-overlay { - display: none; + display: flex; + justify-content: center; + align-items: center; + opacity: 0; position: absolute; right: 0; bottom: 0; left: 0; z-index: 100; - padding: 5px; + padding: 5px 10px; + box-sizing: border-box; + font-size: 13px; overflow: hidden; color: white; - text-align: center; white-space: nowrap; - background: black; background: rgba(0, 0, 0, 0.4); + background: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.75)); } .umb-media-grid__item:hover .umb-media-grid__item-overlay { - display: block; + opacity: 1; + animation: fadeIn; + animation-duration: 0.2s; + animation-timing-function: ease-in-out; } .umb-media-grid__item-name { - text-align: center; - color: @gray; - font-size: 12px; - position: absolute; - bottom: 20px; - right: 0; - left: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .umb-media-grid__item-icon { @@ -129,44 +72,56 @@ transform: translate(-50%,-50%); } -.umb-media-grid__select { +.umb-media-grid__actions { + position: absolute; + z-index: 2; + width: 100%; + top: 0; + padding: 10px; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: flex-end; +} + +.umb-media-grid__action { opacity: 0; border: 1px solid #ffffff; - width: 30px; - height: 30px; + width: 25px; + height: 25px; background: rgba(0, 0, 0, 0.4); - position: absolute; - top: 10px; - right: 10px; - z-index: 10; border-radius: 50px; + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; + color: #ffffff; + margin-left: 7px; + cursor: pointer; } -.umb-media-grid__select.-size-20 { - width: 20px; - height: 20px; +.umb-media-grid__action.-not-clickable { + cursor: default; } -.umb-media-grid__select:hover { +.umb-media-grid__action:first-child { + margin-left: 0; +} + +.umb-media-grid__action:hover { background: @blue; - transition: background 0.2s; + transition: background 0.1s; } -.umb-media-grid__select.-selected { +.umb-media-grid__action.-selected { opacity: 1; background: @blue; } -.umb-media-grid__select-icon { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - color: white; -} - -.umb-media-grid__item:hover .umb-media-grid__select, -.umb-media-grid__folder:hover .umb-media-grid__select{ +.umb-media-grid__item:hover .umb-media-grid__action:not(.-selected), +.umb-media-grid__folder:hover .umb-media-grid__action:not(.-selected) { opacity: 1; - transition: opacity 0.2s; + animation: fadeIn; + animation-duration: 0.2s; + animation-timing-function: ease-in-out; } diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index 449ae42fd2..056dc0fc8a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -87,6 +87,10 @@ form { margin: 0 0 @baseLineHeight; } +form.-no-margin-bottom { + margin-bottom: 0; +} + fieldset { padding: 0; margin: 0; diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index d3c4c0de6e..0e1fcc633b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -511,4 +511,4 @@ height:1px; margin: 10px 0; overflow: hidden; -} \ No newline at end of file +} .umb-loader-wrapper.-bottom { bottom: 0; } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.controller.js new file mode 100644 index 0000000000..1476b852f2 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.controller.js @@ -0,0 +1,114 @@ + (function() { + "use strict"; + + function CopyOverlay($scope, localizationService, eventsService) { + + var vm = this; + + vm.hideSearch = hideSearch; + vm.selectResult = selectResult; + vm.onSearchResults = onSearchResults; + + var dialogOptions = $scope.model; + var searchText = "Search..."; + var node = dialogOptions.currentNode; + + localizationService.localize("general_search").then(function (value) { + searchText = value + "..."; + }); + + $scope.model.relateToOriginal = true; + $scope.dialogTreeEventHandler = $({}); + + vm.searchInfo = { + searchFromId: null, + searchFromName: null, + showSearch: false, + results: [], + selectedSearchResults: [] + }; + + function nodeSelectHandler(ev, args) { + args.event.preventDefault(); + args.event.stopPropagation(); + + if (args.node.metaData.listViewNode) { + //check if list view 'search' node was selected + + vm.searchInfo.showSearch = true; + vm.searchInfo.searchFromId = args.node.metaData.listViewNode.id; + vm.searchInfo.searchFromName = args.node.metaData.listViewNode.name; + } + else { + //eventsService.emit("editors.content.copyController.select", args); + + if ($scope.model.target) { + //un-select if there's a current one selected + $scope.model.target.selected = false; + } + + $scope.model.target = args.node; + $scope.model.target.selected = true; + } + + } + + function nodeExpandedHandler(ev, args) { + if (angular.isArray(args.children)) { + + //iterate children + _.each(args.children, function (child) { + //check if any of the items are list views, if so we need to add a custom + // child: A node to activate the search + if (child.metaData.isContainer) { + child.hasChildren = true; + child.children = [ + { + level: child.level + 1, + hasChildren: false, + name: searchText, + metaData: { + listViewNode: child, + }, + cssClass: "icon umb-tree-icon sprTree icon-search", + cssClasses: ["not-published"] + } + ]; + } + }); + } + } + + function hideSearch() { + vm.searchInfo.showSearch = false; + vm.searchInfo.searchFromId = null; + vm.searchInfo.searchFromName = null; + vm.searchInfo.results = []; + } + + // method to select a search result + function selectResult(evt, result) { + result.selected = result.selected === true ? false : true; + nodeSelectHandler(evt, { event: evt, node: result }); + } + + //callback when there are search results + function onSearchResults(results) { + vm.searchInfo.results = results; + vm.searchInfo.showSearch = true; + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler); + }); + + + } + + angular.module("umbraco").controller("Umbraco.Overlays.CopyOverlay", CopyOverlay); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html new file mode 100644 index 0000000000..a97a90c431 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html @@ -0,0 +1,38 @@ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.controller.js new file mode 100644 index 0000000000..abe58b9a02 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.controller.js @@ -0,0 +1,114 @@ + (function() { + "use strict"; + + function MoveOverlay($scope, localizationService, eventsService) { + + var vm = this; + + vm.hideSearch = hideSearch; + vm.selectResult = selectResult; + vm.onSearchResults = onSearchResults; + + var dialogOptions = $scope.model; + var searchText = "Search..."; + var node = dialogOptions.currentNode; + + localizationService.localize("general_search").then(function (value) { + searchText = value + "..."; + }); + + $scope.model.relateToOriginal = true; + $scope.dialogTreeEventHandler = $({}); + + vm.searchInfo = { + searchFromId: null, + searchFromName: null, + showSearch: false, + results: [], + selectedSearchResults: [] + }; + + function nodeSelectHandler(ev, args) { + args.event.preventDefault(); + args.event.stopPropagation(); + + if (args.node.metaData.listViewNode) { + //check if list view 'search' node was selected + + vm.searchInfo.showSearch = true; + vm.searchInfo.searchFromId = args.node.metaData.listViewNode.id; + vm.searchInfo.searchFromName = args.node.metaData.listViewNode.name; + } + else { + //eventsService.emit("editors.content.copyController.select", args); + + if ($scope.model.target) { + //un-select if there's a current one selected + $scope.model.target.selected = false; + } + + $scope.model.target = args.node; + $scope.model.target.selected = true; + } + + } + + function nodeExpandedHandler(ev, args) { + if (angular.isArray(args.children)) { + + //iterate children + _.each(args.children, function (child) { + //check if any of the items are list views, if so we need to add a custom + // child: A node to activate the search + if (child.metaData.isContainer) { + child.hasChildren = true; + child.children = [ + { + level: child.level + 1, + hasChildren: false, + name: searchText, + metaData: { + listViewNode: child, + }, + cssClass: "icon umb-tree-icon sprTree icon-search", + cssClasses: ["not-published"] + } + ]; + } + }); + } + } + + function hideSearch() { + vm.searchInfo.showSearch = false; + vm.searchInfo.searchFromId = null; + vm.searchInfo.searchFromName = null; + vm.searchInfo.results = []; + } + + // method to select a search result + function selectResult(evt, result) { + result.selected = result.selected === true ? false : true; + nodeSelectHandler(evt, { event: evt, node: result }); + } + + //callback when there are search results + function onSearchResults(results) { + vm.searchInfo.results = results; + vm.searchInfo.showSearch = true; + } + + $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler); + + $scope.$on('$destroy', function () { + $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler); + $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler); + }); + + + } + + angular.module("umbraco").controller("Umbraco.Overlays.MoveOverlay", MoveOverlay); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.html new file mode 100644 index 0000000000..c30f911cd9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/move/move.html @@ -0,0 +1,33 @@ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html index f1a8ccf14b..003031f834 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/buttons/umb-button.html @@ -10,20 +10,23 @@ + {{label}} {{label}} - -