/public/javascripts/app.js
JavaScript | 450 lines | 345 code | 84 blank | 21 comment | 10 complexity | 150f14d701e5e273a1ad5b6ae68a056f MD5 | raw file
Possible License(s): MIT
- /*
- * app.js
- *
- * A client for the notes api.
- */
- (function($) {
- var app = {
- models: {},
- collections: {},
- views: {},
- templates: {},
- routers: {}
- };
- app.templates.notes = _.template('');
- app.templates.note = _.template('\
- <span class="title">\
- <%= title %>\
- </span>\
- <span class="controls">\
- <a href="#" class="destroy">\
- <i class="icon-remove"></i>\
- </a>\
- </span>\
- <div class="clear"></div>\
- ');
- app.templates.editNote = _.template('\
- <form>\
- <div class="title">\
- <input type="text" name="title" value="<%= title %>">\
- </div>\
- <div class="content">\
- <textarea name="content"><%= content %></textarea>\
- </div>\
- <div class="actions">\
- <div class="preview-actions">\
- <button class="button preview">\
- <i class="icon-share-alt"></i>\
- Save & Export\
- </button>\
- <div id="modal-<%= _id %>" class="reveal-modal xlarge">\
- <h2>Export</h2>\
- <div class="preview-window">\
- </div>\
- <div class="actions">\
- Download as \
- <a href="/notes/<%= _id %>/html" class="button" target="_blank">HTML</a>\
- <a href="/notes/<%= _id %>/pdf" class="button" target="_blank">PDF</a>\
- <a href="/notes/<%= _id %>/text" class="button" target="_blank">Text</a>\
- </div>\
- <a class="close-reveal-modal">×</a>\
- </div>\
- </div>\
- <div class="save-actions">\
- <button class="button save"><i class="icon-save"></i>Save</button>\
- or <a href="#" class="close">cancel</a>\
- </div>\
- </div>\
- </form>\
- ');
- app.templates.newNote = _.template('\
- <form>\
- <div class="title">\
- <input type="text" name="title" value="<%= title %>">\
- </div>\
- <div class="content">\
- <textarea name="content"><%= content %></textarea>\
- </div>\
- <div class="actions">\
- <div class="preview-actions">\
- </div>\
- <div class="save-actions">\
- <button class="button save"><i class="icon-save"></i>Save</button>\
- or <a href="#" class="close">cancel</a>\
- </div>\
- </div>\
- </form>\
- ');
- // A single note
- app.models.Note = Backbone.Model.extend({
- defaults: {
- title: 'Untitled',
- content: ''
- },
- urlRoot: '/notes',
- idAttribute: '_id'
- });
- // A collection of notes that belong to the user.
- app.collections.Notes = Backbone.Collection.extend({
- model: app.models.Note,
- url: '/notes'
- });
- // A master view that lists all notes.
- app.views.Notes = Backbone.View.extend({
- template: app.templates.notes,
- tagName: 'ul',
-
- initialize: function(options) {
- var self = this;
-
- self.notes = options.notes;
- self.notes.on('reset', self.render, self);
- self.notes.on('add', function(note) {
- var view = new app.views.Note({note: note});
- $(self.el).append(view.el);
- self.$('>li').tsort('span.title');
- });
- },
- render: function() {
- var self = this;
- $(self.el).empty();
- for (var i = 0, max = self.notes.models.length; i < max; i++) {
- var view = new app.views.Note({note: self.notes.models[i]});
- $(self.el).append(view.el);
- }
- $('#app nav').empty();
- $('#app nav').html(self.el);
- self.delegateEvents();
- self.$('>li').tsort('span.title');
- }
- });
- // A view that edits a single note.
- app.views.EditNote = Backbone.View.extend({
- template: app.templates.editNote,
- tagName: 'article',
- initialize: function(options) {
- var self = this;
- self.note = options.note;
- self.note.on('destroy', self.unrender, self);
- self.note.on('change', self.render, self);
- self.render();
- },
- render: function() {
- var self = this;
- if (!self.note.get('title').length || self.note.get('title').length < 1) {
- self.note.set('title', 'Untitled');
- }
- $(self.el).html(self.template(self.note.toJSON()));
- },
- unrender: function() {
- var self = this;
- self.remove();
- self.unbind();
- },
- events: {
- 'click .save': 'save',
- 'click .preview': 'preview',
- 'click .close': 'close'
- },
- save: function(e) {
- e.preventDefault();
- var self = this;
- self.$('.button').attr('disabled', 'disabled');
- self.note.save({
- 'title': self.$('input[name="title"]').val(),
- 'content': self.$('textarea[name="content"]').val()
- },{
- success: function() {
- self.$('.button').removeAttr('disabled');
- // Success message goes here.
- },
- error: function() {
- self.$('.button').removeAttr('disabled');
- // Error message goes here.
- }
- });
- },
- preview: function(e) {
- e.preventDefault();
- var self = this;
- self.$('.button').attr('disabled', 'disabled');
- self.note.save({
- 'title': self.$('input[name="title"]').val(),
- 'content': self.$('textarea[name="content"]').val()
- }, {
- success: function() {
- self.$('.button').removeAttr('disabled');
- // Success message goes here.
- $.ajax({
- url: '/notes/'+self.note.get('_id')+'/html?partial=true'
- }).done(function(html) {
- self.$('.reveal-modal').reveal({
- animation: 'fade'
- });
- self.$('.preview-window').html('<iframe></iframe>');
- self.$('.preview-window iframe').contents().find('body').html(html);
- });
- },
- error: function() {
- self.$('.button').removeAttr('disabled');
- // Error message goes here.
- }
- });
- },
- close: function(e) {
- e.preventDefault();
- var self = this;
- self.unrender();
- }
- });
- // A view that creates a single note.
- app.views.NewNote = Backbone.View.extend({
- template: app.templates.newNote,
- tagName: 'article',
- initialize: function(options) {
- var self = this;
- self.note = options.note;
- self.notes = options.notes;
- self.render();
- },
- render: function() {
- var self = this;
- if (!self.note.get('title').length || self.note.get('title').length < 1) {
- self.note.set('title', 'Untitled');
- }
- $(self.el).html(self.template(self.note.toJSON()));
- $('#app #main').html(self.el);
- },
- complete: function() {
- var self = this
- , view = new app.views.EditNote({note: self.note});
- $('#app #main').html(view.el);
- },
- unrender: function() {
- var self = this;
- self.remove();
- self.unbind();
- },
- events: {
- 'click .save': 'save',
- 'click .close': 'close'
- },
- save: function(e) {
- e.preventDefault();
- var self = this;
- self.$('.button').attr('disabled', 'disabled');
- self.note.set('title', self.$('input[name="title"]').val());
- self.note.set('content', self.$('textarea[name="content"]').val());
- self.notes.create(self.note, {
- wait: true,
- success: function() {
- self.$('.button').removeAttr('disabled');
- self.complete();
- },
- error: function() {
- self.$('.button').removeAttr('disabled');
- // Error message goes here.
- }
- });
- },
- close: function(e) {
- e.preventDefault();
- var self = this;
- self.unrender();
- }
- });
- app.views.Note = Backbone.View.extend({
- template: app.templates.note,
- tagName: 'li',
- initialize: function(options) {
- var self = this;
- self.note = options.note;
- self.note.on('change', self.render, self);
- self.note.on('destroy', self.unrender, self);
- self.render();
- },
- render: function() {
- var self = this;
- if (!self.note.get('title').length || self.note.get('title').length < 1) {
- self.note.set('title', 'Untitled');
- }
- $(self.el).empty();
- $(self.el).html(self.template(self.note.toJSON()));
- self.delegateEvents();
- },
- unrender: function() {
- var self = this;
- self.remove();
- self.unbind();
- },
- events: {
- 'click .destroy': 'destroy',
- 'click': 'edit'
- },
- edit: function(e) {
- e.preventDefault();
- var self = this;
- self.childView = new app.views.EditNote({note: self.note});
- $('#app #main').html(self.childView.el);
- },
- destroy: function(e) {
- e.preventDefault();
- var self = this
- , confirmed = window.confirm('Are you sure you want to delete the note "'+self.note.get('title')+'"?');
- if (confirmed) {
- self.note.destroy({
- wait: true,
- success: function(model, response) {
- // Success message
- },
- error: function(model, response) {
- // Error message
- }
- });
- }
- }
- });
- // A controller that acts as interface between
- // note model and note view.
- app.routers.Notes = Backbone.Router.extend({
- routes: {
- "": "index",
- "new": "new"
- },
- initialize: function() {
- var self = this;
- self.notes = new app.collections.Notes();
- self.notes.fetch();
- self.el = $('#container');
- },
- index: function() {
- var self = this
- , view = new app.views.Notes({notes: self.notes});
- },
- new: function() {
- var self = this
- , view = new app.views.NewNote({note: new app.models.Note(), notes: self.notes});
- }
- });
- function filter(element,what) {
- var value = $(element).val();
- value = value.toLowerCase().replace(/\b[a-z]/g, function(letter) {
- return letter.toUpperCase();
- });
- if(value == '')
- $(what+' > li').show();
- else{
- $(what+' > li:not(:contains(' + value + '))').hide();
- $(what+' > li:contains(' + value + ')').show();
- }
- };
- $(document).ready(function() {
- // Initialize the routers.
- var noteRouter = new app.routers.Notes();
- // Start the app.
- Backbone.history.start();
- $('#search input').change(function() {
- filter('#search input', '#aside nav ul');
- });
- $('#search a').click(function() {
- filter('#search input', '#aside nav ul');
- });
-
- $('body > header').append('\
- <a class="button new logout" href="/logout">\
- <i class="icon-signout"></i>\
- </a> \
- ');
- $('body > header').append('\
- <a class="button new note" href="#">\
- <i class="icon-plus"></i>\
- New\
- </a>\
- ');
- $('body > header .new.note').live('click', function(e) {
- e.preventDefault();
- noteRouter.new();
- });
- });
-
- })(jQuery);