diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index e7d3734b76a012..55599085e4c9e9 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -39,8 +39,8 @@ "master": { "uncompressed": { "bundle": "TODO(i): temporarily increase the payload size limit from 105779 - this is due to a closure issue related to ESM reexports that still needs to be investigated", - "bundle": 179825 + "bundle": 177447 } } } -} \ No newline at end of file +} diff --git a/packages/common/src/dom_adapter.ts b/packages/common/src/dom_adapter.ts index ba24fbaf10657f..2f6bb80277ae38 100644 --- a/packages/common/src/dom_adapter.ts +++ b/packages/common/src/dom_adapter.ts @@ -43,33 +43,17 @@ export abstract class DomAdapter { abstract querySelectorAll(el: any, selector: string): any[]; abstract remove(el: any): Node; abstract getAttribute(element: any, attribute: string): string|null; - - // Used by platform-server - abstract setProperty(el: Element, name: string, value: any): any; - abstract querySelector(el: any, selector: string): any; - abstract nextSibling(el: any): Node|null; - abstract parentElement(el: any): Node|null; - abstract clearNodes(el: any): any; abstract appendChild(el: any, node: any): any; - abstract removeChild(el: any, node: any): any; - abstract insertBefore(parent: any, ref: any, node: any): any; - abstract setText(el: any, value: string): any; - abstract createComment(text: string): any; abstract createElement(tagName: any, doc?: any): HTMLElement; - abstract createElementNS(ns: string, tagName: string, doc?: any): Element; - abstract createTextNode(text: string, doc?: any): Text; + abstract setAttribute(element: any, name: string, value: string): any; abstract getElementsByTagName(element: any, name: string): HTMLElement[]; - abstract addClass(element: any, className: string): any; - abstract removeClass(element: any, className: string): any; + abstract createHtmlDocument(): HTMLDocument; + abstract getDefaultDocument(): Document; + + // Used by platform-server abstract getStyle(element: any, styleName: string): any; abstract setStyle(element: any, styleName: string, styleValue: string): any; abstract removeStyle(element: any, styleName: string): any; - abstract setAttribute(element: any, name: string, value: string): any; - abstract setAttributeNS(element: any, ns: string, name: string, value: string): any; - abstract removeAttribute(element: any, attribute: string): any; - abstract removeAttributeNS(element: any, ns: string, attribute: string): any; - abstract createHtmlDocument(): HTMLDocument; - abstract getDefaultDocument(): Document; // Used by Title abstract getTitle(doc: Document): string; @@ -80,6 +64,7 @@ export abstract class DomAdapter { abstract isElementNode(node: any): boolean; // Used by Testability + abstract parentElement(el: any): Node|null; abstract isShadowRoot(node: any): boolean; abstract getHost(el: any): any; diff --git a/packages/common/test/directives/ng_if_spec.ts b/packages/common/test/directives/ng_if_spec.ts index fc750d1cf774e6..84b73b4ce14369 100644 --- a/packages/common/test/directives/ng_if_spec.ts +++ b/packages/common/test/directives/ng_if_spec.ts @@ -124,7 +124,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; fixture.detectChanges(); let els = fixture.debugElement.queryAll(By.css('span')); expect(els.length).toEqual(1); - getDOM().addClass(els[0].nativeElement, 'marker'); + els[0].nativeElement.classList.add('marker'); expect(fixture.nativeElement).toHaveText('hello'); getComponent().numberCondition = 2; diff --git a/packages/common/test/directives/non_bindable_spec.ts b/packages/common/test/directives/non_bindable_spec.ts index c3e2de960bcb0b..d77194450cb54c 100644 --- a/packages/common/test/directives/non_bindable_spec.ts +++ b/packages/common/test/directives/non_bindable_spec.ts @@ -37,7 +37,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; // We must use getDOM().querySelector instead of fixture.query here // since the elements inside are not compiled. - const span = getDOM().querySelector(fixture.nativeElement, '#child'); + const span = fixture.nativeElement.querySelector('#child'); expect(hasClass(span, 'compiled')).toBeFalsy(); })); @@ -45,7 +45,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const template = '
{{text}}
'; const fixture = createTestComponent(template); fixture.detectChanges(); - const span = getDOM().querySelector(fixture.nativeElement, '#child'); + const span = fixture.nativeElement.querySelector('#child'); expect(hasClass(span, 'compiled')).toBeTruthy(); })); }); @@ -53,7 +53,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; @Directive({selector: '[test-dec]'}) class TestDirective { - constructor(el: ElementRef) { getDOM().addClass(el.nativeElement, 'compiled'); } + constructor(el: ElementRef) { el.nativeElement.classList.add('compiled'); } } @Component({selector: 'test-cmp', template: ''}) diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index 46ecf5d446b168..b4bbb3670e6eed 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -1589,7 +1589,7 @@ const DEFAULT_COMPONENT_ID = '1'; engine.flush(); resetLog(); - const element = getDOM().querySelector(fixture.nativeElement, '.ng-if'); + const element = fixture.nativeElement.querySelector('.ng-if'); assertHasParent(element, true); cmp.exp = false; diff --git a/packages/core/test/dom/dom_adapter_spec.ts b/packages/core/test/dom/dom_adapter_spec.ts index d2cb6b3a480c46..5ddf2541702b8c 100644 --- a/packages/core/test/dom/dom_adapter_spec.ts +++ b/packages/core/test/dom/dom_adapter_spec.ts @@ -18,7 +18,7 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; }); it('should be able to create text nodes and use them with the other APIs', () => { - const t = getDOM().createTextNode('hello'); + const t = getDOM().getDefaultDocument().createTextNode('hello'); expect(isTextNode(t)).toBe(true); const d = getDOM().createElement('div'); getDOM().appendChild(d, t); @@ -71,7 +71,7 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; getDOM().appendChild(headEl, baseEl); const baseHref = getDOM().getBaseHref(defaultDoc); - getDOM().removeChild(headEl, baseEl); + headEl.removeChild(baseEl); getDOM().resetBaseElement(); expect(baseHref).toEqual('/drop/bass/connon/'); @@ -84,7 +84,7 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; getDOM().appendChild(headEl, baseEl); const baseHref = getDOM().getBaseHref(defaultDoc) !; - getDOM().removeChild(headEl, baseEl); + headEl.removeChild(baseEl); getDOM().resetBaseElement(); expect(baseHref.endsWith('/base')).toBe(true); diff --git a/packages/core/test/linker/integration_spec.ts b/packages/core/test/linker/integration_spec.ts index eba658da46134a..19d01ced8b41d3 100644 --- a/packages/core/test/linker/integration_spec.ts +++ b/packages/core/test/linker/integration_spec.ts @@ -1694,7 +1694,7 @@ function declareTests(config?: {useJit: boolean}) { fixture.componentInstance.ctxProp = 'TITLE'; fixture.detectChanges(); - const el = getDOM().querySelector(fixture.nativeElement, 'span'); + const el = fixture.nativeElement.querySelector('span'); expect(el.title).toBeFalsy(); }); @@ -1707,7 +1707,7 @@ function declareTests(config?: {useJit: boolean}) { fixture.componentInstance.ctxProp = 'TITLE'; fixture.detectChanges(); - const el = getDOM().querySelector(fixture.nativeElement, 'span'); + const el = fixture.nativeElement.querySelector('span'); expect(getDOM().getProperty(el, 'title')).toEqual('TITLE'); }); }); @@ -2685,16 +2685,12 @@ class ComponentWithoutView { @Directive({selector: '[no-duplicate]'}) class DuplicateDir { - constructor(elRef: ElementRef) { - getDOM().setText(elRef.nativeElement, elRef.nativeElement.textContent + 'noduplicate'); - } + constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'noduplicate'; } } @Directive({selector: '[no-duplicate]'}) class OtherDuplicateDir { - constructor(elRef: ElementRef) { - getDOM().setText(elRef.nativeElement, elRef.nativeElement.textContent + 'othernoduplicate'); - } + constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'othernoduplicate'; } } @Directive({selector: 'directive-throwing-error'}) diff --git a/packages/core/test/linker/projection_integration_spec.ts b/packages/core/test/linker/projection_integration_spec.ts index 8509ce9c24b751..495f5356e04826 100644 --- a/packages/core/test/linker/projection_integration_spec.ts +++ b/packages/core/test/linker/projection_integration_spec.ts @@ -136,8 +136,9 @@ describe('projection', () => { componentFactoryResolver.resolveComponentFactory(MultipleContentTagsComponent); expect(componentFactory.ngContentSelectors).toEqual(['h1', '*']); - const nodeOne = getDOM().createTextNode('one'); - const nodeTwo = getDOM().createTextNode('two'); + + const nodeOne = getDOM().getDefaultDocument().createTextNode('one'); + const nodeTwo = getDOM().getDefaultDocument().createTextNode('two'); const component = componentFactory.create(injector, [[nodeOne], [nodeTwo]]); expect(component.location.nativeElement).toHaveText('(one, two)'); }); @@ -175,9 +176,9 @@ describe('projection', () => { componentFactoryResolver.resolveComponentFactory(MultipleContentTagsComponent); expect(componentFactory.ngContentSelectors).toEqual(['h1', '*', 'h2']); - const nodeOne = getDOM().createTextNode('one'); - const nodeTwo = getDOM().createTextNode('two'); - const nodeThree = getDOM().createTextNode('three'); + const nodeOne = getDOM().getDefaultDocument().createTextNode('one'); + const nodeTwo = getDOM().getDefaultDocument().createTextNode('two'); + const nodeThree = getDOM().getDefaultDocument().createTextNode('three'); const component = componentFactory.create(injector, [[nodeOne], [nodeTwo], [nodeThree]]); component.changeDetectorRef.detectChanges(); expect(component.location.nativeElement.textContent.trim()).toBe('1one 2two 3three'); diff --git a/packages/platform-browser/src/browser/browser_adapter.ts b/packages/platform-browser/src/browser/browser_adapter.ts index c46fb67e49d564..c898c07a168d1e 100644 --- a/packages/platform-browser/src/browser/browser_adapter.ts +++ b/packages/platform-browser/src/browser/browser_adapter.ts @@ -74,7 +74,6 @@ const nodeContains: (this: Node, other: Node) => boolean = (() => { /* tslint:disable:requireParameterType no-console */ export class BrowserDomAdapter extends GenericBrowserDomAdapter { static makeCurrent() { setRootDomAdapter(new BrowserDomAdapter()); } - setProperty(el: Node, name: string, value: any) { (el)[name] = value; } getProperty(el: Node, name: string): any { return (el)[name]; } log(error: string): void { @@ -95,7 +94,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { } } - querySelector(el: HTMLElement, selector: string): any { return el.querySelector(selector); } querySelectorAll(el: any, selector: string): any[] { return el.querySelectorAll(selector); } onAndCancel(el: Node, evt: any, listener: any): Function { el.addEventListener(evt, listener, false); @@ -104,43 +102,23 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { return () => { el.removeEventListener(evt, listener, false); }; } dispatchEvent(el: Node, evt: any) { el.dispatchEvent(evt); } - nextSibling(el: Node): Node|null { return el.nextSibling; } parentElement(el: Node): Node|null { return el.parentNode; } - clearNodes(el: Node) { - while (el.firstChild) { - el.removeChild(el.firstChild); - } - } appendChild(el: Node, node: Node) { el.appendChild(node); } - removeChild(el: Node, node: Node) { el.removeChild(node); } remove(node: Node): Node { if (node.parentNode) { node.parentNode.removeChild(node); } return node; } - insertBefore(parent: Node, ref: Node, node: Node) { parent.insertBefore(node, ref); } - setText(el: Node, value: string) { el.textContent = value; } getValue(el: any): string { return el.value; } - createComment(text: string): Comment { return this.getDefaultDocument().createComment(text); } createElement(tagName: string, doc?: Document): HTMLElement { doc = doc || this.getDefaultDocument(); return doc.createElement(tagName); } - createElementNS(ns: string, tagName: string, doc?: Document): Element { - doc = doc || this.getDefaultDocument(); - return doc.createElementNS(ns, tagName); - } - createTextNode(text: string, doc?: Document): Text { - doc = doc || this.getDefaultDocument(); - return doc.createTextNode(text); - } getHost(el: HTMLElement): HTMLElement { return (el).host; } getElementsByTagName(element: any, name: string): HTMLElement[] { return element.getElementsByTagName(name); } - addClass(element: any, className: string) { element.classList.add(className); } - removeClass(element: any, className: string) { element.classList.remove(className); } setStyle(element: any, styleName: string, styleValue: string) { element.style[styleName] = styleValue; } @@ -156,13 +134,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { return element.getAttribute(attribute); } setAttribute(element: Element, name: string, value: string) { element.setAttribute(name, value); } - setAttributeNS(element: Element, ns: string, name: string, value: string) { - element.setAttributeNS(ns, name, value); - } - removeAttribute(element: Element, attribute: string) { element.removeAttribute(attribute); } - removeAttributeNS(element: Element, ns: string, name: string) { - element.removeAttributeNS(ns, name); - } createHtmlDocument(): HTMLDocument { return document.implementation.createHTMLDocument('fakeTitle'); diff --git a/packages/platform-browser/src/browser/meta.ts b/packages/platform-browser/src/browser/meta.ts index 94cf1ca4fb150b..8b10675bb77923 100644 --- a/packages/platform-browser/src/browser/meta.ts +++ b/packages/platform-browser/src/browser/meta.ts @@ -60,7 +60,7 @@ export class Meta { getTag(attrSelector: string): HTMLMetaElement|null { if (!attrSelector) return null; - return this._dom.querySelector(this._doc, `meta[${attrSelector}]`) || null; + return this._doc.querySelector(`meta[${attrSelector}]`) || null; } getTags(attrSelector: string): HTMLMetaElement[] { diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index 8807b340d1ddb0..b1feb2aa423b48 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -153,7 +153,7 @@ function bootstrap( getDOM().appendChild(doc.body, el); getDOM().appendChild(doc.body, el2); getDOM().appendChild(el, lightDom); - getDOM().setText(lightDom, 'loading'); + lightDom.textContent = 'loading'; })); afterEach(destroyPlatform); diff --git a/packages/platform-server/src/domino_adapter.ts b/packages/platform-server/src/domino_adapter.ts index b4a82069158d3c..c9d9e70c15e77c 100644 --- a/packages/platform-server/src/domino_adapter.ts +++ b/packages/platform-server/src/domino_adapter.ts @@ -86,18 +86,6 @@ export class DominoAdapter extends BrowserDomAdapter { return (el)[name]; } - setProperty(el: Element, name: string, value: any) { - if (name === 'href') { - // Even though the server renderer reflects any properties to attributes - // map 'href' to attribute just to handle when setProperty is directly called. - this.setAttribute(el, 'href', value); - } else if (name === 'innerText') { - // Domino does not support innerText. Just map it to textContent. - el.textContent = value; - } - (el)[name] = value; - } - getGlobalEventTarget(doc: Document, target: string): EventTarget|null { if (target === 'window') { return doc.defaultView; @@ -112,7 +100,7 @@ export class DominoAdapter extends BrowserDomAdapter { } getBaseHref(doc: Document): string { - const base = this.querySelector(doc.documentElement !, 'base'); + const base = doc.documentElement !.querySelector('base'); let href = ''; if (base) { href = base.getAttribute('href') !; diff --git a/packages/platform-server/src/server_renderer.ts b/packages/platform-server/src/server_renderer.ts index 71e0f8f0700002..fa751de848fd3b 100644 --- a/packages/platform-server/src/server_renderer.ts +++ b/packages/platform-server/src/server_renderer.ts @@ -72,51 +72,59 @@ class DefaultServerRenderer2 implements Renderer2 { createElement(name: string, namespace?: string, debugInfo?: any): any { if (namespace) { - return getDOM().createElementNS(NAMESPACE_URIS[namespace], name, this.document); + const doc = this.document || getDOM().getDefaultDocument(); + return doc.createElementNS(NAMESPACE_URIS[namespace], name); } return getDOM().createElement(name, this.document); } - createComment(value: string, debugInfo?: any): any { return getDOM().createComment(value); } + createComment(value: string, debugInfo?: any): any { + return getDOM().getDefaultDocument().createComment(value); + } - createText(value: string, debugInfo?: any): any { return getDOM().createTextNode(value); } + createText(value: string, debugInfo?: any): any { + const doc = getDOM().getDefaultDocument(); + return doc.createTextNode(value); + } appendChild(parent: any, newChild: any): void { getDOM().appendChild(parent, newChild); } insertBefore(parent: any, newChild: any, refChild: any): void { if (parent) { - getDOM().insertBefore(parent, refChild, newChild); + parent.insertBefore(newChild, refChild); } } removeChild(parent: any, oldChild: any): void { if (parent) { - getDOM().removeChild(parent, oldChild); + parent.removeChild(oldChild); } } selectRootElement(selectorOrNode: string|any, debugInfo?: any): any { let el: any; if (typeof selectorOrNode === 'string') { - el = getDOM().querySelector(this.document, selectorOrNode); + el = this.document.querySelector(selectorOrNode); if (!el) { throw new Error(`The selector "${selectorOrNode}" did not match any elements`); } } else { el = selectorOrNode; } - getDOM().clearNodes(el); + while (el.firstChild) { + el.removeChild(el.firstChild); + } return el; } parentNode(node: any): any { return getDOM().parentElement(node); } - nextSibling(node: any): any { return getDOM().nextSibling(node); } + nextSibling(node: any): any { return node.nextSibling; } setAttribute(el: any, name: string, value: string, namespace?: string): void { if (namespace) { - getDOM().setAttributeNS(el, NAMESPACE_URIS[namespace], namespace + ':' + name, value); + el.setAttributeNS(NAMESPACE_URIS[namespace], namespace + ':' + name, value); } else { getDOM().setAttribute(el, name, value); } @@ -124,15 +132,15 @@ class DefaultServerRenderer2 implements Renderer2 { removeAttribute(el: any, name: string, namespace?: string): void { if (namespace) { - getDOM().removeAttributeNS(el, NAMESPACE_URIS[namespace], name); + el.removeAttributeNS(NAMESPACE_URIS[namespace], name); } else { - getDOM().removeAttribute(el, name); + el.removeAttribute(name); } } - addClass(el: any, name: string): void { getDOM().addClass(el, name); } + addClass(el: any, name: string): void { el.classList.add(name); } - removeClass(el: any, name: string): void { getDOM().removeClass(el, name); } + removeClass(el: any, name: string): void { el.classList.remove(name); } setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void { getDOM().setStyle(el, style, value); @@ -153,7 +161,11 @@ class DefaultServerRenderer2 implements Renderer2 { setProperty(el: any, name: string, value: any): void { checkNoSyntheticProp(name, 'property'); - getDOM().setProperty(el, name, value); + if (name === 'innerText') { + // Domino does not support innerText. Just map it to textContent. + el.textContent = value; + } + (el)[name] = value; // Mirror property values for known HTML element properties in the attributes. // Skip `innerhtml` which is conservatively marked as an attribute for security // purposes but is not actually an attribute. @@ -166,7 +178,7 @@ class DefaultServerRenderer2 implements Renderer2 { } } - setValue(node: any, value: string): void { getDOM().setText(node, value); } + setValue(node: any, value: string): void { node.textContent = value; } listen( target: 'document'|'window'|'body'|any, eventName: string, diff --git a/packages/platform-server/src/styles_host.ts b/packages/platform-server/src/styles_host.ts index 7e45eb9ba1cbea..3dd3e7320c8558 100644 --- a/packages/platform-server/src/styles_host.ts +++ b/packages/platform-server/src/styles_host.ts @@ -24,7 +24,7 @@ export class ServerStylesHost extends SharedStylesHost { private _addStyle(style: string): void { let adapter = getDOM(); const el = adapter.createElement('style'); - adapter.setText(el, style); + el.textContent = style; if (!!this.transitionId) { adapter.setAttribute(el, 'ng-transition', this.transitionId); } diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index 09d8ce25292aa1..31f488d25fb4b9 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -408,8 +408,8 @@ class HiddenModule { expect(isPlatformServer(moduleRef.injector.get(PLATFORM_ID))).toBe(true); const doc = moduleRef.injector.get(DOCUMENT); - expect(doc.head).toBe(getDOM().querySelector(doc, 'head')); - expect(doc.body).toBe(getDOM().querySelector(doc, 'body')); + expect(doc.head).toBe(doc.querySelector('head') !); + expect(doc.body).toBe(doc.querySelector('body') !); expect(doc.documentElement.textContent).toEqual('Works!'); @@ -447,7 +447,7 @@ class HiddenModule { platform.bootstrapModule(TitleAppModule).then(ref => { const state = ref.injector.get(PlatformState); const doc = ref.injector.get(DOCUMENT); - const title = getDOM().querySelector(doc, 'title'); + const title = doc.querySelector('title') !; expect(title.textContent).toBe('Test App Title'); expect(state.renderToString()).toContain('Test App Title'); }); diff --git a/packages/platform-webworker/src/web_workers/worker/worker_adapter.ts b/packages/platform-webworker/src/web_workers/worker/worker_adapter.ts index eac98e1756d298..942bb3c5d84085 100644 --- a/packages/platform-webworker/src/web_workers/worker/worker_adapter.ts +++ b/packages/platform-webworker/src/web_workers/worker/worker_adapter.ts @@ -42,37 +42,22 @@ export class WorkerDomAdapter extends DomAdapter { } } - setProperty(el: Element, name: string, value: any) { throw 'not implemented'; } getProperty(el: Element, name: string): any { throw 'not implemented'; } - querySelector(el: any, selector: string): HTMLElement { throw 'not implemented'; } 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'; } - nextSibling(el: any): Node { throw 'not implemented'; } parentElement(el: any): Node { throw 'not implemented'; } - clearNodes(el: any) { throw 'not implemented'; } appendChild(el: any, node: any) { throw 'not implemented'; } - removeChild(el: any, node: any) { throw 'not implemented'; } remove(el: any): Node { throw 'not implemented'; } - insertBefore(parent: any, el: any, node: any) { throw 'not implemented'; } - setText(el: any, value: string) { throw 'not implemented'; } - createComment(text: string): any { throw 'not implemented'; } createElement(tagName: any, doc?: any): HTMLElement { throw 'not implemented'; } - createElementNS(ns: string, tagName: string, doc?: any): Element { throw 'not implemented'; } - createTextNode(text: string, doc?: any): Text { throw 'not implemented'; } getHost(el: any): any { throw 'not implemented'; } getElementsByTagName(element: any, name: string): HTMLElement[] { throw 'not implemented'; } - addClass(element: any, className: string) { throw 'not implemented'; } - removeClass(element: any, className: string) { throw 'not implemented'; } setStyle(element: any, styleName: string, styleValue: string) { throw 'not implemented'; } removeStyle(element: any, styleName: string) { throw 'not implemented'; } getStyle(element: any, styleName: string): string { throw 'not implemented'; } getAttribute(element: any, attribute: string): string { throw 'not implemented'; } setAttribute(element: any, name: string, value: string) { throw 'not implemented'; } - setAttributeNS(element: any, ns: string, name: string, value: string) { throw 'not implemented'; } - removeAttribute(element: any, attribute: string) { throw 'not implemented'; } - removeAttributeNS(element: any, ns: string, attribute: string) { throw 'not implemented'; } createHtmlDocument(): HTMLDocument { throw 'not implemented'; } getDefaultDocument(): Document { throw 'not implemented'; } getTitle(doc: Document): string { throw 'not implemented'; }