/lib/code_buddy/public/javascripts/code_buddy.js

https://github.com/houhoulis/code_buddy · JavaScript · 262 lines · 213 code · 45 blank · 4 comment · 16 complexity · d0ff9c1303e129416cd7f7aba1db1907 MD5 · raw file

  1. var CodeBuddy = {
  2. backbone : {}
  3. }
  4. CodeBuddy.backbone.Address = Backbone.Model.extend({
  5. selected: function() {
  6. return CodeBuddy.stack.selectedAddress() == this
  7. },
  8. });
  9. CodeBuddy.backbone.Addresses = Backbone.Collection.extend({
  10. model:CodeBuddy.backbone.Address,
  11. bookmarked: function() {
  12. return this.select(function(address){
  13. return address.get('bookmarked');
  14. })
  15. }
  16. })
  17. CodeBuddy.backbone.Stack = Backbone.Model.extend({
  18. initialize: function() {
  19. _.bindAll(this, 'toggleBookmark', 'selectNextBookmark')
  20. this.bind('change:selected', this.selectionChanged);
  21. this.set({
  22. addresses: new CodeBuddy.backbone.Addresses(this.get('stack_frames'))
  23. })
  24. },
  25. setSelection: function(newSelected) {
  26. if (newSelected >= 0 && newSelected < this.addresses().size()) {
  27. this.set({ selected: newSelected })
  28. }
  29. },
  30. selectPrevious: function() {
  31. this.setSelection(this.get('selected') - 1)
  32. },
  33. selectNext: function() {
  34. this.setSelection(this.get('selected') + 1)
  35. },
  36. addresses: function() {
  37. return this.get('addresses')
  38. },
  39. selectedAddress: function() {
  40. var selected = this.get('selected')
  41. return this.addresses().at(selected)
  42. },
  43. selectionChanged: function(x) {
  44. this.addresses().at(x.previousAttributes().selected).view.render()
  45. this.addresses().at(x.changedAttributes().selected).view.render()
  46. CodeBuddy.codeView.render()
  47. },
  48. toggleBookmark: function() {
  49. this.selectedAddress().set({bookmarked:!this.selectedAddress().get('bookmarked')})
  50. this.selectedAddress().view.render();
  51. },
  52. selectNextBookmark: function() {
  53. var bookmarked = this.addresses().bookmarked();
  54. var length = bookmarked.length;
  55. var toSelect;
  56. if(length > 0) {
  57. var current = _.indexOf(bookmarked, this.selectedAddress())
  58. if(current > -1 && current < length - 1) {
  59. toSelect = bookmarked[current + 1]
  60. } else {
  61. toSelect = bookmarked[0]
  62. }
  63. return this.setSelection(toSelect.cid.substr(1)-1)
  64. }
  65. }
  66. });
  67. // ADDRESS VIEW - SELECTED ADDRESS IN BOLD
  68. CodeBuddy.backbone.AddressView = Backbone.View.extend({
  69. tagName: "li",
  70. template: _.template("<span class='container'><%= path %>:<%= line%><span class='overlay'></span></span>"),
  71. initialize: function() {
  72. this.model.view = this;
  73. },
  74. events: {
  75. click: "open",
  76. dblclick: "toggleBookmark"
  77. },
  78. open: function() {
  79. CodeBuddy.stack.set({selected: this.model.cid.substr(1)-1});
  80. },
  81. toggleBookmark: function() {
  82. this.open();
  83. CodeBuddy.stack.toggleBookmark();
  84. },
  85. render: function() {
  86. $(this.el).removeClass('selected bookmarked')
  87. var html = this.template(this.model.toJSON())
  88. $(this.el).html(html);
  89. if (this.model.selected()) {
  90. $(this.el).addClass('selected')
  91. }
  92. if (this.model.get('bookmarked')) {
  93. $(this.el).addClass('bookmarked')
  94. }
  95. return this;
  96. }
  97. })
  98. // STACK VIEW - LOGIC FOR ASSIGNING EACH ADDRESS VIEW TO EACH LI TAG
  99. CodeBuddy.backbone.StackView = Backbone.View.extend({
  100. el: $("#stack"),
  101. initialize: function() {
  102. _.bindAll(this, 'selectNext', 'selectPrevious', 'addOneAddress')
  103. this.model.view = this;
  104. this.model.get('addresses').each(this.addOneAddress);
  105. },
  106. selectPrevious: function() {
  107. this.model.selectPrevious();
  108. this.ensureVisibility();
  109. return false;
  110. },
  111. selectNext: function() {
  112. this.model.selectNext();
  113. this.ensureVisibility();
  114. return false;
  115. },
  116. ensureVisibility: function() {
  117. var offset = $(CodeBuddy.stack.selectedAddress().view.el).offset()
  118. var windowHeight = $(window).height()
  119. if (offset.top > windowHeight + $(window).scrollTop() - 10) {
  120. // scroll down
  121. $('html,body').animate({scrollTop: offset.top - 200}, 500);
  122. } else if (offset.top < $(window).scrollTop() + 100) {
  123. // scroll up
  124. $('html,body').animate({scrollTop: offset.top - 500}, 500);
  125. }
  126. return false
  127. },
  128. addOneAddress: function(address, index) {
  129. var view = new CodeBuddy.backbone.AddressView({model: address});
  130. $(this.el).append(view.render().el);
  131. }
  132. })
  133. CodeBuddy.backbone.CodeView = Backbone.View.extend({
  134. el:$("#code-viewer"),
  135. initialize: function() {
  136. _.bindAll(this, 'toggleCommands','increaseOpacity', 'decreaseOpacity', 'toggle')
  137. this.code = this.$("#code")
  138. this.current = this.$("#current")
  139. this.opacity = parseFloat(this.el.css("opacity"))
  140. },
  141. render: function() {
  142. this.current.html('<div>' + CodeBuddy.stack.selectedAddress().get('path') + '</div>')
  143. this.code.html(CodeBuddy.stack.selectedAddress().get('code'))
  144. },
  145. toggleCommands: function() {
  146. this.$("#legend").toggle()
  147. },
  148. toggle: function() {
  149. this.el.toggle()
  150. },
  151. editCode: function() {
  152. $.get('../edit/' + CodeBuddy.stack.get('selected'))
  153. },
  154. setOpacity: function(newOpacity) {
  155. if(newOpacity < 0) newOpacity = 0;
  156. if(newOpacity > 1) newOpacity = 1;
  157. this.el.css("opacity", newOpacity);
  158. this.opacity = newOpacity;
  159. },
  160. increaseOpacity: function() {
  161. this.setOpacity(this.opacity + 0.1)
  162. },
  163. decreaseOpacity: function() {
  164. this.setOpacity(this.opacity - 0.1)
  165. }
  166. })
  167. CodeBuddy.backbone.FormView = Backbone.View.extend({
  168. el:$(".form"),
  169. initialize: function() {
  170. _.bindAll(this, 'show', 'hide')
  171. this.el.find('textarea').bind('keydown', 'esc', this.hide)
  172. },
  173. show: function(){
  174. this.el.show();
  175. CodeBuddy.codeView.el.hide()
  176. CodeBuddy.stackView.el.hide()
  177. this.el.find("textarea").focus()
  178. return false;
  179. },
  180. hide: function(){
  181. this.el.hide();
  182. CodeBuddy.codeView.el.show()
  183. CodeBuddy.stackView.el.show()
  184. return false;
  185. }
  186. })
  187. CodeBuddy.setStackKeyBindings = function(){
  188. $(document).bind('keydown', 'up', CodeBuddy.stackView.selectPrevious)
  189. $(document).bind('keydown', 'down', CodeBuddy.stackView.selectNext)
  190. $(document).bind('keydown', 'right', CodeBuddy.codeView.increaseOpacity)
  191. $(document).bind('keydown', 'left', CodeBuddy.codeView.decreaseOpacity)
  192. $(document).bind('keydown', 'a', CodeBuddy.stack.toggleBookmark)
  193. $(document).bind('keydown', 's', CodeBuddy.stack.selectNextBookmark)
  194. $(document).bind('keydown', 'h', CodeBuddy.codeView.toggle)
  195. $(document).bind('keydown', 'e', CodeBuddy.codeView.editCode)
  196. }
  197. CodeBuddy.setGlobalKeyBindings = function(){
  198. $(document).bind('keydown', 'n', CodeBuddy.form.show)
  199. $(document).bind('keydown', 'esc', CodeBuddy.codeView.toggleCommands)
  200. }
  201. CodeBuddy.setup = function(stackJson) {
  202. CodeBuddy.form = new CodeBuddy.backbone.FormView
  203. this.stack = new this.backbone.Stack(stackJson);
  204. this.stackView = new this.backbone.StackView({model: this.stack});
  205. this.codeView = new this.backbone.CodeView();
  206. if(stackJson) {
  207. this.codeView.render();
  208. this.setStackKeyBindings();
  209. CodeBuddy.form.hide()
  210. } else {
  211. CodeBuddy.form.show()
  212. }
  213. CodeBuddy.setGlobalKeyBindings()
  214. $('#new_stack').click(function(){
  215. CodeBuddy.form.show()
  216. })
  217. }