mirror of
https://github.com/atlanticbiomedical/biomedjs.git
synced 2025-07-02 00:47:26 -04:00
Initial Commit
This commit is contained in:
74
public/js/app.js
Normal file
74
public/js/app.js
Normal 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
533
public/js/controllers.js
Normal 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
423
public/js/directives.js
Normal 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
16
public/js/filters.js
Normal 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
0
public/js/lib/angular-ui.js
vendored
Normal file
1046
public/js/lib/bootstrap-datepicker.js
vendored
Normal 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
369
public/js/lib/dialog.js
Normal 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
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
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
114
public/js/services.js
Normal 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;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user