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 / settings.js < prev    next >
Encoding:
JavaScript  |  2004-06-26  |  34.0 KB  |  847 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is Adblock for Mozilla.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * Henrik Aasted Sorensen.
  18.  * Portions created by the Initial Developer are Copyright (C) 2002
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  * Henrik Aasted Sorensen
  23.  * Stefan Kinitz
  24.  * Wladimir Palant
  25.  * rue
  26.  * ***** END LICENSE BLOCK ***** */
  27.  
  28. var sortFlag = 0; // global flag to discern if the user has already been told to "reload settings to activate sort"
  29. var popupBeingShownN = new Array(); // global node for button-menus
  30. popupBeingShownN[0] = false; // boolean: are we showing a button-menu -- "now"
  31. popupBeingShownN[1] = null; // the id of the button-menu showing now -- "currentItem"
  32. var restoreindexTimer; // calls restoreListIndex after a short delay when the list is created / updated
  33. var menuTimer; // deactivates the button-menu's after 15 seconds
  34. var buttonMenusLoaded = false; // global flag to discern if the button-menus have been called -- filter context-menu needs this
  35.  
  36. // Loads preferences into the UI.
  37. function loadPrefWindow() {
  38.  
  39.     try {
  40.         var prefObj = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  41.         var Branch = prefObj.getBranch("adblock.");
  42.         var Enabled = !Branch.prefHasUserValue("enabled") || Branch.getBoolPref("enabled"); // default:true
  43.         var LinkCheck = Branch.prefHasUserValue("linkcheck") && Branch.getBoolPref("linkcheck"); // default:false
  44.         var PageBlock = Branch.prefHasUserValue("pageblock") && Branch.getBoolPref("pageblock"); // default:false
  45.         var Hide = Branch.prefHasUserValue("hide") && Branch.getBoolPref("hide"); // default:false;
  46.         var FastCollapse = Branch.prefHasUserValue("fastcollapse") && Branch.getBoolPref("fastcollapse"); // default:false
  47.         var Patterns = Branch.prefHasUserValue("patterns") ? Branch.getCharPref("patterns").split(" ") : null;
  48.         var ListSort = Branch.prefHasUserValue("listsort") && Branch.getBoolPref("listsort"); // default:false
  49.         var FrameObjects = !Branch.prefHasUserValue("frameobjects") || Branch.getBoolPref("frameobjects"); // default:true
  50.         
  51.     } catch(e) {}
  52.         
  53.     // load patterns into list
  54.     var overwriteCurrentList = true; // always overwrite the current list
  55.     if (Patterns != null && Patterns != "") 
  56.         fillList(Patterns, overwriteCurrentList, ListSort);
  57.     //else document.getElementById("newfilter").focus(); // UNNEEDED: reSelectListItem does this -- empty-list returns focus to the textbox
  58.     
  59.     var enablebox = document.getElementById("enabled");
  60.     enablebox.checked = Enabled;    
  61.         
  62.     var radiohide = document.getElementById("radio-hide");
  63.     var radioremove = document.getElementById("radio-remove");
  64.     radiohide.disabled = !enablebox.checked;
  65.     radioremove.disabled = !enablebox.checked;
  66.     
  67.     if (Hide) radiohide.setAttribute("selected", true);
  68.     else radioremove.setAttribute("selected", true);
  69.     
  70.     /*
  71.     var collapsebox = document.getElementById("fastcollapse");
  72.     collapsebox.checked = FastCollapse;
  73.     (document.getElementById('radio-remove').selected) ?
  74.         document.getElementById('fastcollapse').setAttribute('style', 'visibility: visible') 
  75.         :
  76.         document.getElementById('fastcollapse').setAttribute('style', 'visibility: hidden');
  77.     */
  78.  
  79.     var listsortmenu = document.getElementById("listsort");
  80.     listsortmenu.setAttribute("checked", ListSort);
  81.     var frameobjectsmenu = document.getElementById("frameobjects");
  82.     frameobjectsmenu.setAttribute("checked", FrameObjects);
  83.     var slowcollapsemenu = document.getElementById("slowcollapse");
  84.     slowcollapsemenu.setAttribute("checked", !FastCollapse); // reverse-pref: fast -> slow
  85.     var linkcheckmenu = document.getElementById("linkcheck");
  86.     linkcheckmenu.setAttribute("checked", LinkCheck);
  87.     var pageblockmenu = document.getElementById("pageblock");
  88.     pageblockmenu.setAttribute("checked", PageBlock);
  89.     
  90.     window.setTimeout("restoreListIndex()", 0); // sets the list to the last-selected item, or the input-line if none
  91.     //restoreListIndex();
  92. }
  93.  
  94. // Add a filter to the list -- now constructed for inline-editing :)
  95. function addFilter() {
  96.     var newItem;
  97.     var list = document.getElementById("list");
  98.     var textbox = document.getElementById("newfilter");
  99.     
  100.     // if there's an actual entry
  101.     if (textbox.value != "") {
  102.         // if it's not a regular expression, or it is, BUT we've said 'ok' to the warning
  103.         if (!adblockIsRegExp(textbox.value) || (adblockIsRegExp(textbox.value) && adblockWarnRegExp())) {
  104.             var filter = makePattern(textbox.value); // must be made into pattern
  105.             textbox.value = "";
  106.             var newItem = createListItem(filter);
  107.             var newItemindex = list.getIndexOfItem(newItem);
  108.             list.selectedIndex = newItemindex; // sets the list's selection to the new item
  109.             list.currentItem = newItem;
  110.             list.ensureIndexIsVisible(newItemindex); // scrolls the list to show the new item
  111.             
  112.             enableRevert();
  113.         }        
  114.     }
  115.     //if (!textbox.focused) 
  116.         //textbox.focus(); // always return focus to the textbox
  117. }
  118.  
  119. function fillList(Patterns, overwriteCurrentList, listSortChecked) {    
  120.     var list = document.getElementById("list");
  121.     
  122.     if (overwriteCurrentList && list.getRowCount() != 0) { // use instead for the disabled code -> && list.hasChildNodes()) {
  123.         clearList(true); // clear the list, sans dialog    
  124.     }
  125.         
  126.     // Sort the patterns -- would *much* rather do this with a col-header [rue]
  127.     if (listSortChecked)
  128.         Patterns.sort();    
  129.     
  130.     // fill the list with patterns
  131.     for (var i = 0 ; i < Patterns.length; i++)
  132.         if (!/^[\s]*$/.test(Patterns[i])) createListItem(Patterns[i]); // only non-empty patterns!
  133.     
  134.     restoreindexTimer = setInterval('clearInterval(restoreindexTimer); restoreListIndex();',10);
  135. }
  136.  
  137. // Asks the user if he really wants to clear the list.
  138. function clearList(dontConfirm) {
  139.     if (!dontConfirm)
  140.         if (!confirm("Do you really want to clear the list?")) 
  141.             return;
  142.     var list = document.getElementById("list");
  143.     list.parentNode.replaceChild(list.cloneNode(false), list); // clear the list
  144.         
  145.     enableRevert();
  146. }
  147.  
  148. // Imports filters from web.
  149. function importListFromWeb() {
  150.  
  151.     var URI = Components.classes["@mozilla.org/network/simple-uri;1"].createInstance(Components.interfaces.nsIURI);
  152.         
  153.     try {
  154.         URI.spec = 'http://www.eschew.org:80/filters.txt';
  155.     } catch(e) { console.logStringMessage(e.toString()); alert("oops"); }
  156.     
  157.     var IOService     = Components.classes["@mozilla.org/network/io-service;1"].createInstance(Components.interfaces.nsIIOService);
  158.     
  159.     try {
  160.     // var channel     = IOService.newChannelFromURI( URI );
  161.     var channel = IOService.newChannel('http://www.eschew.org:80/filters.txt', null, null);
  162.     } catch(e) { console.logStringMessage(URI.spec + e.toString()); }
  163.     var stream     = channel.open(); // This should be changed to async mode instead of sync if it doesn't work
  164.     var streamIO     = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
  165.     var overwriteCurrentList = false;
  166.     var input, inputArray, linebreak;
  167.     var validFile = false;
  168.  
  169.     streamIO.init(stream);
  170.     input = streamIO.read(stream.available());
  171.     streamIO.close();
  172.     stream.close();
  173.         
  174.     try {
  175.     // now: unix + mac + dos environment-compatible
  176.     linebreak = input.match(/(?:\[Ad[Bb]lock\])(((\n+)|(\r+))+)/m)[1]; // first: whole match -- second: backref-1 -- etc..
  177.     inputArray = input.split(linebreak);
  178.     
  179.     var headerRe = /\[Ad[Bb]lock\]/; // tests if the first line is adblock's header
  180.     if (headerRe.test(inputArray[0])) {
  181.         inputArray.shift();
  182.         fillList(inputArray, overwriteCurrentList);
  183.         enableRevert(); }
  184.     else 
  185.         alert("File not valid.");
  186.     } catch(e) { console.logStringMessage(input + e.toString() ); }
  187.  
  188. }
  189.  
  190.  
  191.  
  192. // Imports filters from disc.
  193. function importList() {
  194.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
  195.     var stream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
  196.     var streamIO = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
  197.     var overwriteCurrentList = false;
  198.     var input;
  199.     var inputArray;
  200.     var validFile = false;
  201.     
  202.     fp.init(window, "Select a File", fp.modeOpen);
  203.     fp.appendFilters(fp.filterText);
  204.  
  205.     if (fp.show() != fp.returnCancel) {
  206.         stream.init(fp.file, 0x01, 0444, null);
  207.         streamIO.init(stream);
  208.         input = streamIO.read(stream.available());
  209.         streamIO.close();
  210.         stream.close();
  211.         
  212.         /*
  213.         var breakStart = 9, breakEnd = 9-1; // the index just after adblock's header
  214.         while (/\s/.test(input.charAt(breakEnd+1)) )
  215.             breakEnd++;
  216.         var linebreak = input.substring(breakStart, breakEnd);// substring takes two indices, while substr takes index + length
  217.         */
  218.         
  219.         // now: unix + mac + dos environment-compatible
  220.         linebreak = input.match(/(?:\[Ad[Bb]lock\])(((\n+)|(\r+))+)/m)[1]; // first: whole match -- second: backref-1 -- etc..
  221.         inputArray = input.split(linebreak);
  222.         
  223.         var headerRe = /\[Ad[Bb]lock\]/; // tests if the first line is adblock's header
  224.         if (headerRe.test(inputArray[0])) {
  225.             inputArray.shift();
  226.             overwriteCurrentList = confirm("Do you want to overwrite the current list?\n..if not, pressing 'cancel' will append.");
  227.             fillList(inputArray, overwriteCurrentList);
  228.             
  229.             enableRevert(); }
  230.         else 
  231.             alert("File not valid.");
  232.     }
  233. }
  234.  
  235. // Exports the current list of filters to a file on disc.
  236. function exportList() {
  237.     var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
  238.     var stream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  239.  
  240.     fp.init(window, "Select a File", fp.modeSave);
  241.     fp.appendFilters(fp.filterText);
  242.  
  243.     if (fp.show() != fp.returnCancel) {
  244.         if (fp.file.exists())
  245.             fp.file.remove(true);
  246.         fp.file.create(fp.file.NORMAL_FILE_TYPE, 0666);
  247.  
  248.         stream.init(fp.file, 0x02, 0x200, null);
  249.         stream.write("[Adblock]\n", 10);
  250.         
  251.         Patterns = getPatterns().split(" ");
  252.         
  253.          for (var i = 0; i < Patterns.length ; i++) {
  254.             stream.write(Patterns[i], Patterns[i].length);
  255.             if (i < (Patterns.length - 1))
  256.                 stream.write("\n", 1);
  257.         }
  258.         stream.close();
  259.     }
  260. }
  261.  
  262. // Creates a listitem with the proper children for inline-editing -- returns the item's node -- label is set to 'value'
  263. function createListItem(value) {
  264.     var list = document.getElementById("list");
  265.     var newItem = document.createElement("listitem");
  266.  
  267.     value = value.replace(/[\s]*/g, ""); // remove whitespace(s) first -! (for list-import)
  268.     newItem.setAttribute("label", value); // sets the listItem's label for later saving -- needed by saveSettings() -- deactivateModify does this too.
  269.     //newItem.setAttribute("context", "listitem-contextmenu");
  270.     newItem.setAttribute("ondblclick", "listClickControl();");
  271.     
  272.     list.appendChild(newItem);
  273.     return newItem;
  274. }
  275.  
  276. // This function removes illegal characters (at the moment, space) from the patterns.
  277. function makePattern(pat) {
  278.     var res = "";
  279.     for (var i = 0 ; i < pat.length ; i++) {
  280.         switch (pat[i]) {
  281.             case ' ' : 
  282.                 break;
  283.             default :
  284.                 res += pat[i];
  285.                 break;
  286.         }
  287.     }
  288.     return res;
  289. }
  290.  
  291. // receives keypresses from the list-area... and makes decisions :)
  292. function listKeyControl(eventX) {
  293.  
  294.     var keyCodeX = eventX.keyCode; // action-key or '0'
  295.     var charCodeX = eventX.charCode; // character-key or '0'
  296.     keyCodeX += charCodeX; // since one of them is always zero, this works
  297.     
  298.     var list = document.getElementById("list");
  299.     var modifying = findElementWithAttribute("listitem", "modifying", "true");
  300.     var listpress = (eventX.target.id == "list" && list.selectedItem);
  301.     var boundParent = document.getBindingParent(eventX.originalTarget);
  302.     var entrypress = (boundParent && boundParent.id == "newfilter" && eventX.originalTarget.value != "");
  303.     
  304.     switch (keyCodeX) {        
  305.         // called by 'delete'
  306.         case eventX.DOM_VK_BACK_SPACE:
  307.         case eventX.DOM_VK_DELETE:
  308.             if (!modifying && listpress) removeFilter(); // it's possible the user will click another item, but hit 'return' fast enough to be editing the previous one -- the selection index wasn't updated before the keypress
  309.             break;
  310.             
  311.         // called by 'return'
  312.         case eventX.DOM_VK_RETURN:
  313.         case eventX.DOM_VK_ENTER:
  314.             if (modifying) deactivateModify("return"); // if a filter was being modified
  315.             else if (listpress) activateModify(); // if a filter was selected + focused
  316.             else if (entrypress) addFilter(); // if the entry-area was selected + filled
  317.             else { addFilter(); saveSettings(); } // we're finished
  318.             break;
  319.                 
  320.         // called by 'esc'
  321.         case eventX.DOM_VK_ESCAPE:
  322.         case eventX.DOM_VK_CANCEL:
  323.             if (modifying) deactivateModify("esc"); // sends the 'esc' parameter, which signals to keep the old value
  324.             else saveSettings(); // window.close(); // we're finished
  325.             break;
  326.     }
  327. }
  328.  
  329. // receives mouseClicks from the list-area... and makes decisions :)
  330. function listClickControl() {
  331.     var list = document.getElementById("list");
  332.     var selected = list.selectedItem;
  333.     var modifying = findElementWithAttribute("listitem", "modifying", "true");
  334.     
  335.     // if we have a filter selected and in-focus
  336.     if (selected && selected.focus) {
  337.         // if we're not modifying anything already
  338.         if (!modifying) {
  339.             activateModify();
  340.         }
  341.         // we're already modifying something
  342.         else {
  343.             // if we want to activate a different item
  344.             if (modifying != selected) {
  345.                 deactivateModify();
  346.                 activateModify();
  347.             }
  348.         }
  349.     }
  350.     // the listbox lost focus
  351.     else {
  352.         if (modifying &! modifying.focused) {
  353.             deactivateModify();
  354.         }
  355.     }
  356. }
  357.  
  358. // activates the textbox for filter modification -- called by modifyFilter
  359. function activateModify() {
  360.     var list = document.getElementById("list");
  361.     
  362.     if (list.selectedItem) {
  363.         var selectedX = list.selectedItem;
  364.         var selectedXcell = document.getAnonymousNodes(selectedX)[0];
  365.         var selectedXfield = document.getAnonymousNodes(selectedX)[1];
  366.         var filter = selectedXcell.getAttribute("label");
  367.         var selectedIndex = list.selectedIndex;
  368.         var scrollView = list.getIndexOfFirstVisibleRow();
  369.         var visibleRows = list.getNumberOfVisibleRows();
  370.         
  371.         // if the selected item isn't visible, show it
  372.         if (selectedIndex < scrollView ||
  373.                 selectedIndex > (scrollView + visibleRows-1))
  374.             list.scrollToIndex(selectedIndex - (visibleRows/2) + ((visibleRows%2)?1:0)); // set it mid-screen, rounding up
  375.  
  376.         /*
  377.         // if the selected item isn't visible, show it
  378.         if (list.selectedIndex < list.getIndexOfFirstVisibleRow() ||
  379.                 list.selectedIndex > (list.getIndexOfFirstVisibleRow()+list.getNumberOfVisibleRows()-1))
  380.             list.scrollToIndex(list.selectedIndex - (list.getNumberOfVisibleRows()/2)); // set it mid-screen
  381.         */
  382.             
  383.         selectedX.setAttribute("modifying", "true");        
  384.         selectedXcell.hidden = "true";
  385.         selectedXfield.value = filter;
  386.         selectedXfield.setAttribute("hidden", "false");
  387.         selectedX.removeAttribute("ondblclick");
  388.         
  389.         list.blur()
  390.         selectedXfield.focus();
  391.         selectedXfield.setAttribute("onblur", "deactivateModify(event.target);");
  392.     }
  393. }
  394.  
  395. // deactivates the textbox for filter modification -- called by modifyFilter
  396. function deactivateModify(parameter) {
  397.     var modifying = findElementWithAttribute("listitem", "modifying", "true");
  398.     
  399.     if (modifying) {
  400.         var list = document.getElementById("list");
  401.         var selectedIndex = list.selectedIndex;
  402.         var selected = list.selectedItem;
  403.         var disableX = modifying;
  404.         var disableXcell = document.getAnonymousNodes(disableX)[0];
  405.         var disableXfield = document.getAnonymousNodes(disableX)[1];
  406.         var disableXindex = list.getIndexOfItem(disableX);
  407.         var filter = makePattern(disableXfield.value); // note:  'value' needs to be called by method, not property
  408.         
  409.         // if the filter isn't blank, *And* we weren't called by the "esc" key
  410.         if (filter != "" && parameter != "esc") { 
  411.             disableXcell.setAttribute("label", filter);    // save the filter
  412.             disableX.setAttribute("label", filter); // listitem's label: used for later saving -- needed by saveSettings() -- createListItem does this too.
  413.             enableRevert();
  414.         }
  415.         
  416.         disableXcell.setAttribute("hidden", "false");
  417.         disableXfield.setAttribute("hidden", "true");
  418.         disableXfield.removeAttribute("onblur");
  419.         disableX.setAttribute("ondblclick", "listClickControl();");
  420.         
  421.         list.selectedIndex = disableXindex; // restore selection
  422.         list.currentItem = list.getItemAtIndex(list.selectedIndex); // and make it the current item
  423.         list.focus(); // refocus the list -- doesn't interfere with refocusing on other controls, but does refocus the *Window* if we were called by losing it to another
  424.  
  425.          // keep this for last, so listKeyControl wont accidentally activate the wrong field
  426.          //    --(if the user deselects and then presses 'return' fast enough)
  427.         disableX.setAttribute("modifying", "false");    }
  428. }
  429.  
  430. // Removes the selected entry from the list and sets selection to the next item
  431. function removeFilter() {
  432.     var list = document.getElementById("list");
  433.     var textbox = document.getElementById("newfilter");
  434.  
  435.     // if we have an item to remove
  436.     if (list.selectedItem) {
  437.         var item = list.selectedItem;
  438.         var itemindex = list.getIndexOfItem(item); // the current item's index
  439.         var itemplace = itemindex + 1; // this avoids negative numbers later -- 'itemindex' is zero-based
  440.  
  441.         var nextitemindex = itemindex; // points to the next item -- equal, since the item below will move up the index once our current item is removed
  442.         var previtemindex = nextitemindex - 1; // points to the previous -- in case we deleted the lowest entry
  443.  
  444.         var originaltotal = list.getRowCount(); // number of items in list, originally
  445.         var currenttotal = originaltotal-1; // number of items after deletion
  446.         var itemsfollowing = originaltotal - itemplace; // number of items following the deleted item
  447.         
  448.         list.removeChild(item);
  449.         
  450.         enableRevert();
  451.         
  452.         // if we have any items left to select
  453.         if (currenttotal > 0) {
  454.             //if there's any items following our deleted entry
  455.             if (itemsfollowing > 0 )
  456.                 list.selectedIndex = nextitemindex; // sets the list-selection to the next item
  457.             else
  458.                 list.selectedIndex = previtemindex; // sets the list-selection to the previous item
  459.                 
  460.             list.ensureIndexIsVisible(list.selectedIndex); // scrolls the list to show the item
  461.         }    
  462.     }
  463. }
  464.  
  465. // Checks all elements of the specified tagname for an attribute match ON THEIR PARENT --returns first match
  466. function findElementWithParentAttribute(elementTagName, attributeX, valueX) {
  467.     var elementarrayX = document.getElementsByTagName(elementTagName);
  468.     
  469.     for (var z = 0 ; z < elementarrayX.length ; z++) {
  470.         var element = elementarrayX[z];
  471.         if (element.parentNode) {
  472.             if (element.parentNode.hasAttribute(attributeX)) {
  473.                 if (element.parentNode.getAttribute(attributeX) == valueX) {
  474.                     return element;
  475.                 }
  476.             }
  477.         }
  478.     }
  479.     return false; // failure.
  480. }
  481.  
  482.  
  483. // Checks all elements of the specified tagname for an attribute match -- returns first match
  484. function findElementWithAttribute(elementTagName, attributeX, valueX) {
  485.     var elementarrayX = document.getElementsByTagName(elementTagName);
  486.     
  487.     for (var z = 0 ; z < elementarrayX.length ; z++) {
  488.         var element = elementarrayX[z];
  489.         if (element.hasAttribute(attributeX) && element.getAttribute(attributeX) == valueX)
  490.                 return element;
  491.     }
  492.     return false; // failure.
  493. }
  494.  
  495.  
  496. // sets the flag-parameter [+ timer] for button-menu "hovering" -- called by the menus when they show / hide
  497. function setMenuStatus(thisMenu) {
  498.     var thisButton, activeButton, activeMenu;
  499.     // flag to inform filter-contextMenu -- workaround for coordinate-bug"
  500.     //if (!buttonMenusLoaded) buttonMenusLoaded = true; // MOVED: to 'popupshowing' window-listener in settings.xul
  501.     
  502.     if (thisMenu) {
  503.         thisButton = document.getElementsByAttribute("popup", thisMenu.getAttribute("id"))[0];
  504.         thisButton.setAttribute("AdblockMenuActivated", true);
  505.         //menuTimer = setInterval('clearInterval(menuTimer); document.getElementById(document.getElementsByAttribute("AdblockMenuActivated", "true")[0].getAttribute("popup")).hidePopup(); setMenuStatus(null);',10000);
  506.     }
  507.     else {
  508.         activeButton = document.getElementsByAttribute("AdblockMenuActivated", "true");
  509.         activeButton = (activeButton.length) ? activeButton[0]:null; // get the first one, if anything returns
  510.         if (activeButton) activeButton.removeAttribute("AdblockMenuActivated");
  511.         if (menuTimer) clearInterval(menuTimer);
  512.     }
  513. }
  514.  
  515.  
  516. // handles the button-menu's, when they're active
  517. //  -- for "menu-less" buttons, 'thisButton' is passed as null
  518. function checkButtonMenu(thisButton, noMenu) {
  519.     var currentButton, currentMenu, currentMenuId, thisMenu, thisMenuId;
  520.     var eventN;
  521.     
  522.     currentButton = document.getElementsByAttribute("AdblockMenuActivated", "true");
  523.     currentButton = (currentButton.length) ? currentButton[0]:null; // get the first one, if anything returns
  524.  
  525.     // if menu's are active
  526.     if (currentButton) {
  527.  
  528.         // if we're hovering over a "nothing" menu-button..
  529.         if (noMenu) {
  530.             // ..and the *ACTIVE* menu is not a "nothing" menu
  531.             if (!currentButton.hasAttribute("NothingMenu")) {
  532.                 currentMenuId = currentButton.getAttribute("popup"); // get the id of the active menu
  533.                 currentMenu = document.getElementById(currentMenuId); // get the active menu
  534.                 
  535.                 currentMenu.hidePopup(); // hide the first menu
  536.                 currentMenu.removeAttribute("AdblockActivated"); // remove the "menu-active" flag
  537.                 if (menuTimer) clearInterval(menuTimer); // clear the menu-timer
  538.             }
  539.             thisButton.setAttribute("AdblockMenuActivated", true); // set the "menu-active" flag
  540.             thisButton.setAttribute("NothingMenu", "true"); // we're hovering over a "nothing" menu ;P
  541.             menuTimer = setInterval('clearInterval(menuTimer); setMenuStatus(null);',10000); // set the menu-timer
  542.         }
  543.         // we're hovering over a "regular" menu-button
  544.         else {
  545.             currentMenuId = currentButton.getAttribute("popup"); // get the id of the active menu
  546.             currentMenu = document.getElementById(currentMenuId); // get the active menu
  547.             thisMenuId = thisButton.getAttribute("popup"); // get the hovered button's menu
  548.             
  549.             // if the active menu doesn't match to the button we're hovering over
  550.             if (currentMenuId != thisMenuId) {
  551.                 if (! currentButton.hasAttribute("NothingMenu")) currentMenu.hidePopup(); // close the active menu
  552.                 setMenuStatus(null); // remove all menu-flags
  553.                 
  554.                 // fire the button-click to activate our new menu
  555.                 eventN = document.createEvent("MouseEvents");
  556.                 eventN.initMouseEvent("mousedown", true, false, null,
  557.                                0, 0, 0, 0, 0,
  558.                                false, false, false, false,
  559.                                0, null);
  560.                 thisButton.dispatchEvent(eventN); // fire a mouse-event to activate the second menu
  561.             }
  562.         }
  563.     }
  564. }
  565.  
  566.  
  567. // deactivates the menu-hovering of "nothing" menus when a specified window-event is fired
  568. //  -- currently for 'keypress' and 'click'
  569. function checkMenuEvent() {
  570.     var activeButton = document.getElementsByAttribute("AdblockMenuActivated", "true");
  571.     activeButton = (activeButton.length) ? activeButton[0]:null; // get the first one, if anything returns
  572.     //var activeMenuId;
  573.     //var activeMenu;
  574.     
  575.     if (activeButton && activeButton.hasAttribute("NothingMenu")) {
  576.         //activeMenuId = activeButton.getAttribute("popup"); // get the id of the active menu
  577.         //activeMenu = document.getElementById(activeMenuId); // get the active menu
  578.         
  579.         //activeMenu.hidePopup();
  580.         setMenuStatus(null); // remove all menu-flags
  581.     }
  582. }
  583.  
  584.  
  585. // selects a listitem and pops its context-menu
  586. function activateContext(evt) {
  587.     var targetItem = evt.target;
  588.     if(!targetItem || targetItem.nodeName != "listitem") return; // the user clicked on empty-space or the scrollbar
  589.     
  590.     var list = document.getElementById("list");
  591.     var listContextMenu = document.getElementById("listitem-contextmenu");
  592.     list.selectItem(targetItem);
  593.     
  594.     if (!buttonMenusLoaded) var x = evt.screenX, y = evt.screenY; // if the_button-menus/any_contextMenus have been activated, use local-coordinates..
  595.     else  x = evt.clientX, y = evt.clientY; // ..otherwise, use global-coordinates.
  596.     listContextMenu.showPopup(targetItem, x, y, "context", "at_pointer","at_pointer");
  597.  
  598.     //if (!buttonMenusLoaded) buttonMenusLoaded = true; // the first context-click doesn't fire its 'popupshowing' event in the proper window
  599. }
  600.  
  601.  
  602. // sets the list-sort pref from its menuitem
  603. //  -- this is separate from "saveSettings", so we can disable it if we somehow have it set, but don't want the list to be saved as sorted
  604. function setListSort(menuItem) {
  605.     var listOptionsMenu = document.getElementById("options-menu");
  606.     listOptionsMenu.hidePopup();
  607.  
  608.     var listSortChecked = menuItem.getAttribute("checked");
  609.     if (!listSortChecked) listSortChecked = false;
  610.     else listSortChecked = true; // for some reason, this attribute passes a string instead of a boolean -!
  611.     
  612.     try {
  613.         var prefObj = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  614.         var Branch = prefObj.getBranch("adblock.");
  615.         Branch.setBoolPref("listsort", listSortChecked);
  616.         
  617.         if (listSortChecked == true && sortFlag == 0)
  618.             alert("OK. The list will be sorted next time you launch the prefs.");
  619.             
  620.         sortFlag++;
  621.         
  622.     } catch(e) {}
  623.             
  624. }
  625.  
  626. // reselects the currentItem, since the list deselects it on scroll 
  627. //    -- this could just be my old build of mozilla, trippin'...
  628. //        -- "dang" - the hbox also calls at each keypress when an inline-edit is active: now checks 'modifying'
  629. function reSelectListItem() {
  630.     var list = document.getElementById("list");
  631.     var modifying = findElementWithAttribute("listitem", "modifying", "true");
  632.     
  633.     // if we're not modifying anything
  634.     if (!modifying) {
  635.             list.selectedIndex = list.getIndexOfItem(list.currentItem); // reselect our current item
  636.             list.currentItem = list.currentItem; }
  637. }
  638.  
  639. // persists the list's scroll-view by saving a "backup" copy
  640. //    --because the normal "persist-attribute" route isn't working for this one
  641. function persistListIndex() {
  642.     var list = document.getElementById("list");
  643.     var visibleRows = list.getNumberOfVisibleRows();
  644.     var scrollView = list.getIndexOfFirstVisibleRow();
  645.     var selectedIndex = list.selectedIndex;
  646.     
  647.     /* DISABLED: it feels more natural not to use this
  648.     if (scrollView > selectedIndex)
  649.         scrollView = selectedIndex; // if the selected-item is hidden above, set the view to it
  650.     else if (selectedIndex > (scrollView + visibleRows - 1))
  651.         scrollView = selectedIndex - visibleRows + 1; // if the selected-item is hidden below, set the view to show it last
  652.     */
  653.     
  654.     list.setAttribute("persist-scrollView", scrollView);
  655.     list.setAttribute("persist-selectedIndex", selectedIndex);
  656. }
  657.  
  658. // restores the list's selected-index from the persisted "backup"
  659. function restoreListIndex() {
  660.     var list = document.getElementById("list");
  661.     var textbox = document.getElementById("newfilter");
  662.     var savedView = list.getAttribute("persist-scrollView");
  663.     var savedIndex = list.getAttribute("persist-selectedIndex");
  664.     
  665.     // if the list is empty
  666.     if (list.getRowCount() == 0) {
  667.         textbox.focus(); // throw focus to the input-line
  668.     }
  669.         
  670.     
  671.     // otherwise, restore the scroll-view and select the last-saved index
  672.     else {
  673.         // if we have a valid scroll-view and index
  674.         if ((savedView && savedView != -1 && savedView <= list.getRowCount()-1) &&
  675.                 (savedIndex && savedIndex != -1 && savedIndex <= list.getRowCount()-1)) {
  676.             list.focus();
  677.             //list.scrollToIndex(list.getRowCount()-1); // scroll to the last item -- so our next scroll lends the "complete" view
  678.             list.scrollToIndex(savedView); // scroll the list to show the index -- more impressive :)
  679.             //list.ensureIndexIsVisible(savedView); // jump to the given index -- the 'fallback' in case scrollto.. fails
  680.             list.selectedIndex = savedIndex; // select the current item
  681.             list.currentItem = list.getItemAtIndex(savedIndex);
  682.             //list.ensureIndexIsVisible(savedIndex); // make sure we can see the current item
  683.             //list.selectedIndex = savedIndex; // re-select the current item (in case it wasn't visible)
  684.         }
  685.         else {
  686.             list.focus();
  687.             list.ensureIndexIsVisible(list.getRowCount() - 1); // scroll to the last item -- -1 to make zero-based
  688.             list.selectedIndex = list.getRowCount() - 1; // select the item we just scrolled to
  689.         }
  690.     }
  691.     
  692. }
  693.  
  694. // Returns the patterns in one, long string.
  695. // Use split(" ") to turn it into an array.
  696. function getPatterns() {
  697.     var patterns = new Array();
  698.     var list = document.getElementById("list");
  699.     
  700.     for (var i = 0 ; i < list.childNodes.length ; i++)
  701.         if (! /^\s$/.test(list.childNodes[i].getAttribute("label")) )
  702.             patterns.push(list.childNodes[i].getAttribute("label")); // if the pattern isn't just whitespace, add it in
  703.     patterns = patterns.join(" ");
  704.     return patterns;
  705. }
  706.  
  707. // enables the Revert-button once a setting has changed
  708. function enableRevert() {
  709.     var revertButton = document.getElementById("revertbutton")
  710.     if (revertButton.disabled)
  711.         revertButton.setAttribute("disabled", false);
  712. }
  713.  
  714. // confirms and executes a settings-revert to the last saved state
  715. function revertSettings() {
  716.     var confirmRevert = confirm("Are you sure you want to revert?\n..all changes for this pref-session will be undone." );
  717.     
  718.     if (confirmRevert) {
  719.         loadPrefWindow();
  720.         var revertButton = document.getElementById("revertbutton")
  721.         revertButton.setAttribute("disabled", true);
  722.     }
  723. }
  724.  
  725. // Save the settings and close the window.
  726. function saveSettings() {
  727.     var revertButton = document.getElementById("revertbutton");
  728.     var somethingChanged = (revertButton.getAttribute("disabled") == "false"); // if the revert-button isn't disabled, something was changed
  729.     var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
  730.     var prefObj = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  731.     var Branch = prefObj.getBranch("adblock.");
  732.     
  733.     // only save if we've actually changed something
  734.     if (somethingChanged) {
  735.         var patterns = getPatterns();
  736.         Branch.setCharPref("patterns", patterns);
  737.         observerService.notifyObservers(null, "Adblock-PrefChange", "FilterChange");
  738.         
  739.         var enablebox = document.getElementById("enabled");
  740.         Branch.setBoolPref("enabled", enablebox.checked);
  741.     
  742.         var frameobjects = document.getElementById("frameobjects");
  743.         Branch.setBoolPref("frameobjects", (frameobjects.getAttribute("checked") == "true") ? true:false);
  744.     
  745.         var slowcollapse = document.getElementById("slowcollapse");
  746.         Branch.setBoolPref("fastcollapse", (slowcollapse.getAttribute("checked") == "true") ? false:true); // reverse-pref: slow -> fast
  747.  
  748.         var linkcheck = document.getElementById("linkcheck");
  749.         Branch.setBoolPref("linkcheck", (linkcheck.getAttribute("checked") == "true") ? true:false);
  750.         
  751.         var pageblock = document.getElementById("pageblock");
  752.         Branch.setBoolPref("pageblock", (pageblock.getAttribute("checked") == "true") ? true:false);
  753.  
  754.         var radiohide = document.getElementById("radio-hide");
  755.         Branch.setBoolPref("hide", radiohide.selected);
  756.         
  757.         //var collapsebox = document.getElementById("fastcollapse");
  758.         //Branch.setBoolPref("fastcollapse", collapsebox.checked);
  759.  
  760.         //prefObj.savePrefFile(null); // save the prefs to disk -- component.js "loadSettings()" handles this now
  761.         observerService.notifyObservers(null, "Adblock-SavePrefFile", null);
  762.     }
  763.     
  764.     persistListIndex(); // persists the current listitem's index in a separate listbox-attribute
  765.     window.close(); // close out. -- triggers an 'onclose' handler to call "loadSettings()" *in the overlay*
  766. }
  767.  
  768.  
  769. // loads a help page -- needs to be passed a case-variable 'whichPage'
  770. function loadHelpPage(whichPage) {
  771.     var pageUrl;
  772.     
  773.     switch(whichPage) {
  774.         case "about": 
  775.             pageUrl = "http://adblock.mozdev.org/";
  776.             break;
  777.         case "regexp": 
  778.             pageUrl = "http://devedge.netscape.com/library/manuals/2000/javascript/1.5/guide/regexp.html#1010689";
  779.             break;
  780.     }
  781.     
  782.     var windowService = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
  783.     var currentWindow = windowService.getMostRecentWindow("navigator:browser");
  784.     if (currentWindow) {
  785.         try {
  786.           currentWindow.delayedOpenTab(pageUrl);
  787.         } catch(e) { currentWindow.loadURI(pageUrl); }
  788.     }
  789.     else
  790.         window.open(pageUrl);
  791. }
  792.  
  793.  
  794.  
  795. /*
  796.  * Debug Routines
  797.  */
  798.  
  799. // lists everything in an object -- unlimited
  800. function unlimitedListObject(obj) {
  801.     var res = "List: " + obj + "\n\n";
  802.     for(var list in obj)    
  803.         res += list + ": " + eval("obj."+list) + "\n"; //+ " -- " + (eval("obj."+list))?(eval("obj."+list+".nodeName")):null + "\n";
  804.         
  805.     return res + "--\n\n";
  806. }
  807.  
  808.  
  809. // appends a given string to "logfile.txt"
  810. function logfile(logString) {
  811.     var streamOut = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  812.     var dirService = Components.classes['@mozilla.org/file/directory_service;1'].getService(Components.interfaces.nsIProperties);
  813.     var logFile = dirService.get("UChrm", Components.interfaces.nsIFile);// lxr.mozilla.org/seamonkey/source/xpcom/io/nsAppDirectoryServiceDefs.h
  814.     logFile.append("logfile.txt"); // "appends" the file-string to our dir file-obj
  815.     logFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0666); // uniquely name file
  816.     
  817.     // if the file is writable, append logString
  818.     if (logFile.isWritable()) {
  819.         streamOut.init(logFile, 0x02, 0x200, null);
  820.         //streamOut.flush();
  821.         streamOut.write(logString, logString.length);
  822.         streamOut.close();
  823.     }
  824. }
  825.  
  826.  
  827. function listArray(ar) {
  828.     str = "content-size: " + ar.length + "\n";
  829.     for (var i = 0 ; i < ar.length; i++) {
  830.         str += "-"+ar[i]+"-\n";
  831.     }
  832.     
  833.     return str;
  834. }
  835.  
  836. // lists everything in an object -- Useful debug-function.
  837. function listObject(obj, s) {
  838.     var res = "List: " + obj + "\n";
  839.     for(var list in obj) {        
  840.         if (list.indexOf(s) != -1)
  841.             res += list + ", ";
  842.     }
  843.         
  844.     return res;
  845. }
  846.  
  847.