MOBILE-3320 ios: Fix zoomed popover position
This commit is contained in:
		
							parent
							
								
									3c4b4c3786
								
							
						
					
					
						commit
						9ded77f351
					
				| @ -14,7 +14,7 @@ | ||||
| 
 | ||||
| import { Injectable, SimpleChange, ElementRef, KeyValueChanges } from '@angular/core'; | ||||
| import { IonContent } from '@ionic/angular'; | ||||
| import { ModalOptions, PopoverOptions, AlertOptions, AlertButton, TextFieldTypes } from '@ionic/core'; | ||||
| import { ModalOptions, PopoverOptions, AlertOptions, AlertButton, TextFieldTypes, getMode } from '@ionic/core'; | ||||
| import { Md5 } from 'ts-md5'; | ||||
| 
 | ||||
| import { CoreApp } from '@services/app'; | ||||
| @ -37,6 +37,7 @@ import { CoreBSTooltipComponent } from '@components/bs-tooltip/bs-tooltip'; | ||||
| import { CoreViewerImageComponent } from '@features/viewer/components/image/image'; | ||||
| import { CoreFormFields, CoreForms } from '../../singletons/form'; | ||||
| import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; | ||||
| import { CoreZoomLevel } from '@features/settings/services/settings-helper'; | ||||
| 
 | ||||
| /* | ||||
|  * "Utils" service with helper functions for UI, DOM elements and HTML code. | ||||
| @ -1734,9 +1735,19 @@ export class CoreDomUtilsProvider { | ||||
|     ): Promise<T | undefined> { | ||||
| 
 | ||||
|         const popover = await PopoverController.create(popoverOptions); | ||||
|         const zoomLevel = await CoreConfig.get(CoreConstants.SETTINGS_ZOOM_LEVEL, CoreZoomLevel.NORMAL); | ||||
| 
 | ||||
|         await popover.present(); | ||||
| 
 | ||||
|         // Fix popover position if zoom is applied.
 | ||||
|         if (zoomLevel !== CoreZoomLevel.NORMAL) { | ||||
|             switch (getMode()) { | ||||
|                 case 'ios': | ||||
|                     fixIOSPopoverPosition(popover, popoverOptions.event); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // If onDidDismiss is nedded we can add a new param to the function to wait one function or the other.
 | ||||
|         const result = await popover.onWillDismiss<T>(); | ||||
|         if (result?.data) { | ||||
| @ -1849,6 +1860,96 @@ export class CoreDomUtilsProvider { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Fix the position of a popover that was created with a zoom level applied in iOS. | ||||
|  * | ||||
|  * This is necessary because Ionic's implementation gets the body dimensions from `element.ownerDocument.defaultView.innerXXX`, | ||||
|  * which doesn't return the correct dimensions when the `zoom` CSS property is being used. This is only necessary | ||||
|  * in iOS because Android already respects system font sizes, and setting the zoom level is unnecessary. Eventually, we | ||||
|  * should find an alternative implementation for iOS that doesn't require this workaround (also because the `zoom` CSS | ||||
|  * property is not standard and its usage is discouraged for production). | ||||
|  * | ||||
|  * This function has been copied in its entirety from Ionic's source code, only changing the aforementioned calculation | ||||
|  * of the body dimensions with `document.body.clientXXX`. | ||||
|  * | ||||
|  * @see https://github.com/ionic-team/ionic-framework/blob/v5.6.6/core/src/components/popover/animations/ios.enter.ts
 | ||||
|  */ | ||||
| function fixIOSPopoverPosition(baseEl: HTMLElement, ev?: Event): void { | ||||
|     let originY = 'top'; | ||||
|     let originX = 'left'; | ||||
| 
 | ||||
|     const POPOVER_IOS_BODY_PADDING = 5; | ||||
|     const contentEl = baseEl.querySelector('.popover-content') as HTMLElement; | ||||
|     const contentDimentions = contentEl.getBoundingClientRect(); | ||||
|     const contentWidth = contentDimentions.width; | ||||
|     const contentHeight = contentDimentions.height; | ||||
|     const bodyWidth = document.body.clientWidth; | ||||
|     const bodyHeight = document.body.clientHeight; | ||||
|     const targetDim = ev && ev.target && (ev.target as HTMLElement).getBoundingClientRect(); | ||||
|     const targetTop = targetDim != null && 'top' in targetDim ? targetDim.top : bodyHeight / 2 - contentHeight / 2; | ||||
|     const targetLeft = targetDim != null && 'left' in targetDim ? targetDim.left : bodyWidth / 2; | ||||
|     const targetWidth = (targetDim && targetDim.width) || 0; | ||||
|     const targetHeight = (targetDim && targetDim.height) || 0; | ||||
|     const arrowEl = baseEl.querySelector('.popover-arrow') as HTMLElement; | ||||
|     const arrowDim = arrowEl.getBoundingClientRect(); | ||||
|     const arrowWidth = arrowDim.width; | ||||
|     const arrowHeight = arrowDim.height; | ||||
| 
 | ||||
|     if (targetDim == null) { | ||||
|         arrowEl.style.display = 'none'; | ||||
|     } | ||||
| 
 | ||||
|     const arrowCSS = { | ||||
|         top: targetTop + targetHeight, | ||||
|         left: targetLeft + targetWidth / 2 - arrowWidth / 2, | ||||
|     }; | ||||
| 
 | ||||
|     const popoverCSS: { top: number; left: number } = { | ||||
|         top: targetTop + targetHeight + (arrowHeight - 1), | ||||
|         left: targetLeft + targetWidth / 2 - contentWidth / 2, | ||||
|     }; | ||||
| 
 | ||||
|     let checkSafeAreaLeft = false; | ||||
|     let checkSafeAreaRight = false; | ||||
| 
 | ||||
|     if (popoverCSS.left < POPOVER_IOS_BODY_PADDING + 25) { | ||||
|         checkSafeAreaLeft = true; | ||||
|         popoverCSS.left = POPOVER_IOS_BODY_PADDING; | ||||
|     } else if ( | ||||
|         contentWidth + POPOVER_IOS_BODY_PADDING + popoverCSS.left + 25 > bodyWidth | ||||
|     ) { | ||||
|         checkSafeAreaRight = true; | ||||
|         popoverCSS.left = bodyWidth - contentWidth - POPOVER_IOS_BODY_PADDING; | ||||
|         originX = 'right'; | ||||
|     } | ||||
| 
 | ||||
|     if (targetTop + targetHeight + contentHeight > bodyHeight && targetTop - contentHeight > 0) { | ||||
|         arrowCSS.top = targetTop - (arrowHeight + 1); | ||||
|         popoverCSS.top = targetTop - contentHeight - (arrowHeight - 1); | ||||
| 
 | ||||
|         baseEl.className = baseEl.className + ' popover-bottom'; | ||||
|         originY = 'bottom'; | ||||
|     } else if (targetTop + targetHeight + contentHeight > bodyHeight) { | ||||
|         contentEl.style.bottom = POPOVER_IOS_BODY_PADDING + '%'; | ||||
|     } | ||||
| 
 | ||||
|     arrowEl.style.top = arrowCSS.top + 'px'; | ||||
|     arrowEl.style.left = arrowCSS.left + 'px'; | ||||
| 
 | ||||
|     contentEl.style.top = popoverCSS.top + 'px'; | ||||
|     contentEl.style.left = popoverCSS.left + 'px'; | ||||
| 
 | ||||
|     if (checkSafeAreaLeft) { | ||||
|         contentEl.style.left = `calc(${popoverCSS.left}px + var(--ion-safe-area-left, 0px))`; | ||||
|     } | ||||
| 
 | ||||
|     if (checkSafeAreaRight) { | ||||
|         contentEl.style.left = `calc(${popoverCSS.left}px - var(--ion-safe-area-right, 0px))`; | ||||
|     } | ||||
| 
 | ||||
|     contentEl.style.transformOrigin = originY + ' ' + originX; | ||||
| } | ||||
| 
 | ||||
| export const CoreDomUtils = makeSingleton(CoreDomUtilsProvider); | ||||
| 
 | ||||
| type AnchorOrMediaElement = | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user