Element.js 6.59 KB
import React from 'react'
import Move from '../libs/move'
import EventEmitter from '../libs/eventEmitter'
import autoBind from 'react-autobind'

export default class Element extends React.Component {
  static get getDefaultProps() {
    return {
      // allow the initial position to be passed in as a prop
      initialPos: {x: 0, y: 0}
    }
  }

  constructor(props){
    super(props);
    this.state = {
      pos: this.props.initialPos,
      dragging: false,
      rel: null, // position relative to the cursor
      zIndex: 2,
      parent_id: null,
      hasMoved: false,
      edit: false,
      name: this.props.name,
      prev_name: this.props.name
    };
    autoBind(this);
  }

  componentDidUpdate(props, state) {
    if (this.state.dragging && !state.dragging) {
      document.addEventListener('mousemove', this.onMouseMove)
      document.addEventListener('mouseup', this.onMouseUp)
    } else if (!this.state.dragging && state.dragging) {
      document.removeEventListener('mousemove', this.onMouseMove)
      document.removeEventListener('mouseup', this.onMouseUp)
    }
  }

  onMouseDown(event) {
    if (event.button !== 0) return

    if (!this.props.isDropZoneChild) {
      this.handleCloneElement()
    }

    this.setState({
      dragging: true,
      rel: {
        x: event.pageX - this.element().offsetLeft,
        y: event.pageY - this.element().offsetTop
      },
      zIndex: this.state.zIndex++,
      hasMoved: false
    })

    event.stopPropagation()
    event.preventDefault()
  }

  onMouseMove(event) {
    if (!this.state.dragging) return

    let pageWidth
    if (this.props.isDropZoneChild) {
      pageWidth = this.dropzone().clientWidth
    } else {
      pageWidth = document.documentElement.clientWidth + 20
    }
    //var pageHeight = document.documentElement.clientHeight

    const elementWidth = this.element().offsetWidth
    const elementHeight = this.element().offsetHeight

    const maxX = pageWidth - elementWidth
    const maxY = this.dropzone().clientHeight - elementHeight
    let moveX = event.pageX - this.state.rel.x
    let moveY = event.pageY - this.state.rel.y

    moveX = Math.min( maxX, Math.max(0, moveX) )
    moveY = Math.min( maxY, Math.max(0, moveY) )

    this.setState({
      pos: {
        x: moveX,
        y: moveY
      },
      hasMoved: true
    })

    event.stopPropagation()
    event.preventDefault()
  }

  onMouseUp(event) {
    this.setState({ dragging: false })

    if (this.props.isDropZoneChild) {
      const element = {
        id: this.props.id,
        pos_x: this.state.pos.x,
        pos_y: this.state.pos.y,
      }
      if (this.state.hasMoved) {
        EventEmitter.dispatch('element:update', element)
      }
    } else if (this.jl(this.element(), this.dropzone())) {
      this.handleMoveDropZone()
    } else {
      Move( this.element() , { left: this.props.initialPos.x , top: this.props.initialPos.y } )
      this.handleDeleteLastElement()
    }

    event.stopPropagation()
    event.preventDefault()
  }

  element() {
    return this.refs.meta_element
  }

  dropzone() {
    return document.getElementById('dropzone')
  }

  sidebar() {
    return document.getElementById('sidebar')
  }

  handleCloneElement() {
    if (this.props.handleCloneElement) {
      const element = {
        id: this.props.id + 3,
        name: this.props.name,
        initialPos: {
          x: this.props.initialPos.x,
          y: this.props.initialPos.y
        },
        target_type: this.props.target_type
      }
      this.props.handleCloneElement(element)
    }
  }

  handleDeleteLastElement() {
    if (this.props.handleDeleteLastElement) {
      this.props.handleDeleteLastElement()
    }
  }

  handleMoveDropZone() {
    const element = {
      name: this.props.name,
      target_type: this.props.target_type,
      initialPos: {
        x: this.state.pos.x - this.sidebar().clientWidth,
        y: this.state.pos.y - this.sidebar().clientHeight + 55
      }
    }
    EventEmitter.dispatch('moveDropZone', element)

    if (this.props.handleDeleteElement) {
      this.props.handleDeleteElement(this.props.meta_element)
    }
  }

  // 碰撞
  // pz: function(obj1, obj2) {
  //   var L1 = obj1.offsetLeft
	// 	var R1 = obj1.offsetLeft + obj1.offsetWidth
	// 	var T1 = obj1.offsetTop
	// 	var B1 = obj1.offsetTop + obj1.offsetHeight
	//
	// 	var L2 = obj2.offsetLeft
	// 	var R2 = obj2.offsetLeft + obj2.offsetWidth
	// 	var T2 = obj2.offsetTop
	// 	var B2 = obj2.offsetTop + obj2.offsetHeight
	//
	// 	if( R1<L2 || L1>R2 || B1<T2 || T1>B2 ){
	// 		return false
	// 	}
	// 	else{
	// 		return true
	// 	}
  // },

  jl(obj1, obj2){
		let result = obj1.offsetLeft - obj2.offsetLeft - this.props.initialPos.x + 65

    return result > 0 ? true : false
	}

  handleClick() {
    if (this.props.isDropZoneChild) {
      this.setState({ edit: true })
    }
  }

  handleChange(e) {
    this.setState({ name: e.target.value })
  }

  handleBlur() {
    this.handleUpdateName()
  }

  handleKeyPress(e) {
    if (e.key === 'Enter') {
      this.handleUpdateName()
    }
  }

  handleUpdateName() {
    this.setState({ edit: false })
    const element = {
      id: this.props.id,
      name: this.state.name
    }
    if (this.state.name != this.state.prev_name) {
      if (this.state.name.trim() == "") {
        this.setState({ name: this.state.prev_name })
      } else {
        EventEmitter.dispatch('element:update', element)
        this.setState({ prev_name: this.state.name })
      }
    }
  }

  handleDoubleClick() {
    const childrenObjectType = this.props.childrenObjectType
    const url = `/regional_design/${this.props.id}?object=${childrenObjectType}`
    if (childrenObjectType != 'drug_brandreth_grid') {
      this.props.hashHistory.push(url)
    }
  }

  divBlock() {
    return (
      <div style={{ position: 'absolute', left: this.state.pos.x + 'px', top: this.state.pos.y + 'px', zIndex: this.state.zIndex }} ref='meta_element' className="meta-element text-center" onMouseDown={ this.onMouseDown } onDoubleClick={ this.handleDoubleClick }>
        <span onClick={ this.handleClick }>{this.state.name}</span>
      </div>
    )
  }

  inputText() {
    return (
      <div style={{ position: 'absolute', left: this.state.pos.x + 'px', top: this.state.pos.y + 'px', zIndex: this.state.zIndex }} className="input-meta-element text-center">
        <input autoFocus type="text" id="formHorizontalName" className="form-control" ref='name' value={ this.state.name } onChange={ this.handleChange } onBlur={ this.handleBlur } onKeyPress={ this.handleKeyPress } />
      </div>
    )
  }

  render() {
    if (this.state.edit) {
      return this.inputText()
    } else {
      return this.divBlock()
    }
  }
}