From 5b2d5b34808048a639eb4ff14bb382b3b56400d7 Mon Sep 17 00:00:00 2001 From: shahryar tavakkoli Date: Fri, 6 Jan 2023 16:06:24 +0330 Subject: [PATCH] sperate layout, element and utilities file, add new role not to add normal element in main section, based on #4 --- assets/js/app.js | 242 +----------------- .../mishka_template_creator/elements.js | 4 + .../vendor/mishka_template_creator/layout.js | 212 +++++++++++++++ .../mishka_template_creator/utilities.js | 45 ++++ .../live/template_creator_live.ex | 5 + .../live/template_creator_live.html.heex | 2 +- 6 files changed, 272 insertions(+), 238 deletions(-) create mode 100644 assets/vendor/mishka_template_creator/elements.js create mode 100644 assets/vendor/mishka_template_creator/layout.js create mode 100644 assets/vendor/mishka_template_creator/utilities.js diff --git a/assets/js/app.js b/assets/js/app.js index dd14102..4335e8c 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -2,245 +2,13 @@ import 'phoenix_html'; import { Socket } from 'phoenix'; import { LiveSocket } from 'phoenix_live_view'; import topbar from '../vendor/topbar'; -import Sortable from 'sortablejs'; - +import { dragLocation, previewHelper } from "../vendor/mishka_template_creator/utilities" +import { LayoutGroup, ContentGroup } from '../vendor/mishka_template_creator/layout'; // Start Hooks object let Hooks = {}; -const getBlocks = document.getElementById('layout-block'); -const putBlock = document.getElementById('dragLocation'); -const previewHelper = document.getElementById('previewHelper'); -const sortableSpeed = 150; - -Sortable.create(getBlocks, { - group: { - name: 'LayoutGroup', - pull: 'clone', - put: false, - }, - animation: sortableSpeed, - sort: false, - onStart: function (evt) { - previewHelper.classList.add('hidden'); - }, - onEnd: function (evt) { - if (putBlock.children.length === 1) { - previewHelper.classList.remove('hidden'); - } else { - customEventCreator('awesome', evt.item, { text: 'test params' }); - } - }, -}); - -Sortable.create(putBlock, { - group: { - name: 'ContentGroup', - handle: '.handle', - put: ['LayoutGroup'], - }, - animation: sortableSpeed, - swapThreshold: 0.65, - onAdd: function (/**Event*/ evt) { - const elementID = evt.item.dataset.id; - recoverAndConvertAfterDroppingAnItem(evt.item, elementID); - if (elementID === 'section-drag') { - createSectionOnSortableJS(evt.item); - } - }, -}); - -function createSectionOnSortableJS(htmlElement) { - console.log(htmlElement.id); - - // TODO: We need to find original converter - const deletePhx = `[["push",{"event":"delete","value":{"id":"${htmlElement.id}"}}],["show",{"display":null,"time":200,"to":"#delete_confirm","transition":[[],[],[]]}],["show",{"display":null,"time":200,"to":"#delete_confirm-bg","transition":[["transition-all","transform","ease-out","duration-300"],["opacity-0"],["opacity-100"]]}],["show",{"display":null,"time":200,"to":"#delete_confirm-container","transition":[["transition-all","transform","ease-out","duration-300"],["opacity-0","translate-y-4","sm:translate-y-0","sm:scale-95"],["opacity-100","translate-y-0","sm:scale-100"]]}],["focus_first",{"to":"#delete_confirm-content"}]]` - - htmlElement.innerHTML = ` -
- - - - - - - - - - - - - - - - - - - - - - - -
- `; - htmlElement.className = ''; - htmlElement.classList.add('create-section'); - htmlElement.classList.add('!p-20'); - - Sortable.create(htmlElement, { - group: { - name: `section-${uuidv4()}`, - handle: '.handle', - put: ['LayoutGroup'], - }, - animation: sortableSpeed, - swapThreshold: 0.65, - onAdd: function (/**Event*/ evt) { - htmlElement.classList.remove('!p-20'); - const elementID = evt.item.dataset.id; - - recoverAndConvertAfterDroppingAnItem(evt.item, elementID); - - if (elementID === 'section-drag') { - evt.item.innerHTML = ''; - evt.item.classList.add('create-sub-section'); - Sortable.create(evt.item, { - group: { - name: `section-${uuidv4()}`, - handle: '.handle', - put: ['LayoutGroup'], - }, - animation: sortableSpeed, - swapThreshold: 0.65, - }); - } - }, - }); -} - -function recoverAndConvertAfterDroppingAnItem(htmlElement, elementID) { - liveViewAttributeRemover(htmlElement); - htmlElement.setAttribute('id', `${elementID}-clone-${uuidv4()}`); - htmlElement.setAttribute('data-type', elementID); - const blockCodeID = document.querySelector(`[data-id="${elementID}"]`); - blockCodeID.setAttribute('id', elementID); -} - -function liveViewAttributeRemover(htmlElement) { - ['data-id', 'phx-click', 'phx-hook'].map((item) => { - htmlElement.removeAttribute(item); - }); -} - -function customEventCreator(name, htmlElement, params) { - // It is a custom listener to let Phoenix LiveView hook, something happened that it should be listen. - const event = new CustomEvent(name, { - bubbles: true, - detail: params, - }); - // This is a sender and dispatcher for event - htmlElement.dispatchEvent(event); -} - -function uuidv4() { - try { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => - ( - c ^ - (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) - ).toString(16) - ); - } catch (e) { - const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26)); - return randLetter + Date.now(); - } -} +LayoutGroup +ContentGroup // Start hooks Functions, this place we put some hooks we defined in elixir side and communicate with backend Hooks.dragAndDropLocation = { @@ -260,7 +28,7 @@ Hooks.dragAndDropLocation = { this.handleEvent('delete', ({ id }) => { const element = document.getElementById(id); element.remove(); - if (putBlock.children.length === 1) { + if (dragLocation.children.length === 1) { previewHelper.classList.remove('hidden'); } }); diff --git a/assets/vendor/mishka_template_creator/elements.js b/assets/vendor/mishka_template_creator/elements.js new file mode 100644 index 0000000..60eb458 --- /dev/null +++ b/assets/vendor/mishka_template_creator/elements.js @@ -0,0 +1,4 @@ +// Create elements + + +// Helper functions \ No newline at end of file diff --git a/assets/vendor/mishka_template_creator/layout.js b/assets/vendor/mishka_template_creator/layout.js new file mode 100644 index 0000000..949433e --- /dev/null +++ b/assets/vendor/mishka_template_creator/layout.js @@ -0,0 +1,212 @@ +import Sortable from 'sortablejs'; +import { + uuidv4, + customEventCreator, + recoverAndConvertAfterDroppingAnItem, + previewHelper, + sortableSpeed, + layoutBlock as layoutBlockElement, + dragLocation, +} from './utilities'; + +// Create main section +export const LayoutGroup = Sortable.create(layoutBlockElement, { + group: { + name: 'LayoutGroup', + pull: 'clone', + put: false, + }, + animation: sortableSpeed, + sort: false, + onStart: function (evt) { + previewHelper.classList.add('hidden'); + }, + onEnd: function (evt) { + if (dragLocation.children.length === 1) { + previewHelper.classList.remove('hidden'); + } else { + customEventCreator('awesome', evt.item, { text: 'test params' }); + } + }, +}); + +export const ContentGroup = Sortable.create(dragLocation, { + group: { + name: 'ContentGroup', + handle: '.handle', + put: ['LayoutGroup'], + }, + animation: sortableSpeed, + swapThreshold: 0.65, + onAdd: function (/**Event*/ evt) { + const elementID = evt.item.dataset.id; + recoverAndConvertAfterDroppingAnItem(evt.item, elementID); + if (elementID === 'section-drag') { + createSectionOnSortableJS(evt.item); + } else { + evt.item.remove(); + } + }, +}); + +function createSectionOnSortableJS(htmlElement) { + console.log(htmlElement.id); + + // TODO: We need to find original converter + const deletePhx = `[["push",{"event":"delete","value":{"id":"${htmlElement.id}"}}],["show",{"display":null,"time":200,"to":"#delete_confirm","transition":[[],[],[]]}],["show",{"display":null,"time":200,"to":"#delete_confirm-bg","transition":[["transition-all","transform","ease-out","duration-300"],["opacity-0"],["opacity-100"]]}],["show",{"display":null,"time":200,"to":"#delete_confirm-container","transition":[["transition-all","transform","ease-out","duration-300"],["opacity-0","translate-y-4","sm:translate-y-0","sm:scale-95"],["opacity-100","translate-y-0","sm:scale-100"]]}],["focus_first",{"to":"#delete_confirm-content"}]]`; + + htmlElement.innerHTML = ` +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ `; + htmlElement.className = ''; + htmlElement.classList.add('create-section'); + htmlElement.classList.add('!p-20'); + + Sortable.create(htmlElement, { + group: { + name: `section-${uuidv4()}`, + handle: '.handle', + put: ['LayoutGroup'], + }, + animation: sortableSpeed, + swapThreshold: 0.65, + onAdd: function (/**Event*/ evt) { + htmlElement.classList.remove('!p-20'); + const elementID = evt.item.dataset.id; + + recoverAndConvertAfterDroppingAnItem(evt.item, elementID); + + if (elementID === 'section-drag') { + evt.item.innerHTML = ''; + evt.item.classList.add('create-sub-section'); + Sortable.create(evt.item, { + group: { + name: `section-${uuidv4()}`, + handle: '.handle', + put: ['LayoutGroup'], + }, + animation: sortableSpeed, + swapThreshold: 0.65, + }); + } else { + evt.item.remove(); + if (htmlElement.children.length === 1) { + htmlElement.classList.add('!p-20'); + } + } + }, + }); +} + +// Helper functions diff --git a/assets/vendor/mishka_template_creator/utilities.js b/assets/vendor/mishka_template_creator/utilities.js new file mode 100644 index 0000000..2021719 --- /dev/null +++ b/assets/vendor/mishka_template_creator/utilities.js @@ -0,0 +1,45 @@ +const layoutBlock = document.getElementById('layoutBlock'); +const dragLocation = document.getElementById('dragLocation'); +const previewHelper = document.getElementById('previewHelper'); +const sortableSpeed = 150; + +// Helper functions +export function recoverAndConvertAfterDroppingAnItem(htmlElement, elementID) { + liveViewAttributeRemover(htmlElement); + htmlElement.setAttribute('id', `${elementID}-clone-${uuidv4()}`); + htmlElement.setAttribute('data-type', elementID); + const blockCodeID = document.querySelector(`[data-id="${elementID}"]`); + blockCodeID.setAttribute('id', elementID); +} + +export function liveViewAttributeRemover(htmlElement) { + ['data-id', 'phx-click', 'phx-hook'].map((item) => { + htmlElement.removeAttribute(item); + }); +} + +export function customEventCreator(name, htmlElement, params) { + // It is a custom listener to let Phoenix LiveView hook, something happened that it should be listen. + const event = new CustomEvent(name, { + bubbles: true, + detail: params, + }); + // This is a sender and dispatcher for event + htmlElement.dispatchEvent(event); +} + +export function uuidv4() { + try { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => + ( + c ^ + (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4))) + ).toString(16) + ); + } catch (e) { + const randLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26)); + return randLetter + Date.now(); + } +} + +export { layoutBlock, dragLocation, previewHelper, sortableSpeed }; \ No newline at end of file diff --git a/lib/mishka_template_creator_web/live/template_creator_live.ex b/lib/mishka_template_creator_web/live/template_creator_live.ex index 307ca47..117c9c4 100644 --- a/lib/mishka_template_creator_web/live/template_creator_live.ex +++ b/lib/mishka_template_creator_web/live/template_creator_live.ex @@ -24,6 +24,11 @@ defmodule MishkaTemplateCreatorWeb.TemplateCreatorLive do end def handle_event("delete", %{"id" => id}, socket) do + JS.push("delete", value: %{id: id, type: "dom"}) + |> hide_modal("delete_confirm") + |> Map.get(:ops) + |> Jason.encode!() + |> IO.inspect() # after delete count childeren of content div and if is there not any element enable perview {:noreply, assign(socket, :section_id, id)} end diff --git a/lib/mishka_template_creator_web/live/template_creator_live.html.heex b/lib/mishka_template_creator_web/live/template_creator_live.html.heex index c0ba848..bbf8e76 100644 --- a/lib/mishka_template_creator_web/live/template_creator_live.html.heex +++ b/lib/mishka_template_creator_web/live/template_creator_live.html.heex @@ -107,7 +107,7 @@

Layout