Merge branch '7.0.0' of https://github.com/umbraco/Umbraco-CMS into 7.0.0

This commit is contained in:
Shannon
2013-11-05 11:36:49 +11:00
9 changed files with 376 additions and 266 deletions

View File

@@ -1,248 +1,241 @@
/**
* @ngdoc controller
* @name Umbraco.Editors.Content.EditController
* @function
*
* @description
* The controller for the content editor
*/
function ContentEditController($scope, $routeParams, $q, $timeout, $window, contentResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper) {
$scope.defaultButton = null;
$scope.subButtons = [];
$scope.nav = navigationService;
//This sets up the action buttons based on what permissions the user has.
//The allowedActions parameter contains a list of chars, each represents a button by permission so
//here we'll build the buttons according to the chars of the user.
function configureButtons(content) {
//reset
$scope.subButtons = [];
//This is the ideal button order but depends on circumstance, we'll use this array to create the button list
// Publish, SendToPublish, Save
var buttonOrder = ["U", "H", "A"];
//Create the first button (primary button)
//We cannot have the Save or SaveAndPublish buttons if they don't have create permissions when we are creating a new item.
if (!$routeParams.create || _.contains(content.allowedActions, "C")) {
for (var b in buttonOrder) {
if (_.contains(content.allowedActions, buttonOrder[b])) {
$scope.defaultButton = createButtonDefinition(buttonOrder[b]);
break;
}
}
}
//Now we need to make the drop down button list, this is also slightly tricky because:
//We cannot have any buttons if there's no default button above.
//We cannot have the unpublish button (Z) when there's no publish permission.
//We cannot have the unpublish button (Z) when the item is not published.
if ($scope.defaultButton) {
//get the last index of the button order
var lastIndex = _.indexOf(buttonOrder, $scope.defaultButton.letter);
//add the remaining
for (var i = lastIndex + 1; i < buttonOrder.length; i++) {
if (_.contains(content.allowedActions, buttonOrder[i])) {
$scope.subButtons.push(createButtonDefinition(buttonOrder[i]));
}
}
//if we are not creating, then we should add unpublish too,
// so long as it's already published and if the user has access to publish
if (!$routeParams.create) {
if (content.publishDate && _.contains(content.allowedActions,"U")) {
$scope.subButtons.push(createButtonDefinition("Z"));
}
}
}
}
function createButtonDefinition(ch) {
switch (ch) {
case "U":
//publish action
return {
letter: ch,
labelKey: "buttons_saveAndPublish",
handler: $scope.saveAndPublish,
hotKey: "ctrl+p"
};
case "H":
//send to publish
return {
letter: ch,
labelKey: "buttons_saveToPublish",
handler: $scope.sendToPublish,
hotKey: "ctrl+t"
};
case "A":
//save
return {
letter: ch,
labelKey: "buttons_save",
handler: $scope.save,
hotKey: "ctrl+s"
};
case "Z":
//unpublish
return {
letter: ch,
labelKey: "content_unPublish",
handler: $scope.unPublish
};
default:
return null;
}
}
/** This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish */
function performSave(args) {
var deferred = $q.defer();
if (formHelper.submitForm({ scope: $scope, statusMessage: args.statusMessage })) {
args.saveMethod($scope.content, $routeParams.create, fileManager.getFiles())
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
configureButtons(data);
navigationService.syncPath(data.path.split(","), true);
deferred.resolve(data);
}, function (err) {
contentEditingHelper.handleSaveError({
redirectOnFailure: true,
err: err,
allNewProps: contentEditingHelper.getAllProps(err.data),
allOrigProps: contentEditingHelper.getAllProps($scope.content)
});
deferred.reject(err);
});
}
else {
deferred.reject();
}
return deferred.promise;
}
if ($routeParams.create) {
//we are creating so get an empty content item
contentResource.getScaffold($routeParams.id, $routeParams.doctype)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
configureButtons($scope.content);
});
}
else {
//we are editing so get the content item from the server
contentResource.getById($routeParams.id)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
configureButtons($scope.content);
//just get the cached version, no need to force a reload
navigationService.syncPath(data.path.split(","), false);
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
// after the redirect, so we will bind all subscriptions which will show the server validation errors
// if there are any and then clear them so the collection no longer persists them.
serverValidationManager.executeAndClearAllSubscriptions();
});
}
$scope.unPublish = function () {
if (formHelper.submitForm({ scope: $scope, statusMessage: "Unpublishing...", skipValidation: true })) {
contentResource.unPublish($scope.content.id)
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
configureButtons(data);
navigationService.syncPath(data.path.split(","), true);
});
}
};
$scope.sendToPublish = function() {
return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
};
$scope.saveAndPublish = function() {
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
};
$scope.save = function () {
return performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
};
$scope.preview = function(content){
if(!content.id){
$scope.save().then(function(data){
$window.open('dialogs/preview.aspx?id='+data.id,'umbpreview');
});
}else{
$window.open('dialogs/preview.aspx?id='+content.id,'umbpreview');
}
};
$scope.options = function (content) {
if (!content.id) {
return;
}
if (!$scope.actions) {
var menuUrl = umbRequestHelper.getApiUrl(
"contentTreeBaseUrl",
"GetMenu",
[{ id: content.id }, { application: "content" }]);
var node = { menuUrl: menuUrl };
treeService.getMenu({ treeNode: node })
.then(function (data) {
$scope.actions = data.menuItems;
});
}
};
/** this method is called for all action buttons and then we proxy based on the btn definition */
$scope.performAction = function(btn) {
if (!btn || !angular.isFunction(btn.handler)) {
throw "btn.handler must be a function reference";
}
btn.handler.apply(this);
};
}
angular.module("umbraco").controller("Umbraco.Editors.Content.EditController", ContentEditController);
/**
* @ngdoc controller
* @name Umbraco.Editors.Content.EditController
* @function
*
* @description
* The controller for the content editor
*/
function ContentEditController($scope, $routeParams, $q, $timeout, $window, contentResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper) {
$scope.defaultButton = null;
$scope.subButtons = [];
$scope.nav = navigationService;
//This sets up the action buttons based on what permissions the user has.
//The allowedActions parameter contains a list of chars, each represents a button by permission so
//here we'll build the buttons according to the chars of the user.
function configureButtons(content) {
//reset
$scope.subButtons = [];
//This is the ideal button order but depends on circumstance, we'll use this array to create the button list
// Publish, SendToPublish, Save
var buttonOrder = ["U", "H", "A"];
//Create the first button (primary button)
//We cannot have the Save or SaveAndPublish buttons if they don't have create permissions when we are creating a new item.
if (!$routeParams.create || _.contains(content.allowedActions, "C")) {
for (var b in buttonOrder) {
if (_.contains(content.allowedActions, buttonOrder[b])) {
$scope.defaultButton = createButtonDefinition(buttonOrder[b]);
break;
}
}
}
//Now we need to make the drop down button list, this is also slightly tricky because:
//We cannot have any buttons if there's no default button above.
//We cannot have the unpublish button (Z) when there's no publish permission.
//We cannot have the unpublish button (Z) when the item is not published.
if ($scope.defaultButton) {
//get the last index of the button order
var lastIndex = _.indexOf(buttonOrder, $scope.defaultButton.letter);
//add the remaining
for (var i = lastIndex + 1; i < buttonOrder.length; i++) {
if (_.contains(content.allowedActions, buttonOrder[i])) {
$scope.subButtons.push(createButtonDefinition(buttonOrder[i]));
}
}
//if we are not creating, then we should add unpublish too,
// so long as it's already published and if the user has access to publish
if (!$routeParams.create) {
if (content.publishDate && _.contains(content.allowedActions,"U")) {
$scope.subButtons.push(createButtonDefinition("Z"));
}
}
}
}
function createButtonDefinition(ch) {
switch (ch) {
case "U":
//publish action
return {
letter: ch,
labelKey: "buttons_saveAndPublish",
handler: $scope.saveAndPublish,
hotKey: "ctrl+p"
};
case "H":
//send to publish
return {
letter: ch,
labelKey: "buttons_saveToPublish",
handler: $scope.sendToPublish,
hotKey: "ctrl+t"
};
case "A":
//save
return {
letter: ch,
labelKey: "buttons_save",
handler: $scope.save,
hotKey: "ctrl+s"
};
case "Z":
//unpublish
return {
letter: ch,
labelKey: "content_unPublish",
handler: $scope.unPublish
};
default:
return null;
}
}
/** This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish */
function performSave(args) {
var deferred = $q.defer();
if (formHelper.submitForm({ scope: $scope, statusMessage: args.statusMessage })) {
args.saveMethod($scope.content, $routeParams.create, fileManager.getFiles())
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
configureButtons(data);
navigationService.syncPath(data.path.split(","), true);
deferred.resolve(data);
}, function (err) {
contentEditingHelper.handleSaveError({
redirectOnFailure: true,
err: err,
allNewProps: contentEditingHelper.getAllProps(err.data),
allOrigProps: contentEditingHelper.getAllProps($scope.content)
});
deferred.reject(err);
});
}
else {
deferred.reject();
}
return deferred.promise;
}
if ($routeParams.create) {
//we are creating so get an empty content item
contentResource.getScaffold($routeParams.id, $routeParams.doctype)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
configureButtons($scope.content);
});
}
else {
//we are editing so get the content item from the server
contentResource.getById($routeParams.id)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;
configureButtons($scope.content);
//just get the cached version, no need to force a reload
navigationService.syncPath(data.path.split(","), false);
//in one particular special case, after we've created a new item we redirect back to the edit
// route but there might be server validation errors in the collection which we need to display
// after the redirect, so we will bind all subscriptions which will show the server validation errors
// if there are any and then clear them so the collection no longer persists them.
serverValidationManager.executeAndClearAllSubscriptions();
});
}
$scope.unPublish = function () {
if (formHelper.submitForm({ scope: $scope, statusMessage: "Unpublishing...", skipValidation: true })) {
contentResource.unPublish($scope.content.id)
.then(function (data) {
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
contentEditingHelper.handleSuccessfulSave({
scope: $scope,
newContent: data,
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
});
configureButtons(data);
navigationService.syncPath(data.path.split(","), true);
});
}
};
$scope.sendToPublish = function() {
return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
};
$scope.saveAndPublish = function() {
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
};
$scope.save = function () {
return performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
};
$scope.preview = function(content){
if(!content.id){
$scope.save().then(function(data){
$window.open('dialogs/preview.aspx?id='+data.id,'umbpreview');
});
}else{
$window.open('dialogs/preview.aspx?id='+content.id,'umbpreview');
}
};
$scope.options = function(content){
if(!content.id){
return;
}
if(!$scope.actions){
treeService.getMenu({ treeNode: $scope.nav.ui.currentTreeNode })
.then(function(data) {
$scope.actions = data.menuItems;
});
}
};
/** this method is called for all action buttons and then we proxy based on the btn definition */
$scope.performAction = function(btn) {
if (!btn || !angular.isFunction(btn.handler)) {
throw "btn.handler must be a function reference";
}
btn.handler.apply(this);
};
}
angular.module("umbraco").controller("Umbraco.Editors.Content.EditController", ContentEditController);

View File

@@ -6,8 +6,9 @@
* @description
* The controller for the content editor
*/
function DataTypeEditController($scope, $routeParams, $location, dataTypeResource, notificationsService, navigationService, angularHelper, serverValidationManager, contentEditingHelper, formHelper) {
function DataTypeEditController($scope, $routeParams, $location, navigationService, treeService, dataTypeResource, notificationsService, navigationService, angularHelper, serverValidationManager, contentEditingHelper, formHelper) {
$scope.nav = navigationService;
//method used to configure the pre-values when we retreive them from the server
function createPreValueProps(preVals) {
$scope.preValues = [];
@@ -84,6 +85,19 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc
}
});
$scope.options = function(content){
if(!content.id){
return;
}
if(!$scope.actions){
treeService.getMenu({ treeNode: $scope.nav.ui.currentTreeNode })
.then(function(data) {
$scope.actions = data.menuItems;
});
}
};
$scope.save = function() {
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {

View File

@@ -16,12 +16,27 @@
<div class="span8">
<div class="btn-toolbar pull-right umb-btn-toolbar">
<div class="btn-group">
<div class="btn-group" ng-class="{dimmed: content.id === 0}">
<!-- options button -->
<a class="btn" href="#" ng-click="options(content)" prevent-default data-toggle="dropdown">
<i class="icon-settings" style="line-height: 14px"></i> Options
</a>
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">Save</button>
</div>
<a class="btn dropdown-toggle" ng-click="options(content)" data-toggle="dropdown">
<span class="caret"></span>
</a>
<!-- actions -->
<ul class="dropdown-menu umb-actions" role="menu" aria-labelledby="dLabel">
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in actions">
<a prevent-default
ng-click="executeMenuItem(nav.ui.currentTreeNode,action,nav.ui.currentSection)">
<i class="icon icon-{{action.cssclass}}"></i>
<span class="menu-label">{{action.name}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</umb-header>
@@ -54,6 +69,15 @@
<umb-editor model="preValue" is-pre-value="true"></umb-editor>
</umb-property>
<div class="umb-tab-buttons">
<div class="btn-group">
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">
<localize key="buttons_save">Save</localize>
</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -18,11 +18,27 @@
<p class="btn btn-link umb-status-label">{{formStatus}}</p>
</div>
<div class="btn-group">
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">
<localize key="buttons_save">Save</localize>
</button>
</div>
<div class="btn-group" ng-class="{dimmed: content.id === 0}">
<!-- options button -->
<a class="btn" href="#" ng-click="options(content)" prevent-default data-toggle="dropdown">
<i class="icon-settings" style="line-height: 14px"></i> Options
</a>
<a class="btn dropdown-toggle" ng-click="options(content)" data-toggle="dropdown">
<span class="caret"></span>
</a>
<!-- actions -->
<ul class="dropdown-menu umb-actions" role="menu" aria-labelledby="dLabel">
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in actions">
<a prevent-default
ng-click="executeMenuItem(nav.ui.currentTreeNode,action,nav.ui.currentSection)">
<i class="icon icon-{{action.cssclass}}"></i>
<span class="menu-label">{{action.name}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</umb-header>
@@ -37,6 +53,14 @@
<umb-editor model="property"></umb-editor>
</umb-property>
<div class="umb-tab-buttons">
<div class="btn-group">
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">
<localize key="buttons_save">Save</localize>
</button>
</div>
</div>
</div>
</umb-tab>

View File

@@ -6,8 +6,9 @@
* @description
* The controller for the media editor
*/
function mediaEditController($scope, $routeParams, mediaResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper) {
function mediaEditController($scope, $routeParams, mediaResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper) {
$scope.nav = navigationService;
if ($routeParams.create) {
mediaResource.getScaffold($routeParams.id, $routeParams.doctype)
@@ -32,6 +33,19 @@ function mediaEditController($scope, $routeParams, mediaResource, notificationsS
});
}
$scope.options = function(content){
if(!content.id){
return;
}
if(!$scope.actions){
treeService.getMenu({ treeNode: $scope.nav.ui.currentTreeNode })
.then(function(data) {
$scope.actions = data.menuItems;
});
}
};
$scope.save = function () {
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {

View File

@@ -18,9 +18,27 @@
<p class="btn btn-link umb-status-label">{{formStatus}}</p>
</div>
<div class="btn-group">
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">Save</button>
</div>
<div class="btn-group" ng-class="{dimmed: content.id === 0}">
<!-- options button -->
<a class="btn" href="#" ng-click="options(content)" prevent-default data-toggle="dropdown">
<i class="icon-settings" style="line-height: 14px"></i> Options
</a>
<a class="btn dropdown-toggle" ng-click="options(content)" data-toggle="dropdown">
<span class="caret"></span>
</a>
<!-- actions -->
<ul class="dropdown-menu umb-actions" role="menu" aria-labelledby="dLabel">
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in actions">
<a prevent-default
ng-click="executeMenuItem(nav.ui.currentTreeNode,action,nav.ui.currentSection)">
<i class="icon icon-{{action.cssclass}}"></i>
<span class="menu-label">{{action.name}}</span>
</a>
</li>
</ul>
</div>
</div>
</div>
</umb-header>
@@ -34,6 +52,14 @@
<umb-editor model="property"></umb-editor>
</umb-property>
<div class="umb-tab-buttons">
<div class="btn-group">
<button type="submit" data-hotkey="ctrl+s" class="btn btn-success">
<localize key="buttons_save">Save</localize>
</button>
</div>
</div>
</div>
</umb-tab>

View File

@@ -6,8 +6,10 @@
* @description
* The controller for the member editor
*/
function MemberEditController($scope, $routeParams, $location, $q, $window, memberResource, entityResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper) {
function MemberEditController($scope, $routeParams, $location, $q, $window, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, treeService) {
$scope.nav = navigationService;
if ($routeParams.create) {
//we are creating so get an empty member item
memberResource.getScaffold($routeParams.doctype)
@@ -45,6 +47,19 @@ function MemberEditController($scope, $routeParams, $location, $q, $window, memb
}
$scope.options = function(content){
if(!content.id){
return;
}
if(!$scope.actions){
treeService.getMenu({ treeNode: $scope.nav.ui.currentTreeNode })
.then(function(data) {
$scope.actions = data.menuItems;
});
}
};
$scope.save = function() {
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {

View File

@@ -7,7 +7,7 @@ data-file-upload-progress=""
ng-hide="creating"
data-ng-class="{'fileupload-processing': processing() || loadingFiles}">
<span class="btn fileinput-button umb-upload-button-big"
<span class="fileinput-button umb-upload-button-big"
ng-show="touchDevice || images.length === 0"
ng-hide="dropping"
ng-class="{disabled: disabled}">

View File

@@ -36,7 +36,7 @@ module.exports = function(karma) {
'src/common/services/*.js',
'src/common/security/*.js',
'src/common/resources/*.js',
'src/common/mocks/resources/*.js',
'src/common/mocks/**/*.js',
'src/views/**/*.controller.js',
'test/unit/**/*.spec.js',
{pattern: 'lib/umbraco/namespacemanager.js', watched: true, served: true}