Index: third_party/WebKit/Source/devtools/front_end/components/Linkifier.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js |
index a619cb3a3301f4017ec4e940c8600be582924cc6..9a2de9ec0458fb3b55c85074a1487b5c15d71824 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js |
+++ b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js |
@@ -95,46 +95,11 @@ Components.Linkifier = class { |
} |
/** |
- * @param {!Object} revealable |
- * @param {string} text |
- * @param {string=} fallbackHref |
- * @param {number=} fallbackLineNumber |
- * @param {string=} title |
- * @param {string=} classes |
- * @return {!Element} |
- */ |
- static linkifyUsingRevealer(revealable, text, fallbackHref, fallbackLineNumber, title, classes) { |
- var a = createElement('a'); |
- a.className = (classes || '') + ' webkit-html-resource-link'; |
- a.textContent = text.trimMiddle(Components.Linkifier.MaxLengthForDisplayedURLs); |
- a.title = title || text; |
- if (fallbackHref) { |
- a.href = fallbackHref; |
- a.lineNumber = fallbackLineNumber; |
- } |
- |
- /** |
- * @param {!Event} event |
- * @this {Object} |
- */ |
- function clickHandler(event) { |
- event.stopImmediatePropagation(); |
- event.preventDefault(); |
- if (fallbackHref && Components.Linkifier.handleLink(fallbackHref, fallbackLineNumber)) |
- return; |
- |
- Common.Revealer.reveal(this); |
- } |
- a.addEventListener('click', clickHandler.bind(revealable), false); |
- return a; |
- } |
- |
- /** |
* @param {!Element} anchor |
* @param {!Workspace.UILocation} uiLocation |
*/ |
static _bindUILocation(anchor, uiLocation) { |
- anchor[Components.Linkifier._uiLocationSymbol] = uiLocation; |
+ Components.Linkifier._linkInfo(anchor).uiLocation = uiLocation; |
if (!uiLocation) |
return; |
var uiSourceCode = uiLocation.uiSourceCode; |
@@ -150,11 +115,12 @@ Components.Linkifier = class { |
* @param {!Element} anchor |
*/ |
static _unbindUILocation(anchor) { |
- if (!anchor[Components.Linkifier._uiLocationSymbol]) |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ if (!info.uiLocation) |
return; |
- var uiSourceCode = anchor[Components.Linkifier._uiLocationSymbol].uiSourceCode; |
- anchor[Components.Linkifier._uiLocationSymbol] = null; |
+ var uiSourceCode = info.uiLocation.uiSourceCode; |
+ info.uiLocation = null; |
var sourceCodeAnchors = uiSourceCode[Components.Linkifier._sourceCodeAnchors]; |
if (sourceCodeAnchors) |
sourceCodeAnchors.delete(anchor); |
@@ -199,16 +165,15 @@ Components.Linkifier = class { |
locationPool.disposeAll(); |
var anchors = this._anchorsByTarget.remove(target); |
for (var anchor of anchors) { |
- delete anchor[Components.Linkifier._liveLocationSymbol]; |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ info.liveLocation = null; |
Components.Linkifier._unbindUILocation(anchor); |
- var fallbackAnchor = anchor[Components.Linkifier._fallbackAnchorSymbol]; |
- if (fallbackAnchor) { |
- anchor.href = fallbackAnchor.href; |
- anchor.lineNumber = fallbackAnchor.lineNumber; |
- anchor.title = fallbackAnchor.title; |
- anchor.className = fallbackAnchor.className; |
- anchor.textContent = fallbackAnchor.textContent; |
- delete anchor[Components.Linkifier._fallbackAnchorSymbol]; |
+ if (info.fallback) { |
+ anchor.href = info.fallback.href; |
+ anchor.title = info.fallback.title; |
+ anchor.className = info.fallback.className; |
+ anchor.textContent = info.fallback.textContent; |
+ anchor[Components.Linkifier._infoSymbol] = info.fallback[Components.Linkifier._infoSymbol]; |
} |
} |
} |
@@ -237,14 +202,16 @@ Components.Linkifier = class { |
if (!rawLocation) |
return fallbackAnchor; |
- var anchor = this._createAnchor(classes); |
- var liveLocation = Bindings.debuggerWorkspaceBinding.createLiveLocation( |
+ var anchor = Components.Linkifier._createLink('', classes || ''); |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ info.enableDecorator = this._useLinkDecorator; |
+ info.fallback = fallbackAnchor; |
+ info.liveLocation = Bindings.debuggerWorkspaceBinding.createLiveLocation( |
rawLocation, this._updateAnchor.bind(this, anchor), |
/** @type {!Bindings.LiveLocationPool} */ (this._locationPoolByTarget.get(rawLocation.target()))); |
+ |
var anchors = /** @type {!Array<!Element>} */ (this._anchorsByTarget.get(rawLocation.target())); |
anchors.push(anchor); |
- anchor[Components.Linkifier._liveLocationSymbol] = liveLocation; |
- anchor[Components.Linkifier._fallbackAnchorSymbol] = fallbackAnchor; |
return anchor; |
} |
@@ -305,14 +272,16 @@ Components.Linkifier = class { |
if (rawLocations.length === 0) |
return fallbackAnchor; |
- var anchor = this._createAnchor(classes); |
- var liveLocation = Bindings.debuggerWorkspaceBinding.createStackTraceTopFrameLiveLocation( |
+ var anchor = Components.Linkifier._createLink('', classes || ''); |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ info.enableDecorator = this._useLinkDecorator; |
+ info.fallback = fallbackAnchor; |
+ info.liveLocation = Bindings.debuggerWorkspaceBinding.createStackTraceTopFrameLiveLocation( |
rawLocations, this._updateAnchor.bind(this, anchor), |
/** @type {!Bindings.LiveLocationPool} */ (this._locationPoolByTarget.get(target))); |
+ |
var anchors = /** @type {!Array<!Element>} */ (this._anchorsByTarget.get(target)); |
anchors.push(anchor); |
- anchor[Components.Linkifier._liveLocationSymbol] = liveLocation; |
- anchor[Components.Linkifier._fallbackAnchorSymbol] = fallbackAnchor; |
return anchor; |
} |
@@ -322,13 +291,15 @@ Components.Linkifier = class { |
* @return {!Element} |
*/ |
linkifyCSSLocation(rawLocation, classes) { |
- var anchor = this._createAnchor(classes); |
- var liveLocation = Bindings.cssWorkspaceBinding.createLiveLocation( |
+ var anchor = Components.Linkifier._createLink('', classes || ''); |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ info.enableDecorator = this._useLinkDecorator; |
+ info.liveLocation = Bindings.cssWorkspaceBinding.createLiveLocation( |
rawLocation, this._updateAnchor.bind(this, anchor), |
/** @type {!Bindings.LiveLocationPool} */ (this._locationPoolByTarget.get(rawLocation.target()))); |
+ |
var anchors = /** @type {!Array<!Element>} */ (this._anchorsByTarget.get(rawLocation.target())); |
anchors.push(anchor); |
- anchor[Components.Linkifier._liveLocationSymbol] = liveLocation; |
return anchor; |
} |
@@ -338,38 +309,12 @@ Components.Linkifier = class { |
*/ |
disposeAnchor(target, anchor) { |
Components.Linkifier._unbindUILocation(anchor); |
- delete anchor[Components.Linkifier._fallbackAnchorSymbol]; |
- var liveLocation = anchor[Components.Linkifier._liveLocationSymbol]; |
- if (liveLocation) |
- liveLocation.dispose(); |
- delete anchor[Components.Linkifier._liveLocationSymbol]; |
- } |
- |
- /** |
- * @param {string=} classes |
- * @return {!Element} |
- */ |
- _createAnchor(classes) { |
- var anchor = createElement('a'); |
- if (this._useLinkDecorator) |
- anchor[Components.Linkifier._enableDecoratorSymbol] = true; |
- anchor.className = (classes || '') + ' webkit-html-resource-link'; |
- |
- /** |
- * @param {!Event} event |
- */ |
- function clickHandler(event) { |
- var uiLocation = anchor[Components.Linkifier._uiLocationSymbol]; |
- if (!uiLocation) |
- return; |
- |
- event.consume(true); |
- if (Components.Linkifier.handleLink(uiLocation.uiSourceCode.url(), uiLocation.lineNumber)) |
- return; |
- Common.Revealer.reveal(uiLocation); |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ info.fallback = null; |
+ if (info.liveLocation) { |
+ info.liveLocation.dispose(); |
+ info.liveLocation = null; |
} |
- anchor.addEventListener('click', clickHandler, false); |
- return anchor; |
} |
reset() { |
@@ -415,20 +360,19 @@ Components.Linkifier = class { |
* @param {!Element} anchor |
*/ |
static _updateLinkDecorations(anchor) { |
- if (!anchor[Components.Linkifier._enableDecoratorSymbol]) |
+ var info = Components.Linkifier._linkInfo(anchor); |
+ if (!info || !info.enableDecorator) |
return; |
- var uiLocation = anchor[Components.Linkifier._uiLocationSymbol]; |
- if (!Components.Linkifier._decorator || !uiLocation) |
+ if (!Components.Linkifier._decorator || !info.uiLocation) |
return; |
- var icon = anchor[Components.Linkifier._iconSymbol]; |
- if (icon) |
- icon.remove(); |
- icon = Components.Linkifier._decorator.linkIcon(uiLocation.uiSourceCode); |
+ if (info.icon) |
+ anchor.removeChild(info.icon); |
+ var icon = Components.Linkifier._decorator.linkIcon(info.uiLocation.uiSourceCode); |
if (icon) { |
icon.style.setProperty('margin-right', '2px'); |
anchor.insertBefore(icon, anchor.firstChild); |
} |
- anchor[Components.Linkifier._iconSymbol] = icon; |
+ info.icon = icon; |
} |
/** |
@@ -440,31 +384,77 @@ Components.Linkifier = class { |
* @return {!Element} |
*/ |
static linkifyURL(url, text, className, lineNumber, columnNumber) { |
- if (!url) { |
+ if (!url || url.trim().toLowerCase().startsWith('javascript:')) { |
var element = createElementWithClass('span', className); |
- element.textContent = text || Common.UIString('(unknown)'); |
+ element.textContent = text || url || Common.UIString('(unknown)'); |
return element; |
} |
var linkText = text || Bindings.displayNameForURL(url); |
if (typeof lineNumber === 'number' && !text) |
linkText += ':' + (lineNumber + 1); |
+ var title = linkText !== url ? url : ''; |
+ var link = Components.Linkifier._createLink(linkText.trimMiddle(150), className || '', title, url); |
+ var info = Components.Linkifier._linkInfo(link); |
+ if (typeof lineNumber === 'number') |
+ info.lineNumber = lineNumber; |
+ if (typeof columnNumber === 'number') |
+ info.columnNumber = columnNumber; |
+ return link; |
+ } |
+ /** |
+ * @param {!Object} revealable |
+ * @param {string} text |
+ * @param {string=} fallbackHref |
+ * @return {!Element} |
+ */ |
+ static linkifyRevealable(revealable, text, fallbackHref) { |
+ var link = Components.Linkifier._createLink( |
+ text.trimMiddle(Components.Linkifier.MaxLengthForDisplayedURLs), '', undefined, fallbackHref); |
+ Components.Linkifier._linkInfo(link).revealable = revealable; |
+ return link; |
+ } |
+ |
+ /** |
+ * @param {string} text |
+ * @param {string} className |
+ * @param {string=} title |
+ * @param {string=} href |
+ * @returns{!Element} |
+ */ |
+ static _createLink(text, className, title, href) { |
var link = createElementWithClass('a', className); |
- if (!url.trim().toLowerCase().startsWith('javascript:')) { |
- link.href = url; |
- link.classList.add('webkit-html-resource-link'); |
- link[Components.Linkifier._linkSymbol] = true; |
- link.addEventListener('click', Components.Linkifier._handleClick, false); |
- } |
- link.title = linkText !== url ? url : ''; |
- link.textContent = linkText.trimMiddle(150); |
- link.lineNumber = lineNumber; |
- link.columnNumber = columnNumber; |
+ link.classList.add('webkit-html-resource-link'); |
+ if (title) |
+ link.title = title; |
+ if (href) |
+ link.href = href; |
+ link.textContent = text; |
+ link[Components.Linkifier._infoSymbol] = { |
+ icon: null, |
+ enableDecorator: false, |
+ uiLocation: null, |
+ liveLocation: null, |
+ url: href || null, |
+ lineNumber: null, |
+ columnNumber: null, |
+ revealable: null, |
+ fallback: null |
+ }; |
+ link.addEventListener('click', Components.Linkifier._handleClick, false); |
return link; |
} |
/** |
+ * @param {?Element} link |
+ * @return {?Components._LinkInfo} |
+ */ |
+ static _linkInfo(link) { |
+ return /** @type {?Components._LinkInfo} */ (link ? link[Components.Linkifier._infoSymbol] || null : null); |
+ } |
+ |
+ /** |
* @param {!Event} event |
*/ |
static _handleClick(event) { |
@@ -472,8 +462,17 @@ Components.Linkifier = class { |
event.consume(true); |
if (link.preventFollow || UI.isBeingEdited(/** @type {!Node} */ (event.target))) |
return; |
- if (Components.openAnchorLocationRegistry.dispatch({url: link.href, lineNumber: link.lineNumber})) |
+ var info = Components.Linkifier._linkInfo(link); |
+ if (info.uiLocation && |
+ Components.openAnchorLocationRegistry.dispatch( |
+ {url: info.uiLocation.uiSourceCode.url(), lineNumber: info.uiLocation.lineNumber})) |
+ return; |
+ if (info.url && Components.openAnchorLocationRegistry.dispatch({url: info.url, lineNumber: info.lineNumber})) |
return; |
+ if (info.revealable) { |
+ Common.Revealer.reveal(info.revealable); |
+ return; |
+ } |
var actions = Components.Linkifier._linkActions(link); |
if (actions.length) |
actions[0].handler.call(null); |
@@ -484,27 +483,29 @@ Components.Linkifier = class { |
* @return {!Array<{title: string, handler: function()}>} |
*/ |
static _linkActions(link) { |
- var url = null; |
+ var info = Components.Linkifier._linkInfo(link); |
+ var result = []; |
+ if (!info) |
+ return result; |
+ |
+ var url = ''; |
var uiLocation = null; |
- var isLiveLink = false; |
- if (link && link[Components.Linkifier._uiLocationSymbol]) { |
- uiLocation = /** @type {!Workspace.UILocation} */ (link[Components.Linkifier._uiLocationSymbol]); |
+ if (info.uiLocation) { |
+ uiLocation = info.uiLocation; |
url = uiLocation.uiSourceCode.contentURL(); |
- isLiveLink = true; |
- } else if (link && link.href) { |
- url = link.href; |
+ } else if (info.url) { |
+ url = info.url; |
var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url); |
- uiLocation = uiSourceCode ? uiSourceCode.uiLocation(link.lineNumber || 0, link.columnNumber || 0) : null; |
- isLiveLink = false; |
- } else { |
- return []; |
+ uiLocation = uiSourceCode ? uiSourceCode.uiLocation(info.lineNumber || 0, info.columnNumber || 0) : null; |
} |
- var result = []; |
+ if (info.revealable) |
+ result.push({title: Common.UIString('Reveal'), handler: () => Common.Revealer.reveal(info.revealable)}); |
+ |
if (uiLocation) |
result.push({title: Common.UIString('Open'), handler: () => Common.Revealer.reveal(uiLocation)}); |
- var resource = Bindings.resourceForURL(url); |
+ var resource = url ? Bindings.resourceForURL(url) : null; |
if (resource) { |
result.push({ |
title: Common.UIString.capitalize('Open ^link in Application ^panel'), |
@@ -512,7 +513,7 @@ Components.Linkifier = class { |
}); |
} |
- var request = SDK.NetworkLog.requestForURL(url); |
+ var request = url ? SDK.NetworkLog.requestForURL(url) : null; |
if (request) { |
result.push({ |
title: Common.UIString.capitalize('Open ^request in Network ^panel'), |
@@ -520,7 +521,7 @@ Components.Linkifier = class { |
}); |
} |
- if (resource || !isLiveLink) { |
+ if (resource || info.url) { |
result.push({title: UI.openLinkExternallyLabel(), handler: () => InspectorFrontendHost.openInNewTab(url)}); |
result.push({title: UI.copyLinkAddressLabel(), handler: () => InspectorFrontendHost.copyText(url)}); |
} |
@@ -534,13 +535,23 @@ Components.Linkifier._instances = new Set(); |
/** @type {?Components.LinkDecorator} */ |
Components.Linkifier._decorator = null; |
-Components.Linkifier._iconSymbol = Symbol('Linkifier.iconSymbol'); |
-Components.Linkifier._enableDecoratorSymbol = Symbol('Linkifier.enableIconsSymbol'); |
Components.Linkifier._sourceCodeAnchors = Symbol('Linkifier.anchors'); |
-Components.Linkifier._uiLocationSymbol = Symbol('uiLocation'); |
-Components.Linkifier._fallbackAnchorSymbol = Symbol('fallbackAnchor'); |
-Components.Linkifier._liveLocationSymbol = Symbol('liveLocation'); |
-Components.Linkifier._linkSymbol = Symbol('Linkifier.link'); |
+Components.Linkifier._infoSymbol = Symbol('Linkifier.info'); |
+ |
+/** |
+ * @typedef {{ |
+ * icon: ?UI.Icon, |
+ * enableDecorator: boolean, |
+ * uiLocation: ?Workspace.UILocation, |
+ * liveLocation: ?Bindings.LiveLocation, |
+ * url: ?string, |
+ * lineNumber: ?number, |
+ * columnNumber: ?number, |
+ * revealable: ?Object, |
+ * fallback: ?Element |
+ * }} |
+ */ |
+Components._LinkInfo; |
/** |
* The maximum number of characters to display in a URL. |
@@ -660,8 +671,7 @@ Components.Linkifier.LinkContextMenuProvider = class { |
*/ |
appendApplicableItems(event, contextMenu, target) { |
var targetNode = /** @type {!Node} */ (target); |
- while (targetNode && !targetNode[Components.Linkifier._linkSymbol] && |
- !targetNode[Components.Linkifier._uiLocationSymbol]) |
+ while (targetNode && !targetNode[Components.Linkifier._infoSymbol]) |
targetNode = targetNode.parentNodeOrShadowHost(); |
var link = /** @type {?Element} */ (targetNode); |
var actions = Components.Linkifier._linkActions(link); |