| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- 'use strict'
- var attrs: string[] = ['top', 'left', 'right', 'bottom']
- var inited: boolean
- var elementComputedStyle = {}
- var support: string
- function getSupport() {
- if(!('CSS' in window) || typeof CSS.supports != 'function') {
- support = ''
- } else if(CSS.supports('top: env(safe-area-inset-top)')) {
- support = 'env'
- } else if(CSS.supports('top: constant(safe-area-inset-top)')) {
- support = 'constant'
- } else {
- support = ''
- }
- return support
- }
- function init() {
- support = typeof support === 'string' ? support : getSupport()
- if(!support) {
- attrs.forEach((attr: string) => {
- elementComputedStyle[attr] = 0
- })
- return
- }
- function setStyle(el: HTMLElement, style) {
- var elStyle: CSSStyleDeclaration = el.style
- Object.keys(style).forEach(key => {
- var val: string = style[key]
- elStyle[key] = val
- })
- }
- var cbs: Function[] = []
- function parentReady(callback?: Function) {
- if(callback) {
- cbs.push(callback)
- } else {
- cbs.forEach(cb => {
- cb()
- })
- }
- }
- var passiveEvents: any = false
- try {
- var opts = Object.defineProperty({}, 'passive', {
- get: function() {
- passiveEvents = { passive: true }
- }
- })
- window.addEventListener('test', null, opts)
- } catch(e) {
- }
- function addChild(parent: HTMLElement, attr: string) {
- var a1: HTMLElement = document.createElement('div')
- var a2: HTMLElement = document.createElement('div')
- var a1Children: HTMLElement = document.createElement('div')
- var a2Children: HTMLElement = document.createElement('div')
- var W: number = 100
- var MAX: number = 10000
- var aStyle = {
- position: 'absolute',
- width: W + 'px',
- height: '200px',
- boxSizing: 'border-box',
- overflow: 'hidden',
- paddingBottom: `${support}(safe-area-inset-${attr})`
- }
- setStyle(a1, aStyle)
- setStyle(a2, aStyle)
- setStyle(a1Children, {
- transition: '0s',
- animation: 'none',
- width: '400px',
- height: '400px'
- })
- setStyle(a2Children, {
- transition: '0s',
- animation: 'none',
- width: '250%',
- height: '250%'
- })
- a1.appendChild(a1Children)
- a2.appendChild(a2Children)
- parent.appendChild(a1)
- parent.appendChild(a2)
- parentReady(() => {
- a1.scrollTop = a2.scrollTop = MAX
- var a1LastScrollTop: number = a1.scrollTop
- var a2LastScrollTop: number = a2.scrollTop
- function onScroll() {
- if(this.scrollTop === (this === a1 ? a1LastScrollTop : a2LastScrollTop)) {
- return
- }
- a1.scrollTop = a2.scrollTop = MAX
- a1LastScrollTop = a1.scrollTop
- a2LastScrollTop = a2.scrollTop
- attrChange(attr)
- }
- a1.addEventListener('scroll', onScroll, passiveEvents)
- a2.addEventListener('scroll', onScroll, passiveEvents)
- })
- var computedStyle: CSSStyleDeclaration = getComputedStyle(a1)
- Object.defineProperty(elementComputedStyle, attr, {
- configurable: true,
- get() {
- return parseFloat(computedStyle.paddingBottom)
- }
- })
- }
- var parentDiv: HTMLElement = document.createElement('div')
- setStyle(parentDiv, {
- position: 'absolute',
- left: '0',
- top: '0',
- width: '0',
- height: '0',
- zIndex: '-1',
- overflow: 'hidden',
- visibility: 'hidden',
- })
- attrs.forEach(key => {
- addChild(parentDiv, key)
- })
- document.body.appendChild(parentDiv)
- parentReady()
- inited = true
- }
- function getAttr(attr: string): number {
- if(!inited) {
- init()
- }
- return elementComputedStyle[attr]
- }
- var changeAttrs: string[] = []
- function attrChange(attr: string) {
- if(!changeAttrs.length) {
- setTimeout(() => {
- var style = {}
- changeAttrs.forEach(attr => {
- style[attr] = elementComputedStyle[attr]
- })
- changeAttrs.length = 0
- callbacks.forEach(callback => {
- callback(style)
- })
- }, 0)
- }
- changeAttrs.push(attr)
- }
- var callbacks: Function[] = []
- function onChange(callback: Function) {
- if(!getSupport()) {
- return
- }
- if(!inited) {
- init()
- }
- if(typeof callback === 'function') {
- callbacks.push(callback)
- }
- }
- function offChange(callback: Function) {
- var index = callbacks.indexOf(callback)
- if(index >= 0){
- callbacks.splice(index, 1)
- }
- }
- var safeAreaInsets = {
- get support(): boolean {
- return (typeof support === 'string' ? support : getSupport()).length != 0
- },
- get top(): number {
- return getAttr('top')
- },
- get left(): number {
- return getAttr('left')
- },
- get right(): number {
- return getAttr('right')
- },
- get bottom(): number {
- return getAttr('bottom')
- },
- onChange,
- offChange
- }
- export = safeAreaInsets
|