| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * This file is part of Adblock Plus <https://adblockplus.org/>, |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|    3  * Copyright (C) 2006-2017 eyeo GmbH |    3  * Copyright (C) 2006-2017 eyeo GmbH | 
|    4  * |    4  * | 
|    5  * Adblock Plus is free software: you can redistribute it and/or modify |    5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|    6  * it under the terms of the GNU General Public License version 3 as |    6  * it under the terms of the GNU General Public License version 3 as | 
|    7  * published by the Free Software Foundation. |    7  * published by the Free Software Foundation. | 
|    8  * |    8  * | 
|    9  * Adblock Plus is distributed in the hope that it will be useful, |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
|   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| (...skipping 19 matching lines...) Expand all  Loading... | 
|   30 { |   30 { | 
|   31   function onLegacyAPISupported(msg, sender) |   31   function onLegacyAPISupported(msg, sender) | 
|   32   { |   32   { | 
|   33     port.off("safari.legacyAPISupported", onLegacyAPISupported); |   33     port.off("safari.legacyAPISupported", onLegacyAPISupported); | 
|   34     resolve(msg.legacyAPISupported); |   34     resolve(msg.legacyAPISupported); | 
|   35   } |   35   } | 
|   36   port.on("safari.legacyAPISupported", onLegacyAPISupported); |   36   port.on("safari.legacyAPISupported", onLegacyAPISupported); | 
|   37 }); |   37 }); | 
|   38 let contentBlockingActive = false; |   38 let contentBlockingActive = false; | 
|   39 let afterContentBlockingFinished = null; |   39 let afterContentBlockingFinished = null; | 
 |   40 let pendingContentBlockerUpdate = null; | 
|   40 let contentBlockListDirty = true; |   41 let contentBlockListDirty = true; | 
|   41 let lastSetContentBlockerError; |   42 let lastSetContentBlockerError; | 
|   42  |   43  | 
|   43 function clearBlockCounters() |   44 function clearBlockCounters() | 
|   44 { |   45 { | 
|   45   ext.pages.query({}, pages => |   46   ext.pages.query({}, pages => | 
|   46   { |   47   { | 
|   47     for (let page of pages) |   48     for (let page of pages) | 
|   48       page.browserAction.setBadge(); |   49       page.browserAction.setBadge(); | 
|   49   }); |   50   }); | 
|   50 } |   51 } | 
|   51  |   52  | 
|   52 function setContentBlocker(callback) |   53 function setContentBlocker() | 
|   53 { |   54 { | 
|   54   // When given the same rules as last time setContentBlocker will always give |   55   return new Promise((resolve, reject) => | 
|   55   // null (success) to the callback, even when there was actually an error. We |  | 
|   56   // cache the last result therefore so that we can provide a consistent result |  | 
|   57   // and also to avoid wastefully regenerating an identical blocklist. |  | 
|   58   if (!contentBlockListDirty) |  | 
|   59   { |   56   { | 
|   60     callback(lastSetContentBlockerError); |   57     // Reset state and either fulfill or reject this promise. | 
|   61     return; |   58     function completePromise(error) | 
|   62   } |   59     { | 
 |   60       lastSetContentBlockerError = error; | 
 |   61       contentBlockListDirty = false; | 
|   63  |   62  | 
|   64   let contentBlockerList = new ContentBlockerList(); |   63       if (error instanceof Error) | 
|   65   for (let subscription of FilterStorage.subscriptions) |   64         reject(error); | 
|   66     if (!subscription.disabled) |   65       else | 
|   67       for (let filter of subscription.filters) |   66         resolve(); | 
|   68         contentBlockerList.addFilter(filter); |   67     } | 
|   69  |   68  | 
|   70   contentBlockListDirty = false; |   69     // When given the same rules as last time setContentBlocker will always | 
|   71   safari.extension.setContentBlocker( |   70     // resolve with null (success), even when there was actually an | 
|   72     // There is a strange bug in setContentBlocker for Safari 9 where if both |   71     // error. We cache the last result therefore so that we can provide a | 
|   73     // the callback parameter is provided and the rules aren't converted to a |   72     // consistent result and also to avoid wastefully regenerating an identical | 
|   74     // JSON string it fails. Worse still it actually performs the callback twice |   73     // blocklist. | 
|   75     // too, firstly with an empty string and then with an Error: |   74     if (!contentBlockListDirty) | 
|   76     //   "Extension compilation failed: Failed to parse the JSON String." |  | 
|   77     // To mitigate this we convert the rules to JSON here and also ignore |  | 
|   78     // callback values of "". (Usually the callback is performed with either |  | 
|   79     // null for success or an Error on failure.) |  | 
|   80     // Bug #26322821 filed on bugreport.apple.com |  | 
|   81     JSON.stringify(contentBlockerList.generateRules()), |  | 
|   82     function(error) |  | 
|   83     { |   75     { | 
|   84       if (error == "") |   76       completePromise(lastSetContentBlockerError); | 
|   85         return; |   77       return; | 
 |   78     } | 
|   86  |   79  | 
|   87       lastSetContentBlockerError = error; |   80     let contentBlockerList = new ContentBlockerList(); | 
|   88       callback(error); |   81     for (let subscription of FilterStorage.subscriptions) | 
 |   82     { | 
 |   83       if (!subscription.disabled) | 
 |   84       { | 
 |   85         for (let filter of subscription.filters) | 
 |   86           contentBlockerList.addFilter(filter); | 
 |   87       } | 
|   89     } |   88     } | 
|   90   ); |   89  | 
 |   90     contentBlockerList.generateRules().then(rules => | 
 |   91     { | 
 |   92       safari.extension.setContentBlocker( | 
 |   93         // There is a strange bug in setContentBlocker for Safari 9 where if | 
 |   94         // both the callback parameter is provided and the rules aren't | 
 |   95         // converted to a JSON string it fails. Worse still it actually | 
 |   96         // performs the callback twice too, firstly with an empty string and | 
 |   97         // then with an Error: "Extension compilation failed: Failed to parse | 
 |   98         // the JSON String." To mitigate this we convert the rules to JSON here | 
 |   99         // and also ignore callback values of "". (Usually the callback is | 
 |  100         // performed with either null for success or an Error on failure.) | 
 |  101         // Bug #26322821 filed on bugreport.apple.com | 
 |  102         JSON.stringify(rules), | 
 |  103         function(error) | 
 |  104         { | 
 |  105           if (error == "") | 
 |  106             return; | 
 |  107  | 
 |  108           completePromise(error); | 
 |  109         } | 
 |  110       ); | 
 |  111     }) | 
 |  112     .catch(completePromise); | 
 |  113   }); | 
|   91 } |  114 } | 
|   92  |  115  | 
|   93 function updateContentBlocker(isStartup, legacyAPISupported) |  116 function updateContentBlocker(isStartup, legacyAPISupported) | 
|   94 { |  117 { | 
|   95   afterContentBlockingFinished = new Promise(resolve => |  118   // Another update can be requested while one is still in progress (e.g. the | 
 |  119   // user adds filter lists in quick succession). When this happens, save the | 
 |  120   // request and execute it later. | 
 |  121   if (afterContentBlockingFinished) | 
|   96   { |  122   { | 
|   97     setContentBlocker(error => |  123     pendingContentBlockerUpdate = { | 
 |  124       params: Array.from(arguments), | 
 |  125       // Save the current dirty state so we can set it later before calling | 
 |  126       // this function again. | 
 |  127       setDirty: contentBlockListDirty | 
 |  128     }; | 
 |  129     return; | 
 |  130   } | 
 |  131  | 
 |  132   afterContentBlockingFinished = setContentBlocker().then(() => | 
 |  133   { | 
 |  134     if (!contentBlockingActive) | 
|   98     { |  135     { | 
|   99       if (error instanceof Error) |  136       contentBlockingActive = true; | 
|  100       { |  137       clearBlockCounters(); | 
|  101         let suppressErrorMessage = false; |  138     } | 
 |  139   }, | 
 |  140   error => | 
 |  141   { | 
 |  142     let suppressErrorMessage = false; | 
|  102  |  143  | 
|  103         // If the content blocking API fails the first time it's used the |  144     // If the content blocking API fails the first time it's used the | 
|  104         // legacy blocking API (if available) won't have been disabled. |  145     // legacy blocking API (if available) won't have been disabled. | 
|  105         if (!contentBlockingActive && legacyAPISupported) |  146     if (!contentBlockingActive && legacyAPISupported) | 
|  106         { |  147     { | 
|  107           Prefs.safariContentBlocker = false; |  148       Prefs.safariContentBlocker = false; | 
|  108           // If content blocking failed on startup and we're switching back to |  149       // If content blocking failed on startup and we're switching back to | 
|  109           // the legacy API anyway we don't need to show an error message. |  150       // the legacy API anyway we don't need to show an error message. | 
|  110           if (isStartup) |  151       if (isStartup) | 
|  111             suppressErrorMessage = true; |  152         suppressErrorMessage = true; | 
|  112         } |  153     } | 
|  113  |  154  | 
|  114         if (!suppressErrorMessage) |  155     if (!suppressErrorMessage) | 
|  115           alert(error.message); |  156       alert(error.message); | 
|  116       } |  157   }) | 
|  117       else if (!contentBlockingActive) |  158   .then(() => | 
|  118       { |  159   { | 
|  119         contentBlockingActive = true; |  160     afterContentBlockingFinished = null; | 
|  120         clearBlockCounters(); |  | 
|  121       } |  | 
|  122  |  161  | 
|  123       resolve(contentBlockingActive); |  162     // If there's another update pending, execute it now. | 
|  124       afterContentBlockingFinished = null; |  163     if (pendingContentBlockerUpdate) | 
|  125     }); |  164     { | 
 |  165       let {params, setDirty} = pendingContentBlockerUpdate; | 
 |  166       pendingContentBlockerUpdate = null; | 
 |  167  | 
 |  168       if (setDirty) | 
 |  169         contentBlockListDirty = true; | 
 |  170  | 
 |  171       updateContentBlocker.apply(null, params); | 
 |  172       return afterContentBlockingFinished; | 
 |  173     } | 
 |  174  | 
 |  175     return contentBlockingActive; | 
|  126   }); |  176   }); | 
|  127 } |  177 } | 
|  128  |  178  | 
|  129 if (contentBlockingSupported) |  179 if (contentBlockingSupported) | 
|  130 { |  180 { | 
|  131   Promise.all([Prefs.untilLoaded, |  181   Promise.all([Prefs.untilLoaded, | 
|  132                FilterNotifier.once("load"), |  182                FilterNotifier.once("load"), | 
|  133                legacyAPISupported]).then(resolvedValues => |  183                legacyAPISupported]).then(resolvedValues => | 
|  134   { |  184   { | 
|  135     let legacyAPISupported = resolvedValues[2]; |  185     let legacyAPISupported = resolvedValues[2]; | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
|  153     }); |  203     }); | 
|  154   }); |  204   }); | 
|  155 } |  205 } | 
|  156  |  206  | 
|  157 port.on("safari.contentBlockingActive", (msg, sender) => |  207 port.on("safari.contentBlockingActive", (msg, sender) => | 
|  158 { |  208 { | 
|  159   if (!contentBlockingActive && afterContentBlockingFinished) |  209   if (!contentBlockingActive && afterContentBlockingFinished) | 
|  160     return afterContentBlockingFinished; |  210     return afterContentBlockingFinished; | 
|  161   return contentBlockingActive; |  211   return contentBlockingActive; | 
|  162 }); |  212 }); | 
| OLD | NEW |