Extracting BibTex from Zotero works.
[org-fireforg.git] / fireforg / content / overlay.js
blobbb7647c1831f674bd4c6f83490abaf20a61db910
1 //  Fireforg - a Firefox extension for org mode interaction
3 //  Copyright 2009 Andreas Burtzlaff
5 //  Author: Andreas Burtzlaff < andreas at burtz[REMOVE]laff dot de >
6 //  Version: 0.1a
8 //  This file is not part of GNU Emacs.
10 //  This includes a copy of jquery (http://jquery.com/) under its GPL license
11 //  (http://docs.jquery.com/Licensing)
13 //  This program is free software; you can redistribute it and/or
14 //  modify it under the terms of the GNU General Public License as
15 //  published by the Free Software Foundation; either version 2, or (at
16 //  your option) any later version.
18 //  This program is distributed in the hope that it will be useful, but
19 //  WITHOUT ANY WARRANTY; without even the implied warranty of
20 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 //  General Public License for more details.
23 //  You should have received a copy of the GNU General Public License
24 //  along with this program; if not, write to the Free Software
25 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 var fireforg = {
28     // define jquery convenience functions
29     jq: function (a) { return $mb( a, window.content.document); },
31     requestid: 0,
32     // fetch links
33     lookupAndModifyLinks: function () {
35         // remove existing annotations;
36         fireforg.jq(".orgNote").remove();
38         var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
39         var annotationLinkStyle = prefManager.getCharPref("extensions.fireforg.annotationLinkStyle");
40         var annotationLinkTooltip = prefManager.getBoolPref("extensions.fireforg.annotationLinkTooltip");
42         var linksJQ = fireforg.jq("a");
43         
44         linksJQ.each( function () {
47                 var objectJQ = fireforg.jq(this);
48                 var url = objectJQ.attr("href");
50                 var registryEntry = fireforg.getRegistryEntryForLink( url );
52                 if( registryEntry ) {
53                     // add class orgNoteLink in order to be able to select the modified elements later (no css info connected with this class)
54                     //              objectJQ.attr("class", objectJQ.attr("class") + " orgNoteLink");
55                 
56                     objectJQ.attr("style", objectJQ.attr("style") + annotationLinkStyle);
57                     // in order to be able to remove the inserted style string, it has to be stored separately
58                     objectJQ.attr("fireforgStyle", annotationLinkStyle);
60                     // generate tooltip text from entry (BUG: Newline doesn't work here. Rewrite with proper menu on mouseover.)
61                     if( annotationLinkTooltip ) {
62                        var tooltipText = "";
63                        fireforg.jq( registryEntry ).children().each( function () { tooltipText = tooltipText + fireforg.jq( this ).attr("text") + "\n"; });
64                        objectJQ.attr("title", tooltipText );
65                     }
67                 }
69                 /*
70                 var pos = fireforg.jq(this).offset();
71                 //                var posRoot = $mb(window.content.document, window.content.document).offset();
73                 //                var annotation = document.createElement('div');
74                 //annotation.textContent = "OrgTest!";
75                 
76                 var annotation = document.createElement('div');
77                 annotation.class += "orgNote";
78                 //                var img = document.createElement('img');
79                 //img.src = "chrome://fireforg/skin/org-mode-unicorn_16.png";
80                 //annotation.appendChild( img );
81                 //                fireforg.orgProtocolSendURL("fireforg-get-annotations://" + encodeURIComponent(fireforg.requestid)  + "/" + encodeURIComponent( window.content.document.URL));
82                 annotation.textContent = "Org!";
83                 fireforg.jq( annotation ).css({"border-style":"solid", "border-width" : "1px","background-color" : "gray"});
85                 fireforg.jq("body").append( annotation );
86                 var annotationWidth = fireforg.jq("body").children().eq(".orgNote").width();                
87                 var annotationHeight = fireforg.jq(annotation).height();
88                 //alert(annotationWidth);
89                 fireforg.jq(annotation).css( { "position" : "absolute", "left" : "" + (pos.left-40) + "px", "top" : "" + pos.top + "px" ,"z-index" : "3"});
90                 //$mb( annotation, window.content.document ).css( { "position" : "absolute", "left" : "-10px", "top" : "-10px" ,"z-index" : "3"});
91                 */
92             });
94     },
95     onLoadSite: function () {
97         if( fireforg.loadRegistryFromFile() ) {
98             var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
99             if( prefManager.getBoolPref("extensions.fireforg.lookupLinksOnLoad") )
100                 fireforg.lookupAndModifyLinks();
101         } else {
102             fireforg.setStatusBarIconError();
103         }
105     },
106     onUrlSwitch: function() {
107                 
108         if( fireforg.loadRegistryFromFile() ) {
110             // set waiting state
111             fireforg.links = [];
112             fireforg.setStatusBarWaiting();
114             // get URL
115             var url = window.content.document.URL;
116             fireforg.currentLink = url;
118             if( !fireforg.registryDOM ) {
119                 fireforg.setStatusBarIconNormal(0);
120             } else {
121                 
122                 // get all heading for url
123                 fireforg.currentLinkRegistryEntry = fireforg.registryDOM.evaluate("//link[@url=\"" + url +"\"]", fireforg.registryDOM, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
124                 if( fireforg.currentLinkRegistryEntry ) {
125                     fireforg.setStatusBarIconNormal( fireforg.jq( fireforg.currentLinkRegistryEntry ).children().length );
126                 } else {
127                     fireforg.setStatusBarIconNormal( 0 );
128                 }
129                 // get tags for url, remove duplicates
130                 var tags = "";
131                 fireforg.jq( fireforg.currentLinkRegistryEntry ).children().each( function () { var t = fireforg.jq( this ).attr("tags"); if( t != "") { tags = tags + t }; });
132                 if( tags != "" ) {
133                     var tagList = tags.replace("::",":").replace(/^:/,"").replace(/:$/,"").split(":").sort();
134                     if( tagList.length > 0 ) {
135                         var tagNoDup = ":" + tagList[0] + ":";
136                         for( var i = 1 ; i < tagList.length ; i++ ) {
137                             if( tagList[i] != "" && tagList[i] != tagList[i-1] )
138                                 tagNoDup = tagNoDup + tagList[i] + ":";
139                         }
140                         fireforg.setStatusBarTags( tagNoDup );
141                     } else {
142                         fireforg.setStatusBarTags("");
143                     }
144                 } else {
145                     fireforg.setStatusBarTags("");
146                 }
147             }
149             } else {
150                 fireforg.setStatusBarIconError();
151             }
153        
154         
155     },
156     loadRegistryFromFile: function () {
157         var file = Components.classes["@mozilla.org/file/local;1"]
158         .createInstance(Components.interfaces.nsILocalFile);
159         file.initWithPath( Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch).getCharPref("extensions.fireforg.registryFile") );
160         if ( !file.exists() ) {
161             return false;
162         } else {
163             var is = Components.classes["@mozilla.org/network/file-input-stream;1"]
164             .createInstance( Components.interfaces.nsIFileInputStream );
165             is.init( file,0x01, 00004, null);
166             var sis = Components.classes["@mozilla.org/scriptableinputstream;1"]
167             .createInstance( Components.interfaces.nsIScriptableInputStream );
168             sis.init( is );
169             var output = sis.read( sis.available() );
170             
171             var parser = new DOMParser();
172             fireforg.registryDOM = parser.parseFromString( output , "text/xml");
173             var registry = fireforg.registryDOM.childNodes;
176             // load registry
177             fireforg.domEntry = document.getElementById("fireforg_registry");
178             if( fireforg.domEntry ) {
179                 document.removeChild( fireforg.domEntry );
180             }
181             fireforg.domEntry = document.createElement("registry");
182             fireforg.domEntry.id = "fireforg_registry";
184             return true;
185         }
187     },
188     getRegistryEntryForLink: function (url) {
189         try {
190             // the xpath query may be invalid for certain url's
191             return fireforg.registryDOM.evaluate("//link[@url=\"" + url +"\"]", fireforg.registryDOM, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
192         } catch (e) {
193             return null;
194         }
195     },
196     onLoad: function() {
197         // init variables
198         fireforg.timeout = window.setTimeout("",10);
199         fireforg.timeoutCount = 0;
201         // add onclick event handler for status bar icon
202         document.getElementById("fireforg_spi").onclick = fireforg.onStatusbarIconClicked;
204         // add appcontent hook
205         var appcontent = window.document.getElementById("appcontent");
206         appcontent.addEventListener("DOMContentLoaded", fireforg.onLoadSite, false);
207         appcontent.addEventListener("DOMContentLoaded", fireforg.onUrlSwitch, false);
209         // add tab change listener
210         var container = gBrowser.tabContainer;
211         container.addEventListener("TabSelect", fireforg.onUrlSwitch, false);
213         // try to listen to url changes. Found this somewhere on the web. Doesn't work.
214         /*var wnd = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
215         .getInterface(Components.interfaces.nsIWebNavigation)
216         .QueryInterface(Components.interfaces.nsIDocShell)
217         .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
218         .getInterface(Components.interfaces.nsIURIContentListener);
219         wnd.parentContentListener = fireforg.onUrlSwitch; 
220         */
221         // document.getElementById('urlbar').onchange = fireforg.onUrlSwitch;
223         this.initialized = true;
224         this.strings = document.getElementById("fireforg-strings");
226         // try to add "itemDone" handler to Zoteros translator
227         //        if( Zotero.Translate ) {
228         //  alert("Zotero Translate handler injected.");
229         //  Zotero.Translate.prototype.setHandler("itemDone", fireforg.zoteroItemDoneHandler );
230         //} else {
231         window.setTimeout( function () { if( Zotero.Translate ) {
232                     alert("Zotero translator handler injected.");
233                     //(new Zotero.Translate()).setHandler("itemDone", fireforg.zoteroItemDoneHandler );
234                     Zotero.Translate.prototype.fireforg_runHandler = Zotero.Translate.prototype.runHandler;
235                     Zotero.Translate.prototype.runHandler = function(type, argument) {
236                         if( type == "itemDone") {
237                             //                          alert("Zotero hijacked!");
238                             fireforg.zoteroItemDoneHandler( argument );
239                         }
241                         return this.fireforg_runHandler(type, argument);
242                     }
243                 } },5000);
244         //}
246     },
247     onStatusbarIconClicked: function (ev) {
248         if( ev.button == 0 )
249             fireforg.showLinkListPopup();
250         else {
251             document.getElementById('fireforg_popup_menu').openPopup( document.getElementById("fireforg_spi"),"before_end",0,0,false,null);
252         }
253            
254     },
255     showLinkListPopup: function () {
256    
257         if( fireforg.currentLinkRegistryEntry ) {
258            var popupMenu = document.getElementById('fireforg_popup_dynamic');
259                 
260            fireforg.populateMenuWithAnnotations( popupMenu, fireforg.currentLinkRegistryEntry );
261            
262             popupMenu.openPopup( document.getElementById("fireforg_spi"),"before_end",0,0,false,null);
264         }
265     },
266     orgProtocolAcknowledgeResponse: function (id) {
267         fireforg.orgProtocolSendURL("fireforg-acknowledge://" + encodeURIComponent(id));
268     },
269     orgProtocolShowAnnotation: function (file, heading, encoded) {
270         
271         if( !encoded ) {
272             file = encodeURIComponent( file );
273             heading = encodeURIComponent( heading ); }
274         fireforg.orgProtocolSendURL("fireforg-show-annotation://" + file + "/" + heading);
275     },
276     setStatusBarIconNormal: function (matches) {
277         
278         if( matches == 0 ) {
279           document.getElementById('fireforg_spi_image').setAttribute("src","chrome://fireforg/skin/org-mode-unicorn_16.png");
280           document.getElementById('fireforg_spi_label').setAttribute("value","");
281         } else {
282           document.getElementById('fireforg_spi_image').setAttribute("src","chrome://fireforg/skin/org-mode-unicorn_16_highlighted.png");
283           document.getElementById('fireforg_spi_label').setAttribute("value","(" + matches + ")");
284         }
285     },
286     setStatusBarIconError: function () {
287         document.getElementById('fireforg_spi_label').setAttribute("value","Error");
288         document.getElementById('fireforg_spi_label_tags').setAttribute("value","");
289     },
290     setStatusBarWaiting: function () {
291         document.getElementById('fireforg_spi_label').setAttribute("value","...");
292         document.getElementById('fireforg_spi_label_tags').setAttribute("value","");
293     },
294     setStatusBarTags: function (tagString) {
295         document.getElementById('fireforg_spi_label_tags').setAttribute("value",tagString);
296     },
297     orgProtocolStoreLink: function () {
298         fireforg.orgProtocolSendURL("store-link://" + encodeURIComponent(window.content.document.URL),true);// + "/" + encodeURIComponent(document.title), true);
299     },
300     orgProtocolRemember: function () {
301         fireforg.orgProtocolSendURL("remember://" + encodeURIComponent(window.content.document.URL) + "/" + encodeURIComponent(document.title) + "/" + encodeURIComponent(window.getSelection()));
302     },
303     orgProtocolSendURL: function (url) {
304         var req = new XMLHttpRequest();
305         try {
306             req.open('POST', "org-protocol://" + url,true);
307             req.send(null);
308         } catch (ex) { }
309     },
310     contextMenuItemShowing: function (e) {
311         //        alert("ContextMenuItemShowing");
313         var contextMenuEntry = document.getElementById('fireforg_ctx_menu_fireforg_popup');                
315         // remove all children
316         while(contextMenuEntry.hasChildNodes()){
317             contextMenuEntry.removeChild(contextMenuEntry.lastChild);}
319         if( gContextMenu.onLink ) {
320             var url = gContextMenu.link;
322             var registryEntry = fireforg.getRegistryEntryForLink( url );
324             fireforg.populateMenuWithAnnotations( contextMenuEntry, registryEntry );
325              
326         } 
328         
329     },
330     populateMenuWithAnnotations: function (menu, registryEntry ) {
331         // remove all children
332         while(menu.hasChildNodes()){
333             menu.removeChild(menu.lastChild);}
335         if( registryEntry ) {
336             fireforg.jq( registryEntry ).children()
337             .each( 
338                   function () {
339                       //                  alert( "This: " + this);
340                       var headingJQ = fireforg.jq( this );
341                       var file = headingJQ.attr("file");
342                       var headingText = headingJQ.attr("text");
343                       var tags = headingJQ.attr("tags");
345                       var tmpItem = document.createElement("menuitem");
346                       tmpItem.setAttribute("class","fireforg-popupmenu");
347                       tmpItem.setAttribute("label", headingText + "  " + tags );
348                       tmpItem.setAttribute("onclick","fireforg.orgProtocolShowAnnotation(\"" + encodeURIComponent(file) + "\",\"" + encodeURIComponent(headingText) + "\",true)");
349                       menu.appendChild( tmpItem );
350                   });
352         }
353     },
354     // additional "itemDone" handler for Zoteros translator
355     // item : Zotero.item that has been processed
356     zoteroItemDoneHandler: function (item) {
358         alert("itemDoneHandler called with: \n" +
359               "type: " + Zotero.ItemTypes.getName(item.getType()) + "\n" + 
360               "title: " + item.getDisplayTitle(true) + "\n");
361         window.setTimeout( function () {
362                 var translatorObj = new Zotero.Translate("export"); // create Translator for export
363                 translatorObj.setItems( [ item ]);
364                 translatorObj.setTranslator( "9cb70025-a888-4a29-a210-93ec52da40d4" ); // set Translator to use the BibTex translator
365                 translatorObj.setHandler("done", fireforg._zoteroTranslationDone);
366                 // deinject runHandler to avoid recursion
367                 translatorObj.runHandler = translatorObj.fireforg_runHandler;
368                 translatorObj.translate(); }
369             , 2000);
371     
372     },
373     _zoteroTranslationDone: function (obj, worked) {
374         if( !worked )
375             alert("Fireforg: Zotero BibTex export failed!");
376         else {
377             alert("BibTex: " + obj.output.replace(/\r\n/g, "\n") );
378         }
379         // Send to org
381     }
385 window.addEventListener("load", function(e) { fireforg.onLoad(e); }, false);