Remove styled-textbox XBL binding
This commit is contained in:
parent
af892e5cbd
commit
071162f914
2 changed files with 0 additions and 827 deletions
|
@ -1,813 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!--
|
|
||||||
***** BEGIN LICENSE BLOCK *****
|
|
||||||
|
|
||||||
Copyright © 2009 Center for History and New Media
|
|
||||||
George Mason University, Fairfax, Virginia, USA
|
|
||||||
http://zotero.org
|
|
||||||
|
|
||||||
This file is part of Zotero.
|
|
||||||
|
|
||||||
Zotero is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Zotero is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!DOCTYPE bindings SYSTEM "chrome://zotero/locale/zotero.dtd">
|
|
||||||
<bindings xmlns="http://www.mozilla.org/xbl"
|
|
||||||
xmlns:html="http://www.w3.org/1999/xhtml"
|
|
||||||
xmlns:xbl="http://www.mozilla.org/xbl"
|
|
||||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
||||||
<binding id="styled-textbox">
|
|
||||||
<implementation>
|
|
||||||
<field name="_editable"/>
|
|
||||||
<field name="_mode"/>
|
|
||||||
<field name="_format"/>
|
|
||||||
<field name="_changed"/>
|
|
||||||
<field name="_loadHandler"/>
|
|
||||||
<field name="_commandString"/>
|
|
||||||
<field name="_eventHandler"/>
|
|
||||||
<field name="_editor"/>
|
|
||||||
<field name="_value"/>
|
|
||||||
<field name="_timer"/>
|
|
||||||
<field name="_focus"/>
|
|
||||||
<field name="_constructed"/>
|
|
||||||
<field name="_loadOnConstruct"/>
|
|
||||||
|
|
||||||
<constructor><![CDATA[
|
|
||||||
this.mode = this.getAttribute('mode');
|
|
||||||
|
|
||||||
this._iframe = document.getAnonymousElementByAttribute(this, "anonid", "rt-view");
|
|
||||||
|
|
||||||
// Atomic units, HTML -> RTF (cleanup)
|
|
||||||
//[/<\/p>(?!\s*$)/g, "\\par{}"],
|
|
||||||
//[/ /g, " "],
|
|
||||||
//[/\u00A0/g, " "],
|
|
||||||
this._htmlRTFmap = [
|
|
||||||
[/<br \/>/g, "\x0B"],
|
|
||||||
[/<span class=\"tab\"> <\/span>/g, "\\tab{}"],
|
|
||||||
[/‘/g, "‘"],
|
|
||||||
[/’/g, "’"],
|
|
||||||
[/“/g, "“"],
|
|
||||||
[/”/g, "”"],
|
|
||||||
[/ /g, "\u00A0"],
|
|
||||||
[/"(\w)/g, "“$1"],
|
|
||||||
[/([\w,.?!])"/g, "$1”"],
|
|
||||||
[/<p>/g, ""],
|
|
||||||
[/<\/?div[^>]*>/g, ""]
|
|
||||||
];
|
|
||||||
|
|
||||||
// Atomic units, RTF -> HTML (cleanup)
|
|
||||||
this._rtfHTMLmap = [
|
|
||||||
[/\\uc0\{?\\u([0-9]+)\}?(?:{}| )?/g, function(wholeStr, aCode) { return String.fromCharCode(aCode) }],
|
|
||||||
[/\\tab(?:\{\}| )/g, '<span class="tab"> </span>'],
|
|
||||||
[/(?:\\par{}|\\\r?\n)/g, "</p><p>"]
|
|
||||||
];
|
|
||||||
|
|
||||||
this.prepare = function() {
|
|
||||||
// DEBUG: Does this actually happen?
|
|
||||||
if (this.prepared) return;
|
|
||||||
|
|
||||||
// Tag data
|
|
||||||
var _rexData = [
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<span +style=\"font-variant: *small-caps;\">"],
|
|
||||||
["{\\scaps ", "{\\scaps{}"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["<\/span>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<span +style=\"text-decoration: *underline;\">"],
|
|
||||||
["{\\ul{}", "{\\ul "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["<\/span>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<sup>"],
|
|
||||||
["\\super ", "\\super{}"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</sup>"],
|
|
||||||
["\\nosupersub{}", "\\nosupersub "]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<sub>"],
|
|
||||||
["\\sub ", "\\sub{}"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</sub>"],
|
|
||||||
["\\nosupersub{}", "\\nosupersub "]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<em>"],
|
|
||||||
["{\\i{}", "{\\i "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</em>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<i>"],
|
|
||||||
["{\\i{}", "{\\i "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</i>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<b>"],
|
|
||||||
["{\\b{}", "{\\b "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</b>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<strong>"],
|
|
||||||
["{\\b{}", "{\\b "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</strong>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<span +style=\"font-variant: *normal;\">"],
|
|
||||||
["{\\scaps0{}", "{\\scaps0 "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</span>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<span +style=\"font-style: *normal;\">"],
|
|
||||||
["{\\i0{}", "{\\i0 "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</span>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
[
|
|
||||||
["<span +style=\"font-weight: *normal;\">"],
|
|
||||||
["{\\b0{}", "{\\b0 "]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
["</span>"],
|
|
||||||
["}"]
|
|
||||||
]
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
function longestFirst(a, b) {
|
|
||||||
if (a.length < b.length) {
|
|
||||||
return 1;
|
|
||||||
} else if (a.length > b.length) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeRegExpString(str) {
|
|
||||||
if (!str) return str;
|
|
||||||
return str.replace(/\s+/g, " ")
|
|
||||||
.replace(/(?:[\+]|\s[\*])/g, "")
|
|
||||||
.replace(/[\']/g, '\"')
|
|
||||||
.replace(/:\s/g, ":");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.normalizeRegExpString = normalizeRegExpString;
|
|
||||||
|
|
||||||
function composeRex(rexes, noGlobal) {
|
|
||||||
var lst = [];
|
|
||||||
for (var rex in rexes) {
|
|
||||||
lst.push(rex);
|
|
||||||
}
|
|
||||||
lst.sort(longestFirst);
|
|
||||||
var rexStr = "(?:" + lst.join("|") + ")";
|
|
||||||
return new RegExp(rexStr, "g");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create splitting regexps
|
|
||||||
function splitRexMaker(segment) {
|
|
||||||
var rexes = {};
|
|
||||||
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
|
|
||||||
for (var j=0,jlen=_rexData[i].length; j < jlen; j++) {
|
|
||||||
for (var k=0,klen=_rexData[i][j][segment].length; k < klen; k++) {
|
|
||||||
rexes[_rexData[i][j][segment][k].replace("\\", "\\\\")] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var ret = composeRex(rexes, true);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
this.rtfHTMLsplitRex = splitRexMaker(1);
|
|
||||||
this.htmlRTFsplitRex = splitRexMaker(0);
|
|
||||||
|
|
||||||
// Create open-tag sniffing regexp
|
|
||||||
function openSniffRexMaker(segment) {
|
|
||||||
var rexes = {};
|
|
||||||
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
|
|
||||||
for (var j=0,jlen=_rexData[i][0][segment].length; j < jlen; j++) {
|
|
||||||
rexes[_rexData[i][0][segment][j].replace("\\", "\\\\")] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return composeRex(rexes);
|
|
||||||
}
|
|
||||||
this.rtfHTMLopenSniffRex = openSniffRexMaker(1);
|
|
||||||
this.htmlRTFopenSniffRex = openSniffRexMaker(0);
|
|
||||||
|
|
||||||
// Create open-tag remapper
|
|
||||||
function openTagRemapMaker(segment) {
|
|
||||||
var ret = {};
|
|
||||||
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
|
|
||||||
var primaryVal = normalizeRegExpString(_rexData[i][0][segment][0]);
|
|
||||||
for (var j=0,jlen=_rexData[i][0][segment].length; j < jlen; j++) {
|
|
||||||
var key = normalizeRegExpString(_rexData[i][0][segment][j]);
|
|
||||||
ret[key] = primaryVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rtfHTMLopenTagRemap = openTagRemapMaker(1);
|
|
||||||
this.htmlRTFopenTagRemap = openTagRemapMaker(0);
|
|
||||||
|
|
||||||
// Create open-tag-keyed close-tag sniffing regexps
|
|
||||||
function closeTagRexMaker(segment) {
|
|
||||||
var ret = {};
|
|
||||||
var rexes = {};
|
|
||||||
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
|
|
||||||
var primaryVal = _rexData[i][0][segment][0];
|
|
||||||
for (var j=0,jlen=_rexData[i][1][segment].length; j < jlen; j++) {
|
|
||||||
rexes[_rexData[i][1][segment][j]] = true;
|
|
||||||
}
|
|
||||||
ret[primaryVal] = composeRex(rexes);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
this.rtfHTMLcloseTagRex = closeTagRexMaker(1);
|
|
||||||
this.htmlRTFcloseTagRex = closeTagRexMaker(0);
|
|
||||||
|
|
||||||
// Create open-tag-keyed open/close tag registry
|
|
||||||
function tagRegistryMaker(segment) {
|
|
||||||
var antisegment = 1;
|
|
||||||
if (segment == 1) {
|
|
||||||
antisegment = 0;
|
|
||||||
}
|
|
||||||
var ret = {};
|
|
||||||
for (var i=0,ilen=_rexData.length; i < ilen; i++) {
|
|
||||||
var primaryVal = normalizeRegExpString(_rexData[i][0][segment][0]);
|
|
||||||
ret[primaryVal] = {
|
|
||||||
open: normalizeRegExpString(_rexData[i][0][antisegment][0]),
|
|
||||||
close: _rexData[i][1][antisegment][0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rtfHTMLtagRegistry = tagRegistryMaker(1);
|
|
||||||
this.htmlRTFtagRegistry = tagRegistryMaker(0);
|
|
||||||
|
|
||||||
this.prepared = true;
|
|
||||||
}
|
|
||||||
this.prepare();
|
|
||||||
|
|
||||||
this.getSplit = function(mode, txt) {
|
|
||||||
if (!txt) return [];
|
|
||||||
var splt = txt.split(this[mode + "splitRex"]);
|
|
||||||
var mtch = txt.match(this[mode + "splitRex"]);
|
|
||||||
var lst = [splt[0]];
|
|
||||||
for (var i=1,ilen=splt.length; i < ilen; i++) {
|
|
||||||
lst.push(mtch[i-1]);
|
|
||||||
lst.push(splt[i]);
|
|
||||||
}
|
|
||||||
return lst;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getOpenTag = function(mode, str) {
|
|
||||||
var m = str.match(this[mode + "openSniffRex"]);
|
|
||||||
if (m) {
|
|
||||||
m = this[mode + "openTagRemap"][this.normalizeRegExpString(m[0])];
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.convert = function(mode, txt) {
|
|
||||||
var lst = this.getSplit(mode, txt);
|
|
||||||
var sdepth = 0;
|
|
||||||
var depth = 0;
|
|
||||||
for (var i=1,ilen=lst.length; i < ilen; i += 2) {
|
|
||||||
var openTag = this.getOpenTag(mode, lst[i]);
|
|
||||||
if (openTag) {
|
|
||||||
sdepth++;
|
|
||||||
depth = sdepth;
|
|
||||||
for (var j=(i+2),jlen=lst.length; j < jlen; j += 2) {
|
|
||||||
var closeTag = !this.getOpenTag(mode, lst[j]);
|
|
||||||
if (closeTag) {
|
|
||||||
if (depth === sdepth && lst[j].match(this[mode + "closeTagRex"][openTag])) {
|
|
||||||
lst[i] = this[mode + "tagRegistry"][openTag].open;
|
|
||||||
lst[j] = this[mode + "tagRegistry"][openTag].close;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
depth--;
|
|
||||||
} else {
|
|
||||||
depth++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sdepth--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lst.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.htmlToRTF = function(txt) {
|
|
||||||
txt = this.convert("htmlRTF", txt);
|
|
||||||
for (var i=0,ilen=this._htmlRTFmap.length; i < ilen; i++) {
|
|
||||||
var entry = this._htmlRTFmap[i];
|
|
||||||
txt = txt.replace(entry[0], entry[1]);
|
|
||||||
}
|
|
||||||
txt = Zotero.Utilities.unescapeHTML(txt);
|
|
||||||
txt = txt.replace(/[\x7F-\uFFFF]/g, function(aChar) { return "\\uc0\\u"+aChar.charCodeAt(0).toString()+"{}"});
|
|
||||||
return txt.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.rtfToHTML = function(txt) {
|
|
||||||
for (var i=0,ilen=this._rtfHTMLmap.length; i < ilen; i++) {
|
|
||||||
var entry = this._rtfHTMLmap[i];
|
|
||||||
txt = txt.replace(entry[0], entry[1]);
|
|
||||||
}
|
|
||||||
txt = this.convert("rtfHTML", txt);
|
|
||||||
return txt.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._constructed = true;
|
|
||||||
|
|
||||||
// Don't load if a value hasn't yet been set
|
|
||||||
if (this._loadOnConstruct) {
|
|
||||||
this._load();
|
|
||||||
}
|
|
||||||
]]></constructor>
|
|
||||||
|
|
||||||
<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':
|
|
||||||
this._eventHandler = function (event) {
|
|
||||||
// Necessary in Fx32+
|
|
||||||
if (event.wrappedJSObject) {
|
|
||||||
event = event.wrappedJSObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
var commandEvent = false;
|
|
||||||
|
|
||||||
if (Zotero.Prefs.get('debugNoteEvents')) {
|
|
||||||
Zotero.debug(event.type);
|
|
||||||
Zotero.debug(event.which);
|
|
||||||
}
|
|
||||||
switch (event.type) {
|
|
||||||
case 'keydown':
|
|
||||||
// Handle forward-delete, which doesn't register as a keypress
|
|
||||||
// when a selection is cleared
|
|
||||||
if (event.which == event.DOM_VK_DELETE) {
|
|
||||||
this._changed = true;
|
|
||||||
commandEvent = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'keypress':
|
|
||||||
// Ignore keypresses that don't change
|
|
||||||
// any text
|
|
||||||
//Zotero.debug(event.which);
|
|
||||||
if (!event.which &&
|
|
||||||
event.keyCode != event.DOM_VK_DELETE &&
|
|
||||||
event.keyCode != event.DOM_VK_BACK_SPACE) {
|
|
||||||
//Zotero.debug("Not a char");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._changed = true;
|
|
||||||
commandEvent = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// 'change' includes text added via drag-and-drop
|
|
||||||
case 'change':
|
|
||||||
case 'undo':
|
|
||||||
case 'redo':
|
|
||||||
this._changed = true;
|
|
||||||
commandEvent = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ZoteroLinkClick':
|
|
||||||
var zp = typeof ZoteroPane != 'undefined'
|
|
||||||
? ZoteroPane
|
|
||||||
: window.opener.ZoteroPane;
|
|
||||||
zp.loadURI(event.value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger command on change
|
|
||||||
if (commandEvent && this.timeout) {
|
|
||||||
if (this._timer) {
|
|
||||||
clearTimeout(this._timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._timer = setTimeout(function () {
|
|
||||||
var attr = this.getAttribute('oncommand');
|
|
||||||
attr = attr.replace('this', 'thisObj');
|
|
||||||
var func = new Function('thisObj', 'event', attr);
|
|
||||||
func(this, event);
|
|
||||||
}.bind(this), this.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}.bind(this);
|
|
||||||
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 -->
|
|
||||||
<property name="initialized">
|
|
||||||
<getter><![CDATA[
|
|
||||||
return !!this._editor;
|
|
||||||
]]></getter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- Sets or returns formatting (currently, HTML or Integration) of rich text box -->
|
|
||||||
<property name="format">
|
|
||||||
<getter><![CDATA[
|
|
||||||
return this._format;
|
|
||||||
]]></getter>
|
|
||||||
<setter><![CDATA[
|
|
||||||
return this._format = val;
|
|
||||||
]]></setter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- Sets or returns contents of rich text box -->
|
|
||||||
<property name="value">
|
|
||||||
<getter><![CDATA[
|
|
||||||
if (!this._editor) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var output = this._editor.getContent().trim();
|
|
||||||
|
|
||||||
if(this._format == "RTF") {
|
|
||||||
// strip divs
|
|
||||||
if(output.substr(0, 5) == "<div>" && output.substr(-6) == "</div>") {
|
|
||||||
output = output.slice(0, output.length-6).slice(5).trim();
|
|
||||||
}
|
|
||||||
output = this.htmlToRTF(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
]]></getter>
|
|
||||||
<setter><![CDATA[
|
|
||||||
if (self._timer) {
|
|
||||||
clearTimeout(self._timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this._editor) {
|
|
||||||
Zotero.debug('No editor yet');
|
|
||||||
|
|
||||||
this._value = val;
|
|
||||||
if (!this._constructed) {
|
|
||||||
Zotero.debug('Styled textbox not yet constructed', 2);
|
|
||||||
this._loadOnConstruct = true;
|
|
||||||
}
|
|
||||||
else if (!this._loaded) {
|
|
||||||
this._load();
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack to ignore incomplete editors due to rapid note creation in tests
|
|
||||||
if (Zotero.test && !this._editor.getContent) {
|
|
||||||
Zotero.logError("editor.getContent doesn't exist");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.value == val) {
|
|
||||||
Zotero.debug("Textbox value hasn't changed");
|
|
||||||
this._changed = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = val;
|
|
||||||
if(this._format == "RTF") {
|
|
||||||
var bodyStyle = "";
|
|
||||||
if(html.substr(0, 3) == "\\li") {
|
|
||||||
// try to show paragraph formatting
|
|
||||||
var returnIndex = html.indexOf("\r\n");
|
|
||||||
|
|
||||||
var tags = html.substr(1, returnIndex).split("\\");
|
|
||||||
html = html.substr(returnIndex+2);
|
|
||||||
|
|
||||||
for(var i=0; i<tags.length; i++) {
|
|
||||||
var tagName = tags[i].substr(0, 2);
|
|
||||||
var tagValue = tags[i].substring(2, tags[i].length-1);
|
|
||||||
if(tagName == "li") {
|
|
||||||
var li = parseInt(tagValue, 10);
|
|
||||||
} else if(tagName == "fi") {
|
|
||||||
var fi = parseInt(tagValue, 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't negatively indent
|
|
||||||
if(fi < 0 && li == 0) li = -fi;
|
|
||||||
|
|
||||||
bodyStyle = "margin-left:"+(li/20+6)+"pt;text-indent:"+(fi/20)+"pt;";
|
|
||||||
}
|
|
||||||
|
|
||||||
html = this.rtfToHTML(html);
|
|
||||||
|
|
||||||
html = '<div style="'+bodyStyle+'"><p>'+html+"</p></div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
Zotero.debug("Setting content to " + html);
|
|
||||||
|
|
||||||
this._editor.setContent(html);
|
|
||||||
this._changed = false;
|
|
||||||
return val;
|
|
||||||
]]></setter>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<property name="timeout"
|
|
||||||
onset="this.setAttribute('timeout', val); return val;"
|
|
||||||
onget="return parseInt(this.getAttribute('timeout')) || 0;"/>
|
|
||||||
|
|
||||||
<property name="changed" onget="return this._changed;" onset="this._changed = !!val;"/>
|
|
||||||
|
|
||||||
<method name="focus">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
if (this._editor) {
|
|
||||||
this._iframe.focus();
|
|
||||||
this._editor.focus();
|
|
||||||
this._focus = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._focus = true;
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="hasFocus">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
return this._editor ? this._editor.hasFocus() : false;
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="clearUndo">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
if (this._editor) {
|
|
||||||
this._editor.undoManager.clear();
|
|
||||||
this._editor.undoManager.add();
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<method name="onInit">
|
|
||||||
<parameter name="callback"/>
|
|
||||||
<body><![CDATA[
|
|
||||||
if (this.initialized) {
|
|
||||||
// Hack to ignore incomplete editors due to rapid note creation in tests
|
|
||||||
if (Zotero.test && !this._editor.setMode) {
|
|
||||||
Zotero.logError("editor.setMode doesn't exist after initialization");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
callback(this._editor);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!this._onInitCallbacks) {
|
|
||||||
this._onInitCallbacks = [];
|
|
||||||
}
|
|
||||||
this._onInitCallbacks.push(callback);
|
|
||||||
}
|
|
||||||
]]></body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<field name="_loaded"/>
|
|
||||||
<method name="_load">
|
|
||||||
<body>
|
|
||||||
<![CDATA[
|
|
||||||
this._loaded = true;
|
|
||||||
|
|
||||||
// Unless we find a better way, use a separate HTML file
|
|
||||||
// for read-only mode
|
|
||||||
var htmlFile = this.mode + (this.getAttribute('readonly') != 'true' ? "" : "view");
|
|
||||||
|
|
||||||
var url = `resource://zotero/tinymce/${htmlFile}.html`
|
|
||||||
// Pass directionality (LTR/RTL) and locale in URL
|
|
||||||
+ "?locale=" + encodeURIComponent(Zotero.locale)
|
|
||||||
+ "&dir=" + Zotero.dir;
|
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
|
||||||
var uri = Services.io.newURI(url, null, null);
|
|
||||||
|
|
||||||
Zotero.debug("Loading " + uri.spec);
|
|
||||||
|
|
||||||
// Register handler for deferred setting of content
|
|
||||||
var self = this;
|
|
||||||
var matchTo = null;
|
|
||||||
var listener = function(e) {
|
|
||||||
var win = self._iframe.contentWindow;
|
|
||||||
var SJOW = win.wrappedJSObject;
|
|
||||||
|
|
||||||
// only fire if the target matches, or _zoteroMatchTo, which we set last
|
|
||||||
// time the target matched, matches
|
|
||||||
if(e.target !== self._iframe.contentDocument
|
|
||||||
&& (!SJOW._zoteroMatchTo || SJOW._zoteroMatchTo !== matchTo)) return;
|
|
||||||
|
|
||||||
if (!SJOW.tinyMCE) {
|
|
||||||
Zotero.getInstalledExtensions().then(function(exts) {
|
|
||||||
for (let ext of exts) {
|
|
||||||
if (ext.indexOf('NoScript') != -1 && ext.indexOf('disabled') == -1) {
|
|
||||||
var doc = win.document;
|
|
||||||
var div = doc.getElementById('tinymce');
|
|
||||||
var warning = doc.createElement('div');
|
|
||||||
warning.id = 'noScriptWarning';
|
|
||||||
var str = "The NoScript extension is preventing Zotero "
|
|
||||||
+ "from displaying notes. To use NoScript and Zotero together, "
|
|
||||||
+ "whitelist the 'file:' scheme in the NoScript preferences "
|
|
||||||
+ "and restart " + Zotero.appName + ".";
|
|
||||||
warning.appendChild(document.createTextNode(str));
|
|
||||||
div.appendChild(warning);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SJOW.zoteroInit) {
|
|
||||||
SJOW.zoteroInit = function(editor) {
|
|
||||||
// Necessary in Fx32+
|
|
||||||
if (editor.wrappedJSObject) {
|
|
||||||
self._editor = editor.wrappedJSObject;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self._editor = editor;
|
|
||||||
}
|
|
||||||
if (self._value) {
|
|
||||||
self.value = self._value;
|
|
||||||
|
|
||||||
// Prevent undoing to empty note after initialization
|
|
||||||
self._editor.undoManager.clear();
|
|
||||||
self._editor.undoManager.add();
|
|
||||||
}
|
|
||||||
if (self._focus) {
|
|
||||||
setTimeout(function () {
|
|
||||||
self._iframe.focus();
|
|
||||||
self._editor.focus();
|
|
||||||
});
|
|
||||||
self._focus = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add CSS rules to notes
|
|
||||||
if (self.mode == 'note') {
|
|
||||||
let fontSize = Zotero.Prefs.get('note.fontSize');
|
|
||||||
// Fix empty old font prefs before a value was enforced
|
|
||||||
if (fontSize < 6) {
|
|
||||||
fontSize = 11;
|
|
||||||
}
|
|
||||||
var css = "body#zotero-tinymce-note, "
|
|
||||||
+ "body#zotero-tinymce-note p, "
|
|
||||||
+ "body#zotero-tinymce-note th, "
|
|
||||||
+ "body#zotero-tinymce-note td, "
|
|
||||||
+ "body#zotero-tinymce-note pre { "
|
|
||||||
+ "font-size: " + fontSize + "px; "
|
|
||||||
+ "} "
|
|
||||||
+ "body#zotero-tinymce-note, "
|
|
||||||
+ "body#zotero-tinymce-note p { "
|
|
||||||
+ "font-family: "
|
|
||||||
+ Zotero.Prefs.get('note.fontFamily') + "; "
|
|
||||||
+ "}"
|
|
||||||
+ Zotero.Prefs.get('note.css');
|
|
||||||
|
|
||||||
var doc = editor.contentDocument;
|
|
||||||
var head = doc.getElementsByTagName("head")[0];
|
|
||||||
var style = doc.createElement("style");
|
|
||||||
style.innerHTML = css;
|
|
||||||
head.appendChild(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cb;
|
|
||||||
if (this._onInitCallbacks) {
|
|
||||||
while (cb = this._onInitCallbacks.shift()) {
|
|
||||||
// Hack to ignore incomplete editors due to rapid note creation in tests
|
|
||||||
if (Zotero.test && !this._editor.setMode) {
|
|
||||||
Zotero.logError("editor.setMode doesn't exist");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cb(this._editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
var editor = SJOW.tinyMCE.get("tinymce");
|
|
||||||
if (!editor) {
|
|
||||||
Zotero.debug("editor not ready");
|
|
||||||
|
|
||||||
// this is a hack; I'm not sure why we can't identify the event target
|
|
||||||
// next time without it, but apparently we can't
|
|
||||||
matchTo = Zotero.randomString();
|
|
||||||
SJOW._zoteroMatchTo = matchTo;
|
|
||||||
|
|
||||||
// Not ready yet
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self._iframe.removeEventListener("DOMContentLoaded", listener, false);
|
|
||||||
|
|
||||||
if (self._eventHandler) {
|
|
||||||
win.wrappedJSObject.zoteroHandleEvent = self._eventHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run Cut/Copy/Paste with chrome privileges
|
|
||||||
win.wrappedJSObject.zoteroExecCommand = function (doc, command, ui, value) {
|
|
||||||
return doc.execCommand(command, ui, value);
|
|
||||||
}
|
|
||||||
}.bind(this);
|
|
||||||
|
|
||||||
this._iframe.addEventListener("DOMContentLoaded", listener, false);
|
|
||||||
|
|
||||||
let loadURIOptions = {
|
|
||||||
triggeringPrincipal: null,
|
|
||||||
csp: null,
|
|
||||||
loadFlags: Components.interfaces.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
|
|
||||||
referrerInfo: null,
|
|
||||||
postData: null,
|
|
||||||
};
|
|
||||||
this._iframe.webNavigation.loadURI(uri.spec, loadURIOptions);
|
|
||||||
]]>
|
|
||||||
</body>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
</implementation>
|
|
||||||
|
|
||||||
<content>
|
|
||||||
<xul:iframe flex="1" anonid="rt-view" class="rt-view" type="content"
|
|
||||||
xbl:inherits="onfocus,onblur,flex,width,height,hidden"
|
|
||||||
style="overflow: hidden"/>
|
|
||||||
</content>
|
|
||||||
</binding>
|
|
||||||
</bindings>
|
|
|
@ -15,20 +15,6 @@
|
||||||
padding:0;
|
padding:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bindings */
|
|
||||||
textbox[type="styled"]
|
|
||||||
{
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/styled-textbox.xml#styled-textbox');
|
|
||||||
}
|
|
||||||
|
|
||||||
zoteromergegroup {
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/merge.xml#merge-group');
|
|
||||||
}
|
|
||||||
|
|
||||||
zoteromergepane {
|
|
||||||
-moz-binding: url('chrome://zotero/content/bindings/merge.xml#merge-pane');
|
|
||||||
}
|
|
||||||
|
|
||||||
richlistitem {
|
richlistitem {
|
||||||
padding: 0.2em 0.4em;
|
padding: 0.2em 0.4em;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue