Skip to content

Commit

Permalink
Drop relative to layout paths
Browse files Browse the repository at this point in the history
  • Loading branch information
bor3ham committed Nov 12, 2020
1 parent 351f92d commit 977d803
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 135 deletions.
32 changes: 11 additions & 21 deletions react-editor/src/components/draggable.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ function Draggable(props) {
const [{ isBeingDragged, visibility }, drag, preview] = useDrag({
item: {
type: TYPES.EXISTING,
value: {
type: 'field',
field: props.fieldKey,
},
value: props.identifier,
},
collect: (monitor) => ({
isBeingDragged: monitor.isDragging(),
Expand All @@ -28,21 +25,15 @@ function Draggable(props) {
props.onDropNew(
item.value,
'before',
{
type: 'field',
field: props.fieldKey,
}
props.identifier
)
break
}
case TYPES.EXISTING: {
props.onDropExisting(
item.value,
'before',
{
type: 'field',
field: props.fieldKey,
}
props.identifier
)
break
}
Expand All @@ -60,21 +51,15 @@ function Draggable(props) {
props.onDropNew(
item.value,
'after',
{
type: 'field',
field: props.fieldKey,
}
props.identifier
)
break
}
case TYPES.EXISTING: {
props.onDropExisting(
item.value,
'after',
{
type: 'field',
field: props.fieldKey,
}
props.identifier
)
break
}
Expand All @@ -96,10 +81,10 @@ function Draggable(props) {
{!isBeingDragged && isDragHappening && (
<div className="drop-adjacent before" ref={beforeDrop}></div>
)}
{props.children}
{!isBeingDragged && isDragHappening && (
<div className="drop-adjacent after" ref={afterDrop}></div>
)}
{props.children}
</div>
{deletable && <Button className="delete" onClick={props.onDelete}></Button>}
</div>
Expand All @@ -112,6 +97,11 @@ Draggable.propTypes = {
onDropNew: PropTypes.func,
onDropExisting: PropTypes.func,
fieldKey: PropTypes.string,
identifier: PropTypes.shape({
type: PropTypes.oneOf(['field', 'layout']),
field: PropTypes.string,
path: PropTypes.string,
}).isRequired,
}

export default Draggable
5 changes: 4 additions & 1 deletion react-editor/src/fields/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ function Checkbox(props) {
return (
<>
<Draggable
fieldKey={props.fieldKey}
identifier={{
type: 'field',
field: props.fieldKey,
}}
onDelete={handleDelete}
onDropNew={props.context.onDropNew}
onDropExisting={props.context.onDropExisting}
Expand Down
5 changes: 4 additions & 1 deletion react-editor/src/fields/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ function Text(props) {
return (
<>
<Draggable
fieldKey={props.fieldKey}
identifier={{
type: 'field',
field: props.fieldKey,
}}
onDelete={handleDelete}
onDropNew={props.context.onDropNew}
onDropExisting={props.context.onDropExisting}
Expand Down
5 changes: 4 additions & 1 deletion react-editor/src/fields/textarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ function Textarea(props) {
return (
<>
<Draggable
fieldKey={props.fieldKey}
identifier={{
type: 'field',
field: props.fieldKey,
}}
onDelete={handleDelete}
onDropNew={props.context.onDropNew}
onDropExisting={props.context.onDropExisting}
Expand Down
117 changes: 63 additions & 54 deletions react-editor/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
removePathFromLayout,
getFieldsFromLayoutPath,
updateLayoutPath,
getFieldPath,
insertIntoLayout,
} from './layout-functions.js'

const fieldRenderers = {
Expand Down Expand Up @@ -111,60 +113,67 @@ function WebEditor(props) {
}
const handleDropNew = (item, position, relativeTo) => {
console.log('dropped new', item, position, relativeTo)
// const newFields = {
// ...props.config.fields,
// }
// let layoutItem = item
// if (item.type === 'field') {
// let newIndex = 1
// const defaultKey = (index) => {
// return `${item.fieldType}_${index}`
// }
// while (defaultKey(newIndex) in (props.config.fields || {})) {
// newIndex++
// }
// const newFieldKey = defaultKey(newIndex)
// newFields[newFieldKey] = {
// ...item,
// type: item.fieldType,
// }
// if ('fieldType' in newFields[newFieldKey]) {
// delete newFields[newFieldKey].fieldType
// }
// layoutItem = {
// type: 'field',
// field: newFieldKey,
// }
// }
// let newLayout = placeAdjacentInLayout(
// props.config.layout || [],
// layoutItem,
// position,
// relativeTo
// )
// if (!itemIsInLayout(newLayout, layoutItem)) {
// // put all unmentioned fields into config
// for (var fieldKey in props.config.fields || {}) {
// if (!itemIsInLayout(newLayout, {type: 'field', field: fieldKey})) {
// newLayout.push({
// type: 'field',
// field: fieldKey,
// })
// }
// }
// // then try the placement again
// newLayout = placeAdjacentInLayout(
// newLayout,
// layoutItem,
// position,
// relativeTo
// )
// }
// props.onChange({
// ...props.config,
// fields: newFields,
// layout: newLayout,
// })

const updatedConfig = {
...props.config,
}
let layoutItem = item
if (item.type === 'field') {
let newIndex = 1
const defaultKey = (index) => {
return `${item.fieldType}_${index}`
}
while (defaultKey(newIndex) in (props.config.fields || {})) {
newIndex++
}
const newFieldKey = defaultKey(newIndex)
updatedConfig.fields = {
...updatedConfig.fields,
[newFieldKey]: {
...item,
type: item.fieldType,
}
}
if ('fieldType' in updatedConfig.fields[newFieldKey]) {
delete updatedConfig.fields[newFieldKey].fieldType
}
layoutItem = {
type: 'field',
field: newFieldKey,
}
}
let relativeToPath = relativeTo.path
if (relativeTo.type === 'field') {
const layoutFields = getFieldsFromLayoutPath(updatedConfig.layout, '')
// field is not explicitly in layout
if (layoutFields.indexOf(relativeTo.field) == -1) {
updatedConfig.layout = [
...updatedConfig.layout,
]
// so cement all current (not including new) field positions with proper layout
for (var fieldKey in props.config.fields || {}) {
if (layoutFields.indexOf(fieldKey) === -1) {
updatedConfig.layout = [
...updatedConfig.layout,
{
type: 'field',
field: fieldKey,
},
]
}
}
}
relativeToPath = getFieldPath(updatedConfig.layout, relativeTo.field)
}
if (relativeToPath) {
updatedConfig.layout = insertIntoLayout(
updatedConfig.layout,
layoutItem,
position,
relativeToPath
)
}
props.onChange(updatedConfig)
}
return (
<BaseRenderer
Expand Down
101 changes: 48 additions & 53 deletions react-editor/src/layout-functions.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,50 @@
// export function layoutItemsMatch(itemOne, itemTwo) {
// if (itemOne.type !== itemTwo.type) {
// return false
// }
// switch (itemOne.type) {
// case 'field':
// return itemOne.field === itemTwo.field
// }
// }
//
// export function placeAdjacentInLayout(layout, item, position, relativeTo) {
// const updated = []
// const removed = removeItemFromLayout(layout, item)
// removed.map(layoutItem => {
// if (layoutItemsMatch(layoutItem, relativeTo)) {
// if (position === 'before') {
// updated.push(item)
// updated.push(layoutItem)
// }
// else {
// updated.push(layoutItem)
// updated.push(item)
// }
// }
// else {
// if (layoutItem.type === 'container') {
// updated.push({
// ...layoutItem,
// contents: placeAdjacentInLayout(layoutItem.contents || [], item, position, relativeTo),
// })
// }
// else {
// updated.push(layoutItem)
// }
// }
// })
// return updated
// }
export function getFieldPath(layout, fieldKey, currentPath='') {
let path = undefined
layout.map((layoutItem, childIndex) => {
const childPath = `${currentPath ? `${currentPath}.` : ''}${childIndex}`
if (layoutItem.type === 'field' && layoutItem.field === fieldKey) {
path = childPath
return
}
if (layoutItem.type === 'container') {
const contentsPath = getFieldPath(layoutItem.contents || [], fieldKey, childPath)
if (contentsPath) {
path = contentsPath
}
}
})
return path
}

export function insertIntoLayout(layout, item, position, path, currentPath='') {
const updated = []
layout.map((layoutItem, childIndex) => {
const childPath = `${currentPath ? `${currentPath}.` : ''}${childIndex}`
console.log('checking', childPath, 'with', path)
if (childPath === path) {
if (position === 'before') {
updated.push(item)
updated.push(layoutItem)
}
else {
updated.push(layoutItem)
updated.push(item)
}
}
else {
if (layoutItem.type === 'container') {
updated.push({
...layoutItem,
contents: insertIntoLayout(layoutItem.contents || [], item, position, path, childPath),
})
}
else {
updated.push(layoutItem)
}
}
})
return updated
}

export function updateLayoutPath(layout, path, changes, currentPath='') {
const updated = []
Expand Down Expand Up @@ -113,19 +122,5 @@ export function removeFieldFromLayout(layout, fieldKey) {
}

export function fieldIsInLayout(layout, fieldKey) {
let found = false
layout.map(layoutItem => {
if (layoutItem.type === 'field' && layoutItem.field === fieldKey) {
found = true
return
}
if (layoutItem.type === 'container') {
const foundInContainer = fieldIsInLayout(layoutItem.contents || [], fieldKey)
if (foundInContainer) {
found = true
return
}
}
})
return found
return getFieldsFromLayoutPath(layout, '').indexOf(fieldKey) != -1
}
5 changes: 4 additions & 1 deletion react-editor/src/layout/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ function Container(props) {
}
return (
<Draggable
fieldKey={props.fieldKey}
identifier={{
type: 'layout',
path: props.layoutPath,
}}
onDelete={handleDelete}
onDropNew={props.context.onDropNew}
onDropExisting={props.context.onDropExisting}
Expand Down
Loading

0 comments on commit 977d803

Please sign in to comment.