把 TOML 编辑器嵌入你的网站
面向开发者:如何把 TOML 编辑器放进你自己的页面(放在 iframe 中、在单独的窗口中打开,或作为只读查看器),以及文档、保存内容和 AI 结果如何在编辑器和你的服务器之间传递。无需注册,也不需要我们提供的密钥。
任何 https 页面(以及 localhost)都可以用 <iframe> 和 ?embed=1 嵌入编辑器,无需注册,无需密钥。嵌入后,编辑器会隐藏页面文字并显示“保存”按钮。有四种方式传入和取出文档。
1. 从链接打开文件,保存到你的服务器
src= 打开一个文件(你的服务器必须允许 CORS),webhook= 让“保存”(Ctrl+S)把文档发送到该地址。添加 &auto 可在每次修改后保存。
<iframe src="https://toml.giit.ch/zh/?embed=1&src=https://your-site.com/config/app.toml&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
Webhook 会收到一个带 JSON 的 POST 请求 { editor: "toml", event: "save", id, name, content, updated }。链接不携带令牌,因为令牌会留在服务器日志和浏览器历史记录中。因此,在地址中指定 Webhook 适合不需要令牌的保存地址,例如 localhost 或你的内网。对于公共服务器,请通过 tomleditor:load 中的 hook: { url, token } 传入 Webhook 和令牌,并像下面这个简短的 PHP 脚本一样验证令牌:
<?php
header('Access-Control-Allow-Origin: https://toml.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/config/$name.toml", $d['content']);
echo '{"ok":true}';
2. 由你的页面保存文档(postMessage)
编辑器发送 tomleditor:ready,你的页面以 tomleditor:load 回应,编辑器报告 tomleditor:loaded,有实际编辑时发送 tomleditor:change,用户保存时发送 tomleditor:save。你的页面可以发送 tomleditor:get(获取当前状态)或 tomleditor:save(相当于点击“保存”)。这样保存就通过你自己的登录和会话进行。
<iframe id="ed" src="https://toml.giit.ch/zh/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://toml.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'tomleditor:ready') { // 编辑器已就绪:把文档交给它
ed.contentWindow.postMessage({
type: 'tomleditor:load',
name: 'Settings',
content: await (await fetch('/config/app.toml')).text()
}, ORIGIN);
}
if (m.type === 'tomleditor:change') document.title = '● not saved'; // 一次实际编辑
if (m.type === 'tomleditor:save') { // 用户点击了“保存”
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content }) });
document.title = 'Saved';
}
});
// 你自己页面上的保存按钮:回应以 tomleditor:save 返回
function saveNow() { ed.contentWindow.postMessage({ type: 'tomleditor:get' }, ORIGIN); }
</script>
页面内的 AI 助手:在框架中同样可用。在 iframe 上设置 allow="clipboard-write" 后,“复制提示词”会直接使用剪贴板(否则编辑器会退回旧的复制命令,或显示提示词供手动复制)。AI 发送的链接无法到达另一个网站中的编辑器,因此编辑器会提示 AI 和用户把 AI 的完整回答粘贴到编辑器中,或在单独的窗口中打开编辑器。
3. 在单独的窗口中
window.open("https://toml.giit.ch/zh/?embed=window", "tomleditor-17") 会在单独的窗口中打开完整的编辑器,并通过 window.opener 使用相同的消息。AI 的链接可以到达那里。tomleditor:load 还可以带上 context: { host, title, rules }(AI 提示词随后会说明文档属于哪里,并遵循你的规则),以及 hook: { url, token },即仅用于此文档、从不保存的 Webhook。关闭有未保存更改的窗口时会发送 tomleditor:closing。
4. 通过你自己的服务器使用 AI
向编辑器提供你自己的提示词、你网站上的一个地址和本次编辑器会话的密钥。AI 对话框随后会显示“已连接到”你的网站、你告诉 AI 的内容,以及修改当前文档或新建一个文档的选项;复制提示词会把这些都组合起来。AI 带着密钥把结果发送到你的服务器,你的页面再在编辑器中打开它;新文档会单独打开,并保留在用户的浏览器中。每个编辑器会话一个密钥:编辑器打开期间有效,只有在没有密钥时,编辑器才会用 tomleditor:key-request 请求。编辑器自己从不发送密钥,也从不保存它;地址必须是你自己主机或其子域名上的 https 地址。
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // 每个编辑器会话一个密钥
const k = await key();
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content, ai: {
label: 'My Site', prompt: 'Keep every key and every comment.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// 记住 tomleditor:loaded 中的 id,忽略 id 不同的 change/save/closing
// 仅在编辑器没有密钥时:
if (m.type === 'tomleditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'tomleditor:ai', key: k.key }, ORIGIN); }
// 编辑器打开期间,每分钟通知你的服务器;关闭编辑器或页面会使密钥作废
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// 你的服务器有了结果(轮询、SSE …):target 为 "current" 或 "new"
ed.contentWindow.postMessage({ type: 'tomleditor:load', name: 'Settings', content: draft, from: 'ai', target }, ORIGIN);
密钥至少使用 128 位随机数,只保存其哈希值,将每个密钥绑定到已登录用户、文档和本次编辑器会话,每个会话一个,仅在你的页面报告会话仍打开时有效,并在编辑器或页面关闭时作废。
完整协议见 llms.txt,把它交给 AI,AI 就能为你的系统建立连接。其他 giit 编辑器的用法相同,只是各有自己的前缀,见 editors.giit.ch。
以只读方式显示文档(查看器)
?viewer=1 只显示完成的文档:没有代码,没有工具,无法更改任何内容,也不会在浏览器中保存任何内容。文档来自链接(#b64=、?src=)、您的页面通过 tomleditor:load 发送,或以普通表单 POST 到 post.php:字段 content 为文本或 b64 为 base64,可选 name,文本最多 20 MB。
<form method="post" action="https://toml.giit.ch/post.php?viewer=1" target="_blank">
<input type="hidden" name="lang" value="zh">
<input type="hidden" name="name" value="Report">
<input type="hidden" name="b64" value="…">
<button>Open</button>
</form>
不带 viewer=1 时,文档在普通编辑器中打开。无论哪种方式,文档都只保留在内存中:不会保存到服务器,也不会进入“我的文档”。直接打开时,查看器会说明内容来自第三方。