diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /devtools/client/debugger/content/views/event-listeners-view.js | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/debugger/content/views/event-listeners-view.js')
-rw-r--r-- | devtools/client/debugger/content/views/event-listeners-view.js | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/devtools/client/debugger/content/views/event-listeners-view.js b/devtools/client/debugger/content/views/event-listeners-view.js new file mode 100644 index 000000000..993d6506e --- /dev/null +++ b/devtools/client/debugger/content/views/event-listeners-view.js @@ -0,0 +1,295 @@ +/* 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"; + +/* import-globals-from ../../debugger-controller.js */ + +const actions = require("../actions/event-listeners"); +const { bindActionCreators } = require("devtools/client/shared/vendor/redux"); +const { Heritage, WidgetMethods } = require("devtools/client/shared/widgets/view-helpers"); +const { SideMenuWidget } = require("resource://devtools/client/shared/widgets/SideMenuWidget.jsm"); + +/** + * 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; |