From 548bb29035d59de5430c5a0d017fe436a713c7af Mon Sep 17 00:00:00 2001 From: "Gopinath (aka) bluepie" Date: Thu, 14 Oct 2021 03:33:30 +0530 Subject: [PATCH] show placement indicator for dragging over column elements --- src/Components/HtmlWrapper.tsx | 17 ++++- src/Utils/generateDropItemPlaceholder.ts | 97 ++++++++++++++++++++++-- src/Utils/mjmlProcessor.ts | 9 +++ 3 files changed, 112 insertions(+), 11 deletions(-) diff --git a/src/Components/HtmlWrapper.tsx b/src/Components/HtmlWrapper.tsx index 0bbddd5..a2382a0 100644 --- a/src/Components/HtmlWrapper.tsx +++ b/src/Components/HtmlWrapper.tsx @@ -9,7 +9,10 @@ import { findClosestParent, findUniqueIdentifier } from '../Utils/closestParent' import { detectEmptyElement } from '../Utils/detectEmptyBody'; import { findElementInJson } from '../Utils/findElementInMjmlJson'; import { findColumnOfElement } from '../Utils/findElementsParent'; -import { generateDropItemPlaceholder } from '../Utils/generateDropItemPlaceholder'; +import { + generateDropItemPlaceholder, + genereateDropItemPlaceholderForColumn, +} from '../Utils/generateDropItemPlaceholder'; interface HtmlWrapperProps { // children: React.DOMElement, Element>; @@ -161,7 +164,15 @@ export const HtmlWrapper = memo(({ uniqueKey, originalNode }: HtmlWrapperProps) const nearestTag = findClosestParent(currentTarget); // only show place item sign for column's children if (nearestTag?.includes('mj-column') || nearestTag?.includes('mj-section')) { - return; + console.log('::indicator: trigger->column'); + if (nearestTag.includes('mj-column')) { + const madeChange = genereateDropItemPlaceholderForColumn({ mjmlJson, nearestTag, setMjmlJson }); + if (madeChange === true) { + console.log('::indicator: trigger->column -> stopping further processing'); + return; + } + console.log('::indicator: trigger->column -> no updates where done -> proceeding further processing'); + } } let columnElement = memoFind(currentTarget); @@ -169,7 +180,7 @@ export const HtmlWrapper = memo(({ uniqueKey, originalNode }: HtmlWrapperProps) if (columnElement) { [columnElement] = columnElement; } - + console.log('::indicator: trigger->insideColumn'); generateDropItemPlaceholder({ mjmlJson, nearestTag, diff --git a/src/Utils/generateDropItemPlaceholder.ts b/src/Utils/generateDropItemPlaceholder.ts index 8a7e269..f901313 100644 --- a/src/Utils/generateDropItemPlaceholder.ts +++ b/src/Utils/generateDropItemPlaceholder.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import { findUniqueIdentifier } from './closestParent'; +import { findUniqueIdentifier, findUniqueIdentifierFromString } from './closestParent'; import { closeToTopOrBottom, isEventWithTargetElement } from './eventElementRelation'; import { findElementInJson } from './findElementInMjmlJson'; import { cleanMjmlJson } from './mjmlProcessor'; @@ -27,12 +27,12 @@ const generateDropItemPlaceholder = ({ if (isEventWithTargetElement(e, columnElement)) { const suggestionDirection = closeToTopOrBottom(e, nearestElement); if (suggestionDirection) { - let item = findElementInJson(mjmlJson, nearestTag); + let item = findElementInJson(_.cloneDeep(mjmlJson), nearestTag); if (item) { const [, path]: [any, string] = item; // omit the last .child.. index, cuz parent is needed const parent = path.slice(1, path.lastIndexOf('.children')); - let parentObj = _.get(mjmlJson, parent); + let parentObj = _.get(_.cloneDeep(mjmlJson), parent); let newOrder = []; for (var i = 0; parentObj && parentObj.children && i < parentObj.children.length; i++) { let childItem = parentObj['children'][i]; @@ -56,7 +56,7 @@ const generateDropItemPlaceholder = ({ if (parentObj && newOrder.length > 0) { // replace with new order parentObj.children = newOrder; - const updated = _.set(mjmlJson, parent, parentObj); + const updated = _.set(_.cloneDeep(mjmlJson), parent, parentObj); const uniqueColumnIdentifier = findUniqueIdentifier( columnElement, columnElement.classList, @@ -64,9 +64,19 @@ const generateDropItemPlaceholder = ({ ); if (uniqueColumnIdentifier) { const cleaned = cleanMjmlJson(updated, uniqueColumnIdentifier); - setMjmlJson({ ...cleaned }); + if (!_.isEqual(mjmlJson, cleaned)) { + console.log('::update::', mjmlJson, cleaned); + setMjmlJson({ ...cleaned }); + } else { + console.log('::update:: -> but elements are the same, not triggering rerender'); + } } else { - setMjmlJson({ ...updated }); + if (!_.isEqual(mjmlJson, updated)) { + console.log('::update::', mjmlJson, updated); + setMjmlJson({ ...updated }); + } else { + console.log('::update:: -> but elements are the same, not triggering rerender'); + } } } } @@ -76,7 +86,78 @@ const generateDropItemPlaceholder = ({ } }; -export { generateDropItemPlaceholder }; +const genereateDropItemPlaceholderForColumn = ({ + mjmlJson, + setMjmlJson, + nearestTag, +}: Omit) => { + if (nearestTag) { + let find = findElementInJson(mjmlJson, nearestTag); + if (find) { + const cleanedMjmlJson = cleanMjmlJson(_.cloneDeep(mjmlJson)); + console.log('::beforechange::', mjmlJson, cleanedMjmlJson); + const [, path]: [any, string] = find; + let columnObj = _.get(_.cloneDeep(cleanedMjmlJson), path.slice(1)); + let newOrder = []; + for (let i = 0; columnObj && columnObj.children && i < columnObj.children.length; i++) { + const childItem = columnObj['children'][i]; + const cssClass = childItem.attributes && childItem['attributes']['css-class']; + // if there is existing placeholders, removing them + if (cssClass && cssClass.includes('placeitem-placeholder')) { + continue; + } + // remove column empty placeholders + if (cssClass && cssClass.includes('mj-placeholder')) { + continue; + } + newOrder.push(childItem); + } + + // newOrder will not be zero if the column already has items + if (newOrder.length > 0) { + // todo: handle generateDropItemPlaceholder inside this fn. + // by getting event and performing calculations. + return false; + } + + // add the new element + newOrder.push(placeItemPlaceHolder); + + let sectionPath = path.slice(1, path.lastIndexOf('.children')); + if (columnObj) { + // section can contain multiple, + // identify which column is active and replace with new order + columnObj.children = newOrder; + let parentSection = _.get(_.cloneDeep(cleanedMjmlJson), sectionPath); + let columnChildrenNewOrder = []; + debugger; + for (let i = 0; parentSection && parentSection.children && i < parentSection.children.length; i++) { + const childColumn = parentSection['children'][i]; + const cssClass = childColumn.attributes && childColumn['attributes']['css-class']; + const uniqueIdentifer = findUniqueIdentifierFromString(cssClass); + // nearestTag is the uniqueId of the column, + // replace the old column with new one + if (uniqueIdentifer === nearestTag) { + columnChildrenNewOrder.push(columnObj); + continue; + } + columnChildrenNewOrder.push(childColumn); + } + parentSection.children = columnChildrenNewOrder; + const updated = _.set(cleanedMjmlJson, sectionPath, parentSection); + if (!_.isEqual(mjmlJson, updated)) { + console.log('::update::', cleanedMjmlJson, updated); + setMjmlJson({ ...updated }); + } else { + console.log('::update:: -> but elements are the same, not triggering rerender'); + } + return true; + } + } + } +}; + +export { generateDropItemPlaceholder, genereateDropItemPlaceholderForColumn }; const placeItemPlaceHolder = { tagName: 'mj-text', @@ -84,5 +165,5 @@ const placeItemPlaceHolder = { align: 'center', 'css-class': 'placeitem-placeholder', }, - content: '

+

', + content: '

+

', }; diff --git a/src/Utils/mjmlProcessor.ts b/src/Utils/mjmlProcessor.ts index bc11cd3..8043314 100644 --- a/src/Utils/mjmlProcessor.ts +++ b/src/Utils/mjmlProcessor.ts @@ -1,3 +1,5 @@ +import { columnPlaceholder } from '../Components/Section'; + const cleanMjmlJson = (mjmlJson: any, ignore: string = '') => { if (!mjmlJson) { return null; @@ -27,6 +29,13 @@ const cleanMjmlJson = (mjmlJson: any, ignore: string = '') => { newChildren.push(result); } } + + // if the children is column and its length is 0, + // then add a placeholder to the column + if (mjmlJson && mjmlJson['tagName'] === 'mj-column' && newChildren.length === 0) { + newChildren.push(...columnPlaceholder); + } + if (newChildren.length) { mjmlJson['children'] = newChildren; }