on-codemerge
Version:
A WYSIWYG editor for on-codemerge is a user-friendly interface that allows users to edit and view their code in real time, exactly as it will appear in the final product
135 lines (134 loc) • 6.2 kB
JavaScript
/*! on-codemerge v1.3.1 @author Pavel Kuzmin @license MIT @homepage https://s00d.github.io/on-codemerge/ @repository git+https://github.com/s00d/on-codemerge.git Copyright (c) 2026 Pavel Kuzmin - Built on 2026-07-02T13:39:17.947Z */
var p = Object.defineProperty;
var h = (o, e, t) => e in o ? p(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
var l = (o, e, t) => h(o, typeof e != "symbol" ? e + "" : e, t);
import { PopupManager as u } from "../../../core/ui/PopupManager.mjs";
import c from "../../../icons/upload-message.svg.mjs";
import { createContainer as r, createP as n, createInputField as g } from "../../../utils/helpers.mjs";
class w {
constructor(e, t, a, s) {
l(this, "editor");
l(this, "popup");
l(this, "uploader");
l(this, "config");
l(this, "onUpload", null);
// Ссылки на элементы
l(this, "uploadArea", null);
l(this, "uploadMessage", null);
l(this, "uploadProgress", null);
l(this, "progressFill", null);
l(this, "filename", null);
this.onUpload = s, this.editor = e, this.uploader = t, this.config = a, this.popup = new u(e, {
title: "Upload File",
className: "file-upload-menu",
closeOnClickOutside: !0,
buttons: [
{
label: e.t("Cancel"),
variant: "secondary",
onClick: () => this.popup.hide()
}
],
items: [
{
type: "custom",
id: "upload-content",
content: () => this.createUploadContent()
}
]
});
}
createUploadContent() {
const e = r("p-4");
this.uploadArea = r(
"upload-area border-2 border-dashed border-gray-300 rounded-lg p-8 text-center"
), this.uploadMessage = r("upload-message"), this.uploadMessage.insertAdjacentHTML("afterbegin", c);
const t = n("p");
t.className = "mt-2 text-sm text-gray-600", t.innerHTML = `
${this.editor.t("Drag and drop your file here, or")}
<button type="button" class="browse-button text-blue-500 hover:text-blue-700">
${this.editor.t("browse")}
</button>
`, this.uploadMessage.appendChild(t);
const a = n(
"mt-1 text-xs text-gray-500",
this.editor.t("Maximum file size: ") + this.uploader.formatFileSize(this.config.maxFileSize ?? 10 * 1024 * 1024)
);
this.uploadMessage.appendChild(a), this.uploadProgress = r("upload-progress hidden");
const s = r(
"progress-bar h-2 bg-gray-200 rounded-full overflow-hidden"
);
this.progressFill = r(
"progress-fill h-full bg-blue-500 transition-all duration-300"
), this.progressFill.style.width = "0%", s.appendChild(this.progressFill), this.uploadProgress.appendChild(s), this.filename = n(
"mt-2 text-sm text-gray-600",
`${this.editor.t("Uploading")} <span class="filename"></span>...`
), this.uploadProgress.appendChild(this.filename);
const i = g("file");
return i.className = "hidden", this.uploadArea.appendChild(this.uploadMessage), this.uploadArea.appendChild(this.uploadProgress), e.appendChild(this.uploadArea), e.appendChild(i), this.setupEventListeners(this.uploadArea, i), e;
}
setupEventListeners(e, t) {
const a = e.querySelector(".browse-button");
this.editor.on(
"file-drop",
async (s) => {
var i;
if (!s.type.startsWith("image/")) {
if ((i = this.editor) == null || i.ensureEditorFocus(), s.content instanceof File)
await this.handleFileUpload(s.content);
else if (s.content instanceof ArrayBuffer) {
const d = new File([s.content], s.name, { type: s.type });
await this.handleFileUpload(d);
} else if (typeof s.content == "string") {
const d = new File([s.content], s.name, { type: "text/plain" });
await this.handleFileUpload(d);
}
}
}
), a.addEventListener("click", () => {
t.click();
}), t.addEventListener("change", async () => {
var i;
const s = (i = t.files) == null ? void 0 : i[0];
s && (await this.handleFileUpload(s), t.value = "");
});
}
async handleFileUpload(e) {
this.popup.show(), setTimeout(async () => {
if (e.size > 10 * 1024 * 1024) {
alert(
this.editor.t("File size exceeds 10MB limit", {
max: this.uploader.formatFileSize(this.config.maxFileSize ?? 10 * 1024 * 1024)
})
);
return;
}
if (!this.uploadMessage || !this.uploadProgress || !this.progressFill || !this.filename) {
console.error("UI elements are not initialized");
return;
}
this.uploadMessage.classList.add("hidden"), this.uploadProgress.classList.remove("hidden"), this.filename.textContent = e.name;
let t = 0;
const a = setInterval(() => {
t = Math.min(95, t + 5), this.progressFill.style.width = `${t}%`;
}, 50);
try {
const s = await this.uploader.uploadFile(e);
clearInterval(a), this.progressFill.style.width = "100%", await new Promise((i) => setTimeout(i, 500)), this.onUpload && this.onUpload(s), this.popup.hide(), setTimeout(() => {
this.uploadMessage.classList.remove("hidden"), this.uploadProgress.classList.add("hidden"), this.progressFill.style.width = "0%";
}, 300);
} catch {
clearInterval(a), alert(this.editor.t("Upload failed. Please try again.")), this.uploadMessage.classList.remove("hidden"), this.uploadProgress.classList.add("hidden"), this.progressFill.style.width = "0%";
}
}, 100);
}
show() {
this.uploadMessage && this.uploadProgress && this.progressFill && (this.uploadMessage.classList.remove("hidden"), this.uploadProgress.classList.add("hidden"), this.progressFill.style.width = "0%"), this.popup.show();
}
destroy() {
this.popup.hide(), this.uploadArea && (this.editor.off("drag-enter"), this.editor.off("drag-leave"), this.editor.off("drop")), this.uploadArea = null, this.uploadMessage = null, this.uploadProgress = null, this.progressFill = null, this.filename = null, this.editor = null, this.uploader = null, this.popup = null, this.onUpload = null;
}
}
export {
w as FileUploadMenu
};