From a403c9079fb81665caf52dcae0acab6c4b32632e Mon Sep 17 00:00:00 2001 From: Dobie Wollert Date: Fri, 25 Jul 2014 03:00:29 -0400 Subject: [PATCH] sync --- .gitignore | 6 + app/controllers/clients.js | 2 +- app/controllers/schedule.js | 34 +- app/controllers/users.js | 197 +- app/controllers/workorders.js | 23 +- app/model/workorder.js | 1 + app/views/index.jade | 11 +- app/views/tag.jade | 4 + config/auth.js | 15 +- config/config.js | 7 +- config/directory.js | 72 + config/passport.js | 19 +- config/routes.js | 10 +- logs/crash.log | 126 -- public/css/biomed/select2.less | 1138 ++++++------ public/css/biomed/widgets.less | 38 + public/img/select2-spinner.gif | Bin 0 -> 1849 bytes public/img/select2.png | Bin 0 -> 613 bytes public/img/select2x2.png | Bin 0 -> 845 bytes public/js/app.js | 14 +- public/js/controllers.js | 350 +++- public/js/directives.js | 420 ++++- public/js/filters.js | 10 +- public/js/lib/moment.js | 681 +++++-- public/js/lib/select2.js | 2429 +------------------------ public/js/services.js | 8 +- public/partials/clients/edit.html | 33 +- public/partials/messages.html | 4 +- public/partials/schedule/index.html | 5 +- public/partials/techPicker.html | 4 +- public/partials/techSchedule.html | 20 + public/partials/techs/schedule.html | 24 + public/partials/users/index.html | 61 + public/partials/workorders/add.html | 277 ++- public/partials/workorders/edit.html | 307 +++- public/partials/workorders/index.html | 5 +- public/tags/app.js | 25 + server.js | 13 +- test.js | 23 +- 39 files changed, 2875 insertions(+), 3541 deletions(-) create mode 100644 config/directory.js delete mode 100755 logs/crash.log create mode 100644 public/img/select2-spinner.gif create mode 100644 public/img/select2.png create mode 100644 public/img/select2x2.png create mode 100644 public/partials/techSchedule.html create mode 100644 public/partials/techs/schedule.html create mode 100644 public/partials/users/index.html diff --git a/.gitignore b/.gitignore index 16769d8..5e2c5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,8 @@ node_modules node +logs/ +*.log +*.log.old +*.bac +*.old +*.save diff --git a/app/controllers/clients.js b/app/controllers/clients.js index 0452560..c9d53f0 100644 --- a/app/controllers/clients.js +++ b/app/controllers/clients.js @@ -6,7 +6,7 @@ var mongoose = require('mongoose'), var log = require('log4node'); -var frequencies = ["annual","semi","quarterly","sterilizer","tg","ert","rae","medgas","imaging","neptune","anesthesia"]; +var frequencies = ["Medical Device","Sterilizer - TT","Vaporizer","Ice Maker","Anesthesia","Waste Management System","Imaging","Medical Gas Systems","RAE","ERT","N2O Trace Gas","Sterilizer - F","Quarterly","Semi","Annual","legacy","DLLR"]; exports.index = function(req, res) { log.info("clients.index"); diff --git a/app/controllers/schedule.js b/app/controllers/schedule.js index 9792b72..fcdb2e4 100644 --- a/app/controllers/schedule.js +++ b/app/controllers/schedule.js @@ -4,16 +4,34 @@ var mongoose = require('mongoose'), Workorder = mongoose.model('Workorder'); exports.index = function(req, res) { - var date = moment(req.query.date); - var start = date.clone().startOf('day').toDate(); - var end = date.clone().endOf('day').toDate(); + + var start, end; + + + if (req.query.start && req.query.end) { + start = moment(req.query.start).toDate(); + end = moment(req.query.end).toDate(); + } else { + var date = moment(req.query.date); + start = date.clone().startOf('day').toDate(); + end = date.clone().endOf('day').toDate(); + } + + var tech = req.query.tech; + + var query = { + deleted: false, + 'scheduling.start': { '$lte': end }, + 'scheduling.end': { '$gte': start } + }; + + if (tech) { + query['techs'] = tech; + } + Workorder - .find({ - deleted: false, - 'scheduling.start': { '$lte': end }, - 'scheduling.end': { '$gte': start } - }) + .find(query) .populate('techs', 'name') .populate('client', 'name identifier address') .select('scheduling techs client') diff --git a/app/controllers/users.js b/app/controllers/users.js index 3f996c7..29ce87b 100644 --- a/app/controllers/users.js +++ b/app/controllers/users.js @@ -1,25 +1,190 @@ var mongoose = require('mongoose'), + async = require('async'), User = mongoose.model('User'); -exports.index = function(req, res) { - var criteria = { deleted: false }; +var log = require('log4node'); - if (req.query.group) { - criteria.groups = req.query.group; - } +module.exports = function(config, directory) { - if (req.query.perms) { - criteria.perms = req.query.perms; - } - - var query = User.find(criteria) - .select('name groups') - .exec(function(err, results) { - if (err) { - res.json(500, err); - } else { - res.json(results); + function fetch_all_users(callback) { + async.parallel({ + gapps: directory.listUsers, + local: function(callback) { + User.find({ deleted: false }).select('name email groups perms deleted').exec(callback); } + }, callback); + } + + function map_local_users(data, results) { + return function(callback) { + async.each(data, function(item, callback) { + var key = item.email.toLowerCase(); + + if (blacklist.indexOf(key) == -1) + results[key] = item; + + callback(); + }, + callback); + }; + } + + function map_gapps_users(data, results) { + return function(callback) { + async.each(data, function(item, callback) { + var key = item.primaryEmail.toLowerCase(); + + // Ignore if blacklisted + if (blacklist.indexOf(key) != -1) return callback(); + + if (!(key in results)) + results[key] = { + email: item.primaryEmail, + deleted: false, + perms: [ ], + groups: [ ], + name: { + first: item.name.givenName, + last: item.name.familyName + }, + }; + + callback(); + }, + callback); + }; + } + + function reduce_array(data, results) { + return function(callback) { + for (var item in data) { + results.push(data[item]); + } + + results.sort(function(a, b) { + var result = a.name.first.toLowerCase().localeCompare(b.name.first.toLowerCase()); + if (result == 0) + result = a.name.last.toLowerCase().localeCompare(b.name.last.toLowerCase()); + + return result; + }); + + callback(); + }; + } + + function merge_sources(data, callback) { + var map = {}; + var reduce = []; + + async.series([ + map_local_users(data.local, map), + map_gapps_users(data.gapps.users, map), + reduce_array(map, reduce), + ], + function(err) { + callback(err, reduce); }); + } + + return { + index: function(req, res) { + var criteria = { deleted: false }; + + if (req.query.group) { + criteria.groups = req.query.group; + } + + if (req.query.perms) { + criteria.perms = req.query.perms; + } + + if (req.query.userid) { + criteria._id = req.query.userid; + } + + var query = User.find(criteria) + .select('name groups') + .exec(function(err, results) { + if (err) { + res.json(500, err); + } else { + res.json(results); + } + }); + }, + + details: function(req, res) { + + async.waterfall([ + fetch_all_users, + merge_sources, + ], + function(err, results) { + if (err) return res.json(500, err); + res.json(results); + }); + }, + + create: function(req, res) { + log.info("users.create %j", req.body); + + var user = new User({ + email: req.body.email, + name: req.body.name, + groups: req.body.groups, + perms: req.body.perms, + deleted: false + }); + + return user.save(function(err) { + if (err) + log.error("Error: %s", err); + + return res.json(user); + }); + }, + + update: function(req, res) { + var id = req.param('user_id'); + log.info("users.update %s %j", id, req.body); + + return User.findById(id, function(err, user) { + user.email = req.body.email; + user.name = req.body.name; + user.groups = req.body.groups; + user.perms = req.body.perms; + + return user.save(function(err) { + if (err) + log.err("Error: %s", err); + + return res.json(user); + }); + }); + } + }; }; + +var blacklist = [ + "system@atlanticbiomedical.com", + "admin@atlanticbiomedical.com", + "amazons3@atlanticbiomedical.com", + "api@atlanticbiomedical.com", + "biodexservice@atlanticbiomedical.com", + "cerberusapp@atlanticbiomedical.com", + "chattservice@atlanticbiomedical.com", + "dropbox@atlanticbiomedical.com", + "inquiries@atlanticbiomedical.com", + "office@atlanticbiomedical.com", + "parts@atlanticbiomedical.com", + "schedule@atlanticbiomedical.com", + "webapp@atlanticbiomedical.com", + "banfieldservice@atlanticbiomedical.com", + "chris.sewell@atlanticbiomedical.com", + "devel@atlanticbiomedical.com", + "dobie@atlanticbiomedical.com", + "akirayasha@gmail.com", + "receipts@atlanticbiomedical.com", +]; diff --git a/app/controllers/workorders.js b/app/controllers/workorders.js index 111946d..7bb9312 100644 --- a/app/controllers/workorders.js +++ b/app/controllers/workorders.js @@ -67,6 +67,7 @@ module.exports = function(config, calendar) { var workorder = new Workorder({ client: req.body.client, + emails: req.body.emails, createdOn: date, createdBy: req.user, reason: req.body.reason, @@ -117,7 +118,7 @@ module.exports = function(config, calendar) { location: generateLocation(client), start: workorder.scheduling.start, end: workorder.scheduling.end, - attendees: generateAttendees(techs) + attendees: generateAttendees(techs, workorder) }, function(err, result) { if (result) { workorder.calendarId = result.id; @@ -129,7 +130,7 @@ module.exports = function(config, calendar) { if (!notify) return callback(null); - var to = generateToLine(techs); + var to = generateToLine(techs).concat(req.body.emails); if (!to) return callback(null); @@ -197,6 +198,7 @@ module.exports = function(config, calendar) { Workorder.findById(id, function(err, result) { workorder = result; + workorder.emails = req.body.emails; workorder.modifiedBy = req.user; workorder.modifiedOn = modifiedOn; workorder.reason = req.body.reason; @@ -253,7 +255,7 @@ module.exports = function(config, calendar) { location: generateLocation(client), start: workorder.scheduling.start, end: workorder.scheduling.end, - attendees: generateAttendees(techs), + attendees: generateAttendees(techs, workorder), eventId: workorder.calendarId }, function(err, result) { callback(err); @@ -335,6 +337,9 @@ function generateDescription(client, workorder, createdBy, modifiedBy) { "Workorder ID:\n" + " %(biomedId)s\n" + "\n" + + "Scheduled Time:\n" + + " %(scheduleStart)s - %(scheduleEnd)s\n" + + "\n" + "Created By:\n" + " %(createdBy)s\n" + "\n" + @@ -362,6 +367,11 @@ function generateDescription(client, workorder, createdBy, modifiedBy) { "Remarks:\n" + " %(remarks)s\n"; + var format = "MMMM Do YYYY, h:mm a" + + var scheduleStart = moment(workorder.scheduling.start).format(format); + var scheduleEnd = moment(workorder.scheduling.end).format(format); + var resources = { biomedId: workorder.biomedId || '', name: client.name || '', @@ -374,6 +384,8 @@ function generateDescription(client, workorder, createdBy, modifiedBy) { reason: workorder.reason || '', status: workorder.status || '', remarks: workorder.remarks || '', + scheduleStart: scheduleStart, + scheduleEnd: scheduleEnd, phone: '', contact: '', createdBy: '', @@ -396,8 +408,9 @@ function generateDescription(client, workorder, createdBy, modifiedBy) { return sprintf(template, resources); } -function generateAttendees(techs) { - return techs.map(function(t) { return t.email; }); +function generateAttendees(techs, workorder) { + console.log('here'); + return techs.map(function(t) { return t.email; }).concat(workorder.emails); } function generateToLine(techs) { diff --git a/app/model/workorder.js b/app/model/workorder.js index 8e350dd..4b0e5a6 100644 --- a/app/model/workorder.js +++ b/app/model/workorder.js @@ -5,6 +5,7 @@ var mongoose = require('mongoose') var workorderSchema = new Schema({ biomedId: Number, client: { type: ObjectId, ref: 'Client' }, + emails: [String], createdOn: Date, createdBy: { type: ObjectId, ref: 'User' }, modifiedBy: { type: ObjectId, ref: 'User' }, diff --git a/app/views/index.jade b/app/views/index.jade index d23d7e2..0bc874d 100644 --- a/app/views/index.jade +++ b/app/views/index.jade @@ -9,7 +9,7 @@ html(lang="en", ng-app="biomed", ng-controller="biomed.PageCtrl") .navbar-inner a.brand(href='/', target='_self') Atlantic Biomedical progress-panel - ul.nav.pull-right(ng-controller='biomed.AccountCtrl') + ul.nav.pull-right li a(href='https://docs.google.com/a/atlanticbiomedical.com/forms/d/1i7CyNR2lcrz7bOL7u9ssKiMB2iBmXqOdvVKC0GRzRtY/viewform', target='_blank') i.icon-shopping-cart @@ -23,9 +23,9 @@ html(lang="en", ng-app="biomed", ng-controller="biomed.PageCtrl") i.icon-fire | Tickets li - a(ng-click="openDialog()") + a(ng-click="disabledopenDialog()") i.icon-envelope - | Messages + | Messages (disabled) li a(href='/logout', target='_self') i.icon-share-alt @@ -53,6 +53,11 @@ html(lang="en", ng-app="biomed", ng-controller="biomed.PageCtrl") a(href='/workorders') i.icon-wrench | Workorders + + li(data-match-route='/admin.*', ng-show="accountHasPermission('system.admin')") + a(href='/admin') + i.icon-wrench + | Admin .container-fluid ng-view !{js} diff --git a/app/views/tag.jade b/app/views/tag.jade index 6392c9b..cdc3326 100644 --- a/app/views/tag.jade +++ b/app/views/tag.jade @@ -55,6 +55,10 @@ html(lang="en", ng-app="tags", ng-controller="tags.PageCtrl") dd  {{payload.tag.client.name}} ({{payload.tag.client.identifier}}) dt Client Device ID dd  {{tag.clientDeviceId}} + span(ng-repeat='field in fields') + dt(ng-show='{{field.value}}') {{field.label}} + dt(ng-show='{{field.value}}')  {{field.value}} + dt Device dd  {{tag.device}} dt Manufacturer diff --git a/config/auth.js b/config/auth.js index 272201c..cf40ffb 100644 --- a/config/auth.js +++ b/config/auth.js @@ -1,3 +1,5 @@ +var log = require('log4node'); + module.exports = function(app, passport) { app.get('/auth', function(req, res, next) { console.dir(req.headers); @@ -16,13 +18,15 @@ module.exports = function(app, passport) { var options = { callbackURL: 'http://' + req.headers['x-forwarded-host'] + '/auth/callback' }; - console.log(options); passport.authenticate('google', options, function(err, user, info) { var redirectUrl = '/'; if (err) { return next(err); } if (!user) { return res.redirect('/login/error'); } + log.setPrefix("[%d] %l "); + log.info("User Logged In: %s %s", user.name.first, user.name.last); + if (req.session.redirectUrl) { redirectUrl = req.session.redirectUrl; req.session.redirectUrl = null; @@ -43,15 +47,22 @@ module.exports = function(app, passport) { return { requiresUiLogin: function(req, res, next) { if (!req.isAuthenticated()) { -// req.session.redirectUrl = req.url; return res.redirect('/login'); } + + log.setPrefix(function(level) { + return '[' + new Date().toUTCString() + '] ' + level.toUpperCase() + ' ' + req.user.name.first + ' ' + req.user.name.last + ' | '; + }); next(); }, requiresApiAccess: function(req, res, next) { if (!req.isAuthenticated()) { return res.send(403); } + + log.setPrefix(function(level) { + return '[' + new Date().toUTCString() + '] ' + level.toUpperCase() + ' ' + req.user.name.first + ' ' + req.user.name.last + ' | '; + }); next(); } }; diff --git a/config/config.js b/config/config.js index c0294fc..d1065cf 100644 --- a/config/config.js +++ b/config/config.js @@ -29,8 +29,11 @@ module.exports = { clientId: '333768673996-8epedo3je5h59n4l97v4dv8nofs7qnee.apps.googleusercontent.com', clientSecret: 'afu9KhKxckWJ3Tk6uxzp9Pg6', callback: 'http://portal.atlanticbiomedical.com/auth/callback', - accessToken: 'ya29.AHES6ZT1Sj1vpgidR2I_ksLdlV_VeZUjkitnZ01cP6VRrknjUEVbuw', - refreshToken: '1/XQW9P9FNYm6jikTsV8HOIuPAo1APYhwTH5CLhq9263g' +// accessToken: 'ya29.AHES6ZT1Sj1vpgidR2I_ksLdlV_VeZUjkitnZ01cP6VRrknjUEVbuw', +// refreshToken: '1/XQW9P9FNYm6jikTsV8HOIuPAo1APYhwTH5CLhq9263g' + + accessToken: 'ya29.1.AADtN_Xjt0PK6YVs8q5csiQFXQg2ZDtrVhsH6P4a5zm0mHqhGx0Nnjx4Jk68Gw', + refreshToken: '1/_5SkDLYmsi4XNaQyAzld-W5-GEqEqt5byH6VkI-j5QI', }, email: { user: 'api@atlanticbiomedical.com', diff --git a/config/directory.js b/config/directory.js new file mode 100644 index 0000000..0e61654 --- /dev/null +++ b/config/directory.js @@ -0,0 +1,72 @@ +var googleapis = require('googleapis'), + sprintf = require('sprintf'), + OAuth2Client = googleapis.OAuth2Client; + +var apiClient; + +module.exports = function(config) { + + var oauth2Client = new OAuth2Client( + config.auth.clientId, config.auth.clientSecret, config.auth.callback); + + oauth2Client.credentials = { + access_token: config.auth.accessToken, + refresh_token: config.auth.refreshToken + }; + + function toIsoDate(d) { + function pad(n) { return n < 10 ? '0' + n : n } + return d.getUTCFullYear()+'-' + + pad(d.getUTCMonth()+1)+'-' + + pad(d.getUTCDate())+'T' + + pad(d.getUTCHours())+':' + + pad(d.getUTCMinutes())+':' + + pad(d.getUTCSeconds())+'Z'; + } + + return { + listUsers: function(callback) { + api(function(client, callback) { + var params = { + domain: 'atlanticbiomedical.com', + fields: 'users(name,primaryEmail)', + }; + + var request = client.admin.users.list(); + request.params = params; + request.withAuthClient(oauth2Client).execute(function(err, result) { + callback(err, result); + }); + }, callback); + } + }; + + function api(workorder, callback) { + var handler = function(client) { + workorder(client, function(err, result) { + if (oauth2Client.credentials.access_token != config.auth.accessToken) { + console.log("Updating access token"); + config.auth.accessToken = oauth2Client.credentials.access_token; + } + + callback(err, result); + }); + }; + + if (apiClient) { + console.log("Using cached api client"); + handler(apiClient); + } else { + console.log("Getting api client"); + googleapis.discover('admin', 'directory_v1').execute(function(err, client) { + console.log(err); + + if (err) return callback(err); + apiClient = client; + + handler(apiClient); + }); + } + + } +}; diff --git a/config/passport.js b/config/passport.js index 02021e5..275988b 100644 --- a/config/passport.js +++ b/config/passport.js @@ -16,17 +16,22 @@ module.exports = function(passport, config) { passport.use(new GoogleStrategy({ clientID: config.auth.clientId, clientSecret: config.auth.clientSecret, -// callbackURL: config.auth.callback +// callbackURL: config.auth.callback, + passReqToCallback: true }, - function(accessToken, refreshToken, profile, done) { - console.log(profile); - console.log(accessToken); - console.log(refreshToken); - + function(req, accessToken, refreshToken, profile, done) { profile = profile._json; User.findOne({ email: profile.email.toLowerCase() }, function(err, user) { if (err) { return done(err); } - if (!user || !user.hasPermission("system.login")) { + + var source = req.headers['x-forwarded-host']; + + + if ( + !user || + (source == 'portal.atlanticbiomedical.com' && !user.hasPermission("system.login")) || + (source == 'n.atlb.co' && !user.hasPermission("system.tags")) + ) { return done(null, false, { message: "You are not authorized to access this portal." }); } diff --git a/config/routes.js b/config/routes.js index 3042085..718bd62 100644 --- a/config/routes.js +++ b/config/routes.js @@ -1,5 +1,6 @@ +var log = require('log4node'); -module.exports = function(app, auth, piler, calendar, config) { +module.exports = function(app, auth, piler, calendar, directory, config) { piler.addCssUrl("//fonts.googleapis.com/css?family=Open+Sans:400,300"); piler.addCssFile("/css/biomed.less"); @@ -30,7 +31,7 @@ module.exports = function(app, auth, piler, calendar, config) { app.post('/api/clients/:client_id', clients.update); app.del('/api/clients/:client_id', clients.destroy); - var workorders = require('../app/controllers/workorders')(calendar); + var workorders = require('../app/controllers/workorders')(config, calendar); app.get('/api/workorders', workorders.index); app.get('/api/workorders/:workorder_id', workorders.get); app.post('/api/workorders', workorders.create); @@ -40,8 +41,11 @@ module.exports = function(app, auth, piler, calendar, config) { var schedule = require('../app/controllers/schedule'); app.get('/api/schedule', schedule.index); - var users = require('../app/controllers/users'); + var users = require('../app/controllers/users')(config, directory); app.get('/api/users', users.index); + app.get('/api/users/details', users.details); + app.post('/api/users', users.create); + app.post('/api/users/:user_id', users.update); var account = require('../app/controllers/account'); app.get('/api/account', account.profile); diff --git a/logs/crash.log b/logs/crash.log deleted file mode 100755 index 6088648..0000000 --- a/logs/crash.log +++ /dev/null @@ -1,126 +0,0 @@ -Server was reset on 06.07.2013 at 00:32:52 -Server was reset on 06.07.2013 at 00:32:52 -Server was reset on 06.07.2013 at 00:32:52 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.24.2013 at 10:40:55 -Server was reset on 06.26.2013 at 07:24:10 -Server was reset on 06.26.2013 at 07:24:10 -Server was reset on 06.26.2013 at 07:24:10 -Server was reset on 06.26.2013 at 07:24:10 -Server was reset on 06.26.2013 at 07:24:10 -Server was reset on 07.01.2013 at 02:38:49 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.01.2013 at 02:44:36 -Server was reset on 07.19.2013 at 08:33:09 -Server was reset on 07.19.2013 at 08:33:09 -Server was reset on 07.19.2013 at 09:03:11 -Server was reset on 07.19.2013 at 09:03:11 -Server was reset on 07.19.2013 at 10:01:07 -Server was reset on 07.19.2013 at 10:01:07 -Server was reset on 07.19.2013 at 10:01:07 -Server was reset on 07.19.2013 at 10:01:07 -Server was reset on 07.19.2013 at 10:01:07 -Server was reset on 07.19.2013 at 10:35:47 -Server was reset on 07.19.2013 at 10:35:47 -Server was reset on 07.19.2013 at 10:35:47 -Server was reset on 07.19.2013 at 10:35:47 -Server was reset on 07.19.2013 at 10:35:47 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:09:00 -Server was reset on 07.19.2013 at 11:59:11 -Server was reset on 07.19.2013 at 11:59:11 -Server was reset on 07.19.2013 at 11:59:11 -Server was reset on 07.19.2013 at 11:59:11 -Server was reset on 07.19.2013 at 11:59:11 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.19.2013 at 12:19:27 -Server was reset on 07.22.2013 at 00:15:15 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 07.28.2013 at 21:14:04 -Server was reset on 08.07.2013 at 00:39:34 -Server was reset on 08.07.2013 at 17:07:18 -Server was reset on 08.07.2013 at 22:05:41 -Server was reset on 08.07.2013 at 22:05:41 -Server was reset on 08.07.2013 at 22:05:41 -Server was reset on 08.07.2013 at 22:06:43 -Server was reset on 08.07.2013 at 22:06:43 -Server was reset on 08.24.2013 at 13:17:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 08.27.2013 at 10:54:23 -Server was reset on 09.02.2013 at 06:42:51 -Server was reset on 09.02.2013 at 06:42:51 -Server was reset on 09.02.2013 at 06:42:51 diff --git a/public/css/biomed/select2.less b/public/css/biomed/select2.less index ae6e6a9..4adfa5f 100644 --- a/public/css/biomed/select2.less +++ b/public/css/biomed/select2.less @@ -1,523 +1,615 @@ -/* -Version: 3.2 Timestamp: Mon Sep 10 10:38:04 PDT 2012 -*/ -.select2-container { - position: relative; - display: inline-block; - /* inline-block for ie7 */ - zoom: 1; - *display: inline; - vertical-align: top; -} - -.select2-container, -.select2-drop, -.select2-search, -.select2-search input{ - /* - Force border-box so that % widths fit the parent - container without overlap because of margin/padding. - - More Info : http://www.quirksmode.org/css/box.html - */ - -moz-box-sizing: border-box; /* firefox */ - -ms-box-sizing: border-box; /* ie */ - -webkit-box-sizing: border-box; /* webkit */ - -khtml-box-sizing: border-box; /* konqueror */ - box-sizing: border-box; /* css3 */ -} - -.select2-container .select2-choice { - background-color: #fff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); - background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -o-linear-gradient(bottom, #eeeeee 0%, #ffffff 50%); - background-image: -ms-linear-gradient(top, #eeeeee 0%, #ffffff 50%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#ffffff', GradientType = 0); - background-image: linear-gradient(top, #eeeeee 0%, #ffffff 50%); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #aaa; - display: block; - overflow: hidden; - white-space: nowrap; - position: relative; - height: 26px; - line-height: 26px; - padding: 0 0 0 8px; - color: #444; - text-decoration: none; -} - -.select2-container.select2-drop-above .select2-choice -{ - border-bottom-color: #aaa; - -webkit-border-radius:0px 0px 4px 4px; - -moz-border-radius:0px 0px 4px 4px; - border-radius:0px 0px 4px 4px; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.9, white)); - background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 90%); - background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 90%); - background-image: -o-linear-gradient(bottom, #eeeeee 0%, white 90%); - background-image: -ms-linear-gradient(top, #eeeeee 0%,#ffffff 90%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); - background-image: linear-gradient(top, #eeeeee 0%,#ffffff 90%); -} - -.select2-container .select2-choice span { - margin-right: 26px; - display: block; - overflow: hidden; - white-space: nowrap; - -o-text-overflow: ellipsis; - -ms-text-overflow: ellipsis; - text-overflow: ellipsis; -} - -.select2-container .select2-choice abbr { - display: block; - position: absolute; - right: 26px; - top: 8px; - width: 12px; - height: 12px; - font-size: 1px; - background: url('/img/select2.png') right top no-repeat; - cursor: pointer; - text-decoration: none; - border:0; - outline: 0; -} -.select2-container .select2-choice abbr:hover { - background-position: right -11px; - cursor: pointer; -} - -.select2-drop { - background: #fff; - color: #000; - border: 1px solid #aaa; - border-top: 0; - position: absolute; - top: 100%; - -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - -moz-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - -o-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - box-shadow: 0 4px 5px rgba(0, 0, 0, .15); - z-index: 9999; - width:100%; - margin-top:-1px; - - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; -} - -.select2-drop.select2-drop-above { - -webkit-border-radius: 4px 4px 0px 0px; - -moz-border-radius: 4px 4px 0px 0px; - border-radius: 4px 4px 0px 0px; - margin-top:1px; - border-top: 1px solid #aaa; - border-bottom: 0; - - -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); - -moz-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); - -o-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); - box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); -} - -.select2-container .select2-choice div { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; - background: #ccc; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); - background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%); - background-image: -ms-linear-gradient(top, #cccccc 0%, #eeeeee 60%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#cccccc', endColorstr = '#eeeeee', GradientType = 0); - background-image: linear-gradient(top, #cccccc 0%, #eeeeee 60%); - border-left: 1px solid #aaa; - position: absolute; - right: 0; - top: 0; - display: block; - height: 100%; - width: 18px; -} - -.select2-container .select2-choice div b { - background: url('/img/select2.png') no-repeat 0 1px; - display: block; - width: 100%; - height: 100%; -} - -.select2-search { - display: inline-block; - white-space: nowrap; - z-index: 10000; - min-height: 26px; - width: 100%; - margin: 0; - padding-left: 4px; - padding-right: 4px; -} - -.select2-search-hidden { - display: block; - position: absolute; - left: -10000px; -} - -.select2-search input { - background: #fff url('/img/select2.png') no-repeat 100% -22px; background: url('/img/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('/img/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('/img/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('/img/select2.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('/img/select2.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); - background: url('/img/select2.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%, #eeeeee 99%); - padding: 4px 20px 4px 5px; - outline: 0; - border: 1px solid #aaa; - font-family: sans-serif; - font-size: 1em; - width:100%; - margin:0; - height:auto !important; - min-height: 26px; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; - border-radius: 0; - -moz-border-radius: 0; - -webkit-border-radius: 0; -} - -.select2-drop.select2-drop-above .select2-search input -{ - margin-top:4px; -} - -.select2-search input.select2-active { - background: #fff url('spinner.gif') no-repeat 100%; - background: url('spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, -ms-linear-gradient(top, #ffffff 85%, #eeeeee 99%); - background: url('spinner.gif') no-repeat 100%, linear-gradient(top, #ffffff 85%, #eeeeee 99%); -} - - -.select2-container-active .select2-choice, -.select2-container-active .select2-choices { - -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); - -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); - -o-box-shadow : 0 0 5px rgba(0,0,0,.3); - box-shadow : 0 0 5px rgba(0,0,0,.3); - border: 1px solid #5897fb; - outline: none; -} - -.select2-dropdown-open .select2-choice { - border: 1px solid #aaa; - border-bottom-color: transparent; - -webkit-box-shadow: 0 1px 0 #fff inset; - -moz-box-shadow : 0 1px 0 #fff inset; - -o-box-shadow : 0 1px 0 #fff inset; - box-shadow : 0 1px 0 #fff inset; - background-color: #eee; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%); - background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); - -webkit-border-bottom-left-radius : 0; - -webkit-border-bottom-right-radius: 0; - -moz-border-radius-bottomleft : 0; - -moz-border-radius-bottomright: 0; - border-bottom-left-radius : 0; - border-bottom-right-radius: 0; -} - -.select2-dropdown-open .select2-choice div { - background: transparent; - border-left: none; -} -.select2-dropdown-open .select2-choice div b { - background-position: -18px 1px; -} - -/* results */ -.select2-results { - margin: 4px 4px 4px 0; - padding: 0 0 0 4px; - position: relative; - overflow-x: hidden; - overflow-y: auto; - max-height: 200px; -} - -.select2-results ul.select2-result-sub { - margin: 0 0 0 0; -} - -.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } -.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px } -.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px } -.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px } -.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px } -.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px } -.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px } - -.select2-results li { - list-style: none; - display: list-item; -} - -.select2-results li.select2-result-with-children > .select2-result-label { - font-weight: bold; -} - -.select2-results .select2-result-label { - padding: 3px 7px 4px; - margin: 0; - cursor: pointer; -} - -.select2-results .select2-highlighted { - background: #3875d7; - color: #fff; -} -.select2-results li em { - background: #feffde; - font-style: normal; -} -.select2-results .select2-highlighted em { - background: transparent; -} -.select2-results .select2-no-results, -.select2-results .select2-searching, -.select2-results .select2-selection-limit { - background: #f4f4f4; - display: list-item; -} - -/* -disabled look for already selected choices in the results dropdown -.select2-results .select2-disabled.select2-highlighted { - color: #666; - background: #f4f4f4; - display: list-item; - cursor: default; -} -.select2-results .select2-disabled { - background: #f4f4f4; - display: list-item; - cursor: default; -} -*/ -.select2-results .select2-disabled { - display: none; -} - -.select2-more-results.select2-active { - background: #f4f4f4 url('spinner.gif') no-repeat 100%; -} - -.select2-more-results { - background: #f4f4f4; - display: list-item; -} - -/* disabled styles */ - -.select2-container.select2-container-disabled .select2-choice { - background-color: #f4f4f4; - background-image: none; - border: 1px solid #ddd; - cursor: default; -} - -.select2-container.select2-container-disabled .select2-choice div { - background-color: #f4f4f4; - background-image: none; - border-left: 0; -} - - -/* multiselect */ - -.select2-container-multi .select2-choices { - background-color: #fff; - background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); - background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); - background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); - border: 1px solid #aaa; - margin: 0; - padding: 0; - cursor: text; - overflow: hidden; - height: auto !important; - height: 1%; - position: relative; -} - -.select2-container-multi .select2-choices { - min-height: 26px; -} - -.select2-container-multi.select2-container-active .select2-choices { - -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3); - -moz-box-shadow : 0 0 5px rgba(0,0,0,.3); - -o-box-shadow : 0 0 5px rgba(0,0,0,.3); - box-shadow : 0 0 5px rgba(0,0,0,.3); - border: 1px solid #5897fb; - outline: none; -} -.select2-container-multi .select2-choices li { - float: left; - list-style: none; -} -.select2-container-multi .select2-choices .select2-search-field { - white-space: nowrap; - margin: 0; - padding: 0; -} - -.select2-container-multi .select2-choices .select2-search-field input { - color: #666; - background: transparent !important; - font-family: sans-serif; - font-size: 100%; - height: 15px; - padding: 5px; - margin: 1px 0; - outline: 0; - border: 0; - -webkit-box-shadow: none; - -moz-box-shadow : none; - -o-box-shadow : none; - box-shadow : none; -} - -.select2-container-multi .select2-choices .select2-search-field input.select2-active { - background: #fff url('spinner.gif') no-repeat 100% !important; -} - -.select2-default { - color: #999 !important; -} - -.select2-container-multi .select2-choices .select2-search-choice { - -webkit-border-radius: 3px; - -moz-border-radius : 3px; - border-radius : 3px; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; - background-color: #e4e4e4; - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); - background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); - background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); - -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); - color: #333; - border: 1px solid #aaaaaa; - line-height: 13px; - padding: 3px 5px 3px 18px; - margin: 3px 0 3px 5px; - position: relative; - cursor: default; -} -.select2-container-multi .select2-choices .select2-search-choice span { - cursor: default; -} -.select2-container-multi .select2-choices .select2-search-choice-focus { - background: #d4d4d4; -} - -.select2-search-choice-close { - display: block; - position: absolute; - right: 3px; - top: 4px; - width: 12px; - height: 13px; - font-size: 1px; - background: url('/img/select2.png') right top no-repeat; - outline: none; -} - -.select2-container-multi .select2-search-choice-close { - left: 3px; -} - - -.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { - background-position: right -11px; -} -.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { - background-position: right -11px; -} - -/* disabled styles */ - -.select2-container-multi.select2-container-disabled .select2-choices{ - background-color: #f4f4f4; - background-image: none; - border: 1px solid #ddd; - cursor: default; -} - -.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { - background-image: none; - background-color: #f4f4f4; - border: 1px solid #ddd; - padding: 3px 5px 3px 5px; -} - -.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { - display: none; -} -/* end multiselect */ - -.select2-result-selectable .select2-match, -.select2-result-unselectable .select2-result-selectable .select2-match { text-decoration: underline; } -.select2-result-unselectable .select2-match { text-decoration: none; } - -.select2-offscreen { position: absolute; left: -10000px; } - -/* Retina-ize icons */ - -@media only screen and (-webkit-min-device-pixel-ratio: 1.5) { - .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice div b { - background-image: url('/ing/select2x2.png') !important; - background-repeat: no-repeat !important; - background-size: 60px 40px !important; - } - .select2-search input { - background-position: 100% -21px !important; - } -} +/* +Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013 +*/ +.select2-container { + margin: 0; + position: relative; + display: inline-block; + /* inline-block for ie7 */ + zoom: 1; + *display: inline; + vertical-align: middle; +} + +.select2-container, +.select2-drop, +.select2-search, +.select2-search input { + /* + Force border-box so that % widths fit the parent + container without overlap because of margin/padding. + + More Info : http://www.quirksmode.org/css/box.html + */ + -webkit-box-sizing: border-box; /* webkit */ + -moz-box-sizing: border-box; /* firefox */ + box-sizing: border-box; /* css3 */ +} + +.select2-container .select2-choice { + display: block; + height: 26px; + padding: 0 0 0 8px; + overflow: hidden; + position: relative; + + border: 1px solid #aaa; + white-space: nowrap; + line-height: 26px; + color: #444; + text-decoration: none; + + border-radius: 4px; + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #fff; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.5, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 50%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#ffffff', endColorstr = '#eeeeee', GradientType = 0); + background-image: linear-gradient(top, #fff 0%, #eee 50%); +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #aaa; + + border-radius: 0 0 4px 4px; + + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eee), color-stop(0.9, #fff)); + background-image: -webkit-linear-gradient(center bottom, #eee 0%, #fff 90%); + background-image: -moz-linear-gradient(center bottom, #eee 0%, #fff 90%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0); + background-image: linear-gradient(top, #eee 0%, #fff 90%); +} + +.select2-container.select2-allowclear .select2-choice .select2-chosen { + margin-right: 42px; +} + +.select2-container .select2-choice > .select2-chosen { + margin-right: 26px; + display: block; + overflow: hidden; + + white-space: nowrap; + + text-overflow: ellipsis; +} + +.select2-container .select2-choice abbr { + display: none; + width: 12px; + height: 12px; + position: absolute; + right: 24px; + top: 8px; + + font-size: 1px; + text-decoration: none; + + border: 0; + background: url('/img/select2.png') right top no-repeat; + cursor: pointer; + outline: 0; +} + +.select2-container.select2-allowclear .select2-choice abbr { + display: inline-block; +} + +.select2-container .select2-choice abbr:hover { + background-position: right -11px; + cursor: pointer; +} + +.select2-drop-mask { + border: 0; + margin: 0; + padding: 0; + position: fixed; + left: 0; + top: 0; + min-height: 100%; + min-width: 100%; + height: auto; + width: auto; + opacity: 0; + z-index: 9998; + /* styles required for IE to work */ + background-color: #fff; + filter: alpha(opacity=0); +} + +.select2-drop { + width: 100%; + margin-top: -1px; + position: absolute; + z-index: 9999; + top: 100%; + + background: #fff; + color: #000; + border: 1px solid #aaa; + border-top: 0; + + border-radius: 0 0 4px 4px; + + -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-auto-width { + border-top: 1px solid #aaa; + width: auto; +} + +.select2-drop-auto-width .select2-search { + padding-top: 4px; +} + +.select2-drop.select2-drop-above { + margin-top: 1px; + border-top: 1px solid #aaa; + border-bottom: 0; + + border-radius: 4px 4px 0 0; + + -webkit-box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); + box-shadow: 0 -4px 5px rgba(0, 0, 0, .15); +} + +.select2-drop-active { + border: 1px solid #5897fb; + border-top: none; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid #5897fb; +} + +.select2-container .select2-choice .select2-arrow { + display: inline-block; + width: 18px; + height: 100%; + position: absolute; + right: 0; + top: 0; + + border-left: 1px solid #aaa; + border-radius: 0 4px 4px 0; + + background-clip: padding-box; + + background: #ccc; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); + background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); + background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0); + background-image: linear-gradient(top, #ccc 0%, #eee 60%); +} + +.select2-container .select2-choice .select2-arrow b { + display: block; + width: 100%; + height: 100%; + background: url('/img/select2.png') no-repeat 0 1px; +} + +.select2-search { + display: inline-block; + width: 100%; + min-height: 26px; + margin: 0; + padding-left: 4px; + padding-right: 4px; + + position: relative; + z-index: 10000; + + white-space: nowrap; +} + +.select2-search input { + width: 100%; + height: auto !important; + min-height: 26px; + padding: 4px 20px 4px 5px; + margin: 0; + + outline: 0; + font-family: sans-serif; + font-size: 1em; + + border: 1px solid #aaa; + border-radius: 0; + + -webkit-box-shadow: none; + box-shadow: none; + + background: #fff url('/img/select2.png') no-repeat 100% -22px; + background: url('/img/select2.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('/img/select2.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('/img/select2.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('/img/select2.png') no-repeat 100% -22px, linear-gradient(top, #fff 85%, #eee 99%); +} + +.select2-drop.select2-drop-above .select2-search input { + margin-top: 4px; +} + +.select2-search input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100%; + background: url('select2-spinner.gif') no-repeat 100%, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, #fff), color-stop(0.99, #eee)); + background: url('select2-spinner.gif') no-repeat 100%, -webkit-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2-spinner.gif') no-repeat 100%, -moz-linear-gradient(center bottom, #fff 85%, #eee 99%); + background: url('select2-spinner.gif') no-repeat 100%, linear-gradient(top, #fff 85%, #eee 99%); +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} + +.select2-dropdown-open .select2-choice { + border-bottom-color: transparent; + -webkit-box-shadow: 0 1px 0 #fff inset; + box-shadow: 0 1px 0 #fff inset; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + + background-color: #eee; + background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center bottom, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center bottom, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(top, #fff 0%, #eee 50%); +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #5897fb; + border-top-color: transparent; + + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(0.5, #eee)); + background-image: -webkit-linear-gradient(center top, #fff 0%, #eee 50%); + background-image: -moz-linear-gradient(center top, #fff 0%, #eee 50%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0); + background-image: linear-gradient(bottom, #fff 0%, #eee 50%); +} + +.select2-dropdown-open .select2-choice .select2-arrow { + background: transparent; + border-left: none; + filter: none; +} +.select2-dropdown-open .select2-choice .select2-arrow b { + background-position: -18px 1px; +} + +/* results */ +.select2-results { + max-height: 200px; + padding: 0 0 0 4px; + margin: 4px 4px 4px 0; + position: relative; + overflow-x: hidden; + overflow-y: auto; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +.select2-results ul.select2-result-sub { + margin: 0; + padding-left: 0; +} + +.select2-results ul.select2-result-sub > li .select2-result-label { padding-left: 20px } +.select2-results ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 40px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 60px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 80px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 100px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 110px } +.select2-results ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub ul.select2-result-sub > li .select2-result-label { padding-left: 120px } + +.select2-results li { + list-style: none; + display: list-item; + background-image: none; +} + +.select2-results li.select2-result-with-children > .select2-result-label { + font-weight: bold; +} + +.select2-results .select2-result-label { + padding: 3px 7px 4px; + margin: 0; + cursor: pointer; + + min-height: 1em; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.select2-results .select2-highlighted { + background: #3875d7; + color: #fff; +} + +.select2-results li em { + background: #feffde; + font-style: normal; +} + +.select2-results .select2-highlighted em { + background: transparent; +} + +.select2-results .select2-highlighted ul { + background: #fff; + color: #000; +} + + +.select2-results .select2-no-results, +.select2-results .select2-searching, +.select2-results .select2-selection-limit { + background: #f4f4f4; + display: list-item; +} + +/* +disabled look for disabled choices in the results dropdown +*/ +.select2-results .select2-disabled.select2-highlighted { + color: #666; + background: #f4f4f4; + display: list-item; + cursor: default; +} +.select2-results .select2-disabled { + background: #f4f4f4; + display: list-item; + cursor: default; +} + +.select2-results .select2-selected { + display: none; +} + +.select2-more-results.select2-active { + background: #f4f4f4 url('select2-spinner.gif') no-repeat 100%; +} + +.select2-more-results { + background: #f4f4f4; + display: list-item; +} + +/* disabled styles */ + +.select2-container.select2-container-disabled .select2-choice { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container.select2-container-disabled .select2-choice .select2-arrow { + background-color: #f4f4f4; + background-image: none; + border-left: 0; +} + +.select2-container.select2-container-disabled .select2-choice abbr { + display: none; +} + + +/* multiselect */ + +.select2-container-multi .select2-choices { + height: auto !important; + height: 1%; + margin: 0; + padding: 0; + position: relative; + + border: 1px solid #aaa; + cursor: text; + overflow: hidden; + + background-color: #fff; + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eee), color-stop(15%, #fff)); + background-image: -webkit-linear-gradient(top, #eee 1%, #fff 15%); + background-image: -moz-linear-gradient(top, #eee 1%, #fff 15%); + background-image: linear-gradient(top, #eee 1%, #fff 15%); +} + +.select2-locked { + padding: 3px 5px 3px 5px !important; +} + +.select2-container-multi .select2-choices { + min-height: 26px; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #5897fb; + outline: none; + + -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, .3); + box-shadow: 0 0 5px rgba(0, 0, 0, .3); +} +.select2-container-multi .select2-choices li { + float: left; + list-style: none; +} +.select2-container-multi .select2-choices .select2-search-field { + margin: 0; + padding: 0; + white-space: nowrap; +} + +.select2-container-multi .select2-choices .select2-search-field input { + padding: 5px; + margin: 1px 0; + + font-family: sans-serif; + font-size: 100%; + color: #666; + outline: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + background: transparent !important; +} + +.select2-container-multi .select2-choices .select2-search-field input.select2-active { + background: #fff url('select2-spinner.gif') no-repeat 100% !important; +} + +.select2-default { + color: #999 !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + padding: 3px 5px 3px 18px; + margin: 3px 0 3px 5px; + position: relative; + + line-height: 13px; + color: #333; + cursor: default; + border: 1px solid #aaaaaa; + + border-radius: 3px; + + -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05); + + background-clip: padding-box; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + background-color: #e4e4e4; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#f4f4f4', GradientType=0); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); +} +.select2-container-multi .select2-choices .select2-search-choice .select2-chosen { + cursor: default; +} +.select2-container-multi .select2-choices .select2-search-choice-focus { + background: #d4d4d4; +} + +.select2-search-choice-close { + display: block; + width: 12px; + height: 13px; + position: absolute; + right: 3px; + top: 4px; + + font-size: 1px; + outline: none; + background: url('/img/select2.png') right top no-repeat; +} + +.select2-container-multi .select2-search-choice-close { + left: 3px; +} + +.select2-container-multi .select2-choices .select2-search-choice .select2-search-choice-close:hover { + background-position: right -11px; +} +.select2-container-multi .select2-choices .select2-search-choice-focus .select2-search-choice-close { + background-position: right -11px; +} + +/* disabled styles */ +.select2-container-multi.select2-container-disabled .select2-choices { + background-color: #f4f4f4; + background-image: none; + border: 1px solid #ddd; + cursor: default; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice { + padding: 3px 5px 3px 5px; + border: 1px solid #ddd; + background-image: none; + background-color: #f4f4f4; +} + +.select2-container-multi.select2-container-disabled .select2-choices .select2-search-choice .select2-search-choice-close { display: none; + background: none; +} +/* end multiselect */ + + +.select2-result-selectable .select2-match, +.select2-result-unselectable .select2-match { + text-decoration: underline; +} + +.select2-offscreen, .select2-offscreen:focus { + clip: rect(0 0 0 0) !important; + width: 1px !important; + height: 1px !important; + border: 0 !important; + margin: 0 !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; + outline: 0 !important; + left: 0px !important; + top: 0px !important; +} + +.select2-display-none { + display: none; +} + +.select2-measure-scrollbar { + position: absolute; + top: -10000px; + left: -10000px; + width: 100px; + height: 100px; + overflow: scroll; +} +/* Retina-ize icons */ + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi) { + .select2-search input, .select2-search-choice-close, .select2-container .select2-choice abbr, .select2-container .select2-choice .select2-arrow b { + background-image: url('select2x2.png') !important; + background-repeat: no-repeat !important; + background-size: 60px 40px !important; + } + .select2-search input { + background-position: 100% -21px !important; + } +} diff --git a/public/css/biomed/widgets.less b/public/css/biomed/widgets.less index d62400f..7636019 100644 --- a/public/css/biomed/widgets.less +++ b/public/css/biomed/widgets.less @@ -73,6 +73,7 @@ header { font-weight: 500; color: #999999; margin: 0; + margin-bottom: 10px; } } @@ -160,6 +161,42 @@ header { } } +.users { + th, td { + text-align: center; + } + + .group-start { + border-left: 1px solid #dddddd; + } + + .name, .email { text-align: left; white-space: nowrap; } + + .false { + .icon { + .icon-remove; + } + } + + .true { + background-color: #DFF0D8 !important; + + .icon { + .icon-ok; + } + } + + .new { + background-color: #49cced; + color: white; + font-size: 10px; + padding: 2px 5px; + margin: 2px; + .border-radius(2px); + vertical-align: middle; + } +} + .axis path, @@ -248,6 +285,7 @@ header { .tech-label { float: left; + width: 140px; } .enteries { diff --git a/public/img/select2-spinner.gif b/public/img/select2-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..5b33f7e54f4e55b6b8774d86d96895db9af044b4 GIT binary patch literal 1849 zcma*odr(tX9tZI2z31lM+(&YVk%mZ}5P~KlG2s=WSbGzm0!x7^P##Mnh7t-jP!X0Q zk_SQ}Po-L1tlDK;6l?(>v)e5ZBQx4|Y-Q?nr@Px3?9h(3ZWr3^tj=`TP57gKr87N$ zp2wWee1GRRCwo_xahnw)5cxNPJbCg2L6DV|6`#+yw6v6!mDS$f9-JvFD^n;GQ&UrZ zzh5jCkByB101O60U0q#p_1BM>Cv-vP?&s4@g_((4_1L=L$(a91)0=J91Gas#R{McE znYG^9*0A5YZ>#;~+Wkn(W5B0^yELIYLP!K}mB~<)AM@1&nqekynuaEGqPrzoH|KodRXJy)%+w_fu3nE5>@Bd_b zqC$EQ;{c`T&?EsNO|igL9gC7Ygxv?aQUEXMq?~>wg{EyW;VcJ37CUF#HjrT=KQO_* zS>M9yydXk18D(+QDJ1>r);Lav_uYKp$T?4vr{Q$lTo&pKv^?(>L-)G2*lwH!Ah7k? z7oH<8h-(KTKt5V6$8gF)C7Io&P5=SjTh)=zV=E2EUhQZP##L8S{d%UK>>+y82>+FV+#^BzW7u3F)Bb>=lYQ%%j`F>ASe zo*cw@V#u6T`A2He;70mR(V&iV&-7{qP~=SRf&jm9-T{*ZeZ}$rd0#6c&fLG^xJcf5 z+p<`wJYgW+_s*V{uI$nMB;%8`S_3>PfGOj3Rq}@Cx^+j?rk92fANSFDBYnOqQ>Vdj z)(|$AhP4t&Lb=Gvo2#3Gl%9<=Gv`Mz?Po@P4iLF!x}GUWJICDlFk-hS^Whyh7x~VH z@0vD1>HYD4&e+~yzS*-sFR{9`{QEEZO1zg7>R&7cHts-6j!xHVdA8eI+ZlVzd%`es zJT@$#GX(gvCJ1oJN%yLBK}{V=V;seo;!w|Yte!W1%5qLNFWqvZW>h&IiH+oPT=b@E zPhGzv5=(Un*X>v`>%8h_nj^NdYcE6NHS_ifkCV$*D)Tqrbu`s;<=t<4 zAHNqNV?6(g<1PY-w@#I-WYFViz?9TrkMr)u0g`O`u|>T;k|2sV*YF^punvT;$SuTy{j3Gv)yqD!R_CF>yR)MzmmYS5v+~R zXAdD%ng9?df;wd8GxR#%3O+gz};Vo;)sK%Bj-q>Oq%R7JU-KD?vYu>#2UjaDo z&8$>5xW~?KPD_#XFToU1hIb*VOMidUr6iYiO0N|i-7s`T8!cFT`rN!^1Pt78J93i6 z5HI1wIM$94m{3SLDvISDe6$ZG1;eq_D9RTaaC>=cO{@Bs>$IlPCPJJ$h$)-3vzNUQ6OsN#_zWxey!_9%hxwH2_dEJi=yY|1c7nDm2_Lm!Cof8-R_+9UkS zcBE(o47yE)oMR(Q=dp1a2wTX5KvvGyLqlWTa7V&!A*|w|)ax~1_~aJ0=_Lilg*0iQk7#ZD EAHN$8j{pDw literal 0 HcmV?d00001 diff --git a/public/img/select2.png b/public/img/select2.png new file mode 100644 index 0000000000000000000000000000000000000000..1d804ffb99699b9e030f1010314de0970b5a000d GIT binary patch literal 613 zcmV-r0-F7aP)#WY!I$JQV$)A5aAS1BM||2XVJl=+L1^1S1H% zM-&lx?NZpUrHhn>fk<>POqf2sh40}xxGZfc+t+#Eb(qHy9_3*1(U%t9t)QDnI#YAL(|ACV(>)>6WD-t!8tutHkdb^#3`HzoJG3A2@T`% zA|K@o*b!`R#(7)PWrMFn2))Ca3MR4(zaT`Zr61*kZK5NPnZwQszxh$fyv3?&4c>$q z2m=+yc0dRXRAsPDxF6sD;@rK4JGdR_``1S~o6Xi@2&aR6hcSrEp9HVRzEqVDqBn<1%hR=D4e1f^ra^A|34Cjc=Gny{F(o#MrvPYgZuTJOz(n)-F<| zj()qR;C={)N<0RRvDZ^@6ND+W*}gh-Lip(MDt!(zMSO)!j2j+*hxgzC-e3$@(O2p* zu;+gddm(cZwXTCLx*Ky4THOa*^b^F`woveIeCK^0aR|TJ00000NkvXXu0mjfA#WC6 literal 0 HcmV?d00001 diff --git a/public/img/select2x2.png b/public/img/select2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..4bdd5c961d452c49dfa0789c2c7ffb82c238fc24 GIT binary patch literal 845 zcmV-T1G4;yP)upQ6WKflyv?C|ADVW!U!t`EpA+x zB)5#EjWk-_X77YJZtQo`E0SF)^1bZr%)B7Cd`*OK*r z5WG-7e-R9G9^69ksDt29&oyHqxPSt|-S>xi3%PTd+GjY+BGF|nWC(7D-sd(kxqd9~ zS@2YF5vB+>dP8+$l^{oO3-lEWiGA*QIU)Wds#9M6RZ9N zcQ4y4)xqQOxD=vwu%7cz1nY#$lT&y8HCmkWgpwQP#3dhnYj9|2aS_R}IUF_^6s#$= zTm%~>A#oM?KIg$kh=<`gJkeoHa2LrulVy$Yx+N_0R3$4I!R*0677f(FKqm`2_o4~W z0h}fQZ`lC^1A+m;fM7uI(R1`S0KtG@KrkQ}5DW+&@cTnDVIow56KciMk7a899t0bC zC1KI{TsMe5NAR%GD_5`B-@ad4k~K3SO%H z_M31|`HV?E6)u$E3c&*<*n20+V@mRCop>R5;DWuZCmjSo7p@R&OYl^@G -1) + user.groups.splice(index, 1); + else + user.groups.push(group); + + save(user); + } + + $scope.checkGroup = function(user, group) { + return $.inArray(group, user.groups) > -1; + }; + + $scope.togglePerm = function(user, perm) { + var index = user.perms.indexOf(perm); + if (index > -1) + user.perms.splice(index, 1); + else + user.perms.push(perm); + + save(user); + }; + + $scope.checkPerm = function(user, perm) { + return $.inArray(perm, user.perms) > -1; + }; + + $scope.isNew = function(user) { + return !('_id' in user); + }; +}; + biomed.ClientIndexCtrl = function($scope, $filter, $routeParams, Clients, LocationBinder) { $scope.loading = true; @@ -295,13 +403,21 @@ biomed.WorkorderIndexCtrl = function($scope, $filter, $routeParams, Workorders, biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clients, Users) { + $scope.emailsOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': [], + 'formatNoMatches': function() { return 'Type an e-mail address and press return to add it.'; } + }; + $scope.group = 'all'; $scope.model = {}; $scope.picker = { - start: '09:00:00', - end: '17:00:00' + startTime: '09:00:00', + endTime: '09:45:00' }; - $scope.picker.date = new Date(); + $scope.picker.startDate = new Date(); + $scope.picker.endDate = new Date(); var search = $location.search(); @@ -311,6 +427,13 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie $scope.model.maintenanceType = search.type; $scope.workorderType = 'pm'; + } else if (search.workorderType == "meeting") { + $scope.model.reason = "Meeting"; + $scope.workorderType = 'meeting'; + + if (search.clientId) { + $scope.model.client = search.clientId; + } } else { if (search.clientId) { $scope.model.client = search.clientId; @@ -334,23 +457,94 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie $scope.clients = result; }); - $scope.$watch('picker.date', function() { + function convertToDate(date, time) { + return moment(moment(date).format('YYYY-MM-DD') + 'T' + time).toDate(); + } + + function datesOverlap() { + var start = convertToDate($scope.picker.startDate, $scope.picker.startTime); + var end = convertToDate($scope.picker.endDate, $scope.picker.endTime); + return start >= end; + } + + function updateDuration() { + var start = convertToDate($scope.picker.startDate, $scope.picker.startTime); + var end = convertToDate($scope.picker.endDate, $scope.picker.endTime); + + var duration = moment.duration(end - start); + + var days = duration.days() + var hours = duration.hours(); + var minutes = duration.minutes(); + + var result = ""; + + if (days == 1) { + result += "1 Day "; + } + if (days > 1) { + result += days + " Days "; + } + if (hours == 1) { + result += "1 Hour "; + } + if (hours > 1) { + result += hours + " Hours "; + } + if (minutes > 0) { + result += minutes + " Minutes"; + } + + $scope.picker.duration = result; + } + + + $scope.$watch('picker.startDate', function() { Schedule.index({ - date: $scope.picker.date.toJSON() + date: $scope.picker.startDate.toJSON() }, function(result) { $scope.schedule = result; }); + + if (datesOverlap()) { + $scope.picker.endDate = $scope.picker.startDate; + } + updateDuration(); }); - $scope.save = function() { + $scope.$watch('picker.endDate', function() { + if (datesOverlap()) { + $scope.picker.startDate = $scope.picker.endDate; + } + updateDuration(); + }); + + $scope.$watch('picker.startTime', function() { + $scope.picker.endTime = moment($scope.picker.startTime, "HH:mm:ss").add('minutes', 45).format("HH:mm:ss"); + $scope.picker.endDate = $scope.picker.startDate; + updateDuration(); + }); + + $scope.$watch('picker.endTime', function() { + if (datesOverlap()) { + $scope.picker.startTime = moment($scope.picker.endTime, "HH:mm:ss").subtract('minutes', 15).format("HH:mm:ss"); + } + updateDuration(); + }); + + $scope.save = function(notify) { var picker = $scope.picker; var model = $scope.model; - var date = moment(picker.date).format('YYYY-MM-DD'); + var startDate = moment(picker.startDate).format('YYYY-MM-DD'); + var endDate = moment(picker.endDate).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(); + model.scheduling.start = moment(startDate + 'T' + picker.startTime).toDate(); + model.scheduling.end = moment(endDate + 'T' + picker.endTime).toDate(); + + model._notify = notify; Workorders.create(model, function(result) { $location.path("/workorders/" + result._id); @@ -368,6 +562,14 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie var criteria = {}; Users.index(criteria, function(result) { + result.sort(function(a,b) { + var r = a.name.first.localeCompare(b.name.first); + if (r == 0) { + r = a.name.last.localeCompare(b.name.last); + } + return r; + }); + $scope.allUsers = result; $scope.usersMap = {}; @@ -379,6 +581,13 @@ biomed.WorkorderAddCtrl = function($scope, $location, Workorders, Schedule, Clie } biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, Users) { + $scope.emailsOptions = { + 'multiple': true, + 'simple_tags': true, + 'tags': [], + 'formatNoMatches': function() { return 'Type an e-mail address and press return to add it.'; } + }; + $scope.group = 'all'; $scope.route = $routeParams; $scope.loading = true; @@ -390,8 +599,13 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, $scope.master = Workorders.get($routeParams, function() { $scope.loading = false; + + if ($scope.master.reason == "Meeting") { + $scope.workorderType = "meeting"; + } }); + $scope.emails = createController(); $scope.status = createController(); $scope.remarks = createController(); $scope.scheduling = createSchedulingController(); @@ -410,7 +624,9 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, $scope.editing = true; } }, - save: function() { + save: function(notify) { + controller.model._notify = notify; + Workorders.update({id: $scope.master._id}, controller.model); angular.copy(controller.model, $scope.master); controller.visible = false; @@ -434,9 +650,11 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, 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.startDate = moment(controller.model.scheduling.start).startOf('day').toDate(); + controller.endDate = moment(controller.model.scheduling.end).startOf('day').toDate(); + + controller.startTime = moment(controller.model.scheduling.start).format('HH:mm:ss'); + controller.endTime = moment(controller.model.scheduling.end).format('HH:mm:ss'); controller.techs = controller.model.techs.map(function(t) { return t._id; }); @@ -444,13 +662,17 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, $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(); + save: function(notify) { + var startDate = moment(controller.startDate).format('YYYY-MM-DD'); + var endDate = moment(controller.endDate).format('YYYY-MM-DD'); + + controller.model.scheduling.start = moment(startDate + 'T' + controller.startTime).toDate(); + controller.model.scheduling.end = moment(endDate + 'T' + controller.endTime).toDate(); controller.model.techs = controller.techs.map(function(t) { return $scope.usersMap[t]; }); + controller.model._notify = notify; + Workorders.update({id: $scope.master._id}, controller.model); angular.copy(controller.model, $scope.master); controller.visible = false; @@ -466,15 +688,80 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, }; - $scope.$watch('scheduling.date', function() { + function convertToDate(date, time) { + return moment(moment(date).format('YYYY-MM-DD') + 'T' + time).toDate(); + } + + function datesOverlap() { + var start = convertToDate($scope.scheduling.startDate, $scope.scheduling.startTime); + var end = convertToDate($scope.scheduling.endDate, $scope.scheduling.endTime); + return start >= end; + } + function updateDuration() { + var start = convertToDate($scope.scheduling.startDate, $scope.scheduling.startTime); + var end = convertToDate($scope.scheduling.endDate, $scope.scheduling.endTime); + + var duration = moment.duration(end - start); + + var days = duration.days() + var hours = duration.hours(); + var minutes = duration.minutes(); + + var result = ""; + + if (days == 1) { + result += "1 Day "; + } + if (days > 1) { + result += days + " Days "; + } + if (hours == 1) { + result += "1 Hour "; + } + if (hours > 1) { + result += hours + " Hours "; + } + if (minutes > 0) { + result += minutes + " Minutes"; + } + + $scope.scheduling.duration = result; + } + + $scope.$watch('scheduling.startDate', function() { Schedule.index({ - date: $scope.scheduling.date.toJSON() + date: $scope.scheduling.startDate.toJSON() }, function(result) { $scope.scheduling.schedule = result; }); + + if (datesOverlap()) { + $scope.scheduling.endDate = $scope.scheduling.startDate; + } + updateDuration(); }); + $scope.$watch('scheduling.endDate', function() { + if (datesOverlap()) { + $scope.scheduling.startDate = $scope.scheduling.endDate; + } + updateDuration(); + }); + + $scope.$watch('scheduling.startTime', function() { + $scope.scheduling.endTime = moment($scope.scheduling.startTime, "HH:mm:ss").add('minutes', 45).format("HH:mm:ss"); + $scope.scheduling.endDate = $scope.scheduling.startDate; + updateDuration(); + }); + + $scope.$watch('scheduling.endTime', function() { + if (datesOverlap()) { + $scope.scheduling.startTime = moment($scope.scheduling.endTime, "HH:mm:ss").subtract('minutes', 15).format("HH:mm:ss"); + } + updateDuration(); + }); + return controller; } @@ -488,6 +775,14 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, var criteria = {}; Users.index(criteria, function(result) { + result.sort(function(a,b) { + var r = a.name.first.localeCompare(b.name.first); + if (r == 0) { + r = a.name.last.localeCompare(b.name.last); + } + return r; + }); + $scope.allUsers = result; $scope.usersMap = {}; @@ -499,7 +794,7 @@ biomed.WorkorderEditCtrl = function($scope, $routeParams, Workorders, Schedule, }; -biomed.PageCtrl = function($scope, $dialog) { +biomed.PageCtrl = function($scope, $dialog, Account) { $scope.opts = { backdrop: true, keyboard: true, @@ -514,6 +809,17 @@ biomed.PageCtrl = function($scope, $dialog) { var d = $dialog.dialog($scope.opts); d.open(); }; + + $scope.accountHasPermission = function(perm) { + console.log($scope); + if ($scope.account && $scope.account.perms) { + return $scope.account.perms.indexOf(perm) > -1; + } + + return false; + }; + + $scope.account = Account.get(); }; biomed.MessagesCtrl = function($scope, dialog, Users, Messages) { diff --git a/public/js/directives.js b/public/js/directives.js index ddad90a..ff2480e 100644 --- a/public/js/directives.js +++ b/public/js/directives.js @@ -168,16 +168,16 @@ angular.module('biomed.directives', []) } // Use native interface for touch devices - if(isTouch && element.prop('type') === 'text') { +// if(isTouch && element.prop('type') === 'text') { +// +// element.prop('type', 'date'); +// element.on('change', function(ev) { +// scope.$apply(function () { +// controller.$setViewValue(moment(element.val()).toDate()); +// }); +// }); - element.prop('type', 'date'); - element.on('change', function(ev) { - scope.$apply(function () { - controller.$setViewValue(moment(element.val()).toDate()); - }); - }); - - } else { +// } else { // If we have a controller (i.e. ngModelController) then wire it up if(controller) { @@ -208,7 +208,7 @@ angular.module('biomed.directives', []) forceParse: attrs.forceParse || false }); - } +// } // Support add-on var component = element.siblings('[data-toggle="datepicker"]'); @@ -219,8 +219,143 @@ angular.module('biomed.directives', []) } }; }) -.directive('techpicker', function() { +.directive('techschedule', function() { + return { + restrict: 'E', + scope: { + schedule: '=', + date: '=', + onEntryClick: '&' + }, + templateUrl: '/partials/techSchedule.html', + replace: true, + link: function($scope, element, attrs) { + var x, rangeDate, rangeStart, rangeEnd; + function setupScale() { + x = d3.scale.linear() + .range([0, 100]) + .domain([420, 1320]) + .clamp(true); + } + + setupScale(); + + var color = d3.scale.category20(); + var hourWidth = 100 / 15; + + $scope.hourMarkers = []; + for (var i = 7; i < 22; i++) { + $scope.hourMarkers.push({ + date: moment({ hour: i }).toDate(), + style: { + left: x(i * 60) + '%', + width: hourWidth + '%' + } + }); + } + + $scope.$watch('schedule', function(newVal, oldVal) { + generateDate(); + }); + + $scope.$watch('date', function(newVal, oldVal) { + setupScale(); + }); + + function generateDate() { + var range = moment($scope.date); + var data = {}; + + for (var i = 0; i < 7; i++) { + var day = range.clone().add(i, 'days'); + var key = day.format('MM-DD-YYYY'); + var label = day.format('ddd MMM Do YYYY'); + + data[key] = { + label: label, + values: [] + }; + } + + var c = 0; + + angular.forEach($scope.schedule, function(workorder) { + var start = moment(workorder.scheduling.start); + var startMinutes = start.diff(start.clone().startOf('day'), 'minutes'); + + var end = moment(workorder.scheduling.end); + var endMinutes = end.diff(end.clone().startOf('day'), 'minutes'); + + var length = end.diff(start, 'days') + 1; + + console.log('length: ' + length + ' start: ' + startMinutes + ' end: ' + endMinutes); + + var backgroundColor = color(c++); + + for (var i = 0; i < length; i++) { + var adjStart, adjEnd; + + var key = start.clone().add(i, 'days').format('MM-DD-YYYY'); + + if (i == 0) { + adjStart = startMinutes; + } else { + adjStart = 420; + } + + if (i == length - 1) { + adjEnd = endMinutes; + } else { + adjEnd = 1320; + } + + if (data[key]) { + data[key].values.push({ + style: { + backgroundColor: color(c), + left: x(adjStart) + '%', + width: (x(adjEnd) - x(adjStart)) + '%' + }, + workorder: workorder + }); + } + + } + + return; + + angular.forEach(workorder.techs, function(tech) { + var key = tech.name.first + ' ' + tech.name.last; + + if (!data[key]) + return; + + var start = moment(workorder.scheduling.start); + var end = moment(workorder.scheduling.end); + + data[key].values.push({ + style: { + backgroundColor: color(key), + left: x(start) + "%", + width: (x(end) - x(start)) + "%" + }, + workorder: workorder + }); + }) + }); + + $scope.data = data; + } + } + }; +}) +.filter('pretty', function() { + return function(input) { + return "\n" + angular.toJson(input, true); + } +}) +.directive('techpicker', function() { return { restrict: 'E', scope: { @@ -232,24 +367,31 @@ angular.module('biomed.directives', []) 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, rangeDate, rangeStart, rangeEnd; - var x = d3.time.scale() - .range([0, 100]) - .domain([rangeStart, rangeEnd]); + function setupScale() { + rangeDate = moment($scope.date).startOf('day'); + + rangeStart = moment(rangeDate).add('hours', 7); + rangeEnd = moment(rangeDate).add('hours', 22); + + x = d3.time.scale() + .range([0, 100]) + .domain([rangeStart.toDate(), rangeEnd.toDate()]) + .clamp(true); + } + + setupScale(); var color = d3.scale.category20(); - var totalHours = moment.duration(moment(rangeEnd) - moment(rangeStart)).hours(); + var totalHours = moment.duration(rangeEnd - 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: { @@ -267,6 +409,10 @@ angular.module('biomed.directives', []) generateDate(); }); + $scope.$watch('date', function(newVal, oldVal) { + setupScale(); + }); + function generateDate() { var data = {}; @@ -275,7 +421,10 @@ angular.module('biomed.directives', []) angular.forEach($scope.users, function(user) { var key = user.name.first + ' ' + user.name.last; labels.push(key); - data[key] = []; + data[key] = { + id: user._id, + values: [] + }; }); labels.sort(); @@ -285,13 +434,13 @@ angular.module('biomed.directives', []) angular.forEach(workorder.techs, function(tech) { var key = tech.name.first + ' ' + tech.name.last; - if (!data[key]) - return; + 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(); + var start = moment(workorder.scheduling.start); + var end = moment(workorder.scheduling.end); - data[key].push({ + data[key].values.push({ style: { backgroundColor: color(key), left: x(start) + "%", @@ -306,7 +455,224 @@ angular.module('biomed.directives', []) } }; }) -.directive('uiSelect2', function ($timeout) { +.value('uiSelect2Config', {}) +.directive('uiSelect2', ['uiSelect2Config', '$timeout', function (uiSelect2Config, $timeout) { + var options = {}; + if (uiSelect2Config) { + angular.extend(options, uiSelect2Config); + } + return { + require: 'ngModel', + priority: 1, + compile: function (tElm, tAttrs) { + var watch, + repeatOption, + repeatAttr, + isSelect = tElm.is('select'), + isMultiple = angular.isDefined(tAttrs.multiple); + + // Enable watching of the options dataset if in use + if (tElm.is('select')) { + repeatOption = tElm.find( 'optgroup[ng-repeat], optgroup[data-ng-repeat], 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)); + + /* + Convert from Select2 view-model to Angular view-model. + */ + var convertToAngularModel = function(select2_data) { + var model; + if (opts.simple_tags) { + model = []; + angular.forEach(select2_data, function(value, index) { + model.push(value.id); + }); + } else { + model = select2_data; + } + return model; + }; + + /* + Convert from Angular view-model to Select2 view-model. + */ + var convertToSelect2Model = function(angular_data) { + var model = []; + if (!angular_data) { + return model; + } + + if (opts.simple_tags) { + model = []; + angular.forEach( + angular_data, + function(value, index) { + model.push({'id': value, 'text': value}); + }); + } else { + model = angular_data; + } + return model; + }; + + if (isSelect) { + // Use element."); - } - }); - } - - opts = $.extend({}, { - populateResults: function(container, results, query) { - var populate, data, result, children, id=this.opts.id, self=this; - - populate=function(results, container, depth) { - - var i, l, result, selectable, compound, node, label, innerContainer, formatted; - for (i = 0, l = results.length; i < l; i = i + 1) { - - result=results[i]; - selectable=id(result) !== undefined; - compound=result.children && result.children.length > 0; - - node=$("
  • "); - node.addClass("select2-results-dept-"+depth); - node.addClass("select2-result"); - node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable"); - if (compound) { node.addClass("select2-result-with-children"); } - node.addClass(self.opts.formatResultCssClass(result)); - - label=$("
    "); - label.addClass("select2-result-label"); - - formatted=opts.formatResult(result, label, query); - if (formatted!==undefined) { - label.html(self.opts.escapeMarkup(formatted)); - } - - node.append(label); - - if (compound) { - - innerContainer=$("
      "); - innerContainer.addClass("select2-result-sub"); - populate(result.children, innerContainer, depth+1); - node.append(innerContainer); - } - - node.data("select2-data", result); - container.append(node); - } - }; - - populate(results, container, 0); - } - }, $.fn.select2.defaults, opts); - - if (typeof(opts.id) !== "function") { - idKey = opts.id; - opts.id = function (e) { return e[idKey]; }; - } - - if (select) { - opts.query = this.bind(function (query) { - var data = { results: [], more: false }, - term = query.term, - children, firstChild, process; - - process=function(element, collection) { - var group; - if (element.is("option")) { - if (query.matcher(term, element.text(), element)) { - collection.push({id:element.attr("value"), text:element.text(), element: element.get(), css: element.attr("class")}); - } - } else if (element.is("optgroup")) { - group={text:element.attr("label"), children:[], element: element.get(), css: element.attr("class")}; - element.children().each2(function(i, elm) { process(elm, group.children); }); - if (group.children.length>0) { - collection.push(group); - } - } - }; - - children=element.children(); - - // ignore the placeholder option if there is one - if (this.getPlaceholder() !== undefined && children.length > 0) { - firstChild = children[0]; - if ($(firstChild).text() === "") { - children=children.not(firstChild); - } - } - - children.each2(function(i, elm) { process(elm, data.results); }); - - query.callback(data); - }); - // this is needed because inside val() we construct choices from options and there id is hardcoded - opts.id=function(e) { return e.id; }; - opts.formatResultCssClass = function(data) { return data.css; } - } else { - if (!("query" in opts)) { - if ("ajax" in opts) { - ajaxUrl = opts.element.data("ajax-url"); - if (ajaxUrl && ajaxUrl.length > 0) { - opts.ajax.url = ajaxUrl; - } - opts.query = ajax(opts.ajax); - } else if ("data" in opts) { - opts.query = local(opts.data); - } else if ("tags" in opts) { - opts.query = tags(opts.tags); - opts.createSearchChoice = function (term) { return {id: term, text: term}; }; - opts.initSelection = function (element, callback) { - var data = []; - $(splitVal(element.val(), opts.separator)).each(function () { - var id = this, text = this, tags=opts.tags; - if ($.isFunction(tags)) tags=tags(); - $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } }); - data.push({id: id, text: text}); - }); - - callback(data); - }; - } - } - } - if (typeof(opts.query) !== "function") { - throw "query function not defined for Select2 " + opts.element.attr("id"); - } - - return opts; - }, - - /** - * Monitor the original element for changes and update select2 accordingly - */ - // abstract - monitorSource: function () { - this.opts.element.bind("change.select2", this.bind(function (e) { - if (this.opts.element.data("select2-change-triggered") !== true) { - this.initSelection(); - } - })); - }, - - /** - * Triggers the change event on the source element - */ - // abstract - triggerChange: function (details) { - - details = details || {}; - details= $.extend({}, details, { type: "change", val: this.val() }); - // prevents recursive triggering - this.opts.element.data("select2-change-triggered", true); - this.opts.element.trigger(details); - this.opts.element.data("select2-change-triggered", false); - - // some validation frameworks ignore the change event and listen instead to keyup, click for selects - // so here we trigger the click event manually - this.opts.element.click(); - - // ValidationEngine ignorea the change event and listens instead to blur - // so here we trigger the blur event manually if so desired - if (this.opts.blurOnChange) - this.opts.element.blur(); - }, - - - // abstract - enable: function() { - if (this.enabled) return; - - this.enabled=true; - this.container.removeClass("select2-container-disabled"); - }, - - // abstract - disable: function() { - if (!this.enabled) return; - - this.close(); - - this.enabled=false; - this.container.addClass("select2-container-disabled"); - }, - - // abstract - opened: function () { - return this.container.hasClass("select2-dropdown-open"); - }, - - // abstract - positionDropdown: function() { - var offset = this.container.offset(), - height = this.container.outerHeight(), - width = this.container.outerWidth(), - dropHeight = this.dropdown.outerHeight(), - viewportBottom = $(window).scrollTop() + document.documentElement.clientHeight, - dropTop = offset.top + height, - dropLeft = offset.left, - enoughRoomBelow = dropTop + dropHeight <= viewportBottom, - enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(), - aboveNow = this.dropdown.hasClass("select2-drop-above"), - bodyOffset, - above, - css; - - // console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow); - // console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove); - - // fix positioning when body has an offset and is not position: static - - if (this.body().css('position') !== 'static') { - bodyOffset = this.body().offset(); - dropTop -= bodyOffset.top; - dropLeft -= bodyOffset.left; - } - - // always prefer the current above/below alignment, unless there is not enough room - - if (aboveNow) { - above = true; - if (!enoughRoomAbove && enoughRoomBelow) above = false; - } else { - above = false; - if (!enoughRoomBelow && enoughRoomAbove) above = true; - } - - if (above) { - dropTop = offset.top - dropHeight; - this.container.addClass("select2-drop-above"); - this.dropdown.addClass("select2-drop-above"); - } - else { - this.container.removeClass("select2-drop-above"); - this.dropdown.removeClass("select2-drop-above"); - } - - css = $.extend({ - top: dropTop, - left: dropLeft, - width: width - }, evaluate(this.opts.dropdownCss)); - - this.dropdown.css(css); - }, - - // abstract - shouldOpen: function() { - var event; - - if (this.opened()) return false; - - event = $.Event("open"); - this.opts.element.trigger(event); - return !event.isDefaultPrevented(); - }, - - // abstract - clearDropdownAlignmentPreference: function() { - // clear the classes used to figure out the preference of where the dropdown should be opened - this.container.removeClass("select2-drop-above"); - this.dropdown.removeClass("select2-drop-above"); - }, - - /** - * Opens the dropdown - * - * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example, - * the dropdown is already open, or if the 'open' event listener on the element called preventDefault(). - */ - // abstract - open: function () { - - if (!this.shouldOpen()) return false; - - window.setTimeout(this.bind(this.opening), 1); - - return true; - }, - - /** - * Performs the opening of the dropdown - */ - // abstract - opening: function() { - var cid = this.containerId, selector = this.containerSelector, - scroll = "scroll." + cid, resize = "resize." + cid; - - this.container.parents().each(function() { - $(this).bind(scroll, function() { - var s2 = $(selector); - if (s2.length == 0) { - $(this).unbind(scroll); - } - s2.select2("close"); - }); - }); - - $(window).bind(resize, function() { - var s2 = $(selector); - if (s2.length == 0) { - $(window).unbind(resize); - } - s2.select2("close"); - }); - - this.clearDropdownAlignmentPreference(); - - if (this.search.val() === " ") { this.search.val(""); } - - this.container.addClass("select2-dropdown-open").addClass("select2-container-active"); - - this.updateResults(true); - - if(this.dropdown[0] !== this.body().children().last()[0]) { - this.dropdown.detach().appendTo(this.body()); - } - - this.dropdown.show(); - - this.positionDropdown(); - this.dropdown.addClass("select2-drop-active"); - - this.ensureHighlightVisible(); - - this.focusSearch(); - }, - - // abstract - close: function () { - if (!this.opened()) return; - - var self = this; - - this.container.parents().each(function() { - $(this).unbind("scroll." + self.containerId); - }); - $(window).unbind("resize." + this.containerId); - - this.clearDropdownAlignmentPreference(); - - this.dropdown.hide(); - this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active"); - this.results.empty(); - this.clearSearch(); - - this.opts.element.trigger($.Event("close")); - }, - - // abstract - clearSearch: function () { - - }, - - // abstract - ensureHighlightVisible: function () { - var results = this.results, children, index, child, hb, rb, y, more; - - index = this.highlight(); - - if (index < 0) return; - - if (index == 0) { - - // if the first element is highlighted scroll all the way to the top, - // that way any unselectable headers above it will also be scrolled - // into view - - results.scrollTop(0); - return; - } - - children = results.find(".select2-result-selectable"); - - child = $(children[index]); - - hb = child.offset().top + child.outerHeight(); - - // if this is the last child lets also make sure select2-more-results is visible - if (index === children.length - 1) { - more = results.find("li.select2-more-results"); - if (more.length > 0) { - hb = more.offset().top + more.outerHeight(); - } - } - - rb = results.offset().top + results.outerHeight(); - if (hb > rb) { - results.scrollTop(results.scrollTop() + (hb - rb)); - } - y = child.offset().top - results.offset().top; - - // make sure the top of the element is visible - if (y < 0) { - results.scrollTop(results.scrollTop() + y); // y is negative - } - }, - - // abstract - moveHighlight: function (delta) { - var choices = this.results.find(".select2-result-selectable"), - index = this.highlight(); - - while (index > -1 && index < choices.length) { - index += delta; - var choice = $(choices[index]); - if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled")) { - this.highlight(index); - break; - } - } - }, - - // abstract - highlight: function (index) { - var choices = this.results.find(".select2-result-selectable").not(".select2-disabled"); - - if (arguments.length === 0) { - return indexOf(choices.filter(".select2-highlighted")[0], choices.get()); - } - - if (index >= choices.length) index = choices.length - 1; - if (index < 0) index = 0; - - choices.removeClass("select2-highlighted"); - - $(choices[index]).addClass("select2-highlighted"); - this.ensureHighlightVisible(); - - }, - - // abstract - countSelectableResults: function() { - return this.results.find(".select2-result-selectable").not(".select2-disabled").length; - }, - - // abstract - highlightUnderEvent: function (event) { - var el = $(event.target).closest(".select2-result-selectable"); - if (el.length > 0 && !el.is(".select2-highlighted")) { - var choices = this.results.find('.select2-result-selectable'); - this.highlight(choices.index(el)); - } else if (el.length == 0) { - // if we are over an unselectable item remove al highlights - this.results.find(".select2-highlighted").removeClass("select2-highlighted"); - } - }, - - // abstract - loadMoreIfNeeded: function () { - var results = this.results, - more = results.find("li.select2-more-results"), - below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible - offset = -1, // index of first element without data - page = this.resultsPage + 1, - self=this, - term=this.search.val(), - context=this.context; - - if (more.length === 0) return; - below = more.offset().top - results.offset().top - results.height(); - - if (below <= 0) { - more.addClass("select2-active"); - this.opts.query({ - term: term, - page: page, - context: context, - matcher: this.opts.matcher, - callback: this.bind(function (data) { - - // ignore a response if the select2 has been closed before it was received - if (!self.opened()) return; - - - self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context}); - - if (data.more===true) { - more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1)); - window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); - } else { - more.remove(); - } - self.positionDropdown(); - self.resultsPage = page; - })}); - } - }, - - /** - * Default tokenizer function which does nothing - */ - tokenize: function() { - - }, - - /** - * @param initial whether or not this is the call to this method right after the dropdown has been opened - */ - // abstract - updateResults: function (initial) { - var search = this.search, results = this.results, opts = this.opts, data, self=this, input; - - // if the search is currently hidden we do not alter the results - if (initial !== true && (this.showSearchInput === false || !this.opened())) { - return; - } - - search.addClass("select2-active"); - - function postRender() { - results.scrollTop(0); - search.removeClass("select2-active"); - self.positionDropdown(); - } - - function render(html) { - results.html(self.opts.escapeMarkup(html)); - postRender(); - } - - if (opts.maximumSelectionSize >=1) { - data = this.data(); - if ($.isArray(data) && data.length >= opts.maximumSelectionSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) { - render("
    • " + opts.formatSelectionTooBig(opts.maximumSelectionSize) + "
    • "); - return; - } - } - - if (search.val().length < opts.minimumInputLength && checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) { - render("
    • " + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "
    • "); - return; - } - else { - render("
    • " + opts.formatSearching() + "
    • "); - } - - // give the tokenizer a chance to pre-process the input - input = this.tokenize(); - if (input != undefined && input != null) { - search.val(input); - } - - this.resultsPage = 1; - opts.query({ - term: search.val(), - page: this.resultsPage, - context: null, - matcher: opts.matcher, - callback: this.bind(function (data) { - var def; // default choice - - // ignore a response if the select2 has been closed before it was received - if (!this.opened()) return; - - // save context, if any - this.context = (data.context===undefined) ? null : data.context; - - // create a default choice and prepend it to the list - if (this.opts.createSearchChoice && search.val() !== "") { - def = this.opts.createSearchChoice.call(null, search.val(), data.results); - if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) { - if ($(data.results).filter( - function () { - return equal(self.id(this), self.id(def)); - }).length === 0) { - data.results.unshift(def); - } - } - } - - if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) { - render("
    • " + opts.formatNoMatches(search.val()) + "
    • "); - return; - } - - results.empty(); - self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null}); - - if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) { - results.append("
    • " + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "
    • "); - window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10); - } - - this.postprocessResults(data, initial); - - postRender(); - })}); - }, - - // abstract - cancel: function () { - this.close(); - }, - - // abstract - blur: function () { - this.close(); - this.container.removeClass("select2-container-active"); - this.dropdown.removeClass("select2-drop-active"); - // synonymous to .is(':focus'), which is available in jquery >= 1.6 - if (this.search[0] === document.activeElement) { this.search.blur(); } - this.clearSearch(); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - }, - - // abstract - focusSearch: function () { - // need to do it here as well as in timeout so it works in IE - this.search.show(); - this.search.focus(); - - /* we do this in a timeout so that current event processing can complete before this code is executed. - this makes sure the search field is focussed even if the current event would blur it */ - window.setTimeout(this.bind(function () { - // reset the value so IE places the cursor at the end of the input box - this.search.show(); - this.search.focus(); - this.search.val(this.search.val()); - }), 10); - }, - - // abstract - selectHighlighted: function () { - var index=this.highlight(), - highlighted=this.results.find(".select2-highlighted").not(".select2-disabled"), - data = highlighted.closest('.select2-result-selectable').data("select2-data"); - if (data) { - highlighted.addClass("select2-disabled"); - this.highlight(index); - this.onSelect(data); - } - }, - - // abstract - getPlaceholder: function () { - return this.opts.element.attr("placeholder") || - this.opts.element.attr("data-placeholder") || // jquery 1.4 compat - this.opts.element.data("placeholder") || - this.opts.placeholder; - }, - - /** - * Get the desired width for the container element. This is - * derived first from option `width` passed to select2, then - * the inline 'style' on the original element, and finally - * falls back to the jQuery calculated element width. - */ - // abstract - initContainerWidth: function () { - function resolveContainerWidth() { - var style, attrs, matches, i, l; - - if (this.opts.width === "off") { - return null; - } else if (this.opts.width === "element"){ - return this.opts.element.outerWidth() === 0 ? 'auto' : this.opts.element.outerWidth() + 'px'; - } else if (this.opts.width === "copy" || this.opts.width === "resolve") { - // check if there is inline style on the element that contains width - style = this.opts.element.attr('style'); - if (style !== undefined) { - attrs = style.split(';'); - for (i = 0, l = attrs.length; i < l; i = i + 1) { - matches = attrs[i].replace(/\s/g, '') - .match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/); - if (matches !== null && matches.length >= 1) - return matches[1]; - } - } - - if (this.opts.width === "resolve") { - // next check if css('width') can resolve a width that is percent based, this is sometimes possible - // when attached to input type=hidden or elements hidden via css - style = this.opts.element.css('width'); - if (style.indexOf("%") > 0) return style; - - // finally, fallback on the calculated width of the element - return (this.opts.element.outerWidth() === 0 ? 'auto' : this.opts.element.outerWidth() + 'px'); - } - - return null; - } else if ($.isFunction(this.opts.width)) { - return this.opts.width(); - } else { - return this.opts.width; - } - }; - - var width = resolveContainerWidth.call(this); - if (width !== null) { - this.container.attr("style", "width: "+width); - } - } - }); - - SingleSelect2 = clazz(AbstractSelect2, { - - // single - - createContainer: function () { - var container = $("
      ", { - "class": "select2-container" - }).html([ - " ", - " ", - "
      " , - "
      ", - "
      " , - " " , - "
        " , - "
      " , - "
      "].join("")); - return container; - }, - - // single - opening: function () { - this.search.show(); - this.parent.opening.apply(this, arguments); - this.dropdown.removeClass("select2-offscreen"); - }, - - // single - close: function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - this.dropdown.removeAttr("style").addClass("select2-offscreen").insertAfter(this.selection).show(); - }, - - // single - focus: function () { - this.close(); - this.selection.focus(); - }, - - // single - isFocused: function () { - return this.selection[0] === document.activeElement; - }, - - // single - cancel: function () { - this.parent.cancel.apply(this, arguments); - this.selection.focus(); - }, - - // single - initContainer: function () { - - var selection, - container = this.container, - dropdown = this.dropdown, - clickingInside = false; - - this.selection = selection = container.find(".select2-choice"); - - this.search.bind("keydown", this.bind(function (e) { - if (!this.enabled) return; - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - return; - } - - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.TAB: - case KEY.ENTER: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - } else { - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) { - return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - return; - } - - this.open(); - - if (e.which === KEY.ENTER) { - // do not propagate the event otherwise we open, and propagate enter which closes - return; - } - } - })); - - this.search.bind("focus", this.bind(function() { - this.selection.attr("tabIndex", "-1"); - })); - this.search.bind("blur", this.bind(function() { - if (!this.opened()) this.container.removeClass("select2-container-active"); - window.setTimeout(this.bind(function() { this.selection.attr("tabIndex", this.opts.element.attr("tabIndex")); }), 10); - })); - - selection.bind("mousedown", this.bind(function (e) { - clickingInside = true; - - if (this.opened()) { - this.close(); - this.selection.focus(); - } else if (this.enabled) { - this.open(); - } - - clickingInside = false; - })); - - dropdown.bind("mousedown", this.bind(function() { this.search.focus(); })); - - selection.bind("focus", this.bind(function() { - this.container.addClass("select2-container-active"); - // hide the search so the tab key does not focus on it - this.search.attr("tabIndex", "-1"); - })); - - selection.bind("blur", this.bind(function() { - if (!this.opened()) { - this.container.removeClass("select2-container-active"); - } - window.setTimeout(this.bind(function() { this.search.attr("tabIndex", this.opts.element.attr("tabIndex")); }), 10); - })); - - selection.bind("keydown", this.bind(function(e) { - if (!this.enabled) return; - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - return; - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) - || e.which === KEY.ESC) { - return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - return; - } - - if (e.which == KEY.DELETE) { - if (this.opts.allowClear) { - this.clear(); - } - return; - } - - this.open(); - - if (e.which === KEY.ENTER) { - // do not propagate the event otherwise we open, and propagate enter which closes - killEvent(e); - return; - } - - // do not set the search input value for non-alpha-numeric keys - // otherwise pressing down results in a '(' being set in the search field - if (e.which < 48 ) { // '0' == 48 - killEvent(e); - return; - } - - var keyWritten = String.fromCharCode(e.which).toLowerCase(); - - if (e.shiftKey) { - keyWritten = keyWritten.toUpperCase(); - } - - // focus the field before calling val so the cursor ends up after the value instead of before - this.search.focus(); - this.search.val(keyWritten); - - // prevent event propagation so it doesnt replay on the now focussed search field and result in double key entry - killEvent(e); - })); - - selection.delegate("abbr", "mousedown", this.bind(function (e) { - if (!this.enabled) return; - this.clear(); - killEvent(e); - this.close(); - this.triggerChange(); - this.selection.focus(); - })); - - this.setPlaceholder(); - - this.search.bind("focus", this.bind(function() { - this.container.addClass("select2-container-active"); - })); - }, - - // single - clear: function() { - this.opts.element.val(""); - this.selection.find("span").empty(); - this.selection.removeData("select2-data"); - this.setPlaceholder(); - }, - - /** - * Sets selection based on source element's value - */ - // single - initSelection: function () { - var selected; - if (this.opts.element.val() === "") { - this.close(); - this.setPlaceholder(); - } else { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(selected){ - if (selected !== undefined && selected !== null) { - self.updateSelection(selected); - self.close(); - self.setPlaceholder(); - } - }); - } - }, - - // single - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments); - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install the selection initializer - opts.initSelection = function (element, callback) { - var selected = element.find(":selected"); - // a single select box always has a value, no need to null check 'selected' - if ($.isFunction(callback)) - callback({id: selected.attr("value"), text: selected.text()}); - }; - } - - return opts; - }, - - // single - setPlaceholder: function () { - var placeholder = this.getPlaceholder(); - - if (this.opts.element.val() === "" && placeholder !== undefined) { - - // check for a first blank option if attached to a select - if (this.select && this.select.find("option:first").text() !== "") return; - - this.selection.find("span").html(this.opts.escapeMarkup(placeholder)); - - this.selection.addClass("select2-default"); - - this.selection.find("abbr").hide(); - } - }, - - // single - postprocessResults: function (data, initial) { - var selected = 0, self = this, showSearchInput = true; - - // find the selected element in the result list - - this.results.find(".select2-result-selectable").each2(function (i, elm) { - if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) { - selected = i; - return false; - } - }); - - // and highlight it - - this.highlight(selected); - - // hide the search box if this is the first we got the results and there are a few of them - - if (initial === true) { - showSearchInput = this.showSearchInput = countResults(data.results) >= this.opts.minimumResultsForSearch; - this.dropdown.find(".select2-search")[showSearchInput ? "removeClass" : "addClass"]("select2-search-hidden"); - - //add "select2-with-searchbox" to the container if search box is shown - $(this.dropdown, this.container)[showSearchInput ? "addClass" : "removeClass"]("select2-with-searchbox"); - } - - }, - - // single - onSelect: function (data) { - var old = this.opts.element.val(); - - this.opts.element.val(this.id(data)); - this.updateSelection(data); - this.close(); - this.selection.focus(); - - if (!equal(old, this.id(data))) { this.triggerChange(); } - }, - - // single - updateSelection: function (data) { - - var container=this.selection.find("span"), formatted; - - this.selection.data("select2-data", data); - - container.empty(); - formatted=this.opts.formatSelection(data, container); - if (formatted !== undefined) { - container.append(this.opts.escapeMarkup(formatted)); - } - - this.selection.removeClass("select2-default"); - - if (this.opts.allowClear && this.getPlaceholder() !== undefined) { - this.selection.find("abbr").show(); - } - }, - - // single - val: function () { - var val, data = null, self = this; - - if (arguments.length === 0) { - return this.opts.element.val(); - } - - val = arguments[0]; - - if (this.select) { - this.select - .val(val) - .find(":selected").each2(function (i, elm) { - data = {id: elm.attr("value"), text: elm.text()}; - return false; - }); - this.updateSelection(data); - this.setPlaceholder(); - } else { - if (this.opts.initSelection === undefined) { - throw new Error("cannot call val() if initSelection() is not defined"); - } - // val is an id. !val is true for [undefined,null,''] - if (!val) { - this.clear(); - return; - } - this.opts.element.val(val); - this.opts.initSelection(this.opts.element, function(data){ - self.opts.element.val(!data ? "" : self.id(data)); - self.updateSelection(data); - self.setPlaceholder(); - }); - } - }, - - // single - clearSearch: function () { - this.search.val(""); - }, - - // single - data: function(value) { - var data; - - if (arguments.length === 0) { - data = this.selection.data("select2-data"); - if (data == undefined) data = null; - return data; - } else { - if (!value || value === "") { - this.clear(); - } else { - this.opts.element.val(!value ? "" : this.id(value)); - this.updateSelection(value); - } - } - } - }); - - MultiSelect2 = clazz(AbstractSelect2, { - - // multi - createContainer: function () { - var container = $("
      ", { - "class": "select2-container select2-container-multi" - }).html([ - "
        ", - //"
      • California
      • " , - "
      • " , - " " , - "
      • " , - "
      " , - ""].join("")); - return container; - }, - - // multi - prepareOpts: function () { - var opts = this.parent.prepareOpts.apply(this, arguments); - - // TODO validate placeholder is a string if specified - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - // install sthe selection initializer - opts.initSelection = function (element,callback) { - - var data = []; - element.find(":selected").each2(function (i, elm) { - data.push({id: elm.attr("value"), text: elm.text()}); - }); - - if ($.isFunction(callback)) - callback(data); - }; - } - - return opts; - }, - - // multi - initContainer: function () { - - var selector = ".select2-choices", selection; - - this.searchContainer = this.container.find(".select2-search-field"); - this.selection = selection = this.container.find(selector); - - this.search.bind("keydown", this.bind(function (e) { - if (!this.enabled) return; - - if (e.which === KEY.BACKSPACE && this.search.val() === "") { - this.close(); - - var choices, - selected = selection.find(".select2-search-choice-focus"); - if (selected.length > 0) { - this.unselect(selected.first()); - this.search.width(10); - killEvent(e); - return; - } - - choices = selection.find(".select2-search-choice"); - if (choices.length > 0) { - choices.last().addClass("select2-search-choice-focus"); - } - } else { - selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - } - - if (this.opened()) { - switch (e.which) { - case KEY.UP: - case KEY.DOWN: - this.moveHighlight((e.which === KEY.UP) ? -1 : 1); - killEvent(e); - return; - case KEY.ENTER: - case KEY.TAB: - this.selectHighlighted(); - killEvent(e); - return; - case KEY.ESC: - this.cancel(e); - killEvent(e); - return; - } - } - - if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) - || e.which === KEY.BACKSPACE || e.which === KEY.ESC) { - return; - } - - if (this.opts.openOnEnter === false && e.which === KEY.ENTER) { - return; - } - - this.open(); - - if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) { - // prevent the page from scrolling - killEvent(e); - } - })); - - this.search.bind("keyup", this.bind(this.resizeSearch)); - - this.search.bind("blur", this.bind(function(e) { - this.container.removeClass("select2-container-active"); - this.search.removeClass("select2-focused"); - this.clearSearch(); - e.stopImmediatePropagation(); - })); - - this.container.delegate(selector, "mousedown", this.bind(function (e) { - if (!this.enabled) return; - if ($(e.target).closest(".select2-search-choice").length > 0) { - // clicked inside a select2 search choice, do not open - return; - } - this.clearPlaceholder(); - this.open(); - this.focusSearch(); - e.preventDefault(); - })); - - this.container.delegate(selector, "focus", this.bind(function () { - if (!this.enabled) return; - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - this.clearPlaceholder(); - })); - - // set the placeholder if necessary - this.clearSearch(); - }, - - // multi - enable: function() { - if (this.enabled) return; - - this.parent.enable.apply(this, arguments); - - this.search.removeAttr("disabled"); - }, - - // multi - disable: function() { - if (!this.enabled) return; - - this.parent.disable.apply(this, arguments); - - this.search.attr("disabled", true); - }, - - // multi - initSelection: function () { - var data; - if (this.opts.element.val() === "") { - this.updateSelection([]); - this.close(); - // set the placeholder if necessary - this.clearSearch(); - } - if (this.select || this.opts.element.val() !== "") { - var self = this; - this.opts.initSelection.call(null, this.opts.element, function(data){ - if (data !== undefined && data !== null) { - self.updateSelection(data); - self.close(); - // set the placeholder if necessary - self.clearSearch(); - } - }); - } - }, - - // multi - clearSearch: function () { - var placeholder = this.getPlaceholder(); - - if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) { - this.search.val(placeholder).addClass("select2-default"); - // stretch the search box to full width of the container so as much of the placeholder is visible as possible - this.resizeSearch(); - } else { - // we set this to " " instead of "" and later clear it on focus() because there is a firefox bug - // that does not properly render the caret when the field starts out blank - this.search.val(" ").width(10); - } - }, - - // multi - clearPlaceholder: function () { - if (this.search.hasClass("select2-default")) { - this.search.val("").removeClass("select2-default"); - } else { - // work around for the space character we set to avoid firefox caret bug - if (this.search.val() === " ") this.search.val(""); - } - }, - - // multi - opening: function () { - this.parent.opening.apply(this, arguments); - - this.clearPlaceholder(); - this.resizeSearch(); - this.focusSearch(); - }, - - // multi - close: function () { - if (!this.opened()) return; - this.parent.close.apply(this, arguments); - }, - - // multi - focus: function () { - this.close(); - this.search.focus(); - }, - - // multi - isFocused: function () { - return this.search.hasClass("select2-focused"); - }, - - // multi - updateSelection: function (data) { - var ids = [], filtered = [], self = this; - - // filter out duplicates - $(data).each(function () { - if (indexOf(self.id(this), ids) < 0) { - ids.push(self.id(this)); - filtered.push(this); - } - }); - data = filtered; - - this.selection.find(".select2-search-choice").remove(); - $(data).each(function () { - self.addSelectedChoice(this); - }); - self.postprocessResults(); - }, - - tokenize: function() { - var input = this.search.val(); - input = this.opts.tokenizer(input, this.data(), this.bind(this.onSelect), this.opts); - if (input != null && input != undefined) { - this.search.val(input); - if (input.length > 0) { - this.open(); - } - } - - }, - - // multi - onSelect: function (data) { - this.addSelectedChoice(data); - if (this.select) { this.postprocessResults(); } - - if (this.opts.closeOnSelect) { - this.close(); - this.search.width(10); - } else { - if (this.countSelectableResults()>0) { - this.search.width(10); - this.resizeSearch(); - this.positionDropdown(); - } else { - // if nothing left to select close - this.close(); - } - } - - // since its not possible to select an element that has already been - // added we do not need to check if this is a new element before firing change - this.triggerChange({ added: data }); - - this.focusSearch(); - }, - - // multi - cancel: function () { - this.close(); - this.focusSearch(); - }, - - // multi - addSelectedChoice: function (data) { - var choice=$( - "
    • " + - "
      " + - " " + - "
    • "), - id = this.id(data), - val = this.getVal(), - formatted; - - formatted=this.opts.formatSelection(data, choice); - choice.find("div").replaceWith("
      "+this.opts.escapeMarkup(formatted)+"
      "); - choice.find(".select2-search-choice-close") - .bind("mousedown", killEvent) - .bind("click dblclick", this.bind(function (e) { - if (!this.enabled) return; - - $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){ - this.unselect($(e.target)); - this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"); - this.close(); - this.focusSearch(); - })).dequeue(); - killEvent(e); - })).bind("focus", this.bind(function () { - if (!this.enabled) return; - this.container.addClass("select2-container-active"); - this.dropdown.addClass("select2-drop-active"); - })); - - choice.data("select2-data", data); - choice.insertBefore(this.searchContainer); - - val.push(id); - this.setVal(val); - }, - - // multi - unselect: function (selected) { - var val = this.getVal(), - data, - index; - - selected = selected.closest(".select2-search-choice"); - - if (selected.length === 0) { - throw "Invalid argument: " + selected + ". Must be .select2-search-choice"; - } - - data = selected.data("select2-data"); - - index = indexOf(this.id(data), val); - - if (index >= 0) { - val.splice(index, 1); - this.setVal(val); - if (this.select) this.postprocessResults(); - } - selected.remove(); - this.triggerChange({ removed: data }); - }, - - // multi - postprocessResults: function () { - var val = this.getVal(), - choices = this.results.find(".select2-result-selectable"), - compound = this.results.find(".select2-result-with-children"), - self = this; - - choices.each2(function (i, choice) { - var id = self.id(choice.data("select2-data")); - if (indexOf(id, val) >= 0) { - choice.addClass("select2-disabled").removeClass("select2-result-selectable"); - } else { - choice.removeClass("select2-disabled").addClass("select2-result-selectable"); - } - }); - - compound.each2(function(i, e) { - if (e.find(".select2-result-selectable").length==0) { - e.addClass("select2-disabled"); - } else { - e.removeClass("select2-disabled"); - } - }); - - choices.each2(function (i, choice) { - if (!choice.hasClass("select2-disabled") && choice.hasClass("select2-result-selectable")) { - self.highlight(0); - return false; - } - }); - - }, - - // multi - resizeSearch: function () { - - var minimumWidth, left, maxWidth, containerLeft, searchWidth, - sideBorderPadding = getSideBorderPadding(this.search); - - minimumWidth = measureTextWidth(this.search) + 10; - - left = this.search.offset().left; - - maxWidth = this.selection.width(); - containerLeft = this.selection.offset().left; - - searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding; - if (searchWidth < minimumWidth) { - searchWidth = maxWidth - sideBorderPadding; - } - - if (searchWidth < 40) { - searchWidth = maxWidth - sideBorderPadding; - } - this.search.width(searchWidth); - }, - - // multi - getVal: function () { - var val; - if (this.select) { - val = this.select.val(); - return val === null ? [] : val; - } else { - val = this.opts.element.val(); - return splitVal(val, this.opts.separator); - } - }, - - // multi - setVal: function (val) { - var unique; - if (this.select) { - this.select.val(val); - } else { - unique = []; - // filter out duplicates - $(val).each(function () { - if (indexOf(this, unique) < 0) unique.push(this); - }); - this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator)); - } - }, - - // multi - val: function () { - var val, data = [], self=this; - - if (arguments.length === 0) { - return this.getVal(); - } - - val = arguments[0]; - - if (!val) { - this.opts.element.val(""); - this.updateSelection([]); - this.clearSearch(); - return; - } - - // val is a list of ids - this.setVal(val); - - if (this.select) { - this.select.find(":selected").each(function () { - data.push({id: $(this).attr("value"), text: $(this).text()}); - }); - this.updateSelection(data); - } else { - if (this.opts.initSelection === undefined) { - throw new Error("val() cannot be called if initSelection() is not defined") - } - - this.opts.initSelection(this.opts.element, function(data){ - var ids=$(data).map(self.id); - self.setVal(ids); - self.updateSelection(data); - self.clearSearch(); - }); - } - this.clearSearch(); - }, - - // multi - onSortStart: function() { - if (this.select) { - throw new Error("Sorting of elements is not supported when attached to instead."); - } - - // collapse search field into 0 width so its container can be collapsed as well - this.search.width(0); - // hide the container - this.searchContainer.hide(); - }, - - // multi - onSortEnd:function() { - - var val=[], self=this; - - // show search and move it to the end of the list - this.searchContainer.show(); - // make sure the search container is the last item in the list - this.searchContainer.appendTo(this.searchContainer.parent()); - // since we collapsed the width in dragStarted, we resize it here - this.resizeSearch(); - - // update selection - - this.selection.find(".select2-search-choice").each(function() { - val.push(self.opts.id($(this).data("select2-data"))); - }); - this.setVal(val); - this.triggerChange(); - }, - - // multi - data: function(values) { - var self=this, ids; - if (arguments.length === 0) { - return this.selection - .find(".select2-search-choice") - .map(function() { return $(this).data("select2-data"); }) - .get(); - } else { - if (!values) { values = []; } - ids = $.map(values, function(e) { return self.opts.id(e)}); - this.setVal(ids); - this.updateSelection(values); - this.clearSearch(); - } - } - }); - - $.fn.select2 = function () { - - var args = Array.prototype.slice.call(arguments, 0), - opts, - select2, - value, multiple, allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "disable", "positionDropdown", "data"]; - - this.each(function () { - if (args.length === 0 || typeof(args[0]) === "object") { - opts = args.length === 0 ? {} : $.extend({}, args[0]); - opts.element = $(this); - - if (opts.element.get(0).tagName.toLowerCase() === "select") { - multiple = opts.element.attr("multiple"); - } else { - multiple = opts.multiple || false; - if ("tags" in opts) {opts.multiple = multiple = true;} - } - - select2 = multiple ? new MultiSelect2() : new SingleSelect2(); - select2.init(opts); - } else if (typeof(args[0]) === "string") { - - if (indexOf(args[0], allowedMethods) < 0) { - throw "Unknown method: " + args[0]; - } - - value = undefined; - select2 = $(this).data("select2"); - if (select2 === undefined) return; - if (args[0] === "container") { - value=select2.container; - } else { - value = select2[args[0]].apply(select2, args.slice(1)); - } - if (value !== undefined) {return false;} - } else { - throw "Invalid arguments to select2 plugin: " + args; - } - }); - return (value === undefined) ? this : value; - }; - - // plugin defaults, accessible to users - $.fn.select2.defaults = { - width: "copy", - closeOnSelect: true, - openOnEnter: true, - containerCss: {}, - dropdownCss: {}, - containerCssClass: "", - dropdownCssClass: "", - formatResult: function(result, container, query) { - var markup=[]; - markMatch(result.text, query.term, markup); - return markup.join(""); - }, - formatSelection: function (data, container) { - return data ? data.text : undefined; - }, - formatResultCssClass: function(data) {return undefined;}, - formatNoMatches: function () { return "No matches found"; }, - formatInputTooShort: function (input, min) { return "Please enter " + (min - input.length) + " more characters"; }, - formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); }, - formatLoadMore: function (pageNumber) { return "Loading more results..."; }, - formatSearching: function () { return "Searching..."; }, - minimumResultsForSearch: 0, - minimumInputLength: 0, - maximumSelectionSize: 0, - id: function (e) { return e.id; }, - matcher: function(term, text) { - return text.toUpperCase().indexOf(term.toUpperCase()) >= 0; - }, - separator: ",", - tokenSeparators: [], - tokenizer: defaultTokenizer, - escapeMarkup: function (markup) { - if (markup && typeof(markup) === "string") { - return markup.replace(/&/g, "&"); - } - return markup; - }, - blurOnChange: false - }; - - // exports - window.Select2 = { - query: { - ajax: ajax, - local: local, - tags: tags - }, util: { - debounce: debounce, - markMatch: markMatch - }, "class": { - "abstract": AbstractSelect2, - "single": SingleSelect2, - "multi": MultiSelect2 - } - }; - -}(jQuery)); +/* +Copyright 2012 Igor Vaynberg + +Version: 3.4.5 Timestamp: Mon Nov 4 08:22:42 PST 2013 + +This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU +General Public License version 2 (the "GPL License"). You may choose either license to govern your +use of this software only upon the condition that you accept all of the terms of either the Apache +License or the GPL License. + +You may obtain a copy of the Apache License and the GPL License at: + +http://www.apache.org/licenses/LICENSE-2.0 +http://www.gnu.org/licenses/gpl-2.0.html + +Unless required by applicable law or agreed to in writing, software distributed under the Apache License +or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied. See the Apache License and the GPL License for the specific language governing +permissions and limitations under the Apache License and the GPL License. +*/ +!function(a){"undefined"==typeof a.fn.each2&&a.extend(a.fn,{each2:function(b){for(var c=a([0]),d=-1,e=this.length;++dc;c++)e=a.charAt(c),b+=m[e]||e;return b}function o(a,b){for(var c=0,d=b.length;d>c;c+=1)if(q(a,b[c]))return c;return-1}function p(){var b=a(l);b.appendTo("body");var c={width:b.width()-b[0].clientWidth,height:b.height()-b[0].clientHeight};return b.remove(),c}function q(a,c){return a===c?!0:a===b||c===b?!1:null===a||null===c?!1:a.constructor===String?a+""==c+"":c.constructor===String?c+""==a+"":!1}function r(b,c){var d,e,f;if(null===b||b.length<1)return[];for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d}function s(a){return a.outerWidth(!1)-a.width()}function t(c){var d="keyup-change-value";c.on("keydown",function(){a.data(c,d)===b&&a.data(c,d,c.val())}),c.on("keyup",function(){var e=a.data(c,d);e!==b&&c.val()!==e&&(a.removeData(c,d),c.trigger("keyup-change"))})}function u(c){c.on("mousemove",function(c){var d=i;(d===b||d.x!==c.pageX||d.y!==c.pageY)&&a(c.target).trigger("mousemove-filtered",c)})}function v(a,c,d){d=d||b;var e;return function(){var b=arguments;window.clearTimeout(e),e=window.setTimeout(function(){c.apply(d,b)},a)}}function w(a){var c,b=!1;return function(){return b===!1&&(c=a(),b=!0),c}}function x(a,b){var c=v(a,function(a){b.trigger("scroll-debounced",a)});b.on("scroll",function(a){o(a.target,b.get())>=0&&c(a)})}function y(a){a[0]!==document.activeElement&&window.setTimeout(function(){var d,b=a[0],c=a.val().length;a.focus(),a.is(":visible")&&b===document.activeElement&&(b.setSelectionRange?b.setSelectionRange(c,c):b.createTextRange&&(d=b.createTextRange(),d.collapse(!1),d.select()))},0)}function z(b){b=a(b)[0];var c=0,d=0;if("selectionStart"in b)c=b.selectionStart,d=b.selectionEnd-c;else if("selection"in document){b.focus();var e=document.selection.createRange();d=document.selection.createRange().text.length,e.moveStart("character",-b.value.length),c=e.text.length-d}return{offset:c,length:d}}function A(a){a.preventDefault(),a.stopPropagation()}function B(a){a.preventDefault(),a.stopImmediatePropagation()}function C(b){if(!h){var c=b[0].currentStyle||window.getComputedStyle(b[0],null);h=a(document.createElement("div")).css({position:"absolute",left:"-10000px",top:"-10000px",display:"none",fontSize:c.fontSize,fontFamily:c.fontFamily,fontStyle:c.fontStyle,fontWeight:c.fontWeight,letterSpacing:c.letterSpacing,textTransform:c.textTransform,whiteSpace:"nowrap"}),h.attr("class","select2-sizer"),a("body").append(h)}return h.text(b.val()),h.width()}function D(b,c,d){var e,g,f=[];e=b.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0===this.indexOf("select2-")&&f.push(this)})),e=c.attr("class"),e&&(e=""+e,a(e.split(" ")).each2(function(){0!==this.indexOf("select2-")&&(g=d(this),g&&f.push(g))})),b.attr("class",f.join(" "))}function E(a,b,c,d){var e=n(a.toUpperCase()).indexOf(n(b.toUpperCase())),f=b.length;return 0>e?(c.push(d(a)),void 0):(c.push(d(a.substring(0,e))),c.push(""),c.push(d(a.substring(e,e+f))),c.push(""),c.push(d(a.substring(e+f,a.length))),void 0)}function F(a){var b={"\\":"\","&":"&","<":"<",">":">",'"':""","'":"'","/":"/"};return String(a).replace(/[&<>"'\/\\]/g,function(a){return b[a]})}function G(c){var d,e=null,f=c.quietMillis||100,g=c.url,h=this;return function(i){window.clearTimeout(d),d=window.setTimeout(function(){var d=c.data,f=g,j=c.transport||a.fn.select2.ajaxDefaults.transport,k={type:c.type||"GET",cache:c.cache||!1,jsonpCallback:c.jsonpCallback||b,dataType:c.dataType||"json"},l=a.extend({},a.fn.select2.ajaxDefaults.params,k);d=d?d.call(h,i.term,i.page,i.context):null,f="function"==typeof f?f.call(h,i.term,i.page,i.context):f,e&&e.abort(),c.params&&(a.isFunction(c.params)?a.extend(l,c.params.call(h)):a.extend(l,c.params)),a.extend(l,{url:f,dataType:c.dataType,data:d,success:function(a){var b=c.results(a,i.page);i.callback(b)}}),e=j.call(h,l)},f)}}function H(b){var d,e,c=b,f=function(a){return""+a.text};a.isArray(c)&&(e=c,c={results:e}),a.isFunction(c)===!1&&(e=c,c=function(){return e});var g=c();return g.text&&(f=g.text,a.isFunction(f)||(d=g.text,f=function(a){return a[d]})),function(b){var g,d=b.term,e={results:[]};return""===d?(b.callback(c()),void 0):(g=function(c,e){var h,i;if(c=c[0],c.children){h={};for(i in c)c.hasOwnProperty(i)&&(h[i]=c[i]);h.children=[],a(c.children).each2(function(a,b){g(b,h.children)}),(h.children.length||b.matcher(d,f(h),c))&&e.push(h)}else b.matcher(d,f(c),c)&&e.push(c)},a(c().results).each2(function(a,b){g(b,e.results)}),b.callback(e),void 0)}}function I(c){var d=a.isFunction(c);return function(e){var f=e.term,g={results:[]};a(d?c():c).each(function(){var a=this.text!==b,c=a?this.text:this;(""===f||e.matcher(f,c))&&g.results.push(a?this:{id:this,text:this})}),e.callback(g)}}function J(b,c){if(a.isFunction(b))return!0;if(!b)return!1;throw new Error(c+" must be a function or a falsy value")}function K(b){return a.isFunction(b)?b():b}function L(b){var c=0;return a.each(b,function(a,b){b.children?c+=L(b.children):c++}),c}function M(a,c,d,e){var h,i,j,k,l,f=a,g=!1;if(!e.createSearchChoice||!e.tokenSeparators||e.tokenSeparators.length<1)return b;for(;;){for(i=-1,j=0,k=e.tokenSeparators.length;k>j&&(l=e.tokenSeparators[j],i=a.indexOf(l),!(i>=0));j++);if(0>i)break;if(h=a.substring(0,i),a=a.substring(i+l.length),h.length>0&&(h=e.createSearchChoice.call(this,h,c),h!==b&&null!==h&&e.id(h)!==b&&null!==e.id(h))){for(g=!1,j=0,k=c.length;k>j;j++)if(q(e.id(h),e.id(c[j]))){g=!0;break}g||d(h)}}return f!==a?a:void 0}function N(b,c){var d=function(){};return d.prototype=new b,d.prototype.constructor=d,d.prototype.parent=b.prototype,d.prototype=a.extend(d.prototype,c),d}if(window.Select2===b){var c,d,e,f,g,h,j,k,i={x:0,y:0},c={TAB:9,ENTER:13,ESC:27,SPACE:32,LEFT:37,UP:38,RIGHT:39,DOWN:40,SHIFT:16,CTRL:17,ALT:18,PAGE_UP:33,PAGE_DOWN:34,HOME:36,END:35,BACKSPACE:8,DELETE:46,isArrow:function(a){switch(a=a.which?a.which:a){case c.LEFT:case c.RIGHT:case c.UP:case c.DOWN:return!0}return!1},isControl:function(a){var b=a.which;switch(b){case c.SHIFT:case c.CTRL:case c.ALT:return!0}return a.metaKey?!0:!1},isFunctionKey:function(a){return a=a.which?a.which:a,a>=112&&123>=a}},l="
      ",m={"\u24b6":"A","\uff21":"A","\xc0":"A","\xc1":"A","\xc2":"A","\u1ea6":"A","\u1ea4":"A","\u1eaa":"A","\u1ea8":"A","\xc3":"A","\u0100":"A","\u0102":"A","\u1eb0":"A","\u1eae":"A","\u1eb4":"A","\u1eb2":"A","\u0226":"A","\u01e0":"A","\xc4":"A","\u01de":"A","\u1ea2":"A","\xc5":"A","\u01fa":"A","\u01cd":"A","\u0200":"A","\u0202":"A","\u1ea0":"A","\u1eac":"A","\u1eb6":"A","\u1e00":"A","\u0104":"A","\u023a":"A","\u2c6f":"A","\ua732":"AA","\xc6":"AE","\u01fc":"AE","\u01e2":"AE","\ua734":"AO","\ua736":"AU","\ua738":"AV","\ua73a":"AV","\ua73c":"AY","\u24b7":"B","\uff22":"B","\u1e02":"B","\u1e04":"B","\u1e06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24b8":"C","\uff23":"C","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\xc7":"C","\u1e08":"C","\u0187":"C","\u023b":"C","\ua73e":"C","\u24b9":"D","\uff24":"D","\u1e0a":"D","\u010e":"D","\u1e0c":"D","\u1e10":"D","\u1e12":"D","\u1e0e":"D","\u0110":"D","\u018b":"D","\u018a":"D","\u0189":"D","\ua779":"D","\u01f1":"DZ","\u01c4":"DZ","\u01f2":"Dz","\u01c5":"Dz","\u24ba":"E","\uff25":"E","\xc8":"E","\xc9":"E","\xca":"E","\u1ec0":"E","\u1ebe":"E","\u1ec4":"E","\u1ec2":"E","\u1ebc":"E","\u0112":"E","\u1e14":"E","\u1e16":"E","\u0114":"E","\u0116":"E","\xcb":"E","\u1eba":"E","\u011a":"E","\u0204":"E","\u0206":"E","\u1eb8":"E","\u1ec6":"E","\u0228":"E","\u1e1c":"E","\u0118":"E","\u1e18":"E","\u1e1a":"E","\u0190":"E","\u018e":"E","\u24bb":"F","\uff26":"F","\u1e1e":"F","\u0191":"F","\ua77b":"F","\u24bc":"G","\uff27":"G","\u01f4":"G","\u011c":"G","\u1e20":"G","\u011e":"G","\u0120":"G","\u01e6":"G","\u0122":"G","\u01e4":"G","\u0193":"G","\ua7a0":"G","\ua77d":"G","\ua77e":"G","\u24bd":"H","\uff28":"H","\u0124":"H","\u1e22":"H","\u1e26":"H","\u021e":"H","\u1e24":"H","\u1e28":"H","\u1e2a":"H","\u0126":"H","\u2c67":"H","\u2c75":"H","\ua78d":"H","\u24be":"I","\uff29":"I","\xcc":"I","\xcd":"I","\xce":"I","\u0128":"I","\u012a":"I","\u012c":"I","\u0130":"I","\xcf":"I","\u1e2e":"I","\u1ec8":"I","\u01cf":"I","\u0208":"I","\u020a":"I","\u1eca":"I","\u012e":"I","\u1e2c":"I","\u0197":"I","\u24bf":"J","\uff2a":"J","\u0134":"J","\u0248":"J","\u24c0":"K","\uff2b":"K","\u1e30":"K","\u01e8":"K","\u1e32":"K","\u0136":"K","\u1e34":"K","\u0198":"K","\u2c69":"K","\ua740":"K","\ua742":"K","\ua744":"K","\ua7a2":"K","\u24c1":"L","\uff2c":"L","\u013f":"L","\u0139":"L","\u013d":"L","\u1e36":"L","\u1e38":"L","\u013b":"L","\u1e3c":"L","\u1e3a":"L","\u0141":"L","\u023d":"L","\u2c62":"L","\u2c60":"L","\ua748":"L","\ua746":"L","\ua780":"L","\u01c7":"LJ","\u01c8":"Lj","\u24c2":"M","\uff2d":"M","\u1e3e":"M","\u1e40":"M","\u1e42":"M","\u2c6e":"M","\u019c":"M","\u24c3":"N","\uff2e":"N","\u01f8":"N","\u0143":"N","\xd1":"N","\u1e44":"N","\u0147":"N","\u1e46":"N","\u0145":"N","\u1e4a":"N","\u1e48":"N","\u0220":"N","\u019d":"N","\ua790":"N","\ua7a4":"N","\u01ca":"NJ","\u01cb":"Nj","\u24c4":"O","\uff2f":"O","\xd2":"O","\xd3":"O","\xd4":"O","\u1ed2":"O","\u1ed0":"O","\u1ed6":"O","\u1ed4":"O","\xd5":"O","\u1e4c":"O","\u022c":"O","\u1e4e":"O","\u014c":"O","\u1e50":"O","\u1e52":"O","\u014e":"O","\u022e":"O","\u0230":"O","\xd6":"O","\u022a":"O","\u1ece":"O","\u0150":"O","\u01d1":"O","\u020c":"O","\u020e":"O","\u01a0":"O","\u1edc":"O","\u1eda":"O","\u1ee0":"O","\u1ede":"O","\u1ee2":"O","\u1ecc":"O","\u1ed8":"O","\u01ea":"O","\u01ec":"O","\xd8":"O","\u01fe":"O","\u0186":"O","\u019f":"O","\ua74a":"O","\ua74c":"O","\u01a2":"OI","\ua74e":"OO","\u0222":"OU","\u24c5":"P","\uff30":"P","\u1e54":"P","\u1e56":"P","\u01a4":"P","\u2c63":"P","\ua750":"P","\ua752":"P","\ua754":"P","\u24c6":"Q","\uff31":"Q","\ua756":"Q","\ua758":"Q","\u024a":"Q","\u24c7":"R","\uff32":"R","\u0154":"R","\u1e58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1e5a":"R","\u1e5c":"R","\u0156":"R","\u1e5e":"R","\u024c":"R","\u2c64":"R","\ua75a":"R","\ua7a6":"R","\ua782":"R","\u24c8":"S","\uff33":"S","\u1e9e":"S","\u015a":"S","\u1e64":"S","\u015c":"S","\u1e60":"S","\u0160":"S","\u1e66":"S","\u1e62":"S","\u1e68":"S","\u0218":"S","\u015e":"S","\u2c7e":"S","\ua7a8":"S","\ua784":"S","\u24c9":"T","\uff34":"T","\u1e6a":"T","\u0164":"T","\u1e6c":"T","\u021a":"T","\u0162":"T","\u1e70":"T","\u1e6e":"T","\u0166":"T","\u01ac":"T","\u01ae":"T","\u023e":"T","\ua786":"T","\ua728":"TZ","\u24ca":"U","\uff35":"U","\xd9":"U","\xda":"U","\xdb":"U","\u0168":"U","\u1e78":"U","\u016a":"U","\u1e7a":"U","\u016c":"U","\xdc":"U","\u01db":"U","\u01d7":"U","\u01d5":"U","\u01d9":"U","\u1ee6":"U","\u016e":"U","\u0170":"U","\u01d3":"U","\u0214":"U","\u0216":"U","\u01af":"U","\u1eea":"U","\u1ee8":"U","\u1eee":"U","\u1eec":"U","\u1ef0":"U","\u1ee4":"U","\u1e72":"U","\u0172":"U","\u1e76":"U","\u1e74":"U","\u0244":"U","\u24cb":"V","\uff36":"V","\u1e7c":"V","\u1e7e":"V","\u01b2":"V","\ua75e":"V","\u0245":"V","\ua760":"VY","\u24cc":"W","\uff37":"W","\u1e80":"W","\u1e82":"W","\u0174":"W","\u1e86":"W","\u1e84":"W","\u1e88":"W","\u2c72":"W","\u24cd":"X","\uff38":"X","\u1e8a":"X","\u1e8c":"X","\u24ce":"Y","\uff39":"Y","\u1ef2":"Y","\xdd":"Y","\u0176":"Y","\u1ef8":"Y","\u0232":"Y","\u1e8e":"Y","\u0178":"Y","\u1ef6":"Y","\u1ef4":"Y","\u01b3":"Y","\u024e":"Y","\u1efe":"Y","\u24cf":"Z","\uff3a":"Z","\u0179":"Z","\u1e90":"Z","\u017b":"Z","\u017d":"Z","\u1e92":"Z","\u1e94":"Z","\u01b5":"Z","\u0224":"Z","\u2c7f":"Z","\u2c6b":"Z","\ua762":"Z","\u24d0":"a","\uff41":"a","\u1e9a":"a","\xe0":"a","\xe1":"a","\xe2":"a","\u1ea7":"a","\u1ea5":"a","\u1eab":"a","\u1ea9":"a","\xe3":"a","\u0101":"a","\u0103":"a","\u1eb1":"a","\u1eaf":"a","\u1eb5":"a","\u1eb3":"a","\u0227":"a","\u01e1":"a","\xe4":"a","\u01df":"a","\u1ea3":"a","\xe5":"a","\u01fb":"a","\u01ce":"a","\u0201":"a","\u0203":"a","\u1ea1":"a","\u1ead":"a","\u1eb7":"a","\u1e01":"a","\u0105":"a","\u2c65":"a","\u0250":"a","\ua733":"aa","\xe6":"ae","\u01fd":"ae","\u01e3":"ae","\ua735":"ao","\ua737":"au","\ua739":"av","\ua73b":"av","\ua73d":"ay","\u24d1":"b","\uff42":"b","\u1e03":"b","\u1e05":"b","\u1e07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24d2":"c","\uff43":"c","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\xe7":"c","\u1e09":"c","\u0188":"c","\u023c":"c","\ua73f":"c","\u2184":"c","\u24d3":"d","\uff44":"d","\u1e0b":"d","\u010f":"d","\u1e0d":"d","\u1e11":"d","\u1e13":"d","\u1e0f":"d","\u0111":"d","\u018c":"d","\u0256":"d","\u0257":"d","\ua77a":"d","\u01f3":"dz","\u01c6":"dz","\u24d4":"e","\uff45":"e","\xe8":"e","\xe9":"e","\xea":"e","\u1ec1":"e","\u1ebf":"e","\u1ec5":"e","\u1ec3":"e","\u1ebd":"e","\u0113":"e","\u1e15":"e","\u1e17":"e","\u0115":"e","\u0117":"e","\xeb":"e","\u1ebb":"e","\u011b":"e","\u0205":"e","\u0207":"e","\u1eb9":"e","\u1ec7":"e","\u0229":"e","\u1e1d":"e","\u0119":"e","\u1e19":"e","\u1e1b":"e","\u0247":"e","\u025b":"e","\u01dd":"e","\u24d5":"f","\uff46":"f","\u1e1f":"f","\u0192":"f","\ua77c":"f","\u24d6":"g","\uff47":"g","\u01f5":"g","\u011d":"g","\u1e21":"g","\u011f":"g","\u0121":"g","\u01e7":"g","\u0123":"g","\u01e5":"g","\u0260":"g","\ua7a1":"g","\u1d79":"g","\ua77f":"g","\u24d7":"h","\uff48":"h","\u0125":"h","\u1e23":"h","\u1e27":"h","\u021f":"h","\u1e25":"h","\u1e29":"h","\u1e2b":"h","\u1e96":"h","\u0127":"h","\u2c68":"h","\u2c76":"h","\u0265":"h","\u0195":"hv","\u24d8":"i","\uff49":"i","\xec":"i","\xed":"i","\xee":"i","\u0129":"i","\u012b":"i","\u012d":"i","\xef":"i","\u1e2f":"i","\u1ec9":"i","\u01d0":"i","\u0209":"i","\u020b":"i","\u1ecb":"i","\u012f":"i","\u1e2d":"i","\u0268":"i","\u0131":"i","\u24d9":"j","\uff4a":"j","\u0135":"j","\u01f0":"j","\u0249":"j","\u24da":"k","\uff4b":"k","\u1e31":"k","\u01e9":"k","\u1e33":"k","\u0137":"k","\u1e35":"k","\u0199":"k","\u2c6a":"k","\ua741":"k","\ua743":"k","\ua745":"k","\ua7a3":"k","\u24db":"l","\uff4c":"l","\u0140":"l","\u013a":"l","\u013e":"l","\u1e37":"l","\u1e39":"l","\u013c":"l","\u1e3d":"l","\u1e3b":"l","\u017f":"l","\u0142":"l","\u019a":"l","\u026b":"l","\u2c61":"l","\ua749":"l","\ua781":"l","\ua747":"l","\u01c9":"lj","\u24dc":"m","\uff4d":"m","\u1e3f":"m","\u1e41":"m","\u1e43":"m","\u0271":"m","\u026f":"m","\u24dd":"n","\uff4e":"n","\u01f9":"n","\u0144":"n","\xf1":"n","\u1e45":"n","\u0148":"n","\u1e47":"n","\u0146":"n","\u1e4b":"n","\u1e49":"n","\u019e":"n","\u0272":"n","\u0149":"n","\ua791":"n","\ua7a5":"n","\u01cc":"nj","\u24de":"o","\uff4f":"o","\xf2":"o","\xf3":"o","\xf4":"o","\u1ed3":"o","\u1ed1":"o","\u1ed7":"o","\u1ed5":"o","\xf5":"o","\u1e4d":"o","\u022d":"o","\u1e4f":"o","\u014d":"o","\u1e51":"o","\u1e53":"o","\u014f":"o","\u022f":"o","\u0231":"o","\xf6":"o","\u022b":"o","\u1ecf":"o","\u0151":"o","\u01d2":"o","\u020d":"o","\u020f":"o","\u01a1":"o","\u1edd":"o","\u1edb":"o","\u1ee1":"o","\u1edf":"o","\u1ee3":"o","\u1ecd":"o","\u1ed9":"o","\u01eb":"o","\u01ed":"o","\xf8":"o","\u01ff":"o","\u0254":"o","\ua74b":"o","\ua74d":"o","\u0275":"o","\u01a3":"oi","\u0223":"ou","\ua74f":"oo","\u24df":"p","\uff50":"p","\u1e55":"p","\u1e57":"p","\u01a5":"p","\u1d7d":"p","\ua751":"p","\ua753":"p","\ua755":"p","\u24e0":"q","\uff51":"q","\u024b":"q","\ua757":"q","\ua759":"q","\u24e1":"r","\uff52":"r","\u0155":"r","\u1e59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1e5b":"r","\u1e5d":"r","\u0157":"r","\u1e5f":"r","\u024d":"r","\u027d":"r","\ua75b":"r","\ua7a7":"r","\ua783":"r","\u24e2":"s","\uff53":"s","\xdf":"s","\u015b":"s","\u1e65":"s","\u015d":"s","\u1e61":"s","\u0161":"s","\u1e67":"s","\u1e63":"s","\u1e69":"s","\u0219":"s","\u015f":"s","\u023f":"s","\ua7a9":"s","\ua785":"s","\u1e9b":"s","\u24e3":"t","\uff54":"t","\u1e6b":"t","\u1e97":"t","\u0165":"t","\u1e6d":"t","\u021b":"t","\u0163":"t","\u1e71":"t","\u1e6f":"t","\u0167":"t","\u01ad":"t","\u0288":"t","\u2c66":"t","\ua787":"t","\ua729":"tz","\u24e4":"u","\uff55":"u","\xf9":"u","\xfa":"u","\xfb":"u","\u0169":"u","\u1e79":"u","\u016b":"u","\u1e7b":"u","\u016d":"u","\xfc":"u","\u01dc":"u","\u01d8":"u","\u01d6":"u","\u01da":"u","\u1ee7":"u","\u016f":"u","\u0171":"u","\u01d4":"u","\u0215":"u","\u0217":"u","\u01b0":"u","\u1eeb":"u","\u1ee9":"u","\u1eef":"u","\u1eed":"u","\u1ef1":"u","\u1ee5":"u","\u1e73":"u","\u0173":"u","\u1e77":"u","\u1e75":"u","\u0289":"u","\u24e5":"v","\uff56":"v","\u1e7d":"v","\u1e7f":"v","\u028b":"v","\ua75f":"v","\u028c":"v","\ua761":"vy","\u24e6":"w","\uff57":"w","\u1e81":"w","\u1e83":"w","\u0175":"w","\u1e87":"w","\u1e85":"w","\u1e98":"w","\u1e89":"w","\u2c73":"w","\u24e7":"x","\uff58":"x","\u1e8b":"x","\u1e8d":"x","\u24e8":"y","\uff59":"y","\u1ef3":"y","\xfd":"y","\u0177":"y","\u1ef9":"y","\u0233":"y","\u1e8f":"y","\xff":"y","\u1ef7":"y","\u1e99":"y","\u1ef5":"y","\u01b4":"y","\u024f":"y","\u1eff":"y","\u24e9":"z","\uff5a":"z","\u017a":"z","\u1e91":"z","\u017c":"z","\u017e":"z","\u1e93":"z","\u1e95":"z","\u01b6":"z","\u0225":"z","\u0240":"z","\u2c6c":"z","\ua763":"z"};j=a(document),g=function(){var a=1;return function(){return a++}}(),j.on("mousemove",function(a){i.x=a.pageX,i.y=a.pageY}),d=N(Object,{bind:function(a){var b=this;return function(){a.apply(b,arguments)}},init:function(c){var d,e,f=".select2-results";this.opts=c=this.prepareOpts(c),this.id=c.id,c.element.data("select2")!==b&&null!==c.element.data("select2")&&c.element.data("select2").destroy(),this.container=this.createContainer(),this.containerId="s2id_"+(c.element.attr("id")||"autogen"+g()),this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g,"\\$1"),this.container.attr("id",this.containerId),this.body=w(function(){return c.element.closest("body")}),D(this.container,this.opts.element,this.opts.adaptContainerCssClass),this.container.attr("style",c.element.attr("style")),this.container.css(K(c.containerCss)),this.container.addClass(K(c.containerCssClass)),this.elementTabIndex=this.opts.element.attr("tabindex"),this.opts.element.data("select2",this).attr("tabindex","-1").before(this.container).on("click.select2",A),this.container.data("select2",this),this.dropdown=this.container.find(".select2-drop"),D(this.dropdown,this.opts.element,this.opts.adaptDropdownCssClass),this.dropdown.addClass(K(c.dropdownCssClass)),this.dropdown.data("select2",this),this.dropdown.on("click",A),this.results=d=this.container.find(f),this.search=e=this.container.find("input.select2-input"),this.queryCount=0,this.resultsPage=0,this.context=null,this.initContainer(),this.container.on("click",A),u(this.results),this.dropdown.on("mousemove-filtered touchstart touchmove touchend",f,this.bind(this.highlightUnderEvent)),x(80,this.results),this.dropdown.on("scroll-debounced",f,this.bind(this.loadMoreIfNeeded)),a(this.container).on("change",".select2-input",function(a){a.stopPropagation()}),a(this.dropdown).on("change",".select2-input",function(a){a.stopPropagation()}),a.fn.mousewheel&&d.mousewheel(function(a,b,c,e){var f=d.scrollTop();e>0&&0>=f-e?(d.scrollTop(0),A(a)):0>e&&d.get(0).scrollHeight-d.scrollTop()+e<=d.height()&&(d.scrollTop(d.get(0).scrollHeight-d.height()),A(a))}),t(e),e.on("keyup-change input paste",this.bind(this.updateResults)),e.on("focus",function(){e.addClass("select2-focused")}),e.on("blur",function(){e.removeClass("select2-focused")}),this.dropdown.on("mouseup",f,this.bind(function(b){a(b.target).closest(".select2-result-selectable").length>0&&(this.highlightUnderEvent(b),this.selectHighlighted(b))})),this.dropdown.on("click mouseup mousedown",function(a){a.stopPropagation()}),a.isFunction(this.opts.initSelection)&&(this.initSelection(),this.monitorSource()),null!==c.maximumInputLength&&this.search.attr("maxlength",c.maximumInputLength);var h=c.element.prop("disabled");h===b&&(h=!1),this.enable(!h);var i=c.element.prop("readonly");i===b&&(i=!1),this.readonly(i),k=k||p(),this.autofocus=c.element.prop("autofocus"),c.element.prop("autofocus",!1),this.autofocus&&this.focus(),this.nextSearchTerm=b},destroy:function(){var a=this.opts.element,c=a.data("select2");this.close(),this.propertyObserver&&(delete this.propertyObserver,this.propertyObserver=null),c!==b&&(c.container.remove(),c.dropdown.remove(),a.removeClass("select2-offscreen").removeData("select2").off(".select2").prop("autofocus",this.autofocus||!1),this.elementTabIndex?a.attr({tabindex:this.elementTabIndex}):a.removeAttr("tabindex"),a.show())},optionToData:function(a){return a.is("option")?{id:a.prop("value"),text:a.text(),element:a.get(),css:a.attr("class"),disabled:a.prop("disabled"),locked:q(a.attr("locked"),"locked")||q(a.data("locked"),!0)}:a.is("optgroup")?{text:a.attr("label"),children:[],element:a.get(),css:a.attr("class")}:void 0},prepareOpts:function(c){var d,e,f,g,h=this;if(d=c.element,"select"===d.get(0).tagName.toLowerCase()&&(this.select=e=c.element),e&&a.each(["id","multiple","ajax","query","createSearchChoice","initSelection","data","tags"],function(){if(this in c)throw new Error("Option '"+this+"' is not allowed for Select2 when attached to a ","
      "," ","
        ","
      ","
      "].join(""));return b},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.focusser.prop("disabled",!this.isInterfaceEnabled())},opening:function(){var c,d,e;this.opts.minimumResultsForSearch>=0&&this.showSearch(!0),this.parent.opening.apply(this,arguments),this.showSearchInput!==!1&&this.search.val(this.focusser.val()),this.search.focus(),c=this.search.get(0),c.createTextRange?(d=c.createTextRange(),d.collapse(!1),d.select()):c.setSelectionRange&&(e=this.search.val().length,c.setSelectionRange(e,e)),""===this.search.val()&&this.nextSearchTerm!=b&&(this.search.val(this.nextSearchTerm),this.search.select()),this.focusser.prop("disabled",!0).val(""),this.updateResults(!0),this.opts.element.trigger(a.Event("select2-open"))},close:function(a){this.opened()&&(this.parent.close.apply(this,arguments),a=a||{focus:!0},this.focusser.removeAttr("disabled"),a.focus&&this.focusser.focus())},focus:function(){this.opened()?this.close():(this.focusser.removeAttr("disabled"),this.focusser.focus())},isFocused:function(){return this.container.hasClass("select2-container-active")},cancel:function(){this.parent.cancel.apply(this,arguments),this.focusser.removeAttr("disabled"),this.focusser.focus()},destroy:function(){a("label[for='"+this.focusser.attr("id")+"']").attr("for",this.opts.element.attr("id")),this.parent.destroy.apply(this,arguments)},initContainer:function(){var b,d=this.container,e=this.dropdown;this.opts.minimumResultsForSearch<0?this.showSearch(!1):this.showSearch(!0),this.selection=b=d.find(".select2-choice"),this.focusser=d.find(".select2-focusser"),this.focusser.attr("id","s2id_autogen"+g()),a("label[for='"+this.opts.element.attr("id")+"']").attr("for",this.focusser.attr("id")),this.focusser.attr("tabindex",this.elementTabIndex),this.search.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()){if(a.which===c.PAGE_UP||a.which===c.PAGE_DOWN)return A(a),void 0;switch(a.which){case c.UP:case c.DOWN:return this.moveHighlight(a.which===c.UP?-1:1),A(a),void 0;case c.ENTER:return this.selectHighlighted(),A(a),void 0;case c.TAB:return this.selectHighlighted({noFocus:!0}),void 0;case c.ESC:return this.cancel(a),A(a),void 0}}})),this.search.on("blur",this.bind(function(){document.activeElement===this.body().get(0)&&window.setTimeout(this.bind(function(){this.search.focus()}),0)})),this.focusser.on("keydown",this.bind(function(a){if(this.isInterfaceEnabled()&&a.which!==c.TAB&&!c.isControl(a)&&!c.isFunctionKey(a)&&a.which!==c.ESC){if(this.opts.openOnEnter===!1&&a.which===c.ENTER)return A(a),void 0;if(a.which==c.DOWN||a.which==c.UP||a.which==c.ENTER&&this.opts.openOnEnter){if(a.altKey||a.ctrlKey||a.shiftKey||a.metaKey)return;return this.open(),A(a),void 0}return a.which==c.DELETE||a.which==c.BACKSPACE?(this.opts.allowClear&&this.clear(),A(a),void 0):void 0}})),t(this.focusser),this.focusser.on("keyup-change input",this.bind(function(a){if(this.opts.minimumResultsForSearch>=0){if(a.stopPropagation(),this.opened())return;this.open()}})),b.on("mousedown","abbr",this.bind(function(a){this.isInterfaceEnabled()&&(this.clear(),B(a),this.close(),this.selection.focus())})),b.on("mousedown",this.bind(function(b){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.opened()?this.close():this.isInterfaceEnabled()&&this.open(),A(b)})),e.on("mousedown",this.bind(function(){this.search.focus()})),b.on("focus",this.bind(function(a){A(a)})),this.focusser.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})).on("blur",this.bind(function(){this.opened()||(this.container.removeClass("select2-container-active"),this.opts.element.trigger(a.Event("select2-blur")))})),this.search.on("focus",this.bind(function(){this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active")})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.setPlaceholder()},clear:function(b){var c=this.selection.data("select2-data");if(c){var d=a.Event("select2-clearing");if(this.opts.element.trigger(d),d.isDefaultPrevented())return;var e=this.getPlaceholderOption();this.opts.element.val(e?e.val():""),this.selection.find(".select2-chosen").empty(),this.selection.removeData("select2-data"),this.setPlaceholder(),b!==!1&&(this.opts.element.trigger({type:"select2-removed",val:this.id(c),choice:c}),this.triggerChange({removed:c}))}},initSelection:function(){if(this.isPlaceholderOptionSelected())this.updateSelection(null),this.close(),this.setPlaceholder();else{var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.setPlaceholder())})}},isPlaceholderOptionSelected:function(){var a;return this.getPlaceholder()?(a=this.getPlaceholderOption())!==b&&a.prop("selected")||""===this.opts.element.val()||this.opts.element.val()===b||null===this.opts.element.val():!1},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=a.find("option").filter(function(){return this.selected});b(c.optionToData(d))}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=c.val(),f=null;b.query({matcher:function(a,c,d){var g=q(e,b.id(d));return g&&(f=d),g},callback:a.isFunction(d)?function(){d(f)}:a.noop})}),b},getPlaceholder:function(){return this.select&&this.getPlaceholderOption()===b?b:this.parent.getPlaceholder.apply(this,arguments)},setPlaceholder:function(){var a=this.getPlaceholder();if(this.isPlaceholderOptionSelected()&&a!==b){if(this.select&&this.getPlaceholderOption()===b)return;this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(a)),this.selection.addClass("select2-default"),this.container.removeClass("select2-allowclear")}},postprocessResults:function(a,b,c){var d=0,e=this;if(this.findHighlightableChoices().each2(function(a,b){return q(e.id(b.data("select2-data")),e.opts.element.val())?(d=a,!1):void 0}),c!==!1&&(b===!0&&d>=0?this.highlight(d):this.highlight(0)),b===!0){var g=this.opts.minimumResultsForSearch;g>=0&&this.showSearch(L(a.results)>=g)}},showSearch:function(b){this.showSearchInput!==b&&(this.showSearchInput=b,this.dropdown.find(".select2-search").toggleClass("select2-search-hidden",!b),this.dropdown.find(".select2-search").toggleClass("select2-offscreen",!b),a(this.dropdown,this.container).toggleClass("select2-with-searchbox",b))},onSelect:function(a,b){if(this.triggerSelect(a)){var c=this.opts.element.val(),d=this.data();this.opts.element.val(this.id(a)),this.updateSelection(a),this.opts.element.trigger({type:"select2-selected",val:this.id(a),choice:a}),this.nextSearchTerm=this.opts.nextSearchTerm(a,this.search.val()),this.close(),b&&b.noFocus||this.focusser.focus(),q(c,this.id(a))||this.triggerChange({added:a,removed:d})}},updateSelection:function(a){var d,e,c=this.selection.find(".select2-chosen");this.selection.data("select2-data",a),c.empty(),null!==a&&(d=this.opts.formatSelection(a,c,this.opts.escapeMarkup)),d!==b&&c.append(d),e=this.opts.formatSelectionCssClass(a,c),e!==b&&c.addClass(e),this.selection.removeClass("select2-default"),this.opts.allowClear&&this.getPlaceholder()!==b&&this.container.addClass("select2-allowclear")},val:function(){var a,c=!1,d=null,e=this,f=this.data();if(0===arguments.length)return this.opts.element.val();if(a=arguments[0],arguments.length>1&&(c=arguments[1]),this.select)this.select.val(a).find("option").filter(function(){return this.selected}).each2(function(a,b){return d=e.optionToData(b),!1}),this.updateSelection(d),this.setPlaceholder(),c&&this.triggerChange({added:d,removed:f});else{if(!a&&0!==a)return this.clear(c),void 0;if(this.opts.initSelection===b)throw new Error("cannot call val() if initSelection() is not defined");this.opts.element.val(a),this.opts.initSelection(this.opts.element,function(a){e.opts.element.val(a?e.id(a):""),e.updateSelection(a),e.setPlaceholder(),c&&e.triggerChange({added:a,removed:f})})}},clearSearch:function(){this.search.val(""),this.focusser.val("")},data:function(a){var c,d=!1;return 0===arguments.length?(c=this.selection.data("select2-data"),c==b&&(c=null),c):(arguments.length>1&&(d=arguments[1]),a?(c=this.data(),this.opts.element.val(a?this.id(a):""),this.updateSelection(a),d&&this.triggerChange({added:a,removed:c})):this.clear(d),void 0)}}),f=N(d,{createContainer:function(){var b=a(document.createElement("div")).attr({"class":"select2-container select2-container-multi"}).html(["
        ","
      • "," ","
      • ","
      ","
      ","
        ","
      ","
      "].join(""));return b},prepareOpts:function(){var b=this.parent.prepareOpts.apply(this,arguments),c=this;return"select"===b.element.get(0).tagName.toLowerCase()?b.initSelection=function(a,b){var d=[];a.find("option").filter(function(){return this.selected}).each2(function(a,b){d.push(c.optionToData(b))}),b(d)}:"data"in b&&(b.initSelection=b.initSelection||function(c,d){var e=r(c.val(),b.separator),f=[];b.query({matcher:function(c,d,g){var h=a.grep(e,function(a){return q(a,b.id(g))}).length;return h&&f.push(g),h},callback:a.isFunction(d)?function(){for(var a=[],c=0;c0||(this.selectChoice(null),this.clearPlaceholder(),this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.open(),this.focusSearch(),b.preventDefault()))})),this.container.on("focus",b,this.bind(function(){this.isInterfaceEnabled()&&(this.container.hasClass("select2-container-active")||this.opts.element.trigger(a.Event("select2-focus")),this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"),this.clearPlaceholder())})),this.initContainerWidth(),this.opts.element.addClass("select2-offscreen"),this.clearSearch()},enableInterface:function(){this.parent.enableInterface.apply(this,arguments)&&this.search.prop("disabled",!this.isInterfaceEnabled())},initSelection:function(){if(""===this.opts.element.val()&&""===this.opts.element.text()&&(this.updateSelection([]),this.close(),this.clearSearch()),this.select||""!==this.opts.element.val()){var c=this;this.opts.initSelection.call(null,this.opts.element,function(a){a!==b&&null!==a&&(c.updateSelection(a),c.close(),c.clearSearch())})}},clearSearch:function(){var a=this.getPlaceholder(),c=this.getMaxSearchWidth();a!==b&&0===this.getVal().length&&this.search.hasClass("select2-focused")===!1?(this.search.val(a).addClass("select2-default"),this.search.width(c>0?c:this.container.css("width"))):this.search.val("").width(10)},clearPlaceholder:function(){this.search.hasClass("select2-default")&&this.search.val("").removeClass("select2-default")},opening:function(){this.clearPlaceholder(),this.resizeSearch(),this.parent.opening.apply(this,arguments),this.focusSearch(),this.updateResults(!0),this.search.focus(),this.opts.element.trigger(a.Event("select2-open"))},close:function(){this.opened()&&this.parent.close.apply(this,arguments)},focus:function(){this.close(),this.search.focus()},isFocused:function(){return this.search.hasClass("select2-focused")},updateSelection:function(b){var c=[],d=[],e=this;a(b).each(function(){o(e.id(this),c)<0&&(c.push(e.id(this)),d.push(this))}),b=d,this.selection.find(".select2-search-choice").remove(),a(b).each(function(){e.addSelectedChoice(this)}),e.postprocessResults()},tokenize:function(){var a=this.search.val();a=this.opts.tokenizer.call(this,a,this.data(),this.bind(this.onSelect),this.opts),null!=a&&a!=b&&(this.search.val(a),a.length>0&&this.open())},onSelect:function(a,b){this.triggerSelect(a)&&(this.addSelectedChoice(a),this.opts.element.trigger({type:"selected",val:this.id(a),choice:a}),(this.select||!this.opts.closeOnSelect)&&this.postprocessResults(a,!1,this.opts.closeOnSelect===!0),this.opts.closeOnSelect?(this.close(),this.search.width(10)):this.countSelectableResults()>0?(this.search.width(10),this.resizeSearch(),this.getMaximumSelectionSize()>0&&this.val().length>=this.getMaximumSelectionSize()&&this.updateResults(!0),this.positionDropdown()):(this.close(),this.search.width(10)),this.triggerChange({added:a}),b&&b.noFocus||this.focusSearch())},cancel:function(){this.close(),this.focusSearch()},addSelectedChoice:function(c){var j,k,d=!c.locked,e=a("
    • "),f=a("
    • "),g=d?e:f,h=this.id(c),i=this.getVal();j=this.opts.formatSelection(c,g.find("div"),this.opts.escapeMarkup),j!=b&&g.find("div").replaceWith("
      "+j+"
      "),k=this.opts.formatSelectionCssClass(c,g.find("div")),k!=b&&g.addClass(k),d&&g.find(".select2-search-choice-close").on("mousedown",A).on("click dblclick",this.bind(function(b){this.isInterfaceEnabled()&&(a(b.target).closest(".select2-search-choice").fadeOut("fast",this.bind(function(){this.unselect(a(b.target)),this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus"),this.close(),this.focusSearch()})).dequeue(),A(b))})).on("focus",this.bind(function(){this.isInterfaceEnabled()&&(this.container.addClass("select2-container-active"),this.dropdown.addClass("select2-drop-active"))})),g.data("select2-data",c),g.insertBefore(this.searchContainer),i.push(h),this.setVal(i)},unselect:function(b){var d,e,c=this.getVal();if(b=b.closest(".select2-search-choice"),0===b.length)throw"Invalid argument: "+b+". Must be .select2-search-choice";if(d=b.data("select2-data")){for(;(e=o(this.id(d),c))>=0;)c.splice(e,1),this.setVal(c),this.select&&this.postprocessResults();var f=a.Event("select2-removing");f.val=this.id(d),f.choice=d,this.opts.element.trigger(f),f.isDefaultPrevented()||(b.remove(),this.opts.element.trigger({type:"select2-removed",val:this.id(d),choice:d}),this.triggerChange({removed:d}))}},postprocessResults:function(a,b,c){var d=this.getVal(),e=this.results.find(".select2-result"),f=this.results.find(".select2-result-with-children"),g=this;e.each2(function(a,b){var c=g.id(b.data("select2-data"));o(c,d)>=0&&(b.addClass("select2-selected"),b.find(".select2-result-selectable").addClass("select2-selected"))}),f.each2(function(a,b){b.is(".select2-result-selectable")||0!==b.find(".select2-result-selectable:not(.select2-selected)").length||b.addClass("select2-selected")}),-1==this.highlight()&&c!==!1&&g.highlight(0),!this.opts.createSearchChoice&&!e.filter(".select2-result:not(.select2-selected)").length>0&&(!a||a&&!a.more&&0===this.results.find(".select2-no-results").length)&&J(g.opts.formatNoMatches,"formatNoMatches")&&this.results.append("
    • "+g.opts.formatNoMatches(g.search.val())+"
    • ")},getMaxSearchWidth:function(){return this.selection.width()-s(this.search)},resizeSearch:function(){var a,b,c,d,e,f=s(this.search);a=C(this.search)+10,b=this.search.offset().left,c=this.selection.width(),d=this.selection.offset().left,e=c-(b-d)-f,a>e&&(e=c-f),40>e&&(e=c-f),0>=e&&(e=a),this.search.width(Math.floor(e))},getVal:function(){var a;return this.select?(a=this.select.val(),null===a?[]:a):(a=this.opts.element.val(),r(a,this.opts.separator))},setVal:function(b){var c;this.select?this.select.val(b):(c=[],a(b).each(function(){o(this,c)<0&&c.push(this)}),this.opts.element.val(0===c.length?"":c.join(this.opts.separator)))},buildChangeDetails:function(a,b){for(var b=b.slice(0),a=a.slice(0),c=0;c0&&c--,a.splice(d,1),d--);return{added:b,removed:a}},val:function(c,d){var e,f=this;if(0===arguments.length)return this.getVal();if(e=this.data(),e.length||(e=[]),!c&&0!==c)return this.opts.element.val(""),this.updateSelection([]),this.clearSearch(),d&&this.triggerChange({added:this.data(),removed:e}),void 0;if(this.setVal(c),this.select)this.opts.initSelection(this.select,this.bind(this.updateSelection)),d&&this.triggerChange(this.buildChangeDetails(e,this.data()));else{if(this.opts.initSelection===b)throw new Error("val() cannot be called if initSelection() is not defined");this.opts.initSelection(this.opts.element,function(b){var c=a.map(b,f.id);f.setVal(c),f.updateSelection(b),f.clearSearch(),d&&f.triggerChange(f.buildChangeDetails(e,f.data()))})}this.clearSearch()},onSortStart:function(){if(this.select)throw new Error("Sorting of elements is not supported when attached to instead.");this.search.width(0),this.searchContainer.hide()},onSortEnd:function(){var b=[],c=this;this.searchContainer.show(),this.searchContainer.appendTo(this.searchContainer.parent()),this.resizeSearch(),this.selection.find(".select2-search-choice").each(function(){b.push(c.opts.id(a(this).data("select2-data")))}),this.setVal(b),this.triggerChange()},data:function(b,c){var e,f,d=this;return 0===arguments.length?this.selection.find(".select2-search-choice").map(function(){return a(this).data("select2-data")}).get():(f=this.data(),b||(b=[]),e=a.map(b,function(a){return d.opts.id(a)}),this.setVal(e),this.updateSelection(b),this.clearSearch(),c&&this.triggerChange(this.buildChangeDetails(f,this.data())),void 0)}}),a.fn.select2=function(){var d,g,h,i,j,c=Array.prototype.slice.call(arguments,0),k=["val","destroy","opened","open","close","focus","isFocused","container","dropdown","onSortStart","onSortEnd","enable","disable","readonly","positionDropdown","data","search"],l=["opened","isFocused","container","dropdown"],m=["val","data"],n={search:"externalSearch"};return this.each(function(){if(0===c.length||"object"==typeof c[0])d=0===c.length?{}:a.extend({},c[0]),d.element=a(this),"select"===d.element.get(0).tagName.toLowerCase()?j=d.element.prop("multiple"):(j=d.multiple||!1,"tags"in d&&(d.multiple=j=!0)),g=j?new f:new e,g.init(d);else{if("string"!=typeof c[0])throw"Invalid arguments to select2 plugin: "+c;if(o(c[0],k)<0)throw"Unknown method: "+c[0];if(i=b,g=a(this).data("select2"),g===b)return;if(h=c[0],"container"===h?i=g.container:"dropdown"===h?i=g.dropdown:(n[h]&&(h=n[h]),i=g[h].apply(g,c.slice(1))),o(c[0],l)>=0||o(c[0],m)&&1==c.length)return!1}}),i===b?this:i},a.fn.select2.defaults={width:"copy",loadMorePadding:0,closeOnSelect:!0,openOnEnter:!0,containerCss:{},dropdownCss:{},containerCssClass:"",dropdownCssClass:"",formatResult:function(a,b,c,d){var e=[];return E(a.text,c.term,e,d),e.join("")},formatSelection:function(a,c,d){return a?d(a.text):b},sortResults:function(a){return a},formatResultCssClass:function(){return b},formatSelectionCssClass:function(){return b},formatNoMatches:function(){return"No matches found"},formatInputTooShort:function(a,b){var c=b-a.length;return"Please enter "+c+" more character"+(1==c?"":"s")},formatInputTooLong:function(a,b){var c=a.length-b;return"Please delete "+c+" character"+(1==c?"":"s")},formatSelectionTooBig:function(a){return"You can only select "+a+" item"+(1==a?"":"s")},formatLoadMore:function(){return"Loading more results..."},formatSearching:function(){return"Searching..."},minimumResultsForSearch:0,minimumInputLength:0,maximumInputLength:null,maximumSelectionSize:0,id:function(a){return a.id},matcher:function(a,b){return n(""+b).toUpperCase().indexOf(n(""+a).toUpperCase())>=0},separator:",",tokenSeparators:[],tokenizer:M,escapeMarkup:F,blurOnChange:!1,selectOnBlur:!1,adaptContainerCssClass:function(a){return a},adaptDropdownCssClass:function(){return null},nextSearchTerm:function(){return b}},a.fn.select2.ajaxDefaults={transport:a.ajax,params:{type:"GET",cache:!1,dataType:"json"}},window.Select2={query:{ajax:G,local:H,tags:I},util:{debounce:v,markMatch:E,escapeMarkup:F,stripDiacritics:n},"class":{"abstract":d,single:e,multi:f}}}}(jQuery); \ No newline at end of file diff --git a/public/js/services.js b/public/js/services.js index b02f124..dc1c511 100644 --- a/public/js/services.js +++ b/public/js/services.js @@ -25,9 +25,13 @@ angular.module('biomed.services', []) }); }) .factory("Users", function($resource) { - return $resource('/api/users', { }, + return $resource('/api/users/:id/:cmd', + { id: "@id", cmd: "@cmd" }, { index: { method: 'GET', isArray: true }, + details: { method: 'GET', params: { cmd: 'details' }, isArray: true }, + create: { method: 'POST', params: {} }, + update: { method: 'POST', params: { id: 0 } }, }); }) .factory("Schedule", function($resource) { @@ -112,4 +116,4 @@ angular.module('biomed.services', []) }); }); } -}); \ No newline at end of file +}); diff --git a/public/partials/clients/edit.html b/public/partials/clients/edit.html index 8986d3b..8394635 100644 --- a/public/partials/clients/edit.html +++ b/public/partials/clients/edit.html @@ -6,7 +6,8 @@

      {{master.name}}

      {{master.identifier}}

      - Create new Workorder + Create new Workorder + Create new Meeting
      @@ -214,7 +215,7 @@
      -
      +
      @@ -289,21 +290,33 @@ - - - - - + + + + + + + + + + + - + + + + + + +
      Device IDDeviceMakeModelSerial No.Device IDDeviceMakeModelSerial No.Purchase DateWarranty ExpirationPM TestRoom #PO NumberMove to
      There is no information to display.
      There is no information to display.
      {{tag.data.clientDeviceId}} - (Tag:{{tag._id}}) {{tag.data.device}} {{tag.data.make}} {{tag.data.model}} {{tag.data.serialNumber}}{{tag.data.purchaseDate}}{{tag.data.deviceWarrantyExpiration}}{{tag.data.test}}{{tag.data.roomNumber}}{{tag.data.poNumber}}{{tag.data.MoveTo}}
      @@ -355,6 +368,6 @@
      - - + Notice: +

      Changes to the notes for a client does not automatically update every workorder that currently exists for the client. Only new workorders will contain the changed / updated notes. If you need to update the notes for a specific workorder you should go to the work order and re-save the workorder. This will push the updated notes to the techs calendar.

      diff --git a/public/partials/messages.html b/public/partials/messages.html index 270ab5b..a20d828 100644 --- a/public/partials/messages.html +++ b/public/partials/messages.html @@ -70,6 +70,6 @@ \ No newline at end of file + diff --git a/public/partials/schedule/index.html b/public/partials/schedule/index.html index f973639..0be5909 100644 --- a/public/partials/schedule/index.html +++ b/public/partials/schedule/index.html @@ -9,7 +9,8 @@
      Create new Workorder - View PMs + Create new Meeting + View PMs
      Group:
      @@ -31,4 +32,4 @@ date="date" on-entry-click="onEntryClick(entry)">
      -
      \ No newline at end of file +
      diff --git a/public/partials/techPicker.html b/public/partials/techPicker.html index 9b00ee9..2cd4b8e 100644 --- a/public/partials/techPicker.html +++ b/public/partials/techPicker.html @@ -12,9 +12,9 @@
      -
      {{name}}
      +
      -
      {{entry.workorder.client.identifier}}
      +
      {{entry.workorder.client.identifier}}
      diff --git a/public/partials/techSchedule.html b/public/partials/techSchedule.html new file mode 100644 index 0000000..a91e9e3 --- /dev/null +++ b/public/partials/techSchedule.html @@ -0,0 +1,20 @@ +
      +
      +
      + {{ hour.date | date:'h a'}} +
      +
      + +
      +
      +
      +
      +
      +
      +
      +
      {{values.label}}
      +
      +
      {{entry.workorder.client.identifier}}
      +
      +
      +
      diff --git a/public/partials/techs/schedule.html b/public/partials/techs/schedule.html new file mode 100644 index 0000000..ca1ff43 --- /dev/null +++ b/public/partials/techs/schedule.html @@ -0,0 +1,24 @@ + +
      +

      Schedule for {{tech.name.first}} {{tech.name.last}}

      +
      + +
      +
      +
      +
      Date: +
      + + +
      +
      +
      + +
      +
      diff --git a/public/partials/users/index.html b/public/partials/users/index.html new file mode 100644 index 0000000..4ed2a2b --- /dev/null +++ b/public/partials/users/index.html @@ -0,0 +1,61 @@ + +
      +

      Admin

      +
      + +
      +
      +
      +
      + Search: +
      + + +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      GroupsPermissions
      NameE-MailAllBiomedIceOthersSalesPortalTagsMessagesAdmin
      There is no information to display.
      {{user.name.first}} {{user.name.last}} NEW
      +
      +
      diff --git a/public/partials/workorders/add.html b/public/partials/workorders/add.html index 155594c..01d28ec 100644 --- a/public/partials/workorders/add.html +++ b/public/partials/workorders/add.html @@ -1,10 +1,12 @@
      -

      New Workorder

      +

      New Workorder

      +

      New Meeting

      @@ -19,6 +21,12 @@
      +
      + +
      + +
      +
      @@ -30,7 +38,7 @@
      - @@ -38,6 +46,7 @@ + @@ -51,18 +60,23 @@
      @@ -82,86 +96,161 @@
      - - + to - + + {{picker.duration}}
      -
      - +
      + +
      -
      @@ -177,17 +266,17 @@ + date="picker.startDate" + start="picker.startTime" + end="picker.endTime">
      - - + +
      diff --git a/public/partials/workorders/edit.html b/public/partials/workorders/edit.html index 0219998..5fe9014 100644 --- a/public/partials/workorders/edit.html +++ b/public/partials/workorders/edit.html @@ -6,6 +6,8 @@

      #{{master.biomedId}} - {{master.reason}}

      {{master.client.name}} ({{master.client.identifier}})

      +
      Created By: {{master.createdBy.name.first}} {{master.createdBy.name.last}} On {{master.createdOn | date}} {{master.createdOn | time}}
      +
      Last Modified By: {{master.modifiedBy.name.first}} {{master.modifiedBy.name.last}} On {{master.modifiedOn | date}} {{master.modifiedOn | time}}
      @@ -26,16 +28,42 @@ +
      - + +
      + +
      + +
      +
      + {{email}}, + Edit +
      +
      +
      + +
      + +
      +
      +
      + + + +
      +
      +
      +
      +
      @@ -56,6 +84,7 @@ + @@ -68,20 +97,25 @@
      - +
      @@ -92,7 +126,8 @@
      - + +
      @@ -102,95 +137,169 @@
      - {{master.scheduling.start | date}}
      - From {{master.scheduling.start | time}} to {{master.scheduling.end | time}}
      - Techs: {{ master.techs | techs }}
      + From {{master.scheduling.start | date}} {{master.scheduling.start | time}} to {{master.scheduling.end | date}} {{master.scheduling.end | time}}
      + TechsAttendees: {{ master.techs | techs }}
      Edit
      - - + to - + + {{scheduling.duration}}
      +
      - +
      -
      @@ -206,11 +315,12 @@ + date="scheduling.startDate" + start="scheduling.startTime" + end="scheduling.endTime">
      - + +
      @@ -219,12 +329,9 @@
      - +
      -
      - No history is currently available. -
      diff --git a/public/partials/workorders/index.html b/public/partials/workorders/index.html index 90c5066..1c30293 100644 --- a/public/partials/workorders/index.html +++ b/public/partials/workorders/index.html @@ -6,7 +6,8 @@
      - Create new workorder + Create new workorder + Create new meeting
      @@ -42,7 +43,7 @@ Techs: {{ workorder.techs | techs }}
      {{workorder.remarks}} - {{workorder.client.name}} ({{workorder.client.identifier}}) + {{workorder.client.name}} ({{workorder.client.identifier}}) {{workorder.scheduling.start | date}} {{workorder.status}} diff --git a/public/tags/app.js b/public/tags/app.js index af6b936..2ac6c05 100644 --- a/public/tags/app.js +++ b/public/tags/app.js @@ -1,5 +1,18 @@ var tags = {} +var fields = [ + { field: 'device', label: 'Device' }, + { field: 'make', label: 'Manufacture' }, + { field: 'model', label: 'Model' }, + { field: 'serialNumber', label: 'Serial Number' }, + { field: 'purchaseDate', label: 'Purchase Date' }, + { field: 'deviceWarrantyExpiration', label: 'Warranty Expiration' }, + { field: 'test', label: 'PM Test' }, + { field: 'roomNumber', label: 'Room #' }, + { field: 'poNumber', label: 'PO Number' }, + { field: 'MoveTo', label: 'Move To' } +]; + angular.module('tags', ['ngResource', 'biomed.directives']) .factory("Tag", function($resource) { return $resource('/api/tags'); @@ -11,6 +24,7 @@ angular.module('tags', ['ngResource', 'biomed.directives']) index: { method: 'GET', params: {}, isArray: true }, }); }) + tags.PageCtrl = function($scope, $window, Tag, Clients) { console.log($window.payload) @@ -38,4 +52,15 @@ tags.PageCtrl = function($scope, $window, Tag, Clients) { alert('Your changes have been saved.'); }); } + + $scope.fields = []; + + if ($scope.tag) { + for (var i = 0; i < fields.length; i++) { + fields[i].value = $scope.tag[fields[i].field]; + $scope.fields.push(fields[i]); + } + } + + console.log($scope.fields); } diff --git a/server.js b/server.js index e6251c1..e6b82a5 100644 --- a/server.js +++ b/server.js @@ -6,6 +6,13 @@ var env = process.env.NODE_ENV || 'development', config = require('./config/config')[env], mongoose = require('mongoose'); +var log = require('log4node'); +log.reconfigure({ + level: 'info', + file: 'server.log' +}); + +log.info("----- Server Started -----"); // bootstrap db connection mongoose.set('debug', config.debug); @@ -34,11 +41,13 @@ var auth = require('./config/auth')(app, passport); var calendar = require('./config/calendar')(config); +var directory = require('./config/directory')(config); + // Bootstrap routes -require('./config/routes')(app, auth, piler, calendar, config); +require('./config/routes')(app, auth, piler, calendar, directory, config); GLOBAL.health = 'OK' var port = process.env.PORT || 8000 server.listen(port) -console.log('Express app started on port ' + port) \ No newline at end of file +console.log('Express app started on port ' + port) diff --git a/test.js b/test.js index b8bc13d..e373dde 100644 --- a/test.js +++ b/test.js @@ -1,21 +1,10 @@ var env = process.env.NODE_ENV || 'development', - config = require('./config/config')[env], - fs = require('fs'), - calendar = require('./config/calendar')(config), - moment = require('moment'); + config = require('./config/config')[env]; -var event = { - summary: 'Summary', - location: 'Location', - start: moment().hour(5).minute(30).toDate(), - end: moment().hour(6).minute(0).toDate(), - attendees: [ 'akirayasha@gmail.com' ] -}; +config.auth.accessToken = "ya29.1.AADtN_Xjt0PK6YVs8q5csiQFXQg2ZDtrVhsH6P4a5zm0mHqhGx0Nnjx4Jk68Gw"; +config.auth.refreshToken = "1/_5SkDLYmsi4XNaQyAzld-W5-GEqEqt5byH6VkI-j5QI"; -console.log(event); +var directory = require('./config/directory')(config); -calendar.scheduleEvent(event, function(err, res) { - console.log("Result"); - console.log(err); - console.log(res); -}); + +directory.listUsers(function(err, result) { console.log(result); console.log(err); console.log('Done.'); });