├── .gitignore
├── Jakefile.js
├── Makefile
├── README.textile
├── app.js
├── bin
└── nodepad.js
├── helpers.js
├── models.js
├── package.json
├── public
├── images
│ ├── glass.png
│ └── gradient.gif
├── javascripts
│ ├── backbone-min.js
│ ├── documents.js
│ ├── flash.js
│ ├── json.js
│ ├── resize.js
│ └── underscore-min.js
└── stylesheets
│ ├── aristo
│ ├── images
│ │ ├── button_bg.png
│ │ ├── datepicker.gif
│ │ ├── icon_sprite.png
│ │ ├── progress_bar.gif
│ │ ├── slider_h_bg.gif
│ │ ├── slider_handles.png
│ │ ├── slider_v_bg.gif
│ │ ├── tab_bg.gif
│ │ ├── the_gradient.gif
│ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png
│ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png
│ │ ├── ui-bg_flat_10_000000_40x100.png
│ │ ├── ui-bg_glass_100_f6f6f6_1x400.png
│ │ ├── ui-bg_glass_100_fdf5ce_1x400.png
│ │ ├── ui-bg_glass_65_ffffff_1x400.png
│ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png
│ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png
│ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png
│ │ ├── ui-icons_222222_256x240.png
│ │ ├── ui-icons_228ef1_256x240.png
│ │ ├── ui-icons_ef8c08_256x240.png
│ │ ├── ui-icons_ffd27a_256x240.png
│ │ └── ui-icons_ffffff_256x240.png
│ └── jquery-ui-1.8.5.custom.css
│ ├── style.css
│ └── style.styl
├── test
├── app.test.js
└── helper.js
└── views
├── 404.jade
├── 500.jade
├── documents
├── edit.jade
├── fields.jade
├── index.jade
├── new.jade
└── show.jade
├── index.jade
├── layout.jade
├── mailer
└── welcome.jade
├── sessions
└── new.jade
└── users
├── fields.jade
└── new.jade
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sw?
2 | .DS_Store
3 | tmp/*
4 | log/*
5 | node_modules/
6 |
--------------------------------------------------------------------------------
/Jakefile.js:
--------------------------------------------------------------------------------
1 |
2 | desc('Saves all documents to generate keywords');
3 | task('index', [], function() {
4 | app = require('./app');
5 |
6 | app.Document.find({}, function(err, documents) {
7 | documents.forEach(function(d) {
8 | console.log(d._id);
9 | d.save();
10 | });
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | test:
2 | ./node_modules/.bin/mocha
3 |
4 | .PHONY: test
5 |
--------------------------------------------------------------------------------
/README.textile:
--------------------------------------------------------------------------------
1 | h3. Nodepad
2 |
3 | This is a Node notepad, written for a tutorial series on "DailyJS":http://dailyjs.com.
4 |
5 | h3. Updates
6 |
7 | Follow the series on "DailyJS":http://dailyjs.com, "@dailyjs":http://twitter.com/dailyjs, or "@alex_young":http://twitter.com/alex_young.
8 |
9 | h3. Dependencies
10 |
11 | You need to install these on your system first:
12 |
13 | * "Node":http://nodejs.org/
14 | * "npm":https://github.com/isaacs/npm/
15 | * "MongoDB":http://www.mongodb.org/
16 |
17 | These are the libraries that the project requires:
18 |
19 | * "Mongoose":https://github.com/LearnBoost/mongoose
20 | * "Express":http://expressjs.com/
21 | * "Expresso":http://visionmedia.github.com/expresso/
22 | * "Jade":http://jade-lang.com/
23 | * "less":https://github.com/cloudhead/less.js
24 |
25 | See the package.json file for the versions of the dependencies I've tested with.
26 |
27 | On Mac OS Snow Leopard and Debian Lenny/Squeeze.
28 |
29 | h3. Dependency Installation
30 |
31 | Make sure you're running a mongo instance (type mongod
if required).
32 |
33 |
34 | git clone git@github.com:alexyoung/nodepad.git nodepad
35 | cd nodepad
36 | npm install
37 |
38 | node app.js
39 |
40 |
41 | h3. Contributions
42 |
43 | * "luebken":https://github.com/luebken
44 | * "eirikurn":https://github.com/eirikurn
45 | * "@francoislaberge":http://twitter.com/francoislaberge
46 |
47 | h3. License (GPL)
48 |
49 | This program is free software: you can redistribute it and/or modify
50 | it under the terms of the GNU General Public License as published by
51 | the Free Software Foundation, either version 3 of the License, or
52 | (at your option) any later version.
53 |
54 | This program is distributed in the hope that it will be useful,
55 | but WITHOUT ANY WARRANTY; without even the implied warranty of
56 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57 | GNU General Public License for more details.
58 |
59 | You should have received a copy of the GNU General Public License
60 | along with this program. If not, see "http://www.gnu.org/licenses/":http://www.gnu.org/licenses/.
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | connect = require('connect'),
3 | jade = require('jade'),
4 | app = module.exports = express.createServer(),
5 | mongoose = require('mongoose'),
6 | mongoStore = require('connect-mongodb'),
7 | mailer = require('mailer'),
8 | stylus = require('stylus'),
9 | markdown = require('markdown').markdown,
10 | connectTimeout = require('connect-timeout'),
11 | util = require('util'),
12 | path = require('path'),
13 | models = require('./models'),
14 | db,
15 | Document,
16 | User,
17 | LoginToken,
18 | Settings = { development: {}, test: {}, production: {} },
19 | emails;
20 |
21 | function renderJadeFile(template, options) {
22 | var fn = jade.compile(template, options);
23 | return fn(options.locals);
24 | }
25 |
26 | emails = {
27 | send: function(template, mailOptions, templateOptions) {
28 | mailOptions.to = mailOptions.to;
29 | renderJadeFile(path.join(__dirname, 'views', 'mailer', template), templateOptions, function(err, text) {
30 | // Add the rendered Jade template to the mailOptions
31 | mailOptions.body = text;
32 |
33 | // Merge the app's mail options
34 | var keys = Object.keys(app.set('mailOptions')),
35 | k;
36 | for (var i = 0, len = keys.length; i < len; i++) {
37 | k = keys[i];
38 | if (!mailOptions.hasOwnProperty(k))
39 | mailOptions[k] = app.set('mailOptions')[k]
40 | }
41 |
42 | console.log('[SENDING MAIL]', util.inspect(mailOptions));
43 |
44 | // Only send mails in production
45 | if (app.settings.env == 'production') {
46 | mailer.send(mailOptions,
47 | function(err, result) {
48 | if (err) {
49 | console.log(err);
50 | }
51 | }
52 | );
53 | }
54 | });
55 | },
56 |
57 | sendWelcome: function(user) {
58 | this.send('welcome.jade', { to: user.email, subject: 'Welcome to Nodepad' }, { locals: { user: user } });
59 | }
60 | };
61 |
62 | app.helpers(require('./helpers.js').helpers);
63 | app.dynamicHelpers(require('./helpers.js').dynamicHelpers);
64 |
65 | app.configure('development', function() {
66 | app.set('db-uri', 'mongodb://localhost/nodepad-development');
67 | app.use(express.errorHandler({ dumpExceptions: true }));
68 | app.set('view options', {
69 | pretty: true
70 | });
71 | });
72 |
73 | app.configure('test', function() {
74 | app.set('db-uri', 'mongodb://localhost/nodepad-test');
75 | app.set('view options', {
76 | pretty: true
77 | });
78 | });
79 |
80 | app.configure('production', function() {
81 | app.set('db-uri', 'mongodb://localhost/nodepad-production');
82 | });
83 |
84 | app.configure(function() {
85 | app.set('views', __dirname + '/views');
86 | app.use(express.favicon());
87 | app.use(express.bodyParser());
88 | app.use(express.cookieParser());
89 | app.use(connectTimeout({ time: 10000 }));
90 | app.use(express.session({ store: mongoStore(app.set('db-uri')), secret: 'topsecret' }));
91 | app.use(express.logger({ format: '\x1b[1m:method\x1b[0m \x1b[33m:url\x1b[0m :response-time ms' }))
92 | app.use(express.methodOverride());
93 | app.use(stylus.middleware({ src: __dirname + '/public' }));
94 | app.use(express.static(__dirname + '/public'));
95 | app.set('mailOptions', {
96 | host: 'localhost',
97 | port: '25',
98 | from: 'nodepad@example.com'
99 | });
100 | });
101 |
102 | models.defineModels(mongoose, function() {
103 | app.Document = Document = mongoose.model('Document');
104 | app.User = User = mongoose.model('User');
105 | app.LoginToken = LoginToken = mongoose.model('LoginToken');
106 | db = mongoose.connect(app.set('db-uri'));
107 | })
108 |
109 | function authenticateFromLoginToken(req, res, next) {
110 | var cookie = JSON.parse(req.cookies.logintoken);
111 |
112 | LoginToken.findOne({ email: cookie.email,
113 | series: cookie.series,
114 | token: cookie.token }, (function(err, token) {
115 | if (!token) {
116 | res.redirect('/sessions/new');
117 | return;
118 | }
119 |
120 | User.findOne({ email: token.email }, function(err, user) {
121 | if (user) {
122 | req.session.user_id = user.id;
123 | req.currentUser = user;
124 |
125 | token.token = token.randomToken();
126 | token.save(function() {
127 | res.cookie('logintoken', token.cookieValue, { expires: new Date(Date.now() + 2 * 604800000), path: '/' });
128 | next();
129 | });
130 | } else {
131 | res.redirect('/sessions/new');
132 | }
133 | });
134 | }));
135 | }
136 |
137 | function loadUser(req, res, next) {
138 | if (req.session.user_id) {
139 | User.findById(req.session.user_id, function(err, user) {
140 | if (user) {
141 | req.currentUser = user;
142 | next();
143 | } else {
144 | res.redirect('/sessions/new');
145 | }
146 | });
147 | } else if (req.cookies.logintoken) {
148 | authenticateFromLoginToken(req, res, next);
149 | } else {
150 | res.redirect('/sessions/new');
151 | }
152 | }
153 |
154 | app.get('/', loadUser, function(req, res) {
155 | res.redirect('/documents')
156 | });
157 |
158 | // Error handling
159 | function NotFound(msg) {
160 | this.name = 'NotFound';
161 | Error.call(this, msg);
162 | Error.captureStackTrace(this, arguments.callee);
163 | }
164 |
165 | util.inherits(NotFound, Error);
166 |
167 | app.get('/404', function(req, res) {
168 | throw new NotFound;
169 | });
170 |
171 | app.get('/500', function(req, res) {
172 | throw new Error('An expected error');
173 | });
174 |
175 | app.get('/bad', function(req, res) {
176 | unknownMethod();
177 | });
178 |
179 | app.error(function(err, req, res, next) {
180 | if (err instanceof NotFound) {
181 | res.render('404.jade', { status: 404 });
182 | } else {
183 | next(err);
184 | }
185 | });
186 |
187 | if (app.settings.env == 'production') {
188 | app.error(function(err, req, res) {
189 | res.render('500.jade', {
190 | status: 500,
191 | locals: {
192 | error: err
193 | }
194 | });
195 | });
196 | }
197 |
198 | // Document list
199 | app.get('/documents', loadUser, function(req, res) {
200 | Document.find({ user_id: req.currentUser.id },
201 | [], { sort: ['title', 'descending'] },
202 | function(err, documents) {
203 | documents = documents.map(function(d) {
204 | return { title: d.title, id: d._id };
205 | });
206 | res.render('documents/index.jade', {
207 | locals: { documents: documents, currentUser: req.currentUser }
208 | });
209 | });
210 | });
211 |
212 | app.get('/documents.:format?', loadUser, function(req, res) {
213 | Document.find({ user_id: req.currentUser.id },
214 | [], { sort: ['title', 'descending'] },
215 | function(err, documents) {
216 | switch (req.params.format) {
217 | case 'json':
218 | res.send(documents.map(function(d) {
219 | return d.toObject();
220 | }));
221 | break;
222 |
223 | default:
224 | res.send('Format not available', 400);
225 | }
226 | });
227 | });
228 |
229 | app.get('/documents/titles.json', loadUser, function(req, res) {
230 | Document.find({ user_id: req.currentUser.id },
231 | [], { sort: ['title', 'descending'] },
232 | function(err, documents) {
233 | res.send(documents.map(function(d) {
234 | return { title: d.title, id: d._id };
235 | }));
236 | });
237 | });
238 |
239 | app.get('/documents/:id.:format?/edit', loadUser, function(req, res, next) {
240 | Document.findOne({ _id: req.params.id, user_id: req.currentUser.id }, function(err, d) {
241 | if (!d) return next(new NotFound('Document not found'));
242 | res.render('documents/edit.jade', {
243 | locals: { d: d, currentUser: req.currentUser }
244 | });
245 | });
246 | });
247 |
248 | app.get('/documents/new', loadUser, function(req, res) {
249 | res.render('documents/new.jade', {
250 | locals: { d: new Document(), currentUser: req.currentUser }
251 | });
252 | });
253 |
254 | // Create document
255 | app.post('/documents.:format?', loadUser, function(req, res) {
256 | var d = new Document(req.body);
257 | d.user_id = req.currentUser.id;
258 | d.save(function() {
259 | switch (req.params.format) {
260 | case 'json':
261 | var data = d.toObject();
262 | // TODO: Backbone requires 'id', but can I alias it?
263 | data.id = data._id;
264 | res.send(data);
265 | break;
266 |
267 | default:
268 | req.flash('info', 'Document created');
269 | res.redirect('/documents');
270 | }
271 | });
272 | });
273 |
274 | // Read document
275 | app.get('/documents/:id.:format?', loadUser, function(req, res, next) {
276 | Document.findOne({ _id: req.params.id, user_id: req.currentUser.id }, function(err, d) {
277 | if (!d) return next(new NotFound('Document not found'));
278 |
279 | switch (req.params.format) {
280 | case 'json':
281 | res.send(d.toObject());
282 | break;
283 |
284 | case 'html':
285 | res.send(markdown.toHTML(d.data));
286 | break;
287 |
288 | default:
289 | res.render('documents/show.jade', {
290 | locals: { d: d, currentUser: req.currentUser }
291 | });
292 | }
293 | });
294 | });
295 |
296 | // Update document
297 | app.put('/documents/:id.:format?', loadUser, function(req, res, next) {
298 | Document.findOne({ _id: req.params.id, user_id: req.currentUser.id }, function(err, d) {
299 | if (!d) return next(new NotFound('Document not found'));
300 | d.title = req.body.title;
301 | d.data = req.body.data;
302 |
303 | d.save(function(err) {
304 | switch (req.params.format) {
305 | case 'json':
306 | res.send(d.toObject());
307 | break;
308 |
309 | default:
310 | req.flash('info', 'Document updated');
311 | res.redirect('/documents');
312 | }
313 | });
314 | });
315 | });
316 |
317 | // Delete document
318 | app.del('/documents/:id.:format?', loadUser, function(req, res, next) {
319 | Document.findOne({ _id: req.params.id, user_id: req.currentUser.id }, function(err, d) {
320 | if (!d) return next(new NotFound('Document not found'));
321 |
322 | d.remove(function() {
323 | switch (req.params.format) {
324 | case 'json':
325 | res.send('true');
326 | break;
327 |
328 | default:
329 | req.flash('info', 'Document deleted');
330 | res.redirect('/documents');
331 | }
332 | });
333 | });
334 | });
335 |
336 | // Users
337 | app.get('/users/new', function(req, res) {
338 | res.render('users/new.jade', {
339 | locals: { user: new User() }
340 | });
341 | });
342 |
343 | app.post('/users.:format?', function(req, res) {
344 | var user = new User(req.body.user);
345 |
346 | function userSaveFailed() {
347 | req.flash('error', 'Account creation failed');
348 | res.render('users/new.jade', {
349 | locals: { user: user }
350 | });
351 | }
352 |
353 | user.save(function(err) {
354 | if (err) return userSaveFailed();
355 |
356 | req.flash('info', 'Your account has been created');
357 | emails.sendWelcome(user);
358 |
359 | switch (req.params.format) {
360 | case 'json':
361 | res.send(user.toObject());
362 | break;
363 |
364 | default:
365 | req.session.user_id = user.id;
366 | res.redirect('/documents');
367 | }
368 | });
369 | });
370 |
371 | // Sessions
372 | app.get('/sessions/new', function(req, res) {
373 | res.render('sessions/new.jade', {
374 | locals: { user: new User() }
375 | });
376 | });
377 |
378 | app.post('/sessions', function(req, res) {
379 | User.findOne({ email: req.body.user.email }, function(err, user) {
380 | if (user && user.authenticate(req.body.user.password)) {
381 | req.session.user_id = user.id;
382 |
383 | // Remember me
384 | if (req.body.remember_me) {
385 | var loginToken = new LoginToken({ email: user.email });
386 | loginToken.save(function() {
387 | res.cookie('logintoken', loginToken.cookieValue, { expires: new Date(Date.now() + 2 * 604800000), path: '/' });
388 | res.redirect('/documents');
389 | });
390 | } else {
391 | res.redirect('/documents');
392 | }
393 | } else {
394 | req.flash('error', 'Incorrect credentials');
395 | res.redirect('/sessions/new');
396 | }
397 | });
398 | });
399 |
400 | app.del('/sessions', loadUser, function(req, res) {
401 | if (req.session) {
402 | LoginToken.remove({ email: req.currentUser.email }, function() {});
403 | res.clearCookie('logintoken');
404 | req.session.destroy(function() {});
405 | }
406 | res.redirect('/sessions/new');
407 | });
408 |
409 | // Search
410 | app.post('/search.:format?', loadUser, function(req, res) {
411 | Document.find({ user_id: req.currentUser.id, keywords: req.body.s },
412 | function(err, documents) {
413 | console.log(documents);
414 | console.log(err);
415 | switch (req.params.format) {
416 | case 'json':
417 | res.send(documents.map(function(d) {
418 | return { title: d.title, id: d._id };
419 | }));
420 | break;
421 |
422 | default:
423 | res.send('Format not available', 400);
424 | break;
425 | }
426 | });
427 | });
428 |
429 | if (!module.parent) {
430 | app.listen(3000, 'localhost', function() {
431 | console.log('Express server listening on port %d, environment: %s', app.address().port, app.settings.env)
432 | });
433 |
434 | console.log('Using connect %s, Express %s, Jade %s', connect.version, express.version, jade.version);
435 | }
436 |
--------------------------------------------------------------------------------
/bin/nodepad.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | var app = require('../app.js');
3 | app.listen(3000);
4 |
5 |
--------------------------------------------------------------------------------
/helpers.js:
--------------------------------------------------------------------------------
1 | exports.helpers = {
2 | appName: 'Nodepad',
3 | version: '0.1',
4 |
5 | nameAndVersion: function(name, version) {
6 | return name + ' v' + version;
7 | }
8 | };
9 |
10 | function FlashMessage(type, messages) {
11 | this.type = type;
12 | this.messages = typeof messages === 'string' ? [messages] : messages;
13 | }
14 |
15 | FlashMessage.prototype = {
16 | get icon() {
17 | switch (this.type) {
18 | case 'info':
19 | return 'ui-icon-info';
20 | case 'error':
21 | return 'ui-icon-alert';
22 | }
23 | },
24 |
25 | get stateClass() {
26 | switch (this.type) {
27 | case 'info':
28 | return 'ui-state-highlight';
29 | case 'error':
30 | return 'ui-state-error';
31 | }
32 | },
33 |
34 | toHTML: function() {
35 | return '';
40 | }
41 | };
42 |
43 | exports.dynamicHelpers = {
44 | flashMessages: function(req, res) {
45 | var html = '';
46 | ['error', 'info'].forEach(function(type) {
47 | var messages = req.flash(type);
48 | if (messages.length > 0) {
49 | html += new FlashMessage(type, messages).toHTML();
50 | }
51 | });
52 | return html;
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/models.js:
--------------------------------------------------------------------------------
1 | var crypto = require('crypto'),
2 | Document,
3 | User,
4 | LoginToken;
5 |
6 | function extractKeywords(text) {
7 | if (!text) return [];
8 |
9 | return text.
10 | split(/\s+/).
11 | filter(function(v) { return v.length > 2; }).
12 | filter(function(v, i, a) { return a.lastIndexOf(v) === i; });
13 | }
14 |
15 | function defineModels(mongoose, fn) {
16 | var Schema = mongoose.Schema,
17 | ObjectId = Schema.ObjectId;
18 |
19 | /**
20 | * Model: Document
21 | */
22 | Document = new Schema({
23 | 'title': { type: String, index: true },
24 | 'data': String,
25 | 'tags': [String],
26 | 'keywords': [String],
27 | 'user_id': ObjectId
28 | });
29 |
30 | Document.virtual('id')
31 | .get(function() {
32 | return this._id.toHexString();
33 | });
34 |
35 | Document.pre('save', function(next) {
36 | this.keywords = extractKeywords(this.data);
37 | next();
38 | });
39 |
40 | /**
41 | * Model: User
42 | */
43 | function validatePresenceOf(value) {
44 | return value && value.length;
45 | }
46 |
47 | User = new Schema({
48 | 'email': { type: String, validate: [validatePresenceOf, 'an email is required'], index: { unique: true } },
49 | 'hashed_password': String,
50 | 'salt': String
51 | });
52 |
53 | User.virtual('id')
54 | .get(function() {
55 | return this._id.toHexString();
56 | });
57 |
58 | User.virtual('password')
59 | .set(function(password) {
60 | this._password = password;
61 | this.salt = this.makeSalt();
62 | this.hashed_password = this.encryptPassword(password);
63 | })
64 | .get(function() { return this._password; });
65 |
66 | User.method('authenticate', function(plainText) {
67 | return this.encryptPassword(plainText) === this.hashed_password;
68 | });
69 |
70 | User.method('makeSalt', function() {
71 | return Math.round((new Date().valueOf() * Math.random())) + '';
72 | });
73 |
74 | User.method('encryptPassword', function(password) {
75 | return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
76 | });
77 |
78 | User.pre('save', function(next) {
79 | if (!validatePresenceOf(this.password)) {
80 | next(new Error('Invalid password'));
81 | } else {
82 | next();
83 | }
84 | });
85 |
86 | /**
87 | * Model: LoginToken
88 | *
89 | * Used for session persistence.
90 | */
91 | LoginToken = new Schema({
92 | email: { type: String, index: true },
93 | series: { type: String, index: true },
94 | token: { type: String, index: true }
95 | });
96 |
97 | LoginToken.method('randomToken', function() {
98 | return Math.round((new Date().valueOf() * Math.random())) + '';
99 | });
100 |
101 | LoginToken.pre('save', function(next) {
102 | // Automatically create the tokens
103 | this.token = this.randomToken();
104 |
105 | if (this.isNew)
106 | this.series = this.randomToken();
107 |
108 | next();
109 | });
110 |
111 | LoginToken.virtual('id')
112 | .get(function() {
113 | return this._id.toHexString();
114 | });
115 |
116 | LoginToken.virtual('cookieValue')
117 | .get(function() {
118 | return JSON.stringify({ email: this.email, token: this.token, series: this.series });
119 | });
120 |
121 | mongoose.model('Document', Document);
122 | mongoose.model('User', User);
123 | mongoose.model('LoginToken', LoginToken);
124 |
125 | fn();
126 | }
127 |
128 | exports.defineModels = defineModels;
129 |
130 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nodepad",
3 | "description": "A notepad written with Node",
4 | "version": "0.1.1",
5 | "homepage": "http://dailyjs.com",
6 | "author": "Alex R. Young (http://alexyoung.org)",
7 | "directories": {
8 | "public": "./public"
9 | },
10 | "engines": {
11 | "node": ">= 0.4.0"
12 | },
13 | "dependencies": {
14 | "express": "2.5.1",
15 | "connect": "1.8.1",
16 | "mongoose": "2.3.12",
17 | "stylus": "0.18.0",
18 | "jade": "0.18.0",
19 | "connect-mongodb": "1.1.1",
20 | "markdown": "0.3.1",
21 | "mailer": "0.6.7",
22 | "connect-timeout": "0.0.1"
23 | },
24 | "devDependencies": {
25 | "tobi": "0.3.2",
26 | "mocha": "0.0.2"
27 | },
28 | "bin": {
29 | "nodepad": "bin/nodepad.js"
30 | }
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/public/images/glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/images/glass.png
--------------------------------------------------------------------------------
/public/images/gradient.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/images/gradient.gif
--------------------------------------------------------------------------------
/public/javascripts/backbone-min.js:
--------------------------------------------------------------------------------
1 | // Backbone.js 0.5.3
2 | // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Backbone may be freely distributed under the MIT license.
4 | // For all details and documentation:
5 | // http://documentcloud.github.com/backbone
6 | (function(){var h=this,p=h.Backbone,e;e=typeof exports!=="undefined"?exports:h.Backbone={};e.VERSION="0.5.3";var f=h._;if(!f&&typeof require!=="undefined")f=require("underscore")._;var g=h.jQuery||h.Zepto;e.noConflict=function(){h.Backbone=p;return this};e.emulateHTTP=!1;e.emulateJSON=!1;e.Events={bind:function(a,b,c){var d=this._callbacks||(this._callbacks={});(d[a]||(d[a]=[])).push([b,c]);return this},unbind:function(a,b){var c;if(a){if(c=this._callbacks)if(b){c=c[a];if(!c)return this;for(var d=
7 | 0,e=c.length;d/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")},has:function(a){return this.attributes[a]!=null},set:function(a,b){b||(b={});if(!a)return this;if(a.attributes)a=a.attributes;var c=this.attributes,d=this._escapedAttributes;if(!b.silent&&this.validate&&!this._performValidation(a,b))return!1;if(this.idAttribute in a)this.id=a[this.idAttribute];
10 | var e=this._changing;this._changing=!0;for(var g in a){var h=a[g];if(!f.isEqual(c[g],h))c[g]=h,delete d[g],this._changed=!0,b.silent||this.trigger("change:"+g,this,h,b)}!e&&!b.silent&&this._changed&&this.change(b);this._changing=!1;return this},unset:function(a,b){if(!(a in this.attributes))return this;b||(b={});var c={};c[a]=void 0;if(!b.silent&&this.validate&&!this._performValidation(c,b))return!1;delete this.attributes[a];delete this._escapedAttributes[a];a==this.idAttribute&&delete this.id;this._changed=
11 | !0;b.silent||(this.trigger("change:"+a,this,void 0,b),this.change(b));return this},clear:function(a){a||(a={});var b,c=this.attributes,d={};for(b in c)d[b]=void 0;if(!a.silent&&this.validate&&!this._performValidation(d,a))return!1;this.attributes={};this._escapedAttributes={};this._changed=!0;if(!a.silent){for(b in c)this.trigger("change:"+b,this,void 0,a);this.change(a)}return this},fetch:function(a){a||(a={});var b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&
12 | c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"read",this,a)},save:function(a,b){b||(b={});if(a&&!this.set(a,b))return!1;var c=this,d=b.success;b.success=function(a,e,f){if(!c.set(c.parse(a,f),b))return!1;d&&d(c,a,f)};b.error=i(b.error,c,b);var f=this.isNew()?"create":"update";return(this.sync||e.sync).call(this,f,this,b)},destroy:function(a){a||(a={});if(this.isNew())return this.trigger("destroy",this,this.collection,a);var b=this,c=a.success;a.success=function(d){b.trigger("destroy",
13 | b,b.collection,a);c&&c(b,d)};a.error=i(a.error,b,a);return(this.sync||e.sync).call(this,"delete",this,a)},url:function(){var a=k(this.collection)||this.urlRoot||l();if(this.isNew())return a;return a+(a.charAt(a.length-1)=="/"?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this)},isNew:function(){return this.id==null},change:function(a){this.trigger("change",this,a);this._previousAttributes=f.clone(this.attributes);this._changed=!1},hasChanged:function(a){if(a)return this._previousAttributes[a]!=
14 | this.attributes[a];return this._changed},changedAttributes:function(a){a||(a=this.attributes);var b=this._previousAttributes,c=!1,d;for(d in a)f.isEqual(b[d],a[d])||(c=c||{},c[d]=a[d]);return c},previous:function(a){if(!a||!this._previousAttributes)return null;return this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},_performValidation:function(a,b){var c=this.validate(a);if(c)return b.error?b.error(this,c,b):this.trigger("error",this,c,b),!1;return!0}});
15 | e.Collection=function(a,b){b||(b={});if(b.comparator)this.comparator=b.comparator;f.bindAll(this,"_onModelEvent","_removeReference");this._reset();a&&this.reset(a,{silent:!0});this.initialize.apply(this,arguments)};f.extend(e.Collection.prototype,e.Events,{model:e.Model,initialize:function(){},toJSON:function(){return this.map(function(a){return a.toJSON()})},add:function(a,b){if(f.isArray(a))for(var c=0,d=a.length;c').hide().appendTo("body")[0].contentWindow,this.navigate(a);
25 | this._hasPushState?g(window).bind("popstate",this.checkUrl):"onhashchange"in window&&!b?g(window).bind("hashchange",this.checkUrl):setInterval(this.checkUrl,this.interval);this.fragment=a;m=!0;a=window.location;b=a.pathname==this.options.root;if(this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;else if(this._wantsPushState&&this._hasPushState&&b&&a.hash)this.fragment=a.hash.replace(j,""),window.history.replaceState({},
26 | document.title,a.protocol+"//"+a.host+this.options.root+this.fragment);if(!this.options.silent)return this.loadUrl()},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.iframe.location.hash));if(a==this.fragment||a==decodeURIComponent(this.fragment))return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(window.location.hash)},loadUrl:function(a){var b=this.fragment=this.getFragment(a);
27 | return f.any(this.handlers,function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){var c=(a||"").replace(j,"");if(!(this.fragment==c||this.fragment==decodeURIComponent(c))){if(this._hasPushState){var d=window.location;c.indexOf(this.options.root)!=0&&(c=this.options.root+c);this.fragment=c;window.history.pushState({},document.title,d.protocol+"//"+d.host+c)}else if(window.location.hash=this.fragment=c,this.iframe&&c!=this.getFragment(this.iframe.location.hash))this.iframe.document.open().close(),
28 | this.iframe.location.hash=c;b&&this.loadUrl(a)}}});e.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.delegateEvents();this.initialize.apply(this,arguments)};var u=/^(\S+)\s*(.*)$/,n=["model","collection","el","id","attributes","className","tagName"];f.extend(e.View.prototype,e.Events,{tagName:"div",$:function(a){return g(a,this.el)},initialize:function(){},render:function(){return this},remove:function(){g(this.el).remove();return this},make:function(a,
29 | b,c){a=document.createElement(a);b&&g(a).attr(b);c&&g(a).html(c);return a},delegateEvents:function(a){if(a||(a=this.events))for(var b in f.isFunction(a)&&(a=a.call(this)),g(this.el).unbind(".delegateEvents"+this.cid),a){var c=this[a[b]];if(!c)throw Error('Event "'+a[b]+'" does not exist');var d=b.match(u),e=d[1];d=d[2];c=f.bind(c,this);e+=".delegateEvents"+this.cid;d===""?g(this.el).bind(e,c):g(this.el).delegate(d,e,c)}},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=
30 | 0,c=n.length;bShow All');
260 |
261 | if (results.length === 0) {
262 | alert('No results found');
263 | } else {
264 | for (var i = 0; i < results.length; i++) {
265 | var d = new Document(results[i]);
266 | appView.documentList.addDocument(d);
267 | }
268 | }
269 | }, 'json');
270 | }
271 | });
272 |
273 | AppView = Backbone.View.extend({
274 | initialize: function() {
275 | this.documentList = new DocumentList();
276 | this.searchView = new SearchView();
277 | this.toolbar = new ListToolBar();
278 | this.documentControls = new DocumentControls();
279 | }
280 | });
281 |
282 | var appView = new AppView();
283 | window.Documents = Documents;
284 | window.appView = appView;
285 |
286 | $('#logout').click(function(e) {
287 | e.preventDefault();
288 | if (confirm('Are you sure you want to log out?')) {
289 | var element = $(this),
290 | form = $('');
291 | form
292 | .attr({
293 | method: 'POST',
294 | action: '/sessions'
295 | })
296 | .hide()
297 | .append('')
298 | .find('input')
299 | .attr({
300 | 'name': '_method',
301 | 'value': 'delete'
302 | })
303 | .end()
304 | .appendTo('body')
305 | .submit();
306 | }
307 | });
308 | })();
309 |
--------------------------------------------------------------------------------
/public/javascripts/flash.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | function hideFlashMessages() {
3 | $(this).fadeOut();
4 | }
5 |
6 | setTimeout(function() {
7 | $('.flash').each(hideFlashMessages);
8 | }, 5000);
9 | $('.flash').click(hideFlashMessages);
10 | })();
11 |
--------------------------------------------------------------------------------
/public/javascripts/json.js:
--------------------------------------------------------------------------------
1 | /*
2 | http://www.JSON.org/json2.js
3 | 2010-03-20
4 |
5 | Public Domain.
6 |
7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 |
9 | See http://www.JSON.org/js.html
10 |
11 |
12 | This code should be minified before deployment.
13 | See http://javascript.crockford.com/jsmin.html
14 |
15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
16 | NOT CONTROL.
17 |
18 |
19 | This file creates a global JSON object containing two methods: stringify
20 | and parse.
21 |
22 | JSON.stringify(value, replacer, space)
23 | value any JavaScript value, usually an object or array.
24 |
25 | replacer an optional parameter that determines how object
26 | values are stringified for objects. It can be a
27 | function or an array of strings.
28 |
29 | space an optional parameter that specifies the indentation
30 | of nested structures. If it is omitted, the text will
31 | be packed without extra whitespace. If it is a number,
32 | it will specify the number of spaces to indent at each
33 | level. If it is a string (such as '\t' or ' '),
34 | it contains the characters used to indent at each level.
35 |
36 | This method produces a JSON text from a JavaScript value.
37 |
38 | When an object value is found, if the object contains a toJSON
39 | method, its toJSON method will be called and the result will be
40 | stringified. A toJSON method does not serialize: it returns the
41 | value represented by the name/value pair that should be serialized,
42 | or undefined if nothing should be serialized. The toJSON method
43 | will be passed the key associated with the value, and this will be
44 | bound to the value
45 |
46 | For example, this would serialize Dates as ISO strings.
47 |
48 | Date.prototype.toJSON = function (key) {
49 | function f(n) {
50 | // Format integers to have at least two digits.
51 | return n < 10 ? '0' + n : n;
52 | }
53 |
54 | return this.getUTCFullYear() + '-' +
55 | f(this.getUTCMonth() + 1) + '-' +
56 | f(this.getUTCDate()) + 'T' +
57 | f(this.getUTCHours()) + ':' +
58 | f(this.getUTCMinutes()) + ':' +
59 | f(this.getUTCSeconds()) + 'Z';
60 | };
61 |
62 | You can provide an optional replacer method. It will be passed the
63 | key and value of each member, with this bound to the containing
64 | object. The value that is returned from your method will be
65 | serialized. If your method returns undefined, then the member will
66 | be excluded from the serialization.
67 |
68 | If the replacer parameter is an array of strings, then it will be
69 | used to select the members to be serialized. It filters the results
70 | such that only members with keys listed in the replacer array are
71 | stringified.
72 |
73 | Values that do not have JSON representations, such as undefined or
74 | functions, will not be serialized. Such values in objects will be
75 | dropped; in arrays they will be replaced with null. You can use
76 | a replacer function to replace those with JSON values.
77 | JSON.stringify(undefined) returns undefined.
78 |
79 | The optional space parameter produces a stringification of the
80 | value that is filled with line breaks and indentation to make it
81 | easier to read.
82 |
83 | If the space parameter is a non-empty string, then that string will
84 | be used for indentation. If the space parameter is a number, then
85 | the indentation will be that many spaces.
86 |
87 | Example:
88 |
89 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
90 | // text is '["e",{"pluribus":"unum"}]'
91 |
92 |
93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
95 |
96 | text = JSON.stringify([new Date()], function (key, value) {
97 | return this[key] instanceof Date ?
98 | 'Date(' + this[key] + ')' : value;
99 | });
100 | // text is '["Date(---current time---)"]'
101 |
102 |
103 | JSON.parse(text, reviver)
104 | This method parses a JSON text to produce an object or array.
105 | It can throw a SyntaxError exception.
106 |
107 | The optional reviver parameter is a function that can filter and
108 | transform the results. It receives each of the keys and values,
109 | and its return value is used instead of the original value.
110 | If it returns what it received, then the structure is not modified.
111 | If it returns undefined then the member is deleted.
112 |
113 | Example:
114 |
115 | // Parse the text. Values that look like ISO date strings will
116 | // be converted to Date objects.
117 |
118 | myData = JSON.parse(text, function (key, value) {
119 | var a;
120 | if (typeof value === 'string') {
121 | a =
122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
123 | if (a) {
124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
125 | +a[5], +a[6]));
126 | }
127 | }
128 | return value;
129 | });
130 |
131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
132 | var d;
133 | if (typeof value === 'string' &&
134 | value.slice(0, 5) === 'Date(' &&
135 | value.slice(-1) === ')') {
136 | d = new Date(value.slice(5, -1));
137 | if (d) {
138 | return d;
139 | }
140 | }
141 | return value;
142 | });
143 |
144 |
145 | This is a reference implementation. You are free to copy, modify, or
146 | redistribute.
147 | */
148 |
149 | /*jslint evil: true, strict: false */
150 |
151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
154 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
155 | test, toJSON, toString, valueOf
156 | */
157 |
158 |
159 | // Create a JSON object only if one does not already exist. We create the
160 | // methods in a closure to avoid creating global variables.
161 |
162 | if (!this.JSON) {
163 | this.JSON = {};
164 | }
165 |
166 | (function () {
167 |
168 | function f(n) {
169 | // Format integers to have at least two digits.
170 | return n < 10 ? '0' + n : n;
171 | }
172 |
173 | if (typeof Date.prototype.toJSON !== 'function') {
174 |
175 | Date.prototype.toJSON = function (key) {
176 |
177 | return isFinite(this.valueOf()) ?
178 | this.getUTCFullYear() + '-' +
179 | f(this.getUTCMonth() + 1) + '-' +
180 | f(this.getUTCDate()) + 'T' +
181 | f(this.getUTCHours()) + ':' +
182 | f(this.getUTCMinutes()) + ':' +
183 | f(this.getUTCSeconds()) + 'Z' : null;
184 | };
185 |
186 | String.prototype.toJSON =
187 | Number.prototype.toJSON =
188 | Boolean.prototype.toJSON = function (key) {
189 | return this.valueOf();
190 | };
191 | }
192 |
193 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
194 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
195 | gap,
196 | indent,
197 | meta = { // table of character substitutions
198 | '\b': '\\b',
199 | '\t': '\\t',
200 | '\n': '\\n',
201 | '\f': '\\f',
202 | '\r': '\\r',
203 | '"' : '\\"',
204 | '\\': '\\\\'
205 | },
206 | rep;
207 |
208 |
209 | function quote(string) {
210 |
211 | // If the string contains no control characters, no quote characters, and no
212 | // backslash characters, then we can safely slap some quotes around it.
213 | // Otherwise we must also replace the offending characters with safe escape
214 | // sequences.
215 |
216 | escapable.lastIndex = 0;
217 | return escapable.test(string) ?
218 | '"' + string.replace(escapable, function (a) {
219 | var c = meta[a];
220 | return typeof c === 'string' ? c :
221 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
222 | }) + '"' :
223 | '"' + string + '"';
224 | }
225 |
226 |
227 | function str(key, holder) {
228 |
229 | // Produce a string from holder[key].
230 |
231 | var i, // The loop counter.
232 | k, // The member key.
233 | v, // The member value.
234 | length,
235 | mind = gap,
236 | partial,
237 | value = holder[key];
238 |
239 | // If the value has a toJSON method, call it to obtain a replacement value.
240 |
241 | if (value && typeof value === 'object' &&
242 | typeof value.toJSON === 'function') {
243 | value = value.toJSON(key);
244 | }
245 |
246 | // If we were called with a replacer function, then call the replacer to
247 | // obtain a replacement value.
248 |
249 | if (typeof rep === 'function') {
250 | value = rep.call(holder, key, value);
251 | }
252 |
253 | // What happens next depends on the value's type.
254 |
255 | switch (typeof value) {
256 | case 'string':
257 | return quote(value);
258 |
259 | case 'number':
260 |
261 | // JSON numbers must be finite. Encode non-finite numbers as null.
262 |
263 | return isFinite(value) ? String(value) : 'null';
264 |
265 | case 'boolean':
266 | case 'null':
267 |
268 | // If the value is a boolean or null, convert it to a string. Note:
269 | // typeof null does not produce 'null'. The case is included here in
270 | // the remote chance that this gets fixed someday.
271 |
272 | return String(value);
273 |
274 | // If the type is 'object', we might be dealing with an object or an array or
275 | // null.
276 |
277 | case 'object':
278 |
279 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
280 | // so watch out for that case.
281 |
282 | if (!value) {
283 | return 'null';
284 | }
285 |
286 | // Make an array to hold the partial results of stringifying this object value.
287 |
288 | gap += indent;
289 | partial = [];
290 |
291 | // Is the value an array?
292 |
293 | if (Object.prototype.toString.apply(value) === '[object Array]') {
294 |
295 | // The value is an array. Stringify every element. Use null as a placeholder
296 | // for non-JSON values.
297 |
298 | length = value.length;
299 | for (i = 0; i < length; i += 1) {
300 | partial[i] = str(i, value) || 'null';
301 | }
302 |
303 | // Join all of the elements together, separated with commas, and wrap them in
304 | // brackets.
305 |
306 | v = partial.length === 0 ? '[]' :
307 | gap ? '[\n' + gap +
308 | partial.join(',\n' + gap) + '\n' +
309 | mind + ']' :
310 | '[' + partial.join(',') + ']';
311 | gap = mind;
312 | return v;
313 | }
314 |
315 | // If the replacer is an array, use it to select the members to be stringified.
316 |
317 | if (rep && typeof rep === 'object') {
318 | length = rep.length;
319 | for (i = 0; i < length; i += 1) {
320 | k = rep[i];
321 | if (typeof k === 'string') {
322 | v = str(k, value);
323 | if (v) {
324 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
325 | }
326 | }
327 | }
328 | } else {
329 |
330 | // Otherwise, iterate through all of the keys in the object.
331 |
332 | for (k in value) {
333 | if (Object.hasOwnProperty.call(value, k)) {
334 | v = str(k, value);
335 | if (v) {
336 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
337 | }
338 | }
339 | }
340 | }
341 |
342 | // Join all of the member texts together, separated with commas,
343 | // and wrap them in braces.
344 |
345 | v = partial.length === 0 ? '{}' :
346 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
347 | mind + '}' : '{' + partial.join(',') + '}';
348 | gap = mind;
349 | return v;
350 | }
351 | }
352 |
353 | // If the JSON object does not yet have a stringify method, give it one.
354 |
355 | if (typeof JSON.stringify !== 'function') {
356 | JSON.stringify = function (value, replacer, space) {
357 |
358 | // The stringify method takes a value and an optional replacer, and an optional
359 | // space parameter, and returns a JSON text. The replacer can be a function
360 | // that can replace values, or an array of strings that will select the keys.
361 | // A default replacer method can be provided. Use of the space parameter can
362 | // produce text that is more easily readable.
363 |
364 | var i;
365 | gap = '';
366 | indent = '';
367 |
368 | // If the space parameter is a number, make an indent string containing that
369 | // many spaces.
370 |
371 | if (typeof space === 'number') {
372 | for (i = 0; i < space; i += 1) {
373 | indent += ' ';
374 | }
375 |
376 | // If the space parameter is a string, it will be used as the indent string.
377 |
378 | } else if (typeof space === 'string') {
379 | indent = space;
380 | }
381 |
382 | // If there is a replacer, it must be a function or an array.
383 | // Otherwise, throw an error.
384 |
385 | rep = replacer;
386 | if (replacer && typeof replacer !== 'function' &&
387 | (typeof replacer !== 'object' ||
388 | typeof replacer.length !== 'number')) {
389 | throw new Error('JSON.stringify');
390 | }
391 |
392 | // Make a fake root object containing our value under the key of ''.
393 | // Return the result of stringifying the value.
394 |
395 | return str('', {'': value});
396 | };
397 | }
398 |
399 |
400 | // If the JSON object does not yet have a parse method, give it one.
401 |
402 | if (typeof JSON.parse !== 'function') {
403 | JSON.parse = function (text, reviver) {
404 |
405 | // The parse method takes a text and an optional reviver function, and returns
406 | // a JavaScript value if the text is a valid JSON text.
407 |
408 | var j;
409 |
410 | function walk(holder, key) {
411 |
412 | // The walk method is used to recursively walk the resulting structure so
413 | // that modifications can be made.
414 |
415 | var k, v, value = holder[key];
416 | if (value && typeof value === 'object') {
417 | for (k in value) {
418 | if (Object.hasOwnProperty.call(value, k)) {
419 | v = walk(value, k);
420 | if (v !== undefined) {
421 | value[k] = v;
422 | } else {
423 | delete value[k];
424 | }
425 | }
426 | }
427 | }
428 | return reviver.call(holder, key, value);
429 | }
430 |
431 |
432 | // Parsing happens in four stages. In the first stage, we replace certain
433 | // Unicode characters with escape sequences. JavaScript handles many characters
434 | // incorrectly, either silently deleting them, or treating them as line endings.
435 |
436 | text = String(text);
437 | cx.lastIndex = 0;
438 | if (cx.test(text)) {
439 | text = text.replace(cx, function (a) {
440 | return '\\u' +
441 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
442 | });
443 | }
444 |
445 | // In the second stage, we run the text against regular expressions that look
446 | // for non-JSON patterns. We are especially concerned with '()' and 'new'
447 | // because they can cause invocation, and '=' because it can cause mutation.
448 | // But just to be safe, we want to reject all unexpected forms.
449 |
450 | // We split the second stage into 4 regexp operations in order to work around
451 | // crippling inefficiencies in IE's and Safari's regexp engines. First we
452 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
453 | // replace all simple value tokens with ']' characters. Third, we delete all
454 | // open brackets that follow a colon or comma or that begin the text. Finally,
455 | // we look to see that the remaining characters are only whitespace or ']' or
456 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
457 |
458 | if (/^[\],:{}\s]*$/.
459 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
460 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
461 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
462 |
463 | // In the third stage we use the eval function to compile the text into a
464 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
465 | // in JavaScript: it can begin a block or an object literal. We wrap the text
466 | // in parens to eliminate the ambiguity.
467 |
468 | j = eval('(' + text + ')');
469 |
470 | // In the optional fourth stage, we recursively walk the new structure, passing
471 | // each name/value pair to a reviver function for possible transformation.
472 |
473 | return typeof reviver === 'function' ?
474 | walk({'': j}, '') : j;
475 | }
476 |
477 | // If the text is not JSON parseable, then a SyntaxError is thrown.
478 |
479 | throw new SyntaxError('JSON.parse');
480 | };
481 | }
482 | }());
483 |
--------------------------------------------------------------------------------
/public/javascripts/resize.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | // Correct widths and heights based on window size
3 | function resize() {
4 | var height = $(window).height() - $('#header').height() - 1,
5 | width = $('.content').width(),
6 | ov = $('.outline-view'),
7 | ed = $('#editor'),
8 | toolbar = $('.toolbar'),
9 | divider = $('.content-divider'),
10 | content = $('.content'),
11 | controls = $('#controls');
12 |
13 | $('#DocumentTitles').css({ height: height - toolbar.height() + 'px' });
14 | ov.css({ height: height + 'px' });
15 | toolbar.css({ width: ov.width() + 'px' });
16 |
17 | content.css({
18 | height: height - controls.height() + 'px',
19 | width: $('body').width() - ov.width() - divider.width() - 1 + 'px'
20 | });
21 |
22 | divider.css({ height: height + 'px' });
23 |
24 | ed.css({
25 | width: content.width() + 'px',
26 | height: content.height() - 22 - $('input.title').height() + 'px'
27 | }).focus();
28 |
29 | $('#controls').css({
30 | width: content.width() + 'px'
31 | });
32 | }
33 |
34 | $(window).resize(resize);
35 | $(window).focus(resize);
36 | resize();
37 | })();
38 |
39 |
--------------------------------------------------------------------------------
/public/javascripts/underscore-min.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.1.5
2 | // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){var q=this,D=q._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,E=k.unshift,F=o.toString,m=o.hasOwnProperty,s=k.forEach,t=k.map,u=k.reduce,v=k.reduceRight,w=k.filter,x=k.every,y=k.some,p=k.indexOf,z=k.lastIndexOf;o=Array.isArray;var G=Object.keys,A=Function.prototype.bind,c=function(a){return new l(a)};if(typeof module!=="undefined"&&module.exports){module.exports=c;c._=c}else q._=c;c.VERSION="1.1.5";var j=c.each=c.forEach=function(a,b,d){if(a!=null)if(s&&a.forEach===s)a.forEach(b,
9 | d);else if(c.isNumber(a.length))for(var e=0,f=a.length;e=e.computed&&(e={value:f,computed:g})});return e.value};c.min=function(a,b,d){if(!b&&c.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};j(a,function(f,g,h){g=b?b.call(d,f,g,h):f;gh?1:0}),"value")};c.sortedIndex=
14 | function(a,b,d){d=d||c.identity;for(var e=0,f=a.length;e>1;d(a[g])=0})})};c.zip=function(){for(var a=i.call(arguments),b=c.max(c.pluck(a,"length")),d=Array(b),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};c.keys=G||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)if(m.call(a,
20 | d))b[b.length]=d;return b};c.values=function(a){return c.map(a,c.identity)};c.functions=c.methods=function(a){return c.filter(c.keys(a),function(b){return c.isFunction(a[b])}).sort()};c.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};c.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)if(a[d]==null)a[d]=b[d]});return a};c.clone=function(a){return c.isArray(a)?a.slice():c.extend({},a)};c.tap=function(a,b){b(a);return a};c.isEqual=function(a,
21 | b){if(a===b)return true;var d=typeof a;if(d!=typeof b)return false;if(a==b)return true;if(!a&&b||a&&!b)return false;if(a._chain)a=a._wrapped;if(b._chain)b=b._wrapped;if(a.isEqual)return a.isEqual(b);if(c.isDate(a)&&c.isDate(b))return a.getTime()===b.getTime();if(c.isNaN(a)&&c.isNaN(b))return false;if(c.isRegExp(a)&&c.isRegExp(b))return a.source===b.source&&a.global===b.global&&a.ignoreCase===b.ignoreCase&&a.multiline===b.multiline;if(d!=="object")return false;if(a.length&&a.length!==b.length)return false;
22 | d=c.keys(a);var e=c.keys(b);if(d.length!=e.length)return false;for(var f in a)if(!(f in b)||!c.isEqual(a[f],b[f]))return false;return true};c.isEmpty=function(a){if(c.isArray(a)||c.isString(a))return a.length===0;for(var b in a)if(m.call(a,b))return false;return true};c.isElement=function(a){return!!(a&&a.nodeType==1)};c.isArray=o||function(a){return F.call(a)==="[object Array]"};c.isArguments=function(a){return!!(a&&m.call(a,"callee"))};c.isFunction=function(a){return!!(a&&a.constructor&&a.call&&
23 | a.apply)};c.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};c.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};c.isNaN=function(a){return a!==a};c.isBoolean=function(a){return a===true||a===false};c.isDate=function(a){return!!(a&&a.getTimezoneOffset&&a.setUTCFullYear)};c.isRegExp=function(a){return!!(a&&a.test&&a.exec&&(a.ignoreCase||a.ignoreCase===false))};c.isNull=function(a){return a===null};c.isUndefined=function(a){return a===void 0};c.noConflict=function(){q._=
24 | D;return this};c.identity=function(a){return a};c.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};c.template=function(a,b){var d=c.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,
25 | function(e,f){return"',"+f.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(e,f){return"');"+f.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return b?d(b):d};var l=function(a){this._wrapped=a};c.prototype=l.prototype;var r=function(a,b){return b?c(a).chain():a},I=function(a,b){l.prototype[a]=function(){var d=i.call(arguments);E.call(d,this._wrapped);return r(b.apply(c,
26 | d),this._chain)}};c.mixin(c);j(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=k[a];l.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];l.prototype[a]=function(){return r(b.apply(this._wrapped,arguments),this._chain)}});l.prototype.chain=function(){this._chain=true;return this};l.prototype.value=function(){return this._wrapped}})();
27 |
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/button_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/button_bg.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/datepicker.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/datepicker.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/icon_sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/icon_sprite.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/progress_bar.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/progress_bar.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/slider_h_bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/slider_h_bg.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/slider_handles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/slider_handles.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/slider_v_bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/slider_v_bg.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/tab_bg.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/tab_bg.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/the_gradient.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/the_gradient.gif
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_diagonals-thick_18_b81900_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_diagonals-thick_18_b81900_40x40.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_diagonals-thick_20_666666_40x40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_diagonals-thick_20_666666_40x40.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_flat_10_000000_40x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_flat_10_000000_40x100.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_glass_100_f6f6f6_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_glass_100_f6f6f6_1x400.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_glass_100_fdf5ce_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_glass_100_fdf5ce_1x400.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_glass_65_ffffff_1x400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_glass_65_ffffff_1x400.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_gloss-wave_35_f6a828_500x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_gloss-wave_35_f6a828_500x100.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_highlight-soft_100_eeeeee_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_highlight-soft_100_eeeeee_1x100.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-bg_highlight-soft_75_ffe45c_1x100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-bg_highlight-soft_75_ffe45c_1x100.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-icons_222222_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-icons_222222_256x240.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-icons_228ef1_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-icons_228ef1_256x240.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-icons_ef8c08_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-icons_ef8c08_256x240.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-icons_ffd27a_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-icons_ffd27a_256x240.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/images/ui-icons_ffffff_256x240.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexyoung/nodepad/68357e774e2c971b39f9dec343a5c1c763d76401/public/stylesheets/aristo/images/ui-icons_ffffff_256x240.png
--------------------------------------------------------------------------------
/public/stylesheets/aristo/jquery-ui-1.8.5.custom.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Aristo for jQuery UI
3 | * Licensed under Creative Commons Attribution-Share Alike 3.0 with permission from 280 North and Pinvoke.
4 | */
5 |
6 | /*
7 | * jQuery UI CSS Framework @VERSION
8 | *
9 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
10 | * Dual licensed under the MIT or GPL Version 2 licenses.
11 | * http://jquery.org/license
12 | *
13 | * http://docs.jquery.com/UI/Theming/API
14 | */
15 |
16 | /* Layout helpers
17 | ----------------------------------*/
18 | .ui-helper-hidden { display: none; }
19 | .ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
20 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
21 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
22 | .ui-helper-clearfix { display: inline-block; }
23 | /* required comment for clearfix to work in Opera \*/
24 | * html .ui-helper-clearfix { height:1%; }
25 | .ui-helper-clearfix { display:block; }
26 | /* end clearfix */
27 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
28 |
29 |
30 | /* Interaction Cues
31 | ----------------------------------*/
32 | .ui-state-disabled { cursor: default !important; }
33 |
34 |
35 | /* Icons
36 | ----------------------------------*/
37 |
38 | /* states and images */
39 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
40 |
41 |
42 | /* Misc visuals
43 | ----------------------------------*/
44 |
45 | /* Overlays */
46 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
47 |
48 |
49 | /*
50 | * jQuery UI CSS Framework @VERSION
51 | *
52 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
53 | * Dual licensed under the MIT or GPL Version 2 licenses.
54 | * http://jquery.org/license
55 | *
56 | * http://docs.jquery.com/UI/Theming/API
57 | *
58 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller
59 | */
60 |
61 |
62 | /* Component containers
63 | ----------------------------------*/
64 | .ui-widget { font-family: Helvetica, Arial, sans-serif; outline: none;}
65 | .ui-widget a { outline: none; }
66 | .ui-widget .ui-widget { font-size: 1em; }
67 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Helvetica, Arial, sans-serif; font-size: 1em; }
68 | .ui-widget-content { border: 1px solid #dddddd; color: #333333; background: #FFFFFF; }
69 | .ui-widget-content a { color: #333333; }
70 | .ui-widget-header { border: 1px solid #8ab0c6; background: #a7cfe6; color: #ffffff; font-weight: bold; }
71 | .ui-widget-header a { color: #ffffff; }
72 |
73 | /* Interaction states
74 | ----------------------------------*/
75 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #5F83B9; }
76 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
77 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus { border: 1px solid #749aaf; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
78 | .ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
79 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
80 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
81 | .ui-widget :active { outline: none; }
82 |
83 | /* Interaction Cues
84 | ----------------------------------*/
85 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #d2dbf4; background: #f4f8fd; color: #0d2054; -moz-border-radius: 0px !important; -webkit-border-radius: 0px !important; border-radius: 0px !important; font-size: 11px; }
86 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #0d2054; }
87 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #e2d0d0; background: #fcf0f0; color: #280b0b; -moz-border-radius: 0px !important; -webkit-border-radius: 0px !important; border-radius: 0px !important; font-size: 11px; }
88 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #280b0b; }
89 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #280b0b; }
90 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
91 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
92 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
93 | .ui-state-highlight p, .ui-state-error p { margin: 8px 0px; padding: 1px 0px; }
94 | .ui-state-highlight .ui-icon, .ui-state-error .ui-icon { margin: -1px 8px 0px 0px !important; }
95 |
96 | /* Icons
97 | ----------------------------------*/
98 |
99 | /* states and images */
100 | .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
101 | .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
102 | .ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
103 | .ui-state-default .ui-icon { background-image: url(images/ui-icons_222222_256x240.png); }
104 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
105 | .ui-state-active .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
106 | .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
107 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon { background: url(images/icon_sprite.png) -16px 0px no-repeat !important; }
108 |
109 | /* positioning */
110 | .ui-icon-carat-1-n { background-position: 0 0; }
111 | .ui-icon-carat-1-ne { background-position: -16px 0; }
112 | .ui-icon-carat-1-e { background-position: -32px 0; }
113 | .ui-icon-carat-1-se { background-position: -48px 0; }
114 | .ui-icon-carat-1-s { background-position: -64px 0; }
115 | .ui-icon-carat-1-sw { background-position: -80px 0; }
116 | .ui-icon-carat-1-w { background-position: -96px 0; }
117 | .ui-icon-carat-1-nw { background-position: -112px 0; }
118 | .ui-icon-carat-2-n-s { background-position: -128px 0; }
119 | .ui-icon-carat-2-e-w { background-position: -144px 0; }
120 | .ui-icon-triangle-1-n { background-position: 0 -16px; }
121 | .ui-icon-triangle-1-ne { background-position: -16px -16px; }
122 | .ui-icon-triangle-1-e { background-position: -32px -16px; }
123 | .ui-icon-triangle-1-se { background-position: -48px -16px; }
124 | .ui-icon-triangle-1-s { background-position: -64px -16px; }
125 | .ui-icon-triangle-1-sw { background-position: -80px -16px; }
126 | .ui-icon-triangle-1-w { background-position: -96px -16px; }
127 | .ui-icon-triangle-1-nw { background-position: -112px -16px; }
128 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
129 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
130 | .ui-icon-arrow-1-n { background-position: 0 -32px; }
131 | .ui-icon-arrow-1-ne { background-position: -16px -32px; }
132 | .ui-icon-arrow-1-e { background-position: -32px -32px; }
133 | .ui-icon-arrow-1-se { background-position: -48px -32px; }
134 | .ui-icon-arrow-1-s { background-position: -64px -32px; }
135 | .ui-icon-arrow-1-sw { background-position: -80px -32px; }
136 | .ui-icon-arrow-1-w { background-position: -96px -32px; }
137 | .ui-icon-arrow-1-nw { background-position: -112px -32px; }
138 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
139 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
140 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
141 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
142 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
143 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
144 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
145 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
146 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
147 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
148 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
149 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
150 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
151 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
152 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
153 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
154 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
155 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
156 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
157 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
158 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
159 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
160 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
161 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
162 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
163 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
164 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
165 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
166 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
167 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
168 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
169 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
170 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
171 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
172 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
173 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
174 | .ui-icon-arrow-4 { background-position: 0 -80px; }
175 | .ui-icon-arrow-4-diag { background-position: -16px -80px; }
176 | .ui-icon-extlink { background-position: -32px -80px; }
177 | .ui-icon-newwin { background-position: -48px -80px; }
178 | .ui-icon-refresh { background-position: -64px -80px; }
179 | .ui-icon-shuffle { background-position: -80px -80px; }
180 | .ui-icon-transfer-e-w { background-position: -96px -80px; }
181 | .ui-icon-transferthick-e-w { background-position: -112px -80px; }
182 | .ui-icon-folder-collapsed { background-position: 0 -96px; }
183 | .ui-icon-folder-open { background-position: -16px -96px; }
184 | .ui-icon-document { background-position: -32px -96px; }
185 | .ui-icon-document-b { background-position: -48px -96px; }
186 | .ui-icon-note { background-position: -64px -96px; }
187 | .ui-icon-mail-closed { background-position: -80px -96px; }
188 | .ui-icon-mail-open { background-position: -96px -96px; }
189 | .ui-icon-suitcase { background-position: -112px -96px; }
190 | .ui-icon-comment { background-position: -128px -96px; }
191 | .ui-icon-person { background-position: -144px -96px; }
192 | .ui-icon-print { background-position: -160px -96px; }
193 | .ui-icon-trash { background-position: -176px -96px; }
194 | .ui-icon-locked { background-position: -192px -96px; }
195 | .ui-icon-unlocked { background-position: -208px -96px; }
196 | .ui-icon-bookmark { background-position: -224px -96px; }
197 | .ui-icon-tag { background-position: -240px -96px; }
198 | .ui-icon-home { background-position: 0 -112px; }
199 | .ui-icon-flag { background-position: -16px -112px; }
200 | .ui-icon-calendar { background-position: -32px -112px; }
201 | .ui-icon-cart { background-position: -48px -112px; }
202 | .ui-icon-pencil { background-position: -64px -112px; }
203 | .ui-icon-clock { background-position: -80px -112px; }
204 | .ui-icon-disk { background-position: -96px -112px; }
205 | .ui-icon-calculator { background-position: -112px -112px; }
206 | .ui-icon-zoomin { background-position: -128px -112px; }
207 | .ui-icon-zoomout { background-position: -144px -112px; }
208 | .ui-icon-search { background-position: -160px -112px; }
209 | .ui-icon-wrench { background-position: -176px -112px; }
210 | .ui-icon-gear { background-position: -192px -112px; }
211 | .ui-icon-heart { background-position: -208px -112px; }
212 | .ui-icon-star { background-position: -224px -112px; }
213 | .ui-icon-link { background-position: -240px -112px; }
214 | .ui-icon-cancel { background-position: 0 -128px; }
215 | .ui-icon-plus { background-position: -16px -128px; }
216 | .ui-icon-plusthick { background-position: -32px -128px; }
217 | .ui-icon-minus { background-position: -48px -128px; }
218 | .ui-icon-minusthick { background-position: -64px -128px; }
219 | .ui-icon-close { background-position: -80px -128px; }
220 | .ui-icon-closethick { background-position: -96px -128px; }
221 | .ui-icon-key { background-position: -112px -128px; }
222 | .ui-icon-lightbulb { background-position: -128px -128px; }
223 | .ui-icon-scissors { background-position: -144px -128px; }
224 | .ui-icon-clipboard { background-position: -160px -128px; }
225 | .ui-icon-copy { background-position: -176px -128px; }
226 | .ui-icon-contact { background-position: -192px -128px; }
227 | .ui-icon-image { background-position: -208px -128px; }
228 | .ui-icon-video { background-position: -224px -128px; }
229 | .ui-icon-script { background-position: -240px -128px; }
230 | .ui-icon-alert { background-position: 0 -144px; }
231 | .ui-icon-info { background: url(images/icon_sprite.png) 0px 0px no-repeat !important; }
232 | .ui-icon-notice { background-position: -32px -144px; }
233 | .ui-icon-help { background-position: -48px -144px; }
234 | .ui-icon-check { background-position: -64px -144px; }
235 | .ui-icon-bullet { background-position: -80px -144px; }
236 | .ui-icon-radio-off { background-position: -96px -144px; }
237 | .ui-icon-radio-on { background-position: -112px -144px; }
238 | .ui-icon-pin-w { background-position: -128px -144px; }
239 | .ui-icon-pin-s { background-position: -144px -144px; }
240 | .ui-icon-play { background-position: 0 -160px; }
241 | .ui-icon-pause { background-position: -16px -160px; }
242 | .ui-icon-seek-next { background-position: -32px -160px; }
243 | .ui-icon-seek-prev { background-position: -48px -160px; }
244 | .ui-icon-seek-end { background-position: -64px -160px; }
245 | .ui-icon-seek-start { background-position: -80px -160px; }
246 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
247 | .ui-icon-seek-first { background-position: -80px -160px; }
248 | .ui-icon-stop { background-position: -96px -160px; }
249 | .ui-icon-eject { background-position: -112px -160px; }
250 | .ui-icon-volume-off { background-position: -128px -160px; }
251 | .ui-icon-volume-on { background-position: -144px -160px; }
252 | .ui-icon-power { background-position: 0 -176px; }
253 | .ui-icon-signal-diag { background-position: -16px -176px; }
254 | .ui-icon-signal { background-position: -32px -176px; }
255 | .ui-icon-battery-0 { background-position: -48px -176px; }
256 | .ui-icon-battery-1 { background-position: -64px -176px; }
257 | .ui-icon-battery-2 { background-position: -80px -176px; }
258 | .ui-icon-battery-3 { background-position: -96px -176px; }
259 | .ui-icon-circle-plus { background-position: 0 -192px; }
260 | .ui-icon-circle-minus { background-position: -16px -192px; }
261 | .ui-icon-circle-close { background-position: -32px -192px; }
262 | .ui-icon-circle-triangle-e { background-position: -48px -192px; }
263 | .ui-icon-circle-triangle-s { background-position: -64px -192px; }
264 | .ui-icon-circle-triangle-w { background-position: -80px -192px; }
265 | .ui-icon-circle-triangle-n { background-position: -96px -192px; }
266 | .ui-icon-circle-arrow-e { background-position: -112px -192px; }
267 | .ui-icon-circle-arrow-s { background-position: -128px -192px; }
268 | .ui-icon-circle-arrow-w { background-position: -144px -192px; }
269 | .ui-icon-circle-arrow-n { background-position: -160px -192px; }
270 | .ui-icon-circle-zoomin { background-position: -176px -192px; }
271 | .ui-icon-circle-zoomout { background-position: -192px -192px; }
272 | .ui-icon-circle-check { background-position: -208px -192px; }
273 | .ui-icon-circlesmall-plus { background-position: 0 -208px; }
274 | .ui-icon-circlesmall-minus { background-position: -16px -208px; }
275 | .ui-icon-circlesmall-close { background-position: -32px -208px; }
276 | .ui-icon-squaresmall-plus { background-position: -48px -208px; }
277 | .ui-icon-squaresmall-minus { background-position: -64px -208px; }
278 | .ui-icon-squaresmall-close { background-position: -80px -208px; }
279 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
280 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
281 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
282 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
283 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
284 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
285 |
286 |
287 | /* Misc visuals
288 | ----------------------------------*/
289 |
290 | /* Corner radius */
291 | .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
292 | .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
293 | .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
294 | .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
295 | .ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
296 | .ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
297 | .ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
298 | .ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
299 | .ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
300 |
301 | /* Overlays */
302 | .ui-widget-overlay { background: #222d3f; opacity: .70; filter:Alpha(Opacity=70); }
303 | .ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
304 |
305 | /*
306 | * jQuery UI Resizable @VERSION
307 | *
308 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
309 | * Dual licensed under the MIT or GPL Version 2 licenses.
310 | * http://jquery.org/license
311 | *
312 | * http://docs.jquery.com/UI/Resizable#theming
313 | */
314 | .ui-resizable { position: relative;}
315 | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
316 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
317 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
318 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
319 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
320 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
321 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
322 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
323 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
324 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
325 |
326 | /*
327 | * jQuery UI Selectable @VERSION
328 | *
329 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
330 | * Dual licensed under the MIT or GPL Version 2 licenses.
331 | * http://jquery.org/license
332 | *
333 | * http://docs.jquery.com/UI/Selectable#theming
334 | */
335 | .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
336 | /*
337 | * jQuery UI Accordion @VERSION
338 | *
339 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
340 | * Dual licensed under the MIT or GPL Version 2 licenses.
341 | * http://jquery.org/license
342 | *
343 | * http://docs.jquery.com/UI/Accordion#theming
344 | */
345 | /* IE/Win - Fix animation bug - #4615 */
346 | .ui-accordion { width: 100%; }
347 | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; background: url(images/button_bg.png) repeat-x; }
348 | .ui-accordion .ui-accordion-header .ui-state-default { background-position: 0px 0px; }
349 | .ui-accordion .ui-accordion-header.ui-state-active { background-position: 0px -33px; border-color: #749aaf !important; }
350 | .ui-accordion .ui-accordion-header.ui-state-hover, .ui-accordion h3.ui-state-default { border-color: #aaaaaa; }
351 | .ui-accordion .ui-accordion-header.ui-state-active a { color:#1c4257; }
352 | .ui-accordion .ui-accordion-header .ui-icon { background: url(images/icon_sprite.png); }
353 | .ui-accordion .ui-accordion-header.ui-state-active .ui-icon { background-position: 0px -64px; }
354 | .ui-accordion .ui-accordion-header.ui-state-default .ui-icon { background-position: -16px -80px; }
355 | .ui-accordion .ui-accordion-li-fix { display: inline; }
356 | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
357 | .ui-accordion .ui-accordion-header a { display: block; font-size: 12px; padding: .5em .5em .5em .7em; font-weight: bold; color:#4f4f4f; text-shadow: 0px 1px 0px rgba(255,255,255,0.7); }
358 | .ui-accordion-icons .ui-accordion-header a { padding-left: 24px; }
359 | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -7px; }
360 | .ui-accordion .ui-accordion-content { background: #f8fcfe; padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; font-size: 11px; border-color: #749aaf; }
361 | .ui-accordion .ui-accordion-content-active { display: block; }
362 | .ui-accordion .ui-accordion-header, .ui-accordion .ui-accordion-content { -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }
363 | .ui-accordion .ui-state-active { }
364 |
365 | /*
366 | * jQuery UI Autocomplete @VERSION
367 | *
368 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
369 | * Dual licensed under the MIT or GPL Version 2 licenses.
370 | * http://jquery.org/license
371 | *
372 | * http://docs.jquery.com/UI/Autocomplete#theming
373 | */
374 | .ui-autocomplete { position: absolute; z-index: 2 !important; cursor: default; background: #FFFFFF; border: 0px none !important; padding: 0px !important; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); }
375 | .ui-autocomplete-loading { background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat; }
376 | /* workarounds */
377 | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
378 |
379 | /*
380 | * jQuery UI Menu @VERSION
381 | *
382 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
383 | * Dual licensed under the MIT or GPL Version 2 licenses.
384 | * http://jquery.org/license
385 | *
386 | * http://docs.jquery.com/UI/Menu#theming
387 | */
388 | .ui-menu {
389 | list-style:none;
390 | padding: 2px;
391 | margin: 0;
392 | display:block;
393 | float: left;
394 | }
395 | .ui-menu .ui-menu {
396 | margin-top: -3px;
397 | }
398 | .ui-menu .ui-menu-item {
399 | margin:0;
400 | padding: 0;
401 | zoom: 1;
402 | float: left;
403 | clear: left;
404 | width: 100%;
405 | }
406 | .ui-menu .ui-menu-item a {
407 | text-decoration:none;
408 | display:block;
409 | border: 0px none;
410 | padding:.2em .4em;
411 | line-height:1.5;
412 | -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;
413 | zoom:1;
414 | }
415 | .ui-menu .ui-menu-item a.ui-state-hover,
416 | .ui-menu .ui-menu-item a.ui-state-active {
417 | background: #5f83b9;
418 | color: #FFFFFF;
419 | text-shadow: 0px 1px 1px #234386;
420 | font-weight: normal;
421 | margin: -1px;
422 | }
423 |
424 | /*
425 | * jQuery UI Button @VERSION
426 | *
427 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
428 | * Dual licensed under the MIT or GPL Version 2 licenses.
429 | * http://jquery.org/license
430 | *
431 | * http://docs.jquery.com/UI/Button#theming
432 | */
433 | .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; border: 0px none !important; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; } /* the overflow property removes extra width in IE */
434 | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
435 | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
436 | .ui-button-icons-only { width: 3em; }
437 | button.ui-button-icons-only { width: 3.2em; }
438 | .ui-button span { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; border: 1px solid; }
439 |
440 |
441 | /* === INPUT:SUBMIT BUG FIX === */
442 | input.ui-button { background: url(images/button_bg.png) 0px 0px repeat-x !important; color: #4f4f4f; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; border: 1px solid #b6b6b6; outline: none; }
443 | input.ui-button:hover { background: url(images/button_bg.png) 0px 0px repeat-x !important; color: #313131; border-color: #9d9d9d; -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.3); -webkit-box-shadow: 0px 0px 8px rgba(212,212,212,1); box-shadow: 0px 0px 8px rgba(212,212,212,1); }
444 | input.ui-button:active { background: url(images/button_bg.png) 0px bottom repeat-x !important; color: #4f4f4f; border-color: #b6b6b6; }
445 |
446 | /* === IE6 AND IE7 BUTTON WIDTH FIX === */
447 | .ui-button { *display: inline !important; }
448 |
449 | .ui-state-default .ui-button-text { background: url(images/button_bg.png) 0px 0px repeat-x !important; color: #4f4f4f; border-color: #b6b6b6; }
450 | .ui-state-hover .ui-button-text { background: url(images/button_bg.png) 0px 0px repeat-x !important; color: #313131; border-color: #9d9d9d; -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.3); -webkit-box-shadow: 0px 0px 8px rgba(212,212,212,1); box-shadow: 0px 0px 8px rgba(212,212,212,1); }
451 | .ui-state-active .ui-button-text { background: url(images/button_bg.png) 0px bottom repeat-x !important; color: #4f4f4f; border-color: #b6b6b6; }
452 |
453 | /*button text element */
454 | .ui-button .ui-button-text { display: block; line-height: 1.4; font-weight: bold; font-size: 14px; text-shadow: 0px 1px 0px rgba(255,255,255,0.8); }
455 | .ui-button-text-only .ui-button-text { padding: 5px 12px; }
456 | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: 5px; text-indent: -9999999px; }
457 | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: 5px 12px 5px 25px; }
458 | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: 5px 12px 5px 25px;; }
459 | .ui-button-text-icons .ui-button-text { padding-right: 1.8em; }
460 | /* no icon support for input elements, provide padding by default */
461 | input.ui-button { padding: .4em 1em; }
462 |
463 | /*button icon element(s) */
464 | .ui-button .ui-icon { border: 0px none; }
465 | .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; margin-left: 6px; }
466 | .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
467 | .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { }
468 | .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
469 | .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
470 |
471 | /*button sets*/
472 | .ui-buttonset { margin-right: 7px; }
473 | .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
474 | .ui-buttonset, .ui-buttonset span { -moz-border-radius: 0px !important; -webkit-border-radius: 0px !important; border-radius: 0px !important; }
475 | .ui-corner-left .ui-button-text { -moz-border-radius-topleft: 4px !important; -webkit-border-top-left-radius: 4px !important; border-top-left-radius: 4px !important; -moz-border-radius-bottomleft: 4px !important; -webkit-border-bottom-left-radius: 4px !important; border-bottom-left-radius: 4px !important; }
476 | .ui-corner-right .ui-button-text { -moz-border-radius-topright: 4px !important; -webkit-border-top-right-radius: 4px !important; border-top-right-radius: 4px !important; -moz-border-radius-bottomright: 4px !important; -webkit-border-bottom-right-radius: 4px !important; border-bottom-right-radius: 4px !important; }
477 | .ui-buttonset .ui-state-active .ui-button-text { cursor: default; background: url(images/button_bg.png) 0px -33px repeat-x !important; color: #1c4257; border-color: #7096ab; -moz-box-shadow: none !important; -webkit-box-shadow: none !important; box-shadow: none !important; }
478 |
479 | /* workarounds */
480 | button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
481 |
482 | /*
483 | * jQuery UI Dialog @VERSION
484 | *
485 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
486 | * Dual licensed under the MIT or GPL Version 2 licenses.
487 | * http://jquery.org/license
488 | *
489 | * http://docs.jquery.com/UI/Dialog#theming
490 | */
491 | .ui-dialog { position: absolute; padding: 0; width: 300px; overflow: hidden; background: #FFFFFF; -moz-box-shadow: 0px 5px 8px rgba(0,0,0,0.8); -webkit-box-shadow: 0px 5px 8px rgba(0,0,0,0.8); box-shadow: 0px 5px 8px rgba(0,0,0,0.8); }
492 | .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; border-width: 0px 0px 1px 0px; border-color: #979797; background: url(images/the_gradient.gif) 0px 0px repeat-x; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }
493 | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; font-size: 13px; color: #000000; text-shadow: 0px 1px 0px rgba(255,255,255,0.8); }
494 | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: 6px; top: 50%; width: 16px; margin: -9px 0 0 0; height: 16px; }
495 | .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; background: url(images/icon_sprite.png) 0px -16px no-repeat; }
496 | .ui-dialog-titlebar .ui-state-hover { -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; border: 0px none; background: transparent; }
497 | .ui-dialog .ui-dialog-titlebar-close.ui-state-hover span { background-position: -16px -16px ; }
498 | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
499 | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; font-size: 12px; }
500 | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
501 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
502 | .ui-dialog .ui-dialog-buttonpane button { float: right; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; background: transparent !important; border: 0px none; }
503 | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
504 | .ui-draggable .ui-dialog-titlebar { cursor: move; }
505 |
506 | /*
507 | * jQuery UI Slider @VERSION
508 | *
509 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
510 | * Dual licensed under the MIT or GPL Version 2 licenses.
511 | * http://jquery.org/license
512 | *
513 | * http://docs.jquery.com/UI/Slider#theming
514 | */
515 | .ui-slider { position: relative; text-align: left; border: 0px none; }
516 | .ui-state-focus .ui-slider-handle { border: 0px none; }
517 | .ui-slider .ui-slider-handle { background: url(images/slider_handles.png) 0px -23px no-repeat; position: absolute; z-index: 2; width: 23px; height: 23px; cursor: pointer; }
518 | .ui-slider .ui-state-hover { background-position: 0px 0px !important; }
519 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; }
520 | .ui-slider .ui-state-default { border: 0px none; }
521 |
522 | .ui-slider-horizontal { height: 5px; background: url(images/slider_h_bg.gif) 0px 0px repeat-x;}
523 | .ui-slider-horizontal .ui-slider-handle { top: -9px; margin-left: -12px; }
524 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; background: url(images/slider_h_bg.gif) 0px -5px repeat-x; }
525 | .ui-slider-horizontal .ui-slider-range-min { left: 0; }
526 | .ui-slider-horizontal .ui-slider-range-max { right: 0; }
527 |
528 | .ui-slider-vertical { width: 5px; height: 100px; background: url(images/slider_v_bg.gif) -5px 0px repeat-y; }
529 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: -.6em; margin-bottom: -.6em; }
530 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; background: url(images/slider_v_bg.gif) 0px 0px repeat-y; }
531 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
532 | .ui-slider-vertical .ui-slider-range-max { top: 0; }
533 |
534 | /*
535 | * jQuery UI Tabs @VERSION
536 | *
537 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
538 | * Dual licensed under the MIT or GPL Version 2 licenses.
539 | * http://jquery.org/license
540 | *
541 | * http://docs.jquery.com/UI/Tabs#theming
542 | */
543 | .ui-tabs { background: #FFFFFF; position: relative; padding: .2em; zoom: 1; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; border: 0px none; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
544 | .ui-tabs .ui-tabs-nav { border-color: #a8a8a8; border-width: 0px 0px 1px 0px; margin: 0; padding: 0; background: transparent; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }
545 | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; }
546 | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; font-size: 12px; }
547 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
548 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
549 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
550 | .ui-tabs .ui-tabs-panel { display: block; border: 0; padding: 1em 1.4em; background: none; font-size: 12px; border-color: #a8a8a8; border-width: 0px 1px 1px 1px; border-style: solid; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px;}
551 | .ui-tabs .ui-tabs-hide { display: none !important; }
552 | .ui-tabs .ui-tabs-nav li.ui-state-default { background: #cccccc url(images/button_bg.png) 0px 0px repeat-x; border-color: #a8a8a8; }
553 | .ui-tabs .ui-tabs-nav li.ui-state-default a { color: #4f4f4f !important; text-shadow: 0px 1px 0px rgba(255,255,255,0.8); }
554 | .ui-tabs .ui-tabs-nav li.ui-state-active { background: #FFFFFF; }
555 | .ui-tabs-panel .ui-button { border-width: 0px; background: transparent; }
556 |
557 | /*
558 | * jQuery UI Datepicker @VERSION
559 | *
560 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
561 | * Dual licensed under the MIT or GPL Version 2 licenses.
562 | * http://jquery.org/license
563 | *
564 | * http://docs.jquery.com/UI/Datepicker#theming
565 | */
566 | .ui-datepicker { width: 17em; padding: .2em .2em 0; background: #FFFFFF url(images/datepicker.gif) left top repeat-x; -moz-box-shadow: 0px 5px 10px rgba(0,0,0,0.8); -webkit-box-shadow: 0px 5px 10px rgba(0,0,0,0.8); box-shadow: 0px 5px 10px rgba(0,0,0,0.8); }
567 | .ui-datepicker .ui-datepicker-header { position:relative; padding:2px 0px 6px 0px; background: transparent; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; border: 0px none; }
568 | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 6px; width: 16px; height: 16px; border: 0px none; cursor: pointer; }
569 | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
570 | .ui-datepicker .ui-datepicker-prev { left:2px; }
571 | .ui-datepicker .ui-datepicker-next { right:2px; }
572 | .ui-datepicker .ui-datepicker-header .ui-state-hover { background: transparent; border: 0px none; }
573 | .ui-datepicker .ui-datepicker-prev span { background-position: 0px -32px !important; }
574 | .ui-datepicker .ui-datepicker-next span { background-position: -16px -32px !important; }
575 | .ui-datepicker .ui-datepicker-prev-hover span { background-position: 0px -48px !important; }
576 | .ui-datepicker .ui-datepicker-next-hover span { background-position: -16px -48px !important; }
577 | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; background: url(images/icon_sprite.png) no-repeat; }
578 | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; font-size: 12px; color: #000000; text-shadow: 0px 1px 0px rgba(255,255,255,0.8); }
579 | .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
580 | .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
581 | .ui-datepicker select.ui-datepicker-month,
582 | .ui-datepicker select.ui-datepicker-year { width: 49%;}
583 | .ui-datepicker table {width: 100%; font-size: 10px; border-collapse: collapse; margin: 0 0 .4em; }
584 | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
585 | .ui-datepicker td { border: 0; padding: 1px; }
586 | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: 2px 3px 3px; text-align: right; text-decoration: none; }
587 | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
588 | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
589 | .ui-datepicker-buttonpane button { background: url(images/button_bg.png) 0px 0px repeat-x !important; color: #4f4f4f !important; border-color: #b6b6b6 !important; font-weight: bold !important; font-size: 12px; text-shadow: 0px 1px 0px rgba(255,255,255,0.8); }
590 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
591 | .ui-datepicker .ui-datepicker-calendar a { background: transparent; border: 0px none; }
592 | .ui-datepicker .ui-datepicker-calendar .ui-state-active { }
593 | .ui-datepicker .ui-datepicker-calendar a.ui-state-hover { color: #1c4257; }
594 | .ui-datepicker .ui-datepicker-current-day .ui-state-default { background: #5f83b9; color: #FFFFFF !important; text-shadow: 0px 1px 1px #234386; font-weight: bold; }
595 |
596 | /* with multiple calendars */
597 | .ui-datepicker.ui-datepicker-multi { width:auto; }
598 | .ui-datepicker-multi .ui-datepicker-group { float:left; }
599 | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
600 | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
601 | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
602 | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
603 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
604 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
605 | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
606 | .ui-datepicker-row-break { clear:both; width:100%; }
607 |
608 | /* RTL support */
609 | .ui-datepicker-rtl { direction: rtl; }
610 | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
611 | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
612 | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
613 | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
614 | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
615 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
616 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
617 | .ui-datepicker-rtl .ui-datepicker-group { float:right; }
618 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
619 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
620 |
621 | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
622 | .ui-datepicker-cover {
623 | display: none; /*sorry for IE5*/
624 | display/**/: block; /*sorry for IE5*/
625 | position: absolute; /*must have*/
626 | z-index: -1; /*must have*/
627 | filter: mask(); /*must have*/
628 | top: -4px; /*must have*/
629 | left: -4px; /*must have*/
630 | width: 200px; /*must have*/
631 | height: 200px; /*must have*/
632 | }
633 |
634 | /*
635 | * jQuery UI Progressbar @VERSION
636 | *
637 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
638 | * Dual licensed under the MIT or GPL Version 2 licenses.
639 | * http://jquery.org/license
640 | *
641 | * http://docs.jquery.com/UI/Progressbar#theming
642 | */
643 | .ui-progressbar { height: 12px; text-align: left; background: url(images/progress_bar.gif) 0px -14px repeat-x; }
644 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; background: url(images/progress_bar.gif) 0px 0px repeat-x; }
645 |
--------------------------------------------------------------------------------
/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 0;
3 | margin: 0;
4 | font: 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
5 | }
6 | h1,
7 | h2,
8 | h3,
9 | h4,
10 | h5,
11 | h6,
12 | p,
13 | ul,
14 | li,
15 | div,
16 | form {
17 | margin: 0;
18 | padding: 0;
19 | }
20 | a {
21 | outline: none;
22 | -moz-outline-style: none;
23 | }
24 | #header {
25 | width: 100%;
26 | height: 35px;
27 | list-style-type: none;
28 | margin: 0;
29 | padding: 0;
30 | background: #f6f6f6 url("/images/gradient.gif") repeat-x 50% 50%;
31 | border-bottom: 1px solid #999;
32 | }
33 | #header ul {
34 | list-style-type: none;
35 | padding: 8px;
36 | }
37 | #header h1 a {
38 | font-size: 18px;
39 | }
40 | #header ul li {
41 | float: left;
42 | }
43 | #header ul li.right {
44 | float: right;
45 | }
46 | #header a {
47 | font-size: 13px;
48 | font-weight: bold;
49 | text-decoration: none;
50 | color: #333;
51 | text-shadow: #f0f0f0 0 1px 0;
52 | }
53 | .outline-view {
54 | position: absolute;
55 | width: 250px;
56 | background-color: #dfe3ea;
57 | }
58 | #DocumentTitles {
59 | overflow: auto;
60 | }
61 | .outline-view ul li {
62 | margin: 0;
63 | padding: 0;
64 | }
65 | .outline-view ul a {
66 | font-size: 13px;
67 | color: #000;
68 | text-decoration: none;
69 | display: block;
70 | padding: 7px 10px;
71 | }
72 | .outline-view ul li.selected a {
73 | color: #fff;
74 | font-weight: bold;
75 | text-shadow: #666 0 1px 1px;
76 | }
77 | .outline-view ul .selected {
78 | font-weight: bold;
79 | color: #fff;
80 | background-color: #8897ba;
81 | background: -webkit-gradient(linear, left top, left bottom, from(#b2bed7), to(#8897ba));
82 | background: -moz-linear-gradient(top, #b2bed7, #8897ba);
83 | }
84 | .outline-view ahover {
85 | background-color: #f0f0f0 !important;
86 | }
87 | .outline-view a {
88 | outline: none;
89 | }
90 | .content-divider {
91 | position: absolute;
92 | left: 250px;
93 | background-color: #999;
94 | width: 2px;
95 | margin: 0;
96 | padding: 0;
97 | cursor: e-resize;
98 | cursor: col-resize;
99 | }
100 | .content {
101 | position: absolute;
102 | left: 251px;
103 | margin: 0;
104 | padding: 0;
105 | overflow: auto;
106 | overflow-x: hidden;
107 | }
108 | ul.toolbar {
109 | list-style-type: none;
110 | margin: 0;
111 | padding: 0;
112 | background: #f6f6f6 url("/images/glass.png") repeat-x 50% 50%;
113 | height: 30px;
114 | border-top: 1px solid #c5c5c5;
115 | position: absolute;
116 | left: 0;
117 | bottom: 0;
118 | }
119 | ul.toolbar li {
120 | float: left;
121 | border-right: 1px solid #c5c5c5;
122 | }
123 | ul.toolbar li.right {
124 | float: right;
125 | border-left: 1px solid #c5c5c5;
126 | }
127 | ul.toolbar a {
128 | display: block;
129 | padding: 6px 10px;
130 | font-size: 14px;
131 | border: 1px solid #f5f4f5;
132 | color: #666;
133 | font-weight: bold !important;
134 | width: 14px;
135 | text-align: center;
136 | font-size: 15px;
137 | line-height: 16px;
138 | }
139 | ul.toolbar a {
140 | text-shadow: #fff 0 1px 0;
141 | text-decoration: none;
142 | }
143 | ul.toolbar a:active {
144 | background-color: #666;
145 | color: #fff;
146 | }
147 | #editor-container {
148 | float: right;
149 | width: 100%;
150 | }
151 | #editor,
152 | #editor-container input.title {
153 | border: none;
154 | outline: none;
155 | font-size: 108%;
156 | float: right;
157 | clear: both;
158 | border-bottom: 1px solid #999;
159 | margin: 0;
160 | width: 100%;
161 | padding: 5px 0;
162 | }
163 | #editor-container input:focus {
164 | background-color: #ffc;
165 | }
166 | #editor-container input.title {
167 | float: left;
168 | padding-left: 4px;
169 | margin-left: 1px;
170 | }
171 | #controls {
172 | position: absolute;
173 | left: 252px;
174 | bottom: 0;
175 | height: 30px;
176 | border-top: 1px solid #c5c5c5;
177 | background: #f6f6f6 url("/images/glass.png") repeat-x 50% 50%;
178 | }
179 | #controls a {
180 | font-size: 13px;
181 | width: 44px;
182 | }
183 | #html-container {
184 | padding: 10px;
185 | background-color: #f6f6f6;
186 | font-size: 110%;
187 | }
188 | #html-container p,
189 | #html-container ul,
190 | #html-container ol,
191 | #html-container li,
192 | #html-container h1,
193 | #html-container h2,
194 | #html-container h3,
195 | #html-container h4,
196 | #html-container h5,
197 | #html-container h6 {
198 | margin: 10px 0;
199 | }
200 | #html-container li {
201 | margin-left: 20px;
202 | }
203 | #html-button.active {
204 | background-color: #dfe3ea;
205 | }
206 | .page {
207 | padding: 10px;
208 | }
209 | .page h2 {
210 | margin-bottom: 10px;
211 | }
212 | .page p {
213 | margin: 10px 0;
214 | }
215 | .flash {
216 | position: absolute;
217 | top: 0;
218 | bottom: 0;
219 | z-index: 1001;
220 | width: 100%;
221 | opacity: 0.75;
222 | background-color: #111;
223 | }
224 | .flash span {
225 | float: left;
226 | margin-right: 0.7em;
227 | }
228 | .flash .ui-corner-all {
229 | width: 300px;
230 | margin: 50px auto 0 auto;
231 | padding: 0 5px;
232 | opacity: 0.9;
233 | font-weight: bold;
234 | -moz-box-shadow: 0 0 8px #f6f6f6;
235 | -webkit-box-shadow: 0 0 8px #f6f6f6;
236 | box-shadow: 0 0 8px #f6f6f6;
237 | }
238 | form.users {
239 | background-color: #f0f0f0;
240 | border: 1px solid #999;
241 | float: left;
242 | padding: 0 10px 10px 10px;
243 | }
244 | form.users div {
245 | padding: 10px 0 0 0;
246 | float: left;
247 | clear: left;
248 | }
249 | form.users label {
250 | width: 140px;
251 | float: left;
252 | clear: right;
253 | color: #666;
254 | font-weight: bold;
255 | }
256 | form.users input[type=submit] {
257 | margin-left: 140px;
258 | clear: both;
259 | }
260 | form.search {
261 | margin-right: 10px;
262 | }
263 | #show-all {
264 | color: #999;
265 | }
266 |
--------------------------------------------------------------------------------
/public/stylesheets/style.styl:
--------------------------------------------------------------------------------
1 | active-colour = #dfe3ea
2 | highlight-colour = #c5c5c5
3 | faded-white = #f0f0f0
4 | light-grey = #f6f6f6
5 | medium-grey = #999
6 | dark-grey = #666
7 | black = #111
8 | selected-colour = #8897ba
9 | light-selection-colour = #ffc
10 |
11 | grey-border()
12 | border-top 1px solid highlight-colour
13 |
14 | glass-background()
15 | background light-grey url('/images/glass.png') repeat-x 50% 50%
16 |
17 | light-shadow()
18 | text-shadow faded-white 0 1px 0
19 |
20 | dark-shadow()
21 | text-shadow dark-grey 0 1px 1px
22 |
23 | centre-shadow(size, colour)
24 | -moz-box-shadow 0 0 size colour
25 | -webkit-box-shadow 0 0 size colour
26 | box-shadow 0 0 size colour
27 |
28 | body
29 | padding 0
30 | margin 0
31 | font 14px "Lucida Grande", "Helvetica Nueue", Arial, sans-serif
32 |
33 | h1, h2, h3, h4, h5, h6, p, ul, li, div, form
34 | margin 0
35 | padding 0
36 |
37 | a
38 | outline none
39 | -moz-outline-style none
40 |
41 | #header
42 | width 100%
43 | height 35px
44 | list-style-type none
45 | margin 0
46 | padding 0
47 | background light-grey url('/images/gradient.gif') repeat-x 50% 50%
48 | border-bottom 1px solid medium-grey
49 |
50 | #header ul
51 | list-style-type none
52 | padding 8px
53 |
54 | #header h1 a
55 | font-size 18px
56 |
57 | #header ul li
58 | float left
59 |
60 | #header ul li.right
61 | float right
62 |
63 | #header a
64 | font-size 13px
65 | font-weight bold
66 | text-decoration none
67 | color #333
68 | light-shadow()
69 |
70 | .outline-view
71 | position absolute
72 | width 250px
73 | background-color active-colour
74 |
75 | #DocumentTitles
76 | overflow auto
77 |
78 | .outline-view ul li
79 | margin 0
80 | padding 0
81 |
82 | .outline-view ul a
83 | font-size 13px
84 | color #000
85 | text-decoration none
86 | display block
87 | padding 7px 10px
88 |
89 | .outline-view ul li.selected a
90 | color #fff
91 | font-weight bold
92 | dark-shadow()
93 |
94 | .outline-view ul .selected
95 | font-weight bold
96 | color #fff
97 | background-color selected-colour
98 | background -webkit-gradient(linear, left top, left bottom, from(#b2bed7), to(selected-colour))
99 | background -moz-linear-gradient(top, #b2bed7, selected-colour)
100 |
101 | .outline-view ahover
102 | background-color faded-white !important
103 |
104 | .outline-view a
105 | outline none
106 |
107 | .content-divider
108 | position absolute
109 | left 250px
110 | background-color medium-grey
111 | width 2px
112 | margin 0
113 | padding 0
114 | cursor e-resize
115 | cursor col-resize
116 |
117 | .content
118 | position absolute
119 | left 251px
120 | margin 0
121 | padding 0
122 | overflow auto
123 | overflow-x hidden
124 |
125 | ul.toolbar
126 | list-style-type none
127 | margin 0
128 | padding 0
129 | glass-background()
130 | height 30px
131 | grey-border()
132 | position absolute
133 | left 0
134 | bottom 0
135 |
136 | ul.toolbar li
137 | float left
138 | border-right 1px solid highlight-colour
139 |
140 | ul.toolbar li.right
141 | float right
142 | border-left 1px solid highlight-colour
143 |
144 | ul.toolbar a
145 | display block
146 | padding 6px 10px
147 | font-size 14px
148 | border 1px solid #F5F4F5
149 | color dark-grey
150 | font-weight bold !important
151 | width 14px
152 | text-align center
153 | font-size 15px
154 | line-height 16px
155 |
156 | ul.toolbar a
157 | text-shadow #fff 0 1px 0
158 | text-decoration none
159 |
160 | ul.toolbar a:active
161 | background-color dark-grey
162 | color white
163 |
164 | #editor-container
165 | float right
166 | width 100%
167 |
168 | #editor, #editor-container input.title
169 | border none
170 | outline none
171 | font-size 108%
172 | float right
173 | clear both
174 | border-bottom 1px solid medium-grey
175 | margin 0
176 | width 100%
177 | padding 5px 0
178 |
179 | #editor-container input:focus
180 | background-color light-selection-colour
181 |
182 | #editor-container input.title
183 | float left
184 | padding-left 4px
185 | margin-left 1px
186 |
187 | #controls
188 | position absolute
189 | left 252px
190 | bottom 0
191 | height 30px
192 | grey-border()
193 | glass-background()
194 |
195 | #controls a
196 | font-size 13px
197 | width 44px
198 |
199 | #html-container
200 | padding 10px
201 | background-color light-grey
202 | font-size 110%
203 |
204 | #html-container p,
205 | #html-container ul,
206 | #html-container ol,
207 | #html-container li,
208 | #html-container h1,
209 | #html-container h2,
210 | #html-container h3,
211 | #html-container h4,
212 | #html-container h5,
213 | #html-container h6
214 | margin 10px 0
215 |
216 | #html-container li
217 | margin-left 20px
218 |
219 | #html-button.active
220 | background-color active-colour
221 |
222 | .page
223 | padding 10px
224 |
225 | .page h2
226 | margin-bottom 10px
227 |
228 | .page p
229 | margin 10px 0
230 |
231 | .flash
232 | position absolute
233 | top 0
234 | bottom 0
235 | z-index 1001
236 | width 100%
237 | opacity 0.75
238 | background-color black
239 |
240 | .flash span
241 | float left
242 | margin-right .7em
243 |
244 | .flash .ui-corner-all
245 | width 300px
246 | margin 50px auto 0 auto
247 | padding 0 5px
248 | opacity 0.9
249 | font-weight bold
250 | centre-shadow(8px, light-grey)
251 |
252 | form.users
253 | background-color faded-white
254 | border 1px solid medium-grey
255 | float left
256 | padding 0 10px 10px 10px
257 |
258 | form.users div
259 | padding 10px 0 0 0
260 | float left
261 | clear left
262 |
263 | form.users label
264 | width 140px
265 | float left
266 | clear right
267 | color dark-grey
268 | font-weight bold
269 |
270 | form.users input[type=submit]
271 | margin-left 140px
272 | clear both
273 |
274 | form.search
275 | margin-right 10px
276 |
277 | #show-all
278 | color medium-grey
279 |
--------------------------------------------------------------------------------
/test/app.test.js:
--------------------------------------------------------------------------------
1 | var app = require(__dirname + '/../app'),
2 | assert = require('assert'),
3 | tobi = require('tobi'),
4 | testHelper = require('./helper'),
5 | browser = tobi.createBrowser(app);
6 |
7 | describe('Sign in', function() {
8 | before(function(done) {
9 | testHelper.clear([app.User], function() {
10 | var user = new app.User({'email' : 'alex@example.com', 'password' : 'test' });
11 | user.save(done);
12 | console.log('done');
13 | });
14 | });
15 |
16 | after(function(done) {
17 | app.close();
18 | done();
19 | });
20 |
21 | it('should allow valid users to sign in', function(done) {
22 | // FIXME: tobi doesn't seem to work at the moment
23 | browser.get('/sessions/new', function(res, $) {
24 | console.log('got / page');
25 | // Fill email, password and submit form
26 | $('form#login')
27 | .fill('user[email]', 'alex@example.com')
28 | .fill('user[password]', 'test')
29 | .submit(function(res, $) {
30 | console.log('form submitted');
31 | // Form submitted, new page loaded.
32 | assert.equal(browser.text('#header a.destroy'), 'Log Out');
33 | testHelper.end();
34 | done();
35 | });
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/helper.js:
--------------------------------------------------------------------------------
1 | // Force test environment
2 | process.env.NODE_ENV = 'test';
3 | var state = {
4 | models: []
5 | };
6 |
7 | function prepare(models, next) {
8 | var modelCount = models.length;
9 | models.forEach(function(model) {
10 | modelCount--;
11 | model.find({}, function(err, records) {
12 | var count = records.length;
13 | records.forEach(function(result) {
14 | result.remove();
15 | count--;
16 | });
17 | if (count === 0 && modelCount === 0) next();
18 | });
19 | });
20 | };
21 |
22 | module.exports = {
23 | clear: function(models, next) {
24 | prepare(models, next);
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/views/404.jade:
--------------------------------------------------------------------------------
1 | .page
2 | h2 Page Not Found
3 | p That page could not be found.
4 |
--------------------------------------------------------------------------------
/views/500.jade:
--------------------------------------------------------------------------------
1 | .page
2 | h2 Error
3 | p Something went wrong with the application.
4 | h3 Error Details
5 | pre #{error}
6 |
--------------------------------------------------------------------------------
/views/documents/edit.jade:
--------------------------------------------------------------------------------
1 | h2 Edit Document
2 | p
3 | a.button(href='/documents')
4 | ← All Documents
5 | form(method='post', action='/documents/' + d.id)
6 | input(name='d[id]', value=d.id, type='hidden')
7 | input(name='_method', value='PUT', type='hidden')
8 | !=partial('fields', { locals: { d: d } })
9 |
10 |
--------------------------------------------------------------------------------
/views/documents/fields.jade:
--------------------------------------------------------------------------------
1 | div
2 | label Title:
3 | input(name='d[title]', value=d.title || '')
4 | div
5 | label Note:
6 | div
7 | textarea(name='d[data]')= d.data
8 | div
9 | input(type='submit', value='Save')
10 |
11 |
--------------------------------------------------------------------------------
/views/documents/index.jade:
--------------------------------------------------------------------------------
1 | #left.outline-view
2 | #DocumentTitles
3 | ul#document-list
4 | li#document-row-template(style='display: none')
5 | a(id='document_{{ id }}') {{ title }}
6 |
7 | ul.toolbar
8 | li
9 | a#create-document(href='/documents/new')
10 | +
11 | li
12 | a#delete-document(href='#')
13 | -
14 |
15 | .content-divider
16 |
17 | .content
18 | #html-container(style='display: none')
19 | #editor-container
20 | div.title
21 | input.title(name='d[title]')= d.title
22 | textarea#editor(name='d[data]')
23 |
24 | ul#controls.toolbar
25 | li
26 | a#save-button(href='#') Save
27 | li
28 | a#html-button(href='#') HTML
29 |
30 |
--------------------------------------------------------------------------------
/views/documents/new.jade:
--------------------------------------------------------------------------------
1 | .page
2 | h2 New Document
3 | p
4 | a.button(href='/documents') ← All Documents
5 | form(method='post', action='/documents')
6 | !=partial('fields', { locals: { d: d } })
7 |
8 |
--------------------------------------------------------------------------------
/views/documents/show.jade:
--------------------------------------------------------------------------------
1 | h2=d.title
2 | a.button(href='/documents/' + d.id + '/edit') Edit
3 | p
4 | a.button(href='/documents')
5 | ← All Documents
6 | p=d.data
7 |
--------------------------------------------------------------------------------
/views/index.jade:
--------------------------------------------------------------------------------
1 | h1= title
2 | p Welcome to #{title}
--------------------------------------------------------------------------------
/views/layout.jade:
--------------------------------------------------------------------------------
1 | !!!
2 | html
3 | head
4 | title= 'Nodepad'
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | link(rel='stylesheet', href='/stylesheets/aristo/jquery-ui-1.8.5.custom.css')
7 | script(type='text/javascript', src='/javascripts/json.js')
8 | script(type='text/javascript', src='https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js')
9 | script(type='text/javascript', src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js')
10 | script(type='text/javascript', src='/javascripts/underscore-min.js')
11 | script(type='text/javascript', src='/javascripts/backbone-min.js')
12 | body
13 | #container
14 | #header
15 | ul
16 | li
17 | h1
18 | a(href='/') #{nameAndVersion(appName, version)}
19 | - if (typeof currentUser !== 'undefined')
20 | li.right
21 | a#logout(href='/sessions') Log Out
22 | li.right
23 | form.search(action='/search')
24 | input(name='s', value='Search')
25 | !{flashMessages}
26 | != body
27 | script(type='text/javascript', src='/javascripts/flash.js')
28 | - if (typeof documents !== 'undefined')
29 | script(type='text/javascript', src='/javascripts/documents.js')
30 | script(type='text/javascript', src='/javascripts/resize.js')
31 | script(type='text/javascript')
32 | $(function() {
33 | if (typeof Documents !== 'undefined')
34 | Documents.reset(!{JSON.stringify(documents)});
35 | });
36 |
37 |
--------------------------------------------------------------------------------
/views/mailer/welcome.jade:
--------------------------------------------------------------------------------
1 | | Dear #{user.email},
2 | |
3 | | Welcome to Nodepad!
4 | |
5 | | Regards,
6 | |
7 | | The Nodepad Mail Robot
8 |
9 |
--------------------------------------------------------------------------------
/views/sessions/new.jade:
--------------------------------------------------------------------------------
1 | .page
2 | h2 Log In
3 | p
4 | a.button(href='/users/new') Create an account →
5 | form.users#login(method='post', action='/sessions')
6 | !=partial('../users/fields', { locals: { user: user } })
7 | div
8 | label(for='remember_me') Remember me:
9 | input#remember_me(type='checkbox', name='remember_me')
10 | div
11 | input(type='submit', value='Log In')
12 |
13 |
--------------------------------------------------------------------------------
/views/users/fields.jade:
--------------------------------------------------------------------------------
1 | div
2 | label Email:
3 | input(name='user[email]', value=user.email || '')
4 |
5 | div
6 | label Password:
7 | input(name='user[password]', value=user.password || '', type='password')
8 |
9 |
--------------------------------------------------------------------------------
/views/users/new.jade:
--------------------------------------------------------------------------------
1 | .page
2 | h2 Register
3 |
4 | form.users(method='post', action='/users')
5 | !=partial('fields', { locals: { user: user } })
6 | div
7 | input(type='submit', value='Register')
8 | span \ or
9 | a(href='/sessions/new') Log In
10 |
11 |
--------------------------------------------------------------------------------