15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @fileoverview This file provides a class that can be used to open URLs based
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * on user interactions. It ensures a consistent behavior when it comes to
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * holding down Ctrl and Shift while clicking or activating the a link.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This depends on the {@code chrome.windows} and {@code chrome.tabs}
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * extensions API.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cr.define('cr', function() {
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * The kind of link open we want to perform.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @enum {number}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var LinkKind = {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FOREGROUND_TAB: 0,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BACKGROUND_TAB: 1,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WINDOW: 2,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SELF: 3,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    INCOGNITO: 4
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * This class is used to handle opening of links based on user actions. The
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * following actions are currently implemented:
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * * Press Ctrl and click a link. Or click a link with your middle mouse
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *   button (or mousewheel). Or press Enter while holding Ctrl.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     Opens the link in a new tab in the background .
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * * Press Ctrl+Shift and click a link. Or press Shift and click a link with
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *   your middle mouse button (or mousewheel). Or press Enter while holding
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *   Ctrl+Shift.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     Opens the link in a new tab and switches to the newly opened tab.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * * Press Shift and click a link. Or press Enter while holding Shift.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     Opens the link in a new window.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * On Mac, uses Command instead of Ctrl.
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * For keyboard support you need to use keydown.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {!LocalStrings} localStrings The local strings object which is used
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     to localize the warning prompt in case the user tries to open a lot of
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     links.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @constructor
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  function LinkController(localStrings) {
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.localStrings_ = localStrings;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LinkController.prototype = {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The number of links that can be opened before showing a warning confirm
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * message.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    warningLimit: 15,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * The DOM window that we want to open links into in case we are opening
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * links in the same window.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @type {!Window}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    window: window,
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * This method is used for showing the warning confirm message when the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * user is trying to open a lot of links.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {number} The number of URLs to open.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return {string} The message to show the user.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    getWarningMessage: function(count) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return this.localStrings_.getStringF('should_open_all', count);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Open an URL from a mouse or keyboard event.
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} url The URL to open.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Event} e The event triggering the opening of the URL.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    openUrlFromEvent: function(url, e) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // We only support keydown Enter and non right click events.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (e.type == 'keydown' && e.keyIdentifier == 'Enter' ||
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          e.button != 2) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var kind;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        var ctrl = cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (e.button == 1 || ctrl) // middle, ctrl or keyboard
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kind = e.shiftKey ? LinkKind.FOREGROUND_TAB : LinkKind.BACKGROUND_TAB;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else // left or keyboard
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kind = e.shiftKey ? LinkKind.WINDOW : LinkKind.SELF;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.openUrls([url], kind);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Opens a URL in a new tab, window or incognito window.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {string} url The URL to open.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {LinkKind} kind The kind of open we want to do.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    openUrl: function(url, kind) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.openUrls([url], kind);
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    },
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Opens URLs in new tab, window or incognito mode.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {!Array.<string>} urls The URLs to open.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param {LinkKind} kind The kind of open we want to do.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    openUrls: function(urls, kind) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (urls.length < 1)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (urls.length > this.warningLimit) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (!this.window.confirm(this.getWarningMessage(urls.length)))
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Fix '#124' URLs since opening those in a new window does not work. We
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // prepend the base URL when we encounter those.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var base = this.window.location.href.split('#')[0];
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      urls = urls.map(function(url) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return url[0] == '#' ? base + url : url;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      });
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      var incognito = kind == LinkKind.INCOGNITO;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (kind == LinkKind.WINDOW || incognito) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        chrome.windows.create({
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          url: urls,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          incognito: incognito
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        });
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else if (kind == LinkKind.FOREGROUND_TAB ||
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 kind == LinkKind.BACKGROUND_TAB) {
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        urls.forEach(function(url, i) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          chrome.tabs.create({
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            url: url,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            selected: kind == LinkKind.FOREGROUND_TAB && !i
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          });
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        });
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      } else {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this.window.location.href = urls[0];
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Export
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LinkController: LinkController,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LinkKind: LinkKind
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)});
156