table.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. // Generated by CoffeeScript 2.0.0-beta4
  2. (function() {
  3. // ------------------------------------------------------------------------
  4. // 變數與常數設置
  5. // ------------------------------------------------------------------------
  6. // 模組名稱。
  7. var Attribute, ClassName, EVENT_NAMESPACE, Error, Event, MODULE_NAMESPACE, NAME, Order, Selector, Settings;
  8. NAME = 'table';
  9. // 模組事件鍵名。
  10. EVENT_NAMESPACE = `.${NAME}`;
  11. // 模組命名空間。
  12. MODULE_NAMESPACE = `module-${NAME}`;
  13. // 模組設定。
  14. Settings = {
  15. // 消音所有提示,甚至是錯誤訊息。
  16. silent: false,
  17. // 顯示除錯訊息。
  18. debug: true,
  19. // 監聽 DOM 結構異動並自動重整快取。
  20. observeChanges: true,
  21. // 當行被展開時所會呼叫的回呼函式。
  22. onRowExpand: (event, index) => {},
  23. // 當行被閉合時所會呼叫的回呼函式。
  24. onRowCollapse: (event, index) => {},
  25. // 當垂直排被重新排序時所會呼叫的回呼函式。
  26. onSort: (event, order, index) => {}
  27. };
  28. // 排序
  29. Order = {
  30. ASCENDING: 'ascending',
  31. DESCENDING: 'descending'
  32. };
  33. // 元素標籤。
  34. Attribute = {
  35. COLSPAN: 'colspan'
  36. };
  37. // 事件名稱。
  38. Event = {
  39. ROW_EXPAND: `rowexpand${EVENT_NAMESPACE}`,
  40. ROW_COLLAPSE: `rowcollapse${EVENT_NAMESPACE}`,
  41. SORT: `sort${EVENT_NAMESPACE}`,
  42. CLICK: `click${EVENT_NAMESPACE}`
  43. };
  44. // 樣式名稱。
  45. ClassName = {
  46. DESCENDING: 'descending',
  47. ASCENDING: 'ascending',
  48. EXPANDED: 'expanded',
  49. SORTABLE: 'sortable',
  50. SORTED: 'sorted'
  51. };
  52. // 選擇器名稱。
  53. Selector = {
  54. EXPANDABLE: 'tr.expandable',
  55. EXPANDABLE_COLUMN: 'tr.expandable + tr td',
  56. EXPAND_CONTROL: 'tr.expandable > td.expand.control',
  57. ROW: 'tbody tr',
  58. HEADER: 'thead th',
  59. DESCENDING_HEADER: 'thead th.sorted.descending',
  60. ASCENDING_HEADER: 'thead th.sorted.ascending'
  61. };
  62. // 錯誤訊息。
  63. Error = {};
  64. // ------------------------------------------------------------------------
  65. // 模組註冊
  66. // ------------------------------------------------------------------------
  67. ts.register({NAME, MODULE_NAMESPACE, Error, Settings}, ({$allModules, $this, element, debug, settings}) => {
  68. var module;
  69. // ------------------------------------------------------------------------
  70. // 區域變數
  71. // ------------------------------------------------------------------------
  72. // ------------------------------------------------------------------------
  73. // 模組定義
  74. // ------------------------------------------------------------------------
  75. return module = {
  76. expand: {
  77. row: (index) => {
  78. module.get.$row(index).addClass(ClassName.EXPANDED);
  79. return module.trigger.row.expand(index);
  80. }
  81. },
  82. collapse: {
  83. row: (index) => {
  84. module.get.$row(index).removeClass(ClassName.EXPANDED);
  85. return module.trigger.row.collapse(index);
  86. }
  87. },
  88. toggle: {
  89. row: (index) => {
  90. if (module.is.expanded(index)) {
  91. return module.collapse.row(index);
  92. } else {
  93. return module.expand.row(index);
  94. }
  95. }
  96. },
  97. sort: {
  98. table: (order, index) => {
  99. var i, len, reverse, t, tbody, tr;
  100. module.get.$header().removeClass(ClassName.SORTED, ClassName.ASCENDING, ClassName.DESCENDING);
  101. tbody = element.tBodies[0];
  102. tr = Array.prototype.slice.call(tbody.rows, 0);
  103. reverse = -((+(order === Order.ASCENDING)) || -1);
  104. tr = tr.sort((a, b) => {
  105. a = a.cells[index].textContent.replace(',', '').trim();
  106. b = b.cells[index].textContent.replace(',', '').trim();
  107. switch (false) {
  108. case !!isNaN(a):
  109. return reverse * (+a - +b);
  110. case !new Date(a).getTime():
  111. return reverse * (new Date(a) - new Date(b));
  112. default:
  113. return reverse * (a.localeCompare(b));
  114. }
  115. });
  116. for (i = 0, len = tr.length; i < len; i++) {
  117. t = tr[i];
  118. tbody.appendChild(t);
  119. }
  120. module.set.sorted(index);
  121. module.set.order(order, index);
  122. return module.trigger.sort(order, index);
  123. },
  124. ascending: (index) => {
  125. module.sort.table(Order.ASCENDING, index);
  126. return $allModules;
  127. },
  128. descending: (index) => {
  129. module.sort.table(Order.DESCENDING, index);
  130. return $allModules;
  131. }
  132. },
  133. trigger: {
  134. sort: (order, index) => {
  135. return $this.trigger(Event.SORT, module.get.$header(index).get(), order, index);
  136. },
  137. row: {
  138. expand: (index) => {
  139. return $this.trigger(Event.ROW_EXPAND, module.get.$row(index).get(), index);
  140. },
  141. collapse: (index) => {
  142. return $this.trigger(Event.ROW_COLLAPSE, module.get.$row(index).get(), index);
  143. }
  144. }
  145. },
  146. is: {
  147. sortable: () => {
  148. return $this.hasClass(ClassName.SORTABLE);
  149. },
  150. table: () => {
  151. return $this.is('table');
  152. },
  153. expanded: (index) => {
  154. return module.get.$row(index).hasClass(ClassName.EXPANDED);
  155. },
  156. ascending: () => {
  157. return $this.find(Selector.ASCENDING_HEADER).length !== 0;
  158. },
  159. descending: () => {
  160. return $this.find(Selector.DESCENDING_HEADER).length !== 0;
  161. }
  162. },
  163. set: {
  164. sorted: (index) => {
  165. return module.get.$header(index).addClass(ClassName.SORTED);
  166. },
  167. order: (order, index) => {
  168. var $header;
  169. $header = module.get.$header(index);
  170. switch (order) {
  171. case Order.ASCENDING:
  172. return $header.addClass(ClassName.ASCENDING);
  173. case Order.DESCENDING:
  174. return $header.addClass(ClassName.DESCENDING);
  175. }
  176. },
  177. colspan: (colspan) => {
  178. return $this.find(Selector.EXPANDABLE_COLUMN).attr(Attribute.COLSPAN, colspan);
  179. }
  180. },
  181. get: {
  182. $header: (index) => {
  183. if (index === void 0) {
  184. return $this.find(Selector.HEADER);
  185. } else {
  186. return $this.find(Selector.HEADER).eq(index);
  187. }
  188. },
  189. $row: (index) => {
  190. if (index === void 0) {
  191. return $this.find(Selector.ROW);
  192. } else {
  193. return $this.find(Selector.ROW).eq(index);
  194. }
  195. }
  196. },
  197. bind: {
  198. events: () => {
  199. $this.on(Event.CLICK, Selector.EXPAND_CONTROL, function() {
  200. debug('發生 EXPAND CLICK 事件', this);
  201. return module.toggle.row(ts(this).closest(Selector.EXPANDABLE).index());
  202. });
  203. $this.on(Event.SORT, (event, context, order, index) => {
  204. debug('發生 SORT 事件', context);
  205. return settings.onSort.call(context, event, order, index);
  206. });
  207. $this.on(Event.ROW_COLLAPSE, (event, context, index) => {
  208. debug('發生 ROW_COLLAPSE 事件', context);
  209. return settings.onRowCollapse.call(context, event, index);
  210. });
  211. return $this.on(Event.ROW_EXPAND, (event, context, index) => {
  212. debug('發生 ROW_EXPAND 事件', context);
  213. return settings.onRowExpand.call(context, event, index);
  214. });
  215. },
  216. sortable: {
  217. events: () => {
  218. return $this.on(Event.CLICK, Selector.HEADER, function() {
  219. var index;
  220. debug('發生 SORTABLE CLICK 事件', this);
  221. index = ts(this).index();
  222. if (module.is.ascending()) {
  223. return module.sort.descending(index);
  224. } else {
  225. return module.sort.ascending(index);
  226. }
  227. });
  228. }
  229. }
  230. },
  231. // ------------------------------------------------------------------------
  232. // 基礎方法
  233. // ------------------------------------------------------------------------
  234. initialize: () => {
  235. debug('初始化表格', element);
  236. if (!module.is.table()) {
  237. return;
  238. }
  239. module.bind.events();
  240. module.set.colspan(99);
  241. if (module.is.sortable()) {
  242. return module.bind.sortable.events();
  243. }
  244. },
  245. instantiate: () => {
  246. return debug('實例化表格', element);
  247. },
  248. refresh: () => {
  249. return $allModules;
  250. },
  251. destroy: () => {
  252. debug('摧毀表格', element);
  253. $this.removeData(MODULE_NAMESPACE).off(EVENT_NAMESPACE);
  254. return $allModules;
  255. }
  256. };
  257. });
  258. }).call(this);