OLD | NEW |
1 | 1 |
2 // Helpers | 2 // Helpers |
3 | 3 |
4 function $(id) { | 4 function $(id) { |
5 return document.getElementById(id); | 5 return document.getElementById(id); |
6 } | 6 } |
7 | 7 |
8 // TODO(arv): Remove these when classList is available in HTML5. | 8 // TODO(arv): Remove these when classList is available in HTML5. |
9 // https://bugs.webkit.org/show_bug.cgi?id=20709 | 9 // https://bugs.webkit.org/show_bug.cgi?id=20709 |
10 function hasClass(el, name) { | 10 function hasClass(el, name) { |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 | 87 |
88 gotMostVisited = true; | 88 gotMostVisited = true; |
89 onDataLoaded(); | 89 onDataLoaded(); |
90 } | 90 } |
91 | 91 |
92 function downloadsList(data) { | 92 function downloadsList(data) { |
93 logEvent('received downloads'); | 93 logEvent('received downloads'); |
94 | 94 |
95 // We should only show complete downloads. | 95 // We should only show complete downloads. |
96 data = data.filter(function(d) { | 96 data = data.filter(function(d) { |
| 97 d.type = 'download'; |
| 98 d.timestamp = d.started; |
97 return d.state == 'COMPLETE'; | 99 return d.state == 'COMPLETE'; |
98 }); | 100 }); |
99 data.length = Math.min(data.length, 5); | 101 |
100 processData('#download-items', data); | 102 gotRecentItems(data, 'download'); |
101 } | 103 } |
102 | 104 |
103 function recentlyClosedTabs(data) { | 105 function recentlyClosedTabs(data) { |
104 logEvent('received recently closed tabs'); | 106 logEvent('received recently closed tabs'); |
105 data.length = Math.min(data.length, 5); | 107 |
106 processData('#tab-items', data); | 108 // We handle timestamp 0 as now |
| 109 data.forEach(function(d) { |
| 110 if (d.timestamp == 0) { |
| 111 d.timestamp = Date.now(); |
| 112 } |
| 113 }); |
| 114 |
| 115 gotRecentItems(data); |
| 116 } |
| 117 |
| 118 var recentItems = []; |
| 119 var recentItemKeys = {}; |
| 120 |
| 121 function getRecentItemKey(d) { |
| 122 // type == window does not have a URL |
| 123 return d.type + (d.url || d.sessionId) + d.timestamp; |
| 124 } |
| 125 |
| 126 function gotRecentItems(data) { |
| 127 // Add new items |
| 128 for (var i = 0; i < data.length; i++) { |
| 129 var d = data[i]; |
| 130 var key = getRecentItemKey(d); |
| 131 if (!(key in recentItemKeys)) { |
| 132 recentItems.push(d); |
| 133 recentItemKeys[key] = true; |
| 134 } |
| 135 } |
| 136 |
| 137 recentItems.sort(function(d1, d2) { |
| 138 return d2.timestamp - d1.timestamp; |
| 139 }); |
| 140 |
| 141 renderRecentItems(); |
| 142 } |
| 143 |
| 144 function renderRecentItems() { |
| 145 // When tips are shown we only show 10 items |
| 146 var desiredCount = shownSections & Section.TIPS ? 10 : 20; |
| 147 desiredCount -= 2; // Show all downloads and all history uses two rows. |
| 148 |
| 149 processData('#recent-activities > .item-container', |
| 150 recentItems.slice(0, desiredCount)); |
107 } | 151 } |
108 | 152 |
109 function onShownSections(mask) { | 153 function onShownSections(mask) { |
110 logEvent('received shown sections'); | 154 logEvent('received shown sections'); |
111 if (mask != shownSections) { | 155 if (mask != shownSections) { |
| 156 var oldShownSections = shownSections; |
| 157 shownSections = mask; |
112 | 158 |
113 // Only invalidate most visited if needed. | 159 // Only invalidate most visited if needed. |
114 if ((mask & Section.THUMB) != (shownSections & Section.THUMB) || | 160 if ((mask & Section.THUMB) != (oldShownSections & Section.THUMB) || |
115 (mask & Section.LIST) != (shownSections & Section.LIST)) { | 161 (mask & Section.LIST) != (oldShownSections & Section.LIST)) { |
116 mostVisited.invalidate(); | 162 mostVisited.invalidate(); |
117 } | 163 } |
118 | 164 |
119 shownSections = mask; | 165 if ((mask & Section.RECENT) != (oldShownSections & Section.RECENT)) { |
| 166 notifyLowerSectionForChange(Section.RECENT); |
| 167 } |
| 168 |
| 169 if ((mask & Section.TIPS) != (oldShownSections & Section.TIPS)) { |
| 170 notifyLowerSectionForChange(Section.TIPS); |
| 171 } |
| 172 |
120 mostVisited.updateDisplayMode(); | 173 mostVisited.updateDisplayMode(); |
121 layoutLowerSections(); | 174 layoutLowerSections(); |
122 updateOptionMenu(); | 175 updateOptionMenu(); |
123 } | 176 } |
124 | 177 |
125 gotShownSections = true; | 178 gotShownSections = true; |
126 onDataLoaded(); | 179 onDataLoaded(); |
127 } | 180 } |
128 | 181 |
129 function saveShownSections() { | 182 function saveShownSections() { |
130 chrome.send('setShownSections', [String(shownSections)]); | 183 chrome.send('setShownSections', [String(shownSections)]); |
131 } | 184 } |
132 | 185 |
133 function tips(data) { | 186 function tips(data) { |
134 logEvent('received tips data'); | 187 logEvent('received tips data'); |
135 data.length = Math.min(data.length, 5); | 188 data.length = Math.min(data.length, 5); |
136 processData('#tip-items', data); | 189 processData('#tip-items', data); |
137 } | 190 } |
138 | 191 |
139 // This global variable is used to skip parts of the DOM tree for the global | |
140 // jst processing done by the i18n. | |
141 var processing = false; | |
142 | |
143 function processData(selector, data) { | 192 function processData(selector, data) { |
144 var output = document.querySelector(selector); | 193 var output = document.querySelector(selector); |
145 | 194 |
146 // Wait until ready | 195 // Wait until ready |
147 if (typeof JsEvalContext !== 'function' || !output) { | 196 if (typeof JsEvalContext !== 'function' || !output) { |
148 logEvent('JsEvalContext is not yet available, ' + selector); | 197 logEvent('JsEvalContext is not yet available, ' + selector); |
149 document.addEventListener('DOMContentLoaded', function() { | 198 document.addEventListener('DOMContentLoaded', function() { |
150 processData(selector, data); | 199 processData(selector, data); |
151 }); | 200 }); |
152 } else { | 201 } else { |
153 var d0 = Date.now(); | 202 var d0 = Date.now(); |
154 var input = new JsEvalContext(data); | 203 var input = new JsEvalContext(data); |
155 processing = true; | |
156 jstProcess(input, output); | 204 jstProcess(input, output); |
157 processing = false; | |
158 logEvent('processData: ' + selector + ', ' + (Date.now() - d0)); | 205 logEvent('processData: ' + selector + ', ' + (Date.now() - d0)); |
159 } | 206 } |
160 } | 207 } |
161 | 208 |
162 function getThumbnailClassName(data) { | 209 function getThumbnailClassName(data) { |
163 return 'thumbnail-container' + | 210 return 'thumbnail-container' + |
164 (data.pinned ? ' pinned' : '') + | 211 (data.pinned ? ' pinned' : '') + |
165 (data.filler ? ' filler' : ''); | 212 (data.filler ? ' filler' : ''); |
166 } | 213 } |
167 | 214 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 // THUMBS and LIST are mutually exclusive. | 312 // THUMBS and LIST are mutually exclusive. |
266 if (section == Section.THUMB) { | 313 if (section == Section.THUMB) { |
267 // hide LIST | 314 // hide LIST |
268 shownSections &= ~Section.LIST; | 315 shownSections &= ~Section.LIST; |
269 mostVisited.invalidate(); | 316 mostVisited.invalidate(); |
270 } else if (section == Section.LIST) { | 317 } else if (section == Section.LIST) { |
271 // hide THUMB | 318 // hide THUMB |
272 shownSections &= ~Section.THUMB; | 319 shownSections &= ~Section.THUMB; |
273 mostVisited.invalidate(); | 320 mostVisited.invalidate(); |
274 } else { | 321 } else { |
275 notifyLowerSectionForChange(section, false); | 322 notifyLowerSectionForChange(section); |
276 layoutLowerSections(); | 323 layoutLowerSections(); |
277 } | 324 } |
278 | 325 |
279 updateOptionMenu(); | 326 updateOptionMenu(); |
280 mostVisited.updateDisplayMode(); | 327 mostVisited.updateDisplayMode(); |
281 mostVisited.layout(); | 328 mostVisited.layout(); |
282 } | 329 } |
283 } | 330 } |
284 | 331 |
285 function hideSection(section) { | 332 function hideSection(section) { |
286 if (section & shownSections) { | 333 if (section & shownSections) { |
287 shownSections &= ~section; | 334 shownSections &= ~section; |
288 | 335 |
289 if (section & Section.THUMB || section & Section.LIST) { | 336 if (section & Section.THUMB || section & Section.LIST) { |
290 mostVisited.invalidate(); | 337 mostVisited.invalidate(); |
291 } | 338 } |
292 | 339 |
293 if (section & Section.RECENT|| section & Section.TIPS) { | 340 if (section & Section.RECENT || section & Section.TIPS) { |
294 notifyLowerSectionForChange(section, true); | 341 notifyLowerSectionForChange(section); |
295 layoutLowerSections(); | 342 layoutLowerSections(); |
296 } | 343 } |
297 | 344 |
298 updateOptionMenu(); | 345 updateOptionMenu(); |
299 mostVisited.updateDisplayMode(); | 346 mostVisited.updateDisplayMode(); |
300 mostVisited.layout(); | 347 mostVisited.layout(); |
301 } | 348 } |
302 } | 349 } |
303 | 350 |
304 function notifyLowerSectionForChange(section, large) { | 351 function notifyLowerSectionForChange(section) { |
305 // Notify recent and tips if they need to display more data. | 352 // Notify recent and tips if they need to display more data. |
306 if (section == Section.RECENT || section == Section.TIPS) { | 353 if (section == Section.RECENT || section == Section.TIPS) { |
307 // we are hiding one of them so if the other one is visible it is now | |
308 // {@code large}. | |
309 if (shownSections & Section.RECENT) { | 354 if (shownSections & Section.RECENT) { |
310 recentChangedSize(large); | 355 recentChangedSize(!(shownSections & Section.TIPS)); |
311 } else if (shownSections & Section.TIPS) { | 356 } |
312 tipsChangedSize(large); | 357 if (shownSections & Section.TIPS) { |
| 358 tipsChangedSize(!(shownSections & Section.RECENT)); |
313 } | 359 } |
314 } | 360 } |
315 } | 361 } |
316 | 362 |
317 var mostVisited = { | 363 var mostVisited = { |
318 getItem: function(el) { | 364 getItem: function(el) { |
319 return findAncestorByClass(el, 'thumbnail-container'); | 365 return findAncestorByClass(el, 'thumbnail-container'); |
320 }, | 366 }, |
321 | 367 |
322 getHref: function(el) { | 368 getHref: function(el) { |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 } | 602 } |
557 }); | 603 }); |
558 | 604 |
559 this.dirty_ = false; | 605 this.dirty_ = false; |
560 | 606 |
561 logEvent('mostVisited.layout: ' + (Date.now() - d0)); | 607 logEvent('mostVisited.layout: ' + (Date.now() - d0)); |
562 } | 608 } |
563 }; | 609 }; |
564 | 610 |
565 function recentChangedSize(large) { | 611 function recentChangedSize(large) { |
566 // TODO(arv): Implement | 612 if (large) { |
| 613 addClass($('recent-activities'), 'large'); |
| 614 } else { |
| 615 removeClass($('recent-activities'), 'large'); |
| 616 } |
| 617 |
| 618 renderRecentItems(); |
567 } | 619 } |
568 | 620 |
569 function tipsChangedSize(large) { | 621 function tipsChangedSize(large) { |
570 // TODO(arv): Implement | 622 // TODO(arv): Implement |
571 } | 623 } |
572 | 624 |
573 // Recent activities | 625 // Recent activities |
574 | 626 |
575 function layoutLowerSections() { | 627 function layoutLowerSections() { |
576 // This lower sections are inline blocks so all we need to do is to set the | 628 // This lower sections are inline blocks so all we need to do is to set the |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
917 }); | 969 }); |
918 | 970 |
919 function handleIfEnterKey(f) { | 971 function handleIfEnterKey(f) { |
920 return function(e) { | 972 return function(e) { |
921 if (e.keyIdentifier == 'Enter') { | 973 if (e.keyIdentifier == 'Enter') { |
922 f(e); | 974 f(e); |
923 } | 975 } |
924 }; | 976 }; |
925 } | 977 } |
926 | 978 |
927 $('downloads').addEventListener('click', maybeOpenFile); | |
928 $('downloads').addEventListener('keydown', handleIfEnterKey(maybeOpenFile)); | |
929 | |
930 function maybeOpenFile(e) { | 979 function maybeOpenFile(e) { |
931 var el = findAncestor(e.target, function(el) { | 980 var el = findAncestor(e.target, function(el) { |
932 return el.fileId !== undefined; | 981 return el.fileId !== undefined; |
933 }); | 982 }); |
934 if (el) { | 983 if (el) { |
935 chrome.send('openFile', [String(el.fileId)]); | 984 chrome.send('openFile', [String(el.fileId)]); |
936 e.preventDefault(); | 985 e.preventDefault(); |
937 } | 986 } |
938 } | 987 } |
939 | 988 |
940 var recentTabs = $('recent-tabs'); | |
941 recentTabs.addEventListener('click', maybeReopenTab); | |
942 recentTabs.addEventListener('keydown', handleIfEnterKey(maybeReopenTab)); | |
943 | |
944 function maybeReopenTab(e) { | 989 function maybeReopenTab(e) { |
945 var el = findAncestor(e.target, function(el) { | 990 var el = findAncestor(e.target, function(el) { |
946 return el.sessionId !== undefined; | 991 return el.sessionId !== undefined; |
947 }); | 992 }); |
948 if (el) { | 993 if (el) { |
949 chrome.send('reopenTab', [String(el.sessionId)]); | 994 chrome.send('reopenTab', [String(el.sessionId)]); |
950 e.preventDefault(); | 995 e.preventDefault(); |
951 } | 996 } |
952 } | 997 } |
953 | 998 |
954 recentTabs.addEventListener('mouseover', maybeShowWindowMenu); | |
955 recentTabs.addEventListener('focus', maybeShowWindowMenu, true); | |
956 | |
957 | |
958 function maybeShowWindowMenu(e) { | 999 function maybeShowWindowMenu(e) { |
959 var el = findAncestor(e.target, function(el) { | 1000 var f = function(el) { |
960 return el.tabItems !== undefined; | 1001 return el.tabItems !== undefined; |
961 }); | 1002 }; |
962 if (el) { | 1003 var el = findAncestor(e.target, f); |
| 1004 var relatedEl = findAncestor(e.relatedTarget, f); |
| 1005 if (el && el != relatedEl) { |
963 windowMenu.show(e, el, el.tabItems); | 1006 windowMenu.show(e, el, el.tabItems); |
964 } | 1007 } |
965 } | 1008 } |
966 | 1009 |
| 1010 |
| 1011 var recentActivitiesElement = $('recent-activities'); |
| 1012 recentActivitiesElement.addEventListener('click', maybeOpenFile); |
| 1013 recentActivitiesElement.addEventListener('keydown', |
| 1014 handleIfEnterKey(maybeOpenFile)); |
| 1015 |
| 1016 recentActivitiesElement.addEventListener('click', maybeReopenTab); |
| 1017 recentActivitiesElement.addEventListener('keydown', |
| 1018 handleIfEnterKey(maybeReopenTab)); |
| 1019 |
| 1020 recentActivitiesElement.addEventListener('mouseover', maybeShowWindowMenu); |
| 1021 recentActivitiesElement.addEventListener('focus', maybeShowWindowMenu, true); |
| 1022 |
967 /** | 1023 /** |
968 * This object represents a window/tooltip representing a closed window. It is | 1024 * This object represents a window/tooltip representing a closed window. It is |
969 * shown when hovering over a closed window item or when the item is focused. It | 1025 * shown when hovering over a closed window item or when the item is focused. It |
970 * gets hidden when blurred or when mousing out of the menu or the item. | 1026 * gets hidden when blurred or when mousing out of the menu or the item. |
971 * @param {Element} menuEl The element to use as the menu. | 1027 * @param {Element} menuEl The element to use as the menu. |
972 * @constructor | 1028 * @constructor |
973 */ | 1029 */ |
974 function WindowMenu(menuEl) { | 1030 function WindowMenu(menuEl) { |
| 1031 // TODO(arv): Rename WindowTooltip and make it behave even more like a |
| 1032 // tooltip. |
975 this.menuEl = menuEl; | 1033 this.menuEl = menuEl; |
976 var self = this; | |
977 this.boundHide_ = bind(this.hide, this); | 1034 this.boundHide_ = bind(this.hide, this); |
978 menuEl.onmouseover = function() { | 1035 this.boundHandleMouseOut_ = bind(this.handleMouseOut, this); |
979 clearTimeout(self.timer); | |
980 }; | |
981 menuEl.onmouseout = this.boundHide_; | |
982 } | 1036 } |
983 | 1037 |
984 WindowMenu.prototype = { | 1038 WindowMenu.prototype = { |
985 timer: 0, | 1039 timer: 0, |
986 show: function(e, linkEl, tabs) { | 1040 show: function(e, linkEl, tabs) { |
987 optionMenu.hide(); | 1041 optionMenu.hide(); |
988 | 1042 |
989 clearTimeout(this.timer); | 1043 clearTimeout(this.timer); |
990 processData('#window-menu', tabs); | 1044 processData('#window-menu', tabs); |
991 var rect = linkEl.getBoundingClientRect(); | 1045 var rect = linkEl.getBoundingClientRect(); |
992 var bodyRect = document.body.getBoundingClientRect() | 1046 var bodyRect = document.body.getBoundingClientRect() |
993 var rtl = document.documentElement.dir == 'rtl'; | 1047 var rtl = document.documentElement.dir == 'rtl'; |
994 | 1048 |
995 this.menuEl.style.display = 'block'; | 1049 this.menuEl.style.display = 'block'; |
996 this.menuEl.style.left = (rtl ? | 1050 // When focused show below, like a drop down menu. |
997 rect.left + bodyRect.left + rect.width - this.menuEl.offsetWidth : | 1051 if (e.type == 'focus') { |
998 rect.left + bodyRect.left) + 'px'; | 1052 this.menuEl.style.left = (rtl ? |
999 this.menuEl.style.top = rect.top + bodyRect.top + rect.height + 'px'; | 1053 rect.left + bodyRect.left + rect.width - this.menuEl.offsetWidth : |
| 1054 rect.left + bodyRect.left) + 'px'; |
| 1055 this.menuEl.style.top = rect.top + bodyRect.top + rect.height + 'px'; |
| 1056 } else { |
| 1057 this.menuEl.style.left = bodyRect.left + (rtl ? |
| 1058 e.clientX - this.menuEl.offsetWidth : |
| 1059 e.clientX) + 'px'; |
| 1060 this.menuEl.style.top = e.clientY + bodyRect.top + 'px'; |
| 1061 } |
1000 | 1062 |
1001 if (e.type == 'focus') { | 1063 if (e.type == 'focus') { |
1002 linkEl.onblur = this.boundHide_; | 1064 linkEl.onblur = this.boundHide_; |
1003 } else { // mouseover | 1065 } else { // mouseover |
1004 linkEl.onmouseout = this.boundHide_; | 1066 linkEl.onmouseout = this.boundHandleMouseOut_; |
1005 } | 1067 } |
1006 }, | 1068 }, |
1007 hide: function() { | 1069 handleMouseOut: function(e) { |
| 1070 // Don't hide when move to another item in the link. |
| 1071 var f = function(el) { |
| 1072 return el.tabItems !== undefined; |
| 1073 }; |
| 1074 var el = findAncestor(e.target, f); |
| 1075 var relatedEl = findAncestor(e.relatedTarget, f); |
| 1076 if (el && el != relatedEl) { |
| 1077 this.hide(); |
| 1078 } |
| 1079 }, |
| 1080 hide: function(e) { |
1008 // Delay before hiding. | 1081 // Delay before hiding. |
1009 var self = this; | 1082 var self = this; |
1010 this.timer = setTimeout(function() { | 1083 this.timer = setTimeout(function() { |
1011 self.menuEl.style.display = 'none'; | 1084 self.menuEl.style.display = 'none'; |
1012 }, 100); | 1085 }, 100); |
1013 } | 1086 } |
1014 }; | 1087 }; |
1015 | 1088 |
1016 var windowMenu = new WindowMenu($('window-menu')); | 1089 var windowMenu = new WindowMenu($('window-menu')); |
1017 | 1090 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1203 el.addEventListener('dragover', bind(this.handleDragOver, this)); | 1276 el.addEventListener('dragover', bind(this.handleDragOver, this)); |
1204 el.addEventListener('dragleave', bind(this.handleDragLeave, this)); | 1277 el.addEventListener('dragleave', bind(this.handleDragLeave, this)); |
1205 el.addEventListener('drop', bind(this.handleDrop, this)); | 1278 el.addEventListener('drop', bind(this.handleDrop, this)); |
1206 el.addEventListener('dragend', bind(this.handleDragEnd, this)); | 1279 el.addEventListener('dragend', bind(this.handleDragEnd, this)); |
1207 el.addEventListener('drag', bind(this.handleDrag, this)); | 1280 el.addEventListener('drag', bind(this.handleDrag, this)); |
1208 el.addEventListener('mousedown', bind(this.handleMouseDown, this)); | 1281 el.addEventListener('mousedown', bind(this.handleMouseDown, this)); |
1209 } | 1282 } |
1210 }; | 1283 }; |
1211 | 1284 |
1212 dnd.init(); | 1285 dnd.init(); |
OLD | NEW |