import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import {transToArray, preventDefault, getScrollTop} from '../../utils/Tool'
import Logger from '../../utils/logger'
import Icon from '../../icon'
/**
* <h5>筛选控件,主要包括组件:</h5>
* <strong><a href='../classes/FilterContainer.html'>FilterContainer 单选筛选</a></strong><br/>
* <strong><a href='../classes/FilterCheckbox.html'>FilterCheckbox 多选筛选</a></strong><br>
* <strong><a href='../classes/FilterPanelSimple.html'>FilterPanelSimple 简单面板</a></strong><br>
* <strong><a href='../classes/FilterPanel.html'>FilterPanel 面板</a></strong><br>
* <strong><a href='../classes/FilterPanelCheckbox.html'>FilterPanelCheckbox 多选面板</a></strong><br>
* <strong><a href='../classes/FilterItemGroup.html'>FilterItemGroup 主菜单</a></strong><br>
* <strong><a href='../classes/FilterItem.html'>FilterItem 筛选项</a></strong><br>
* <h6>点击以上链接或者左侧导航栏的组件名称链接进行查看</h6>
* @module 筛选控件
* @main 筛选控件
* @static
*/
/**
* 单选筛选<br/>
* - 可通过index设置筛选默认打开的面板。默认-1,即都不打开。
* - 可通过hideCat选择是否要显示筛选头部。
* - 可通过clickCallback设置有效选择的回调,当没有按钮时选中即触发,有按钮时点击按钮时触发。
* - 可通过noShadow设置是否显示阴影,默认显示。
* - 可通过hideCallback手动调用隐藏panel。
* - 可通过closeCallback获取点击阴影关闭的回调。
*
* 主要属性和接口:
* - index: 默认打开的面板。
* - hideCat: 是否显示筛选头部。
* - clickCallback: 有效选择的回调。
* - noShadow: 是否显示阴影。
* - hideCallback: 手动调用隐藏panel。
*
* 有4种形式,其一,简单单选模式。<br/>
* 如:
* ```code
* this.state = {
* panel1:[
* {key:'sndq',value:'上南地区'},
* {key:'ljz',value:'陆家嘴'},
* {key:'bbb',value:'八佰伴'},
* {key:'pdxq',value:'浦东新区'}
* ]
* }
* ...
* <FilterContainer index={0} hideCat={false} clickCallback={this.clickCallback.bind(this)} ref={(container)=>{this.container=container}} noShadow={true}>
* <PanelSimple readOnly className='panel1' selected={{key:'ljz',value:'陆家嘴'}}>
* {
* this.state.panel1.map(function(item){
* return <Item key={item.key} itemKey={item.key}>{item.value}</Item>
* })
* }
* </PanelSimple>
* </FilterContainer>
* ...
* this.container.hideCallback();
* ```
* 其二,简单多选模式。<br/>
* 如:
* ```code
* <FilterContainer index={0} clickCallback={this.clickCallback.bind(this)}>
* <PanelCheckbox readOnly className='panel1' selected={{key:'ljz',value:'陆家嘴'}} type='simple'>
* {
* this.state.panel1.map(function(item){
* return <Item key={item.key} itemKey={item.key}>{item.value}</Item>
* })
* }
* </PanelCheckbox>
* </FilterContainer>
* ```
* 其三,双栏单选模式。<br/>
* 如:
* ```code
* <FilterContainer index={0} hideCat={false} clickCallback={this.clickCallback.bind(this)}>
* <Panel readOnly selected={{key:'s_flower',value:'花店'}}>
* <ItemGroup label={<span style={{color:'red'}}>美食</span>}>
* <Item itemKey='f_bbc'>本帮江浙菜</Item>
* ...
* </ItemGroup>
* <ItemGroup label='电影'>
* <Item itemKey='m_p'>私人影院</Item>
* ...
* </ItemGroup>
* ...
* </Panel>
* </FilterContainer>
* ```
* 其三,双栏多选模式。<br/>
* 如:
* ```code
* <FilterContainer index={0} hideCat={false} clickCallback={this.clickCallback.bind(this)}>
* <PanelCheckbox readOnly selected={{key:'s_flower',value:'花店'}}>
* <ItemGroup mainKey='ms' label={<span style={{color:'red'}}>美食</span>}>
* <Item itemKey='f_bbc'>本帮江浙菜</Item>
* ...
* </ItemGroup>
* <ItemGroup mainKey='dy' label='电影'>
* <Item itemKey='m_p'>私人影院</Item>
* ...
* </ItemGroup>
* ...
* </PanelCheckbox>
* </FilterContainer>
* ```
*
* @class FilterContainer
* @module 筛选控件
* @extends Component
* @constructor
* @since 2.0.0
* @demo ph-filter|ph-filter.js {展示}
* @show true
* */
export default class FilterContainer extends Component{
static propTypes= {
/**
* 默认展开筛选的索引,默认-1,即都不展开
* @property index
* @type Number
* @default -1
* */
index: PropTypes.number,
/**
* 是否隐藏头部
* @property hideCat
* @type Boolean
* @default false
* */
hideCat: PropTypes.bool,
/**
* 是否显示阴影
* @property noShadow
* @type Boolean
* @default false
* */
noShadow: PropTypes.bool,
/**
* 有效选择触发的回调函数
* @method clickCallback
* @param {string} key 返回选中的key值
* @type Function
* */
clickCallback: PropTypes.func,
/**
* 手动隐藏panel
* @method hideCallback
* @type Function
* */
hideCallback: PropTypes.func,
/**
* 点击阴影关闭的回调
* @method closeCallback
* @type Function
* */
closeCallback: PropTypes.func
}
static defaultProps = {
index: -1,
hideCat: false,
clickCallback: null,
stable: false
}
constructor(props,context){
super(props,context)
new Logger('ph-filter')
this.catClick = false
this.activeIndex = props.index
this.state={
catList: this.getCatList(props),
activeCat: props.index,
fixed: false
}
this.windowScrollHandle = this.windowScrollHandle.bind(this)
this.containerOffsetTop = 0
window.addEventListener('scroll', this.windowScrollHandle, false)
}
windowScrollHandle(){
if(this.state.activeCat>-1) return
if(getScrollTop() > this.containerOffsetTop){
if(!this.state.fixed) this.setState({fixed: true})
}else{
if(this.state.fixed) this.setState({fixed: false})
}
}
componentDidMount(){
setTimeout(()=>{
this.containerOffsetTop = this.filterContainer.offsetTop
}, 0)
}
componentWillUnmount(){
window.removeEventListener('scroll', this.windowScrollHandle, false)
this.fixScroll(null)
}
componentWillReceiveProps(nextProps){
let self = this,
setted = false // 解决map无法跳出的问题
React.Children.map(nextProps.children, function(panel,index){
if(setted) return
if(self.state.catList[index] !== panel.props.selected){
self.setState({
catList: self.getCatList(nextProps)
})
setted = true
}
})
}
getCatList(props){
return React.Children.map(props.children, function(panel,index){
//如果panel设置了selected属性的话直接读取selected属性;如果panel没有设置selected属性,则读取default用来展示在cat列表中
return panel.props.selected && panel.props.selected.key ? panel.props.selected:{
key:'',
value: panel.props.default ? panel.props.default:''
}
})
}
setCatList(){
this.setState({
catList: this.getCatList(this.props)
})
}
categoryChange(index,category,hasButtons,options){
let catList = this.state.catList.slice(),
{clickCallback} = this.props
if(hasButtons) return
catList[index] = category
this.setState({
catList,
activeCat: -1
}, ()=>{
this.fixScroll(-1)
})
console.log('>>>>hasButtons', hasButtons)
clickCallback && clickCallback(category.key, this.state.activeCat, options)
}
activeCat(index){
//展开某一个cat
this.catClick = true
this.activeIndex = index
if(index==this.state.activeCat){
index = -1
}
this.setState({
activeCat:index
}, ()=>{
this.catClick = false
this.fixScroll(index)
});
}
renderPanelList(){
let self=this,
{catList,activeCat}=self.state
return React.Children.map(this.props.children,function(panel,index){
let {choose, getChooseData, hideCat} = self.props,
{clickCallback} = panel.props,
show = (index==activeCat)
if(hideCat && index==0) show=true;
if(self.catClick && self.activeIndex==index) clickCallback && clickCallback(activeCat==index);
let panelProps = {
categoryChange: self.categoryChange.bind(self),
// selected: catList[index],
setCatList: self.setCatList.bind(self),
panelIndex: index,
show: show,
getChooseData: transToArray(getChooseData)
}
return React.cloneElement(panel, panelProps)
})
}
renderCatList(){
if(this.props.hideCat){
return null;
}
let self=this,
{catList,activeCat}=self.state
return catList.map(function(catCfg,index){
return (
<li key={'cat-'+index}
className={classnames('ph-col', 'ph-filter-header-item', index==activeCat ? 'active':'')}
onClick={function(){self.activeCat(index);}}
>
<a href='javascript:;'>
<span className='ph-filter-header-text'>{catList[index].value}</span>
<Icon phIcon='expand-more' />
</a>
</li>
)
})
}
fixScroll(index){
let elem = document.body,
classList = elem.classList,
scrollingElement = document.scrollingElement || elem
if(index==null){
classList.remove('noscroll')
return
}
if(index==-1){
classList.remove('noscroll')
scrollingElement.scrollTop = this.scrollTop
}else{
if(elem.className.indexOf('noscroll')==-1) {
this.scrollTop = scrollingElement.scrollTop
// if(this.filterContainer.offsetTop && this.scrollTop < this.filterContainer.offsetTop){ // 打开时滚动到顶部
// this.scrollTop = this.filterContainer.offsetTop
// }
classList.add('noscroll')
elem.style.top = -this.scrollTop + 'px'
}
}
}
closeCallback(){
this.hidePanel()
this.props.closeCallback && this.props.closeCallback()
}
hidePanel(){
this.setState({
activeCat: -1
}, ()=>{
this.fixScroll(-1)
})
}
hideCallback(){
this.hidePanel()
}
render(){
let {stable, className, noShadow, style} = this.props,
{activeCat, fixed} = this.state
return(
<div className='ph-filter-occupy'>
<div className={classnames(
'ph-filter-container',
activeCat==-1? '':'ph-filter-container-shadow',
noShadow? 'ph-filter-container-noshadow':'',
fixed? 'ph-filter-container-fixed':'',
className
)}
ref={(filterContainer)=>{this.filterContainer = filterContainer}}
style={{top: stable && !fixed && activeCat>-1? this.containerOffsetTop+'px':'', ...style}}
>
<div className='ph-filter-shadow' onClick={this.closeCallback.bind(this)}></div>
<ul className='cat ph-row ph-filter-header'>
{this.renderCatList()}
</ul>
{this.renderPanelList()}
</div>
</div>
);
}
}