blob: 395371f13510b324d8c4e7977e1214667f595cee [file] [log] [blame]
/*
* 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.
*/
'use strict'
import './switch.css'
const defaults = {
color: '#64bd63',
secondaryColor: '#dfdfdf',
jackColor: '#fff',
jackSecondaryColor: null,
className: 'weex-switch',
disabledOpacity: 0.5,
speed: '0.4s',
width: 100,
height: 60,
// is width and height scalable ?
scalable: false
}
function transitionize (element, props) {
const transitions = []
for (const key in props) {
transitions.push(key + ' ' + props[key])
}
element.style.transition = transitions.join(', ')
element.style.webkitTransition = transitions.join(', ')
}
function setSize (comp) {
const min = Math.min(comp.width, comp.height)
const max = Math.max(comp.width, comp.height)
comp.node.style.width = max + 'px'
comp.node.style.height = min + 'px'
comp.node.style.borderRadius = min / 2 + 'px'
comp.jack.style.width
= comp.jack.style.height
= min + 'px'
}
function setPosition (comp, clicked) {
let checked = comp.checked
const node = comp.node
const jack = comp.jack
if (clicked && checked) {
checked = false
}
else if (clicked && !checked) {
checked = true
}
if (checked === true) {
comp.checked = true
if (window.getComputedStyle) {
jack.style.left = parseInt(window.getComputedStyle(node).width)
- parseInt(window.getComputedStyle(jack).width) + 'px'
}
else {
jack.style.left = parseInt(node.currentStyle['width'])
- parseInt(jack.currentStyle['width']) + 'px'
}
comp.options.color && colorize(comp)
setSpeed(comp)
}
else {
comp.checked = false
jack.style.left = 0
node.style.boxShadow = 'inset 0 0 0 0 ' + comp.options.secondaryColor
node.style.borderColor = comp.options.secondaryColor
node.style.backgroundColor
= (comp.options.secondaryColor !== defaults.secondaryColor)
? comp.options.secondaryColor
: '#fff'
jack.style.backgroundColor
= (comp.options.jackSecondaryColor !== comp.options.jackColor)
? comp.options.jackSecondaryColor
: comp.options.jackColor
setSpeed(comp)
}
}
function setSpeed (comp) {
let switcherProp = {}
const jackProp = {
'background-color': comp.options.speed,
left: comp.options.speed.replace(/[a-z]/, '') / 2 + 's'
}
if (comp.checked) {
switcherProp = {
border: comp.options.speed,
'box-shadow': comp.options.speed,
'background-color': comp.options.speed.replace(/[a-z]/, '') * 3 + 's'
}
}
else {
switcherProp = {
border: comp.options.speed,
'box-shadow': comp.options.speed
}
}
transitionize(comp.node, switcherProp)
transitionize(comp.jack, jackProp)
}
function colorize (comp) {
const nodeHeight = comp.node.offsetHeight / 2
comp.node.style.backgroundColor = comp.options.color
comp.node.style.borderColor = comp.options.color
comp.node.style.boxShadow = 'inset 0 0 0 '
+ nodeHeight
+ 'px '
+ comp.options.color
comp.jack.style.backgroundColor = comp.options.jackColor
}
function getClickHandler (comp) {
if (!comp._clickHandler) {
comp._clickHandler = function () {
setPosition(comp, true)
comp.dispatchEvent('change', {
value: comp.checked
})
}
}
return comp._clickHandler
}
const proto = {
create () {
const node = document.createElement('span')
this.jack = document.createElement('small')
node.appendChild(this.jack)
node.className = this.options.className
this.node = node
this.attr.disabled.call(this, this.data.attr.disabled)
return node
},
onAppend () {
setSize(this)
setPosition(this)
},
enable () {
this.disabled && (this.disabled = false)
this.node.style.opacity = 1
this.node.addEventListener('click', getClickHandler(this))
},
disable () {
!this.disabled && (this.disabled = true)
this.node.style.opacity = defaults.disabledOpacity
this.node.removeEventListener('click', getClickHandler(this))
}
}
const attr = {
disabled: function (val) {
this.disabled = val && val !== 'false'
this.disabled ? this.disable() : this.enable()
}
}
const style = {
width: function (val) {
if (!this.options.scalable) {
return
}
val = parseFloat(val)
if (isNaN(val) || val < 0) {
val = this.options.width
}
this.width = val
this.setSize()
},
height: function (val) {
if (!this.options.scalable) {
return
}
val = parseFloat(val)
if (isNaN(val) || val < 0) {
val = this.options.height
}
this.height = val
this.setSize()
}
}
const event = {
change: {
updator () {
return {
attrs: {
checked: this.checked
}
}
},
extra () {
return {
value: this.checked
}
}
}
}
function init (Weex) {
const Atomic = Weex.Atomic
const extend = Weex.utils.extend
// attrs:
// - checked: if is checked.
// - disabled: if true, this component is not available for interaction.
function Switch (data) {
this.options = extend({}, defaults)
this.checked = data.attr.checked
&& data.attr.checked !== 'false'
this.data = data
this.width = this.options.width
this.height = this.options.height
Atomic.call(this, data)
}
Switch.prototype = Object.create(Atomic.prototype)
extend(Switch.prototype, proto)
extend(Switch.prototype, { attr })
extend(Switch.prototype, {
style: extend(Object.create(Atomic.prototype.style), style)
})
extend(Switch.prototype, { event })
Weex.registerComponent('switch', Switch)
}
export default { init }