| Index: desktop-options.js | 
| =================================================================== | 
| --- a/desktop-options.js | 
| +++ b/desktop-options.js | 
| @@ -547,14 +547,17 @@ | 
| return null; | 
| } | 
|  | 
| -  function sendMessageHandleErrors(message, onSuccess) | 
| +  function sendMessageHandleErrors(message, callback) | 
| { | 
| browser.runtime.sendMessage(message, (errors) => | 
| { | 
| -      if (errors.length > 0) | 
| -        alert(errors.join("\n")); | 
| -      else if (onSuccess) | 
| -        onSuccess(); | 
| +      if (callback) | 
| +      { | 
| +        if (errors.length > 0) | 
| +          callback(errors); | 
| +        else | 
| +          callback(); | 
| +      } | 
| }); | 
| } | 
|  | 
| @@ -648,14 +651,37 @@ | 
| }); | 
| break; | 
| case "save-custom-filters": | 
| +        const filters = E("custom-filters-raw").value; | 
| sendMessageHandleErrors({ | 
| type: "filters.importRaw", | 
| -          text: E("custom-filters-raw").value, | 
| +          text: filters, | 
| removeExisting: true | 
| }, | 
| -        () => | 
| +        (errors) => | 
| { | 
| -          setCustomFiltersView("read"); | 
| +          if (errors) | 
| +          { | 
| +            E("custom-filters").classList.add("warning"); | 
| +            const customFiltersError = clearAndGetCustomFiltersError(); | 
| + | 
| +            // The current error does not contain info about the line | 
| +            // that generated such error. | 
| +            // Whenever the error object will pass the bad filter | 
| +            // within its properties, this split should be removed. | 
| +            const lines = filters.split("\n"); | 
| +            const messages = errors.map(error => lines[error.lineno - 1]); | 
| +            for (const message of messages) | 
| +            { | 
| +              const li = document.createElement("li"); | 
| +              customFiltersError.appendChild(li).textContent = message; | 
| +            } | 
| +            if (errors.length > 5) | 
| +              customFiltersError.classList.add("many"); | 
| +          } | 
| +          else | 
| +          { | 
| +            setCustomFiltersView("read"); | 
| +          } | 
| }); | 
| break; | 
| case "show-more-filters-section": | 
| @@ -749,12 +775,22 @@ | 
| } | 
| } | 
|  | 
| +  function clearAndGetCustomFiltersError() | 
| +  { | 
| +    const customFiltersError = E("custom-filters-error"); | 
| +    customFiltersError.textContent = ""; | 
| +    customFiltersError.classList.remove("many"); | 
| +    return customFiltersError; | 
| +  } | 
| + | 
| function setCustomFiltersView(mode) | 
| { | 
| let customFiltersElement = E("custom-filters-raw"); | 
| updateCustomFiltersUi(); | 
| if (mode == "read") | 
| { | 
| +      E("custom-filters").classList.remove("warning"); | 
| +      clearAndGetCustomFiltersError(); | 
| customFiltersElement.disabled = true; | 
| if (!customFiltersElement.value) | 
| { | 
| @@ -918,10 +954,10 @@ | 
| { | 
| setLinks("enable-acceptable-ads-description", link); | 
| }); | 
| -    setElementText(E("tracking-warning-1"), "options_tracking_warning_1", | 
| +    setElementText(E("tracking-warning-1"), "options_tracking_warning_1", | 
| [getMessage("common_feature_privacy_title"), | 
| -      getMessage("options_acceptableAds_ads_label")]); | 
| -    setElementText(E("tracking-warning-3"), "options_tracking_warning_3", | 
| +       getMessage("options_acceptableAds_ads_label")]); | 
| +    setElementText(E("tracking-warning-3"), "options_tracking_warning_3", | 
| [getMessage("options_acceptableAds_privacy_label")]); | 
|  | 
| getDocLink("privacy_friendly_ads", (link) => | 
| @@ -963,7 +999,8 @@ | 
|  | 
| getDocLink("filterdoc", (link) => | 
| { | 
| -      E("link-filters").setAttribute("href", link); | 
| +      E("link-filters-1").setAttribute("href", link); | 
| +      E("link-filters-2").setAttribute("href", link); | 
| }); | 
|  | 
| getDocLink("subscriptions", (link) => | 
| @@ -1158,11 +1195,7 @@ | 
| browser.runtime.sendMessage({ | 
| type: "filters.get", | 
| subscriptionUrl: subscription.url | 
| -        }, | 
| -        (filters) => | 
| -        { | 
| -          loadCustomFilters(filters); | 
| -        }); | 
| +        }, loadCustomFilters); | 
| } | 
| }); | 
| loadRecommendations(); | 
| @@ -1295,7 +1328,7 @@ | 
| updateSubscription(subscription); | 
| break; | 
| case "added": | 
| -        let {url, recommended} = subscription; | 
| +        let {url} = subscription; | 
| // Handle custom subscription | 
| if (/^~user/.test(url)) | 
| { | 
|  |