home *** CD-ROM | disk | FTP | other *** search
/ Australian Personal Computer 2004 September / APC0409D1.iso / f_looks / files / adblock-0.5-dev.xpi / chrome / adblock.jar / content / component.js < prev    next >
Encoding:
Text File  |  2004-06-27  |  42.7 KB  |  969 lines

  1. /*
  2. ** authored by Wladimir and rue
  3. */
  4.  
  5.  
  6. /*
  7.  * Constants / Globals
  8.  */
  9.  
  10. const ADBLOCK_CONTRACTID = "@mozilla.org/adblock;1";
  11. const ADBLOCK_CID = Components.ID('{34274bf4-1d97-a289-e984-17e546307e4f}');
  12.  
  13. const CONTENTPOLICY_CONTRACTID = "@mozilla.org/layout/content-policy;1";
  14. const CONTENTPOLICY_DESCRIPTION = "Content policy service";
  15.  
  16. const PREFSERVICE_CONTRACTID = "@mozilla.org/preferences-service;1";
  17. const STDURL_CONTRACTID = "@mozilla.org/network/standard-url;1";
  18. const DIRSERVICE_CONTRACTID = '@mozilla.org/file/directory_service;1';
  19.  
  20. var SubScriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].createInstance(Components.interfaces.mozIJSSubScriptLoader);
  21.  
  22. var origComponent = null;
  23. var origContentPolicy = null;
  24. var apiConstants = new Object(); // handle old + new api constants
  25. var blockTypes = [];            // blockable content-policy types
  26. var blockSchemes = [];            // blockable content-policy schemes
  27. var exceptionTypes = [];        // unblocked content-policy types
  28. var exceptionNames = [];        // unblocked node names
  29. var linkTypes = [];                // link-blockable content-policy types
  30. var linkSchemes = [];            // link-blockable href-protocols
  31. var baseTypes = [];                // unalterable content-policy types
  32. var baseNames = [];                // unalterable node names
  33. var frameCounter = 0;            // counter for "unique" obj-tab names
  34.  
  35. var isEnabled = false;
  36. var linkCheck = false;            // pref: check parent-links for img / obj's
  37. var pageBlock = false;            // pref: allow page-blocking
  38. var removeAds = false;
  39. var fastCollapse = false;
  40. var frameObjects = false;
  41. var patterns = [];
  42.  
  43.  
  44. /*
  45.  * Content policy class definition
  46.  */
  47.  
  48. var policy = {
  49.     // nsIContentPolicy interface implementation
  50.     shouldLoad: function(contentType, contentLocation, requestOrigin, requestingNode, mimeTypeGuess, extra) {
  51.  
  52.          // if it's an unblockable-type, or unknown-scheme, return the normal policy
  53.         if ( !blockTypes[contentType] || !blockSchemes[contentLocation.scheme]
  54.                 /*|| ( exceptionTypes[contentType] && exceptionNames[context.nodeName.toLowerCase()] )*/ // applets are back -!
  55.             )
  56.             return origContentPolicy ?
  57.                     origContentPolicy.shouldLoad(contentType, contentLocation, requestOrigin, requestingNode, mimeTypeGuess, extra) 
  58.                     : 
  59.                     apiConstants.ACCEPT;
  60.  
  61.          // handle old api
  62.          if (apiConstants.oldStyleAPI) {     // bool is set by adblockInit()
  63.              var context = requestOrigin;     // oldStyleAPI @params: function(contentType, contentLocation, context, wnd)
  64.              var wnd = requestingNode; /*requestOrigin=false, requestingNode=false, mimeTypeGuess=false;*/ }
  65.          else {
  66.              if (requestingNode) // moronically, this argument is now "optional"
  67.                  wnd = requestingNode.defaultView || (requestingNode.ownerDocument ? requestingNode.ownerDocument.defaultView : null);
  68.              context = requestingNode; }
  69.          
  70.         if (isEnabled) {
  71.             var filterMatch = null;
  72.     
  73.             // if we've already checked this url, use the prior result -- filter-cache
  74.             if (wnd && typeof(wnd.top._AdblockFiltered)!='undefined' && typeof(wnd.top._AdblockFiltered[contentLocation.spec]!='undefined'))
  75.                 filterMatch = wnd.top._AdblockFiltered[contentLocation.spec];
  76.             // if any containing-link matches a filter..
  77.             if (filterMatch == null && context && wnd && linkCheck && linkTypes[contentType]) filterMatch = checkLinks(contentType, contentLocation, context, wnd);
  78.             // if we didn't match a link, check the element's source
  79.             if (filterMatch == null) filterMatch = isBlocked(contentLocation); // store the matching filter, or null
  80.  
  81.             if (filterMatch) {
  82.  
  83.                     // special handling for documents
  84.                     if (contentType == apiConstants.DOCUMENT) {
  85.                         // we'll have to comb through the windows+tabs manually, now; looking for this unloaded URI
  86.                         if (pageBlock) { if (apiConstants.oldStyleAPI) adblockPageBlock(filterMatch, contentLocation, wnd); } // if page-block is enabled, write a message and stop.
  87.                         else return apiConstants.ACCEPT; } // no need to continue if the page will load (it would only add us to the adblockable-listing)
  88.  
  89.                     // filter-cache
  90.                     if (wnd) {
  91.                         if (typeof(wnd.top._AdblockFiltered) == 'undefined') wnd.top._AdblockFiltered = []; // create the "filtered" asc-array
  92.                         if (typeof(wnd.top._AdblockFiltered) == 'object' && !wnd.top._AdblockFiltered[contentLocation.spec]) // some (whack) sites dont allow proper access to wnd.top
  93.                             wnd.top._AdblockFiltered[contentLocation.spec] = filterMatch; } // add the matched url to our filtered-cache
  94.                     
  95.                     var node = elementInterface(contentType, context, wnd);
  96.                     
  97.                     if (node) {
  98.                         // metadata
  99.                         storeAdblockData(node, contentLocation, contentType, filterMatch);
  100.         
  101.                         // special handling for applets -- disables by specifying a default class
  102.                         if (node.nodeName.toLowerCase() == "applet") {
  103.                             node.setAttribute("AdblockCode", node.getAttribute("code")); // save the original code attribute
  104.                             node.setAttribute("code", "java.applet.Applet"); // this is a default class, which does nothing
  105.                             if (node.hasAttribute("AdblockFrameName"))
  106.                                 node.ownerDocument.getElementById(node.getAttribute("AdblockFrameName")).style.visibility = 'hidden'; }// hide tab-frame -- applets
  107.                         
  108.                         // hide overlay / frame -- on filter-dialog "refiltration" -- not applets, though
  109.                         else {
  110.                             if (typeof(node._AdblockOverlay) != 'undefined' && node._AdblockOverlay.style.visibility != 'hidden')
  111.                                 node._AdblockOverlay.style.visibility = 'hidden'; // hide flash-overlay
  112.                             if (typeof(node._AdblockFrame) != 'undefined')
  113.                                 node._AdblockFrame.style.visibility = 'hidden'; } // hide tab-frame -- objects
  114.         
  115.                         // if it's not a base-element
  116.                         if ( ! (baseTypes[contentType] && baseNames[node.nodeName.toLowerCase()] )) {
  117.                             var immediate = apiConstants.oldStyleAPI ? (node._AdblockImmediate) : (mimeTypeGuess == apiConstants.IMMEDIATE); // (extra instanceof Components.interfaces.nsISupports)
  118.                             if (removeAds) adblockRemoveFast(node, wnd, immediate); // ..and we're set to 'remove', collapse the node.
  119.                             else adblockHide(node, wnd, immediate); } // ..otherwise, hide it
  120.                     }
  121.     
  122.                 var loadNode = removeAds ? apiConstants.REJECT_REQUEST : apiConstants.ACCEPT;
  123.                 return loadNode; // bool: "shouldload" node?
  124.             }
  125.             //  node wasn't blocked -- update filter-cache
  126.             if (wnd) {
  127.                 if (typeof(wnd.top._AdblockFiltered) == 'undefined') wnd.top._AdblockFiltered = []; // create the "filtered" asc-array
  128.                 if (typeof(wnd.top._AdblockFiltered) == 'object') wnd.top._AdblockFiltered[contentLocation.spec] = false; } // add the unblocked url to our filtered-cache --  ps: some (whack) sites dont allow proper access to wnd.top
  129.         }
  130.  
  131.         // either the node wasn't blocked OR we're not enabled:
  132.         // -- check original policy, and then object-frame addition..
  133.         loadNode = origContentPolicy ? // apiConstants.notReal isn't defined, allowing us to selectively pass "undefined" if we want
  134.                     origContentPolicy.shouldLoad(contentType, contentLocation, requestOrigin, requestingNode, mimeTypeGuess, extra) 
  135.                     : 
  136.                     apiConstants.ACCEPT;
  137.         if (loadNode == apiConstants.ACCEPT && contentType != apiConstants.DOCUMENT) { // ..not for Documents, though!
  138.             node = elementInterface(contentType, context, wnd); // 'node' declared prior
  139.             
  140.             if (node) {
  141.                 // store filtering-metadata
  142.                 storeAdblockData(node, contentLocation, contentType, null);
  143.                 // if we're set to, add a frame to all applets + objects + raw-embeds
  144.                 node = elementInterface(contentType, context, wnd);
  145.                 if (isEnabled && frameObjects 
  146.                         && (contentType == apiConstants.OBJECT || /embed/.test(node.nodeName.toLowerCase()) ) // objects *and* raw-embeds
  147.                         && contentLocation.spec != node.ownerDocument.URL ) // it's not a standalone object
  148.                     makeObjectFrame(node, contentType, contentLocation, wnd); // add frame
  149.             }
  150.         
  151.         }
  152.         return loadNode;
  153.     },
  154.  
  155.     // this is now for urls that directly load media, and meta-refreshes (before activation)
  156.     shouldProcess: function(contentType, contentLocation, requestOrigin, requestingNode, mimeType, extra) {
  157.          /* If + When the time comes... we're ready:
  158.          // handle old api
  159.          if (apiConstants.oldStyleAPI) {     // bool is set by adblockInit()
  160.              var context = requestOrigin;     // oldStyleAPI @params: function(contentType, contentLocation, context, wnd)
  161.              var wnd = requestingNode; }
  162.          else {
  163.              wnd = requestingNode.ownerDocument.defaultView;
  164.              context = requestingNode; } */
  165.         return origContentPolicy ? 
  166.                     origContentPolicy.shouldProcess(contentType, contentLocation, requestOrigin, requestingNode, mimeType, extra) 
  167.                     : 
  168.                     apiConstants.ACCEPT;
  169.     },
  170.  
  171.     // nsISupports interface implementation
  172.     QueryInterface: function(iid) {
  173.         if (!iid.equals(Components.interfaces.nsISupports) &&
  174.             !iid.equals(Components.interfaces.nsIContentPolicy))
  175.         {
  176.             if (origComponent)
  177.                 return origComponent.QueryInterface(iid);
  178.             else
  179.                 throw Components.results.NS_ERROR_NO_INTERFACE;
  180.         }
  181.  
  182.         return this;
  183.     }
  184. };
  185.  
  186. // Factory object
  187. var factory =
  188. {
  189.     // nsIFactory interface implementation
  190.      createInstance: function(outer, iid) {
  191.         if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION;
  192.         return policy;
  193.     },
  194.  
  195.     // nsIObserver + nsIPrefBranchObserver interface implementation
  196.     observe: function(subject, topic, prefName) { 
  197.         // subject: [wrapped nsISupports :: nsIPrefBranch], nsIPrefBranchInternal
  198.         // topic: "changed"
  199.         
  200.         if (topic == "Adblock-SavePrefFile") {
  201.             var prefObj = Components.classes[PREFSERVICE_CONTRACTID].getService(Components.interfaces.nsIPrefService);
  202.             prefObj.savePrefFile(null); // save the prefs to disk
  203.             return; }
  204.         else if (topic == "Adblock-PrefChange" && prefName == "FilterChange") {
  205.             adblockLoadSettings(prefName); // reload -- with prefname
  206.             return; }
  207.         else if (topic == "Adblock-LoadAPIConstants") {
  208.             var appShell = Components.classes["@mozilla.org/appshell/appShellService;1"].getService(Components.interfaces.nsIAppShellService);
  209.             var hiddenWnd = appShell.hiddenDOMWindow; // global hidden-window
  210.             if (!hiddenWnd.apiConstants) hiddenWnd.apiConstants = apiConstants;
  211.             return; }
  212.         else {
  213.             var prefRe = /^adblock\.(?!observer|patterns)/; // reloads settings only on appropriate pref-change
  214.             if (prefRe.test(prefName)) adblockLoadSettings(prefName); } // reload -- with prefname
  215.  
  216.     },
  217.  
  218.     // nsISupports interface implementation
  219.     QueryInterface: function(iid) {
  220.         if (!iid.equals(Components.interfaces.nsISupports) &&
  221.             !iid.equals(Components.interfaces.nsISupportsWeakReference) &&
  222.             !iid.equals(Components.interfaces.nsIFactory) &&
  223.             !iid.equals(Components.interfaces.nsIObserver))
  224.         {
  225.             dump("Adblock content policy factory object: QI unknown interface: " + iid + "\n");
  226.             throw Components.results.NS_ERROR_NO_INTERFACE;
  227.         }
  228.  
  229.         return this;
  230.     }
  231. }
  232.  
  233.  
  234.  
  235. /*
  236.  * Core Routines
  237.  */
  238.  
  239. adblockInit(); // begin initialization
  240.  
  241. // Initialization and registration
  242. function adblockInit() {
  243.  
  244.     if (typeof(Components.classes[ADBLOCK_CONTRACTID]) == 'undefined') {
  245.     
  246.         // Saving original content policy
  247.         try {
  248.             origComponent = Components.classes[CONTENTPOLICY_CONTRACTID].getService();
  249.             origContentPolicy = origComponent.QueryInterface(Components.interfaces.nsIContentPolicy);
  250.         } catch (e) { dump("Adblock content policy init: exception when loading original content policy component: " + e + "\n"); }
  251.     
  252.         if (!origContentPolicy)
  253.             return;
  254.     
  255.         // Component registration
  256.         var compMgr = Components.manager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  257.         var cid = compMgr.contractIDToCID(CONTENTPOLICY_CONTRACTID);
  258.     
  259.         compMgr.registerFactory(cid, CONTENTPOLICY_DESCRIPTION, CONTENTPOLICY_CONTRACTID, factory);
  260.         compMgr.registerFactory(ADBLOCK_CID, CONTENTPOLICY_DESCRIPTION, ADBLOCK_CONTRACTID, factory);
  261.  
  262.     }
  263.  
  264.     // Standard Pref-observer registration
  265.     try {
  266.         var prefInternal = Components.classes[PREFSERVICE_CONTRACTID].getService(Components.interfaces.nsIPrefBranchInternal);
  267.         prefInternal.addObserver("adblock", factory, true);
  268.     } catch (e) { dump("Adblock content policy registration: exception when registering pref observer: " + e + "\n"); }
  269.  
  270.     // Custom Pref-observer registration
  271.     try {
  272.         var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  273.         observerService.addObserver(factory, "Adblock-PrefChange", true);
  274.         observerService.addObserver(factory, "Adblock-SavePrefFile", true);
  275.         observerService.addObserver(factory, "Adblock-LoadAPIConstants", true);
  276.     } catch (e) { dump("Adblock content policy registration: exception when registering saveprefs observer: " + e + "\n"); }
  277.  
  278.     // Variable initialization
  279.     
  280.     // content-policy api constants : old + new
  281.     apiConstants.oldStyleAPI = typeof(Components.interfaces.nsIContentPolicy.TYPE_DOCUMENT) == 'undefined';
  282.     apiConstants.UNIMPLEMENTED = -72591; // our own, custom value -- hopefully it remains available  ( -used by apiConstants.REFRESH)
  283.     apiConstants.OTHER =         Components.interfaces.nsIContentPolicy.OTHER         | Components.interfaces.nsIContentPolicy.TYPE_OTHER;
  284.     apiConstants.SCRIPT =         Components.interfaces.nsIContentPolicy.SCRIPT         | Components.interfaces.nsIContentPolicy.TYPE_SCRIPT;
  285.     apiConstants.IMAGE =         Components.interfaces.nsIContentPolicy.IMAGE         | Components.interfaces.nsIContentPolicy.TYPE_IMAGE;
  286.     apiConstants.STYLESHEET =     Components.interfaces.nsIContentPolicy.STYLESHEET     | Components.interfaces.nsIContentPolicy.TYPE_STYLESHEET;
  287.     apiConstants.OBJECT =         Components.interfaces.nsIContentPolicy.OBJECT         | Components.interfaces.nsIContentPolicy.TYPE_OBJECT;
  288.     apiConstants.DOCUMENT =     Components.interfaces.nsIContentPolicy.DOCUMENT     | Components.interfaces.nsIContentPolicy.TYPE_DOCUMENT;
  289.     apiConstants.SUBDOCUMENT =     Components.interfaces.nsIContentPolicy.SUBDOCUMENT     | Components.interfaces.nsIContentPolicy.TYPE_SUBDOCUMENT;
  290.     apiConstants.REFRESH =             apiConstants.oldStyleAPI ? apiConstants.UNIMPLEMENTED : Components.interfaces.nsIContentPolicy.TYPE_REFRESH; // new api ONLY :: shouldProcess() handles this
  291.     apiConstants.ACCEPT =             apiConstants.oldStyleAPI ? true  : Components.interfaces.nsIContentPolicy.ACCEPT;             // +1
  292.     apiConstants.REJECT_REQUEST =     apiConstants.oldStyleAPI ? false : Components.interfaces.nsIContentPolicy.REJECT_REQUEST;     // -1 -- unilateral rejection
  293.     apiConstants.REJECT_TYPE =         apiConstants.oldStyleAPI ? false : Components.interfaces.nsIContentPolicy.REJECT_TYPE;         // -2 -- rejected based solely on its type (of the above flags)
  294.     apiConstants.REJECT_SERVER =     apiConstants.oldStyleAPI ? false : Components.interfaces.nsIContentPolicy.REJECT_SERVER;     // -3 -- rejected based on hosting/requesting server (aContentLocation or aRequestOrigin)
  295.     apiConstants.REJECT_OTHER =     apiConstants.oldStyleAPI ? false : Components.interfaces.nsIContentPolicy.REJECT_OTHER;     // -4 -- maybe direct third-party callers to consult the "extra" param for additional details
  296.     apiConstants.IMMEDIATE = -73; // another custom value (smaller for speed) -- same hope
  297.     apiConstants.NULL = -92; // UNUSED: custom value
  298.     
  299.     // blockable types + schemes
  300.     blockTypes[apiConstants.UNIMPLEMENTED] = false; // DISABLED
  301.     blockTypes[apiConstants.SCRIPT] = true;
  302.     blockTypes[apiConstants.IMAGE] = true;
  303.     blockTypes[apiConstants.OBJECT] = true;
  304.     blockTypes[apiConstants.DOCUMENT] = true;
  305.     blockTypes[apiConstants.SUBDOCUMENT] = true;
  306.     blockSchemes["file"] = false;
  307.     blockSchemes["http"] = true;
  308.     blockSchemes["https"] = true;
  309.  
  310.     // unblocked types + nodeNames
  311.     exceptionTypes[apiConstants.OBJECT] = false; // DISABLED
  312.     exceptionNames["applet"] = false; // DISABLED
  313.  
  314.     // link-searchable types + href-protocols
  315.     linkTypes[apiConstants.IMAGE] = true;
  316.     linkTypes[apiConstants.OBJECT] = true;
  317.     linkSchemes["file:"] = false;
  318.     linkSchemes["http:"] = true;
  319.     linkSchemes["https:"] = true;
  320.     linkSchemes["javascript:"] = true;
  321.  
  322.     // unalterable content-policy types + nodeNames -- root-elements
  323.     baseTypes[apiConstants.IMAGE] = true;
  324.     baseTypes[apiConstants.DOCUMENT] = true;
  325.     baseTypes[apiConstants.SCRIPT] = true;
  326.     baseNames["html"] = true;
  327.     baseNames["body"] = true;
  328.     baseNames["script"] = true;
  329.  
  330.     // Temp-Dir Cleanup (for prior uninstalls) -- separate, in case there's no default profile, or the user isn't root
  331.     var dirArray = new Array();
  332.     dirArray[0] = "AChrom";     // app. chrome magic-key
  333.     dirArray[1] = "UChrm";         // profile chrome magic-key
  334.     dirArray[2] = "ProfD";         // profile directory magic-key
  335.     dirArray[3] = "ComsD";         // component directory magic-key
  336.     for (var i = 0, n ; i < dirArray.length ; i++) {
  337.         try { 
  338.             var dirService = Components.classes[DIRSERVICE_CONTRACTID].getService(Components.interfaces.nsIProperties);
  339.             var currentDir = dirService.get(dirArray[i], Components.interfaces.nsIFile);
  340.             var tempDir = currentDir.clone();
  341.             var uninstalledFile = currentDir.clone();
  342.             
  343.             tempDir.append("adblock-temp");
  344.             uninstalledFile.append("adblock-uninstalled");
  345.             n = 1;
  346.             
  347.             // remove temp-dir
  348.             if (tempDir.exists()) tempDir.remove(true);
  349.             
  350.             // remove installer-uninstalled files
  351.             while (uninstalledFile.exists()) {
  352.                 uninstalledFile.remove(true);
  353.                 uninstalledFile = currentDir.clone();
  354.                 uninstalledFile.append("adblock-uninstalled" + n);
  355.                 n++; }
  356.         } catch(e) { /*throw(e);*/ }
  357.     }
  358.  
  359.     // Load Settings
  360.     adblockLoadSettings("Init");
  361. }
  362.  
  363. // returns the queryInterface to a dom-object or frame / iframe -- for 'shouldload' policy-check
  364. function elementInterface(contentType, context, wnd) {
  365.     try {
  366.         if (!apiConstants.oldStyleAPI)
  367.             return context;
  368.         else if (contentType == apiConstants.SUBDOCUMENT)
  369.             return wnd.frameElement;
  370.         else if (contentType == apiConstants.DOCUMENT)
  371.             return wnd.document.documentElement
  372.         else 
  373.             return context.QueryInterface(Components.interfaces.nsIDOMElement);
  374.     } catch(e) { return context; }
  375. }
  376.  
  377. // stores adblock-metadata for an element
  378. function storeAdblockData(node, contentLocation, contentType, filterMatch) {
  379.     try { if (apiConstants.oldStyleAPI) node = node.QueryInterface(Components.interfaces.nsIDOMElement); } // this totally mangles the new API
  380.     catch(e) {}
  381.     try {
  382.         // special handling for UNLOADED or blocked applets
  383.         if (node.nodeName.toLowerCase() == "applet" && (node.hasAttribute("AdblockData") || !filterMatch) ) { // loaded or unmatched
  384.             if (!node.hasAttribute("AdblockData")) {
  385.                 node.setAttribute("AdblockData", true); // applets can't directly test for "public-classes"
  386.                 node.setAttribute("AdblockLocation", contentLocation.spec);
  387.                 node.setAttribute("AdblockType", contentType); }
  388.             node.setAttribute("AdblockMatch", filterMatch); }
  389.         else {
  390.             if (typeof(node._AdblockData) == 'undefined') node._AdblockData = []; // applets can't test "typeof"
  391.             node._AdblockData.push(contentLocation);
  392.             node._AdblockData.push(contentType);
  393.             node._AdblockData.push(filterMatch); } // null, or the matched filter
  394.     }
  395.     catch(e) {}
  396. }
  397.  
  398. // stores the reference to a local-document's nsIDocShell -- for reflows
  399. function storeAdblockDocShell(wnd) {
  400.     
  401. }
  402.  
  403. // for blocked / hidden pages 
  404. //   -- writes a message showing the filter and its matched portion of url
  405. function adblockPageBlock(filterMatch, contentLocation, wnd) {
  406.     filterMatch = filterMatch.toString(); // force-convert filter to string
  407.     var urlRe = new RegExp(filterMatch.replace(/^\/(.*)\/i?$/, "($1)"), "i"); // must come before filterMatch's change
  408.     var urlHilight = contentLocation.spec.replace(urlRe, "<span class='urlHilight'>$1</span>");
  409.     var simpleRe = /\(\?\:\\n\)\?/; // test for the "Adblock simple-filter" flag
  410.     if (simpleRe.test(filterMatch)) filterMatch = filterMatch.replace(/^\/(.*)\(\?\:\\n\)\?\/i?$/, "$1").replace(/\\\./g, " ").replace(/\.\*/g, "*").replace(/\s/g, ".").replace(/\\/g, ""); // the first 'replace' is same as substr, below -- left regexp for fun
  411.     else filterMatch = filterMatch.substr(0, filterMatch.length - 1); //.replace(/\\/g, "\\\\"); // length isn't zero-based + / + $ + flag "i" are anchored to end
  412.     var title = contentLocation.host.replace(/^www\./, "");
  413.     var pageElementLocal = wnd.document.documentElement;
  414.     // write the block-message into the page -- [Note: doesn't center properly for pages with prior content]
  415.     pageElementLocal.innerHTML = "\
  416.         <head>\
  417.             <style type='text/css'>\
  418.             <!--\
  419.                 .massive     { font-family: Times, Times New Roman, Serif; font-size: 400%; color: #999999;}\
  420.                 .infotext    { font-family: Arial, Helvetica, San-serif; font-size: medium; color: #999999;}\
  421.                 .filter        { font-family: Arial, Helvetica, San-serif; font-size: medium; color: #993333;}\
  422.                 .url        { font-family: Arial, Helvetica, San-serif; font-size: small; color: #999999;}\
  423.                 .urlHilight    { border-width: 0 0 1px 0; border-color: default; border-style: none none solid none;}\
  424.             -->\
  425.             </style>\
  426.         </head>\
  427.         <body>\
  428.             <table style='width: 100%; height: 100%;'><tr valign='middle'><td><center>\
  429.                 <span class='massive'>Adblock</span><br>\
  430.                 <span class='infotext'>This site has been blocked: </span><span class='filter'>"+filterMatch+"</span><br>\
  431.                 <span class='url'>"+urlHilight+"</span>\
  432.             </center></td></tr></table>\
  433.         </body>";
  434.     //wnd.setTimeout("document.title = 'Adblocked: "+title+"';", 0);
  435.     //wnd.gURLBar.value = contentLocation.spec;
  436.     
  437.     // fire the notification-event -- so our listener can set the urlbar / content.uri
  438.     pageElementLocal.adblockURI = contentLocation;
  439.     var event = pageElementLocal.ownerDocument.createEvent('Events');
  440.     event.initEvent("adblock-pageblock", true, false);
  441.     event.adblockURI = contentLocation;
  442.     pageElementLocal.dispatchEvent(event);
  443. }
  444.  
  445. // hides a BLOCKED element -- faster / less thorough
  446. function adblockRemoveFast(node, wnd, immediate) {
  447.     // serialize iframes - to avoid graphics-glitch -- old api only
  448.     if (apiConstants.oldStyleAPI && node.nodeName.toLowerCase() == "iframe")
  449.         wnd.document.documentElement.innerHTML = "";
  450.  
  451.     // collapse frameset-cols+rows for frames
  452.     if (node.nodeName.toLowerCase() == "frame" && node.parentNode.nodeName.toLowerCase() == "frameset") {
  453.         var i = 0, prevFrame = node;
  454.         while (prevFrame.previousSibling) {
  455.             if (/^frame|frameset$/i.test(prevFrame.previousSibling.nodeName)) i++;
  456.             prevFrame = prevFrame.previousSibling; }
  457.  
  458.         /* This was a frameset alteration-listener. it proved too complicated to be desirable
  459.         if (node.parentNode.hasAttribute("adblockrows") || node.parentNode.hasAttribute("adblockcols"))
  460.             return;
  461.             node.parentNode.removeEventListener("DOMAttrModified", onFramesetChange, true); */
  462.         var setTypes = ["cols", "rows"], RowsOrCols;
  463.         for (var t in setTypes) {
  464.             RowsOrCols = setTypes[t];
  465.             if (node.parentNode.hasAttribute(RowsOrCols))
  466.                 adblockRemoveSlow(node, wnd, immediate, '\
  467.                     var setWidths = node.parentNode.getAttribute("'+RowsOrCols+'").split(",");\
  468.                     setWidths['+i+'] = "0";\
  469.                     setWidths = setWidths.join(",");\
  470.                     node.parentNode.setAttribute("adblock'+RowsOrCols+'", setWidths);\
  471.                     node.parentNode.setAttribute("'+RowsOrCols+'", setWidths);\
  472.                 '); }
  473.         /*node.parentNode.addEventListener("DOMAttrModified", onFramesetChange, true);*/
  474.     }
  475.     // explicitly hide nodes (when adding a filter)
  476.     else (fastCollapse) ?
  477.         adblockHide(node, wnd, immediate)
  478.         :
  479.         adblockRemoveSlow(node, wnd, immediate);
  480. }
  481.  
  482. /* We're stuck with code-strings below -- newer builds sandbox anonymous-functions from accessing 'node' */
  483.  
  484. // hides a BLOCKED element -- slower / more thorough
  485. function adblockRemoveSlow(node, wnd, immediate, removalCode) {
  486.     // use timeout to collapse node - otherwise the reflow-queue doesn't catch it
  487.     // set style + collapse frameset-cols+rows for frames (if specified)
  488.     if (immediate) (removalCode) ? eval(removalCode) : (node.style.display = "none");
  489.     else {
  490.         var nodeIndex = adblockNodeIndex(wnd, node);
  491.         wnd.setTimeout(
  492.                 "var node = window._AdblockObjects["+nodeIndex+"];\
  493.                 "+  (removalCode ? removalCode : "node.style.display = 'none';")  +"\
  494.                 delete window._AdblockObjects["+nodeIndex+"];", 0); // no content will be loaded
  495.     }
  496. }
  497.  
  498. // hides a LOADED element
  499. function adblockHide(node, wnd, immediate) {
  500.     // use timeout to hide node - so reflow-queue gets it
  501.     try {node = node.QueryInterface(Components.interfaces.nsIDOMElement);} catch(e) {}
  502.     if (immediate) node.style.setProperty("visibility", "hidden", "important");
  503.     else {
  504.         var nodeIndex = adblockNodeIndex(wnd, node);
  505.         wnd.setTimeout(
  506.                 "var node = window._AdblockObjects["+nodeIndex+"];\
  507.                 node.style.setProperty('visibility', 'hidden', 'important');\
  508.                 delete window._AdblockObjects["+nodeIndex+"];", 0); // content will load
  509.     }
  510. }
  511.  
  512. // indexes the relevant node, for setTimeout -- newer builds fails to pass this proper
  513. function adblockNodeIndex(wnd, node) {
  514.     if (typeof(wnd._AdblockObjects) == 'undefined') { 
  515.         wnd._AdblockObjects=[]; 
  516.         wnd._AdblockCounter=0; }
  517.     var nodeIndex = ""+wnd._AdblockCounter++;
  518.     switch(arguments.length) {
  519.         case 1: break;
  520.         case 2: wnd._AdblockObjects[nodeIndex] = node; break;
  521.         default: 
  522.             wnd._AdblockObjects[nodeIndex] = new Array();
  523.             for (var n = 1 ; n < arguments.length ; n++)
  524.                 wnd._AdblockObjects.push(arguments[n]); // for makeObjectFrame()
  525.             break;
  526.     }
  527.     
  528.     return nodeIndex;
  529. }
  530.  
  531.  
  532.  
  533. /*
  534.  * URL checking
  535.  */
  536.  
  537. // Tests if any containing-link matches a filter
  538. function checkLinks(contentType, contentLocation, context, wnd) {
  539.     var parentLink = null, parentLinkLocation, parentNode = elementInterface(contentType, context, wnd).parentNode;
  540.     while (parentNode && parentLink == null) {
  541.         if (typeof(parentNode.href) != 'undefined' && parentNode.href 
  542.                 && linkSchemes[parentNode.protocol.toLowerCase()] ) 
  543.             parentLink = parentNode.href;
  544.         //else if (parentNode.getAttribute("URL")) parentLink = parentNode.getAttribute("URL"); // unneeded ?
  545.         else parentNode = parentNode.parentNode; }
  546.     if (parentLink) { try {
  547.         parentLinkLocation = new Object();
  548.         parentLinkLocation.spec = parentLink;
  549.         parentLinkLocation.host = "all"; //}
  550.         var linkMatch = isBlocked(parentLinkLocation); 
  551.         //if (linkMatch) parentNode.removeAttribute("href"); // DISABLED: stops other children from being caught --eliminate link, if matching
  552.         return linkMatch; } catch(e) { wnd.alert("Adblock LinkCheck Error: " + contentLocation.spec + "\n\n" + parentLink + "\n\n" + e); return null;} }
  553.     else 
  554.         return null;
  555. }
  556.  
  557. // Tests if a given URL should be blocked
  558. function isBlocked(url) {
  559.     if (typeof(patterns[url.host]) != 'undefined') {
  560.         var matchingPattern = checkURL(url.spec, patterns[url.host]);
  561.         if (matchingPattern || url.host == 'all') 
  562.             return matchingPattern; } // if no matches (and not linkCheck), continue..
  563.         
  564.     if (typeof(patterns['']) != 'undefined') {
  565.         matchingPattern = checkURL(url.spec, patterns['']);
  566.         return matchingPattern; } // if no matches, we're done.
  567. }
  568.  
  569. // Checks if the URL matches any of the patterns from the list
  570. function checkURL(url, patterns) {
  571.     for (var i=0; i<patterns.length; i++)
  572.         if (patterns[i].test(url))
  573.             return patterns[i];
  574.  
  575.     return null; // if no matches, return null
  576. }
  577.  
  578.  
  579.  
  580. /*
  581.  * Filter management
  582.  */
  583.  
  584. // Loads the preferences
  585. function adblockLoadSettings(prefName) {
  586.     var prefObj = Components.classes[PREFSERVICE_CONTRACTID].getService(Components.interfaces.nsIPrefService);
  587.     var Branch = prefObj.getBranch("adblock.");
  588.  
  589.     // Load Bool-prefs -- on init or inidividual-change
  590.     if (prefName && prefName != "FilterChange") {
  591.         isEnabled = !Branch.prefHasUserValue("enabled") || Branch.getBoolPref("enabled"); // default:true
  592.         linkCheck = Branch.prefHasUserValue("linkcheck") && Branch.getBoolPref("linkcheck"); // default:false
  593.         pageBlock = Branch.prefHasUserValue("pageblock") && Branch.getBoolPref("pageblock"); // default:false
  594.         removeAds = !Branch.prefHasUserValue("hide") || !Branch.getBoolPref("hide"); // rev-hide -- default:true
  595.         fastCollapse = Branch.prefHasUserValue("fastcollapse") && Branch.getBoolPref("fastcollapse"); // default:false
  596.         frameObjects = !Branch.prefHasUserValue("frameobjects") || Branch.getBoolPref("frameobjects"); // default:true
  597.         // don't continue, if we're not initializing
  598.         if (prefName != "Init") return;
  599.     }
  600.     
  601.     // Load Filter-list -- on init or list-change
  602.     patterns = [];
  603.     var url = Components.classes[STDURL_CONTRACTID].createInstance(Components.interfaces.nsIURI);
  604.     var list = Branch.prefHasUserValue("patterns") ? Branch.getCharPref("patterns") : null;
  605.     
  606.     /*
  607.     // Default Filters (for unset pref)
  608.     if (list == null) {
  609.         SubScriptLoader.loadSubScript("chrome://adblock/content/component-defaultfilters.js"); // gives us "var defaultFilterString"
  610.         Branch.setCharPref('patterns', defaultFilterString);
  611.         list = defaultFilterString; }
  612.     */
  613.     
  614.     // Duplicate management
  615.     if (list && list != "") {
  616.         // remove duplicate entries
  617.         list = list.split(" ");
  618.         var origLength = list.length;
  619.         var duplicateFound = false, lastMatch;
  620.         var tempList = list.slice(0, list.length); // copy the list
  621.         tempList.sort();
  622.         for (var d = 0; d < list.length; d++) {
  623.             binSearchArray(tempList, list[d]); // remove the "initial" entry
  624.             duplicateFound = binSearchArray(tempList, list[d]); // first duplicate (if any)
  625.             if (duplicateFound) {
  626.                 var m = true;
  627.                 while (m) m = binSearchArray(tempList, list[d]); // remove further duplicates from tempList
  628.                 for (var r = d+1; r < list.length; r++)
  629.                     if (list[r] == duplicateFound) { // only match the duplicates (second+)
  630.                         list.splice(r, 1); // remove duplicate from real list
  631.                         lastMatch = r;
  632.                         r--; // back the counter - from splice 
  633.                     }
  634.                 list.splice(d, 1); // remove original item..
  635.                 list.splice(lastMatch-1, 0, duplicateFound); // ..reinserting at last match-point (-1 from splice)
  636.                 d--; // back the counter - from splice
  637.             }
  638.         }
  639.         // save list -- on truncation, or pref-change
  640.         if (list.length < origLength || prefName) 
  641.             try {
  642.                 var joinedList = (list.slice(0, list.length)).join(" "); // copy+join the list
  643.                 //prefListReloading = true; // window-flag to keep prefs from reloading
  644.                 Branch.setCharPref("patterns", joinedList);
  645.                 prefObj.savePrefFile(null); // save the prefs to disk 
  646.             } catch(e) {}
  647.         // load list into memory
  648.         for (var i = 0; i < list.length; i++) {
  649.             list[i].replace(/\s/g, '');
  650.             if (list[i].match(/^https?:\/\/[^*\/]+\//)) {
  651.                 url.spec = list[i];
  652.                 addPattern(list[i], url.host); }
  653.             else
  654.                 addPattern(list[i], "");
  655.         }
  656.     }
  657. }
  658.  
  659. // Converts a pattern into RegExp and adds it to the list
  660. function addPattern(pattern, host) {
  661.     if (typeof(patterns[host]) == 'undefined')
  662.         patterns[host] = [];
  663.     if (typeof(patterns['all']) == 'undefined')
  664.         patterns['all'] = [];
  665.  
  666.     var regexp;
  667.     if (pattern.charAt(0) == "/" && pattern.charAt(pattern.length - 1) == "/")  // pattern is a regexp already
  668.         regexp = pattern.substr(1, pattern.length - 2);
  669.     else
  670.         regexp = pattern.replace(/^[\*]*(.(?:[^\*]|[\*]+[^\*])*)[\*]*$/, "$1").replace(/[\*]+/, "*").replace(/([^\w\*])/g, "\\$1").replace(/\*/g, ".*") + "(?:\\n)?"; // append flag for "adblock simple-filter" -- for filterall's de-regexp
  671.         //regexp = pattern.replace(/(?:^\*).|.(?:\*$)/g, "").replace(/([^\w\*])/g, "\\$1").replace(/\*/g, ".*") + "(?:\\n)?"; // append flag for "adblock simple-filter" -- for filterall's de-regexp
  672.         //regexp = "^" + pattern.replace(/([^\w\*])/g, "\\$1").replace(/\*/g, ".*") + "(ABsf)?" + "$";
  673.  
  674.     regexp = new RegExp(regexp, "i");
  675.     
  676.     patterns[host].push(regexp);
  677.     patterns['all'].push(regexp);
  678. }
  679.  
  680. // binary array-search -- returns lowest-matching element if found; false otherwise
  681. // -- Requires a SORTED array
  682. //  -- note: sorting with a compareFunction defines ordering -> return: zero::unchanged, pos::first value, neg::second value
  683. function binSearchArray(array, searchItem) {
  684.     var low = 0;
  685.     var high = (array.length-1>0) ? array.length-1 : 0; // in case array.length == 1
  686.     var searchPoint = 0;
  687.     var prevPoint = 0;
  688.     var match = null;
  689.     while (match == null) {
  690.         searchPoint = Math.floor((high-low)/2+low);
  691.         if (searchPoint == prevPoint) {
  692.             searchPoint = (prevPoint==low) ? high : low; // due to rounding (floor), we might get stuck - so jump
  693.             high = low; } // matches false if the search-term isn't found
  694.         if (array[searchPoint] == searchItem) {
  695.             match = array[searchPoint];
  696.             array.splice(searchPoint, 1); } // remove match from search-array
  697.         else if (high==low) match = false;                                                    
  698.         else if (searchItem < array[searchPoint]) high = searchPoint;
  699.         else if (searchItem > array[searchPoint]) low = searchPoint;
  700.         prevPoint = searchPoint;
  701.     }
  702.     return match;
  703. }
  704.  
  705.  
  706.  
  707. /*
  708.  * Object frames
  709.  */
  710.  
  711. // Creates a frame around a new object node
  712. function makeObjectFrame(node, contentType, contentLocation, wnd) {
  713.     try {node = node.QueryInterface(Components.interfaces.nsIDOMElement);} catch(e) {}
  714.     //var isApplet = (node.nodeName.toLowerCase() == "applet"); // applet-frames can't be wrapped
  715.     var isApplet = true; // let's see how this works... :P~
  716.  
  717.     // Don't continue if we already have a frame
  718.     if (isApplet)
  719.         if (node.hasAttribute("AdblockFramedObject") || node.hasAttribute("AdblockFramedObject2")) return;
  720.     else 
  721.         if (typeof(node._AdblockFrame) != 'undefined') return;
  722.  
  723.     // Create frame node
  724.     var frame, subDiv1, subDiv2, span;
  725.     frame = node.ownerDocument.createElement('div'); 
  726.     subDiv1 = node.ownerDocument.createElement('div');
  727.     subDiv2 = node.ownerDocument.createElement('div');
  728.     span = node.ownerDocument.createElement('span');
  729.     
  730.     // Style frame node
  731.     frame.setAttribute("style", style="margin: 0px; padding: 0px; overflow: visible;");
  732.     subDiv1.setAttribute("style", "height: 0px; width: 100%; overflow: visible;");
  733.     subDiv2.setAttribute("style", "padding: 1px; vertical-align: bottom; border-style: ridge ridge none ridge; border-width: 2px 2px 0px 2px; -moz-border-radius-topleft: 10px; -moz-border-radius-topright: 10px; -moz-opacity: 0.5; background-color: white;  position: relative; top: -19px; left: -5px; z-index: 900;  width: 48px; height: 15px;  cursor: pointer; overflow: visible;");
  734.     span.setAttribute("style", "font-family: Arial,Helvetica,Sans-serif; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; line-height: 140%; text-align: right; text-decoration: none; -moz-opacity: 1.5; color: black;");
  735.     subDiv1.setAttribute("align", "right"); // right-align the tab.
  736.     subDiv2.setAttribute("align", "center"); // center tab-text.
  737.  
  738.     // Adjust frame-width: if applets, or if we have a relative object width (%)
  739.     if (isApplet || (node.getAttribute('width') && node.getAttribute('width').match(/%$/)) ) {
  740.         frame.style.width = node.getAttribute('width'); 
  741.         frame.style.display = 'block'; }
  742.     else
  743.         frame.style.display = 'table-cell';
  744.  
  745.     // Assemble frame node
  746.     frame.appendChild(subDiv1);
  747.     subDiv1.appendChild(subDiv2);
  748.     subDiv2.appendChild(span);
  749.     span.appendChild(node.ownerDocument.createTextNode('Adblock'));
  750.     
  751.     // Add cross-node references
  752.     frame._AdblockObject = node; // add Node reference to frame
  753.     //if (!isApplet) // it's all manually overridden, for now
  754.     if (node.nodeName.toLowerCase() != "applet") {
  755.         node._AdblockFrame = frame; // objects: add Frame reference to node
  756.         node.setAttribute("AdblockFramedObject2", true); }
  757.     else {
  758.         frame._AdblockData = new Array(); // applets: add Node data to frame
  759.         frame._AdblockData.push(contentLocation);
  760.         frame._AdblockData.push(contentType); 
  761.         node.setAttribute("AdblockFramedObject", true); }
  762.     frame.setAttribute("AdblockFrame", true); // to identify the outer-frame on tab-click
  763.     subDiv2.addEventListener('click', onBlockObject, false); // event listener, for tab-click
  764.     var frameName = "adblock-frame-n"+frameCounter++;
  765.     frame.id = frameName;
  766.     node.setAttribute("AdblockFrameName", frameName);
  767.     
  768.     // Add event listeners to the object node (in case it's moved)
  769.     //node.addEventListener('DOMNodeInserted', onNodeInserted, false);
  770.     //node.ownerDocument.addEventListener('DOMNodeRemoved', onNodeRemoved, false);
  771.  
  772.     // Cannot add the frame right now - the object has not been added to the document yet
  773.     /*if (!isApplet)*/ node.style.setProperty('visibility', 'hidden', 'important'); // hide node, so the frame-swap doesn't show
  774.     
  775.     var nodeIndex = adblockNodeIndex(wnd);
  776.     wnd._AdblockObjects[nodeIndex] = [node, frame, isApplet]; // we need to do this locally, for some reason
  777.  
  778.     // insert frame, relocating to bottom if hidden by window-top
  779.     //   -- and increase parent-iframe's height if necessary
  780.     wnd.setTimeout( '\
  781.             var node = window._AdblockObjects["'+nodeIndex+'"][0];\
  782.             var frame = window._AdblockObjects["'+nodeIndex+'"][1];\
  783.             var isApplet = window._AdblockObjects["'+nodeIndex+'"][2];\
  784.             var style = node.ownerDocument.defaultView.getComputedStyle(node, "");\
  785.             if (!frame.style.width) frame.style.width = style.getPropertyValue("width");\
  786.     \
  787.             var currentOffset = node, y = node.offsetTop;\
  788.             while (currentOffset.offsetParent) {\
  789.                 y += currentOffset.offsetParent.offsetTop;\
  790.                 currentOffset = currentOffset.offsetParent; }\
  791.             if (y < 20) {\
  792.                 var subFrame = frame.firstChild, subFrame2 = frame.firstChild.firstChild;\
  793.                 subFrame2.style.setProperty("-moz-border-radius-bottomleft", "10px", null);\
  794.                 subFrame2.style.setProperty("-moz-border-radius-bottomright", "10px", null);\
  795.                 subFrame2.style.setProperty("border-style", "none ridge ridge ridge", null);\
  796.                 subFrame2.style.setProperty("border-width", "0px 2px 2px 2px", null);\
  797.                 subFrame2.style.setProperty("top", (isApplet) ? "0px":style.getPropertyValue("height"), null);\
  798.                 subFrame2.style.setProperty("right", "-5px", null);\
  799.                 subFrame2.style.removeProperty("left");\
  800.                 subFrame2.style.removeProperty("-moz-border-radius-topleft");\
  801.                 subFrame2.style.removeProperty("-moz-border-radius-topright");\
  802.                 subFrame.setAttribute("align", "left");\
  803.                 if (node.nextSibling) var evalCode = "node.parentNode.insertBefore(frame, node.nextSibling);";\
  804.                 else evalCode = "node.parentNode.appendChild(frame);";\
  805.             }\
  806.             else\
  807.                 evalCode = "node.parentNode.insertBefore(frame, node);";\
  808.     \
  809.             var parentiFrame = node.ownerDocument.defaultView.frameElement;\
  810.             if (parentiFrame != null) {\
  811.                 var nodeHeight = parseInt(style.getPropertyValue("height").replace(/(\d+).*$/, "$1"));\
  812.                 var parentiFrameStyle = node.ownerDocument.defaultView.getComputedStyle(parentiFrame, "");\
  813.                 var parentiFrameHeight = parseInt(parentiFrameStyle.getPropertyValue("height").replace(/(\d+).*$/, "$1"));\
  814.                 if (nodeHeight + 20 + y > parentiFrameHeight) {\
  815.                     parentiFrame.style.setProperty("height", nodeHeight+20+y, "important");\
  816.                     parentiFrame.height = nodeHeight+20+y; }\
  817.             }\
  818.     \
  819.             eval(evalCode);\
  820.             node.style.removeProperty("visibility");\
  821.             delete window._AdblockObjects["'+nodeIndex+'"];\
  822.         ', 0);
  823. }
  824.  
  825. // Event handler, object element has been removed from the document - hide the frame
  826. function onNodeRemoved(event) {
  827.     var node = event.target;
  828.     if (!node.hasAttribute("AdblockFrameName")) return;
  829.  
  830.     if (node.nodeName.toLowerCase() == "applet") {
  831.         var frame = document.getElementById(node.getAttribute("AdblockFrameName"));
  832.         /*
  833.         // Have to move the child temporarily to prevent the document from reloading
  834.         var head = node.parentNode.getElementsByTagName('head')[0];
  835.         if (head) head.appendChild(frame.parentNode.removeChild(frame)); 
  836.         */
  837.     }
  838.     else {
  839.         frame = node._AdblockFrame;
  840.         /*frame.parentNode.removeChild(frame);*/ }
  841.     
  842.     frame.style.display = "none";
  843. }
  844.  
  845. // Event handler, object element has been reinserted into the document - unhide the frame
  846. function onNodeInserted(event) {
  847.     var node = event.target;
  848.     if (!node.hasAttribute("AdblockFrameName")) return;
  849.     
  850.     if (node.nodeName.toLowerCase() == "applet") {
  851.         var frame = document.getElementById(node.getAttribute("AdblockFrameName"));
  852.         frame.parentNode.removeChild(frame); }
  853.     else frame = node._AdblockFrame;
  854.     //alert("frame: "+frame +"\nnode: "+ node +"\nparentNode: "+ node.parentNode +"\nnextSibling: "+ node.nextSibling);
  855.     
  856.     /*
  857.     var above = (frame.firstChild.style.getPropertyValue("align") == "right");
  858.     if (above) node.parentNode.insertBefore(frame, node);
  859.     else {
  860.         if (node.nextSibling) node.parentNode.insertBefore(frame, node.nextSibling);
  861.         else node.parentNode.appendChild(frame); }
  862.     */
  863.     
  864.     frame.style.removeProperty("display");
  865. }
  866.  
  867. // Event handler, frameset attribute has changed
  868. function onFramesetChange(event) {
  869.     if (/^(cols|rows)$/.test(event.attrName)) {
  870.         var node = event.target;
  871.         node.removeEventListener("DOMAttrModified", onFramesetChange, true);
  872.         if (node.getAttribute(event.attrName) != node.getAttribute("adblock"+event.attrName))
  873.             node.setAttribute(event.attrName, node.getAttribute("adblock"+event.attrName));
  874.         node.addEventListener("DOMAttrModified", onFramesetChange, true);
  875.     }
  876. }
  877.  
  878. // Event handler, Adblock Tab has been clicked
  879. function onBlockObject(event) {
  880.     var data, node, frame = event.target;
  881.     while ( ! (frame.nodeName.toLowerCase() == "div" && frame.hasAttribute("AdblockFrame")) )
  882.         frame = frame.parentNode;
  883.     node = frame._AdblockObject;
  884.     //node = node.QueryInterface(Components.interfaces.nsIDOMElement); -- causes issues with flash
  885.     if (node.nodeName.toLowerCase() == "applet") data = frame._AdblockData; // applet's can't store this directly
  886.     else data = node._AdblockData; // if we don't have an applet
  887.  
  888.     itemFramedDialog(node, data);
  889. }
  890.  
  891. // pops a filter dialog for FRAMED, embedded media
  892. function itemFramedDialog(node, data) {
  893.     var page = node.ownerDocument; // -ownerDocument -!
  894.     //node = node.QueryInterface(Components.interfaces.nsIDOMElement); -- causes issues with flash
  895.     
  896.     // passes the target item to the dialogue via window.argument[1] -- allows the item to be refiltered on 'accept'
  897.     var dialogHandle = node.ownerDocument.defaultView.top.openDialog("chrome://adblock/content/addfilterdialog.xul","Add filter", "chrome,modal,centerscreen", data[0].spec, node);
  898. }
  899.  
  900.  
  901.  
  902. /*
  903.  * Debug Routines
  904.  */
  905.  
  906. // lists everything in an object -- unlimited
  907. function unlimitedListObject(obj) {
  908.     var res = "Listing: " + obj + "\n\n"+obj.nodeName+"\n"+obj.value+"\n";
  909.     for(var list in obj)    
  910.         res += list + ": " + eval("obj."+list) + "\n"; //+ " -- " + (eval("obj."+list))?(eval("obj."+list+".nodeName")):null + "\n";
  911.         
  912.     return res + "--\n\n";
  913. }
  914.  
  915.  
  916. // appends a given string to "logfile.txt"
  917. function logfile(logString) {
  918.     var streamOut = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  919.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  920.     var logFile = dirService.get("UChrm", Components.interfaces.nsIFile);// lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h
  921.     logFile.append("logfile.txt"); // "appends" the file-string to our dir file-obj
  922.     logFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); // uniquely name file
  923.     
  924.     // if the file is writable, append logString
  925.     if (logFile.isWritable()) {
  926.         streamOut.init(logFile, 0x02, 0x200, null);
  927.         //streamOut.flush();
  928.         streamOut.write(logString, logString.length);
  929.         streamOut.close();
  930.     }
  931. }
  932.  
  933. // Creates a text-listing for an item's nested node structure, n-layers deep -- very useful debug tool
  934. function listChildNodesX(itemN, depthX) {
  935.     if (!itemN.hasChildNodes) return null;
  936.     if (itemN.hasChildNodes()) {
  937.     
  938.         var itemlengthN = itemN.childNodes.length
  939.         var prefixcharsX = '- - ';
  940.         var prefixstringX = ' ';
  941.         var cnodesL = ' ';
  942.         
  943.         // if this is our first recursion-call, 'depthX' wont be an array yet
  944.         if (!depthX[1]) {
  945.             depthX = [0, depthX]; // define iteration counter and recursion limit
  946.         }
  947.  
  948.         // sets appropriate indentation, multiplying the prefix-string by our current depth
  949.         for (var v = 0 ; v < depthX[0] ; v++) {
  950.             prefixstringX += prefixcharsX;
  951.         }
  952.         
  953.         cnodesL += ' :' + itemlengthN + '\n'; // prints the number of childnodes for this depth
  954.         
  955.         for (var w = 0 ; w < itemlengthN ; w++) {
  956.             cnodesL += prefixstringX + w + '. ' + itemN.childNodes.item(w);
  957.             if (itemN.childNodes.item(w).hasChildNodes()) {
  958.                 if (depthX[0] < depthX[1]) {
  959.                     depthX[0]++;
  960.                     cnodesL += listChildNodesX(itemN.childNodes.item(w), depthX); }
  961.             }
  962.             else cnodesL += '\n';
  963.         }
  964.     }
  965.     return cnodesL;
  966. }
  967.  
  968.  
  969.