mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 15:58:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
378
devtools/client/debugger/utils.js
Normal file
378
devtools/client/debugger/utils.js
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
/* globals document, window */
|
||||
/* import-globals-from ./debugger-controller.js */
|
||||
"use strict";
|
||||
|
||||
// Maps known URLs to friendly source group names and put them at the
|
||||
// bottom of source list.
|
||||
var KNOWN_SOURCE_GROUPS = {
|
||||
"Add-on SDK": "resource://gre/modules/commonjs/",
|
||||
};
|
||||
|
||||
KNOWN_SOURCE_GROUPS[L10N.getStr("anonymousSourcesLabel")] = "anonymous";
|
||||
|
||||
var XULUtils = {
|
||||
/**
|
||||
* Create <command> elements within `commandset` with event handlers
|
||||
* bound to the `command` event
|
||||
*
|
||||
* @param commandset HTML Element
|
||||
* A <commandset> element
|
||||
* @param commands Object
|
||||
* An object where keys specify <command> ids and values
|
||||
* specify event handlers to be bound on the `command` event
|
||||
*/
|
||||
addCommands: function (commandset, commands) {
|
||||
Object.keys(commands).forEach(name => {
|
||||
let node = document.createElement("command");
|
||||
node.id = name;
|
||||
// XXX bug 371900: the command element must have an oncommand
|
||||
// attribute as a string set by `setAttribute` for keys to use it
|
||||
node.setAttribute("oncommand", " ");
|
||||
node.addEventListener("command", commands[name]);
|
||||
commandset.appendChild(node);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Used to detect minification for automatic pretty printing
|
||||
const SAMPLE_SIZE = 50; // no of lines
|
||||
const INDENT_COUNT_THRESHOLD = 5; // percentage
|
||||
const CHARACTER_LIMIT = 250; // line character limit
|
||||
|
||||
/**
|
||||
* Utility functions for handling sources.
|
||||
*/
|
||||
var SourceUtils = {
|
||||
_labelsCache: new Map(), // Can't use WeakMaps because keys are strings.
|
||||
_groupsCache: new Map(),
|
||||
_minifiedCache: new Map(),
|
||||
|
||||
/**
|
||||
* Returns true if the specified url and/or content type are specific to
|
||||
* javascript files.
|
||||
*
|
||||
* @return boolean
|
||||
* True if the source is likely javascript.
|
||||
*/
|
||||
isJavaScript: function (aUrl, aContentType = "") {
|
||||
return (aUrl && /\.jsm?$/.test(this.trimUrlQuery(aUrl))) ||
|
||||
aContentType.includes("javascript");
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the source text is minified by using
|
||||
* the percentage indented of a subset of lines
|
||||
*
|
||||
* @return object
|
||||
* A promise that resolves to true if source text is minified.
|
||||
*/
|
||||
isMinified: function (key, text) {
|
||||
if (this._minifiedCache.has(key)) {
|
||||
return this._minifiedCache.get(key);
|
||||
}
|
||||
|
||||
let isMinified;
|
||||
let lineEndIndex = 0;
|
||||
let lineStartIndex = 0;
|
||||
let lines = 0;
|
||||
let indentCount = 0;
|
||||
let overCharLimit = false;
|
||||
|
||||
// Strip comments.
|
||||
text = text.replace(/\/\*[\S\s]*?\*\/|\/\/(.+|\n)/g, "");
|
||||
|
||||
while (lines++ < SAMPLE_SIZE) {
|
||||
lineEndIndex = text.indexOf("\n", lineStartIndex);
|
||||
if (lineEndIndex == -1) {
|
||||
break;
|
||||
}
|
||||
if (/^\s+/.test(text.slice(lineStartIndex, lineEndIndex))) {
|
||||
indentCount++;
|
||||
}
|
||||
// For files with no indents but are not minified.
|
||||
if ((lineEndIndex - lineStartIndex) > CHARACTER_LIMIT) {
|
||||
overCharLimit = true;
|
||||
break;
|
||||
}
|
||||
lineStartIndex = lineEndIndex + 1;
|
||||
}
|
||||
|
||||
isMinified =
|
||||
((indentCount / lines) * 100) < INDENT_COUNT_THRESHOLD || overCharLimit;
|
||||
|
||||
this._minifiedCache.set(key, isMinified);
|
||||
return isMinified;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the labels, groups and minify cache, populated by methods like
|
||||
* SourceUtils.getSourceLabel or Source Utils.getSourceGroup.
|
||||
* This should be done every time the content location changes.
|
||||
*/
|
||||
clearCache: function () {
|
||||
this._labelsCache.clear();
|
||||
this._groupsCache.clear();
|
||||
this._minifiedCache.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a unique, simplified label from a source url.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The source url.
|
||||
* @return string
|
||||
* The simplified label.
|
||||
*/
|
||||
getSourceLabel: function (aUrl) {
|
||||
let cachedLabel = this._labelsCache.get(aUrl);
|
||||
if (cachedLabel) {
|
||||
return cachedLabel;
|
||||
}
|
||||
|
||||
let sourceLabel = null;
|
||||
|
||||
for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
|
||||
if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
|
||||
sourceLabel = aUrl.substring(KNOWN_SOURCE_GROUPS[name].length);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sourceLabel) {
|
||||
sourceLabel = this.trimUrl(aUrl);
|
||||
}
|
||||
|
||||
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(sourceLabel));
|
||||
this._labelsCache.set(aUrl, unicodeLabel);
|
||||
return unicodeLabel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets as much information as possible about the hostname and directory paths
|
||||
* of an url to create a short url group identifier.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The source url.
|
||||
* @return string
|
||||
* The simplified group.
|
||||
*/
|
||||
getSourceGroup: function (aUrl) {
|
||||
let cachedGroup = this._groupsCache.get(aUrl);
|
||||
if (cachedGroup) {
|
||||
return cachedGroup;
|
||||
}
|
||||
|
||||
try {
|
||||
// Use an nsIURL to parse all the url path parts.
|
||||
var uri = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
||||
} catch (e) {
|
||||
// This doesn't look like a url, or nsIURL can't handle it.
|
||||
return "";
|
||||
}
|
||||
|
||||
let groupLabel = uri.prePath;
|
||||
|
||||
for (let name of Object.keys(KNOWN_SOURCE_GROUPS)) {
|
||||
if (aUrl.startsWith(KNOWN_SOURCE_GROUPS[name])) {
|
||||
groupLabel = name;
|
||||
}
|
||||
}
|
||||
|
||||
let unicodeLabel = NetworkHelper.convertToUnicode(unescape(groupLabel));
|
||||
this._groupsCache.set(aUrl, unicodeLabel);
|
||||
return unicodeLabel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Trims the url by shortening it if it exceeds a certain length, adding an
|
||||
* ellipsis at the end.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The source url.
|
||||
* @param number aLength [optional]
|
||||
* The expected source url length.
|
||||
* @param number aSection [optional]
|
||||
* The section to trim. Supported values: "start", "center", "end"
|
||||
* @return string
|
||||
* The shortened url.
|
||||
*/
|
||||
trimUrlLength: function (aUrl, aLength, aSection) {
|
||||
aLength = aLength || SOURCE_URL_DEFAULT_MAX_LENGTH;
|
||||
aSection = aSection || "end";
|
||||
|
||||
if (aUrl.length > aLength) {
|
||||
switch (aSection) {
|
||||
case "start":
|
||||
return ELLIPSIS + aUrl.slice(-aLength);
|
||||
break;
|
||||
case "center":
|
||||
return aUrl.substr(0, aLength / 2 - 1) + ELLIPSIS + aUrl.slice(-aLength / 2 + 1);
|
||||
break;
|
||||
case "end":
|
||||
return aUrl.substr(0, aLength) + ELLIPSIS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return aUrl;
|
||||
},
|
||||
|
||||
/**
|
||||
* Trims the query part or reference identifier of a url string, if necessary.
|
||||
*
|
||||
* @param string aUrl
|
||||
* The source url.
|
||||
* @return string
|
||||
* The shortened url.
|
||||
*/
|
||||
trimUrlQuery: function (aUrl) {
|
||||
let length = aUrl.length;
|
||||
let q1 = aUrl.indexOf("?");
|
||||
let q2 = aUrl.indexOf("&");
|
||||
let q3 = aUrl.indexOf("#");
|
||||
let q = Math.min(q1 != -1 ? q1 : length,
|
||||
q2 != -1 ? q2 : length,
|
||||
q3 != -1 ? q3 : length);
|
||||
|
||||
return aUrl.slice(0, q);
|
||||
},
|
||||
|
||||
/**
|
||||
* Trims as much as possible from a url, while keeping the label unique
|
||||
* in the sources container.
|
||||
*
|
||||
* @param string | nsIURL aUrl
|
||||
* The source url.
|
||||
* @param string aLabel [optional]
|
||||
* The resulting label at each step.
|
||||
* @param number aSeq [optional]
|
||||
* The current iteration step.
|
||||
* @return string
|
||||
* The resulting label at the final step.
|
||||
*/
|
||||
trimUrl: function (aUrl, aLabel, aSeq) {
|
||||
if (!(aUrl instanceof Ci.nsIURL)) {
|
||||
try {
|
||||
// Use an nsIURL to parse all the url path parts.
|
||||
aUrl = Services.io.newURI(aUrl, null, null).QueryInterface(Ci.nsIURL);
|
||||
} catch (e) {
|
||||
// This doesn't look like a url, or nsIURL can't handle it.
|
||||
return aUrl;
|
||||
}
|
||||
}
|
||||
if (!aSeq) {
|
||||
let name = aUrl.fileName;
|
||||
if (name) {
|
||||
// This is a regular file url, get only the file name (contains the
|
||||
// base name and extension if available).
|
||||
|
||||
// If this url contains an invalid query, unfortunately nsIURL thinks
|
||||
// it's part of the file extension. It must be removed.
|
||||
aLabel = aUrl.fileName.replace(/\&.*/, "");
|
||||
} else {
|
||||
// This is not a file url, hence there is no base name, nor extension.
|
||||
// Proceed using other available information.
|
||||
aLabel = "";
|
||||
}
|
||||
aSeq = 1;
|
||||
}
|
||||
|
||||
// If we have a label and it doesn't only contain a query...
|
||||
if (aLabel && aLabel.indexOf("?") != 0) {
|
||||
// A page may contain multiple requests to the same url but with different
|
||||
// queries. It is *not* redundant to show each one.
|
||||
if (!DebuggerView.Sources.getItemForAttachment(e => e.label == aLabel)) {
|
||||
return aLabel;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the url query.
|
||||
if (aSeq == 1) {
|
||||
let query = aUrl.query;
|
||||
if (query) {
|
||||
return this.trimUrl(aUrl, aLabel + "?" + query, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
// Append the url reference.
|
||||
if (aSeq == 2) {
|
||||
let ref = aUrl.ref;
|
||||
if (ref) {
|
||||
return this.trimUrl(aUrl, aLabel + "#" + aUrl.ref, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
// Prepend the url directory.
|
||||
if (aSeq == 3) {
|
||||
let dir = aUrl.directory;
|
||||
if (dir) {
|
||||
return this.trimUrl(aUrl, dir.replace(/^\//, "") + aLabel, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
// Prepend the hostname and port number.
|
||||
if (aSeq == 4) {
|
||||
let host;
|
||||
try {
|
||||
// Bug 1261860: jar: URLs throw when accessing `hostPost`
|
||||
host = aUrl.hostPort;
|
||||
} catch (e) {}
|
||||
if (host) {
|
||||
return this.trimUrl(aUrl, host + "/" + aLabel, aSeq + 1);
|
||||
}
|
||||
aSeq++;
|
||||
}
|
||||
// Use the whole url spec but ignoring the reference.
|
||||
if (aSeq == 5) {
|
||||
return this.trimUrl(aUrl, aUrl.specIgnoringRef, aSeq + 1);
|
||||
}
|
||||
// Give up.
|
||||
return aUrl.spec;
|
||||
},
|
||||
|
||||
parseSource: function (aDebuggerView, aParser) {
|
||||
let editor = aDebuggerView.editor;
|
||||
|
||||
let contents = editor.getText();
|
||||
let location = aDebuggerView.Sources.selectedValue;
|
||||
let parsedSource = aParser.get(contents, location);
|
||||
|
||||
return parsedSource;
|
||||
},
|
||||
|
||||
findIdentifier: function (aEditor, parsedSource, x, y) {
|
||||
let editor = aEditor;
|
||||
|
||||
// Calculate the editor's line and column at the current x and y coords.
|
||||
let hoveredPos = editor.getPositionFromCoords({ left: x, top: y });
|
||||
let hoveredOffset = editor.getOffset(hoveredPos);
|
||||
let hoveredLine = hoveredPos.line;
|
||||
let hoveredColumn = hoveredPos.ch;
|
||||
|
||||
let scriptInfo = parsedSource.getScriptInfo(hoveredOffset);
|
||||
|
||||
// If the script length is negative, we're not hovering JS source code.
|
||||
if (scriptInfo.length == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Using the script offset, determine the actual line and column inside the
|
||||
// script, to use when finding identifiers.
|
||||
let scriptStart = editor.getPosition(scriptInfo.start);
|
||||
let scriptLineOffset = scriptStart.line;
|
||||
let scriptColumnOffset = (hoveredLine == scriptStart.line ? scriptStart.ch : 0);
|
||||
|
||||
let scriptLine = hoveredLine - scriptLineOffset;
|
||||
let scriptColumn = hoveredColumn - scriptColumnOffset;
|
||||
let identifierInfo = parsedSource.getIdentifierAt({
|
||||
line: scriptLine + 1,
|
||||
column: scriptColumn,
|
||||
scriptIndex: scriptInfo.index
|
||||
});
|
||||
|
||||
return identifierInfo;
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue