add basic Word integration. to see it in action, copy Zotero.dot to Microsoft Office 2004/Office/Startup/Word. if the gods are with you, you should see a new toolbar the next time you open Word.
not yet implemented: - formatted in-text citations, rather than placeholders - footnotes - selection of citation style (for now, only APA is available) - support for non-ASCII characters - exclusion of notes from select items window - Windows support (although it shouldn't be difficult) - probably much more...
This commit is contained in:
parent
a976d4cd0e
commit
c2c82e3c54
4 changed files with 352 additions and 2 deletions
BIN
Zotero.dot
Normal file
BIN
Zotero.dot
Normal file
Binary file not shown.
|
@ -202,7 +202,9 @@ CSL.prototype.createBibliography = function(items, format) {
|
|||
// add line feeds
|
||||
if(format == "HTML") {
|
||||
var coins = Scholar.OpenURL.createContextObject(item, "1.0");
|
||||
string += '<span class="Z3988" title="'+coins.replace("&", "&")+'"></span>';
|
||||
if(coins) {
|
||||
string += '<span class="Z3988" title="'+coins.replace("&", "&")+'"></span>';
|
||||
}
|
||||
|
||||
if(this._class == "note") {
|
||||
output += "<li>"+string+"</li>\r\n";
|
||||
|
@ -215,6 +217,8 @@ CSL.prototype.createBibliography = function(items, format) {
|
|||
output += index+". ";
|
||||
}
|
||||
output += string+"\\\r\n\\\r\n";
|
||||
} else if(format == "Integration") {
|
||||
output += string+"\r\n\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -760,6 +764,8 @@ CSL.prototype._escapeString = function(string, format) {
|
|||
}
|
||||
|
||||
return newString;
|
||||
} else if(format == "Integration") {
|
||||
return string.replace(/\\/g, "\\\\");
|
||||
} else {
|
||||
return string;
|
||||
}
|
||||
|
@ -820,7 +826,7 @@ CSL.prototype._formatString = function(element, string, format, dontEscape) {
|
|||
if(style) {
|
||||
string = '<span style="'+style+'">'+string+'</span>';
|
||||
}
|
||||
} else if(format == "RTF") {
|
||||
} else if(format == "RTF" || format == "Integration") {
|
||||
if(element["font-style"] && (element["font-style"] == "oblique" || element["font-style"] == "italic")) {
|
||||
string = "\\i "+string+"\\i0 ";
|
||||
}
|
||||
|
|
340
chrome/chromeFiles/content/scholar/xpcom/integration.js
Normal file
340
chrome/chromeFiles/content/scholar/xpcom/integration.js
Normal file
|
@ -0,0 +1,340 @@
|
|||
Scholar.Integration = new function() {
|
||||
var _contentLengthRe = /[\r\n]Content-Length: *([0-9]+)/i;
|
||||
var _XMLRe = /<\?[^>]+\?>/;
|
||||
this.ns = "http://chnm.gmu.edu/firefoxscholar/soap";
|
||||
|
||||
this.init = init;
|
||||
this.handleHeader = handleHeader;
|
||||
this.handleEnvelope = handleEnvelope;
|
||||
|
||||
/*
|
||||
* initializes a very rudimentary web server used for SOAP RPC
|
||||
*/
|
||||
function init() {
|
||||
// start listening on socket
|
||||
var sock = Components.classes["@mozilla.org/network/server-socket;1"];
|
||||
serv = sock.createInstance();
|
||||
serv = serv.QueryInterface(Components.interfaces.nsIServerSocket);
|
||||
|
||||
// bind to a random port on loopback only
|
||||
serv.init(50001, true, -1);
|
||||
serv.asyncListen(Scholar.Integration.SocketListener);
|
||||
|
||||
Scholar.debug("Integration HTTP server listening on 127.0.0.1:"+serv.port);
|
||||
}
|
||||
|
||||
/*
|
||||
* registers a SOAP method
|
||||
*/
|
||||
function registerSOAP(name, callback) {
|
||||
_registeredSOAP[name] = callback;
|
||||
}
|
||||
|
||||
/*
|
||||
* handles an HTTP request
|
||||
*/
|
||||
function handleHeader(header) {
|
||||
// get first line of request (all we care about for now)
|
||||
var spaceIndex = header.indexOf(" ");
|
||||
var method = header.substr(0, spaceIndex);
|
||||
var uri = header.substr(spaceIndex+1);
|
||||
|
||||
if(!method || !uri) {
|
||||
return _generateResponse("400 Bad Request");
|
||||
}
|
||||
|
||||
if(method != "POST") {
|
||||
return _generateResponse("501 Method Not Implemented");
|
||||
} else {
|
||||
// parse content length
|
||||
var m = _contentLengthRe.exec(header);
|
||||
if(!m) {
|
||||
return _generateResponse("400 Bad Request");
|
||||
} else {
|
||||
return parseInt(m[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handles a SOAP envelope
|
||||
*/
|
||||
function handleEnvelope(envelope) {
|
||||
Scholar.debug("Got SOAP envelope");
|
||||
Scholar.debug(envelope);
|
||||
envelope = envelope.replace(_XMLRe, "");
|
||||
|
||||
var env = new Namespace("http://schemas.xmlsoap.org/soap/envelope/");
|
||||
var xml = new XML(envelope);
|
||||
var request = xml.env::Body.children()[0];
|
||||
if(request.namespace() != this.ns) {
|
||||
Scholar.debug("SOAP method not supported: invalid namespace");
|
||||
} else {
|
||||
var name = request.localName();
|
||||
if(Scholar.Integration.SOAP[name]) {
|
||||
if(request.input.length()) {
|
||||
var input = request.input.toString();
|
||||
var vars = new Array();
|
||||
vars[0] = "";
|
||||
var i = 0;
|
||||
|
||||
colonIndex = input.indexOf(":");
|
||||
while(colonIndex != -1) {
|
||||
Scholar.debug(input);
|
||||
if(input[colonIndex+1] == ":") { // escaped
|
||||
vars[i] += input.substr(0, colonIndex+1);
|
||||
input = input.substr(colonIndex+2);
|
||||
} else { // not escaped
|
||||
vars[i] += input.substr(0, colonIndex);
|
||||
i++;
|
||||
vars[i] = "";
|
||||
input = input.substr(colonIndex+1);
|
||||
}
|
||||
colonIndex = input.indexOf(":");
|
||||
}
|
||||
vars[i] += input;
|
||||
} else {
|
||||
var vars = null;
|
||||
}
|
||||
|
||||
// execute request
|
||||
var output = Scholar.Integration.SOAP[name](vars);
|
||||
|
||||
// ugh: we can't use real SOAP, since AppleScript VBA can't pass
|
||||
// objects, so implode arrays
|
||||
if(!output) {
|
||||
output = "";
|
||||
}
|
||||
|
||||
if(typeof(output) == "object") {
|
||||
for(var i in output) {
|
||||
if(typeof(output[i]) == "string") {
|
||||
output[i] = output[i].replace(/:/g, "::");
|
||||
}
|
||||
}
|
||||
output = output.join(":");
|
||||
}
|
||||
|
||||
// create envelope
|
||||
var responseEnvelope = <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Body>
|
||||
<m:{name}Response xmlns:m={this.ns}>
|
||||
<output>{output}</output>
|
||||
</m:{name}Response>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>;
|
||||
|
||||
// return OK
|
||||
return _generateResponse("200 OK", 'text/xml; charset="utf-8"',
|
||||
responseEnvelope.toXMLString());
|
||||
} else {
|
||||
Scholar.debug("SOAP method not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generates the response to an HTTP request
|
||||
*/
|
||||
function _generateResponse(status, contentType, body) {
|
||||
var response = "HTTP/1.0 "+status+"\r\n";
|
||||
|
||||
if(body) {
|
||||
if(contentType) {
|
||||
response += "Content-Type: "+contentType+"\r\n";
|
||||
}
|
||||
response += "Content-Length: "+body.length+"\r\n\r\n"+body;
|
||||
} else {
|
||||
response += "Content-Length: 0\r\n\r\n"
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
Scholar.Integration.SocketListener = new function() {
|
||||
this.onSocketAccepted = onSocketAccepted;
|
||||
|
||||
/*
|
||||
* called when a socket is opened
|
||||
*/
|
||||
function onSocketAccepted(socket, transport) {
|
||||
// get an input stream
|
||||
var iStream = transport.openInputStream(0, 0, 0);
|
||||
var oStream = transport.openOutputStream(0, 0, 0);
|
||||
|
||||
var dataListener = new Scholar.Integration.DataListener(iStream, oStream);
|
||||
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"]
|
||||
.createInstance(Components.interfaces.nsIInputStreamPump);
|
||||
pump.init(iStream, -1, -1, 0, 0, false);
|
||||
pump.asyncRead(dataListener, null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handles the actual acquisition of data
|
||||
*/
|
||||
Scholar.Integration.DataListener = function(iStream, oStream) {
|
||||
this.header = "";
|
||||
this.headerFinished = false;
|
||||
|
||||
this.body = "";
|
||||
this.bodyLength = 0;
|
||||
|
||||
this.iStream = iStream;
|
||||
this.oStream = oStream;
|
||||
this.sStream = Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
this.sStream.init(iStream);
|
||||
|
||||
this.foundReturn = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* called when a request begins (although the request should have begun before
|
||||
* the DataListener was generated)
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype.onStartRequest = function(request, context) {}
|
||||
|
||||
/*
|
||||
* called when a request stops
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype.onStopRequest = function(request, context, status) {
|
||||
this.iStream.close();
|
||||
this.oStream.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* called when new data is available
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype.onDataAvailable = function(request, context,
|
||||
inputStream, offset, count) {
|
||||
var readData = this.sStream.read(count);
|
||||
|
||||
if(this.headerFinished) { // reading body
|
||||
this.body += readData;
|
||||
// check to see if data is done
|
||||
this._bodyData();
|
||||
} else { // reading header
|
||||
// see if there's a magic double return
|
||||
var lineBreakIndex = readData.indexOf("\r\n\r\n");
|
||||
if(lineBreakIndex != -1) {
|
||||
if(lineBreakIndex != 0) {
|
||||
this.header += readData.substr(0, lineBreakIndex+4);
|
||||
this.body = readData.substr(lineBreakIndex+4);
|
||||
}
|
||||
|
||||
this._headerFinished();
|
||||
return;
|
||||
}
|
||||
var lineBreakIndex = readData.indexOf("\n\n");
|
||||
if(lineBreakIndex != -1) {
|
||||
if(lineBreakIndex != 0) {
|
||||
this.header += readData.substr(0, lineBreakIndex+2);
|
||||
this.body = readData.substr(lineBreakIndex+2);
|
||||
}
|
||||
|
||||
this._headerFinished();
|
||||
return;
|
||||
}
|
||||
if(this.header && this.header[this.header.length-1] == "\n" &&
|
||||
(readData[0] == "\n" || readData[0] == "\r")) {
|
||||
if(readData.length > 1 && readData[1] == "\n") {
|
||||
this.header += readData.substr(0, 2);
|
||||
this.body = readData.substr(2);
|
||||
} else {
|
||||
this.header += readData[0];
|
||||
this.body = readData.substr(1);
|
||||
}
|
||||
|
||||
this._headerFinished();
|
||||
return;
|
||||
}
|
||||
this.header += readData;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* processes an HTTP header and decides what to do
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype._headerFinished = function() {
|
||||
this.headerFinished = true;
|
||||
var output = Scholar.Integration.handleHeader(this.header);
|
||||
|
||||
if(typeof(output) == "number") {
|
||||
this.bodyLength = output;
|
||||
// check to see if data is done
|
||||
this._bodyData();
|
||||
} else {
|
||||
this._requestFinished(output);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* checks to see if Content-Length bytes of body have been read and, if they
|
||||
* have, processes the body
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype._bodyData = function() {
|
||||
if(this.body.length >= this.bodyLength) {
|
||||
if(this.body.length > this.bodyLength) {
|
||||
// truncate
|
||||
this.body = this.body.substr(0, this.bodyLength);
|
||||
}
|
||||
|
||||
var output = Scholar.Integration.handleEnvelope(this.body);
|
||||
this._requestFinished(output);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* returns HTTP data from a request
|
||||
*/
|
||||
Scholar.Integration.DataListener.prototype._requestFinished = function(response) {
|
||||
// close input stream
|
||||
this.iStream.close();
|
||||
|
||||
// write response
|
||||
this.oStream.write(response, response.length);
|
||||
|
||||
// close output stream
|
||||
this.oStream.close();
|
||||
}
|
||||
|
||||
Scholar.Integration.SOAP = new function() {
|
||||
this.getCitation = getCitation;
|
||||
this.getBibliography = getBibliography;
|
||||
|
||||
function getCitation(parameters) {
|
||||
var myWindow = Components.classes["@mozilla.org/appshell/appShellService;1"]
|
||||
.getService(Components.interfaces.nsIAppShellService)
|
||||
.hiddenDOMWindow;
|
||||
|
||||
var io = {dataIn: null, dataOut: null};
|
||||
myWindow.openDialog('chrome://scholar/content/selectItemsDialog.xul','',
|
||||
'chrome,popup,modal,centerscreen,titlebar=no',io);
|
||||
|
||||
if(io.dataOut && io.dataOut[0]) {
|
||||
var item = Scholar.Items.get(io.dataOut[0]);
|
||||
var creator = item.getCreator(0);
|
||||
return [io.dataOut[0], "{{"+creator.lastName+"}}"]
|
||||
}
|
||||
}
|
||||
|
||||
function getBibliography(vars) {
|
||||
// get items
|
||||
var itemIDs = vars[1].split(",");
|
||||
var items = Scholar.Items.get(itemIDs);
|
||||
|
||||
return Scholar.Cite.getBibliography(vars[0], items, "Integration");
|
||||
}
|
||||
}
|
||||
|
||||
/*Scholar.Integration.registerURL("/", "text/plain", function(vars) {
|
||||
return "Hi there! The HTTP server is working!";
|
||||
});
|
||||
Scholar.Integration.registerURL("/getBibliography", "text/html",
|
||||
function(vars) { return Scholar.Integration.Cite.getBibliography(vars) });
|
||||
Scholar.Integration.registerURL("/getCitation", "text/html",
|
||||
function(vars) { return Scholar.Integration.Cite.getCitation(vars) });*/
|
||||
|
||||
Scholar.Integration.init();
|
|
@ -58,6 +58,10 @@ Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
|||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://scholar/content/xpcom/utilities.js");
|
||||
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://scholar/content/xpcom/integration.js");
|
||||
|
||||
Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||
.getService(Ci.mozIJSSubScriptLoader)
|
||||
.loadSubScript("chrome://scholar/content/xpcom/file.js");
|
||||
|
|
Loading…
Add table
Reference in a new issue