| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- import React from 'react'
- import { shallowEqualImmutable, getY, isMac } from 'utils/utils'
- import uiActions from 'actions/ui'
- import newEventActions from 'actions/newEvent'
- import newEventStores from 'stores/newEvent'
- import {
- getEventBlockByBid,
- filterBlocks,
- getBidList
- } from 'stores/funcs/newEvent'
- import { dragPosition, dragUtils } from 'stores/funcs/event/dragUtils'
- import { CONTEXT_MENU_TYPE, EVENT_BLOCK_TYPE } from 'const/const'
- export default class Block extends React.Component {
- constructor(props) {
- super(props)
- this.curBlockId = newEventStores.curBlockId
- this.multiBlockIds = newEventStores.multiBlockIds
- this.state = {
- isActive: this.isActive(props.bid),
- isEnable: this.isEnable(props.bid),
- isExpand: this.isExpand(props.bid),
- hasChildren: this.hasChildren(props.bid)
- }
- this.onEventChange = this.onEventChange.bind(this)
- this.isActive = this.isActive.bind(this)
- this.isEnable = this.isEnable.bind(this)
- this.isExpand = this.isExpand.bind(this)
- this.onSelectBlock = this.onSelectBlock.bind(this)
- this.onToggleBlockExpand = this.onToggleBlockExpand.bind(this)
- this.getLineColor = this.getLineColor.bind(this)
- this.getGapLeft = this.getGapLeft.bind(this)
- // 拖拽
- this.allowDrag = this.allowDrag.bind(this)
- this.allowDrop = this.allowDrop.bind(this)
- this.getPosition = this.getPosition.bind(this)
- this.onDragStart = this.onDragStart.bind(this)
- this.onDragEnd = this.onDragEnd.bind(this)
- this.onDragOver = this.onDragOver.bind(this)
- this.onDrop = this.onDrop.bind(this)
- // 右键
- this.onContextMenu = this.onContextMenu.bind(this)
- }
- shouldComponentUpdate(nextProps, nextState) {
- return (
- !shallowEqualImmutable(this.props, nextProps) ||
- !shallowEqualImmutable(this.state, nextState)
- )
- }
- componentDidUpdate(preProps) {
- let obj = {}
- // bid改变时需要更新
- if (preProps.bid !== this.props.bid) {
- obj.isActive = this.isActive()
- obj.isEnable = this.isEnable()
- obj.isExpand = this.isExpand()
- obj.hasChildren = this.hasChildren()
- }
- if (Object.keys(obj).length > 0) {
- this.setState(obj)
- }
- }
- componentDidMount() {
- this.unsubscribe = newEventStores.listen(this.onEventChange)
- }
- componentWillUnmount() {
- this.unsubscribe()
- }
- onEventChange(status) {
- let obj = {}
- if (status.types.includes('curBlockId')) {
- if (this.curBlockId !== status.data.curBlockId) {
- this.curBlockId = status.data.curBlockId
- let isActive = this.isActive()
- if (this.state.isActive !== isActive) {
- obj.isActive = isActive
- }
- }
- }
- if (status.types.includes('multiBlockIds')) {
- this.multiBlockIds = status.data.multiBlockIds
- let isActive = this.isActive()
- if (this.state.isActive !== isActive) {
- obj.isActive = isActive
- }
- }
- if (status.types.includes('toggleBlockProp')) {
- if (this.props.bid === status.data.affectBlockId) {
- if (status.data.prop === 'enable') {
- let isEnable = this.isEnable()
- if (this.state.isEnable !== isEnable) {
- obj.isEnable = isEnable
- }
- } else if (status.data.prop === 'expand') {
- let isExpand = this.isExpand()
- if (this.state.isExpand !== isExpand) {
- obj.isExpand = isExpand
- }
- }
- }
- }
- if (
- (status.types.includes('changeBlockChildren') &&
- status.data &&
- status.data.parentBid === this.props.bid) ||
- (status.types.includes('reloadBlock') &&
- this.props.bid === status.data.affectBlockId)
- ) {
- let hasChildren = this.hasChildren()
- if (hasChildren !== this.state.hasChildren) {
- obj.hasChildren = hasChildren
- }
- }
- if (Object.keys(obj).length > 0) {
- this.setState(obj)
- }
- }
- isActive(bid) {
- let _bid = bid || this.props.bid
- return this.curBlockId === _bid || this.multiBlockIds.indexOf(_bid) >= 0
- }
- isEnable(bid) {
- let _bid = bid || this.props.bid
- let result = true
- let block = getEventBlockByBid(_bid)
- if (block) {
- result = block.enable !== false
- }
- return result
- }
- isExpand(bid) {
- let _bid = bid || this.props.bid
- let result = true
- let block = getEventBlockByBid(_bid)
- if (block) {
- result = block.expand !== false
- }
- return result
- }
- hasChildren(bid) {
- let _bid = bid || this.props.bid
- let result = false
- let block = getEventBlockByBid(_bid)
- if (block) {
- result = block.children && block.children.length > 0
- }
- return result
- }
- onSelectBlock(e, allowMulti = false) {
- if (
- this.props.eventNodeId &&
- this.props.eventNodeId !== newEventStores.curEventNodeId
- ) {
- newEventActions.selectEvent({ eventNodeId: this.props.eventNodeId })
- } else {
- // 多选
- let isCtrl = e && (isMac ? e.metaKey : e.ctrlKey)
- if (isCtrl) {
- newEventActions.selectMultiBlocks({ blockId: this.props.bid })
- return
- }
- let isShift = e && e.shiftKey
- if (isShift) {
- newEventActions.shiftSelectBlocks({ blockId: this.props.bid })
- return
- }
- }
- if (
- !this.state.isActive ||
- (
- this.multiBlockIds.length > 0 &&
- (
- !allowMulti ||
- (
- allowMulti &&
- !this.multiBlockIds?.includes(this.props.bid)
- )
- )
- )
- ) {
- newEventActions.selectBlock({ blockId: this.props.bid })
- }
- }
- onToggleBlockExpand() {
- newEventActions.toggleBlockProp({ blockId: this.props.bid, prop: 'expand' })
- }
- getLineColor() {
- let group = ['red', 'green', 'purple', 'ching', 'orange', 'blue']
- return group[this.props.layer % 6]
- }
- getNextLineColor() {
- let group = ['red', 'green', 'purple', 'ching', 'orange', 'blue']
- return group[(this.props.layer + 1) % 6]
- }
- getGapLeft() {
- return 8 + this.props.layer * 20 + (this.props.layer + 1)
- }
- getGroupColor() {
- const group = ['color1', 'color2', 'color3', 'color4', 'color5']
- // const group = ['#7F438F', '#E5C88E', '#EEB2B2', '#B5D8F1', '#CBFF97']
- return group[(this.props.groupLayer) % 5]
- }
- blockMainStyle() {
- if (this.props.groupLayer >= 1) {
- return {
- paddingLeft: `${(this.props.nestGroupLayer - 1) * 2}px`,
- marginRight: `${(this.props.groupLayer) * 2}px`
- }
- }
- return null
- }
- getLoops(bid) {
- let _bid = bid || this.props.bid
- let block = getEventBlockByBid(_bid)
- if (block && block.type === EVENT_BLOCK_TYPE.LOOP) {
- if (this.props.loops) {
- return JSON.stringify(
- [].concat(JSON.parse(this.props.loops), [block.bid])
- )
- } else {
- return JSON.stringify([block.bid])
- }
- } else {
- return this.props.loops
- }
- }
- indexLeftStyle() {
- // let _bid = this.props.bid
- // let block = getEventBlockByBid(_bid)
- // console.log(block?.type, this.props.offspringInNestGroupLayer, this.props.nestGroupLayer)
- if (this.props.offspringInNestGroupLayer >= 2 && this.props.nestGroupLayer === 0) {
- return { marginLeft: 20 + (this.props.offspringInNestGroupLayer - 1) * 2 + 'px' }
- }
- return undefined
- }
- extraGapGroupLayer() {
- if (this.props.offspringInNestGroupLayer >= 2 && this.props.nestGroupLayer === 0) {
- return this.props.offspringInNestGroupLayer
- } else {
- return this.props.extraGapGroupLayer || 0
- }
- }
- //拖拽
- allowDrag() {
- let allow = true
- if (
- document.activeElement.tagName === 'INPUT' ||
- document.activeElement.tagName === 'TEXTAREA'
- ) {
- allow = false // block dragging
- }
- if (!this.isActive(this.props.bid)) {
- this.onSelectBlock()
- }
- return allow
- }
- allowDrop(bid, position, multiInfo) {
- let result = false
- let dragBlock = getEventBlockByBid(bid)
- let targetBlock = getEventBlockByBid(this.props.bid)
- let dropBlock = undefined
- switch (position) {
- case dragPosition.mid:
- // 加到targetBlock里面
- dropBlock = targetBlock
- break
- case dragPosition.bot:
- case dragPosition.top:
- // 实际是放在targetBlock的父级
- if (targetBlock.parentBid) {
- let targetParentBlock = getEventBlockByBid(targetBlock.parentBid)
- if (targetParentBlock) {
- dropBlock = targetParentBlock
- } else {
- dropBlock = undefined
- }
- }
- break
- }
- if (multiInfo && multiInfo.length > 0) {
- // 多个移动
- let blockTypes = []
- multiInfo = filterBlocks(multiInfo)
- multiInfo.forEach(bid => {
- let block = getEventBlockByBid(bid)
- if (block && block.type) {
- let type = block.type
- if (blockTypes.indexOf(type) === -1) {
- blockTypes.push(type)
- }
- }
- })
- if (
- targetBlock &&
- targetBlock.type === EVENT_BLOCK_TYPE.ROOT &&
- blockTypes.length === 1 &&
- blockTypes[0] === EVENT_BLOCK_TYPE.ROOT &&
- position !== dragPosition.mid
- ) {
- // 拖的和drop的都是Root只可放上和下
- result = true
- } else if (dropBlock) {
- // 提炼出可drop的情况
- if (dropBlock.type === EVENT_BLOCK_TYPE.ACTION) {
- if (
- blockTypes.length === 1 &&
- blockTypes[0] === EVENT_BLOCK_TYPE.STATUS &&
- dropBlock.action &&
- dropBlock.action.callback === true
- ) {
- result = true
- }
- } else if (dropBlock.type === EVENT_BLOCK_TYPE.COMMENT) {
- result = false
- } else {
- if (
- blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) === -1 &&
- blockTypes.indexOf(EVENT_BLOCK_TYPE.STATUS) === -1
- ) {
- result = true
- }
- }
- }
- } else {
- // 单个移动
- if (
- dragBlock &&
- targetBlock &&
- dragBlock.type === EVENT_BLOCK_TYPE.ROOT &&
- targetBlock.type === EVENT_BLOCK_TYPE.ROOT &&
- position !== dragPosition.mid
- ) {
- // 拖的和drop的都是Root只可放上和下
- result = true
- } else if (dragBlock && dropBlock) {
- // 提炼出可drop的情况
- if (dropBlock.type === EVENT_BLOCK_TYPE.ACTION) {
- if (
- dragBlock.type === EVENT_BLOCK_TYPE.STATUS &&
- dropBlock.action &&
- dropBlock.action.callback === true
- ) {
- result = true
- }
- } else if (dropBlock.type === EVENT_BLOCK_TYPE.COMMENT) {
- result = false
- } else {
- if (
- dragBlock.type !== EVENT_BLOCK_TYPE.ROOT &&
- dragBlock.type !== EVENT_BLOCK_TYPE.STATUS
- ) {
- result = true
- }
- }
- }
- }
- return result
- }
- getPosition(dragBlockId, deltaTop, maxHeight, multiInfo) {
- let position = dragPosition.mid
- let mid1 = maxHeight / 3
- let mid2 = (maxHeight * 2) / 3
- if (deltaTop >= 0 && deltaTop <= mid1) {
- position = dragPosition.top
- } else if (deltaTop >= mid2 && deltaTop <= maxHeight) {
- position = dragPosition.bot
- }
- let dropBlock = getEventBlockByBid(this.props.bid)
- if (multiInfo && multiInfo.length > 0) {
- // 多个移动
- let blockTypes = []
- multiInfo = filterBlocks(multiInfo)
- multiInfo.forEach(bid => {
- let block = getEventBlockByBid(bid)
- if (block && block.type) {
- blockTypes.push(block.type)
- }
- })
- if (
- dropBlock &&
- dropBlock.type === EVENT_BLOCK_TYPE.ROOT &&
- blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) === -1
- ) {
- // drop为root且drap均非root的情况
- position = dragPosition.mid
- }
- } else {
- // 单个移动
- let dragBlock = getEventBlockByBid(dragBlockId)
- if (
- dropBlock &&
- dropBlock.type === EVENT_BLOCK_TYPE.ROOT &&
- !(dragBlock && dragBlock.type === EVENT_BLOCK_TYPE.ROOT)
- ) {
- // 不同为root的情况且drop的root的情况
- position = dragPosition.mid
- }
- }
- return position
- }
- onDragStart(e) {
- dragUtils.isDragging = true
- e.stopPropagation()
- if (!this.allowDrag()) {
- e.preventDefault()
- return
- }
- e.dataTransfer.effectAllowed = 'move'
- dragUtils.setDraggingItemInfo(this.props.bid, this.state.isExpand)
- dragUtils.setDraggingMultiItemsInfo(this.multiBlockIds)
- // 对block的处理
- if (this.multiBlockIds.length === 0) {
- if (this.state.isExpand && this.state.hasChildren) {
- // 关闭起来
- newEventActions.toggleBlockProp({
- blockId: this.props.bid,
- prop: 'expand',
- value: false,
- addRecord: false
- })
- }
- }
- }
- onDragEnd(e) {
- // drop先执行
- e.stopPropagation()
- if (dragUtils.isDragging) {
- dragUtils.isDragging = false
- let dragInfo = dragUtils.getDraggingItemInfo()
- // 对block的处理
- if (dragInfo) {
- newEventActions.toggleBlockProp({
- blockId: dragInfo.bid,
- prop: 'expand',
- value: dragInfo.expand,
- addRecord: false
- })
- }
- dragUtils.resetDraggingItem()
- }
- }
- onDragOver(e) {
- e.stopPropagation()
- if (!dragUtils.isDragging) {
- return
- }
- e.preventDefault()
- let allowDrop = true
- let deltaTop =
- e.clientY -
- getY(e.currentTarget) +
- document.querySelector('.jenga-panel').scrollTop
- let maxHeight = e.currentTarget.clientHeight
- let position = dragPosition.mid
- let info = dragUtils.getDraggingItemInfo()
- let multiInfo = dragUtils.getDraggingMultiItemsInfo()
- if (multiInfo && multiInfo.length > 0) {
- // 多个移动
- // console.log('多个移动。。。')
- multiInfo = filterBlocks(multiInfo)
- let bidList = []
- multiInfo.forEach(bid => {
- getBidList({ blockId: bid, list: bidList })
- })
- if (bidList.indexOf(this.props.bid) > -1) {
- // dragOver为自己或childern时不允许
- allowDrop = false
- // console.log('包含自己。。。')
- } else {
- let blockTypes = []
- multiInfo.forEach(bid => {
- let block = getEventBlockByBid(bid)
- if (block && block.type) {
- let type = block.type
- if (blockTypes.indexOf(type) === -1) {
- blockTypes.push(type)
- }
- }
- })
- if (
- multiInfo.length > 1 &&
- blockTypes.indexOf(EVENT_BLOCK_TYPE.ROOT) > -1 &&
- blockTypes.length > 1
- ) {
- // 多个待移动block中同时有root和非root时不允许
- allowDrop = false
- // console.log('同时有root和非root。。。')
- } else {
- // 对drag的处理
- // console.log('ok。。。')
- position = this.getPosition(info.bid, deltaTop, maxHeight, multiInfo)
- allowDrop = this.allowDrop(info.bid, position, multiInfo)
- }
- }
- } else {
- // 单个移动
- // console.log('单个移动。。。')
- // 相同bid不允许
- if (this.props.bid !== info.bid) {
- // 对drag的处理
- position = this.getPosition(info.bid, deltaTop, maxHeight, multiInfo)
- allowDrop = this.allowDrop(info.bid, position, multiInfo)
- } else {
- allowDrop = false
- }
- }
- dragUtils.setOverItemInfo(position, this.props.bid, allowDrop)
- }
- onDrop(e) {
- e.stopPropagation()
- e.preventDefault()
- dragUtils.isDragging = false
- let dragInfo = dragUtils.getDraggingItemInfo()
- let multiInfo = dragUtils.getDraggingMultiItemsInfo()
- multiInfo = filterBlocks(multiInfo)
- let overInfo = dragUtils.getOverItemInfo()
- // 对block的处理
- if (multiInfo.length === 0) {
- if (dragInfo) {
- newEventActions.toggleBlockProp({
- blockId: dragInfo.bid,
- prop: 'expand',
- value: dragInfo.expand,
- addRecord: false
- })
- }
- }
- // 移动block
- if (overInfo && overInfo.isAllow) {
- newEventActions.moveBlock({
- srcBlockId: dragInfo.bid,
- targetBlockId: overInfo.bid,
- position: overInfo.overPosition,
- multiSrcBlockIds: multiInfo
- })
- }
- dragUtils.resetDraggingItem()
- }
- onContextMenu(e) {
- e.preventDefault()
- e.stopPropagation()
- this.onSelectBlock(e, true)
- let info = {
- x: e.pageX,
- y: e.pageY,
- type: CONTEXT_MENU_TYPE.EVENT
- }
- uiActions.contextMenu(info)
- }
- render() {
- return null
- }
- }
|