PageRenderTime 71ms CodeModel.GetById 44ms RepoModel.GetById 1ms app.codeStats 0ms

/beancounter/static/js/lib.js

https://bitbucket.org/xamox/beancounter
JavaScript | 202 lines | 154 code | 30 blank | 18 comment | 7 complexity | 96af4042f4f2d49090493dc30b3e15a3 MD5 | raw file
Possible License(s): 0BSD
  1. // vim: fdm=marker
  2. /*
  3. * Copyright (c) 2011-2012 Audrius KaĹžukauskas
  4. *
  5. * This file is part of BeanCounter and is released under
  6. * the ISC license, see LICENSE for more details.
  7. */
  8. /*jslint indent: 4, browser: true, nomen: true, sloppy: true */
  9. /*global $, _, Backbone, DATA */
  10. var B = {};
  11. B.Collection = Backbone.Collection.extend({ // {{{
  12. // Get a list of checked items.
  13. checked: function () {
  14. return this.filter(function (model) {
  15. return model.get('checked');
  16. });
  17. },
  18. // Get a list of checked items ids.
  19. checkedIds: function () {
  20. return _(this.checked()).pluck('id');
  21. }
  22. }); // }}}
  23. B.Views = {};
  24. // Generic table row view.
  25. B.Views.Row = Backbone.View.extend({ // {{{
  26. tagName: 'tr',
  27. events: {
  28. 'click input[type=checkbox]': 'toggleChecked',
  29. 'mouseenter': 'showEditIcon',
  30. 'mouseleave': 'hideEditIcon',
  31. 'click div.edit': 'edit'
  32. },
  33. initialize: function () {
  34. this.model.on('remove', this.remove, this);
  35. this.model.on('change:checked', this.toggleClass, this);
  36. },
  37. remove: function () {
  38. this.model.off('remove', this.remove);
  39. this.model.off('change:checked', this.toggleClass);
  40. Backbone.View.prototype.remove.call(this);
  41. },
  42. render: function () {
  43. this.$el.html(this.template(this.model.toJSON()));
  44. return this;
  45. },
  46. toggleChecked: function () {
  47. this.model.toggleChecked();
  48. },
  49. toggleClass: function () {
  50. this.$el.removeAttr('style').toggleClass('checked');
  51. },
  52. showEditIcon: function () {
  53. var icon = this.$('div.edit');
  54. if (!icon.prop('disabled')) {
  55. icon.show();
  56. }
  57. },
  58. hideEditIcon: function () {
  59. var icon = this.$('div.edit');
  60. if (!icon.prop('disabled')) {
  61. icon.hide();
  62. }
  63. },
  64. edit: function () {
  65. var Form = this.formFactory(),
  66. form = new Form({model: this.model});
  67. this.$el.after(form.render().el);
  68. this.remove();
  69. form.focus();
  70. this.model.trigger('edit:start');
  71. }
  72. }); // }}}
  73. // Generic form view.
  74. B.Views.Form = Backbone.View.extend({ // {{{
  75. tagName: 'tr',
  76. events: {
  77. 'keydown': 'processKeyDown',
  78. 'click button[name=save]': 'saveChanges',
  79. 'click button[name=cancel]': 'remove'
  80. },
  81. // Get form field values.
  82. getValues: function () {
  83. var values = {};
  84. this.$('input[type=text]').each(function () {
  85. values[this.name] = this.value;
  86. });
  87. return values;
  88. },
  89. processKeyDown: function (e) {
  90. switch (e.keyCode) {
  91. case 13: // Enter.
  92. this.saveChanges();
  93. break;
  94. case 27: // Esc.
  95. this.remove();
  96. break;
  97. }
  98. },
  99. focus: function () {
  100. this.$('td:nth-child(2) input').focus();
  101. }
  102. }); // }}}
  103. // Generic table view.
  104. B.Views.Table = Backbone.View.extend({ // {{{
  105. events: {
  106. 'click input.check-all': 'toggleCheckAll'
  107. },
  108. initialize: function () {
  109. this.collection.on('reset', this.render, this);
  110. this.collection.on('add', this.appendNew, this);
  111. this.collection.on('sort', this.sortTable, this);
  112. this.collection.on('remove', this.showEmptyNotice, this);
  113. },
  114. render: function () {
  115. // Clear tbody contents before rendering.
  116. this.$('tbody').empty();
  117. this.$('input.check-all').prop('checked', false);
  118. if (this.collection.isEmpty()) {
  119. this.$('tr.empty-msg').show();
  120. this.$('input.check-all').hide();
  121. } else {
  122. this.$('tr.empty-msg').hide();
  123. this.$('input.check-all').show();
  124. this.collection.each(function (model) {
  125. this.append(model);
  126. }, this);
  127. this.sortTable();
  128. }
  129. return this;
  130. },
  131. append: function (model) {
  132. var Row = this.rowFactory(),
  133. row = new Row({model: model}),
  134. $el = row.render().$el;
  135. this.$el.append($el);
  136. return $el;
  137. },
  138. // Append newly created row to the table.
  139. appendNew: function (model) {
  140. var $el = this.append(model);
  141. this.sortTable();
  142. this.$('input.check-all').prop('checked', false).show();
  143. $el.css({backgroundColor: '#eaa228'})
  144. .animate({backgroundColor: '#fff'}, 1000);
  145. },
  146. sortTable: function () {
  147. var thIndex = this.$('th.sort-header').index();
  148. this.$('tbody td').filter(function () {
  149. return $(this).index() === thIndex;
  150. }).sortElements(function (a, b) {
  151. return $.text([a]) > $.text([b]) ? 1 : -1;
  152. }, function () {
  153. return this.parentNode;
  154. });
  155. },
  156. toggleCheckAll: function (e) {
  157. var checked = e.target.checked;
  158. this.collection.each(function (model) {
  159. if (model.get('checked') !== checked) {
  160. model.toggleChecked();
  161. }
  162. });
  163. this.$('tbody input[type=checkbox]').prop('checked', checked);
  164. },
  165. // Show 'table is empty' notice if collection is empty.
  166. showEmptyNotice: function () {
  167. if (this.collection.isEmpty()) {
  168. this.$('tr.empty-msg').show();
  169. this.$('input.check-all').hide();
  170. }
  171. }
  172. }); // }}}