Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TinyMCE Comments Plugin #473

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions ghostwriter/static/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,15 @@ hr {
right: 25px;
}

.comment-avatar {
width: 40px !important;
height: 40px !important;
border-radius: 50% !important;
border-style: solid !important;
border-width: 1px !important;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19) !important;
}

domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
/* ---------------------------------------------------
WYSIWYG-APPLIED STYLES
----------------------------------------------------- */
Expand Down Expand Up @@ -2681,6 +2690,19 @@ ol {
font-size: .8em;
}

/*----------------------------------------------------
COMMENT STYLES
------------------------------------------------------ */
#comment-thread {
clear: both;
}

.comment-header {
display: flex;
justify-content: center;
align-items: center;
}

/* ---------------------------------------------------
NOTIFICATIONS
----------------------------------------------------- */
Expand Down
6 changes: 4 additions & 2 deletions ghostwriter/static/js/tinymce/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
max_height: window_height - 250,
autoresize_bottom_margin: 10,
toolbar_mode: 'floating',
plugins: 'searchreplace autoresize visualchars visualblocks save preview lists image hr autosave advlist code wordcount codesample searchreplace paste link case table pagebreak',
plugins: 'searchreplace autoresize visualchars visualblocks save preview lists image hr autosave advlist code wordcount codesample searchreplace paste link case table pagebreak ghostwriter-comments',
toolbar: 'subscript superscript bold italic underline link blockquote case highlight | bullist numlist | codesample codeInline | table tablerowheader | evidenceUpload | searchreplace removeformat save | editorsHints',
contextmenu: 'table formats bold italic underline link removeformat',
contextmenu: 'table comment formats bold italic underline link removeformat',
paste_as_text: true,
paste_data_images: false,
browser_spellcheck: true,
Expand All @@ -72,6 +72,7 @@
.underline { text-decoration: underline; }
.tablerow1 { background-color: #D3D3D3; }
blockquote { border-left: 5px solid #ccc; padding: 0.5em; margin: 0.5em; }
.comment { background-color: #FF7E79 }
`,
formats: {
alignleft: {
Expand Down Expand Up @@ -161,6 +162,7 @@
table_default_styles: {'border-collapse': 'collapse', 'width': '100%', 'border-style': 'solid', 'border-width': '1px'},
table_default_attributes: {class: 'table table-sm table-striped table-bordered'},
table_header_type: 'sectionCells',
extended_valid_elements: 'span[class|comment-data]'
};

// TinyMCE config for most fields
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
tinymce.PluginManager.add('ghostwriter-comments', function(editor) {
// Function to decode the users hex username into ascii
function hex2ascii(hexString) {
let decodedStr = '';
for (let i = 0; i < hexString.length; i += 2) {
const byte = parseInt(hexString.substr(i, 2), 16);
decodedStr += String.fromCharCode(byte);
}
return decodedStr
}

// Create Comment
function createComment(comment, selection) {
const commentNode = editor.selection.getNode();
let commentThread = readComments(commentNode);
commentThread.push({ author: username, comment: comment });
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
editor.execCommand('mceInsertContent', false, `<span class="comment" comment-data="${encodeURIComponent(JSON.stringify(commentThread))}">${selection}</span>`);
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
}

// Read Comments
function readComments(commentNode) {
let commentThread = [];
if (commentNode.nodeName === 'SPAN' && commentNode.hasAttribute('comment-data')) {
commentDataDecoded = decodeURIComponent(commentNode.getAttribute('comment-data'));
commentData = JSON.parse(commentDataDecoded);
commentData.forEach(item => {
const author = item.author;
const comment = item.comment;
commentThread.push({ author: author, comment: comment });
});
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
}
return commentThread;
}

// Update Comments

// Resolve Comments
function resolveComment(commentNode) {
commentNode.className = 'comment-resolved';
}

// Delete Comments


editor.ui.registry.addMenuItem('comment', {
icon: 'comment',
text: 'Comment',
onAction: function () {
const selection = editor.selection.getContent();
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
const node = editor.selection.getNode();
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
let commentsThread = '';
readComments(node).forEach(item => {
const author = item.author;
const comment = item.comment;
const float = author === username ? 'right' : 'left';
commentsThread +=
`<div id="comment-thread" style="float: ${float};">
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
<div class="comment-header">
<h1>${hex2ascii(author)}</h1>
<img class="comment-avatar" src="/users/${hex2ascii(author)}/avatar" alt="Avatar">
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
</div>
<p>${comment}</p>
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
</div>`;
});

if (selection) {
domwhewell-sage marked this conversation as resolved.
Show resolved Hide resolved
const commentBox = editor.windowManager.open({
title: 'Add Comment',
body: {
type: 'panel',
items: [
{ type: 'htmlpanel', name: 'existingComments', html: commentsThread},
{ type: 'textarea', name: 'comment', label: 'Comment' },
]
},
buttons: [
{ type: 'cancel', text: 'Cancel' },
{ type: 'custom', text: 'Resolve' },
{ type: 'submit', text: 'Post' }
],
onSubmit: (api) => {
const comment = api.getData().comment;
// Add the comment to the dictionary
createComment(comment, selection);
api.close();
},
onAction: (api) => {
const Node = editor.selection.getNode();
if (Node.nodeName === 'SPAN' && Node.hasAttribute('comment-data')) {
resolveComment(Node);
api.close();
}
}
});
}
}
});

editor.on('click', function (e) {
const node = editor.selection.getNode();
if (node.nodeName === 'SPAN' && node.className === 'comment' && node.hasAttribute('comment-data')) {
editor.selection.select(node.firstChild);
editor.ui.registry.getAll().menuItems.comment.onAction();
}
});
});
Loading