Added missing stream.close
[org-fireforg.git] / fireforg / content / overlay.js
blobbae315158371825820668e029c2460b97f0d0707
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         var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
199         // init variables
200         fireforg.timeout = window.setTimeout("",10);
201         fireforg.timeoutCount = 0;
203         // add onclick event handler for status bar icon
204         document.getElementById("fireforg_spi").onclick = fireforg.onStatusbarIconClicked;
206         // add appcontent hook
207         var appcontent = window.document.getElementById("appcontent");
208         appcontent.addEventListener("DOMContentLoaded", fireforg.onLoadSite, false);
209         appcontent.addEventListener("DOMContentLoaded", fireforg.onUrlSwitch, false);
211         // add tab change listener
212         var container = gBrowser.tabContainer;
213         container.addEventListener("TabSelect", fireforg.onUrlSwitch, false);
215         // try to listen to url changes. Found this somewhere on the web. Doesn't work.
216         /*var wnd = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
217         .getInterface(Components.interfaces.nsIWebNavigation)
218         .QueryInterface(Components.interfaces.nsIDocShell)
219         .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
220         .getInterface(Components.interfaces.nsIURIContentListener);
221         wnd.parentContentListener = fireforg.onUrlSwitch; 
222         */
223         // document.getElementById('urlbar').onchange = fireforg.onUrlSwitch;
225         this.initialized = true;
226         this.strings = document.getElementById("fireforg-strings");
228         if( prefManager.getBoolPref("extensions.fireforg.injectZotero") )        
229             window.setTimeout( fireforg.injectZoteroAccordingToPref ,5000);
230         
232     },
233     onStatusbarIconClicked: function (ev) {
234         if( ev.button == 0 )
235             fireforg.showLinkListPopup();
236         else {
237             document.getElementById('fireforg_popup_menu').openPopup( document.getElementById("fireforg_spi"),"before_end",0,0,false,null);
238         }           
239     },
240     showLinkListPopup: function () {
241    
242         if( fireforg.currentLinkRegistryEntry ) {
243            var popupMenu = document.getElementById('fireforg_popup_dynamic');
244                 
245            fireforg.populateMenuWithAnnotations( popupMenu, fireforg.currentLinkRegistryEntry );
246            
247             popupMenu.openPopup( document.getElementById("fireforg_spi"),"before_end",0,0,false,null);
249         }
250     },
251     orgProtocolAcknowledgeResponse: function (id) {
252         fireforg.orgProtocolSendURL("fireforg-acknowledge://" + encodeURIComponent(id));
253     },
254     orgProtocolShowAnnotation: function (file, heading, encoded) {
255         
256         if( !encoded ) {
257             file = encodeURIComponent( file );
258             heading = encodeURIComponent( heading ); }
259         fireforg.orgProtocolSendURL("fireforg-show-annotation://" + file + "/" + heading);
260     },
261     setStatusBarIconNormal: function (matches) {
262         
263         if( matches == 0 ) {
264           document.getElementById('fireforg_spi_image').setAttribute("src","chrome://fireforg/skin/org-mode-unicorn_16.png");
265           document.getElementById('fireforg_spi_label').setAttribute("value","");
266         } else {
267           document.getElementById('fireforg_spi_image').setAttribute("src","chrome://fireforg/skin/org-mode-unicorn_16_highlighted.png");
268           document.getElementById('fireforg_spi_label').setAttribute("value","(" + matches + ")");
269         }
270     },
271     setStatusBarIconError: function () {
272         document.getElementById('fireforg_spi_label').setAttribute("value","Error");
273         document.getElementById('fireforg_spi_label_tags').setAttribute("value","");
274     },
275     setStatusBarWaiting: function () {
276         document.getElementById('fireforg_spi_label').setAttribute("value","...");
277         document.getElementById('fireforg_spi_label_tags').setAttribute("value","");
278     },
279     setStatusBarTags: function (tagString) {
280         document.getElementById('fireforg_spi_label_tags').setAttribute("value",tagString);
281     },
282     orgProtocolStoreLink: function () {
283         fireforg.orgProtocolSendURL("store-link://" + encodeURIComponent(window.content.document.URL) + "/" + encodeURIComponent(document.title));
284     },
285     orgProtocolRemember: function () {
286         fireforg.orgProtocolSendURL("remember://" + encodeURIComponent(window.content.document.URL) + "/" + encodeURIComponent(document.title) + "/" + encodeURIComponent(window.getSelection()));
287     },
288     orgProtocolSendURL: function (url) {
289         var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
290         
291         if( prefManager.getBoolPref("extensions.fireforg.macWorkaround") ) { // Workaround
292             var tmpFileName = prefManager.getCharPref("extensions.fireforg.macWorkaroundFile");
293             var file = Components.classes["@mozilla.org/file/local;1"]
294                 .createInstance(Components.interfaces.nsILocalFile);
295             file.initWithPath( tmpFileName );
296             if(file.exists() == false) {
297                 file.create( Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 420);
298             }
300             var stream = Components.classes["@mozilla.org/network/file-output-stream;1"]
301                 .createInstance(Components.interfaces.nsIFileOutputStream);
303             stream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);
304             var finalString = "org-protocol://" + url;
305             stream.write( finalString, finalString.length);
306             stream.close();
308         } else {
309             var req = new XMLHttpRequest();
310             try {
311                 req.open('POST', "org-protocol://" + url,true);
312                 req.send(null);
313             } catch (ex) { }
314         }
315     },
316     contextMenuItemShowing: function (e) {
317         //        alert("ContextMenuItemShowing");
319         var contextMenuEntry = document.getElementById('fireforg_ctx_menu_fireforg_popup');                
321         // remove all children
322         while(contextMenuEntry.hasChildNodes()){
323             contextMenuEntry.removeChild(contextMenuEntry.lastChild);}
325         if( gContextMenu.onLink ) {
326             var url = gContextMenu.link;
328             var registryEntry = fireforg.getRegistryEntryForLink( url );
330             fireforg.populateMenuWithAnnotations( contextMenuEntry, registryEntry );
331              
332         } 
334         
335     },
336     populateMenuWithAnnotations: function (menu, registryEntry ) {
337         // remove all children
338         while(menu.hasChildNodes()){
339             menu.removeChild(menu.lastChild);}
341         if( registryEntry ) {
342             fireforg.jq( registryEntry ).children()
343             .each( 
344                   function () {
345                       //                  alert( "This: " + this);
346                       var headingJQ = fireforg.jq( this );
347                       var file = headingJQ.attr("file");
348                       var headingText = headingJQ.attr("text");
349                       var tags = headingJQ.attr("tags");
351                       var tmpItem = document.createElement("menuitem");
352                       tmpItem.setAttribute("class","fireforg-popupmenu");
353                       tmpItem.setAttribute("label", headingText + "  " + tags );
354                       tmpItem.setAttribute("onclick","fireforg.orgProtocolShowAnnotation(\"" + encodeURIComponent(file) + "\",\"" + encodeURIComponent(headingText) + "\",true)");
355                       menu.appendChild( tmpItem );
356                   });
358         }
359     },
361     injectZoteroAccordingToPref: function () {
362         var prefManager = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
363         if( prefManager.getBoolPref("extensions.fireforg.injectZotero") ) {
364             if( Zotero.Translate ) {
365                 if( !Zotero.Translate.prototype.fireforg_runHandler ) {
366                     Zotero.Translate.prototype.fireforg_runHandler = Zotero.Translate.prototype.runHandler;
367                     Zotero.Translate.prototype.runHandler = function(type, argument) {
368                         if( type == "itemDone") {
369                             fireforg.zoteroItemDoneHandler( argument );
370                         }
371                         return this.fireforg_runHandler(type, argument);
372                     }
373                     //  alert("Zotero translator handler injected.");
374                 }
375             }
376         } else { // remove injection
377             if( Zotero.Translate() ) {
378                 if( Zotero.Translate.prototype.fireforg_runHandler ) {
379                     Zotero.Translate.prototype.runHandler = Zoter.Translate.prototype.fireforg_runHandler;
380                     //alert("Zotero injection removed");
381                 }
382             }
383         }
384     },
385     // additional "itemDone" handler for Zoteros translator
386     // item : Zotero.item that has been processed
387     zoteroItemDoneHandler: function (item) {
389         /*alert("itemDoneHandler called with: \n" +
390           "type: " + Zotero.ItemTypes.getName(item.getType()) + "\n" + 
391           "title: " + item.getDisplayTitle(true) + "\n");*/
392         window.setTimeout( function () {
393                 //alert( "item.attachments : " + item.getAttachments());
395                 var translatorObj = new Zotero.Translate("export"); // create Translator for export
396                 translatorObj.setItems( [ item ]);
397                 translatorObj.setTranslator( "9cb70025-a888-4a29-a210-93ec52da40d4" ); // set Translator to use the BibTex translator
398                 translatorObj.setHandler("done", fireforg._zoteroTranslationDone);
399                 // deinject runHandler to avoid recursion
400                 translatorObj.runHandler = translatorObj.fireforg_runHandler;
401                 translatorObj.translate(); }
402             , 2000);
404     
405     },
406     _zoteroTranslationDone: function (obj, worked) {
407         if( !worked )
408             alert("Fireforg: Zotero BibTex export failed!");
409         else {
410             var bibtex =  obj.output.replace(/\r\n/g, "\n");
411             //alert("BibTex: " + bibtex );
412             
413             // Send to org
414             fireforg.orgProtocolSendURL("fireforg-bibtex-entry://" + encodeURIComponent( bibtex ) ); 
415         }
416     }
420 window.addEventListener("load", function(e) { fireforg.onLoad(e); }, false);