' +
'
' +
'
' +
'
' +
@@ -61,7 +62,7 @@ angular.module("umbraco.directives")
about it.
*/
scope.options = function(e, n, ev){
- emitEvent("treeOptionsClick", {element: e, node: n, event: ev});
+ emitEvent("treeOptionsClick", {element: e, tree: scope.tree, node: n, event: ev});
};
/**
@@ -71,7 +72,7 @@ angular.module("umbraco.directives")
defined on the tree
*/
scope.select = function(e,n,ev){
- emitEvent("treeNodeSelect", { element: e, node: n, event: ev });
+ emitEvent("treeNodeSelect", { element: e, tree: scope.tree, node: n, event: ev });
};
/** method to set the current animation for the node.
@@ -95,7 +96,7 @@ angular.module("umbraco.directives")
scope.load = function(arrow, node) {
if (node.expanded) {
enableDeleteAnimations = false;
- emitEvent("treeNodeCollapsing", { element: arrow, node: node });
+ emitEvent("treeNodeCollapsing", { element: arrow, tree: scope.tree, node: node });
node.expanded = false;
}
else {
@@ -106,19 +107,19 @@ angular.module("umbraco.directives")
/* helper to force reloading children of a tree node */
scope.loadChildren = function(arrow, node, forceReload){
//emit treeNodeExpanding event, if a callback object is set on the tree
- emitEvent("treeNodeExpanding", { element: arrow, node: node });
+ emitEvent("treeNodeExpanding", { element: arrow, tree: scope.tree, node: node });
if (node.hasChildren && (forceReload || !node.children || (angular.isArray(node.children) && node.children.length === 0))) {
//get the children from the tree service
treeService.loadNodeChildren({ node: node, section: scope.section })
.then(function(data) {
//emit expanded event
- emitEvent("treeNodeExpanded", { element: arrow, node: node, children: data });
+ emitEvent("treeNodeExpanded", { element: arrow, tree: scope.tree, node: node, children: data });
enableDeleteAnimations = true;
});
}
else {
- emitEvent("treeNodeExpanded", { element: arrow, node: node, children: node.children });
+ emitEvent("treeNodeExpanded", { element: arrow, tree: scope.tree, node: node, children: node.children });
node.expanded = true;
enableDeleteAnimations = true;
}
@@ -139,6 +140,10 @@ angular.module("umbraco.directives")
scope.loadChildren(null, scope.node, true);
}else if( !node.metaData.treeAlias && activePath.indexOf(node.id) >= 0){
scope.loadChildren(null, scope.node, true);
+
+ scope.path = activePath.filter( function(element) {
+ return listToDelete.indexOf(obj.id) === -1;
+ });
}
}
};
@@ -146,8 +151,9 @@ angular.module("umbraco.directives")
//if the current path contains the node id, we will auto-expand the tree item children
scope.expandActivePath(scope.node, scope.activetree, scope.path);
+ scope.node.stateCssClass = scope.node.cssClasses.join(" ");
- var template = '
';
+ var template = '
';
var newElement = angular.element(template);
$compile(newElement)(scope);
element.append(newElement);
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js
index 5e7f042825..1a36dcc24f 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js
@@ -1,8 +1,10 @@
angular.module('umbraco.directives.validation')
.directive('valCompare',function () {
return {
- require: "ngModel",
- link: function(scope, elem, attrs, ctrl) {
+ require: "ngModel",
+ link: function (scope, elem, attrs, ctrl) {
+
+ //TODO: Pretty sure this should be done using a requires ^form in the directive declaration
var otherInput = elem.inheritedData("$formController")[attrs.valCompare];
ctrl.$parsers.push(function(value) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
index 75ca905c4a..ad1b268618 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js
@@ -5,8 +5,9 @@
* @element textarea
* @requires formController
* @description This directive is used to control the display of the property level validation message.
-* We will listen for server side validation changes
-* and when an error is detected for this property we'll show the error message
+* We will listen for server side validation changes
+* and when an error is detected for this property we'll show the error message.
+* In order for this directive to work, the valStatusChanged directive must be placed on the containing form.
**/
function valPropertyMsg(serverValidationManager) {
return {
@@ -32,17 +33,16 @@ function valPropertyMsg(serverValidationManager) {
scope.errorMsg = "";
//listen for form error changes
- scope.$watch(function() {
- return formCtrl.$error;
- }, function() {
- if (formCtrl.$invalid) {
+ scope.$on("valStatusChanged", function(evt, args) {
+ if (args.form.$invalid) {
//first we need to check if the valPropertyMsg validity is invalid
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
//since we already have an error we'll just return since this means we've already set the
// hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
return;
- } else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
+ }
+ else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
//check if it's one of the properties that is invalid in the current content property
hasError = true;
//update the validation message if we don't already have one assigned.
@@ -54,18 +54,20 @@ function valPropertyMsg(serverValidationManager) {
}
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
- } else {
+ }
+ else {
hasError = false;
scope.errorMsg = "";
}
- } else {
+ }
+ else {
hasError = false;
scope.errorMsg = "";
}
}, true);
//listen for the forms saving event
- scope.$on("saving", function (ev, args) {
+ scope.$on("saving", function(ev, args) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
var err;
@@ -73,7 +75,7 @@ function valPropertyMsg(serverValidationManager) {
if (scope.property) {
err = serverValidationManager.getPropertyError(scope.property.alias, "");
}
- scope.errorMsg = err ? err.errorMsg : "Property has errors";
+ scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
else if (!hasError) {
scope.errorMsg = "";
@@ -93,14 +95,16 @@ function valPropertyMsg(serverValidationManager) {
// So once a field is changed that has a server error assigned to it
// we need to re-validate it for the server side validator so the user can resubmit
// the form. Of course normal client-side validators will continue to execute.
- scope.$watch("property.value", function (newValue) {
+ scope.$watch("property.value", function(newValue) {
//we are explicitly checking for valServer errors here, since we shouldn't auto clear
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
// is the only one, then we'll clear.
var errCount = 0;
for (var e in formCtrl.$error) {
- errCount++;
+ if (e) {
+ errCount++;
+ }
}
if ((errCount === 1 && formCtrl.$error.valPropertyMsg !== undefined) ||
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js
index bf37d73392..d1103cdbc3 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js
@@ -6,17 +6,36 @@
* NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string
**/
function valRegex() {
+
return {
require: 'ngModel',
restrict: "A",
link: function (scope, elm, attrs, ctrl) {
+ var flags = "";
+ if (attrs.valRegexFlags) {
+ try {
+ flags = scope.$eval(attrs.valRegexFlags);
+ if (!flags) {
+ flags = attrs.valRegexFlags;
+ }
+ }
+ catch (e) {
+ flags = attrs.valRegexFlags;
+ }
+ }
var regex;
try {
- regex = new RegExp(scope.$eval(attrs.valRegex));
+ var resolved = scope.$eval(attrs.valRegex);
+ if (resolved) {
+ regex = new RegExp(resolved, flags);
+ }
+ else {
+ regex = new RegExp(attrs.valRegex, flags);
+ }
}
catch(e) {
- regex = new RegExp(attrs.valRegex);
+ regex = new RegExp(attrs.valRegex, flags);
}
var patternValidator = function (viewValue) {
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valstatuschanged.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valstatuschanged.directive.js
new file mode 100644
index 0000000000..aeb3b39ff7
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valstatuschanged.directive.js
@@ -0,0 +1,24 @@
+/**
+* @ngdoc directive
+* @name umbraco.directives.directive:valStatusChanged
+* @restrict A
+* @description Used to broadcast an event to all elements inside this one to notify that form validation has
+* changed. If we don't use this that means you have to put a watch for each directive on a form's validation
+* changing which would result in much higher processing. We need to actually watch the whole $error collection of a form
+* because just watching $valid or $invalid doesn't acurrately trigger form validation changing.
+**/
+function valStatusChanged() {
+ return {
+ require: "form",
+ restrict: "A",
+ link: function (scope, element, attr, formCtrl) {
+
+ scope.$watch(function () {
+ return formCtrl.$error;
+ }, function () {
+ scope.$broadcast("valStatusChanged", { form: formCtrl });
+ }, true);
+ }
+ };
+}
+angular.module('umbraco.directives').directive("valStatusChanged", valStatusChanged);
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js
index 9740adfabc..c38466ac45 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js
@@ -4,6 +4,7 @@
* @name umbraco.directives.directive:valTab
* @restrict A
* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data.
+* In order for this directive to work, the valStatusChanged directive must be placed on the containing form.
**/
function valTab() {
return {
@@ -15,23 +16,22 @@ function valTab() {
scope.tabHasError = false;
- //watch the current form's validation for the current field name
- scope.$watch(function() {
- return formCtrl.$valid;
- }, function() {
- var tabContent = element.closest(".umb-panel").find("#" + tabId);
-
- if (formCtrl.$invalid) {
+ //listen for form validation changes
+ scope.$on("valStatusChanged", function(evt, args) {
+ if (!args.form.$valid) {
+ var tabContent = element.closest(".umb-panel").find("#" + tabId);
//check if the validation messages are contained inside of this tabs
if (tabContent.find(".ng-invalid").length > 0) {
scope.tabHasError = true;
} else {
scope.tabHasError = false;
}
- } else {
+ }
+ else {
scope.tabHasError = false;
}
});
+
}
};
}
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 7cf9c61111..72cbfe9cd2 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
@@ -531,8 +531,25 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*/
publish: function (content, isNew, files) {
return saveContentItem(content, "publish" + (isNew ? "New" : ""), files);
+ },
+
+ publishById: function(id){
+
+ if (!id) {
+ throw "id cannot be null";
+ }
+
+ return umbRequestHelper.resourcePromise(
+ $http.post(
+ umbRequestHelper.getApiUrl(
+ "contentApiBaseUrl",
+ "PostPublishById",
+ [{ id: id }])),
+ 'Failed to publish content with id ' + id);
+
}
+
};
}
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 a23697344b..e008f3b69f 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
@@ -95,7 +95,7 @@ function entityResource($q, $http, umbRequestHelper) {
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetById",
- [{ id: id, type: type }])),
+ [{ id: id}, {type: type }])),
'Failed to retreive entity data for id ' + id);
},
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js
index bf726be952..3f27e308a5 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/member.resource.js
@@ -30,7 +30,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @methodOf umbraco.resources.memberResource
*
* @description
- * Gets a member item with a given id
+ * Gets a member item with a given key
*
* ##usage
*
@@ -41,7 +41,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* });
*
*
- * @param {Int} id id of member item to return
+ * @param {Guid} key key of member item to return
* @returns {Promise} resourcePromise object containing the member item.
*
*/
@@ -62,7 +62,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @methodOf umbraco.resources.memberResource
*
* @description
- * Deletes a member item with a given id
+ * Deletes a member item with a given key
*
* ##usage
*
@@ -72,7 +72,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* });
*
*
- * @param {Int} id id of member item to delete
+ * @param {Guid} key id of member item to delete
* @returns {Promise} resourcePromise object.
*
*/
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/tree.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/tree.resource.js
index 66391893ea..9938012cc3 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/tree.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/tree.resource.js
@@ -39,12 +39,19 @@ function treeResource($q, $http, umbRequestHelper) {
throw "The object specified for does not contain a 'section' property";
}
+ if(!options.tree){
+ options.tree = "";
+ }
+
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"treeApplicationApiBaseUrl",
"GetApplicationTrees",
- [{ application: options.section }])),
+ [
+ {application: options.section},
+ {tree: options.tree}
+ ])),
'Failed to retreive data for application tree ' + options.section);
},
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 03fd6b2946..25faf0b75c 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
@@ -213,7 +213,7 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser
}
args.scope.$broadcast("saved", { scope: args.scope });
- if (!this.redirectToCreatedContent(args.newContent.id)) {
+ if (!this.redirectToCreatedContent(args.redirectId ? args.redirectId : args.newContent.id)) {
//we are not redirecting because this is not new content, it is existing content. In this case
// we need to detect what properties have changed and re-bind them with the server data.
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js
index 08f1690a1b..842f6ff7c3 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/dialog.service.js
@@ -66,7 +66,7 @@ angular.module('umbraco.services')
var scope = options.scope || $rootScope.$new();
//Modal dom obj and unique id
- dialog.element = $('
');
+ dialog.element = $('
');
var id = dialog.template.replace('.html', '').replace('.aspx', '').replace(/[\/|\.|:\&\?\=]/g, "-") + '-' + scope.$id;
if (options.inline) {
@@ -355,6 +355,25 @@ angular.module('umbraco.services')
return openDialog(options);
},
+ /**
+ * @ngdoc method
+ * @name umbraco.services.dialogService#memberPicker
+ * @methodOf umbraco.services.dialogService
+ *
+ * @description
+ * Opens a member picker in a modal, the callback returns a object representing the selected member
+ * @param {Object} options member picker dialog options object
+ * @param {$scope} options.scope dialog scope
+ * @param {$scope} options.multiPicker should the tree pick one or multiple members before returning
+ * @param {Function} options.callback callback function
+ * @returns {Object} modal object
+ */
+ memberPicker: function (options) {
+ options.template = 'views/common/dialogs/memberPicker.html';
+ options.show = true;
+ return openDialog(options);
+ },
+
/**
* @ngdoc method
* @name umbraco.services.dialogService#iconPicker
@@ -383,6 +402,7 @@ angular.module('umbraco.services')
* @param {Object} options iconpicker dialog options object
* @param {$scope} options.scope dialog scope
* @param {$scope} options.section tree section to display
+ * @param {$scope} options.treeAlias specific tree to display
* @param {$scope} options.multiPicker should the tree pick one or multiple items before returning
* @param {Function} options.callback callback function
* @returns {Object} modal object
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/localization.service.js b/src/Umbraco.Web.UI.Client/src/common/services/localization.service.js
index b7b7b99b98..4f09611ef5 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/localization.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/localization.service.js
@@ -1,8 +1,6 @@
angular.module('umbraco.services')
.factory('localizationService', function ($http, $q, $rootScope, $window, $filter, userService) {
- var localize = {
- // use the $window service to get the language of the user's browser
- language: userService.getCurrentUser().locale,
+ var service = {
// array to hold the localized resource string entries
dictionary:[],
// location of the resource file
@@ -13,61 +11,76 @@ angular.module('umbraco.services')
// success handler for all server communication
successCallback:function (data) {
// store the returned array in the dictionary
- localize.dictionary = data;
+ service.dictionary = data;
// set the flag that the resource are loaded
- localize.resourceFileLoaded = true;
+ service.resourceFileLoaded = true;
// broadcast that the file has been loaded
$rootScope.$broadcast('localizeResourcesUpdates');
},
// allows setting of language on the fly
setLanguage: function(value) {
- localize.language = value;
- localize.initLocalizedResources();
+ service.initLocalizedResources();
},
// allows setting of resource url on the fly
setUrl: function(value) {
- localize.url = value;
- localize.initLocalizedResources();
- },
-
- // builds the url for locating the resource file
- buildUrl: function() {
- return '/i18n/resources-locale_' + localize.language + '.js';
+ service.url = value;
+ service.initLocalizedResources();
},
// loads the language resource file from the server
initLocalizedResources:function () {
var deferred = $q.defer();
// build the url to retrieve the localized resource file
- $http({ method:"GET", url:localize.url, cache:false })
+ $http({ method:"GET", url:service.url, cache:false })
.then(function(response){
- localize.resourceFileLoaded = true;
- localize.dictionary = response.data;
+ service.resourceFileLoaded = true;
+ service.dictionary = response.data;
$rootScope.$broadcast('localizeResourcesUpdates');
- return deferred.resolve(localize.dictionary);
+ return deferred.resolve(service.dictionary);
}, function(err){
return deferred.reject("Something broke");
});
return deferred.promise;
},
+ //helper to tokenize and compile a localization string
+ tokenize: function(value,scope) {
+ if(value){
+ var localizer = value.split(':');
+ var retval = {tokens: undefined, key: localizer[0].substring(0)};
+ if(localizer.length > 0){
+ retval.tokens = localizer[1].split(',');
+ for (var x = 0; x < retval.tokens.length; x++) {
+ retval.tokens[x] = scope.$eval(retval.tokens[x]);
+ }
+ }
+
+ return retval;
+ }
+ },
+
// checks the dictionary for a localized resource string
- getLocalizedString: function(value) {
- if(localize.resourceFileLoaded){
- return _lookup(value);
+ localize: function(value,tokens) {
+ if(service.resourceFileLoaded){
+ return service._lookup(value,tokens);
}else{
- localize.initLocalizedResources().then(function(dic){
- return _lookup(value);
+ service.initLocalizedResources().then(function(dic){
+ return service._lookup(value,tokens);
});
}
},
- _lookup: function(value){
- var entry = localize.dictionary[value];
+ _lookup: function(value,tokens){
+ var entry = service.dictionary[value];
if(entry){
+ if(tokens){
+ for (var i = 0; i < tokens.length; i++) {
+ entry = entry.replace("%"+i+"%", tokens[i]);
+ }
+ }
return entry;
}
return "[" + value + "]";
@@ -77,8 +90,8 @@ angular.module('umbraco.services')
};
// force the load of the resource file
- localize.initLocalizedResources();
+ service.initLocalizedResources();
// return the local instance when called
- return localize;
+ return service;
});
\ No newline at end of file
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 2495bbf00c..326f4f51d6 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
@@ -31,7 +31,7 @@ angular.module('umbraco.services')
ui.showContextMenu = false;
ui.showContextMenuDialog = false;
ui.stickyNavigation = false;
-
+ ui.showTray = false;
service.hideUserDialog();
//$("#search-form input").focus();
break;
@@ -53,6 +53,11 @@ angular.module('umbraco.services')
ui.showContextMenu = false;
ui.showSearchResults = true;
ui.showContextMenuDialog = false;
+
+ $timeout(function(){
+ $("#search-field").focus();
+ });
+
break;
default:
ui.showNavigation = false;
@@ -60,6 +65,7 @@ angular.module('umbraco.services')
ui.showContextMenuDialog = false;
ui.showSearchResults = false;
ui.stickyNavigation = false;
+ ui.showTray = false;
break;
}
}
@@ -121,7 +127,14 @@ angular.module('umbraco.services')
}
setMode("tree");
},
-
+
+ showTray: function () {
+ ui.showTray = true;
+ },
+
+ hideTray: function () {
+ ui.showTray = false;
+ },
/**
* @ngdoc method
* @name umbraco.services.navigationService#syncTree
@@ -160,6 +173,10 @@ angular.module('umbraco.services')
//TODO: investicate if we need to halt watch triggers
//and instead pause them and then manually tell the tree to digest path changes
//as this might be a bit heavy loading
+ if(!angular.isArray(path)){
+ path = path.split(",");
+ }
+
this.ui.currentPath = path;
},
@@ -192,7 +209,6 @@ angular.module('umbraco.services')
return;
}
-
service.active = false;
$timeout(function(){
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 39dda8f5d5..a5461a20cd 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
@@ -1,56 +1,77 @@
angular.module('umbraco.services')
-.factory('searchService', function ($q, $log, entityResource) {
+.factory('searchService', function ($q, $log, entityResource, contentResource) {
var m = {results: []};
- return {
+ var service = {
results: m,
- search: function(term){
- m.results.length = 0;
- var deferred = $q.defer();
- var i = 0;
-
- entityResource.search(term, "Document").then(function(data){
+ searchMembers: function(args){
+ entityResource.search(args.term, "Member").then(function(data){
_.each(data, function(el){
- el.menuUrl = "UmbracoTrees/ContentTree/GetMenu?id=" + el.id + "&application=content";
+ el.menuUrl = "UmbracoTrees/MemberTree/GetMenu?id=" + el.Id + "&application=member";
+ el.metaData = {treeAlias: "member"};
+ el.title = el.Fields.nodeName;
+ el.subTitle = el.Fields.email;
+ el.id = el.Id;
});
- m.results.push({
+ args.results.push({
+ icon: "icon-user",
+ editor: "member/member/edit/",
+ matches: data
+ });
+ });
+ },
+ searchContent: function(args){
+ entityResource.search(args.term, "Document").then(function(data){
+
+ _.each(data, function(el){
+ el.menuUrl = "UmbracoTrees/ContentTree/GetMenu?id=" + el.Id + "&application=content";
+ el.metaData = {treeAlias: "content"};
+ el.title = el.Fields.nodeName;
+ el.id = el.Id;
+
+ contentResource.getNiceUrl(el.Id).then(function(url){
+ el.subTitle = angular.fromJson(url);
+ });
+ });
+
+ args.results.push({
icon: "icon-document",
editor: "content/content/edit/",
matches: data
});
- i++;
-
-
- if(i === 2){
- deferred.resolve(m);
- }
});
-
- entityResource.search(term, "Media").then(function(data){
+ },
+ searchMedia: function(args){
+ entityResource.search(args.term, "Media").then(function(data){
_.each(data, function(el){
- el.menuUrl = "UmbracoTrees/MediaTree/GetMenu?id=" + el.id + "&application=media";
+ el.menuUrl = "UmbracoTrees/MediaTree/GetMenu?id=" + el.Id + "&application=media";
+ el.metaData = {treeAlias: "media"};
+ el.title = el.Fields.nodeName;
+ el.id = el.Id;
});
- m.results.push({
+ args.results.push({
icon: "icon-picture",
editor: "media/media/edit/",
matches: data
});
- i++;
-
- if(i === 2){
- deferred.resolve(m);
- }
});
+ },
+ search: function(term){
+ m.results.length = 0;
- return deferred.promise;
+ service.searchMedia({term:term, results:m.results});
+ service.searchContent({term:term, results:m.results});
+ service.searchMembers({term:term, results:m.results});
},
setCurrent: function(sectionAlias){
currentSection = sectionAlias;
}
};
+
+ return service;
});
\ No newline at end of file
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 cdeef6c823..038bf00113 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
@@ -27,6 +27,22 @@ function tinyMceService(dialogService, $log, imageHelper, $http, $timeout, macro
'Failed to retreive entity data for id ');
},
+ /**
+ * @ngdoc method
+ * @name umbraco.services.tinyMceService#defaultPrevalues
+ * @methodOf umbraco.services.tinyMceService
+ *
+ * @description
+ * Returns a default configration to fallback on in case none is provided
+ *
+ */
+ defaultPrevalues: function () {
+ var cfg = {};
+ cfg.toolbar = ["code", "bold", "italic", "umbracocss","alignleft", "aligncenter", "alignright", "bullist","numlist", "outdent", "indent", "link", "image", "umbmediapicker", "umbembeddialog", "umbmacro"];
+ cfg.stylesheets = [];
+ cfg.dimensions = {height: 400, width: 600};
+ return cfg;
+ },
/**
* @ngdoc method
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 b34cd72c79..ff079dde36 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
@@ -234,7 +234,7 @@ function treeService($q, treeResource, iconHelper, notificationsService, $rootSc
.then(function(data) {
//this will be called once the tree app data has loaded
var result = {
- name: section,
+ name: data.name,
alias: section,
root: data
};
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
index d44bb9ccb5..c39b56a5e9 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js
@@ -19,24 +19,31 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ
*/
dictionaryToQueryString: function (queryStrings) {
- if (!angular.isArray(queryStrings)) {
- throw "The queryString parameter is not an array of key value pairs";
+
+ if (angular.isArray(queryStrings)) {
+ return _.map(queryStrings, function (item) {
+ var key = null;
+ var val = null;
+ for (var k in item) {
+ key = k;
+ val = item[k];
+ break;
+ }
+ if (key === null || val === null) {
+ throw "The object in the array was not formatted as a key/value pair";
+ }
+ return key + "=" + val;
+ }).join("&");
}
- return _.map(queryStrings, function (item) {
- var key = null;
- var val = null;
- for (var k in item) {
- key = k;
- val = item[k];
- break;
- }
- if (key == null || val == null) {
- throw "The object in the array was not formatted as a key/value pair";
- }
- return key + "=" + val;
- }).join("&");
+ /*
+ //if we have a simple object, we can simply map with $.param
+ //but with the current structure we cant since an array is an object and an object is an array
+ if(angular.isObject(queryStrings)){
+ return decodeURIComponent($.param(queryStrings));
+ }*/
+ throw "The queryString parameter is not an array of key value pairs";
},
/**
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
index 1deb464037..1fc040527a 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js
@@ -203,7 +203,7 @@ function umbDataFormatter() {
/** 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 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);
var genericTab = _.find(displayModel.tabs, function (item) {
@@ -216,8 +216,12 @@ function umbDataFormatter() {
var propEmail = _.find(genericTab.properties, function (item) {
return item.alias === "_umb_email";
});
+ var propPass = _.find(genericTab.properties, function (item) {
+ return item.alias === "_umb_password";
+ });
saveModel.email = propEmail.value;
saveModel.username = propLogin.value;
+ saveModel.password = propPass.value;
return saveModel;
},
diff --git a/src/Umbraco.Web.UI.Client/src/index.html b/src/Umbraco.Web.UI.Client/src/index.html
index 7b1800850e..34656d0759 100644
--- a/src/Umbraco.Web.UI.Client/src/index.html
+++ b/src/Umbraco.Web.UI.Client/src/index.html
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less
index 79aeca4333..3a35c06ad5 100644
--- a/src/Umbraco.Web.UI.Client/src/less/forms.less
+++ b/src/Umbraco.Web.UI.Client/src/less/forms.less
@@ -4,12 +4,8 @@
// UMBRACO STYLES
// --------------
-.hideLabel label {
- display: none;
-}
-.hideLabel .controls-row {
- margin-left: 0px !Important;
-}
+
+
small.umb-detail,
label small, .guiDialogTiny {
diff --git a/src/Umbraco.Web.UI.Client/src/less/grid.less b/src/Umbraco.Web.UI.Client/src/less/grid.less
index dc2c1b5345..1734cba772 100644
--- a/src/Umbraco.Web.UI.Client/src/less/grid.less
+++ b/src/Umbraco.Web.UI.Client/src/less/grid.less
@@ -66,14 +66,26 @@ body {
position: absolute;
}
-/* refactor colors into a seperate class */
#applications {
z-index: 1000;
height: 100%;
- position: relative;
+ left: 0px;
+ top: 0;
+ bottom: 0;
+ position: absolute;
text-align: center
}
+#applications-tray {
+ z-index: 900;
+ left: 80px;
+ top: 0;
+ bottom: 0;
+ position: absolute;
+ height: 100%;
+ text-align: center;
+}
+
#search-form {
display: block;
margin: 0px;
@@ -105,7 +117,6 @@ body {
padding-top: 100px;
}
-
#dialog {
min-width: 500px;
left: 100%;
diff --git a/src/Umbraco.Web.UI.Client/src/less/listview.less b/src/Umbraco.Web.UI.Client/src/less/listview.less
index fc932805ce..a82d72b1b0 100644
--- a/src/Umbraco.Web.UI.Client/src/less/listview.less
+++ b/src/Umbraco.Web.UI.Client/src/less/listview.less
@@ -86,6 +86,10 @@
color: @grayLight
}
+.umb-listview .selected i.icon, .umb-listview tr:hover i.icon{display: none}
+.umb-listview .selected input[type="checkbox"], .umb-listview tr:hover input[type="checkbox"]{display: inline-block;}
+.umb-listview .inactive{color: @grayLight;}
+
.umb-listview table thead {
font-size: 11px;
font-weight: 600;
diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less
index dc67ac1d3a..fe8c76bd19 100644
--- a/src/Umbraco.Web.UI.Client/src/less/main.less
+++ b/src/Umbraco.Web.UI.Client/src/less/main.less
@@ -113,7 +113,6 @@ h5{
padding-bottom: 15px;
margin-bottom: 10px !important;
}
-
.umb-pane > .umb-control-group:last-child {
border: none;
padding-bottom: 0 !important;
@@ -146,7 +145,7 @@ h5{
display: inline-block
}
-.hidelabel .controls-row {
+.hidelabel > div > .controls-row, .hidelabel > .controls-row {
padding: 0px;
border: none;
margin: 0px !important;
diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less
index ae854db66a..dba73d1c07 100644
--- a/src/Umbraco.Web.UI.Client/src/less/panel.less
+++ b/src/Umbraco.Web.UI.Client/src/less/panel.less
@@ -58,7 +58,7 @@ h1.headline{height: 40px; padding: 30px 0 0 20px;}
position: absolute;
padding: 0px 0px 0px 20px;
}
-.umb-panel-header h1, {
+.umb-panel-header h1 {
margin: 0;
font-size: @fontSizeMedium;
font-weight: 400;
@@ -71,7 +71,6 @@ h1.headline{height: 40px; padding: 30px 0 0 20px;}
.umb-headline-editor-wrapper input {
background: none;
border: none;
- width: auto;
margin: -9px 0 0 0;
padding: 0 0 2px 0;
border-radius: 0;
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 dcb134bd85..b0472e8e76 100644
--- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less
+++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less
@@ -17,6 +17,13 @@
width: 95%;
}
+.umb-dialog .umb-editor {
+ width: 95%;
+}
+.umb-dialog .umb-control-group .help-block {
+ width: 95%;
+}
+
.umb-codeeditor{
width: 99%;
}
diff --git a/src/Umbraco.Web.UI.Client/src/less/sections.less b/src/Umbraco.Web.UI.Client/src/less/sections.less
index 19ce8cb0c3..3f6f10ae74 100644
--- a/src/Umbraco.Web.UI.Client/src/less/sections.less
+++ b/src/Umbraco.Web.UI.Client/src/less/sections.less
@@ -6,6 +6,7 @@ ul.sections {
display: block;
background: @blackLight;
height: 100%;
+ width: 80px;
}
ul.sections li {
@@ -97,8 +98,7 @@ ul.sections li.current a{
padding-left: 0px;
}
-ul.sections li.help {
-
+ul.sections li.help {
margin: 0;
position: absolute;
bottom: 0;
@@ -110,3 +110,12 @@ ul.sections li.help {
ul.sections li.help a {
border-bottom: none;
}
+
+// Section slide-out tray for additional apps
+// -------------------------
+li.expand a, li.expand{border: none !Important;}
+
+ul.sections-tray {
+ padding-top: 100px;
+ width: 80px;
+}
diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less
index 78aca06998..2aa2256860 100644
--- a/src/Umbraco.Web.UI.Client/src/less/tree.less
+++ b/src/Umbraco.Web.UI.Client/src/less/tree.less
@@ -138,6 +138,12 @@
background: @grayLighter
}
+.umb-tree small.search-subtitle{
+ color: @grayLight;
+ display: block;
+ padding-left: 35px;
+}
+
a.umb-options {
visibility: hidden;
cursor: pointer;
@@ -208,6 +214,32 @@ li.root > div > a.umb-options {
float: left
}
+
+// Tree item states
+// -------------------------
+div.not-published > i.icon,div.not-published > a{
+ color: @grayLight;
+}
+div.protected:before{
+ content:"\e256";
+ font-family: 'icomoon';
+ color: @red;
+ position: absolute;
+ font-size: 20px;
+ padding-left: 7px;
+ padding-top: 7px;
+}
+
+div.has-unpublished-version:before{
+ content:"\e25a";
+ font-family: 'icomoon';
+ color: @green;
+ position: absolute;
+ font-size: 20px;
+ padding-left: 7px;
+ padding-top: 7px;
+}
+
// Tree context menu
// -------------------------
.umb-actions {
diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js
index 9ef8f48768..3d4b1dbd8a 100644
--- a/src/Umbraco.Web.UI.Client/src/routes.js
+++ b/src/Umbraco.Web.UI.Client/src/routes.js
@@ -95,7 +95,7 @@ app.config(function ($routeProvider) {
// Here we need to figure out if this route is for a package tree and if so then we need
// to change it's convention view path to:
- // /App_Plugins/{mypackage}/umbraco/{treetype}/{method}.html
+ // /App_Plugins/{mypackage}/backoffice/{treetype}/{method}.html
// otherwise if it is a core tree we use the core paths:
// views/{treetype}/{method}.html
@@ -105,7 +105,7 @@ app.config(function ($routeProvider) {
if (packageTreeFolder) {
$scope.templateUrl = Umbraco.Sys.ServerVariables.umbracoSettings.appPluginsPath +
"/" + packageTreeFolder +
- "/umbraco/" + $routeParams.tree + "/" + $routeParams.method + ".html";
+ "/backoffice/" + $routeParams.tree + "/" + $routeParams.method + ".html";
}
else {
$scope.templateUrl = 'views/' + $routeParams.tree + '/' + $routeParams.method + '.html';
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js
index 4861499cf6..a172a482fb 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.controller.js
@@ -1,8 +1,41 @@
//used for the media picker dialog
angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController",
- function ($scope, eventsService, $log) {
+ function ($scope, eventsService, entityResource, searchService, $log) {
var dialogOptions = $scope.$parent.dialogOptions;
$scope.dialogTreeEventHandler = $({});
+ $scope.results = [];
+
+ $scope.select = function(result){
+ entityResource.getById(result.id, "Document").then(function(ent){
+ if(dialogOptions && dialogOptions.multipicker){
+
+ $scope.showSearch = false;
+ $scope.results = [];
+ $scope.term = "";
+ $scope.oldTerm = undefined;
+
+ $scope.select(ent);
+ }else{
+ $scope.submit(ent);
+ }
+ });
+ };
+
+ $scope.performSearch = function(){
+ if($scope.term){
+ if($scope.oldTerm !== $scope.term){
+ $scope.results = [];
+ searchService.searchContent({term: $scope.term, results: $scope.results});
+ $scope.showSearch = true;
+ $scope.oldTerm = $scope.term;
+ }
+ }else{
+ $scope.oldTerm = "";
+ $scope.showSearch = false;
+ $scope.results = [];
+ }
+ };
+
$scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){
args.event.preventDefault();
diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
index 57549f01da..32109e5fcd 100644
--- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
+++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/contentpicker.html
@@ -1,19 +1,54 @@