Javascript  |  156行  |  4.77 KB

// Copyright (c) 2012 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.

/**
 * @fileoverview This file provides a class that can be used to open URLs based
 * on user interactions. It ensures a consistent behavior when it comes to
 * holding down Ctrl and Shift while clicking or activating the a link.
 *
 * This depends on the {@code chrome.windows} and {@code chrome.tabs}
 * extensions API.
 */

cr.define('cr', function() {

  /**
   * The kind of link open we want to perform.
   * @enum {number}
   */
  var LinkKind = {
    FOREGROUND_TAB: 0,
    BACKGROUND_TAB: 1,
    WINDOW: 2,
    SELF: 3,
    INCOGNITO: 4
  };

  /**
   * This class is used to handle opening of links based on user actions. The
   * following actions are currently implemented:
   *
   * * Press Ctrl and click a link. Or click a link with your middle mouse
   *   button (or mousewheel). Or press Enter while holding Ctrl.
   *     Opens the link in a new tab in the background .
   * * Press Ctrl+Shift and click a link. Or press Shift and click a link with
   *   your middle mouse button (or mousewheel). Or press Enter while holding
   *   Ctrl+Shift.
   *     Opens the link in a new tab and switches to the newly opened tab.
   * * Press Shift and click a link. Or press Enter while holding Shift.
   *     Opens the link in a new window.
   *
   * On Mac, uses Command instead of Ctrl.
   * For keyboard support you need to use keydown.
   *
   * @param {!LocalStrings} localStrings The local strings object which is used
   *     to localize the warning prompt in case the user tries to open a lot of
   *     links.
   * @constructor
   */
  function LinkController(localStrings) {
    this.localStrings_ = localStrings;
  }

  LinkController.prototype = {
    /**
     * The number of links that can be opened before showing a warning confirm
     * message.
     */
    warningLimit: 15,

    /**
     * The DOM window that we want to open links into in case we are opening
     * links in the same window.
     * @type {!Window}
     */
    window: window,

    /**
     * This method is used for showing the warning confirm message when the
     * user is trying to open a lot of links.
     * @param {number} The number of URLs to open.
     * @return {string} The message to show the user.
     */
    getWarningMessage: function(count) {
      return this.localStrings_.getStringF('should_open_all', count);
    },

    /**
     * Open an URL from a mouse or keyboard event.
     * @param {string} url The URL to open.
     * @param {!Event} e The event triggering the opening of the URL.
     */
    openUrlFromEvent: function(url, e) {
      // We only support keydown Enter and non right click events.
      if (e.type == 'keydown' && e.keyIdentifier == 'Enter' ||
          e.button != 2) {
        var kind;
        var ctrl = cr.isMac && e.metaKey || !cr.isMac && e.ctrlKey;

        if (e.button == 1 || ctrl) // middle, ctrl or keyboard
          kind = e.shiftKey ? LinkKind.FOREGROUND_TAB : LinkKind.BACKGROUND_TAB;
        else // left or keyboard
          kind = e.shiftKey ? LinkKind.WINDOW : LinkKind.SELF;

        this.openUrls([url], kind);
      }
    },


    /**
     * Opens a URL in a new tab, window or incognito window.
     * @param {string} url The URL to open.
     * @param {LinkKind} kind The kind of open we want to do.
     */
    openUrl: function(url, kind) {
      this.openUrls([url], kind);
    },

    /**
     * Opens URLs in new tab, window or incognito mode.
     * @param {!Array.<string>} urls The URLs to open.
     * @param {LinkKind} kind The kind of open we want to do.
     */
    openUrls: function(urls, kind) {
      if (urls.length < 1)
        return;

      if (urls.length > this.warningLimit) {
        if (!this.window.confirm(this.getWarningMessage(urls.length)))
          return;
      }

      // Fix '#124' URLs since opening those in a new window does not work. We
      // prepend the base URL when we encounter those.
      var base = this.window.location.href.split('#')[0];
      urls = urls.map(function(url) {
        return url[0] == '#' ? base + url : url;
      });

      var incognito = kind == LinkKind.INCOGNITO;
      if (kind == LinkKind.WINDOW || incognito) {
        chrome.windows.create({
          url: urls,
          incognito: incognito
        });
      } else if (kind == LinkKind.FOREGROUND_TAB ||
                 kind == LinkKind.BACKGROUND_TAB) {
        urls.forEach(function(url, i) {
          chrome.tabs.create({
            url: url,
            selected: kind == LinkKind.FOREGROUND_TAB && !i
          });
        });
      } else {
        this.window.location.href = urls[0];
      }
    }
  };

  // Export
  return {
    LinkController: LinkController,
    LinkKind: LinkKind
  };
});