UNPKG

sheercms

Version:

Sheer Cliff CMS is a simple and powerful content management system (CMS) for Node JS.

861 lines (738 loc) 29.3 kB
/* 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(); });