diff --git a/src/lib/icon/fake-svgs.ts b/src/lib/icon/fake-svgs.ts index ae075cd5d70a..eca391690067 100644 --- a/src/lib/icon/fake-svgs.ts +++ b/src/lib/icon/fake-svgs.ts @@ -1,6 +1,4 @@ -import { - Response, - ResponseOptions} from '@angular/http'; +import {Response, ResponseOptions} from '@angular/http'; /** * Fake URLs and associated SVG documents used by tests. diff --git a/src/lib/icon/icon-errors.ts b/src/lib/icon/icon-errors.ts new file mode 100644 index 000000000000..96550575528e --- /dev/null +++ b/src/lib/icon/icon-errors.ts @@ -0,0 +1,43 @@ +import {MdError} from '../core'; + +/** + * Exception thrown when attempting to load an icon with a name that cannot be found. + * @docs-private + */ +export class MdIconNameNotFoundError extends MdError { + constructor(iconName: string) { + super(`Unable to find icon with the name "${iconName}"`); + } +} + +/** + * Exception thrown when attempting to load SVG content that does not contain the expected + * tag. + * @docs-private + */ +export class MdIconSvgTagNotFoundError extends MdError { + constructor() { + super(' tag not found'); + } +} + +/** + * Exception thrown when the consumer attempts to use `` without including @angular/http. + * @docs-private + */ +export class MdIconNoHttpProviderError extends MdError { + constructor() { + super('Could not find Http provider for use with Angular Material icons. ' + + 'Please include the HttpModule from @angular/http in your app imports.'); + } +} + +/** + * Exception thrown when an invalid icon name is passed to an md-icon component. + * @docs-private + */ +export class MdIconInvalidNameError extends MdError { + constructor(iconName: string) { + super(`Invalid icon name: "${iconName}"`); + } +} diff --git a/src/lib/icon/icon-registry.ts b/src/lib/icon/icon-registry.ts index a10e93b04ec7..9f6da9a6d96c 100644 --- a/src/lib/icon/icon-registry.ts +++ b/src/lib/icon/icon-registry.ts @@ -1,8 +1,12 @@ -import {Injectable, SecurityContext} from '@angular/core'; +import {Injectable, SecurityContext, Optional, SkipSelf} from '@angular/core'; import {SafeResourceUrl, DomSanitizer} from '@angular/platform-browser'; import {Http} from '@angular/http'; -import {MdError} from '../core'; import {Observable} from 'rxjs/Observable'; +import { + MdIconNameNotFoundError, + MdIconSvgTagNotFoundError, + MdIconNoHttpProviderError, +} from './icon-errors'; import 'rxjs/add/observable/forkJoin'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/map'; @@ -14,27 +18,6 @@ import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; -/** - * Exception thrown when attempting to load an icon with a name that cannot be found. - * @docs-private - */ -export class MdIconNameNotFoundError extends MdError { - constructor(iconName: string) { - super(`Unable to find icon with the name "${iconName}"`); - } -} - -/** - * Exception thrown when attempting to load SVG content that does not contain the expected - * tag. - * @docs-private - */ -export class MdIconSvgTagNotFoundError extends MdError { - constructor() { - super(' tag not found'); - } -} - /** * Configuration for an icon, including the URL and possibly the cached SVG element. * @docs-private @@ -44,9 +27,6 @@ class SvgIconConfig { constructor(public url: SafeResourceUrl) { } } -/** Returns the cache key to use for an icon namespace and name. */ -const iconKey = (namespace: string, name: string) => namespace + ':' + name; - /** * Service to register and display icons used by the component. * - Registers icon URLs by namespace and name. @@ -83,7 +63,7 @@ export class MdIconRegistry { */ private _defaultFontSetClass = 'material-icons'; - constructor(private _http: Http, private _sanitizer: DomSanitizer) {} + constructor(@Optional() private _http: Http, private _sanitizer: DomSanitizer) {} /** * Registers an icon by URL in the default namespace. @@ -386,7 +366,11 @@ export class MdIconRegistry { * cached, so future calls with the same URL may not cause another HTTP request. */ private _fetchUrl(safeUrl: SafeResourceUrl): Observable { - let url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl); + if (!this._http) { + throw new MdIconNoHttpProviderError(); + } + + const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl); // Store in-progress fetches to avoid sending a duplicate request for a URL when there is // already a request in progress for that URL. It's necessary to call share() on the @@ -408,8 +392,24 @@ export class MdIconRegistry { } } +export function ICON_REGISTRY_PROVIDER_FACTORY( + parentRegistry: MdIconRegistry, http: Http, sanitizer: DomSanitizer) { + return parentRegistry || new MdIconRegistry(http, sanitizer); +} + +export const ICON_REGISTRY_PROVIDER = { + // If there is already an MdIconRegistry available, use that. Otherwise, provide a new one. + provide: MdIconRegistry, + deps: [[new Optional(), new SkipSelf(), MdIconRegistry], [new Optional(), Http], DomSanitizer], + useFactory: ICON_REGISTRY_PROVIDER_FACTORY +}; /** Clones an SVGElement while preserving type information. */ function cloneSvg(svg: SVGElement): SVGElement { return svg.cloneNode(true) as SVGElement; } + +/** Returns the cache key to use for an icon namespace and name. */ +function iconKey(namespace: string, name: string) { + return namespace + ':' + name; +} diff --git a/src/lib/icon/icon.spec.ts b/src/lib/icon/icon.spec.ts index 178b40ff2c69..ab2d3e89375e 100644 --- a/src/lib/icon/icon.spec.ts +++ b/src/lib/icon/icon.spec.ts @@ -1,10 +1,11 @@ import {inject, async, TestBed} from '@angular/core/testing'; import {SafeResourceUrl, DomSanitizer} from '@angular/platform-browser'; -import {XHRBackend} from '@angular/http'; +import {HttpModule, XHRBackend} from '@angular/http'; import {MockBackend} from '@angular/http/testing'; import {Component} from '@angular/core'; import {MdIconModule} from './index'; import {MdIconRegistry} from './icon-registry'; +import {MdIconNoHttpProviderError} from './icon-errors'; import {getFakeSvgHttpResponse} from './fake-svgs'; @@ -36,7 +37,7 @@ describe('MdIcon', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [MdIconModule], + imports: [HttpModule, MdIconModule], declarations: [ MdIconColorTestApp, MdIconLigatureTestApp, @@ -394,6 +395,37 @@ describe('MdIcon', () => { }); +describe('MdIcon without HttpModule', () => { + let mdIconRegistry: MdIconRegistry; + let sanitizer: DomSanitizer; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MdIconModule.forRoot()], + declarations: [MdIconFromSvgNameTestApp], + }); + + TestBed.compileComponents(); + })); + + beforeEach(inject([MdIconRegistry, DomSanitizer], (mir: MdIconRegistry, ds: DomSanitizer) => { + mdIconRegistry = mir; + sanitizer = ds; + })); + + it('should throw an error when trying to load a remote icon', async() => { + expect(() => { + mdIconRegistry.addSvgIcon('fido', sanitizer.bypassSecurityTrustResourceUrl('dog.svg')); + + let fixture = TestBed.createComponent(MdIconFromSvgNameTestApp); + + fixture.componentInstance.iconName = 'fido'; + fixture.detectChanges(); + }).toThrowError(MdIconNoHttpProviderError); + }); +}); + + /** Test components that contain an MdIcon. */ @Component({template: `{{iconName}}`}) class MdIconLigatureTestApp { diff --git a/src/lib/icon/icon.ts b/src/lib/icon/icon.ts index 7b4522632329..3f7e1347bf2a 100644 --- a/src/lib/icon/icon.ts +++ b/src/lib/icon/icon.ts @@ -9,20 +9,10 @@ import { SimpleChange, ViewEncapsulation, AfterViewChecked, - Optional, - SkipSelf, } from '@angular/core'; -import {Http} from '@angular/http'; -import {DomSanitizer} from '@angular/platform-browser'; -import {MdError} from '../core'; -import {MdIconRegistry, MdIconNameNotFoundError} from './icon-registry'; +import {MdIconRegistry} from './icon-registry'; +import {MdIconNameNotFoundError, MdIconInvalidNameError} from './icon-errors'; -/** Exception thrown when an invalid icon name is passed to an md-icon component. */ -export class MdIconInvalidNameError extends MdError { - constructor(iconName: string) { - super(`Invalid icon name: "${iconName}"`); - } -} /** * Component to display an icon. It can be used in the following ways: @@ -250,15 +240,3 @@ export class MdIcon implements OnChanges, OnInit, AfterViewChecked { } } } - -export function ICON_REGISTRY_PROVIDER_FACTORY( - parentRegistry: MdIconRegistry, http: Http, sanitizer: DomSanitizer) { - return parentRegistry || new MdIconRegistry(http, sanitizer); -} - -export const ICON_REGISTRY_PROVIDER = { - // If there is already an MdIconRegistry available, use that. Otherwise, provide a new one. - provide: MdIconRegistry, - deps: [[new Optional(), new SkipSelf(), MdIconRegistry], Http, DomSanitizer], - useFactory: ICON_REGISTRY_PROVIDER_FACTORY, -}; diff --git a/src/lib/icon/index.ts b/src/lib/icon/index.ts index 16217e94a3a7..c26f97c64428 100644 --- a/src/lib/icon/index.ts +++ b/src/lib/icon/index.ts @@ -1,11 +1,11 @@ import {NgModule} from '@angular/core'; -import {HttpModule} from '@angular/http'; import {MdCommonModule} from '../core'; -import {MdIcon, ICON_REGISTRY_PROVIDER} from './icon'; +import {MdIcon} from './icon'; +import {ICON_REGISTRY_PROVIDER} from './icon-registry'; @NgModule({ - imports: [HttpModule, MdCommonModule], + imports: [MdCommonModule], exports: [MdIcon, MdCommonModule], declarations: [MdIcon], providers: [ICON_REGISTRY_PROVIDER], @@ -14,4 +14,5 @@ export class MdIconModule {} export * from './icon'; -export {MdIconRegistry} from './icon-registry'; +export * from './icon-errors'; +export * from './icon-registry'; diff --git a/src/lib/package.json b/src/lib/package.json index 4f9f0db55c0a..885abbc6218a 100644 --- a/src/lib/package.json +++ b/src/lib/package.json @@ -23,7 +23,6 @@ "homepage": "https://github.com/angular/material2#readme", "peerDependencies": { "@angular/core": "^4.0.0", - "@angular/common": "^4.0.0", - "@angular/http": "^4.0.0" + "@angular/common": "^4.0.0" } }