refactor(core): move DomAdapter style methods to ServerRenderer (#32408)

PR Close #32408
This commit is contained in:
Kara Erickson 2019-08-30 10:16:20 -07:00 committed by Miško Hevery
parent 970b58b13f
commit c207ad80fd
10 changed files with 46 additions and 100 deletions

View File

@ -50,11 +50,6 @@ export abstract class DomAdapter {
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;
// Used by Title
abstract getTitle(doc: Document): string;
abstract setTitle(doc: Document, newTitle: string): any;

View File

@ -36,27 +36,6 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util';
expect(() => getDOM().remove(d)).not.toThrow();
});
it('should parse styles with urls correctly', () => {
const d = getDOM().createElement('div');
getDOM().setStyle(d, 'background-url', 'url(http://test.com/bg.jpg)');
expect(getDOM().getStyle(d, 'background-url')).toBe('url(http://test.com/bg.jpg)');
});
// Test for regression caused by angular/angular#22536
it('should parse styles correctly following the spec', () => {
const d = getDOM().createElement('div');
getDOM().setStyle(d, 'background-image', 'url("paper.gif")');
expect(d.style.backgroundImage).toBe('url("paper.gif")');
expect(d.style.getPropertyValue('background-image')).toBe('url("paper.gif")');
expect(getDOM().getStyle(d, 'background-image')).toBe('url("paper.gif")');
});
it('should parse camel-case styles correctly', () => {
const d = getDOM().createElement('div');
getDOM().setStyle(d, 'marginRight', '10px');
expect(getDOM().getStyle(d, 'margin-right')).toBe('10px');
});
if (getDOM().supportsDOMEvents()) {
describe('getBaseHref', () => {
beforeEach(() => getDOM().resetBaseElement());

View File

@ -147,13 +147,11 @@ function declareTests(config?: {useJit: boolean}) {
fixture.componentInstance.ctxProp = '10';
fixture.detectChanges();
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
.toEqual('10px');
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('10px');
fixture.componentInstance.ctxProp = null !;
fixture.detectChanges();
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
.toEqual('');
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('');
});
it('should consume binding to property names where attr name and property name do not match',

View File

@ -247,12 +247,12 @@ function declareTests(config?: {useJit: boolean}) {
fixture.detectChanges();
// In some browsers, this will contain the full background specification, not just
// the color.
expect(getDOM().getStyle(e, 'background')).toMatch(/red.*/);
expect(e.style['background']).toMatch(/red.*/);
ci.ctxProp = 'url(javascript:evil())';
fixture.detectChanges();
// Updated value gets rejected, no value change.
expect(getDOM().getStyle(e, 'background')).not.toContain('javascript');
expect(e.style['background']).not.toContain('javascript');
});
modifiedInIvy('Unknown property error thrown during update mode, not creation mode')

View File

@ -164,8 +164,8 @@ const removeEventListener = '__zone_symbol__removeEventListener' as 'removeEvent
Services.checkAndUpdateView(view);
const el = rootNodes[0];
expect(getDOM().getStyle(el, 'width')).toBe('10px');
expect(getDOM().getStyle(el, 'color')).toBe('red');
expect(el.style['width']).toBe('10px');
expect(el.style['color']).toBe('red');
});
});
});

View File

@ -119,16 +119,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
getElementsByTagName(element: any, name: string): HTMLElement[] {
return element.getElementsByTagName(name);
}
setStyle(element: any, styleName: string, styleValue: string) {
element.style[styleName] = styleValue;
}
removeStyle(element: any, stylename: string) {
// IE requires '' instead of null
// see https://github.com/angular/angular/issues/7916
element.style[stylename] = '';
}
getStyle(element: any, stylename: string): string { return element.style[stylename]; }
getAttribute(element: Element, attribute: string): string|null {
return element.getAttribute(attribute);

View File

@ -109,55 +109,6 @@ export class DominoAdapter extends BrowserDomAdapter {
return href;
}
/** @internal */
_readStyleAttribute(element: any): {[name: string]: string} {
const styleMap: {[name: string]: string} = {};
const styleAttribute = element.getAttribute('style');
if (styleAttribute) {
const styleList = styleAttribute.split(/;+/g);
for (let i = 0; i < styleList.length; i++) {
const style = styleList[i].trim();
if (style.length > 0) {
const colonIndex = style.indexOf(':');
if (colonIndex === -1) {
throw new Error(`Invalid CSS style: ${style}`);
}
const name = style.substr(0, colonIndex).trim();
styleMap[name] = style.substr(colonIndex + 1).trim();
}
}
}
return styleMap;
}
/** @internal */
_writeStyleAttribute(element: any, styleMap: {[name: string]: string}) {
let styleAttrValue = '';
for (const key in styleMap) {
const newValue = styleMap[key];
if (newValue) {
styleAttrValue += key + ':' + styleMap[key] + ';';
}
}
element.setAttribute('style', styleAttrValue);
}
setStyle(element: any, styleName: string, styleValue?: string|null) {
styleName = styleName.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
const styleMap = this._readStyleAttribute(element);
styleMap[styleName] = styleValue || '';
this._writeStyleAttribute(element, styleMap);
}
removeStyle(element: any, styleName: string) {
// IE requires '' instead of null
// see https://github.com/angular/angular/issues/7916
this.setStyle(element, styleName, '');
}
getStyle(element: any, styleName: string): string {
const styleMap = this._readStyleAttribute(element);
return styleMap[styleName] || '';
}
dispatchEvent(el: Node, evt: any) {
el.dispatchEvent(evt);

View File

@ -143,11 +143,16 @@ class DefaultServerRenderer2 implements Renderer2 {
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);
style = style.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
const styleMap = _readStyleAttribute(el);
styleMap[style] = value || '';
_writeStyleAttribute(el, styleMap);
}
removeStyle(el: any, style: string, flags: RendererStyleFlags2): void {
getDOM().removeStyle(el, style);
// IE requires '' instead of null
// see https://github.com/angular/angular/issues/7916
this.setStyle(el, style, '', flags);
}
// The value was validated already as a property binding, against the property name.
@ -246,3 +251,34 @@ class EmulatedEncapsulationServerRenderer2 extends DefaultServerRenderer2 {
return el;
}
}
function _readStyleAttribute(element: any): {[name: string]: string} {
const styleMap: {[name: string]: string} = {};
const styleAttribute = element.getAttribute('style');
if (styleAttribute) {
const styleList = styleAttribute.split(/;+/g);
for (let i = 0; i < styleList.length; i++) {
const style = styleList[i].trim();
if (style.length > 0) {
const colonIndex = style.indexOf(':');
if (colonIndex === -1) {
throw new Error(`Invalid CSS style: ${style}`);
}
const name = style.substr(0, colonIndex).trim();
styleMap[name] = style.substr(colonIndex + 1).trim();
}
}
}
return styleMap;
}
function _writeStyleAttribute(element: any, styleMap: {[name: string]: string}) {
let styleAttrValue = '';
for (const key in styleMap) {
const newValue = styleMap[key];
if (newValue) {
styleAttrValue += key + ':' + styleMap[key] + ';';
}
}
element.setAttribute('style', styleAttrValue);
}

View File

@ -53,9 +53,6 @@ export class WorkerDomAdapter extends DomAdapter {
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'; }
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'; }
createHtmlDocument(): HTMLDocument { throw 'not implemented'; }

View File

@ -115,10 +115,10 @@ let lastCreatedRenderer: Renderer2;
expect(hasClass(el, 'a')).toBe(false);
lastCreatedRenderer.setStyle(workerEl, 'width', '10px');
expect(getDOM().getStyle(el, 'width')).toEqual('10px');
expect(el.style['width']).toEqual('10px');
lastCreatedRenderer.removeStyle(workerEl, 'width');
expect(getDOM().getStyle(el, 'width')).toEqual('');
expect(el.style['width']).toEqual('');
lastCreatedRenderer.setAttribute(workerEl, 'someattr', 'someValue');
expect(getDOM().getAttribute(el, 'someattr')).toEqual('someValue');