Skip to content

Instantly share code, notes, and snippets.

@xgqfrms
Last active February 24, 2023 15:00
Show Gist options
  • Save xgqfrms/abbd95da478d3574febc9f5c6064838b to your computer and use it in GitHub Desktop.
Save xgqfrms/abbd95da478d3574febc9f5c6064838b to your computer and use it in GitHub Desktop.
Group Sortable H5-DnD Framework App
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="author" content="xgqfrms">
<meta name="generator" content="VS code">
<title>Group H5DnD Framework App</title>
<!-- css -->
<link rel="stylesheet" href="https://cdn.xgqfrms.xyz/sweetalert/sweetalert.css">
<!-- <link rel="stylesheet" href="./libs/sweetalert.css">
<link rel="stylesheet" href="./group.css"> -->
</head>
<body>
<section class="modules-boxes">
<ul class="containers">
<li><span data-uid="container-01" draggable="true">container-01</span></li>
<li><span data-uid="container-02" draggable="true">container-02</span></li>
<li><span data-uid="container-03" draggable="true">container-03</span></li>
</ul>
<br>
<ul class="modules">
<li><span data-uid="module-01" draggable="true">module-01</span></li>
<li><span data-uid="module-02" draggable="true">module-02</span></li>
<li><span data-uid="module-03" draggable="true">module-03</span></li>
<li><span data-uid="module-04" draggable="true">module-04</span></li>
<li><span data-uid="module-05" draggable="true">module-05</span></li>
<li><span data-uid="module-06" draggable="true">module-06</span></li>
<li><span data-uid="module-07" draggable="true">module-07</span></li>
<li><span data-uid="module-08" draggable="true">module-08</span></li>
</ul>
</section>
<section>
<div data-box="container">
<div class="boxes-container" id="boxes_container"></div>
</div>
</section>
<!-- libs -->
<script src="https://cdn.xgqfrms.xyz/Sortable/sortable.min.js"></script>
<script src="https://cdn.xgqfrms.xyz/sweetalert/sweetalert.min.js"></script>
<!-- <script src="./libs/Sortable.min.js"></script>
<script src="./libs/sweetalert.min.js"></script> -->
<!-- js -->
<!-- <script src="./group.js"></script> -->
</body>
</html>
"use strict";
/**
*
* @author xgqfrms
* @license MIT
* @copyright xgqfrms
*
* @description group
* @augments
* @example
*
*/
// no need jQuery
let $ = {
qs: function qs(uid = ``) {
return document.querySelector(uid);
},
qsa: function qsa(uid = ``) {
return document.querySelectorAll(uid);
},
};
const checkModuleExist = (uid = ``) => {
let result = false;
const exsitModules = [...$.qsa(`[data-exist*="module-"]`)];
exsitModules.filter(
(exsitModule, i) => {
let id = exsitModule.dataset.exist.substr(7);
if (uid === id) {
console.log(`module exist`, uid);
result = true;
return result;
} else {
console.log(`module not exist`, uid);
}
}
);
return result;
};
const showContainer = (that = ``, uid = ``) => {
// showContainer(uid);
let template = `
<div data-id="modules-container-box" class="modules-container-box">
<div data-id="modules-container-title" class="modules-container-title">容器 ${uid} title</div>
<ul data-id="modules-container" class="modules-container" draggable="false"></ul>
</div>
`;
if (that) {
that.insertAdjacentHTML(`beforeend`, template);
setTimeout(() => {
// sortContainers();
sortModules();
ModuleLoader.init();
}, 0);
}
// const box = $.qs(`[data-test="container"]`);
// if (box) {
// box.insertAdjacentHTML(`beforeend`, template);
// }
};
const showModule = (that = ``, uid = ``) => {
// showModule(uid);
// const box = $.qs(`[data-test="container"]`);
let template = `
<li draggable="false" class="module">
<p class="drag-handle-box" draggable="false">
<span class="drag-handle">☰</span>
<span class="drag-handle-title" draggable="false">模块 ${uid} title</span>
</p>
<div data-modules="safety-content" draggable="false" data-exist="module-${uid}">
模块 ${uid} content<br/>
</div>
</li>
`;
let exist = checkModuleExist(uid);
if (that && !exist) {
that.insertAdjacentHTML(`beforeend`, template);
setTimeout(() => {
// sortContainers();
// sortModules();
}, 0);
} else {
swal({
title: "此模块已存在!",
text: `
此模块已存在, 不能再次拖放!\n
1 秒后自动关闭.
`,
icon: "warning",
className: "warning-alert-style",
timer: 2000,
button: {
text: "关闭",
value: true,
visible: true,
closeModal: true
}
});
}
};
const ContainerLoader = (
(debug = false) => {
return {
dragstart: function(e) {
let uid = e.target.dataset.uid;
// let uid = e.target.dataset.uid.substr(10);
e.dataTransfer.effectAllowed = `move`;
e.target.style.opacity = "1";
e.dataTransfer.setData("text/plain", `${uid}`);
console.log(`%c container drag uid!`, `color: #0f0`, uid);
},
dragend: function(e) {
e.preventDefault();
// e.stopPropagation();
return true;
},
dragenter: function(e) {
e.preventDefault();
// this.classList.add(`over-border`);
return true;
},
dragover: function(e) {
e.preventDefault();
// return false;
// this.classList.add(`over-border`);
return true;
},
dragleave: function(e) {
e.preventDefault();
// this.classList.remove(`over-border`);
return true;
},
drop: function(e) {
e.preventDefault();
e.stopPropagation();
// this.classList.remove(`over-border`);
let that = this;
let uid = e.dataTransfer.getData("text/plain");
let regex = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/igm;
if (regex.test(uid)) {
console.warn(`uid is invalid!`, uid.length);
} else {
if (typeof(uid) === "string" && uid.length) {
try {
// Container
if (uid.includes(`container-`)) {
console.log(`%c container drop uid!`, `color: #f0f`, uid);
showContainer(that, uid.replace(`container-`, ``));
} else {
// console.warn(`BUG: 模块只能托放到容器中!`, uid.length);
swal({
title: "模块只能托放到容器中!",
text: `
请先拖放容器到布局,再拖放模块!\n
1 秒后自动关闭.
`,
icon: "warning",
className: "warning-alert-style",
timer: 2000,
button: {
text: "关闭",
value: true,
visible: true,
closeModal: true
}
});
}
} catch (error) {
console.log(`%c Sorry, showContainer some errors occurred!`, `color: #f0f`, error);
}
} else {
// invalid value
}
}
},
init: function() {
let containers = $.qsa(`[data-uid*="container"]`);
for (let i = 0; i < containers.length; i++) {
containers[i].addEventListener(`dragstart`, this.dragstart, false);
}
// H5 DnD & capture
// let container_box = $.qs(`[data-test="container"]`);
// let container_box = $.qs(`.boxes-container`);
let container_box = $.qs(`#boxes_container`);
// container_box.addEventListener(`dragenter`, this.dragenter, false);
container_box.addEventListener(`dragover`, this.dragover, false);// must set dragover !!!
// container_box.addEventListener(`dragleave`, this.dragleave, false);
container_box.addEventListener(`drop`, this.drop, false);
}
};
}
)();
const ModuleLoader = (
(debug = false) => {
return {
dragstart: function(e) {
let uid = e.target.dataset.uid;
// let uid = e.target.dataset.uid.substr(7);
e.dataTransfer.effectAllowed = `move`;
e.target.style.opacity = "1";
e.dataTransfer.setData("text/plain", `${uid}`);
console.log(`%c module drag uid!`, `color: #0f0`, uid);
},
dragend: function(e) {
e.preventDefault();
// e.stopPropagation();
return true;
},
dragenter: function(e) {
e.preventDefault();
// this.classList.add(`over-border`);
return true;
},
dragover: function(e) {
e.preventDefault();
// return false;
// this.classList.add(`over-border`);
return true;
},
dragleave: function(e) {
e.preventDefault();
// this.classList.remove(`over-border`);
return true;
},
drop: function(e) {
e.preventDefault();
e.stopPropagation();
// this.classList.remove(`over-border`);
let that = this;
// console.warn(`that = `, this);
let uid = e.dataTransfer.getData("text/plain");
// let uid = e.dataTransfer.getData("text/plain").split(",")[0];
let regex = /[\u3040-\u30ff\u3400-\u4dbf\u4e00-\u9fff\uf900-\ufaff\uff66-\uff9f]/igm;
if (regex.test(uid) || uid.includes(`☰`)) {
console.warn(`uid is invalid!`, uid.length);
} else {
if (typeof(uid) === "string" && uid.length) {
try {
// Module
if (uid.includes(`module-`)) {
console.log(`%c module drop uid!`, `color: #f0f`, uid);
showModule(that, uid.replace(`module-`, ``));
} else {
swal({
// title: "容器不可以托放(模块/容器)中!",
title: "容器只能托放到布局中!",
text: `
请先拖放容器到布局,再拖放模块!\n
1 秒后自动关闭.
`,
icon: "warning",
className: "warning-alert-style",
timer: 2000,
button: {
text: "关闭",
value: true,
visible: true,
closeModal: true
}
});
}
} catch (error) {
console.log(`%c Sorry, showModule some errors occurred!`, `color: #f0f`, error);
}
} else {
// invalid value
}
}
},
init: function() {
let modules = $.qsa(`[data-uid*="module"]`);
for (let i = 0; i < modules.length; i++) {
modules[i].addEventListener(`dragstart`, this.dragstart, false);
}
// H5 DnD & capture
let modules_container = $.qsa(`[data-id="modules-container"]`);
modules_container.forEach(
(container, i) => {
// container.addEventListener(`dragenter`, this.dragenter, false);
container.addEventListener(`dragover`, this.dragover, false);
// container.addEventListener(`dragleave`, this.dragleave, false);
container.addEventListener(`drop`, this.drop, false);
}
);
}
};
}
)();
const sortContainers = () => {
try {
// typeof(Sortable) === "function"
if (Sortable) {
// containers
Sortable.create($.qs("#boxes_container"), {
draggable: ".modules-container-box",
handle: ".modules-container-title",
animation: 150
});
} else {
throw new Error(`Sortable.js is not imported!`);
}
} catch (error) {
console.error(`sortContainers Error: \n`, error);
}
};
const sortModules = () => {
try {
// typeof(Sortable) === "function"
if (Sortable) {
// modules
let uids = [...$.qsa(`[data-id="modules-container"]`)];
[].forEach.call(uids, (uid) => {
Sortable.create(uid, {
group: "containers", // groupe & drag handle
draggable: '.module',
handle: ".drag-handle",
animation: 150
});
});
} else {
throw new Error(`Sortable.js is not imported!`);
}
} catch (error) {
console.error(`sortModules Error: \n`, error);
}
};
const initSort = () => {
try {
// typeof(Sortable) === "function"
if (Sortable) {
// containers
Sortable.create($.qs("#boxes_container"), {
draggable: ".modules-container-box",
handle: ".modules-container-title",
animation: 150
});
// modules
let uids = [...$.qsa(`[data-id="modules-container"]`)];
[].forEach.call(uids, (uid) => {
Sortable.create(uid, {
group: "containers", // groupe & drag handle
draggable: '.module',
handle: ".drag-handle",
animation: 150
});
});
} else {
throw new Error(`Sortable.js is not imported!`);
}
} catch (error) {
console.error(`Sortable Error: \n`, error);
}
};
document.addEventListener(`DOMContentLoaded`, () => {
ContainerLoader.init();
ModuleLoader.init();
});
window.onload = () => {
// delay
initSort();
};
@charset "UTf-8";
/* group.css */
html,
body {
margin: 0;
padding: 0;
position: relative;
color: #464637;
min-height: 100%;
font-size: 20px;
font-family: 'Roboto', sans-serif;
font-weight: 300;
}
html {
background-image: linear-gradient(to bottom, #F4E2C9 20%, #F4D7C9 100%);
}
.layer {
/* float: left; */
}
[data-test="container"] {
width: 80%;
margin-left: 20%;
min-height: 200px;
background: #000;
color: #fff;
}
.modules-boxes {
width: 20%;
color: #fff;
float: left;
}
.containers li span,
.modules li span {
cursor: move;
/* -webkit-user-drag: auto; */
}
[data-uid*="container"],
[data-uid*="module"] {
user-select: none;
}
.drag-handle-box {
height: 23px;
line-height: 1.2rem;
background: #FF7373;
width: 200px;
}
.title {
color: #fff;
padding: 3px 10px;
display: inline-block;
position: relative;
background-color: #FF7373;
z-index: 1000;
margin: 10px;
}
[data-id="modules-container-box"] {
box-sizing: border-box;
float: left;
width: 100%;
}
[data-id="modules-container-title"] {
background: #FF7373;
margin: 5px;
padding: 5px;
margin-bottom: 0;
padding-bottom: 0;
/* fallback */
cursor: move;
cursor: grabbing;
user-select: none;
width: 200px;
}
ul {
list-style: none;
margin: 5px;
padding: 5px;
margin-top: 0;
display: block;
background: #ccc;
height: 100%;
min-height: 100px;
/* min-height: 300px; */
}
.boxes-container {
width: 80%;
height: 100%;
/* min-height: 400px;
max-height: 500px; */
/* max-height: 600px;
min-height: 600px; */
max-height: 100vh;
min-height: 100vh;
margin: 0 10px 0 20%;
background: #2196f3;
overflow: auto;
}
.boxes-container li {
background-color: #fff;
padding: 10px 40px;
/* display: inline-block; */
display: block;
border: 1px solid #5F9EDF;
margin: 5px;
}
.boxes-container li:first-letter {
text-transform: uppercase;
}
.drag-handle {
margin-right: 10px;
font: bold 20px Sans-Serif;
color: #5F9EDF;
display: inline-block;
/* css fallback */
cursor: move;
cursor: grabbing;
user-select: none;
}
.drag-handle-title {
user-select: none;
}
[data-modules="safety-content"] {
color: #fff;
background: #000;
/* user-select: none; */
}
/* sweetalert */
.warning-alert-style {
/* color: #0f0 !important; */
/* background: #fd1f1fd0; */
background: #ffffff;
box-sizing: border-box;
/* border: 1px solid red; */
}
.swal-title {
color: #000;
}
.swal-text {
color: #fd1f1fd0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment