Chromium Code Reviews| 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..5616cd588a3214c952bbb64b39f2df862759b054 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,17 @@ 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); |
| + if (this._useLinkDecorator) |
| + info.enableDecorator = true; |
|
lushnikov
2016/11/21 20:14:07
here and below: just info.enableDecorator = this._
dgozman
2016/11/21 22:37:47
Done.
|
| + 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 +273,17 @@ 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); |
| + if (this._useLinkDecorator) |
| + info.enableDecorator = true; |
| + 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 +293,16 @@ Components.Linkifier = class { |
| * @return {!Element} |
| */ |
| linkifyCSSLocation(rawLocation, classes) { |
| - var anchor = this._createAnchor(classes); |
| - var liveLocation = Bindings.cssWorkspaceBinding.createLiveLocation( |
| + var anchor = Components.Linkifier._createLink('', classes || ''); |
|
lushnikov
2016/11/21 20:14:07
so what is "anchor" and what is "link"? Do we diff
dgozman
2016/11/21 22:37:47
Same thing. I just think that linkifier should wor
|
| + var info = Components.Linkifier._linkInfo(anchor); |
| + if (this._useLinkDecorator) |
| + info.enableDecorator = true; |
| + 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 +312,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 +363,19 @@ Components.Linkifier = class { |
| * @param {!Element} anchor |
| */ |
| static _updateLinkDecorations(anchor) { |
| - if (!anchor[Components.Linkifier._enableDecoratorSymbol]) |
| + var info = Components.Linkifier._linkInfo(anchor); |
| + if (!info.enableDecorator) |
|
lushnikov
2016/11/21 20:14:07
if (!info || !info.enableDecorator)
dgozman
2016/11/21 22:37:47
Done.
|
| 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 +387,77 @@ Components.Linkifier = class { |
| * @return {!Element} |
| */ |
| static linkifyURL(url, text, className, lineNumber, columnNumber) { |
| - if (!url) { |
| + if (!url || url.trim().toLowerCase().startsWith('javascript:')) { |
|
lushnikov
2016/11/21 20:14:07
this drops link.lineNumber and link.columnNumber w
dgozman
2016/11/21 22:37:47
Don't need them anymore, since we don't use extern
|
| 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); |
|
lushnikov
2016/11/21 20:14:07
nit: we tend to not use '&&' in this way.
return
dgozman
2016/11/21 22:37:47
Done.
|
| + } |
| + |
| + /** |
| * @param {!Event} event |
| */ |
| static _handleClick(event) { |
| @@ -472,8 +465,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,18 +486,18 @@ Components.Linkifier = class { |
| * @return {!Array<{title: string, handler: function()}>} |
| */ |
| static _linkActions(link) { |
| - var url = null; |
| + var info = Components.Linkifier._linkInfo(link); |
| + if (info && info.revealable) |
|
lushnikov
2016/11/21 20:14:07
let's not bail-out
dgozman
2016/11/21 22:37:47
Done.
|
| + return []; |
| + var url = ''; |
| var uiLocation = null; |
| - var isLiveLink = false; |
| - if (link && link[Components.Linkifier._uiLocationSymbol]) { |
| - uiLocation = /** @type {!Workspace.UILocation} */ (link[Components.Linkifier._uiLocationSymbol]); |
| + if (info && info.uiLocation) { |
| + uiLocation = info.uiLocation; |
| url = uiLocation.uiSourceCode.contentURL(); |
| - isLiveLink = true; |
| - } else if (link && link.href) { |
| - url = link.href; |
| + } else if (info && info.url) { |
| + url = info.url; |
| var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url); |
| - uiLocation = uiSourceCode ? uiSourceCode.uiLocation(link.lineNumber || 0, link.columnNumber || 0) : null; |
| - isLiveLink = false; |
| + uiLocation = uiSourceCode ? uiSourceCode.uiLocation(info.lineNumber || 0, info.columnNumber || 0) : null; |
| } else { |
| return []; |
| } |
| @@ -520,7 +522,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 +536,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 +672,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); |