/devstream/static/js/stream.js

https://github.com/marconi/devstream · JavaScript · 211 lines · 152 code · 25 blank · 34 comment · 9 complexity · e9a014495e2e68bf3cecc75b20ceb7be MD5 · raw file

  1. (function($) {
  2. /**
  3. * Models and Collections
  4. */
  5. window.StreamItem = Backbone.Model.extend({
  6. urlRoot: '/status/'
  7. });
  8. window.StreamItemList = Backbone.Collection.extend({
  9. model: StreamItem,
  10. url: '/stream/',
  11. comparator: function(streamItem) {
  12. // sort in descending so the last added is at the top
  13. return -streamItem.get("id");
  14. }
  15. });
  16. /**
  17. * Views
  18. */
  19. window.StreamItemView = Backbone.View.extend({
  20. className: 'row',
  21. initialize: function() {
  22. _.bindAll(this, 'render');
  23. // listen for change event
  24. this.model.bind('change', this.render, this);
  25. this.model.bind('destroy', this.remove, this);
  26. this.template = _.template($('#stream-item-template').html());
  27. },
  28. render: function() {
  29. var renderedContent = this.template(this.model.toJSON());
  30. $(this.el).html(renderedContent);
  31. return this;
  32. },
  33. remove: function() {
  34. $(this.el).remove();
  35. }
  36. });
  37. window.StreamView = Backbone.View.extend({
  38. className: 'row stream',
  39. initialize: function() {
  40. _.bindAll(this, 'render');
  41. this.template = _.template($('#stream-template').html());
  42. // listen for reset event
  43. this.collection.bind('reset', this.reset, this);
  44. this.collection.bind('add', this.addItem, this);
  45. // render initially so adding items below
  46. // triggers the render.
  47. $(this.el).html(this.template({}));
  48. // hide empty message and more link by default,
  49. // only show preloader since it'll try to fetch.
  50. this.$('.stream-empty').hide();
  51. this.$('.stream-more').hide();
  52. // show more link and hide preloader
  53. // if collection is not empty
  54. if (this.collection.length > 0) {
  55. this.$('.more-preloader').hide();
  56. this.$('.stream-more').show();
  57. }
  58. this.collection.fetch({data: {group_id: window.activeGroupId}});
  59. },
  60. events: {
  61. "keypress textarea#status": "updateStatus",
  62. "click .stream-more a": "moreStatus"
  63. },
  64. addItem: function(item) {
  65. var streamItemView = new StreamItemView({model: item});
  66. this.$(".stream-items").append(streamItemView.render().el);
  67. // hide empty message, display show more link
  68. this.$('.stream-empty').hide();
  69. this.$('.stream-more').show();
  70. },
  71. reset: function() {
  72. // clear out existing rows, after all this is a reset
  73. this.$(".stream-items .row").remove();
  74. // if we have data from the server,
  75. // hide preloader and show more link.
  76. if (this.collection.length > 0) {
  77. this.$('.more-preloader').hide();
  78. this.$('.stream-empty').hide();
  79. this.$('.stream-more').show();
  80. }
  81. // if there's no status, show empty message
  82. // and hide preloader and more link.
  83. else {
  84. this.$('.more-preloader').hide();
  85. this.$('.stream-more').hide();
  86. this.$('.stream-empty').show();
  87. }
  88. // then add each new item in the collection
  89. this.collection.each(this.addItem);
  90. },
  91. updateStatus: function(e) {
  92. if (e.keyCode !== 13) {
  93. return;
  94. }
  95. var rawStatus = this.$("textarea#status").val();
  96. if (rawStatus.trim() === "") {
  97. return;
  98. }
  99. var collection = this.collection;
  100. // create and save the status first before adding
  101. // to the collection.
  102. var newStatus = new StreamItem({
  103. status: rawStatus.trim(),
  104. type: 'STATUS',
  105. group_id: window.activeGroupId
  106. });
  107. newStatus.save({}, {
  108. success: function(model, response) {
  109. collection.add(model);
  110. collection.sort();
  111. },
  112. error: function(model, response) {
  113. console.log("Error saving status: " + response);
  114. }
  115. });
  116. this.$("textarea#status").val("").focus();
  117. e.preventDefault();
  118. },
  119. moreStatus: function(e) {
  120. var streamView = this;
  121. var collection = streamView.collection;
  122. var lastItem = collection.last();
  123. var data = {};
  124. if (lastItem !== undefined) {
  125. data['last_id'] = lastItem.get("id");
  126. }
  127. // hide show more link and show preloader
  128. streamView.$('.stream-more a').hide();
  129. streamView.$('.more-preloader').show();
  130. // append group_id
  131. data['group_id'] = window.activeGroupId;
  132. $.ajax({
  133. type: "GET",
  134. data: data,
  135. url: "/stream/more",
  136. dataType: "json",
  137. success: function(data, textStatus, jqXHR) {
  138. if (data === null) {
  139. // if there's no more data,
  140. // hide the show more link and preloader.
  141. streamView.$('.more-preloader').hide();
  142. streamView.$('.stream-more a').hide();
  143. }
  144. else {
  145. collection.add(data);
  146. }
  147. },
  148. statusCode: {
  149. 200: function (data, textStatus, jqXHR) {
  150. // only toggle back show more link and
  151. // preloader if there's still more data.
  152. if (data !== null) {
  153. // toggle show more and preloader
  154. streamView.$('.more-preloader').hide();
  155. streamView.$('.stream-more a').show();
  156. }
  157. },
  158. 400: function (data, textStatus, jqXHR) {
  159. console.log("Error: " + data);
  160. }
  161. }
  162. });
  163. e.preventDefault();
  164. }
  165. });
  166. /**
  167. * Router
  168. */
  169. window.Stream = Backbone.Router.extend({
  170. routes: {
  171. '': 'home'
  172. },
  173. initialize: function(container) {
  174. this.streamView = new StreamView({
  175. el: $(container),
  176. collection: new StreamItemList()
  177. });
  178. },
  179. home: function() {
  180. }
  181. });
  182. $(document).ready(function() {
  183. window.streamApp = new Stream('#main-stream');
  184. Backbone.history.start();
  185. });
  186. })(jQuery);