Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / third_party / tvcm / src / tvcm / ui / sortable_table.js
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /**
8  * @fileoverview A sortable table with history states.
9  */
10 tvcm.requireStylesheet('tvcm.ui.sortable_table');
11
12 tvcm.require('tvcm.ui');
13
14 tvcm.exportTo('tvcm.ui', function() {
15   /**
16    * @constructor
17    */
18   var SortableTable = tvcm.ui.define('sortable-table');
19
20   var UNSORTED_ARROW = '&#x25BF';
21   var SORT_ASCENDING_ARROW = '&#x25BE';
22   var SORT_DESCENDING_ARROW = '&#x25B4';
23   var SORT_DIR_ASCENDING = 'downward';
24   var SORT_DIR_DESCENDING = 'upward';
25
26   SortableTable.prototype = {
27     __proto__: HTMLTableElement.prototype,
28
29     decorate: function() {
30       this.classList.add('sortable-table');
31       if (!this.tHead)
32         return;
33       var headerRow = this.tHead.rows[0];
34       var currentState = window.history.state;
35       for (var i = 0; i < headerRow.cells.length; i++) {
36         headerRow.cells[i].addEventListener('click',
37                                             this.onItemClicked_, true);
38         headerRow.cells[i].innerHTML += '&nbsp;' + UNSORTED_ARROW;
39       }
40
41       if (currentState && currentState.tableSorting) {
42         var hashCode = this.sortingHashCode_();
43         if (currentState.tableSorting[hashCode]) {
44           this.sort(currentState.tableSorting[hashCode].col,
45                     currentState.tableSorting[hashCode].sortDirection);
46         }
47       }
48     },
49
50     onItemClicked_: function(e) {
51       // 'this' refers to the table cell that has been clicked.
52       var headerRow = this.parentNode;
53       var table = headerRow.parentNode.parentNode;
54       var colIndex = Array.prototype.slice.call(headerRow.cells).indexOf(this);
55       var sortDirection = table.sort(colIndex);
56       var currentState = history.state;
57       if (!currentState.tableSorting)
58         currentState.tableSorting = {};
59       currentState.tableSorting[table.sortingHashCode_()] = {
60         col: colIndex,
61         sortDirection: sortDirection
62       };
63       window.history.pushState(currentState);
64     },
65
66     sort: function(colIndex, opt_sortDirection) {
67       var headerRow = this.tHead.rows[0];
68       var headerCell = headerRow.cells[colIndex];
69
70       if (!headerCell.hasAttribute('sort')) {
71         // we are either sorting a new column (not previously sorted),
72         // or sorting based on a given sort direction (opt_sortDirection).
73         return sortByColumn_(headerRow, headerCell, colIndex,
74                              opt_sortDirection);
75       } else {
76         // resort the current sort column in the other direction
77         return reverseSortDirection_(headerRow, headerCell, opt_sortDirection);
78       }
79       return sortDirection;
80     },
81
82     // A very simple hash function, based only on the header row and
83     // the table location. It is used to check that table loaded
84     // can be sorted according to the given history information.
85     sortingHashCode_: function() {
86       if (this.sortingHashValue_)
87         return this.sortingHashValue_;
88       var headerText = this.tHead.rows[0].innerText;
89       var hash = 0;
90       for (var i = 0; i < headerText.length; i++) {
91         if (headerText.charCodeAt(i) < 127)
92           hash += headerText.charCodeAt(i);
93       }
94
95       // use the table index as well in case the same table
96       // is displayed more than once on a single page.
97       var tableIndex = Array.prototype.slice.call(
98           document.getElementsByClassName('sortable-table')).indexOf(this);
99       this.sortingHashValue_ = tableIndex + '' + hash;
100       return this.sortingHashValue_;
101     }
102   };
103
104   function compareAscending_(a, b) {
105     return compare_(a, b);
106   }
107
108   function compareDescending_(a, b) {
109     return compare_(b, a);
110   }
111
112   function compare_(a, b) {
113     var a1 = parseFloat(a);
114     var b1 = parseFloat(b);
115     if (isNaN(a1) && isNaN(b1))
116       return a.toString().localeCompare(b.toString());
117     if (isNaN(a1))
118       return -1;
119     if (isNaN(b1))
120       return 1;
121     return a1 - b1;
122   }
123
124   function sortByColumn_(headerRow, headerCell, colIndex, opt_sortDirection) {
125     var sortDirection = opt_sortDirection || SORT_DIR_ASCENDING;
126     // remove sort attribute from other header elements.
127     for (var i = 0; i < headerRow.cells.length; i++) {
128       if (headerRow.cells[i].getAttribute('sort')) {
129         headerRow.cells[i].removeAttribute('sort');
130         var headerStr = headerRow.cells[i].innerHTML;
131         headerRow.cells[i].innerHTML =
132             headerStr.substr(0, headerStr.length - 2) + UNSORTED_ARROW;
133       }
134     }
135
136     var headerStr = headerRow.cells[colIndex].innerHTML;
137     headerCell.innerHTML = headerStr.substr(0, headerStr.length - 2) +
138                            (sortDirection == SORT_DIR_ASCENDING ?
139                             SORT_ASCENDING_ARROW : SORT_DESCENDING_ARROW);
140
141     headerCell.setAttribute('sort', sortDirection);
142     var rows = headerRow.parentNode.parentNode.tBodies[0].rows;
143     var tempRows = [];
144     for (var i = 0; i < rows.length; i++) {
145       tempRows.push([rows[i].cells[colIndex].innerText, rows[i]]);
146     }
147
148     tempRows.sort(sortDirection == SORT_DIR_ASCENDING ?
149                       compareAscending_ : compareDescending_);
150
151     for (var j = 0; j < tempRows.length; j++) {
152       headerRow.parentNode.parentNode.tBodies[0].
153           appendChild(tempRows[j][1]);
154     }
155     return sortDirection;
156   }
157
158   function reverseSortDirection_(headerRow, headerCell, opt_sortDirection) {
159     var sortDirection = headerCell.getAttribute('sort');
160     // if it is already sorted in the correct direction, do nothing.
161     if (opt_sortDirection == sortDirection)
162       return sortDirection;
163     sortDirection = sortDirection == SORT_DIR_DESCENDING ?
164                     SORT_DIR_ASCENDING : SORT_DIR_DESCENDING;
165     headerCell.setAttribute('sort', sortDirection);
166     var headerStr = headerCell.innerHTML;
167     headerCell.innerHTML = headerStr.substr(0, headerStr.length - 2) +
168                            (sortDirection == SORT_DIR_ASCENDING ?
169                             SORT_ASCENDING_ARROW : SORT_DESCENDING_ARROW);
170     // instead of re-sorting, we reverse the sorted rows.
171     var headerRow = headerCell.parentNode;
172     var tbody = headerRow.parentNode.parentNode.tBodies[0];
173     var tempRows = [];
174     for (var i = 0; i < tbody.rows.length; i++)
175       tempRows[tempRows.length] = tbody.rows[i];
176     for (var i = tempRows.length - 1; i >= 0; i--)
177       tbody.appendChild(tempRows[i]);
178     return sortDirection;
179   }
180
181   return {
182     SortableTable: SortableTable
183   };
184 });