summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/resources/event_bindings.js
blob: 6fcdd0038ddb048cba9475b69906f3acfe21377b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright (c) 2009 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.

// -----------------------------------------------------------------------------
// NOTE: If you change this file you need to touch renderer_resources.grd to
// have your change take effect.
// -----------------------------------------------------------------------------

var chrome = chrome || {};
(function () {
  native function AttachEvent(eventName);
  native function DetachEvent(eventName);

  // Event object.  If opt_eventName is provided, this object represents
  // the unique instance of that named event, and dispatching an event
  // with that name will route through this object's listeners.
  //
  // Example:
  //   chrome.tabs.onChanged = new chrome.Event("tab-changed");
  //   chrome.tabs.onChanged.addListener(function(data) { alert(data); });
  //   chrome.Event.dispatch_("tab-changed", "hi");
  // will result in an alert dialog that says 'hi'.
  chrome.Event = function(opt_eventName) {
    this.eventName_ = opt_eventName;
    this.listeners_ = [];
  };

  // A map of event names to the event object that is registered to that name.
  chrome.Event.attached_ = {};

  // Dispatches a named event with the given JSON array, which is deserialized
  // before dispatch. The JSON array is the list of arguments that will be
  // sent with the event callback.
  chrome.Event.dispatchJSON_ = function(name, args) {
    if (chrome.Event.attached_[name]) {
      if (args) {
        args = goog.json.parse(args);
      }
      chrome.Event.attached_[name].dispatch.apply(
          chrome.Event.attached_[name], args);
    }
  };

  // Dispatches a named event with the given arguments, supplied as an array.
  chrome.Event.dispatch_ = function(name, args) {
    if (chrome.Event.attached_[name]) {
      chrome.Event.attached_[name].dispatch.apply(
          chrome.Event.attached_[name], args);
    }
  };

  // Registers a callback to be called when this event is dispatched.
  chrome.Event.prototype.addListener = function(cb) {
    this.listeners_.push(cb);
    if (this.listeners_.length == 1) {
      this.attach_();
    }
  };

  // Unregisters a callback.
  chrome.Event.prototype.removeListener = function(cb) {
    var idx = this.findListener_(cb);
    if (idx == -1) {
      return;
    }

    this.listeners_.splice(idx, 1);
    if (this.listeners_.length == 0) {
      this.detach_();
    }
  };

  // Test if the given callback is registered for this event.
  chrome.Event.prototype.hasListener = function(cb) {
    return this.findListeners_(cb) > -1;
  };

  // Returns the index of the given callback if registered, or -1 if not
  // found.
  chrome.Event.prototype.findListener_ = function(cb) {
    for (var i = 0; i < this.listeners_.length; i++) {
      if (this.listeners_[i] == cb) {
        return i;
      }
    }

    return -1;
  };

  // Dispatches this event object to all listeners, passing all supplied
  // arguments to this function each listener.
  chrome.Event.prototype.dispatch = function(varargs) {
    var args = Array.prototype.slice.call(arguments);
    for (var i = 0; i < this.listeners_.length; i++) {
      try {
        this.listeners_[i].apply(null, args);
      } catch (e) {
        console.error(e);
      }
    }
  };

  // Attaches this event object to its name.  Only one object can have a given
  // name.
  chrome.Event.prototype.attach_ = function() {
    AttachEvent(this.eventName_);
    this.unloadHandler_ = this.detach_.bind(this);
    window.addEventListener('unload', this.unloadHandler_, false);
    if (!this.eventName_)
      return;

    if (chrome.Event.attached_[this.eventName_]) {
      throw new Error("chrome.Event '" + this.eventName_ +
                      "' is already attached.");
    }

    chrome.Event.attached_[this.eventName_] = this;
  };

  // Detaches this event object from its name.
  chrome.Event.prototype.detach_ = function() {
    window.removeEventListener('unload', this.unloadHandler_, false);
    DetachEvent(this.eventName_);
    if (!this.eventName_)
      return;

    if (!chrome.Event.attached_[this.eventName_]) {
      throw new Error("chrome.Event '" + this.eventName_ +
                      "' is not attached.");
    }

    delete chrome.Event.attached_[this.eventName_];
  };
})();