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 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; | ||||
|  | ||||
| @ -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()); | ||||
|  | ||||
| @ -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', | ||||
|  | ||||
| @ -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') | ||||
|  | ||||
| @ -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'); | ||||
|         }); | ||||
|       }); | ||||
|     }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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'; } | ||||
|  | ||||
| @ -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'); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user