Created
December 14, 2011 02:03
-
-
Save randito/1474893 to your computer and use it in GitHub Desktop.
Backbone source from http://chopapp.com/ => Extracted from http://chopapp.com/assets/all.js?1320423538
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var CodeSnip = Backbone.Model.extend({ | |
urlRoot: 'code_snips', | |
defaults: { | |
}, | |
initialize: function () { | |
} | |
}); | |
var Comment = Backbone.Model.extend({ | |
defaults: { | |
text: '' | |
} | |
}); | |
var Note = Backbone.Model.extend({ | |
defaults: { | |
text: '' | |
}, | |
toJSON: function () { | |
var attributes = Backbone.Model.prototype.toJSON.call(this); | |
attributes.isNew = this.isNew(); | |
return attributes; | |
} | |
}); | |
var CommentsCollection = Backbone.Collection.extend({ | |
model: Comment, | |
url: '/comments' | |
}); | |
var NotesCollection = Backbone.Collection.extend({ | |
model: Note, | |
url: '/notes' | |
}); | |
var NoteView = Backbone.View.extend({ | |
tagName: 'li', | |
className: 'note read-only', | |
template: JST['note'], | |
events: { | |
'click .add-comment': 'clickAddComment' | |
}, | |
initialize: function (options) { | |
_.bindAll(this, 'render', 'addComment', 'commentSaved'); | |
this.model.bind('change:text', this.render); | |
this.comments = new CommentsCollection(this.model.get('comments')); | |
this.comments.bind('add', this.addComment); | |
}, | |
render: function () { | |
$(this.el).html(this.template(this.model.toJSON())); | |
this.comments.each(this.addComment); | |
return this; | |
}, | |
clickAddComment: function (event) { | |
var comment = new Comment({ | |
note_id: this.model.get('id'), | |
user_name: $.cookie('name'), | |
owner_cookie_id: $.cookie('id') | |
}); | |
event.preventDefault(); | |
this.comments.add(comment); | |
this.$('.add-comment').hide(); | |
}, | |
addComment: function (comment) { | |
var commentView = new CommentView({model: comment, note: this.model}); | |
this.$('.add-comment').before(commentView.render().el); | |
commentView.$('.text-edit').select(); | |
commentView.bind('saved', this.commentSaved); | |
}, | |
commentSaved: function () { | |
this.$('.add-comment').show(); | |
} | |
}); | |
var EditableNoteView = NoteView.extend({ | |
className: 'note', | |
events: { | |
'click .save.note': 'save', | |
'keypress': 'keypress', | |
'click .note.text': 'startEditing', | |
'click .delete': 'destroy', | |
'click': 'dontpropagate' | |
}, | |
initialize: function (options) { | |
NoteView.prototype.initialize.call(this, options); | |
_.bindAll(this, 'stopEditing', 'remove', 'clickDocument', 'dontpropagate', 'destroy'); | |
}, | |
render: function () { | |
NoteView.prototype.render.call(this); | |
if (this.model.isNew()) { | |
this.startEditing(); | |
} else { | |
$(this.el).removeClass('editing'); | |
} | |
return this; | |
}, | |
save: function () { | |
$(this.el).addClass('loading'); | |
this.model.save( | |
{text: this.$('.note.text-edit').val()}, | |
{success: this.stopEditing} | |
); | |
}, | |
destroy: function (event) { | |
event.preventDefault(); | |
if (this.model.isNew()) { | |
this.model.collection.remove(this.model); | |
} else { | |
this.model.destroy(); | |
} | |
$(document).unbind('click.cancel-note', this.clickDocument); | |
}, | |
startEditing: function () { | |
$(document).bind('click.cancel-note', this.clickDocument); | |
$(this.el).addClass('editing'); | |
this.$('.note.text-edit').select(); | |
}, | |
clickDocument: function (event) { | |
if (this.model.isNew()) { | |
this.destroy(event); | |
} else { | |
this.stopEditing(); | |
} | |
}, | |
dontpropagate: function (event) { | |
event.stopPropagation(); | |
}, | |
stopEditing: function () { | |
$(this.el).removeClass('editing loading'); | |
this.render(); | |
$(document).unbind('click.cancel-note', this.clickDocument); | |
}, | |
keypress: function (event) { | |
if (event.which === 13) { | |
event.preventDefault(); | |
this.save(); | |
} | |
} | |
}); | |
var CodeSnipView = Backbone.View.extend({ | |
template: JST['code_snip'], | |
noteViewClass: NoteView, | |
initialize: function (options) { | |
_.bindAll(this, 'render', 'addNote', 'fetchModel', 'fetchModelSuccess', 'changeNotes', 'saveName'); | |
this.notes = new NotesCollection(this.model.get('notes')); | |
// _.delay(this.fetchModel, 2000); | |
this.model.bind('change:notes', this.changeNotes); | |
this.setCookieId(); | |
}, | |
render: function () { | |
var self = this; | |
$(this.el).html(this.template(this.model.toJSON())); | |
this.notes.each(function (note, collection, wtfobj) { | |
self.addNote(note, collection, wtfobj, true); | |
}); | |
this.$('#nameModal form').bind('submit', this.saveName); | |
if ($.cookie('name') === null) { | |
this.$('#nameModal').reveal({animation: 'none'}); | |
} | |
return this; | |
}, | |
saveName: function (event) { | |
event.preventDefault(); | |
$.cookie('name', this.$('#nameModal input').val(), {expires: 365}); | |
this.$('#nameModal').trigger('reveal:close'); | |
}, | |
addNote: function (note, collection, wtfobj, skipAnimation) { | |
var noteView = new this.noteViewClass({model: note}), | |
$lines = this.$('.line'), | |
$firstLine = $lines.eq(note.get('line_start')), | |
$lastLine = $lines.eq(note.get('line_end')), | |
$chopper = $('<div class="chop-it"></div>'); | |
if (typeof skipAnimation === 'undefined') { | |
skipAnimation = false; | |
} | |
$lines.slice(note.get('line_start') + 1, note.get('line_end')).addClass('annotated'); | |
$firstLine.addClass('first annotated'); | |
$lastLine.addClass('last annotated'); | |
$chopper.css({ | |
left: -this.$('#choppinBroccoli').offset().left + 20 + 'px', | |
top: $firstLine.position().top + 'px', | |
height: $lastLine.position().top - $firstLine.position().top + $lastLine.height() + 'px' | |
}); | |
this.$('#choppinBroccoli').prepend($chopper); | |
if (skipAnimation) { | |
$lastLine.after(noteView.render().el); | |
$chopper.animate({left: '-13px'}, 0); | |
} else if (note.isNew()) { | |
$chopper.animate({left: '-13px'}, 350, 'easeInQuint', function () { | |
$lastLine.after(noteView.render().el); | |
noteView.$('.text-edit').select(); | |
}); | |
} else { | |
$lastLine.after(noteView.render().el); | |
$chopper.animate({left: '-13px'}, 350, 'easeInQuint'); | |
} | |
}, | |
fetchModel: function () { | |
this.model.fetch({success: this.fetchModelSuccess}); | |
}, | |
fetchModelSuccess: function () { | |
_.delay(this.fetchModel, 10000); | |
}, | |
changeNotes: function (model, notes) { | |
this.notes.refresh(notes); | |
this.render(); | |
}, | |
setCookieId: function () { | |
if ($.cookie('id') === null) { | |
$.cookie('id', (new Date).valueOf(), {expires: 365}); | |
} | |
} | |
}); | |
var EditableCodeSnipView = CodeSnipView.extend({ | |
noteViewClass: EditableNoteView, | |
className: 'editable', | |
events: { | |
'mousedown .line:not(.annotated)': 'mousedown', | |
'mouseenter .line': 'mouseenter', | |
'mouseleave': 'mouseleave', | |
'mouseup .line': 'mouseup' | |
}, | |
initialize: function(options) { | |
CodeSnipView.prototype.initialize.call(this, options); | |
this.notes.bind('add', this.addNote); | |
this.notes.bind('remove', this.render); | |
}, | |
mousedown: function (event) { | |
if (this.isLeftClick(event)) { | |
event.preventDefault(); | |
$(event.currentTarget).addClass('start-drag selected'); | |
this.dragging = true; | |
} | |
}, | |
mouseup: function (event) { | |
if (this.isLeftClick(event) && this.dragging) { | |
var $lines = this.$('.line'), | |
note = new Note({ | |
code_snip_id: this.model.get('token'), | |
line_start: $lines.index($lines.filter('.selected:first')), | |
line_end: $lines.index($lines.filter('.selected:last')), | |
owner_cookie_id: $.cookie('id') | |
}); | |
this.stopSelecting(); | |
this.notes.add(note); | |
} | |
}, | |
mouseleave: function (event) { | |
this.stopSelecting(); | |
}, | |
mouseenter: function (event) { | |
var $lines = this.$('.line'), | |
startIndex, | |
endIndex, | |
oldStartIndex; | |
if (this.dragging) { | |
$lines.removeClass('end-drag'); | |
$(event.currentTarget).addClass('end-drag'); | |
startIndex = $lines.index($lines.filter('.start-drag')); | |
endIndex = $lines.index($lines.filter('.end-drag')); | |
if (endIndex < startIndex) { | |
oldStartIndex = startIndex; | |
startIndex = endIndex; | |
endIndex = oldStartIndex; | |
} | |
$lines.removeClass('selected first last'); | |
$lines.slice(startIndex, endIndex + 1).addClass('selected'); | |
$lines.filter('.selected:first').addClass('first'); | |
$lines.filter('.selected:last').addClass('last'); | |
} | |
}, | |
stopSelecting: function () { | |
this.dragging = false; | |
this.$('.line').removeClass('selected start-drag end-drag'); | |
}, | |
isLeftClick: function (event) { | |
return event.which === 1; | |
} | |
}); | |
var NewCodeSnipView = Backbone.View.extend({ | |
template: JST['new'], | |
initialize: function() { | |
_.bindAll(this, 'render', 'create', 'createSuccess'); | |
}, | |
events: { | |
'click #langToggle li': 'clickLanguage', | |
'click #langToggle li.more li': 'showHiddenLanguange', | |
'click #captureFromUrl': 'showCaptireFromUrl', | |
'click textarea, #langToggle': 'showPaste', | |
'click .close-url': 'showPaste' | |
}, | |
render: function() { | |
$(this.el).html(this.template({})); | |
this.$('form').bind('submit', this.create); | |
this.$('input[placeholder],textarea[placeholder]').placeholder(); | |
return this; | |
}, | |
create: function (event) { | |
var $form = $(event.currentTarget), | |
self = this, | |
codeSnip; | |
event.preventDefault(); | |
CHOP.controller.transitionOut(function () { | |
//// Need to post this manually because of bug with Rails correctly handling JSON encoding of double linebreaks | |
//// http://stackoverflow.com/questions/5074034/activesupportjson-decode-does-not-properly-handle-literal-line-breaks | |
// codeSnip = new CodeSnip({ | |
// code: $form.find('[name=code]').val(), | |
// language: $form.find('[name=language]').val(), | |
// url: $form.find('[name=url]').val() | |
// }); | |
// codeSnip.save({}, {success: self.createSuccess}); | |
$.post( | |
$form.attr('action'), | |
$form.serialize(), | |
self.createSuccess | |
); | |
}); | |
}, | |
createSuccess: function (codeSnipAttributes) { | |
var codeSnip = new CodeSnip(codeSnipAttributes), | |
editableCodeSnipView = new EditableCodeSnipView({model: codeSnip}); | |
CHOP.controller.transitionIn(function () { | |
return editableCodeSnipView.render().el; | |
}); | |
Backbone.history.saveLocation(codeSnip.get('token')); | |
}, | |
clickLanguage: function (event) { | |
var $this = $(event.currentTarget); | |
event.preventDefault(); | |
$this.siblings().removeClass('active'); | |
$this.addClass('active'); | |
this.$('#langInput').val($this.data('value')); | |
}, | |
showHiddenLanguange: function (event) { | |
var $selectedLi = $(event.currentTarget); | |
event.preventDefault(); | |
event.stopPropagation(); | |
$selectedLi.closest('.more').replaceWith($selectedLi); | |
$selectedLi.trigger('click'); | |
}, | |
showCaptireFromUrl: function (event) { | |
event.preventDefault(); | |
$(event.currentTarget).closest('.page-bubble').addClass('with-url'); | |
}, | |
showPaste: function (event) { | |
event.preventDefault(); | |
$(event.currentTarget).closest('.page-bubble').removeClass('with-url'); | |
} | |
}); | |
var CommentView = Backbone.View.extend({ | |
className: 'comment', | |
template: JST['comment'], | |
events: { | |
'click .save': 'save', | |
'keypress': 'keypress' | |
}, | |
initialize: function(options) { | |
_.bindAll(this, 'render', 'stopEditing'); | |
this.note = options.note; | |
this.model.bind('change:text', this.render); | |
}, | |
render: function () { | |
$(this.el).html(this.template(this.model.toJSON())); | |
if (this.model.isNew()) { | |
$(this.el).addClass('editing'); | |
} else { | |
$(this.el).removeClass('editing'); | |
} | |
if (this.model.get('owner_cookie_id') === this.note.get('owner_cookie_id')) { | |
$(this.el).addClass('owner-comment') | |
} | |
return this; | |
}, | |
save: function () { | |
$(this.el).addClass('loading'); | |
this.model.save( | |
{text: this.$('.text-edit').val()}, | |
{success: this.stopEditing} | |
); | |
}, | |
stopEditing: function () { | |
$(this.el).removeClass('editing loading'); | |
this.trigger('saved'); | |
}, | |
keypress: function (event) { | |
if (event.which === 13) { | |
event.preventDefault(); | |
this.save(); | |
} | |
} | |
}); | |
var CodeSnipController = Backbone.Controller.extend({ | |
routes: { | |
"": "new", | |
"about": "about", | |
":id": "show" | |
}, | |
'new': function() { | |
var newCodeSnipView = new NewCodeSnipView(); | |
this.transition(function () { | |
return newCodeSnipView.render().el; | |
}); | |
}, | |
show: function(id) { | |
var codeSnip = new CodeSnip({id: id}) | |
self = this; | |
this.transitionOut(function () { | |
codeSnip.fetch({success: function (model, response) { | |
var codeSnipView = new CodeSnipView({model: codeSnip}); | |
self.transitionIn(function () { | |
return codeSnipView.el; | |
}, function () { | |
codeSnipView.render(); | |
}); | |
}}); | |
}); | |
}, | |
about: function () { | |
this.transition(function () { | |
return JST['about']({}); | |
}); | |
}, | |
transitionOut: function (callback) { | |
callback = callback || $.noop; | |
$('#applicationContainer').fadeOutAndSlide({complete: callback}); | |
}, | |
transitionIn: function (contentCallback, callback) { | |
callback = callback || $.noop; | |
$('#applicationContainer') | |
.html(contentCallback()) | |
.fadeInAndSlide(); | |
callback(); | |
}, | |
transition: function (contentCallback) { | |
this.transitionOut(_.bind(this.transitionIn, this, contentCallback)); | |
} | |
}); | |
var CHOP = {}; | |
$(document).ready(function () { | |
CHOP.controller = new CodeSnipController; | |
Backbone.history.start(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Extracted from the wonderful Zurb chopapp.com single page app: http://chopapp.com/assets/all.js?1320423538
Posted to review some backbone.js code.