1 /* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
\r
3 * Beagle Extension: Index webpages you visit using the Beagle Indexing Engine.
\r
4 * An Extension for the Firefox (and Mozilla?) Browser.
\r
7 // Initiate a new preference instance.
\r
8 var gPref = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
\r
9 var gEnv = Components.classes["@mozilla.org/process/environment;1"].getService(Components.interfaces.nsIEnvironment);
\r
11 // Load jslib parts used in file execution
\r
12 var gFile = new FileUtils();
\r
14 // Create the global variables
\r
15 var gBeagleRunStatus = 0;
\r
16 var gBeagleDataPath = gEnv.get("HOME") + "/.beagle/ToIndex";
\r
17 var gBeagleDataDir = new Dir(gBeagleDataPath);
\r
18 var gBeagleBestPath;
\r
20 function beagleFindFileInPath(filename)
\r
22 var path = gEnv.get("PATH");
\r
24 var split = path.split(':');
\r
26 while (idx < split.length) {
\r
27 var trypath = split[idx++] + '/' + filename;
\r
28 if (gFile.exists(trypath))
\r
35 function beagleInit()
\r
37 dump ("beagleInit started!\n");
\r
39 gBeagleBestPath = beagleFindFileInPath("beagle-search");
\r
41 dump ("beagleInit: Found beagle-search: " + gBeagleBestPath + "\n");
\r
43 // Create eventlistener to trigger when context menu is invoked.
\r
44 if (gBeagleBestPath) {
\r
46 document.getElementById('contentAreaContextMenu').addEventListener('popupshowing',
\r
54 // Get the global enable/disable pref
\r
55 try { bPref = gPref.getBoolPref('beagle.enabled'); }
\r
56 catch(e) { bPref = true }
\r
59 gBeagleRunStatus = 0;
\r
61 gBeagleRunStatus = -1;
\r
63 // Add listener for page loads
\r
64 if (document.getElementById("appcontent"))
\r
65 document.getElementById("appcontent").addEventListener("load",
\r
68 dump ("beagleInit : Listening to document['appcontent'].load\n");
\r
70 beagleUpdateStatus ();
\r
74 // Copied from nsIWebBrowserPersist.idl
\r
77 // Only use cached data (could fail)
\r
78 var PERSIST_FLAGS_FROM_CACHE = 1;
\r
79 // Replace existing files on the disk
\r
80 var PERSIST_FLAGS_REPLACE_EXISTING_FILES = 32;
\r
81 // Don't modify or add base tags
\r
82 var PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS = 64;
\r
83 // Don't make any adjustments to links
\r
84 var PERSIST_FLAGS_DONT_FIXUP_LINKS = 512;
\r
85 // Don't make any adjustments to filenames
\r
86 var PERSIST_FLAGS_DONT_CHANGE_FILENAMES = 2048;
\r
87 // Cleanup on failure
\r
88 var PERSIST_FLAGS_CLEANUP_ON_FAILURE = 8192;
\r
90 var PERSIST_MASK = (PERSIST_FLAGS_FROM_CACHE |
\r
91 PERSIST_FLAGS_REPLACE_EXISTING_FILES |
\r
92 PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS |
\r
93 PERSIST_FLAGS_DONT_FIXUP_LINKS |
\r
94 PERSIST_FLAGS_DONT_CHANGE_FILENAMES |
\r
95 PERSIST_FLAGS_CLEANUP_ON_FAILURE);
\r
98 var ENCODE_FLAGS_RAW = 4;
\r
99 // Convert links to absolute links where possible.
\r
100 var ENCODE_FLAGS_ABSOLUTE_LINKS = 128;
\r
102 var ENCODE_MASK = (ENCODE_FLAGS_RAW | ENCODE_FLAGS_ABSOLUTE_LINKS);
\r
104 function beagleWriteContent(page, tmpfilepath)
\r
106 var tmpfile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
\r
107 tmpfile.initWithPath(tmpfilepath);
\r
109 var persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
\r
110 persist.persistFlags = PERSIST_MASK;
\r
112 persist.saveDocument(page, tmpfile, null, null, ENCODE_MASK, 0);
\r
115 function beagleWriteMetadata(page, tmpfilepath)
\r
117 var tmpfile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
\r
118 tmpfile.initWithPath(tmpfilepath);
\r
120 var stream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
\r
121 stream.QueryInterface(Components.interfaces.nsIOutputStream);
\r
122 stream.init(tmpfile, 0x04 | 0x08 | 0x20, 0600, 0);
\r
127 line = page.location.href + "\n";
\r
128 stream.write(line, line.length);
\r
130 // Second line: Hit Type
\r
131 line = "WebHistory\n";
\r
132 stream.write(line, line.length);
\r
134 // Third line: Mime type
\r
135 line = "text/html\n";
\r
136 stream.write(line, line.length);
\r
138 // Additional lines: Properties
\r
139 line = "k:_unindexed:encoding=" + page.characterSet + "\n";
\r
140 stream.write(line, line.length);
\r
146 function beagleShouldIndex(page)
\r
148 // user disabled, or can't find beagle-index-url.
\r
149 if (gBeagleRunStatus == -1)
\r
154 page.location == 'about:blank' ||
\r
155 !page.location.href) {
\r
156 dump("beagleShouldIndex: strange page: " + page + "\n");
\r
161 fPref = gPref.getCharPref('beagle.security.filters');
\r
162 var filtered = fPref.split(';');
\r
163 for (j = 0; j < filtered.length; j++){
\r
164 if (page.location.host.search("/"+filtered[j]+"/i") != -1){
\r
165 dump("beagleShouldIndex: filtered host: " + page.location.host + '\n');
\r
166 gBeagleRunStatus = -2;
\r
167 beagleUpdateStatus ();
\r
175 if (page.location.protocol == "https:") {
\r
178 // secure content, check if user wants it indexed
\r
179 try { bPref = gPref.getBoolPref('beagle.security.active'); }
\r
180 catch(e) { bPref = false }
\r
183 // don't index. disable and return.
\r
184 gBeagleRunStatus = -2;
\r
185 beagleUpdateStatus ();
\r
188 } else if (gBeagleRunStatus == -2) {
\r
189 // no longer secure content, re-enable
\r
190 gBeagleRunStatus = 0;
\r
191 beagleUpdateStatus ();
\r
197 function beaglePageLoad(event)
\r
199 var page = event.originalTarget;
\r
201 if (!beagleShouldIndex (page))
\r
204 if (!gFile.exists (gEnv.get("HOME") + "/.beagle")) {
\r
205 dump("beaglePageLoad: ~/.beagle doesn't exist, not indexing");
\r
209 dump("beaglePageLoad: storing page: " + page.location.href + "\n");
\r
211 if (!gFile.exists(gBeagleDataPath)) {
\r
213 gBeagleDataDir.create ();
\r
214 dump ("beaglePageLoad: Created .beagle/firefox\n");
\r
216 dump ("beaglePageLoad: Unable to create .beagle/firefox: " + e + "\n");
\r
220 var hash = hex_md5(page.location.href);
\r
221 var tmpdatapath = gBeagleDataPath + "/firefox-beagle-" + hash + ".html";
\r
222 var tmpmetapath = gBeagleDataPath + "/.firefox-beagle-" + hash + ".html";
\r
225 beagleWriteContent(page, tmpdatapath);
\r
226 dump ("beaglePageLoad: beagleWriteContent sucessful!\n");
\r
227 beagleWriteMetadata(page, tmpmetapath);
\r
228 dump ("beaglePageLoad: beagleWriteMetadata sucessful!\n");
\r
230 alert ("beaglePageLoad: beagleWriteContent/Metadata failed: " + ex);
\r
234 function beagleRunBest(query)
\r
237 dump("Running best with query: "+ query + "\n");
\r
238 var retval = gFile.spawn(gBeagleBestPath, ["", query]);
\r
240 alert("Error running best: " + retval);
\r
242 alert("Caught error from best: " + e);
\r
246 function beagleShowPrefs()
\r
248 window.openDialog('chrome://beagle/content/beaglePrefs.xul',
\r
250 'chrome,modal=yes,resizable=no',
\r
254 function beagleProcessClick(event)
\r
256 // Right-click event.
\r
257 if (event.button == 2) {
\r
262 // Left-click event (also single click, like Mac).
\r
263 if (event.button == 0) {
\r
264 if (event.ctrlKey) {
\r
265 // Ctrl-click for Mac properties. Works on PC too.
\r
268 switch(gBeagleRunStatus) {
\r
270 // currently enabled. disable by user.
\r
271 gBeagleRunStatus = -1;
\r
272 gPref.setBoolPref('beagle.enabled', false);
\r
276 // currently disabled (by user or by secure content). enable.
\r
277 gBeagleRunStatus = 0;
\r
278 gPref.setBoolPref('beagle.enabled', true);
\r
281 // last run was an error, show the error
\r
282 alert("Error running Beagle Indexer: " + gBeagleRunStatus);
\r
286 beagleUpdateStatus();
\r
291 function beagleUpdateStatus()
\r
293 var icon = document.getElementById('beagle-notifier-status');
\r
295 switch(gBeagleRunStatus) {
\r
297 icon.setAttribute("status","000");
\r
298 icon.setAttribute("tooltiptext","Beagle indexing active. Click to disable.");
\r
300 case -1: // disabled by user
\r
301 case -2: // disabled for secure protocol
\r
302 icon.setAttribute("status","00f");
\r
303 icon.setAttribute("tooltiptext","Beagle indexing disabled. Click to enable.");
\r
305 default: // anything else is an error
\r
306 icon.setAttribute("status","f00");
\r
307 icon.setAttribute("tooltiptext",
\r
308 "Error while indexing: " + gBeagleRunStatus);
\r
313 // Create event listener.
\r
314 window.addEventListener('load', beagleInit, false);
\r
316 // Right-click context menu
\r
317 function beagleContext()
\r
321 // Find context menu display preference.
\r
322 try { bPref = gPref.getBoolPref('beagle.context.active'); }
\r
325 // Set hidden property of context menu and separators.
\r
326 document.getElementById('beagle-context-menu').hidden = !(bPref);
\r
327 document.getElementById('beagle-context-sep-a').hidden = !(bPref);
\r
328 document.getElementById('beagle-context-sep-b').hidden = !(bPref);
\r
330 // If not displaying context menu, return.
\r
331 if (!bPref) return;
\r
333 // Separator A (top) display preference.
\r
334 try { bPref = gPref.getBoolPref('beagle.context.sep.a'); }
\r
335 catch(e) { bPref = false }
\r
336 document.getElementById('beagle-context-sep-a').hidden = !(bPref);
\r
338 // Separator B (bottom) display preference.
\r
339 try { bPref = gPref.getBoolPref('beagle.context.sep.b'); }
\r
340 catch(e) { bPref = false }
\r
341 document.getElementById('beagle-context-sep-b').hidden = !(bPref);
\r
343 // Should search link item be hidden or shown?
\r
344 document.getElementById('beagle-context-search-link').hidden = !(gContextMenu.onLink);
\r
346 // Should text search item be hidden or shown?
\r
347 document.getElementById('beagle-context-search-text').hidden = !(gContextMenu.isTextSelected);
\r
348 document.getElementById('beagle-context-search-text').setAttribute("label","Search for \"" + gContextMenu.searchSelected() + "\"");
\r