diff --git a/chrome/content/zotero/xpcom/editorInstance.js b/chrome/content/zotero/xpcom/editorInstance.js index b379ca950b..018c06f31d 100644 --- a/chrome/content/zotero/xpcom/editorInstance.js +++ b/chrome/content/zotero/xpcom/editorInstance.js @@ -238,6 +238,74 @@ class EditorInstance { win.focus(); } } + + /** + * Transform plain text, containing some supported HTML tags, into actual HTML. + * A similar code is also used in pdf-reader mini editor for annotation text and comments. + * It basically creates a text node and then parses and wraps specific parts + * of it into supported HTML tags + * + * @param text Plain text flavored with some HTML tags + * @returns {string} HTML + * @private + */ + _transformTextToHTML(text) { + const supportedFormats = ['i', 'b', 'sub', 'sup']; + + function getFormatter(str) { + let results = supportedFormats.map(format => str.toLowerCase().indexOf('<' + format + '>')); + results = results.map((offset, idx) => [supportedFormats[idx], offset]); + results.sort((a, b) => a[1] - b[1]); + for (let result of results) { + let format = result[0]; + let offset = result[1]; + if (offset < 0) continue; + let lastIndex = str.toLowerCase().indexOf('', offset); + if (lastIndex >= 0) { + let parts = []; + parts.push(str.slice(0, offset)); + parts.push(str.slice(offset + format.length + 2, lastIndex)); + parts.push(str.slice(lastIndex + format.length + 3)); + return { + format, + parts + }; + } + } + return null; + } + + function walkFormat(parent) { + let child = parent.firstChild; + while (child) { + if (child.nodeType === 3) { + let text = child.nodeValue; + let formatter = getFormatter(text); + if (formatter) { + let nodes = []; + nodes.push(doc.createTextNode(formatter.parts[0])); + let midNode = doc.createElement(formatter.format); + midNode.appendChild(doc.createTextNode(formatter.parts[1])); + nodes.push(midNode); + nodes.push(doc.createTextNode(formatter.parts[2])); + child.replaceWith(...nodes); + child = midNode; + } + } + walkFormat(child); + child = child.nextSibling; + } + } + + let parser = Components.classes['@mozilla.org/xmlextras/domparser;1'] + .createInstance(Components.interfaces.nsIDOMParser); + let doc = parser.parseFromString('', 'text/html'); + + // innerText transforms \n into
+ doc.body.innerText = text; + walkFormat(doc.body); + return doc.body.innerHTML; + } /** * @param {Zotero.Item[]} annotations @@ -324,18 +392,23 @@ class EditorInstance { // Text if (annotation.text) { - highlightHTML = `“${annotation.text.trim()}”`; + let text = this._transformTextToHTML(annotation.text.trim()); + highlightHTML = `“${text}”`; } // Note if (annotation.comment) { - commentHTML = ' ' + annotation.comment.trim(); + let comment = this._transformTextToHTML(annotation.comment.trim()); + // Move comment to the next line if it has multiple lines + commentHTML = (((highlightHTML || imageHTML || citationHTML) && comment.includes('' : ' ') + comment; + } + + if (citationHTML) { + // Move citation to the next line if highlight has multiple lines or is after image + citationHTML = ((highlightHTML && highlightHTML.includes('' : '') + citationHTML; } let otherHTML = [highlightHTML, citationHTML, commentHTML].filter(x => x).join(' '); - if (imageHTML && otherHTML) { - imageHTML += '
'; - } html += '

' + imageHTML + otherHTML + '

\n'; } return { html, citationItems: storedCitationItems }; diff --git a/note-editor b/note-editor index e8539c524e..a348bbdebf 160000 --- a/note-editor +++ b/note-editor @@ -1 +1 @@ -Subproject commit e8539c524e4deb0404aaf69a08e8e119f25c9d2a +Subproject commit a348bbdebf2771222f628c8d14546e3b410c5a58 diff --git a/pdf-reader b/pdf-reader index 65bb0ea542..326c2e0829 160000 --- a/pdf-reader +++ b/pdf-reader @@ -1 +1 @@ -Subproject commit 65bb0ea542694d8a88a6c1aacb8488274ad96c03 +Subproject commit 326c2e0829522662fc35528dbde6454949142bb4 diff --git a/pdf-worker b/pdf-worker index 41f952bccf..0b289deeb9 160000 --- a/pdf-worker +++ b/pdf-worker @@ -1 +1 @@ -Subproject commit 41f952bccf4e038888791a120e41f0eeae1f2458 +Subproject commit 0b289deeb93dbc0f4d563897ac24e04e2942e097