Index: chrome/browser/resources/ntp/most_visited.js |
diff --git a/chrome/browser/resources/ntp/most_visited.js b/chrome/browser/resources/ntp/most_visited.js |
deleted file mode 100644 |
index 1b2202798001ba74120c864b1ef0623dae2e2c2f..0000000000000000000000000000000000000000 |
--- a/chrome/browser/resources/ntp/most_visited.js |
+++ /dev/null |
@@ -1,713 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-// Dependencies that we should remove/formalize: |
-// util.js |
-// |
-// afterTransition |
-// chrome.send |
-// hideNotification |
-// isRtl |
-// localStrings |
-// logEvent |
-// showNotification |
- |
- |
-var MostVisited = (function() { |
- |
- function addPinnedUrl(item, index) { |
- chrome.send('addPinnedURL', [item.url, item.title, item.faviconUrl || '', |
- item.thumbnailUrl || '', String(index)]); |
- } |
- |
- function getItem(el) { |
- return findAncestorByClass(el, 'thumbnail-container'); |
- } |
- |
- function updatePinnedDom(el, pinned) { |
- el.querySelector('.pin').title = localStrings.getString(pinned ? |
- 'unpinthumbnailtooltip' : 'pinthumbnailtooltip'); |
- if (pinned) { |
- el.classList.add('pinned'); |
- } else { |
- el.classList.remove('pinned'); |
- } |
- } |
- |
- function getThumbnailIndex(el) { |
- var nodes = el.parentNode.querySelectorAll('.thumbnail-container'); |
- return Array.prototype.indexOf.call(nodes, el); |
- } |
- |
- function MostVisited(el, miniview, menu, useSmallGrid, visible) { |
- this.element = el; |
- this.miniview = miniview; |
- this.menu = menu; |
- this.useSmallGrid_ = useSmallGrid; |
- this.visible_ = visible; |
- |
- this.createThumbnails_(); |
- this.applyMostVisitedRects_(); |
- |
- el.addEventListener('click', this.handleClick_.bind(this)); |
- el.addEventListener('keydown', this.handleKeyDown_.bind(this)); |
- |
- document.addEventListener('DOMContentLoaded', |
- this.ensureSmallGridCorrect.bind(this)); |
- |
- // Commands |
- document.addEventListener('command', this.handleCommand_.bind(this)); |
- document.addEventListener('canExecute', this.handleCanExecute_.bind(this)); |
- |
- // DND |
- el.addEventListener('dragstart', this.handleDragStart_.bind(this)); |
- el.addEventListener('dragenter', this.handleDragEnter_.bind(this)); |
- el.addEventListener('dragover', this.handleDragOver_.bind(this)); |
- el.addEventListener('dragleave', this.handleDragLeave_.bind(this)); |
- el.addEventListener('drop', this.handleDrop_.bind(this)); |
- el.addEventListener('dragend', this.handleDragEnd_.bind(this)); |
- el.addEventListener('drag', this.handleDrag_.bind(this)); |
- el.addEventListener('mousedown', this.handleMouseDown_.bind(this)); |
- } |
- |
- MostVisited.prototype = { |
- togglePinned_: function(el) { |
- var index = getThumbnailIndex(el); |
- var item = this.data[index]; |
- item.pinned = !item.pinned; |
- if (item.pinned) { |
- addPinnedUrl(item, index); |
- } else { |
- chrome.send('removePinnedURL', [item.url]); |
- } |
- updatePinnedDom(el, item.pinned); |
- }, |
- |
- swapPosition_: function(source, destination) { |
- var nodes = source.parentNode.querySelectorAll('.thumbnail-container'); |
- var sourceIndex = getThumbnailIndex(source); |
- var destinationIndex = getThumbnailIndex(destination); |
- swapDomNodes(source, destination); |
- |
- var sourceData = this.data[sourceIndex]; |
- addPinnedUrl(sourceData, destinationIndex); |
- sourceData.pinned = true; |
- updatePinnedDom(source, true); |
- |
- var destinationData = this.data[destinationIndex]; |
- // Only update the destination if it was pinned before. |
- if (destinationData.pinned) { |
- addPinnedUrl(destinationData, sourceIndex); |
- } |
- this.data[destinationIndex] = sourceData; |
- this.data[sourceIndex] = destinationData; |
- |
- chrome.send('recordAction', ['MostVisitedReordered']); |
- }, |
- |
- updateSettingsLink: function(hasBlacklistedUrls) { |
- if (hasBlacklistedUrls) |
- $('most-visited-settings').classList.add('has-blacklist'); |
- else |
- $('most-visited-settings').classList.remove('has-blacklist'); |
- }, |
- |
- blacklist: function(el) { |
- var self = this; |
- var url = el.href; |
- chrome.send('blacklistURLFromMostVisited', [url]); |
- |
- el.classList.add('hide'); |
- |
- // Find the old item. |
- var oldUrls = {}; |
- var oldIndex = -1; |
- var oldItem; |
- var data = this.data; |
- for (var i = 0; i < data.length; i++) { |
- if (data[i].url == url) { |
- oldItem = data[i]; |
- oldIndex = i; |
- } |
- oldUrls[data[i].url] = true; |
- } |
- |
- // Send 'getMostVisitedPages' with a callback since we want to find the |
- // new page and add that in the place of the removed page. |
- chromeSend('getMostVisited', [], 'setMostVisitedPages', |
- function(data, hasBlacklistedUrls) { |
- // Update settings link. |
- self.updateSettingsLink(hasBlacklistedUrls); |
- |
- // Find new item. |
- var newItem; |
- for (var i = 0; i < data.length; i++) { |
- if (!(data[i].url in oldUrls)) { |
- newItem = data[i]; |
- break; |
- } |
- } |
- |
- if (!newItem) { |
- // If no other page is available to replace the blacklisted item, |
- // we need to reorder items s.t. all filler items are in the rightmost |
- // indices. |
- self.data = data; |
- |
- // Replace old item with new item in the most visited data array. |
- } else if (oldIndex != -1) { |
- var oldData = self.data.concat(); |
- oldData.splice(oldIndex, 1, newItem); |
- self.data = oldData; |
- el.classList.add('fade-in'); |
- } |
- |
- // We wrap the title in a <span class=blacklisted-title>. We pass an |
- // empty string to the notifier function and use DOM to insert the real |
- // string. |
- var actionText = localStrings.getString('undothumbnailremove'); |
- |
- // Show notification and add undo callback function. |
- var wasPinned = oldItem.pinned; |
- showNotification('', actionText, function() { |
- self.removeFromBlackList(url); |
- if (wasPinned) { |
- addPinnedUrl(oldItem, oldIndex); |
- } |
- chrome.send('getMostVisited'); |
- }); |
- |
- // Now change the DOM. |
- var removeText = localStrings.getString('thumbnailremovednotification'); |
- var notifyMessageEl = document.querySelector('#notification > *'); |
- notifyMessageEl.textContent = removeText; |
- |
- // Focus the undo link. |
- var undoLink = document.querySelector( |
- '#notification > .link > [tabindex]'); |
- undoLink.focus(); |
- }); |
- }, |
- |
- removeFromBlackList: function(url) { |
- chrome.send('removeURLsFromMostVisitedBlacklist', [url]); |
- }, |
- |
- clearAllBlacklisted: function() { |
- chrome.send('clearMostVisitedURLsBlacklist', []); |
- hideNotification(); |
- }, |
- |
- dirty_: false, |
- invalidate_: function() { |
- this.dirty_ = true; |
- }, |
- |
- visible_: true, |
- get visible() { |
- return this.visible_; |
- }, |
- set visible(visible) { |
- if (this.visible_ != visible) { |
- this.visible_ = visible; |
- this.invalidate_(); |
- } |
- }, |
- |
- useSmallGrid_: false, |
- get useSmallGrid() { |
- return this.useSmallGrid_; |
- }, |
- set useSmallGrid(b) { |
- if (this.useSmallGrid_ != b) { |
- this.useSmallGrid_ = b; |
- this.invalidate_(); |
- } |
- }, |
- |
- layout: function() { |
- if (!this.dirty_) |
- return; |
- var d0 = Date.now(); |
- this.applyMostVisitedRects_(); |
- this.dirty_ = false; |
- logEvent('mostVisited.layout: ' + (Date.now() - d0)); |
- }, |
- |
- createThumbnails_: function() { |
- var singleHtml = |
- '<a class="thumbnail-container filler" tabindex="1">' + |
- '<div class="edit-mode-border">' + |
- '<div class="edit-bar">' + |
- '<div class="pin"></div>' + |
- '<div class="spacer"></div>' + |
- '<div class="remove"></div>' + |
- '</div>' + |
- '<span class="thumbnail-wrapper">' + |
- '<span class="thumbnail"></span>' + |
- '</span>' + |
- '</div>' + |
- '<div class="title">' + |
- '<div></div>' + |
- '</div>' + |
- '</a>'; |
- this.element.innerHTML = Array(8 + 1).join(singleHtml); |
- var children = this.element.children; |
- for (var i = 0; i < 8; i++) { |
- children[i].id = 't' + i; |
- children[i].onmouseover = this.handleMouseOver_.bind(this); |
- children[i].onmouseout = this.handleMouseOut_.bind(this); |
- } |
- }, |
- |
- getMostVisitedLayoutRects_: function() { |
- var small = this.useSmallGrid; |
- |
- var cols = 4; |
- var rows = 2; |
- var marginWidth = 10; |
- var marginHeight = 7; |
- var borderWidth = 4; |
- var thumbWidth = small ? 150 : 207; |
- var thumbHeight = small ? 93 : 129; |
- var w = thumbWidth + 2 * borderWidth + 2 * marginWidth; |
- var h = thumbHeight + 40 + 2 * marginHeight; |
- var sumWidth = cols * w - 2 * marginWidth; |
- var topSpacing = 10; |
- |
- var rtl = isRtl(); |
- var rects = []; |
- |
- if (this.visible) { |
- for (var i = 0; i < rows * cols; i++) { |
- var row = Math.floor(i / cols); |
- var col = i % cols; |
- var left = rtl ? sumWidth - col * w - thumbWidth - 2 * borderWidth : |
- col * w; |
- |
- var top = row * h + topSpacing; |
- |
- rects[i] = {left: left, top: top}; |
- } |
- } |
- return rects; |
- }, |
- |
- applyMostVisitedRects_: function() { |
- if (this.visible) { |
- var rects = this.getMostVisitedLayoutRects_(); |
- var children = this.element.children; |
- for (var i = 0; i < 8; i++) { |
- var t = children[i]; |
- t.style.left = rects[i].left + 'px'; |
- t.style.top = rects[i].top + 'px'; |
- t.style.right = ''; |
- var innerStyle = t.firstElementChild.style; |
- innerStyle.left = innerStyle.top = ''; |
- } |
- } |
- }, |
- |
- // Work around for http://crbug.com/25329 |
- ensureSmallGridCorrect: function(expected) { |
- if (expected != this.useSmallGrid) |
- this.applyMostVisitedRects_(); |
- }, |
- |
- getRectByIndex_: function(index) { |
- return this.getMostVisitedLayoutRects_()[index]; |
- }, |
- |
- // Commands |
- |
- handleCommand_: function(e) { |
- var commandId = e.command.id; |
- switch (commandId) { |
- case 'clear-all-blacklisted': |
- this.clearAllBlacklisted(); |
- chrome.send('getMostVisited'); |
- break; |
- } |
- }, |
- |
- handleCanExecute_: function(e) { |
- if (e.command.id == 'clear-all-blacklisted') |
- e.canExecute = true; |
- }, |
- |
- // DND |
- |
- currentOverItem_: null, |
- get currentOverItem() { |
- return this.currentOverItem_; |
- }, |
- set currentOverItem(item) { |
- var style; |
- if (item != this.currentOverItem_) { |
- if (this.currentOverItem_) { |
- style = this.currentOverItem_.firstElementChild.style; |
- style.left = style.top = ''; |
- } |
- this.currentOverItem_ = item; |
- |
- if (item) { |
- // Make the drag over item move 15px towards the source. The movement |
- // is done by only moving the edit-mode-border (as in the mocks) and |
- // it is done with relative positioning so that the movement does not |
- // change the drop target. |
- var dragIndex = getThumbnailIndex(this.dragItem_); |
- var overIndex = getThumbnailIndex(item); |
- if (dragIndex == -1 || overIndex == -1) { |
- return; |
- } |
- |
- var dragRect = this.getRectByIndex_(dragIndex); |
- var overRect = this.getRectByIndex_(overIndex); |
- |
- var x = dragRect.left - overRect.left; |
- var y = dragRect.top - overRect.top; |
- var z = Math.sqrt(x * x + y * y); |
- var z2 = 15; |
- var x2 = x * z2 / z; |
- var y2 = y * z2 / z; |
- |
- style = this.currentOverItem_.firstElementChild.style; |
- style.left = x2 + 'px'; |
- style.top = y2 + 'px'; |
- } |
- } |
- }, |
- dragItem_: null, |
- startX_: 0, |
- startY_: 0, |
- startScreenX_: 0, |
- startScreenY_: 0, |
- dragEndTimer_: null, |
- hoverStartTime_: null, |
- |
- isDragging: function() { |
- return !!this.dragItem_; |
- }, |
- |
- handleDragStart_: function(e) { |
- // For the purpose of recording histograms, treat this as the end of |
- // hovering over the thumbnail. |
- this.RecordHoverTime_(false); |
- |
- var thumbnail = getItem(e.target); |
- if (thumbnail) { |
- // Don't set data since HTML5 does not allow setting the name for |
- // url-list. Instead, we just rely on the dragging of link behavior. |
- this.dragItem_ = thumbnail; |
- this.dragItem_.classList.add('dragging'); |
- this.dragItem_.style.zIndex = 2; |
- e.dataTransfer.effectAllowed = 'copyLinkMove'; |
- } |
- }, |
- |
- handleDragEnter_: function(e) { |
- if (this.canDropOnElement_(this.currentOverItem)) { |
- e.preventDefault(); |
- } |
- }, |
- |
- handleDragOver_: function(e) { |
- var item = getItem(e.target); |
- this.currentOverItem = item; |
- if (this.canDropOnElement_(item)) { |
- e.preventDefault(); |
- e.dataTransfer.dropEffect = 'move'; |
- } |
- }, |
- |
- handleDragLeave_: function(e) { |
- var item = getItem(e.target); |
- if (item) { |
- e.preventDefault(); |
- } |
- |
- this.currentOverItem = null; |
- }, |
- |
- handleDrop_: function(e) { |
- var dropTarget = getItem(e.target); |
- if (this.canDropOnElement_(dropTarget)) { |
- dropTarget.style.zIndex = 1; |
- this.swapPosition_(this.dragItem_, dropTarget); |
- // The timeout below is to allow WebKit to see that we turned off |
- // pointer-event before moving the thumbnails so that we can get out of |
- // hover mode. |
- window.setTimeout((function() { |
- this.invalidate_(); |
- this.layout(); |
- }).bind(this), 10); |
- e.preventDefault(); |
- if (this.dragEndTimer_) { |
- window.clearTimeout(this.dragEndTimer_); |
- this.dragEndTimer_ = null; |
- } |
- afterTransition(function() { |
- dropTarget.style.zIndex = ''; |
- }); |
- } |
- }, |
- |
- handleDragEnd_: function(e) { |
- var dragItem = this.dragItem_; |
- if (dragItem) { |
- dragItem.style.pointerEvents = ''; |
- dragItem.classList.remove('dragging'); |
- |
- afterTransition(function() { |
- // Delay resetting zIndex to let the animation finish. |
- dragItem.style.zIndex = ''; |
- // Same for overflow. |
- dragItem.parentNode.style.overflow = ''; |
- }); |
- |
- this.invalidate_(); |
- this.layout(); |
- this.dragItem_ = null; |
- } |
- }, |
- |
- handleDrag_: function(e) { |
- // Moves the drag item making sure that it is not displayed outside the |
- // browser viewport. |
- var item = getItem(e.target); |
- var rect = this.element.getBoundingClientRect(); |
- item.style.pointerEvents = 'none'; |
- |
- var x = this.startX_ + e.screenX - this.startScreenX_; |
- var y = this.startY_ + e.screenY - this.startScreenY_; |
- |
- // The position of the item is relative to #most-visited so we need to |
- // subtract that when calculating the allowed position. |
- x = Math.max(x, -rect.left); |
- x = Math.min(x, document.body.clientWidth - rect.left - item.offsetWidth - |
- 2); |
- // The shadow is 2px |
- y = Math.max(-rect.top, y); |
- y = Math.min(y, document.body.clientHeight - rect.top - |
- item.offsetHeight - 2); |
- |
- // Override right in case of RTL. |
- item.style.right = 'auto'; |
- item.style.left = x + 'px'; |
- item.style.top = y + 'px'; |
- item.style.zIndex = 2; |
- }, |
- |
- // We listen to mousedown to get the relative position of the cursor for |
- // dnd. |
- handleMouseDown_: function(e) { |
- var item = getItem(e.target); |
- if (item) { |
- this.startX_ = item.offsetLeft; |
- this.startY_ = item.offsetTop; |
- this.startScreenX_ = e.screenX; |
- this.startScreenY_ = e.screenY; |
- |
- // We don't want to focus the item on mousedown. However, to prevent |
- // focus one has to call preventDefault but this also prevents the drag |
- // and drop (sigh) so we only prevent it when the user is not doing a |
- // left mouse button drag. |
- if (e.button != 0) // LEFT |
- e.preventDefault(); |
- } |
- }, |
- |
- canDropOnElement_: function(el) { |
- return this.dragItem_ && el && |
- el.classList.contains('thumbnail-container') && |
- !el.classList.contains('filler'); |
- }, |
- |
- // Thumbnail hovering |
- |
- // TODO(mmenke): Either implement preconnect/prerendering based on |
- // hovering, or remove this code. |
- |
- /** |
- * Record the time the mouse has been hovering over a thumbnail. |
- * |clicked| must be true if the thumbnail was clicked, or false if |
- * the cursor was moved off of the thumbnail. |
- */ |
- RecordHoverTime_: function(clicked) { |
- if (!this.hoverStartTime_) |
- return; |
- var hoverDuration = (new Date()).getTime() - this.hoverStartTime_; |
- if (hoverDuration > 500) |
- hoverDuration = 500; |
- chrome.send('recordInHistogram', |
- [clicked ? 'NewTabPage.HoverTimeClicked' |
- : 'NewTabPage.HoverTimeNotClicked', |
- hoverDuration, |
- 500]); |
- this.hoverStartTime_ = null; |
- }, |
- |
- /** |
- * Record the time the cursor started hovering over a thumbnail. |
- * Do nothing if currently dragging the thumbnail. |
- */ |
- handleMouseOver_: function() { |
- if (!this.isDragging()) |
- this.hoverStartTime_ = (new Date()).getTime(); |
- }, |
- |
- /** |
- * Record the time the cursor spend hovering over the thumbnail. |
- */ |
- handleMouseOut_: function() { |
- this.RecordHoverTime_(false); |
- }, |
- |
- |
- /// data |
- |
- data_: null, |
- get data() { |
- return this.data_; |
- }, |
- set data(data) { |
- // We append the class name with the "filler" so that we can style fillers |
- // differently. |
- var maxItems = 8; |
- data.length = Math.min(maxItems, data.length); |
- var len = data.length; |
- for (var i = len; i < maxItems; i++) { |
- data[i] = {filler: true}; |
- } |
- |
- // On setting we need to update the items |
- this.data_ = data; |
- this.updateMostVisited_(); |
- this.updateMiniview_(); |
- this.updateMenu_(); |
- }, |
- |
- updateMostVisited_: function() { |
- |
- function getThumbnailClassName(item) { |
- return 'thumbnail-container' + |
- (item.pinned ? ' pinned' : '') + |
- (item.filler ? ' filler' : ''); |
- } |
- |
- var data = this.data; |
- var children = this.element.children; |
- for (var i = 0; i < data.length; i++) { |
- var d = data[i]; |
- var t = children[i]; |
- |
- // If we have a filler continue |
- var oldClassName = t.className; |
- var newClassName = getThumbnailClassName(d); |
- if (oldClassName != newClassName) { |
- t.className = newClassName; |
- } |
- |
- // No need to continue if this is a filler. |
- if (newClassName == 'thumbnail-container filler') { |
- // Make sure the user cannot tab to the filler. |
- t.tabIndex = -1; |
- t.querySelector('.thumbnail-wrapper').style.backgroundImage = ''; |
- continue; |
- } |
- // Allow focus. |
- t.tabIndex = 1; |
- |
- t.href = d.url; |
- t.setAttribute('ping', |
- getAppPingUrl('PING_BY_URL', d.url, 'NTP_MOST_VISITED')); |
- t.querySelector('.pin').title = localStrings.getString(d.pinned ? |
- 'unpinthumbnailtooltip' : 'pinthumbnailtooltip'); |
- t.querySelector('.remove').title = |
- localStrings.getString('removethumbnailtooltip'); |
- |
- // There was some concern that a malformed malicious URL could cause an |
- // XSS attack but setting style.backgroundImage = 'url(javascript:...)' |
- // does not execute the JavaScript in WebKit. |
- |
- var thumbnailUrl = d.thumbnailUrl || 'chrome://thumb/' + d.url; |
- t.querySelector('.thumbnail-wrapper').style.backgroundImage = |
- url(thumbnailUrl); |
- var titleDiv = t.querySelector('.title > div'); |
- titleDiv.xtitle = titleDiv.textContent = d.title; |
- var faviconUrl = d.faviconUrl || 'chrome://favicon/' + d.url; |
- titleDiv.style.backgroundImage = url(faviconUrl); |
- titleDiv.dir = d.direction; |
- } |
- }, |
- |
- updateMiniview_: function() { |
- this.miniview.textContent = ''; |
- var data = this.data.slice(0, MAX_MINIVIEW_ITEMS); |
- for (var i = 0, item; item = data[i]; i++) { |
- if (item.filler) { |
- continue; |
- } |
- |
- var span = document.createElement('span'); |
- var a = span.appendChild(document.createElement('a')); |
- a.href = item.url; |
- a.setAttribute('ping', |
- getAppPingUrl('PING_BY_URL', item.url, 'NTP_MOST_VISITED')); |
- a.textContent = item.title; |
- a.style.backgroundImage = url('chrome://favicon/' + item.url); |
- a.className = 'item'; |
- this.miniview.appendChild(span); |
- } |
- updateMiniviewClipping(this.miniview); |
- }, |
- |
- updateMenu_: function() { |
- clearClosedMenu(this.menu); |
- var data = this.data.slice(0, MAX_MINIVIEW_ITEMS); |
- for (var i = 0, item; item = data[i]; i++) { |
- if (!item.filler) { |
- addClosedMenuEntry( |
- this.menu, item.url, item.title, 'chrome://favicon/' + item.url, |
- getAppPingUrl('PING_BY_URL', item.url, 'NTP_MOST_VISITED')); |
- } |
- } |
- addClosedMenuFooter( |
- this.menu, 'most-visited', MENU_THUMB, Section.THUMB); |
- }, |
- |
- handleClick_: function(e) { |
- var target = e.target; |
- if (target.classList.contains('pin')) { |
- this.togglePinned_(getItem(target)); |
- e.preventDefault(); |
- } else if (target.classList.contains('remove')) { |
- this.blacklist(getItem(target)); |
- e.preventDefault(); |
- } else { |
- var item = getItem(target); |
- if (item) { |
- var index = Array.prototype.indexOf.call(item.parentNode.children, |
- item); |
- this.RecordHoverTime_(true); |
- if (index != -1) |
- chrome.send('recordInHistogram', |
- ['NewTabPage.MostVisited', index, 8]); |
- } |
- } |
- }, |
- |
- /** |
- * Allow blacklisting most visited site using the keyboard. |
- */ |
- handleKeyDown_: function(e) { |
- if (!cr.isMac && e.keyCode == 46 || // Del |
- cr.isMac && e.metaKey && e.keyCode == 8) { // Cmd + Backspace |
- this.blacklist(e.target); |
- } |
- } |
- }; |
- |
- return MostVisited; |
-})(); |