true to hide icon.
@param {string=} alias show and edit the content alias.
-@param {boolean=} aliasLocked Set to true to lock the alias.
@param {boolean=} hideAlias Set to true to hide alias.
@param {string=} description Add a description to the content.
@param {boolean=} hideDescription Set to true to hide description.
-
+@param {boolean=} setpagetitle If true the page title will be set to reflect the type of data the header is working with
+@param {string=} editorfor The localization to use to aid accessibility on the edit and create screen
**/
(function () {
'use strict';
- function EditorHeaderDirective(editorService) {
+ function EditorHeaderDirective(editorService, localizationService, editorState) {
+
+ function link(scope, $injector) {
- function link(scope) {
scope.vm = {};
scope.vm.dropdownOpen = false;
scope.vm.currentVariant = "";
+ scope.loading = true;
+ scope.accessibility = {};
+ scope.accessibility.a11yMessage = "";
+ scope.accessibility.a11yName = "";
+ scope.accessibility.a11yMessageVisible = false;
+ scope.accessibility.a11yNameVisible = false;
+
+ // need to call localizationService service outside of routine to set a11y due to promise requirements
+ if (editorState.current) {
+ //to do make work for user create/edit
+ // to do make it work for user group create/ edit
+ // to make it work for language edit/create
+ scope.isNew = editorState.current.id === 0 ||
+ editorState.current.id === "0" ||
+ editorState.current.id === -1 ||
+ editorState.current.id === 0 ||
+ editorState.current.id === "-1";
+
+ var localizeVars = [
+ scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
+ "placeholders_a11yName",
+ scope.isNew ? "general_new" : "general_edit"
+ ];
+
+ if (scope.editorfor) {
+ localizeVars.push(scope.editorfor);
+ }
+ localizationService.localizeMany(localizeVars).then(function (data) {
+ setAccessibilityForEditor(data);
+ scope.loading = false;
+ });
+ }
scope.goBack = function () {
if (scope.onBack) {
@@ -247,6 +280,57 @@ Use this directive to construct a header inside the main editor window.
editorService.iconPicker(iconPicker);
};
+ function setAccessibilityForEditor(data) {
+
+ if (editorState.current) {
+ if (scope.nameLocked) {
+ scope.accessibility.a11yName = scope.name;
+ SetPageTitle(scope.name);
+ } else {
+
+ scope.accessibility.a11yMessage = data[0];
+ scope.accessibility.a11yName = data[1];
+ var title = data[2] + ":";
+ if (!scope.isNew) {
+ scope.accessibility.a11yMessage += " " + scope.name;
+ title += " " + scope.name;
+ } else {
+ var name = "";
+ if (editorState.current.contentTypeName) {
+ name = editorState.current.contentTypeName;
+ } else if (scope.editorfor) {
+ name = data[3];
+ }
+ if (name !== "") {
+ scope.accessibility.a11yMessage += " " + name;
+ scope.accessibility.a11yName = name + " " + scope.accessibility.a11yName;
+ title += " " + name;
+ }
+ }
+ if (title !== data[2] + ":") {
+ SetPageTitle(title);
+ }
+
+ }
+ scope.accessibility.a11yMessageVisible = !isEmptyOrSpaces(scope.accessibility.a11yMessage);
+ scope.accessibility.a11yNameVisible = !isEmptyOrSpaces(scope.accessibility.a11yName);
+ }
+
+ }
+
+ function isEmptyOrSpaces(str) {
+ return str === null || str===undefined || str.trim ==='';
+ }
+
+ function SetPageTitle(title) {
+ var setTitle = false;
+ if (scope.setpagetitle !== undefined) {
+ setTitle = scope.setpagetitle;
+ }
+ if (setTitle) {
+ scope.$emit("$changeTitle", title);
+ }
+ }
}
var directive = {
@@ -262,7 +346,6 @@ Use this directive to construct a header inside the main editor window.
icon: "=",
hideIcon: "@",
alias: "=",
- aliasLocked: "<",
hideAlias: "=",
description: "=",
hideDescription: "@",
@@ -271,7 +354,9 @@ Use this directive to construct a header inside the main editor window.
onSelectNavigationItem: "&?",
key: "=",
onBack: "&?",
- showBackButton: ""
+ showBackButton: "",
+ editorfor: "=",
+ setpagetitle:"="
},
link: link
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js
index 0f3d251e82..eb3c134f0b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js
@@ -31,6 +31,7 @@
@param {boolean} disabled Set the checkbox to be disabled.
@param {boolean} required Set the checkbox to be required.
@param {callback} onChange Callback when the value of the checkbox change by interaction.
+@param {string} cssClass Set a css class modifier
**/
@@ -78,7 +79,8 @@
serverValidationField: "@",
disabled: "<",
required: "<",
- onChange: "&?"
+ onChange: "&?",
+ cssClass: "@?"
}
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js
index 302378b8c0..06b9e51fba 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/property/umbproperty.directive.js
@@ -16,6 +16,9 @@ angular.module("umbraco.directives")
replace: true,
templateUrl: 'views/components/property/umb-property.html',
link: function (scope) {
+
+ scope.propertyEditorAPI = {};
+
userService.getCurrentUser().then(function (u) {
var isAdmin = u.userGroups.indexOf('admin') !== -1;
scope.propertyAlias = (Umbraco.Sys.ServerVariables.isDebuggingEnabled === true || isAdmin) ? scope.property.alias : null;
@@ -32,6 +35,19 @@ angular.module("umbraco.directives")
self.setPropertyError = function (errorMsg) {
$scope.property.propertyErrorMessage = errorMsg;
};
+
+ var unsubscribe = $scope.$on("ExposePropertyEditorAPI", function(event, api) {
+
+ //avoid eventual parent properties to capture this.
+ event.stopPropagation();
+
+ $scope.propertyEditorAPI = api;
+ });
+
+ $scope.$on("$destroy", function () {
+ unsubscribe();
+ });
+
}
};
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
index 7d1def43a8..7ff7f7fa66 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
@@ -18,6 +18,7 @@
config: "<",
validation: "<",
culture: "",
+ inputId: "@?",
onValueChanged: "&"
}
});
@@ -43,13 +44,13 @@
vm.hidePrompt = hidePrompt;
vm.onKeyUpOnTag = onKeyUpOnTag;
- vm.htmlId = "t" + String.CreateGuid();
vm.isLoading = true;
vm.tagToAdd = "";
vm.promptIsVisible = "-1";
vm.viewModel = [];
function onInit() {
+ vm.inputId = vm.inputId || "t" + String.CreateGuid();
assetsService.loadJs("lib/typeahead.js/typeahead.bundle.min.js").then(function () {
@@ -106,7 +107,7 @@
minLength: 1
};
- typeahead = $element.find('.tags-' + vm.htmlId).typeahead(opts, sources)
+ typeahead = $element.find('.tags-' + vm.inputId).typeahead(opts, sources)
.bind("typeahead:selected", function (obj, datum, name) {
angularHelper.safeApply($rootScope, function () {
addTagInternal(datum["text"]);
@@ -153,7 +154,7 @@
tagsHound.clearRemoteCache();
tagsHound = null;
}
- $element.find('.tags-' + vm.htmlId).typeahead('destroy');
+ $element.find('.tags-' + vm.inputId).typeahead('destroy');
}
function configureViewModel(isInitLoad) {
@@ -228,7 +229,7 @@
function addTagOnEnter(e) {
var code = e.keyCode || e.which;
if (code == 13) { //Enter keycode
- if ($element.find('.tags-' + vm.htmlId).parent().find(".tt-menu .tt-cursor").length === 0) {
+ if ($element.find('.tags-' + vm.inputId).parent().find(".tt-menu .tt-cursor").length === 0) {
//this is required, otherwise the html form will attempt to submit.
e.preventDefault();
addTag();
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js
index dfd1e1184d..fcc02f53a2 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgridselector.directive.js
@@ -1,7 +1,7 @@
(function () {
'use strict';
- function GridSelector($location, overlayService) {
+ function GridSelector($location, overlayService, editorService) {
function link(scope, el, attr, ctrl) {
@@ -56,8 +56,16 @@
};
scope.openTemplate = function (selectedItem) {
- var url = "/settings/templates/edit/" + selectedItem.id;
- $location.url(url);
+ const editor = {
+ id: selectedItem.id,
+ submit: function () {
+ editorService.close();
+ },
+ close: function () {
+ editorService.close();
+ }
+ };
+ editorService.templateEditor(editor);
}
scope.setAsDefaultItem = function (selectedItem) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js
index 7aa23cad7c..96a072330b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbpropertyfileupload.directive.js
@@ -299,7 +299,7 @@
*/
onFilesChanged: "&",
onInit: "&",
- required: "@"
+ required: "="
},
transclude: true,
controllerAs: 'vm',
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
index 81e439a9bb..6673002981 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/assets.service.js
@@ -250,9 +250,10 @@ angular.module('umbraco.services')
*
* @param {Array} pathArray string array of paths to the files to load
* @param {Scope} scope optional scope to pass into the loader
+ * @param {string} defaultAssetType optional default asset type used to load assets with no extension
* @returns {Promise} Promise object which resolves when all the files has loaded
*/
- load: function (pathArray, scope) {
+ load: function (pathArray, scope, defaultAssetType) {
var promise;
if (!angular.isArray(pathArray)) {
@@ -294,14 +295,29 @@ angular.module('umbraco.services')
promise = $q.all(promises);
// Split into css and js asset arrays, and use LazyLoad on each array
- var cssAssets = _.filter(assets,
- function (asset) {
- return asset.path.match(/(\.css$|\.css\?)/ig);
- });
- var jsAssets = _.filter(assets,
- function (asset) {
- return asset.path.match(/(\.js$|\.js\?)/ig);
- });
+ var cssAssets = [];
+ var jsAssets = [];
+
+ for (var i = 0; i < assets.length; i++) {
+ var asset = assets[i];
+ if (asset.path.match(/(\.css$|\.css\?)/ig)) {
+ cssAssets.push(asset);
+ } else if (asset.path.match(/(\.js$|\.js\?)/ig)) {
+ jsAssets.push(asset);
+ } else {
+ // Handle unknown assets
+ switch (defaultAssetType) {
+ case "css":
+ cssAssets.push(asset);
+ break;
+ case "js":
+ jsAssets.push(asset);
+ break;
+ default:
+ throw "Found unknown asset without a valid defaultAssetType specified";
+ }
+ }
+ }
function assetLoaded(asset) {
asset.state = "loaded";
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
index 647133f0b7..c3a1ba6432 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/clipboard.service.js
@@ -1,203 +1,264 @@
-/**
- * @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 {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
- * @param {string} alias A string defining the alias of the data to store, example: 'product'
- * @param {object} data 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 {string} type A string defining the type of data test for.
- * @param {string} aliases 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 {string} type A string defining the type of data to recive.
- * @param {string} aliases 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 {string} type A string defining the type of data to recive.
- * @param {string} aliases 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 {string} type A string defining the type of data to remove.
- * @param {string} aliases 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);
+/**
+ * @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, iconHelper) {
+
+
+ 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 prepareEntryForStorage = function(entryData) {
+
+ var shallowCloneData = Object.assign({}, entryData);// 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;
+
+ return shallowCloneData;
+ }
+
+ var isEntryCompatible = function(entry, type, allowedAliases) {
+ return entry.type === type
+ &&
+ (
+ (entry.alias && allowedAliases.filter(allowedAlias => allowedAlias === entry.alias).length > 0)
+ ||
+ (entry.aliases && entry.aliases.filter(entryAlias => allowedAliases.filter(allowedAlias => allowedAlias === entryAlias).length > 0).length === entry.aliases.length)
+ );
+ }
+
+
+ var service = {};
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.clipboardService#copy
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
+ * @param {string} alias A string defining the alias of the data to store, example: 'product'
+ * @param {object} entry A object containing the properties to be saved, this could be the object of a ElementType, ContentNode, ...
+ * @param {string} displayLabel (optional) A string swetting the label to display when showing paste entries.
+ *
+ * @description
+ * Saves a single JS-object with a type and alias to the clipboard.
+ */
+ service.copy = function(type, alias, data, displayLabel) {
+
+ var storage = retriveStorage();
+
+ var uniqueKey = 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 !== uniqueKey;
+ }
+ );
+
+ var entry = {unique:uniqueKey, type:type, alias:alias, data:prepareEntryForStorage(data), label:displayLabel || data.name, icon:iconHelper.convertFromLegacyIcon(data.icon)};
+ storage.entries.push(entry);
+
+ if (saveStorage(storage) === true) {
+ notificationsService.success("Clipboard", "Copied to clipboard.");
+ } else {
+ notificationsService.error("Clipboard", "Couldnt copy this data to clipboard.");
+ }
+
+ };
+
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.clipboardService#copyArray
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param {string} type A string defining the type of data to storing, example: 'elementTypeArray', 'contentNodeArray'
+ * @param {string} aliases An array of strings defining the alias of the data to store, example: ['banana', 'apple']
+ * @param {object} datas An array of objects containing the properties to be saved, example: [ElementType, ElementType, ...]
+ * @param {string} displayLabel A string setting the label to display when showing paste entries.
+ * @param {string} displayIcon A string setting the icon to display when showing paste entries.
+ * @param {string} uniqueKey A string prodiving an identifier for this entry, existing entries with this key will be removed to ensure that you only have the latest copy of this data.
+ *
+ * @description
+ * Saves a single JS-object with a type and alias to the clipboard.
+ */
+ service.copyArray = function(type, aliases, datas, displayLabel, displayIcon, uniqueKey) {
+
+ var storage = retriveStorage();
+
+ // Clean up each entry
+ var copiedDatas = datas.map(data => prepareEntryForStorage(data));
+
+ // remove previous copies of this entry:
+ storage.entries = storage.entries.filter(
+ (entry) => {
+ return entry.unique !== uniqueKey;
+ }
+ );
+
+ var entry = {unique:uniqueKey, type:type, aliases:aliases, data:copiedDatas, label:displayLabel, icon:displayIcon};
+
+ storage.entries.push(entry);
+
+ if (saveStorage(storage) === true) {
+ notificationsService.success("Clipboard", "Copied to clipboard.");
+ } else {
+ notificationsService.error("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 {string} type A string defining the type of data test for.
+ * @param {string} aliases 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 {string} type A string defining the type of data to recive.
+ * @param {string} aliases 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, allowedAliases) {
+
+ var storage = retriveStorage();
+
+ // Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
+ var filteretEntries = storage.entries.filter(
+ (entry) => {
+ return isEntryCompatible(entry, type, allowedAliases);
+ }
+ );
+
+ return filteretEntries;
+ };
+
+ /**
+ * @ngdoc method
+ * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @methodOf umbraco.services.clipboardService
+ *
+ * @param {string} type A string defining the type of data to recive.
+ * @param {string} aliases 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 {string} type A string defining the type of data to remove.
+ * @param {string} aliases 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, allowedAliases) {
+
+ var storage = retriveStorage();
+
+ // Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
+ var filteretEntries = storage.entries.filter(
+ (entry) => {
+ return !isEntryCompatible(entry, type, allowedAliases);
+ }
+ );
+
+ 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/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
index 02e85c278a..3c64401933 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js
@@ -606,10 +606,12 @@ When building a custom infinite editor view you can use the same components as a
* @methodOf umbraco.services.editorService
*
* @description
- * Opens the document type editor in infinite editing, the submit callback returns the saved document type
+ * Opens the document type editor in infinite editing, the submit callback returns the alias of the saved document type.
* @param {Object} editor rendering options
- * @param {Callback} editor.submit Submits the editor
- * @param {Callback} editor.close Closes the editor
+ * @param {Callback} editor.id Indicates the ID of the document type to be edited. Alternatively the ID may be set to `-1` in combination with `create` being set to `true` to open the document type editor for creating a new document type.
+ * @param {Callback} editor.create Set to `true` to open the document type editor for creating a new document type.
+ * @param {Callback} editor.submit Submits the editor.
+ * @param {Callback} editor.close Closes the editor.
* @returns {Object} editor object
*/
function documentTypeEditor(editor) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
index ca89f7824b..ce70e9f543 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js
@@ -465,6 +465,8 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
throw "section cannot be null";
}
+ appState.setMenuState("currentNode", node);
+
if (action.metaData && action.metaData["actionRoute"] && angular.isString(action.metaData["actionRoute"])) {
//first check if the menu item simply navigates to a route
var parts = action.metaData["actionRoute"].split("?");
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 2165c1b7cb..0b8965e4fe 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
@@ -65,10 +65,39 @@
open(overlay);
}
+ function confirm(overlay) {
+
+ if (!overlay.closeButtonLabelKey) overlay.closeButtonLabelKey = "general_cancel";
+ if (!overlay.view) overlay.view = "views/common/overlays/confirm/confirm.html";
+ if (!overlay.close) overlay.close = function () { close(); };
+
+ switch (overlay.confirmType) {
+
+ case "delete":
+ if (!overlay.confirmMessageStyle) overlay.confirmMessageStyle = "danger";
+ if (!overlay.submitButtonStyle) overlay.submitButtonStyle = "danger";
+ if (!overlay.submitButtonLabelKey) overlay.submitButtonLabelKey = "contentTypeEditor_yesDelete";
+ break;
+
+ default:
+ if (!overlay.submitButtonLabelKey) overlay.submitButtonLabelKey = "general_confirm";
+
+ }
+
+ open(overlay);
+
+ }
+
+ function confirmDelete(overlay) {
+ confirm(overlay);
+ }
+
var service = {
open: open,
close: close,
- ysod: ysod
+ ysod: ysod,
+ confirm: confirm,
+ confirmDelete: confirmDelete
};
return service;
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/propertyeditor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/propertyeditor.service.js
new file mode 100644
index 0000000000..0b24e78567
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/services/propertyeditor.service.js
@@ -0,0 +1,29 @@
+(function() {
+ 'use strict';
+
+ function propertyEditorService() {
+ /**
+ * @ngdoc function
+ * @name umbraco.services.propertyEditorService#expose
+ * @methodOf umbraco.services.propertyEditorService
+ * @function
+ *
+ * @param {object} scope An object containing API for the PropertyEditor
+ */
+ function exposeAPI(scope, api) {
+ if (!scope) {
+ throw "scope cannot be null";
+ }
+ if (!api) {
+ throw "api cannot be null";
+ }
+ scope.$emit("ExposePropertyEditorAPI", api);
+ }
+
+ return {
+ exposeAPI: exposeAPI
+ };
+ }
+
+ angular.module('umbraco.services').factory('propertyEditorService', propertyEditorService);
+})();
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
index 1351da081a..4d4f8792cf 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
@@ -735,7 +735,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//get all macro divs and load their content
$(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () {
- self.loadMacroContent($(this), null);
+ self.loadMacroContent($(this), null, editor);
});
});
@@ -850,14 +850,15 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
var $macroDiv = $(editor.dom.select("div.umb-macro-holder." + uniqueId));
+ editor.setDirty(true);
//async load the macro content
- this.loadMacroContent($macroDiv, macroObject);
+ this.loadMacroContent($macroDiv, macroObject, editor);
},
/** loads in the macro content async from the server */
- loadMacroContent: function ($macroDiv, macroData) {
+ loadMacroContent: function ($macroDiv, macroData, editor) {
//if we don't have the macroData, then we'll need to parse it from the macro div
if (!macroData) {
@@ -893,7 +894,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
$macroDiv.removeClass("loading");
htmlResult = htmlResult.trim();
if (htmlResult !== "") {
+ var wasDirty = editor.isDirty();
$ins.html(htmlResult);
+ if (!wasDirty) {
+ editor.undoManager.clear();
+ }
}
});
});
diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less
index 83d254c73c..391fafb3fa 100644
--- a/src/Umbraco.Web.UI.Client/src/less/belle.less
+++ b/src/Umbraco.Web.UI.Client/src/less/belle.less
@@ -77,6 +77,7 @@
@import "listview.less";
@import "gridview.less";
@import "footer.less";
+@import "filter-toggle.less";
@import "forms/umb-validation-label.less";
@@ -129,6 +130,7 @@
@import "components/umb-media-grid.less";
@import "components/umb-folder-grid.less";
@import "components/umb-content-grid.less";
+@import "components/umb-contextmenu.less";
@import "components/umb-layout-selector.less";
@import "components/tooltip/umb-tooltip.less";
@import "components/tooltip/umb-tooltip-list.less";
@@ -137,6 +139,7 @@
@import "components/umb-grid.less";
@import "components/umb-empty-state.less";
@import "components/umb-property-editor.less";
+@import "components/umb-property-actions.less";
@import "components/umb-color-swatches.less";
@import "components/check-circle.less";
@import "components/umb-file-icon.less";
@@ -187,6 +190,8 @@
@import "components/users/umb-user-preview.less";
@import "components/users/umb-user-picker-list.less";
+@import "components/contextdialogs/umb-dialog-datatype-delete.less";
+
// Utilities
@import "utilities/layout/_display.less";
@@ -217,6 +222,7 @@
@import "dashboards/umbraco-forms.less";
@import "dashboards/examine-management.less";
@import "dashboards/healthcheck.less";
+@import "dashboards/nucache.less";
@import "typeahead.less";
@import "hacks.less";
diff --git a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less
index 8b043c9045..b36c73a61a 100644
--- a/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less
+++ b/src/Umbraco.Web.UI.Client/src/less/canvas-designer.less
@@ -280,7 +280,7 @@ ul.sections {
margin:0;
padding:0;
margin-left: -80px;
- overflow: scroll;
+ overflow: auto;
overflow-x: hidden;
height: calc(100% - 91px);
@@ -316,35 +316,40 @@ ul.sections li a {
&:hover {
span, i {
opacity: 1;
+ color:#fff;
}
}
}
ul.sections li a i {
font-size: 30px;
+ opacity: 0.8;
}
ul.sections li a span {
- display:block;
+ display: block;
font-size: 10px;
line-height: 1.4em;
- opacity: 0.4;
+ opacity: 0.8;
}
ul.sections li.current {
- background-color: #2E2246;
-}
-
-ul.sections li.current a i {
- color: #ffffff;
-}
-
-ul.sections li.current, ul.sections li:hover {
border-left: 4px #f5c1bc solid;
}
-.fix-left-menu:hover ul.sections li a span,
-.fix-left-menu:hover ul.sections li a i,
+ul.sections li.current a i {
+ color: #f5c1bc;
+}
+
+ul.sections li.current {
+ border-left: 4px #f5c1bc solid;
+}
+
+ul.sections li:hover a i,
+ul.sections li:hover a span {
+ opacity: 1;
+}
+
.fix-left-menu:hover .help {
opacity: 1;
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/contextdialogs/umb-dialog-datatype-delete.less b/src/Umbraco.Web.UI.Client/src/less/components/contextdialogs/umb-dialog-datatype-delete.less
new file mode 100644
index 0000000000..0e0b8f22bd
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/components/contextdialogs/umb-dialog-datatype-delete.less
@@ -0,0 +1,33 @@
+.umb-dialog-datatype-delete {
+
+
+ .umb-dialog-datatype-delete__table-head-column-name {
+ width: 140px;
+ }
+
+ .umb-table-body__icon {
+ margin-right: 5px;
+ vertical-align: top;
+ display: inline-block;
+ }
+
+ .table tbody td {
+ vertical-align: top;
+ }
+ .table tbody td > span {
+ margin: 5px 0;
+ vertical-align: middle;
+ }
+ .table tbody p {
+ line-height: 12px;
+ margin: 5px 0;
+ vertical-align: middle;
+ }
+
+ .table tbody .icon {
+ vertical-align: top;
+ margin-right: 5px;
+ display: inline-block;
+ }
+
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/notifications/umb-notifications.less b/src/Umbraco.Web.UI.Client/src/less/components/notifications/umb-notifications.less
index 1065082820..67038380ca 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/notifications/umb-notifications.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/notifications/umb-notifications.less
@@ -39,3 +39,8 @@
padding-top: 20px;
padding-bottom: 20px;
}
+
+
+.emptySection .umb-notifications{
+ left:0;
+}
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 d060f34a36..609cf0af3d 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less
@@ -117,7 +117,7 @@
.umb-overlay.umb-overlay-center .umb-overlay-drawer {
border: none;
background: transparent;
- padding: 0 30px 20px;
+ padding: 0 20px 20px;
}
/* ---------- OVERLAY TARGET ---------- */
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-contextmenu.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-contextmenu.less
new file mode 100644
index 0000000000..8512e2020d
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-contextmenu.less
@@ -0,0 +1,75 @@
+.umb-contextmenu {
+ margin: 0;
+ list-style: none;
+ user-select: none;
+
+ overflow: hidden;
+ border-radius: 3px;
+ border: 1px solid @dropdownBorder;
+ .box-shadow(0 5px 20px rgba(0,0,0,.3));
+ border-bottom: 1px solid rgba(0,0,0,.2);
+
+ .sep {
+ display: block;
+ border-top: 1px solid @gray-9;
+
+ &:first-child {
+ border-top: none;
+ }
+ }
+
+}
+
+.umb-contextmenu-item {
+
+ .icon {
+ font-size: 18px;
+ vertical-align: middle;
+ }
+
+ .menu-label {
+ display: inline-block;
+ vertical-align: middle;
+ margin-left: 5px;
+ }
+
+ button {
+
+ position: relative;
+
+ display: block;
+ font-weight: normal;
+ line-height: @baseLineHeight;
+ white-space: nowrap;
+
+ background-color: @ui-option;
+ border: 0;
+ padding: 7px 12px;
+ color: @ui-option-type;
+ width: 100%;
+
+ font-size: 14px;
+ text-align: left;
+
+ &:hover {
+ text-decoration: none;
+ color: @ui-option-type-hover;
+ background-color: @ui-option-hover;
+ }
+ }
+
+ &.-opens-dialog {
+ .menu-label:after {
+ // adds an ellipsis (...) after the menu label for actions that open a dialog
+ content: '\2026';
+ }
+ }
+ button:disabled {
+ cursor: not-allowed;
+ color: @ui-option-disabled-type;
+ &:hover {
+ color: @ui-option-disabled-type-hover;
+ background-color: @ui-option;
+ }
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less
index 22975ec6bb..7f19c4933c 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less
@@ -12,6 +12,14 @@
line-height: 22px;
cursor: pointer !important;
+ &.-small-text{
+ font-size: 13px;
+ }
+
+ &.-bold{
+ font-weight: 700;
+ }
+
&__text {
margin: 0 0 0 26px;
position: relative;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
index 7b8845542e..76223589e4 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-logviewer.less
@@ -1,5 +1,3 @@
-/* PACKAGE DETAILS */
-
.umb-logviewer {
display: flex;
flex-flow: row wrap;
@@ -41,7 +39,7 @@
flex: 1 1 auto;
width: 100%;
margin-bottom: 30px;
- margin-right: 0;
+ margin-right: 0;
}
.umb-logviewer__sidebar {
@@ -49,3 +47,99 @@
width: 100%;
}
}
+
+.umb-logviewer-search {
+ .filter-name {
+ margin-left: 5px;
+ margin-right: 3px;
+ max-width: 150px;
+ }
+
+ .dropdown-item {
+ padding: 8px 20px 8px 16px;
+ }
+
+ .filter {
+ position: relative;
+
+ a.btn-link {
+ padding-left: 0px;
+ }
+ }
+
+ .search-box {
+ width: 100%;
+
+ .flex-auto {
+ position: relative;
+
+ .search-input {
+ width: 100%;
+ padding-right: 160px;
+ }
+
+ .icon-rate {
+ position: absolute;
+ top: 0;
+ line-height: 32px;
+ right: 140px;
+ color: #fdb45c;
+ cursor: pointer;
+ }
+
+ .icon-wrong {
+ position: absolute;
+ top: 0;
+ line-height: 32px;
+ right: 120px;
+ color: #bbbabf;
+ cursor: pointer;
+ }
+
+ .umb-variant-switcher__toggle {
+ top: 1px;
+ right: 0;
+ position: absolute;
+
+ .icon-navigation-down {
+ margin-top: 0;
+ }
+ }
+
+ .saved-searches {
+ width: 100%;
+ max-height: 250px;
+ overflow-y: scroll;
+ margin-top: -10px;
+ }
+ }
+ }
+
+ .log-items {
+ .table {
+ table-layout: fixed;
+
+ thead th:first-child, thead th:nth-child(3) {
+ width: 20%;
+ }
+
+ thead th:nth-child(2) {
+ width: 15%;
+ }
+
+ tr td:nth-child(3) {
+ word-break: break-word;
+ }
+ }
+
+ .exception {
+ border-left: 4px solid #D42054;
+ padding: 0 10px 10px 10px;
+ box-shadow: rgba(0,0,0,0.07) 2px 2px 10px;
+
+ .exception-message {
+ white-space: pre-wrap;
+ }
+ }
+ }
+}
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 56b4e19122..455a147395 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
@@ -1,5 +1,4 @@
.umb-nested-content {
- text-align: center;
position: relative;
}
@@ -170,6 +169,7 @@
.umb-nested-content__add-content {
display: flex;
+ width: 100%;
align-items: center;
justify-content: center;
border: 1px dashed @ui-action-discreet-border;
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less
new file mode 100644
index 0000000000..3ce284870e
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-property-actions.less
@@ -0,0 +1,96 @@
+.umb-property-actions {
+ display: inline;
+}
+
+.umb-property-actions__toggle,
+.umb-property-actions__menu-open-toggle {
+ position: relative;
+ display: flex;
+ flex: 0 0 auto;
+ padding: 6px 6px;
+ text-align: center;
+ cursor: pointer;
+ border-radius: 3px;
+
+ background-color: @ui-action-hover;
+
+ i {
+ height: 3px !important;
+ width: 3px !important;
+ border-radius: 3px;
+ background: @ui-action-type;
+ display: inline-block;
+ margin: 0 2px 0 0;
+
+ &:last-child {
+ margin: 0;
+ }
+ }
+ &:hover {
+ i {
+ background: @ui-action-type-hover;
+ }
+ }
+}
+.umb-property-actions__menu-open-toggle {
+ position: absolute;
+ z-index:1;
+ outline: none;// this is not acceccible by keyboard, since we use the .umb-property-actions__toggle for that.
+
+ top: -15px;
+ border-radius: 3px 3px 0 0;
+
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+
+ border: 1px solid @dropdownBorder;
+
+ border-bottom: 1px solid @gray-9;
+
+ .box-shadow(0 5px 20px rgba(0,0,0,.3));
+
+ background-color: white;
+
+}
+
+.umb-property .umb-property-actions {
+ float: left;
+}
+.umb-property .umb-property-actions__toggle {
+ margin-top: 2px;
+ opacity: 0;
+ transition: opacity 120ms;
+}
+.umb-property:hover .umb-property-actions__toggle,
+.umb-property .umb-property-actions__toggle:focus {
+ opacity: 1;
+}
+// Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered.
+.umb-property:hover .umb-property:not(:hover) .umb-property-actions__toggle {
+ opacity: 0;
+}
+
+.umb-property-actions__menu {
+
+ position: absolute;
+ z-index: 1000;
+
+ display: block;
+
+ float: left;
+ min-width: 160px;
+ list-style: none;
+
+ .umb-contextmenu {
+
+ border-top-left-radius: 0;
+ margin-top:1px;
+
+ }
+
+ .umb-contextmenu-item > button {
+
+ z-index:2;// need to stay on top of menu-toggle-open shadow.
+
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less b/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less
index 0c219af1e4..7b842c40ad 100644
--- a/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less
+++ b/src/Umbraco.Web.UI.Client/src/less/dashboards/examine-management.less
@@ -12,4 +12,9 @@
border-bottom-left-radius: 0;
}
}
+
+ .umb-panel-group__details-status-action{
+ background-color:transparent;
+ padding-left:0;
+ }
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/dashboards/nucache.less b/src/Umbraco.Web.UI.Client/src/less/dashboards/nucache.less
new file mode 100644
index 0000000000..4ebe1d47b0
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/dashboards/nucache.less
@@ -0,0 +1,13 @@
+#nuCache {
+ .no-background {
+ background-color: transparent;
+ }
+
+ .top-border {
+ border-top: 2px solid #f3f3f5;
+ }
+
+ .no-left-padding {
+ padding-left: 0;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less b/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less
new file mode 100644
index 0000000000..82f9f3f553
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/filter-toggle.less
@@ -0,0 +1,20 @@
+.filter-toggle{
+ margin: 0;
+ padding: 0 8px 0 0;
+ position: relative;
+}
+
+.filter-toggle__level{
+ display: inline-block;
+ font-weight: 700;
+ margin: 0 5px;
+ max-width: 150px;
+}
+
+.filter-toggle__icon{
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ margin: auto 0;
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less
index 920fcdb1eb..86a1acbeae 100644
--- a/src/Umbraco.Web.UI.Client/src/less/main.less
+++ b/src/Umbraco.Web.UI.Client/src/less/main.less
@@ -116,24 +116,42 @@ h5.-black {
margin: 20px;
}
.umb-control-group {
- border-bottom: 1px solid @gray-11;
- padding-bottom: 20px;
+ position: relative;
+ &::after {
+ content: '';
+ display:block;
+ margin-top: 20px;
+ width: 100%;
+ height: 1px;
+ background-color: @gray-11;
+ }
}
.umb-control-group.-no-border {
- border: none;
+ &::after {
+ margin-top: 0px;
+ height: 0;
+ background-color: transparent;
+ }
}
.umb-property:last-of-type .umb-control-group {
- border: none;
- margin-bottom: 0 !important;
- padding-bottom: 0;
+ &::after {
+ margin-top: 0px;
+ height: 0;
+ background-color: transparent;
+ }
+ margin-bottom: 0 !important;
}
/* BLOCK MODE */
.block-form .umb-control-group {
- border-bottom: none;
- padding-bottom: 0;
+ margin-top: 0px;
+ &::after {
+ margin-top: 0px;
+ height: 0;
+ background-color: transparent;
+ }
}
.block-form .umb-control-group label .help-block,
@@ -163,7 +181,36 @@ h5.-black {
}
.umb-control-group .umb-el-wrap {
- padding: 0
+ padding: 0;
+}
+.form-horizontal .umb-control-group .control-header {
+ float: left;
+ width: 160px;
+ padding-top: 5px;
+ text-align: left;
+
+ .control-label {
+ float: left;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+
+ .control-description {
+ display: block;
+ clear: both;
+ max-width:480px;// avoiding description becoming too wide when its placed on top of property.
+ margin-bottom: 10px;
+ }
+}
+@media (max-width: 767px) {
+
+ .form-horizontal .umb-control-group .control-header {
+ float: none;
+ width: 100%;
+ }
+
+
}
/* LABELS*/
diff --git a/src/Umbraco.Web.UI.Client/src/less/modals.less b/src/Umbraco.Web.UI.Client/src/less/modals.less
index 84de751b12..fa23e08983 100644
--- a/src/Umbraco.Web.UI.Client/src/less/modals.less
+++ b/src/Umbraco.Web.UI.Client/src/less/modals.less
@@ -99,7 +99,7 @@
top: 0px;
left: 0px;
right: 0px;
- bottom: 52px;
+ bottom: 49px;
}
.umb-dialog-body .umb-pane{margin-top: 15px;}
@@ -111,7 +111,7 @@
left: 0px;
right: 0px;
bottom: 0px;
- padding: 20px;
+ padding: 8px;
margin: 0;
.btn.umb-outline {
diff --git a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less
index 6c38aa4a31..787e50f204 100644
--- a/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less
+++ b/src/Umbraco.Web.UI.Client/src/less/utilities/_spacing.less
@@ -67,4 +67,18 @@
.ml6 { margin-left: @spacing-extra-extra-large; }
.ml7 { margin-left: @spacing-extra-extra-extra-large; }
+.mr0 { margin-right: @spacing-none; }
+.mr1 { margin-right: @spacing-extra-small; }
+.mr2 { margin-right: @spacing-small; }
+.mr3 { margin-right: @spacing-medium; }
+.mr4 { margin-right: @spacing-large; }
+.mr5 { margin-right: @spacing-extra-large; }
+.mr6 { margin-right: @spacing-extra-extra-large; }
+.mr7 { margin-right: @spacing-extra-extra-extra-large; }
+
.p0 { padding: @spacing-none; }
+
+.pt0 { padding-top: @spacing-none; }
+.pb0 { padding-bottom: @spacing-none; }
+.pl0 { padding-left: @spacing-none; }
+.pr0 { padding-right: @spacing-none; }
diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less
index 166640829b..e8f6d4ee58 100644
--- a/src/Umbraco.Web.UI.Client/src/less/variables.less
+++ b/src/Umbraco.Web.UI.Client/src/less/variables.less
@@ -132,6 +132,7 @@
@ui-option-type: @blueExtraDark;
@ui-option-type-hover: @blueMid;
+@ui-option: white;
@ui-option-hover: @sand-7;
@ui-option-disabled-type: @gray-6;
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html
index 071d093ab4..4096192081 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/compositions/compositions.html
@@ -60,7 +60,7 @@
- {{model.result.queryExpression}}
+ {{model.result.queryExpression}}
+
+