all
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
index 50a32e0b05..ae9f0121ca 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js
@@ -602,8 +602,6 @@
$scope.page.buttonGroupState = 'error';
handleHttpException(err);
});
-
-
},
close: function () {
overlayService.close();
@@ -641,13 +639,14 @@
overlayService.close();
return $q.when(data);
},
- function (err) {
- clearDirtyState($scope.content.variants);
- model.submitButtonState = "error";
- //re-map the dialog model since we've re-bound the properties
- dialog.variants = $scope.content.variants;
- handleHttpException(err);
- });
+ function (err) {
+ clearDirtyState($scope.content.variants);
+ model.submitButtonState = "error";
+ //re-map the dialog model since we've re-bound the properties
+ dialog.variants = $scope.content.variants;
+
+ handleHttpException(err);
+ });
},
close: function () {
overlayService.close();
@@ -699,14 +698,18 @@
clearNotifications($scope.content);
overlayService.close();
return $q.when(data);
- },
- function (err) {
- clearDirtyState($scope.content.variants);
- model.submitButtonState = "error";
- //re-map the dialog model since we've re-bound the properties
- dialog.variants = $scope.content.variants;
- handleHttpException(err);
- });
+ }, function (err) {
+ clearDirtyState($scope.content.variants);
+ model.submitButtonState = "error";
+ //re-map the dialog model since we've re-bound the properties
+ dialog.variants = $scope.content.variants;
+
+ //ensure error messages are displayed
+ formHelper.showNotifications(err.data);
+ clearNotifications($scope.content);
+
+ handleHttpException(err);
+ });
},
close: function () {
overlayService.close();
@@ -760,20 +763,24 @@
clearNotifications($scope.content);
overlayService.close();
return $q.when(data);
- },
- function (err) {
- clearDirtyState($scope.content.variants);
- //model.submitButtonState = "error";
- // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely.
- if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) {
- model.submitButtonState = "success";
- } else {
- model.submitButtonState = "error";
- }
+ }, function (err) {
+ clearDirtyState($scope.content.variants);
+ //model.submitButtonState = "error";
+ // Because this is the "save"-action, then we actually save though there was a validation error, therefor we will show success and display the validation errors politely.
+ if(err && err.data && err.data.ModelState && Object.keys(err.data.ModelState).length > 0) {
+ model.submitButtonState = "success";
+ } else {
+ model.submitButtonState = "error";
//re-map the dialog model since we've re-bound the properties
dialog.variants = $scope.content.variants;
+
+ //ensure error messages are displayed
+ formHelper.showNotifications(err.data);
+ clearNotifications($scope.content);
+
handleHttpException(err);
- });
+ }
+ })
},
close: function (oldModel) {
overlayService.close();
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js
index 1b63dde26c..75df00c596 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditorheader.directive.js
@@ -192,6 +192,7 @@ Use this directive to construct a header inside the main editor window.
@param {array=} tabs Array of tabs. See example above.
@param {array=} navigation Array of sub views. See example above.
@param {boolean=} nameLocked Set to true to lock the name.
+@param {number=} nameMaxLength Maximum length of the name.
@param {object=} menu Add a context menu to the editor.
@param {string=} icon Show and edit the content icon. Opens an overlay to change the icon.
@param {boolean=} hideIcon Set to true to hide icon.
@@ -210,11 +211,11 @@ Use this directive to construct a header inside the main editor window.
function EditorHeaderDirective(editorService, localizationService, editorState, $rootScope) {
- function link(scope, $injector) {
+ function link(scope) {
scope.vm = {};
scope.vm.dropdownOpen = false;
- scope.vm.currentVariant = "";
+ scope.vm.currentVariant = "";
scope.loading = true;
scope.accessibility = {};
scope.accessibility.a11yMessage = "";
@@ -222,6 +223,12 @@ Use this directive to construct a header inside the main editor window.
scope.accessibility.a11yMessageVisible = false;
scope.accessibility.a11yNameVisible = false;
+ // trim the name if required
+ scope.nameMaxLength = scope.nameMaxLength || 255;
+ if (scope.name && scope.name.length > scope.nameMaxLength) {
+ scope.name = scope.name.substring(0, scope.nameMaxLength - 1) + '…';
+ }
+
// 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
@@ -376,6 +383,7 @@ Use this directive to construct a header inside the main editor window.
name: "=",
nameLocked: "=",
nameRequired: "=?",
+ nameMaxLength: "=?",
menu: "=",
hideActionsMenu: "",
icon: "=",
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
index 9bd1909960..f3a0451191 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbfocuslock.directive.js
@@ -33,7 +33,7 @@
$rootScope.lastKnownFocusableElements.push(document.activeElement);
// List of elements that can be focusable within the focus lock
- var focusableElementsSelector = '[role="button"], a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide), select:not([disabled]):not(.ng-hide)';
+ var focusableElementsSelector = '[role="button"], a[href]:not([disabled]):not(.ng-hide), button:not([disabled]):not(.ng-hide), textarea:not([disabled]):not(.ng-hide), input:not([disabled]):not(.ng-hide):not([type="hidden"]), select:not([disabled]):not(.ng-hide)';
function getDomNodes(){
infiniteEditorsWrapper = document.querySelector('.umb-editors');
@@ -123,7 +123,15 @@
lastKnownElement.focus();
}
else if(defaultFocusedElement === null ){
- firstFocusableElement.focus();
+ // If the first focusable elements are either items from the umb-sub-views-nav menu or the umb-button-ellipsis we most likely want to start the focus on the second item
+ var avoidStartElm = focusableElements.findIndex(elm => elm.classList.contains('umb-button-ellipsis') || elm.classList.contains('umb-sub-views-nav-item__action') || elm.classList.contains('umb-tab-button'));
+
+ if(avoidStartElm === 0) {
+ focusableElements[1].focus();
+ }
+ else {
+ firstFocusableElement.focus();
+ }
}
else {
defaultFocusedElement.focus();
@@ -175,34 +183,27 @@
}
function onInit(targetElm) {
-
$timeout(() => {
+ // Fetch the DOM nodes we need
+ getDomNodes();
- // Fetch the DOM nodes we need
- getDomNodes();
+ cleanupEventHandlers();
- cleanupEventHandlers();
+ getFocusableElements(targetElm);
- getFocusableElements(targetElm);
+ if(focusableElements.length > 0) {
- if(focusableElements.length > 0) {
+ observeDomChanges();
- observeDomChanges();
+ setElementFocus();
- setElementFocus();
-
- // Handle keydown
- target.addEventListener('keydown', handleKeydown);
- }
-
- });
+ // Handle keydown
+ target.addEventListener('keydown', handleKeydown);
+ }
+ }, 500);
}
- scope.$on('$includeContentLoaded', () => {
- angularHelper.safeApply(scope, () => {
- onInit();
- });
- });
+ onInit();
// If more than one editor is still open then re-initialize otherwise remove the event listener
scope.$on('$destroy', function () {
@@ -243,6 +244,3 @@
angular.module('umbraco.directives').directive('umbFocusLock', FocusLock);
})();
-
-
-// TODO: Ensure the domObserver is NOT started when there is only one infinite overlay and it's being destroyed!
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/localization/localize.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/localization/localize.directive.js
index 2262da4c16..6fea8d8c84 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/localization/localize.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/localization/localize.directive.js
@@ -1,85 +1,101 @@
angular.module('umbraco.directives')
- /**
- * @ngdoc directive
- * @name umbraco.directives.directive:localize
- * @restrict EA
- * @function
- * @description
- *
- * Component
- * Localize a specific token to put into the HTML as an item.
- *
- *
- * Attribute
- * Add an HTML attribute to an element containing the HTML attribute name you wish to localize,
- * using the format of '@section_key' or 'section_key'.
- *
- * ##Usage
- *
- *
- * Close
- * Fallback value
- *
- *
- *
- *
- *
- *
- **/
- .directive('localize', function ($log, localizationService) {
- return {
- restrict: 'E',
- scope: {
- key: '@',
- tokens: '=',
- watchTokens: '@'
- },
- replace: true,
- link: function (scope, element, attrs) {
- var key = scope.key;
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:localize
+* @restrict EA
+* @function
+* @description
+*
+* Used to localize text in HTMl-elements or attributes using translation keys. Translations are stored in umbraco/config/lang/ or the /lang-folder of a package i App_Plugins.
+*
+*
+* Component/Element
+ * Localize a specific token to put into the HTML as an item
+*
+*
+* Attribute
+ * Add a HTML attribute to an element containing the HTML attribute name you wish to localise
+ * Using the format of '@section_key' or 'section_key'
+*
+* ##Basic Usage
+*
+*
+* Close
+* Fallback value
+*
+*
+*
+*
+*
+*
+* ##Use with tokens
+* Also supports tokens inside the translation key, example of a translation
+*
+* You have %0% characters left of %1%
+*
+* Can be used like this:
+*
+* You have %0% characters left of %1%
+*
+*
+* Where the "tokens"-attribute is an array of tokens for the translations, "watch-tokens" will make the component watch the expression passed.
+**/
+.directive('localize', function ($log, localizationService) {
+ return {
+ restrict: 'E',
+ scope: {
+ key: '@',
+ tokens: '=',
+ watchTokens: '@'
+ },
+ replace: true,
+ link: function (scope, element, attrs) {
+ var key = scope.key;
scope.text = '';
- // A render function to be able to update tokens as values update
- function render() {
- element.html(localizationService.tokenReplace(scope.text, scope.tokens || null));
- }
-
- localizationService.localize(key).then(function (value) {
- scope.text = value;
- render();
- });
-
- if (scope.watchTokens === 'true') {
- scope.$watch("tokens", render, true);
- }
+ // A render function to be able to update tokens as values update.
+ function render() {
+ element.html(localizationService.tokenReplace(scope.text, scope.tokens || null));
}
- };
- })
- .directive('localize', function ($log, localizationService) {
- return {
- restrict: 'A',
- link: function (scope, element, attrs) {
- // Support one or more attribute properties to update
- var keys = attrs.localize.split(',');
- Utilities.forEach(keys, (value, key) => {
- var attr = element.attr(value);
- if (attr) {
+ // As per component definition in ngdoc above, the initial inner html of the element is to be used as fallback value
+ var fallbackValue = element.html();
+ localizationService.localize(key, null, fallbackValue).then(function (value) {
+ scope.text = value;
+ render();
+ });
+
+ if (scope.watchTokens === 'true') {
+ scope.$watch("tokens", render, true);
+ }
+ }
+ };
+})
+.directive('localize', function ($log, localizationService) {
+ return {
+ restrict: 'A',
+ link: function (scope, element, attrs) {
+ //Support one or more attribute properties to update
+ var keys = attrs.localize.split(',');
+
+ Utilities.forEach(keys, (value, key) => {
+ var attr = element.attr(value);
+ if (attr) {
// Localizing is done async, so make sure the key isn't visible
element.removeAttr(value);
-
- if (attr[0] === '@') {
- // If the translation key starts with @ then remove it
- attr = attr.substring(1);
- }
- var t = localizationService.tokenize(attr, scope);
-
- localizationService.localize(t.key, t.tokens).then(function (val) {
- element.attr(value, val);
- });
+ if (attr[0] === '@') {
+ //If the translation key starts with @ then remove it
+ attr = attr.substring(1);
}
- });
- }
- };
- });
+
+ var t = localizationService.tokenize(attr, scope);
+
+ localizationService.localize(t.key, t.tokens).then(function (val) {
+ element.attr(value, val);
+ });
+ }
+ });
+ }
+ };
+});
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 f4cfacbf70..25e55455db 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
@@ -75,7 +75,21 @@
// inheritance is (i.e.infinite editing)
var found = angularHelper.traverseScopeChain($scope, s => s && s.vm && s.vm.constructor.name === "UmbPropertyController");
vm.parentUmbProperty = found ? found.vm : null;
+ }
+
+ if (vm.property.description) {
+ // split by lines containing only '--'
+ var descriptionParts = vm.property.description.split(/^--$/gim);
+ if (descriptionParts.length > 1) {
+ // if more than one part, we have an extended description,
+ // combine to one extended description, and remove leading linebreak
+ vm.property.extendedDescription = descriptionParts.splice(1).join("--").substring(1);
+ vm.property.extendedDescriptionVisible = false;
+
+ // set propertydescription to first part, and remove trailing linebreak
+ vm.property.description = descriptionParts[0].slice(0, -1);
}
+ }
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
index 44d45263da..79da9e3ac6 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
@@ -582,7 +582,7 @@
};
scope.canRemoveTab = (tab) => {
- return tab.inherited !== true;
+ return scope.canRemoveGroup(tab) && _.every(scope.model.groups.filter(group => group.parentAlias === tab.alias), group => scope.canRemoveGroup(group));
};
scope.setTabOverflowState = (overflowLeft, overflowRight) => {
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js
index 51fc6284b8..98f02b7e06 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/upload/umbfiledropzone.directive.js
@@ -31,7 +31,7 @@ angular.module("umbraco.directives")
propertyAlias: '@',
accept: '@',
maxFileSize: '@',
-
+
compact: '@',
hideDropzone: '@',
acceptedMediatypes: '=',
@@ -42,9 +42,10 @@ angular.module("umbraco.directives")
},
link: function(scope, element, attrs) {
scope.queue = [];
- scope.done = [];
- scope.rejected = [];
+ scope.totalQueued = 0;
scope.currentFile = undefined;
+ scope.processed = [];
+ scope.totalMessages = 0;
function _filterFile(file) {
var ignoreFileNames = ['Thumbs.db'];
@@ -65,51 +66,50 @@ angular.module("umbraco.directives")
function _filesQueued(files, event) {
//Push into the queue
Utilities.forEach(files, file => {
- if (_filterFile(file) === true) {
-
- if (file.$error) {
- scope.rejected.push(file);
- } else {
- scope.queue.push(file);
- }
+ if (_filterFile(file) === true) {
+ file.messages = [];
+ scope.queue.push(file);
}
});
- //when queue is done, kick the uploader
- if (!scope.working) {
- // Upload not allowed
- if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) {
- files.map(file => {
- file.uploadStatus = "error";
- file.serverErrorMessage = "File type is not allowed here";
- scope.rejected.push(file);
- });
- scope.queue = [];
- }
- // If we have Accepted Media Types, we will ask to choose Media Type, if Choose Media Type returns false, it only had one choice and therefor no reason to
- if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) {
- scope.contentTypeAlias = "umbracoAutoSelect";
-
- _processQueueItem();
- }
+ // Upload not allowed
+ if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) {
+ files.map(file => {
+ file.messages.push({message: "File type is not allowed here", type: "Error"});
+ });
}
+
+ // If we have Accepted Media Types, we will ask to choose Media Type, if Choose Media Type returns false, it only had one choice and therefor no reason to
+ if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) {
+ scope.contentTypeAlias = "umbracoAutoSelect";
+ }
+
+ // Add the processed length, as we might be uploading in stages
+ scope.totalQueued = scope.queue.length + scope.processed.length;
+
+ _processQueueItems();
}
- function _processQueueItem() {
- if (scope.queue.length > 0) {
+ function _processQueueItems() {
+ // if we have processed all files, either by successful
+ // upload, or attending to all messages, we deem the
+ // action complete, else continue processing files
+ scope.totalMessages = scope.processed.filter(e => e.messages.length > 0).length;
+ if (scope.totalQueued === scope.processed.length) {
+ if (scope.totalMessages === 0) {
+ if (scope.filesUploaded) {
+ //queue is empty, trigger the done action
+ scope.filesUploaded(scope.done);
+ }
+ //auto-clear the done queue after 3 secs
+ var currentLength = scope.processed.length;
+ $timeout(function() {
+ scope.processed.splice(0, currentLength);
+ }, 3000);
+ }
+ } else {
scope.currentFile = scope.queue.shift();
_upload(scope.currentFile);
- } else if (scope.done.length > 0) {
- if (scope.filesUploaded) {
- //queue is empty, trigger the done action
- scope.filesUploaded(scope.done);
- }
-
- //auto-clear the done queue after 3 secs
- var currentLength = scope.done.length;
- $timeout(function() {
- scope.done.splice(0, currentLength);
- }, 3000);
}
}
@@ -134,55 +134,36 @@ angular.module("umbraco.directives")
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
// set percentage property on file
file.uploadProgress = progressPercentage;
- // set uploading status on file
- file.uploadStatus = "uploading";
}
})
- .success(function(data, status, headers, config) {
- if (data.notifications && data.notifications.length > 0) {
- // set error status on file
- file.uploadStatus = "error";
- // Throw message back to user with the cause of the error
- file.serverErrorMessage = data.notifications[0].message;
- // Put the file in the rejected pool
- scope.rejected.push(file);
- } else {
- // set done status on file
- file.uploadStatus = "done";
- file.uploadProgress = 100;
- // set date/time for when done - used for sorting
- file.doneDate = new Date();
- // Put the file in the done pool
- scope.done.push(file);
- }
+ .success(function (data, status, headers, config) {
+ // Set server messages
+ file.messages = data.notifications;
+ scope.processed.push(file);
+ //after processing, test if everything is done
scope.currentFile = undefined;
- //after processing, test if everthing is done
- _processQueueItem();
+ _processQueueItems();
})
.error(function(evt, status, headers, config) {
- // set status done
- file.uploadStatus = "error";
//if the service returns a detailed error
if (evt.InnerException) {
- file.serverErrorMessage = evt.InnerException.ExceptionMessage;
+ file.messages.push({ message: evt.InnerException.ExceptionMessage, type: "Error" });
//Check if its the common "too large file" exception
if (evt.InnerException.StackTrace &&
evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
- file.serverErrorMessage = "File too large to upload";
+ file.messages.push({ message: "File too large to upload", type: "Error" });
}
} else if (evt.Message) {
- file.serverErrorMessage = evt.Message;
- } else if (evt && typeof evt === 'string') {
- file.serverErrorMessage = evt;
+ file.messages.push({message: evt.Message, type: "Error"});
+ } else if (evt && typeof evt === "string") {
+ file.messages.push({message: evt, type: "Error"});
}
// If file not found, server will return a 404 and display this message
if (status === 404) {
- file.serverErrorMessage = "File not found";
+ file.messages.push({message: "File not found", type: "Error"});
}
- //after processing, test if everthing is done
- scope.rejected.push(file);
scope.currentFile = undefined;
- _processQueueItem();
+ _processQueueItems();
});
}
@@ -224,16 +205,14 @@ angular.module("umbraco.directives")
availableItems: filteredMediaTypes,
submit: function (model) {
scope.contentTypeAlias = model.selectedItem.alias;
- _processQueueItem();
+ _processQueueItems();
overlayService.close();
},
close: function () {
scope.queue.map(function (file) {
- file.uploadStatus = "error";
- file.serverErrorMessage = "No files uploaded, no mediatype selected";
- scope.rejected.push(file);
+ file.messages.push({message:"No files uploaded, no mediatype selected", type: "Error"});
});
scope.queue = [];
@@ -245,14 +224,26 @@ angular.module("umbraco.directives")
overlayService.open(dialog);
});
- return true;// yes, we did open the choose-media dialog, therefor we return true.
+ return true; // yes, we did open the choose-media dialog, therefore we return true.
+ }
+
+ scope.dismissMessages = function (file) {
+ file.messages = [];
+ _processQueueItems();
+ }
+
+ scope.dismissAllMessages = function () {
+ Utilities.forEach(scope.processed, file => {
+ file.messages = [];
+ });
+ _processQueueItems();
}
scope.handleFiles = function(files, event, invalidFiles) {
const allFiles = [...files, ...invalidFiles];
// add unique key for each files to use in ng-repeats
- allFiles.forEach(file => {
+ Utilities.forEach(allFiles, file => {
file.key = String.CreateGuid();
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/getDomElement.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/getDomElement.directive.js
index 2a0c9c3aec..28a32665d7 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/util/getDomElement.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/getDomElement.directive.js
@@ -1,17 +1,17 @@
angular.module("umbraco.directives").directive("retriveDomElement", function () {
- var directiveDefinitionObject = {
+ var directiveDefinitionObject = {
- restrict: "A",
- selector: '[retriveDomElement]',
- scope: {
- "retriveDomElement": "&"
- },
- link: {
- post: function(scope, iElement, iAttrs, controller) {
- scope.retriveDomElement({element:iElement, attributes: iAttrs});
+ restrict: "A",
+ selector: '[retriveDomElement]',
+ scope: {
+ "retriveDomElement": "&"
+ },
+ link: {
+ post: function (scope, iElement, iAttrs, controller) {
+ scope.retriveDomElement({ element: iElement, attributes: iAttrs });
+ }
}
- }
- };
+ };
- return directiveDefinitionObject;
+ return directiveDefinitionObject;
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/util/retrieveDomElement.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/util/retrieveDomElement.directive.js
new file mode 100644
index 0000000000..74b2639340
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/util/retrieveDomElement.directive.js
@@ -0,0 +1,17 @@
+angular.module("umbraco.directives").directive("retrieveDomElement", function () {
+ var directiveDefinitionObject = {
+
+ restrict: "A",
+ selector: '[retrieveDomElement]',
+ scope: {
+ "retrieveDomElement": "&"
+ },
+ link: {
+ post: function(scope, iElement, iAttrs, controller) {
+ scope.retrieveDomElement({element:iElement, attributes: iAttrs});
+ }
+ }
+ };
+
+ return directiveDefinitionObject;
+});
diff --git a/src/Umbraco.Web.UI.Client/src/common/filters/simpleMarkdown.filter.js.js b/src/Umbraco.Web.UI.Client/src/common/filters/simpleMarkdown.filter.js.js
new file mode 100644
index 0000000000..d33b96916a
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/filters/simpleMarkdown.filter.js.js
@@ -0,0 +1,20 @@
+/**
+* @ngdoc filter
+* @name umbraco.filters.simpleMarkdown
+* @description
+* Used when rendering a string as Markdown as HTML (i.e. with ng-bind-html). Allows use of **bold**, *italics*,  and [links](url)
+**/
+angular.module("umbraco.filters").filter('simpleMarkdown', function () {
+ return function (text) {
+ if (!text) {
+ return '';
+ }
+
+ return text
+ .replace(/\*\*(.*)\*\*/gim, '$1')
+ .replace(/\*(.*)\*/gim, '$1')
+ .replace(/!\[(.*?)\]\((.*?)\)/gim, "
")
+ .replace(/\[(.*?)\]\((.*?)\)/gim, "$1")
+ .replace(/\n/g, '
').trim();
+ };
+});
diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js
index 05594115e1..08c28fcbd1 100644
--- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js
+++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/entity.mocks.js
@@ -34,7 +34,7 @@ angular.module('umbraco.mocks').
return [200, nodes, null];
}
- function returnUrlsbyUdis(status, data, headers) {
+ function returnUrlsByIds(status, data, headers) {
if (!mocksUtils.checkAuth()) {
return [401, null, null];
@@ -83,8 +83,8 @@ angular.module('umbraco.mocks').
.respond(returnEntitybyIdsPost);
$httpBackend
- .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetUrlsByUdis'))
- .respond(returnUrlsbyUdis);
+ .whenPOST(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetUrlsByIds'))
+ .respond(returnUrlsByIds);
$httpBackend
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetAncestors'))
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js
index 78fefc8db5..e09718176c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js
@@ -37,7 +37,7 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
umbRequestHelper.getApiUrl(
"authenticationApiBaseUrl",
"Get2FAProviders")),
- 'Could not retrive two factor provider info');
+ 'Could not retrieve two factor provider info');
},
/**
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js
index 6398cc55e7..ada64bd3f6 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/contenttype.resource.js
@@ -129,7 +129,7 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
* });
*
*
- * @param {Int} contentTypeId id of the content item to retrive allowed child types for
+ * @param {Int} contentTypeId id of the content item to retrieve allowed child types for
* @returns {Promise} resourcePromise object.
*
*/
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 60a5d235fe..f90f86364b 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
@@ -23,7 +23,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
* });
*
*
- * @param {String} editorAlias string alias of editor type to retrive prevalues configuration for
+ * @param {String} editorAlias string alias of editor type to retrieve prevalues configuration for
* @param {Int} id id of datatype to retrieve prevalues for
* @returns {Promise} resourcePromise object.
*
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
index c6dc313bc7..d94bb4e6be 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
@@ -127,6 +127,24 @@ function entityResource($q, $http, umbRequestHelper) {
'Failed to retrieve url for id:' + id);
},
+ getUrlsByIds: function(ids, type, culture) {
+ var query = `type=${type}&culture=${culture || ""}`;
+
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl(
+ "entityApiBaseUrl",
+ "GetUrlsByIds",
+ query),
+ {
+ ids: ids
+ }),
+ 'Failed to retrieve url map for ids ' + ids);
+ },
+
+ /**
+ * @deprecated use getUrlsByIds instead.
+ */
getUrlsByUdis: function(udis, culture) {
var query = "culture=" + (culture || "");
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js
index 9ae5c378ce..4e98b1d8cc 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/log.resource.js
@@ -1,7 +1,7 @@
/**
* @ngdoc service
* @name umbraco.resources.logResource
- * @description Retrives log history from umbraco
+ * @description Retrieves log history from umbraco
*
*
**/
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
index 46ef8d2919..b71c272d35 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/logviewer.resource.js
@@ -1,7 +1,7 @@
/**
* @ngdoc service
* @name umbraco.resources.logViewerResource
- * @description Retrives Umbraco log items (by default from JSON files on disk)
+ * @description Retrieves Umbraco log items (by default from JSON files on disk)
*
*
**/
@@ -25,7 +25,10 @@ function logViewerResource($q, $http, umbRequestHelper) {
getNumberOfErrors: (startDate, endDate) =>
request('GET', 'GetNumberOfErrors', '?startDate=' + startDate + '&endDate=' + endDate, 'Failed to retrieve number of errors in logs'),
-
+
+ getLogLevels: () =>
+ request('GET', 'GetLogLevels', null, 'Failed to retrieve log levels'),
+
getLogLevel: () =>
request('GET', 'GetLogLevel', null, 'Failed to retrieve log level'),
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js
index e3fab86067..62fe2b7367 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/mediatype.resource.js
@@ -85,7 +85,7 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter, locali
* $scope.type = type;
* });
*
- * @param {Int} mediaId id of the media item to retrive allowed child types for
+ * @param {Int} mediaId id of the media item to retrieve allowed child types for
* @returns {Promise} resourcePromise object.
*
*/
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
index fb145418ed..c91903eb0f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/redirecturls.resource.js
@@ -27,7 +27,7 @@
* });
*
* @param {String} searchTerm Searh term
- * @param {Int} pageIndex index of the page to retrive items from
+ * @param {Int} pageIndex index of the page to retrieve items from
* @param {Int} pageSize The number of items on a page
*/
function searchRedirectUrls(searchTerm, pageIndex, pageSize) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
index 4f5f47fb81..22baed8472 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
@@ -442,7 +442,7 @@
* @ngdoc method
* @name getAvailableAliasesForBlockContent
* @methodOf umbraco.services.blockEditorModelObject
- * @description Retrive a list of aliases that are available for content of blocks in this property editor, does not contain aliases of block settings.
+ * @description Retrieve a list of aliases that are available for content of blocks in this property editor, does not contain aliases of block settings.
* @return {Array} array of strings representing alias.
*/
getAvailableAliasesForBlockContent: function () {
@@ -460,7 +460,7 @@
* @ngdoc method
* @name getAvailableBlocksForBlockPicker
* @methodOf umbraco.services.blockEditorModelObject
- * @description Retrive a list of available blocks, the list containing object with the confirugation model(blockConfigModel) and the element type model(elementTypeModel).
+ * @description Retrieve a list of available blocks, the list containing object with the confirugation model(blockConfigModel) and the element type model(elementTypeModel).
* The purpose of this data is to provide it for the Block Picker.
* @return {Array} array of objects representing available blocks, each object containing properties blockConfigModel and elementTypeModel.
*/
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 901e5fa93c..abf173b129 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
@@ -6,8 +6,8 @@
* @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.
+ * Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrieve.
+ * The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrieve the posible entries for a paste scenario.
*
*/
function clipboardService($window, notificationsService, eventsService, localStorageService, iconHelper) {
@@ -77,7 +77,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
var STORAGE_KEY = "umbClipboardService";
- var retriveStorage = function() {
+ var retrieveStorage = function() {
if (localStorageService.isSupported === false) {
return null;
}
@@ -103,7 +103,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
try {
// Check that we can parse the JSON:
- var storageJSON = JSON.parse(storageString);
+ var _ = JSON.parse(storageString);
// Store the string:
localStorageService.set(STORAGE_KEY, storageString);
@@ -114,11 +114,8 @@ function clipboardService($window, notificationsService, eventsService, localSto
} catch(e) {
return false;
}
-
- return false;
}
-
function resolvePropertyForStorage(prop, type) {
type = type || "raw";
@@ -159,9 +156,6 @@ function clipboardService($window, notificationsService, eventsService, localSto
);
}
-
-
-
function resolvePropertyForPaste(prop, type) {
type = type || "raw";
@@ -173,8 +167,6 @@ function clipboardService($window, notificationsService, eventsService, localSto
}
}
-
-
var service = {};
/**
@@ -300,7 +292,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
*/
service.copy = function(type, alias, data, displayLabel, displayIcon, uniqueKey, firstLevelClearupMethod) {
- var storage = retriveStorage();
+ var storage = retrieveStorage();
displayLabel = displayLabel || data.name;
displayIcon = displayIcon || iconHelper.convertFromLegacyIcon(data.icon);
@@ -347,7 +339,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
type = "elementType";
}
- var storage = retriveStorage();
+ var storage = retrieveStorage();
// Clean up each entry
var copiedDatas = datas.map(data => prepareEntryForStorage(type, data, firstLevelClearupMethod));
@@ -383,6 +375,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
return localStorageService.isSupported;
};
+
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#hasEntriesOfType
@@ -396,16 +389,17 @@ function clipboardService($window, notificationsService, eventsService, localSto
*/
service.hasEntriesOfType = function(type, aliases) {
- if(service.retriveEntriesOfType(type, aliases).length > 0) {
+ if(service.retrieveEntriesOfType(type, aliases).length > 0) {
return true;
}
return false;
};
+
/**
* @ngdoc method
- * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @name umbraco.services.supportsCopy#retrieveEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to recive.
@@ -414,9 +408,9 @@ function clipboardService($window, notificationsService, eventsService, localSto
* @description
* Returns an array of entries matching the given type and one of the provided aliases.
*/
- service.retriveEntriesOfType = function(type, allowedAliases) {
+ service.retrieveEntriesOfType = function(type, allowedAliases) {
- var storage = retriveStorage();
+ var storage = retrieveStorage();
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
var filteretEntries = storage.entries.filter(
@@ -428,9 +422,19 @@ function clipboardService($window, notificationsService, eventsService, localSto
return filteretEntries;
};
+
+ /**
+ * @obsolete Use the typo-free version instead.
+ */
+ service.retriveEntriesOfType = (type, allowedAliases) => {
+ console.warn('clipboardService.retriveEntriesOfType is obsolete, use clipboardService.retrieveEntriesOfType instead');
+ return service.retrieveEntriesOfType(type, allowedAliases);
+ }
+
+
/**
* @ngdoc method
- * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @name umbraco.services.supportsCopy#retrieveDataOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to recive.
@@ -439,13 +443,23 @@ function clipboardService($window, notificationsService, eventsService, localSto
* @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);
+ service.retrieveDataOfType = function(type, aliases) {
+ return service.retrieveEntriesOfType(type, aliases).map((x) => x.data);
};
+
+ /**
+ * @obsolete Use the typo-free version instead.
+ */
+ service.retriveDataOfType = (type, aliases) => {
+ console.warn('clipboardService.retriveDataOfType is obsolete, use clipboardService.retrieveDataOfType instead');
+ return service.retrieveDataOfType(type, aliases);
+ }
+
+
/**
* @ngdoc method
- * @name umbraco.services.supportsCopy#retriveEntriesOfType
+ * @name umbraco.services.supportsCopy#clearEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to remove.
@@ -456,7 +470,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
*/
service.clearEntriesOfType = function(type, allowedAliases) {
- var storage = retriveStorage();
+ var storage = retrieveStorage();
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
var filteretEntries = storage.entries.filter(
@@ -470,7 +484,6 @@ function clipboardService($window, notificationsService, eventsService, localSto
saveStorage(storage);
};
-
var emitClipboardStorageUpdate = _.debounce(function(e) {
eventsService.emit("clipboardService.storageUpdate");
}, 1000);
@@ -478,10 +491,7 @@ function clipboardService($window, notificationsService, eventsService, localSto
// Fires if LocalStorage was changed from another tab than this one.
$window.addEventListener("storage", emitClipboardStorageUpdate);
-
-
return service;
}
-
angular.module("umbraco.services").factory("clipboardService", clipboardService);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
index 0d8d5c782a..f4c6063a9a 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js
@@ -624,24 +624,29 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
var origProp = allOrigProps[k];
var alias = origProp.alias;
var newProp = getNewProp(alias, allNewProps);
- if (newProp && !_.isEqual(origProp.value, newProp.value)) {
+ if (newProp) {
+ // Always update readonly state
+ origProp.readonly = newProp.readonly;
- //they have changed so set the origContent prop to the new one
- var origVal = origProp.value;
+ // Check whether the value has changed and update accordingly
+ if (!_.isEqual(origProp.value, newProp.value)) {
- origProp.value = newProp.value;
+ //they have changed so set the origContent prop to the new one
+ var origVal = origProp.value;
- //instead of having a property editor $watch their expression to check if it has
- // been updated, instead we'll check for the existence of a special method on their model
- // and just call it.
- if (Utilities.isFunction(origProp.onValueChanged)) {
- //send the newVal + oldVal
- origProp.onValueChanged(origProp.value, origVal);
+ origProp.value = newProp.value;
+
+ //instead of having a property editor $watch their expression to check if it has
+ // been updated, instead we'll check for the existence of a special method on their model
+ // and just call it.
+ if (Utilities.isFunction(origProp.onValueChanged)) {
+ //send the newVal + oldVal
+ origProp.onValueChanged(origProp.value, origVal);
+ }
+
+ changed.push(origProp);
}
-
- changed.push(origProp);
}
-
}
}
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
index 9970995a28..ba9ebc1b00 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/tree.service.js
@@ -390,7 +390,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
*
* @description
* Gets a child node with a given ID, from a specific treeNode
- * @param {object} treeNode to retrive child node from
+ * @param {object} treeNode to retrieve child node from
* @param {int} id id of child node
*/
getChildNode: function (treeNode, id) {
@@ -411,7 +411,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
*
* @description
* Gets a descendant node by id
- * @param {object} treeNode to retrive descendant node from
+ * @param {object} treeNode to retrieve descendant node from
* @param {int} id id of descendant node
* @param {string} treeAlias - optional tree alias, if fetching descendant node from a child of a listview document
*/
@@ -494,7 +494,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
*
* @description
* Gets the root node of the current tree type for a given tree node
- * @param {object} treeNode to retrive tree root node from
+ * @param {object} treeNode to retrieve tree root node from
*/
getTreeRoot: function (treeNode) {
if (!treeNode) {
@@ -531,7 +531,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
*
* @description
* Gets the node's tree alias, this is done by looking up the meta-data of the current node's root node
- * @param {object} treeNode to retrive tree alias from
+ * @param {object} treeNode to retrieve tree alias from
*/
getTreeAlias: function (treeNode) {
var root = this.getTreeRoot(treeNode);
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js
index 4db5af883e..7e4d7eaa4a 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js
@@ -269,41 +269,62 @@
/** formats the display model used to display the member to the model used to save the member */
formatMemberPostData: function (displayModel, action) {
- //this is basically the same as for media but we need to explicitly add the username,email, password to the save model
+ //this is basically the same as for media but we need to explicitly add the username, email, password to the save model
var saveModel = this.formatMediaPostData(displayModel, action);
saveModel.key = displayModel.key;
- var genericTab = _.find(displayModel.tabs, function (item) {
- return item.id === 0;
- });
-
- //map the member login, email, password and groups
- var propLogin = _.find(genericTab.properties, function (item) {
- return item.alias === "_umb_login";
- });
- var propEmail = _.find(genericTab.properties, function (item) {
- return item.alias === "_umb_email";
- });
- var propPass = _.find(genericTab.properties, function (item) {
- return item.alias === "_umb_password";
- });
- var propGroups = _.find(genericTab.properties, function (item) {
- return item.alias === "_umb_membergroup";
- });
- saveModel.email = propEmail.value.trim();
- saveModel.username = propLogin.value.trim();
-
- saveModel.password = this.formatChangePasswordModel(propPass.value);
-
- var selectedGroups = [];
- for (var n in propGroups.value) {
- if (propGroups.value[n] === true) {
- selectedGroups.push(n);
+ // Map membership properties
+ _.each(displayModel.membershipProperties, prop => {
+ switch (prop.alias) {
+ case '_umb_login':
+ saveModel.username = prop.value.trim();
+ break;
+ case '_umb_email':
+ saveModel.email = prop.value.trim();
+ break;
+ case '_umb_password':
+ saveModel.password = this.formatChangePasswordModel(prop.value);
+ break;
+ case '_umb_membergroup':
+ saveModel.memberGroups = _.keys(_.pick(prop.value, value => value === true));
+ break;
}
- }
- saveModel.memberGroups = selectedGroups;
+ });
+
+ // saveModel.password = this.formatChangePasswordModel(propPass.value);
+ //
+ // var selectedGroups = [];
+ // for (var n in propGroups.value) {
+ // if (propGroups.value[n] === true) {
+ // selectedGroups.push(n);
+ // }
+ // }
+ // saveModel.memberGroups = selectedGroups;
+
+ // Map custom member provider properties
+ var memberProviderPropAliases = _.pairs(displayModel.fieldConfig);
+ _.each(displayModel.tabs, tab => {
+ _.each(tab.properties, prop => {
+ var foundAlias = _.find(memberProviderPropAliases, item => prop.alias === item[1]);
+ if (foundAlias) {
+ // we know the current property matches an alias, now we need to determine which membership provider property it was for
+ // by looking at the key
+ switch (foundAlias[0]) {
+ case "umbracoMemberLockedOut":
+ saveModel.isLockedOut = Object.toBoolean(prop.value);
+ break;
+ case "umbracoMemberApproved":
+ saveModel.isApproved = Object.toBoolean(prop.value);
+ break;
+ case "umbracoMemberComments":
+ saveModel.comments = prop.value;
+ break;
+ }
+ }
+ });
+ });
return saveModel;
},
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less
index b5d8c3cced..284a7a8007 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less
@@ -1,6 +1,5 @@
.umb-file-dropzone {
-
// drop zone
// tall and small version - animate height
.dropzone {
@@ -21,17 +20,16 @@
&.is-small {
height: 100px;
+
.illustration {
width: 200px;
}
}
-
+
&.drag-over {
border: 1px dashed @gray-1;
}
}
-
-
// center the content of the drop zone
.content {
position: absolute;
@@ -41,8 +39,6 @@
display: flex;
flex-direction: column;
}
-
-
// file select link
.file-select {
background: transparent;
@@ -54,11 +50,10 @@
margin-top: 10px;
&:hover {
- color: @ui-action-discreet-type-hover;
- text-decoration: none;
+ color: @ui-action-discreet-type-hover;
+ text-decoration: none;
}
}
-
// uploading / uploaded file list
.file-list {
list-style: none;
@@ -67,12 +62,10 @@
padding: 10px 20px;
.file {
- //border-bottom: 1px dashed @orange;
- display: block;
- width: 100%;
padding: 5px 0;
position: relative;
border-top: 1px solid @gray-8;
+
&:first-child {
border-top: none;
}
@@ -80,13 +73,21 @@
&.ng-enter {
animation: fadeIn 0.5s;
}
+
&.ng-leave {
animation: fadeOut 2s;
}
+
.file-description {
color: @gray-3;
font-size: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
width: 100%;
+ }
+
+ .file-messages, .file-messages span {
display: block;
}
@@ -95,25 +96,11 @@
width: 100%;
}
- .file-icon {
- position: absolute;
- right: 0;
- bottom: 0;
-
- .icon {
- font-size: 20px;
- &.ng-enter {
- animation: fadeIn 0.5s;
- }
- &.ng-leave {
- animation: fadeIn 0.5s;
- }
- }
+ .ok-all {
+ margin-left: auto;
}
}
}
-
-
// progress bars
// could be moved to its own less file
.file-progress {
@@ -131,5 +118,4 @@
width: 0;
}
}
-
}
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 71be01e6ff..d25fe62c08 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
@@ -225,6 +225,17 @@
.umb-media-grid__list-item.selected, .umb-media-grid__list-item.selected:hover, .umb-media-grid__list-item.selected:focus {
border: 2px solid #f5c1bc !important;
}
+.umb-media-grid__list-item-name:hover {
+ text-decoration:underline;
+}
+.umb-media-grid__list-item.-filtered:not(.-folder) {
+ cursor: not-allowed;
+
+ * {
+ pointer-events: none;
+ }
+}
+
.umb-media-grid__list-view .umb-table-cell.umb-table__name {
flex: 1 1 25%;
diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less
index 66afbfd73f..43911fccb1 100644
--- a/src/Umbraco.Web.UI.Client/src/less/main.less
+++ b/src/Umbraco.Web.UI.Client/src/less/main.less
@@ -237,7 +237,6 @@ umb-property:last-of-type .umb-control-group {
}
.control-description {
- max-width:480px;// avoiding description becoming too wide when its placed on top of property.
margin-bottom: 5px;
}
}
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 fd699b79d0..2805e7f79b 100644
--- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less
+++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
@@ -526,7 +526,9 @@
position: absolute;
bottom: -20px;
height: 20px;
+ min-width: 100px;
right: 0;
+ text-align: right;
z-index: @zindexCropperOverlay - 1;
font-size: 12px;
opacity: 0.7;
@@ -566,12 +568,17 @@
}
}
-.umb-cropper .crop-controls-wrapper__icon-left {
- margin-right: 10px;
-
-}
+.umb-cropper .crop-controls-wrapper__icon-left,
.umb-cropper .crop-controls-wrapper__icon-right {
- margin-left: 10px;
+ color: @gray-3;
+}
+
+.umb-cropper .crop-controls-wrapper__icon-left {
+ margin-right: 15px;
+}
+
+.umb-cropper .crop-controls-wrapper__icon-right {
+ margin-left: 15px;
font-size: 22px;
}
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.controller.js
index 5b9626c676..f69467b0a1 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/drawers/help/help.controller.js
@@ -1,3 +1,4 @@
+
(function () {
"use strict";
@@ -13,6 +14,12 @@
vm.customDashboard = null;
vm.tours = [];
vm.systemInfoDisplay = false;
+ vm.labels = {};
+ vm.labels.copiedSuccessInfo = "";
+ vm.labels.copySuccessStatus = "";
+ vm.labels.copiedErrorInfo = "";
+ vm.labels.copyErrorStatus = "";
+
vm.closeDrawer = closeDrawer;
vm.startTour = startTour;
@@ -36,6 +43,24 @@
localizationService.localize("general_help").then(function(data){
vm.title = data;
});
+ //Set help dashboard messages
+ var labelKeys = [
+ "general_help",
+ "speechBubbles_copySuccessMessage",
+ "general_success",
+ "speechBubbles_cannotCopyInformation",
+ "general_error"
+ ];
+ localizationService.localizeMany(labelKeys).then(function(resp){
+ [
+ vm.title,
+ vm.labels.copiedSuccessInfo,
+ vm.labels.copySuccessStatus,
+ vm.labels.copiedErrorInfo,
+ vm.labels.copyErrorStatus
+ ] = resp;
+ });
+
currentUserResource.getUserData().then(function(systemInfo){
vm.systemInfo = systemInfo;
let browserInfo = platformService.getBrowserInfo();
@@ -43,7 +68,7 @@
vm.systemInfo.push({name :"Browser", data: browserInfo.name + " " + browserInfo.version});
}
vm.systemInfo.push({name :"Browser OS", data: getPlatform()});
- });
+ } );
tourService.getGroupedTours().then(function(groupedTours) {
vm.tours = groupedTours;
getTourGroupCompletedPercentage();
@@ -208,22 +233,33 @@
}
}
function copyInformation(){
- let copyText = "\n\n\n\nCategory | Data\n-- | --\n";
+ //Write start and end text for table formatting in github issues
+ let copyStartText = "\n\n\n\nCategory | Data\n-- | --\n";
+ let copyEndText = "\n\n\n";
+
+ let copyText = copyStartText;
vm.systemInfo.forEach(function (info){
copyText += info.name + " | " + info.data + "\n";
});
- copyText += "\n\n\n"
- navigator.clipboard.writeText(copyText);
- if(copyText != null){
- notificationsService.success("Copied!", "Your system information is now in your clipboard");
+
+ copyText += copyEndText;
+
+ // Check if copyText is only start + end text
+ // if it is something went wrong and we will not copy to clipboard
+ let emptyCopyText = copyStartText + copyEndText;
+ if(copyText !== emptyCopyText) {
+ notificationsService.success(vm.labels.copySuccessStatus, vm.labels.copiedSuccessInfo);
+ navigator.clipboard.writeText(copyText);
}
- else{
- notificationsService.error("Error", "Could not copy system information");
+ else {
+ notificationsService.error(vm.labels.copyErrorStatus, vm.labels.copiedErrorInfo);
}
}
+
function getPlatform() {
return window.navigator.platform;
}
+
evts.push(eventsService.on("appState.tour.complete", function (event, tour) {
tourService.getGroupedTours().then(function(groupedTours) {
vm.tours = groupedTours;
@@ -239,8 +275,8 @@
});
oninit();
-
}
angular.module("umbraco").controller("Umbraco.Drawers.Help", HelpDrawerController);
+
})();
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
index 8fe5526c53..ed705db26b 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/blockeditor/blockeditor.html
@@ -6,6 +6,7 @@
-