目录
关于在TinyMCE中使用注释的指导,请参阅:使用注释。
关于TinyMCE注释插件的概述,请参阅:概述。
关于配置注释插件的说明,请参阅:开始使用注释插件 - 选择模式。
概述
此插件仅适用于付费的TinyMCE订阅。
注释插件允许用户通过直接在TinyMCE编辑器中添加注释来发起和参与对话。它还支持查看文档中的所有注释,以便高效协作。
交互式示例
以下演示使用的是注释插件的默认模式——回调模式。有关嵌入式模式的演示,请参阅嵌入式模式交互式示例。
HTML
<textarea id="comments-callback">
<h2>欢迎使用Tiny注释!</h2>
<p>请尝试我们Tiny注释高级插件的这个演示。</p>
<ol>
<li>高亮你想要评论的内容。</li>
<li>点击工具栏中的<em>添加注释</em>图标。</li>
<li>在注释侧边栏底部的文本字段中输入你的注释。</li>
<li>点击<strong>注释</strong>。</li>
</ol>
<p>你的注释<span class="mce-annotation tox-comment" data-mce-annotation-uid="mce-conversation_19679600221621399703915" data-mce-annotation="tinycomments">then</span>会附加到文本上,<span class="mce-annotation tox-comment" data-mce-annotation-uid="mce-conversation_420304606321716900864126" data-mce-annotation="tinycomments">exactly like this!</span></p>
<p>如果你想在自己的环境中试用Tiny注释,Tiny注释是你可以在注册Tiny账户后免费试用14天的高级插件之一。也请务必查看我们的文档。</p>
<h2>一个简单的表格供你操作</h2>
<table style="border-collapse: collapse; width: 100%;" border="1">
<thead>
<tr>
<th>产品</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://www.tiny.cloud/">Tiny Cloud</a></td>
<td>将强大的富文本编辑功能集成到你的应用程序中最简单、最可靠的方法。</td>
</tr>
<tr>
<td><a href="https://www.tiny.cloud/drive/">Tiny Drive</a></td>
<td>云端的TinyMCE图像和文件管理。</td>
</tr>
</tbody>
</table>
<p>感谢支持TinyMCE!我们希望它能帮助用户创建出色的内容。</p>
</textarea>JS
const API_URL = 'https://demouserdirectory.tiny.cloud/v1/users';
const user_id = 'james-wilson';
const collaborator_id = 'mia-andersson';
const now = new Date();
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000).toISOString();
const anhourago = new Date(now.getTime() - 60 * 60 * 1000).toISOString();
const fakeDelay = 200;
const randomString = () => {
return crypto.getRandomValues(new Uint32Array(1))[0].toString(36).substring(2, 14);
};
const conversationDb = {
'mce-conversation_19679600221621399703915': {
uid: 'mce-conversation_19679600221621399703915',
comments: [{
uid: 'mce-conversation_19679600221621399703915',
author: user_id,
authorName: 'James Wilson',
authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
content: `What do you think about this?`,
createdAt: yesterday,
modifiedAt: yesterday
}, {
uid: 'mce-conversation_19679600221621399703917',
author: collaborator_id,
authorName: 'Mia Andersson',
authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
content: `I think this is a great idea!`,
createdAt: anhourago,
modifiedAt: anhourago,
}]
},
'mce-conversation_420304606321716900864126': {
uid: 'mce-conversation_420304606321716900864126',
comments: [{
uid: 'mce-conversation_420304606321716900864126',
author: collaborator_id,
authorName: 'Mia Andersson',
authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_mia-andersson_128_e6f9424b.jpg',
content: `Please revise this sentence, exclamation points are unprofessional!`,
createdAt: yesterday,
modifiedAt: anhourago
}]
}
};
const tinycomments_create = (req, done, fail) => {
if (req.content === 'fail') {
fail(new Error('Something has gone wrong...'));
} else {
const uid = 'annotation-' + randomString();
conversationDb[uid] = {
uid,
comments: [{
uid,
author: user_id,
authorName: 'James Wilson',
authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
content: req.content,
createdAt: req.createdAt,
modifiedAt: req.createdAt
}]
};
setTimeout(() => done({ conversationUid: uid }), fakeDelay);
}
};
const tinycomments_reply = (req, done) => {
const commentUid = 'annotation-' + randomString();
conversationDb[req.conversationUid].comments.push({
uid: commentUid,
author: user_id,
authorName: 'James Wilson',
authorAvatar: 'https://sneak-preview.tiny.cloud/demouserdirectory/images/employee_james-wilson_128_52f19412.jpg',
content: req.content,
createdAt: req.createdAt,
modifiedAt: req.createdAt
});
setTimeout(() => done({ commentUid: commentUid }), fakeDelay);
};
const tinycomments_delete = (req, done) => {
if (user_id === collaborator_id) { // 用你自己的逻辑替换,例如检查用户是否创建了对话
delete conversationDb[req.conversationUid];
setTimeout(() => done({ canDelete: true }), fakeDelay);
} else {
setTimeout(() => done({ canDelete: false, reason: 'Must be admin user' }), fakeDelay);
}
};
const tinycomments_resolve = (req, done) => {
const conversation = conversationDb[req.conversationUid];
if (user_id === conversation.comments[0].author) { // 用你自己的逻辑替换,例如检查用户是否有管理员权限
delete conversationDb[req.conversationUid];
setTimeout(() => done({ canResolve: true }), fakeDelay);
} else {
setTimeout(() => done({ canResolve: false, reason: 'Must be conversation author' }), fakeDelay);
}
};
const tinycomments_delete_comment = (req, done) => {
const oldcomments = conversationDb[req.conversationUid].comments;
let reason = 'Comment not found';
const newcomments = oldcomments.filter((comment) => {
if (comment.uid === req.commentUid) { // 找到要删除的评论
if (user_id === comment.author) { // 用你自己的逻辑替换,例如检查用户是否有管理员权限
return false; // 删除该评论
} else {
reason = 'Not authorised to delete this comment'; // 更新原因
}
}
return true; // 保留该评论
});
if (newcomments.length === oldcomments.length) {
setTimeout(() => done({ canDelete: false, reason }), fakeDelay);
} else {
conversationDb[req.conversationUid].comments = newcomments;
setTimeout(() => done({ canDelete: true }), fakeDelay);
}
};
const tinycomments_edit_comment = (req, done) => {
const oldcomments = conversationDb[req.conversationUid].comments;
let reason = 'Comment not found';
let canEdit = false;
const newcomments = oldcomments.map((comment) => {
if (comment.uid === req.commentUid) { // 找到要删除的评论
if (user_id === comment.author) { // 用你自己的逻辑替换,例如检查用户是否有管理员权限
canEdit = true; // 用户可以编辑该评论
return { ...comment, content: req.content, modifiedAt: new Date().toISOString() }; // 更新该评论
} else {
reason = 'Not authorised to edit this comment'; // 更新原因
}
}
return comment; // 保留该评论
});
if (canEdit) {
conversationDb[req.conversationUid].comments = newcomments;
setTimeout(() => done({ canEdit }), fakeDelay);
} else {
setTimeout(() => done({ canEdit, reason }), fakeDelay);
}
};
const tinycomments_delete_all = (req, done) => {
const conversation = conversationDb[req.conversationUid];
if (user_id === conversation.comments[0].author) { // 用你自己的逻辑替换,例如检查用户是否有管理员权限
delete conversationDb[req.conversationUid];
setTimeout(()=> done({ canDelete: true }), fakeDelay); } else { setTimeout(() => done({ canDelete: false, reason: 'Must be conversation author' }), fakeDelay); }};const tinycomments_lookup = (req, done) => { setTimeout(() => { done({ conversation: { uid: conversationDb[req.conversationUid].uid, comments: [...conversationDb[req.conversationUid].comments] } }); }, fakeDelay);};const tinycomments_fetch = (conversationUids, done) => { const fetchedConversations = {}; conversationUids.forEach((uid) => { const conversation = conversationDb[uid]; if (conversation) { fetchedConversations[uid] = {...conversation}; } }); setTimeout(() => done({ conversations: fetchedConversations }), fakeDelay);};tinymce.init({ selector: 'textarea#comments-callback', toolbar: 'addcomment showcomments code | bold italic underline', menubar: 'file edit view insert format tools tc help', menu: { tc: { title: 'TinyComments', items: 'addcomment showcomments deleteallconversations' } }, plugins: [ 'tinycomments', 'help', 'code', 'quickbars', 'link', 'lists', 'image' ], quickbars_selection_toolbar: 'alignleft aligncenter alignright | addcomment showcomments', quickbars_image_toolbar: 'alignleft aligncenter alignright | rotateleft rotateright | imageoptions', tinycomments_mode: 'callback', tinycomments_mentions_enabled: true, sidebar_show: 'showcomments', tinycomments_create, tinycomments_reply, tinycomments_delete, tinycomments_resolve, tinycomments_delete_all, tinycomments_lookup, tinycomments_delete_comment, tinycomments_edit_comment, tinycomments_fetch, user_id, fetch_users: (userIds) => Promise.all(userIds .map((userId) => fetch(`${API_URL}/${userId}`) .then((response) => response.json()) .catch(() => ({ id: userId }))))});在内容中无缝协作
通过 Comments 插件,用户可以:
通过直观的界面创建和回复评论,实现内容协作。
控制删除或解决单个评论或整个评论线程的权限。
Comments 插件的主要功能
Comments 插件使用户能够:
创建评论
编辑评论
回复评论
搜索评论
解决评论线程
删除评论或整个线程
支持的内容
文本
区块
Comments 插件在 TinyMCE 6.1 及更高版本中支持以下功能:
开始使用 Comments 插件 - 选择模式
Comments 插件提供两种模式:
回调模式
此默认模式将评论存储在外部(如数据库中),需要使用回调函数管理评论数据。设置详情请参阅:在回调模式下配置 Comments 插件。
嵌入模式
在此模式下,评论直接存储在内容中,无需回调配置。设置详情请参阅:在嵌入模式下配置 Comments 插件。
只有当 TinyMCE 以经典模式运行时才支持 Comments 插件。Comments 插件需要侧边栏,而侧边栏在内联或无干扰模式下不受支持。有关编辑模式差异的更多信息,请参阅 内联编辑模式。