sheercms
Version:
Sheer Cliff CMS is a simple and powerful content management system (CMS) for Node JS.
861 lines (738 loc) • 29.3 kB
JavaScript
/*
Angular Controller: Content
*/
app.controller('ContentController', function($scope, $location, $q, $modal, $routeParams, TemplateService, ContentService, DialogService, GroupService, ContentTypeService, $timeout, $compile) {
$scope.data = {
view: "",
viewPath: "",
message: "",
messageType: "",
items: [],
templates: [],
contentTypes: [],
filteredTemplates: [],
views: [
{name: 'list', text: 'List', visible: false },
{name: 'gallery', text: 'Gallery', visible: false },
{name: 'calendar', text: 'Calendar', visible: false }
],
allowUpload: false,
types: [],
title: "Content",
useCacheFlag: true,
branch: "",
groups: [],
group: null,
groupsCopy: [],
noGroupsMsg: ''
};
$scope.filters = {
category: null
};
$scope.popover = {
title: "Actions",
content: '',
placement: "top",
html: true
};
$scope.checks = {
all: false
}
$scope.paging = {
show: true,
start: 0,
end: 0,
total: 0,
pageSize: 20,
pageNum: 1,
pageCount: 0,
paginate: function(num) {
loadGroupItems($scope.data.group._id, num, true);
}
};
$scope.buttons = {
newGroup: true,
refreshGroups: true,
reorderGroups: true,
saveGroupOrder: false,
cancelGroupOrder: false,
newItem: true,
upload: false,
publish: true,
unpublish: true,
delete: true,
restore: true,
refresh: true,
move: true
};
$scope.groupSortableOptions = {
helper: function(e, elem) {
var helper = elem.clone();
helper.width($(".group-list").width());
helper.height(60);
helper.addClass("group-sortable-helper");
return helper;
},
placeholder: 'group-sortable-placeholder',
disabled: true
};
$scope.selectedItem = null;
$scope.selectItem = function(event, item) {
var element = $(event.target);
//hide all other tooltips
$(".tooltipstered").tooltipster('hide');
if (!element.is('input') && !element.is('a') && !element.is('img')) {
if ($scope.selectedItem === item)
{
$scope.selectedItem = null;
}
else if ($scope.data.group)
{
$scope.selectedItem = item;
var rights = $scope.data.group.rights;
if (rights.read === true) {
var html = '<div class="item-tooltip">' +
' <div class="toolbar"><ul>' +
' <li><a href="javascript:void(0);" ng-click="editItem(\'' + item.contentId + '\')"><img src="/cms/static/images/icons/32/cog_edit.png" alt="Edit Properties" title="Edit Properties"/><span>Properties</span></a></li>';
//can this item be designed?
if (rights.update === true && ContentService.canDesign(item) === true) {
var url = item.url + "?cmsmode=design";
html += '<li><a target="_blank" href="' + url + '" ng-click="clearSelection()"><img src="/cms/static/images/icons/32/page_edit.png" alt="Design" title="Open this item in design mode"/><span>Design</span></a></li>';
}
//close up the toolbar
html += '</ul></div></div>';
if (element.attr("tooltip-loaded") !== "true") {
element.tooltipster({
content: $($compile(html)($scope)),
trigger: 'custom',
offsetY: -8,
speed: 100,
theme: 'tooltipster-itemlist'
});
element.attr("tooltip-loaded", "true");
}
element.tooltipster('show');
}
}
}
};
$scope.clearSelectedItem = function() {
hidePopupToolbar();
$scope.selectedItem = null;
};
function hidePopupToolbar()
{
//hide all other tooltips
$(".tooltipstered").tooltipster('hide');
}
$scope.filter = function() {
//filter the items in the list by category
$scope.refresh();
};
function resetFilters() {
$scope.filters.category = null;
}
/*=== Groups ===*/
$scope.showNewGroup = function() {
var name = prompt("Enter the new group name:");
if (name && name.length > 0) {
var group = {
name: name,
branch: $scope.data.branch.name,
parentId: null
};
GroupService.create(group).then(function(result) {
if (result && result.success === true) {
loadGroups(null, false).then(function() {
if ($scope.data.groups) {
for(var i = 0; i < $scope.data.groups.length; i++) {
var g = $scope.data.groups[i];
if (g._id == result.group._id) {
$scope.changeGroup(g);
break;
}
}
}
});
} else if (result) {
$scope.setMessage(result.message, 'alert-danger', false);
} else {
$scope.setMessage('An unknown error occurred.', 'alert-danger', false);
}
});
}
};
$scope.refreshGroups = function() {
loadGroups(null, false);
};
$scope.changeGroup = function(group, pageNum) {
if (group && group != $scope.data.group) {
resetFilters();
$scope.data.view = null;
$scope.data.viewPath = "";
$scope.data.group = group;
//load the views of this group
if (group.views && group.views.length > 0) {
for(var i = 0; i < $scope.data.views.length; i++) {
$scope.data.views[i].visible = false;
for(var j = 0; j < group.views.length; j++) {
if ($scope.data.views[i].name === group.views[j]) {
$scope.data.views[i].visible = true;
}
}
}
}
else {
//just select the list view
for(var i = 0; i < $scope.data.views.length; i++) {
$scope.data.views[i].visible = ($scope.data.views[i].name === 'list');
}
}
//select the first visible view
for(var i = 0; i < $scope.data.views.length; i++) {
var v = $scope.data.views[i];
if (v.visible === true) {
$scope.setView(v);
break;
}
}
updateButtons(group.branch);
var page = pageNum || 1;
//load group items
loadGroupItems(group._id, page, true);
}
};
$scope.reorderGroups = function() {
$scope.buttons.newGroup = false;
$scope.buttons.refreshGroups = false;
$scope.buttons.reorderGroups = false;
$scope.buttons.saveGroupOrder = true;
$scope.buttons.cancelGroupOrder = true;
$(".group-list").sortable("option", "disabled", false);
//save off a copy of the groups list
$scope.data.groupsCopy = [];
for(var i = 0; i < $scope.data.groups.length; i++) {
$scope.data.groupsCopy.push($scope.data.groups[i]);
}
};
$scope.saveGroupOrder = function() {
stopSortingGroups();
//save the new sort order
GroupService.reorder($scope.data.groups, $scope.data.branch, null).then(function(result) {
if (result && result.success === true) {
loadGroups(null, false);
} else if (result) {
$scope.setMessage(result.message, 'alert-danger', false);
} else {
$scope.setMessage('An unknown error occurred.', 'alert-danger', false);
}
});
};
$scope.cancelGroupOrder = function() {
stopSortingGroups();
//revert the list
$scope.data.groups = [];
for(var i = 0; i < $scope.data.groupsCopy.length; i++) {
$scope.data.groups.push($scope.data.groupsCopy[i]);
}
};
function stopSortingGroups() {
$scope.buttons.newGroup = true;
$scope.buttons.refreshGroups = true;
$scope.buttons.reorderGroups = true;
$scope.buttons.saveGroupOrder = false;
$scope.buttons.cancelGroupOrder = false;
$(".group-list").sortable("option", "disabled", true);
}
$scope.editGroup = function(group) {
if ($scope.global.isAdmin === true) {
var modalInstance = $modal.open({
templateUrl: 'GroupPropsDialog',
controller: GroupPropsDialogController,
windowClass: 'large-dialog',
resolve: {
group: function () {
return group;
},
types: function () {
return $scope.data.contentTypes;
}
}
});
modalInstance.result.then(function (value) {
if (value == true) {
//saved or deleted successfully - reload groups
loadGroups(null, false);
}
}, function () {
//modal cancelled
});
}
};
function loadGroups(branch, useCache) {
var d = $q.defer();
branch = branch || $scope.data.branch.name;
console.log("Loading groups in branch: " + branch);
if (useCache == false)
GroupService.clearCache(branch);
GroupService.list(branch, null).then(function(result) {
if (result && result.success === true) {
//only add groups that the user has read access to
$scope.data.groups = [];
for(var i = 0; i < result.groups.length; i++) {
var g = result.groups[i];
if (g.rights && g.rights.read == true)
$scope.data.groups.push(g);
}
//if the selected group isn't in the list, then make it null
if ($scope.data.group) {
var found = false;
for (var i = 0; i < $scope.data.groups.length; i++) {
if ($scope.data.groups[i]._id === $scope.data.group._id) {
found = true;
$scope.data.group = $scope.data.groups[i]; //re-assign the group so it gets new data
break;
}
}
if (found === false) {
$scope.data.group = null;
}
}
} else if (result) {
$scope.setMessage(result.message, 'alert-danger', false);
} else {
$scope.setMessage('An unknown error occurred.', 'alert-danger', false);
}
if (!$scope.data.groups || $scope.data.groups.length == 0) {
if ($scope.global.isAdmin == true)
$scope.data.noGroupsMsg = 'There are no groups in this branch. Create item groups by clicking the "New Group" toolbar button.';
else
$scope.data.noGroupsMsg = 'You do not have access to any group in this branch.';
}
d.resolve();
});
return d.promise;
}
/*=== End of Groups ===*/
$scope.editItem = function(id) {
$scope.clearSelectedItem();
$scope.clearMessage();
$location.path('/edit/' + id);
};
$scope.clearSelection = function(id) {
$scope.clearSelectedItem();
$scope.clearMessage();
};
$scope.publishItem = function(id) {
var ids = [id];
runBatchCommand('publish', null, ids);
};
$scope.deleteItem = function(id) {
if (confirm("Are you sure you want to delete this item?")) {
var ids = [id];
runBatchCommand('delete', null, ids);
}
};
$scope.setView = function(view) {
$scope.data.view = view;
$scope.data.viewPath = '/cms/static/routes/content/views/' + view.name + '.html';
updateButtons($scope.data.branch);
};
function loadGroupItems(groupId, pageNumber, useCache) {
if (groupId) {
$scope.paging.pageNum = pageNumber;
//get the filters
var category = $scope.filters.category || '';
$location.search('groupId', groupId);
$location.search('category', category);
$location.search('page', pageNumber);
var options = {
groupId: groupId,
page: pageNumber,
size: $scope.paging.pageSize,
useCache: useCache,
category: category
}
ContentService.getContentItems(options).then(function (data) {
$scope.data.message = data.message;
$scope.data.messageType = data.success == true ? "alert-success" : "alert-danger";
if (data.success) {
ContentService.setItemsStatusCss(data.items);
$scope.data.items = data.items;
//set the paging data
$scope.paging.start = (pageNumber - 1) * $scope.paging.pageSize + 1;
$scope.paging.end = data.hasParent == true ? ($scope.paging.start + data.items.length - 2) : ($scope.paging.start + data.items.length - 1);
$scope.paging.total = data.total;
$scope.paging.pageCount = Math.ceil(data.total / $scope.paging.pageSize);
$scope.paging.pages = [];
for (var i = 0; i < $scope.paging.pageCount; i++)
$scope.paging.pages.push(i + 1);
}
if ($scope.data.items == null)
$scope.data.items = [];
$timeout(function () {
resize();
}, 100);
});
}
else {
$scope.data.items = [];
$scope.paging.pageNum = 1;
$scope.paging.pages = [];
$timeout(function () {
resize();
}, 100);
}
}
$scope.refresh = function() {
if ($scope.data.group) {
ContentService.clearCacheByGroup($scope.data.group._id);
if ($scope.data.view && $scope.data.view.name === 'calendar')
$scope.$broadcast('refreshItems'); //broadcast this to the child controller
else
loadGroupItems($scope.data.group._id, 1, false);
}
};
$scope.showNewItem = function(startDate, endDate) {
$scope.clearSelectedItem();
var types = ContentService.filterContentTypes($scope.data.group, $scope.data.contentTypes);
//if the list of views includes calendar, then set the start and end date if they are null
if (startDate == null && endDate == null && hasView('calendar') == true) {
startDate = new Date();
startDate.setHours(0, 0, 0, 0); //get today's date without time
endDate = new Date();
endDate.setDate(endDate.getDate()+1);
endDate.setHours(0,0,0,0);
}
var modalInstance = $modal.open({
templateUrl: 'NewItemDialog',
controller: NewItemDialogController,
windowClass: 'large-dialog',
resolve: {
groupId: function () {
return $scope.data.group ? $scope.data.group._id : null;
},
startDate: function() {
return startDate;
},
endDate: function() {
return endDate;
},
types: function() {
return types;
}
}
});
modalInstance.result.then(function (contentId) {
//ok clicked
if (contentId) {
$location.path('/edit/' + contentId);
}
}, function () {
//modal cancelled
});
};
$scope.publishItems = function() {
var items = getCheckedItems();
if (items == null || items.length == 0) {
alert('You must check at least one item to perform this command.');
}
else if (confirm("Are you sure you want to publish all of the checked items?")) {
//see if there are any deleted items
var delCount = 0;
var ids = [];
for(var i = 0; i < items.length; i++) {
var item = items[i];
if (item.status == 'D')
delCount++;
else
ids.push(item.contentId);
}
if (delCount > 0 && ids.length > 0 &&
!confirm("You have checked at least one deleted content item.\nDeleted item cannot be published.\nContinue with the other items?")) {
return;
}
else if (delCount > 0 && ids.length == 0) {
alert("You have checked only deleted content items.\nDeleted item cannot be published.");
return;
}
//run the command on the remaining non-deleted items
runBatchCommand('publish', null, ids);
}
};
$scope.unPublishItems = function() {
var items = getCheckedItems();
if (items == null || items.length == 0) {
alert('You must check at least one item to perform this command.');
}
else if (confirm("Are you sure you want to un-publish all of the checked items?")) {
//see if there are any non-published items
var count = 0;
var ids = [];
for(var i = 0; i < items.length; i++) {
var item = items[i];
if (item.status != 'P' && item.status != 'M')
count++;
else
ids.push(item.contentId);
}
if (count > 0 && ids.length > 0 &&
!confirm("You have checked at least one content item that cannot be un-published.\nContinue with the other items?")) {
return;
}
else if (count > 0 && ids.length == 0) {
alert("You have checked only content items that cannot be un-published.");
return;
}
//run the command on the remaining published items
runBatchCommand('unpublish', null, ids);
}
};
$scope.deleteItems = function() {
var items = getCheckedItems();
if (items == null || items.length == 0) {
alert('You must check at least one item to perform this command.');
}
else if (confirm("Are you sure you want to delete all of the checked items?")) {
//see if there are any items already in a deleted status
var perm = null;
var ids = [];
for(var i = 0; i < items.length; i++) {
var item = items[i];
if (item.status == 'D') {
if (perm == null)
perm = confirm("At least one checked item already has a deleted status.\nDo you want to permanently delete those items?");
}
if (item.status != 'D' || perm == true)
ids.push(item.contentId);
}
if (ids.length == 0) {
alert("There are no checked items that can be deleted.");
return;
}
//run the command on the remaining published items
runBatchCommand('delete', null, ids);
}
};
$scope.restoreItems = function() {
var items = getCheckedItems();
if (items == null || items.length == 0) {
alert('You must check at least one item to perform this command.');
}
else if (confirm("Are you sure you want to restore all of the checked items?")) {
//only restore deleted items
var ids = [];
for(var i = 0; i < items.length; i++) {
var item = items[i];
if (item.status == 'D')
ids.push(item.contentId);
}
if (ids.length == 0) {
alert("There are no checked items that can be restored.");
return;
}
//run the command on the remaining published items
runBatchCommand('restore', null, ids);
}
};
$scope.moveItems = function() {
var items = getCheckedItems();
if (items == null || items.length == 0) {
alert('You must check at least one item to move.');
return;
}
//show the group picker dialog
DialogService.openGroupSelector($scope.data.branch.name, "Select a Group", function(group) {
if (group) {
var ids = [];
for(var i = 0; i < items.length; i++)
ids.push(items[i].contentId);
//move items to this group
runBatchCommand('moveItems', {groupId: group._id}, ids);
ContentService.clearAllCache();
}
});
};
$scope.showUpload = function() {
if ($scope.data.group) {
var options = {
title: "Upload Media",
groupId: $scope.data.group._id,
onClose: function (uploadCount) {
//refresh the item list if at least one file was uploaded
if (uploadCount && uploadCount > 0) {
$scope.refresh();
$scope.refreshGroups();
}
}
};
DialogService.openUploadMedia(options);
}
};
$scope.toggleCheckAll = function() {
for(var i = 0; i < $scope.data.items.length; i++) {
var item = $scope.data.items[i];
if (item.contentId != $scope.data.parentId)
item.checked = $scope.checks.all;
}
};
$scope.toggleCheck = function(item) {
if (item.checked == false)
$scope.checks.all = false;
};
function runBatchCommand(cmd, options, ids) {
if ($scope.data.group) {
ContentService.runBatchCommand(cmd, options, ids, $scope.data.group._id).then(function (result) {
if (result && result.success == true) {
$scope.setMessage(result.message, 'alert-success');
timeoutClearMessage();
$scope.refresh();
if (cmd === 'moveItems' || cmd === 'delete')
$scope.refreshGroups();
} else if (result) {
$scope.setMessage(result.message, 'alert-danger');
} else {
$scope.setMessage('An unknown error occurred.', 'alert-danger');
}
});
}
}
function getCheckedItems() {
var arr = [];
for(var i = 0; i < $scope.data.items.length; i++) {
var item = $scope.data.items[i];
if (item.checked == true)
arr.push(item);
}
return arr;
}
function hasView(name) {
for(var i = 0; i < $scope.data.views.length; i++) {
var v = $scope.data.views[i];
if (v.name === name && v.visible === true)
return true;
}
return false;
}
function isNullOrEmpty(s) {
return (s && s.length > 0) ? false : true;
}
function init() {
resize();
//$scope.setView("list");
var branch = ContentService.getBranchData($location.path());
if (branch) {
$scope.data.title = branch.text;
$scope.data.branch = branch;
updateButtons(branch.name);
var groupId = $location.search() === null ? null : $location.search().groupId;
var sPageNum = $location.search() === null ? 1 : parseInt($location.search().page);
var pageNum = sPageNum == NaN ? 1 : sPageNum;
loadGroups(branch.name, true).then(function (data) {
//select the correct group
if ($scope.data.groups && $scope.data.groups.length > 0) {
if (groupId) {
for (var i = 0; i < $scope.data.groups.length; i++) {
var g = $scope.data.groups[i];
if (g._id === groupId) {
$scope.changeGroup(g, pageNum);
break;
}
}
}
else {
//select the first group
$scope.changeGroup($scope.data.groups[0], pageNum);
}
}
//loadGroupItems(groupId, 1, true);
TemplateService.list(true).then(function (data) {
$scope.data.templates = data.templates;
});
ContentTypeService.list(true).then(function(data) {
$scope.data.contentTypes = data.contentTypes;
});
});
}
else {
$scope.setMessage("Invalid item branch!", "alert-danger");
}
}
function updateButtons(branchName) {
if ($scope.data.group) {
var rights = $scope.data.group.rights;
if (branchName === 'content') {
$scope.buttons.newItem = rights.create;
$scope.buttons.upload = false;
}
else if (branchName === 'media') {
$scope.buttons.newItem = false;
$scope.buttons.upload = rights.create;
}
if ($scope.data.view.name === 'calendar') {
$scope.paging.show = false;
$scope.buttons.publish = false;
$scope.buttons.unpublish = false;
$scope.buttons.delete = false;
$scope.buttons.restore = false;
$scope.buttons.refresh = true;
$scope.buttons.move = false;
}
else if ($scope.data.view.name === 'gallery') {
$scope.paging.show = true;
$scope.buttons.publish = false;
$scope.buttons.unpublish = false;
$scope.buttons.delete = false;
$scope.buttons.restore = false;
$scope.buttons.refresh = true;
$scope.buttons.move = false;
}
else {
$scope.paging.show = true;
$scope.buttons.publish = rights.publish;
$scope.buttons.unpublish = rights.publish;
$scope.buttons.delete = rights.delete;
$scope.buttons.restore = rights.update;
$scope.buttons.move = true; // $scope.global.isAdmin;
$scope.buttons.refresh = true;
}
}
else {
$scope.buttons.newItem = false;
$scope.buttons.upload = false;
$scope.buttons.publish = false;
$scope.buttons.delete = false;
$scope.buttons.restore = false;
$scope.buttons.move = false;
$scope.buttons.unpublish = false;
}
//only admins can create and modify item groups
if ($scope.global.isAdmin === true) {
$scope.buttons.newGroup = true;
$scope.buttons.reorderGroups = true;
}
else {
$scope.buttons.newGroup = false;
$scope.buttons.reorderGroups = false;
}
}
$scope.clearMessage = function() {
$scope.data.message = "";
$scope.data.messageType = "";
}
$scope.setMessage = function(msg, type, doTimeout) {
$scope.data.message = msg;
$scope.data.messageType = type;
if (doTimeout === true)
timeoutClearMessage();
}
function timeoutClearMessage() {
$timeout(function() {
$scope.clearMessage();
}, 4000);
}
function resize() {
$scope.$parent.resize('.main-view', '.main-view-left');
}
init();
});