Guest User

Untitled

a guest
Sep 30th, 2014
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.   // Send the file name and line number of any error message. This will help us
  2.   // to trace down any frequent errors we can't confirm ourselves.
  3.   window.addEventListener("error", function(e) {
  4.     var str = "Error: " +
  5.              (e.filename||"anywhere").replace(chrome.extension.getURL(""), "") +
  6.              ":" + (e.lineno||"anywhere");
  7.     if (chrome && chrome.runtime && (chrome.runtime.id === "pljaalgmajnlogcgiohkhdmgpomjcihk")) {
  8.         var stack = "-" + ((e.error && e.error.message)||"") +
  9.                     "-" + ((e.error && e.error.stack)||"");
  10.         stack = stack.replace(/:/gi, ";").replace(/\n/gi, "");
  11.         str += stack;
  12.     }
  13.     //check to see if there's any URL info in the stack trace, if so, don't log it
  14.     if (str.indexOf("http") >= 0) {
  15.        return;
  16.     }
  17.     STATS.msg(str);
  18.     sessionStorage.setItem("errorOccurred", true);
  19.     storage_set("error", str);
  20.     log(str);
  21.   });
  22.  
  23.   if (!SAFARI) {
  24.     // Records how many ads have been blocked by AdBlock.  This is used
  25.     // by the AdBlock app in the Chrome Web Store to display statistics
  26.     // to the user.
  27.     var blockCounts = (function() {
  28.       var key = "blockage_stats";
  29.       var data = storage_get(key);
  30.       if (!data)
  31.         data = {};
  32.       if (data.start === undefined)
  33.         data.start = Date.now();
  34.       if (data.total === undefined)
  35.         data.total = 0;
  36.       data.version = 1;
  37.       storage_set(key, data);
  38.  
  39.       return {
  40.         recordOneAdBlocked: function(tabId) {
  41.           var data = storage_get(key);
  42.           data.total += 1;
  43.           storage_set(key, data);
  44.  
  45.           //code for incrementing ad blocks
  46.           currentTab = frameData.get(tabId);
  47.           if(currentTab){
  48.             currentTab.blockCount++;
  49.           }
  50.         },
  51.         get: function() {
  52.           return storage_get(key);
  53.         },
  54.         getTotalAdsBlocked: function(tabId){
  55.           if(tabId){
  56.             currentTab = frameData.get(tabId);
  57.             return currentTab ? currentTab.blockCount : 0;
  58.           }
  59.           return this.get().total;
  60.         }
  61.       };
  62.     })();
  63.  
  64.   }
  65.  
  66.   //called from bandaids, for use on our getadblock.com site
  67.   var get_adblock_user_id = function() {
  68.     return storage_get("userid");
  69.   };
  70.  
  71.   //called from bandaids, for use on our getadblock.com site
  72.   var get_first_run = function() {
  73.     return STATS.firstRun;
  74.   };
  75.  
  76.   //called from bandaids, for use on our getadblock.com site
  77.   var set_first_run_to_false = function() {
  78.     STATS.firstRun = false;
  79.   };
  80.  
  81.   // OPTIONAL SETTINGS
  82.  
  83.   function Settings() {
  84.     var defaults = {
  85.       debug_logging: false,
  86.       youtube_channel_whitelist: false,
  87.       show_google_search_text_ads: false,
  88.       whitelist_hulu_ads: false, // Issue 7178
  89.       show_context_menu_items: true,
  90.       show_advanced_options: false,
  91.       display_stats: true,
  92.       show_block_counts_help_link: true,
  93.       dropbox_sync: false,
  94.       show_survey: true,
  95.     };
  96.     var settings = storage_get('settings') || {};
  97.     this._data = $.extend(defaults, settings);
  98.  
  99.   };
  100.   Settings.prototype = {
  101.     set: function(name, is_enabled) {
  102.       this._data[name] = is_enabled;
  103.       // Don't store defaults that the user hasn't modified
  104.       var stored_data = storage_get("settings") || {};
  105.       stored_data[name] = is_enabled;
  106.       storage_set('settings', stored_data);
  107.     },
  108.     get_all: function() {
  109.       return this._data;
  110.     }
  111.   };
  112.   _settings = new Settings();
  113.  
  114.   // Open a new tab with a given URL.
  115.   // Inputs:
  116.   //   url: string - url for the tab
  117.   //   nearActive: bool - open the tab near currently active (instead of at the end). optional, defaults to false
  118.   //   safariWindow (Safari only): window object - window where the tab will be created. optional, defaults
  119.   //     to active window. Because Safari supports clickthrough on extension elements, Safari code will almost
  120.   //    always need to pass this argument. Chrome doesn't support it, so leave this argument empty in Chrome code.
  121.   function openTab(url, nearActive, safariWindow) {
  122.     if (!SAFARI) {
  123.       if (!nearActive) {
  124.         chrome.tabs.create({url: url});
  125.       } else {
  126.         chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  127.            chrome.tabs.create({ url: url, index: (tabs[0] ? tabs[0].index + 1 : undefined) });
  128.         });
  129.       }
  130.     } else {
  131.       safariWindow = safariWindow || safari.application.activeBrowserWindow;
  132.       var index = undefined;
  133.       if (nearActive && safariWindow && safariWindow.activeTab) {
  134.         for (var i = 0; i < safariWindow.tabs.length; i++) {
  135.           if (safariWindow.tabs[i] === safariWindow.activeTab) {
  136.             index = i + 1;
  137.             break;
  138.           }
  139.         }
  140.       }
  141.       var tab;
  142.       if (safariWindow) {
  143.         tab = safariWindow.openTab("foreground", index); // index may be undefined
  144.         if (!safariWindow.visible) {
  145.           safariWindow.activate();
  146.         }
  147.       } else {
  148.         tab = safari.application.openBrowserWindow().tabs[0];
  149.       }
  150.       var relative = (!/:\/\//.test(url)); // fix relative URLs
  151.       tab.url = (relative ? chrome.extension.getURL(url) : url);
  152.     }
  153.   };
  154.  
  155.   // Implement blocking via the Chrome webRequest API.
  156.   if (!SAFARI) {
  157.     // Stores url, whitelisting, and blocking info for a tabid+frameid
  158.     // TODO: can we avoid making this a global?
  159.     frameData = {
  160.       // Returns the data object for the frame with ID frameId on the tab with
  161.       // ID tabId. If frameId is not specified, it'll return the data for all
  162.       // frames on the tab with ID tabId. Returns undefined if tabId and frameId
  163.       // are not being tracked.
  164.       get: function(tabId, frameId) {
  165.         if (frameId !== undefined)
  166.           return (frameData[tabId] || {})[frameId];
  167.         return frameData[tabId];
  168.       },
  169.  
  170.       // Record that |tabId|, |frameId| points to |url|.
  171.       record: function(tabId, frameId, url) {
  172.         var fd = frameData;
  173.         if (!fd[tabId]) fd[tabId] = {};
  174.         fd[tabId][frameId] = {
  175.           url: url,
  176.           // Cache these as they'll be needed once per request
  177.           domain: parseUri(url).hostname,
  178.           resources: {}
  179.         };
  180.         if (frameId === 0) {
  181.           fd[tabId][frameId].whitelisted = page_is_whitelisted(url);
  182.         }
  183.       },
  184.  
  185.       // Watch for requests for new tabs and frames, and track their URLs.
  186.       // Inputs: details: object from onBeforeRequest callback
  187.       // Returns false if this request's tab+frame are not trackable.
  188.       track: function(details) {
  189.         var fd = frameData, tabId = details.tabId;
  190.  
  191.         // A hosted app's background page
  192.         if (tabId === -1) {
  193.            return false;
  194.         }
  195.  
  196.         if (details.type === 'main_frame') { // New tab
  197.           delete fd[tabId];
  198.           fd.record(tabId, 0, details.url);
  199.           fd[tabId].blockCount = 0;
  200.           log("\n-------", fd.get(tabId, 0).domain, ": loaded in tab", tabId, "--------\n\n");
  201.           return true;
  202.         }
  203.  
  204.         // Request from a tab opened before AdBlock started, or from a
  205.         // chrome:// tab containing an http:// iframe
  206.         if (!fd[tabId]) {
  207.           log("[DEBUG]", "Ignoring unknown tab:", tabId, details.frameId, details.url);
  208.           return false;
  209.         }
  210.  
  211.         // Some times e.g. Youtube create empty iframes via JavaScript and
  212.         // inject code into them.  So requests appear from unknown frames.
  213.         // Treat these frames as having the same URL as the tab.
  214.         var potentialEmptyFrameId = (details.type === 'sub_frame' ? details.parentFrameId: details.frameId);
  215.         if (undefined === fd.get(tabId, potentialEmptyFrameId)) {
  216.           fd.record(tabId, potentialEmptyFrameId, fd.get(tabId, 0).url);
  217.           log("[DEBUG]", "Null frame", tabId, potentialEmptyFrameId, "found; giving it the tab's URL.");
  218.         }
  219.  
  220.         if (details.type === 'sub_frame') { // New frame
  221.           fd.record(tabId, details.frameId, details.url);
  222.           log("[DEBUG]", "=========== Tracking frame", tabId, details.parentFrameId, details.frameId, details.url);
  223.         }
  224.  
  225.         return true;
  226.       },
  227.  
  228.       // Record a resource for the resource blocker.
  229.       storeResource: function(tabId, frameId, url, elType) {
  230.         if (!get_settings().show_advanced_options)
  231.           return;
  232.         var data = frameData.get(tabId, frameId);
  233.         if (data !== undefined)
  234.           data.resources[elType + ':|:' + url] = null;
  235.       },
  236.  
  237.       // When a tab is closed, delete all its data
  238.       onTabClosedHandler: function(tabId) {
  239.         log("[DEBUG]", "----------- Closing tab", tabId);
  240.         delete frameData[tabId];
  241.       }
  242.     };
  243.  
  244.     // When a request starts, perhaps block it.
  245.     function onBeforeRequestHandler(details) {
  246.       if (adblock_is_paused())
  247.         return { cancel: false };
  248.  
  249.       if (!frameData.track(details))
  250.         return { cancel: false };
  251.  
  252.       var tabId = details.tabId;
  253.       var elType = ElementTypes.fromOnBeforeRequestType(details.type);
  254.  
  255.       if (frameData.get(tabId, 0).whitelisted) {
  256.         log("[DEBUG]", "Ignoring whitelisted tab", tabId, details.url.substring(0, 100));
  257.         return { cancel: false };
  258.       }
  259.  
  260.       // For most requests, Chrome and we agree on who sent the request: the frame.
  261.       // But for iframe loads, we consider the request to be sent by the outer
  262.       // frame, while Chrome claims it's sent by the new iframe.  Adjust accordingly.
  263.       var requestingFrameId = (details.type === 'sub_frame' ? details.parentFrameId : details.frameId);
  264.  
  265.       frameData.storeResource(tabId, requestingFrameId, details.url, elType);
  266.  
  267.       // May the URL be loaded by the requesting frame?
  268.       var frameDomain = frameData.get(tabId, requestingFrameId).domain;
  269.       var blocked = _myfilters.blocking.matches(details.url, elType, frameDomain);
  270.  
  271.       // Issue 7178
  272.       if (blocked && frameDomain === "www.hulu.com") {
  273.         if (frameData.get(tabId, 0).domain !== "www.hulu.com"
  274.             && /ads\.hulu\.com/.test(details.url)) // good enough
  275.           blocked = false;
  276.       }
  277.  
  278.       var canPurge = (elType & (ElementTypes.image | ElementTypes.subdocument | ElementTypes.object));
  279.       if (canPurge && blocked) {
  280.         // frameUrl is used by the recipient to determine whether they're the frame who should
  281.         // receive this or not.  Because the #anchor of a page can change without navigating
  282.         // the frame, ignore the anchor when matching.
  283.         var frameUrl = frameData.get(tabId, requestingFrameId).url.replace(/#.*$/, "");
  284.         var data = { command: "purge-elements", tabId: tabId, frameUrl: frameUrl, url:details.url, elType: elType };
  285.         chrome.tabs.sendRequest(tabId, data);
  286.       }
  287.  
  288.       if (blocked){
  289.         blockCounts.recordOneAdBlocked(tabId);
  290.         updateBadge(tabId);
  291.       }
  292.       log("[DEBUG]", "Block result", blocked, details.type, frameDomain, details.url.substring(0, 100));
  293.       if (blocked && elType === ElementTypes.image) {
  294.         // 1x1 px transparant image.
  295.         // Same URL as ABP and Ghostery to prevent conflict warnings (issue 7042)
  296.         return {redirectUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="};
  297.       }
  298.       if (blocked && elType === ElementTypes.subdocument) {
  299.         return { redirectUrl: "about:blank" };
  300.       }
  301.       return { cancel: blocked };
  302.     }
  303.  
  304.     // Popup blocking
  305.     function onCreatedNavigationTargetHandler(details) {
  306.       if (adblock_is_paused())
  307.           return;
  308.       var opener = frameData.get(details.sourceTabId, details.sourceFrameId);
  309.       if (opener === undefined)
  310.         return;
  311.       if (frameData.get(details.sourceTabId, 0).whitelisted)
  312.         return;
  313.       // Change to opener's url in so that it would still be tested against the
  314.       // blocking filter's regex rule. Github issue # 69
  315.       if (details.url === "about:blank")
  316.         details.url = opener.url;
  317.       var match = _myfilters.blocking.matches(details.url, ElementTypes.popup, opener.domain);
  318.       if (match)
  319.         chrome.tabs.remove(details.tabId);
  320.       frameData.storeResource(details.sourceTabId, details.sourceFrameId, details.url, ElementTypes.popup);
  321.     };
  322.   }
  323.  
  324.   debug_report_elemhide = function(selector, matches, sender) {
  325.     if (!window.frameData)
  326.       return;
  327.     frameData.storeResource(sender.tab.id, 0, selector, "HIDE");
  328.     var data = frameData.get(sender.tab.id, 0);
  329.     if (data) {
  330.       log(data.domain, ": hiding rule", selector, "matched:\n", matches);
  331.       blockCounts.recordOneAdBlocked(sender.tab.id);
  332.       updateBadge(sender.tab.id);
  333.     }
  334.   }
  335.  
  336.   // UNWHITELISTING
  337.  
  338.   // Look for a custom filter that would whitelist options.url,
  339.   // and if any exist, remove the first one.
  340.   // Inputs: url:string - a URL that may be whitelisted by a custom filter
  341.   // Returns: true if a filter was found and removed; false otherwise.
  342.   try_to_unwhitelist = function(url) {
  343.       url = url.replace(/#.*$/, ''); // Whitelist ignores anchors
  344.       var custom_filters = get_custom_filters_text().split('\n');
  345.       for (var i = 0; i < custom_filters.length; i++) {
  346.           var text = custom_filters[i];
  347.           var whitelist = text.search(/@@\*\$document,domain=\~/);
  348.           // Blacklist site, which is whitelisted by global @@*&document,domain=~ filter
  349.           if (whitelist > -1) {
  350.               // Remove protocols
  351.               url = url.replace(/((http|https):\/\/)?(www.)?/, "").split(/[/?#]/)[0];
  352.  
  353.               text = text + "|~" + url;
  354.               set_custom_filters_text(text);
  355.               return true;
  356.           } else {
  357.               if (!Filter.isWhitelistFilter(text))
  358.                   continue;
  359.               try {
  360.                   var filter = PatternFilter.fromText(text);
  361.               } catch (ex) {
  362.                   continue;
  363.               }
  364.               if (!filter.matches(url, ElementTypes.document, false))
  365.                   continue;
  366.  
  367.               custom_filters.splice(i, 1); // Remove this whitelist filter text
  368.               var new_text = custom_filters.join('\n');
  369.               set_custom_filters_text(new_text);
  370.               return true;
  371.           }
  372.       }
  373.       return false;
  374.   }
  375.  
  376.   // Called when Chrome blocking needs to clear the in-memory cache.
  377.   // No-op for Safari.
  378.   handlerBehaviorChanged = function() {
  379.     if (SAFARI)
  380.       return;
  381.     try {
  382.       chrome.webRequest.handlerBehaviorChanged();
  383.     } catch (ex) {
  384.     }
  385.   }
  386.  
  387.   // CUSTOM FILTERS
  388.  
  389.   // Get the custom filters text as a \n-separated text string.
  390.   get_custom_filters_text = function() {
  391.     return storage_get('custom_filters') || '';
  392.   }
  393.  
  394.   // Set the custom filters to the given \n-separated text string, and
  395.   // rebuild the filterset.
  396.   // Inputs: filters:string the new filters.
  397.   set_custom_filters_text = function(filters) {
  398.     storage_set('custom_filters', filters);
  399.     chrome.extension.sendRequest({command: "filters_updated"});
  400.     _myfilters.rebuild();
  401.     if (!SAFARI && db_client.isAuthenticated())
  402.         settingstable.set("custom_filters", localStorage.custom_filters);
  403.   }
  404.  
  405.   // Removes a custom filter entry.
  406.   // Inputs: host:domain of the custom filters to be reset.
  407.   remove_custom_filter = function(host) {
  408.     var text = get_custom_filters_text();
  409.     var custom_filters_arr = text ? text.split("\n"):[];
  410.     var new_custom_filters_arr = [];
  411.     var identifier = host;
  412.  
  413.     for(var i = 0; i < custom_filters_arr.length; i++) {
  414.       var entry = custom_filters_arr[i];
  415.       //Make sure that the identifier is at the start of the entry
  416.       if(entry.indexOf(identifier) === 0) { continue; }
  417.       new_custom_filters_arr.push(entry);
  418.     }
  419.  
  420.     text = new_custom_filters_arr.join("\n");
  421.     set_custom_filters_text(text.trim());
  422.   }
  423.  
  424.   // count_cache singleton.
  425.   var count_cache = (function(count_map) {
  426.     var cache = count_map;
  427.     // Update custom filter count stored in localStorage
  428.     var _updateCustomFilterCount = function() {
  429.       storage_set("custom_filter_count", cache);
  430.     };
  431.  
  432.     return {
  433.       // Update custom filter count cache and value stored in localStorage.
  434.       // Inputs: new_count_map:count map - count map to replace existing count cache
  435.       updateCustomFilterCountMap: function(new_count_map) {
  436.         cache = new_count_map || cache;
  437.         _updateCustomFilterCount();
  438.       },
  439.       // Remove custom filter count for host
  440.       // Inputs: host:string - url of the host
  441.       removeCustomFilterCount: function(host) {
  442.         if(host && cache[host]) {
  443.           delete cache[host];
  444.           _updateCustomFilterCount();
  445.         }
  446.       },
  447.       // Get current custom filter count for a particular domain
  448.       // Inputs: host:string - url of the host
  449.       getCustomFilterCount: function(host) {
  450.         return cache[host] || 0;
  451.       },
  452.       // Add 1 to custom filter count for the filters domain.
  453.       // Inputs: filter:string - line of text to be added to custom filters.
  454.       addCustomFilterCount: function(filter) {
  455.         var host = filter.split("##")[0];
  456.         cache[host] = this.getCustomFilterCount(host) + 1;
  457.         _updateCustomFilterCount();
  458.       }
  459.     }
  460.   })(storage_get("custom_filter_count") || {});
  461.  
  462.   // Entry point for customize.js, used to update custom filter count cache.
  463.   updateCustomFilterCountMap = function(new_count_map) {
  464.     count_cache.updateCustomFilterCountMap(new_count_map);
  465.   }
  466.  
  467.   remove_custom_filter_for_host = function(host) {
  468.     if(count_cache.getCustomFilterCount(host)) {
  469.       remove_custom_filter(host);
  470.       count_cache.removeCustomFilterCount(host);
  471.     }
  472.   }
  473.  
  474.   confirm_removal_of_custom_filters_on_host = function(host) {
  475.     var custom_filter_count = count_cache.getCustomFilterCount(host);
  476.     var confirmation_text   = translate("confirm_undo_custom_filters", [custom_filter_count, host]);
  477.     if (!confirm(confirmation_text)) { return; }
  478.     remove_custom_filter_for_host(host);
  479.     chrome.tabs.reload();
  480.   };
  481.  
  482.   get_settings = function() {
  483.     return _settings.get_all();
  484.   }
  485.  
  486.   set_setting = function(name, is_enabled, sync) {
  487.     _settings.set(name, is_enabled);
  488.  
  489.     if (name === "debug_logging")
  490.       logging(is_enabled);
  491.  
  492.     if (!SAFARI && sync) {
  493.         sync_setting(name, is_enabled);
  494.     }
  495.   }
  496.  
  497.   // MYFILTERS PASSTHROUGHS
  498.  
  499.   // Rebuild the filterset based on the current settings and subscriptions.
  500.   update_filters = function() {
  501.     _myfilters.rebuild();
  502.   }
  503.  
  504.   // Fetch the latest version of all subscribed lists now.
  505.   update_subscriptions_now = function() {
  506.     _myfilters.checkFilterUpdates(true);
  507.   }
  508.  
  509.   // Returns map from id to subscription object.  See filters.js for
  510.   // description of subscription object.
  511.   get_subscriptions_minus_text = function() {
  512.     var result = {};
  513.     for (var id in _myfilters._subscriptions) {
  514.       result[id] = {};
  515.       for (var attr in _myfilters._subscriptions[id]) {
  516.         if (attr === "text") continue;
  517.         result[id][attr] = _myfilters._subscriptions[id][attr];
  518.       }
  519.     }
  520.     return result;
  521.   }
  522.  
  523.   // Get subscribed filter lists
  524.   get_subscribed_filter_lists = function() {
  525.       var subs = get_subscriptions_minus_text();
  526.       var subscribed_filter_names = [];
  527.       for (var id in subs) {
  528.           if (subs[id].subscribed)
  529.               subscribed_filter_names.push(id);
  530.       }
  531.       return subscribed_filter_names;
  532.   }
  533.  
  534.   // Subscribes to a filter subscription.
  535.   // Inputs: id: id to which to subscribe.  Either a well-known
  536.   //             id, or "url:xyz" pointing to a user-specified list.
  537.   //         requires: the id of a list if it is a supplementary list,
  538.   //                   or null if nothing required
  539.   // Returns: null, upon completion
  540.   subscribe = function(options, sync) {
  541.       _myfilters.changeSubscription(options.id, {
  542.           subscribed: true,
  543.           requiresList: options.requires
  544.       });
  545.       if (!SAFARI && sync !== true && db_client.isAuthenticated()) {
  546.           settingstable.set("filter_lists", get_subscribed_filter_lists().toString());
  547.       }
  548.   }
  549.  
  550.   // Unsubscribes from a filter subscription.
  551.   // Inputs: id: id from which to unsubscribe.
  552.   //         del: (bool) if the filter should be removed or not
  553.   // Returns: null, upon completion.
  554.   unsubscribe = function(options, sync) {
  555.       _myfilters.changeSubscription(options.id, {
  556.           subscribed: false,
  557.           deleteMe: (options.del ? true : undefined)
  558.       });
  559.       if (!SAFARI && sync !== true && db_client.isAuthenticated()) {
  560.           settingstable.set("filter_lists", get_subscribed_filter_lists().toString());
  561.       }
  562.   }
  563.  
  564.   // Returns true if the url cannot be blocked
  565.   page_is_unblockable = function(url) {
  566.     if (!url) { // Safari empty/bookmarks/top sites page
  567.       return true;
  568.     } else {
  569.       var scheme = parseUri(url).protocol;
  570.       return (scheme !== 'http:' && scheme !== 'https:' && scheme !== 'feed:');
  571.     }
  572.   }
  573.  
  574.   // Get or set if AdBlock is paused
  575.   // Inputs: newValue (optional boolean): if true, AdBlock will be paused, if
  576.   //                  false, AdBlock will not be paused.
  577.   // Returns: undefined if newValue was specified, otherwise it returns true
  578.   //          if paused, false otherwise.
  579.   adblock_is_paused = function(newValue) {
  580.     if (newValue === undefined) {
  581.       return sessionStorage.getItem('adblock_is_paused') === "true";
  582.     }
  583.     sessionStorage.setItem('adblock_is_paused', newValue);
  584.   }
  585.  
  586.   // INFO ABOUT CURRENT PAGE
  587.  
  588.   // Get interesting information about the current tab.
  589.   // Inputs:
  590.   //   callback: function(info).
  591.   //   info object passed to callback: {
  592.   //     tab: Tab object
  593.   //     whitelisted: bool - whether the current tab's URL is whitelisted.
  594.   //     disabled_site: bool - true if the url is e.g. about:blank or the
  595.   //                           Extension Gallery, where extensions don't run.
  596.   //     total_blocked: int - # of ads blocked since install
  597.   //     tab_blocked: int - # of ads blocked on this tab
  598.   //     display_stats: bool - whether block counts are displayed on button
  599.   //   }
  600.   // Returns: null (asynchronous)
  601.   getCurrentTabInfo = function(callback, secondTime) {
  602.     chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  603.       if (tabs.length === 0)
  604.         return; // For example: only the background devtools or a popup are opened
  605.       var tab = tabs[0];
  606.  
  607.       if (tab && !tab.url) {
  608.         // Issue 6877: tab URL is not set directly after you opened a window
  609.         // using window.open()
  610.         if (!secondTime)
  611.           window.setTimeout(function() {
  612.             getCurrentTabInfo(callback, true);
  613.           }, 250);
  614.         return;
  615.       }
  616.  
  617.       var disabled_site = page_is_unblockable(tab.url);
  618.       var total_blocked = blockCounts.getTotalAdsBlocked();
  619.       var tab_blocked = blockCounts.getTotalAdsBlocked(tab.id);
  620.       var display_stats = get_settings().display_stats;
  621.  
  622.       var result = {
  623.         tab: tab,
  624.         disabled_site: disabled_site,
  625.         total_blocked: total_blocked,
  626.         tab_blocked: tab_blocked,
  627.         display_stats: display_stats
  628.       };
  629.       if (!disabled_site)
  630.         result.whitelisted = page_is_whitelisted(tab.url);
  631.  
  632.       callback(result);
  633.     });
  634.   }
  635.  
  636.   // Returns true if anything in whitelist matches the_domain.
  637.   //   url: the url of the page
  638.   //   type: one out of ElementTypes, default ElementTypes.document,
  639.   //         to check what the page is whitelisted for: hiding rules or everything
  640.   page_is_whitelisted = function(url, type) {
  641.     if (!url) { // Safari empty/bookmarks/top sites page
  642.       return true;
  643.     }
  644.     url = url.replace(/\#.*$/, ''); // Remove anchors
  645.     if (!type)
  646.       type = ElementTypes.document;
  647.     var whitelist = _myfilters.blocking.whitelist;
  648.     return whitelist.matches(url, type, parseUri(url).hostname, false);
  649.   }
  650.  
  651.   updateDisplayStats = function(isChecked, tabId) {
  652.     set_setting("display_stats", isChecked);
  653.     updateBadge(tabId);
  654.   }
  655.  
  656.   if (!SAFARI) {
  657.     updateBadge = function(tabId) {
  658.       var display = get_settings().display_stats;
  659.       var badge_text = "";
  660.       var main_frame = frameData.get(tabId, 0);
  661.       // main_frame is undefined if the tab is a new one, so no use updating badge.
  662.       if (!main_frame) return;
  663.  
  664.       var isBlockable = !page_is_unblockable(main_frame.url) && !page_is_whitelisted(main_frame.url) && !/chrome\/newtab/.test(main_frame.url);
  665.  
  666.       if(display && (main_frame && isBlockable) && !adblock_is_paused()){
  667.         badge_text = blockCounts.getTotalAdsBlocked(tabId).toString();
  668.         if (badge_text === "0")
  669.           badge_text = ""; // Only show the user when we've done something useful
  670.       }
  671.       chrome.browserAction.setBadgeText({text: badge_text, tabId: tabId});
  672.       chrome.browserAction.setBadgeBackgroundColor({ color: "#555" });
  673.     };
  674.  
  675.     // Set the button image and context menus according to the URL
  676.     // of the current tab.
  677.     updateButtonUIAndContextMenus = function() {
  678.  
  679.       function setContextMenus(info) {
  680.         chrome.contextMenus.removeAll();
  681.         if (!get_settings().show_context_menu_items)
  682.           return;
  683.  
  684.         if (adblock_is_paused() || info.whitelisted || info.disabled_site)
  685.           return;
  686.  
  687.         function addMenu(title, callback) {
  688.           chrome.contextMenus.create({
  689.             title: title,
  690.             contexts: ["all"],
  691.             onclick: function(clickdata, tab) { callback(tab, clickdata); }
  692.           });
  693.         }
  694.  
  695.         addMenu(translate("block_this_ad"), function(tab, clickdata) {
  696.           emit_page_broadcast(
  697.             {fn:'top_open_blacklist_ui', options:{info: clickdata}},
  698.             {tab: tab}
  699.           );
  700.         });
  701.  
  702.         addMenu(translate("block_an_ad_on_this_page"), function(tab) {
  703.           emit_page_broadcast(
  704.             {fn:'top_open_blacklist_ui', options:{nothing_clicked: true}},
  705.             {tab: tab}
  706.           );
  707.         });
  708.  
  709.         var host                = parseUri(info.tab.url).host;
  710.         var custom_filter_count = count_cache.getCustomFilterCount(host);
  711.         if (custom_filter_count) {
  712.           addMenu(translate("undo_last_block"), function(tab) {
  713.             confirm_removal_of_custom_filters_on_host(host);
  714.           });
  715.         }
  716.       }
  717.  
  718.       function setBrowserButton(info) {
  719.         var tabId = info.tab.id;
  720.         chrome.browserAction.setBadgeText({text: "", tabId: tabId});
  721.         if (adblock_is_paused()) {
  722.           chrome.browserAction.setIcon({path:{'19': "img/icon19-grayscale.png", '38': "img/icon38-grayscale.png"}, tabId: tabId});
  723.         } else if (info.disabled_site &&
  724.             !/^chrome-extension:.*pages\/install\//.test(info.tab.url)) {
  725.           // Show non-disabled icon on the installation-success page so it
  726.           // users see how it will normally look. All other disabled pages
  727.           // will have the gray one
  728.           chrome.browserAction.setIcon({path:{'19': "img/icon19-grayscale.png", '38': "img/icon38-grayscale.png"}, tabId: tabId});
  729.         } else if (info.whitelisted) {
  730.           chrome.browserAction.setIcon({path:{'19': "img/icon19-whitelisted.png", '38': "img/icon38-whitelisted.png"}, tabId: tabId});
  731.         } else {
  732.           chrome.browserAction.setIcon({path:{'19': "img/icon19.png", '38': "img/icon38.png"}, tabId: tabId});
  733.           updateBadge(tabId);
  734.         }
  735.       }
  736.  
  737.       getCurrentTabInfo(function(info) {
  738.         setContextMenus(info);
  739.         setBrowserButton(info);
  740.       });
  741.     }
  742.   }
  743.  
  744.   // These functions are usually only called by content scripts.
  745.  
  746.   // Add a new custom filter entry.
  747.   // Inputs: filter:string line of text to add to custom filters.
  748.   // Returns: null if succesfull, otherwise an exception
  749.   add_custom_filter = function(filter) {
  750.     var custom_filters = get_custom_filters_text();
  751.     try {
  752.       if (FilterNormalizer.normalizeLine(filter)) {
  753.         if (Filter.isSelectorFilter(filter)) {
  754.           count_cache.addCustomFilterCount(filter);
  755.           if (!SAFARI)
  756.             updateButtonUIAndContextMenus();
  757.         }
  758.         custom_filters = custom_filters + '\n' + filter;
  759.         set_custom_filters_text(custom_filters);
  760.         return null;
  761.       }
  762.       return "This filter is unsupported";
  763.     } catch(ex) {
  764.       return ex;
  765.     }
  766.   };
  767.  
  768.   // Return the contents of a local file.
  769.   // Inputs: file:string - the file relative address, eg "js/foo.js".
  770.   // Returns: the content of the file.
  771.   readfile = function(file) {
  772.     // A bug in jquery prevents local files from being read, so use XHR.
  773.     var xhr = new XMLHttpRequest();
  774.     xhr.open("GET", chrome.extension.getURL(file), false);
  775.     xhr.send();
  776.     return xhr.responseText;
  777.   };
  778.  
  779.   // Creates a custom filter entry that whitelists a given page
  780.   // Inputs: url:string url of the page
  781.   // Returns: null if successful, otherwise an exception
  782.   create_page_whitelist_filter = function(url) {
  783.     var url = url.replace(/#.*$/, '');  // Remove anchors
  784.     var parts = url.match(/^([^\?]+)(\??)/); // Detect querystring
  785.     var has_querystring = parts[2];
  786.     var filter = '@@|' + parts[1] + (has_querystring ? '?' : '|') + '$document';
  787.     return add_custom_filter(filter);
  788.   }
  789.  
  790.   // Creates a custom filter entry that whitelists YouTube channel
  791.   // Inputs: url:string url of the page
  792.   // Returns: null if successful, otherwise an exception
  793.   create_whitelist_filter_for_youtube_channel = function(url) {
  794.     if (/channel/.test(url)) {
  795.       var get_channel = url.match(/channel=([^]*)/)[1];
  796.     } else {
  797.       var get_channel = url.split('/').pop();
  798.     }
  799.     var filter = '@@||youtube.com/*' + get_channel + '$document';
  800.     return add_custom_filter(filter);
  801.   }
  802.  
  803.   // Inputs: options object containing:
  804.   //           domain:string the domain of the calling frame.
  805.   get_content_script_data = function(options, sender) {
  806.     var settings = get_settings();
  807.     var runnable = !adblock_is_paused() && !page_is_unblockable(sender.tab.url);
  808.     var running = runnable && !page_is_whitelisted(sender.tab.url);
  809.     var hiding = running && !page_is_whitelisted(sender.tab.url,
  810.                                                         ElementTypes.elemhide);
  811.     var result = {
  812.       settings: settings,
  813.       runnable: runnable,
  814.       running: running,
  815.       hiding: hiding
  816.     };
  817.  
  818.     if (hiding) {
  819.       result.selectors = _myfilters.hiding.filtersFor(options.domain);
  820.     }
  821.     return result;
  822.   };
  823.  
  824.   // Bounce messages back to content scripts.
  825.   if (!SAFARI) {
  826.     emit_page_broadcast = (function() {
  827.       var injectMap = {
  828.         'top_open_whitelist_ui': {
  829.           allFrames: false,
  830.           include: [
  831.             "jquery/jquery.min.js",
  832.             "jquery/jquery-ui.custom.min.js",
  833.             "uiscripts/load_jquery_ui.js",
  834.             "uiscripts/top_open_whitelist_ui.js"
  835.             ]
  836.         },
  837.         'top_open_blacklist_ui': {
  838.           allFrames: false,
  839.           include: [
  840.             "jquery/jquery.min.js",
  841.             "jquery/jquery-ui.custom.min.js",
  842.             "uiscripts/load_jquery_ui.js",
  843.             "uiscripts/blacklisting/overlay.js",
  844.             "uiscripts/blacklisting/clickwatcher.js",
  845.             "uiscripts/blacklisting/elementchain.js",
  846.             "uiscripts/blacklisting/blacklistui.js",
  847.             "uiscripts/top_open_blacklist_ui.js"
  848.             ]
  849.         },
  850.         'send_content_to_back': {
  851.           allFrames: true,
  852.           include: [
  853.             "uiscripts/send_content_to_back.js"
  854.             ]
  855.         }
  856.       };
  857.       // Inject the required scripts to execute fn_name(parameter) in
  858.       // the current tab.
  859.       // Inputs: fn_name:string name of function to execute on tab.
  860.       //         fn_name must exist in injectMap above.
  861.       //         parameter:object to pass to fn_name.  Must be JSON.stringify()able.
  862.       //         injectedSoFar?:int used to recursively inject required scripts.
  863.       var executeOnTab = function(fn_name, parameter, injectedSoFar) {
  864.         injectedSoFar = injectedSoFar || 0;
  865.         var data = injectMap[fn_name];
  866.         var details = { allFrames: data.allFrames };
  867.         // If there's anything to inject, inject the next item and recurse.
  868.         if (data.include.length > injectedSoFar) {
  869.           details.file = data.include[injectedSoFar];
  870.           chrome.tabs.executeScript(undefined, details, function() {
  871.             executeOnTab(fn_name, parameter, injectedSoFar + 1);
  872.           });
  873.         }
  874.         // Nothing left to inject, so execute the function.
  875.         else {
  876.           var param = JSON.stringify(parameter);
  877.           details.code = fn_name + "(" + param + ");";
  878.           chrome.tabs.executeScript(undefined, details);
  879.         }
  880.       };
  881.  
  882.       // The emit_page_broadcast() function
  883.       var theFunction = function(request) {
  884.         executeOnTab(request.fn, request.options);
  885.       };
  886.       return theFunction;
  887.     })();
  888.   }
  889.  
  890.   // Open the resource blocker when requested from the Chrome popup.
  891.   launch_resourceblocker = function(query) {
  892.     openTab("pages/resourceblock.html" + query, true);
  893.   }
  894.  
  895.   // Open subscribe popup when new filter list was subscribed from site
  896.   launch_subscribe_popup = function(loc) {
  897.     window.open(chrome.extension.getURL('pages/subscribe.html?' + loc),
  898.     "_blank",
  899.     'scrollbars=0,location=0,resizable=0,width=450,height=140');
  900.   }
  901.  
  902.   // Get the framedata for resourceblock
  903.   resourceblock_get_frameData = function(tabId) {
  904.     return frameData.get(tabId);
  905.   }
  906.  
  907.   // Return chrome.i18n._getL10nData() for content scripts who cannot
  908.   // call that function (since it loads extension files from disk.)
  909.   // Only defined in Safari.
  910.   get_l10n_data = (SAFARI ? chrome.i18n._getL10nData : undefined);
  911.  
  912.  
  913.   // BGcall DISPATCH
  914.   (function() {
  915.     chrome.extension.onRequest.addListener(
  916.       function(request, sender, sendResponse) {
  917.         if (request.command != "call")
  918.           return; // not for us
  919.         // +1 button in browser action popup loads a frame which
  920.         // runs content scripts.  Ignore their cries for ad blocking.
  921.         if ((sender.tab === undefined) || (sender.tab === null))
  922.           return;
  923.         var fn = window[request.fn];
  924.         request.args.push(sender);
  925.         var result = fn.apply(window, request.args);
  926.         sendResponse(result);
  927.       }
  928.     );
  929.   })();
  930.  
  931.   // BROWSER ACTION AND CONTEXT MENU UPDATES
  932.   (function() {
  933.     if (SAFARI)
  934.       return;
  935.  
  936.     //TEMP: until crbug.com/60435 is fixed, check if chrome.tabs exists.
  937.     //Otherwise the extension doesn't work (e.g. doesn't block ads)
  938.     if (chrome.tabs) {
  939.       chrome.tabs.onUpdated.addListener(function(tabid, changeInfo, tab) {
  940.         if (tab.active && changeInfo.status === "loading")
  941.           updateButtonUIAndContextMenus();
  942.       });
  943.       chrome.tabs.onActivated.addListener(function() {
  944.         updateButtonUIAndContextMenus();
  945.       });
  946.  
  947.       // Github Issue # 69 and 11
  948.       if (OPERA) {
  949.         chrome.tabs.onCreated.addListener(function(tab) {
  950.           chrome.tabs.get(tab.id, function(tabDetails) {
  951.             // If tab is undefined (Which happens sometimes, weird),
  952.             // get out of the function
  953.             if (!tabDetails || !tabDetails.openerTabId) return;
  954.  
  955.             // Should mean that tab is a popup or was
  956.             // opened through a link.
  957.  
  958.             // Manually create the details to be passed to
  959.             // navigation target handler.
  960.             var details = {
  961.               sourceTabId: tabDetails.openerTabId,
  962.               sourceFrameId: 0,
  963.               tabId: tabDetails.id,
  964.               url: tabDetails.url || "about:blank",
  965.             }
  966.  
  967.             // Call pop up handler.
  968.             onCreatedNavigationTargetHandler(details);
  969.           });
  970.         });
  971.       }
  972.     }
  973.   })();
  974.  
  975.   if (get_settings().debug_logging)
  976.     logging(true);
  977.  
  978.   _myfilters = new MyFilters();
  979.   _myfilters.init();
  980.   // Record that we exist.
  981.   STATS.startPinging();
  982.  
  983.   if (STATS.firstRun && (SAFARI || OPERA || chrome.runtime.id !== "pljaalgmajnlogcgiohkhdmgpomjcihk")) {
  984.     openTab("https://getadblock.com/installed/?u=" + STATS.userId);
  985.   }
  986.  
  987.   if (!SAFARI) {
  988.     // Chrome blocking code.  Near the end so synchronous request handler
  989.     // doesn't hang Chrome while AdBlock initializes.
  990.     chrome.webRequest.onBeforeRequest.addListener(onBeforeRequestHandler, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]);
  991.     chrome.tabs.onRemoved.addListener(frameData.onTabClosedHandler);
  992.     // Popup blocking
  993.     if (chrome.webNavigation)
  994.       chrome.webNavigation.onCreatedNavigationTarget.addListener(onCreatedNavigationTargetHandler);
  995.  
  996.     var handleEarlyOpenedTabs = function(tabs) {
  997.       log("Found", tabs.length, "tabs that were already opened");
  998.       for (var i=0; i<tabs.length; i++) {
  999.         var currentTab = tabs[i], tabId = currentTab.id;
  1000.         if (!frameData.get(tabId)) // unknown tab
  1001.           frameData.track({url: currentTab.url, tabId: tabId, type: "main_frame"});
  1002.         updateBadge(tabId);
  1003.         // TODO: once we're able to get the parentFrameId, call
  1004.         // chrome.webNavigation.getAllFrames to 'load' the subframes
  1005.       }
  1006.     }
  1007.     chrome.tabs.query({url: "http://*/*"}, handleEarlyOpenedTabs);
  1008.     chrome.tabs.query({url: "https://*/*"}, handleEarlyOpenedTabs);
  1009.   }
  1010.  
  1011.   /* YouTube Channel Whitelist implementation */
  1012.   if (!SAFARI) {
  1013.       function run_yt_channel_whitelist(url) {
  1014.           if (/youtube.com/.test(url) && get_settings().youtube_channel_whitelist)
  1015.               chrome.tabs.executeScript({file:"ytchannel.js"});
  1016.       }
  1017.  
  1018.       chrome.tabs.onCreated.addListener(function() {
  1019.           chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function (tabs) {
  1020.             if (tabs.length === 0)
  1021.                 return;
  1022.               run_yt_channel_whitelist(tabs[0].url);
  1023.           });
  1024.       });
  1025.  
  1026.       chrome.tabs.onUpdated.addListener(function() {
  1027.           chrome.tabs.query({'active': true, 'lastFocusedWindow': true}, function (tabs) {
  1028.             if (tabs.length === 0)
  1029.                 return; // For example: only the background devtools or a popup are opened
  1030.             run_yt_channel_whitelist(tabs[0].url);
  1031.           });
  1032.       });
  1033.   }
  1034.  
  1035.   // BETA CODE
  1036.  
  1037.   if (!SAFARI && chrome.runtime.id === "pljaalgmajnlogcgiohkhdmgpomjcihk") {
  1038.       // Display beta page after each update for beta-users only
  1039.       chrome.runtime.onInstalled.addListener(function(details) {
  1040.           if (details.reason === "update" || details.reason === "install") {
  1041.               openTab("https://getadblock.com/beta");
  1042.           }
  1043.       });
  1044.   }
  1045.  
  1046.   // DEBUG INFO
  1047.  
  1048.   // Get debug info for bug reporting and ad reporting
  1049.   getDebugInfo = function() {
  1050.  
  1051.       // Get AdBlock version
  1052.       var AdBlockVersion = chrome.runtime.getManifest().version;
  1053.  
  1054.       // Get subscribed filter lists
  1055.       var subscribed_filter_names = [];
  1056.       var get_subscriptions = get_subscriptions_minus_text();
  1057.       for (var id in get_subscriptions) {
  1058.           if (get_subscriptions[id].subscribed)
  1059.               subscribed_filter_names.push(id);
  1060.       }
  1061.  
  1062.       // Get last known error
  1063.       var adblock_error = storage_get("error");
  1064.  
  1065.       // Get total pings
  1066.       var adblock_pings = storage_get("total_pings");
  1067.  
  1068.       // Get custom filters
  1069.       var adblock_custom_filters = storage_get("custom_filters");
  1070.  
  1071.       // Get settings
  1072.       var adblock_settings = [];
  1073.       var settings = get_settings();
  1074.       for (setting in settings)
  1075.           adblock_settings.push(setting+": "+get_settings()[setting] + "\n");
  1076.       adblock_settings = adblock_settings.join('');
  1077.  
  1078.       // Create debug info for a bug report or an ad report
  1079.       var info = [];
  1080.       info.push("==== Filter Lists ====");
  1081.       info.push(subscribed_filter_names.join('  \n'));
  1082.       info.push("");
  1083.       if (adblock_custom_filters) {
  1084.           info.push("==== Custom Filters ====");
  1085.           info.push(adblock_custom_filters);
  1086.           info.push("");
  1087.       }
  1088.       info.push("==== Settings ====");
  1089.       info.push(adblock_settings);
  1090.       info.push("==== Other info: ====");
  1091.       info.push("AdBlock version number: " + AdBlockVersion +
  1092.                (chrome.runtime && chrome.runtime.id === "pljaalgmajnlogcgiohkhdmgpomjcihk" ? " Beta" : ""));
  1093.       if (adblock_error)
  1094.           info.push("Last known error: " + adblock_error);
  1095.       info.push("Total pings: " + adblock_pings);
  1096.       info.push("UserAgent: " + navigator.userAgent.replace(/;/,""));
  1097.  
  1098.       return info.join('  \n');
  1099.   }
  1100.  
  1101.   // Code for making a bug report
  1102.   makeReport = function() {
  1103.       var body = [];
  1104.       body.push(chrome.i18n.getMessage("englishonly") + "!");
  1105.       body.push("");
  1106.       body.push("Please answer the following questions so that we can process your bug report, otherwise, we may have to ignore it.");
  1107.       body.push("Also, please put your name, or a screen name, and your email above so that we can contact you if needed.");
  1108.       body.push("If you don't want your report to be made public, check that box, too.");
  1109.       body.push("");
  1110.       body.push("**Can you provide detailed steps on how to reproduce the problem?**");
  1111.       body.push("");
  1112.       body.push("1. ");
  1113.       body.push("2. ");
  1114.       body.push("3. ");
  1115.       body.push("");
  1116.       body.push("**What should happen when you do the above steps**");
  1117.       body.push("");
  1118.       body.push("");
  1119.       body.push("**What actually happened?**");
  1120.       body.push("");
  1121.       body.push("");
  1122.       body.push("**Do you have any other comments? If you can, can you please attach a screenshot of the bug?**");
  1123.       body.push("");
  1124.       body.push("");
  1125.       body.push("--- The questions below are optional but VERY helpful. ---");
  1126.       body.push("");
  1127.       body.push("If unchecking all filter lists fixes the problem, which one filter" +
  1128.                 "list must you check to cause the problem again after another restart?");
  1129.       body.push("");
  1130.       body.push("Technical Chrome users: Go to chrome://extensions ->" +
  1131.                 "Developer Mode -> Inspect views: background page -> Console. " +
  1132.                 "Paste the contents here:");
  1133.       body.push("");
  1134.       body.push("====== Do not touch below this line ======");
  1135.       body.push("");
  1136.       body.push(getDebugInfo());
  1137.       var out = encodeURIComponent(body.join('  \n'));
  1138.  
  1139.       return out;
  1140.   };
  1141.  
  1142.   // SYNCHRONIZATION
  1143.  
  1144.   // Sync settings, filter lists & custom filters
  1145.   // after authentication with Dropbox
  1146.   if (!SAFARI) {
  1147.       var db_client = new Dropbox.Client({key: "3unh2i0le3dlzio"});
  1148.       var settingstable = null;
  1149.  
  1150.       // Return true, if user is authenticated
  1151.       function dropboxauth() {
  1152.           return db_client.isAuthenticated();
  1153.       }
  1154.  
  1155.       // Login with Dropbox
  1156.       function dropboxlogin() {
  1157.           db_client.authenticate(function(error, client) {
  1158.               if (error) return;
  1159.               set_setting("dropbox_sync", true);
  1160.               settingssync();
  1161.               chrome.runtime.sendMessage({message: "signedin"});
  1162.           });
  1163.       }
  1164.  
  1165.       // Logout from Dropbox
  1166.       function dropboxlogout() {
  1167.           db_client.signOut(function(error, client) {
  1168.               if (error) return;
  1169.               set_setting("dropbox_sync", false);
  1170.               chrome.runtime.sendMessage({message: "signedout"});
  1171.           });
  1172.       }
  1173.  
  1174.       function settingssync() {
  1175.           var datastoreManager = db_client.getDatastoreManager();
  1176.           datastoreManager.openDefaultDatastore(function(error, datastore) {
  1177.               if (error) return;
  1178.  
  1179.               // Create table for sync
  1180.               var table = datastore.getTable("AdBlock");
  1181.  
  1182.               // Fill table with user's settings, filter lists & custom filters
  1183.               settingstable = table.getOrInsert("settings", {
  1184.                   filter_lists: get_subscribed_filter_lists().toString(),
  1185.                   debug_logging: get_settings().debug_logging,
  1186.                   youtube_channel_whitelist: get_settings().youtube_channel_whitelist,
  1187.                   show_google_search_text_ads: get_settings().show_google_search_text_ads,
  1188.                   whitelist_hulu_ads: get_settings().whitelist_hulu_ads,
  1189.                   show_context_menu_items: get_settings().show_context_menu_items,
  1190.                   show_advanced_options: get_settings().show_advanced_options,
  1191.                   display_stats: get_settings().display_stats,
  1192.                   show_block_counts_help_link: get_settings().show_block_counts_help_link
  1193.               });
  1194.  
  1195.               // Prevent deleting filters in some cases
  1196.               var sync = settingstable.get("custom_filters");
  1197.               var local = localStorage.custom_filters;
  1198.               var filters;
  1199.               if (sync === local) {
  1200.                   filters = "";
  1201.               } else if (local === undefined && sync !== "") {
  1202.                   filters = sync;
  1203.               } else if (sync !== "" && local) {
  1204.                   filters = local + sync;
  1205.               } else {
  1206.                   filters = local;
  1207.               }
  1208.               if (filters !== "" && filters !== undefined) {
  1209.                   filters = filters.replace(/\""/g, "");
  1210.                   settingstable.set("custom_filters", filters);
  1211.               }
  1212.  
  1213.               // Listener, which fires when table has been updated
  1214.               datastore.recordsChanged.addListener(function(event) {
  1215.                   savesettings();
  1216.               });
  1217.  
  1218.               // Set resolution to remote changes
  1219.               table.setResolutionRule("completed", "remote");
  1220.               savesettings();
  1221.  
  1222.               // Get settings, filter lists & custom filters and save them
  1223.               function savesettings() {
  1224.                   // Subscribe & unsubscribe filter lists
  1225.                   var filterlists_sync = settingstable.get("filter_lists").split(",");
  1226.                   var filterlists_local = get_subscribed_filter_lists();
  1227.                   for (var i=0; i < filterlists_sync.length; i++)
  1228.                       if (settingstable.get("filter_lists") !== "")
  1229.                           subscribe({id: filterlists_sync[i]}, true);
  1230.                   for (var i=0; i < filterlists_local.length; i++) {
  1231.                       if (filterlists_sync.indexOf(filterlists_local[i]) === -1)
  1232.                           unsubscribe({id: filterlists_local[i]}, true);
  1233.                   }
  1234.  
  1235.                   // Set custom filters
  1236.                   var custom = settingstable.get("custom_filters");
  1237.                   localStorage.custom_filters = custom;
  1238.                   chrome.extension.sendRequest({command: "filters_updated"});
  1239.  
  1240.                   // Set settings
  1241.                   var advanced = settingstable.get("show_advanced_options");
  1242.                   set_setting("show_advanced_options", advanced);
  1243.                   var debug = settingstable.get("debug_logging");
  1244.                   set_setting("debug_logging", debug);
  1245.                   var ytchannel = settingstable.get("youtube_channel_whitelist");
  1246.                   set_setting("youtube_channel_whitelist", ytchannel);
  1247.                   var googleads = settingstable.get("show_google_search_text_ads");
  1248.                   set_setting("show_google_search_text_ads", googleads);
  1249.                   var huluads = settingstable.get("whitelist_hulu_ads");
  1250.                   set_setting("whitelist_hulu_ads", huluads);
  1251.                   var showcontextmenu = settingstable.get("show_context_menu_items");
  1252.                   set_setting("show_context_menu_items", showcontextmenu);
  1253.                   var stats = settingstable.get("display_stats");
  1254.                   set_setting("display_stats", stats);
  1255.                   var blockcountslink = settingstable.get("show_block_counts_help_link");
  1256.                   set_setting("show_block_counts_help_link", blockcountslink);
  1257.                   chrome.runtime.sendMessage({message: "update_checkbox"});
  1258.               }
  1259.           });
  1260.       }
  1261.  
  1262.       // Reset db_client, if it got in an error state
  1263.       if (!SAFARI) {
  1264.           chrome.runtime.onMessage.addListener(
  1265.               function(request, sender, sendResponse) {
  1266.                   if (request.message === "clienterror")
  1267.                       db_client.reset();
  1268.               }
  1269.           );
  1270.       }
  1271.  
  1272.       // Sync value of changed setting
  1273.       function sync_setting(name, is_enabled) {
  1274.           if (settingstable && db_client.isAuthenticated())
  1275.               settingstable.set(name, is_enabled);
  1276.       }
  1277.   }
  1278.  
  1279.   log("\n===FINISHED LOADING===\n\n");
Add Comment
Please, Sign In to add comment