Files
coolcoth.com/public/assets/js/fixed-editor.js
T
2026-08-08 15:53:53 +08:00

89 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 固定版面富文本编辑器(依赖 contenteditable + execCommand,无外部依赖)
* - 工具栏:加粗/斜体/标题/列表/引用/链接/图片
* - 图片:从素材库选择或上传(复用 admin/media 接口)
* - 保存前将富文本 HTML 同步到隐藏 textarea(name=content)
*/
(function () {
'use strict';
var ed = document.getElementById('fxEditor');
var ta = document.getElementById('fxContent');
var form = document.getElementById('fxForm');
if (!ed || !ta || !form) return;
function sync() { ta.value = ed.innerHTML; }
ed.addEventListener('input', sync);
form.addEventListener('submit', function () { sync(); });
// 工具栏命令
document.querySelectorAll('.fx-toolbar button[data-cmd]').forEach(function (b) {
b.addEventListener('mousedown', function (e) { e.preventDefault(); }); // 防止编辑器失焦
b.addEventListener('click', function () {
var cmd = b.getAttribute('data-cmd');
var val = b.getAttribute('data-val') || null;
ed.focus();
document.execCommand(cmd, false, val);
sync();
});
});
// 链接
var linkBtn = document.getElementById('fxLink');
if (linkBtn) linkBtn.addEventListener('click', function () {
var url = prompt('链接地址(如 /contact 或 https://...');
if (url) { ed.focus(); document.execCommand('createLink', false, url); sync(); }
});
// 图片弹层
var modal = document.getElementById('fxModal');
var imgBtn = document.getElementById('fxImg');
var closeBtn = document.getElementById('fxModalClose');
if (imgBtn) imgBtn.addEventListener('click', openModal);
if (closeBtn) closeBtn.addEventListener('click', function () { modal.hidden = true; });
if (modal) modal.addEventListener('click', function (e) { if (e.target === modal) modal.hidden = true; });
function insertImg(url) {
ed.focus();
document.execCommand('insertHTML', false,
'<img src="' + url + '" alt="" style="max-width:100%;border-radius:8px;display:block;margin:8px 0">');
sync();
modal.hidden = true;
}
function openModal() {
modal.hidden = false;
var lib = document.getElementById('fxLib');
lib.innerHTML = '<span style="font-size:12px;color:#94a3b8">加载中…</span>';
fetch(window.__PB_MEDIA__)
.then(function (r) { return r.json(); })
.then(function (j) {
lib.innerHTML = '';
var items = (j && j.items) || [];
if (!items.length) { lib.innerHTML = '<span style="font-size:12px;color:#94a3b8">暂无素材,先上传</span>'; return; }
items.forEach(function (it) {
var img = document.createElement('img');
img.src = it.url; img.title = it.name;
img.addEventListener('click', function () { insertImg(it.url); });
lib.appendChild(img);
});
})
.catch(function () { lib.innerHTML = '<span style="font-size:12px;color:#dc2626">加载失败</span>'; });
}
// 上传图片
var up = document.getElementById('fxUp');
if (up) up.addEventListener('change', function () {
var file = this.files && this.files[0];
if (!file) return;
var fd = new FormData();
fd.append('file', file);
fetch(window.__PB_UPLOAD__, { method: 'POST', body: fd, headers: { 'X-CSRF-TOKEN': window.__PB_CSRF__ } })
.then(function (r) { return r.json(); })
.then(function (j) {
if (j && j.ok) { insertImg(j.url); openModal(); }
else alert((j && j.msg) || '上传失败');
})
.catch(function () { alert('上传失败,请重试'); });
this.value = '';
});
})();