├── client ├── css │ ├── client.css │ ├── main.css │ └── bootstrap-responsive.css ├── img │ ├── favicon.ico │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png ├── app │ ├── api │ │ ├── api.js │ │ └── Api.js │ ├── model │ │ └── Author.js │ ├── core.js │ ├── controllers │ │ ├── authorsController.js │ │ └── BaseController.js │ ├── templates │ │ └── Main.handlebars │ └── views │ │ └── MainView.js ├── main.js ├── lib │ ├── emberjs │ │ └── load.js │ ├── requirejs │ │ ├── plugins │ │ │ ├── order.js │ │ │ └── text.js │ │ └── require.js │ └── bootstrap │ │ └── bootstrap.js └── index.html ├── .gitignore ├── test ├── db │ └── start-db.sh ├── get-authors.sh ├── delete-author.sh ├── create-author.sh └── jshint │ └── jshint-check.sh ├── package.json ├── server ├── model │ └── Author.js └── api │ └── authors.js ├── app.js └── readme.md /client/css/client.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | test/db/mongodb-*/ 2 | test/db/data/ 3 | node_modules/ 4 | nbproject/ 5 | client-build/ 6 | -------------------------------------------------------------------------------- /client/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abelaska/nodejs-emberjs-mongodb/HEAD/client/img/favicon.ico -------------------------------------------------------------------------------- /test/db/start-db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | [ ! -d data ] && mkdir data 4 | mongodb-linux-*/bin/mongod --dbpath data --rest 5 | -------------------------------------------------------------------------------- /test/get-authors.sh: -------------------------------------------------------------------------------- 1 | curl -v -X GET \ 2 | -H "accept: application/json" \ 3 | http://localhost:3000/api/authors 4 | 5 | -------------------------------------------------------------------------------- /client/css/main.css: -------------------------------------------------------------------------------- 1 | @import url("bootstrap.css"); 2 | @import url("bootstrap-responsive.css"); 3 | @import url("client.css"); 4 | -------------------------------------------------------------------------------- /client/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abelaska/nodejs-emberjs-mongodb/HEAD/client/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /client/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/abelaska/nodejs-emberjs-mongodb/HEAD/client/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /test/delete-author.sh: -------------------------------------------------------------------------------- 1 | curl -v -X DELETE \ 2 | -H "accept: application/json" \ 3 | http://localhost:3000/api/authors/4f97d9b0e816a79121000001 4 | 5 | -------------------------------------------------------------------------------- /client/app/api/api.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'app/api/Api' 3 | ],function( 4 | Api 5 | ){ 6 | "use strict"; 7 | 8 | return Api.create({}); 9 | }); 10 | -------------------------------------------------------------------------------- /client/app/model/Author.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'lib/emberjs/load' 3 | ],function( 4 | em 5 | ){ 6 | "use strict"; 7 | 8 | return em.Object.extend({ 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /test/create-author.sh: -------------------------------------------------------------------------------- 1 | curl -v -X POST \ 2 | -H "content-type: application/json" \ 3 | -H "accept: application/json" \ 4 | -d '{"name":"My Name"}' http://localhost:3000/api/authors 5 | 6 | -------------------------------------------------------------------------------- /client/main.js: -------------------------------------------------------------------------------- 1 | /*global console:false */ 2 | 3 | require([ 4 | "app/core" 5 | ],function(){ 6 | "use strict"; 7 | 8 | console.log('Client application started'); 9 | }); 10 | -------------------------------------------------------------------------------- /test/jshint/jshint-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | for file in `find ../.. -name "*.js" | grep -v "client/lib" | grep -v "node_modules" | grep -v "client.build"`; do 4 | echo ===Linting $file...=== 5 | jshint $file; 6 | done 7 | echo 8 | -------------------------------------------------------------------------------- /client/lib/emberjs/load.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'lib/requirejs/plugins/order!lib/jquery/jquery', 3 | 'lib/requirejs/plugins/order!lib/bootstrap/bootstrap', 4 | 'lib/requirejs/plugins/order!lib/emberjs/ember-0.9.8.1.js' 5 | ],function() { 6 | return Ember; 7 | }); 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-emberjs-mongodb", 3 | "version": "0.0.2", 4 | "private": true, 5 | "scripts": { 6 | "start": "NODE_ENV=development node app" 7 | }, 8 | "dependencies": { 9 | "express": "3.0.x", 10 | "mongoose": "2.5.x", 11 | "requirejs": "1.0.x" 12 | } 13 | } -------------------------------------------------------------------------------- /server/model/Author.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'mongoose' 3 | ],function( 4 | mongoose 5 | ){ 6 | "use strict"; 7 | 8 | var Schema = mongoose.Schema; 9 | 10 | var Author = new Schema({ 11 | name : String 12 | }); 13 | 14 | return mongoose.model('Author', Author); 15 | }); 16 | -------------------------------------------------------------------------------- /client/app/core.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'lib/emberjs/load', 3 | "app/views/MainView", 4 | "app/controllers/authorsController" 5 | ],function( 6 | em, 7 | MainView, 8 | authorsController 9 | ){ 10 | "use strict"; 11 | 12 | em.App = em.Application.create({ 13 | mainView: MainView.create({}), 14 | authorsController: authorsController 15 | }); 16 | 17 | em.App.mainView.appendTo('body'); 18 | 19 | return em.App; 20 | }); 21 | -------------------------------------------------------------------------------- /client/app/controllers/authorsController.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'app/model/Author', 3 | 'app/controllers/BaseController' 4 | ],function( 5 | Author, 6 | BaseController 7 | ){ 8 | "use strict"; 9 | 10 | return BaseController.create({ 11 | 12 | resourceType: Author, 13 | 14 | getAll: function(onDone, onFail) { 15 | this.clearAll(); 16 | this.api.getAllAuthors(function(json) { 17 | this.loadAll(json); 18 | if (onDone) { 19 | onDone(); 20 | } 21 | }.bind(this), function(err) { 22 | if (onFail) { 23 | onFail(err); 24 | } 25 | }.bind(this)); 26 | } 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /client/app/controllers/BaseController.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'lib/emberjs/load', 3 | 'app/api/api' 4 | ],function( 5 | em, 6 | api 7 | ){ 8 | "use strict"; 9 | 10 | return em.ArrayController.extend({ 11 | 12 | resourceType: em.required(), 13 | 14 | api: api, 15 | 16 | load: function(json) { 17 | var resource = this.get('resourceType').create(json); 18 | this.pushObject(resource); 19 | }, 20 | 21 | loadAll: function(json) { 22 | for (var i=0; i < json.length; i++) { 23 | this.load(json[i]); 24 | } 25 | }, 26 | 27 | clearAll: function() { 28 | this.set('content', []); 29 | } 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Node.js + Require.js + Express.js + Ember.js + Mongoose.js + MongoDB + Twitter Bootstrap 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /client/app/templates/Main.handlebars: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

nodejs-emberjs-mongodb

5 |

Proof of concept application.

6 |

Dependencies

7 | 17 |
18 |
19 |

Authors
Refresh

20 | 21 | 22 | 23 | 24 | 25 | 26 | {{#each Em.App.authorsController}} 27 | 28 | 29 | 30 | 31 | 32 | {{/each}} 33 | 34 |
IdName
{{_id}}{{name}}
remove
35 | 36 |
37 | {{view Ember.TextField valueBinding="newAuthor.name" id="authorName" placeholder="New author name"}} 38 |
Create new author
39 |
40 |
41 |
42 |
43 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /*global console:false, __dirname:false, process:false */ 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var requirejs = require('requirejs'); 8 | 9 | requirejs.config({ 10 | nodeRequire: require 11 | }); 12 | 13 | requirejs([ 14 | 'express', 15 | 'mongoose', 16 | 'server/api/authors' 17 | ], function( 18 | express, 19 | mongoose, 20 | api_authors 21 | ){ 22 | "use strict"; 23 | 24 | // connect to MongoDB 25 | mongoose.connect('mongodb://localhost/example'); 26 | 27 | var app = express(); 28 | 29 | app.configure(function(){ 30 | app.use(express.favicon()); 31 | app.use(express.bodyParser()); 32 | app.use(express.methodOverride()); 33 | app.use(app.router); 34 | }); 35 | 36 | app.configure('development', function(){ 37 | app.use(express.logger('dev')); 38 | app.use(express['static'](__dirname + '/client')); 39 | app.use(express.errorHandler({ 40 | dumpExceptions: true, 41 | showStack: true 42 | })); 43 | }); 44 | 45 | app.configure('production', function(){ 46 | 47 | // build client if directory client-build not found 48 | var path = require('path'); 49 | if (!path.existsSync("client-build")) { 50 | require('./build'); 51 | } 52 | 53 | app.use(express['static'](__dirname + '/client-build')); 54 | }); 55 | 56 | // ROUTES 57 | app.get('/api/authors', api_authors.getAll); 58 | app.del('/api/authors/:id', api_authors.remove); 59 | app.post('/api/authors', api_authors.create); 60 | 61 | // HTTP 62 | var port = process.env.PORT || 3000; 63 | app.listen(port); 64 | 65 | console.log("Http server listening on port 3000"); 66 | }); 67 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Node.js + Ember.js + MongoDB 2 | ============================= 3 | 4 | Proof of concept application. 5 | 6 | ### Dependencies: 7 | 8 | * [http://nodejs.org](http://nodejs.org) 0.6.x 9 | * [http://requirejs.org](http://requirejs.org) 1.0.x 10 | * [http://expressjs.com](http://expressjs.com) 3.0.x 11 | * [http://mongoosejs.com](http://mongoosejs.com) 2.5.x 12 | * [http://www.mongodb.org](http://www.mongodb.org) 2.0.x 13 | * [http://jquery.com](http://jquery.com) 1.7.2 14 | * [http://emberjs.com](http://emberjs.com) 0.9.8.1 15 | * [http://twitter.github.com/bootstrap](http://twitter.github.com/bootstrap) 2.0.3 16 | 17 | ### How to run in development environment 18 | 19 | 1. You have to start local MongoDB instance 20 | 2. Go to the project directory 21 | 22 | $ cd nodejs-emberjs-mongodb 23 | 24 | 3. Install required Node.js modules 25 | 26 | $ npm install 27 | 28 | 4. Start Node.js HTTP server 29 | 30 | $ npm start 31 | 32 | 5. Visit address [http://localhost:3000](http://localhost:3000) 33 | 6. Enjoy! 34 | 35 | ### Build and run production version 36 | 37 | 1. You have to start local MongoDB instance 38 | 2. Go to the project directory 39 | 40 | $ cd nodejs-emberjs-mongodb 41 | 42 | 3. Install required Node.js modules 43 | 44 | $ npm install 45 | 46 | 4. Start Node.js HTTP server in production environment, client javascript and css files will be automatically optimized 47 | 48 | $ NODE_ENV=production node app 49 | 50 | ### Manual client build 51 | 52 | 1. Go to the project directory 53 | 54 | $ cd nodejs-emberjs-mongodb 55 | 56 | 2. Build client 57 | 58 | $ node build 59 | -------------------------------------------------------------------------------- /client/app/views/MainView.js: -------------------------------------------------------------------------------- 1 | /*global console:false */ 2 | 3 | define([ 4 | 'lib/emberjs/load', 5 | 'app/model/Author', 6 | 'app/controllers/authorsController', 7 | 'lib/requirejs/plugins/text!app/templates/Main.handlebars' 8 | ],function( 9 | em, 10 | Author, 11 | authorsController, 12 | mainTemplateSource 13 | ){ 14 | "use strict"; 15 | 16 | return em.View.extend({ 17 | template: em.Handlebars.compile(mainTemplateSource), 18 | 19 | newAuthor: null, 20 | 21 | init: function() { 22 | this._super(); 23 | this.refresh(); 24 | this.newAuthor = Author.create(); 25 | }, 26 | 27 | refresh: function() { 28 | authorsController.getAll(); 29 | }, 30 | 31 | removeAuthor: function(event) { 32 | var authorId = event.context.get('_id'); 33 | 34 | authorsController.api.removeAuthor(authorId, function() { 35 | 36 | authorsController.removeObject(event.context); 37 | 38 | }.bind(this), function(err) { 39 | console.log('error', err); 40 | }.bind(this)); 41 | }, 42 | 43 | createAuthor: function() { 44 | 45 | var authorName = this.newAuthor.get('name'); 46 | 47 | if (authorName === undefined || authorName === null || authorName === '') { 48 | em.$('#authorName').focus(); 49 | return; 50 | } 51 | 52 | authorsController.api.createAuthor({ 53 | name: authorName 54 | },function(data) { 55 | 56 | this.newAuthor.set('_id', data.id); 57 | 58 | authorsController.pushObject(this.newAuthor); 59 | 60 | this.set('newAuthor', Author.create()); 61 | 62 | }.bind(this), function(err) { 63 | console.log('error', err); 64 | }.bind(this)); 65 | } 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /client/app/api/Api.js: -------------------------------------------------------------------------------- 1 | /*global console:false */ 2 | 3 | define([ 4 | 'lib/emberjs/load' 5 | ],function( 6 | em 7 | ){ 8 | "use strict"; 9 | 10 | return em.Object.extend({ 11 | 12 | baseUrl: '/api', 13 | 14 | getAllAuthors: function(onDone, onFail) { 15 | this._get('/authors', onDone, onFail); 16 | }, 17 | 18 | removeAuthor: function(authorId, onDone, onFail) { 19 | this._delete('/authors/'+authorId, null, onDone, onFail); 20 | }, 21 | 22 | createAuthor: function(author, onDone, onFail) { 23 | this._post('/authors', author, onDone, onFail); 24 | }, 25 | 26 | _ajax: function(type, resourceUrl, data, onDone, onFail, onAlways) { 27 | console.log('_'+type+'('+this.baseUrl + resourceUrl+')'); 28 | return em.$.ajax({ 29 | url: this.baseUrl + resourceUrl, 30 | dataType: 'json', 31 | data: data, 32 | type: type 33 | }).done(function(json) { 34 | if (onDone) { 35 | onDone(json); 36 | } 37 | }).fail(function(error) { 38 | if (onFail) { 39 | onFail(error); 40 | } 41 | }).always(function() { 42 | if (onAlways) { 43 | onAlways(); 44 | } 45 | }); 46 | }, 47 | 48 | _get: function(resourceUrl, onDone, onFail, onAlways) { 49 | this._ajax('GET', resourceUrl, null, onDone, onFail, onAlways); 50 | }, 51 | 52 | _post: function(resourceUrl, data, onDone, onFail, onAlways) { 53 | this._ajax('POST', resourceUrl, data, onDone, onFail, onAlways); 54 | }, 55 | 56 | _put: function(resourceUrl, data, onDone, onFail, onAlways) { 57 | this._ajax('PUT', resourceUrl, data, onDone, onFail, onAlways); 58 | }, 59 | 60 | _delete: function(resourceUrl, data, onDone, onFail, onAlways) { 61 | this._ajax('DELETE', resourceUrl, data, onDone, onFail, onAlways); 62 | } 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /server/api/authors.js: -------------------------------------------------------------------------------- 1 | /*global console:false */ 2 | 3 | define([ 4 | 'server/model/Author' 5 | ],function( 6 | Author 7 | ){ 8 | "use strict"; 9 | 10 | return { 11 | remove: function(req, res) { 12 | Author.findById(req.params.id, function (err, author) { 13 | if (err) { 14 | res.json(500,{ 15 | error: err 16 | }); 17 | console.log('Failed to get author id ' + req.params.id + ', ' + err); 18 | } else { 19 | if (author === null) { 20 | res.send(404,''); 21 | console.log('Author ' + req.params.id + ' not found'); 22 | } else { 23 | author.remove(function (err) { 24 | if (err) { 25 | res.json(500,{ 26 | error: err 27 | }); 28 | console.log('Failed to remove author id ' + req.params.id + ', ' + err); 29 | } else { 30 | res.json(200,''); 31 | console.log('Deleted author ' + JSON.stringify(author)); 32 | } 33 | }); 34 | } 35 | } 36 | }); 37 | }, 38 | 39 | getAll: function(req, res) { 40 | Author.find({}, function (err, authors) { 41 | if (err) { 42 | res.json(500,{ 43 | error: err 44 | }); 45 | console.log('Failed to get authors, ' + err); 46 | } else { 47 | res.json(200, authors); 48 | console.log('Found authors ' + JSON.stringify(authors)); 49 | } 50 | }); 51 | }, 52 | 53 | create: function(req, res) { 54 | var author = new Author({ 55 | name: req.body.name 56 | }); 57 | author.save(function (err) { 58 | if (err) { 59 | res.json(500,{ 60 | error: err 61 | }); 62 | console.log('Failed to create author ' + JSON.stringify(req.body) + ', ' + err); 63 | } else { 64 | res.json(200,{ 65 | id : author.id 66 | }); 67 | console.log('Created author ' + JSON.stringify(req.body)); 68 | } 69 | }); 70 | } 71 | }; 72 | }); 73 | -------------------------------------------------------------------------------- /client/lib/requirejs/plugins/order.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS order 1.0.5 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/jrburke/requirejs for details 5 | */ 6 | /*jslint nomen: false, plusplus: false, strict: false */ 7 | /*global require: false, define: false, window: false, document: false, 8 | setTimeout: false */ 9 | 10 | //Specify that requirejs optimizer should wrap this code in a closure that 11 | //maps the namespaced requirejs API to non-namespaced local variables. 12 | /*requirejs namespace: true */ 13 | 14 | (function () { 15 | 16 | //Sadly necessary browser inference due to differences in the way 17 | //that browsers load and execute dynamically inserted javascript 18 | //and whether the script/cache method works when ordered execution is 19 | //desired. Currently, Gecko and Opera do not load/fire onload for scripts with 20 | //type="script/cache" but they execute injected scripts in order 21 | //unless the 'async' flag is present. 22 | //However, this is all changing in latest browsers implementing HTML5 23 | //spec. With compliant browsers .async true by default, and 24 | //if false, then it will execute in order. Favor that test first for forward 25 | //compatibility. 26 | var testScript = typeof document !== "undefined" && 27 | typeof window !== "undefined" && 28 | document.createElement("script"), 29 | 30 | supportsInOrderExecution = testScript && (testScript.async || 31 | ((window.opera && 32 | Object.prototype.toString.call(window.opera) === "[object Opera]") || 33 | //If Firefox 2 does not have to be supported, then 34 | //a better check may be: 35 | //('mozIsLocallyAvailable' in window.navigator) 36 | ("MozAppearance" in document.documentElement.style))), 37 | 38 | //This test is true for IE browsers, which will load scripts but only 39 | //execute them once the script is added to the DOM. 40 | supportsLoadSeparateFromExecute = testScript && 41 | testScript.readyState === 'uninitialized', 42 | 43 | readyRegExp = /^(complete|loaded)$/, 44 | cacheWaiting = [], 45 | cached = {}, 46 | scriptNodes = {}, 47 | scriptWaiting = []; 48 | 49 | //Done with the test script. 50 | testScript = null; 51 | 52 | //Callback used by the type="script/cache" callback that indicates a script 53 | //has finished downloading. 54 | function scriptCacheCallback(evt) { 55 | var node = evt.currentTarget || evt.srcElement, i, 56 | moduleName, resource; 57 | 58 | if (evt.type === "load" || readyRegExp.test(node.readyState)) { 59 | //Pull out the name of the module and the context. 60 | moduleName = node.getAttribute("data-requiremodule"); 61 | 62 | //Mark this cache request as loaded 63 | cached[moduleName] = true; 64 | 65 | //Find out how many ordered modules have loaded 66 | for (i = 0; (resource = cacheWaiting[i]); i++) { 67 | if (cached[resource.name]) { 68 | resource.req([resource.name], resource.onLoad); 69 | } else { 70 | //Something in the ordered list is not loaded, 71 | //so wait. 72 | break; 73 | } 74 | } 75 | 76 | //If just loaded some items, remove them from cacheWaiting. 77 | if (i > 0) { 78 | cacheWaiting.splice(0, i); 79 | } 80 | 81 | //Remove this script tag from the DOM 82 | //Use a setTimeout for cleanup because some older IE versions vomit 83 | //if removing a script node while it is being evaluated. 84 | setTimeout(function () { 85 | node.parentNode.removeChild(node); 86 | }, 15); 87 | } 88 | } 89 | 90 | /** 91 | * Used for the IE case, where fetching is done by creating script element 92 | * but not attaching it to the DOM. This function will be called when that 93 | * happens so it can be determined when the node can be attached to the 94 | * DOM to trigger its execution. 95 | */ 96 | function onFetchOnly(node) { 97 | var i, loadedNode, resourceName; 98 | 99 | //Mark this script as loaded. 100 | node.setAttribute('data-orderloaded', 'loaded'); 101 | 102 | //Cycle through waiting scripts. If the matching node for them 103 | //is loaded, and is in the right order, add it to the DOM 104 | //to execute the script. 105 | for (i = 0; (resourceName = scriptWaiting[i]); i++) { 106 | loadedNode = scriptNodes[resourceName]; 107 | if (loadedNode && 108 | loadedNode.getAttribute('data-orderloaded') === 'loaded') { 109 | delete scriptNodes[resourceName]; 110 | require.addScriptToDom(loadedNode); 111 | } else { 112 | break; 113 | } 114 | } 115 | 116 | //If just loaded some items, remove them from waiting. 117 | if (i > 0) { 118 | scriptWaiting.splice(0, i); 119 | } 120 | } 121 | 122 | define({ 123 | version: '1.0.5', 124 | 125 | load: function (name, req, onLoad, config) { 126 | var hasToUrl = !!req.nameToUrl, 127 | url, node, context; 128 | 129 | //If no nameToUrl, then probably a build with a loader that 130 | //does not support it, and all modules are inlined. 131 | if (!hasToUrl) { 132 | req([name], onLoad); 133 | return; 134 | } 135 | 136 | url = req.nameToUrl(name, null); 137 | 138 | //Make sure the async attribute is not set for any pathway involving 139 | //this script. 140 | require.s.skipAsync[url] = true; 141 | if (supportsInOrderExecution || config.isBuild) { 142 | //Just a normal script tag append, but without async attribute 143 | //on the script. 144 | req([name], onLoad); 145 | } else if (supportsLoadSeparateFromExecute) { 146 | //Just fetch the URL, but do not execute it yet. The 147 | //non-standards IE case. Really not so nice because it is 148 | //assuming and touching requrejs internals. OK though since 149 | //ordered execution should go away after a long while. 150 | context = require.s.contexts._; 151 | 152 | if (!context.urlFetched[url] && !context.loaded[name]) { 153 | //Indicate the script is being fetched. 154 | context.urlFetched[url] = true; 155 | 156 | //Stuff from require.load 157 | require.resourcesReady(false); 158 | context.scriptCount += 1; 159 | 160 | //Fetch the script now, remember it. 161 | node = require.attach(url, context, name, null, null, onFetchOnly); 162 | scriptNodes[name] = node; 163 | scriptWaiting.push(name); 164 | } 165 | 166 | //Do a normal require for it, once it loads, use it as return 167 | //value. 168 | req([name], onLoad); 169 | } else { 170 | //Credit to LABjs author Kyle Simpson for finding that scripts 171 | //with type="script/cache" allow scripts to be downloaded into 172 | //browser cache but not executed. Use that 173 | //so that subsequent addition of a real type="text/javascript" 174 | //tag will cause the scripts to be executed immediately in the 175 | //correct order. 176 | if (req.specified(name)) { 177 | req([name], onLoad); 178 | } else { 179 | cacheWaiting.push({ 180 | name: name, 181 | req: req, 182 | onLoad: onLoad 183 | }); 184 | require.attach(url, null, name, scriptCacheCallback, "script/cache"); 185 | } 186 | } 187 | } 188 | }); 189 | }()); 190 | -------------------------------------------------------------------------------- /client/lib/requirejs/plugins/text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS text 1.0.8 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/jrburke/requirejs for details 5 | */ 6 | /*jslint regexp: true, plusplus: true, sloppy: true */ 7 | /*global require: false, XMLHttpRequest: false, ActiveXObject: false, 8 | define: false, window: false, process: false, Packages: false, 9 | java: false, location: false */ 10 | 11 | (function () { 12 | var progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], 13 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, 14 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, 15 | hasLocation = typeof location !== 'undefined' && location.href, 16 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), 17 | defaultHostName = hasLocation && location.hostname, 18 | defaultPort = hasLocation && (location.port || undefined), 19 | buildMap = []; 20 | 21 | define(function () { 22 | var text, fs; 23 | 24 | text = { 25 | version: '1.0.8', 26 | 27 | strip: function (content) { 28 | //Strips declarations so that external SVG and XML 29 | //documents can be added to a document without worry. Also, if the string 30 | //is an HTML document, only the part inside the body tag is returned. 31 | if (content) { 32 | content = content.replace(xmlRegExp, ""); 33 | var matches = content.match(bodyRegExp); 34 | if (matches) { 35 | content = matches[1]; 36 | } 37 | } else { 38 | content = ""; 39 | } 40 | return content; 41 | }, 42 | 43 | jsEscape: function (content) { 44 | return content.replace(/(['\\])/g, '\\$1') 45 | .replace(/[\f]/g, "\\f") 46 | .replace(/[\b]/g, "\\b") 47 | .replace(/[\n]/g, "\\n") 48 | .replace(/[\t]/g, "\\t") 49 | .replace(/[\r]/g, "\\r"); 50 | }, 51 | 52 | createXhr: function () { 53 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first. 54 | var xhr, i, progId; 55 | if (typeof XMLHttpRequest !== "undefined") { 56 | return new XMLHttpRequest(); 57 | } else if (typeof ActiveXObject !== "undefined") { 58 | for (i = 0; i < 3; i++) { 59 | progId = progIds[i]; 60 | try { 61 | xhr = new ActiveXObject(progId); 62 | } catch (e) {} 63 | 64 | if (xhr) { 65 | progIds = [progId]; // so faster next time 66 | break; 67 | } 68 | } 69 | } 70 | 71 | return xhr; 72 | }, 73 | 74 | /** 75 | * Parses a resource name into its component parts. Resource names 76 | * look like: module/name.ext!strip, where the !strip part is 77 | * optional. 78 | * @param {String} name the resource name 79 | * @returns {Object} with properties "moduleName", "ext" and "strip" 80 | * where strip is a boolean. 81 | */ 82 | parseName: function (name) { 83 | var strip = false, index = name.indexOf("."), 84 | modName = name.substring(0, index), 85 | ext = name.substring(index + 1, name.length); 86 | 87 | index = ext.indexOf("!"); 88 | if (index !== -1) { 89 | //Pull off the strip arg. 90 | strip = ext.substring(index + 1, ext.length); 91 | strip = strip === "strip"; 92 | ext = ext.substring(0, index); 93 | } 94 | 95 | return { 96 | moduleName: modName, 97 | ext: ext, 98 | strip: strip 99 | }; 100 | }, 101 | 102 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, 103 | 104 | /** 105 | * Is an URL on another domain. Only works for browser use, returns 106 | * false in non-browser environments. Only used to know if an 107 | * optimized .js version of a text resource should be loaded 108 | * instead. 109 | * @param {String} url 110 | * @returns Boolean 111 | */ 112 | useXhr: function (url, protocol, hostname, port) { 113 | var match = text.xdRegExp.exec(url), 114 | uProtocol, uHostName, uPort; 115 | if (!match) { 116 | return true; 117 | } 118 | uProtocol = match[2]; 119 | uHostName = match[3]; 120 | 121 | uHostName = uHostName.split(':'); 122 | uPort = uHostName[1]; 123 | uHostName = uHostName[0]; 124 | 125 | return (!uProtocol || uProtocol === protocol) && 126 | (!uHostName || uHostName === hostname) && 127 | ((!uPort && !uHostName) || uPort === port); 128 | }, 129 | 130 | finishLoad: function (name, strip, content, onLoad, config) { 131 | content = strip ? text.strip(content) : content; 132 | if (config.isBuild) { 133 | buildMap[name] = content; 134 | } 135 | onLoad(content); 136 | }, 137 | 138 | load: function (name, req, onLoad, config) { 139 | //Name has format: some.module.filext!strip 140 | //The strip part is optional. 141 | //if strip is present, then that means only get the string contents 142 | //inside a body tag in an HTML string. For XML/SVG content it means 143 | //removing the declarations so the content can be inserted 144 | //into the current doc without problems. 145 | 146 | // Do not bother with the work if a build and text will 147 | // not be inlined. 148 | if (config.isBuild && !config.inlineText) { 149 | onLoad(); 150 | return; 151 | } 152 | 153 | var parsed = text.parseName(name), 154 | nonStripName = parsed.moduleName + '.' + parsed.ext, 155 | url = req.toUrl(nonStripName), 156 | useXhr = (config && config.text && config.text.useXhr) || 157 | text.useXhr; 158 | 159 | //Load the text. Use XHR if possible and in a browser. 160 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { 161 | text.get(url, function (content) { 162 | text.finishLoad(name, parsed.strip, content, onLoad, config); 163 | }); 164 | } else { 165 | //Need to fetch the resource across domains. Assume 166 | //the resource has been optimized into a JS module. Fetch 167 | //by the module name + extension, but do not include the 168 | //!strip part to avoid file system issues. 169 | req([nonStripName], function (content) { 170 | text.finishLoad(parsed.moduleName + '.' + parsed.ext, 171 | parsed.strip, content, onLoad, config); 172 | }); 173 | } 174 | }, 175 | 176 | write: function (pluginName, moduleName, write, config) { 177 | if (buildMap.hasOwnProperty(moduleName)) { 178 | var content = text.jsEscape(buildMap[moduleName]); 179 | write.asModule(pluginName + "!" + moduleName, 180 | "define(function () { return '" + 181 | content + 182 | "';});\n"); 183 | } 184 | }, 185 | 186 | writeFile: function (pluginName, moduleName, req, write, config) { 187 | var parsed = text.parseName(moduleName), 188 | nonStripName = parsed.moduleName + '.' + parsed.ext, 189 | //Use a '.js' file name so that it indicates it is a 190 | //script that can be loaded across domains. 191 | fileName = req.toUrl(parsed.moduleName + '.' + 192 | parsed.ext) + '.js'; 193 | 194 | //Leverage own load() method to load plugin value, but only 195 | //write out values that do not have the strip argument, 196 | //to avoid any potential issues with ! in file names. 197 | text.load(nonStripName, req, function (value) { 198 | //Use own write() method to construct full module value. 199 | //But need to create shell that translates writeFile's 200 | //write() to the right interface. 201 | var textWrite = function (contents) { 202 | return write(fileName, contents); 203 | }; 204 | textWrite.asModule = function (moduleName, contents) { 205 | return write.asModule(moduleName, fileName, contents); 206 | }; 207 | 208 | text.write(pluginName, nonStripName, textWrite, config); 209 | }, config); 210 | } 211 | }; 212 | 213 | if (text.createXhr()) { 214 | text.get = function (url, callback) { 215 | var xhr = text.createXhr(); 216 | xhr.open('GET', url, true); 217 | xhr.onreadystatechange = function (evt) { 218 | //Do not explicitly handle errors, those should be 219 | //visible via console output in the browser. 220 | if (xhr.readyState === 4) { 221 | callback(xhr.responseText); 222 | } 223 | }; 224 | xhr.send(null); 225 | }; 226 | } else if (typeof process !== "undefined" && 227 | process.versions && 228 | !!process.versions.node) { 229 | //Using special require.nodeRequire, something added by r.js. 230 | fs = require.nodeRequire('fs'); 231 | 232 | text.get = function (url, callback) { 233 | var file = fs.readFileSync(url, 'utf8'); 234 | //Remove BOM (Byte Mark Order) from utf8 files if it is there. 235 | if (file.indexOf('\uFEFF') === 0) { 236 | file = file.substring(1); 237 | } 238 | callback(file); 239 | }; 240 | } else if (typeof Packages !== 'undefined') { 241 | //Why Java, why is this so awkward? 242 | text.get = function (url, callback) { 243 | var encoding = "utf-8", 244 | file = new java.io.File(url), 245 | lineSeparator = java.lang.System.getProperty("line.separator"), 246 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), 247 | stringBuffer, line, 248 | content = ''; 249 | try { 250 | stringBuffer = new java.lang.StringBuffer(); 251 | line = input.readLine(); 252 | 253 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 254 | // http://www.unicode.org/faq/utf_bom.html 255 | 256 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: 257 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 258 | if (line && line.length() && line.charAt(0) === 0xfeff) { 259 | // Eat the BOM, since we've already found the encoding on this file, 260 | // and we plan to concatenating this buffer with others; the BOM should 261 | // only appear at the top of a file. 262 | line = line.substring(1); 263 | } 264 | 265 | stringBuffer.append(line); 266 | 267 | while ((line = input.readLine()) !== null) { 268 | stringBuffer.append(lineSeparator); 269 | stringBuffer.append(line); 270 | } 271 | //Make sure we return a JavaScript string and not a Java string. 272 | content = String(stringBuffer.toString()); //String 273 | } finally { 274 | input.close(); 275 | } 276 | callback(content); 277 | }; 278 | } 279 | 280 | return text; 281 | }); 282 | }()); 283 | -------------------------------------------------------------------------------- /client/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.0.3 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | .clearfix { 12 | *zoom: 1; 13 | } 14 | 15 | .clearfix:before, 16 | .clearfix:after { 17 | display: table; 18 | content: ""; 19 | } 20 | 21 | .clearfix:after { 22 | clear: both; 23 | } 24 | 25 | .hide-text { 26 | font: 0/0 a; 27 | color: transparent; 28 | text-shadow: none; 29 | background-color: transparent; 30 | border: 0; 31 | } 32 | 33 | .input-block-level { 34 | display: block; 35 | width: 100%; 36 | min-height: 28px; 37 | -webkit-box-sizing: border-box; 38 | -moz-box-sizing: border-box; 39 | -ms-box-sizing: border-box; 40 | box-sizing: border-box; 41 | } 42 | 43 | .hidden { 44 | display: none; 45 | visibility: hidden; 46 | } 47 | 48 | .visible-phone { 49 | display: none !important; 50 | } 51 | 52 | .visible-tablet { 53 | display: none !important; 54 | } 55 | 56 | .hidden-desktop { 57 | display: none !important; 58 | } 59 | 60 | @media (max-width: 767px) { 61 | .visible-phone { 62 | display: inherit !important; 63 | } 64 | .hidden-phone { 65 | display: none !important; 66 | } 67 | .hidden-desktop { 68 | display: inherit !important; 69 | } 70 | .visible-desktop { 71 | display: none !important; 72 | } 73 | } 74 | 75 | @media (min-width: 768px) and (max-width: 979px) { 76 | .visible-tablet { 77 | display: inherit !important; 78 | } 79 | .hidden-tablet { 80 | display: none !important; 81 | } 82 | .hidden-desktop { 83 | display: inherit !important; 84 | } 85 | .visible-desktop { 86 | display: none !important ; 87 | } 88 | } 89 | 90 | @media (max-width: 480px) { 91 | .nav-collapse { 92 | -webkit-transform: translate3d(0, 0, 0); 93 | } 94 | .page-header h1 small { 95 | display: block; 96 | line-height: 18px; 97 | } 98 | input[type="checkbox"], 99 | input[type="radio"] { 100 | border: 1px solid #ccc; 101 | } 102 | .form-horizontal .control-group > label { 103 | float: none; 104 | width: auto; 105 | padding-top: 0; 106 | text-align: left; 107 | } 108 | .form-horizontal .controls { 109 | margin-left: 0; 110 | } 111 | .form-horizontal .control-list { 112 | padding-top: 0; 113 | } 114 | .form-horizontal .form-actions { 115 | padding-right: 10px; 116 | padding-left: 10px; 117 | } 118 | .modal { 119 | position: absolute; 120 | top: 10px; 121 | right: 10px; 122 | left: 10px; 123 | width: auto; 124 | margin: 0; 125 | } 126 | .modal.fade.in { 127 | top: auto; 128 | } 129 | .modal-header .close { 130 | padding: 10px; 131 | margin: -10px; 132 | } 133 | .carousel-caption { 134 | position: static; 135 | } 136 | } 137 | 138 | @media (max-width: 767px) { 139 | body { 140 | padding-right: 20px; 141 | padding-left: 20px; 142 | } 143 | .navbar-fixed-top, 144 | .navbar-fixed-bottom { 145 | margin-right: -20px; 146 | margin-left: -20px; 147 | } 148 | .container-fluid { 149 | padding: 0; 150 | } 151 | .dl-horizontal dt { 152 | float: none; 153 | width: auto; 154 | clear: none; 155 | text-align: left; 156 | } 157 | .dl-horizontal dd { 158 | margin-left: 0; 159 | } 160 | .container { 161 | width: auto; 162 | } 163 | .row-fluid { 164 | width: 100%; 165 | } 166 | .row, 167 | .thumbnails { 168 | margin-left: 0; 169 | } 170 | [class*="span"], 171 | .row-fluid [class*="span"] { 172 | display: block; 173 | float: none; 174 | width: auto; 175 | margin-left: 0; 176 | } 177 | .input-large, 178 | .input-xlarge, 179 | .input-xxlarge, 180 | input[class*="span"], 181 | select[class*="span"], 182 | textarea[class*="span"], 183 | .uneditable-input { 184 | display: block; 185 | width: 100%; 186 | min-height: 28px; 187 | -webkit-box-sizing: border-box; 188 | -moz-box-sizing: border-box; 189 | -ms-box-sizing: border-box; 190 | box-sizing: border-box; 191 | } 192 | .input-prepend input, 193 | .input-append input, 194 | .input-prepend input[class*="span"], 195 | .input-append input[class*="span"] { 196 | display: inline-block; 197 | width: auto; 198 | } 199 | } 200 | 201 | @media (min-width: 768px) and (max-width: 979px) { 202 | .row { 203 | margin-left: -20px; 204 | *zoom: 1; 205 | } 206 | .row:before, 207 | .row:after { 208 | display: table; 209 | content: ""; 210 | } 211 | .row:after { 212 | clear: both; 213 | } 214 | [class*="span"] { 215 | float: left; 216 | margin-left: 20px; 217 | } 218 | .container, 219 | .navbar-fixed-top .container, 220 | .navbar-fixed-bottom .container { 221 | width: 724px; 222 | } 223 | .span12 { 224 | width: 724px; 225 | } 226 | .span11 { 227 | width: 662px; 228 | } 229 | .span10 { 230 | width: 600px; 231 | } 232 | .span9 { 233 | width: 538px; 234 | } 235 | .span8 { 236 | width: 476px; 237 | } 238 | .span7 { 239 | width: 414px; 240 | } 241 | .span6 { 242 | width: 352px; 243 | } 244 | .span5 { 245 | width: 290px; 246 | } 247 | .span4 { 248 | width: 228px; 249 | } 250 | .span3 { 251 | width: 166px; 252 | } 253 | .span2 { 254 | width: 104px; 255 | } 256 | .span1 { 257 | width: 42px; 258 | } 259 | .offset12 { 260 | margin-left: 764px; 261 | } 262 | .offset11 { 263 | margin-left: 702px; 264 | } 265 | .offset10 { 266 | margin-left: 640px; 267 | } 268 | .offset9 { 269 | margin-left: 578px; 270 | } 271 | .offset8 { 272 | margin-left: 516px; 273 | } 274 | .offset7 { 275 | margin-left: 454px; 276 | } 277 | .offset6 { 278 | margin-left: 392px; 279 | } 280 | .offset5 { 281 | margin-left: 330px; 282 | } 283 | .offset4 { 284 | margin-left: 268px; 285 | } 286 | .offset3 { 287 | margin-left: 206px; 288 | } 289 | .offset2 { 290 | margin-left: 144px; 291 | } 292 | .offset1 { 293 | margin-left: 82px; 294 | } 295 | .row-fluid { 296 | width: 100%; 297 | *zoom: 1; 298 | } 299 | .row-fluid:before, 300 | .row-fluid:after { 301 | display: table; 302 | content: ""; 303 | } 304 | .row-fluid:after { 305 | clear: both; 306 | } 307 | .row-fluid [class*="span"] { 308 | display: block; 309 | float: left; 310 | width: 100%; 311 | min-height: 28px; 312 | margin-left: 2.762430939%; 313 | *margin-left: 2.709239449638298%; 314 | -webkit-box-sizing: border-box; 315 | -moz-box-sizing: border-box; 316 | -ms-box-sizing: border-box; 317 | box-sizing: border-box; 318 | } 319 | .row-fluid [class*="span"]:first-child { 320 | margin-left: 0; 321 | } 322 | .row-fluid .span12 { 323 | width: 99.999999993%; 324 | *width: 99.9468085036383%; 325 | } 326 | .row-fluid .span11 { 327 | width: 91.436464082%; 328 | *width: 91.38327259263829%; 329 | } 330 | .row-fluid .span10 { 331 | width: 82.87292817100001%; 332 | *width: 82.8197366816383%; 333 | } 334 | .row-fluid .span9 { 335 | width: 74.30939226%; 336 | *width: 74.25620077063829%; 337 | } 338 | .row-fluid .span8 { 339 | width: 65.74585634900001%; 340 | *width: 65.6926648596383%; 341 | } 342 | .row-fluid .span7 { 343 | width: 57.182320438000005%; 344 | *width: 57.129128948638304%; 345 | } 346 | .row-fluid .span6 { 347 | width: 48.618784527%; 348 | *width: 48.5655930376383%; 349 | } 350 | .row-fluid .span5 { 351 | width: 40.055248616%; 352 | *width: 40.0020571266383%; 353 | } 354 | .row-fluid .span4 { 355 | width: 31.491712705%; 356 | *width: 31.4385212156383%; 357 | } 358 | .row-fluid .span3 { 359 | width: 22.928176794%; 360 | *width: 22.874985304638297%; 361 | } 362 | .row-fluid .span2 { 363 | width: 14.364640883%; 364 | *width: 14.311449393638298%; 365 | } 366 | .row-fluid .span1 { 367 | width: 5.801104972%; 368 | *width: 5.747913482638298%; 369 | } 370 | input, 371 | textarea, 372 | .uneditable-input { 373 | margin-left: 0; 374 | } 375 | input.span12, 376 | textarea.span12, 377 | .uneditable-input.span12 { 378 | width: 714px; 379 | } 380 | input.span11, 381 | textarea.span11, 382 | .uneditable-input.span11 { 383 | width: 652px; 384 | } 385 | input.span10, 386 | textarea.span10, 387 | .uneditable-input.span10 { 388 | width: 590px; 389 | } 390 | input.span9, 391 | textarea.span9, 392 | .uneditable-input.span9 { 393 | width: 528px; 394 | } 395 | input.span8, 396 | textarea.span8, 397 | .uneditable-input.span8 { 398 | width: 466px; 399 | } 400 | input.span7, 401 | textarea.span7, 402 | .uneditable-input.span7 { 403 | width: 404px; 404 | } 405 | input.span6, 406 | textarea.span6, 407 | .uneditable-input.span6 { 408 | width: 342px; 409 | } 410 | input.span5, 411 | textarea.span5, 412 | .uneditable-input.span5 { 413 | width: 280px; 414 | } 415 | input.span4, 416 | textarea.span4, 417 | .uneditable-input.span4 { 418 | width: 218px; 419 | } 420 | input.span3, 421 | textarea.span3, 422 | .uneditable-input.span3 { 423 | width: 156px; 424 | } 425 | input.span2, 426 | textarea.span2, 427 | .uneditable-input.span2 { 428 | width: 94px; 429 | } 430 | input.span1, 431 | textarea.span1, 432 | .uneditable-input.span1 { 433 | width: 32px; 434 | } 435 | } 436 | 437 | @media (min-width: 1200px) { 438 | .row { 439 | margin-left: -30px; 440 | *zoom: 1; 441 | } 442 | .row:before, 443 | .row:after { 444 | display: table; 445 | content: ""; 446 | } 447 | .row:after { 448 | clear: both; 449 | } 450 | [class*="span"] { 451 | float: left; 452 | margin-left: 30px; 453 | } 454 | .container, 455 | .navbar-fixed-top .container, 456 | .navbar-fixed-bottom .container { 457 | width: 1170px; 458 | } 459 | .span12 { 460 | width: 1170px; 461 | } 462 | .span11 { 463 | width: 1070px; 464 | } 465 | .span10 { 466 | width: 970px; 467 | } 468 | .span9 { 469 | width: 870px; 470 | } 471 | .span8 { 472 | width: 770px; 473 | } 474 | .span7 { 475 | width: 670px; 476 | } 477 | .span6 { 478 | width: 570px; 479 | } 480 | .span5 { 481 | width: 470px; 482 | } 483 | .span4 { 484 | width: 370px; 485 | } 486 | .span3 { 487 | width: 270px; 488 | } 489 | .span2 { 490 | width: 170px; 491 | } 492 | .span1 { 493 | width: 70px; 494 | } 495 | .offset12 { 496 | margin-left: 1230px; 497 | } 498 | .offset11 { 499 | margin-left: 1130px; 500 | } 501 | .offset10 { 502 | margin-left: 1030px; 503 | } 504 | .offset9 { 505 | margin-left: 930px; 506 | } 507 | .offset8 { 508 | margin-left: 830px; 509 | } 510 | .offset7 { 511 | margin-left: 730px; 512 | } 513 | .offset6 { 514 | margin-left: 630px; 515 | } 516 | .offset5 { 517 | margin-left: 530px; 518 | } 519 | .offset4 { 520 | margin-left: 430px; 521 | } 522 | .offset3 { 523 | margin-left: 330px; 524 | } 525 | .offset2 { 526 | margin-left: 230px; 527 | } 528 | .offset1 { 529 | margin-left: 130px; 530 | } 531 | .row-fluid { 532 | width: 100%; 533 | *zoom: 1; 534 | } 535 | .row-fluid:before, 536 | .row-fluid:after { 537 | display: table; 538 | content: ""; 539 | } 540 | .row-fluid:after { 541 | clear: both; 542 | } 543 | .row-fluid [class*="span"] { 544 | display: block; 545 | float: left; 546 | width: 100%; 547 | min-height: 28px; 548 | margin-left: 2.564102564%; 549 | *margin-left: 2.510911074638298%; 550 | -webkit-box-sizing: border-box; 551 | -moz-box-sizing: border-box; 552 | -ms-box-sizing: border-box; 553 | box-sizing: border-box; 554 | } 555 | .row-fluid [class*="span"]:first-child { 556 | margin-left: 0; 557 | } 558 | .row-fluid .span12 { 559 | width: 100%; 560 | *width: 99.94680851063829%; 561 | } 562 | .row-fluid .span11 { 563 | width: 91.45299145300001%; 564 | *width: 91.3997999636383%; 565 | } 566 | .row-fluid .span10 { 567 | width: 82.905982906%; 568 | *width: 82.8527914166383%; 569 | } 570 | .row-fluid .span9 { 571 | width: 74.358974359%; 572 | *width: 74.30578286963829%; 573 | } 574 | .row-fluid .span8 { 575 | width: 65.81196581200001%; 576 | *width: 65.7587743226383%; 577 | } 578 | .row-fluid .span7 { 579 | width: 57.264957265%; 580 | *width: 57.2117657756383%; 581 | } 582 | .row-fluid .span6 { 583 | width: 48.717948718%; 584 | *width: 48.6647572286383%; 585 | } 586 | .row-fluid .span5 { 587 | width: 40.170940171000005%; 588 | *width: 40.117748681638304%; 589 | } 590 | .row-fluid .span4 { 591 | width: 31.623931624%; 592 | *width: 31.5707401346383%; 593 | } 594 | .row-fluid .span3 { 595 | width: 23.076923077%; 596 | *width: 23.0237315876383%; 597 | } 598 | .row-fluid .span2 { 599 | width: 14.529914530000001%; 600 | *width: 14.4767230406383%; 601 | } 602 | .row-fluid .span1 { 603 | width: 5.982905983%; 604 | *width: 5.929714493638298%; 605 | } 606 | input, 607 | textarea, 608 | .uneditable-input { 609 | margin-left: 0; 610 | } 611 | input.span12, 612 | textarea.span12, 613 | .uneditable-input.span12 { 614 | width: 1160px; 615 | } 616 | input.span11, 617 | textarea.span11, 618 | .uneditable-input.span11 { 619 | width: 1060px; 620 | } 621 | input.span10, 622 | textarea.span10, 623 | .uneditable-input.span10 { 624 | width: 960px; 625 | } 626 | input.span9, 627 | textarea.span9, 628 | .uneditable-input.span9 { 629 | width: 860px; 630 | } 631 | input.span8, 632 | textarea.span8, 633 | .uneditable-input.span8 { 634 | width: 760px; 635 | } 636 | input.span7, 637 | textarea.span7, 638 | .uneditable-input.span7 { 639 | width: 660px; 640 | } 641 | input.span6, 642 | textarea.span6, 643 | .uneditable-input.span6 { 644 | width: 560px; 645 | } 646 | input.span5, 647 | textarea.span5, 648 | .uneditable-input.span5 { 649 | width: 460px; 650 | } 651 | input.span4, 652 | textarea.span4, 653 | .uneditable-input.span4 { 654 | width: 360px; 655 | } 656 | input.span3, 657 | textarea.span3, 658 | .uneditable-input.span3 { 659 | width: 260px; 660 | } 661 | input.span2, 662 | textarea.span2, 663 | .uneditable-input.span2 { 664 | width: 160px; 665 | } 666 | input.span1, 667 | textarea.span1, 668 | .uneditable-input.span1 { 669 | width: 60px; 670 | } 671 | .thumbnails { 672 | margin-left: -30px; 673 | } 674 | .thumbnails > li { 675 | margin-left: 30px; 676 | } 677 | .row-fluid .thumbnails { 678 | margin-left: 0; 679 | } 680 | } 681 | 682 | @media (max-width: 979px) { 683 | body { 684 | padding-top: 0; 685 | } 686 | .navbar-fixed-top { 687 | position: static; 688 | margin-bottom: 18px; 689 | } 690 | .navbar-fixed-top .navbar-inner { 691 | padding: 5px; 692 | } 693 | .navbar .container { 694 | width: auto; 695 | padding: 0; 696 | } 697 | .navbar .brand { 698 | padding-right: 10px; 699 | padding-left: 10px; 700 | margin: 0 0 0 -5px; 701 | } 702 | .nav-collapse { 703 | clear: both; 704 | } 705 | .nav-collapse .nav { 706 | float: none; 707 | margin: 0 0 9px; 708 | } 709 | .nav-collapse .nav > li { 710 | float: none; 711 | } 712 | .nav-collapse .nav > li > a { 713 | margin-bottom: 2px; 714 | } 715 | .nav-collapse .nav > .divider-vertical { 716 | display: none; 717 | } 718 | .nav-collapse .nav .nav-header { 719 | color: #999999; 720 | text-shadow: none; 721 | } 722 | .nav-collapse .nav > li > a, 723 | .nav-collapse .dropdown-menu a { 724 | padding: 6px 15px; 725 | font-weight: bold; 726 | color: #999999; 727 | -webkit-border-radius: 3px; 728 | -moz-border-radius: 3px; 729 | border-radius: 3px; 730 | } 731 | .nav-collapse .btn { 732 | padding: 4px 10px 4px; 733 | font-weight: normal; 734 | -webkit-border-radius: 4px; 735 | -moz-border-radius: 4px; 736 | border-radius: 4px; 737 | } 738 | .nav-collapse .dropdown-menu li + li a { 739 | margin-bottom: 2px; 740 | } 741 | .nav-collapse .nav > li > a:hover, 742 | .nav-collapse .dropdown-menu a:hover { 743 | background-color: #222222; 744 | } 745 | .nav-collapse.in .btn-group { 746 | padding: 0; 747 | margin-top: 5px; 748 | } 749 | .nav-collapse .dropdown-menu { 750 | position: static; 751 | top: auto; 752 | left: auto; 753 | display: block; 754 | float: none; 755 | max-width: none; 756 | padding: 0; 757 | margin: 0 15px; 758 | background-color: transparent; 759 | border: none; 760 | -webkit-border-radius: 0; 761 | -moz-border-radius: 0; 762 | border-radius: 0; 763 | -webkit-box-shadow: none; 764 | -moz-box-shadow: none; 765 | box-shadow: none; 766 | } 767 | .nav-collapse .dropdown-menu:before, 768 | .nav-collapse .dropdown-menu:after { 769 | display: none; 770 | } 771 | .nav-collapse .dropdown-menu .divider { 772 | display: none; 773 | } 774 | .nav-collapse .navbar-form, 775 | .nav-collapse .navbar-search { 776 | float: none; 777 | padding: 9px 15px; 778 | margin: 9px 0; 779 | border-top: 1px solid #222222; 780 | border-bottom: 1px solid #222222; 781 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 782 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 783 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 784 | } 785 | .navbar .nav-collapse .nav.pull-right { 786 | float: none; 787 | margin-left: 0; 788 | } 789 | .nav-collapse, 790 | .nav-collapse.collapse { 791 | height: 0; 792 | overflow: hidden; 793 | } 794 | .navbar .btn-navbar { 795 | display: block; 796 | } 797 | .navbar-static .navbar-inner { 798 | padding-right: 10px; 799 | padding-left: 10px; 800 | } 801 | } 802 | 803 | @media (min-width: 980px) { 804 | .nav-collapse.collapse { 805 | height: auto !important; 806 | overflow: visible !important; 807 | } 808 | } 809 | -------------------------------------------------------------------------------- /client/lib/bootstrap/bootstrap.js: -------------------------------------------------------------------------------- 1 | /* =================================================== 2 | * bootstrap-transition.js v2.0.3 3 | * http://twitter.github.com/bootstrap/javascript.html#transitions 4 | * =================================================== 5 | * Copyright 2012 Twitter, Inc. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | * ========================================================== */ 19 | 20 | 21 | !function ($) { 22 | 23 | $(function () { 24 | 25 | "use strict"; // jshint ;_; 26 | 27 | 28 | /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) 29 | * ======================================================= */ 30 | 31 | $.support.transition = (function () { 32 | 33 | var transitionEnd = (function () { 34 | 35 | var el = document.createElement('bootstrap') 36 | , transEndEventNames = { 37 | 'WebkitTransition' : 'webkitTransitionEnd' 38 | , 'MozTransition' : 'transitionend' 39 | , 'OTransition' : 'oTransitionEnd' 40 | , 'msTransition' : 'MSTransitionEnd' 41 | , 'transition' : 'transitionend' 42 | } 43 | , name 44 | 45 | for (name in transEndEventNames){ 46 | if (el.style[name] !== undefined) { 47 | return transEndEventNames[name] 48 | } 49 | } 50 | 51 | }()) 52 | 53 | return transitionEnd && { 54 | end: transitionEnd 55 | } 56 | 57 | })() 58 | 59 | }) 60 | 61 | }(window.jQuery);/* ========================================================== 62 | * bootstrap-alert.js v2.0.3 63 | * http://twitter.github.com/bootstrap/javascript.html#alerts 64 | * ========================================================== 65 | * Copyright 2012 Twitter, Inc. 66 | * 67 | * Licensed under the Apache License, Version 2.0 (the "License"); 68 | * you may not use this file except in compliance with the License. 69 | * You may obtain a copy of the License at 70 | * 71 | * http://www.apache.org/licenses/LICENSE-2.0 72 | * 73 | * Unless required by applicable law or agreed to in writing, software 74 | * distributed under the License is distributed on an "AS IS" BASIS, 75 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 76 | * See the License for the specific language governing permissions and 77 | * limitations under the License. 78 | * ========================================================== */ 79 | 80 | 81 | !function ($) { 82 | 83 | "use strict"; // jshint ;_; 84 | 85 | 86 | /* ALERT CLASS DEFINITION 87 | * ====================== */ 88 | 89 | var dismiss = '[data-dismiss="alert"]' 90 | , Alert = function (el) { 91 | $(el).on('click', dismiss, this.close) 92 | } 93 | 94 | Alert.prototype.close = function (e) { 95 | var $this = $(this) 96 | , selector = $this.attr('data-target') 97 | , $parent 98 | 99 | if (!selector) { 100 | selector = $this.attr('href') 101 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 102 | } 103 | 104 | $parent = $(selector) 105 | 106 | e && e.preventDefault() 107 | 108 | $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) 109 | 110 | $parent.trigger(e = $.Event('close')) 111 | 112 | if (e.isDefaultPrevented()) return 113 | 114 | $parent.removeClass('in') 115 | 116 | function removeElement() { 117 | $parent 118 | .trigger('closed') 119 | .remove() 120 | } 121 | 122 | $.support.transition && $parent.hasClass('fade') ? 123 | $parent.on($.support.transition.end, removeElement) : 124 | removeElement() 125 | } 126 | 127 | 128 | /* ALERT PLUGIN DEFINITION 129 | * ======================= */ 130 | 131 | $.fn.alert = function (option) { 132 | return this.each(function () { 133 | var $this = $(this) 134 | , data = $this.data('alert') 135 | if (!data) $this.data('alert', (data = new Alert(this))) 136 | if (typeof option == 'string') data[option].call($this) 137 | }) 138 | } 139 | 140 | $.fn.alert.Constructor = Alert 141 | 142 | 143 | /* ALERT DATA-API 144 | * ============== */ 145 | 146 | $(function () { 147 | $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) 148 | }) 149 | 150 | }(window.jQuery);/* ============================================================ 151 | * bootstrap-button.js v2.0.3 152 | * http://twitter.github.com/bootstrap/javascript.html#buttons 153 | * ============================================================ 154 | * Copyright 2012 Twitter, Inc. 155 | * 156 | * Licensed under the Apache License, Version 2.0 (the "License"); 157 | * you may not use this file except in compliance with the License. 158 | * You may obtain a copy of the License at 159 | * 160 | * http://www.apache.org/licenses/LICENSE-2.0 161 | * 162 | * Unless required by applicable law or agreed to in writing, software 163 | * distributed under the License is distributed on an "AS IS" BASIS, 164 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 165 | * See the License for the specific language governing permissions and 166 | * limitations under the License. 167 | * ============================================================ */ 168 | 169 | 170 | !function ($) { 171 | 172 | "use strict"; // jshint ;_; 173 | 174 | 175 | /* BUTTON PUBLIC CLASS DEFINITION 176 | * ============================== */ 177 | 178 | var Button = function (element, options) { 179 | this.$element = $(element) 180 | this.options = $.extend({}, $.fn.button.defaults, options) 181 | } 182 | 183 | Button.prototype.setState = function (state) { 184 | var d = 'disabled' 185 | , $el = this.$element 186 | , data = $el.data() 187 | , val = $el.is('input') ? 'val' : 'html' 188 | 189 | state = state + 'Text' 190 | data.resetText || $el.data('resetText', $el[val]()) 191 | 192 | $el[val](data[state] || this.options[state]) 193 | 194 | // push to event loop to allow forms to submit 195 | setTimeout(function () { 196 | state == 'loadingText' ? 197 | $el.addClass(d).attr(d, d) : 198 | $el.removeClass(d).removeAttr(d) 199 | }, 0) 200 | } 201 | 202 | Button.prototype.toggle = function () { 203 | var $parent = this.$element.parent('[data-toggle="buttons-radio"]') 204 | 205 | $parent && $parent 206 | .find('.active') 207 | .removeClass('active') 208 | 209 | this.$element.toggleClass('active') 210 | } 211 | 212 | 213 | /* BUTTON PLUGIN DEFINITION 214 | * ======================== */ 215 | 216 | $.fn.button = function (option) { 217 | return this.each(function () { 218 | var $this = $(this) 219 | , data = $this.data('button') 220 | , options = typeof option == 'object' && option 221 | if (!data) $this.data('button', (data = new Button(this, options))) 222 | if (option == 'toggle') data.toggle() 223 | else if (option) data.setState(option) 224 | }) 225 | } 226 | 227 | $.fn.button.defaults = { 228 | loadingText: 'loading...' 229 | } 230 | 231 | $.fn.button.Constructor = Button 232 | 233 | 234 | /* BUTTON DATA-API 235 | * =============== */ 236 | 237 | $(function () { 238 | $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { 239 | var $btn = $(e.target) 240 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 241 | $btn.button('toggle') 242 | }) 243 | }) 244 | 245 | }(window.jQuery);/* ========================================================== 246 | * bootstrap-carousel.js v2.0.3 247 | * http://twitter.github.com/bootstrap/javascript.html#carousel 248 | * ========================================================== 249 | * Copyright 2012 Twitter, Inc. 250 | * 251 | * Licensed under the Apache License, Version 2.0 (the "License"); 252 | * you may not use this file except in compliance with the License. 253 | * You may obtain a copy of the License at 254 | * 255 | * http://www.apache.org/licenses/LICENSE-2.0 256 | * 257 | * Unless required by applicable law or agreed to in writing, software 258 | * distributed under the License is distributed on an "AS IS" BASIS, 259 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 260 | * See the License for the specific language governing permissions and 261 | * limitations under the License. 262 | * ========================================================== */ 263 | 264 | 265 | !function ($) { 266 | 267 | "use strict"; // jshint ;_; 268 | 269 | 270 | /* CAROUSEL CLASS DEFINITION 271 | * ========================= */ 272 | 273 | var Carousel = function (element, options) { 274 | this.$element = $(element) 275 | this.options = options 276 | this.options.slide && this.slide(this.options.slide) 277 | this.options.pause == 'hover' && this.$element 278 | .on('mouseenter', $.proxy(this.pause, this)) 279 | .on('mouseleave', $.proxy(this.cycle, this)) 280 | } 281 | 282 | Carousel.prototype = { 283 | 284 | cycle: function (e) { 285 | if (!e) this.paused = false 286 | this.options.interval 287 | && !this.paused 288 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 289 | return this 290 | } 291 | 292 | , to: function (pos) { 293 | var $active = this.$element.find('.active') 294 | , children = $active.parent().children() 295 | , activePos = children.index($active) 296 | , that = this 297 | 298 | if (pos > (children.length - 1) || pos < 0) return 299 | 300 | if (this.sliding) { 301 | return this.$element.one('slid', function () { 302 | that.to(pos) 303 | }) 304 | } 305 | 306 | if (activePos == pos) { 307 | return this.pause().cycle() 308 | } 309 | 310 | return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) 311 | } 312 | 313 | , pause: function (e) { 314 | if (!e) this.paused = true 315 | clearInterval(this.interval) 316 | this.interval = null 317 | return this 318 | } 319 | 320 | , next: function () { 321 | if (this.sliding) return 322 | return this.slide('next') 323 | } 324 | 325 | , prev: function () { 326 | if (this.sliding) return 327 | return this.slide('prev') 328 | } 329 | 330 | , slide: function (type, next) { 331 | var $active = this.$element.find('.active') 332 | , $next = next || $active[type]() 333 | , isCycling = this.interval 334 | , direction = type == 'next' ? 'left' : 'right' 335 | , fallback = type == 'next' ? 'first' : 'last' 336 | , that = this 337 | , e = $.Event('slide') 338 | 339 | this.sliding = true 340 | 341 | isCycling && this.pause() 342 | 343 | $next = $next.length ? $next : this.$element.find('.item')[fallback]() 344 | 345 | if ($next.hasClass('active')) return 346 | 347 | if ($.support.transition && this.$element.hasClass('slide')) { 348 | this.$element.trigger(e) 349 | if (e.isDefaultPrevented()) return 350 | $next.addClass(type) 351 | $next[0].offsetWidth // force reflow 352 | $active.addClass(direction) 353 | $next.addClass(direction) 354 | this.$element.one($.support.transition.end, function () { 355 | $next.removeClass([type, direction].join(' ')).addClass('active') 356 | $active.removeClass(['active', direction].join(' ')) 357 | that.sliding = false 358 | setTimeout(function () { that.$element.trigger('slid') }, 0) 359 | }) 360 | } else { 361 | this.$element.trigger(e) 362 | if (e.isDefaultPrevented()) return 363 | $active.removeClass('active') 364 | $next.addClass('active') 365 | this.sliding = false 366 | this.$element.trigger('slid') 367 | } 368 | 369 | isCycling && this.cycle() 370 | 371 | return this 372 | } 373 | 374 | } 375 | 376 | 377 | /* CAROUSEL PLUGIN DEFINITION 378 | * ========================== */ 379 | 380 | $.fn.carousel = function (option) { 381 | return this.each(function () { 382 | var $this = $(this) 383 | , data = $this.data('carousel') 384 | , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) 385 | if (!data) $this.data('carousel', (data = new Carousel(this, options))) 386 | if (typeof option == 'number') data.to(option) 387 | else if (typeof option == 'string' || (option = options.slide)) data[option]() 388 | else if (options.interval) data.cycle() 389 | }) 390 | } 391 | 392 | $.fn.carousel.defaults = { 393 | interval: 5000 394 | , pause: 'hover' 395 | } 396 | 397 | $.fn.carousel.Constructor = Carousel 398 | 399 | 400 | /* CAROUSEL DATA-API 401 | * ================= */ 402 | 403 | $(function () { 404 | $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { 405 | var $this = $(this), href 406 | , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 407 | , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) 408 | $target.carousel(options) 409 | e.preventDefault() 410 | }) 411 | }) 412 | 413 | }(window.jQuery);/* ============================================================= 414 | * bootstrap-collapse.js v2.0.3 415 | * http://twitter.github.com/bootstrap/javascript.html#collapse 416 | * ============================================================= 417 | * Copyright 2012 Twitter, Inc. 418 | * 419 | * Licensed under the Apache License, Version 2.0 (the "License"); 420 | * you may not use this file except in compliance with the License. 421 | * You may obtain a copy of the License at 422 | * 423 | * http://www.apache.org/licenses/LICENSE-2.0 424 | * 425 | * Unless required by applicable law or agreed to in writing, software 426 | * distributed under the License is distributed on an "AS IS" BASIS, 427 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 428 | * See the License for the specific language governing permissions and 429 | * limitations under the License. 430 | * ============================================================ */ 431 | 432 | 433 | !function ($) { 434 | 435 | "use strict"; // jshint ;_; 436 | 437 | 438 | /* COLLAPSE PUBLIC CLASS DEFINITION 439 | * ================================ */ 440 | 441 | var Collapse = function (element, options) { 442 | this.$element = $(element) 443 | this.options = $.extend({}, $.fn.collapse.defaults, options) 444 | 445 | if (this.options.parent) { 446 | this.$parent = $(this.options.parent) 447 | } 448 | 449 | this.options.toggle && this.toggle() 450 | } 451 | 452 | Collapse.prototype = { 453 | 454 | constructor: Collapse 455 | 456 | , dimension: function () { 457 | var hasWidth = this.$element.hasClass('width') 458 | return hasWidth ? 'width' : 'height' 459 | } 460 | 461 | , show: function () { 462 | var dimension 463 | , scroll 464 | , actives 465 | , hasData 466 | 467 | if (this.transitioning) return 468 | 469 | dimension = this.dimension() 470 | scroll = $.camelCase(['scroll', dimension].join('-')) 471 | actives = this.$parent && this.$parent.find('> .accordion-group > .in') 472 | 473 | if (actives && actives.length) { 474 | hasData = actives.data('collapse') 475 | if (hasData && hasData.transitioning) return 476 | actives.collapse('hide') 477 | hasData || actives.data('collapse', null) 478 | } 479 | 480 | this.$element[dimension](0) 481 | this.transition('addClass', $.Event('show'), 'shown') 482 | this.$element[dimension](this.$element[0][scroll]) 483 | } 484 | 485 | , hide: function () { 486 | var dimension 487 | if (this.transitioning) return 488 | dimension = this.dimension() 489 | this.reset(this.$element[dimension]()) 490 | this.transition('removeClass', $.Event('hide'), 'hidden') 491 | this.$element[dimension](0) 492 | } 493 | 494 | , reset: function (size) { 495 | var dimension = this.dimension() 496 | 497 | this.$element 498 | .removeClass('collapse') 499 | [dimension](size || 'auto') 500 | [0].offsetWidth 501 | 502 | this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') 503 | 504 | return this 505 | } 506 | 507 | , transition: function (method, startEvent, completeEvent) { 508 | var that = this 509 | , complete = function () { 510 | if (startEvent.type == 'show') that.reset() 511 | that.transitioning = 0 512 | that.$element.trigger(completeEvent) 513 | } 514 | 515 | this.$element.trigger(startEvent) 516 | 517 | if (startEvent.isDefaultPrevented()) return 518 | 519 | this.transitioning = 1 520 | 521 | this.$element[method]('in') 522 | 523 | $.support.transition && this.$element.hasClass('collapse') ? 524 | this.$element.one($.support.transition.end, complete) : 525 | complete() 526 | } 527 | 528 | , toggle: function () { 529 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 530 | } 531 | 532 | } 533 | 534 | 535 | /* COLLAPSIBLE PLUGIN DEFINITION 536 | * ============================== */ 537 | 538 | $.fn.collapse = function (option) { 539 | return this.each(function () { 540 | var $this = $(this) 541 | , data = $this.data('collapse') 542 | , options = typeof option == 'object' && option 543 | if (!data) $this.data('collapse', (data = new Collapse(this, options))) 544 | if (typeof option == 'string') data[option]() 545 | }) 546 | } 547 | 548 | $.fn.collapse.defaults = { 549 | toggle: true 550 | } 551 | 552 | $.fn.collapse.Constructor = Collapse 553 | 554 | 555 | /* COLLAPSIBLE DATA-API 556 | * ==================== */ 557 | 558 | $(function () { 559 | $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) { 560 | var $this = $(this), href 561 | , target = $this.attr('data-target') 562 | || e.preventDefault() 563 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 564 | , option = $(target).data('collapse') ? 'toggle' : $this.data() 565 | $(target).collapse(option) 566 | }) 567 | }) 568 | 569 | }(window.jQuery);/* ============================================================ 570 | * bootstrap-dropdown.js v2.0.3 571 | * http://twitter.github.com/bootstrap/javascript.html#dropdowns 572 | * ============================================================ 573 | * Copyright 2012 Twitter, Inc. 574 | * 575 | * Licensed under the Apache License, Version 2.0 (the "License"); 576 | * you may not use this file except in compliance with the License. 577 | * You may obtain a copy of the License at 578 | * 579 | * http://www.apache.org/licenses/LICENSE-2.0 580 | * 581 | * Unless required by applicable law or agreed to in writing, software 582 | * distributed under the License is distributed on an "AS IS" BASIS, 583 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 584 | * See the License for the specific language governing permissions and 585 | * limitations under the License. 586 | * ============================================================ */ 587 | 588 | 589 | !function ($) { 590 | 591 | "use strict"; // jshint ;_; 592 | 593 | 594 | /* DROPDOWN CLASS DEFINITION 595 | * ========================= */ 596 | 597 | var toggle = '[data-toggle="dropdown"]' 598 | , Dropdown = function (element) { 599 | var $el = $(element).on('click.dropdown.data-api', this.toggle) 600 | $('html').on('click.dropdown.data-api', function () { 601 | $el.parent().removeClass('open') 602 | }) 603 | } 604 | 605 | Dropdown.prototype = { 606 | 607 | constructor: Dropdown 608 | 609 | , toggle: function (e) { 610 | var $this = $(this) 611 | , $parent 612 | , selector 613 | , isActive 614 | 615 | if ($this.is('.disabled, :disabled')) return 616 | 617 | selector = $this.attr('data-target') 618 | 619 | if (!selector) { 620 | selector = $this.attr('href') 621 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 622 | } 623 | 624 | $parent = $(selector) 625 | $parent.length || ($parent = $this.parent()) 626 | 627 | isActive = $parent.hasClass('open') 628 | 629 | clearMenus() 630 | 631 | if (!isActive) $parent.toggleClass('open') 632 | 633 | return false 634 | } 635 | 636 | } 637 | 638 | function clearMenus() { 639 | $(toggle).parent().removeClass('open') 640 | } 641 | 642 | 643 | /* DROPDOWN PLUGIN DEFINITION 644 | * ========================== */ 645 | 646 | $.fn.dropdown = function (option) { 647 | return this.each(function () { 648 | var $this = $(this) 649 | , data = $this.data('dropdown') 650 | if (!data) $this.data('dropdown', (data = new Dropdown(this))) 651 | if (typeof option == 'string') data[option].call($this) 652 | }) 653 | } 654 | 655 | $.fn.dropdown.Constructor = Dropdown 656 | 657 | 658 | /* APPLY TO STANDARD DROPDOWN ELEMENTS 659 | * =================================== */ 660 | 661 | $(function () { 662 | $('html').on('click.dropdown.data-api', clearMenus) 663 | $('body') 664 | .on('click.dropdown', '.dropdown form', function (e) { e.stopPropagation() }) 665 | .on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle) 666 | }) 667 | 668 | }(window.jQuery);/* ========================================================= 669 | * bootstrap-modal.js v2.0.3 670 | * http://twitter.github.com/bootstrap/javascript.html#modals 671 | * ========================================================= 672 | * Copyright 2012 Twitter, Inc. 673 | * 674 | * Licensed under the Apache License, Version 2.0 (the "License"); 675 | * you may not use this file except in compliance with the License. 676 | * You may obtain a copy of the License at 677 | * 678 | * http://www.apache.org/licenses/LICENSE-2.0 679 | * 680 | * Unless required by applicable law or agreed to in writing, software 681 | * distributed under the License is distributed on an "AS IS" BASIS, 682 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 683 | * See the License for the specific language governing permissions and 684 | * limitations under the License. 685 | * ========================================================= */ 686 | 687 | 688 | !function ($) { 689 | 690 | "use strict"; // jshint ;_; 691 | 692 | 693 | /* MODAL CLASS DEFINITION 694 | * ====================== */ 695 | 696 | var Modal = function (content, options) { 697 | this.options = options 698 | this.$element = $(content) 699 | .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this)) 700 | } 701 | 702 | Modal.prototype = { 703 | 704 | constructor: Modal 705 | 706 | , toggle: function () { 707 | return this[!this.isShown ? 'show' : 'hide']() 708 | } 709 | 710 | , show: function () { 711 | var that = this 712 | , e = $.Event('show') 713 | 714 | this.$element.trigger(e) 715 | 716 | if (this.isShown || e.isDefaultPrevented()) return 717 | 718 | $('body').addClass('modal-open') 719 | 720 | this.isShown = true 721 | 722 | escape.call(this) 723 | backdrop.call(this, function () { 724 | var transition = $.support.transition && that.$element.hasClass('fade') 725 | 726 | if (!that.$element.parent().length) { 727 | that.$element.appendTo(document.body) //don't move modals dom position 728 | } 729 | 730 | that.$element 731 | .show() 732 | 733 | if (transition) { 734 | that.$element[0].offsetWidth // force reflow 735 | } 736 | 737 | that.$element.addClass('in') 738 | 739 | transition ? 740 | that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : 741 | that.$element.trigger('shown') 742 | 743 | }) 744 | } 745 | 746 | , hide: function (e) { 747 | e && e.preventDefault() 748 | 749 | var that = this 750 | 751 | e = $.Event('hide') 752 | 753 | this.$element.trigger(e) 754 | 755 | if (!this.isShown || e.isDefaultPrevented()) return 756 | 757 | this.isShown = false 758 | 759 | $('body').removeClass('modal-open') 760 | 761 | escape.call(this) 762 | 763 | this.$element.removeClass('in') 764 | 765 | $.support.transition && this.$element.hasClass('fade') ? 766 | hideWithTransition.call(this) : 767 | hideModal.call(this) 768 | } 769 | 770 | } 771 | 772 | 773 | /* MODAL PRIVATE METHODS 774 | * ===================== */ 775 | 776 | function hideWithTransition() { 777 | var that = this 778 | , timeout = setTimeout(function () { 779 | that.$element.off($.support.transition.end) 780 | hideModal.call(that) 781 | }, 500) 782 | 783 | this.$element.one($.support.transition.end, function () { 784 | clearTimeout(timeout) 785 | hideModal.call(that) 786 | }) 787 | } 788 | 789 | function hideModal(that) { 790 | this.$element 791 | .hide() 792 | .trigger('hidden') 793 | 794 | backdrop.call(this) 795 | } 796 | 797 | function backdrop(callback) { 798 | var that = this 799 | , animate = this.$element.hasClass('fade') ? 'fade' : '' 800 | 801 | if (this.isShown && this.options.backdrop) { 802 | var doAnimate = $.support.transition && animate 803 | 804 | this.$backdrop = $('