asia-weex-vue-render4light
Version:
Web renderer for weex project written in Vue DSL.
266 lines (250 loc) • 7.21 kB
JavaScript
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import config from '../config'
import { camelize } from './func'
const { bindingStyleNamesForPx2Rem } = config
// whether to support using 0.5px to paint 1px width border.
let _supportHairlines
export function supportHairlines () {
if (typeof _supportHairlines === 'undefined') {
const dpr = window.devicePixelRatio
if (dpr && dpr >= 2 && document.documentElement) {
const docElm = document.documentElement
const testElm = document.createElement('div')
const fakeBody = document.createElement('body')
const beforeNode = docElm.firstElementChild || docElm.firstChild
testElm.style.border = '0.5px solid transparent'
fakeBody.appendChild(testElm)
docElm.insertBefore(fakeBody, beforeNode)
_supportHairlines = testElm.offsetHeight === 1
docElm.removeChild(fakeBody)
}
else {
_supportHairlines = false
}
}
return _supportHairlines
}
let support = null
export function supportSticky () {
if (support !== null) {
return support
}
const element = window.document.createElement('div')
const elementStyle = element.style
elementStyle.cssText = 'position:-webkit-sticky;position:sticky;'
support = elementStyle.position.indexOf('sticky') !== -1
return support
}
/**
* get transformObj
*/
export function getTransformObj (elm) {
let styleObj = {}
if (!elm) { return styleObj }
const transformStr = elm.style.webkitTransform
|| elm.style.mozTransform
|| elm.style.transform
if (transformStr && transformStr.match(/(?: *(?:translate|rotate|scale)[^(]*\([^(]+\))+/i)) {
styleObj = transformStr.trim().replace(/, +/g, ',').split(' ').reduce(function (pre, str) {
['translate', 'scale', 'rotate'].forEach(function (name) {
if (new RegExp(name, 'i').test(str)) {
pre[name] = str
}
})
return pre
}, {})
}
return styleObj
}
/**
* translate a transform string from a transformObj.
*/
export function getTransformStr (obj) {
return Object.keys(obj).reduce(function (pre, key) {
return pre + obj[key] + ' '
}, '')
}
/**
* add transform style to element.
* @param {HTMLElement} elm
* @param {object} style: transform object, format is like this:
* {
* translate: 'translate3d(2px, 2px, 2px)',
* scale: 'scale(0.2)',
* rotate: 'rotate(30deg)'
* }
* @param {boolean} replace: whether to replace all transform properties.
*/
export function addTransform (elm, style, replace) {
if (!style) { return }
let styleObj = {}
if (!replace) {
styleObj = getTransformObj(elm)
}
for (const key in style) {
const val = style[key]
if (val) {
styleObj[key] = val
}
}
const resStr = getTransformStr(styleObj)
elm.style.webkitTransform = resStr
elm.style.mozTransform = resStr
elm.style.transform = resStr
}
/**
* copy a transform behaviour from one element to another.
* key could be: 'translate' | 'scale' | 'rotate'
*/
export function copyTransform (from, to, key) {
let str
if (!key) {
str = from.style.webkitTransform
|| from.style.mozTransform
|| from.style.transform
}
else {
const fromObj = getTransformObj(from)
if (!fromObj[key]) { return }
const toObj = getTransformObj(to)
toObj[key] = fromObj[key]
str = getTransformStr(toObj)
}
to.style.webkitTransform = str
to.style.mozTransform = str
to.style.transform = str
}
/**
* get color's r, g, b value.
* @param {string} color support all kinds of value of color.
*/
export function getRgb (color) {
const haxReg = /#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})/
const rgbReg = /rgb\((\d+),\s*(\d+),\s*(\d+)\)/
const span = document.createElement('span')
const body = document.body
span.style.cssText = `color: ${color}; width: 0px; height: 0px;`
body && body.appendChild(span)
color = window.getComputedStyle(span).color + ''
body && body.removeChild(span)
let match
match = color.match(haxReg)
if (match) {
return {
r: parseInt(match[1], 16),
g: parseInt(match[2], 16),
b: parseInt(match[3], 16)
}
}
match = color.match(rgbReg)
if (match) {
return {
r: parseInt(match[1]),
g: parseInt(match[2]),
b: parseInt(match[3])
}
}
}
/**
* get style sheet with owner node's id
* @param {string} id owner node id.
*/
export function getStyleSheetById (id) {
if (!id) { return }
const styleSheets = document.styleSheets
const len = styleSheets.length
for (let i = 0; i < len; i++) {
const styleSheet = styleSheets[i]
if (styleSheet.ownerNode.id === id) {
return styleSheet
}
}
}
function getChildrenTotalWidth (children) {
const len = children.length
let total = 0
for (let i = 0; i < len; i++) {
total += children[i].getBoundingClientRect().width
}
return total
}
/**
* get total content width of the element.
* @param {HTMLElement} elm
*/
export function getRangeWidth (elm) {
const children = elm.children
if (!children) {
return elm.getBoundingClientRect().width
}
if (!Range) {
return getChildrenTotalWidth(children)
}
const range = document.createRange()
if (!range.selectNodeContents) {
return getChildrenTotalWidth(children)
}
range.selectNodeContents(elm)
return range.getBoundingClientRect().width
}
/**
* px2rem and camelize keys.
*/
export function styleObject2rem (style, rootValue) {
const obj = {}
for (const k in style) {
const camK = camelize(k)
if (bindingStyleNamesForPx2Rem.indexOf(camK) > -1) {
obj[camK] = px2rem(style[k] + '', rootValue)
}
else {
obj[camK] = style[k]
}
}
return obj
}
export function px2rem (px, rootValue) {
return px.replace(/([+-]?\d+(?:.\d*)?)([p|w]x)/g, function ($0, $1, $2) {
if ($2 === 'wx') { // 'wx' -> px
return $1 + 'px'
}
else { // 'px' -> rem
const pxVal = parseFloat($1)
const sign = pxVal > 0
? 1 : pxVal < 0 ?
-1 : 0
if (Math.abs(pxVal) <= 1) {
return supportHairlines()
? `${sign * 0.5}px`
: `${sign * 1}px`
}
return pxVal
/ (rootValue || window.weex.config.env.rem)
+ 'rem'
}
})
}
export function rem2px (rem, rootValue) {
return rem.replace(/([+-]?\d+(?:.\d*)?)rem/g, function ($0, $1) {
return parseFloat($1)
* (rootValue || window.weex.config.env.rem)
+ 'px'
})
}