diff --git a/lib/EventListener.js b/lib/EventListener.js new file mode 100644 index 0000000..f8c9c23 --- /dev/null +++ b/lib/EventListener.js @@ -0,0 +1,56 @@ +/** + * Copyright 2013-2014 Facebook, Inc. + * + * This file contains a modified version of: + * https://github.com/facebook/react/blob/v0.12.0/src/vendor/stubs/EventListener.js + * + * Licensed 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. + * + * TODO: remove in favour of solution provided by: + * https://github.com/facebook/react/issues/285 + */ + +/** + * Does not take into account specific nature of platform. + */ +'use strict'; + +var EventListener = { + /** + * Listen to DOM events during the bubble phase. + * + * @param {DOMEventTarget} target DOM element to register listener on. + * @param {string} eventType Event type, e.g. 'click' or 'mouseover'. + * @param {function} callback Callback function. + * @return {object} Object with a `remove` method. + */ + listen: function listen(target, eventType, callback) { + if (target.addEventListener) { + target.addEventListener(eventType, callback, false); + return { + remove: function remove() { + target.removeEventListener(eventType, callback, false); + } + }; + } else if (target.attachEvent) { + target.attachEvent('on' + eventType, callback); + return { + remove: function remove() { + target.detachEvent('on' + eventType, callback); + } + }; + } + } +}; + +module.exports = EventListener; diff --git a/lib/Slider.js b/lib/Slider.js index 44f3237..b5c4146 100644 --- a/lib/Slider.js +++ b/lib/Slider.js @@ -1,5 +1,6 @@ /** @jsx React.DOM */ var React = require('react'); +var EventListener = require('./EventListener'); function pauseEvent(e) { if (e.stopPropagation) { @@ -13,6 +14,13 @@ function pauseEvent(e) { return false; } +function prefixClsFn(prefixCls) { + var args = Array.prototype.slice.call(arguments, 1); + return args.map((s)=> { + return prefixCls + '-' + s; + }).join(' '); +} + var Slider = React.createClass({ propTypes: { min: React.PropTypes.number, @@ -43,7 +51,7 @@ var Slider = React.createClass({ getInitialState: function() { var props = this.props; - var value = props.value; + var value = this._trimAlignValue(props.value); var marksLen = props.marks.length; if (marksLen > 0) { value = ((props.max - props.min) / (marksLen - 1)) * (props.index); @@ -54,7 +62,7 @@ var Slider = React.createClass({ upperBound: 0, sliderLength: 0, value: value, - active: props.disabled ? '' : ((value > 0 || props.index > 0) ? 'active' : '') + active: props.disabled ? '' : ((value > props.min || props.index > 0) ? 'active' : '') }; }, @@ -64,12 +72,14 @@ var Slider = React.createClass({ }, componentDidMount: function() { - window.addEventListener('resize', this.handleResize); + this._onHandleResizeListener = EventListener.listen(window, 'resize', this.handleResize); this.handleResize(); }, componentWillUnmount: function() { - window.removeEventListener('resize', this.handleResize); + if (this._onHandleResizeListener) { + this._onHandleResizeListener.remove(); + } }, getValue: function() { @@ -124,32 +134,30 @@ var Slider = React.createClass({ var nextValue = this._trimAlignValue(this._calcValue(pixelOffset)); - this.setState({value: nextValue, active: 'active'}, callback.bind(this)); + this.setState({value: nextValue, active: 'active'}, callback); }, _triggerEvents: function(event) { - if (this.props[event]) { - this.props[event](this.state.value); + var props = this.props; + var hasMarks = props.marks && props.marks.length > 0; + if (props[event]) { + props[event](hasMarks ? this.getIndex() : this.state.value); } }, - _addEventHandles: function(eventMap) { - for (var key in eventMap) { - document.addEventListener(key, eventMap[key], false); - } + _addEventHandles: function() { + this._onMouseMoveListener = EventListener.listen(document, 'mousemove', this._onMouseMove); + this._onMouseUpListener = EventListener.listen(document, 'mouseup', this._onMouseUp); }, - _removeEventHandles: function (eventMap) { - for (var key in eventMap) { - document.removeEventListener(key, eventMap[key], false); + _removeEventHandles: function () { + if (this._onMouseMoveListener) { + this._onMouseMoveListener.remove(); } - }, - _getMouseEventMap: function() { - return { - mousemove: this._onMouseMove, - mouseup: this._onMouseUp - }; + if (this._onMouseUpListener) { + this._onMouseUpListener.remove(); + } }, _start: function(position) { @@ -165,18 +173,18 @@ var Slider = React.createClass({ }); }, - _end: function(eventMap) { - this._removeEventHandles(eventMap); + _end: function() { + this._removeEventHandles(); this.setState(this._triggerEvents.bind(this, 'onAfterChange')); }, _onMouseUp: function() { - this._end(this._getMouseEventMap()); + this._end(); }, _onMouseMove: function(e) { - var position = e.pageX; - + pauseEvent(e); + var position = e.pageX || e.clientX; var props = this.props; var state = this.state; @@ -201,6 +209,7 @@ var Slider = React.createClass({ var sliderMin = rect.left; var sliderMax = rect.right; + this.setState({ upperBound: slider.clientWidth, sliderLength: Math.abs(sliderMax - sliderMin), @@ -209,27 +218,29 @@ var Slider = React.createClass({ }, handleMouseDown: function() { - return function(e) { + return (e) => { if (this.props.disabled) { return; } - var position = e.pageX; + var position = e.pageX || e.clientX; this._start(position); - this._addEventHandles(this._getMouseEventMap()); + this._addEventHandles(); pauseEvent(e); - }.bind(this); + }; }, handleSliderMouseDown: function(e) { if (this.props.disabled) { return; } - var position = e.pageX; - this._calValueByPos(position, function() { - this._triggerEvents('onChange'); - this._start(position); - this._addEventHandles(this._getMouseEventMap()); - }.bind(this)); + var position = e.pageX || e.clientX; + this._calValueByPos(position, + () => { + this._triggerEvents('onChange'); + this._start(position); + this._addEventHandles(); + } + ); pauseEvent(e); }, @@ -239,15 +250,21 @@ var Slider = React.createClass({ var stepNum = marksLen > 0 ? marksLen : Math.floor((props.max - props.min) / props.step) + 1; var unit = this.state.sliderLength / (stepNum - 1); - var stepClassName = props.className + '-step'; + var prefixCls = props.className; + var stepClassName = prefixClsFn(prefixCls, 'step'); var elements = []; for (var i = 0; i < stepNum; i++) { + var offset = unit * i; var style = { - left: (unit * i).toFixed(5) + 'px' + left: offset.toFixed(5) }; + var className = prefixClsFn(prefixCls, 'dot'); + if (i <= this.getIndex() || (this._calcValue(offset) <= this.getValue())) { + className = prefixClsFn(prefixCls, 'dot', 'dot-active'); + } elements[i] = ( - + ); } @@ -265,16 +282,22 @@ var Slider = React.createClass({ var offset = unit * i; var style = { - width: (unit / 2).toFixed(5) + 'px' + width: (unit / 2).toFixed(5) }; if (i === (marksLen - 1)) { style.right = '0'; style.width = 'auto'; }else { - style.left = (i > 0 ? (offset - (unit / 4)).toFixed(5) : offset) + 'px'; + style.left = (i > 0 ? (offset - (unit / 4)).toFixed(5) : offset); + } + + var prefixCls = this.props.className; + var className = prefixClsFn(prefixCls, 'mark-text'); + + if (i <= this.getIndex()) { + className = prefixClsFn(prefixCls, 'mark-text', 'mark-text-active'); } - var className = this.props.className + '-mark-text '; return ( {this.props.marks[i]} @@ -289,8 +312,11 @@ var Slider = React.createClass({ elements[i] = this.renderMark(i); } + var prefixCls = this.props.className; + var className = prefixClsFn(prefixCls, 'mark'); + return ( -
+
{elements}
); @@ -298,9 +324,15 @@ var Slider = React.createClass({ renderHandle: function(offset) { var handleStyle = { - left: offset + 'px' + left: offset }; - var className = this.props.className + '-handle ' + this.state.active; + + var prefixCls = this.props.className; + var className = prefixClsFn(prefixCls, 'handle'); + + if (this.state.active) { + className = prefixClsFn(prefixCls, 'handle', 'handle-active'); + } return (
); @@ -334,7 +368,8 @@ var Slider = React.createClass({ var steps = (props.step > 1 || props.marks.length > 0) ? this.renderSteps() : null; var sliderMarks = (props.marks.length > 0) ? this.renderMarks() : null; - var sliderClassName = props.className + (props.disabled ? ' '+props.className+ '-disabled' : ''); + var prefixCls = props.className; + var sliderClassName = props.disabled ? prefixClsFn(prefixCls, 'disabled') : prefixCls; return (