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
5cr.define('cr.ui', function() {
6
7  /**
8   * The class name to set on the document element.
9   * @const
10   */
11  var CLASS_NAME = 'focus-outline-visible';
12
13  /**
14   * This class sets a CSS class name on the HTML element of |doc| when the user
15   * presses the tab key. It removes the class name when the user clicks
16   * anywhere.
17   *
18   * This allows you to write CSS like this:
19   *
20   * html.focus-outline-visible my-element:focus {
21   *   outline: 5px auto -webkit-focus-ring-color;
22   * }
23   *
24   * And the outline will only be shown if the user uses the keyboard to get to
25   * it.
26   *
27   * @param {Document} doc The document to attach the focus outline manager to.
28   * @constructor
29   */
30  function FocusOutlineManager(doc) {
31    this.classList_ = doc.documentElement.classList;
32    var self = this;
33    doc.addEventListener('keydown', function(e) {
34      if (e.keyCode == 9)  // Tab
35        self.focusByKeyboard_ = true;
36    }, true);
37
38    doc.addEventListener('mousedown', function(e) {
39      self.focusByKeyboard_ = false;
40    }, true);
41
42    doc.addEventListener('focus', function(event) {
43      // Update visibility only when focus is actually changed.
44      self.visible = self.focusByKeyboard_;
45    }, true);
46  }
47
48  FocusOutlineManager.prototype = {
49    /**
50     * Whether focus change is triggered by TAB key.
51     * @type {boolean}
52     * @private
53     */
54    focusByKeyboard_: true,
55
56    /**
57     * Whether the focus outline should be visible.
58     * @type {boolean}
59     */
60    set visible(visible) {
61      if (visible)
62        this.classList_.add(CLASS_NAME);
63      else
64        this.classList_.remove(CLASS_NAME);
65    },
66    get visible() {
67      return this.classList_.contains(CLASS_NAME);
68    }
69  };
70
71  /**
72   * Array of Document and FocusOutlineManager pairs.
73   * @type {Array}
74   */
75  var docsToManager = [];
76
77  /**
78   * Gets a per document sigleton focus outline manager.
79   * @param {Document} doc The document to get the |FocusOutlineManager| for.
80   * @return {FocusOutlineManager} The per document singleton focus outline
81   *     manager.
82   */
83  FocusOutlineManager.forDocument = function(doc) {
84    for (var i = 0; i < docsToManager.length; i++) {
85      if (doc == docsToManager[i][0])
86        return docsToManager[i][1];
87    }
88    var manager = new FocusOutlineManager(doc);
89    docsToManager.push([doc, manager]);
90    return manager;
91  };
92
93  return {
94    FocusOutlineManager: FocusOutlineManager
95  };
96});
97