Initial Commit

This commit is contained in:
root
2013-05-06 03:38:29 -04:00
commit d392a540e7
134 changed files with 22012 additions and 0 deletions

74
public/js/app.js Normal file
View File

@ -0,0 +1,74 @@
var biomed = {};
angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directives', 'ngResource', 'ui.bootstrap.dialog'])
.run(function($rootScope) {
$rootScope.TECH_GROUPS = {
all: 'All',
biomed: 'Biomed',
ice: 'Ice',
sales: 'Sales',
other: 'Others'
};
})
.config(function($routeProvider, $locationProvider, $httpProvider) {
var JSON_START = /^\s*(\[|\{[^\{])/,
JSON_END = /[\}\]]\s*$/,
PROTECTION_PREFIX = /^\)\]\}',?\n/,
DATE_MATCHER = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
$httpProvider.defaults.transformResponse = [function(data) {
if (angular.isString(data)) {
data = data.replace(PROTECTION_PREFIX, '');
if (JSON_START.test(data) && JSON_END.test(data)) {
data = JSON.parse(data, function(key, val) {
if (DATE_MATCHER.test(val))
return new Date(val);
return val;
})
}
return data;
}
}];
$locationProvider.html5Mode(true);
$routeProvider
.when('/schedule', {
templateUrl: '/partials/schedule/index.html',
controller: biomed.ScheduleIndexCtrl
})
.when('/schedule/pms', {
templateUrl: '/partials/schedule/pms.html',
controller: biomed.SchedulePmsCtrl
})
.when('/clients', {
templateUrl: '/partials/clients/index.html',
controller: biomed.ClientIndexCtrl,
reloadOnSearch: false
})
.when('/clients/add', {
templateUrl: '/partials/clients/add.html',
controller: biomed.ClientAddCtrl
})
.when('/clients/:id', {
templateUrl: '/partials/clients/edit.html',
controller: biomed.ClientEditCtrl
})
.when('/workorders', {
templateUrl: '/partials/workorders/index.html',
controller: biomed.WorkorderIndexCtrl,
reloadOnSearch: false
})
.when('/workorders/add', {
templateUrl: '/partials/workorders/add.html',
controller: biomed.WorkorderAddCtrl
})
.when('/workorders/:id', {
templateUrl: '/partials/workorders/edit.html',
controller: biomed.WorkorderEditCtrl
})
.otherwise({
redirectTo: '/schedule'
});
});

533
public/js/controllers.js Normal file
View File

@ -0,0 +1,533 @@
biomed.AccountCtrl = function($scope, Account) {
$scope.account = Account.get();
};
biomed.ScheduleIndexCtrl = function($scope, $location, Users, Schedule, LocationBinder) {
// LocationBinder($scope, ['date'], { date: new Date() });
updateUsers();
if (!$scope.date) {
$scope.date = new Date();
}
$scope.group = 'all';
$scope.$watch('date', updateDate);
$scope.$watch('group', updateUsers);
$scope.onEntryClick = function(entry) {
$location.path('/workorders/' + entry.workorder._id);
};
function updateDate() {
Schedule.index({
date: $scope.date.toJSON()
}, function(result) {
$scope.schedule = result;
});
}
function updateUsers() {
Users.index({ group: $scope.group }, function(result) {
$scope.users = result;
});
}
};
biomed.SchedulePmsCtrl = function($scope, Clients) {
$scope.loading = true;
$scope.month = moment().month();
var allData = Clients.frequencies(function() {
filter();
$scope.loading = false;
});
function filter() {
$scope.pms = [];
angular.forEach(allData, function(client) {
angular.forEach(client.frequencies, function(value, key) {
if (value[$scope.month]) {
$scope.pms.push({
reason: key,
client: client
});
}
});
});
}
$scope.$watch('month', filter);
};
biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, LocationBinder) {
$scope.loading = true;
var allData = Clients.index(function() {
$scope.loading = false;
$scope.filter();
});
var filteredData = [];
var index = 0;
var initialPageSize = 100;
var pageSize = 5;
$scope.canLoad = true;
$scope.$watch('query', function() {
$scope.filter();
});
LocationBinder($scope, ['query']);
$scope.filter = function() {
filteredData = $filter('filter')(allData, $scope.query);
index = initialPageSize;
$scope.canLoad = true;
$scope.clients = filteredData.slice(0, initialPageSize);
};
$scope.addItems = function() {
$scope.clients = $scope.clients.concat(filteredData.slice(index, index + pageSize));
index += pageSize;
$scope.canLoad = index < filteredData.length;
}
};
biomed.ClientAddCtrl = function($scope, Clients, $location) {
$scope.save = function() {
$scope.model.contacts = [$scope.primaryContact, $scope.secondaryContact];
Clients.create($scope.model, function(result) {
$location.path("/clients/" + result._id);
})
};
};
biomed.ClientEditCtrl = function($scope, $routeParams, Clients) {
$scope.route = $routeParams;
$scope.loading = true;
$scope.master = Clients.get($routeParams, function() {
$scope.loading = false;
});
$scope.workorders = Clients.workorders($routeParams, function() {
updatePms();
});
$scope.identification = createController();
$scope.address = createController();
$scope.primaryContact = createContactController(0);
$scope.secondaryContact = createContactController(1);
$scope.other = createOtherController();
function updatePms() {
var currentMonth = new Date().getMonth();
$scope.pms = [];
angular.forEach($scope.master.frequencies, function(value, key) {
if (value[currentMonth]) {
$scope.pms.push(key);
}
});
}
function createOtherController() {
var controller = {
edit: function() {
if (!$scope.editing) {
angular.copy($scope.master, controller.model);
controller.visible = true;
$scope.editing = true;
}
},
destroy: function() {
Clients.destroy({id: $scope.master._id});
window.history.back();
},
reset: function() {
angular.copy($scope.master, controller.model);
controller.visible = false;
$scope.editing = false;
},
model: {},
form: {}
};
return controller;
}
function createController() {
var controller = {
edit: function() {
if (!$scope.editing) {
angular.copy($scope.master, controller.model);
controller.visible = true;
$scope.editing = true;
}
},
save: function() {
Clients.update({id: $scope.master._id}, controller.model);
angular.copy(controller.model, $scope.master);
controller.visible = false;
$scope.editing = false;
},
reset: function() {
angular.copy($scope.master, controller.model);
controller.visible = false;
$scope.editing = false;
},
model: {},
form: {}
};
return controller;
}
function createContactController(index) {
var controller = {
edit: function() {
if (!$scope.editing) {
angular.copy($scope.master, controller.model);
if (!controller.model.contacts[index]) {
controller.model.contacts[index] = {};
}
controller.visible = true;
$scope.editing = true;
}
},
save: function() {
Clients.update({id: $scope.master._id}, controller.model);
angular.copy(controller.model, $scope.master);
controller.visible = false;
$scope.editing = false;
},
reset: function() {
angular.copy($scope.master, controller.model);
controller.visible = false;
$scope.editing = false;
},
model: {},
form: {}
};
return controller;
}
$scope.toggleFrequency = function(frequency, month) {
$scope.master.frequencies[frequency][month] =! $scope.master.frequencies[frequency][month];
Clients.update({id: $scope.master._id}, $scope.master, function() {
updatePms();
});
}
};
biomed.WorkorderIndexCtrl = function($scope, $filter, $routeParams, Workorders, LocationBinder) {
$scope.loading = true;
var data = {};
var defaultEnd = moment().toDate();
var defaultStart = moment(defaultEnd).subtract('days', 7).toDate();
LocationBinder($scope, ['query', 'start', 'end'], {
start: defaultStart,
end: defaultEnd
});
fetchData();
var filteredData = [];
var index = 0;
var initialPageSize = 100;
var pageSize = 5;
$scope.canLoad = true;
$scope.$watch('query', filter);
$scope.$watch('start', fetchData);
$scope.$watch('end', fetchData);
$scope.addItems = function() {
$scope.workorders = $scope.workorders.concat(filteredData.slice(index, index + pageSize));
index += pageSize;
$scope.canLoad = index < filteredData.length;
}
function filter() {
filteredData = $filter('filter')(data, $scope.query);
index = initialPageSize;
$scope.canLoad = true;
$scope.workorders = filteredData.slice(0, initialPageSize);
};
function fetchData() {
$scope.loading = true;
data = Workorders.index({
start: $scope.start.toJSON(),
end: $scope.end.toJSON()
}, function() {
$scope.loading = false;
filter();
});
}
}
biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clients, Users) {
$scope.group = 'all';
$scope.model = {};
$scope.picker = {
start: '09:00:00',
end: '17:00:00'
};
$scope.picker.date = new Date();
var search = $location.search();
if (search.clientId) {
$scope.model.client = search.clientId;
}
if (search.reason) {
$scope.model.reason = search.reason;
}
if (search.remarks) {
$scope.model.remarks = search.remarks;
}
updateAllUsers();
updateUsers();
$scope.$watch('group', updateUsers);
Clients.index(function(result) {
$scope.clients = result;
});
$scope.$watch('picker.date', function() {
Schedule.index({
date: $scope.picker.date.toJSON()
}, function(result) {
$scope.schedule = result;
});
});
$scope.save = function() {
var picker = $scope.picker;
var model = $scope.model;
var date = moment(picker.date).format('YYYY-MM-DD');
model.status = 'scheduled';
model.scheduling = {};
model.scheduling.start = moment(date + 'T' + picker.start).toDate();
model.scheduling.end = moment(date + 'T' + picker.end).toDate();
Workorders.create(model, function(result) {
$location.path("/workorders/" + result._id);
});
};
function updateUsers() {
Users.index({ group: $scope.group }, function(result) {
$scope.users = result;
});
}
function updateAllUsers() {
var criteria = {};
Users.index(criteria, function(result) {
$scope.allUsers = result;
$scope.usersMap = {};
$scope.allUsers.forEach(function(user) {
$scope.usersMap[user._id] = user;
});
});
}
}
biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, Users) {
$scope.group = 'all';
$scope.route = $routeParams;
$scope.loading = true;
updateAllUsers();
updateUsers();
$scope.$watch('group', updateUsers);
$scope.master = Workorders.get($routeParams, function() {
$scope.loading = false;
});
$scope.status = createController();
$scope.remarks = createController();
$scope.scheduling = createSchedulingController();
$scope.destroy = function() {
Workorders.destroy({id: $scope.master._id});
window.history.back();
}
function createController() {
var controller = {
edit: function() {
if (!$scope.editing) {
angular.copy($scope.master, controller.model);
controller.visible = true;
$scope.editing = true;
}
},
save: function() {
Workorders.update({id: $scope.master._id}, controller.model);
angular.copy(controller.model, $scope.master);
controller.visible = false;
$scope.editing = false;
},
reset: function() {
angular.copy($scope.master, controller.model);
controller.visible = false;
$scope.editing = false;
},
model: {},
form: {}
};
return controller;
}
function createSchedulingController() {
var controller = {
edit: function() {
if (!$scope.editing) {
angular.copy($scope.master, controller.model);
controller.date = moment(controller.model.scheduling.start).startOf('day').toDate();
controller.start = moment(controller.model.scheduling.start).format('HH:mm:ss');
controller.end = moment(controller.model.scheduling.end).format('HH:mm:ss');
controller.techs = controller.model.techs.map(function(t) { return t._id; });
controller.visible = true;
$scope.editing = true;
}
},
save: function() {
var date = moment(controller.date).format('YYYY-MM-DD');
controller.model.scheduling.start = moment(date + 'T' + controller.start).toDate();
controller.model.scheduling.end = moment(date + 'T' + controller.end).toDate();
controller.model.techs = controller.techs.map(function(t) { return $scope.usersMap[t]; });
Workorders.update({id: $scope.master._id}, controller.model);
angular.copy(controller.model, $scope.master);
controller.visible = false;
$scope.editing = false;
},
reset: function() {
angular.copy($scope.master, controller.model);
controller.visible = false;
$scope.editing = false;
},
model: {},
form: {}
};
$scope.$watch('scheduling.date', function() {
Schedule.index({
date: $scope.scheduling.date.toJSON()
}, function(result) {
$scope.scheduling.schedule = result;
});
});
return controller;
}
function updateUsers() {
Users.index({ group: $scope.group }, function(result) {
$scope.users = result;
});
}
function updateAllUsers() {
var criteria = {};
Users.index(criteria, function(result) {
$scope.allUsers = result;
$scope.usersMap = {};
$scope.allUsers.forEach(function(user) {
$scope.usersMap[user._id] = user;
});
});
}
};
biomed.PageCtrl = function($scope, $dialog) {
$scope.opts = {
backdrop: true,
keyboard: true,
backdropClick: true,
dialogFade: true,
backdropFade: true,
templateUrl: '/partials/messages.html',
controller: 'biomed.MessagesCtrl'
};
$scope.openDialog = function(){
var d = $dialog.dialog($scope.opts);
d.open();
};
};
biomed.MessagesCtrl = function($scope, dialog, Users, Messages) {
$scope.model = {};
$scope.model.messages = [
{ message: 'Telephoned', checked: false },
{ message: 'Came to see you', checked: false },
{ message: 'Wants to see you', checked: false },
{ message: 'Returned your call', checked: false },
{ message: 'Please call', checked: false },
{ message: 'Will call again', checked: false },
{ message: 'Rush', checked: false },
{ message: 'Special Attention', checked: false }
];
Users.index({ perms: "messages.receive" }, function(result) {
$scope.users = result;
});
$scope.send = function() {
Messages.send($scope.model, function(result) {
dialog.close();
});
};
$scope.cancel = function() {
dialog.close();
};
};

423
public/js/directives.js Normal file
View File

@ -0,0 +1,423 @@
angular.module('biomed.directives', [])
.directive("bioNavbar", function($location) {
return {
restrict: 'A',
link: function($scope, element, attrs, controller) {
$scope.$watch(function() {
return $location.path();
}, function(newValue, oldValue) {
element.find('li[data-match-route]').each(function(k, li) {
var $li = angular.element(li);
var pattern = $li.attr('data-match-route');
var regex = new RegExp('^' + pattern + '$', ['i']);
if (regex.test(newValue)) {
$li.addClass('active');
} else {
$li.removeClass('active');
}
});
});
}
}
})
.directive('infiniteScroll', function ($window) {
return {
link:function (scope, element, attrs) {
var offset = parseInt(attrs.threshold) || 0;
var e = angular.element($window);
e.bind("scroll", function() {
if (scope.canLoad && e.height() + e.scrollTop() >= $(document).height() - offset) {
scope.$apply(attrs.infiniteScroll);
}
});
}
}
})
.directive('tabbable', function() {
return {
restrict: 'C',
compile: function(element) {
var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
tabContent = angular.element('<div class="tab-content"></div>');
tabContent.append(element.contents());
element.append(navTabs).append(tabContent);
},
controller: ['$scope', '$element', function($scope, $element) {
var navTabs = $element.contents().eq(0),
ngModel = $element.controller('ngModel') || {},
tabs = [],
selectedTab;
ngModel.$render = function() {
var $viewValue = this.$viewValue;
if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
if(selectedTab) {
selectedTab.paneElement.removeClass('active');
selectedTab.tabElement.removeClass('active');
selectedTab = null;
}
if($viewValue) {
for(var i = 0, ii = tabs.length; i < ii; i++) {
if ($viewValue == tabs[i].value) {
selectedTab = tabs[i];
break;
}
}
if (selectedTab) {
selectedTab.paneElement.addClass('active');
selectedTab.tabElement.addClass('active');
}
}
}
};
this.addPane = function(element, attr) {
var li = angular.element('<li><a href></a></li>'),
a = li.find('a'),
tab = {
paneElement: element,
paneAttrs: attr,
tabElement: li
};
tabs.push(tab);
attr.$observe('value', update)();
attr.$observe('title', function(){ update(); a.text(tab.title); })();
function update() {
tab.title = attr.title;
tab.value = attr.value || attr.title;
if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
// we are not part of angular
ngModel.$viewValue = tab.value;
}
ngModel.$render();
}
navTabs.append(li);
li.bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
if (ngModel.$setViewValue) {
$scope.$apply(function() {
ngModel.$setViewValue(tab.value);
ngModel.$render();
});
} else {
// we are not part of angular
ngModel.$viewValue = tab.value;
ngModel.$render();
}
});
return function() {
tab.tabElement.remove();
for(var i = 0, ii = tabs.length; i < ii; i++ ) {
if (tab == tabs[i]) {
tabs.splice(i, 1);
}
}
};
}
}]
};
})
.directive('tabPane', function() {
return {
require: '^tabbable',
restrict: 'C',
link: function(scope, element, attrs, tabsCtrl) {
element.bind('$remove', tabsCtrl.addPane(element, attrs));
}
};
})
.directive('datepicker', function($timeout) {
var isTouch = 'ontouchstart' in window && !window.navigator.userAgent.match(/PhantomJS/i);
return {
restrict: 'A',
require: '?ngModel',
link: function postLink(scope, element, attrs, controller) {
var format = 'MM-DD-YYYY';
// Handle date validity according to dateFormat
if(controller) {
controller.$formatters.unshift(function(value) {
return moment(value).format(format);
});
controller.$parsers.unshift(function(viewValue) {
if (angular.isDate(viewValue)) {
return viewValue;
} else {
var date = moment(viewValue);
if (date.isValid()) {
return date;
} else {
return undefined;
}
}
});
}
// Use native interface for touch devices
if(isTouch && element.prop('type') === 'text') {
element.prop('type', 'date');
element.on('change', function(ev) {
scope.$apply(function () {
controller.$setViewValue(moment(element.val()).toDate());
});
});
} else {
// If we have a controller (i.e. ngModelController) then wire it up
if(controller) {
element.on('changeDate', function(ev) {
scope.$apply(function () {
controller.$setViewValue(moment(element.val()).toDate());
});
});
}
// Popover GarbageCollection
var $popover = element.closest('.popover');
if($popover) {
$popover.on('hide', function(e) {
var datepicker = element.data('datepicker');
if(datepicker) {
datepicker.picker.remove();
element.data('datepicker', null);
}
});
}
// Create datepicker
element.attr('data-toggle', 'datepicker');
element.datepicker({
autoclose: true,
format: 'mm-dd-yyyy',
forceParse: attrs.forceParse || false
});
}
// Support add-on
var component = element.siblings('[data-toggle="datepicker"]');
if(component.length) {
component.on('click', function() { element.trigger('focus'); });
}
}
};
})
.directive('techpicker', function() {
return {
restrict: 'E',
scope: {
users: '=',
schedule: '=',
date: '=',
onEntryClick: '&'
},
templateUrl: '/partials/techPicker.html',
replace: true,
link: function($scope, element, attrs) {
var timePickerParser = d3.time.format('%I:%M%p');
var rangeStart = timePickerParser.parse('7:00am');
var rangeEnd = timePickerParser.parse('10:00pm');
var x = d3.time.scale()
.range([0, 100])
.domain([rangeStart, rangeEnd]);
var color = d3.scale.category20();
var totalHours = moment.duration(moment(rangeEnd) - moment(rangeStart)).hours();
var hourWidth = 100 / totalHours;
$scope.hourMarkers = [];
for (var i = 0; i < totalHours; i++) {
var date = moment(rangeStart).add('hours', i).toDate();
$scope.hourMarkers.push({
date: date,
style: {
left: x(date) + "%",
width: hourWidth + "%"
}
});
}
$scope.$watch('users', function(newVal, oldVal) {
generateDate();
});
$scope.$watch('schedule', function(newVal, oldVal) {
generateDate();
});
function generateDate() {
var data = {};
var labels = [];
angular.forEach($scope.users, function(user) {
var key = user.name.first + ' ' + user.name.last;
labels.push(key);
data[key] = [];
});
labels.sort();
color.domain(labels);
angular.forEach($scope.schedule, function(workorder) {
angular.forEach(workorder.techs, function(tech) {
var key = tech.name.first + ' ' + tech.name.last;
if (!data[key])
return;
var start = moment(workorder.scheduling.start).year(1900).month(0).date(1).toDate();
var end = moment(workorder.scheduling.end).year(1900).month(0).date(1).toDate();
data[key].push({
style: {
backgroundColor: color(key),
left: x(start) + "%",
width: (x(end) - x(start)) + "%"
},
workorder: workorder
});
})
});
$scope.data = data;
}
}
};
})
.directive('uiSelect2', function ($timeout) {
var options = {};
return {
require: '?ngModel',
compile: function (tElm, tAttrs) {
var watch,
repeatOption,
repeatAttr,
isSelect = tElm.is('select'),
isMultiple = (tAttrs.multiple !== undefined);
// Enable watching of the options dataset if in use
if (tElm.is('select')) {
repeatOption = tElm.find('option[ng-repeat], option[data-ng-repeat]');
if (repeatOption.length) {
repeatAttr = repeatOption.attr('ng-repeat') || repeatOption.attr('data-ng-repeat');
watch = jQuery.trim(repeatAttr.split('|')[0]).split(' ').pop();
}
}
return function (scope, elm, attrs, controller) {
// instance-specific options
var opts = angular.extend({}, options, scope.$eval(attrs.uiSelect2));
if (isSelect) {
// Use <select multiple> instead
delete opts.multiple;
delete opts.initSelection;
} else if (isMultiple) {
opts.multiple = true;
}
if (controller) {
// Watch the model for programmatic changes
controller.$render = function () {
if (isSelect) {
elm.select2('val', controller.$modelValue);
} else {
if (isMultiple) {
if (!controller.$modelValue) {
elm.select2('data', []);
} else if (angular.isArray(controller.$modelValue)) {
elm.select2('data', controller.$modelValue);
} else {
elm.select2('val', controller.$modelValue);
}
} else {
if (angular.isObject(controller.$modelValue)) {
elm.select2('data', controller.$modelValue);
} else {
elm.select2('val', controller.$modelValue);
}
}
}
};
// Watch the options dataset for changes
if (watch) {
scope.$watch(watch, function (newVal, oldVal, scope) {
if (!newVal) return;
// Delayed so that the options have time to be rendered
$timeout(function () {
elm.select2('val', controller.$viewValue);
// Refresh angular to remove the superfluous option
elm.trigger('change');
});
});
}
if (!isSelect) {
// Set the view and model value and update the angular template manually for the ajax/multiple select2.
elm.bind("change", function () {
scope.$apply(function () {
controller.$setViewValue(elm.select2('data'));
});
});
if (opts.initSelection) {
var initSelection = opts.initSelection;
opts.initSelection = function (element, callback) {
initSelection(element, function (value) {
controller.$setViewValue(value);
callback(value);
});
};
}
}
}
attrs.$observe('disabled', function (value) {
elm.select2(value && 'disable' || 'enable');
});
if (attrs.ngMultiple) {
scope.$watch(attrs.ngMultiple, function(newVal) {
elm.select2(opts);
});
}
// Set initial value since Angular doesn't
elm.val(scope.$eval(attrs.ngModel));
// Initialize the plugin late so that the injected DOM does not disrupt the template compiler
$timeout(function () {
elm.select2(opts);
// Not sure if I should just check for !isSelect OR if I should check for 'tags' key
if (!opts.initSelection && !isSelect)
controller.$setViewValue(elm.select2('data'));
});
};
}
};
});

16
public/js/filters.js Normal file
View File

@ -0,0 +1,16 @@
angular.module('biomed.filters', [])
.filter('techs', function() {
return function(techs) {
if (!techs) return techs;
return techs.map(function(tech) {
return tech.name.first + ' ' + tech.name.last;
}).join(', ');
};
})
.filter('time', function() {
return function(time) {
return moment(time).format('h:mma');
};
});

0
public/js/lib/angular-ui.js vendored Normal file
View File

1046
public/js/lib/bootstrap-datepicker.js vendored Normal file

File diff suppressed because it is too large Load Diff

369
public/js/lib/dialog.js Normal file
View File

@ -0,0 +1,369 @@
// The `$dialogProvider` can be used to configure global defaults for your
// `$dialog` service.
var dialogModule = angular.module('ui.bootstrap.dialog', ['ui.bootstrap.transition']);
dialogModule.controller('MessageBoxController', ['$scope', 'dialog', 'model', function($scope, dialog, model){
$scope.title = model.title;
$scope.message = model.message;
$scope.buttons = model.buttons;
$scope.close = function(res){
dialog.close(res);
};
}]);
dialogModule.provider("$dialog", function(){
// The default options for all dialogs.
var defaults = {
backdrop: true,
dialogClass: 'modal',
backdropClass: 'modal-backdrop',
transitionClass: 'fade',
triggerClass: 'in',
dialogOpenClass: 'modal-open',
resolve:{},
backdropFade: false,
dialogFade:false,
keyboard: true, // close with esc key
backdropClick: true // only in conjunction with backdrop=true
/* other options: template, templateUrl, controller */
};
var globalOptions = {};
var activeBackdrops = {value : 0};
// The `options({})` allows global configuration of all dialogs in the application.
//
// var app = angular.module('App', ['ui.bootstrap.dialog'], function($dialogProvider){
// // don't close dialog when backdrop is clicked by default
// $dialogProvider.options({backdropClick: false});
// });
this.options = function(value){
globalOptions = value;
};
// Returns the actual `$dialog` service that is injected in controllers
this.$get = ["$http", "$document", "$compile", "$rootScope", "$controller", "$templateCache", "$q", "$transition", "$injector",
function ($http, $document, $compile, $rootScope, $controller, $templateCache, $q, $transition, $injector) {
var body = $document.find('body');
function createElement(clazz) {
var el = angular.element("<div>");
el.addClass(clazz);
return el;
}
// The `Dialog` class represents a modal dialog. The dialog class can be invoked by providing an options object
// containing at lest template or templateUrl and controller:
//
// var d = new Dialog({templateUrl: 'foo.html', controller: 'BarController'});
//
// Dialogs can also be created using templateUrl and controller as distinct arguments:
//
// var d = new Dialog('path/to/dialog.html', MyDialogController);
function Dialog(opts) {
var self = this, options = this.options = angular.extend({}, defaults, globalOptions, opts);
this._open = false;
this.backdropEl = createElement(options.backdropClass);
if(options.backdropFade){
this.backdropEl.addClass(options.transitionClass);
this.backdropEl.removeClass(options.triggerClass);
}
this.modalEl = createElement(options.dialogClass);
if(options.dialogFade){
this.modalEl.addClass(options.transitionClass);
this.modalEl.removeClass(options.triggerClass);
}
this.handledEscapeKey = function(e) {
if (e.which === 27) {
self.close();
e.preventDefault();
self.$scope.$apply();
}
};
this.handleBackDropClick = function(e) {
self.close();
e.preventDefault();
self.$scope.$apply();
};
}
// The `isOpen()` method returns wether the dialog is currently visible.
Dialog.prototype.isOpen = function(){
return this._open;
};
// The `open(templateUrl, controller)` method opens the dialog.
// Use the `templateUrl` and `controller` arguments if specifying them at dialog creation time is not desired.
Dialog.prototype.open = function(templateUrl, controller){
var self = this, options = this.options;
if(templateUrl){
options.templateUrl = templateUrl;
}
if(controller){
options.controller = controller;
}
if(!(options.template || options.templateUrl)) {
throw new Error('Dialog.open expected template or templateUrl, neither found. Use options or open method to specify them.');
}
this._loadResolves().then(function(locals) {
var $scope = locals.$scope = self.$scope = locals.$scope ? locals.$scope : $rootScope.$new();
self.modalEl.html(locals.$template);
if (self.options.controller) {
var ctrl = $controller(self.options.controller, locals);
self.modalEl.contents().data('ngControllerController', ctrl);
}
$compile(self.modalEl)($scope);
self._addElementsToDom();
body.addClass(self.options.dialogOpenClass);
// trigger tranisitions
setTimeout(function(){
if(self.options.dialogFade){ self.modalEl.addClass(self.options.triggerClass); }
if(self.options.backdropFade){ self.backdropEl.addClass(self.options.triggerClass); }
});
self._bindEvents();
});
this.deferred = $q.defer();
return this.deferred.promise;
};
// closes the dialog and resolves the promise returned by the `open` method with the specified result.
Dialog.prototype.close = function(result){
var self = this;
var fadingElements = this._getFadingElements();
body.removeClass(self.options.dialogOpenClass);
if(fadingElements.length > 0){
for (var i = fadingElements.length - 1; i >= 0; i--) {
$transition(fadingElements[i], removeTriggerClass).then(onCloseComplete);
}
return;
}
this._onCloseComplete(result);
function removeTriggerClass(el){
el.removeClass(self.options.triggerClass);
}
function onCloseComplete(){
if(self._open){
self._onCloseComplete(result);
}
}
};
Dialog.prototype._getFadingElements = function(){
var elements = [];
if(this.options.dialogFade){
elements.push(this.modalEl);
}
if(this.options.backdropFade){
elements.push(this.backdropEl);
}
return elements;
};
Dialog.prototype._bindEvents = function() {
if(this.options.keyboard){ body.bind('keydown', this.handledEscapeKey); }
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.bind('click', this.handleBackDropClick); }
};
Dialog.prototype._unbindEvents = function() {
if(this.options.keyboard){ body.unbind('keydown', this.handledEscapeKey); }
if(this.options.backdrop && this.options.backdropClick){ this.backdropEl.unbind('click', this.handleBackDropClick); }
};
Dialog.prototype._onCloseComplete = function(result) {
this._removeElementsFromDom();
this._unbindEvents();
this.deferred.resolve(result);
};
Dialog.prototype._addElementsToDom = function(){
body.append(this.modalEl);
if(this.options.backdrop) {
if (activeBackdrops.value === 0) {
body.append(this.backdropEl);
}
activeBackdrops.value++;
}
this._open = true;
};
Dialog.prototype._removeElementsFromDom = function(){
this.modalEl.remove();
if(this.options.backdrop) {
activeBackdrops.value--;
if (activeBackdrops.value === 0) {
this.backdropEl.remove();
}
}
this._open = false;
};
// Loads all `options.resolve` members to be used as locals for the controller associated with the dialog.
Dialog.prototype._loadResolves = function(){
var values = [], keys = [], templatePromise, self = this;
if (this.options.template) {
templatePromise = $q.when(this.options.template);
} else if (this.options.templateUrl) {
templatePromise = $http.get(this.options.templateUrl, {cache:$templateCache})
.then(function(response) { return response.data; });
}
angular.forEach(this.options.resolve || [], function(value, key) {
keys.push(key);
values.push(angular.isString(value) ? $injector.get(value) : $injector.invoke(value));
});
keys.push('$template');
values.push(templatePromise);
return $q.all(values).then(function(values) {
var locals = {};
angular.forEach(values, function(value, index) {
locals[keys[index]] = value;
});
locals.dialog = self;
return locals;
});
};
// The actual `$dialog` service that is injected in controllers.
return {
// Creates a new `Dialog` with the specified options.
dialog: function(opts){
return new Dialog(opts);
},
// creates a new `Dialog` tied to the default message box template and controller.
//
// Arguments `title` and `message` are rendered in the modal header and body sections respectively.
// The `buttons` array holds an object with the following members for each button to include in the
// modal footer section:
//
// * `result`: the result to pass to the `close` method of the dialog when the button is clicked
// * `label`: the label of the button
// * `cssClass`: additional css class(es) to apply to the button for styling
messageBox: function(title, message, buttons){
return new Dialog({templateUrl: 'template/dialog/message.html', controller: 'MessageBoxController', resolve:
{model: function() {
return {
title: title,
message: message,
buttons: buttons
};
}
}});
}
};
}];
});
angular.module('ui.bootstrap.transition', [])
/**
* $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
* @param {DOMElement} element The DOMElement that will be animated.
* @param {string|object|function} trigger The thing that will cause the transition to start:
* - As a string, it represents the css class to be added to the element.
* - As an object, it represents a hash of style attributes to be applied to the element.
* - As a function, it represents a function to be called that will cause the transition to occur.
* @return {Promise} A promise that is resolved when the transition finishes.
*/
.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
var $transition = function(element, trigger, options) {
options = options || {};
var deferred = $q.defer();
var endEventName = $transition[options.animation ? "animationEndEventName" : "transitionEndEventName"];
var transitionEndHandler = function(event) {
$rootScope.$apply(function() {
element.unbind(endEventName, transitionEndHandler);
deferred.resolve(element);
});
};
if (endEventName) {
element.bind(endEventName, transitionEndHandler);
}
// Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
$timeout(function() {
if ( angular.isString(trigger) ) {
element.addClass(trigger);
} else if ( angular.isFunction(trigger) ) {
trigger(element);
} else if ( angular.isObject(trigger) ) {
element.css(trigger);
}
//If browser does not support transitions, instantly resolve
if ( !endEventName ) {
deferred.resolve(element);
}
});
// Add our custom cancel function to the promise that is returned
// We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
// i.e. it will therefore never raise a transitionEnd event for that transition
deferred.promise.cancel = function() {
if ( endEventName ) {
element.unbind(endEventName, transitionEndHandler);
}
deferred.reject('Transition cancelled');
};
return deferred.promise;
};
// Work out the name of the transitionEnd event
var transElement = document.createElement('trans');
var transitionEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
};
var animationEndEventNames = {
'WebkitTransition': 'webkitAnimationEnd',
'MozTransition': 'animationend',
'OTransition': 'oAnimationEnd',
'msTransition': 'MSAnimationEnd',
'transition': 'animationend'
};
function findEndEventName(endEventNames) {
for (var name in endEventNames){
if (transElement.style[name] !== undefined) {
return endEventNames[name];
}
}
}
$transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
$transition.animationEndEventName = findEndEventName(animationEndEventNames);
return $transition;
}]);

1400
public/js/lib/moment.js Normal file

File diff suppressed because it is too large Load Diff

2407
public/js/lib/select2.js Normal file

File diff suppressed because it is too large Load Diff

114
public/js/services.js Normal file
View File

@ -0,0 +1,114 @@
angular.module('biomed.services', [])
.factory("Clients", function($resource) {
return $resource('/api/clients/:id/:cmd',
{ id: "@id", cmd: "@cmd" },
{
index: { method: 'GET', params: {}, isArray: true },
frequencies:{ method: 'GET', params: { cmd: 'frequencies' }, isArray: true },
get: { method: 'GET', params: { id: 0} },
create: { method: 'POST', params: {} },
update: { method: 'POST', params: { id: 0} },
destroy: { method: 'DELETE', params: { id: 0 } },
workorders: { method: 'GET', params: { id: 0, cmd: 'workorders' }, isArray: true }
});
})
.factory("Workorders", function($resource) {
return $resource('/api/workorders/:id',
{ id: "@id" },
{
index: { method: 'GET', params: {}, isArray: true },
get: { method: 'GET', params: { id: 0} },
create: { method: 'POST', params: {} },
update: { method: 'POST', params: { id: 0} },
destroy: { method: 'DELETE', params: { id: 0 } },
});
})
.factory("Users", function($resource) {
return $resource('/api/users', { },
{
index: { method: 'GET', isArray: true },
});
})
.factory("Schedule", function($resource) {
return $resource('/api/schedule', { },
{
index: { method: 'GET', isArray: true },
});
})
.factory("Account", function($resource) {
return $resource('/api/account',
{ id: "@id", cmd: "@cmd" },
{
get: { method: 'GET' },
});
})
.factory("Messages", function($resource) {
return $resource('/api/messages/:cmd',
{ cmd: "@cmd" },
{
send: { method: 'POST', params: { cmd: 'send' } },
});
})
.factory("LocationBinder", function($location, $timeout) {
var DATE_MATCHER = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
return function($scope, params, defaults) {
function init() {
var search = $location.search();
params.forEach(function(binding) {
var val = search[binding];
if (val) {
if (DATE_MATCHER.test(val)) {
val = new Date(val);
}
$scope[binding] = val;
} else if (defaults && defaults[binding]) {
$scope[binding] = defaults[binding];
}
});
}
init();
var updateTimeout;
function updateLocation() {
console.log("Update Timer Fired");
if (updateTimeout) $timeout.cancel(updateTimeout);
updateTimeout = $timeout(function() {
params.forEach(function(binding) {
var val = $scope[binding] || null;
if (angular.isDate(val)) {
val = val.toJSON();
}
$location.search(binding, val);
});
}, 1000);
}
params.forEach(function(binding) {
$scope.$watch(binding, function() {
updateLocation();
});
});
$scope.$on('$routeUpdate', function() {
console.log('Route updated');
var search = $location.search();
params.forEach(function(binding) {
var val = search[binding];
if (DATE_MATCHER.test(val)) {
val = new Date(val);
}
$scope[binding] = val;
});
});
}
});