Bug 991757 - add telemetry for the context menu, r=mconley,bgrins,f=bwinton

This commit is contained in:
Gijs Kruitbosch 2014-08-14 20:44:59 +02:00
Родитель 1e7dad43eb
Коммит e126ede3c2
5 изменённых файлов: 146 добавлений и 5 удалений

Просмотреть файл

@ -3,6 +3,9 @@
# 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/.
# NB: IF YOU ADD ITEMS TO THIS FILE, PLEASE UPDATE THE WHITELIST IN
# BrowserUITelemetry.jsm. SEE BUG 991757 FOR DETAILS.
<menugroup id="context-navigation">
<menuitem id="context-back"
class="menuitem-iconic"

Просмотреть файл

@ -38,6 +38,9 @@ nsContextMenu.prototype = {
// Initialize (disable/remove) menu items.
this.initItems();
// Register this opening of the menu with telemetry:
this._checkTelemetryForMenu(aXulMenu);
},
hiding: function CM_hiding() {
@ -45,6 +48,11 @@ nsContextMenu.prototype = {
InlineSpellCheckerUI.clearSuggestionsFromMenu();
InlineSpellCheckerUI.clearDictionaryListFromMenu();
InlineSpellCheckerUI.uninit();
// This handler self-deletes, only run it if it is still there:
if (this._onPopupHiding) {
this._onPopupHiding();
}
},
initItems: function CM_initItems() {
@ -1703,5 +1711,76 @@ nsContextMenu.prototype = {
selectedText]);
menuItem.label = menuLabel;
menuItem.accessKey = gNavigatorBundle.getString("contextMenuSearch.accesskey");
},
_getTelemetryClickInfo: function(aXulMenu) {
this._onPopupHiding = () => {
aXulMenu.ownerDocument.removeEventListener("command", activationHandler, true);
aXulMenu.removeEventListener("popuphiding", this._onPopupHiding, true);
delete this._onPopupHiding;
let eventKey = [
this._telemetryPageContext,
this._telemetryHadCustomItems ? "withcustom" : "withoutcustom"
];
let target = this._telemetryClickID || "close-without-interaction";
BrowserUITelemetry.registerContextMenuInteraction(eventKey, target);
};
let activationHandler = (e) => {
// Deal with command events being routed to command elements; figure out
// what triggered the event (which will have the right e.target)
if (e.sourceEvent) {
e = e.sourceEvent;
}
// Target should be in the menu (this catches using shortcuts for items
// not in the menu while the menu is up)
if (!aXulMenu.contains(e.target)) {
return;
}
// Check if this is a page menu item:
if (e.target.hasAttribute(PageMenu.GENERATEDITEMID_ATTR)) {
this._telemetryClickID = "custom-page-item";
} else {
this._telemetryClickID = (e.target.id || "unknown").replace(/^context-/i, "");
}
};
aXulMenu.ownerDocument.addEventListener("command", activationHandler, true);
aXulMenu.addEventListener("popuphiding", this._onPopupHiding, true);
},
_getTelemetryPageContextInfo: function() {
if (this.isContentSelected) {
return "selection";
}
if (this.onLink) {
if (this.onImage || this.onCanvas) {
return "image-link";
}
return "link";
}
if (this.onImage) {
return "image"
}
if (this.onCanvas) {
return "canvas";
}
if (this.onVideo || this.onAudio) {
return "media";
}
if (this.onTextInput) {
return "input";
}
if (this.onSocial) {
return "social";
}
return "other";
},
_checkTelemetryForMenu: function(aXulMenu) {
this._telemetryClickID = null;
this._telemetryPageContext = this._getTelemetryPageContextInfo();
this._telemetryHadCustomItems = this.hasPageMenu;
this._getTelemetryClickInfo(aXulMenu);
},
};

Просмотреть файл

@ -119,6 +119,9 @@ function* clickOnInspectMenuItem(node) {
info("Triggering inspect action.");
yield contextMenu.inspectNode();
// Clean up context menu:
contextMenu.hiding();
info("Waiting for inspector to update.");
yield getActiveInspector().once("inspector-updated");
}

Просмотреть файл

@ -31,6 +31,10 @@ let test = asyncTest(function*() {
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
let contextMenu = new nsContextMenu(contentAreaContextMenu);
yield contextMenu.inspectNode();
// Clean up context menu:
contextMenu.hiding();
yield onInspectorReady;
let target = TargetFactory.forTab(gBrowser.selectedTab);

Просмотреть файл

@ -170,6 +170,8 @@ this.BrowserUITelemetry = {
init: function() {
UITelemetry.addSimpleMeasureFunction("toolbars",
this.getToolbarMeasures.bind(this));
UITelemetry.addSimpleMeasureFunction("contextmenu",
this.getContextMenuInfo.bind(this));
// Ensure that UITour.jsm remains lazy-loaded, yet always registers its
// simple measure function with UITelemetry.
UITelemetry.addSimpleMeasureFunction("UITour",
@ -220,11 +222,13 @@ this.BrowserUITelemetry = {
*
* @param aKeys the Array of keys to chain Objects together with.
* @param aEndWith the value to assign to the last key.
* @param aRoot the root object onto which we create/get the object chain
* designated by aKeys.
* @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;
_ensureObjectChain: function(aKeys, aEndWith, aRoot) {
let current = aRoot;
let parent = null;
aKeys.unshift(this._bucket);
for (let [i, key] of Iterator(aKeys)) {
@ -242,8 +246,8 @@ this.BrowserUITelemetry = {
},
_countableEvents: {},
_countEvent: function(aKeyArray) {
let countObject = this._ensureObjectChain(aKeyArray, 0);
_countEvent: function(aKeyArray, root=this._countableEvents) {
let countObject = this._ensureObjectChain(aKeyArray, 0, root);
let lastItemKey = aKeyArray[aKeyArray.length - 1];
countObject[lastItemKey]++;
},
@ -587,6 +591,54 @@ this.BrowserUITelemetry = {
}
},
_contextMenuItemWhitelist: new Set([
"close-without-interaction", // for closing the menu without clicking it.
"custom-page-item", // The ID we use for page-provided items
"unknown", // The bucket for stuff with no id.
// Everything we know of so far (which will exclude add-on items):
"navigation", "back", "forward", "reload", "stop", "bookmarkpage",
"spell-no-suggestions", "spell-add-to-dictionary",
"spell-undo-add-to-dictionary", "openlinkincurrent", "openlinkintab",
"openlink", "openlinkprivate", "bookmarklink", "sharelink", "savelink",
"marklinkMenu", "copyemail", "copylink", "media-play", "media-pause",
"media-mute", "media-unmute", "media-playbackrate",
"media-playbackrate-050x", "media-playbackrate-100x",
"media-playbackrate-150x", "media-playbackrate-200x",
"media-showcontrols", "media-hidecontrols", "video-showstats",
"video-hidestats", "video-fullscreen", "leave-dom-fullscreen",
"reloadimage", "viewimage", "viewvideo", "copyimage-contents", "copyimage",
"copyvideourl", "copyaudiourl", "saveimage", "shareimage", "sendimage",
"setDesktopBackground", "viewimageinfo", "viewimagedesc", "savevideo",
"sharevideo", "saveaudio", "video-saveimage", "sendvideo", "sendaudio",
"ctp-play", "ctp-hide", "sharepage", "savepage", "markpageMenu",
"viewbgimage", "undo", "cut", "copy", "paste", "delete", "selectall",
"keywordfield", "searchselect", "shareselect", "frame", "showonlythisframe",
"openframeintab", "openframe", "reloadframe", "bookmarkframe", "saveframe",
"printframe", "viewframesource", "viewframeinfo",
"viewpartialsource-selection", "viewpartialsource-mathml",
"viewsource", "viewinfo", "spell-check-enabled",
"spell-add-dictionaries-main", "spell-dictionaries",
"spell-dictionaries-menu", "spell-add-dictionaries",
"bidi-text-direction-toggle", "bidi-page-direction-toggle", "inspect",
]),
_contextMenuInteractions: {},
registerContextMenuInteraction: function(keys, itemID) {
if (itemID) {
if (!this._contextMenuItemWhitelist.has(itemID)) {
itemID = "other-item";
}
keys.push(itemID);
}
this._countEvent(keys, this._contextMenuInteractions);
},
getContextMenuInfo: function() {
return this._contextMenuInteractions;
},
_bucket: BUCKET_DEFAULT,
_bucketTimer: null,