Index: lib/main.js |
=================================================================== |
--- a/lib/main.js |
+++ b/lib/main.js |
@@ -4,89 +4,277 @@ |
* http://mozilla.org/MPL/2.0/. |
*/ |
-Cu.import("resource://gre/modules/Services.jsm"); |
+dump( "--------\n" ); |
-let {WindowObserver} = require("windowObserver"); |
+Cu.import( "resource://gre/modules/Services.jsm" ); |
+let {WindowObserver} = require( "windowObserver" ); |
+let { Application_Session } = require( "application" ); |
+let { Bootstrap_XPCOM } = require( "bootstrap_xpcom" ); |
+let { Command_Line } = require( "command_line" ); |
+dump( "main.js: all require() finished\n" ); |
+ |
+//------------------------------------------------------- |
+// Main |
+//------------------------------------------------------- |
+ |
+var Main = new Bootstrap_XPCOM.Singleton_class( |
+ "ABP Crawler - Main", |
+ Components.ID( "{7beffb8d-13e4-472c-9623-e3f3d7f37383}" ), |
+ "@adblockplus.org/abpcrawler/main;1", |
+ [ Ci.nsIObserver ], |
+ [] ); |
+ |
+Main.observe = function( subject, topic, data ) |
+{ |
+ dump( "Main.observe: topic = " + topic + ( data ? ", data = " + data : "" ) + "\n" ); |
+ switch ( topic ) |
+ { |
+ case "profile-before-change": |
+ this.remove_observation_topic( topic ); |
+ break; |
+ } |
+}; |
+ |
+/** |
+ * Startup function. |
+ * |
+ * Strictly speaking this is only the startup function for automatic sessions at this time. The interactive version |
+ * will already have initialized below. |
+ */ |
+Main.startup = function() |
+{ |
+ dump( "Main/startup: invoked.\n" ); |
+ |
+ if ( !( "flags" in Command_Line ) ) |
+ { |
+ throw new Error( "No flags found in Command_Line.\n" ); |
+ } |
+ var flags = Command_Line.flags; |
+ if ( !( "abpcrawler" in flags ) || !flags.abpcrawler ) |
+ { |
+ // No session for us. |
+ return; |
+ } |
+ /* |
+ * There was a command line argument that ordered an automatic run. Here we check the arguments for validity, |
+ * create an Application_Session, and start it running. |
+ */ |
+ var session = make_session( flags ); |
+ if ( !session ) |
+ { |
+ // Error messages were already generated in make_session. |
+ return; |
+ } |
+ if ( !session.window ) |
+ { |
+ dump( "Main: session does not have a window. Aborted.\n" ); |
+ return; |
+ } |
+ this.session = session; |
+ /* |
+ * At this point we have a session and its window, but the window may not be initialized. So what we have to do is |
+ * to wait for the window to show up. |
+ */ |
+ this.ready_listener = this.ready.bind( this ); |
+ session.window.addEventListener( "load", this.ready_listener ); |
+ // This action should really have a timeout attached to it. |
+ dump( "Main/startup: waiting for window load.\n"); |
+}; |
+ |
+/** |
+ * Launch the session when we're fully ready and have a window object. |
+ */ |
+Main.ready = function() |
+{ |
+ if ( !this.session.window.gBrowser ) |
+ { |
+ dump( "Main/ready: session window does not have a 'gBrowser' member.\n" ); |
+ this.session.window.close(); |
+ this.session.close(); |
+ return; |
+ } |
+ this.session.window.removeEventListener( "load", this.ready_listener ); |
+ this.ready_listener = null; |
+ |
+ dump( "Main: running session.\n" ); |
+ try |
+ { |
+ this.session.run( this.done.bind( this ) ); |
+ } |
+ catch ( e ) |
+ { |
+ dump( "Main: unexpected error running session = " + e.message + "\n" ); |
+ this.done(); |
+ } |
+}; |
+ |
+Main.done = function() |
+{ |
+ if ( this.session ) |
+ { |
+ /* |
+ * We have responsibility for the window, since we created it. |
+ */ |
+ if ( this.session.window ) |
+ { |
+ this.session.window.close(); |
+ } |
+ this.session.close(); |
+ } |
+}; |
+ |
+/* |
+ * Initialize the Main object. It's built individually, so this is code that would otherwise be in a constructor. |
+ */ |
+try |
+{ |
+ Main.init(); |
+ Main.add_observation_topic( "profile-before-change" ); |
+ Command_Line.set_startup_hook( Main.startup.bind( Main ) ); |
+} |
+catch ( e ) |
+{ |
+ dump( "main.js: Unexpected exception in Main.init(): " + e.message ); |
+} |
+ |
+//------------------------------------------------------- |
+// Automatic |
+//------------------------------------------------------- |
+function make_session( flags ) |
+{ |
+ /* |
+ * Check that the flags are syntactically correct. |
+ */ |
+ if ( !( "input_file" in flags ) ) |
+ { |
+ dump( "abpcrawler: Missing flag '-input_file'.\n" ); |
+ return null; |
+ } |
+ if ( !( "output_dir" in flags ) ) |
+ { |
+ dump( "abpcrawler: Missing flag '-output_dir'.\n" ); |
+ return null; |
+ } |
+ /* |
+ * Provide defaults for any absent flags. |
+ */ |
+ var max_tabs = ( "max_tabs" in flags ) ? flags.max_tabs : 5; |
+ var base_name = ( "output_base" in flags ) ? flags.output_base : "crawl_results"; |
+ /* |
+ * At this point all the syntax of the arguments is valid. Now we create the actual resources used. |
+ */ |
+ var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].getService( Ci.nsIWindowWatcher ); |
+ var window = ww.openWindow( null, "chrome://browser/content/", "abpcrawler_main", null, null ); |
+ /* |
+ * 5 minute timeout |
+ */ |
+ var session = new Application_Session( window, false, max_tabs, 300000, null ); |
+ try |
+ { |
+ session.set_input_file( flags.input_file ); |
+ session.add_output_file( flags.output_dir, base_name, true, "JSON" ); |
+ } |
+ catch ( e ) |
+ { |
+ dump( "abpcrawler: " + e.message + "\n" ); |
+ return null; |
+ } |
+ return session; |
+} |
+ |
+//------------------------------------------------------- |
+// Setup |
+//------------------------------------------------------- |
let knownWindowTypes = |
{ |
"navigator:browser": true, |
__proto__: null |
}; |
-new WindowObserver({ |
- applyToWindow: function(window) |
+/* |
+ * We initialize the interactive version, which means hooking into the menu. |
+ * |
+ * At this time, we're doing this regardless of whether we actual need an interactive session. Later, we may initialize |
+ * differently or not at all if we're only running an automatic session. |
+ */ |
+new WindowObserver( { |
+ applyToWindow: function( window ) |
{ |
- let type = window.document.documentElement.getAttribute("windowtype"); |
- if (!(type in knownWindowTypes)) |
+ let type = window.document.documentElement.getAttribute( "windowtype" ); |
+ if ( !(type in knownWindowTypes) ) |
return; |
- window.addEventListener("popupshowing", popupShowingHandler, false); |
- window.addEventListener("popuphidden", popupHiddenHandler, false); |
+ window.addEventListener( "popupshowing", popupShowingHandler, false ); |
+ window.addEventListener( "popuphidden", popupHiddenHandler, false ); |
}, |
- removeFromWindow: function(window) |
+ removeFromWindow: function( window ) |
{ |
- let type = window.document.documentElement.getAttribute("windowtype"); |
- if (!(type in knownWindowTypes)) |
+ let type = window.document.documentElement.getAttribute( "windowtype" ); |
+ if ( !(type in knownWindowTypes) ) |
return; |
- window.removeEventListener("popupshowing", popupShowingHandler, false); |
- window.removeEventListener("popuphidden", popupHiddenHandler, false); |
+ window.removeEventListener( "popupshowing", popupShowingHandler, false ); |
+ window.removeEventListener( "popuphidden", popupHiddenHandler, false ); |
} |
-}); |
+} ); |
+ |
+//------------------------------------------------------- |
+// Interactive |
+//------------------------------------------------------- |
function getMenuItem() |
{ |
// Randomize URI to work around bug 719376 |
- let stringBundle = Services.strings.createBundle("chrome://abpcrawler/locale/global.properties?" + Math.random()); |
- let result = [stringBundle.GetStringFromName("crawler.label")]; |
+ let stringBundle = Services.strings.createBundle( "chrome://abpcrawler/locale/global.properties?" + Math.random() ); |
+ let result = [stringBundle.GetStringFromName( "crawler.label" )]; |
getMenuItem = function() result; |
return getMenuItem(); |
} |
-function popupShowingHandler(event) |
+function popupShowingHandler( event ) |
{ |
let popup = event.target; |
- if (!/^(abp-(?:toolbar|status|menuitem)-)popup$/.test(popup.id)) |
+ if ( !/^(abp-(?:toolbar|status|menuitem)-)popup$/.test( popup.id ) ) |
return; |
- popupHiddenHandler(event); |
+ popupHiddenHandler( event ); |
let [label] = getMenuItem(); |
- let item = popup.ownerDocument.createElement("menuitem"); |
- item.setAttribute("label", label); |
- item.setAttribute("class", "abpcrawler-item"); |
+ let item = popup.ownerDocument.createElement( "menuitem" ); |
+ item.setAttribute( "label", label ); |
+ item.setAttribute( "class", "abpcrawler-item" ); |
- item.addEventListener("command", popupCommandHandler, false); |
+ item.addEventListener( "command", popupCommandHandler, false ); |
let insertBefore = null; |
- for (let child = popup.firstChild; child; child = child.nextSibling) |
- if (/-options$/.test(child.id)) |
+ for ( let child = popup.firstChild ; child ; child = child.nextSibling ) |
+ if ( /-options$/.test( child.id ) ) |
insertBefore = child; |
- popup.insertBefore(item, insertBefore); |
+ popup.insertBefore( item, insertBefore ); |
} |
-function popupHiddenHandler(event) |
+function popupHiddenHandler( event ) |
{ |
let popup = event.target; |
- if (!/^(abp-(?:toolbar|status|menuitem)-)popup$/.test(popup.id)) |
+ if ( !/^(abp-(?:toolbar|status|menuitem)-)popup$/.test( popup.id ) ) |
return; |
- let items = popup.getElementsByClassName("abpcrawler-item"); |
- while (items.length) |
- items[0].parentNode.removeChild(items[0]); |
+ let items = popup.getElementsByClassName( "abpcrawler-item" ); |
+ while ( items.length ) |
+ items[0].parentNode.removeChild( items[0] ); |
} |
-function popupCommandHandler(event) |
+function popupCommandHandler( event ) |
{ |
- if (!("@adblockplus.org/abp/public;1" in Cc)) |
+ if ( !("@adblockplus.org/abp/public;1" in Cc) ) |
return; |
- let crawlerWnd = Services.wm.getMostRecentWindow("abpcrawler:crawl"); |
- if (crawlerWnd) |
+ let crawlerWnd = Services.wm.getMostRecentWindow( "abpcrawler:crawl" ); |
+ if ( crawlerWnd ) |
crawlerWnd.focus(); |
else |
- event.target.ownerDocument.defaultView.openDialog("chrome://abpcrawler/content/crawler.xul", "_blank", "chrome,centerscreen,resizable,dialog=no"); |
+ event.target.ownerDocument.defaultView.openDialog( "chrome://abpcrawler/content/crawler.xul", "_blank", "chrome,centerscreen,resizable,dialog=no" ); |
} |