diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js
index e411be2c83..e65a3d238c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js
@@ -512,6 +512,7 @@ Opens an overlay to show a custom YSOD.
model: "=",
view: "=",
position: "@",
+ size: "=?",
parentScope: "=?"
},
link: link
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbnestedcontent.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbnestedcontent.directive.js
index 366294630b..471714d30b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbnestedcontent.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbnestedcontent.directive.js
@@ -3,7 +3,7 @@
function () {
var link = function ($scope) {
-
+
// Clone the model because some property editors
// do weird things like updating and config values
// so we want to ensure we start from a fresh every
@@ -12,10 +12,10 @@
$scope.nodeContext = $scope.model;
// Find the selected tab
- var selectedTab = $scope.model.tabs[0];
+ var selectedTab = $scope.model.variants[0].tabs[0];
if ($scope.tabAlias) {
- angular.forEach($scope.model.tabs, function (tab) {
+ angular.forEach($scope.model.variants[0].tabs, function (tab) {
if (tab.alias.toLowerCase() === $scope.tabAlias.toLowerCase()) {
selectedTab = tab;
return;
@@ -31,9 +31,9 @@
// Tell inner controls we are submitting
$scope.$broadcast("formSubmitting", { scope: $scope });
-
+
// Sync the values back
- angular.forEach($scope.ngModel.tabs, function (tab) {
+ angular.forEach($scope.ngModel.variants[0].tabs, function (tab) {
if (tab.alias.toLowerCase() === selectedTab.alias.toLowerCase()) {
var localPropsMap = selectedTab.properties.reduce(function (map, obj) {
@@ -94,4 +94,4 @@
// },
// link: link
// }
-//});
\ No newline at end of file
+//});
diff --git a/src/Umbraco.Web.UI.Client/src/common/filters/truncate.filter.js b/src/Umbraco.Web.UI.Client/src/common/filters/truncate.filter.js
new file mode 100644
index 0000000000..5efe0f5fff
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/filters/truncate.filter.js
@@ -0,0 +1,31 @@
+/**
+ * @ngdoc filter
+ * @name umbraco.filters.filter:truncate
+ * @namespace truncateFilter
+ *
+ * param {any} wordwise if true, the string will be cut after last fully displayed word.
+ * param {any} max max length of the outputtet string
+ * param {any} tail option tail, defaults to: ' ...'
+ *
+ * @description
+ * Limits the length of a string, if a cut happens only the string will be appended with three dots to indicate that more is available.
+ */
+angular.module("umbraco.filters").filter('truncate',
+ function () {
+ return function (value, wordwise, max, tail) {
+ if (!value) return '';
+ max = parseInt(max, 10);
+ if (!max) return value;
+ if (value.length <= max) return value;
+
+ value = value.substr(0, max);
+ if (wordwise) {
+ var lastspace = value.lastIndexOf(' ');
+ if (lastspace != -1) {
+ value = value.substr(0, lastspace);
+ }
+ }
+ return value + (tail || (wordwise ? ' …' : '…'));
+ };
+ }
+);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js b/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js
new file mode 100644
index 0000000000..6be9aba335
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js
@@ -0,0 +1,203 @@
+/**
+ * @ngdoc service
+ * @name umbraco.services.clipboardService
+ *
+ * @requires notificationsService
+ * @requires eventsService
+ *
+ * @description
+ * Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
+ * The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
+ *
+ */
+function clipboardService(notificationsService, eventsService, localStorageService) {
+
+
+ var STORAGE_KEY = "umbClipboardService";
+
+ var retriveStorage = function() {
+ if (localStorageService.isSupported === false) {
+ return null;
+ }
+ var dataJSON;
+ var dataString = localStorageService.get(STORAGE_KEY);
+ if (dataString != null) {
+ dataJSON = JSON.parse(dataString);
+ }
+
+ if(dataJSON == null) {
+ dataJSON = new Object();
+ }
+
+ if(dataJSON.entries === undefined) {
+ dataJSON.entries = [];
+ }
+
+ return dataJSON;
+ }
+
+ var saveStorage = function(storage) {
+ var storageString = JSON.stringify(storage);
+
+ try {
+ var storageJSON = JSON.parse(storageString);
+ localStorageService.set(STORAGE_KEY, storageString);
+
+ eventsService.emit("clipboardService.storageUpdate");
+
+ return true;
+ } catch(e) {
+ return false;
+ }
+
+ return false;
+ }
+
+
+ var service = {};
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.clipboardService#copy
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param type {string} umbraco A string defining the type of data to storing, example: 'elementType', 'contentNode'
+ * @param alias {string} umbraco A string defining the alias of the data to store, example: 'product'
+ * @param data {object} umbraco A object containing the properties to be saved.
+ *
+ * @description
+ * Saves a single JS-object with a type and alias to the clipboard.
+ */
+ service.copy = function(type, alias, data) {
+
+ var storage = retriveStorage();
+
+ var shallowCloneData = Object.assign({}, data);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
+ delete shallowCloneData.key;
+ delete shallowCloneData.$$hashKey;
+
+ var key = data.key || data.$$hashKey || console.error("missing unique key for this content");
+
+ // remove previous copies of this entry:
+ storage.entries = storage.entries.filter(
+ (entry) => {
+ return entry.unique !== key;
+ }
+ );
+
+ var entry = {unique:key, type:type, alias:alias, data:shallowCloneData};
+ storage.entries.push(entry);
+
+ if (saveStorage(storage) === true) {
+ notificationsService.success("Clipboard", "Copied to clipboard.");
+ } else {
+ notificationsService.success("Clipboard", "Couldnt copy this data to clipboard.");
+ }
+
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#supported
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @description
+ * Determins wether the current browser is able to performe its actions.
+ */
+ service.isSupported = function() {
+ return localStorageService.isSupported;
+ };
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#hasEntriesOfType
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param type {string} umbraco A string defining the type of data test for.
+ * @param aliases {string} umbraco A array of strings providing the alias of the data you want to test for.
+ *
+ * @description
+ * Determines whether the current clipboard has entries that match a given type and one of the aliases.
+ */
+ service.hasEntriesOfType = function(type, aliases) {
+
+ if(service.retriveEntriesOfType(type, aliases).length > 0) {
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param type {string} umbraco A string defining the type of data to recive.
+ * @param aliases {string} umbraco A array of strings providing the alias of the data you want to recive.
+ *
+ * @description
+ * Returns an array of entries matching the given type and one of the provided aliases.
+ */
+ service.retriveEntriesOfType = function(type, aliases) {
+
+ var storage = retriveStorage();
+
+ // Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
+ var filteretEntries = storage.entries.filter(
+ (entry) => {
+ return (entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
+ }
+ );
+
+ return filteretEntries;
+ };
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param type {string} umbraco A string defining the type of data to recive.
+ * @param aliases {string} umbraco A array of strings providing the alias of the data you want to recive.
+ *
+ * @description
+ * Returns an array of data of entries matching the given type and one of the provided aliases.
+ */
+ service.retriveDataOfType = function(type, aliases) {
+ return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
+ };
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param type {string} umbraco A string defining the type of data to remove.
+ * @param aliases {string} umbraco A array of strings providing the alias of the data you want to remove.
+ *
+ * @description
+ * Removes entries matching the given type and one of the provided aliases.
+ */
+ service.clearEntriesOfType = function(type, aliases) {
+
+ var storage = retriveStorage();
+
+ // Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
+ var filteretEntries = storage.entries.filter(
+ (entry) => {
+ return !(entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
+ }
+ );
+
+ storage.entries = filteretEntries;
+
+ saveStorage(storage);
+ };
+
+
+
+ return service;
+}
+angular.module("umbraco.services").factory("clipboardService", clipboardService);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
index 6de0b4170b..e853e07092 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/overlay.service.js
@@ -27,6 +27,11 @@
overlay.position = "center";
}
+ // set the default overlay size to small
+ if(!overlay.size) {
+ overlay.size = "small";
+ }
+
// use a default empty view if nothing is set
if(!overlay.view) {
overlay.view = "views/common/overlays/default/default.html";
@@ -72,4 +77,4 @@
angular.module("umbraco.services").factory("overlayService", overlayService);
-})();
\ No newline at end of file
+})();
diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less
index 441f52c81b..1e48500bb0 100644
--- a/src/Umbraco.Web.UI.Client/src/less/belle.less
+++ b/src/Umbraco.Web.UI.Client/src/less/belle.less
@@ -130,6 +130,7 @@
@import "components/tooltip/umb-tooltip.less";
@import "components/tooltip/umb-tooltip-list.less";
@import "components/overlays/umb-overlay-backdrop.less";
+@import "components/overlays/umb-itempicker.less";
@import "components/umb-grid.less";
@import "components/umb-empty-state.less";
@import "components/umb-property-editor.less";
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/card.less b/src/Umbraco.Web.UI.Client/src/less/components/card.less
index 0f4f2a7a9d..8324698685 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/card.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/card.less
@@ -6,6 +6,7 @@
position: relative;
padding: 5px 10px 5px 10px;
background: white;
+ width: 100%;
.title{padding: 12px; color: @gray-3; border-bottom: 1px solid @gray-8; font-weight: 400; font-size: 16px; text-transform: none; margin: 0 -10px 10px -10px;}
@@ -84,63 +85,73 @@
padding: 0;
margin: 0 auto;
list-style: none;
-
+ width: 100%;
+
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.umb-card-grid li {
- padding: 5px;
overflow: hidden;
font-size: 12px;
text-align: center;
- width: 100px;
box-sizing: border-box;
position: relative;
+ width: 100px;
}
-.umb-card-grid li.-four-in-row {
+.umb-card-grid.-four-in-row li {
flex: 0 0 25%;
max-width: 25%;
}
-.umb-card-grid li.-three-in-row {
+.umb-card-grid.-three-in-row li {
flex: 0 0 33.33%;
max-width:33.33%;
}
.umb-card-grid .umb-card-grid-item {
+ position: relative;
display: block;
width: 100%;
- height: 100%;
+ //height: 100%;
+ padding-top: 100%;
border-radius: 3px;
- padding-bottom: 5px;
+ transition: background-color 120ms;
+
+ > span {
+ position: absolute;
+ top: 10px;
+ bottom: 10px;
+ left: 10px;
+ right: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ background-color: transparent;
+ }
}
- .umb-card-grid .umb-card-grid-item:hover,
- .umb-card-grid .umb-card-grid-item:focus,
- .umb-card-grid .umb-card-grid-item:hover > *,
- .umb-card-grid .umb-card-grid-item:focus > * {
- background: @ui-option-hover;
+.umb-card-grid .umb-card-grid-item:hover,
+.umb-card-grid .umb-card-grid-item:focus {
+ background-color: @ui-option-hover;
color: @ui-option-type-hover;
- cursor: pointer;
- outline: none;
- border-radius: 3px;
}
.umb-card-grid a {
- color: @ui-option-type;
- text-decoration: none;
- }
+ color: @ui-option-type;
+ text-decoration: none;
+}
.umb-card-grid i {
- font-size: 30px;
- line-height: 50px;
- display: block;
- color: @ui-option-type;
- }
+ font-size: 30px;
+ line-height: 20px;
+ margin-bottom: 10px;
+ display: block;
+}
.umb-card-grid .umb-card-grid-item__loading {
position: absolute;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less
index 9205dc9c5f..f5050fad85 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less
@@ -5,51 +5,72 @@
z-index: @zindexUmbOverlay;
animation: fadeIn 0.2s;
box-shadow: 0 10px 50px rgba(0,0,0,0.1), 0 6px 20px rgba(0,0,0,0.16);
+ text-align: left;
}
.umb-overlay__form {
display: flex;
flex-wrap: nowrap;
flex-direction: column;
- height: 100%;
}
.umb-overlay .umb-overlay-header {
- //background: @gray-10;
border-bottom: 1px solid @purple-l3;
- //background: @blueExtraDark;
- //color:@u-white;
- padding: 10px;
margin-top: 0;
flex-grow: 0;
flex-shrink: 0;
+
+ padding: 20px 30px 0;
}
-.umb-overlay .umb-overlay__title {
+
+.umb-overlay__section-header {
+ width: 100%;
+ margin-top:30px;
+ margin-bottom: 10px;
+
+ h5 {
+ display: inline;
+ }
+
+ button {
+ display: inline;
+ float: right;
+ background-color: transparent;
+ border:none;
+ &:hover {
+ color: @ui-option-type-hover;
+ }
+ }
+}
+
+.umb-overlay__title {
font-size: @fontSizeLarge;
color: @black;
font-weight: bold;
margin: 7px 0;
}
-.umb-overlay .umb-overlay__subtitle {
+.umb-overlay__subtitle {
font-size: @fontSizeSmall;
color: @gray-3;
margin: 0;
}
-.umb-overlay .umb-overlay-container {
+.umb-overlay-container {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
- overflow-y: auto;
- overflow-x: hidden;
position: relative;
- height: auto;
+
+ padding: 0px 30px;
+ margin-bottom: 10px;
+ max-height: calc(100vh - 170px);
+ overflow-y: auto;
}
-.umb-overlay .umb-overlay-drawer {
+.umb-overlay-drawer {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 31px;
@@ -60,16 +81,16 @@
border-top: 1px solid @purple-l3;
}
-.umb-overlay .umb-overlay-drawer.-auto-height {
+.umb-overlay-drawer.-auto-height {
flex-basis: auto;
}
-.umb-overlay .umb-overlay-drawer .umb-overlay-drawer__align-right {
+.umb-overlay-drawer .umb-overlay-drawer__align-right {
display: flex;
justify-content: flex-end;
}
-.umb-overlay .umb-overlay-drawer .umb-overlay-drawer-content .dropdown-menu {
+.umb-overlay-drawer .umb-overlay-drawer-content .dropdown-menu {
right: 0;
left: auto;
}
@@ -89,46 +110,44 @@
.umb-overlay.umb-overlay-center .umb-overlay-header {
border: none;
background: transparent;
- padding: 20px 20px 0 20px;
+ padding: 30px 30px 0;
}
.umb-overlay.umb-overlay-center .umb-overlay__form {
- max-height: 80vh;
-}
-
-.umb-overlay.umb-overlay-center .umb-overlay-container {
- padding: 20px;
+
}
.umb-overlay.umb-overlay-center .umb-overlay-drawer {
border: none;
background: transparent;
- padding: 0 20px 20px 20px;
+ padding: 0 30px 20px;
}
/* ---------- OVERLAY TARGET ---------- */
.umb-overlay.umb-overlay-target {
width: 400px;
- height: 400px;
+ max-height: 100vh;
box-sizing: border-box;
border-radius: @baseBorderRadius;
+ /* default:
+ &.umb-overlay--small {
+ width: 400px;
+ }
+ */
+ &.umb-overlay--medium {
+ width: 480px;
+ }
}
.umb-overlay.umb-overlay-target .umb-overlay-header {
border: none;
background: transparent;
- padding: 20px 20px 0 20px;
- text-align: center;
-}
-
-.umb-overlay.umb-overlay-target .umb-overlay-container {
- padding: 20px;
}
.umb-overlay.umb-overlay-target .umb-overlay-drawer {
border: none;
background: transparent;
- padding: 0 20px 20px 20px;
+ padding: 0 30px 20px;
}
/* ---------- OVERLAY RIGHT ---------- */
@@ -143,14 +162,9 @@
.umb-overlay.umb-overlay-right .umb-overlay-header {
flex-basis: 100px;
- padding: 20px;
box-sizing: border-box;
}
-.umb-overlay.umb-overlay-right .umb-overlay-container {
- padding: 20px;
-}
-
// reset the top position to 0 because we are in a asbolute container and want to
// overlay to go all the way to the top
.umb-editors .umb-overlay.umb-overlay-right {
@@ -175,14 +189,10 @@
.umb-overlay.umb-overlay-left .umb-overlay-header {
flex-basis: 100px;
- padding: 20px;
+ padding: 30px 30px 0;
box-sizing: border-box;
}
-.umb-overlay.umb-overlay-left .umb-overlay-container {
- padding: 20px;
-}
-
@media (max-width: 767px) {
.umb-overlay.umb-overlay-left {
margin-left: 61px;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays/umb-itempicker.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays/umb-itempicker.less
new file mode 100644
index 0000000000..3727c92251
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays/umb-itempicker.less
@@ -0,0 +1,6 @@
+.umb-itempicker .form-search {
+ margin-top:10px;
+}
+.umb-card-grid {
+ margin-top: 10px;
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less
index b49be17a40..f1a6300481 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-nested-content.less
@@ -87,23 +87,11 @@
.umb-nested-content__icons {
opacity: 0;
- transition: opacity .15s ease-in-out;
+ transition: opacity 120ms ease-in-out;
position: absolute;
- right: 0px;
- top: 2px;
- background-color: @white;
+ right: 8px;
+ top: 4px;
padding: 5px;
-
- &:before {
- content: ' ';
- position: absolute;
- display: block;
- width: 30px;
- left: -30px;
- top: 0;
- bottom: 0;
- background: linear-gradient(90deg, rgba(255,255,255,0), white);
- }
}
.umb-nested-content__item--active > .umb-nested-content__header-bar {
@@ -130,41 +118,22 @@
-.umb-nested-content__icon,
-.umb-nested-content__icon.umb-nested-content__icon--disabled:hover {
+.umb-nested-content__icon {
display: inline-block;
- padding: 4px 6px;
+ padding: 4px;
margin: 2px;
cursor: pointer;
- background: @white;
- border: 1px solid @gray-7;
- border-radius: 200px;
- text-decoration: none !important;
+ color: @ui-option-type;
}
-.umb-nested-content__icon.umb-nested-content__icon--disabled:hover {
- cursor: default;
-}
-
-.umb-nested-content__icon:hover,
-.umb-nested-content__icon--active
-{
- color: @white;
- background: @blueMid;
- border-color: @blueMid;
+.umb-nested-content__icon:hover {
+ color: @ui-option-type-hover;
text-decoration: none;
}
-.umb-nested-content__icon .icon,
-.umb-nested-content__icon.umb-nested-content__icon--disabled:hover .icon {
+.umb-nested-content__icon .icon {
display: block;
font-size: 16px !important;
- color: @gray-3;
-}
-
-.umb-nested-content__icon:hover .icon,
-.umb-nested-content__icon--active .icon {
- color: @white;
}
.umb-nested-content__icon--disabled {
@@ -223,16 +192,6 @@
display: none !important;
}
-.umb-nested-content__help-text {
- display: inline-block;
- padding: 10px 20px 10px 20px;
- clear: both;
- font-size: 14px;
- color: @gray-3;
- background: @gray-10;
- border-radius: 15px;
-}
-
.umb-nested-content__doctypepicker table input,
.umb-nested-content__doctypepicker table select {
width: 100%;
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html
index 43933f8051..fd859b9e2e 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/datatypepicker/datatypepicker.html
@@ -33,24 +33,25 @@