Adds rich text support to notes
- Still a few issues - Converts plaintext notes to HTML on upgrade
This commit is contained in:
parent
b46860f6a4
commit
651bcf2380
15 changed files with 282 additions and 46 deletions
|
@ -192,7 +192,7 @@
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
<textbox id="editor" type="styled" hidden="true" flex="1"/>
|
<textbox id="editor" type="styled" mode="integration" hidden="true" flex="1"/>
|
||||||
|
|
||||||
<hbox style="margin-top: 15px">
|
<hbox style="margin-top: 15px">
|
||||||
<hbox>
|
<hbox>
|
||||||
|
|
|
@ -155,11 +155,11 @@
|
||||||
textbox.setAttribute('readonly', 'true');
|
textbox.setAttribute('readonly', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
var scrollPos = textbox.inputField.scrollTop;
|
//var scrollPos = textbox.inputField.scrollTop;
|
||||||
if (this.item) {
|
if (this.item) {
|
||||||
textbox.value = this.item.getNote();
|
textbox.value = this.item.getNote();
|
||||||
}
|
}
|
||||||
textbox.inputField.scrollTop = scrollPos;
|
//textbox.inputField.scrollTop = scrollPos;
|
||||||
|
|
||||||
this._id('linksbox').hidden = !(this.displayTags && this.displayRelated);
|
this._id('linksbox').hidden = !(this.displayTags && this.displayRelated);
|
||||||
|
|
||||||
|
@ -322,7 +322,7 @@
|
||||||
<method name="disableUndo">
|
<method name="disableUndo">
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
this.noteField.editor.enableUndo(true);
|
//this.noteField.editor.enableUndo(true);
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -330,7 +330,7 @@
|
||||||
<method name="enableUndo">
|
<method name="enableUndo">
|
||||||
<body>
|
<body>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
this.noteField.editor.enableUndo(false);
|
//this.noteField.editor.enableUndo(false);
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
<content>
|
<content>
|
||||||
<xul:vbox xbl:inherits="flex">
|
<xul:vbox xbl:inherits="flex">
|
||||||
<xul:label id="citeLabel"/>
|
<xul:label id="citeLabel"/>
|
||||||
<xul:textbox id="noteField" multiline="true" type="timed" timeout="1000" flex="1"/>
|
<xul:textbox id="noteField" type="styled" mode="note" timeout="1000" flex="1"/>
|
||||||
<xul:hbox id="linksbox" hidden="true">
|
<xul:hbox id="linksbox" hidden="true">
|
||||||
<xul:linksbox id="links" flex="1"/>
|
<xul:linksbox id="links" flex="1"/>
|
||||||
</xul:hbox>
|
</xul:hbox>
|
||||||
|
|
|
@ -28,23 +28,33 @@
|
||||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||||
<binding id="styled-textbox">
|
<binding id="styled-textbox">
|
||||||
<implementation>
|
<implementation>
|
||||||
|
<field name="_mode"/>
|
||||||
|
<field name="_format"/>
|
||||||
|
<field name="_loadHandler"/>
|
||||||
|
<field name="_commandString"/>
|
||||||
|
<field name="_eventHandler"/>
|
||||||
|
<field name="_timer"/>
|
||||||
|
|
||||||
<constructor><![CDATA[
|
<constructor><![CDATA[
|
||||||
this._browser = document.getAnonymousElementByAttribute(this, "anonid", "rt-view");
|
this.mode = this.getAttribute('mode');
|
||||||
|
|
||||||
|
this._iframe = document.getAnonymousElementByAttribute(this, "anonid", "rt-view");
|
||||||
this._editor = null;
|
this._editor = null;
|
||||||
this._value = null;
|
this._value = null;
|
||||||
|
|
||||||
this._rtfMap = {
|
this._rtfMap = {
|
||||||
"\\":"\\\\",
|
"\\":"\\\\",
|
||||||
"&":"&",
|
"<em>":"\\i ",
|
||||||
"<":"<",
|
"</em>":"\\i0 ",
|
||||||
">":">",
|
|
||||||
"<i>":"\\i ",
|
"<i>":"\\i ",
|
||||||
"</i>":"\\i0 ",
|
"</i>":"\\i0 ",
|
||||||
|
"<strong>":"\\b ",
|
||||||
|
"</strong>":"\\b0 ",
|
||||||
"<b>":"\\b ",
|
"<b>":"\\b ",
|
||||||
"</b>":"\\b0 ",
|
"</b>":"\\b0 ",
|
||||||
"<u>":"\\ul ",
|
"<u>":"\\ul ",
|
||||||
"</u>":"\\ul0 ",
|
"</u>":"\\ul0 ",
|
||||||
"<br>":"\x0B",
|
"<br />":"\x0B",
|
||||||
"<sup>":"\\super ",
|
"<sup>":"\\super ",
|
||||||
"</sup>":"\\super0 ",
|
"</sup>":"\\super0 ",
|
||||||
"<sub>":"\\sub ",
|
"<sub>":"\\sub ",
|
||||||
|
@ -56,41 +66,108 @@
|
||||||
|
|
||||||
// not sure why an event is necessary here, but it is
|
// not sure why an event is necessary here, but it is
|
||||||
var me = this;
|
var me = this;
|
||||||
this._loadHandler = function() {me._browserLoaded()};
|
this._loadHandler = function() {me._iframeLoaded()};
|
||||||
this._browser.addEventListener("DOMContentLoaded", this._loadHandler, false);
|
this._iframe.addEventListener("DOMContentLoaded", this._loadHandler, false);
|
||||||
]]></constructor>
|
]]></constructor>
|
||||||
|
|
||||||
<!-- Called when browser is loaded. Until the browser is loaded, we can't do
|
<!-- Called when iframe browser is loaded. Until the browser is loaded, we can't do
|
||||||
anything with it, so we just keep track of what's supposed to
|
anything with it, so we just keep track of what's supposed to
|
||||||
happen. -->
|
happen. -->
|
||||||
<method name="_browserLoaded">
|
<method name="_iframeLoaded">
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
this._browser.removeEventListener("DOMContentLoaded", this._loadHandler, false);
|
this._iframe.removeEventListener("DOMContentLoaded", this._loadHandler, false);
|
||||||
|
|
||||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||||
getService(Components.interfaces.nsIIOService);
|
getService(Components.interfaces.nsIIOService);
|
||||||
var uri = ios.newURI("chrome://zotero/content/tiny_mce/integration.html", null, null);
|
var uri = ios.newURI("chrome://zotero/content/tiny_mce/" + this.mode + ".html", null, null);
|
||||||
var chromeReg = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
|
var chromeReg = Components.classes["@mozilla.org/chrome/chrome-registry;1"].
|
||||||
getService(Components.interfaces.nsIChromeRegistry);
|
getService(Components.interfaces.nsIChromeRegistry);
|
||||||
var fileURI = chromeReg.convertChromeURL(uri);
|
var fileURI = chromeReg.convertChromeURL(uri);
|
||||||
|
|
||||||
this._browser.webNavigation.loadURI(fileURI.spec,
|
this._iframe.webNavigation.loadURI(fileURI.spec,
|
||||||
Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null);
|
Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY, null, null, null);
|
||||||
|
|
||||||
// Register handler for deferred setting of content
|
// Register handler for deferred setting of content
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
||||||
var listener = function() {
|
var listener = function() {
|
||||||
me._browser.removeEventListener("DOMContentLoaded", listener, false);
|
me._iframe.removeEventListener("DOMContentLoaded", listener, false);
|
||||||
var editor = me._browser.contentWindow.wrappedJSObject.tinyMCE.get("tinymce");
|
var editor = me._iframe.contentWindow.wrappedJSObject.tinyMCE.get("tinymce");
|
||||||
|
|
||||||
editor.onInit.add(function() {
|
editor.onInit.add(function() {
|
||||||
me._editor = editor;
|
me._editor = editor;
|
||||||
if(me._value) me.value = me._value;
|
if(me._value) me.value = me._value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (me._eventHandler) {
|
||||||
|
me._iframe.contentWindow.wrappedJSObject.handleEvent = me._eventHandler;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
this._browser.addEventListener("DOMContentLoaded", listener, false);
|
this._iframe.addEventListener("DOMContentLoaded", listener, false);
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
<property name="mode">
|
||||||
|
<getter><![CDATA[
|
||||||
|
if (!this._mode) {
|
||||||
|
throw ("mode is not defined in styled-textbox.xml");
|
||||||
|
}
|
||||||
|
return this._mode;
|
||||||
|
]]></getter>
|
||||||
|
<setter><![CDATA[
|
||||||
|
Zotero.debug("Setting mode to " + val);
|
||||||
|
switch (val) {
|
||||||
|
case 'note':
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this._eventHandler = function (event) {
|
||||||
|
Zotero.debug(event.type);
|
||||||
|
switch (event.type) {
|
||||||
|
case 'keypress':
|
||||||
|
// Ignore keypresses that don't change
|
||||||
|
// any text
|
||||||
|
if (!event.isChar &&
|
||||||
|
event.keyCode != event.DOM_VK_DELETE &&
|
||||||
|
event.keyCode != event.DOM_VK_BACK_SPACE) {
|
||||||
|
//Zotero.debug("Not a char");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'change':
|
||||||
|
Zotero.debug("Event type is " + event.type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self._timer) {
|
||||||
|
clearTimeout(self._timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the command event
|
||||||
|
self._timer = self.timeout && setTimeout(function () {
|
||||||
|
var attr = self.getAttribute('oncommand');
|
||||||
|
attr = attr.replace('this', 'thisObj');
|
||||||
|
var func = new Function('thisObj', 'event', attr);
|
||||||
|
func(self, event);
|
||||||
|
}, self.timeout);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'integration':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw ("Invalid mode '" + val + "' in styled-textbox.xml");
|
||||||
|
}
|
||||||
|
return this._mode = val;
|
||||||
|
]]></setter>
|
||||||
|
</property>
|
||||||
|
|
||||||
<!-- Sets or returns formatting (currently, HTML or Integration) of rich text box -->
|
<!-- Sets or returns formatting (currently, HTML or Integration) of rich text box -->
|
||||||
<property name="format">
|
<property name="format">
|
||||||
<getter><![CDATA[
|
<getter><![CDATA[
|
||||||
|
@ -104,30 +181,50 @@
|
||||||
<!-- Sets or returns contents of rich text box -->
|
<!-- Sets or returns contents of rich text box -->
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<getter><![CDATA[
|
<getter><![CDATA[
|
||||||
this._editor.execCommand("mceCleanup");
|
var output = this._editor.getBody();
|
||||||
var body = this._editor.getBody();
|
output = output.innerHTML;
|
||||||
var output = body.innerHTML;
|
Zotero.debug("RAW");
|
||||||
|
Zotero.debug(output);
|
||||||
|
|
||||||
|
var output = this._editor.getContent();
|
||||||
|
Zotero.debug("XHTML");
|
||||||
|
Zotero.debug(output);
|
||||||
|
|
||||||
if(this._format == "Integration" || this._format == "RTF") {
|
if(this._format == "Integration" || this._format == "RTF") {
|
||||||
// do appropriate replacement operations
|
// do appropriate replacement operations
|
||||||
for(var needle in this._rtfMap) {
|
for(var needle in this._rtfMap) {
|
||||||
output = output.replace(needle, this._rtfMap[needle], "g");
|
output = output.replace(needle, this._rtfMap[needle], "g");
|
||||||
}
|
}
|
||||||
|
|
||||||
output = output.replace("<p>", "", "g");
|
output = output.replace("<p>", "", "g");
|
||||||
output = output.replace("</p>", "\\par ", "g");
|
output = output.replace("</p>", "\\par ", "g");
|
||||||
output = output.replace(/<\/?div[^>]*>/g, "");
|
output = output.replace(/<\/?div[^>]*>/g, "");
|
||||||
output = Zotero.Utilities.prototype.trim(output);
|
output = Zotero.Utilities.prototype.trim(output);
|
||||||
|
output = Zotero.Utilities.prototype.unescapeHTML(output);
|
||||||
if(output.substr(-4) == "\\par") output = output.substr(0, output.length-4);
|
if(output.substr(-4) == "\\par") output = output.substr(0, output.length-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
]]></getter>
|
]]></getter>
|
||||||
<setter><![CDATA[
|
<setter><![CDATA[
|
||||||
|
Zotero.debug("Setting value!");
|
||||||
|
|
||||||
|
if (self._timer) {
|
||||||
|
clearTimeout(self._timer);
|
||||||
|
}
|
||||||
|
|
||||||
if(!this._editor) {
|
if(!this._editor) {
|
||||||
// if not loaded, wait until it is to set
|
// if not loaded, wait until it is to set
|
||||||
return this._value = val;
|
return this._value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.value == val) {
|
||||||
|
Zotero.debug("Value hasn't changed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.debug("Value has changed");
|
||||||
|
|
||||||
var html = val;
|
var html = val;
|
||||||
|
|
||||||
if(this._format == "Integration" || this._format == "RTF") {
|
if(this._format == "Integration" || this._format == "RTF") {
|
||||||
|
@ -169,11 +266,16 @@
|
||||||
return val;
|
return val;
|
||||||
]]></setter>
|
]]></setter>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
|
<property name="timeout"
|
||||||
|
onset="this.setAttribute('timeout', val); return val;"
|
||||||
|
onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
|
||||||
</implementation>
|
</implementation>
|
||||||
|
|
||||||
<content>
|
<content>
|
||||||
<xul:iframe flex="1" anonid="rt-view" class="rt-view" type="content" style="min-height:130px"
|
<xul:iframe flex="1" anonid="rt-view" class="rt-view" type="content"
|
||||||
xbl:inherits="onfocus,onblur,flex,width,height,hidden"/>
|
xbl:inherits="onfocus,onblur,flex,width,height,hidden"
|
||||||
|
style="overflow: hidden"/>
|
||||||
</content>
|
</content>
|
||||||
</binding>
|
</binding>
|
||||||
</bindings>
|
</bindings>
|
|
@ -111,6 +111,6 @@
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
<textbox id="editor" type="styled" flex="1"/>
|
<textbox id="editor" type="styled" mode="integration" flex="1"/>
|
||||||
</vbox>
|
</vbox>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
@ -1,13 +1,32 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tinymce_parent {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 130px;
|
||||||
|
}
|
||||||
|
#tinymce_tbl {
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript" src="tiny_mce.js"></script>
|
<script type="text/javascript" src="tiny_mce.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
tinyMCE.init({
|
tinyMCE.init({
|
||||||
// General options
|
// General options
|
||||||
mode : "none",
|
mode : "none",
|
||||||
theme : "advanced",
|
theme : "advanced",
|
||||||
content_css : "../../../skin/default/zotero/tinymce-content.css",
|
content_css : "../../../skin/default/zotero/tinymce/integration-content.css",
|
||||||
|
|
||||||
// Theme options
|
// Theme options
|
||||||
theme_advanced_buttons1 : "bold,italic,underline,|,sub,sup,|,removeformat",
|
theme_advanced_buttons1 : "bold,italic,underline,|,sub,sup,|,removeformat",
|
||||||
|
@ -20,7 +39,7 @@
|
||||||
tinyMCE.execCommand("mceAddControl", true, "tinymce");
|
tinyMCE.execCommand("mceAddControl", true, "tinymce");
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body style="border: 0; margin: 0;">
|
<body>
|
||||||
<div id="tinymce" style="width:100%"></div>
|
<div id="tinymce"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,24 +2,79 @@
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
<head>
|
<head>
|
||||||
<title>TinyMCE</title>
|
<title>TinyMCE</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
#tinymce_parent {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
#tinymce_tbl {
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.mceLayout > tbody > tr.mceLast {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
top: 82px;
|
||||||
|
bottom: 2px;
|
||||||
|
left: 1px;
|
||||||
|
right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.mceIframeContainer {
|
||||||
|
display: block;
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
#tinymce_ifr {
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<script type="text/javascript" src="tiny_mce.js"></script>
|
<script type="text/javascript" src="tiny_mce.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
tinyMCE.init({
|
tinyMCE.init({
|
||||||
// General options
|
// General options
|
||||||
mode : "textareas",
|
mode : "none",
|
||||||
theme : "advanced",
|
theme : "advanced",
|
||||||
|
content_css : "../../../skin/default/zotero/tinymce/note-content.css",
|
||||||
|
button_tile_map : true,
|
||||||
|
language : "en", // TODO: localize
|
||||||
|
entity_encoding : "raw",
|
||||||
|
gecko_spellcheck : true,
|
||||||
|
|
||||||
|
handle_event_callback : function (event) {
|
||||||
|
if (handleEvent) {
|
||||||
|
handleEvent(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onchange_callback : function () {
|
||||||
|
var event = { type: 'change' };
|
||||||
|
if (handleEvent) {
|
||||||
|
handleEvent(event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fix_list_elements : true,
|
||||||
|
fix_table_elements : true,
|
||||||
|
|
||||||
// Theme options
|
// Theme options
|
||||||
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,sub,sup,|,forecolor,backcolor,|,removeformat",
|
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,sub,sup,|,forecolor,backcolor,|,removeformat,code",
|
||||||
theme_advanced_buttons2 : "justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink",
|
theme_advanced_buttons2 : "justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,|,outdent,indent,blockquote,|,link,unlink",
|
||||||
theme_advanced_buttons3 : "formatselect,fontselect,fontsizeselect",
|
theme_advanced_buttons3 : "formatselect,fontselect,fontsizeselect",
|
||||||
theme_advanced_toolbar_location : "top",
|
theme_advanced_toolbar_location : "top",
|
||||||
theme_advanced_toolbar_align : "left",
|
theme_advanced_toolbar_align : "left",
|
||||||
theme_advanced_resizing : true
|
theme_advanced_resizing : true
|
||||||
});
|
});
|
||||||
|
tinyMCE.execCommand("mceAddControl", true, "tinymce");
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<textarea id="tinymce" rows="15" cols="80" style="width: 100%"></textarea>
|
<div id="tinymce"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1240,10 +1240,16 @@ Zotero.Item.prototype.save = function() {
|
||||||
sql = "INSERT INTO itemNotes "
|
sql = "INSERT INTO itemNotes "
|
||||||
+ "(itemID, sourceItemID, note, title) VALUES (?,?,?,?)";
|
+ "(itemID, sourceItemID, note, title) VALUES (?,?,?,?)";
|
||||||
var parent = this.isNote() ? this.getSource() : null;
|
var parent = this.isNote() ? this.getSource() : null;
|
||||||
|
var noteText = this._noteText ? this._noteText : '';
|
||||||
|
// Add <div> wrapper if not present
|
||||||
|
if (!noteText.match(/^<div class="zotero\-note znv[0-9]+">.*<\/div>$/)) {
|
||||||
|
noteText = '<div class="zotero-note znv1">' + noteText + '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
var bindParams = [
|
var bindParams = [
|
||||||
itemID,
|
itemID,
|
||||||
parent ? parent : null,
|
parent ? parent : null,
|
||||||
this._noteText ? this._noteText : '',
|
noteText,
|
||||||
this._noteTitle ? this._noteTitle : ''
|
this._noteTitle ? this._noteTitle : ''
|
||||||
];
|
];
|
||||||
Zotero.DB.query(sql, bindParams);
|
Zotero.DB.query(sql, bindParams);
|
||||||
|
@ -1575,10 +1581,15 @@ Zotero.Item.prototype.save = function() {
|
||||||
sql = "REPLACE INTO itemNotes "
|
sql = "REPLACE INTO itemNotes "
|
||||||
+ "(itemID, sourceItemID, note, title) VALUES (?,?,?,?)";
|
+ "(itemID, sourceItemID, note, title) VALUES (?,?,?,?)";
|
||||||
var parent = this.isNote() ? this.getSource() : null;
|
var parent = this.isNote() ? this.getSource() : null;
|
||||||
|
var noteText = this._noteText;
|
||||||
|
// Add <div> wrapper if not present
|
||||||
|
if (!noteText.match(/^<div class="zotero\-note znv[0-9]+">.*<\/div>$/)) {
|
||||||
|
noteText = '<div class="zotero-note znv1">' + noteText + '</div>';
|
||||||
|
}
|
||||||
var bindParams = [
|
var bindParams = [
|
||||||
this.id,
|
this.id,
|
||||||
parent ? parent : null,
|
parent ? parent : null,
|
||||||
this._noteText,
|
noteText,
|
||||||
this._noteTitle
|
this._noteTitle
|
||||||
];
|
];
|
||||||
Zotero.DB.query(sql, bindParams);
|
Zotero.DB.query(sql, bindParams);
|
||||||
|
@ -1983,6 +1994,8 @@ Zotero.Item.prototype.getNote = function() {
|
||||||
|
|
||||||
var sql = "SELECT note FROM itemNotes WHERE itemID=?";
|
var sql = "SELECT note FROM itemNotes WHERE itemID=?";
|
||||||
var note = Zotero.DB.valueQuery(sql, this.id);
|
var note = Zotero.DB.valueQuery(sql, this.id);
|
||||||
|
// Don't include <div> wrapper when returning value
|
||||||
|
note = note.replace(/^<div class="zotero-note znv[0-9]+">(.*)<\/div>$/, '$1');
|
||||||
|
|
||||||
this._noteText = note ? note : '';
|
this._noteText = note ? note : '';
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ Zotero.Notes = new function() {
|
||||||
* Return first line (or first MAX_LENGTH characters) of note content
|
* Return first line (or first MAX_LENGTH characters) of note content
|
||||||
**/
|
**/
|
||||||
function noteToTitle(text) {
|
function noteToTitle(text) {
|
||||||
|
text = Zotero.Utilities.prototype.trim(text);
|
||||||
|
text = Zotero.Utilities.prototype.unescapeHTML(text);
|
||||||
|
|
||||||
var max = this.MAX_TITLE_LENGTH;
|
var max = this.MAX_TITLE_LENGTH;
|
||||||
|
|
||||||
var t = text.substring(0, max);
|
var t = text.substring(0, max);
|
||||||
|
|
|
@ -995,6 +995,20 @@ Zotero.DBConnection.prototype._getDBConnection = function () {
|
||||||
};
|
};
|
||||||
this._connection.createFunction('regexp', 2, rx);
|
this._connection.createFunction('regexp', 2, rx);
|
||||||
|
|
||||||
|
// text2html UDF
|
||||||
|
var rx = {
|
||||||
|
onFunctionCall: function (arg) {
|
||||||
|
var str = arg.getUTF8String(0);
|
||||||
|
str = Zotero.Utilities.prototype.htmlSpecialChars(str);
|
||||||
|
str = '<p>'
|
||||||
|
+ str.replace(/\n/g, '</p><p>')
|
||||||
|
.replace(/\t/g, ' ')
|
||||||
|
.replace(/ /g, ' ')
|
||||||
|
+ '</p>';
|
||||||
|
return str.replace(/<p>\s*<\/p>/g, '<p> </p>');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this._connection.createFunction('text2html', 1, rx);
|
||||||
|
|
||||||
return this._connection;
|
return this._connection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,14 @@ Zotero.Report = new function() {
|
||||||
|
|
||||||
// Independent note
|
// Independent note
|
||||||
if (arr['note']) {
|
if (arr['note']) {
|
||||||
content += '<p>' + escapeXML(arr['note']) + '</p>\n';
|
content += '\n';
|
||||||
|
if (arr.note.substr(0, 1024).match(/<p[^>]*>/)) {
|
||||||
|
content += arr.note + '\n';
|
||||||
|
}
|
||||||
|
// Wrap plaintext notes in <p>
|
||||||
|
else {
|
||||||
|
content += '<p class="plaintext">' + arr.note + '</p>\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,7 +92,15 @@ Zotero.Report = new function() {
|
||||||
content += '<ul class="notes">\n';
|
content += '<ul class="notes">\n';
|
||||||
for each(var note in arr.reportChildren.notes) {
|
for each(var note in arr.reportChildren.notes) {
|
||||||
content += '<li id="i' + note.itemID + '">\n';
|
content += '<li id="i' + note.itemID + '">\n';
|
||||||
content += '<p>' + escapeXML(note.note) + '</p>\n';
|
|
||||||
|
content += note.note + '\n';
|
||||||
|
if (note.note.substr(0, 1024).match(/<p[^>]*>/)) {
|
||||||
|
content += note.note + '\n';
|
||||||
|
}
|
||||||
|
// Wrap plaintext notes in <p>
|
||||||
|
else {
|
||||||
|
content += '<p class="plaintext">' + note.note + '</p>\n';
|
||||||
|
}
|
||||||
|
|
||||||
// Child note tags
|
// Child note tags
|
||||||
content += _generateTagsList(note);
|
content += _generateTagsList(note);
|
||||||
|
|
|
@ -1945,6 +1945,11 @@ Zotero.Schema = new function(){
|
||||||
if (i==42) {
|
if (i==42) {
|
||||||
Zotero.DB.query("UPDATE itemAttachments SET syncState=0");
|
Zotero.DB.query("UPDATE itemAttachments SET syncState=0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1.5 Sync Preview 2.3
|
||||||
|
if (i==43) {
|
||||||
|
Zotero.DB.query("UPDATE itemNotes SET note='<div class=\"zotero-note znv1\">' || TEXT2HTML(note) || '</div>' WHERE note NOT LIKE '<div class=\"zotero-note %'");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateDBVersion('userdata', toVersion);
|
_updateDBVersion('userdata', toVersion);
|
||||||
|
|
|
@ -113,12 +113,8 @@ ul.notes > li p:last-child {
|
||||||
|
|
||||||
|
|
||||||
/* Preserve whitespace on notes */
|
/* Preserve whitespace on notes */
|
||||||
ul.notes li p, li.note p {
|
ul.notes li p.plaintext, li.note p.plaintext {
|
||||||
white-space: pre-wrap; /* css-3 */
|
white-space: pre-wrap;
|
||||||
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
|
||||||
white-space: -pre-wrap; /* Opera 4-6 */
|
|
||||||
white-space: -o-pre-wrap; /* Opera 7 */
|
|
||||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Display tags within child notes inline */
|
/* Display tags within child notes inline */
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
body, td, pre {font-family:Times New Roman, Times, serif; font-size:14px; margin: 8px;}
|
body, td, pre {font-family:Times New Roman, Times, serif; font-size:14px; margin: 8px;}
|
||||||
p, div {margin:0; padding:0}
|
p, div {margin:0; padding:0}
|
14
chrome/skin/default/zotero/tinymce/note-content.css
Normal file
14
chrome/skin/default/zotero/tinymce/note-content.css
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
body {
|
||||||
|
font-size: 11px;
|
||||||
|
font-family: Lucida Grande, Tahoma, Verdana, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
blockquote p:not(:empty):before {
|
||||||
|
content: '“'
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote p:not(:empty):after {
|
||||||
|
content: '”'
|
||||||
|
}
|
||||||
|
*/
|
|
@ -1,4 +1,4 @@
|
||||||
-- 42
|
-- 43
|
||||||
|
|
||||||
-- This file creates tables containing user-specific data -- any changes made
|
-- This file creates tables containing user-specific data -- any changes made
|
||||||
-- here must be mirrored in transition steps in schema.js::_migrateSchema()
|
-- here must be mirrored in transition steps in schema.js::_migrateSchema()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue