Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Side by Side Diff: chrome/browser/resources/ntp_search/thumbnail_page.js

Issue 10829131: Refactoring NTP5: new implementation of TilePage and MostVisitedPage (which now inherits from Thumb… (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 cr.define('ntp', function() { 5 cr.define('ntp', function() {
6 'use strict'; 6 'use strict';
7 7
8 var TilePage = ntp.TilePage; 8 var Tile = ntp.Tile2;
9 var TilePage = ntp.TilePage2;
9 10
10 /** 11 /**
11 * A counter for generating unique tile IDs. 12 * A counter for generating unique tile IDs.
12 */ 13 */
13 var tileID = 0; 14 var tileID = 0;
14 15
15 /** 16 /**
16 * Creates a new Most Visited object for tiling. 17 * Creates a new Most Visited object for tiling.
jeremycho_google 2012/08/02 03:00:49 most visited (please make another pass cleaning th
pedrosimonetti2 2012/08/03 18:14:12 Done.
17 * @constructor 18 * @constructor
jeremycho_google 2012/08/02 03:00:49 @param
pedrosimonetti2 2012/08/03 18:14:12 Done.
18 * @extends {HTMLAnchorElement} 19 * @extends {HTMLAnchorElement}
19 */ 20 */
20 function MostVisited() { 21 function Thumbnail(gridValues) {
21 var el = cr.doc.createElement('a'); 22 var el = cr.doc.createElement('a');
22 el.__proto__ = MostVisited.prototype; 23 el.__proto__ = Thumbnail.prototype;
23 el.initialize(); 24 el.initialize(gridValues);
24 25
25 return el; 26 return el;
26 } 27 }
27 28
28 MostVisited.prototype = { 29 Thumbnail.prototype = Tile.subclass({
29 __proto__: HTMLAnchorElement.prototype, 30 __proto__: HTMLAnchorElement.prototype,
30 31
31 initialize: function() { 32 // TODO(pedrosimonetti): document
33 isRemovable: true,
34
35 initialize: function(gridValues) {
36 Tile.prototype.initialize.apply(this, arguments);
32 this.reset(); 37 this.reset();
33 38
34 this.addEventListener('click', this.handleClick_); 39 this.addEventListener('click', this.handleClick_);
35 this.addEventListener('keydown', this.handleKeyDown_); 40 this.addEventListener('keydown', this.handleKeyDown_);
36 }, 41 },
37 42
38 get index() { 43 get index() {
jeremycho_google 2012/08/02 00:19:11 Can this be deleted? It's almost identical to 'in
pedrosimonetti2 2012/08/03 18:14:12 Done.
39 assert(this.tile); 44 assert(this.tile);
40 return this.tile.index; 45 return this.tile.index;
41 }, 46 },
42 47
43 get data() { 48 get data() {
44 return this.data_; 49 return this.data_;
45 }, 50 },
46 51
47 /** 52 /**
48 * Clears the DOM hierarchy for this node, setting it back to the default 53 * Clears the DOM hierarchy for this node, setting it back to the default
49 * for a blank thumbnail. 54 * for a blank thumbnail.
50 */ 55 */
51 reset: function() { 56 reset: function() {
52 this.className = 'most-visited filler real'; 57 this.className = 'tile-content most-visited real';
53 this.innerHTML = 58 this.innerHTML =
54 '<span class="thumbnail-wrapper fills-parent">' + 59 '<span class="thumbnail-wrapper fills-parent">' +
55 '<div class="close-button"></div>' + 60 (this.isRemovable ? '<div class="close-button"></div>' : '') +
56 '<span class="thumbnail fills-parent">' + 61 '<span class="thumbnail fills-parent">' +
62 // TODO(pedrosimonetti): remove all references (HTML+CSS+JS)
57 // thumbnail-shield provides a gradient fade effect. 63 // thumbnail-shield provides a gradient fade effect.
58 '<div class="thumbnail-shield fills-parent"></div>' + 64 //'<div class="thumbnail-shield fills-parent"></div>' +
59 '</span>' + 65 '</span>' +
60 '<span class="favicon"></span>' + 66 // TODO(pedrosimonetti): remove all references (HTML+CSS+JS)
67 //'<span class="favicon"></span>' +
61 '</span>' + 68 '</span>' +
62 '<div class="color-stripe"></div>' + 69 // TODO(pedrosimonetti): remove all references (HTML+CSS+JS)
70 //'<div class="color-stripe"></div>' +
63 '<span class="title"></span>'; 71 '<span class="title"></span>';
64 72
65 this.querySelector('.close-button').title = 73 if (this.isRemovable) {
66 loadTimeData.getString('removethumbnailtooltip'); 74 this.querySelector('.close-button').title =
75 loadTimeData.getString('removethumbnailtooltip');
76 }
67 77
68 this.tabIndex = -1; 78 this.tabIndex = -1;
69 this.data_ = null; 79 this.data_ = null;
70 this.removeAttribute('id'); 80 this.removeAttribute('id');
71 this.title = ''; 81 this.title = '';
72 }, 82 },
73 83
74 /** 84 /**
75 * Update the appearance of this tile according to |data|. 85 * Update the appearance of this tile according to |data|.
76 * @param {Object} data A dictionary of relevant data for the page. 86 * @param {Object} data A dictionary of relevant data for the page.
77 */ 87 */
78 updateForData: function(data) { 88 updateForData: function(data) {
79 if (this.classList.contains('blacklisted') && data) { 89 if (this.classList.contains('blacklisted') && data) {
80 // Animate appearance of new tile. 90 // Animate appearance of new tile.
81 this.classList.add('new-tile-contents'); 91 this.classList.add('new-tile-contents');
82 } 92 }
83 this.classList.remove('blacklisted'); 93 this.classList.remove('blacklisted');
84 94
85 if (!data || data.filler) { 95 if (!data || data.filler) {
86 if (this.data_) 96 if (this.data_)
87 this.reset(); 97 this.reset();
88 return; 98 return;
89 } 99 }
90 100
91 var id = tileID++; 101 var id = tileID++;
102 // TODO(pedrosimonetti): refactor
92 this.id = 'most-visited-tile-' + id; 103 this.id = 'most-visited-tile-' + id;
93 this.data_ = data; 104 this.data_ = data;
94 this.classList.add('focusable'); 105 this.classList.add('focusable');
95 106
96 var faviconDiv = this.querySelector('.favicon'); 107 // TODO(pedrosimonetti): remove all references (HTML+CSS+JS)
97 var faviconUrl = 'chrome://favicon/size/16/' + data.url; 108 //var faviconDiv = this.querySelector('.favicon');
98 faviconDiv.style.backgroundImage = url(faviconUrl); 109 //var faviconUrl = 'chrome://favicon/size/16/' + data.url;
99 chrome.send('getFaviconDominantColor', [faviconUrl, this.id]); 110 //faviconDiv.style.backgroundImage = url(faviconUrl);
111 //chrome.send('getFaviconDominantColor', [faviconUrl, this.id]);
100 112
101 var title = this.querySelector('.title'); 113 var title = this.querySelector('.title');
102 title.textContent = data.title; 114 title.textContent = data.title;
103 title.dir = data.direction; 115 title.dir = data.direction;
104 116
105 // Sets the tooltip. 117 // Sets the tooltip.
106 this.title = data.title; 118 this.title = data.title;
107 119
108 var thumbnailUrl = 'chrome://thumb/' + data.url; 120 var thumbnailUrl = ntp.getThumbnailUrl(data.url);
109 this.querySelector('.thumbnail').style.backgroundImage = 121 this.querySelector('.thumbnail').style.backgroundImage =
110 url(thumbnailUrl); 122 url(thumbnailUrl);
111 123
112 this.href = data.url; 124 this.href = data.url;
113 125
114 this.classList.remove('filler'); 126 this.classList.remove('filler');
115 }, 127 },
116 128
117 /** 129 /**
118 * Sets the color of the favicon dominant color bar. 130 * Sets the color of the favicon dominant color bar.
119 * @param {string} color The css-parsable value for the color. 131 * @param {string} color The css-parsable value for the color.
120 */ 132 */
121 set stripeColor(color) { 133 // TODO(xci) delete
122 this.querySelector('.color-stripe').style.backgroundColor = color; 134 //set stripeColor(color) {
123 }, 135 // this.querySelector('.color-stripe').style.backgroundColor = color;
136 //},
124 137
125 /** 138 /**
126 * Handles a click on the tile. 139 * Handles a click on the tile.
127 * @param {Event} e The click event. 140 * @param {Event} e The click event.
128 */ 141 */
129 handleClick_: function(e) { 142 handleClick_: function(e) {
143 debugger;
130 if (e.target.classList.contains('close-button')) { 144 if (e.target.classList.contains('close-button')) {
131 this.blacklist_(); 145 this.blacklist_();
132 e.preventDefault(); 146 e.preventDefault();
133 } else { 147 } else {
134 // Records an app launch from the most visited page (Chrome will decide 148 // Records an app launch from the most visited page (Chrome will decide
135 // whether the url is an app). TODO(estade): this only works for clicks; 149 // whether the url is an app). TODO(estade): this only works for clicks;
136 // other actions like "open in new tab" from the context menu won't be 150 // other actions like "open in new tab" from the context menu won't be
137 // recorded. Can this be fixed? 151 // recorded. Can this be fixed?
138 chrome.send('recordAppLaunchByURL', 152 chrome.send('recordAppLaunchByURL',
139 [encodeURIComponent(this.href), 153 [encodeURIComponent(this.href),
140 ntp.APP_LAUNCH.NTP_MOST_VISITED]); 154 ntp.APP_LAUNCH.NTP_MOST_VISITED]);
141 // Records the index of this tile. 155 // Records the index of this tile.
142 chrome.send('metricsHandler:recordInHistogram', 156 chrome.send('metricsHandler:recordInHistogram',
143 ['NewTabPage.MostVisited', this.index, 8]); 157 ['NewTabPage.Thumbnail', this.index, 8]);
144 chrome.send('mostVisitedAction', 158 chrome.send('mostVisitedAction',
jeremycho_google 2012/08/02 03:00:49 This is MostVisited specific. Should handleClick_
pedrosimonetti2 2012/08/03 18:14:12 handleClick_ is not implemented in the Thumbnail c
145 [ntp.NtpFollowAction.CLICKED_TILE]); 159 [ntp.NtpFollowAction.CLICKED_TILE]);
146 } 160 }
147 }, 161 },
148 162
149 /** 163 /**
150 * Allow blacklisting most visited site using the keyboard. 164 * Allow blacklisting most visited site using the keyboard.
jeremycho_google 2012/08/02 03:00:49 Move to MostVisited?
pedrosimonetti2 2012/08/03 18:14:12 Done.
151 */ 165 */
152 handleKeyDown_: function(e) { 166 handleKeyDown_: function(e) {
153 if (!cr.isMac && e.keyCode == 46 || // Del 167 if (!cr.isMac && e.keyCode == 46 || // Del
154 cr.isMac && e.metaKey && e.keyCode == 8) { // Cmd + Backspace 168 cr.isMac && e.metaKey && e.keyCode == 8) { // Cmd + Backspace
155 this.blacklist_(); 169 this.blacklist_();
156 } 170 }
157 }, 171 },
158 172
159 /** 173 /**
160 * Permanently removes a page from Most Visited. 174 * Permanently removes a page from Most Visited.
161 */ 175 */
162 blacklist_: function() { 176 blacklist_: function() {
163 this.showUndoNotification_(); 177 this.showUndoNotification_();
164 chrome.send('blacklistURLFromMostVisited', [this.data_.url]); 178 chrome.send('blacklistURLFromThumbnail', [this.data_.url]);
165 this.reset(); 179 this.reset();
166 chrome.send('getMostVisited'); 180 chrome.send('getThumbnail');
167 this.classList.add('blacklisted'); 181 this.classList.add('blacklisted');
168 }, 182 },
169 183
170 showUndoNotification_: function() { 184 showUndoNotification_: function() {
171 var data = this.data_; 185 var data = this.data_;
172 var self = this; 186 var self = this;
173 var doUndo = function() { 187 var doUndo = function() {
174 chrome.send('removeURLsFromMostVisitedBlacklist', [data.url]); 188 chrome.send('removeURLsFromThumbnailBlacklist', [data.url]);
175 self.updateForData(data); 189 self.updateForData(data);
176 } 190 }
177 191
178 var undo = { 192 var undo = {
179 action: doUndo, 193 action: doUndo,
180 text: loadTimeData.getString('undothumbnailremove'), 194 text: loadTimeData.getString('undothumbnailremove'),
181 }; 195 };
182 196
183 var undoAll = { 197 var undoAll = {
184 action: function() { 198 action: function() {
185 chrome.send('clearMostVisitedURLsBlacklist'); 199 chrome.send('clearThumbnailURLsBlacklist');
186 }, 200 },
187 text: loadTimeData.getString('restoreThumbnailsShort'), 201 text: loadTimeData.getString('restoreThumbnailsShort'),
188 }; 202 };
189 203
190 ntp.showNotification( 204 ntp.showNotification(
191 loadTimeData.getString('thumbnailremovednotification'), 205 loadTimeData.getString('thumbnailremovednotification'),
192 [undo, undoAll]); 206 [undo, undoAll]);
193 }, 207 },
194 208
195 /** 209 /**
196 * Set the size and position of the most visited tile.
197 * @param {number} size The total size of |this|.
198 * @param {number} x The x-position.
199 * @param {number} y The y-position.
200 * animate.
201 */
202 setBounds: function(size, x, y) {
203 this.style.width = toCssPx(size);
204 this.style.height = toCssPx(heightForWidth(size));
205
206 this.style.left = toCssPx(x);
207 this.style.right = toCssPx(x);
208 this.style.top = toCssPx(y);
209 },
210
211 /**
212 * Returns whether this element can be 'removed' from chrome (i.e. whether 210 * Returns whether this element can be 'removed' from chrome (i.e. whether
213 * the user can drag it onto the trash and expect something to happen). 211 * the user can drag it onto the trash and expect something to happen).
214 * @return {boolean} True, since most visited pages can always be 212 * @return {boolean} True, since most visited pages can always be
215 * blacklisted. 213 * blacklisted.
216 */ 214 */
217 canBeRemoved: function() { 215 canBeRemoved: function() {
218 return true; 216 return this.isRemovable;
219 }, 217 },
220 218
221 /** 219 /**
222 * Removes this element from chrome, i.e. blacklists it. 220 * Removes this element from chrome, i.e. blacklists it.
223 */ 221 */
224 removeFromChrome: function() { 222 removeFromChrome: function() {
225 this.blacklist_(); 223 this.blacklist_();
226 this.parentNode.classList.add('finishing-drag'); 224 this.parentNode.classList.add('finishing-drag');
227 }, 225 },
228 226
229 /** 227 /**
230 * Called when a drag of this tile has ended (after all animations have 228 * Called when a drag of this tile has ended (after all animations have
231 * finished). 229 * finished).
232 */ 230 */
233 finalizeDrag: function() { 231 finalizeDrag: function() {
234 this.parentNode.classList.remove('finishing-drag'); 232 this.parentNode.classList.remove('finishing-drag');
235 }, 233 },
236 234
237 /** 235 /**
238 * Called when a drag is starting on the tile. Updates dataTransfer with 236 * Called when a drag is starting on the tile. Updates dataTransfer with
239 * data for this tile (for dragging outside of the NTP). 237 * data for this tile (for dragging outside of the NTP).
240 */ 238 */
239 // TODO(xci) delete
241 setDragData: function(dataTransfer) { 240 setDragData: function(dataTransfer) {
242 dataTransfer.setData('Text', this.data_.title); 241 dataTransfer.setData('Text', this.data_.title);
243 dataTransfer.setData('URL', this.data_.url); 242 dataTransfer.setData('URL', this.data_.url);
244 }, 243 },
245 }; 244 });
246 245
247 var mostVisitedPageGridValues = { 246 var THUMBNAIL_COUNT = 8; // TODO(xci)
248 // The fewest tiles we will show in a row.
249 minColCount: 2,
250 // The most tiles we will show in a row.
251 maxColCount: 4,
252
253 // The smallest a tile can be.
254 minTileWidth: 122,
255 // The biggest a tile can be. 212 (max thumbnail width) + 2.
256 maxTileWidth: 214,
257
258 // The padding between tiles, as a fraction of the tile width.
259 tileSpacingFraction: 1 / 8,
260 };
261 TilePage.initGridValues(mostVisitedPageGridValues);
262 247
263 /** 248 /**
264 * Calculates the height for a Most Visited tile for a given width. The size 249 * Creates a new ThumbnailPage object.
265 * is based on the thumbnail, which should have a 212:132 ratio.
266 * @return {number} The height.
267 */
268 function heightForWidth(width) {
269 // The 2s are for borders, the 31 is for the title.
270 return (width - 2) * 132 / 212 + 2 + 31;
271 }
272
273 var THUMBNAIL_COUNT = 8;
274
275 /**
276 * Creates a new MostVisitedPage object.
277 * @constructor 250 * @constructor
278 * @extends {TilePage} 251 * @extends {TilePage}
279 */ 252 */
280 function MostVisitedPage() { 253 function ThumbnailPage() {
281 var el = new TilePage(mostVisitedPageGridValues); 254 var el = new TilePage();
282 el.__proto__ = MostVisitedPage.prototype; 255 el.__proto__ = ThumbnailPage.prototype;
283 el.initialize(); 256 el.initialize();
284 257
285 return el; 258 return el;
286 } 259 }
287 260
288 MostVisitedPage.prototype = { 261 ThumbnailPage.prototype = {
289 __proto__: TilePage.prototype, 262 __proto__: TilePage.prototype,
290 263
264 gridValues_: {
265 tileWidth: 130,
266 tileHeight: 78,
267 tileHorMargin: 18, // TODO margin with CSS. There's no margin in first col
268 tileVerMargin: 22,
269 tileBorderWidth: 1,
270 bottomPanelHorMargin: 100,
271
272 tileCount: 10, // debug
273 tileClassName: 'thumbnail',
274 reinforceStyles: true,
275
276 // debug
277 slowFactor: 1,
278 debug: false
279 },
280
281 // TODO(pedrosimonetti): document
282 ThumbnailClass: Thumbnail,
283
291 initialize: function() { 284 initialize: function() {
292 this.classList.add('most-visited-page'); 285 this.classList.add('most-visited-page');
jeremycho_google 2012/08/02 03:00:49 most-visited
pedrosimonetti2 2012/08/03 18:14:12 I renamed it to 'thumbnail-page' and overrided the
293 this.data_ = null; 286 this.data_ = null;
294 this.mostVisitedTiles_ = this.getElementsByClassName('most-visited real'); 287 this.mostVisitedTiles_ = this.getElementsByClassName('most-visited real');
295 288
296 this.addEventListener('carddeselected', this.handleCardDeselected_); 289 this.addEventListener('carddeselected', this.handleCardDeselected_);
297 this.addEventListener('cardselected', this.handleCardSelected_); 290 this.addEventListener('cardselected', this.handleCardSelected_);
298 }, 291 },
299 292
300 /** 293 /**
301 * Create blank (filler) tiles. 294 * Create blank (filler) tiles.
302 * @private 295 * @private
303 */ 296 */
304 createTiles_: function() { 297 createTiles_: function() {
305 for (var i = 0; i < THUMBNAIL_COUNT; i++) { 298 for (var i = 0; i < THUMBNAIL_COUNT; i++) {
306 this.appendTile(new MostVisited()); 299 this.appendTile(new this.ThumbnailClass(this.gridValues_));
307 } 300 }
308 }, 301 },
309 302
310 /** 303 /**
311 * Update the tiles after a change to |data_|. 304 * Update the tiles after a change to |data_|.
312 */ 305 */
313 updateTiles_: function() { 306 updateTiles_: function() {
314 for (var i = 0; i < THUMBNAIL_COUNT; i++) { 307 for (var i = 0; i < THUMBNAIL_COUNT; i++) {
315 var page = this.data_[i]; 308 var page = this.data_[i];
316 var tile = this.mostVisitedTiles_[i]; 309 var tile = this.mostVisitedTiles_[i];
317 310
311 // TODO(pedrosimonetti): what do we do when there's no tile here?
312 if (!tile) {
313 return;
314 }
315
318 if (i >= this.data_.length) 316 if (i >= this.data_.length)
319 tile.reset(); 317 tile.reset();
320 else 318 else
321 tile.updateForData(page); 319 tile.updateForData(page);
322 } 320 }
323 }, 321 },
324 322
325 /** 323 /**
326 * Handles the 'card deselected' event (i.e. the user clicked to another 324 * Handles the 'card deselected' event (i.e. the user clicked to another
327 * pane). 325 * pane).
(...skipping 16 matching lines...) Expand all
344 chrome.send('mostVisitedSelected'); 342 chrome.send('mostVisitedSelected');
345 }, 343 },
346 344
347 /** 345 /**
348 * Array of most visited data objects. 346 * Array of most visited data objects.
349 * @type {Array} 347 * @type {Array}
350 */ 348 */
351 get data() { 349 get data() {
352 return this.data_; 350 return this.data_;
353 }, 351 },
354 set data(data) { 352 set data(data) {
jeremycho_google 2012/08/02 03:00:49 As we discussed, make virtual?
pedrosimonetti2 2012/08/03 18:14:12 Done.
355 var startTime = Date.now(); 353 var startTime = Date.now();
356 354
357 // The first time data is set, create the tiles. 355 // The first time data is set, create the tiles.
358 if (!this.data_) { 356 if (!this.data_) {
359 this.createTiles_(); 357 this.createTiles_();
360 this.data_ = data.slice(0, THUMBNAIL_COUNT); 358 this.data_ = data.slice(0, THUMBNAIL_COUNT);
361 } else { 359 } else {
362 this.data_ = refreshData(this.data_, data); 360 this.data_ = refreshData(this.data_, data);
363 } 361 }
364 362
365 this.updateTiles_(); 363 this.updateTiles_();
366 logEvent('mostVisited.layout: ' + (Date.now() - startTime)); 364 logEvent('mostVisited.layout: ' + (Date.now() - startTime));
367 }, 365 },
368 366
369 /** @inheritDoc */ 367 /** @inheritDoc */
370 shouldAcceptDrag: function(e) { 368 shouldAcceptDrag: function(e) {
371 return false; 369 return false;
372 }, 370 },
373
374 /** @inheritDoc */
375 heightForWidth: heightForWidth,
376 }; 371 };
377 372
378 /** 373 /**
379 * Executed once the NTP has loaded. Checks if the Most Visited pane is 374 * Executed once the NTP has loaded. Checks if the Most Visited pane is
380 * shown or not. If it is shown, the 'mostVisitedSelected' message is sent 375 * shown or not. If it is shown, the 'mostVisitedSelected' message is sent
381 * to the C++ code, to record the fact that the user has seen this pane. 376 * to the C++ code, to record the fact that the user has seen this pane.
382 */ 377 */
383 MostVisitedPage.onLoaded = function() { 378 // TODO(pedrosimonetti) is it possible to keep this inside Thumbnail class?
379 /*
380 ThumbnailPage.onLoaded = function() {
384 if (ntp.getCardSlider() && 381 if (ntp.getCardSlider() &&
385 ntp.getCardSlider().currentCardValue && 382 ntp.getCardSlider().currentCardValue &&
386 ntp.getCardSlider().currentCardValue.classList 383 ntp.getCardSlider().currentCardValue.classList
387 .contains('most-visited-page')) { 384 .contains('most-visited-page')) {
388 chrome.send('mostVisitedSelected'); 385 chrome.send('mostVisitedSelected');
389 } 386 }
390 } 387 }
391 388 */
392 /**
393 * We've gotten additional Most Visited data. Update our old data with the
394 * new data. The ordering of the new data is not important, except when a
395 * page is pinned. Thus we try to minimize re-ordering.
396 * @param {Array} oldData The current Most Visited page list.
397 * @param {Array} newData The new Most Visited page list.
398 * @return {Array} The merged page list that should replace the current page
399 * list.
400 */
401 function refreshData(oldData, newData) {
402 oldData = oldData.slice(0, THUMBNAIL_COUNT);
403 newData = newData.slice(0, THUMBNAIL_COUNT);
404
405 // Copy over pinned sites directly.
406 for (var j = 0; j < newData.length; j++) {
407 if (newData[j].pinned) {
408 oldData[j] = newData[j];
409 // Mark the entry as 'updated' so we don't try to update again.
410 oldData[j].updated = true;
411 // Mark the newData page as 'used' so we don't try to re-use it.
412 newData[j].used = true;
413 }
414 }
415
416 // Look through old pages; if they exist in the newData list, keep them
417 // where they are.
418 for (var i = 0; i < oldData.length; i++) {
419 if (!oldData[i] || oldData[i].updated)
420 continue;
421
422 for (var j = 0; j < newData.length; j++) {
423 if (newData[j].used)
424 continue;
425
426 if (newData[j].url == oldData[i].url) {
427 // The background image and other data may have changed.
428 oldData[i] = newData[j];
429 oldData[i].updated = true;
430 newData[j].used = true;
431 break;
432 }
433 }
434 }
435
436 // Look through old pages that haven't been updated yet; replace them.
437 for (var i = 0; i < oldData.length; i++) {
438 if (oldData[i] && oldData[i].updated)
439 continue;
440
441 for (var j = 0; j < newData.length; j++) {
442 if (newData[j].used)
443 continue;
444
445 oldData[i] = newData[j];
446 oldData[i].updated = true;
447 newData[j].used = true;
448 break;
449 }
450
451 if (oldData[i] && !oldData[i].updated)
452 oldData[i] = null;
453 }
454
455 // Clear 'updated' flags so this function will work next time it's called.
456 for (var i = 0; i < THUMBNAIL_COUNT; i++) {
457 if (oldData[i])
458 oldData[i].updated = false;
459 }
460
461 return oldData;
462 };
463 389
464 return { 390 return {
465 MostVisitedPage: MostVisitedPage, 391 Thumbnail: Thumbnail,
466 refreshData: refreshData, 392 ThumbnailPage: ThumbnailPage
467 }; 393 };
468 }); 394 });
469 395
470 document.addEventListener('ntpLoaded', ntp.MostVisitedPage.onLoaded);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698