Name change, registry stuff and started work on motion painter

This commit is contained in:
IDGallagher
2024-09-18 10:21:12 +01:00
parent 19d24dd442
commit 98c823b201
8 changed files with 1020 additions and 9 deletions
+21
View File
@@ -0,0 +1,21 @@
name: Publish to Comfy registry
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "pyproject.toml"
jobs:
publish-node:
name: Publish Custom Node to registry
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Publish Custom Node
uses: Comfy-Org/publish-node-action@main
with:
## Add your own personal access token to your Github Repository secrets and reference it here.
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
+12 -6
View File
@@ -6,15 +6,21 @@
"""
from .nodes.flow import *
from .nodes.motion_painter import *
# Mount web directory
WEB_DIRECTORY = f"./web"
NODE_CLASS_MAPPINGS = {
"IG Flow Model Loader": IG_FlowModelLoader,
"IG Flow Predictor": IG_FlowPredictor,
"IG Flow Animator": IG_FlowAnimator,
"MI2V Flow Model Loader": MI2V_FlowModelLoader,
"MI2V Flow Predictor": MI2V_FlowPredictor,
"MI2V Flow Animator": MI2V_FlowAnimator,
"MI2V Motion Painter": MI2V_MotionPainter,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"IG Flow Model Loader": "💾 IG Flow Model Loader",
"IG Flow Predictor": "🌊 IG Flow Predictor",
"IG Flow Animator": "🌊 IG Flow Animator",
"MI2V Flow Model Loader": "💾 MI2V Flow Model Loader",
"MI2V Flow Predictor": "🌊 MI2V Flow Predictor",
"MI2V Flow Animator": "🌊 MI2V Flow Animator",
"MI2V Motion Painter": "🎨 MI2V Motion Painter",
}
+3 -3
View File
@@ -36,7 +36,7 @@ from ..animation.utils.convert_from_ckpt import (
convert_ldm_vae_checkpoint,
)
class IG_FlowModelLoader:
class MI2V_FlowModelLoader:
@classmethod
def INPUT_TYPES(s):
return {"required": {
@@ -140,7 +140,7 @@ class IG_FlowModelLoader:
}
return (flow_model,)
class IG_FlowPredictor:
class MI2V_FlowPredictor:
@classmethod
def INPUT_TYPES(s):
return {
@@ -244,7 +244,7 @@ class IG_FlowPredictor:
return (flow_tensor.to(intermediate_device), flow_preview.to(intermediate_device),)
class IG_FlowAnimator:
class MI2V_FlowAnimator:
@classmethod
def INPUT_TYPES(s):
return {
+83
View File
@@ -0,0 +1,83 @@
import os
import json
from server import PromptServer
from aiohttp import web
import hashlib
# Directory to save node settings
SETTINGS_DIR = os.path.join(os.path.dirname(__file__), "settings_nodes")
os.makedirs(SETTINGS_DIR, exist_ok=True)
PREFIX = "_settings.json"
def is_valid_filename(filename):
return filename and isinstance(filename, str) and filename.strip() != ""
def get_settings_filepath(filename):
return os.path.join(SETTINGS_DIR, filename + PREFIX)
def load_settings(filename):
filepath = get_settings_filepath(filename)
if os.path.isfile(filepath):
with open(filepath, "r") as f:
try:
return json.load(f)
except json.JSONDecodeError:
pass
return {}
def save_settings(filename, data):
filepath = get_settings_filepath(filename)
with open(filepath, "w") as f:
json.dump(data, f)
@PromptServer.instance.routes.get("/motion_vector/load_settings/{node_name}")
async def load_settings_route(request):
filename = request.match_info.get("node_name", None)
data = load_settings(filename) if is_valid_filename(filename) else {}
return web.json_response({"settings": data})
@PromptServer.instance.routes.post("/motion_vector/save_settings")
async def save_settings_route(request):
try:
data = await request.json()
filename = data.get("name")
settings = data.get("settings")
if is_valid_filename(filename):
save_settings(filename, settings)
return web.json_response({"message": "Settings saved successfully"}, status=200)
else:
raise ValueError("Invalid filename")
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
class MI2V_MotionPainter:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image": ("IMAGE",),
},
"hidden": {
"unique_id": "UNIQUE_ID"
},
}
RETURN_TYPES = ("IMAGE", "VECTOR_DATA")
FUNCTION = "execute"
CATEGORY = "Custom Nodes"
def execute(self, image, unique_id):
# The actual processing will be handled on the client side.
return (image, None)
@classmethod
def IS_CHANGED(cls, image, unique_id):
# Use the hash of the image and unique ID to determine if the node has changed.
m = hashlib.sha256()
m.update(str(unique_id).encode('utf-8'))
# Assuming 'image' is a filepath or an object that can be hashed.
if isinstance(image, str) and os.path.isfile(image):
with open(image, "rb") as f:
m.update(f.read())
return m.hexdigest()
+15
View File
@@ -0,0 +1,15 @@
[project]
name = "comfyui-ig-motion-i2v"
description = "ComfyUI adaptation of https://github.com/G-U-N/Motion-I2V"
version = "0.5.0"
license = { file = "LICENSE" }
dependencies = []
[project.urls]
Repository = "https://github.com/IDGallagher/ComfyUI-IG-Motion-I2V"
# Used by Comfy Registry https://comfyregistry.org
[tool.comfy]
PublisherId = "iggy101"
DisplayName = "ComfyUI-IG-Motion-I2V"
Icon = ""
+10
View File
File diff suppressed because one or more lines are too long
+208
View File
@@ -0,0 +1,208 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import { fabric } from "./lib/fabric.js";
console.log("HELLO WORLD");
function resizeCanvas(node, sizes)
{
const { width, height } = sizes ?? node.painter.currentCanvasSize;
node.painter.canvas.setDimensions({
width: width,
height: height,
});
node.painter.canvas.getElement().width = width;
node.painter.canvas.getElement().height = height;
node.painter.canvas.renderAll();
app.graph.setDirtyCanvas(true, false);
}
class MotionPainter {
constructor(node, canvas) {
this.node = node;
this.canvas = this.initCanvas(canvas);
this.arrows = [];
this.isDrawing = false;
this.startPoint = null;
this.currentCanvasSize = { width: 512, height: 512 };
console.log("INIT");
}
initCanvas(canvasEl) {
this.canvas = new fabric.Canvas(canvasEl, {
isDrawingMode: true,
backgroundColor: "transparent",
width: 512,
height: 512,
enablePointerEvents: true,
});
this.canvas.backgroundColor = "#ffffff";
fabric.util.addListener(
this.canvas.upperCanvasEl,
"contextmenu",
function (e) {
e.preventDefault();
}
);
return this.canvas;
}
}
function MotionPainterWidget(node, app) {
const widget = {
type: "motion_painter_widget",
name: `motion_painter_widget`,
callback: () => {},
draw: function (ctx, _, widgetWidth, y, widgetHeight)
{
const margin = 10,
left_offset = 8,
top_offset = 50,
visible = app.canvas.ds.scale > 0.6 && this.type === "motion_painter_widget",
w = widgetWidth - margin * 2 - 80,
clientRectBound = ctx.canvas.getBoundingClientRect(),
transform = new DOMMatrix()
.scaleSelf(
clientRectBound.width / ctx.canvas.width,
clientRectBound.height / ctx.canvas.height
)
.multiplySelf(ctx.getTransform())
.translateSelf(margin, margin + y),
scale = new DOMMatrix().scaleSelf(transform.a, transform.d);
let aspect_ratio = 1;
if (node?.imgs && typeof node.imgs !== undefined) {
aspect_ratio = node.imgs[0].naturalHeight / node.imgs[0].naturalWidth;
}
Object.assign(this.painter_wrap.style, {
left: `${
transform.a * margin * left_offset +
transform.e +
clientRectBound.left
}px`,
top: `${
transform.d + transform.f + top_offset + clientRectBound.top
}px`,
width: `${w * transform.a}px`,
height: `${w * transform.d}px`,
position: "absolute",
zIndex: app.graph._nodes.indexOf(node),
});
Object.assign(this.painter_wrap.children[0].style, {
transformOrigin: "0 0",
transform: scale,
width: w + "px",
height: w * aspect_ratio + "px",
});
Object.assign(this.painter_wrap.children[1].style, {
transformOrigin: "0 0",
transform: scale,
width: w + "px",
height: w * aspect_ratio + "px",
});
}
}
// Fabric canvas
let canvasPainter = document.createElement("canvas");
node.painter = new MotionPainter(node, canvasPainter)
node.painter.canvas.setWidth(node.painter.currentCanvasSize.width);
node.painter.canvas.setHeight(node.painter.currentCanvasSize.height);
resizeCanvas(node, node.painter.canvas);
widget.painter_wrap = node.painter.canvas.wrapperEl;
widget.parent = node;
document.body.appendChild(widget.painter_wrap);
// Add customWidget to node
node.addCustomWidget(widget);
widget.onRemove = () => {
widget.painter_wrap?.remove();
};
node.onResize = function ()
{
let [w, h] = this.size;
let aspect_ratio = 1;
if (node?.imgs && typeof this.imgs !== undefined) {
aspect_ratio = this.imgs[0].naturalHeight / this.imgs[0].naturalWidth;
}
let buffer = 90;
if (w > this.painter.maxNodeSize) w = w - (w - this.painter.maxNodeSize);
if (w < 600) w = 600;
h = w * aspect_ratio + buffer;
this.size = [w, h];
};
app.canvas.onDrawBackground = function ()
{
// Draw node isnt fired once the node is off the screen
// if it goes off screen quickly, the input may not be removed
// this shifts it off screen so it can be moved back if the node is visible.
for (let n in app.graph._nodes) {
const currnode = app.graph._nodes[n];
for (let w in currnode.widgets) {
let wid = currnode.widgets[w];
if (Object.hasOwn(wid, "motion_painter_widget")) {
wid.painter_wrap.style.left = -8000 + "px";
wid.painter_wrap.style.position = "absolute";
}
}
}
};
app.graph.setDirtyCanvas(true, false);
node.onResize();
return { widget: widget };
}
app.registerExtension({
name: "MI2V Motion Painter",
async beforeRegisterNodeDef(nodeType, nodeData, appInstance) {
if (nodeData.name === "MI2V Motion Painter") {
console.log("Registering onNodeCreated for MI2V_MotionPainter");
// Create node
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = async function () {
const r = onNodeCreated
? onNodeCreated.apply(this, arguments)
: undefined;
console.log("onNodeCreated called for node:", this.type);
// const node = this;
// // Initialize imageName property
// node.imageName = "default_image.png"; // Set a default image name or path
// // Optionally, add a widget to select the image
// node.addWidget("image", "image", null, (value) => {
// node.imageName = value;
// node.motionPainter.loadInputImage();
// });
MotionPainterWidget.apply(this, [this, appInstance]);
this.painter.canvas.renderAll();
this.title = "HELLOOOO";
};
}
},
});
+668
View File
@@ -0,0 +1,668 @@
// Make modal window
function makeModal({
title = "Message",
text = "No text",
type = "info",
parent = null,
stylePos = "fixed",
} = {}) {
const overlay = document.createElement("div");
Object.assign(overlay.style, {
display: "none",
position: stylePos,
background: "rgba(0 0 0 / 0.8)",
opacity: 0,
top: "0",
left: "0",
right: "0",
bottom: "0",
zIndex: "500",
transition: "all .8s",
cursor: "pointer",
});
const boxModal = document.createElement("div");
Object.assign(boxModal.style, {
transition: "all 0.5s",
opacity: 0,
display: "none",
position: stylePos,
top: "50%",
left: "50%",
transform: "translate(-50%,-50%)",
background: "#525252",
minWidth: "300px",
fontFamily: "sans-serif",
zIndex: "501",
border: "1px solid rgb(255 255 255 / 45%)",
});
boxModal.className = "alekpet_modal_window";
const boxModalBody = document.createElement("div");
Object.assign(boxModalBody.style, {
display: "flex",
flexDirection: "column",
textAlign: "center",
});
boxModalBody.className = "alekpet_modal_body";
const boxModalHtml = `
<div class="alekpet_modal_header" style="display: flex; align-items: center; background: #222; width: 100%;justify-content: center;">
<div class="alekpet_modal_title" style="flex-basis: 85%; text-align: center;padding: 5px;">${title}</div>
<div class="alekpet_modal_close">✕</div>
</div>
<div class="alekpet_modal_description" style="padding: 8px;">${text}</div>`;
boxModalBody.innerHTML = boxModalHtml;
const alekpet_modal_header = boxModalBody.querySelector(
".alekpet_modal_header"
);
Object.assign(alekpet_modal_header.style, {
display: "flex",
alignItems: "center",
});
const close = boxModalBody.querySelector(".alekpet_modal_close");
Object.assign(close.style, {
cursor: "pointer",
});
let parentElement = document.body;
if (parent && parent.nodeType === 1) {
parentElement = parent;
}
boxModal.append(boxModalBody);
parentElement.append(overlay, boxModal);
const removeEvent = new Event("removeElements");
const remove = () => {
animateTransitionProps(boxModal, { opacity: 0 }).then(() =>
animateTransitionProps(overlay, { opacity: 0 }).then(() => {
parentElement.removeChild(boxModal);
parentElement.removeChild(overlay);
})
);
};
boxModal.addEventListener("removeElements", remove);
overlay.addEventListener("removeElements", remove);
animateTransitionProps(overlay)
.then(() => {
overlay.addEventListener("click", () => {
overlay.dispatchEvent(removeEvent);
});
animateTransitionProps(boxModal);
})
.then(() =>
boxModal
.querySelector(".alekpet_modal_close")
.addEventListener("click", () => boxModal.dispatchEvent(removeEvent))
);
}
function findWidget(node, value, attr = "name", func = "find") {
return node?.widgets
? node.widgets[func]((w) =>
Array.isArray(value) ? value.includes(w[attr]) : w[attr] === value
)
: null;
}
function animateTransitionProps(
el,
props = { opacity: 1 },
preStyles = { display: "block" }
) {
Object.assign(el.style, preStyles);
return new Promise((res) => {
setTimeout(() => {
Object.assign(el.style, props);
const transstart = () => (el.isAnimating = true);
const transchancel = () => (el.isAnimating = false);
el.addEventListener("transitionstart", transstart);
el.addEventListener("transitioncancel", transchancel);
el.addEventListener("transitionend", function transend() {
el.isAnimating = false;
el.removeEventListener("transitionend", transend);
el.removeEventListener("transitionend", transchancel);
el.removeEventListener("transitionend", transstart);
res(el);
});
}, 100);
});
}
function animateClick(target, opacityVal = 0.9) {
if (target?.isAnimating) return;
const hide = +target.style.opacity === 0;
return animateTransitionProps(target, {
opacity: hide ? opacityVal : 0,
}).then(() => showHide({ elements: [target], hide: !hide }));
}
function showHide({ elements = [], hide = null, displayProp = "block" } = {}) {
Array.from(elements).forEach((el) => {
if (hide !== null) {
el.style.display = !hide ? displayProp : "none";
} else {
el.style.display =
!el.style.display || el.style.display === "none" ? displayProp : "none";
}
});
}
function isEmptyObject(obj) {
if (!obj) return true;
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
function makeElement(tag, attrs = {}) {
if (!tag) tag = "div";
const element = document.createElement(tag);
Object.keys(attrs).forEach((key) => {
const currValue = attrs[key];
if (key === "class") {
if (Array.isArray(currValue)) {
element.classList.add(...currValue);
} else if (currValue instanceof String || typeof currValue === "string") {
element.className = currValue;
}
} else if (key === "dataset") {
try {
if (Array.isArray(currValue)) {
currValue.forEach((datasetArr) => {
const [prop, propval] = Object.entries(datasetArr)[0];
element.dataset[prop] = propval;
});
} else {
Object.entries(currValue).forEach((datasetArr) => {
const [prop, propval] = datasetArr;
element.dataset[prop] = propval;
});
}
} catch (err) {
console.log(err);
}
} else if (key === "style") {
if (
typeof currValue === "object" &&
!Array.isArray(currValue) &&
Object.keys(currValue).length
) {
Object.assign(element[key], currValue);
} else if (
typeof currValue === "object" &&
Array.isArray(currValue) &&
currValue.length
) {
element[key] = [...currValue];
} else if (currValue instanceof String || typeof currValue === "string") {
element[key] = currValue;
}
} else if (["for"].includes(key)) {
element.setAttribute(key, currValue);
} else if (key === "children") {
element.append(...(currValue instanceof Array ? currValue : [currValue]));
} else if (key === "parent") {
currValue.append(element);
} else {
element[key] = currValue;
}
});
return element;
}
function isValidStyle(opt, strColor) {
let op = new Option().style;
if (!op.hasOwnProperty(opt))
return { result: false, color: "", color_hex: "" };
op[opt] = strColor;
return {
result: op[opt] !== "",
color_rgb: op[opt],
color_hex: rgbToHex(op[opt]),
};
}
function rgbToHex(rgb) {
const regEx = new RegExp(/\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);
if (regEx.test(rgb)) {
let [, r, g, b] = regEx.exec(rgb);
r = parseInt(r).toString(16);
g = parseInt(g).toString(16);
b = parseInt(b).toString(16);
r = r.length === 1 ? r + "0" : r;
g = g.length === 1 ? g + "0" : g;
b = b.length === 1 ? b + "0" : b;
return `#${r}${g}${b}`;
}
}
async function getDataJSON(url) {
try {
const response = await fetch(url);
const jsonData = await response.json();
return jsonData;
} catch (err) {
return new Error(err);
}
}
function deepMerge(target, source) {
if (source?.nodeType) return;
for (let key in source) {
if (source[key] instanceof Object && key in target) {
Object.assign(source[key], deepMerge(target[key], source[key]));
}
}
Object.assign(target || {}, source);
return target;
}
const THEME_MODAL_WINDOW_BASE = {
stylesTitle: {
background: "auto",
padding: "5px",
borderRadius: "6px",
marginBottom: "5px",
alignSelf: "stretch",
},
stylesWrapper: {
display: "none",
opacity: 0,
minWidth: "220px",
position: "absolute",
left: "50%",
top: "50%",
transform: "translate(-50%, -50%)",
opacity: 0,
transition: "all .8s",
fontFamily: "monospace",
zIndex: 99999,
},
stylesBox: {
display: "flex",
flexDirection: "column",
background: "#0e0e0e",
padding: "6px",
justifyContent: "center",
alignItems: "center",
gap: "3px",
textAlign: "center",
borderRadius: "6px",
color: "white",
border: "2px solid silver",
boxShadow: "2px 2px 4px silver",
maxWidth: "300px",
},
stylesClose: {
position: "absolute",
top: "-10px",
right: "-10px",
background: "silver",
borderRadius: "50%",
width: "20px",
height: "20px",
cursor: "pointer",
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: "0.8rem",
},
};
const THEMES_MODAL_WINDOW = {
error: {
stylesTitle: {
...THEME_MODAL_WINDOW_BASE.stylesTitle,
background: "#8f210f",
},
stylesBox: {
...THEME_MODAL_WINDOW_BASE.stylesBox,
background: "#3b2222",
boxShadow: "3px 3px 6px #141414",
border: "1px solid #f91b1b",
},
stylesWrapper: { ...THEME_MODAL_WINDOW_BASE.stylesWrapper },
stylesClose: {
...THEME_MODAL_WINDOW_BASE.stylesClose,
background: "#3b2222",
},
},
warning: {
stylesTitle: {
...THEME_MODAL_WINDOW_BASE.stylesTitle,
background: "#e99818",
},
stylesBox: {
...THEME_MODAL_WINDOW_BASE.stylesBox,
background: "#594e32",
boxShadow: "3px 3px 6px #141414",
border: "1px solid #e99818",
},
stylesWrapper: { ...THEME_MODAL_WINDOW_BASE.stylesWrapper },
stylesClose: {
...THEME_MODAL_WINDOW_BASE.stylesClose,
background: "#594e32",
},
},
normal: {
stylesTitle: {
...THEME_MODAL_WINDOW_BASE.stylesTitle,
background: "#108f0f",
},
stylesBox: {
...THEME_MODAL_WINDOW_BASE.stylesBox,
background: "#223b2a",
boxShadow: "3px 3px 6px #141414",
border: "1px solid #108f0f",
},
stylesWrapper: { ...THEME_MODAL_WINDOW_BASE.stylesWrapper },
stylesClose: {
...THEME_MODAL_WINDOW_BASE.stylesClose,
background: "#223b2a",
},
},
};
const defaultOptions = {
auto: {
autohide: false,
autoshow: false,
autoremove: false,
propStyles: { opacity: 0 },
propPreStyles: {},
timewait: 2000,
},
overlay: {
overlay_enabled: false,
overlayClasses: [],
overlayStyles: {},
},
close: { closeRemove: false, showClose: true },
parent: null,
};
function createWindowModal({
textTitle = "Message",
textBody = "Hello world!",
textFooter = null,
classesWrapper = [],
stylesWrapper = {},
classesBox = [],
stylesBox = {},
classesTitle = [],
stylesTitle = {},
classesBody = [],
stylesBody = {},
classesClose = [],
stylesClose = {},
classesFooter = [],
stylesFooter = {},
options = defaultOptions,
} = {}) {
// Check all options exist
const _options = deepMerge(
JSON.parse(JSON.stringify(defaultOptions)),
options
);
const {
parent,
overlay: { overlay_enabled, overlayClasses, overlayStyles },
close: { closeRemove, showClose },
auto: {
autohide,
autoshow,
autoremove,
timewait,
propStyles,
propPreStyles,
},
} = _options;
// Function past text(html)
function addText(text, parent) {
if (!parent) return;
switch (typeof text) {
case "string":
if (/^\<*.\/?\>$/.test(text)) {
parent.innerHTML(text);
} else {
parent.textContent = text;
}
break;
case "object":
default:
if (Array.isArray(text)) {
text.forEach((element) => parent.append(element));
} else if (text.nodeType === 1 || text.nodeType === 3)
parent.append(text);
}
}
// Overlay
let overlayElement = null;
if (overlay_enabled) {
overlayElement = makeElement("div", {
class: [...overlayClasses],
style: {
display: "none",
position: "fixed",
background: "rgba(0 0 0 / 0.8)",
opacity: 0,
top: 0,
left: 0,
right: 0,
bottom: 0,
zIndex: 99999,
transition: "all .8s",
cursor: "pointer",
...overlayStyles,
},
});
}
// Wrapper
const wrapper_settings = makeElement("div", {
class: ["alekpet__wrapper__window", ...classesWrapper],
});
Object.assign(wrapper_settings.style, {
...THEME_MODAL_WINDOW_BASE.stylesWrapper,
...stylesWrapper,
});
// Box
const box__settings = makeElement("div", {
class: ["alekpet__window__box", ...classesBox],
});
Object.assign(box__settings.style, {
...THEME_MODAL_WINDOW_BASE.stylesBox,
...stylesBox,
});
// Title
const box_settings_title = makeElement("div", {
class: ["alekpet__window__title", ...classesTitle],
});
Object.assign(box_settings_title.style, {
...THEME_MODAL_WINDOW_BASE.stylesTitle,
...stylesTitle,
});
// Add text (html) to title
addText(textTitle, box_settings_title);
// Body
const box_settings_body = makeElement("div", {
class: ["alekpet__window__body", ...classesBody],
});
Object.assign(box_settings_body.style, {
display: "flex",
flexDirection: "column",
alignItems: "flex-end",
gap: "5px",
textWrap: "wrap",
...stylesBody,
});
// Add text (html) to body
addText(textBody, box_settings_body);
// Close button
const close__box__button = makeElement("div", {
class: ["close__box__button", ...classesClose],
textContent: "✖",
});
Object.assign(close__box__button.style, {
...THEME_MODAL_WINDOW_BASE.stylesClose,
...stylesClose,
});
if (!showClose) close__box__button.style.display = "none";
const closeEvent = new Event("closeModal");
const closeModalWindow = function () {
overlay_enabled
? animateTransitionProps(overlayElement, {
opacity: 0,
})
.then(() =>
animateTransitionProps(wrapper_settings, {
opacity: 0,
})
)
.then(() => {
if (closeRemove) {
parent.removeChild(wrapper_settings);
parent.removeChild(overlayElement);
} else {
showHide({ elements: [wrapper_settings, overlayElement] });
}
})
: animateTransitionProps(wrapper_settings, {
opacity: 0,
}).then(() => {
showHide({ elements: [wrapper_settings] });
});
};
close__box__button.addEventListener("closeModal", closeModalWindow);
close__box__button.addEventListener("click", () =>
close__box__button.dispatchEvent(closeEvent)
);
close__box__button.onmouseenter = () => {
close__box__button.style.opacity = 0.8;
};
close__box__button.onmouseleave = () => {
close__box__button.style.opacity = 1;
};
box__settings.append(box_settings_title, box_settings_body);
// Footer
if (textFooter) {
const box_settings_footer = makeElement("div", {
class: [...classesFooter],
});
Object.assign(box_settings_footer.style, {
...stylesFooter,
});
// Add text (html) to body
addText(textFooter, box_settings_footer);
box__settings.append(box_settings_footer);
}
wrapper_settings.append(close__box__button, box__settings);
if (parent && parent.nodeType === 1) {
if (overlay_enabled) parent.append(overlayElement);
parent.append(wrapper_settings);
if (autoshow) {
overlay_enabled
? animateClick(overlayElement).then(() =>
animateClick(wrapper_settings).then(
() =>
autohide &&
setTimeout(
() =>
animateTransitionProps(
wrapper_settings,
{ ...propStyles },
{ ...propPreStyles }
)
.then(() =>
animateTransitionProps(
overlayElement,
{ ...propStyles },
{ ...propPreStyles }
)
)
.then(() => {
if (autoremove) {
parent.removeChild(wrapper_settings);
parent.removeChild(overlayElement);
}
}),
timewait
)
)
)
: animateClick(wrapper_settings).then(
() =>
autohide &&
setTimeout(
() =>
animateTransitionProps(
wrapper_settings,
{ ...propStyles },
{ ...propPreStyles }
).then(
() => autoremove && parent.removeChild(wrapper_settings)
),
timewait
)
);
}
}
return wrapper_settings;
}
export {
makeModal,
createWindowModal,
animateTransitionProps,
animateClick,
showHide,
makeElement,
getDataJSON,
isEmptyObject,
isValidStyle,
rgbToHex,
findWidget,
THEMES_MODAL_WINDOW,
};