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 3// found in the LICENSE file. 4 5/** 6 * @fileoverview This file provides a class that can be used to open URLs based 7 * on user interactions. It ensures a consistent behavior when it comes to 8 * holding down Ctrl and Shift while clicking or activating the a link. 9 * 10 * This depends on the {@code chrome.windows} and {@code chrome.tabs} 11 * extensions API. 12 */ 13 14cr.define('cr', function() { 15 16 /** 17 * The kind of link open we want to perform. 18 * @enum {number} 19 */ 20 var LinkKind = { 21 FOREGROUND_TAB: 0, 22 BACKGROUND_TAB: 1, 23 WINDOW: 2, 24 SELF: 3, 25 INCOGNITO: 4 26 }; 27 28 /** 29 * This class is used to handle opening of links based on user actions. The 30 * following actions are currently implemented: 31 * 32 * * Press Ctrl and click a link. Or click a link with your middle mouse 33 * button (or mousewheel). Or press Enter while holding Ctrl. 34 * Opens the link in a new tab in the background . 35 * * Press Ctrl+Shift and click a link. Or press Shift and click a link with 36 * your middle mouse button (or mousewheel). Or press Enter while holding 37 * Ctrl+Shift. 38 * Opens the link in a new tab and switches to the newly opened tab. 39 * * Press Shift and click a link. Or press Enter while holding Shift. 40 * Opens the link in a new window. 41 * 42 * On Mac, uses Command instead of Ctrl. 43 * For keyboard support you need to use keydown. 44 * 45 * @param {!LocalStrings} localStrings The local strings object which is used 46 * to localize the warning prompt in case the user tries to open a lot of 47 * links. 48 * @constructor 49 */ 50 function LinkController(localStrings) { 51 this.localStrings_ = localStrings; 52 } 53 54 LinkController.prototype = { 55 /** 56 * The number of links that can be opened before showing a warning confirm 57 * message. 58 */ 59 warningLimit: 15, 60 61 /** 62 * The DOM window that we want to open links into in case we are opening 63 * links in the same window. 64 * @type {!Window} 65 */ 66 window: window, 67 68 /** 69 * This method is used for showing the warning confirm message when the 70 * user is trying to open a lot of links. 71 * @param {number} The number of URLs to open. 72 * @return {string} The message to show the user. 73 */ 74 getWarningMessage: function(count) { 75 return this.localStrings_.getStringF('should_open_all', count); 76 }, 77 78 /** 79 * Open an URL from a mouse or keyboard event. 80 * @param {string} url The URL to open. 81 * @param {!Event} e The event triggering the opening of the URL. 82 */ 83 openUrlFromEvent: function(url, e) { 84 // We only support keydown Enter and non right click events. 85 if (e.type == 'keydown' && e.keyIdentifier == 'Enter' || 86 e.button != 2) { 87 var kind; 88 var ctrl = cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey; 89 90 if (e.button == 1 || ctrl) // middle, ctrl or keyboard 91 kind = e.shiftKey ? LinkKind.FOREGROUND_TAB : LinkKind.BACKGROUND_TAB; 92 else // left or keyboard 93 kind = e.shiftKey ? LinkKind.WINDOW : LinkKind.SELF; 94 95 this.openUrls([url], kind); 96 } 97 }, 98 99 100 /** 101 * Opens a URL in a new tab, window or incognito window. 102 * @param {string} url The URL to open. 103 * @param {LinkKind} kind The kind of open we want to do. 104 */ 105 openUrl: function(url, kind) { 106 this.openUrls([url], kind); 107 }, 108 109 /** 110 * Opens URLs in new tab, window or incognito mode. 111 * @param {!Array.<string>} urls The URLs to open. 112 * @param {LinkKind} kind The kind of open we want to do. 113 */ 114 openUrls: function(urls, kind) { 115 if (urls.length < 1) 116 return; 117 118 if (urls.length > this.warningLimit) { 119 if (!this.window.confirm(this.getWarningMessage(urls.length))) 120 return; 121 } 122 123 // Fix '#124' URLs since opening those in a new window does not work. We 124 // prepend the base URL when we encounter those. 125 var base = this.window.location.href.split('#')[0]; 126 urls = urls.map(function(url) { 127 return url[0] == '#' ? base + url : url; 128 }); 129 130 var incognito = kind == LinkKind.INCOGNITO; 131 if (kind == LinkKind.WINDOW || incognito) { 132 chrome.windows.create({ 133 url: urls, 134 incognito: incognito 135 }); 136 } else if (kind == LinkKind.FOREGROUND_TAB || 137 kind == LinkKind.BACKGROUND_TAB) { 138 urls.forEach(function(url, i) { 139 chrome.tabs.create({ 140 url: url, 141 selected: kind == LinkKind.FOREGROUND_TAB && !i 142 }); 143 }); 144 } else { 145 this.window.location.href = urls[0]; 146 } 147 } 148 }; 149 150 // Export 151 return { 152 LinkController: LinkController, 153 LinkKind: LinkKind 154 }; 155}); 156