From 9c69fe350f1b242013b2b169e3d1ba994a8c3423 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 11:18:21 +0100 Subject: [PATCH 01/10] feat(platform-browser): implemented LinkDefinition and Link Service Closes #34605 --- packages/platform-browser/src/browser/link.ts | 150 +++++++++++++ .../platform-browser/src/platform-browser.ts | 1 + .../test/browser/link_spec.ts | 201 ++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 packages/platform-browser/src/browser/link.ts create mode 100644 packages/platform-browser/test/browser/link_spec.ts diff --git a/packages/platform-browser/src/browser/link.ts b/packages/platform-browser/src/browser/link.ts new file mode 100644 index 000000000000..4efa35211879 --- /dev/null +++ b/packages/platform-browser/src/browser/link.ts @@ -0,0 +1,150 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import { + DOCUMENT, + ɵDomAdapter as DomAdapter, + ɵgetDOM as getDOM +} from '@angular/common'; +import { Inject, Injectable, ɵɵinject } from '@angular/core'; + +/** + * Represents a link element. + * + * @publicApi + */ +export type LinkDefinition = { + charset?: string; + crossorigin?: 'anonymous' | 'use-credentials'; + disabled?: boolean; + href?: string; + hreflang?: string; + media?: string; + methods?: string; + rel?: string; + sizes?: string; + target?: string; + type?: string; +} & +{ + [prop: string]: string; +}; + +/** + * Factory to create Link service. + */ +export function createLink() { + return new Link(ɵɵinject(DOCUMENT)); +} + +/** + * A service that can be used to get and add link tags. + * + * @publicApi + */ +@Injectable({ providedIn: 'root', useFactory: createLink, deps: [] }) +export class Link { + private _dom: DomAdapter; + constructor(@Inject(DOCUMENT) private _doc: any) { + this._dom = getDOM(); + } + + addLink( + link: LinkDefinition, + forceCreation: boolean = false + ): HTMLLinkElement | null { + if (!link) return null; + return this._getOrCreateElement(link, forceCreation); + } + + addLinks( + links: LinkDefinition[], + forceCreation: boolean = false + ): HTMLLinkElement[] { + if (!links) return []; + return links.reduce((result: HTMLLinkElement[], link: LinkDefinition) => { + if (link) { + result.push(this._getOrCreateElement(link, forceCreation)); + } + return result; + }, []); + } + + getLink(attrSelector: string): HTMLLinkElement | null { + if (!attrSelector) return null; + return this._doc.querySelector(`link[${attrSelector}]`) || null; + } + + getLinks(attrSelector: string): HTMLLinkElement[] { + if (!attrSelector) return []; + const list /*NodeList*/ = this._doc.querySelectorAll( + `link[${attrSelector}]` + ); + return list ? [].slice.call(list) : []; + } + + updateLink(link: LinkDefinition, selector?: string): HTMLLinkElement | null { + if (!link) return null; + selector = selector || this._parseSelector(link); + const linkEl: HTMLLinkElement = this.getLink(selector)!; + if (linkEl) { + return this._setLinkElementAttributes(link, linkEl); + } + return this._getOrCreateElement(link, true); + } + + removeLink(attrSelector: string): void { + this.removeLinkElement(this.getLink(attrSelector)!); + } + + removeLinkElement(link: HTMLLinkElement): void { + if (link) { + this._dom.remove(link); + } + } + + private _getOrCreateElement( + link: LinkDefinition, + forceCreation: boolean = false + ): HTMLLinkElement { + if (!forceCreation) { + const selector: string = this._parseSelector(link); + const elem: HTMLLinkElement = this.getLink(selector) !; + // It's allowed to have multiple elements with the same name so it's not enough to + // just check that element with the same name already present on the page. We also need to + // check if element has tag attributes + if (elem && this._containsAttributes(link, elem)) return elem; + } + const element: HTMLLinkElement = this._dom.createElement( + 'link' + ) as HTMLLinkElement; + this._setLinkElementAttributes(link, element); + const head = this._doc.getElementsByTagName('head')[0]; + head.appendChild(element); + return element; + } + + private _setLinkElementAttributes( + link: LinkDefinition, + el: HTMLLinkElement + ): HTMLLinkElement { + Object.keys(link).forEach((prop: string) => + el.setAttribute(prop, link[prop]) + ); + return el; + } + + private _parseSelector(link: LinkDefinition): string { + const attr: string = link.rel ? 'rel' : 'property'; + return `${attr}="${link[attr]}"`; + } + + private _containsAttributes(link: LinkDefinition, elem: HTMLLinkElement): boolean { + return Object.keys(link).every((key: string) => elem.getAttribute(key) === link[key]); + } +} diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index 5c3d5ac11fe4..ade099541890 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -8,6 +8,7 @@ export {BrowserModule, platformBrowser} from './browser'; export {Meta, MetaDefinition} from './browser/meta'; +export {Link, LinkDefinition} from './browser/link'; export {Title} from './browser/title'; export {disableDebugTools, enableDebugTools} from './browser/tools/tools'; export {BrowserTransferStateModule, StateKey, TransferState, makeStateKey} from './browser/transfer_state'; diff --git a/packages/platform-browser/test/browser/link_spec.ts b/packages/platform-browser/test/browser/link_spec.ts new file mode 100644 index 000000000000..3515efd61c0a --- /dev/null +++ b/packages/platform-browser/test/browser/link_spec.ts @@ -0,0 +1,201 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ɵgetDOM as getDOM} from '@angular/common'; +import {Injectable} from '@angular/core'; +import {TestBed} from '@angular/core/testing'; +import {BrowserModule, Link} from '@angular/platform-browser'; +import {expect} from '@angular/platform-browser/testing/src/matchers'; + +{ + describe('Link service', () => { + let doc: Document; + let linkService: Link; + let defaultLink: HTMLLinkElement; + + beforeEach(() => { + doc = getDOM().createHtmlDocument(); + linkService = new Link(doc); + defaultLink = getDOM().createElement('link', doc) as HTMLLinkElement; + defaultLink.setAttribute('rel', 'canonical'); + defaultLink.setAttribute('href', 'https://example.com'); + doc.getElementsByTagName('head')[0].appendChild(defaultLink); + }); + + afterEach(() => getDOM().remove(defaultLink)); + + it('should return link tag matching selector', () => { + const actual: HTMLLinkElement = linkService.getLink('rel="canonical"') !; + expect(actual).not.toBeNull(); + expect(actual.getAttribute('href')).toEqual('https://example.com'); + }); + + it('should return all link tags matching selector', () => { + const tag1 = linkService.addLink({rel: 'stylesheet', href: 'http://foo.bar'}) !; + const tag2 = linkService.addLink({rel: 'stylesheet', href: 'http://bar.baz'}) !; + + const actual: HTMLLinkElement[] = linkService.getLinks('rel=stylesheet'); + expect(actual.length).toEqual(2); + expect(actual[0].getAttribute('href')).toEqual('http://foo.bar'); + expect(actual[1].getAttribute('href')).toEqual('http://bar.baz'); + + // clean up + linkService.removeLinkElement(tag1); + linkService.removeLinkElement(tag2); + }); + + it('should return null if link tag does not exist', () => { + const actual: HTMLLinkElement = linkService.getLink('fake=fake') !; + expect(actual).toBeNull(); + }); + + it('should remove link tag by the given selector', () => { + const selector = 'rel=stylesheet'; + expect(linkService.getLink(selector)).toBeNull(); + + linkService.addLink({rel: 'stylesheet', href: 'http://foo.bar'}); + + expect(linkService.getLink(selector)).not.toBeNull(); + + linkService.removeLink(selector); + + expect(linkService.getLink(selector)).toBeNull(); + }); + + it('should remove link tag by the given element', () => { + const selector = 'rel=stylesheet'; + expect(linkService.getLink(selector)).toBeNull(); + + linkService.addLinks([{rel: 'stylesheet', href: 'http://foo.bar'}]); + + const link = linkService.getLink(selector) !; + expect(link).not.toBeNull(); + + linkService.removeLinkElement(link); + + expect(linkService.getLink(selector)).toBeNull(); + }); + + it('should update link tag matching the given selector', () => { + const selector = 'rel="stylesheet"'; + linkService.updateLink({rel: 'stylesheet'}, selector); + + const actual = linkService.getLink(selector); + expect(actual).not.toBeNull(); + expect(actual !.getAttribute('rel')).toEqual('stylesheet'); + }); + + it('should extract selector from the tag definition', () => { + const selector = 'rel="stylesheet"'; + linkService.updateLink({property: 'stylesheet', href: 'http://foo.bar'}); + + const actual = linkService.getLink(selector); + expect(actual).not.toBeNull(); + expect(actual !.getAttribute('href')).toEqual('http://foo.bar'); + }); + + it('should create link tag if it does not exist', () => { + const selector = 'rel="stylesheet"'; + + linkService.updateLink({rel: 'stylesheet', href: 'http://foo.bar'}, selector); + + const actual = linkService.getLink(selector) !; + expect(actual).not.toBeNull(); + expect(actual.getAttribute('href')).toEqual('http://foo.bar'); + + // clean up + linkService.removeLinkElement(actual); + }); + + it('should add new link tag', () => { + const selector = 'rel="stylesheet"'; + expect(linkService.getLink(selector)).toBeNull(); + + linkService.addLink({rel: 'stylesheet', href: 'http://foo.bar'}); + + const actual = linkService.getLink(selector) !; + expect(actual).not.toBeNull(); + expect(actual.getAttribute('href')).toEqual('http://foo.bar'); + + // clean up + linkService.removeLinkElement(actual); + }); + + it('should add multiple new link tags', () => { + const nameSelector = 'rel="canonical"'; + const propertySelector = 'rel="author"'; + expect(linkService.getLink(nameSelector)).toBeNull(); + expect(linkService.getLink(propertySelector)).toBeNull(); + + linkService.addLinks([ + {rel: 'canonical', href: 'http://foo.bar'}, + {rel: 'author', href: 'http://bar.baz'} + ]); + const canonicalLink = linkService.getLink(nameSelector) !; + const authorLink = linkService.getLink(propertySelector) !; + expect(canonicalLink).not.toBeNull(); + expect(authorLink).not.toBeNull(); + + // clean up + linkService.removeLinkElement(canonicalLink); + linkService.removeLinkElement(authorLink); + }); + + it('should not add meta tag if it is already present on the page and has the same attr', () => { + const selector = 'rel="canonical"'; + expect(linkService.getLinks(selector).length).toEqual(1); + + linkService.addLink({rel: 'canonical', href: 'http://example.com'}); + + expect(linkService.getLinks(selector).length).toEqual(1); + }); + + it('should add meta tag if it is already present on the page and but has different attr', + () => { + const selector = 'rel="canonical"'; + expect(linkService.getLinks(selector).length).toEqual(1); + + const meta = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}) !; + + expect(linkService.getLinks(selector).length).toEqual(2); + + // clean up + linkService.removeLinkElement(meta); + }); + + it('should add meta tag if it is already present on the page and force true', () => { + const selector = 'rel="canonical"'; + expect(linkService.getLinks(selector).length).toEqual(1); + + const meta = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}, true) !; + + expect(linkService.getLinks(selector).length).toEqual(2); + + // clean up + linkService.removeLinkElement(meta); + }); + }); + + describe('integration test', () => { + + @Injectable() + class DependsOnLink { + constructor(public link: Link) {} + } + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [BrowserModule], + providers: [DependsOnLink], + }); + }); + + it('should inject Link service when using BrowserModule', + () => expect(TestBed.inject(DependsOnLink).link).toBeAnInstanceOf(Link)); + }); +} From c7aab70390cebfec8314c6c82179fc54b09135a8 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 11:50:23 +0100 Subject: [PATCH 02/10] style(platform-browser): format code --- packages/platform-browser/src/browser/link.ts | 28 ++++--- packages/platform-browser/src/browser/meta.ts | 81 +++++++++++++------ .../platform-browser/src/platform-browser.ts | 49 ++++++++--- 3 files changed, 109 insertions(+), 49 deletions(-) diff --git a/packages/platform-browser/src/browser/link.ts b/packages/platform-browser/src/browser/link.ts index 4efa35211879..8fedb1904239 100644 --- a/packages/platform-browser/src/browser/link.ts +++ b/packages/platform-browser/src/browser/link.ts @@ -10,8 +10,8 @@ import { DOCUMENT, ɵDomAdapter as DomAdapter, ɵgetDOM as getDOM -} from '@angular/common'; -import { Inject, Injectable, ɵɵinject } from '@angular/core'; +} from "@angular/common"; +import { Inject, Injectable, ɵɵinject } from "@angular/core"; /** * Represents a link element. @@ -20,7 +20,7 @@ import { Inject, Injectable, ɵɵinject } from '@angular/core'; */ export type LinkDefinition = { charset?: string; - crossorigin?: 'anonymous' | 'use-credentials'; + crossorigin?: "anonymous" | "use-credentials"; disabled?: boolean; href?: string; hreflang?: string; @@ -30,8 +30,7 @@ export type LinkDefinition = { sizes?: string; target?: string; type?: string; -} & -{ +} & { [prop: string]: string; }; @@ -47,7 +46,7 @@ export function createLink() { * * @publicApi */ -@Injectable({ providedIn: 'root', useFactory: createLink, deps: [] }) +@Injectable({ providedIn: "root", useFactory: createLink, deps: [] }) export class Link { private _dom: DomAdapter; constructor(@Inject(DOCUMENT) private _doc: any) { @@ -114,17 +113,17 @@ export class Link { ): HTMLLinkElement { if (!forceCreation) { const selector: string = this._parseSelector(link); - const elem: HTMLLinkElement = this.getLink(selector) !; + const elem: HTMLLinkElement = this.getLink(selector)!; // It's allowed to have multiple elements with the same name so it's not enough to // just check that element with the same name already present on the page. We also need to // check if element has tag attributes if (elem && this._containsAttributes(link, elem)) return elem; } const element: HTMLLinkElement = this._dom.createElement( - 'link' + "link" ) as HTMLLinkElement; this._setLinkElementAttributes(link, element); - const head = this._doc.getElementsByTagName('head')[0]; + const head = this._doc.getElementsByTagName("head")[0]; head.appendChild(element); return element; } @@ -140,11 +139,16 @@ export class Link { } private _parseSelector(link: LinkDefinition): string { - const attr: string = link.rel ? 'rel' : 'property'; + const attr: string = link.rel ? "rel" : "property"; return `${attr}="${link[attr]}"`; } - private _containsAttributes(link: LinkDefinition, elem: HTMLLinkElement): boolean { - return Object.keys(link).every((key: string) => elem.getAttribute(key) === link[key]); + private _containsAttributes( + link: LinkDefinition, + elem: HTMLLinkElement + ): boolean { + return Object.keys(link).every( + (key: string) => elem.getAttribute(key) === link[key] + ); } } diff --git a/packages/platform-browser/src/browser/meta.ts b/packages/platform-browser/src/browser/meta.ts index 0962e4656ce3..c3e64936da66 100644 --- a/packages/platform-browser/src/browser/meta.ts +++ b/packages/platform-browser/src/browser/meta.ts @@ -6,8 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {DOCUMENT, ɵDomAdapter as DomAdapter, ɵgetDOM as getDOM} from '@angular/common'; -import {Inject, Injectable, ɵɵinject} from '@angular/core'; +import { + DOCUMENT, + ɵDomAdapter as DomAdapter, + ɵgetDOM as getDOM +} from "@angular/common"; +import { Inject, Injectable, ɵɵinject } from "@angular/core"; /** * Represents a meta element. @@ -15,13 +19,16 @@ import {Inject, Injectable, ɵɵinject} from '@angular/core'; * @publicApi */ export type MetaDefinition = { - charset?: string; content?: string; httpEquiv?: string; id?: string; itemprop?: string; + charset?: string; + content?: string; + httpEquiv?: string; + id?: string; + itemprop?: string; name?: string; property?: string; scheme?: string; url?: string; -} & -{ +} & { // TODO(IgorMinar): this type looks wrong [prop: string]: string; }; @@ -38,17 +45,25 @@ export function createMeta() { * * @publicApi */ -@Injectable({providedIn: 'root', useFactory: createMeta, deps: []}) +@Injectable({ providedIn: "root", useFactory: createMeta, deps: [] }) export class Meta { private _dom: DomAdapter; - constructor(@Inject(DOCUMENT) private _doc: any) { this._dom = getDOM(); } + constructor(@Inject(DOCUMENT) private _doc: any) { + this._dom = getDOM(); + } - addTag(tag: MetaDefinition, forceCreation: boolean = false): HTMLMetaElement|null { + addTag( + tag: MetaDefinition, + forceCreation: boolean = false + ): HTMLMetaElement | null { if (!tag) return null; return this._getOrCreateElement(tag, forceCreation); } - addTags(tags: MetaDefinition[], forceCreation: boolean = false): HTMLMetaElement[] { + addTags( + tags: MetaDefinition[], + forceCreation: boolean = false + ): HTMLMetaElement[] { if (!tags) return []; return tags.reduce((result: HTMLMetaElement[], tag: MetaDefinition) => { if (tag) { @@ -58,28 +73,32 @@ export class Meta { }, []); } - getTag(attrSelector: string): HTMLMetaElement|null { + getTag(attrSelector: string): HTMLMetaElement | null { if (!attrSelector) return null; return this._doc.querySelector(`meta[${attrSelector}]`) || null; } getTags(attrSelector: string): HTMLMetaElement[] { if (!attrSelector) return []; - const list /*NodeList*/ = this._doc.querySelectorAll(`meta[${attrSelector}]`); + const list /*NodeList*/ = this._doc.querySelectorAll( + `meta[${attrSelector}]` + ); return list ? [].slice.call(list) : []; } - updateTag(tag: MetaDefinition, selector?: string): HTMLMetaElement|null { + updateTag(tag: MetaDefinition, selector?: string): HTMLMetaElement | null { if (!tag) return null; selector = selector || this._parseSelector(tag); - const meta: HTMLMetaElement = this.getTag(selector) !; + const meta: HTMLMetaElement = this.getTag(selector)!; if (meta) { return this._setMetaElementAttributes(tag, meta); } return this._getOrCreateElement(tag, true); } - removeTag(attrSelector: string): void { this.removeTagElement(this.getTag(attrSelector) !); } + removeTag(attrSelector: string): void { + this.removeTagElement(this.getTag(attrSelector)!); + } removeTagElement(meta: HTMLMetaElement): void { if (meta) { @@ -87,34 +106,48 @@ export class Meta { } } - private _getOrCreateElement(meta: MetaDefinition, forceCreation: boolean = false): - HTMLMetaElement { + private _getOrCreateElement( + meta: MetaDefinition, + forceCreation: boolean = false + ): HTMLMetaElement { if (!forceCreation) { const selector: string = this._parseSelector(meta); - const elem: HTMLMetaElement = this.getTag(selector) !; + const elem: HTMLMetaElement = this.getTag(selector)!; // It's allowed to have multiple elements with the same name so it's not enough to // just check that element with the same name already present on the page. We also need to // check if element has tag attributes if (elem && this._containsAttributes(meta, elem)) return elem; } - const element: HTMLMetaElement = this._dom.createElement('meta') as HTMLMetaElement; + const element: HTMLMetaElement = this._dom.createElement( + "meta" + ) as HTMLMetaElement; this._setMetaElementAttributes(meta, element); - const head = this._doc.getElementsByTagName('head')[0]; + const head = this._doc.getElementsByTagName("head")[0]; head.appendChild(element); return element; } - private _setMetaElementAttributes(tag: MetaDefinition, el: HTMLMetaElement): HTMLMetaElement { - Object.keys(tag).forEach((prop: string) => el.setAttribute(prop, tag[prop])); + private _setMetaElementAttributes( + tag: MetaDefinition, + el: HTMLMetaElement + ): HTMLMetaElement { + Object.keys(tag).forEach((prop: string) => + el.setAttribute(prop, tag[prop]) + ); return el; } private _parseSelector(tag: MetaDefinition): string { - const attr: string = tag.name ? 'name' : 'property'; + const attr: string = tag.name ? "name" : "property"; return `${attr}="${tag[attr]}"`; } - private _containsAttributes(tag: MetaDefinition, elem: HTMLMetaElement): boolean { - return Object.keys(tag).every((key: string) => elem.getAttribute(key) === tag[key]); + private _containsAttributes( + tag: MetaDefinition, + elem: HTMLMetaElement + ): boolean { + return Object.keys(tag).every( + (key: string) => elem.getAttribute(key) === tag[key] + ); } } diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index ade099541890..945f8ebc3750 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -6,18 +6,41 @@ * found in the LICENSE file at https://angular.io/license */ -export {BrowserModule, platformBrowser} from './browser'; -export {Meta, MetaDefinition} from './browser/meta'; -export {Link, LinkDefinition} from './browser/link'; -export {Title} from './browser/title'; -export {disableDebugTools, enableDebugTools} from './browser/tools/tools'; -export {BrowserTransferStateModule, StateKey, TransferState, makeStateKey} from './browser/transfer_state'; -export {By} from './dom/debug/by'; -export {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; -export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, HammerGestureConfig, HammerLoader, HammerModule} from './dom/events/hammer_gestures'; -export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl, SafeValue} from './security/dom_sanitization_service'; +export { BrowserModule, platformBrowser } from "./browser"; +export { Meta, MetaDefinition } from "./browser/meta"; +export { Link, LinkDefinition } from "./browser/link"; +export { Title } from "./browser/title"; +export { disableDebugTools, enableDebugTools } from "./browser/tools/tools"; +export { + BrowserTransferStateModule, + StateKey, + TransferState, + makeStateKey +} from "./browser/transfer_state"; +export { By } from "./dom/debug/by"; +export { + EVENT_MANAGER_PLUGINS, + EventManager +} from "./dom/events/event_manager"; +export { + HAMMER_GESTURE_CONFIG, + HAMMER_LOADER, + HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, + HammerGestureConfig, + HammerLoader, + HammerModule +} from "./dom/events/hammer_gestures"; +export { + DomSanitizer, + SafeHtml, + SafeResourceUrl, + SafeScript, + SafeStyle, + SafeUrl, + SafeValue +} from "./security/dom_sanitization_service"; -export * from './private_export'; -export {VERSION} from './version'; +export * from "./private_export"; +export { VERSION } from "./version"; // This must be exported so it doesn't get tree-shaken away prematurely -export {ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__} from './dom/debug/ng_probe'; +export { ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__ } from "./dom/debug/ng_probe"; From 57731e67dd6d5fa05494978c925f4762a68c77f7 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 12:07:57 +0100 Subject: [PATCH 03/10] style(platform-browser): reformat code and tests --- packages/platform-browser/src/browser/link.ts | 79 ++++++------------ packages/platform-browser/src/browser/meta.ts | 81 ++++++------------- .../platform-browser/src/platform-browser.ts | 49 +++-------- .../test/browser/link_spec.ts | 12 +-- .../test/browser/meta_spec.ts | 7 +- 5 files changed, 65 insertions(+), 163 deletions(-) diff --git a/packages/platform-browser/src/browser/link.ts b/packages/platform-browser/src/browser/link.ts index 8fedb1904239..71aae8f35d37 100644 --- a/packages/platform-browser/src/browser/link.ts +++ b/packages/platform-browser/src/browser/link.ts @@ -6,12 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import { - DOCUMENT, - ɵDomAdapter as DomAdapter, - ɵgetDOM as getDOM -} from "@angular/common"; -import { Inject, Injectable, ɵɵinject } from "@angular/core"; +import {DOCUMENT, ɵDomAdapter as DomAdapter, ɵgetDOM as getDOM} from '@angular/common'; +import {Inject, Injectable, ɵɵinject} from '@angular/core'; /** * Represents a link element. @@ -19,9 +15,7 @@ import { Inject, Injectable, ɵɵinject } from "@angular/core"; * @publicApi */ export type LinkDefinition = { - charset?: string; - crossorigin?: "anonymous" | "use-credentials"; - disabled?: boolean; + charset?: string; crossorigin?: 'anonymous' | 'use-credentials'; disabled?: boolean; href?: string; hreflang?: string; media?: string; @@ -30,7 +24,8 @@ export type LinkDefinition = { sizes?: string; target?: string; type?: string; -} & { +} & +{ [prop: string]: string; }; @@ -46,25 +41,17 @@ export function createLink() { * * @publicApi */ -@Injectable({ providedIn: "root", useFactory: createLink, deps: [] }) +@Injectable({providedIn: 'root', useFactory: createLink, deps: []}) export class Link { private _dom: DomAdapter; - constructor(@Inject(DOCUMENT) private _doc: any) { - this._dom = getDOM(); - } + constructor(@Inject(DOCUMENT) private _doc: any) { this._dom = getDOM(); } - addLink( - link: LinkDefinition, - forceCreation: boolean = false - ): HTMLLinkElement | null { + addLink(link: LinkDefinition, forceCreation: boolean = false): HTMLLinkElement|null { if (!link) return null; return this._getOrCreateElement(link, forceCreation); } - addLinks( - links: LinkDefinition[], - forceCreation: boolean = false - ): HTMLLinkElement[] { + addLinks(links: LinkDefinition[], forceCreation: boolean = false): HTMLLinkElement[] { if (!links) return []; return links.reduce((result: HTMLLinkElement[], link: LinkDefinition) => { if (link) { @@ -74,32 +61,28 @@ export class Link { }, []); } - getLink(attrSelector: string): HTMLLinkElement | null { + getLink(attrSelector: string): HTMLLinkElement|null { if (!attrSelector) return null; return this._doc.querySelector(`link[${attrSelector}]`) || null; } getLinks(attrSelector: string): HTMLLinkElement[] { if (!attrSelector) return []; - const list /*NodeList*/ = this._doc.querySelectorAll( - `link[${attrSelector}]` - ); + const list /*NodeList*/ = this._doc.querySelectorAll(`link[${attrSelector}]`); return list ? [].slice.call(list) : []; } - updateLink(link: LinkDefinition, selector?: string): HTMLLinkElement | null { + updateLink(link: LinkDefinition, selector?: string): HTMLLinkElement|null { if (!link) return null; selector = selector || this._parseSelector(link); - const linkEl: HTMLLinkElement = this.getLink(selector)!; + const linkEl: HTMLLinkElement = this.getLink(selector) !; if (linkEl) { return this._setLinkElementAttributes(link, linkEl); } return this._getOrCreateElement(link, true); } - removeLink(attrSelector: string): void { - this.removeLinkElement(this.getLink(attrSelector)!); - } + removeLink(attrSelector: string): void { this.removeLinkElement(this.getLink(attrSelector) !); } removeLinkElement(link: HTMLLinkElement): void { if (link) { @@ -107,48 +90,34 @@ export class Link { } } - private _getOrCreateElement( - link: LinkDefinition, - forceCreation: boolean = false - ): HTMLLinkElement { + private _getOrCreateElement(link: LinkDefinition, forceCreation: boolean = false): + HTMLLinkElement { if (!forceCreation) { const selector: string = this._parseSelector(link); - const elem: HTMLLinkElement = this.getLink(selector)!; + const elem: HTMLLinkElement = this.getLink(selector) !; // It's allowed to have multiple elements with the same name so it's not enough to // just check that element with the same name already present on the page. We also need to // check if element has tag attributes if (elem && this._containsAttributes(link, elem)) return elem; } - const element: HTMLLinkElement = this._dom.createElement( - "link" - ) as HTMLLinkElement; + const element: HTMLLinkElement = this._dom.createElement('link') as HTMLLinkElement; this._setLinkElementAttributes(link, element); - const head = this._doc.getElementsByTagName("head")[0]; + const head = this._doc.getElementsByTagName('head')[0]; head.appendChild(element); return element; } - private _setLinkElementAttributes( - link: LinkDefinition, - el: HTMLLinkElement - ): HTMLLinkElement { - Object.keys(link).forEach((prop: string) => - el.setAttribute(prop, link[prop]) - ); + private _setLinkElementAttributes(link: LinkDefinition, el: HTMLLinkElement): HTMLLinkElement { + Object.keys(link).forEach((prop: string) => el.setAttribute(prop, link[prop])); return el; } private _parseSelector(link: LinkDefinition): string { - const attr: string = link.rel ? "rel" : "property"; + const attr: string = link.rel ? 'rel' : 'property'; return `${attr}="${link[attr]}"`; } - private _containsAttributes( - link: LinkDefinition, - elem: HTMLLinkElement - ): boolean { - return Object.keys(link).every( - (key: string) => elem.getAttribute(key) === link[key] - ); + private _containsAttributes(link: LinkDefinition, elem: HTMLLinkElement): boolean { + return Object.keys(link).every((key: string) => elem.getAttribute(key) === link[key]); } } diff --git a/packages/platform-browser/src/browser/meta.ts b/packages/platform-browser/src/browser/meta.ts index c3e64936da66..0962e4656ce3 100644 --- a/packages/platform-browser/src/browser/meta.ts +++ b/packages/platform-browser/src/browser/meta.ts @@ -6,12 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import { - DOCUMENT, - ɵDomAdapter as DomAdapter, - ɵgetDOM as getDOM -} from "@angular/common"; -import { Inject, Injectable, ɵɵinject } from "@angular/core"; +import {DOCUMENT, ɵDomAdapter as DomAdapter, ɵgetDOM as getDOM} from '@angular/common'; +import {Inject, Injectable, ɵɵinject} from '@angular/core'; /** * Represents a meta element. @@ -19,16 +15,13 @@ import { Inject, Injectable, ɵɵinject } from "@angular/core"; * @publicApi */ export type MetaDefinition = { - charset?: string; - content?: string; - httpEquiv?: string; - id?: string; - itemprop?: string; + charset?: string; content?: string; httpEquiv?: string; id?: string; itemprop?: string; name?: string; property?: string; scheme?: string; url?: string; -} & { +} & +{ // TODO(IgorMinar): this type looks wrong [prop: string]: string; }; @@ -45,25 +38,17 @@ export function createMeta() { * * @publicApi */ -@Injectable({ providedIn: "root", useFactory: createMeta, deps: [] }) +@Injectable({providedIn: 'root', useFactory: createMeta, deps: []}) export class Meta { private _dom: DomAdapter; - constructor(@Inject(DOCUMENT) private _doc: any) { - this._dom = getDOM(); - } + constructor(@Inject(DOCUMENT) private _doc: any) { this._dom = getDOM(); } - addTag( - tag: MetaDefinition, - forceCreation: boolean = false - ): HTMLMetaElement | null { + addTag(tag: MetaDefinition, forceCreation: boolean = false): HTMLMetaElement|null { if (!tag) return null; return this._getOrCreateElement(tag, forceCreation); } - addTags( - tags: MetaDefinition[], - forceCreation: boolean = false - ): HTMLMetaElement[] { + addTags(tags: MetaDefinition[], forceCreation: boolean = false): HTMLMetaElement[] { if (!tags) return []; return tags.reduce((result: HTMLMetaElement[], tag: MetaDefinition) => { if (tag) { @@ -73,32 +58,28 @@ export class Meta { }, []); } - getTag(attrSelector: string): HTMLMetaElement | null { + getTag(attrSelector: string): HTMLMetaElement|null { if (!attrSelector) return null; return this._doc.querySelector(`meta[${attrSelector}]`) || null; } getTags(attrSelector: string): HTMLMetaElement[] { if (!attrSelector) return []; - const list /*NodeList*/ = this._doc.querySelectorAll( - `meta[${attrSelector}]` - ); + const list /*NodeList*/ = this._doc.querySelectorAll(`meta[${attrSelector}]`); return list ? [].slice.call(list) : []; } - updateTag(tag: MetaDefinition, selector?: string): HTMLMetaElement | null { + updateTag(tag: MetaDefinition, selector?: string): HTMLMetaElement|null { if (!tag) return null; selector = selector || this._parseSelector(tag); - const meta: HTMLMetaElement = this.getTag(selector)!; + const meta: HTMLMetaElement = this.getTag(selector) !; if (meta) { return this._setMetaElementAttributes(tag, meta); } return this._getOrCreateElement(tag, true); } - removeTag(attrSelector: string): void { - this.removeTagElement(this.getTag(attrSelector)!); - } + removeTag(attrSelector: string): void { this.removeTagElement(this.getTag(attrSelector) !); } removeTagElement(meta: HTMLMetaElement): void { if (meta) { @@ -106,48 +87,34 @@ export class Meta { } } - private _getOrCreateElement( - meta: MetaDefinition, - forceCreation: boolean = false - ): HTMLMetaElement { + private _getOrCreateElement(meta: MetaDefinition, forceCreation: boolean = false): + HTMLMetaElement { if (!forceCreation) { const selector: string = this._parseSelector(meta); - const elem: HTMLMetaElement = this.getTag(selector)!; + const elem: HTMLMetaElement = this.getTag(selector) !; // It's allowed to have multiple elements with the same name so it's not enough to // just check that element with the same name already present on the page. We also need to // check if element has tag attributes if (elem && this._containsAttributes(meta, elem)) return elem; } - const element: HTMLMetaElement = this._dom.createElement( - "meta" - ) as HTMLMetaElement; + const element: HTMLMetaElement = this._dom.createElement('meta') as HTMLMetaElement; this._setMetaElementAttributes(meta, element); - const head = this._doc.getElementsByTagName("head")[0]; + const head = this._doc.getElementsByTagName('head')[0]; head.appendChild(element); return element; } - private _setMetaElementAttributes( - tag: MetaDefinition, - el: HTMLMetaElement - ): HTMLMetaElement { - Object.keys(tag).forEach((prop: string) => - el.setAttribute(prop, tag[prop]) - ); + private _setMetaElementAttributes(tag: MetaDefinition, el: HTMLMetaElement): HTMLMetaElement { + Object.keys(tag).forEach((prop: string) => el.setAttribute(prop, tag[prop])); return el; } private _parseSelector(tag: MetaDefinition): string { - const attr: string = tag.name ? "name" : "property"; + const attr: string = tag.name ? 'name' : 'property'; return `${attr}="${tag[attr]}"`; } - private _containsAttributes( - tag: MetaDefinition, - elem: HTMLMetaElement - ): boolean { - return Object.keys(tag).every( - (key: string) => elem.getAttribute(key) === tag[key] - ); + private _containsAttributes(tag: MetaDefinition, elem: HTMLMetaElement): boolean { + return Object.keys(tag).every((key: string) => elem.getAttribute(key) === tag[key]); } } diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index 945f8ebc3750..ee025649b9af 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -6,41 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ -export { BrowserModule, platformBrowser } from "./browser"; -export { Meta, MetaDefinition } from "./browser/meta"; -export { Link, LinkDefinition } from "./browser/link"; -export { Title } from "./browser/title"; -export { disableDebugTools, enableDebugTools } from "./browser/tools/tools"; -export { - BrowserTransferStateModule, - StateKey, - TransferState, - makeStateKey -} from "./browser/transfer_state"; -export { By } from "./dom/debug/by"; -export { - EVENT_MANAGER_PLUGINS, - EventManager -} from "./dom/events/event_manager"; -export { - HAMMER_GESTURE_CONFIG, - HAMMER_LOADER, - HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, - HammerGestureConfig, - HammerLoader, - HammerModule -} from "./dom/events/hammer_gestures"; -export { - DomSanitizer, - SafeHtml, - SafeResourceUrl, - SafeScript, - SafeStyle, - SafeUrl, - SafeValue -} from "./security/dom_sanitization_service"; +export {BrowserModule, platformBrowser} from './browser'; +export {Link, LinkDefinition} from './browser/link'; +export {Meta, MetaDefinition} from './browser/meta'; +export {Title} from './browser/title'; +export {disableDebugTools, enableDebugTools} from './browser/tools/tools'; +export {BrowserTransferStateModule, StateKey, TransferState, makeStateKey} from './browser/transfer_state'; +export {By} from './dom/debug/by'; +export {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; +export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, HammerGestureConfig, HammerLoader, HammerModule} from './dom/events/hammer_gestures'; +export {DomSanitizer, SafeHtml, SafeResourceUrl, SafeScript, SafeStyle, SafeUrl, SafeValue} from './security/dom_sanitization_service'; -export * from "./private_export"; -export { VERSION } from "./version"; +export * from './private_export'; +export {VERSION} from './version'; // This must be exported so it doesn't get tree-shaken away prematurely -export { ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__ } from "./dom/debug/ng_probe"; +export {ELEMENT_PROBE_PROVIDERS__POST_R3__ as ɵELEMENT_PROBE_PROVIDERS__POST_R3__} from './dom/debug/ng_probe'; diff --git a/packages/platform-browser/test/browser/link_spec.ts b/packages/platform-browser/test/browser/link_spec.ts index 3515efd61c0a..0ca10f98c679 100644 --- a/packages/platform-browser/test/browser/link_spec.ts +++ b/packages/platform-browser/test/browser/link_spec.ts @@ -132,10 +132,8 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; expect(linkService.getLink(nameSelector)).toBeNull(); expect(linkService.getLink(propertySelector)).toBeNull(); - linkService.addLinks([ - {rel: 'canonical', href: 'http://foo.bar'}, - {rel: 'author', href: 'http://bar.baz'} - ]); + linkService.addLinks( + [{rel: 'canonical', href: 'http://foo.bar'}, {rel: 'author', href: 'http://bar.baz'}]); const canonicalLink = linkService.getLink(nameSelector) !; const authorLink = linkService.getLink(propertySelector) !; expect(canonicalLink).not.toBeNull(); @@ -182,17 +180,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); describe('integration test', () => { - @Injectable() class DependsOnLink { constructor(public link: Link) {} } beforeEach(() => { - TestBed.configureTestingModule({ - imports: [BrowserModule], - providers: [DependsOnLink], - }); + TestBed.configureTestingModule({imports: [BrowserModule], providers: [DependsOnLink]}); }); it('should inject Link service when using BrowserModule', diff --git a/packages/platform-browser/test/browser/meta_spec.ts b/packages/platform-browser/test/browser/meta_spec.ts index 41d59fcd3df9..d20885260035 100644 --- a/packages/platform-browser/test/browser/meta_spec.ts +++ b/packages/platform-browser/test/browser/meta_spec.ts @@ -179,21 +179,16 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; // clean up metaService.removeTagElement(meta); }); - }); describe('integration test', () => { - @Injectable() class DependsOnMeta { constructor(public meta: Meta) {} } beforeEach(() => { - TestBed.configureTestingModule({ - imports: [BrowserModule], - providers: [DependsOnMeta], - }); + TestBed.configureTestingModule({imports: [BrowserModule], providers: [DependsOnMeta]}); }); it('should inject Meta service when using BrowserModule', From ff7a2d07c2fc957e4a5c4b9e9b381d30f72bec09 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 12:34:21 +0100 Subject: [PATCH 04/10] test(platform-browser): fix tests for `Link` service --- packages/platform-browser/test/browser/link_spec.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/platform-browser/test/browser/link_spec.ts b/packages/platform-browser/test/browser/link_spec.ts index 0ca10f98c679..ca0b348c48d2 100644 --- a/packages/platform-browser/test/browser/link_spec.ts +++ b/packages/platform-browser/test/browser/link_spec.ts @@ -92,7 +92,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; it('should extract selector from the tag definition', () => { const selector = 'rel="stylesheet"'; - linkService.updateLink({property: 'stylesheet', href: 'http://foo.bar'}); + linkService.updateLink({rel: 'stylesheet', href: 'http://foo.bar'}); const actual = linkService.getLink(selector); expect(actual).not.toBeNull(); @@ -127,13 +127,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); it('should add multiple new link tags', () => { - const nameSelector = 'rel="canonical"'; + const nameSelector = 'rel="stylesheet"'; const propertySelector = 'rel="author"'; expect(linkService.getLink(nameSelector)).toBeNull(); expect(linkService.getLink(propertySelector)).toBeNull(); linkService.addLinks( - [{rel: 'canonical', href: 'http://foo.bar'}, {rel: 'author', href: 'http://bar.baz'}]); + [{rel: 'stylesheet', href: 'http://foo.bar'}, {rel: 'author', href: 'http://bar.baz'}]); const canonicalLink = linkService.getLink(nameSelector) !; const authorLink = linkService.getLink(propertySelector) !; expect(canonicalLink).not.toBeNull(); @@ -148,8 +148,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const selector = 'rel="canonical"'; expect(linkService.getLinks(selector).length).toEqual(1); - linkService.addLink({rel: 'canonical', href: 'http://example.com'}); - + linkService.addLink({rel: 'canonical', href: 'https://example.com'}); expect(linkService.getLinks(selector).length).toEqual(1); }); From c22c6744a7c6502ffa74dcda69da668d82fa6c9f Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 12:37:18 +0100 Subject: [PATCH 05/10] fix(platform-browser): fix `_parseSelector` implementation --- packages/platform-browser/src/browser/link.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platform-browser/src/browser/link.ts b/packages/platform-browser/src/browser/link.ts index 71aae8f35d37..01e6eefc7a4a 100644 --- a/packages/platform-browser/src/browser/link.ts +++ b/packages/platform-browser/src/browser/link.ts @@ -113,7 +113,7 @@ export class Link { } private _parseSelector(link: LinkDefinition): string { - const attr: string = link.rel ? 'rel' : 'property'; + const attr: string = link.rel ? 'rel' : 'href'; return `${attr}="${link[attr]}"`; } From 48984cf15ed722bccb69e03ff0e8b68b0f8162d5 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 13:22:21 +0100 Subject: [PATCH 06/10] test(platform-browser): replace 'meta' with 'link' in test --- .../platform-browser/test/browser/link_spec.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/platform-browser/test/browser/link_spec.ts b/packages/platform-browser/test/browser/link_spec.ts index ca0b348c48d2..f5151fbafa08 100644 --- a/packages/platform-browser/test/browser/link_spec.ts +++ b/packages/platform-browser/test/browser/link_spec.ts @@ -144,7 +144,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; linkService.removeLinkElement(authorLink); }); - it('should not add meta tag if it is already present on the page and has the same attr', () => { + it('should not add link tag if it is already present on the page and has the same attr', () => { const selector = 'rel="canonical"'; expect(linkService.getLinks(selector).length).toEqual(1); @@ -152,29 +152,29 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; expect(linkService.getLinks(selector).length).toEqual(1); }); - it('should add meta tag if it is already present on the page and but has different attr', + it('should add link tag if it is already present on the page and but has different attr', () => { const selector = 'rel="canonical"'; expect(linkService.getLinks(selector).length).toEqual(1); - const meta = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}) !; + const link = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}) !; expect(linkService.getLinks(selector).length).toEqual(2); // clean up - linkService.removeLinkElement(meta); + linkService.removeLinkElement(link); }); - it('should add meta tag if it is already present on the page and force true', () => { + it('should add link tag if it is already present on the page and force true', () => { const selector = 'rel="canonical"'; expect(linkService.getLinks(selector).length).toEqual(1); - const meta = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}, true) !; + const link = linkService.addLink({rel: 'canonical', href: 'http://bar.baz'}, true) !; expect(linkService.getLinks(selector).length).toEqual(2); // clean up - linkService.removeLinkElement(meta); + linkService.removeLinkElement(link); }); }); From 4400de4ea72ae8b3534ac7e6c552bd11a92004cd Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 1 Jan 2020 13:33:18 +0100 Subject: [PATCH 07/10] refactor(platform-browser): update default LinkDefinition props see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link --- packages/platform-browser/src/browser/link.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/platform-browser/src/browser/link.ts b/packages/platform-browser/src/browser/link.ts index 01e6eefc7a4a..e9cc77ca7ca2 100644 --- a/packages/platform-browser/src/browser/link.ts +++ b/packages/platform-browser/src/browser/link.ts @@ -15,14 +15,19 @@ import {Inject, Injectable, ɵɵinject} from '@angular/core'; * @publicApi */ export type LinkDefinition = { - charset?: string; crossorigin?: 'anonymous' | 'use-credentials'; disabled?: boolean; - href?: string; + as?: string; crossorigin?: 'anonymous' | 'use-credentials'; disabled?: boolean; href?: string; hreflang?: string; + importance?: 'auto' | 'high' | 'low'; + integrity?: string; media?: string; methods?: string; + prefetch?: string; + referrerpolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | + 'origin-when-cross-origin' | 'unsafe-url'; rel?: string; sizes?: string; target?: string; + title?: string; type?: string; } & { From 5c3e11ee4fe857757baa6e9c215d946867e4ff68 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 15 Jan 2020 07:34:26 +0100 Subject: [PATCH 08/10] fix(platform-browser): add missing Link and LinkDefinition to .d.ts --- .angulardoc.json | 4 ++ .../platform-browser/platform-browser.d.ts | 37 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 .angulardoc.json diff --git a/.angulardoc.json b/.angulardoc.json new file mode 100644 index 000000000000..893827dc19f3 --- /dev/null +++ b/.angulardoc.json @@ -0,0 +1,4 @@ +{ + "repoId": "7d495bf4-f0d2-460a-a96d-cff3c2c9d0ce", + "lastSync": 0 +} \ No newline at end of file diff --git a/tools/public_api_guard/platform-browser/platform-browser.d.ts b/tools/public_api_guard/platform-browser/platform-browser.d.ts index 7817c149ac1c..3d55862d12f9 100644 --- a/tools/public_api_guard/platform-browser/platform-browser.d.ts +++ b/tools/public_api_guard/platform-browser/platform-browser.d.ts @@ -65,6 +65,43 @@ export declare class HammerModule { export declare function makeStateKey(key: string): StateKey; +export declare class Link { + constructor(_doc: any); + addLink(tag: LinkDefinition, forceCreation?: boolean): HTMLLinkElement | null; + addLinks(tags: LinkDefinition[], forceCreation?: boolean): HTMLLinkElement[]; + getLink(attrSelector: string): HTMLLinkElement | null; + getLinks(attrSelector: string): HTMLLinkElement[]; + removeLink(attrSelector: string): void; + removeLinkElement(meta: HTMLLinkElement): void; + updateLink(tag: LinkDefinition, selector?: string): HTMLLinkElement | null; +} + +export declare type LinkDefinition = { + as?: string; + crossorigin?: "anonymous" | "use-credentials"; + disabled?: boolean; + href?: string; + hreflang?: string; + importance?: "auto" | "high" | "low"; + integrity?: string; + media?: string; + methods?: string; + prefetch?: string; + referrerpolicy?: + | "no-referrer" + | "no-referrer-when-downgrade" + | "origin" + | "origin-when-cross-origin" + | "unsafe-url"; + rel?: string; + sizes?: string; + target?: string; + title?: string; + type?: string; +} & { + [prop: string]: string; +}; + export declare class Meta { constructor(_doc: any); addTag(tag: MetaDefinition, forceCreation?: boolean): HTMLMetaElement | null; From 55fe8e349ffeb7be6f0d8dbff2b6cac93d4041c1 Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Wed, 15 Jan 2020 07:36:04 +0100 Subject: [PATCH 09/10] fix(platform-browser): remove .angulardoc.json file --- .angulardoc.json | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .angulardoc.json diff --git a/.angulardoc.json b/.angulardoc.json deleted file mode 100644 index 893827dc19f3..000000000000 --- a/.angulardoc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "repoId": "7d495bf4-f0d2-460a-a96d-cff3c2c9d0ce", - "lastSync": 0 -} \ No newline at end of file From ac43446418f6907cfcac0287e8aa746402ca1e7c Mon Sep 17 00:00:00 2001 From: Danny Koppenhagen Date: Fri, 28 Feb 2020 07:41:03 +0100 Subject: [PATCH 10/10] fix: accept public api change ...by running `yarn bazel run //tools/public_api_guard:platform-browser_api.accept` --- .../platform-browser/platform-browser.d.ts | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/tools/public_api_guard/platform-browser/platform-browser.d.ts b/tools/public_api_guard/platform-browser/platform-browser.d.ts index 3d55862d12f9..50ad955c6bc9 100644 --- a/tools/public_api_guard/platform-browser/platform-browser.d.ts +++ b/tools/public_api_guard/platform-browser/platform-browser.d.ts @@ -63,36 +63,29 @@ export declare type HammerLoader = () => Promise; export declare class HammerModule { } -export declare function makeStateKey(key: string): StateKey; - export declare class Link { constructor(_doc: any); - addLink(tag: LinkDefinition, forceCreation?: boolean): HTMLLinkElement | null; - addLinks(tags: LinkDefinition[], forceCreation?: boolean): HTMLLinkElement[]; + addLink(link: LinkDefinition, forceCreation?: boolean): HTMLLinkElement | null; + addLinks(links: LinkDefinition[], forceCreation?: boolean): HTMLLinkElement[]; getLink(attrSelector: string): HTMLLinkElement | null; getLinks(attrSelector: string): HTMLLinkElement[]; removeLink(attrSelector: string): void; - removeLinkElement(meta: HTMLLinkElement): void; - updateLink(tag: LinkDefinition, selector?: string): HTMLLinkElement | null; + removeLinkElement(link: HTMLLinkElement): void; + updateLink(link: LinkDefinition, selector?: string): HTMLLinkElement | null; } export declare type LinkDefinition = { as?: string; - crossorigin?: "anonymous" | "use-credentials"; + crossorigin?: 'anonymous' | 'use-credentials'; disabled?: boolean; href?: string; hreflang?: string; - importance?: "auto" | "high" | "low"; + importance?: 'auto' | 'high' | 'low'; integrity?: string; media?: string; methods?: string; prefetch?: string; - referrerpolicy?: - | "no-referrer" - | "no-referrer-when-downgrade" - | "origin" - | "origin-when-cross-origin" - | "unsafe-url"; + referrerpolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'unsafe-url'; rel?: string; sizes?: string; target?: string; @@ -102,6 +95,8 @@ export declare type LinkDefinition = { [prop: string]: string; }; +export declare function makeStateKey(key: string): StateKey; + export declare class Meta { constructor(_doc: any); addTag(tag: MetaDefinition, forceCreation?: boolean): HTMLMetaElement | null;