1 /**
  2  * Comment controller and view
  3  * DOM event and comment model event handlers should live here.
  4  * This view handles comment edit, delete and the sample text reverse actions, also
  5  * listens to model change and destroy events to update the view in DOM.
  6  *
  7  * @class CommentView
  8  * @extends Backbone.View
  9  * @author Bodnar Istvan <istvan@gawker.com>
 10  */
 11 /*global Mustache, FormView */
 12 var CommentView = Backbone.View.extend(
 13 /** @lends CommentView.prototype */
 14 	{
 15 		/**
 16 		 * Html tag name of the container element that'll be created when initializing new instance.
 17 		 * This container is then accessible via the this.el (native DOM node) or this.$el (jQuery node)
 18 		 * variables.
 19 		 * @type String
 20 		 */
 21 		tagName: 'li',
 22 	
 23 		/**
 24 		 * CSS class name of the container element
 25 		 * @type String
 26 		 */
 27 		className: 'comment',
 28 		
 29 		/**
 30 		 * The map of delegated event handlers
 31 		 * @type Object
 32 		 */
 33 		 events: {
 34 			'click .edit': 'edit',
 35 			'click .delete': 'delete',
 36 			'click .reverse': 'reverse'
 37 		},
 38 		
 39 		/**
 40 		 * View init method, subscribing to model events
 41 		 */
 42 		initialize: function () {
 43 			this.model.on('change', this.render, this);
 44 			this.model.on('destroy', this.remove, this);
 45 		},
 46 		
 47 		/**
 48 		 * Render the new comment DOM element from a template using Mustache
 49 		 * @returns {CommentView} Returns the view instance itself, to allow chaining view commands.
 50 		 */
 51 		render: function () {
 52 			// template is rendered in the main html, inside a <script /> tag with the specified id
 53 			var template = $('#comment-template').text();
 54 
 55 			// variables passed to the template for rendering
 56 			var template_vars = {
 57 				author: this.model.get('author'),
 58 				text: this.model.get('text')
 59 			};
 60 			
 61 			// set the inner html of the container element to the Mustache rendered output
 62 			this.$el.html(Mustache.to_html(template, template_vars));
 63 			return this;
 64 		},
 65 		
 66 		/**
 67 		 * Edit button click handler
 68 		 * @returns {Boolean} Returns false to stop propagation
 69 		 */
 70 		edit: function () {
 71 			// create new FormView instance to edit the comment
 72 			var formview = new FormView({model: this.model});
 73 			
 74 			// insert FormView instance after the comment container
 75 			this.$el.after(formview.render().$el);
 76 			
 77 			// listen to save success event to handle successful form submit event
 78 			formview.on('success', this.handleEditSuccess, this);
 79 			return false;
 80 		},
 81 		
 82 		/**
 83 		 * Delete button click handler
 84 		 * @returns {Boolean} Returns false to stop propagation
 85 		 */
 86 		delete: function () {
 87 			// delete model from memory
 88 			this.model.id = undefined;
 89 			this.model.destroy();
 90 
 91 			// note: since the view is subscribed to the models 'destroy' event, view will be also removed
 92 			// automatically, no need to delete container form DOM
 93 			return false;
 94 		},
 95 		
 96 		/**
 97 		 * "Reverse" button click handler
 98 		 * @returns {Boolean} Returns false to stop propagation
 99 		 */
100 		 reverse: function () {
101 			// run the models sample text reverse method
102 			this.model.reverseText();
103 			return false;
104 		},
105 		
106 		/**
107 		 * Handles form save success event
108 		 * @params {CommentModel} model Model returned by successful comment "save" action
109 		 */
110 		handleEditSuccess: function (model) {
111 			// create a new notification that is removed after 5 seconds
112 			var $notification = $('<div />')
113 									.text('Comment by ' + model.get('author') + ' is saved.')
114 									.addClass('notification');
115 			
116 			// append notification to edited comments container element
117 			this.$el.append($notification);
118 			
119 			// remove notification after 5 seconds
120 			setTimeout(function () {
121 				$notification.remove();
122 			}, 5000);
123 		},
124 		
125 		/**
126 		 * Override the default view remove method with custom actions
127 		 */
128 		remove: function () {
129 			// remove container element from DOM
130 			this.$el.remove();
131 		}
132 	}
133 );