src/dom/css/share.js
import { avalon, oneObject, cssHooks, window } from '../../seed/core'
var cssMap = oneObject('float','cssFloat')
export {
cssMap,
cssHooks
}
avalon.cssNumber = oneObject('animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom')
var prefixes = ['', '-webkit-', '-o-', '-moz-', '-ms-']
/* istanbul ignore next */
avalon.cssName = function (name, host, camelCase) {
if (cssMap[name]) {
return cssMap[name]
}
host = host || avalon.root.style || {}
for (var i = 0, n = prefixes.length; i < n; i++) {
camelCase = avalon.camelize(prefixes[i] + name)
if (camelCase in host) {
return (cssMap[name] = camelCase)
}
}
return null
}
/* istanbul ignore next */
avalon.css = function (node, name, value, fn) {
//读写删除元素节点的样式
if (node instanceof avalon) {
node = node[0]
}
if (node.nodeType !== 1) {
return
}
var prop = avalon.camelize(name)
name = avalon.cssName(prop) || /* istanbul ignore next*/ prop
if (value === void 0 || typeof value === 'boolean') { //获取样式
fn = cssHooks[prop + ':get'] || cssHooks['@:get']
if (name === 'background') {
name = 'backgroundColor'
}
var val = fn(node, name)
return value === true ? parseFloat(val) || 0 : val
} else if (value === '') { //请除样式
node.style[name] = ''
} else { //设置样式
if (value == null || value !== value) {
return
}
if (isFinite(value) && !avalon.cssNumber[prop]) {
value += 'px'
}
fn = cssHooks[prop + ':set'] || cssHooks['@:set']
fn(node, name, value)
}
}
/* istanbul ignore next */
avalon.fn.css = function (name, value) {
if (avalon.isPlainObject(name)) {
for (var i in name) {
avalon.css(this, i, name[i])
}
} else {
var ret = avalon.css(this, name, value)
}
return ret !== void 0 ? ret : this
}
/* istanbul ignore next */
avalon.fn.position = function () {
var offsetParent, offset,
elem = this[0],
parentOffset = {
top: 0,
left: 0
}
if (!elem) {
return parentOffset
}
if (this.css('position') === 'fixed') {
offset = elem.getBoundingClientRect()
} else {
offsetParent = this.offsetParent() //得到真正的offsetParent
offset = this.offset() // 得到正确的offsetParent
if (offsetParent[0].tagName !== 'HTML') {
parentOffset = offsetParent.offset()
}
parentOffset.top += avalon.css(offsetParent[0], 'borderTopWidth', true)
parentOffset.left += avalon.css(offsetParent[0], 'borderLeftWidth', true)
// Subtract offsetParent scroll positions
parentOffset.top -= offsetParent.scrollTop()
parentOffset.left -= offsetParent.scrollLeft()
}
return {
top: offset.top - parentOffset.top - avalon.css(elem, 'marginTop', true),
left: offset.left - parentOffset.left - avalon.css(elem, 'marginLeft', true)
}
}
/* istanbul ignore next */
avalon.fn.offsetParent = function () {
var offsetParent = this[0].offsetParent
while (offsetParent && avalon.css(offsetParent, 'position') === 'static') {
offsetParent = offsetParent.offsetParent
}
return avalon(offsetParent || avalon.root)
}
/* istanbul ignore next */
cssHooks['@:set'] = function (node, name, value) {
try {
//node.style.width = NaN;node.style.width = 'xxxxxxx';
//node.style.width = undefine 在旧式IE下会抛异常
node.style[name] = value
} catch (e) {
}
}
/* istanbul ignore next */
cssHooks['@:get'] = function (node, name) {
if (!node || !node.style) {
throw new Error('getComputedStyle要求传入一个节点 ' + node)
}
var ret, styles = window.getComputedStyle(node, null)
if (styles) {
ret = name === 'filter' ? styles.getPropertyValue(name) : styles[name]
if (ret === '') {
ret = node.style[name] //其他浏览器需要我们手动取内联样式
}
}
return ret
}
cssHooks['opacity:get'] = function (node) {
var ret = cssHooks['@:get'](node, 'opacity')
return ret === '' ? '1' : ret
}
'top,left'.replace(avalon.rword, function (name) {
cssHooks[name + ':get'] = function (node) {
var computed = cssHooks['@:get'](node, name)
return /px$/.test(computed) ? computed :
avalon(node).position()[name] + 'px'
}
})
var cssShow = {
position: 'absolute',
visibility: 'hidden',
display: 'block'
}
var rdisplayswap = /^(none|table(?!-c[ea]).+)/
/* istanbul ignore next */
function showHidden(node, array) {
//http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
if (rdisplayswap.test(cssHooks['@:get'](node, 'display'))) {
var obj = {
node: node
}
for (var name in cssShow) {
obj[name] = node.style[name]
node.style[name] = cssShow[name]
}
array.push(obj)
}
var parent = node.parentNode
if (parent && parent.nodeType === 1) {
showHidden(parent, array)
}
}
}
/* istanbul ignore next*/
avalon.each({
Width: 'width',
Height: 'height'
}, function (name, method) {
var clientProp = 'client' + name,
scrollProp = 'scroll' + name,
offsetProp = 'offset' + name
cssHooks[method + ':get'] = function (node, which, override) {
var boxSizing = -4
if (typeof override === 'number') {
boxSizing = override
}
which = name === 'Width' ? ['Left', 'Right'] : ['Top', 'Bottom']
var ret = node[offsetProp] // border-box 0
if (boxSizing === 2) { // margin-box 2
return ret + avalon.css(node, 'margin' + which[0], true) + avalon.css(node, 'margin' + which[1], true)
}
if (boxSizing < 0) { // padding-box -2
ret = ret - avalon.css(node, 'border' + which[0] + 'Width', true) - avalon.css(node, 'border' + which[1] + 'Width', true)
}
if (boxSizing === -4) { // content-box -4
ret = ret - avalon.css(node, 'padding' + which[0], true) - avalon.css(node, 'padding' + which[1], true)
}
return ret
}
cssHooks[method + '&get'] = function (node) {
var hidden = []
showHidden(node, hidden)
var val = cssHooks[method + ':get'](node)
for (var i = 0, obj; obj = hidden[i++];) {
node = obj.node
for (var n in obj) {
if (typeof obj[n] === 'string') {
node.style[n] = obj[n]
}
}
}
return val
}
avalon.fn[method] = function (value) { //会忽视其display
var node = this[0]
if (arguments.length === 0) {
if (node.setTimeout) { //取得窗口尺寸
return node['inner' + name] ||
node.document.documentElement[clientProp] ||
node.document.body[clientProp] //IE6下前两个分别为undefined,0
}
if (node.nodeType === 9) { //取得页面尺寸
var doc = node.documentElement
//FF chrome html.scrollHeight< body.scrollHeight
//IE 标准模式 : html.scrollHeight> body.scrollHeight
//IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
}
return cssHooks[method + '&get'](node)
} else {
return this.css(method, value)
}
}
avalon.fn['inner' + name] = function () {
return cssHooks[method + ':get'](this[0], void 0, -2)
}
avalon.fn['outer' + name] = function (includeMargin) {
return cssHooks[method + ':get'](this[0], void 0, includeMargin === true ? 2 : 0)
}
})
export function getWindow(node) {
return node.window || node.defaultView || node.parentWindow || false
}