++ ++ +++ + +
+ (function () {
+ "use strict";
+
+ function Controller() {
+
+ var vm = this;
+ vm.toggle = toggle;
+
+ function toggle(item) {
+ if(item.checked) {
+ // do something if item is checked
+ }
+ else {
+ // do something else if item is unchecked
+ }
+ }
+
+ function init() {
+ vm.items = [{
+ name: "Item 1",
+ description: "Item 1 description",
+ checked: false,
+ disabled: false
+ }, {
+ name: "Item 2",
+ description: "Item 2 description",
+ checked: true,
+ disabled: true
+ }];
+ }
+
+ init();
+ }
+
+ angular.module("umbraco").controller("My.Controller", Controller);
+
+ })();
+
+
+@param {Array} items The items to list in the toggle group
+@param {callback} onClick The function which should be called when the toggle is clicked for one of the items.
+
+**/
+
+(function () {
+ 'use strict';
+
+ function ToggleGroupDirective() {
+
+ function link(scope, el, attr, ctrl) {
+
+ scope.change = function(item) {
+ if (item.disabled) {
+ return;
+ }
+
+ item.checked = !item.checked;
+ if(scope.onClick) {
+ scope.onClick({'item': item});
+ }
+ };
+
+ }
+
+ var directive = {
+ restrict: 'E',
+ replace: true,
+ templateUrl: 'views/components/buttons/umb-toggle-group.html',
+ scope: {
+ items: "=",
+ onClick: "&"
+ },
+ link: link
+ };
+
+ return directive;
+
+ }
+
+ angular.module('umbraco.directives').directive('umbToggleGroup', ToggleGroupDirective);
+
+})();
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
index 4ba4cf96bb..b81e62a66b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tree/umbtreesearchbox.directive.js
@@ -12,6 +12,7 @@ function treeSearchBox(localizationService, searchService, $q) {
searchFromName: "@",
showSearch: "@",
section: "@",
+ ignoreUserStartNodes: "@",
hideSearchCallback: "=",
searchCallback: "="
},
@@ -34,6 +35,7 @@ function treeSearchBox(localizationService, searchService, $q) {
scope.showSearch = "false";
}
+
//used to cancel any request in progress if another one needs to take it's place
var canceler = null;
@@ -60,6 +62,11 @@ function treeSearchBox(localizationService, searchService, $q) {
searchArgs["searchFrom"] = scope.searchFromId;
}
+ //append ignoreUserStartNodes value if there is one
+ if (scope.ignoreUserStartNodes) {
+ searchArgs["ignoreUserStartNodes"] = scope.ignoreUserStartNodes;
+ }
+
searcher(searchArgs).then(function (data) {
scope.searchCallback(data);
//set back to null so it can be re-created
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
index e7abc81841..4c1a8747d1 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbpagination.directive.js
@@ -91,6 +91,10 @@ Use this directive to generate a pagination.
function link(scope, el, attr, ctrl) {
function activate() {
+ // page number is sometimes a string - let's make sure it's an int before we do anything with it
+ if (scope.pageNumber) {
+ scope.pageNumber = parseInt(scope.pageNumber);
+ }
scope.pagination = [];
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/umbpermission.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/users/umbpermission.directive.js
deleted file mode 100644
index bae87789ca..0000000000
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/users/umbpermission.directive.js
+++ /dev/null
@@ -1,36 +0,0 @@
-(function () {
- 'use strict';
-
- function PermissionDirective() {
-
- function link(scope, el, attr, ctrl) {
-
- scope.change = function() {
- scope.selected = !scope.selected;
- if(scope.onChange) {
- scope.onChange({'selected': scope.selected});
- }
- };
-
- }
-
- var directive = {
- restrict: 'E',
- replace: true,
- templateUrl: 'views/components/users/umb-permission.html',
- scope: {
- name: "=",
- description: "=?",
- selected: "=",
- onChange: "&"
- },
- link: link
- };
-
- return directive;
-
- }
-
- angular.module('umbraco.directives').directive('umbPermission', PermissionDirective);
-
-})();
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js
index 8b93666172..601ff2f671 100644
--- a/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js
+++ b/src/Umbraco.Web.UI.Client/src/common/mocks/services/localization.mocks.js
@@ -215,14 +215,6 @@ angular.module('umbraco.mocks').
"placeholders_nameentity": "Name the %0%...",
"placeholders_search": "Type to search...",
"placeholders_filter": "Type to filter...",
- "editcontenttype_allowedchildnodetypes": "Allowed child nodetypes",
- "editcontenttype_create": "Create",
- "editcontenttype_deletetab": "Delete tab",
- "editcontenttype_description": "Description",
- "editcontenttype_newtab": "New tab",
- "editcontenttype_tab": "Tab",
- "editcontenttype_thumbnail": "Thumbnail",
- "editcontenttype_iscontainercontenttype": "Use as container content type",
"editdatatype_addPrevalue": "Add prevalue",
"editdatatype_dataBaseDatatype": "Database datatype",
"editdatatype_guid": "Property editor GUID",
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
index b807a4dc31..d571de0e2d 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
@@ -365,17 +365,28 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
*
* @param {Int} id id of content item to return
- * @param {Int} culture optional culture to retrieve the item in
+ * @param {Bool} options.ignoreUserStartNodes set to true to allow a user to choose nodes that they normally don't have access to
* @returns {Promise} resourcePromise object containing the content item.
*
*/
- getById: function (id) {
+ getById: function (id, options) {
+ var defaults = {
+ ignoreUserStartNodes: false
+ };
+ if (options === undefined) {
+ options = {};
+ }
+ //overwrite the defaults if there are any specified
+ angular.extend(defaults, options);
+ //now copy back to the options we will use
+ options = defaults;
+
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetById",
- { id: id })),
+ [{ id: id }, { ignoreUserStartNodes: options.ignoreUserStartNodes }])),
'Failed to retrieve data for content id ' + id)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
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 753d180880..d5145727ac 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
@@ -284,15 +284,31 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity.
*
*/
- getAncestors: function (id, type, culture) {
+ getAncestors: function (id, type, culture, options) {
+ var defaults = {
+ ignoreUserStartNodes: false
+ };
+ if (options === undefined) {
+ options = {};
+ }
+ //overwrite the defaults if there are any specified
+ angular.extend(defaults, options);
+ //now copy back to the options we will use
+ options = defaults;
if (culture === undefined) culture = "";
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetAncestors",
- [{ id: id }, { type: type }, { culture: culture }])),
- 'Failed to retrieve ancestor data for id ' + id);
+ [
+ { id: id },
+ { type: type },
+ { culture: culture },
+ { ignoreUserStartNodes: options.ignoreUserStartNodes }
+ ])),
+
+ 'Failed to retrieve ancestor data for id ' + id);
},
/**
@@ -424,7 +440,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 1,
filter: '',
orderDirection: "Ascending",
- orderBy: "SortOrder"
+ orderBy: "SortOrder",
+ ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
@@ -453,7 +470,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageSize: options.pageSize,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
- filter: encodeURIComponent(options.filter)
+ filter: encodeURIComponent(options.filter),
+ ignoreUserStartNodes: options.ignoreUserStartNodes
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -481,12 +499,19 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
- search: function (query, type, searchFrom, canceler) {
+ search: function (query, type, options, canceler) {
var args = [{ query: query }, { type: type }];
- if (searchFrom) {
- args.push({ searchFrom: searchFrom });
+
+ if(options !== undefined) {
+ if (options.searchFrom) {
+ args.push({ searchFrom: options.searchFrom });
+ }
+ if (options.ignoreUserStartNodes) {
+ args.push({ ignoreUserStartNodes: options.ignoreUserStartNodes });
+ }
}
+
var httpConfig = {};
if (canceler) {
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 dad5345e6c..bcdaddd22f 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
@@ -53,7 +53,7 @@ function logResource($q, $http, umbRequestHelper) {
*
* @param {Object} options options object
* @param {Int} options.id the id of the entity
- * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
+ * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
* @param {Int} options.pageNumber if paging data, current page index, default = 1
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
@@ -122,7 +122,7 @@ function logResource($q, $http, umbRequestHelper) {
*
*
* @param {Object} options options object
- * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
+ * @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
* @param {Int} options.pageNumber if paging data, current page index, default = 1
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
index 1d6d5171a1..462184c9f2 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
@@ -329,7 +329,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder",
- orderBySystemField: true
+ orderBySystemField: true,
+ ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
@@ -367,6 +368,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
"GetChildren",
[
{ id: parentId },
+ { ignoreUserStartNodes: options.ignoreUserStartNodes },
{ pageNumber: options.pageNumber },
{ pageSize: options.pageSize },
{ orderBy: options.orderBy },
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js
index 8aaddbf98f..20d014ab0f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/listviewhelper.service.js
@@ -45,7 +45,7 @@
(function () {
'use strict';
- function listViewHelper(localStorageService) {
+ function listViewHelper($location, localStorageService, urlHelper) {
var firstSelectedIndex = 0;
var localStorageKey = "umblistViewLayout";
@@ -559,6 +559,32 @@
}
+ /**
+ * @ngdoc method
+ * @name umbraco.services.listViewHelper#editItem
+ * @methodOf umbraco.services.listViewHelper
+ *
+ * @description
+ * Method for opening an item in a list view for editing.
+ *
+ * @param {Object} item The item to edit
+ */
+ function editItem(item) {
+ if (!item.editPath) {
+ return;
+ }
+ var parts = item.editPath.split("?");
+ var path = parts[0];
+ var params = parts[1]
+ ? urlHelper.getQueryStringParams("?" + parts[1])
+ : {};
+
+ $location.path(path);
+ for (var p in params) {
+ $location.search(p, params[p]);
+ }
+ }
+
function isMatchingLayout(id, layout) {
// legacy format uses "nodeId", be sure to look for both
return layout.id === id || layout.nodeId === id;
@@ -579,7 +605,8 @@
isSelectedAll: isSelectedAll,
setSortingDirection: setSortingDirection,
setSorting: setSorting,
- getButtonPermissions: getButtonPermissions
+ getButtonPermissions: getButtonPermissions,
+ editItem: editItem
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
index 04c431767c..a2010d20f2 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/search.service.js
@@ -42,7 +42,11 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- return entityResource.search(args.term, "Member", args.searchFrom).then(function (data) {
+ var options = {
+ searchFrom: args.searchFrom
+ }
+
+ return entityResource.search(args.term, "Member", options).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMemberResult(item);
});
@@ -67,7 +71,12 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- return entityResource.search(args.term, "Document", args.searchFrom, args.canceler).then(function (data) {
+ var options = {
+ searchFrom: args.searchFrom,
+ ignoreUserStartNodes: args.ignoreUserStartNodes
+ }
+
+ return entityResource.search(args.term, "Document", options, args.canceler).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureContentResult(item);
});
@@ -92,7 +101,12 @@ angular.module('umbraco.services')
throw "args.term is required";
}
- return entityResource.search(args.term, "Media", args.searchFrom).then(function (data) {
+ var options = {
+ searchFrom: args.searchFrom,
+ ignoreUserStartNodes: args.ignoreUserStartNodes
+ }
+
+ return entityResource.search(args.term, "Media", options).then(function (data) {
_.each(data, function (item) {
searchResultFormatter.configureMediaResult(item);
});
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 ce4bf6077c..2fd75184ca 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
@@ -48,7 +48,14 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
if (configuredStylesheets) {
angular.forEach(configuredStylesheets, function (val, key) {
- stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + val + ".css");
+ if (val.indexOf(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/") === 0) {
+ // current format (full path to stylesheet)
+ stylesheets.push(val);
+ }
+ else {
+ // legacy format (stylesheet name only) - must prefix with stylesheet folder and postfix with ".css"
+ stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + val + ".css");
+ }
promises.push(stylesheetResource.getRulesByName(val).then(function (rules) {
angular.forEach(rules, function (rule) {
@@ -1143,11 +1150,25 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
let self = this;
+ function getIgnoreUserStartNodes(args) {
+ var ignoreUserStartNodes = false;
+ // Most property editors have a "config" property with ignoreUserStartNodes on then
+ if (args.model.config) {
+ ignoreUserStartNodes = Object.toBoolean(args.model.config.ignoreUserStartNodes);
+ }
+ // EXCEPT for the grid's TinyMCE editor, that one wants to be special and the config is called "configuration" instead
+ else if (args.model.configuration) {
+ ignoreUserStartNodes = Object.toBoolean(args.model.configuration.ignoreUserStartNodes);
+ }
+ return ignoreUserStartNodes;
+ }
+
//create link picker
self.createLinkPicker(args.editor, function (currentTarget, anchorElement) {
var linkPicker = {
currentTarget: currentTarget,
anchors: editorState.current ? self.getAnchorNames(JSON.stringify(editorState.current.properties)) : [],
+ ignoreUserStartNodes: getIgnoreUserStartNodes(args),
submit: function (model) {
self.insertLinkInEditor(args.editor, model.target, anchorElement);
editorService.close();
@@ -1161,13 +1182,25 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//Create the insert media plugin
self.createMediaPicker(args.editor, function (currentTarget, userData) {
+
+ var startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
+ var startNodeIsVirtual = userData.startMediaIds.length !== 1;
+
+ var ignoreUserStartNodes = getIgnoreUserStartNodes(args);
+ if (ignoreUserStartNodes) {
+ ignoreUserStartNodes = true;
+ startNodeId = -1;
+ startNodeIsVirtual = true;
+ }
+
var mediaPicker = {
currentTarget: currentTarget,
onlyImages: true,
showDetails: true,
disableFolderSelect: true,
- startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
- startNodeIsVirtual: userData.startMediaIds.length !== 1,
+ startNodeId: startNodeId,
+ startNodeIsVirtual: startNodeIsVirtual,
+ ignoreUserStartNodes: ignoreUserStartNodes,
submit: function (model) {
self.insertMediaInEditor(args.editor, model.selection[0]);
editorService.close();
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 6a15c0f553..d61d1c3ba1 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
@@ -29,6 +29,15 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
return cacheKey;
}
+ // Adapted from: https://stackoverflow.com/a/2140723
+ // Please note, we can NOT test this functionality correctly in Phantom because it implements
+ // the localeCompare method incorrectly: https://github.com/ariya/phantomjs/issues/11063
+ function invariantEquals(a, b) {
+ return typeof a === "string" && typeof b === "string"
+ ? a.localeCompare(b, undefined, { sensitivity: "base" }) === 0
+ : a === b;
+ }
+
return {
/** Internal method to return the tree cache */
@@ -165,8 +174,8 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
Umbraco.Sys.ServerVariables.umbracoPlugins.trees &&
angular.isArray(Umbraco.Sys.ServerVariables.umbracoPlugins.trees)) {
- var found = _.find(Umbraco.Sys.ServerVariables.umbracoPlugins.trees, function(item) {
- return item.alias === treeAlias;
+ var found = _.find(Umbraco.Sys.ServerVariables.umbracoPlugins.trees, function (item) {
+ return invariantEquals(item.alias, treeAlias);
});
return found ? found.packageFolder : undefined;
diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less
index 2a53c25f68..f02babda30 100644
--- a/src/Umbraco.Web.UI.Client/src/less/belle.less
+++ b/src/Umbraco.Web.UI.Client/src/less/belle.less
@@ -164,6 +164,7 @@
@import "components/buttons/umb-button.less";
@import "components/buttons/umb-button-group.less";
@import "components/buttons/umb-toggle.less";
+@import "components/buttons/umb-toggle-group.less";
@import "components/notifications/umb-notifications.less";
@import "components/umb-file-dropzone.less";
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle-group.less b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle-group.less
new file mode 100644
index 0000000000..df60c8aed1
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/less/components/buttons/umb-toggle-group.less
@@ -0,0 +1,35 @@
+.umb-toggle-group {
+ .umb-toggle-group-item {
+ display: flex;
+ border-bottom: 1px solid @gray-9;
+ padding: 7px 0;
+ }
+
+ .umb-toggle-group-item:last-of-type {
+ border-bottom: none;
+ }
+
+ .umb-toggle-group-item__toggle {
+ padding-right: 20px;
+ cursor: pointer;
+ }
+
+ .umb-toggle-group-item__content {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ flex: 1 1 auto;
+ cursor: pointer;
+ }
+
+ .umb-toggle-group-item--disabled .umb-toggle-group-item__toggle,
+ .umb-toggle-group-item--disabled .umb-toggle-group-item__content {
+ cursor: not-allowed;
+ opacity: 0.8;
+ }
+
+ .umb-toggle-group-item__description {
+ font-size: 13px;
+ color: @gray-4;
+ }
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less
index 2d1cbd10ff..2a8137e5f9 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less
@@ -1,7 +1,7 @@
.umb-expansion-panel {
background: @white;
border-radius: 3px;
- margin-bottom: 16px;
+ margin-bottom: 20px;
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.16);
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less
index b66ab40335..8358dc4b67 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/tree/umb-tree.less
@@ -228,40 +228,64 @@ body.touch .umb-tree {
}
}
-.umb-tree-item__annotation {
- &::before {
- font-family: 'icomoon';
- position: absolute;
- bottom: 0;
- }
-}
+.has-unpublished-version, .is-container, .protected {
+ > .umb-tree-item__inner {
+ > .umb-tree-item__annotation {
+ background-color: @white;
+ border-radius: 50%;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ margin-left: 12px;
+ top: 17px;
-.has-unpublished-version > .umb-tree-item__inner > .umb-tree-item__annotation::before {
- content: "\e25a";
- color: @green;
- font-size: 20px;
- margin-left: -25px;
+ &::before {
+ font-family: 'icomoon';
+ position: absolute;
+ top: -4px;
+ }
+ }
+
+ &:hover > .umb-tree-item__annotation {
+ background-color: @ui-option-hover;
+ }
+ }
+
+ &.current > .umb-tree-item__inner > .umb-tree-item__annotation {
+ background-color: @pinkLight;
+ }
}
.is-container > .umb-tree-item__inner > .umb-tree-item__annotation::before {
content: "\e04e";
color: @blue;
font-size: 9px;
- margin-left: -20px;
+ margin-left: 2px;
+ left: 0px;
+}
+
+.has-unpublished-version > .umb-tree-item__inner > .umb-tree-item__annotation::before {
+ content: "\e25a";
+ color: @green;
+ font-size: 23px;
+ margin-left: 16px;
+ left: -21px;
}
.protected > .umb-tree-item__inner > .umb-tree-item__annotation::before {
content: "\e256";
color: @red;
- font-size: 20px;
- margin-left: -25px;
+ font-size: 23px;
+ margin-left: -3px;
+ left: -2px;
}
.locked > .umb-tree-item__inner > .umb-tree-item__annotation::before {
content: "\e0a7";
color: @red;
font-size: 9px;
- margin-left: -20px;
+ margin-left: 2px;
+ left: 0px;
}
.no-access {
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
index fb83504a1f..c0e91e28c2 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-box.less
@@ -1,7 +1,7 @@
.umb-box {
background: @white;
border-radius: 3px;
- margin-bottom: 8px;
+ margin-bottom: 20px;
box-shadow: 0 1px 1px 0 rgba(0,0,0,.16);
}
@@ -28,4 +28,4 @@
.umb-box-content {
padding: 20px;
-}
\ No newline at end of file
+}
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
index f4725fa82d..1e3cf54450 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
@@ -28,9 +28,11 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
searchFromName: null,
showSearch: false,
results: [],
- selectedSearchResults: []
+ selectedSearchResults: [],
+ ignoreUserStartNodes: dialogOptions.ignoreUserStartNodes
};
+ $scope.customTreeParams = dialogOptions.ignoreUserStartNodes ? "ignoreUserStartNodes=" + dialogOptions.ignoreUserStartNodes : "";
$scope.showTarget = $scope.model.hideTarget !== true;
// this ensures that we only sync the tree once and only when it's ready
@@ -73,7 +75,11 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
});
// get the content properties to build the anchor name list
- contentResource.getById(id).then(function (resp) {
+
+ var options = {};
+ options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
+
+ contentResource.getById(id, options).then(function (resp) {
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
$scope.model.target.url = resp.urls[0].text;
});
@@ -119,7 +125,10 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
if (args.node.id < 0) {
$scope.model.target.url = "/";
} else {
- contentResource.getById(args.node.id).then(function (resp) {
+ var options = {};
+ options.ignoreUserStartNodes = dialogOptions.ignoreUserStartNodes;
+
+ contentResource.getById(args.node.id, options).then(function (resp) {
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
$scope.model.target.url = resp.urls[0].text;
});
@@ -139,9 +148,17 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
$scope.switchToMediaPicker = function () {
userService.getCurrentUser().then(function (userData) {
+ var startNodeId = userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0];
+ var startNodeIsVirtual = userData.startMediaIds.length !== 1;
+ if (dialogOptions.ignoreUserStartNodes) {
+ startNodeId = -1;
+ startNodeIsVirtual = true;
+ }
+
var mediaPicker = {
- startNodeId: userData.startMediaIds.length !== 1 ? -1 : userData.startMediaIds[0],
- startNodeIsVirtual: userData.startMediaIds.length !== 1,
+ startNodeId: startNodeId,
+ startNodeIsVirtual: startNodeIsVirtual,
+ ignoreUserStartNodes: dialogOptions.ignoreUserStartNodes,
submit: function (model) {
var media = model.selection[0];
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
index 71fcf2f493..414dbecfc2 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.html
@@ -68,6 +68,7 @@
search-from-id="{{searchInfo.searchFromId}}"
search-from-name="{{searchInfo.searchFromName}}"
show-search="{{searchInfo.showSearch}}"
+ ignore-user-start-nodes="{{searchInfo.ignoreUserStartNodes}}"
section="{{section}}">
@@ -84,6 +85,7 @@
section="content"
hideheader="true"
hideoptions="true"
+ customtreeparams="{{customTreeParams}}"
api="dialogTreeApi"
on-init="onTreeInit()"
enablelistviewexpand="true"
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
index 2d6a2be471..2ba2300730 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/mediapicker/mediapicker.controller.js
@@ -20,11 +20,13 @@ angular.module("umbraco")
$scope.showDetails = dialogOptions.showDetails;
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
+ $scope.ignoreUserStartNodes = Object.toBoolean(dialogOptions.ignoreUserStartNodes);
$scope.cropSize = dialogOptions.cropSize;
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
$scope.lockedFolder = true;
$scope.allowMediaEdit = dialogOptions.allowMediaEdit ? dialogOptions.allowMediaEdit : false;
+ var userStartNodes = [];
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
var allowedUploadFiles = mediaHelper.formatFileTypes(umbracoSettings.allowedUploadFiles);
if ($scope.onlyImages) {
@@ -54,7 +56,8 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
- filter: ''
+ filter: "",
+ ignoreUserStartNodes: $scope.model.ignoreUserStartNodes
};
//preload selected item
@@ -66,7 +69,7 @@ angular.module("umbraco")
function onInit() {
if ($scope.startNodeId !== -1) {
entityResource.getById($scope.startNodeId, "media")
- .then(function (ent) {
+ .then(function(ent) {
$scope.startNodeId = ent.id;
run();
});
@@ -143,7 +146,7 @@ angular.module("umbraco")
}
};
- $scope.gotoFolder = function(folder) {
+ $scope.gotoFolder = function (folder) {
if (!$scope.multiPicker) {
deselectAllImages($scope.model.selection);
}
@@ -152,8 +155,10 @@ angular.module("umbraco")
folder = { id: -1, name: "Media", icon: "icon-folder" };
}
+ var options = {};
if (folder.id > 0) {
- entityResource.getAncestors(folder.id, "media")
+ options.ignoreUserStartNodes = $scope.model.ignoreUserStartNodes;
+ entityResource.getAncestors(folder.id, "media", options)
.then(function(anc) {
$scope.path = _.filter(anc,
function(f) {
@@ -169,13 +174,26 @@ angular.module("umbraco")
$scope.path = [];
}
- $scope.lockedFolder = folder.id === -1 && $scope.model.startNodeIsVirtual;
+ $scope.lockedFolder = (folder.id === -1 && $scope.model.startNodeIsVirtual) || hasFolderAccess(folder) === false;
+
$scope.currentFolder = folder;
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
- return getChildren(folder.id);
+ options.ignoreUserStartNodes = $scope.ignoreUserStartNodes;
+ return getChildren(folder.id, options);
};
+ function hasFolderAccess(node) {
+ var nodePath = node.path ? node.path.split(',') : [node.id];
+
+ for (var i = 0; i < nodePath.length; i++) {
+ if (userStartNodes.indexOf(parseInt(nodePath[i])) !== -1)
+ return true;
+ }
+
+ return false;
+ }
+
$scope.clickHandler = function(image, event, index) {
if (image.isFolder) {
if ($scope.disableFolderSelect) {
@@ -299,7 +317,8 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
- filter: ''
+ filter: "",
+ ignoreUserStartNodes: $scope.model.ignoreUserStartNodes
};
getChildren($scope.currentFolder.id);
}
@@ -367,9 +386,9 @@ angular.module("umbraco")
}
}
- function getChildren(id) {
+ function getChildren(id, options) {
$scope.loading = true;
- return mediaResource.getChildren(id)
+ return mediaResource.getChildren(id, options)
.then(function(data) {
$scope.searchOptions.filter = "";
$scope.images = data.items ? data.items : [];
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/nodepermissions/nodepermissions.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/nodepermissions/nodepermissions.html
index 1846e3caa2..58490fa224 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/nodepermissions/nodepermissions.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/nodepermissions/nodepermissions.html
@@ -17,12 +17,7 @@
-
- Select the tab who's properties should be displayed. If left blank, the first tab on the doc type will be used.
+
+ Select the group whose properties should be displayed. If left blank, the first group on the document type will be used.
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
index d54a17e15a..979baef0f7 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
@@ -25,6 +25,7 @@
section: "content",
treeAlias: "content",
multiPicker: false,
+ ignoreUserStartNodes: Object.toBoolean($scope.model.config.ignoreUserStartNodes),
idType: $scope.model.config.idType ? $scope.model.config.idType : "int",
submit: function (model) {
select(model.selection[0]);
@@ -47,6 +48,7 @@
section: "content",
treeAlias: "content",
multiPicker: false,
+ ignoreUserStartNodes: Object.toBoolean($scope.model.config.ignoreUserStartNodes),
idType: $scope.model.config.idType ? $scope.model.config.idType : "udi",
submit: function (model) {
select(model.selection[0]);
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.controller.js
index 59e0429678..1b489d6283 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.controller.js
@@ -40,14 +40,17 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
$scope.stylesheets = stylesheets;
});
- $scope.selected = function(cmd, alias, lookup){
- if (lookup && angular.isArray(lookup)) {
- cmd.selected = lookup.indexOf(alias) >= 0;
- return cmd.selected;
- }
- return false;
+ $scope.commandSelected = function(cmd) {
+ cmd.selected = $scope.model.value.toolbar.indexOf(cmd.alias) >= 0;
+ return cmd.selected;
};
+ $scope.cssSelected = function (css) {
+ // support both current format (full stylesheet path) and legacy format (stylesheet name only)
+ css.selected = $scope.model.value.stylesheets.indexOf(css.path) >= 0 ||$scope.model.value.stylesheets.indexOf(css.name) >= 0;
+ return css.selected;
+ }
+
$scope.selectCommand = function(command){
var index = $scope.model.value.toolbar.indexOf(command.alias);
@@ -60,11 +63,16 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
$scope.selectStylesheet = function (css) {
- var index = $scope.model.value.stylesheets.indexOf(css.name);
+ // find out if the stylesheet is already selected; first look for the full stylesheet path (current format)
+ var index = $scope.model.value.stylesheets.indexOf(css.path);
+ if (index === -1) {
+ // ... then look for the stylesheet name (legacy format)
+ index = $scope.model.value.stylesheets.indexOf(css.name);
+ }
- if(css.selected && index === -1){
- $scope.model.value.stylesheets.push(css.name);
- }else if(index >= 0){
+ if(index === -1){
+ $scope.model.value.stylesheets.push(css.path);
+ }else{
$scope.model.value.stylesheets.splice(index, 1);
}
};
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
index 6314e0b31e..463b1a03e0 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
@@ -4,7 +4,7 @@