Merge remote-tracking branch 'origin/7.0.0' into 7.0.0--property-editor-guid-to-alias

Conflicts:
	src/Umbraco.Core/Configuration/LegacyUmbracoSettings.cs
	src/Umbraco.Core/Persistence/Migrations/Syntax/Alter/Expressions/AlterColumnExpression.cs
	src/Umbraco.Core/PropertyEditors/TinyMcePropertyEditorValueConverter.cs
	src/Umbraco.Core/XmlHelper.cs
	src/Umbraco.Tests/ObjectExtensionsTests.cs
	src/Umbraco.Web/PropertyEditors/RteMacroRenderingPropertyEditorValueConverter.cs
	src/Umbraco.Web/Routing/DefaultUrlProvider.cs
	src/Umbraco.Web/Umbraco.Web.csproj
	src/Umbraco.Web/umbraco.presentation/macro.cs
This commit is contained in:
Shannon
2013-09-17 00:27:17 +10:00
130 changed files with 2785 additions and 1282 deletions

View File

@@ -1,2 +1,4 @@
angular.module("umbraco.directives", ["umbraco.directives.editors"]);
angular.module("umbraco.directives.editors", []);
angular.module("umbraco.directives", ["umbraco.directives.editors", "umbraco.directives.html", "umbraco.directives.validation"]);
angular.module("umbraco.directives.editors", []);
angular.module("umbraco.directives.html", []);
angular.module("umbraco.directives.validation", []);

View File

@@ -0,0 +1,2 @@
The html directives does nothing but display html, with simple one-way binding
and is therefore simpler to use then alot of the strict property bound ones

View File

@@ -0,0 +1,20 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbProperty
* @restrict E
**/
angular.module("umbraco.directives.html")
.directive('umbControlGroup', function () {
return {
scope: {
label: "@",
description: "@",
hideLabel: "@",
alias: "@"
},
transclude: true,
restrict: 'E',
replace: true,
templateUrl: 'views/directives/html/umb-control-group.html'
};
});

View File

@@ -0,0 +1,14 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbProperty
* @restrict E
**/
angular.module("umbraco.directives.html")
.directive('umbPane', function () {
return {
transclude: true,
restrict: 'E',
replace: true,
templateUrl: 'views/directives/html/umb-pane.html'
};
});

View File

@@ -1,14 +1,14 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbPanel
* @restrict E
**/
angular.module("umbraco.directives")
.directive('umbPanel', function(){
return {
restrict: 'E',
replace: true,
transclude: 'true',
templateUrl: 'views/directives/umb-panel.html'
};
/**
* @ngdoc directive
* @name umbraco.directives.directive:umbPanel
* @restrict E
**/
angular.module("umbraco.directives.html")
.directive('umbPanel', function(){
return {
restrict: 'E',
replace: true,
transclude: 'true',
templateUrl: 'views/directives/html/umb-panel.html'
};
});

View File

@@ -0,0 +1,123 @@
/**
* General-purpose validator for ngModel.
* angular.js comes with several built-in validation mechanism for input fields (ngRequired, ngPattern etc.) but using
* an arbitrary validation function requires creation of a custom formatters and / or parsers.
* The ui-validate directive makes it easy to use any function(s) defined in scope as a validator function(s).
* A validator function will trigger validation on both model and input changes.
*
* @example <input val-custom=" 'myValidatorFunction($value)' ">
* @example <input val-custom="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }">
* @example <input val-custom="{ foo : '$value > anotherModel' }" val-custom-watch=" 'anotherModel' ">
* @example <input val-custom="{ foo : '$value > anotherModel', bar : 'validateFoo($value)' }" val-custom-watch=" { foo : 'anotherModel' } ">
*
* @param val-custom {string|object literal} If strings is passed it should be a scope's function to be used as a validator.
* If an object literal is passed a key denotes a validation error key while a value should be a validator function.
* In both cases validator function should take a value to validate as its argument and should return true/false indicating a validation result.
*/
/*
This code comes from the angular UI project, we had to change the directive name and module
but other then that its unmodified
*/
angular.module('umbraco.directives.validation')
.directive('valCustom', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
var validateFn, watch, validators = {},
validateExpr = scope.$eval(attrs.valCustom);
if (!validateExpr){ return;}
if (angular.isString(validateExpr)) {
validateExpr = { validator: validateExpr };
}
angular.forEach(validateExpr, function (exprssn, key) {
validateFn = function (valueToValidate) {
var expression = scope.$eval(exprssn, { '$value' : valueToValidate });
if (angular.isObject(expression) && angular.isFunction(expression.then)) {
// expression is a promise
expression.then(function(){
ctrl.$setValidity(key, true);
}, function(){
ctrl.$setValidity(key, false);
});
return valueToValidate;
} else if (expression) {
// expression is true
ctrl.$setValidity(key, true);
return valueToValidate;
} else {
// expression is false
ctrl.$setValidity(key, false);
return undefined;
}
};
validators[key] = validateFn;
ctrl.$formatters.push(validateFn);
ctrl.$parsers.push(validateFn);
});
function apply_watch(watch)
{
//string - update all validators on expression change
if (angular.isString(watch))
{
scope.$watch(watch, function(){
angular.forEach(validators, function(validatorFn){
validatorFn(ctrl.$modelValue);
});
});
return;
}
//array - update all validators on change of any expression
if (angular.isArray(watch))
{
angular.forEach(watch, function(expression){
scope.$watch(expression, function()
{
angular.forEach(validators, function(validatorFn){
validatorFn(ctrl.$modelValue);
});
});
});
return;
}
//object - update appropriate validator
if (angular.isObject(watch))
{
angular.forEach(watch, function(expression, validatorKey)
{
//value is string - look after one expression
if (angular.isString(expression))
{
scope.$watch(expression, function(){
validators[validatorKey](ctrl.$modelValue);
});
}
//value is array - look after all expressions in array
if (angular.isArray(expression))
{
angular.forEach(expression, function(intExpression)
{
scope.$watch(intExpression, function(){
validators[validatorKey](ctrl.$modelValue);
});
});
}
});
}
}
// Support for val-custom-watch
if (attrs.valCustomWatch){
apply_watch( scope.$eval(attrs.valCustomWatch) );
}
}
};
});

View File

@@ -1,30 +1,30 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valHighlight
* @restrict A
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
**/
function valHighlight($timeout) {
return {
restrict: "A",
link: function (scope, element, attrs, ctrl) {
scope.$watch(function() {
return scope.$eval(attrs.valHighlight);
}, function(newVal, oldVal) {
if (newVal === true) {
element.addClass("highlight-error");
$timeout(function () {
//set the bound scope property to false
scope[attrs.valHighlight] = false;
}, 1000);
}
else {
element.removeClass("highlight-error");
}
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valHighlight
* @restrict A
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
**/
function valHighlight($timeout) {
return {
restrict: "A",
link: function (scope, element, attrs, ctrl) {
scope.$watch(function() {
return scope.$eval(attrs.valHighlight);
}, function(newVal, oldVal) {
if (newVal === true) {
element.addClass("highlight-error");
$timeout(function () {
//set the bound scope property to false
scope[attrs.valHighlight] = false;
}, 1000);
}
else {
element.removeClass("highlight-error");
}
});
}
};
}
angular.module('umbraco.directives').directive("valHighlight", valHighlight);

View File

@@ -0,0 +1,22 @@
angular.module('umbraco.directives.validation')
.directive('valCompare',function () {
return {
require: "ngModel",
link: function(scope, elem, attrs, ctrl) {
var otherInput = elem.inheritedData("$formController")[attrs.valCompare];
ctrl.$parsers.push(function(value) {
if(value === otherInput.$viewValue) {
ctrl.$setValidity("valCompare", true);
return value;
}
ctrl.$setValidity("valCompare", false);
});
otherInput.$parsers.push(function(value) {
ctrl.$setValidity("valCompare", value === ctrl.$viewValue);
return value;
});
}
};
});

View File

@@ -1,151 +1,151 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valPropertyMsg
* @restrict A
* @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
**/
function valPropertyMsg(serverValidationManager) {
return {
scope: {
property: "=property"
},
require: "^form", //require that this directive is contained within an ngForm
replace: true, //replace the element with the template
restrict: "E", //restrict to element
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
/**
Our directive requries a reference to a form controller
which gets passed in to this parameter
*/
link: function (scope, element, attrs, formCtrl) {
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
//if there's any remaining errors in the server validation service then we should show them.
var showValidation = serverValidationManager.items.length > 0;
var hasError = false;
//create properties on our custom scope so we can use it in our template
scope.errorMsg = "";
//listen for error changes
scope.$watch("formCtrl.$error", function () {
if (formCtrl.$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) {
//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.
if (showValidation && scope.errorMsg === "") {
var err;
//this can be null if no property was assigned
if (scope.property) {
err = serverValidationManager.getPropertyError(scope.property.alias, "");
}
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
}
else {
hasError = false;
scope.errorMsg = "";
}
}
else {
hasError = false;
scope.errorMsg = "";
}
}, true);
//listen for the forms saving event
scope.$on("saving", function (ev, args) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
var err;
//this can be null if no property was assigned
if (scope.property) {
err = serverValidationManager.getPropertyError(scope.property.alias, "");
}
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
else if (!hasError) {
scope.errorMsg = "";
}
});
//listen for the forms saved event
scope.$on("saved", function (ev, args) {
showValidation = false;
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
});
//We need to subscribe to any changes to our model (based on user input)
// This is required because when we have a server error we actually invalidate
// the form which means it cannot be resubmitted.
// 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) {
//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 scope.formCtrl.$error) {
errCount++;
}
if ((errCount === 1 && scope.formCtrl.$error.valPropertyMsg !== undefined) ||
(formCtrl.$invalid && scope.formCtrl.$error.valServer !== undefined)) {
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
}
}, true);
//listen for server validation changes
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
// validation changes to fields in the property this is because some server side validators may not
// return the field name for which the error belongs too, just the property for which it belongs.
// It's important to note that we need to subscribe to server validation changes here because we always must
// indicate that a content property is invalid at the property level since developers may not actually implement
// the correct field validation in their property editors.
if (scope.property) { //this can be null if no property was assigned
serverValidationManager.subscribe(scope.property.alias, "", function(isValid, propertyErrors, allErrors) {
hasError = !isValid;
if (hasError) {
//set the error message to the server message
scope.errorMsg = propertyErrors[0].errorMsg;
//flag that the current validator is invalid
formCtrl.$setValidity('valPropertyMsg', false);
}
else {
scope.errorMsg = "";
//flag that the current validator is valid
formCtrl.$setValidity('valPropertyMsg', true);
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function() {
serverValidationManager.unsubscribe(scope.property.alias, "");
});
}
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valPropertyMsg
* @restrict A
* @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
**/
function valPropertyMsg(serverValidationManager) {
return {
scope: {
property: "=property"
},
require: "^form", //require that this directive is contained within an ngForm
replace: true, //replace the element with the template
restrict: "E", //restrict to element
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
/**
Our directive requries a reference to a form controller
which gets passed in to this parameter
*/
link: function (scope, element, attrs, formCtrl) {
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
//if there's any remaining errors in the server validation service then we should show them.
var showValidation = serverValidationManager.items.length > 0;
var hasError = false;
//create properties on our custom scope so we can use it in our template
scope.errorMsg = "";
//listen for error changes
scope.$watch("formCtrl.$error", function () {
if (formCtrl.$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) {
//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.
if (showValidation && scope.errorMsg === "") {
var err;
//this can be null if no property was assigned
if (scope.property) {
err = serverValidationManager.getPropertyError(scope.property.alias, "");
}
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
}
else {
hasError = false;
scope.errorMsg = "";
}
}
else {
hasError = false;
scope.errorMsg = "";
}
}, true);
//listen for the forms saving event
scope.$on("saving", function (ev, args) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
var err;
//this can be null if no property was assigned
if (scope.property) {
err = serverValidationManager.getPropertyError(scope.property.alias, "");
}
scope.errorMsg = err ? err.errorMsg : "Property has errors";
}
else if (!hasError) {
scope.errorMsg = "";
}
});
//listen for the forms saved event
scope.$on("saved", function (ev, args) {
showValidation = false;
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
});
//We need to subscribe to any changes to our model (based on user input)
// This is required because when we have a server error we actually invalidate
// the form which means it cannot be resubmitted.
// 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) {
//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 scope.formCtrl.$error) {
errCount++;
}
if ((errCount === 1 && scope.formCtrl.$error.valPropertyMsg !== undefined) ||
(formCtrl.$invalid && scope.formCtrl.$error.valServer !== undefined)) {
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
}
}, true);
//listen for server validation changes
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
// validation changes to fields in the property this is because some server side validators may not
// return the field name for which the error belongs too, just the property for which it belongs.
// It's important to note that we need to subscribe to server validation changes here because we always must
// indicate that a content property is invalid at the property level since developers may not actually implement
// the correct field validation in their property editors.
if (scope.property) { //this can be null if no property was assigned
serverValidationManager.subscribe(scope.property.alias, "", function(isValid, propertyErrors, allErrors) {
hasError = !isValid;
if (hasError) {
//set the error message to the server message
scope.errorMsg = propertyErrors[0].errorMsg;
//flag that the current validator is invalid
formCtrl.$setValidity('valPropertyMsg', false);
}
else {
scope.errorMsg = "";
//flag that the current validator is valid
formCtrl.$setValidity('valPropertyMsg', true);
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function() {
serverValidationManager.unsubscribe(scope.property.alias, "");
});
}
}
};
}
angular.module('umbraco.directives').directive("valPropertyMsg", valPropertyMsg);

View File

@@ -1,45 +1,45 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valRegex
* @restrict A
* @description A custom directive to allow for matching a value against a regex string.
* 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 regex;
try {
regex = new RegExp(scope.$eval(attrs.valRegex));
}
catch(e) {
regex = new RegExp(attrs.valRegex);
}
var patternValidator = function (viewValue) {
//NOTE: we don't validate on empty values, use required validator for that
if (!viewValue || regex.test(viewValue)) {
// it is valid
ctrl.$setValidity('valRegex', true);
//assign a message to the validator
ctrl.errorMsg = "";
return viewValue;
}
else {
// it is invalid, return undefined (no model update)
ctrl.$setValidity('valRegex', false);
//assign a message to the validator
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
return undefined;
}
};
ctrl.$formatters.push(patternValidator);
ctrl.$parsers.push(patternValidator);
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valRegex
* @restrict A
* @description A custom directive to allow for matching a value against a regex string.
* 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 regex;
try {
regex = new RegExp(scope.$eval(attrs.valRegex));
}
catch(e) {
regex = new RegExp(attrs.valRegex);
}
var patternValidator = function (viewValue) {
//NOTE: we don't validate on empty values, use required validator for that
if (!viewValue || regex.test(viewValue)) {
// it is valid
ctrl.$setValidity('valRegex', true);
//assign a message to the validator
ctrl.errorMsg = "";
return viewValue;
}
else {
// it is invalid, return undefined (no model update)
ctrl.$setValidity('valRegex', false);
//assign a message to the validator
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
return undefined;
}
};
ctrl.$formatters.push(patternValidator);
ctrl.$parsers.push(patternValidator);
}
};
}
angular.module('umbraco.directives').directive("valRegex", valRegex);

View File

@@ -1,63 +1,63 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valServer
* @restrict A
* @description This directive is used to associate a content property with a server-side validation response
* so that the validators in angular are updated based on server-side feedback.
**/
function valServer(serverValidationManager) {
return {
require: 'ngModel',
restrict: "A",
link: function (scope, element, attr, ctrl) {
if (!scope.model || !scope.model.alias){
throw "valServer can only be used in the scope of a content property object";
}
var currentProperty = scope.model;
//default to 'value' if nothing is set
var fieldName = "value";
if (attr.valServer) {
fieldName = scope.$eval(attr.valServer);
if (!fieldName) {
//eval returned nothing so just use the string
fieldName = attr.valServer;
}
}
//subscribe to the changed event of the view model. This is required because when we
// have a server error we actually invalidate the form which means it cannot be
// resubmitted. 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.
ctrl.$viewChangeListeners.push(function () {
if (ctrl.$invalid) {
ctrl.$setValidity('valServer', true);
}
});
//subscribe to the server validation changes
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
if (!isValid) {
ctrl.$setValidity('valServer', false);
//assign an error msg property to the current validator
ctrl.errorMsg = propertyErrors[0].errorMsg;
}
else {
ctrl.$setValidity('valServer', true);
//reset the error message
ctrl.errorMsg = "";
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function () {
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valServer
* @restrict A
* @description This directive is used to associate a content property with a server-side validation response
* so that the validators in angular are updated based on server-side feedback.
**/
function valServer(serverValidationManager) {
return {
require: 'ngModel',
restrict: "A",
link: function (scope, element, attr, ctrl) {
if (!scope.model || !scope.model.alias){
throw "valServer can only be used in the scope of a content property object";
}
var currentProperty = scope.model;
//default to 'value' if nothing is set
var fieldName = "value";
if (attr.valServer) {
fieldName = scope.$eval(attr.valServer);
if (!fieldName) {
//eval returned nothing so just use the string
fieldName = attr.valServer;
}
}
//subscribe to the changed event of the view model. This is required because when we
// have a server error we actually invalidate the form which means it cannot be
// resubmitted. 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.
ctrl.$viewChangeListeners.push(function () {
if (ctrl.$invalid) {
ctrl.$setValidity('valServer', true);
}
});
//subscribe to the server validation changes
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
if (!isValid) {
ctrl.$setValidity('valServer', false);
//assign an error msg property to the current validator
ctrl.errorMsg = propertyErrors[0].errorMsg;
}
else {
ctrl.$setValidity('valServer', true);
//reset the error message
ctrl.errorMsg = "";
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function () {
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
});
}
};
}
angular.module('umbraco.directives').directive("valServer", valServer);

View File

@@ -1,54 +1,54 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valServerField
* @restrict A
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
* so that the validators in angular are updated based on server-side feedback.
**/
function valServerField(serverValidationManager) {
return {
require: 'ngModel',
restrict: "A",
link: function (scope, element, attr, ctrl) {
if (!attr.valServerField) {
throw "valServerField must have a field name for referencing server errors";
}
var fieldName = attr.valServerField;
//subscribe to the changed event of the view model. This is required because when we
// have a server error we actually invalidate the form which means it cannot be
// resubmitted. 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.
ctrl.$viewChangeListeners.push(function () {
if (ctrl.$invalid) {
ctrl.$setValidity('valServerField', true);
}
});
//subscribe to the server validation changes
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
if (!isValid) {
ctrl.$setValidity('valServerField', false);
//assign an error msg property to the current validator
ctrl.errorMsg = fieldErrors[0].errorMsg;
}
else {
ctrl.$setValidity('valServerField', true);
//reset the error message
ctrl.errorMsg = "";
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function () {
serverValidationManager.unsubscribe(null, fieldName);
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valServerField
* @restrict A
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
* so that the validators in angular are updated based on server-side feedback.
**/
function valServerField(serverValidationManager) {
return {
require: 'ngModel',
restrict: "A",
link: function (scope, element, attr, ctrl) {
if (!attr.valServerField) {
throw "valServerField must have a field name for referencing server errors";
}
var fieldName = attr.valServerField;
//subscribe to the changed event of the view model. This is required because when we
// have a server error we actually invalidate the form which means it cannot be
// resubmitted. 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.
ctrl.$viewChangeListeners.push(function () {
if (ctrl.$invalid) {
ctrl.$setValidity('valServerField', true);
}
});
//subscribe to the server validation changes
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
if (!isValid) {
ctrl.$setValidity('valServerField', false);
//assign an error msg property to the current validator
ctrl.errorMsg = fieldErrors[0].errorMsg;
}
else {
ctrl.$setValidity('valServerField', true);
//reset the error message
ctrl.errorMsg = "";
}
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
// but they are a different callback instance than the above.
element.bind('$destroy', function () {
serverValidationManager.unsubscribe(null, fieldName);
});
}
};
}
angular.module('umbraco.directives').directive("valServerField", valServerField);

View File

@@ -1,32 +1,32 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valShowValidation
* @restrict A
* @description Used to toggle the show-validation class on the element containing the form elements to validate.
* This is used because we don't want to show validation messages until after the form is submitted and then reset
* the process when the form is successful. We do this by listening to the current controller's saving and saved events.
**/
function valShowValidation(serverValidationManager) {
return {
restrict: "A",
link: function (scope, element, attr, ctrl) {
//we should show validation if there are any msgs in the server validation collection
if (serverValidationManager.items.length > 0) {
element.addClass("show-validation");
}
//listen for the forms saving event
scope.$on("saving", function (ev, args) {
element.addClass("show-validation");
});
//listen for the forms saved event
scope.$on("saved", function (ev, args) {
element.removeClass("show-validation");
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valShowValidation
* @restrict A
* @description Used to toggle the show-validation class on the element containing the form elements to validate.
* This is used because we don't want to show validation messages until after the form is submitted and then reset
* the process when the form is successful. We do this by listening to the current controller's saving and saved events.
**/
function valShowValidation(serverValidationManager) {
return {
restrict: "A",
link: function (scope, element, attr, ctrl) {
//we should show validation if there are any msgs in the server validation collection
if (serverValidationManager.items.length > 0) {
element.addClass("show-validation");
}
//listen for the forms saving event
scope.$on("saving", function (ev, args) {
element.addClass("show-validation");
});
//listen for the forms saved event
scope.$on("saved", function (ev, args) {
element.removeClass("show-validation");
});
}
};
}
angular.module('umbraco.directives').directive("valShowValidation", valShowValidation);

View File

@@ -1,40 +1,40 @@
/**
* @ngdoc directive
* @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.
**/
function valTab() {
return {
require: "^form",
restrict: "A",
link: function (scope, element, attr, formCtrl) {
var tabId = "tab" + scope.tab.id;
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
scope.tabHasError = false;
//watch the current form's validation for the current field name
scope.$watch("formCtrl.$valid", function () {
var tabContent = element.closest(".umb-panel").find("#" + tabId);
if (formCtrl.$invalid) {
//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 {
scope.tabHasError = false;
}
});
}
};
}
/**
* @ngdoc directive
* @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.
**/
function valTab() {
return {
require: "^form",
restrict: "A",
link: function (scope, element, attr, formCtrl) {
var tabId = "tab" + scope.tab.id;
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
scope.tabHasError = false;
//watch the current form's validation for the current field name
scope.$watch("formCtrl.$valid", function () {
var tabContent = element.closest(".umb-panel").find("#" + tabId);
if (formCtrl.$invalid) {
//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 {
scope.tabHasError = false;
}
});
}
};
}
angular.module('umbraco.directives').directive("valTab", valTab);

View File

@@ -1,64 +1,64 @@
function valToggleMsg(serverValidationManager) {
return {
require: "^form",
restrict: "A",
/**
Our directive requries a reference to a form controller which gets passed in to this parameter
*/
link: function (scope, element, attr, formCtrl) {
if (!attr.valToggleMsg){
throw "valToggleMsg requires that a reference to a validator is specified";
}
if (!attr.valMsgFor){
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
}
if (!formCtrl[attr.valMsgFor]) {
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
}
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
//if there's any remaining errors in the server validation service then we should show them.
var showValidation = serverValidationManager.items.length > 0;
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
scope.$watch("formCtrl." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function () {
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
element.show();
}
else {
element.hide();
}
});
scope.$on("saving", function(ev, args) {
showValidation = true;
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
element.show();
}
else {
element.hide();
}
});
scope.$on("saved", function (ev, args) {
showValidation = false;
element.hide();
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valToggleMsg
* @restrict A
* @element input
* @requires formController
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
**/
function valToggleMsg(serverValidationManager) {
return {
require: "^form",
restrict: "A",
/**
Our directive requries a reference to a form controller which gets passed in to this parameter
*/
link: function (scope, element, attr, formCtrl) {
if (!attr.valToggleMsg){
throw "valToggleMsg requires that a reference to a validator is specified";
}
if (!attr.valMsgFor){
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
}
if (!formCtrl[attr.valMsgFor]) {
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
}
//assign the form control to our isolated scope so we can watch it's values
scope.formCtrl = formCtrl;
//if there's any remaining errors in the server validation service then we should show them.
var showValidation = serverValidationManager.items.length > 0;
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
scope.$watch("formCtrl." + attr.valMsgFor + ".$error." + attr.valToggleMsg, function () {
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
element.show();
}
else {
element.hide();
}
});
scope.$on("saving", function(ev, args) {
showValidation = true;
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
element.show();
}
else {
element.hide();
}
});
scope.$on("saved", function (ev, args) {
showValidation = false;
element.hide();
});
}
};
}
/**
* @ngdoc directive
* @name umbraco.directives.directive:valToggleMsg
* @restrict A
* @element input
* @requires formController
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
**/
angular.module('umbraco.directives').directive("valToggleMsg", valToggleMsg);

View File

@@ -263,6 +263,38 @@ function entityResource($q, $http, umbRequestHelper) {
'Failed to retreive document data for ids ' + idQuery);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#searchDocuments
* @methodOf umbraco.resources.entityResource
*
* @description
* Gets an array of content entities, given a query
*
* ##usage
* <pre>
* entityResource.searchDocuments("news")
* .then(function(contentArray) {
* var myDoc = contentArray;
* alert('they are here!');
* });
* </pre>
*
* @param {String} Query search query
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
searchDocuments: function (query) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"SearchDocuments",
query)),
'Failed to retreive document data for query ' + query);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#getMediaById
@@ -329,8 +361,40 @@ function entityResource($q, $http, umbRequestHelper) {
"GetMediaByIds",
idQuery)),
'Failed to retreive media data for ids ' + idQuery);
},
/**
* @ngdoc method
* @name umbraco.resources.entityResource#searchMedia
* @methodOf umbraco.resources.entityResource
*
* @description
* Gets an array of medoa entities, given a query
*
* ##usage
* <pre>
* entityResource.searchMedia("news")
* .then(function(mediaArray) {
* var myDoc = mediaArray;
* alert('they are here!');
* });
* </pre>
*
* @param {String} Query search query
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
searchMedia: function (query) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"SearchMedia",
query)),
'Failed to retreive media data for query ' + query);
}
};
}

View File

@@ -68,6 +68,36 @@ function userResource($q, $http, umbRequestHelper) {
"userApiBaseUrl",
"GetAll")),
'Failed to retreive all users');
},
/**
* @ngdoc method
* @name umbraco.resources.userResource#changePassword
* @methodOf umbraco.resources.userResource
*
* @description
* Changes the current users password
*
* ##usage
* <pre>
* contentResource.getAll()
* .then(function(userArray) {
* var myUsers = userArray;
* alert('they are here!');
* });
* </pre>
*
* @returns {Promise} resourcePromise object containing the user array.
*
*/
changePassword: function (oldPassword, newPassword) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"userApiBaseUrl",
"PostChangePassword"),
{ oldPassword: oldPassword, newPassword: newPassword }),
'Failed to change password');
}
};
}

View File

@@ -101,13 +101,15 @@ angular.module('umbraco.services')
};
scope.close = function(data) {
if (dialog.closeCallback) {
if (dialog.closeCallback) {
dialog.closeCallback(data);
}
}
dialog.element.modal('hide');
dialog.element.remove();
$("#" + dialog.element.attr("id")).remove();
if(dialog.element){
dialog.element.modal('hide');
dialog.element.remove();
$("#" + dialog.element.attr("id")).remove();
}
};
//if iframe is enabled, inject that instead of a template
@@ -260,8 +262,10 @@ angular.module('umbraco.services')
* @param {Object} args if specified this object will be sent to any callbacks registered on the dialogs.
*/
close: function (dialog, args) {
dialog.scope.close();
if(dialog && dialog.scope){
dialog.scope.close();
}
//removeDialog(dialog, args);
},
@@ -323,7 +327,7 @@ angular.module('umbraco.services')
*
* @description
* Opens a mcaro picker in a modal, the callback returns a object representing the macro and it's parameters
* @param {Object} options mediapicker dialog options object
* @param {Object} options macropicker dialog options object
* @param {$scope} options.scope dialog scope
* @param {Function} options.callback callback function
* @returns {Object} modal object
@@ -334,6 +338,44 @@ angular.module('umbraco.services')
return openDialog(options);
},
/**
* @ngdoc method
* @name umbraco.services.dialogService#iconPicker
* @methodOf umbraco.services.dialogService
*
* @description
* Opens a icon picker in a modal, the callback returns a object representing the selected icon
* @param {Object} options iconpicker dialog options object
* @param {$scope} options.scope dialog scope
* @param {Function} options.callback callback function
* @returns {Object} modal object
*/
iconPicker: function (options) {
options.template = 'views/common/dialogs/iconPicker.html';
options.show = true;
return openDialog(options);
},
/**
* @ngdoc method
* @name umbraco.services.dialogService#treePicker
* @methodOf umbraco.services.dialogService
*
* @description
* Opens a tree picker in a modal, the callback returns a object representing the selected tree item
* @param {Object} options iconpicker dialog options object
* @param {$scope} options.scope dialog scope
* @param {$scope} options.section tree section 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
*/
treePicker: function (options) {
options.template = 'views/common/dialogs/treePicker.html';
options.show = true;
return openDialog(options);
},
/**
* @ngdoc method
* @name umbraco.services.dialogService#propertyDialog
@@ -354,6 +396,19 @@ angular.module('umbraco.services')
return openDialog(options);
},
/**
* @ngdoc method
* @name umbraco.services.dialogService#ysodDialog
* @methodOf umbraco.services.dialogService
*
* @description
* Opens a dialog to an embed dialog
*/
embedDialog: function (options) {
options.template = 'views/common/dialogs/rteembed.html';
options.show = true;
return openDialog(options);
},
/**
* @ngdoc method
* @name umbraco.services.dialogService#ysodDialog

View File

@@ -114,7 +114,7 @@ angular.module('umbraco.services')
* @param {string} sectionAlias The alias of the section the tree should load data from
*/
showTree: function (sectionAlias) {
if (!this.ui.stickyNavigation && sectionAlias !== this.ui.currentSection) {
if (sectionAlias !== this.ui.currentSection) {
this.ui.currentSection = sectionAlias;
setMode("tree");
}
@@ -346,7 +346,7 @@ angular.module('umbraco.services')
var dialog = dialogService.open(
{
container: $("#dialog div.umb-panel-body"),
container: $("#dialog div.umb-modalcolumn-body"),
scope: scope,
inline: true,
show: true,

View File

@@ -72,7 +72,6 @@ angular.module('umbraco.services')
},
logout: function () {
return authResource.performLogout()
.then(function (data) {
currentUser = null;

View File

@@ -11,6 +11,19 @@
margin-left: 0px !Important;
}
small.umb-detail,
label small {
color: #b3b3b3 !important;
text-decoration: none;
display: block;
font-weight: normal
}
label.control-label {
padding-top: 8px !important;
}
.controls-row label{padding: 0px 10px 0px 10px; vertical-align: center}
//utill styll to hide child untill hover
.hover-show{visibility: hidden;}
*:hover > .hover-show{visibility: visible;}
@@ -436,10 +449,13 @@ input[type="checkbox"][readonly] {
}
}
//non-html5 states, pp: added default ng-invalid class
input.highlight-error,
select.highlight-error,
textarea.highlight-error {
textarea.highlight-error,
input.ng-dirty.ng-invalid,
select.ng-dirty.ng-invalid,
textarea.ng-dirty.ng-invalid{
border-color: #953b39 !important;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;

View File

@@ -25,9 +25,6 @@ body {
padding: 20px
}
.fill {
height: 100%
}
#layout {
position: relative;
@@ -42,19 +39,17 @@ body {
margin: 0;
}
#contentwrapper {
height: 100%;
#contentwrapper, #contentcolumn {
position: absolute;
top: 0px; bottom: 0px; right: 0px; left: 80px;
z-index: 10;
margin: 0
}
#contentcolumn {
position: relative;
margin-left: 80px;
z-index: 10;
height: 100%;}
left: 0px;
}
.content-column-body{height: 100%;}
#contentcolumn iframe {
display: block;
position: relative;
@@ -121,20 +116,16 @@ body {
#tree {
padding: 0px;
position: relative;
z-index: 100 !important;
height: 100%;
overflow: auto;
}
#tree .umb-tree {
padding: 15px 0px 20px 0px;
padding: 0px 0px 20px 0px;
}
#search-results {
position: relative;
z-index: 100;
padding: 15px 0px 20px 0px;
z-index: 200;
}
#contextMenu {

View File

@@ -146,17 +146,7 @@ div.umb-codeeditor .umb-btn-toolbar {
margin: auto
}
small.umb-detail,
label small {
color: #b3b3b3 !important;
text-decoration: none;
display: block;
font-weight: normal
}
label {
padding-top: 8px !important;
}
/* FORM GRID */

View File

@@ -3,44 +3,54 @@
/* Modalcolumn is used for menu panels */
.umb-modalcolumn {
background: #fff;
background: white;
border-left: #f6f6f6 1px solid;
}
.umb-modalcolumn .umb-panel-header {
white-space: nowrap
}
.umb-modalcolumn .umb-panel-body {
padding: 0px
.umb-modalcolumn-header {
background: @grayLighter;
border-bottom: 1px solid @grayLight;
height: 79px;
padding: 20px 20px 0px 20px;
}
.no-padding .umb-panel-body {
.umb-modalcolumn-header h1{
margin: 0;
font-size: @fontSizeLarge;
font-weight: 400;
padding-top: 10px !important;
text-transform: capitalize !important;
}
.umb-modalcolumn-body {
padding: 0px;
background: white;
top: 101px;
position: absolute;
left: 0px;
right: 0px;
bottom: 0px;
}
.no-padding .umb-modalcolumn-body {
padding: 0px
}
.umb-modalcolumn .umb-panel-header .btn {
.umb-modalcolumn .umb-modalcolumn-header .btn {
position: absolute;
top: 13px;
right: 15px
}
.umb-modalcolumn .umb-modal-close-icon {
position: absolute;
top: 17px;
left: 27px;
}
.umb-modalcolumn .umb-modal-close-icon i {
background: url(close.png);
width: 18px;
height: 18px
}
.umb-modalcolumn iframe {
border: none;
padding: 0px;
margin: 0px;
}
.umb-modalcolumn h1 {
padding-top: 10px !important;
text-transform: capitalize !important;
}
/* umb.dialog is used for the dialogs on the conent tree*/
@@ -131,7 +141,7 @@
.umb-modal .thumbnail {
.umb-thumbnails .thumbnail {
padding: 0;
border:none;
}
@@ -140,43 +150,46 @@
margin: 0 0 20px 0
}*/
.umb-modal .thumbnails > li {
.umb-thumbnails > li {
margin: 0 20px 20px 0;
text-align: center;
}
.umb-modal .thumbnail img {
/*height: 100px;*/
}
.umb-thumbnails i{margin: auto;}
.umb-modal .thumbnails .selected img, .umb-modal .thumbnails img:hover {
.umb-thumbnails .selected img, .umb-thumbnails img:hover {
opacity: 0.5
}
.umb-modal .thumbnails > li.folder {
.umb-thumbnails > li.folder {
width: 100px;
/*height: 100px;*/
display: block;
background: @grayLighter;
text-align: center;
font-size: 12px
font-size: 12px;
}
.umb-modal .thumbnails > li.folder .icon-folder{
color: @grayLight;
.umb-thumbnails a{
outline: none;
border:none !important;
box-shadow:none !important;
}
.umb-thumbnails > li.folder .icon-folder{
display: block;
font-size: 90px;
height: 75px;
width:100px;
color: @grayLight;
}
.umb-modal .thumbnails > li.folder a {
.umb-thumbnails > li.folder a {
width: 100px;
height: 100px;
display: block
}
.umb-modal .thumbnails > li.folder a:hover {
.umb-thumbnails > li.folder a:hover {
text-decoration: none
}

View File

@@ -1,15 +1,30 @@
// Panel
// -------------------------
.umb-panel{background: white;}
.umb-panel{
background: white;
position: absolute;
top: 0px; bottom: 0px; left: 0px; right: 0px;}
.umb-panel-nobody{padding-top: 100px;}
.umb-panel-header {
height: 79px;
padding: 20px 20px 0px 20px;
background: @grayLighter;
border-bottom: 1px solid @grayLight;
height: 79px;
position: absolute;
height: 99px;
top: 0px;
right: 0px;
left: 0px;
}
.umb-panel-body {
top: 101px;
left: 0px;
right: 0px;
bottom: 20px;
position: relative;
clear: both;
}
.umb-panel-header h1.umb-headline-editor {
cursor: text;
@@ -18,20 +33,31 @@
.umb-panel-header h1.umb-headline-editor {
cursor: text;
}
.umb-headline-editor-wrapper,
h1.headline{height: 40px; padding: 30px 0 0 20px;}
.umb-headline-editor-wrapper{height: 50px;}
.umb-headline-editor-wrapper h1, h1.headline {
margin: 0;
font-size: @fontSizeLarge;
font-weight: 400;
text-align: left;
}
.umb-headline-editor-wrapper .help-inline{display: none !Important;}
.umb-headline-editor-wrapper.error h1{
border-bottom: 1px dashed @red; color: @red; cursor: pointer;
};
.umb-panel-header .umb-nav-tabs{
bottom: -1px;
position: absolute;
padding: 0px 0px 0px 20px;
}
.umb-panel-header h1, {
margin: 0;
font-size: @fontSizeLarge;
font-weight: 400;
color: @gray;
padding: 4px 0px 4px 6px;
line-height: 22px;
width: 100%;
}
@@ -61,11 +87,10 @@
.umb-panel-header .umb-btn-toolbar {
float: right;
padding: 20px 20px 0 0;
}
.umb-panel-body {
clear: both;
}
.umb-panel-footer {
margin: 0;

View File

@@ -111,14 +111,15 @@
cursor: pointer
}
.umb-tree ins:before {
font-size: 11px;
.umb-tree ins {
font-size: 12px;
}
.umb-tree .icon {
vertical-align: middle;
margin: 1px 13px 1px 0px;
color: #414141
color: #414141;
font-size: 15px;
}
.umb-tree i.noSpr {
display: inline-block;
@@ -448,7 +449,7 @@ height:1px;
}
body.touch .umb-tree .icon{font-size: 17px;}
body.touch .umb-tree ins{font-size: 20px; visibility: visible; padding: 7px;}
body.touch .umb-tree ins{font-size: 14px; visibility: visible; padding: 7px;}
body.touch .umb-tree li div {
padding-top: 8px;
padding-bottom: 8px;

View File

@@ -2,7 +2,7 @@
<umb-panel val-show-validation>
<umb-header tabs="dashboard.tabs">
<div class="umb-headline-editor-wrapper span12">
<h1 class="headline">{{dashboard.name}}</h1>
<h1>{{dashboard.name}}</h1>
</div>
</umb-header>
<umb-tab-view>

View File

@@ -17,7 +17,7 @@
<div class="umb-panel-body umb-scrollable" auto-scale="0">
<div class="umb-control-group">
<ul class="thumbnails">
<ul class="umb-thumbnails thumbnails">
<li class="span1" ng-repeat="icon in icons|filter: searchTerm">
<a href="#" title="{{icon}}" class="thumbnail" ng-click="submit(icon)" prevent-default>
<i class="{{icon}} large" style="font-size: 32px"></i>

View File

@@ -53,9 +53,10 @@ data-file-upload="options" data-file-upload-progress="" data-ng-class="{'fileupl
</ul>
</div>
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader" ng-hide="active() == 0"></div>
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader"
ng-hide="active() == 0"></div>
<ul class="thumbnails">
<ul class="umb-thumbnails thumbnails">
<li class="span2 folder" ng-repeat="image in images | orderBy:'contentTypeAlias' | filter:searchTerm">
<a href="#" class="thumbnail" ng-class="{selected: dialogData.selection.indexOf(image) > -1}"
ng-click="selectMediaItem(image)"

View File

@@ -0,0 +1,33 @@
angular.module("umbraco").controller("Umbraco.Dialogs.RteEmbedController", function ($scope, $http) {
$scope.url = "";
$scope.width = 500;
$scope.height = 300;
$scope.constrain = true;
$scope.preview = "";
$scope.success = false;
$scope.preview = function(){
if ($scope.url != "") {
$scope.preview = "<div class=\"umb-loader\">";
$scope.success = false;
$http({ method: 'GET', url: '/umbraco/UmbracoApi/RteEmbed/GetEmbed', params: { url: $scope.url, width: $scope.width, height: $scope.height } })
.success(function(data) {
$scope.preview = data.Markup;
$scope.success = true;
})
.error(function() {
$scope.preview = "";
});
}
};
$scope.insert = function(){
$scope.submit($scope.preview);
};
});

View File

@@ -0,0 +1,30 @@
<div class="umb-panel" ng-controller="Umbraco.Dialogs.RteEmbedController">
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar">
<input type="button" ng-click="insert()" class="btn btn-primary" value="Insert" ng-disabled="!success" />
</div>
</div>
</div>
<div class="umb-panel-body umb-scrollable" auto-scale="1">
<div class="umb-panel">
<div class="umb-control-group">
<label for="url">Url</label>
<input id="url" type="text" ng-model="url" ng-change="preview()"/>
<label>Size:</label>
<input type="text" ng-model="width"/> x <input type="text" ng-model="height" />
<label for="constrain">Constrain:</label>
<input id="constrain" type="checkbox" ng-model="constrain"/>
<div ng-bind-html-unsafe="preview">
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,26 @@
//used for the media picker dialog
angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
function ($scope, eventsService, $log) {
var dialogOptions = $scope.$parent.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$scope.section = dialogOptions.section | "content";
$scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.TreePickerController.Select", args).then(function(args){
if(dialogOptions && dialogOptions.multipicker){
$(args.event.target.parentElement)
.find("i.umb-tree-icon")
.attr("class", "icon umb-tree-icon sprTree icon-check blue");
$scope.select(args.node);
}else{
$scope.submit(args.node);
}
});
});
});

View File

@@ -0,0 +1,23 @@
<div class="umb-panel" ng-controller="Umbraco.Dialogs.TreePickerController">
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar">
<input type="button" ng-click="submit(dialogData)" class="btn btn-primary" value="select" />
</div>
</div>
</div>
<div class="umb-panel-body umb-scrollable">
<div class="tab-content umb-control-group">
<div class="umb-pane">
<umb-tree
section="{{section}}"
cachekey="contentpickerDialog"
showheader="false"
showoptions="false"
eventhandler="dialogTreeEventHandler">
</umb-tree>
</div>
</div>
</div>
</div>

View File

@@ -10,8 +10,7 @@
<small>{{user.email}}</small>
</div>
<div class="umb-panel-body umb-scrollable" auto-scale="1">
<div class="umb-panel-body umb-scrollable">
<div class="tab-content umb-control-group">
<div class="umb-pane">
<h5>Your profile</h5>

View File

@@ -0,0 +1,49 @@
<form name="passwordForm" ng-controller="Umbraco.Dashboard.StartupChangePasswordController">
<h3>Change password</h3>
<p>Enter your current password, then repeat your new password to change it</p>
<umb-pane>
<umb-control-group label="Old password">
<input type="password" name="oldpass" ng-model="profile.oldPassword" required/>
<small class="help-inline"
ng-show="passwordForm.oldpass.$error.required">
Required
</small>
<small class="help-inline"
ng-show="passwordForm.passcompare.$error.serverside">
Old password was not correct
</small>
</umb-control-group>
<umb-control-group label="New password">
<input type="password" name="pass" ng-model="profile.newPassword" required/>
<span class="help-inline" val-msg-for="pass" val-toggle-msg="required">Required</span>
</umb-control-group>
<umb-control-group label="Repeat new password">
<input type="password" name="passcompare"
val-custom="{compare: '$value === profile.newPassword'}"
val-custom-watch="'profile.newPassword'"
ng-model="profile.repeatNewPassword" required/>
<small class="help-inline"
ng-show="passwordForm.passcompare.$error.required">
Required
</small>
<small class="help-inline"
ng-show="passwordForm.passcompare.$error.compare">
You must re-enter the new password
</small>
</umb-control-group>
<umb-control-group hideLabel="1">
<button class="btn btn-primary"
ng-click="changePassword(profile)">Change</button>
</umb-control-group>
</umb-pane>
</form>

View File

@@ -1,6 +1,4 @@
function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
//xmlHelper.parseFeed("http://umbraco.org/feeds/videos/getting-started").then(function(feed){
//});
@@ -16,5 +14,22 @@ function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
});
});
}
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
function ChangePasswordDashboardController($scope, xmlhelper, $log, userResource) {
//this is the model we will pass to the service
$scope.profile = {};
$scope.changePassword = function (p) {
userResource.changePassword(p.oldPassword, p.newPassword).then(function () {
alert("changed");
$scope.passwordForm.$setValidity(true);
}, function () {
alert("not changed");
//this only happens if there is a wrong oldPassword sent along
$scope.passwordForm.oldpass.$setValidity("oldPassword", false);
});
}
}
angular.module("umbraco").controller("Umbraco.Dashboard.StartupChangePasswordController", ChangePasswordDashboardController);

View File

@@ -25,7 +25,7 @@
</div>
</umb-header>
<div class="umb-panel-body umb-scrollable row-fluid" auto-scale="1">
<div class="umb-panel-body umb-scrollable row-fluid">
<div class="tab-content form-horizontal">
<div class="umb-pane">

View File

@@ -0,0 +1,13 @@
<div class="umb-property">
<div class="control-group umb-control-group" ng-class="{hidelabel:hideLabel, error: propertyForm.$invalid}" >
<div class="umb-el-wrap">
<label class="control-label" ng-hide="hideLabel" for="{{alias}}">
{{label}}
<small>{{description}}</small>
</label>
<div class="controls controls-row" ng-transclude>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<div class="umb-pane" ng-transclude>
</div>

View File

@@ -1,3 +1,3 @@
<div class="umb-panel tabbable" ng-transclude>
</div>
<div class="umb-panel tabbable" ng-transclude>
</div>

View File

@@ -1,12 +1,12 @@
<div id='contextMenu' class="umb-modalcolumn fill shadow umb-panel"
<div id='contextMenu' class="umb-modalcolumn fill shadow"
ng-swipe-left="nav.hideMenu()"
ng-show="nav.ui.showContextMenu" ng-animate="'slide'">
<div class='umb-panel-header'>
<div class='umb-modalcolumn-header'>
<h1>{{nav.ui.dialogTitle}}</h1>
</div>
<div class='umb-panel-body'>
<div class='umb-modalcolumn-body'>
<ul class="umb-actions">
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in nav.ui.actions">
<a prevent-default

View File

@@ -29,14 +29,15 @@
</div>
<!-- navigation container -->
<div id="navigation" class="fill shadow umb-panel umb-modalcolumn"
<div id="navigation" class="fill shadow umb-modalcolumn"
ng-show="nav.ui.showNavigation"
ng-animate="'slide'">
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6">
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6" style="z-index: 100">
<!-- the search -->
<div id="search-form" ng-animate="'slide'">
<div class="umb-panel-header">
<div id="search-form">
<div class="umb-modalcolumn-header">
<form class="form-search" ng-controller="Umbraco.SearchController" novalidate>
<i class="icon-search"></i>
<input type="text"
@@ -50,7 +51,8 @@
</div>
<!-- Search results -->
<div id="search-results" class="umb-panel fill" ng-show="nav.ui.showSearchResults" ng-animate="'slide'">
<div id="search-results" class="umb-modalcolumn-body"
ng-show="nav.ui.showSearchResults">
<h5 class="umb-tree-header">Search results</h5>
<ul class="umb-item-list" ng-repeat="resultGroup in nav.ui.searchResults">
@@ -68,23 +70,23 @@
<!-- the tree -->
<div id="tree" class="umb-panel fill" ng-animate="'slide'">
<div id="tree" class="umb-modalcolumn-body">
<umb-tree eventhandler="treeEventHandler" section="{{nav.ui.currentSection}}" ></umb-tree>
</div>
</div>
<div class="offset6">
<div class="offset6" style="z-index: 10">
<!-- The context menu -->
<umb-context-menu></umb-context-menu>
<!-- Tree dialogs -->
<div id="dialog" class='umb-modalcolumn fill shadow umb-panel'
<div id="dialog" class='umb-modalcolumn fill shadow'
ng-swipe-left="nav.hideDialog()"
ng-show="nav.ui.showContextMenuDialog" ng-animate="'slide'">
<div class='umb-panel-header'>
<div class='umb-modalcolumn-header'>
<h1>{{nav.ui.dialogTitle}}</h1>
</div>
<div class='umb-panel-body'>
<div class='umb-modalcolumn-body'>
</div>
</div>
</div>

View File

@@ -1,3 +0,0 @@
<div class="umb-pane">
</div>

View File

@@ -0,0 +1,31 @@
angular.module("umbraco")
.controller("Umbraco.Editors.FolderBrowserController",
function ($rootScope, $scope, assetsService, $routeParams, umbRequestHelper, mediaResource, imageHelper) {
var dialogOptions = $scope.$parent.dialogOptions;
$scope.options = {
url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"),
autoUpload: true,
formData:{
currentFolder: $routeParams.id
}
};
$scope.loadChildren = function(id){
mediaResource.getChildren(id)
.then(function(data) {
$scope.images = data;
//update the thumbnail property
_.each($scope.images, function(img) {
img.thumbnail = imageHelper.getThumbnail({ imageModel: img, scope: $scope });
});
});
};
$scope.$on('fileuploadstop', function(event, files){
$scope.loadChildren($scope.options.formData.currentFolder);
});
//init load
$scope.loadChildren($routeParams.id);
}
);

View File

@@ -0,0 +1,27 @@
<form ng-controller="Umbraco.Editors.FolderBrowserController" id="fileupload"
method="POST" enctype="multipart/form-data"
data-file-upload="options" data-file-upload-progress="" data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
<div style="height: 10px; margin: 10px 0px 10px 0px" class="umb-loader"
ng-hide="active() == 0"></div>
<ul class="umb-thumbnails thumbnails">
<li class="span2 folder" ng-repeat="image in images | orderBy:'contentTypeAlias' | filter:searchTerm">
<a href="#/media/media/edit/{{image.id}}" class="thumbnail">
<img ng-src="{{image.thumbnail}}" ng-switch-when="Image" alt="{{image.name}}"/>
<div ng-switch on="!!image.thumbnail" >
<img ng-src="{{image.thumbnail}}" class="image" ng-switch-when="true" alt="{{image.name}}"/>
<div ng-switch-default>
<i class="icon-folder large"></i>
{{image.name}}
</div>
</div>
</a>
</li>
</ul>
</div>
</div>
</form>

View File

@@ -11,7 +11,7 @@ angular.module("umbraco")
menubar : false,
statusbar: false,
height: 340,
toolbar: "bold italic | styleselect | alignleft aligncenter alignright | bullist numlist | outdent indent | link image mediapicker iconpicker",
toolbar: "bold italic | styleselect | alignleft aligncenter alignright | bullist numlist | outdent indent | link image mediapicker iconpicker embeddialog",
setup : function(editor) {
@@ -69,7 +69,20 @@ angular.module("umbraco")
editor.insertContent(i);
}});
}
});
});
editor.addButton('embeddialog', {
icon: 'media',
tooltip: 'Embed',
onclick: function () {
dialogService.embedDialog({
scope: $scope, callback: function (data) {
editor.insertContent(data);
}
});
}
});
}
});

View File

@@ -0,0 +1,11 @@
angular.module('umbraco').controller("Umbraco.Editors.UserPickerController",
function($rootScope, $scope, $log, userResource){
userResource.getAll().then(function (userArray) {
$scope.users = userArray;
});
if ($scope.model.value === null || $scope.model.value === undefined) {
$scope.model.value = "";
}
});

View File

@@ -0,0 +1,7 @@
<select
ng-controller="Umbraco.Editors.UserPickerController"
name="{{ model.alias }}"
ng-model=" model.value"
ng-options="user.id as user.name for user in users">
<option value="">Select User</option>
</select>

View File

@@ -14,14 +14,17 @@ describe('notification tests', function () {
var not1 = notifications.success("success", "something great happened");
var not2 = notifications.error("error", "something great happened");
var not3 = notifications.warning("warning", "something great happened");
var not4 = notifications.warning("warning", "");
expect(notifications.getCurrent().length).toBe(3);
expect(notifications.getCurrent().length).toBe(4);
//remove at index 0
notifications.remove(0);
expect(notifications.getCurrent().length).toEqual(2);
expect(notifications.getCurrent()[0].headline).toBe("error");
expect(notifications.getCurrent().length).toEqual(3);
expect(notifications.getCurrent()[0].headline).toBe("error:");
expect(notifications.getCurrent()[1].headline).toBe("warning:");
expect(notifications.getCurrent()[2].headline).toBe("warning");
notifications.removeAll();
expect(notifications.getCurrent().length).toEqual(0);