2013-12-10 11:49:02 -08:00
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
this.EXPORTED_SYMBOLS = ["BrowserUITelemetry"];
|
|
|
|
|
|
|
|
const Cu = Components.utils;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
|
|
|
|
"resource://gre/modules/UITelemetry.jsm");
|
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
|
|
|
"resource:///modules/RecentWindow.jsm");
|
2013-12-10 11:49:24 -08:00
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
|
|
|
"resource:///modules/CustomizableUI.jsm");
|
|
|
|
|
|
|
|
const ALL_BUILTIN_ITEMS = [
|
|
|
|
"fullscreen-button",
|
|
|
|
"switch-to-metro-button",
|
|
|
|
];
|
2013-12-10 11:49:02 -08:00
|
|
|
|
2013-12-17 14:00:13 -08:00
|
|
|
const OTHER_MOUSEUP_MONITORED_ITEMS = [
|
|
|
|
"PlacesChevron",
|
|
|
|
"PlacesToolbarItems",
|
|
|
|
];
|
|
|
|
|
2013-12-10 11:49:02 -08:00
|
|
|
this.BrowserUITelemetry = {
|
|
|
|
init: function() {
|
|
|
|
UITelemetry.addSimpleMeasureFunction("toolbars",
|
|
|
|
this.getToolbarMeasures.bind(this));
|
2013-12-10 11:49:24 -08:00
|
|
|
Services.obs.addObserver(this, "browser-delayed-startup-finished", false);
|
|
|
|
},
|
|
|
|
|
|
|
|
observe: function(aSubject, aTopic, aData) {
|
|
|
|
if (aTopic == "browser-delayed-startup-finished") {
|
|
|
|
this._registerWindow(aSubject);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For the _countableEvents object, constructs a chain of
|
|
|
|
* Javascript Objects with the keys in aKeys, with the final
|
|
|
|
* key getting the value in aEndWith. If the final key already
|
|
|
|
* exists in the final object, its value is not set. In either
|
|
|
|
* case, a reference to the second last object in the chain is
|
|
|
|
* returned.
|
|
|
|
*
|
|
|
|
* Example - suppose I want to store:
|
|
|
|
* _countableEvents: {
|
|
|
|
* a: {
|
|
|
|
* b: {
|
|
|
|
* c: 0
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* And then increment the "c" value by 1, you could call this
|
|
|
|
* function like this:
|
|
|
|
*
|
|
|
|
* let example = this._ensureObjectChain([a, b, c], 0);
|
|
|
|
* example["c"]++;
|
|
|
|
*
|
|
|
|
* Subsequent repetitions of these last two lines would
|
|
|
|
* simply result in the c value being incremented again
|
|
|
|
* and again.
|
|
|
|
*
|
|
|
|
* @param aKeys the Array of keys to chain Objects together with.
|
|
|
|
* @param aEndWith the value to assign to the last key.
|
|
|
|
* @returns a reference to the second last object in the chain -
|
|
|
|
* so in our example, that'd be "b".
|
|
|
|
*/
|
|
|
|
_ensureObjectChain: function(aKeys, aEndWith) {
|
|
|
|
let current = this._countableEvents;
|
|
|
|
let parent = null;
|
|
|
|
for (let [i, key] of Iterator(aKeys)) {
|
|
|
|
if (!(key in current)) {
|
|
|
|
if (i == aKeys.length - 1) {
|
|
|
|
current[key] = aEndWith;
|
|
|
|
} else {
|
|
|
|
current[key] = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
parent = current;
|
|
|
|
current = current[key];
|
|
|
|
}
|
|
|
|
return parent;
|
|
|
|
},
|
|
|
|
|
|
|
|
_countableEvents: {},
|
2013-12-10 15:26:37 -08:00
|
|
|
_countMouseUpEvent: function(aCategory, aAction, aButton) {
|
2013-12-10 11:49:24 -08:00
|
|
|
const BUTTONS = ["left", "middle", "right"];
|
2013-12-10 15:26:37 -08:00
|
|
|
let buttonKey = BUTTONS[aButton];
|
2013-12-10 11:49:24 -08:00
|
|
|
if (buttonKey) {
|
|
|
|
let countObject =
|
|
|
|
this._ensureObjectChain([aCategory, aAction, buttonKey], 0);
|
|
|
|
countObject[buttonKey]++;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_registerWindow: function(aWindow) {
|
|
|
|
aWindow.addEventListener("unload", this);
|
|
|
|
let document = aWindow.document;
|
|
|
|
|
|
|
|
for (let areaID of CustomizableUI.areas) {
|
|
|
|
let areaNode = document.getElementById(areaID);
|
2013-12-16 03:28:38 -08:00
|
|
|
if (areaNode) {
|
|
|
|
(areaNode.customizationTarget || areaNode).addEventListener("mouseup", this);
|
|
|
|
}
|
2013-12-10 11:49:24 -08:00
|
|
|
}
|
2013-12-17 14:00:13 -08:00
|
|
|
|
|
|
|
for (let itemID of OTHER_MOUSEUP_MONITORED_ITEMS) {
|
|
|
|
let item = document.getElementById(itemID);
|
|
|
|
if (item) {
|
|
|
|
item.addEventListener("mouseup", this);
|
|
|
|
}
|
|
|
|
}
|
2013-12-10 11:49:24 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
_unregisterWindow: function(aWindow) {
|
|
|
|
aWindow.removeEventListener("unload", this);
|
|
|
|
let document = aWindow.document;
|
|
|
|
|
|
|
|
for (let areaID of CustomizableUI.areas) {
|
|
|
|
let areaNode = document.getElementById(areaID);
|
2013-12-16 03:28:38 -08:00
|
|
|
if (areaNode) {
|
|
|
|
(areaNode.customizationTarget || areaNode).removeEventListener("mouseup", this);
|
|
|
|
}
|
2013-12-10 11:49:24 -08:00
|
|
|
}
|
2013-12-17 14:00:13 -08:00
|
|
|
|
|
|
|
for (let itemID of OTHER_MOUSEUP_MONITORED_ITEMS) {
|
|
|
|
let item = document.getElementById(itemID);
|
|
|
|
if (item) {
|
|
|
|
item.removeEventListener("mouseup", this);
|
|
|
|
}
|
|
|
|
}
|
2013-12-10 11:49:24 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
handleEvent: function(aEvent) {
|
|
|
|
switch(aEvent.type) {
|
|
|
|
case "unload":
|
|
|
|
this._unregisterWindow(aEvent.currentTarget);
|
|
|
|
break;
|
|
|
|
case "mouseup":
|
|
|
|
this._handleMouseUp(aEvent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_handleMouseUp: function(aEvent) {
|
2013-12-17 14:00:13 -08:00
|
|
|
let targetID = aEvent.currentTarget.id;
|
|
|
|
|
|
|
|
switch (targetID) {
|
|
|
|
case "PlacesToolbarItems":
|
|
|
|
this._PlacesToolbarItemsMouseUp(aEvent);
|
|
|
|
break;
|
|
|
|
case "PlacesChevron":
|
|
|
|
this._PlacesChevronMouseUp(aEvent);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
this._checkForBuiltinItem(aEvent);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
_PlacesChevronMouseUp: function(aEvent) {
|
|
|
|
let target = aEvent.originalTarget;
|
|
|
|
let result = target.id == "PlacesChevron" ? "chevron" : "overflowed-item";
|
|
|
|
this._countMouseUpEvent("click-bookmarks-bar", result, aEvent.button);
|
|
|
|
},
|
|
|
|
|
|
|
|
_PlacesToolbarItemsMouseUp: function(aEvent) {
|
|
|
|
let target = aEvent.originalTarget;
|
|
|
|
// If this isn't a bookmark-item, we don't care about it.
|
|
|
|
if (!target.classList.contains("bookmark-item")) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = target.hasAttribute("container") ? "container" : "item";
|
|
|
|
this._countMouseUpEvent("click-bookmarks-bar", result, aEvent.button);
|
|
|
|
},
|
|
|
|
|
|
|
|
_checkForBuiltinItem: function(aEvent) {
|
2013-12-10 11:49:24 -08:00
|
|
|
let item = aEvent.originalTarget;
|
|
|
|
// Perhaps we're seeing one of the default toolbar items
|
|
|
|
// being clicked.
|
|
|
|
if (ALL_BUILTIN_ITEMS.indexOf(item.id) != -1) {
|
|
|
|
// Base case - we clicked directly on one of our built-in items,
|
|
|
|
// and we can go ahead and register that click.
|
2013-12-10 15:26:37 -08:00
|
|
|
this._countMouseUpEvent("click-builtin-item", item.id, aEvent.button);
|
2013-12-10 11:49:24 -08:00
|
|
|
}
|
2013-12-10 11:49:02 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
getToolbarMeasures: function() {
|
|
|
|
// Grab the most recent non-popup, non-private browser window for us to
|
|
|
|
// analyze the toolbars in...
|
|
|
|
let win = RecentWindow.getMostRecentBrowserWindow({
|
|
|
|
private: false,
|
|
|
|
allowPopups: false
|
|
|
|
});
|
|
|
|
|
|
|
|
// If there are no such windows, we're out of luck. :(
|
|
|
|
if (!win) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
let document = win.document;
|
|
|
|
let result = {};
|
|
|
|
|
2013-12-17 14:00:13 -08:00
|
|
|
// Determine if the Bookmarks bar is currently visible
|
|
|
|
let bookmarksBar = document.getElementById("PersonalToolbar");
|
|
|
|
result.bookmarksBarEnabled = bookmarksBar && !bookmarksBar.collapsed;
|
|
|
|
|
2013-12-10 11:49:24 -08:00
|
|
|
result.countableEvents = this._countableEvents;
|
|
|
|
|
2013-12-10 11:49:02 -08:00
|
|
|
return result;
|
|
|
|
},
|
|
|
|
};
|