mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-07-15 03:29:01 +00:00
291 lines
10 KiB
JavaScript
291 lines
10 KiB
JavaScript
/* 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";
|
|
|
|
const actions = require('../actions/event-listeners');
|
|
const { bindActionCreators } = require('devtools/client/shared/vendor/redux');
|
|
|
|
/**
|
|
* Functions handling the event listeners UI.
|
|
*/
|
|
function EventListenersView(controller) {
|
|
dumpn("EventListenersView was instantiated");
|
|
|
|
this.actions = bindActionCreators(actions, controller.dispatch);
|
|
this.getState = () => controller.getState().eventListeners;
|
|
|
|
this._onCheck = this._onCheck.bind(this);
|
|
this._onClick = this._onClick.bind(this);
|
|
|
|
controller.onChange("event-listeners", this.renderListeners.bind(this));
|
|
}
|
|
|
|
EventListenersView.prototype = Heritage.extend(WidgetMethods, {
|
|
/**
|
|
* Initialization function, called when the debugger is started.
|
|
*/
|
|
initialize: function() {
|
|
dumpn("Initializing the EventListenersView");
|
|
|
|
this.widget = new SideMenuWidget(document.getElementById("event-listeners"), {
|
|
showItemCheckboxes: true,
|
|
showGroupCheckboxes: true
|
|
});
|
|
|
|
this.emptyText = L10N.getStr("noEventListenersText");
|
|
this._eventCheckboxTooltip = L10N.getStr("eventCheckboxTooltip");
|
|
this._onSelectorString = " " + L10N.getStr("eventOnSelector") + " ";
|
|
this._inSourceString = " " + L10N.getStr("eventInSource") + " ";
|
|
this._inNativeCodeString = L10N.getStr("eventNative");
|
|
|
|
this.widget.addEventListener("check", this._onCheck, false);
|
|
this.widget.addEventListener("click", this._onClick, false);
|
|
},
|
|
|
|
/**
|
|
* Destruction function, called when the debugger is closed.
|
|
*/
|
|
destroy: function() {
|
|
dumpn("Destroying the EventListenersView");
|
|
|
|
this.widget.removeEventListener("check", this._onCheck, false);
|
|
this.widget.removeEventListener("click", this._onClick, false);
|
|
},
|
|
|
|
renderListeners: function(listeners) {
|
|
listeners.forEach(listener => {
|
|
this.addListener(listener, { staged: true });
|
|
});
|
|
|
|
// Flushes all the prepared events into the event listeners container.
|
|
this.commit();
|
|
},
|
|
|
|
/**
|
|
* Adds an event to this event listeners container.
|
|
*
|
|
* @param object aListener
|
|
* The listener object coming from the active thread.
|
|
* @param object aOptions [optional]
|
|
* Additional options for adding the source. Supported options:
|
|
* - staged: true to stage the item to be appended later
|
|
*/
|
|
addListener: function(aListener, aOptions = {}) {
|
|
let { node: { selector }, function: { url }, type } = aListener;
|
|
if (!type) return;
|
|
|
|
// Some listener objects may be added from plugins, thus getting
|
|
// translated to native code.
|
|
if (!url) {
|
|
url = this._inNativeCodeString;
|
|
}
|
|
|
|
// If an event item for this listener's url and type was already added,
|
|
// avoid polluting the view and simply increase the "targets" count.
|
|
let eventItem = this.getItemForPredicate(aItem =>
|
|
aItem.attachment.url == url &&
|
|
aItem.attachment.type == type);
|
|
|
|
if (eventItem) {
|
|
let { selectors, view: { targets } } = eventItem.attachment;
|
|
if (selectors.indexOf(selector) == -1) {
|
|
selectors.push(selector);
|
|
targets.setAttribute("value", L10N.getFormatStr("eventNodes", selectors.length));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// There's no easy way of grouping event types into higher-level groups,
|
|
// so we need to do this by hand.
|
|
let is = (...args) => args.indexOf(type) != -1;
|
|
let has = str => type.includes(str);
|
|
let starts = str => type.startsWith(str);
|
|
let group;
|
|
|
|
if (starts("animation")) {
|
|
group = L10N.getStr("animationEvents");
|
|
} else if (starts("audio")) {
|
|
group = L10N.getStr("audioEvents");
|
|
} else if (is("levelchange")) {
|
|
group = L10N.getStr("batteryEvents");
|
|
} else if (is("cut", "copy", "paste")) {
|
|
group = L10N.getStr("clipboardEvents");
|
|
} else if (starts("composition")) {
|
|
group = L10N.getStr("compositionEvents");
|
|
} else if (starts("device")) {
|
|
group = L10N.getStr("deviceEvents");
|
|
} else if (is("fullscreenchange", "fullscreenerror", "orientationchange",
|
|
"overflow", "resize", "scroll", "underflow", "zoom")) {
|
|
group = L10N.getStr("displayEvents");
|
|
} else if (starts("drag") || starts("drop")) {
|
|
group = L10N.getStr("dragAndDropEvents");
|
|
} else if (starts("gamepad")) {
|
|
group = L10N.getStr("gamepadEvents");
|
|
} else if (is("canplay", "canplaythrough", "durationchange", "emptied",
|
|
"ended", "loadeddata", "loadedmetadata", "pause", "play", "playing",
|
|
"ratechange", "seeked", "seeking", "stalled", "suspend", "timeupdate",
|
|
"volumechange", "waiting")) {
|
|
group = L10N.getStr("mediaEvents");
|
|
} else if (is("blocked", "complete", "success", "upgradeneeded", "versionchange")) {
|
|
group = L10N.getStr("indexedDBEvents");
|
|
} else if (is("blur", "change", "focus", "focusin", "focusout", "invalid",
|
|
"reset", "select", "submit")) {
|
|
group = L10N.getStr("interactionEvents");
|
|
} else if (starts("key") || is("input")) {
|
|
group = L10N.getStr("keyboardEvents");
|
|
} else if (starts("mouse") || has("click") || is("contextmenu", "show", "wheel")) {
|
|
group = L10N.getStr("mouseEvents");
|
|
} else if (starts("DOM")) {
|
|
group = L10N.getStr("mutationEvents");
|
|
} else if (is("abort", "error", "hashchange", "load", "loadend", "loadstart",
|
|
"pagehide", "pageshow", "progress", "timeout", "unload", "uploadprogress",
|
|
"visibilitychange")) {
|
|
group = L10N.getStr("navigationEvents");
|
|
} else if (is("pointerlockchange", "pointerlockerror")) {
|
|
group = L10N.getStr("pointerLockEvents");
|
|
} else if (is("compassneedscalibration", "userproximity")) {
|
|
group = L10N.getStr("sensorEvents");
|
|
} else if (starts("storage")) {
|
|
group = L10N.getStr("storageEvents");
|
|
} else if (is("beginEvent", "endEvent", "repeatEvent")) {
|
|
group = L10N.getStr("timeEvents");
|
|
} else if (starts("touch")) {
|
|
group = L10N.getStr("touchEvents");
|
|
} else {
|
|
group = L10N.getStr("otherEvents");
|
|
}
|
|
|
|
// Create the element node for the event listener item.
|
|
const itemView = this._createItemView(type, selector, url);
|
|
|
|
// Event breakpoints survive target navigations. Make sure the newly
|
|
// inserted event item is correctly checked.
|
|
const activeEventNames = this.getState().activeEventNames;
|
|
const checkboxState = activeEventNames.indexOf(type) != -1;
|
|
|
|
// Append an event listener item to this container.
|
|
this.push([itemView.container], {
|
|
staged: aOptions.staged, /* stage the item to be appended later? */
|
|
attachment: {
|
|
url: url,
|
|
type: type,
|
|
view: itemView,
|
|
selectors: [selector],
|
|
group: group,
|
|
checkboxState: checkboxState,
|
|
checkboxTooltip: this._eventCheckboxTooltip
|
|
}
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Gets all the event types known to this container.
|
|
*
|
|
* @return array
|
|
* List of event types, for example ["load", "click"...]
|
|
*/
|
|
getAllEvents: function() {
|
|
return this.attachments.map(e => e.type);
|
|
},
|
|
|
|
/**
|
|
* Gets the checked event types in this container.
|
|
*
|
|
* @return array
|
|
* List of event types, for example ["load", "click"...]
|
|
*/
|
|
getCheckedEvents: function() {
|
|
return this.attachments.filter(e => e.checkboxState).map(e => e.type);
|
|
},
|
|
|
|
/**
|
|
* Customization function for creating an item's UI.
|
|
*
|
|
* @param string aType
|
|
* The event type, for example "click".
|
|
* @param string aSelector
|
|
* The target element's selector.
|
|
* @param string url
|
|
* The source url in which the event listener is located.
|
|
* @return object
|
|
* An object containing the event listener view nodes.
|
|
*/
|
|
_createItemView: function(aType, aSelector, aUrl) {
|
|
let container = document.createElement("hbox");
|
|
container.className = "dbg-event-listener";
|
|
|
|
let eventType = document.createElement("label");
|
|
eventType.className = "plain dbg-event-listener-type";
|
|
eventType.setAttribute("value", aType);
|
|
container.appendChild(eventType);
|
|
|
|
let typeSeparator = document.createElement("label");
|
|
typeSeparator.className = "plain dbg-event-listener-separator";
|
|
typeSeparator.setAttribute("value", this._onSelectorString);
|
|
container.appendChild(typeSeparator);
|
|
|
|
let eventTargets = document.createElement("label");
|
|
eventTargets.className = "plain dbg-event-listener-targets";
|
|
eventTargets.setAttribute("value", aSelector);
|
|
container.appendChild(eventTargets);
|
|
|
|
let selectorSeparator = document.createElement("label");
|
|
selectorSeparator.className = "plain dbg-event-listener-separator";
|
|
selectorSeparator.setAttribute("value", this._inSourceString);
|
|
container.appendChild(selectorSeparator);
|
|
|
|
let eventLocation = document.createElement("label");
|
|
eventLocation.className = "plain dbg-event-listener-location";
|
|
eventLocation.setAttribute("value", SourceUtils.getSourceLabel(aUrl));
|
|
eventLocation.setAttribute("flex", "1");
|
|
eventLocation.setAttribute("crop", "center");
|
|
container.appendChild(eventLocation);
|
|
|
|
return {
|
|
container: container,
|
|
type: eventType,
|
|
targets: eventTargets,
|
|
location: eventLocation
|
|
};
|
|
},
|
|
|
|
/**
|
|
* The check listener for the event listeners container.
|
|
*/
|
|
_onCheck: function({ detail: { description, checked }, target }) {
|
|
if (description == "item") {
|
|
this.getItemForElement(target).attachment.checkboxState = checked;
|
|
|
|
this.actions.updateEventBreakpoints(this.getCheckedEvents());
|
|
return;
|
|
}
|
|
|
|
// Check all the event items in this group.
|
|
this.items
|
|
.filter(e => e.attachment.group == description)
|
|
.forEach(e => this.callMethod("checkItem", e.target, checked));
|
|
},
|
|
|
|
/**
|
|
* The select listener for the event listeners container.
|
|
*/
|
|
_onClick: function({ target }) {
|
|
// Changing the checkbox state is handled by the _onCheck event. Avoid
|
|
// handling that again in this click event, so pass in "noSiblings"
|
|
// when retrieving the target's item, to ignore the checkbox.
|
|
let eventItem = this.getItemForElement(target, { noSiblings: true });
|
|
if (eventItem) {
|
|
let newState = eventItem.attachment.checkboxState ^= 1;
|
|
this.callMethod("checkItem", eventItem.target, newState);
|
|
}
|
|
},
|
|
|
|
_eventCheckboxTooltip: "",
|
|
_onSelectorString: "",
|
|
_inSourceString: "",
|
|
_inNativeCodeString: ""
|
|
});
|
|
|
|
module.exports = EventListenersView;
|