Index: lams_build/conf/etherpad/etherpad-lite/node_modules/ep_comments_page/static/js/index.js =================================================================== diff -u -r0fef0bd96a5652683230ac548a27c3eab6e8c9fd -rf9dafe60150e1899c37200977b198e0546ced60c --- lams_build/conf/etherpad/etherpad-lite/node_modules/ep_comments_page/static/js/index.js (.../index.js) (revision 0fef0bd96a5652683230ac548a27c3eab6e8c9fd) +++ lams_build/conf/etherpad/etherpad-lite/node_modules/ep_comments_page/static/js/index.js (.../index.js) (revision f9dafe60150e1899c37200977b198e0546ced60c) @@ -16,9 +16,9 @@ const newComment = require('ep_comments_page/static/js/newComment'); const padcookie = require('ep_etherpad-lite/static/js/pad_cookie').padcookie; const preCommentMark = require('ep_comments_page/static/js/preCommentMark'); - const getCommentIdOnFirstPositionSelected = events.getCommentIdOnFirstPositionSelected; const hasCommentOnSelection = events.hasCommentOnSelection; +const Security = require('ep_etherpad-lite/static/js/security'); const cssFiles = [ 'ep_comments_page/static/css/comment.css', @@ -27,6 +27,12 @@ const UPDATE_COMMENT_LINE_POSITION_EVENT = 'updateCommentLinePosition'; +const parseMultiline = (text) => { + if (!text) return text; + text = JSON.stringify(text); + return text.substr(1, (text.length - 2)); +}; + /* ******************************************************************** * ep_comments Plugin * ******************************************************************** */ @@ -590,11 +596,6 @@ comment.commentId = commentId; comment.reply = true; - // LAMS fixed a bug where new line characters caused an error - if (comment.changeTo) { - comment.changeTo = comment.changeTo.replaceAll(/\n/g, ' '); - } - content = $('#commentsTemplate').tmpl(comment); if (comment.author !== clientVars.userId) { $(content).find('.comment-actions-wrapper').addClass('hidden'); @@ -791,12 +792,87 @@ $('iframe[name="ace_outer"]').contents().find(`#${commentId}`).remove(); }; -const parseMultiline = (text) => { - if (!text) return text; - text = JSON.stringify(text); - return text.substr(1, (text.length - 2)); +const cloneLine = (line) => { + const padOuter = $('iframe[name="ace_outer"]').contents(); + const padInner = padOuter.find('iframe[name="ace_inner"]'); + + const lineElem = $(line.lineNode); + const lineClone = lineElem.clone(); + const innerOffset = $(padInner).offset().left; + const innerPadding = parseInt(padInner.css('padding-left') + lineElem.offset().left); + const innerdocbodyMargin = innerOffset + innerPadding || 0; + padInner.contents().find('body').append(lineClone); + lineClone.css({position: 'absolute'}); + lineClone.css(lineElem.offset()); + lineClone.css({left: innerdocbodyMargin}); + lineClone.width(lineElem.width()); + + return lineClone; }; +let isHeading = function (index) { + const attribs = this.documentAttributeManager.getAttributesOnLine(index); + for (let i = 0; i < attribs.length; i++) { + if (attribs[i][0] === 'heading') { + const value = attribs[i][1]; + i = attribs.length; + return value; + } + } + return false; +}; + +const getXYOffsetOfRep = (rep) => { + let selStart = rep.selStart; + let selEnd = rep.selEnd; + // make sure end is after start + if (selStart[0] > selEnd[0] || (selStart[0] === selEnd[0] && selStart[1] > selEnd[1])) { + selEnd = selStart; + selStart = _.clone(selStart); + } + + let startIndex = 0; + const endIndex = selEnd[1]; + const lineIndex = selEnd[0]; + if (selStart[0] === selEnd[0]) { + startIndex = selStart[1]; + } + + const padInner = $('iframe[name="ace_outer"]').contents().find('iframe[name="ace_inner"]'); + + // Get the target Line + const startLine = rep.lines.atIndex(selStart[0]); + const endLine = rep.lines.atIndex(selEnd[0]); + const clone = cloneLine(endLine); + let lineText = Security.escapeHTML($(endLine.lineNode).text()).split(''); + lineText.splice(endIndex, 0, ''); + lineText.splice(startIndex, 0, ''); + lineText = lineText.join(''); + + const heading = isHeading(lineIndex); + if (heading) { + lineText = `<${heading}>${lineText}`; + } + $(clone).html(lineText); + + // Is the line visible yet? + if ($(startLine.lineNode).length !== 0) { + const worker = $(clone).find('#selectWorker'); + // A standard generic offset' + let top = worker.offset().top + padInner.offset().top + parseInt(padInner.css('padding-top')); + let left = worker.offset().left; + // adjust position + top += worker[0].offsetHeight; + + if (left < 0) { + left = 0; + } + // Remove the clone element + $(clone).remove(); + return [left, top]; + } +}; + EpComments.prototype.displayNewCommentForm = function () { const rep = {}; const ace = this.ace; @@ -826,7 +902,10 @@ $('#newComment').find('.from-value').text(selectedText); // Display form - newComment.showNewCommentPopup(); + setTimeout(() => { + const position = getXYOffsetOfRep(rep); + newComment.showNewCommentPopup(position); + }); // Check if the first element selected is visible in the viewport const $firstSelectedElement = this.getFirstElementSelected(); @@ -1323,6 +1402,7 @@ // Once ace is initialized, we set ace_doInsertHeading and bind it to the context exports.aceInitialized = (hookName, context, cb) => { const editorInfo = context.editorInfo; + isHeading = _(isHeading).bind(context); editorInfo.ace_getRepFromSelector = _(getRepFromSelector).bind(context); editorInfo.ace_getCommentIdOnFirstPositionSelected = _(getCommentIdOnFirstPositionSelected).bind(context); Index: lams_build/conf/etherpad/readme.txt =================================================================== diff -u -r29e53dbd342d463ece036ca8c0a24f4c49b26405 -rf9dafe60150e1899c37200977b198e0546ced60c --- lams_build/conf/etherpad/readme.txt (.../readme.txt) (revision 29e53dbd342d463ece036ca8c0a24f4c49b26405) +++ lams_build/conf/etherpad/readme.txt (.../readme.txt) (revision f9dafe60150e1899c37200977b198e0546ced60c) @@ -13,7 +13,7 @@ adminpads2: plugin to list and delete pads in /admin 2.1.16 authornames: Adds author names to span titles (shows on hover) 0.2.0 author_neat: Neat author display 0.0.31 - comments_page: Adds comments on sidebar and link it to the text 0.1.41 + comments_page: Adds comments on sidebar and link it to the text 0.1.47 export_authors: Etherpad plugin to add author information to the html export 0.1.1 headings2: Adds heading support 0.2.7 message_all: Use the Etherpad admin backend to send a message to all connected users 1.1.0