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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user