| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 var g_browserBridge; | 5 var g_browserBridge; |
| 6 var g_mainView; | 6 var g_mainView; |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * Main entry point called once the page has loaded. | 9 * Main entry point called once the page has loaded. |
| 10 */ | 10 */ |
| (...skipping 858 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 869 newRow[aggregateKey] = aggregates[aggregateKey].getValue(); | 869 newRow[aggregateKey] = aggregates[aggregateKey].getValue(); |
| 870 } | 870 } |
| 871 | 871 |
| 872 return mergedRows; | 872 return mergedRows; |
| 873 } | 873 } |
| 874 | 874 |
| 875 // -------------------------------------------------------------------------- | 875 // -------------------------------------------------------------------------- |
| 876 // HTML drawing code | 876 // HTML drawing code |
| 877 // -------------------------------------------------------------------------- | 877 // -------------------------------------------------------------------------- |
| 878 | 878 |
| 879 /** | |
| 880 * Draws a title into |parent| that describes |groupKey|. | |
| 881 */ | |
| 882 function drawGroupTitle(parent, groupKey) { | |
| 883 if (groupKey.length == 0) { | |
| 884 // Empty group key means there was no grouping. | |
| 885 return; | |
| 886 } | |
| 887 | |
| 888 var parent = addNode(parent, 'div'); | |
| 889 parent.className = 'group-title-container'; | |
| 890 | |
| 891 // Each component of the group key represents the "key=value" constraint for | |
| 892 // this group. Show these as an AND separated list. | |
| 893 for (var i = 0; i < groupKey.length; ++i) { | |
| 894 if (i > 0) | |
| 895 addNode(parent, 'i', ' and '); | |
| 896 var e = groupKey[i]; | |
| 897 addNode(parent, 'b', getNameForKey(e.key) + ' = '); | |
| 898 addNode(parent, 'span', e.value); | |
| 899 } | |
| 900 } | |
| 901 | |
| 902 /** | |
| 903 * Renders the information for a particular group. | |
| 904 */ | |
| 905 function drawGroup(parent, groupData, columns, | |
| 906 columnOnClickHandler, currentSortKeys, displaySettings, | |
| 907 expandHandler, shrinkHandler, showAllHandler, | |
| 908 showNoneHandler) { | |
| 909 var div = addNode(parent, 'div'); | |
| 910 div.className = 'group-container'; | |
| 911 | |
| 912 drawGroupTitle(div, groupData.key); | |
| 913 | |
| 914 var table = addNode(div, 'table'); | |
| 915 | |
| 916 drawDataTable(table, groupData, columns, columnOnClickHandler, | |
| 917 currentSortKeys, displaySettings.limit, | |
| 918 expandHandler, shrinkHandler, showAllHandler, | |
| 919 showNoneHandler); | |
| 920 } | |
| 921 | |
| 922 /** | |
| 923 * Renders a row that describes all the aggregate values for |columns|. | |
| 924 */ | |
| 925 function drawAggregateRow(tbody, aggregates, columns) { | |
| 926 var tr = addNode(tbody, 'tr'); | |
| 927 tr.className = 'aggregator-row'; | |
| 928 | |
| 929 for (var i = 0; i < columns.length; ++i) { | |
| 930 var key = columns[i]; | |
| 931 var td = addNode(tr, 'td'); | |
| 932 | |
| 933 // Most of our outputs are numeric, so we want to align them to the right. | |
| 934 // However for the unique counts we will center. | |
| 935 if (KEY_PROPERTIES[key].aggregator == UniquifyAggregator) { | |
| 936 td.align = 'center'; | |
| 937 } else { | |
| 938 td.align = 'right'; | |
| 939 } | |
| 940 | |
| 941 var aggregator = aggregates[key]; | |
| 942 if (aggregator) | |
| 943 td.innerText = aggregator.getValueAsText(); | |
| 944 } | |
| 945 } | |
| 946 | |
| 947 /** | |
| 948 * Renders a table which summarizes all |column| fields for |data|. | |
| 949 */ | |
| 950 function drawDataTable(table, data, columns, columnOnClickHandler, | |
| 951 currentSortKeys, limit, expandHandler, shrinkHandler, | |
| 952 showAllHandler, showNoneHandler) { | |
| 953 table.className = 'results-table'; | |
| 954 var thead = addNode(table, 'thead'); | |
| 955 var tbody = addNode(table, 'tbody'); | |
| 956 | |
| 957 drawAggregateRow(thead, data.aggregates, columns); | |
| 958 drawTableHeader(thead, columns, columnOnClickHandler, currentSortKeys); | |
| 959 drawTableBody(tbody, data.rows, columns, limit); | |
| 960 drawTruncationRow(tbody, data.rows.length, limit, columns.length, | |
| 961 expandHandler, shrinkHandler, showAllHandler, | |
| 962 showNoneHandler); | |
| 963 } | |
| 964 | |
| 965 /** | |
| 966 * Renders a row which describes how many rows the table has, how many are | |
| 967 * currently hidden, and a set of buttons to show more. | |
| 968 */ | |
| 969 function drawTruncationRow(tbody, numRows, limit, numColumns, | |
| 970 expandHandler, shrinkHandler, showAllHandler, | |
| 971 showNoneHandler) { | |
| 972 var numHiddenRows = Math.max(numRows - limit, 0); | |
| 973 var numVisibleRows = numRows - numHiddenRows; | |
| 974 | |
| 975 var tr = addNode(tbody, 'tr'); | |
| 976 tr.className = 'truncation-row'; | |
| 977 var td = addNode(tr, 'td'); | |
| 978 td.colSpan = numColumns; | |
| 979 | |
| 980 addText(td, numRows + ' rows'); | |
| 981 if (numHiddenRows > 0) { | |
| 982 var s = addNode(td, 'span', ' (' + numHiddenRows + ' hidden) '); | |
| 983 s.style.color = 'red'; | |
| 984 } | |
| 985 | |
| 986 if (numVisibleRows > LIMIT_INCREMENT) | |
| 987 addNode(td, 'button', 'Show less').onclick = shrinkHandler; | |
| 988 if (numVisibleRows > 0) | |
| 989 addNode(td, 'button', 'Show none').onclick = showNoneHandler; | |
| 990 | |
| 991 if (numHiddenRows > 0) { | |
| 992 addNode(td, 'button', 'Show more').onclick = expandHandler; | |
| 993 addNode(td, 'button', 'Show all').onclick = showAllHandler; | |
| 994 } | |
| 995 } | |
| 996 | |
| 997 function drawTableHeader(thead, columns, columnOnClickHandler, | |
| 998 currentSortKeys) { | |
| 999 var tr = addNode(thead, 'tr'); | |
| 1000 for (var i = 0; i < columns.length; ++i) { | |
| 1001 var key = columns[i]; | |
| 1002 var th = addNode(tr, 'th', getNameForKey(key)); | |
| 1003 th.onclick = columnOnClickHandler.bind(this, key); | |
| 1004 | |
| 1005 // Draw an indicator if we are currently sorted on this column. | |
| 1006 // TODO(eroman): Should use an icon instead of asterisk! | |
| 1007 for (var j = 0; j < currentSortKeys.length; ++j) { | |
| 1008 if (sortKeysMatch(currentSortKeys[j], key)) { | |
| 1009 var sortIndicator = addNode(th, 'span', '*'); | |
| 1010 sortIndicator.style.color = 'red'; | |
| 1011 if (sortKeyIsReversed(currentSortKeys[j])) { | |
| 1012 // Use double-asterisk for descending columns. | |
| 1013 addText(sortIndicator, '*'); | |
| 1014 } | |
| 1015 break; | |
| 1016 } | |
| 1017 } | |
| 1018 } | |
| 1019 } | |
| 1020 | |
| 1021 function getTextValueForProperty(key, value) { | 879 function getTextValueForProperty(key, value) { |
| 1022 if (value == undefined) { | 880 if (value == undefined) { |
| 1023 // A value may be undefined as a result of having merging rows. We | 881 // A value may be undefined as a result of having merging rows. We |
| 1024 // won't actually draw it, but this might be called by the filter. | 882 // won't actually draw it, but this might be called by the filter. |
| 1025 return ''; | 883 return ''; |
| 1026 } | 884 } |
| 1027 | 885 |
| 1028 var textPrinter = KEY_PROPERTIES[key].textPrinter; | 886 var textPrinter = KEY_PROPERTIES[key].textPrinter; |
| 1029 if (textPrinter) | 887 if (textPrinter) |
| 1030 return textPrinter(value); | 888 return textPrinter(value); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1074 // value, and hence avoid it overflowing! | 932 // value, and hence avoid it overflowing! |
| 1075 var kMinLengthBeforeWrap = 20; | 933 var kMinLengthBeforeWrap = 20; |
| 1076 | 934 |
| 1077 addText(td, text.substr(0, kMinLengthBeforeWrap)); | 935 addText(td, text.substr(0, kMinLengthBeforeWrap)); |
| 1078 for (var i = kMinLengthBeforeWrap; i < text.length; ++i) { | 936 for (var i = kMinLengthBeforeWrap; i < text.length; ++i) { |
| 1079 addNode(td, 'wbr'); | 937 addNode(td, 'wbr'); |
| 1080 addText(td, text.substr(i, 1)); | 938 addText(td, text.substr(i, 1)); |
| 1081 } | 939 } |
| 1082 } | 940 } |
| 1083 | 941 |
| 1084 function drawTableBody(tbody, rows, columns, limit) { | |
| 1085 for (var i = 0; i < rows.length && i < limit; ++i) { | |
| 1086 var e = rows[i]; | |
| 1087 | |
| 1088 var tr = addNode(tbody, 'tr'); | |
| 1089 | |
| 1090 for (var c = 0; c < columns.length; ++c) { | |
| 1091 var key = columns[c]; | |
| 1092 var value = e[key]; | |
| 1093 | |
| 1094 var td = addNode(tr, 'td'); | |
| 1095 drawValueToCell(td, key, value); | |
| 1096 } | |
| 1097 } | |
| 1098 } | |
| 1099 | |
| 1100 // -------------------------------------------------------------------------- | 942 // -------------------------------------------------------------------------- |
| 1101 // Helper code for handling the sort and grouping dropdowns. | 943 // Helper code for handling the sort and grouping dropdowns. |
| 1102 // -------------------------------------------------------------------------- | 944 // -------------------------------------------------------------------------- |
| 1103 | 945 |
| 1104 function addOptionsForGroupingSelect(select) { | 946 function addOptionsForGroupingSelect(select) { |
| 1105 // Add "no group" choice. | 947 // Add "no group" choice. |
| 1106 addNode(select, 'option', '---').value = ''; | 948 addNode(select, 'option', '---').value = ''; |
| 1107 | 949 |
| 1108 for (var i = 0; i < GROUPING_DROPDOWN_CHOICES.length; ++i) { | 950 for (var i = 0; i < GROUPING_DROPDOWN_CHOICES.length; ++i) { |
| 1109 var key = GROUPING_DROPDOWN_CHOICES[i]; | 951 var key = GROUPING_DROPDOWN_CHOICES[i]; |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1373 return columns; | 1215 return columns; |
| 1374 }, | 1216 }, |
| 1375 | 1217 |
| 1376 redrawData_: function() { | 1218 redrawData_: function() { |
| 1377 // Clear the results div, sine we may be overwriting older data. | 1219 // Clear the results div, sine we may be overwriting older data. |
| 1378 var parent = $(RESULTS_DIV_ID); | 1220 var parent = $(RESULTS_DIV_ID); |
| 1379 parent.innerHTML = ''; | 1221 parent.innerHTML = ''; |
| 1380 | 1222 |
| 1381 var columns = this.getVisibleColumnKeys_(); | 1223 var columns = this.getVisibleColumnKeys_(); |
| 1382 | 1224 |
| 1383 var columnOnClickHandler = this.onClickColumn_.bind(this); | |
| 1384 | |
| 1385 // Draw each group. | 1225 // Draw each group. |
| 1386 for (var i = 0; i < this.sortedGroupKeys_.length; ++i) { | 1226 for (var i = 0; i < this.sortedGroupKeys_.length; ++i) { |
| 1387 var k = this.sortedGroupKeys_[i]; | 1227 var k = this.sortedGroupKeys_[i]; |
| 1388 drawGroup(parent, | 1228 this.drawGroup_(parent, k, columns); |
| 1389 this.groupedData_[k], | 1229 } |
| 1390 columns, | 1230 }, |
| 1391 columnOnClickHandler, | 1231 |
| 1392 this.currentSortKeys_, | 1232 /** |
| 1393 this.getGroupDisplaySettings_(k), | 1233 * Renders the information for a particular group. |
| 1394 this.changeGroupDisplayLimit_.bind(this, k, LIMIT_INCREMENT), | 1234 */ |
| 1395 this.changeGroupDisplayLimit_.bind(this, k, -LIMIT_INCREMENT), | 1235 drawGroup_: function(parent, groupKey, columns) { |
| 1396 this.changeGroupDisplayLimit_.bind(this, k, Infinity), | 1236 var groupData = this.groupedData_[groupKey]; |
| 1397 this.changeGroupDisplayLimit_.bind(this, k, -Infinity)); | 1237 |
| 1238 var div = addNode(parent, 'div'); |
| 1239 div.className = 'group-container'; |
| 1240 |
| 1241 this.drawGroupTitle_(div, groupData.key); |
| 1242 |
| 1243 var table = addNode(div, 'table'); |
| 1244 |
| 1245 this.drawDataTable_(table, groupData, columns, groupKey); |
| 1246 }, |
| 1247 |
| 1248 /** |
| 1249 * Draws a title into |parent| that describes |groupKey|. |
| 1250 */ |
| 1251 drawGroupTitle_: function(parent, groupKey) { |
| 1252 if (groupKey.length == 0) { |
| 1253 // Empty group key means there was no grouping. |
| 1254 return; |
| 1255 } |
| 1256 |
| 1257 var parent = addNode(parent, 'div'); |
| 1258 parent.className = 'group-title-container'; |
| 1259 |
| 1260 // Each component of the group key represents the "key=value" constraint |
| 1261 // for this group. Show these as an AND separated list. |
| 1262 for (var i = 0; i < groupKey.length; ++i) { |
| 1263 if (i > 0) |
| 1264 addNode(parent, 'i', ' and '); |
| 1265 var e = groupKey[i]; |
| 1266 addNode(parent, 'b', getNameForKey(e.key) + ' = '); |
| 1267 addNode(parent, 'span', e.value); |
| 1268 } |
| 1269 }, |
| 1270 |
| 1271 /** |
| 1272 * Renders a table which summarizes all |column| fields for |data|. |
| 1273 */ |
| 1274 drawDataTable_: function(table, data, columns, groupKey) { |
| 1275 table.className = 'results-table'; |
| 1276 var thead = addNode(table, 'thead'); |
| 1277 var tbody = addNode(table, 'tbody'); |
| 1278 |
| 1279 var displaySettings = this.getGroupDisplaySettings_(groupKey); |
| 1280 var limit = displaySettings.limit; |
| 1281 |
| 1282 this.drawAggregateRow_(thead, data.aggregates, columns); |
| 1283 this.drawTableHeader_(thead, columns); |
| 1284 this.drawTableBody_(tbody, data.rows, columns, limit); |
| 1285 this.drawTruncationRow_(tbody, data.rows.length, limit, columns.length, |
| 1286 groupKey); |
| 1287 }, |
| 1288 |
| 1289 drawTableHeader_: function(thead, columns) { |
| 1290 var tr = addNode(thead, 'tr'); |
| 1291 for (var i = 0; i < columns.length; ++i) { |
| 1292 var key = columns[i]; |
| 1293 var th = addNode(tr, 'th', getNameForKey(key)); |
| 1294 th.onclick = this.onClickColumn_.bind(this, key); |
| 1295 |
| 1296 // Draw an indicator if we are currently sorted on this column. |
| 1297 // TODO(eroman): Should use an icon instead of asterisk! |
| 1298 for (var j = 0; j < this.currentSortKeys_.length; ++j) { |
| 1299 if (sortKeysMatch(this.currentSortKeys_[j], key)) { |
| 1300 var sortIndicator = addNode(th, 'span', '*'); |
| 1301 sortIndicator.style.color = 'red'; |
| 1302 if (sortKeyIsReversed(this.currentSortKeys_[j])) { |
| 1303 // Use double-asterisk for descending columns. |
| 1304 addText(sortIndicator, '*'); |
| 1305 } |
| 1306 break; |
| 1307 } |
| 1308 } |
| 1309 } |
| 1310 }, |
| 1311 |
| 1312 drawTableBody_: function(tbody, rows, columns, limit) { |
| 1313 for (var i = 0; i < rows.length && i < limit; ++i) { |
| 1314 var e = rows[i]; |
| 1315 |
| 1316 var tr = addNode(tbody, 'tr'); |
| 1317 |
| 1318 for (var c = 0; c < columns.length; ++c) { |
| 1319 var key = columns[c]; |
| 1320 var value = e[key]; |
| 1321 |
| 1322 var td = addNode(tr, 'td'); |
| 1323 drawValueToCell(td, key, value); |
| 1324 } |
| 1325 } |
| 1326 }, |
| 1327 |
| 1328 /** |
| 1329 * Renders a row that describes all the aggregate values for |columns|. |
| 1330 */ |
| 1331 drawAggregateRow_: function(tbody, aggregates, columns) { |
| 1332 var tr = addNode(tbody, 'tr'); |
| 1333 tr.className = 'aggregator-row'; |
| 1334 |
| 1335 for (var i = 0; i < columns.length; ++i) { |
| 1336 var key = columns[i]; |
| 1337 var td = addNode(tr, 'td'); |
| 1338 |
| 1339 // Most of our outputs are numeric, so we want to align them to the |
| 1340 // right. However for the unique counts we will center. |
| 1341 if (KEY_PROPERTIES[key].aggregator == UniquifyAggregator) { |
| 1342 td.align = 'center'; |
| 1343 } else { |
| 1344 td.align = 'right'; |
| 1345 } |
| 1346 |
| 1347 var aggregator = aggregates[key]; |
| 1348 if (aggregator) |
| 1349 td.innerText = aggregator.getValueAsText(); |
| 1350 } |
| 1351 }, |
| 1352 |
| 1353 /** |
| 1354 * Renders a row which describes how many rows the table has, how many are |
| 1355 * currently hidden, and a set of buttons to show more. |
| 1356 */ |
| 1357 drawTruncationRow_: function(tbody, numRows, limit, numColumns, groupKey) { |
| 1358 var numHiddenRows = Math.max(numRows - limit, 0); |
| 1359 var numVisibleRows = numRows - numHiddenRows; |
| 1360 |
| 1361 var tr = addNode(tbody, 'tr'); |
| 1362 tr.className = 'truncation-row'; |
| 1363 var td = addNode(tr, 'td'); |
| 1364 td.colSpan = numColumns; |
| 1365 |
| 1366 addText(td, numRows + ' rows'); |
| 1367 if (numHiddenRows > 0) { |
| 1368 var s = addNode(td, 'span', ' (' + numHiddenRows + ' hidden) '); |
| 1369 s.style.color = 'red'; |
| 1370 } |
| 1371 |
| 1372 if (numVisibleRows > LIMIT_INCREMENT) { |
| 1373 addNode(td, 'button', 'Show less').onclick = |
| 1374 this.changeGroupDisplayLimit_.bind( |
| 1375 this, groupKey, -LIMIT_INCREMENT); |
| 1376 } |
| 1377 if (numVisibleRows > 0) { |
| 1378 addNode(td, 'button', 'Show none').onclick = |
| 1379 this.changeGroupDisplayLimit_.bind(this, groupKey, -Infinity); |
| 1380 } |
| 1381 |
| 1382 if (numHiddenRows > 0) { |
| 1383 addNode(td, 'button', 'Show more').onclick = |
| 1384 this.changeGroupDisplayLimit_.bind(this, groupKey, LIMIT_INCREMENT); |
| 1385 addNode(td, 'button', 'Show all').onclick = |
| 1386 this.changeGroupDisplayLimit_.bind(this, groupKey, Infinity); |
| 1398 } | 1387 } |
| 1399 }, | 1388 }, |
| 1400 | 1389 |
| 1401 /** | 1390 /** |
| 1402 * Adjusts the row limit for group |groupKey| by |delta|. | 1391 * Adjusts the row limit for group |groupKey| by |delta|. |
| 1403 */ | 1392 */ |
| 1404 changeGroupDisplayLimit_: function(groupKey, delta) { | 1393 changeGroupDisplayLimit_: function(groupKey, delta) { |
| 1405 // Get the current settings for this group. | 1394 // Get the current settings for this group. |
| 1406 var settings = this.getGroupDisplaySettings_(groupKey, true); | 1395 var settings = this.getGroupDisplaySettings_(groupKey, true); |
| 1407 | 1396 |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1746 groupKey.push(entry); | 1735 groupKey.push(entry); |
| 1747 } | 1736 } |
| 1748 | 1737 |
| 1749 return JSON.stringify(groupKey); | 1738 return JSON.stringify(groupKey); |
| 1750 }; | 1739 }; |
| 1751 }, | 1740 }, |
| 1752 }; | 1741 }; |
| 1753 | 1742 |
| 1754 return MainView; | 1743 return MainView; |
| 1755 })(); | 1744 })(); |
| OLD | NEW |