refactor(core): move DomAdapter style methods to ServerRenderer (#32408)
PR Close #32408
This commit is contained in:
parent
970b58b13f
commit
c207ad80fd
|
@ -50,11 +50,6 @@ export abstract class DomAdapter {
|
||||||
abstract createHtmlDocument(): HTMLDocument;
|
abstract createHtmlDocument(): HTMLDocument;
|
||||||
abstract getDefaultDocument(): Document;
|
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
|
// Used by Title
|
||||||
abstract getTitle(doc: Document): string;
|
abstract getTitle(doc: Document): string;
|
||||||
abstract setTitle(doc: Document, newTitle: string): any;
|
abstract setTitle(doc: Document, newTitle: string): any;
|
||||||
|
|
|
@ -36,27 +36,6 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util';
|
||||||
expect(() => getDOM().remove(d)).not.toThrow();
|
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()) {
|
if (getDOM().supportsDOMEvents()) {
|
||||||
describe('getBaseHref', () => {
|
describe('getBaseHref', () => {
|
||||||
beforeEach(() => getDOM().resetBaseElement());
|
beforeEach(() => getDOM().resetBaseElement());
|
||||||
|
|
|
@ -147,13 +147,11 @@ function declareTests(config?: {useJit: boolean}) {
|
||||||
|
|
||||||
fixture.componentInstance.ctxProp = '10';
|
fixture.componentInstance.ctxProp = '10';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
|
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('10px');
|
||||||
.toEqual('10px');
|
|
||||||
|
|
||||||
fixture.componentInstance.ctxProp = null !;
|
fixture.componentInstance.ctxProp = null !;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(getDOM().getStyle(fixture.debugElement.children[0].nativeElement, 'height'))
|
expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('');
|
||||||
.toEqual('');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should consume binding to property names where attr name and property name do not match',
|
it('should consume binding to property names where attr name and property name do not match',
|
||||||
|
|
|
@ -247,12 +247,12 @@ function declareTests(config?: {useJit: boolean}) {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
// In some browsers, this will contain the full background specification, not just
|
// In some browsers, this will contain the full background specification, not just
|
||||||
// the color.
|
// the color.
|
||||||
expect(getDOM().getStyle(e, 'background')).toMatch(/red.*/);
|
expect(e.style['background']).toMatch(/red.*/);
|
||||||
|
|
||||||
ci.ctxProp = 'url(javascript:evil())';
|
ci.ctxProp = 'url(javascript:evil())';
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
// Updated value gets rejected, no value change.
|
// 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')
|
modifiedInIvy('Unknown property error thrown during update mode, not creation mode')
|
||||||
|
|
|
@ -164,8 +164,8 @@ const removeEventListener = '__zone_symbol__removeEventListener' as 'removeEvent
|
||||||
Services.checkAndUpdateView(view);
|
Services.checkAndUpdateView(view);
|
||||||
|
|
||||||
const el = rootNodes[0];
|
const el = rootNodes[0];
|
||||||
expect(getDOM().getStyle(el, 'width')).toBe('10px');
|
expect(el.style['width']).toBe('10px');
|
||||||
expect(getDOM().getStyle(el, 'color')).toBe('red');
|
expect(el.style['color']).toBe('red');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -119,16 +119,6 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
||||||
getElementsByTagName(element: any, name: string): HTMLElement[] {
|
getElementsByTagName(element: any, name: string): HTMLElement[] {
|
||||||
return element.getElementsByTagName(name);
|
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 {
|
getAttribute(element: Element, attribute: string): string|null {
|
||||||
return element.getAttribute(attribute);
|
return element.getAttribute(attribute);
|
||||||
|
|
|
@ -109,55 +109,6 @@ export class DominoAdapter extends BrowserDomAdapter {
|
||||||
return href;
|
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) {
|
dispatchEvent(el: Node, evt: any) {
|
||||||
el.dispatchEvent(evt);
|
el.dispatchEvent(evt);
|
||||||
|
|
||||||
|
|
|
@ -143,11 +143,16 @@ class DefaultServerRenderer2 implements Renderer2 {
|
||||||
removeClass(el: any, name: string): void { el.classList.remove(name); }
|
removeClass(el: any, name: string): void { el.classList.remove(name); }
|
||||||
|
|
||||||
setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void {
|
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 {
|
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.
|
// The value was validated already as a property binding, against the property name.
|
||||||
|
@ -246,3 +251,34 @@ class EmulatedEncapsulationServerRenderer2 extends DefaultServerRenderer2 {
|
||||||
return el;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -53,9 +53,6 @@ export class WorkerDomAdapter extends DomAdapter {
|
||||||
createElement(tagName: any, doc?: any): HTMLElement { throw 'not implemented'; }
|
createElement(tagName: any, doc?: any): HTMLElement { throw 'not implemented'; }
|
||||||
getHost(el: any): any { throw 'not implemented'; }
|
getHost(el: any): any { throw 'not implemented'; }
|
||||||
getElementsByTagName(element: any, name: string): HTMLElement[] { 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'; }
|
getAttribute(element: any, attribute: string): string { throw 'not implemented'; }
|
||||||
setAttribute(element: any, name: string, value: string) { throw 'not implemented'; }
|
setAttribute(element: any, name: string, value: string) { throw 'not implemented'; }
|
||||||
createHtmlDocument(): HTMLDocument { throw 'not implemented'; }
|
createHtmlDocument(): HTMLDocument { throw 'not implemented'; }
|
||||||
|
|
|
@ -115,10 +115,10 @@ let lastCreatedRenderer: Renderer2;
|
||||||
expect(hasClass(el, 'a')).toBe(false);
|
expect(hasClass(el, 'a')).toBe(false);
|
||||||
|
|
||||||
lastCreatedRenderer.setStyle(workerEl, 'width', '10px');
|
lastCreatedRenderer.setStyle(workerEl, 'width', '10px');
|
||||||
expect(getDOM().getStyle(el, 'width')).toEqual('10px');
|
expect(el.style['width']).toEqual('10px');
|
||||||
|
|
||||||
lastCreatedRenderer.removeStyle(workerEl, 'width');
|
lastCreatedRenderer.removeStyle(workerEl, 'width');
|
||||||
expect(getDOM().getStyle(el, 'width')).toEqual('');
|
expect(el.style['width']).toEqual('');
|
||||||
|
|
||||||
lastCreatedRenderer.setAttribute(workerEl, 'someattr', 'someValue');
|
lastCreatedRenderer.setAttribute(workerEl, 'someattr', 'someValue');
|
||||||
expect(getDOM().getAttribute(el, 'someattr')).toEqual('someValue');
|
expect(getDOM().getAttribute(el, 'someattr')).toEqual('someValue');
|
||||||
|
|
Loading…
Reference in New Issue