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

Side by Side Diff: chrome/browser/resources/ntp4/bookmarks_page.js

Issue 8760003: [ntp4] Remove bookmarks page implementation and resources. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: update page_list_view.js Created 9 years 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 cr.define('ntp4', function() {
6 'use strict';
7
8 var localStrings = new LocalStrings;
9
10 /**
11 * A running count of bookmark tiles that we create so that each will have
12 * a unique ID.
13 */
14 var tileId = 0;
15
16 /**
17 * The maximum number of tiles that we will display on this page. If there
18 * are not enough spaces to show all bookmarks, we'll include a link to the
19 * Bookmarks manager.
20 * TODO(csilv): Eliminate the need for this restraint.
21 * @type {number}
22 * @const
23 */
24 var MAX_BOOKMARK_TILES = 18;
25
26 /**
27 * The root node's ID. We need this to determine removable items (direct
28 * children aren't removable).
29 * @type {number}
30 * @const
31 */
32 var ROOT_NODE_ID = '0';
33
34 /**
35 * The bookmark bar's ID. We need this to allow combining the root and
36 * bookmarks bars at the top level of the folder hierarchy/bookmarks page.
37 * aren't removable).
38 * @type {number}
39 * @const
40 */
41 var BOOKMARKS_BAR_ID = '1';
42
43 /**
44 * Creates a new bookmark object.
45 * @param {Object} data The url and title.
46 * @constructor
47 * @extends {HTMLDivElement}
48 */
49 function Bookmark(data) {
50 var el = $('bookmark-template').cloneNode(true);
51 el.__proto__ = Bookmark.prototype;
52 el.initialize(data);
53
54 return el;
55 }
56
57 Bookmark.prototype = {
58 __proto__: HTMLDivElement.prototype,
59
60 /**
61 * Initialize the bookmark object.
62 * @param {Object} data The bookmark data (url, title, etc).
63 */
64 initialize: function(data) {
65 this.data = data;
66 this.hidden = false;
67
68 var id = tileId++;
69 this.id = 'bookmark_tile_' + id;
70
71 var title = this.querySelector('.title');
72 title.textContent = this.data.title;
73
74 // Sets the tooltip.
75 this.title = this.data.title;
76
77 if (this.data.url) {
78 var button = this.querySelector('.button');
79 button.href = title.href = this.data.url;
80 }
81
82 var faviconDiv = this.querySelector('.favicon');
83 var faviconUrl;
84 if (this.data.url) {
85 faviconUrl = 'chrome://favicon/size/16/' + this.data.url;
86 chrome.send('getFaviconDominantColor', [faviconUrl, this.id]);
87 } else {
88 faviconUrl = 'chrome://theme/IDR_BOOKMARK_BAR_FOLDER';
89 // TODO(csilv): Should we vary this color by platform?
90 this.stripeColor = '#919191';
91 }
92 faviconDiv.style.backgroundImage = url(faviconUrl);
93
94 if (this.canBeRemoved())
95 this.classList.add('removable');
96
97 this.addEventListener('click', this.handleClick_.bind(this));
98 },
99
100 /**
101 * Sets the color of the favicon dominant color bar.
102 * @param {string} color The css-parsable value for the color.
103 */
104 set stripeColor(color) {
105 this.querySelector('.color-stripe').style.backgroundColor = color;
106 },
107
108 /**
109 * Set the size and position of the bookmark tile.
110 * @param {number} size The total size of |this|.
111 * @param {number} x The x-position.
112 * @param {number} y The y-position.
113 * animate.
114 */
115 setBounds: function(size, x, y) {
116 this.style.width = size + 'px';
117 this.style.height = heightForWidth(size) + 'px';
118
119 this.style.left = x + 'px';
120 this.style.right = x + 'px';
121 this.style.top = y + 'px';
122 },
123
124 /**
125 * Set some data on the drag when it starts.
126 * @param {DataTransfer} dataTransfer A data transfer object from the
127 * current drag.
128 */
129 setDragData: function(dataTransfer) {
130 // OS X requires extra data drag data to consider a drag useful, so we're
131 // appending some semi-useful data at the end to force drags to work on
132 // this OS. Don't use this data for anything -- this is just a hack to
133 // ensure drag works the same as on other platforms.
134 dataTransfer.setData('Text', this.data.id);
135 },
136
137 /**
138 * Invoked when a bookmark is clicked
139 * @param {Event} e The click event.
140 * @private
141 */
142 handleClick_: function(e) {
143 if (e.target.classList.contains('close-button')) {
144 e.preventDefault();
145 this.removeFromChrome();
146 } else if (!this.data.url) {
147 chrome.send('getBookmarksData', [this.data.id]);
148 e.preventDefault();
149 }
150 },
151
152 /** @inheritDoc */
153 removeFromChrome: function() {
154 chrome.send('removeBookmark', [this.data.id]);
155 },
156
157 /**
158 * All bookmarks except for children of the root node.
159 * @return {boolean} Whether or not the item can be removed.
160 */
161 canBeRemoved: function() {
162 return this.data.parentId !== ROOT_NODE_ID;
163 },
164 };
165
166 /**
167 * Creates a new bookmark title object.
168 * @param {Object} data The url and title.
169 * @constructor
170 * @extends {HTMLDivElement}
171 */
172 function BookmarkTitle(data) {
173 var el = cr.doc.createElement('div');
174 el.__proto__ = BookmarkTitle.prototype;
175 el.initialize(data);
176
177 return el;
178 }
179
180 BookmarkTitle.prototype = {
181 __proto__: HTMLDivElement.prototype,
182
183 /**
184 * Initialize the bookmark title object.
185 */
186 initialize: function(data) {
187 this.className = 'title-crumb';
188 this.folderId = data.id;
189 this.textContent = data.parentId ? data.title :
190 localStrings.getString('bookmarksPage');
191
192 this.addEventListener('click', this.handleClick_);
193 },
194
195 /**
196 * Invoked when a bookmark title is clicked
197 * @param {Event} e The click event.
198 * @private
199 */
200 handleClick_: function(e) {
201 chrome.send('getBookmarksData', [this.folderId]);
202 },
203 };
204
205 var TilePage = ntp4.TilePage;
206
207 var bookmarksPageGridValues = {
208 // The fewest tiles we will show in a row.
209 minColCount: 3,
210 // The most tiles we will show in a row.
211 maxColCount: 6,
212
213 // The smallest a tile can be.
214 minTileWidth: 64,
215 // The biggest a tile can be.
216 maxTileWidth: 96,
217
218 // The padding between tiles, as a fraction of the tile width.
219 tileSpacingFraction: 1 / 2,
220 };
221 TilePage.initGridValues(bookmarksPageGridValues);
222
223 /**
224 * Calculates the height for a bookmarks tile for a given width. The size
225 * is based on a desired size of 96x72 ratio.
226 * @return {number} The height.
227 */
228 function heightForWidth(width) {
229 // The 2s are for borders, the 31 is for the title.
230 return (width - 2) * 72 / 96 + 2 + 31;
231 }
232
233 /**
234 * Creates a new BookmarksPage object.
235 * @constructor
236 * @extends {TilePage}
237 */
238 function BookmarksPage() {
239 var el = new TilePage(bookmarksPageGridValues);
240 el.__proto__ = BookmarksPage.prototype;
241 el.initialize();
242
243 return el;
244 }
245
246 BookmarksPage.prototype = {
247 __proto__: TilePage.prototype,
248
249 /**
250 * Initialize the bookmarks page object.
251 */
252 initialize: function() {
253 this.classList.add('bookmarks-page');
254
255 // Insert the bookmark titles header which is unique to bookmark pages.
256 var titleWrapper = $('bookmarks-title-wrapper')
257 titleWrapper.hidden = false;
258 this.insertBefore(titleWrapper, this.firstChild);
259
260 // Insert the top & bottom links for the Bookmarks Manager page.
261 var pageContent = this.querySelector('.tile-page-content');
262 var topWrapper = $('bookmarks-top-link-wrapper');
263 pageContent.insertBefore(topWrapper, pageContent.firstChild);
264 topWrapper.hidden = false;
265 pageContent.appendChild($('bookmarks-bottom-link-wrapper'));
266 },
267
268 /**
269 * Build the bookmark titles bar (ie, navigation hiearchy).
270 * @param {Array} items The parent hiearchy of the current folder.
271 * @private
272 */
273 updateBookmarkTitles_: function(items) {
274 var wrapper = $('bookmarks-title-wrapper');
275 var title = wrapper.querySelector('.section-title');
276 title.innerHTML = '';
277
278 for (var i = items.length - 1; i > 0; i--) {
279 title.appendChild(new BookmarkTitle(items[i]));
280
281 var separator = document.createElement('hr');
282 separator.className = 'bookmark-separator';
283 title.appendChild(separator);
284 }
285
286 var titleCrumb = new BookmarkTitle(items[0]);
287 titleCrumb.classList.add('title-crumb-active');
288 title.appendChild(titleCrumb);
289 },
290
291 /**
292 * Build the bookmark tiles.
293 * @param {Array} items The contents of the current folder.
294 * @private
295 */
296 updateBookmarkTiles_: function(items) {
297 this.removeAllTiles();
298 var tile_count = Math.min(items.length, MAX_BOOKMARK_TILES);
299 for (var i = 0; i < tile_count; i++)
300 this.appendTile(new Bookmark(items[i]), false);
301
302 var folder_id = this.id == ROOT_NODE_ID ? BOOKMARKS_BAR_ID : this.id;
303 var top_link = $('bookmarks-top-link-wrapper').querySelector('a');
304 top_link.href = 'chrome://bookmarks/#' + folder_id;
305
306 var wrapper = $('bookmarks-bottom-link-wrapper');
307 if (items.length > MAX_BOOKMARK_TILES) {
308 var bottom_link = wrapper.querySelector('a');
309 bottom_link.href = 'chrome://bookmarks/#' + folder_id;
310 wrapper.hidden = false;
311 } else {
312 wrapper.hidden = true;
313 }
314
315 if (this.id === ROOT_NODE_ID && !tile_count && !cr.isChromeOS)
316 this.showImportPromo_();
317 },
318
319 /**
320 * Determine whether a bookmark ID matches a folder in the current
321 * hierarchy.
322 * @param {string} id The bookmark ID to search for.
323 * @private
324 */
325 isBookmarkInParentHierarchy_: function(id) {
326 var titlesWrapper = $('bookmarks-title-wrapper');
327 var titles = titlesWrapper.querySelectorAll('.title-crumb');
328 for (var i = 0; i < titles.length; i++) {
329 var bookmarkTitle = titles[i];
330 if (bookmarkTitle.folderId == id)
331 return true;
332 }
333 return false;
334 },
335
336 /**
337 * Tells if we're in currently in the given folder.
338 * @param {String} id The folder node's ID.
339 * @returns {boolean} If it's in that folder (visually).
340 */
341 currentlyInFolder_: function(id) {
342 return id === this.id || (this.id === ROOT_NODE_ID &&
343 id === BOOKMARKS_BAR_ID);
344 },
345
346 /** @inheritDoc */
347 shouldAcceptDrag: function(e) {
348 var tile = ntp4.getCurrentlyDraggingTile();
349 if (tile)
350 return !!tile.querySelector('.most-visited, .bookmark');
351 // If there was no dragging tile, look for a URL in the drag data.
352 return e.dataTransfer && e.dataTransfer.types &&
353 e.dataTransfer.types.indexOf('url') != -1;
354 },
355
356 /** @inheritDoc */
357 heightForWidth: heightForWidth,
358
359 /**
360 * Invoked before a batch import begins. We will ignore added/changed
361 * notifications while the operation is in progress.
362 */
363 bookmarkImportBegan: function() {
364 this.importing = true;
365 },
366
367 /**
368 * Invoked after a batch import finishes. We will reload the bookmarks
369 * page to reflect the new state.
370 */
371 bookmarkImportEnded: function() {
372 this.importing = false;
373 chrome.send('getBookmarksData', []);
374 },
375
376 /**
377 * Invoked when a node has been added.
378 * @param {string} id The id of the newly created bookmark node.
379 * @param {Object} bookmark The new bookmark node.
380 * @param {boolean} fromCurrentPage True if the action was from this page.
381 */
382 bookmarkNodeAdded: function(id, bookmark, fromCurrentPage) {
383 if (this.importing) return;
384 if (this.currentlyInFolder_(bookmark.parentId)) {
385 // Hide the import promo if it exists.
386 this.hideImportPromo_();
387 // Only add the item if it should be visible.
388 if (bookmark.index < MAX_BOOKMARK_TILES) {
389 // If source of the add came from this page, show an animated
390 // insertion, otherwise just quietly do it.
391 this.addTileAt(new Bookmark(bookmark), bookmark.index,
392 fromCurrentPage);
393 // Delete extra tiles if they exist.
394 while (this.tiles.length > MAX_BOOKMARK_TILES) {
395 var tile = this.tiles[this.tiles.length - 1];
396 this.removeTile(tile, false);
397 }
398 this.repositionTiles_();
399 }
400 }
401 },
402
403 /**
404 * Invoked when the title or url of a node changes.
405 * @param {string} id The id of the changed node.
406 * @param {Object} changeInfo Details of the changed node.
407 */
408 bookmarkNodeChanged: function(id, changeInfo) {
409 if (this.importing) return;
410
411 // If the current folder or parent is being re-named, reload the page.
412 // TODO(csilv): Optimize this to reload just the titles.
413 if (this.isBookmarkInParentHierarchy_(id)) {
414 chrome.send('getBookmarksData', [this.id]);
415 return;
416 }
417
418 // If the target item is contained in this folder, update just that item.
419 for (var i = 0; i < this.tiles.length; i++) {
420 var tile = this.tiles[i];
421 var data = tile.firstChild.data;
422
423 if (data.id == id) {
424 data.title = changeInfo.title;
425 var title = tile.querySelector('.title');
426 title.textContent = data.title;
427
428 if (changeInfo.url) {
429 data.url = changeInfo.url;
430 var button = tile.querySelector('.button');
431 button.href = title.href = data.url;
432 }
433 break;
434 }
435 }
436 },
437
438 /**
439 * Invoked when the children (just direct children, not descendants) of
440 * a folder have been reordered in some way, such as sorted.
441 * @param {string} id The id of the reordered bookmark node.
442 * @param {!Object} reorderInfo Details of the reordered bookmark node.
443 */
444 bookmarkNodeChildrenReordered: function(id, reorderInfo) {
445 if (this.currentlyInFolder_(id))
446 chrome.send('getBookmarksData', [this.id]);
447 },
448
449 /**
450 * Invoked when a node has moved.
451 * @param {string} id The id of the moved bookmark node.
452 * @param {!Object} moveInfo Details of the moved bookmark.
453 */
454 bookmarkNodeMoved: function(id, moveInfo) {
455 // TODO(csilv): Optimize this by doing less than reloading the folder.
456 // Reload the current page if the target item is the current folder
457 // or a parent of the current folder.
458 if (this.isBookmarkInParentHierarchy_(id)) {
459 chrome.send('getBookmarksData', [this.id]);
460 return;
461 }
462
463 // Reload the current page if the target item is being moved to/from the
464 // current folder.
465 if (this.currentlyInFolder_(moveInfo.parentId) ||
466 this.currentlyInFolder_(moveInfo.oldParentId)) {
467 chrome.send('getBookmarksData', [this.id]);
468 }
469 },
470
471 /**
472 * Invoked when a node has been removed from a folder.
473 * @param {string} id The id of the removed bookmark node.
474 * @param {!Object} removeInfo Details of the removed bookmark node.
475 * @param {boolearn} fromCurrentPage If the event was from this page.
476 */
477 bookmarkNodeRemoved: function(id, removeInfo, fromCurrentPage) {
478 // If the target item is the visibile folder or a parent folder, load
479 // the parent of the removed item.
480 if (this.isBookmarkInParentHierarchy_(id)) {
481 chrome.send('getBookmarksData', [removeInfo.parentId]);
482 return;
483 }
484
485 // If the target item is contained in the visible folder, find the
486 // matching tile and delete it.
487 if (this.currentlyInFolder_(removeInfo.parentId)) {
488 for (var i = 0; i < this.tiles.length; i++) {
489 var tile = this.tiles[i];
490 if (tile.firstChild.data.id == id) {
491 this.removeTile(tile, fromCurrentPage);
492 break;
493 }
494 }
495 }
496 },
497
498 /**
499 * Set the bookmark data that should be displayed, replacing any existing
500 * data.
501 * @param {Object} data Data that shoudl be displayed. Contains arrays
502 * 'items' and 'navigationItems'.
503 */
504 set data(data) {
505 this.id = data.navigationItems[0].id;
506 this.updateBookmarkTiles_(data.items);
507 this.updateBookmarkTitles_(data.navigationItems);
508 },
509
510 /** @inheritDoc */
511 get extraBottomPadding() {
512 return 40;
513 },
514
515 /** @inheritDoc */
516 setDropEffect: function(dataTransfer) {
517 var tile = ntp4.getCurrentlyDraggingTile();
518 if (tile && tile.querySelector('.bookmark'))
519 ntp4.setCurrentDropEffect(dataTransfer, 'move');
520 else
521 ntp4.setCurrentDropEffect(dataTransfer, 'copy');
522 },
523
524 /** @inheritDoc */
525 addDragData: function(dataTransfer, index) {
526 var parentId = ROOT_NODE_ID == this.id ? BOOKMARKS_BAR_ID : this.id;
527 var currentlyDraggingTile = ntp4.getCurrentlyDraggingTile();
528 if (currentlyDraggingTile) {
529 var tileContents = currentlyDraggingTile.firstChild;
530 if (tileContents.classList.contains('most-visited')) {
531 this.generateBookmarkForLink(parentId, index,
532 tileContents.textContent,
533 tileContents.href);
534 }
535 } else {
536 this.addOutsideData_(dataTransfer, parentId, index);
537 }
538 },
539
540 /**
541 * If we got an outside drag from a page or the URL bar.
542 * @param {!DataTransfer} dataTransfer The drag data transfer object.
543 * @param {number} parentId The parent ID for the current bookmark level.
544 * @param {number} index Position it will be inserted relative to siblings.
545 */
546 addOutsideData_: function(dataTransfer, parentId, index) {
547 var url = dataTransfer.getData('url');
548 assert(url && url !== window.location.href);
549 // Look for any text/html types first (links, etc.).
550 var title, html = dataTransfer.getData('text/html');
551 if (html) {
552 // NOTE: Don't insert this into the DOM! It could XSS the page!
553 var node = this.ownerDocument.createElement('div');
554 node.innerHTML = html;
555 var text = node.textContent, img = node.firstChild;
556 // OS X prepends a <meta> tag to the html for some reason...
557 if ('META' == img.nodeName)
558 img = img.nextSibling;
559 // Use the combined text (if it exists), otherwise fall back to an
560 // image's alternate text (if they dragged an image onto this page).
561 title = text || ('IMG' == img.nodeName && img.alt);
562 }
563 // If we *still* don't have a title, just use the URL.
564 if (!title)
565 title = url;
566 // Create a bookmark for the dropped data.
567 this.generateBookmarkForLink(parentId, index, title, url);
568 },
569
570 /**
571 * Show the 'Import bookmarks' promo.
572 * @private
573 */
574 showImportPromo_: function() {
575 var importTemplate = $('bookmarks-import-data-link-template');
576 var importWrapper = importTemplate.cloneNode(true);
577 importWrapper.id = '';
578 importWrapper.hidden = false;
579 this.querySelector('.tile-page-content').appendChild(importWrapper);
580 },
581
582 /**
583 * Hide the 'Import bookmarks' promo.
584 * @private
585 */
586 hideImportPromo_: function() {
587 var wrapper = this.querySelector('.bookmarks-import-data-link-wrapper');
588 if (wrapper)
589 wrapper.parentNode.removeChild(wrapper);
590 },
591
592 /**
593 * Create a bookmark from a title/url.
594 * @param {!string} parentId Stringified int64 of the parent node's ID.
595 * @param {number} index Sibling relative index, i.e. 3rd on this level.
596 * @param {string} title More human readable title of the bookmark.
597 * @param {string} url URL of the bookmark to be created.
598 */
599 generateBookmarkForLink: function(parentId, index, title, url) {
600 // Bookmark creation actually only *requires* a parent ID, as if we just
601 // pass a parent ID it's created as a folder with blank title as a child
602 // of that parent.
603 assert(parentId);
604 chrome.send('createBookmark', [parentId, index, title, url]);
605 },
606
607 /** @inheritDoc */
608 tileMoved: function(tile, prevIndex) {
609 var parentId = ROOT_NODE_ID == this.id ? BOOKMARKS_BAR_ID : this.id;
610 chrome.send('moveBookmark', [tile.firstChild.data.id, parentId,
611 tile.index + (prevIndex < tile.index)]);
612 },
613 };
614
615 /**
616 * Initializes and renders the bookmark chevron canvas. This needs to be
617 * performed after the page has been loaded so that we have access to the
618 * style sheet values.
619 */
620 function initBookmarkChevron() {
621 var wrapperStyle = window.getComputedStyle($('bookmarks-title-wrapper'));
622 var width = 10;
623 var height = parseInt(wrapperStyle.height, 10);
624 var ctx = document.getCSSCanvasContext('2d', 'bookmark-chevron',
625 width, height);
626 ctx.strokeStyle = wrapperStyle.borderBottomColor;
627 ctx.beginPath();
628 ctx.moveTo(0, 0);
629 ctx.lineTo(width, height / 2);
630 ctx.lineTo(0, height);
631 ctx.stroke();
632 }
633
634 /**
635 * Set the dominant color for a bookmark tile. This is the callback method
636 * from a request made when the tile was created.
637 * @param {string} id The ID of the bookmark tile.
638 * @param {string} color The color represented as a CSS string.
639 */
640 function setBookmarksFaviconDominantColor(id, color) {
641 var tile = $(id);
642 if (tile)
643 tile.stripeColor = color;
644 }
645
646 return {
647 BookmarksPage: BookmarksPage,
648 initBookmarkChevron: initBookmarkChevron,
649 };
650 });
651
652 window.addEventListener('load', ntp4.initBookmarkChevron);
OLDNEW
« no previous file with comments | « chrome/browser/resources/ntp4/bookmarks_page.css ('k') | chrome/browser/resources/ntp4/new_tab.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698