Files
react-native-devtools-frontend/front_end/panels/elements/DOMLinkifier.ts
T
Jack Franklin 84442c6766 [DarkMode] remove enableLegacyPatching option
The option was only allowed to be set to `false`, so it's not been
used at all, so now we can remove it, given that we've had the dark
mode legacy patching disabled without any major bugs in the past few
weeks.

Bug: chromium:1152736
Change-Id: I1e794d75f9c354a0d16b1b3975f7ebdf82b3448b
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2988303
Commit-Queue: Jack Franklin <jacktfranklin@chromium.org>
Reviewed-by: Paul Lewis <aerotwist@chromium.org>
2021-06-29 10:07:32 +00:00

157 lines
5.5 KiB
TypeScript

// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable rulesdir/no_underscored_properties */
import * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as SDK from '../../core/sdk/sdk.js';
import * as UI from '../../ui/legacy/legacy.js';
const UIStrings = {
/**
* @description Text displayed when trying to create a link to a node in the UI, but the node
* location could not be found so we display this placeholder instead. Node refers to a DOM node.
* This should be translated if appropriate.
*/
node: '<node>',
};
const str_ = i18n.i18n.registerUIStrings('panels/elements/DOMLinkifier.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export const decorateNodeLabel = function(
node: SDK.DOMModel.DOMNode, parentElement: HTMLElement, tooltipContent?: string): void {
const originalNode = node;
const isPseudo = node.nodeType() === Node.ELEMENT_NODE && node.pseudoType();
if (isPseudo && node.parentNode) {
node = node.parentNode;
}
let title = node.nodeNameInCorrectCase();
const nameElement = parentElement.createChild('span', 'node-label-name');
nameElement.textContent = title;
const idAttribute = node.getAttribute('id');
if (idAttribute) {
const idElement = parentElement.createChild('span', 'node-label-id');
const part = '#' + idAttribute;
title += part;
UI.UIUtils.createTextChild(idElement, part);
// Mark the name as extra, since the ID is more important.
nameElement.classList.add('extra');
}
const classAttribute = node.getAttribute('class');
if (classAttribute) {
const classes = classAttribute.split(/\s+/);
if (classes.length) {
const foundClasses = new Set<string>();
const classesElement = parentElement.createChild('span', 'extra node-label-class');
for (let i = 0; i < classes.length; ++i) {
const className = classes[i];
if (className && !foundClasses.has(className)) {
const part = '.' + className;
title += part;
UI.UIUtils.createTextChild(classesElement, part);
foundClasses.add(className);
}
}
}
}
if (isPseudo) {
const pseudoElement = parentElement.createChild('span', 'extra node-label-pseudo');
const pseudoText = '::' + originalNode.pseudoType();
UI.UIUtils.createTextChild(pseudoElement, pseudoText);
title += pseudoText;
}
UI.Tooltip.Tooltip.install(parentElement, tooltipContent || title);
};
export const linkifyNodeReference = function(
node: SDK.DOMModel.DOMNode|null, options: Common.Linkifier.Options|undefined = {
tooltip: undefined,
preventKeyboardFocus: undefined,
}): Node {
if (!node) {
return document.createTextNode(i18nString(UIStrings.node));
}
const root = document.createElement('span');
root.classList.add('monospace');
const shadowRoot = UI.Utils.createShadowRootWithCoreStyles(
root, {cssFile: 'panels/elements/domLinkifier.css', delegatesFocus: undefined});
const link = (shadowRoot.createChild('div', 'node-link') as HTMLDivElement);
decorateNodeLabel(node, link, options.tooltip);
link.addEventListener('click', () => {
Common.Revealer.reveal(node, false);
return false;
}, false);
link.addEventListener('mouseover', node.highlight.bind(node, undefined), false);
link.addEventListener('mouseleave', () => SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight(), false);
if (!options.preventKeyboardFocus) {
link.addEventListener('keydown', event => event.key === 'Enter' && Common.Revealer.reveal(node, false) && false);
link.tabIndex = 0;
UI.ARIAUtils.markAsLink(link);
}
return root;
};
export const linkifyDeferredNodeReference = function(
deferredNode: SDK.DOMModel.DeferredDOMNode, options: Common.Linkifier.Options|undefined = {
tooltip: undefined,
preventKeyboardFocus: undefined,
}): Node {
const root = document.createElement('div');
const shadowRoot = UI.Utils.createShadowRootWithCoreStyles(
root, {cssFile: 'panels/elements/domLinkifier.css', delegatesFocus: undefined});
const link = (shadowRoot.createChild('div', 'node-link') as HTMLDivElement);
link.createChild('slot');
link.addEventListener('click', deferredNode.resolve.bind(deferredNode, onDeferredNodeResolved), false);
link.addEventListener('mousedown', e => e.consume(), false);
if (!options.preventKeyboardFocus) {
link.addEventListener('keydown', event => event.key === 'Enter' && deferredNode.resolve(onDeferredNodeResolved));
link.tabIndex = 0;
UI.ARIAUtils.markAsLink(link);
}
function onDeferredNodeResolved(node: SDK.DOMModel.DOMNode|null): void {
Common.Revealer.reveal(node);
}
return root;
};
// @empty-line
let linkifierInstance: Linkifier;
export class Linkifier implements Common.Linkifier.Linkifier {
static instance(opts: {
forceNew: boolean|null,
} = {forceNew: null}): Linkifier {
const {forceNew} = opts;
if (!linkifierInstance || forceNew) {
linkifierInstance = new Linkifier();
}
return linkifierInstance;
}
linkify(object: Object, options?: Common.Linkifier.Options): Node {
if (object instanceof SDK.DOMModel.DOMNode) {
return linkifyNodeReference(object, options);
}
if (object instanceof SDK.DOMModel.DeferredDOMNode) {
return linkifyDeferredNodeReference(object, options);
}
throw new Error('Can\'t linkify non-node');
}
}