unserver-unify
Version:
562 lines (559 loc) • 21 kB
JavaScript
;
//Directive used to set metisMenu and minimalize button
angular.module('bamboo').directive('sideNavigation', function($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
// Call metsi to build when user signup
scope.$watch('authentication.user', function() {
$timeout(function() {
element.metisMenu();
});
});
}
};
}).directive('minimalizaSidebar', function($timeout) {
return {
restrict: 'A',
template: '<a class="navbar-minimalize minimalize-styl-2 btn btn-primary " href="" ng-click="minimalize()"><i class="fa fa-bars"></i></a>',
controller: function($scope) {
$scope.minimalize = function() {
angular.element('body').toggleClass('mini-navbar');
if (!angular.element('body').hasClass('mini-navbar') || angular.element('body').hasClass('body-small')) {
// Hide menu in order to smoothly turn on when maximize menu
angular.element('#side-menu').hide();
// For smoothly turn on menu
$timeout(function() {
angular.element('#side-menu').fadeIn(500);
}, 100);
} else {
// Remove all inline style from jquery fadeIn function to reset menu state
angular.element('#side-menu').removeAttr('style');
}
};
}
};
}).directive('contentList', function() {
return {
restrict: 'E',
templateUrl: 'components/content/content_list.html', // markup for template
scope: {
setting: '=' // allows data to be passed into directive from controller scope
}
};
}).directive('mobileContentListView', function() {
return {
restrict: 'E',
templateUrl: 'components/content/mobile_content_list_view.html', // markup for template
scope: {
setting: '=', // allows data to be passed into directive from controller scope
q: "@"
},
};
}).directive('contentListView', function() {
return {
restrict: 'E',
templateUrl: 'components/content/content_list_view.html', // markup for template
scope: {
setting: '=' // allows data to be passed into directive from controller scope
}
};
}).directive('contentListViewNews', function() {
return {
restrict: 'E',
templateUrl: 'components/content/content_list_view_news.html', // markup for template
scope: {
setting: '=' // allows data to be passed into directive from controller scope
}
};
}).directive('focusMe', function($timeout) {
return {
scope: {
trigger: '@focusMe'
},
link: function(scope, element) {
scope.$watch('trigger', function(value) {
if (value === "true") {
$timeout(function() {
element[0].focus();
});
}
});
}
};
}).directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
var onChange = $parse(attrs.onChange);
element.bind('change', function() {
scope.$apply(function() {
modelSetter(scope, element[0].files[0]);
onChange(scope);
});
});
}
};
}]).directive('ngThumb', ['$window', function($window) {
var helper = {
support: !!($window.FileReader && $window.CanvasRenderingContext2D),
isFile: function(item) {
return angular.isObject(item) && item instanceof $window.File;
},
isImage: function(file) {
var type = '|' + file.type.slice(file.type.lastIndexOf('/') + 1) + '|';
return '|jpg|png|jpeg|bmp|gif|'.indexOf(type) !== -1;
}
};
return {
restrict: 'A',
template: '<canvas/>',
link: function(scope, element, attributes) {
if (!helper.support) return;
var params = scope.$eval(attributes.ngThumb);
if (!helper.isFile(params.file)) return;
if (!helper.isImage(params.file)) return;
var canvas = element.find('canvas');
var reader = new FileReader();
reader.onload = onLoadFile;
reader.readAsDataURL(params.file);
function onLoadFile(event) {
var img = new Image();
img.onload = onLoadImage;
img.src = event.target.result;
}
function onLoadImage() {
var width = params.width || this.width / this.height * params.height;
var height = params.height || this.height / this.width * params.width;
canvas.attr({
width: width,
height: height
});
canvas[0].getContext('2d').drawImage(this, 0, 0, width, height);
}
}
};
}]).directive('passwordConfirm', ['$parse', function($parse) {
return {
restrict: 'A',
scope: {
matchTarget: '=',
},
require: 'ngModel',
link: function link(scope, elem, attrs, ctrl) {
var validator = function(value) {
ctrl.$setValidity('match', value === scope.matchTarget);
return value;
}
ctrl.$parsers.unshift(validator);
ctrl.$formatters.push(validator);
// This is to force validator when the original password gets changed
scope.$watch('matchTarget', function(newval, oldval) {
validator(ctrl.$viewValue);
});
}
};
}]).directive('preventAction', [function() {
return {
restrict: 'A',
link: function($scope, $ele) {
$ele.bind("contextmenu cut copy", function(e) {
e.preventDefault();
})
}
}
}]).factory('$translateStaticFilesLoader', ['$q', '$http', function($q, $http) {
return function(options) {
if (!options || (!angular.isString(options.prefix) || !angular.isString(options.suffix))) {
throw new Error('Couldn\'t load static files, no prefix or suffix specified!');
}
var deferred = $q.defer();
$http(angular.extend({
url: [
options.prefix,
options.key,
options.suffix
].join(''),
method: 'GET',
params: ''
}, options.$http)).then(function(res) {
deferred.resolve(res.data);
},function(res) {
deferred.reject(options.key);
});
return deferred.promise;
};
}]).directive('ngModelOnblur', function() {
// override the default input to update on blur
// from http://jsfiddle.net/cn8VF/
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elm, attr, ngModelCtrl) {
if (attr.type === 'radio' || attr.type === 'checkbox') return;
elm.unbind('input').unbind('keydown').unbind('change');
elm.bind('blur', function() {
scope.$apply(function() {
ngModelCtrl.$setViewValue(elm.val());
});
});
}
};
}).directive('json', ["$compile", function($compile) {
return {
restrict: 'E',
scope: {
child: '=',
type: '@',
defaultCollapsed: '='
},
link: function(scope, element) {
var stringName = "Text";
var objectName = "Object";
var arrayName = "Array";
var refName = "Reference";
var boolName = "Boolean";
scope.valueTypes = [stringName, objectName, arrayName, refName, boolName];
scope.sortableOptions = {
axis: 'y'
};
if (scope.$parent.defaultCollapsed === undefined) {
scope.collapsed = false;
} else {
scope.collapsed = scope.defaultCollapsed;
}
if (scope.collapsed) {
scope.chevron = "glyphicon-chevron-right";
} else {
scope.chevron = "glyphicon-chevron-down";
}
//////
// Helper functions
//////
var getType = function(obj) {
var type = Object.prototype.toString.call(obj);
if (type === "[object Object]") {
return "Object";
} else if (type === "[object Array]") {
return "Array";
} else if (type === "[object Boolean]") {
return "Boolean";
} else {
return "Literal";
}
};
var isNumber = function(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
};
scope.getType = function(obj) {
return getType(obj);
};
scope.toggleCollapse = function() {
if (scope.collapsed) {
scope.collapsed = false;
scope.chevron = "glyphicon-chevron-down";
} else {
scope.collapsed = true;
scope.chevron = "glyphicon-chevron-right";
}
};
scope.moveKey = function(obj, key, newkey) {
//moves key to newkey in obj
if (key !== newkey) {
obj[newkey] = obj[key];
delete obj[key];
}
};
scope.deleteKey = function(obj, key) {
if (getType(obj) == "Object") {
if (confirm('Delete "' + key + '" and all it contains?')) {
delete obj[key];
}
} else if (getType(obj) == "Array") {
if (confirm('Delete "' + obj[key] + '"?')) {
obj.splice(key, 1);
}
} else {
console.error("object to delete from was " + obj);
}
};
scope.addItem = function(obj) {
if (getType(obj) == "Object") {
// check input for key
if (scope.keyName == undefined || scope.keyName.length == 0) {
alert("Please fill in a name");
} else if (scope.keyName.indexOf("$") == 0) {
alert("The name may not start with $ (the dollar sign)");
} else if (scope.keyName.indexOf("_") == 0) {
alert("The name may not start with _ (the underscore)");
} else {
if (obj[scope.keyName]) {
if (!confirm('An item with the name "' + scope.keyName + '" exists already. Do you really want to replace it?')) {
return;
}
}
// add item to object
switch (scope.valueType) {
case stringName:
obj[scope.keyName] = scope.valueName ? scope.possibleNumber(scope.valueName) : "";
break;
case objectName:
obj[scope.keyName] = {};
break;
case arrayName:
obj[scope.keyName] = [];
break;
case refName:
obj[scope.keyName] = {
"Reference!!!!": "todo"
};
break;
case boolName:
obj[scope.keyName] = false;
break;
}
//clean-up
scope.keyName = "";
scope.valueName = "";
scope.showAddKey = false;
}
} else if (getType(obj) == "Array") {
// add item to array
switch (scope.valueType) {
case stringName:
obj.push(scope.valueName ? scope.valueName : "");
break;
case objectName:
obj.push({});
break;
case arrayName:
obj.push([]);
break;
case boolName:
obj.push(false);
break;
case refName:
obj.push({
"Reference!!!!": "todo"
});
break;
}
scope.valueName = "";
scope.showAddKey = false;
} else {
console.error("object to add to was " + obj);
}
};
scope.possibleNumber = function(val) {
return isNumber(val) ? parseFloat(val) : val;
};
//////
// Template Generation
//////
// Note:
// sometimes having a different ng-model and then saving it on ng-change
// into the object or array is necessary for all updates to work
// recursion
var switchTemplate = '<span ng-switch on="getType(val)" >' + '<json ng-switch-when="Object" child="val" type="object" default-collapsed="defaultCollapsed"></json>' + '<json ng-switch-when="Array" child="val" type="array" default-collapsed="defaultCollapsed"></json>' + '<span ng-switch-when="Boolean" type="boolean">' + '<input type="checkbox" ng-model="val" ng-model-onblur ng-change="child[key] = val">' + '</span>' + '<span ng-switch-default class="jsonLiteral"><input type="text" ng-model="val" ' + 'placeholder="Empty" ng-model-onblur ng-change="child[key] = possibleNumber(val)"/>' + '</span>' + '</span>';
// display either "plus button" or "key-value inputs"
var addItemTemplate = '<div ng-switch on="showAddKey" class="block" >' + '<span ng-switch-when="true">';
if (scope.type == "object") {
// input key
addItemTemplate += '<input placeholder="Name" type="text" ui-keyup="{\'enter\':\'addItem(child)\'}" ' + 'class="form-control input-sm addItemKeyInput" ng-model="$parent.keyName" /> ';
}
addItemTemplate +=
// value type dropdown
'<select ng-model="$parent.valueType" ng-options="option for option in valueTypes" class="form-control input-sm"' + 'ng-init="$parent.valueType=\'' + stringName + '\'" ui-keydown="{\'enter\':\'addItem(child)\'}"></select>'
// input value
+ '<span ng-show="$parent.valueType == \'' + stringName + '\'"> : <input type="text" placeholder="Value" ' + 'class="form-control input-sm addItemValueInput" ng-model="$parent.valueName" ui-keyup="{\'enter\':\'addItem(child)\'}"/></span> '
// Add button
+ '<button class="btn btn-primary btn-sm" ng-click="addItem(child)">Add</button> ' + '<button class="btn btn-default btn-sm" ng-click="$parent.showAddKey=false">Cancel</button>' + '</span>' + '<span ng-switch-default>'
// plus button
+ '<button class="addObjectItemBtn" ng-click="$parent.showAddKey = true"><i class="glyphicon glyphicon-plus"></i></button>' + '</span>' + '</div>';
// start template
if (scope.type == "object") {
var template = '<i ng-click="toggleCollapse()" class="glyphicon" ng-class="chevron"></i>' + '<span class="jsonItemDesc">' + objectName + '</span>' + '<div class="jsonContents" ng-hide="collapsed">'
// repeat
+ '<span class="block" ng-hide="key.indexOf(\'_\') == 0" ng-repeat="(key, val) in child">'
// object key
+ '<span class="jsonObjectKey">' + '<input class="keyinput" type="text" ng-model="newkey" ng-init="newkey=key" ' + 'ng-blur="moveKey(child, key, newkey)"/>'
// delete button
+ '<i class="deleteKeyBtn glyphicon glyphicon-trash" ng-click="deleteKey(child, key)"></i>' + '</span>'
// object value
+ '<span class="jsonObjectValue">' + switchTemplate + '</span>' + '</span>'
// repeat end
+ addItemTemplate + '</div>';
} else if (scope.type == "array") {
var template = '<i ng-click="toggleCollapse()" class="glyphicon"' + 'ng-class="chevron"></i>' + '<span class="jsonItemDesc">' + arrayName + '</span>' + '<div class="jsonContents" ng-hide="collapsed">' + '<ol class="arrayOl" ui-sortable="sortableOptions" ng-model="child">'
// repeat
+ '<li class="arrayItem" ng-repeat="val in child">'
// delete button
+ '<i class="deleteKeyBtn glyphicon glyphicon-trash" ng-click="deleteKey(child, $index)"></i>' + '<i class="moveArrayItemBtn glyphicon glyphicon-align-justify"></i>' + '<span>' + switchTemplate + '</span>' + '</li>'
// repeat end
+ '</ol>' + addItemTemplate + '</div>';
} else {
console.error("scope.type was " + scope.type);
}
var newElement = angular.element(template);
$compile(newElement)(scope);
element.replaceWith(newElement);
}
};
}]).filter('encodeURIComponent', function() {
return window.encodeURIComponent;
}).filter('offset', function() {
return function(input, start) {
if (input instanceof Array) {
start = parseInt(start, 10);
return input.slice(start);
} else {
return input;
}
};
}).filter('numToLetters', function() {
var fn = function(num) {
var mod = num % 26,
pow = num / 26 | 0,
out = mod ? String.fromCharCode(64 + mod) : (--pow, 'Z');
return pow ? fn(pow) + out : out;
};
return function(input) {
return fn(input);
};
}).filter('fileSize', function() {
return function(input) {
if (isNaN(input)) return input;
if (input < (1024 * 1024)) {
return (input / 1024).toFixed(2) + ' KB ';
} else {
return (input / 1024 / 1024).toFixed(2) + ' MB ';
}
};
}).filter('kbFileSize', function() {
return function(input) {
if (isNaN(input)) return input;
return Math.round(input / 1024) + ' KB';
};
}).filter('secondsToDateTime', [function() {
return function(seconds) {
return new Date(1970, 0, 1).setSeconds(seconds);
};
}]).filter('trans', function($rootScope) {
var tran = function(obj) {
if ($rootScope.currentLanguage == 'Chinese') {
return obj.chn || obj;
} else {
return obj.eng || obj;
}
}
tran.$stateful = true;
return tran;
}).filter('isEmpty', function() {
var bar;
return function(obj) {
// null and undefined are "empty"
if (obj == null) return true;
// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return false;
if (obj.length === 0) return true;
// Otherwise, does it have any properties of its own?
// Note that this doesn't handle
// toString and valueOf enumeration bugs in IE < 9
for (bar in obj) {
if (obj.hasOwnProperty(bar)) {
return false;
}
}
return true;
};
}).filter('notEmpty', function() {
var bar;
return function(obj) {
// null and undefined are "empty"
if (obj == null) return false;
// Assume if it has a length property with a non-zero value
// that that property is correct.
if (obj.length > 0) return true;
if (obj.length === 0) return false;
// Otherwise, does it have any properties of its own?
// Note that this doesn't handle
// toString and valueOf enumeration bugs in IE < 9
for (bar in obj) {
if (obj.hasOwnProperty(bar)) {
return true;
}
}
return false;
};
}).directive("averageStarRating", function() {
return {
restrict: "AE",
template: "<div class='average-rating-container'>" + " <ul class='rating background' class='readonly'>" + " <li ng-repeat='star in stars' class='star'>" + " <i class='fa fa-star'></i>" + //★
" </li>" + " </ul>" + " <ul class='rating foreground' class='readonly' style='width:{{filledInStarsContainerWidth}}%'>" + " <li ng-repeat='star in stars' class='star filled'>" + " <i class='fa fa-star'></i>" + //★
" </li>" + " </ul>" + "</div>",
scope: {
ratingValue: "=",
max: "=max", //optional: default is 5
},
link: function(scope, elem) {
if (scope.max == undefined) {
scope.max = 5;
}
function updateStars() {
scope.stars = [];
for (var i = 0; i < scope.max; i++) {
scope.stars.push({});
}
var starContainerMaxWidth = 100; //%
scope.filledInStarsContainerWidth = scope.ratingValue / scope.max * starContainerMaxWidth;
}
scope.$watch('ratingValue', function(newval) {
if (newval) {
updateStars();
}
});
}
};
}).directive('pageSelect', function() {
return {
restrict: 'E',
template: '<input type="text" size="2" class="select-page" ng-model="inputPage" ng-change="selectPage(inputPage)">',
link: function(scope, element) {
scope.$watch('currentPage', function(c) {
scope.inputPage = c;
});
}
}
}).directive("scroll", function($window) {
return function(scope, element) {
angular.element($window).bind("scroll", function() {
if (this.pageYOffset >= 300) {
scope.bottomFlag = true;
//console.log('Scrolled below header.');
} else {
scope.bottomFlag = false;
//console.log('Header is in view.');
}
scope.$apply();
});
};
}).directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
}).directive('parseStyle', function() {
return function(scope, elem)
{
elem.html(scope.$eval('\'' + elem.html() + '\''));
}
});