diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
index 2388aae2b2..723a365eb0 100644
--- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less
+++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
@@ -126,21 +126,21 @@ ul.color-picker li a {
// Media picker
// --------------------------------------------------
.umb-mediapicker .add-link {
- display: inline-block;
- height: 120px;
- width: 120px;
- text-align: center;
- color: @gray-8;
- border: 2px @gray-8 dashed;
- line-height: 120px;
- text-decoration: none;
+ display: flex;
+ justify-content:center;
+ align-items:center;
+ width: 120px;
+ text-align: center;
+ color: @gray-8;
+ border: 2px @gray-8 dashed;
+ text-decoration: none;
- transition: all 150ms ease-in-out;
+ transition: all 150ms ease-in-out;
- &:hover {
- color: @turquoise-d1;
- border-color: @turquoise;
- }
+ &:hover {
+ color: @turquoise-d1;
+ border-color: @turquoise;
+ }
}
.umb-mediapicker .picked-image {
@@ -207,11 +207,10 @@ ul.color-picker li a {
.umb-mediapicker .umb-sortable-thumbnails li {
flex-direction: column;
- margin: 0;
+ margin: 0 5px 0 0;
padding: 5px;
}
-
.umb-sortable-thumbnails li:hover a {
display: flex;
justify-content: center;
@@ -219,16 +218,20 @@ ul.color-picker li a {
}
.umb-sortable-thumbnails li img {
- max-width:100%;
- max-height:100%;
- margin:auto;
- display:block;
- background-image: url(../img/checkered-background.png);
+ max-width:100%;
+ max-height:100%;
+ margin:auto;
+ display:block;
+ background-image: url(../img/checkered-background.png);
}
-.umb-sortable-thumbnails li img.noScale{
- max-width: none !important;
- max-height: none !important;
+.umb-sortable-thumbnails li img.trashed {
+ opacity:0.3;
+}
+
+.umb-sortable-thumbnails li img.noScale {
+ max-width: none !important;
+ max-height: none !important;
}
.umb-sortable-thumbnails .umb-icon-holder {
@@ -254,8 +257,8 @@ ul.color-picker li a {
}
.umb-sortable-thumbnails li:hover .umb-sortable-thumbnails__actions {
- opacity: 1;
- visibility: visible;
+ opacity: 1;
+ visibility: visible;
}
.umb-sortable-thumbnails .umb-sortable-thumbnails__action {
@@ -285,27 +288,27 @@ ul.color-picker li a {
// -------------------------------------------------
.umb-cropper{
- position: relative;
+ position: relative;
}
.umb-cropper img, .umb-cropper-gravity img{
- position: relative;
- max-width: 100%;
- height: auto;
- top: 0;
- left: 0;
+ position: relative;
+ max-width: 100%;
+ height: auto;
+ top: 0;
+ left: 0;
}
.umb-cropper img {
- max-width: none;
+ max-width: none;
}
.umb-cropper .overlay, .umb-cropper-gravity .overlay {
- top: 0;
- left: 0;
- cursor: move;
- z-index: 6001;
- position: absolute;
+ top: 0;
+ left: 0;
+ cursor: move;
+ z-index: 6001;
+ position: absolute;
}
.umb-cropper .viewport{
@@ -317,43 +320,43 @@ ul.color-picker li a {
}
.umb-cropper-gravity .viewport{
- overflow: hidden;
- position: relative;
- width: 100%;
- height: 100%;
+ overflow: hidden;
+ position: relative;
+ width: 100%;
+ height: 100%;
}
.umb-cropper .viewport:after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 5999;
- -moz-opacity: .75;
- opacity: .75;
- filter: alpha(opacity=7);
- -webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
- -moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
- box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 5999;
+ -moz-opacity: .75;
+ opacity: .75;
+ filter: alpha(opacity=7);
+ -webkit-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
+ -moz-box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
+ box-shadow: inset 0 0 0 20px white,inset 0 0 0 21px rgba(0,0,0,.1),inset 0 0 20px 21px rgba(0,0,0,.2);
}
.umb-cropper-gravity .overlay{
- width: 14px;
- height: 14px;
- text-align: center;
- border-radius: 20px;
- background: @turquoise;
- border: 3px solid @white;
- opacity: 0.8;
+ width: 14px;
+ height: 14px;
+ text-align: center;
+ border-radius: 20px;
+ background: @turquoise;
+ border: 3px solid @white;
+ opacity: 0.8;
}
.umb-cropper-gravity .overlay i {
- font-size: 26px;
- line-height: 26px;
- opacity: 0.8 !important;
+ font-size: 26px;
+ line-height: 26px;
+ opacity: 0.8 !important;
}
.umb-cropper .crop-container {
@@ -361,16 +364,16 @@ ul.color-picker li a {
}
.umb-cropper .crop-slider {
- padding: 10px;
- border-top: 1px solid @gray-10;
- margin-top: 10px;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-wrap: wrap;
- @media (min-width: 769px) {
+ padding: 10px;
+ border-top: 1px solid @gray-10;
+ margin-top: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ @media (min-width: 769px) {
padding: 10px 50px 10px 50px;
- }
+ }
}
.umb-cropper .crop-slider i {
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
index 9b3316ec1a..229ec614de 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
@@ -1,7 +1,7 @@
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
-function contentPickerController($scope, entityResource, editorState, iconHelper, $routeParams, angularHelper, navigationService, $location, miniEditorHelper) {
+function contentPickerController($scope, entityResource, editorState, iconHelper, $routeParams, angularHelper, navigationService, $location, miniEditorHelper, localizationService) {
var unsubscribe;
@@ -154,7 +154,6 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
}
}
-
if ($routeParams.section === "settings" && $routeParams.tree === "documentTypes") {
//if the content-picker is being rendered inside the document-type editor, we don't need to process the startnode query
dialogOptions.startNodeId = -1;
@@ -287,8 +286,12 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
entityResource.getUrl(entity.id, entityType).then(function(data){
// update url
angular.forEach($scope.renderModel, function(item){
- if(item.id === entity.id) {
- item.url = data;
+ if (item.id === entity.id) {
+ if (entity.trashed) {
+ item.url = localizationService.dictionary.general_recycleBin;
+ } else {
+ item.url = data;
+ }
}
});
});
@@ -330,6 +333,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
"icon": item.icon,
"path": item.path,
"url": item.url,
+ "trashed": item.trashed,
"published": (item.metaData && item.metaData.IsPublished === false && entityType === "Document") ? false : true
// only content supports published/unpublished content so we set everything else to published so the UI looks correct
});
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
index 75cc74f02d..1755840cc8 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.html
@@ -1,5 +1,8 @@
+
+
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
index 6652c52cc0..21a0717779 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
@@ -1,7 +1,7 @@
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController",
- function ($rootScope, $scope, dialogService, entityResource, mediaResource, mediaHelper, $timeout, userService, $location) {
+ function ($rootScope, $scope, dialogService, entityResource, mediaResource, mediaHelper, $timeout, userService, $location, localizationService) {
//check the pre-values for multi-picker
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
@@ -25,17 +25,44 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
// the mediaResource has server side auth configured for which the user must have
// access to the media section, if they don't they'll get auth errors. The entityResource
// acts differently in that it allows access if the user has access to any of the apps that
- // might require it's use. Therefore we need to use the metatData property to get at the thumbnail
+ // might require it's use. Therefore we need to use the metaData property to get at the thumbnail
// value.
- entityResource.getByIds(ids, "Media").then(function (medias) {
+ entityResource.getByIds(ids, "Media").then(function(medias) {
- _.each(medias, function (media, i) {
+ // The service only returns item results for ids that exist (deleted items are silently ignored).
+ // This results in the picked items value to be set to contain only ids of picked items that could actually be found.
+ // Since a referenced item could potentially be restored later on, instead of changing the selected values here based
+ // on whether the items exist during a save event - we should keep "placeholder" items for picked items that currently
+ // could not be fetched. This will preserve references and ensure that the state of an item does not differ depending
+ // on whether it is simply resaved or not.
+ // This is done by remapping the int/guid ids into a new array of items, where we create "Deleted item" placeholders
+ // when there is no match for a selected id. This will ensure that the values being set on save, are the same as before.
+
+ medias = _.map(ids,
+ function(id) {
+ var found = _.find(medias,
+ function(m) {
+ return m.udi === id || m.id === id;
+ });
+ if (found) {
+ return found;
+ } else {
+ return {
+ name: localizationService.dictionary.mediaPicker_deletedItem,
+ id: $scope.model.config.idType !== "udi" ? id : null,
+ udi: $scope.model.config.idType === "udi" ? id : null,
+ icon: "icon-picture",
+ thumbnail: null,
+ trashed: true
+ };
+ }
+ });
- //only show non-trashed items
- if (media.parentId >= -1) {
-
- if (!media.thumbnail) {
+ _.each(medias,
+ function(media, i) {
+ // if there is no thumbnail, try getting one if the media is not a placeholder item
+ if (!media.thumbnail && media.id && media.metaData) {
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
@@ -43,12 +70,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
if ($scope.model.config.idType === "udi") {
$scope.ids.push(media.udi);
- }
- else {
+ } else {
$scope.ids.push(media.id);
}
- }
- });
+ });
$scope.sync();
});
@@ -80,8 +105,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
submit: function(model) {
_.each(model.selectedImages, function(media, i) {
-
- if (!media.thumbnail) {
+ // if there is no thumbnail, try getting one if the media is not a placeholder item
+ if (!media.thumbnail && media.id && media.metaData) {
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
@@ -99,10 +124,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
-
}
};
-
};
$scope.sortableOptions = {
@@ -140,5 +163,4 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
//update the display val again if it has changed from the server
setupViewModel();
};
-
});
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html
index f3aab992dd..70dd9ed2e5 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html
@@ -1,47 +1,47 @@
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml
index d01bea3d36..d64e8b82ed 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml
@@ -784,6 +784,15 @@ Mange hilsner fra Umbraco robotten
Du har ikke konfigureret nogen godkendte farver
+
+
Du har valgt et dokument som er slettet eller lagt i papirkurven
+
Du har valgt dokumenter som er slettede eller lagt i papirkurven
+
+
+
Du har valgt et medie som er slettet eller lagt i papirkurven
+
Du har valgt medier som er slettede eller lagt i papirkurven
+
Slettet medie
+
indtast eksternt link
vælg en intern side
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
index 1b71237ea4..4169c88335 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
@@ -952,6 +952,15 @@ To manage your website, simply open the Umbraco back office and start adding con
You have not configured any approved colours
+
+
You have picked a content item currently deleted or in the recycle bin
+
You have picked content items currently deleted or in the recycle bin
+
+
+
You have picked a media item currently deleted or in the recycle bin
+
You have picked media items currently deleted or in the recycle bin
+
Deleted item
+
enter external link
choose internal page
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
index c271ce8f65..13e0ebdad5 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
@@ -1011,6 +1011,15 @@ To manage your website, simply open the Umbraco back office and start adding con
You have not configured any approved colors
+
+
You have picked a content item currently deleted or in the recycle bin
+
You have picked content items currently deleted or in the recycle bin
+
+
+
You have picked a media item currently deleted or in the recycle bin
+
You have picked media items currently deleted or in the recycle bin
+
Deleted item
+
enter external link
choose internal page
diff --git a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs
index 9f6e5b28da..12afceea05 100644
--- a/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs
+++ b/src/Umbraco.Web/Models/ContentEditing/EntityBasic.cs
@@ -2,10 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
-using System.Linq;
using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Models.Validation;
diff --git a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs
index 5be9d550e5..3d825ab055 100644
--- a/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/EntityModelMapper.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Web.Models.Mapping
config.CreateMap
()
.ForMember(x => x.Udi, expression => expression.MapFrom(x => Udi.Create(UmbracoObjectTypesExtensions.GetUdiType(x.NodeObjectTypeId), x.Key)))
.ForMember(basic => basic.Icon, expression => expression.MapFrom(entity => entity.ContentTypeIcon))
- .ForMember(dto => dto.Trashed, expression => expression.Ignore())
+ .ForMember(dto => dto.Trashed, expression => expression.MapFrom(x => x.Trashed))
.ForMember(x => x.Alias, expression => expression.Ignore())
.AfterMap((entity, basic) =>
{