Merge branch 'u4-4972' of https://github.com/AndyButland/Umbraco-CMS into AndyButland-u4-4972

Conflicts:
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html
This commit is contained in:
Shannon
2014-09-10 15:35:05 +10:00
35 changed files with 942 additions and 83 deletions

View File

@@ -68,6 +68,38 @@ function contentTypeResource($q, $http, umbRequestHelper) {
"GetAllowedChildren",
[{ contentId: contentId }])),
'Failed to retrieve data for content id ' + contentId);
},
/**
* @ngdoc method
* @name umbraco.resources.contentTypeResource#getContainerConfig
* @methodOf umbraco.resources.contentTypeResource
*
* @description
* Returns a JSON structure for configuration of the container content type
*
* ##usage
* <pre>
* contentTypeResource.getContainerConfig(1234)
* .then(function(config) {
* $scope.options = {
* pageSize: config.pageSize,
* };
* });
* </pre>
* @param {Int} contentId id of the content item to retrive the container config for
* @returns {Promise} resourcePromise object.
*
*/
getContainerConfig: function (contentId) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentTypeApiBaseUrl",
"GetContainerConfig",
[{ contentId: contentId }])),
'Failed to retrieve container config data for content id ' + contentId);
}
};

View File

@@ -35,6 +35,38 @@ function mediaTypeResource($q, $http, umbRequestHelper) {
"GetAllowedChildren",
[{ contentId: mediaId }])),
'Failed to retrieve allowed types for media id ' + mediaId);
},
/**
* @ngdoc method
* @name umbraco.resources.mediaTypeResource#getContainerConfig
* @methodOf umbraco.resources.mediaTypeResource
*
* @description
* Returns a JSON structure for configuration of the container content type
*
* ##usage
* <pre>
* mediaTypeResource.getContainerConfig(1234)
* .then(function(config) {
* $scope.options = {
* pageSize: config.pageSize,
* };
* });
* </pre>
* @param {Int} contentId id of the content item to retrive the container config for
* @returns {Promise} resourcePromise object.
*
*/
getContainerConfig: function (contentId) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"mediaTypeApiBaseUrl",
"GetContainerConfig",
[{ contentId: contentId }])),
'Failed to retrieve container config data for media id ' + contentId);
}
};

View File

@@ -82,6 +82,13 @@
color: @black
}
.umb-listview table a.no-sort {
cursor: default;
}
.umb-listview table a.no-sort:hover {
text-decoration: none;
}
.umb-listview .icon-star {
color: @grayLight
}

View File

@@ -6,7 +6,7 @@
* @description
* The controller for the content editor
*/
function ContentEditController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper, editorState, $http) {
function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper, editorState, $http) {
//setup scope vars
$scope.defaultButton = null;
@@ -188,6 +188,15 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
return deferred.promise;
}
function resetLastListPageNumber(content) {
// We're using rootScope to store the page number for list views, so if returning to the list
// we can restore the page. If we've moved on to edit a piece of content that's not the list or it's children
// we should remove this so as not to confuse if navigating to a different list
if (!content.isChildOfListView && !content.isContainer) {
$rootScope.lastListViewPageViewed = null;
}
}
if ($routeParams.create) {
//we are creating so get an empty content item
contentResource.getScaffold($routeParams.id, $routeParams.doctype)
@@ -198,6 +207,8 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
editorState.set($scope.content);
configureButtons($scope.content);
resetLastListPageNumber($scope.content);
});
}
else {
@@ -219,6 +230,7 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
syncTreeNode($scope.content, data.path, true);
resetLastListPageNumber($scope.content);
});
}

View File

@@ -45,6 +45,12 @@
</a>
</div>
<div class="btn-group" ng-show="content.isChildOfListView">
<a class="btn" href="#/content/content/edit/{{content.parentId}}">
<localize key="buttons_returnToList">Return to list</localize>
</a>
</div>
<div class="btn-group dropup" ng-if="defaultButton" >
<!-- primary button -->
<a class="btn btn-success" href="#" ng-click="performAction(defaultButton)" prevent-default>
@@ -54,8 +60,9 @@
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
<span class="caret"></span>
</a>
<a href="#">Return to list</a>
<!-- sub buttons -->
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel" ng-if="subButtons.length > 0">
<li ng-repeat="btn in subButtons">

View File

@@ -29,46 +29,112 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
items: []
};
// Set "default default" options (i.e. those if no container configuration has been saved)
$scope.options = {
pageSize: 10,
pageNumber: 1,
filter: '',
orderBy: 'UpdateDate',
orderDirection: "desc"
orderBy: 'updateDate',
orderDirection: "desc",
allowBulkPublish: true,
allowBulkUnpublish: true,
allowBulkDelete: true,
additionalColumns: [
{ alias: 'UpdateDate', header: 'Last edited', localizationKey: 'defaultdialogs_lastEdited' },
{ alias: 'Updator', header: 'Last edited', localizationKey: 'content_updatedBy' }
]
};
// Retrieve the container configuration for the content type and set options before presenting initial view
contentTypeResource.getContainerConfig($routeParams.id)
.then(function (config) {
if (typeof config.pageSize !== 'undefined') {
$scope.options.pageSize = config.pageSize;
}
if (typeof config.additionalColumns !== 'undefined') {
$scope.options.additionalColumns = config.additionalColumns;
}
if (typeof config.orderBy !== 'undefined') {
$scope.options.orderBy = config.orderBy;
}
if (typeof config.orderDirection !== 'undefined') {
$scope.options.orderDirection = config.orderDirection;
}
if (typeof config.allowBulkPublish !== 'undefined') {
$scope.options.allowBulkPublish = config.allowBulkPublish;
}
if (typeof config.allowBulkUnpublish !== 'undefined') {
$scope.options.allowBulkUnpublish = config.allowBulkUnpublish;
}
if (typeof config.allowBulkDelete !== 'undefined') {
$scope.options.allowBulkDelete = config.allowBulkDelete;
}
$scope.initView();
});
$scope.next = function () {
if ($scope.options.pageNumber < $scope.listViewResultSet.totalPages) {
$scope.options.pageNumber++;
$scope.reloadView($scope.contentId);
saveLastPageNumber();
}
};
$scope.goToPage = function (pageNumber) {
$scope.options.pageNumber = pageNumber + 1;
$scope.reloadView($scope.contentId);
saveLastPageNumber();
};
$scope.sort = function (field) {
$scope.sort = function (field, allow) {
if (allow) {
$scope.options.orderBy = field;
$scope.options.orderBy = field;
if ($scope.options.orderDirection === "desc") {
$scope.options.orderDirection = "asc";
} else {
$scope.options.orderDirection = "desc";
}
if ($scope.options.orderDirection === "desc") {
$scope.options.orderDirection = "asc";
} else {
$scope.options.orderDirection = "desc";
$scope.reloadView($scope.contentId);
}
$scope.reloadView($scope.contentId);
};
$scope.prev = function () {
if ($scope.options.pageNumber > 1) {
$scope.options.pageNumber--;
$scope.reloadView($scope.contentId);
saveLastPageNumber();
}
};
saveLastPageNumber = function () {
// Saves the last page number into rootScope, so we can retrieve it when returning to the list and
// re-present the correct page
$rootScope.lastListViewPageViewed = {
contentId: $scope.contentId,
pageNumber: $scope.options.pageNumber
};
};
$scope.initView = function () {
if ($routeParams.id) {
$scope.pagination = new Array(10);
$scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id);
$scope.contentId = $routeParams.id;
$scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21";
// If we have a last page number saved, go straight to that one
if ($rootScope.lastListViewPageViewed && $rootScope.lastListViewPageViewed.contentId == $scope.contentId) {
$scope.goToPage($rootScope.lastListViewPageViewed.pageNumber - 1);
} else {
$scope.reloadView($scope.contentId);
}
}
};
@@ -78,9 +144,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
$scope.reloadView = function (id) {
contentResource.getChildren(id, $scope.options).then(function (data) {
$scope.listViewResultSet = data;
$scope.pagination = [];
$scope.pagination = [];
for (var i = $scope.listViewResultSet.totalPages - 1; i >= 0; i--) {
$scope.pagination[i] = { index: i, name: i + 1 };
@@ -93,6 +158,65 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
});
};
$scope.getColumnName = function (index) {
return $scope.options.additionalColumns[index].header;
};
$scope.getColumnLocalizationKey = function (index) {
return $scope.options.additionalColumns[index].localizationKey;
};
$scope.getPropertyValue = function (alias, result) {
// Camel-case the alias
alias = alias.charAt(0).toLowerCase() + alias.slice(1);
// First try to pull the value directly from the alias (e.g. updatedBy)
var value = result[alias];
// If this returns an object, look for the name property of that (e.g. owner.name)
if (value === Object(value)) {
value = value['name'];
}
// If we've got nothing yet, look at a user defined property
if (typeof value === 'undefined') {
value = $scope.getCustomPropertyValue(alias, result.properties);
}
// If we have a date, format it
if (isDate(value)) {
value = value.substring(0, value.length - 3);
}
// Return what we've got
return value;
};
isDate = function (val) {
return val.match(/^(\d{4})\-(\d{2})\-(\d{2})\ (\d{2})\:(\d{2})\:(\d{2})$/);
};
$scope.getCustomPropertyValue = function (alias, properties) {
var value = '';
var index = 0;
var foundAlias = false;
for (var i = 0; i < properties.length; i++) {
if (properties[i].alias == alias) {
foundAlias = true;
break;
}
index++;
}
if (foundAlias) {
value = properties[index].value;
}
return value;
};
//assign debounce method to the search to limit the queries
$scope.search = _.debounce(function () {
$scope.options.pageNumber = 1;
@@ -236,16 +360,6 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
}
};
if ($routeParams.id) {
$scope.pagination = new Array(10);
$scope.listViewAllowedTypes = contentTypeResource.getAllowedTypes($routeParams.id);
$scope.reloadView($routeParams.id);
$scope.contentId = $routeParams.id;
$scope.isTrashed = $routeParams.id === "-20" || $routeParams.id === "-21";
}
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.ListViewController", listViewController);

View File

@@ -23,17 +23,17 @@
</ul>
</div>
<div class="btn-group" ng-show="isAnythingSelected()" ng-if="entityType === 'content' && !isTrashed">
<div class="btn-group" ng-show="isAnythingSelected()" ng-if="entityType === 'content' && !isTrashed && options.allowBulkPublish">
<a class="btn btn-success" ng-disabled="actionInProgress" ng-click="publish()" prevent-default>
<localize key="actions_publish">Publish</localize>
</a>
</div>
<div class="btn-group" ng-show="isAnythingSelected()" ng-if="entityType === 'content' && !isTrashed">
<div class="btn-group" ng-show="isAnythingSelected()" ng-if="entityType === 'content' && !isTrashed && options.allowBulkUnpublish">
<a class="btn btn-warning" ng-disabled="actionInProgress" ng-click="unpublish()" prevent-default>
<localize key="actions_unpublish">Unpublish</localize>
</a>
</div>
<div class="btn-group" ng-show="isAnythingSelected()">
<div class="btn-group" ng-show="isAnythingSelected()" ng-if="options.allowBulkDelete">
<a class="btn btn-danger" ng-disabled="actionInProgress" ng-click="delete()" prevent-default>
<localize key="actions_delete">Delete</localize>
</a>
@@ -45,16 +45,23 @@
<thead>
<tr>
<td style="width: 35px">
<input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()"></td>
<td><a href="#" ng-click="sort('Name')" prevent-default>
<localize key="general_name">Name</localize>
<i class="icon-sort"></i></a></td>
<td><a href="#" ng-click="sort('UpdateDate')" prevent-default>
<localize key="defaultdialogs_lastEdited">Last edited</localize>
<i class="icon-sort"></i></a></td>
<td><a href="#" ng-click="sort('Owner')" prevent-default>
<localize key="content_updatedBy">Updated by</localize>
<i class="icon-sort"></i></a></td>
<input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()">
</td>
<td>
<a href="#" ng-click="sort('Name', true)" prevent-default>
<localize key="general_name">Name</localize>
<i class="icon-sort"></i>
</a>
</td>
<td ng-repeat="column in options.additionalColumns">
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'no-sort':!column.allowSorting}" prevent-default>
<localize ng-if="getColumnLocalizationKey($index) !==''" key="{{getColumnLocalizationKey($index)}}">{{getColumnName($index)}}</localize>
<span ng-if="getColumnLocalizationKey($index) === ''">{{getColumnName($index)}}</span>
<i class="icon-sort"></i>
</a>
</td>
<td>
<form class="pull-right" novalidate>
<i class="icon-search"></i>
@@ -78,27 +85,23 @@
<td>
<i class="icon {{result.icon}}" ng-class="getIcon(result)"></i>
<input type="checkbox" ng-model="result.selected">
</td>
<td>
<a ng-class="{inactive: (entityType === 'content' && !result.published) || isTrashed}" href="#/{{entityType}}/{{entityType}}/edit/{{result.id}}">{{result.name}}</a>
</td>
<td>
{{result.updateDate|date:'medium'}}
<!--<<span class="label label-success">Publish</span>-->
</td>
<td>
{{result.owner.name}}
<!--<span class="label">Admin</span>-->
<td ng-repeat="column in options.additionalColumns">
{{getPropertyValue(column.alias, result)}}
</td>
<td></td>
</tr>
</tbody>
<tfoot ng-show="pagination.length > 1">
<tr>
<th colspan="5">
<th colspan="{{options.additionalColumns.length + 3}}">
<div class="pull-left">
</div>
<div class="pagination pagination-right">