feat(aio): support disabling DocViewer animations via class
				
					
				
			This commit is contained in:
		
							parent
							
								
									74e3115686
								
							
						
					
					
						commit
						f8fe53aeb0
					
				| @ -13,7 +13,7 @@ import { | |||||||
|   TestDocViewerComponent, TestModule, TestParentComponent |   TestDocViewerComponent, TestModule, TestParentComponent | ||||||
| } from 'testing/doc-viewer-utils'; | } from 'testing/doc-viewer-utils'; | ||||||
| import { MockLogger } from 'testing/logger.service'; | import { MockLogger } from 'testing/logger.service'; | ||||||
| import { DocViewerComponent } from './doc-viewer.component'; | import { DocViewerComponent, NO_ANIMATIONS } from './doc-viewer.component'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| describe('DocViewerComponent', () => { | describe('DocViewerComponent', () => { | ||||||
| @ -656,122 +656,142 @@ describe('DocViewerComponent', () => { | |||||||
|         beforeEach(() => DocViewerComponent.animationsEnabled = animationsEnabled); |         beforeEach(() => DocViewerComponent.animationsEnabled = animationsEnabled); | ||||||
|         afterEach(() => DocViewerComponent.animationsEnabled = true); |         afterEach(() => DocViewerComponent.animationsEnabled = true); | ||||||
| 
 | 
 | ||||||
|         it('should return an observable', done => { |         [true, false].forEach(noAnimations => { | ||||||
|           docViewer.swapViews().subscribe(done, done.fail); |           describe(`(.${NO_ANIMATIONS}: ${noAnimations})`, () => { | ||||||
|         }); |             beforeEach(() => docViewerEl.classList[noAnimations ? 'add' : 'remove'](NO_ANIMATIONS)); | ||||||
| 
 | 
 | ||||||
|         it('should swap the views', async () => { |             it('should return an observable', done => { | ||||||
|           await doSwapViews(); |               docViewer.swapViews().subscribe(done, done.fail); | ||||||
|  |             }); | ||||||
| 
 | 
 | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |             it('should swap the views', async () => { | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |               await doSwapViews(); | ||||||
|           expect(docViewer.currViewContainer).toBe(oldNextViewContainer); |  | ||||||
|           expect(docViewer.nextViewContainer).toBe(oldCurrViewContainer); |  | ||||||
| 
 | 
 | ||||||
|           await doSwapViews(); |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |               expect(docViewer.currViewContainer).toBe(oldNextViewContainer); | ||||||
|  |               expect(docViewer.nextViewContainer).toBe(oldCurrViewContainer); | ||||||
| 
 | 
 | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); |               await doSwapViews(); | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); |  | ||||||
|           expect(docViewer.currViewContainer).toBe(oldCurrViewContainer); |  | ||||||
|           expect(docViewer.nextViewContainer).toBe(oldNextViewContainer); |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|         it('should emit `docRemoved` after removing the leaving view', async () => { |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); | ||||||
|           const onDocRemovedSpy = jasmine.createSpy('onDocRemoved').and.callFake(() => { |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); | ||||||
|             expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |               expect(docViewer.currViewContainer).toBe(oldCurrViewContainer); | ||||||
|             expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); |               expect(docViewer.nextViewContainer).toBe(oldNextViewContainer); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             it('should emit `docRemoved` after removing the leaving view', async () => { | ||||||
|  |               const onDocRemovedSpy = jasmine.createSpy('onDocRemoved').and.callFake(() => { | ||||||
|  |                 expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |                 expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); | ||||||
|  |               }); | ||||||
|  | 
 | ||||||
|  |               docViewer.docRemoved.subscribe(onDocRemovedSpy); | ||||||
|  | 
 | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); | ||||||
|  | 
 | ||||||
|  |               await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |               expect(onDocRemovedSpy).toHaveBeenCalledTimes(1); | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             it('should not emit `docRemoved` if the leaving view is already removed', async () => { | ||||||
|  |               const onDocRemovedSpy = jasmine.createSpy('onDocRemoved'); | ||||||
|  | 
 | ||||||
|  |               docViewer.docRemoved.subscribe(onDocRemovedSpy); | ||||||
|  |               docViewerEl.removeChild(oldCurrViewContainer); | ||||||
|  | 
 | ||||||
|  |               await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |               expect(onDocRemovedSpy).not.toHaveBeenCalled(); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             it('should emit `docInserted` after inserting the entering view', async () => { | ||||||
|  |               const onDocInsertedSpy = jasmine.createSpy('onDocInserted').and.callFake(() => { | ||||||
|  |                 expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |                 expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |               }); | ||||||
|  | 
 | ||||||
|  |               docViewer.docInserted.subscribe(onDocInsertedSpy); | ||||||
|  | 
 | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); | ||||||
|  | 
 | ||||||
|  |               await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |               expect(onDocInsertedSpy).toHaveBeenCalledTimes(1); | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             it('should call the callback after inserting the entering view', async () => { | ||||||
|  |               const onInsertedCb = jasmine.createSpy('onInsertedCb').and.callFake(() => { | ||||||
|  |                 expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |                 expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |               }); | ||||||
|  |               const onDocInsertedSpy = jasmine.createSpy('onDocInserted'); | ||||||
|  | 
 | ||||||
|  |               docViewer.docInserted.subscribe(onDocInsertedSpy); | ||||||
|  | 
 | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); | ||||||
|  | 
 | ||||||
|  |               await doSwapViews(onInsertedCb); | ||||||
|  | 
 | ||||||
|  |               expect(onInsertedCb).toHaveBeenCalledTimes(1); | ||||||
|  |               expect(onInsertedCb).toHaveBeenCalledBefore(onDocInsertedSpy); | ||||||
|  |               expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |               expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             it('should empty the previous view', async () => { | ||||||
|  |               await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |               expect(docViewer.currViewContainer.innerHTML).toBe('Next view'); | ||||||
|  |               expect(docViewer.nextViewContainer.innerHTML).toBe(''); | ||||||
|  | 
 | ||||||
|  |               docViewer.nextViewContainer.innerHTML = 'Next view 2'; | ||||||
|  |               await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |               expect(docViewer.currViewContainer.innerHTML).toBe('Next view 2'); | ||||||
|  |               expect(docViewer.nextViewContainer.innerHTML).toBe(''); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             if (animationsEnabled && !noAnimations) { | ||||||
|  |               // Only test this when there are animations. Without animations, the views are swapped
 | ||||||
|  |               // synchronously, so there is no need (or way) to abort.
 | ||||||
|  |               it('should abort swapping if the returned observable is unsubscribed from', async () => { | ||||||
|  |                 docViewer.swapViews().subscribe().unsubscribe(); | ||||||
|  |                 await doSwapViews(); | ||||||
|  | 
 | ||||||
|  |                 // Since the first call was cancelled, only one swapping should have taken place.
 | ||||||
|  |                 expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |                 expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |                 expect(docViewer.currViewContainer).toBe(oldNextViewContainer); | ||||||
|  |                 expect(docViewer.nextViewContainer).toBe(oldCurrViewContainer); | ||||||
|  |                 expect(docViewer.currViewContainer.innerHTML).toBe('Next view'); | ||||||
|  |                 expect(docViewer.nextViewContainer.innerHTML).toBe(''); | ||||||
|  |               }); | ||||||
|  |             } else { | ||||||
|  |               it('should swap views synchronously when animations are disabled', () => { | ||||||
|  |                 const cbSpy = jasmine.createSpy('cb'); | ||||||
|  | 
 | ||||||
|  |                 docViewer.swapViews(cbSpy).subscribe(); | ||||||
|  | 
 | ||||||
|  |                 expect(cbSpy).toHaveBeenCalledTimes(1); | ||||||
|  |                 expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); | ||||||
|  |                 expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); | ||||||
|  |                 expect(docViewer.currViewContainer).toBe(oldNextViewContainer); | ||||||
|  |                 expect(docViewer.nextViewContainer).toBe(oldCurrViewContainer); | ||||||
|  |                 expect(docViewer.currViewContainer.innerHTML).toBe('Next view'); | ||||||
|  |                 expect(docViewer.nextViewContainer.innerHTML).toBe(''); | ||||||
|  |               }); | ||||||
|  |             } | ||||||
|           }); |           }); | ||||||
| 
 |  | ||||||
|           docViewer.docRemoved.subscribe(onDocRemovedSpy); |  | ||||||
| 
 |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); |  | ||||||
| 
 |  | ||||||
|           await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|           expect(onDocRemovedSpy).toHaveBeenCalledTimes(1); |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|         }); |         }); | ||||||
| 
 |  | ||||||
|         it('should not emit `docRemoved` if the leaving view is already removed', async () => { |  | ||||||
|           const onDocRemovedSpy = jasmine.createSpy('onDocRemoved'); |  | ||||||
| 
 |  | ||||||
|           docViewer.docRemoved.subscribe(onDocRemovedSpy); |  | ||||||
|           docViewerEl.removeChild(oldCurrViewContainer); |  | ||||||
| 
 |  | ||||||
|           await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|           expect(onDocRemovedSpy).not.toHaveBeenCalled(); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         it('should emit `docInserted` after inserting the entering view', async () => { |  | ||||||
|           const onDocInsertedSpy = jasmine.createSpy('onDocInserted').and.callFake(() => { |  | ||||||
|             expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|             expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|           }); |  | ||||||
| 
 |  | ||||||
|           docViewer.docInserted.subscribe(onDocInsertedSpy); |  | ||||||
| 
 |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); |  | ||||||
| 
 |  | ||||||
|           await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|           expect(onDocInsertedSpy).toHaveBeenCalledTimes(1); |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         it('should call the callback after inserting the entering view', async () => { |  | ||||||
|           const onInsertedCb = jasmine.createSpy('onInsertedCb').and.callFake(() => { |  | ||||||
|             expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|             expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|           }); |  | ||||||
|           const onDocInsertedSpy = jasmine.createSpy('onDocInserted'); |  | ||||||
| 
 |  | ||||||
|           docViewer.docInserted.subscribe(onDocInsertedSpy); |  | ||||||
| 
 |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(true); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(false); |  | ||||||
| 
 |  | ||||||
|           await doSwapViews(onInsertedCb); |  | ||||||
| 
 |  | ||||||
|           expect(onInsertedCb).toHaveBeenCalledTimes(1); |  | ||||||
|           expect(onInsertedCb).toHaveBeenCalledBefore(onDocInsertedSpy); |  | ||||||
|           expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|           expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         it('should empty the previous view', async () => { |  | ||||||
|           await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|           expect(docViewer.currViewContainer.innerHTML).toBe('Next view'); |  | ||||||
|           expect(docViewer.nextViewContainer.innerHTML).toBe(''); |  | ||||||
| 
 |  | ||||||
|           docViewer.nextViewContainer.innerHTML = 'Next view 2'; |  | ||||||
|           await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|           expect(docViewer.currViewContainer.innerHTML).toBe('Next view 2'); |  | ||||||
|           expect(docViewer.nextViewContainer.innerHTML).toBe(''); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         if (animationsEnabled) { |  | ||||||
|           // Without animations, the views are swapped synchronously,
 |  | ||||||
|           // so there is no need (or way) to abort.
 |  | ||||||
|           it('should abort swapping if the returned observable is unsubscribed from', async () => { |  | ||||||
|             docViewer.swapViews().subscribe().unsubscribe(); |  | ||||||
|             await doSwapViews(); |  | ||||||
| 
 |  | ||||||
|             // Since the first call was cancelled, only one swapping should have taken place.
 |  | ||||||
|             expect(docViewerEl.contains(oldCurrViewContainer)).toBe(false); |  | ||||||
|             expect(docViewerEl.contains(oldNextViewContainer)).toBe(true); |  | ||||||
|             expect(docViewer.currViewContainer).toBe(oldNextViewContainer); |  | ||||||
|             expect(docViewer.nextViewContainer).toBe(oldCurrViewContainer); |  | ||||||
|             expect(docViewer.currViewContainer.innerHTML).toBe('Next view'); |  | ||||||
|             expect(docViewer.nextViewContainer.innerHTML).toBe(''); |  | ||||||
|           }); |  | ||||||
|         } |  | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
|  | |||||||
| @ -15,6 +15,9 @@ import { Logger } from 'app/shared/logger.service'; | |||||||
| import { TocService } from 'app/shared/toc.service'; | import { TocService } from 'app/shared/toc.service'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // Constants
 | ||||||
|  | export const NO_ANIMATIONS = 'no-animations'; | ||||||
|  | 
 | ||||||
| // Initialization prevents flicker once pre-rendering is on
 | // Initialization prevents flicker once pre-rendering is on
 | ||||||
| const initialDocViewerElement = document.querySelector('aio-doc-viewer'); | const initialDocViewerElement = document.querySelector('aio-doc-viewer'); | ||||||
| const initialDocViewerContent = initialDocViewerElement ? initialDocViewerElement.innerHTML : ''; | const initialDocViewerContent = initialDocViewerElement ? initialDocViewerElement.innerHTML : ''; | ||||||
| @ -186,8 +189,11 @@ export class DocViewerComponent implements DoCheck, OnDestroy { | |||||||
|     }; |     }; | ||||||
|     const animateProp = |     const animateProp = | ||||||
|         (elem: HTMLElement, prop: string, from: string, to: string, duration = 333) => { |         (elem: HTMLElement, prop: string, from: string, to: string, duration = 333) => { | ||||||
|  |           const animationsDisabled = !DocViewerComponent.animationsEnabled | ||||||
|  |                                      || this.hostElement.classList.contains(NO_ANIMATIONS); | ||||||
|  | 
 | ||||||
|           elem.style.transition = ''; |           elem.style.transition = ''; | ||||||
|           return !DocViewerComponent.animationsEnabled |           return animationsDisabled | ||||||
|               ? this.void$.do(() => elem.style[prop] = to) |               ? this.void$.do(() => elem.style[prop] = to) | ||||||
|               : this.void$ |               : this.void$ | ||||||
|                     // In order to ensure that the `from` value will be applied immediately (i.e.
 |                     // In order to ensure that the `from` value will be applied immediately (i.e.
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user