diff --git a/resource/tinymce/css/note-ui.css b/resource/tinymce/css/note-ui.css index 10a4e4fe3..62ebdb9b5 100644 --- a/resource/tinymce/css/note-ui.css +++ b/resource/tinymce/css/note-ui.css @@ -26,8 +26,8 @@ html, body { /* Shrink the buttons a bit */ .mce-btn-small button { - padding-left: 4px !important; - padding-right: 4px !important; + padding-left: 3px !important; + padding-right: 3px !important; } .mce-listbox button { diff --git a/resource/tinymce/note.html b/resource/tinymce/note.html index 5edd947e4..0e80ca280 100644 --- a/resource/tinymce/note.html +++ b/resource/tinymce/note.html @@ -15,16 +15,16 @@ entity_encoding: 'raw', fix_list_elements: true, - plugins: "autolink,code,contextmenu,directionality,link,lists,paste,searchreplace", + plugins: "autolink,code,contextmenu,directionality,link,lists,paste,searchreplace,textcolor", - toolbar1: "bold italic underline strikethrough | subscript superscript | forecolor backcolor | blockquote link | %DIR% | removeformat", - toolbar2: "formatselect | alignleft aligncenter alignright | bullist numlist outdent indent | searchreplace", + toolbar1: "bold italic underline strikethrough | subscript superscript | forecolor backcolor | blockquote link | removeformat", + toolbar2: "formatselect | alignleft aligncenter alignright | bullist numlist outdent indent | %DIR% | searchreplace", toolbar_items_size: 'small', menubar: false, resize: false, statusbar: false, - contextmenu: "link | code", + contextmenu: "link | dir | code", link_context_toolbar: true, link_assume_external_targets: true, @@ -36,12 +36,18 @@ // Set text direction var dir = window.location.href.match(/dir=(ltr|rtl)/)[1]; + var opDir = dir.split("").reverse().join(""); ed.settings.directionality = dir; - // Include button for opposite direction, to function as a toggle - ed.settings.toolbar1 = ed.settings.toolbar1.replace( - "%DIR%", - dir.split("").reverse().join("") - ); + ed.addMenuItem('dir', { + icon: opDir, + // TODO: Show correct label based on current line + text: opDir == 'rtl' ? "Right to left" : "Left to right", + onclick: function () { + ed.execCommand('mceDirection' + opDir.toUpperCase()); + }, + context: 'insert', + prependToContext: true + }); }, init_instance_callback: function (ed) { diff --git a/resource/tinymce/plugins/link/plugin.js b/resource/tinymce/plugins/link/plugin.js index 60fde6865..34c685e37 100644 --- a/resource/tinymce/plugins/link/plugin.js +++ b/resource/tinymce/plugins/link/plugin.js @@ -64,7 +64,7 @@ tinymce.PluginManager.add('link', function(editor) { document.body.removeChild(link); } - function openDetachedWindow(url) { /* Added by Zotero */ editor.execCommand("ZoteroLinkClick", false, url); return; + function openDetachedWindow(url) { /* Added by Zotero */ editor.execCommand("ZoteroLinkClick", false, url); } /* // Chrome and Webkit has implemented noopener and works correctly with/without popup blocker // Firefox has it implemented noopener but when the popup blocker is activated it doesn't work // Edge has only implemented noreferrer and it seems to remove opener as well @@ -91,7 +91,7 @@ tinymce.PluginManager.add('link', function(editor) { } } - function gotoLink(a) { + */function gotoLink(a) { if (a) { var href = getHref(a); if (/^#/.test(href)) { diff --git a/resource/tinymce/plugins/textcolor/plugin.js b/resource/tinymce/plugins/textcolor/plugin.js new file mode 100644 index 000000000..145afb176 --- /dev/null +++ b/resource/tinymce/plugins/textcolor/plugin.js @@ -0,0 +1,297 @@ +/** + * plugin.js + * + * Released under LGPL License. + * Copyright (c) 1999-2015 Ephox Corp. All rights reserved + * + * License: http://www.tinymce.com/license + * Contributing: http://www.tinymce.com/contributing + */ + +/*global tinymce:true */ +/*eslint consistent-this:0 */ + +tinymce.PluginManager.add('textcolor', function(editor) { + var cols, rows; + + rows = { + forecolor: editor.settings.forecolor_rows || editor.settings.textcolor_rows || 5, + backcolor: editor.settings.backcolor_rows || editor.settings.textcolor_rows || 5 + }; + cols = { + forecolor: editor.settings.forecolor_cols || editor.settings.textcolor_cols || 8, + backcolor: editor.settings.backcolor_cols || editor.settings.textcolor_cols || 8 + }; + + function getCurrentColor(format) { + var color; + + editor.dom.getParents(editor.selection.getStart(), function(elm) { + var value; + + if ((value = elm.style[format == 'forecolor' ? 'color' : 'background-color'])) { + color = value; + } + }); + + return color; + } + + function mapColors(type) { + var i, colors = [], colorMap; + + colorMap = [ + "000000", "Black", + "993300", "Burnt orange", + "333300", "Dark olive", + "003300", "Dark green", + "003366", "Dark azure", + "000080", "Navy Blue", + "333399", "Indigo", + "333333", "Very dark gray", + "800000", "Maroon", + "FF6600", "Orange", + "808000", "Olive", + "008000", "Green", + "008080", "Teal", + "0000FF", "Blue", + "666699", "Grayish blue", + "808080", "Gray", + "FF0000", "Red", + "FF9900", "Amber", + "99CC00", "Yellow green", + "339966", "Sea green", + "33CCCC", "Turquoise", + "3366FF", "Royal blue", + "800080", "Purple", + "999999", "Medium gray", + "FF00FF", "Magenta", + "FFCC00", "Gold", + "FFFF00", "Yellow", + "00FF00", "Lime", + "00FFFF", "Aqua", + "00CCFF", "Sky blue", + "993366", "Red violet", + "FFFFFF", "White", + "FF99CC", "Pink", + "FFCC99", "Peach", + "FFFF99", "Light yellow", + "CCFFCC", "Pale green", + "CCFFFF", "Pale cyan", + "99CCFF", "Light sky blue", + "CC99FF", "Plum" + ]; + + colorMap = editor.settings.textcolor_map || colorMap; + colorMap = editor.settings[type + '_map'] || colorMap; + + for (i = 0; i < colorMap.length; i += 2) { + colors.push({ + text: colorMap[i + 1], + color: '#' + colorMap[i] + }); + } + + return colors; + } + + function renderColorPicker() { + var ctrl = this, colors, color, html, last, x, y, i, id = ctrl._id, count = 0, type; + + type = ctrl.settings.origin; + + function getColorCellHtml(color, title) { + var isNoColor = color == 'transparent'; + + return ( + '' + + '
' + + (isNoColor ? '×' : '') + + '
' + + '' + ); + } + + colors = mapColors(type); + colors.push({ + text: tinymce.translate("No color"), + color: "transparent" + }); + + html = ''; + last = colors.length - 1; + + for (y = 0; y < rows[type]; y++) { + html += ''; + + for (x = 0; x < cols[type]; x++) { + i = y * cols[type] + x; + + if (i > last) { + html += ''; + } else { + color = colors[i]; + html += getColorCellHtml(color.color, color.text); + } + } + + html += ''; + } + + if (editor.settings.color_picker_callback) { + html += ( + '' + + '' + + '' + ); + + html += ''; + + for (x = 0; x < cols[type]; x++) { + html += getColorCellHtml('', 'Custom color'); + } + + html += ''; + } + + html += '
' + + '
' + + '' + + '
' + + '
'; + + return html; + } + + function applyFormat(format, value) { + editor.undoManager.transact(function() { + editor.focus(); + editor.formatter.apply(format, {value: value}); + editor.nodeChanged(); + }); + } + + function removeFormat(format) { + editor.undoManager.transact(function() { + editor.focus(); + editor.formatter.remove(format, {value: null}, null, true); + editor.nodeChanged(); + }); + } + + function onPanelClick(e) { + var buttonCtrl = this.parent(), value, type; + + type = buttonCtrl.settings.origin; + + function selectColor(value) { + buttonCtrl.hidePanel(); + buttonCtrl.color(value); + applyFormat(buttonCtrl.settings.format, value); + } + + function resetColor() { + buttonCtrl.hidePanel(); + buttonCtrl.resetColor(); + removeFormat(buttonCtrl.settings.format); + } + + function setDivColor(div, value) { + div.style.background = value; + div.setAttribute('data-mce-color', value); + } + + if (tinymce.DOM.getParent(e.target, '.mce-custom-color-btn')) { + buttonCtrl.hidePanel(); + + editor.settings.color_picker_callback.call(editor, function(value) { + var tableElm = buttonCtrl.panel.getEl().getElementsByTagName('table')[0]; + var customColorCells, div, i; + + customColorCells = tinymce.map(tableElm.rows[tableElm.rows.length - 1].childNodes, function(elm) { + return elm.firstChild; + }); + + for (i = 0; i < customColorCells.length; i++) { + div = customColorCells[i]; + if (!div.getAttribute('data-mce-color')) { + break; + } + } + + // Shift colors to the right + // TODO: Might need to be the left on RTL + if (i == cols[type]) { + for (i = 0; i < cols[type] - 1; i++) { + setDivColor(customColorCells[i], customColorCells[i + 1].getAttribute('data-mce-color')); + } + } + + setDivColor(div, value); + selectColor(value); + }, getCurrentColor(buttonCtrl.settings.format)); + } + + value = e.target.getAttribute('data-mce-color'); + if (value) { + if (this.lastId) { + document.getElementById(this.lastId).setAttribute('aria-selected', false); + } + + e.target.setAttribute('aria-selected', true); + this.lastId = e.target.id; + + if (value == 'transparent') { + resetColor(); + } else { + selectColor(value); + } + } else if (value !== null) { + buttonCtrl.hidePanel(); + } + } + + function onButtonClick() { + var self = this; + + if (self._color) { + applyFormat(self.settings.format, self._color); + } else { + removeFormat(self.settings.format); + } + } + + editor.addButton('forecolor', { + type: 'colorbutton', + tooltip: 'Text color', + format: 'forecolor', + panel: { + origin: 'forecolor', + role: 'application', + ariaRemember: true, + html: renderColorPicker, + onclick: onPanelClick + }, + onclick: onButtonClick + }); + + editor.addButton('backcolor', { + type: 'colorbutton', + tooltip: 'Background color', + format: 'hilitecolor', + panel: { + origin: 'backcolor', + role: 'application', + ariaRemember: true, + html: renderColorPicker, + onclick: onPanelClick + }, + onclick: onButtonClick + }); +});