refactor(core): move misc methods that only have one version from DomAdapter (#32408)
PR Close #32408
This commit is contained in:
parent
c207ad80fd
commit
1a7c79746d
|
@ -50,22 +50,14 @@ export abstract class DomAdapter {
|
|||
abstract createHtmlDocument(): HTMLDocument;
|
||||
abstract getDefaultDocument(): Document;
|
||||
|
||||
// Used by Title
|
||||
abstract getTitle(doc: Document): string;
|
||||
abstract setTitle(doc: Document, newTitle: string): any;
|
||||
|
||||
// Used by By.css
|
||||
abstract elementMatches(n: any, selector: string): boolean;
|
||||
abstract isElementNode(node: any): boolean;
|
||||
|
||||
// Used by Testability
|
||||
abstract parentElement(el: any): Node|null;
|
||||
abstract isShadowRoot(node: any): boolean;
|
||||
abstract getHost(el: any): any;
|
||||
|
||||
// Used by KeyEventsPlugin
|
||||
abstract onAndCancel(el: any, evt: any, listener: any): Function;
|
||||
abstract getEventKey(event: any): string;
|
||||
abstract supportsDOMEvents(): boolean;
|
||||
|
||||
// Used by PlatformLocation and ServerEventManagerPlugin
|
||||
|
|
|
@ -3743,7 +3743,7 @@ const DEFAULT_COMPONENT_ID = '1';
|
|||
})();
|
||||
|
||||
function assertHasParent(element: any, yes: boolean) {
|
||||
const parent = getDOM().parentElement(element);
|
||||
const parent = element.parentNode;
|
||||
if (yes) {
|
||||
expect(parent).toBeTruthy();
|
||||
} else {
|
||||
|
|
|
@ -878,7 +878,7 @@ class TestCmptWithPropBindings {
|
|||
fixture = TestBed.createComponent(SimpleContentComp);
|
||||
fixture.detectChanges();
|
||||
|
||||
const parent = getDOM().parentElement(fixture.nativeElement) !;
|
||||
const parent = fixture.nativeElement.parentElement;
|
||||
const content = fixture.componentInstance.content.nativeElement;
|
||||
|
||||
// Move the content element outside the component
|
||||
|
|
|
@ -11,50 +11,6 @@ import {ɵglobal as global} from '@angular/core';
|
|||
|
||||
import {GenericBrowserDomAdapter} from './generic_browser_adapter';
|
||||
|
||||
|
||||
const DOM_KEY_LOCATION_NUMPAD = 3;
|
||||
|
||||
// Map to convert some key or keyIdentifier values to what will be returned by getEventKey
|
||||
const _keyMap: {[k: string]: string} = {
|
||||
// The following values are here for cross-browser compatibility and to match the W3C standard
|
||||
// cf http://www.w3.org/TR/DOM-Level-3-Events-key/
|
||||
'\b': 'Backspace',
|
||||
'\t': 'Tab',
|
||||
'\x7F': 'Delete',
|
||||
'\x1B': 'Escape',
|
||||
'Del': 'Delete',
|
||||
'Esc': 'Escape',
|
||||
'Left': 'ArrowLeft',
|
||||
'Right': 'ArrowRight',
|
||||
'Up': 'ArrowUp',
|
||||
'Down': 'ArrowDown',
|
||||
'Menu': 'ContextMenu',
|
||||
'Scroll': 'ScrollLock',
|
||||
'Win': 'OS'
|
||||
};
|
||||
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
const _chromeNumKeyPadMap = {
|
||||
'A': '1',
|
||||
'B': '2',
|
||||
'C': '3',
|
||||
'D': '4',
|
||||
'E': '5',
|
||||
'F': '6',
|
||||
'G': '7',
|
||||
'H': '8',
|
||||
'I': '9',
|
||||
'J': '*',
|
||||
'K': '+',
|
||||
'M': '-',
|
||||
'N': '.',
|
||||
'O': '/',
|
||||
'\x60': '0',
|
||||
'\x90': 'NumLock'
|
||||
};
|
||||
|
||||
const nodeContains: (this: Node, other: Node) => boolean = (() => {
|
||||
if (global['Node']) {
|
||||
return global['Node'].prototype.contains || function(this: Node, node: any) {
|
||||
|
@ -102,7 +58,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
return () => { el.removeEventListener(evt, listener, false); };
|
||||
}
|
||||
dispatchEvent(el: Node, evt: any) { el.dispatchEvent(evt); }
|
||||
parentElement(el: Node): Node|null { return el.parentNode; }
|
||||
appendChild(el: Node, node: Node) { el.appendChild(node); }
|
||||
remove(node: Node): Node {
|
||||
if (node.parentNode) {
|
||||
|
@ -115,7 +70,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
doc = doc || this.getDefaultDocument();
|
||||
return doc.createElement(tagName);
|
||||
}
|
||||
getHost(el: HTMLElement): HTMLElement { return (<any>el).host; }
|
||||
getElementsByTagName(element: any, name: string): HTMLElement[] {
|
||||
return element.getElementsByTagName(name);
|
||||
}
|
||||
|
@ -129,45 +83,11 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
|||
return document.implementation.createHTMLDocument('fakeTitle');
|
||||
}
|
||||
getDefaultDocument(): Document { return document; }
|
||||
getTitle(doc: Document): string { return doc.title; }
|
||||
setTitle(doc: Document, newTitle: string) { doc.title = newTitle || ''; }
|
||||
elementMatches(n: any, selector: string): boolean {
|
||||
if (this.isElementNode(n)) {
|
||||
return n.matches && n.matches(selector) ||
|
||||
n.msMatchesSelector && n.msMatchesSelector(selector) ||
|
||||
n.webkitMatchesSelector && n.webkitMatchesSelector(selector);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
isElementNode(node: Node): boolean { return node.nodeType === Node.ELEMENT_NODE; }
|
||||
|
||||
isShadowRoot(node: any): boolean { return node instanceof DocumentFragment; }
|
||||
|
||||
getEventKey(event: any): string {
|
||||
let key = event.key;
|
||||
if (key == null) {
|
||||
key = event.keyIdentifier;
|
||||
// keyIdentifier is defined in the old draft of DOM Level 3 Events implemented by Chrome and
|
||||
// Safari cf
|
||||
// http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/events.html#Events-KeyboardEvents-Interfaces
|
||||
if (key == null) {
|
||||
return 'Unidentified';
|
||||
}
|
||||
if (key.startsWith('U+')) {
|
||||
key = String.fromCharCode(parseInt(key.substring(2), 16));
|
||||
if (event.location === DOM_KEY_LOCATION_NUMPAD && _chromeNumKeyPadMap.hasOwnProperty(key)) {
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
key = (_chromeNumKeyPadMap as any)[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _keyMap[key] || key;
|
||||
}
|
||||
getGlobalEventTarget(doc: Document, target: string): EventTarget|null {
|
||||
if (target === 'window') {
|
||||
return window;
|
||||
|
|
|
@ -22,7 +22,7 @@ export function appInitializerFactory(transitionId: string, document: any, injec
|
|||
injector.get(ApplicationInitStatus).donePromise.then(() => {
|
||||
const dom = getDOM();
|
||||
const styles: any[] =
|
||||
Array.prototype.slice.apply(dom.querySelectorAll(document, `style[ng-transition]`));
|
||||
Array.prototype.slice.apply(document.querySelectorAll(`style[ng-transition]`));
|
||||
styles.filter(el => dom.getAttribute(el, 'ng-transition') === transitionId)
|
||||
.forEach(el => dom.remove(el));
|
||||
});
|
||||
|
|
|
@ -59,8 +59,8 @@ export class BrowserGetTestability implements GetTestability {
|
|||
return null;
|
||||
}
|
||||
if (getDOM().isShadowRoot(elem)) {
|
||||
return this.findTestabilityInTree(registry, getDOM().getHost(elem), true);
|
||||
return this.findTestabilityInTree(registry, (<any>elem).host, true);
|
||||
}
|
||||
return this.findTestabilityInTree(registry, getDOM().parentElement(elem), true);
|
||||
return this.findTestabilityInTree(registry, elem.parentElement, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,11 +33,11 @@ export class Title {
|
|||
/**
|
||||
* Get the title of the current HTML document.
|
||||
*/
|
||||
getTitle(): string { return getDOM().getTitle(this._doc); }
|
||||
getTitle(): string { return this._doc.title; }
|
||||
|
||||
/**
|
||||
* Set the title of the current HTML document.
|
||||
* @param newTitle
|
||||
*/
|
||||
setTitle(newTitle: string) { getDOM().setTitle(this._doc, newTitle); }
|
||||
setTitle(newTitle: string) { this._doc.title = newTitle || ''; }
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ export class By {
|
|||
static css(selector: string): Predicate<DebugElement> {
|
||||
return (debugElement) => {
|
||||
return debugElement.nativeElement != null ?
|
||||
getDOM().elementMatches(debugElement.nativeElement, selector) :
|
||||
elementMatches(debugElement.nativeElement, selector) :
|
||||
false;
|
||||
};
|
||||
}
|
||||
|
@ -55,3 +55,13 @@ export class By {
|
|||
return (debugNode) => debugNode.providerTokens !.indexOf(type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
function elementMatches(n: any, selector: string): boolean {
|
||||
if (getDOM().isElementNode(n)) {
|
||||
return n.matches && n.matches(selector) ||
|
||||
n.msMatchesSelector && n.msMatchesSelector(selector) ||
|
||||
n.webkitMatchesSelector && n.webkitMatchesSelector(selector);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,50 @@ import {EventManagerPlugin} from './event_manager';
|
|||
*/
|
||||
const MODIFIER_KEYS = ['alt', 'control', 'meta', 'shift'];
|
||||
|
||||
const DOM_KEY_LOCATION_NUMPAD = 3;
|
||||
|
||||
// Map to convert some key or keyIdentifier values to what will be returned by getEventKey
|
||||
const _keyMap: {[k: string]: string} = {
|
||||
// The following values are here for cross-browser compatibility and to match the W3C standard
|
||||
// cf http://www.w3.org/TR/DOM-Level-3-Events-key/
|
||||
'\b': 'Backspace',
|
||||
'\t': 'Tab',
|
||||
'\x7F': 'Delete',
|
||||
'\x1B': 'Escape',
|
||||
'Del': 'Delete',
|
||||
'Esc': 'Escape',
|
||||
'Left': 'ArrowLeft',
|
||||
'Right': 'ArrowRight',
|
||||
'Up': 'ArrowUp',
|
||||
'Down': 'ArrowDown',
|
||||
'Menu': 'ContextMenu',
|
||||
'Scroll': 'ScrollLock',
|
||||
'Win': 'OS'
|
||||
};
|
||||
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
const _chromeNumKeyPadMap = {
|
||||
'A': '1',
|
||||
'B': '2',
|
||||
'C': '3',
|
||||
'D': '4',
|
||||
'E': '5',
|
||||
'F': '6',
|
||||
'G': '7',
|
||||
'H': '8',
|
||||
'I': '9',
|
||||
'J': '*',
|
||||
'K': '+',
|
||||
'M': '-',
|
||||
'N': '.',
|
||||
'O': '/',
|
||||
'\x60': '0',
|
||||
'\x90': 'NumLock'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves modifiers from key-event objects.
|
||||
*/
|
||||
|
@ -96,7 +140,7 @@ export class KeyEventsPlugin extends EventManagerPlugin {
|
|||
|
||||
static getEventFullKey(event: KeyboardEvent): string {
|
||||
let fullKey = '';
|
||||
let key = getDOM().getEventKey(event);
|
||||
let key = getEventKey(event);
|
||||
key = key.toLowerCase();
|
||||
if (key === ' ') {
|
||||
key = 'space'; // for readability
|
||||
|
@ -141,3 +185,27 @@ export class KeyEventsPlugin extends EventManagerPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEventKey(event: any): string {
|
||||
let key = event.key;
|
||||
if (key == null) {
|
||||
key = event.keyIdentifier;
|
||||
// keyIdentifier is defined in the old draft of DOM Level 3 Events implemented by Chrome and
|
||||
// Safari cf
|
||||
// http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/events.html#Events-KeyboardEvents-Interfaces
|
||||
if (key == null) {
|
||||
return 'Unidentified';
|
||||
}
|
||||
if (key.startsWith('U+')) {
|
||||
key = String.fromCharCode(parseInt(key.substring(2), 16));
|
||||
if (event.location === DOM_KEY_LOCATION_NUMPAD && _chromeNumKeyPadMap.hasOwnProperty(key)) {
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
key = (_chromeNumKeyPadMap as any)[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _keyMap[key] || key;
|
||||
}
|
||||
|
|
|
@ -20,24 +20,24 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
|
|||
|
||||
beforeEach(() => {
|
||||
doc = getDOM().createHtmlDocument();
|
||||
initialTitle = getDOM().getTitle(doc);
|
||||
initialTitle = doc.title;
|
||||
titleService = new Title(doc);
|
||||
});
|
||||
|
||||
afterEach(() => { getDOM().setTitle(doc, initialTitle); });
|
||||
afterEach(() => { doc.title = initialTitle; });
|
||||
|
||||
it('should allow reading initial title',
|
||||
() => { expect(titleService.getTitle()).toEqual(initialTitle); });
|
||||
|
||||
it('should set a title on the injected document', () => {
|
||||
titleService.setTitle('test title');
|
||||
expect(getDOM().getTitle(doc)).toEqual('test title');
|
||||
expect(doc.title).toEqual('test title');
|
||||
expect(titleService.getTitle()).toEqual('test title');
|
||||
});
|
||||
|
||||
it('should reset title to empty string if title not provided', () => {
|
||||
titleService.setTitle(null !);
|
||||
expect(getDOM().getTitle(doc)).toEqual('');
|
||||
expect(doc.title).toEqual('');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ class DefaultServerRenderer2 implements Renderer2 {
|
|||
return el;
|
||||
}
|
||||
|
||||
parentNode(node: any): any { return getDOM().parentElement(node); }
|
||||
parentNode(node: any): any { return node.parentNode; }
|
||||
|
||||
nextSibling(node: any): any { return node.nextSibling; }
|
||||
|
||||
|
|
|
@ -47,22 +47,16 @@ export class WorkerDomAdapter extends DomAdapter {
|
|||
querySelectorAll(el: any, selector: string): any[] { throw 'not implemented'; }
|
||||
onAndCancel(el: any, evt: any, listener: any): Function { throw 'not implemented'; }
|
||||
dispatchEvent(el: any, evt: any) { throw 'not implemented'; }
|
||||
parentElement(el: any): Node { throw 'not implemented'; }
|
||||
appendChild(el: any, node: any) { throw 'not implemented'; }
|
||||
remove(el: any): Node { throw 'not implemented'; }
|
||||
createElement(tagName: any, doc?: any): HTMLElement { throw 'not implemented'; }
|
||||
getHost(el: any): any { throw 'not implemented'; }
|
||||
getElementsByTagName(element: any, name: string): HTMLElement[] { throw 'not implemented'; }
|
||||
getAttribute(element: any, attribute: string): string { throw 'not implemented'; }
|
||||
setAttribute(element: any, name: string, value: string) { throw 'not implemented'; }
|
||||
createHtmlDocument(): HTMLDocument { throw 'not implemented'; }
|
||||
getDefaultDocument(): Document { throw 'not implemented'; }
|
||||
getTitle(doc: Document): string { throw 'not implemented'; }
|
||||
setTitle(doc: Document, newTitle: string) { throw 'not implemented'; }
|
||||
elementMatches(n: any, selector: string): boolean { throw 'not implemented'; }
|
||||
isElementNode(node: any): boolean { throw 'not implemented'; }
|
||||
isShadowRoot(node: any): boolean { throw 'not implemented'; }
|
||||
getEventKey(event: any): string { throw 'not implemented'; }
|
||||
supportsDOMEvents(): boolean { throw 'not implemented'; }
|
||||
getGlobalEventTarget(doc: Document, target: string): any { throw 'not implemented'; }
|
||||
getHistory(): History { throw 'not implemented'; }
|
||||
|
|
Loading…
Reference in New Issue