sheercms
Version:
Sheer Cliff CMS is a simple and powerful content management system (CMS) for Node JS.
497 lines (434 loc) • 16.9 kB
JavaScript
var app = angular.module('app', ['ngRoute', 'ngSanitize', 'ui.sortable', 'ui.select2', 'angularFileUpload', 'ui.bootstrap', 'ui.calendar', 'ngQuickDate', 'angular-data.DSCacheFactory', 'ngCookies']);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/', {
redirectTo: '/content'
}).
when('/menus', {
templateUrl: '/cms/static/routes/menus/menus.html',
controller: 'MenuController'
}).
when('/content', {
templateUrl: '/cms/static/routes/content/content.html',
controller: 'ContentController',
reloadOnSearch: false
}).
when('/media', {
templateUrl: '/cms/static/routes/content/content.html',
controller: 'ContentController',
reloadOnSearch: false
}).
when('/edit/:contentId', {
templateUrl: '/cms/static/routes/content/edit.html',
controller: 'EditController'
}).
when('/users', {
templateUrl: '/cms/static/routes/users/users.html',
controller: 'UserController'
}).
when('/templates', {
templateUrl: '/cms/static/routes/templates/templates.html',
controller: 'TemplateController'
}).
when('/types', {
templateUrl: '/cms/static/routes/types/contentTypes.html',
controller: 'ContentTypeController'
}).
when('/dashboard', {
templateUrl: '/cms/static/routes/dashboard/dashboard.html',
controller: 'DashboardController'
}).
when('/logs', {
templateUrl: '/cms/static/routes/logs/logs.html',
controller: 'LogController'
}).
when('/cache', {
templateUrl: '/cms/static/routes/cache/cache.html',
controller: 'CacheController'
}).
when('/packages', {
templateUrl: '/cms/static/routes/packages/packages.html',
controller: 'PackageController'
}).
when('/stats', {
templateUrl: '/cms/static/routes/stats/stats.html',
controller: 'StatController'
});
}]);
app.constant('uiAceConfig', {})
.directive('uiAce', ['uiAceConfig', function (uiAceConfig) {
if (angular.isUndefined(window.ace)) {
throw new Error('ui-ace need ace to work... (o rly?)');
}
/**
* Sets editor options such as the wrapping mode or the syntax checker.
*
* The supported options are:
*
* <ul>
* <li>showGutter</li>
* <li>useWrapMode</li>
* <li>onLoad</li>
* <li>theme</li>
* <li>mode</li>
* </ul>
*
* @param acee
* @param session ACE editor session
* @param {object} opts Options to be set
*/
var setOptions = function(acee, session, opts) {
// Boolean options
if (angular.isDefined(opts.showGutter)) {
acee.renderer.setShowGutter(opts.showGutter);
}
if (angular.isDefined(opts.useWrapMode)) {
session.setUseWrapMode(opts.useWrapMode);
}
if (angular.isDefined(opts.showInvisibles)) {
acee.renderer.setShowInvisibles(opts.showInvisibles);
}
if (angular.isDefined(opts.showIndentGuides)) {
acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
}
if (angular.isDefined(opts.useSoftTabs)) {
session.setUseSoftTabs(opts.useSoftTabs);
}
// commands
if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
acee.commands.addCommands([
{
name: 'unfind',
bindKey: {
win: 'Ctrl-F',
mac: 'Command-F'
},
exec: function () {
return false;
},
readOnly: true
}
]);
}
// onLoad callback
if (angular.isFunction(opts.onLoad)) {
opts.onLoad(acee);
}
// Basic options
if (angular.isString(opts.theme)) {
acee.setTheme('ace/theme/' + opts.theme);
}
if (angular.isString(opts.mode)) {
session.setMode('ace/mode/' + opts.mode);
}
//additional settings
acee.setShowPrintMargin(false);
};
return {
restrict: 'EA',
require: '?ngModel',
link: function (scope, elm, attrs, ngModel) {
/**
* Corresponds the uiAceConfig ACE configuration.
* @type object
*/
var options = uiAceConfig.ace || {};
/**
* uiAceConfig merged with user options via json in attribute or data binding
* @type object
*/
var opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
/**
* ACE editor
* @type object
*/
var acee = window.ace.edit(elm[0]);
/**
* ACE editor session.
* @type object
* @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
*/
var session = acee.getSession();
/**
* Reference to a change listener created by the listener factory.
* @function
* @see listenerFactory.onChange
*/
var onChangeListener;
/**
* Reference to a blur listener created by the listener factory.
* @function
* @see listenerFactory.onBlur
*/
var onBlurListener;
/**
* Calls a callback by checking its existing. The argument list
* is variable and thus this function is relying on the arguments
* object.
* @throws {Error} If the callback isn't a function
*/
var executeUserCallback = function () {
/**
* The callback function grabbed from the array-like arguments
* object. The first argument should always be the callback.
*
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
* @type {*}
*/
var callback = arguments[0];
/**
* Arguments to be passed to the callback. These are taken
* from the array-like arguments object. The first argument
* is stripped because that should be the callback function.
*
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
* @type {Array}
*/
var args = Array.prototype.slice.call(arguments, 1);
if (angular.isDefined(callback)) {
scope.$apply(function () {
if (angular.isFunction(callback)) {
callback(args);
} else {
throw new Error('ui-ace use a function as callback.');
}
});
}
};
/**
* Listener factory. Until now only change listeners can be created.
* @type object
*/
var listenerFactory = {
/**
* Creates a change listener which propagates the change event
* and the editor session to the callback from the user option
* onChange. It might be exchanged during runtime, if this
* happens the old listener will be unbound.
*
* @param callback callback function defined in the user options
* @see onChangeListener
*/
onChange: function (callback) {
return function (e) {
var newValue = session.getValue();
if (newValue !== scope.$eval(attrs.value) && !scope.$$phase && !scope.$root.$$phase) {
if (angular.isDefined(ngModel)) {
scope.$apply(function () {
ngModel.$setViewValue(newValue);
});
}
executeUserCallback(callback, e, acee);
}
};
},
/**
* Creates a blur listener which propagates the editor session
* to the callback from the user option onBlur. It might be
* exchanged during runtime, if this happens the old listener
* will be unbound.
*
* @param callback callback function defined in the user options
* @see onBlurListener
*/
onBlur: function (callback) {
return function () {
executeUserCallback(callback, acee);
};
}
};
attrs.$observe('readonly', function (value) {
acee.setReadOnly(value === 'true');
});
// Value Blind
if (angular.isDefined(ngModel)) {
ngModel.$formatters.push(function (value) {
if (angular.isUndefined(value) || value === null) {
return '';
}
else if (angular.isObject(value) || angular.isArray(value)) {
throw new Error('ui-ace cannot use an object or an array as a model');
}
return value;
});
ngModel.$render = function () {
session.setValue(ngModel.$viewValue);
};
}
// set the options here, even if we try to watch later, if this
// line is missing things go wrong (and the tests will also fail)
setOptions(acee, session, opts);
// Listen for option updates
scope.$watch( attrs.uiAce, function() {
opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
// unbind old change listener
session.removeListener('change', onChangeListener);
// bind new change listener
onChangeListener = listenerFactory.onChange(opts.onChange);
session.on('change', onChangeListener);
// unbind old blur listener
//session.removeListener('blur', onBlurListener);
acee.removeListener('blur', onBlurListener);
// bind new blur listener
onBlurListener = listenerFactory.onBlur(opts.onBlur);
acee.on('blur', onBlurListener);
setOptions(acee, session, opts);
}, /* deep watch */ true );
// EVENTS
onChangeListener = listenerFactory.onChange(opts.onChange);
session.on('change', onChangeListener);
onBlurListener = listenerFactory.onBlur(opts.onBlur);
acee.on('blur', onBlurListener);
elm.on('$destroy', function () {
acee.session.$stopWorker();
acee.destroy();
});
scope.$watch(function() {
return [elm[0].offsetWidth, elm[0].offsetHeight];
}, function() {
acee.resize();
acee.renderer.updateFull();
}, true);
}
};
}]);
app.directive('tabs', function ($parse) {
return {
restrict: 'AC',
link: function (scope, element, attrs) {
//find the tallest pane and make them all that size
/*var t = 0;
element.find(".tabs-body > div").each(function() {
var h = $(this).height();
if (h > t)
t = h;
});
if (t < 0)
element.find(".tabs-body").css("height", t + "px");*/
element.find(".tabs-head a").on("click", function() {
var i = $(this).parent().index();
element.find(".tabs-head li").removeClass("active");
$(this).parent().addClass("active");
element.find(".tabs-body > div").removeClass("active");
element.find(".tabs-body > div:eq(" + i + ")").addClass("active");
});
}
};
});
app.run(function($rootScope) {
/*$rootScope.themeConfig = {};
function loadThemeConfig() {
ThemeService.getCurrentTheme().then(function(config) {
$rootScope.themeConfig = config;
});
}
loadThemeConfig();
*/
});
app.controller('LoginController', function($scope, $location, GroupService) {
function init() {
GroupService.clearAllCache();
}
init();
});
app.controller('CMSController', function($scope, $location, UserService, $modal, $cookieStore, CacheService) {
$scope.pageData = null;
$scope.global = {
helloName: "",
isAdmin: false
};
$scope.menu = null;
$scope.menuClicked = function(item, sub) {
$scope.menu.selectedItem = item
if (item.items && item.items.length > 0) {
for(var i = 0; i < $scope.menu.items.length; i++) {
$scope.menu.items[i].expanded = false;
}
item.expanded = true;
}
};
$scope.editProfile = function() {
var modalInstance = $modal.open({
templateUrl: 'UserProfileDialog',
controller: UserProfileDialogController,
resolve: {
user: function () {
return $scope.pageData.user;
},
parentScope: function() {
return $scope;
}
}
});
modalInstance.result.then(function() {
//closed
});
};
$scope.setHelloName = function() {
var user = $scope.pageData.user;
if (user) {
$scope.global.helloName = (user.firstName && user.firstName.length > 0) ? user.firstName : user.username;
}
};
$scope.resize = function() {
if (arguments && arguments.length > 0) {
var winH = $(window).height();
//remove all min-heights
for (var i = 0; i < arguments.length; i++) {
var el = $(arguments[i]);
el.css("min-height", '');
}
var firstEl = $(arguments[0]);
var curH = firstEl.height();
var h = (winH - 70);
if (curH > h)
h = curH;
firstEl.css("min-height", h + 'px');
//remaining elements are inside first element
for (var i = 1; i < arguments.length; i++) {
var el = $(arguments[i]);
el.css("min-height", h + 'px');
}
}
};
function init() {
var pageDataJson = $("#pageData").val();
$scope.pageData = JSON.parse(pageDataJson);
$scope.menu = $scope.pageData.menu;
$scope.global.isAdmin = $scope.pageData.isAdmin;
$scope.setHelloName();
//should we clear the cache
var cookie = $cookieStore.get('sheercms');
if (cookie) {
/*if (cookie.clearCache == true) {
CacheService.clearClientCache();
cookie.clearCache = false;
$cookieStore.put('sheercms', cookie);
}*/
$scope.global.cookie = cookie;
}
//select the first menu item
$scope.menu.selectedItem = $scope.menu.items[0];
$scope.$on('$locationChangeStart', function(event) {
$scope.menu.selectedItem = null;
var path = $location.path();
if (path && path.indexOf('/') === 0) {
if (path === '/') {
//my dashboard
$scope.menu.selectedItem = $scope.menu.items[0];
}
else {
path = '#' + path.substr(1);
for(var i = 0; i < $scope.menu.items.length; i++) {
var m = $scope.menu.items[i];
if (path === m.url) {
$scope.menu.selectedItem = m;
break;
}
}
}
}
});
}
init();
});