Compare commits

...

45 commits

Author SHA1 Message Date
Raymond Hill
3703f5efb8
New version for stable release 2026-03-10 20:42:16 -04:00
Raymond Hill
d92b6f315f
Update main.yml 2026-03-06 09:30:05 -05:00
Raymond Hill
8f544e53bc
New revision for dev build 2026-02-24 08:59:17 -05:00
Raymond Hill
b230effdbc
Update changelog 2026-02-24 08:55:51 -05:00
Raymond Hill
98d3e9500a
Improve json-edit-related scriptlets 2026-02-24 08:50:41 -05:00
Raymond Hill
f1689a9ab3
Make Firefox dev build auto-update 2026-02-16 10:24:19 -05:00
Raymond Hill
a85fc33ce8
Import translaetion work from https://crowdin.com/project/ublock 2026-02-11 18:05:25 -05:00
Raymond Hill
8d9832b4d6
[mv3] Remove "Steven Black’s Unified Hosts" list
Related feedback:
https://github.com/uBlockOrigin/uAssets/issues/17917#issuecomment-3876123107
2026-02-10 12:10:26 -05:00
Raymond Hill
2b63dcdcb6
[mv3] Force register content scripts when none are found
Possibly will fix cases of no content scripts found in Safari.

Related issue:
https://github.com/uBlockOrigin/uAssets/issues/30158#issuecomment-3869144473
2026-02-09 09:25:57 -05:00
Raymond Hill
aedaa97867
Import translation work from https://crowdin.com/project/ublock 2026-02-08 14:24:17 -05:00
Raymond Hill
93577ecca1
[mv3] Fix removeparam conversion
Related issue:
https://github.com/uBlockOrigin/uAssets/issues/30636
2026-02-08 09:56:25 -05:00
Raymond Hill
60a1b43d71
New revision for dev build 2026-02-07 11:50:41 -05:00
Raymond Hill
51c1b4a6ec
Update changelog 2026-02-07 11:50:20 -05:00
Raymond Hill
baffd32dab
Improve trusted-create-html scriptlet 2026-02-07 11:46:57 -05:00
Raymond Hill
2ce376cf1d
Improve prevent-fetch scriptlet
Related discussion:
https://github.com/uBlockOrigin/uAssets/issues/30731
2026-02-07 11:13:29 -05:00
Raymond Hill
efc59a2fc8
Revert "[mv3][safari] Bring back "AdGuard/uBO – URL Tracking Protection""
This reverts commit c7ff0f8c42.
2026-02-03 18:00:40 -05:00
Raymond Hill
c7ff0f8c42
[mv3][safari] Bring back "AdGuard/uBO – URL Tracking Protection"
Related issue:
https://github.com/uBlockOrigin/uBOL-home/issues/476
2026-02-03 17:38:15 -05:00
Raymond Hill
1ec05d4c0a
[mv3][safari] Remove image from removeparam
Revert https://github.com/gorhill/uBlock/commit/7aff7da77d for Safari.
2026-02-02 11:06:18 -05:00
Raymond Hill
916d2af99f
New revision for dev build 2026-02-01 10:57:37 -05:00
Raymond Hill
ac017e7664
Update changelog 2026-02-01 10:57:02 -05:00
Raymond Hill
a8ad95394d
Fix handling of extraMatch parameter in trusted-click-element scriptlet
Related feedback:
https://old.reddit.com/r/uBlockOrigin/comments/1qry49n/
2026-02-01 10:54:34 -05:00
Raymond Hill
719798329b
Fix misleading tooltip
Related issue:
https://github.com/uBlockOrigin/uBlock-issues/discussions/3934
2026-01-31 13:34:46 -05:00
Raymond Hill
d1877d448b
Import translation work from https://crowdin.com/project/ublock 2026-01-31 13:32:56 -05:00
Raymond Hill
0901e9b660
New revision for dev build 2026-01-30 11:16:07 -05:00
Raymond Hill
c00849befa
Update changelog 2026-01-30 11:15:49 -05:00
Raymond Hill
7d95c58408
Improve generateContentFn helper scriptlet
New directive: `join:[separator][sub-directives]`

[separator] is an author-defined two-character string to be used to split
the following sub-directives string. The sub-directives are fed back into
the helper scriptlet to generate sub-content, which will be joined into
a single string. Example:

...##+js(trusted-prevent-fetch, propstomatch, join:--length:10-20--[some literal content]--length:80-100-- push['ads'])
2026-01-30 11:05:57 -05:00
Raymond Hill
359cb070eb
[mv3] Fix minor regression in reported troubleshooting info 2026-01-29 08:38:53 -05:00
Raymond Hill
7aff7da77d
[mv3] Add image to generic removeparam filters
Related discussion:
https://github.com/uBlockOrigin/uBOL-home/issues/140#issuecomment-3817666188
2026-01-29 08:26:29 -05:00
Raymond Hill
9b4f41df94
[mv3] Improve conversion of removeparam filters to DNR rules
Related issue:
https://github.com/uBlockOrigin/uBOL-home/issues/140
2026-01-28 12:10:50 -05:00
Raymond Hill
2a0842f177
Update changelog 2026-01-26 10:13:38 -05:00
Raymond Hill
552761ec0c
New revision for dev build 2026-01-26 10:12:20 -05:00
Raymond Hill
168394440c
Improve prevent-xhr scriptlet 2026-01-26 10:11:05 -05:00
Raymond Hill
84434e0e7e
Update changelog 2026-01-25 15:59:26 -05:00
Raymond Hill
d383966044
New revision for dev build 2026-01-25 15:58:17 -05:00
Raymond Hill
18a8fc7675
Improve proxyApplyFn helper scriptlet 2026-01-25 15:57:21 -05:00
Raymond Hill
976d12d048
New stable release version 2026-01-25 15:06:42 -05:00
Raymond Hill
08b7eafd26
Import translation work from https://crowdin.com/project/ublock 2026-01-25 13:38:42 -05:00
Raymond Hill
9f0c55fccb
[mv3] Minor change for when side-loaded 2026-01-23 12:31:06 -05:00
Raymond Hill
c6de97ceb7
[mv3] Add to troubleshooting info 2026-01-21 15:40:01 -05:00
Raymond Hill
f36dd3461b
[mv3] Fix regex in regex substitution rules
Related issue:
https://github.com/uBlockOrigin/uBOL-home/issues/594
2026-01-21 09:40:35 -05:00
Raymond Hill
d44a1ddf2a
Make Firefox dev build auto-update 2026-01-19 09:16:52 -05:00
Raymond Hill
d136c08710
Import translation work from https://crowdin.com/project/ublock 2026-01-18 12:23:17 -05:00
Raymond Hill
f4c3c823fb
Rename list 2026-01-18 10:29:56 -05:00
Raymond Hill
b74b1a789c
[mv3] Remove obsolete comment 2026-01-17 13:28:25 -05:00
Raymond Hill
222f4fbbc1
[mv3] Fix equality test between two rulesets
Related issue:
https://github.com/uBlockOrigin/uBOL-home/issues/591
2026-01-17 13:19:51 -05:00
65 changed files with 820 additions and 653 deletions

View file

@ -12,7 +12,7 @@ jobs:
permissions:
contents: write # for creating release
name: Build packages
runs-on: ubuntu-latest
runs-on: ubuntu-slim
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Clone repository

View file

@ -1,3 +1,15 @@
- [Improve `json-edit`-related scriptlets](https://github.com/gorhill/uBlock/commit/98d3e9500a)
- [Improve `trusted-create-html` scriptlet](https://github.com/gorhill/uBlock/commit/baffd32dab)
- [Improve `prevent-fetch` scriptlet](https://github.com/gorhill/uBlock/commit/2ce376cf1d)
- [Fix handling of `extraMatch` parameter in `trusted-click-element` scriptlet](https://github.com/gorhill/uBlock/commit/a8ad95394d)
- [Improve `generateContentFn` helper scriptlet](https://github.com/gorhill/uBlock/commit/7d95c58408)
- [Improve `prevent-xhr` scriptlet](https://github.com/gorhill/uBlock/commit/168394440c)
- [Improve `proxyApplyFn` helper scriptlet](https://github.com/gorhill/uBlock/commit/18a8fc7675)
----------
# 1.69.0
- [Add `adthrive` shim](https://github.com/gorhill/uBlock/commit/b8bf0bbab4)
- [Add `elem.shadowRoot` fallback in `getShadowRoot`](https://github.com/gorhill/uBlock/commit/c8b42ea819) (by @antonok-edm)
- [Fix merging of uncommitted filters](https://github.com/gorhill/uBlock/commit/c8004c4b02)

View file

@ -476,7 +476,7 @@
"group": "annoyances",
"parent": "EasyList Annoyances",
"off": true,
"title": "EasyList AI Suggestions",
"title": "EasyList AI Widgets",
"tags": "annoyances",
"preferred": true,
"contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-ai.txt",

View file

@ -476,7 +476,7 @@
"group": "annoyances",
"parent": "EasyList Annoyances",
"off": true,
"title": "EasyList AI Suggestions",
"title": "EasyList AI Widgets",
"tags": "annoyances",
"preferred": true,
"contentURL": "https://ublockorigin.github.io/uAssets/thirdparties/easylist-ai.txt",

View file

@ -3,13 +3,13 @@
"uBlock0@raymondhill.net": {
"updates": [
{
"version": "1.68.1.7",
"version": "1.69.1.4",
"browser_specific_settings": {
"gecko": {
"strict_min_version": "115.0"
}
},
"update_link": "https://github.com/gorhill/uBlock/releases/download/1.68.1b7/uBlock0_1.68.1b7.firefox.signed.xpi"
"update_link": "https://github.com/gorhill/uBlock/releases/download/1.69.1b4/uBlock0_1.69.1b4.firefox.signed.xpi"
}
]
}

2
dist/version vendored
View file

@ -1 +1 @@
1.68.1.102
1.70.0

View file

@ -1,12 +1,12 @@
uBO Lite (uBOL) je blokovač obsahu založený na MV3.
Výchozí sada pravidel koresponduje k výchozím sadám filtrů uBlock Origin:
Výchozí sada pravidel odpovídá výchozím sadám filtrů uBlock Origin:
- Vestavěný seznam filtrů uBlock Origin
- EasyList
- EasyPrivacy
- Peter Lowes Ad and tracking server list
- Seznam reklamních a sledovacích serverů Petera Lowea
Další sady pravidel můžete povolit na stránce nastavení - klikněte na ikonu _Ozubeného kolečka_ ve vyskakovacím panelu.
Další sady pravidel můžete povolit na stránce nastavení - klepněte na ikonu _Ozubeného kolečka_ ve vyskakovacím panelu.
uBOL je zcela deklarativní, což znamená, že pro filtrování není potřeba permanentní proces uBOL a filtrování obsahu založené na vstřikování CSS/JS je spolehlivě prováděno samotným prohlížečem, nikoli rozšířením. To znamená, že samotný uBOL nespotřebovává zdroje CPU/paměti, zatímco probíhá blokování obsahu proces servisního pracovníka uBOL je vyžadován _pouze_ při interakci s vyskakovacím panelem nebo stránkami nastavení.
uBOL je zcela deklarativní, což znamená, že pro filtrování není potřeba permanentní proces uBOL a filtrování obsahu založené na vstřikování CSS/JS je spolehlivě prováděno samotným prohlížečem, nikoli rozšířením. To znamená, že samotný uBOL nespotřebovává zdroje CPU/paměti, zatímco probíhá blokování obsahu - proces servisního pracovníka uBOL je vyžadován _jen_ při interakci s vyskakovacím panelem nebo stránkami nastavení.

View file

@ -384,11 +384,11 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "إعادة تعيين إلى الإعدادات الافتراضية…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "سيتم حذف جميع إعداداتك المخصصة. هل تريد حقاً إعادة ضبط الإعدادات إلى الوضع الافتراضي؟",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Вредоносни домейни",
"message": "Защита от зловреден софтуер, сигурност",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -4,7 +4,7 @@
"description": "extension name."
},
"extShortDesc": {
"message": "Eksperimentalni blokator sadržaja bez dopuštenja. Blokira oglase, trakere za praćenje, \"rudare\" kovanica kripto valute i još [...]",
"message": "Efikasno blokator sadržaja. Blokira oglase, trackere, rudare i još mnogo toga odmah nakon instalacije.",
"description": "this will be in the Chrome web store: must be 132 characters or less"
},
"perRulesetStats": {

View file

@ -12,7 +12,7 @@
"description": "Appears aside each filter list in the _3rd-party filters_ pane"
},
"dashboardName": {
"message": "uBO Lite Ovládací panel",
"message": "uBO Lite - Ovládací panel",
"description": "English: uBO Lite — Dashboard"
},
"settingsPageName": {
@ -32,19 +32,19 @@
"description": "appears as tab name in dashboard"
},
"aboutPrivacyPolicy": {
"message": "Ochrana soukromí",
"message": "Zásady ochrany osobních údajů",
"description": "Link to privacy policy on GitHub (English)"
},
"popupFilteringModeLabel": {
"message": "Filtrovací režim",
"message": "režim filtrování",
"description": "Label in the popup panel for the current filtering mode"
},
"popupLocalToolsLabel": {
"message": "Na této webové stránce",
"message": "Na tomto webu",
"description": "Label in the popup panel for the local tools section"
},
"popupTipReport": {
"message": "Nahlásit problém na této webové stránce",
"message": "Nahlásit problém",
"description": "Tooltip used for the 'chat' icon in the panel"
},
"popupTipDashboard": {
@ -136,11 +136,11 @@
"description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page"
},
"supportS6P1S1": {
"message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen.",
"message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen. <b>Poznámka:</b> Klepnutím na tlačítko bude originální stránka odeslána na GitHub.",
"description": "A paragraph in the filter issue reporter section"
},
"supportFindSpecificButton": {
"message": "Vyhledat podobná hlášení",
"message": "Vyhledat podobná hlášení na GitHubu",
"description": "A clickable link in the filter issue reporter section"
},
"supportS6URL": {
@ -148,7 +148,7 @@
"description": "Label for the URL of the page"
},
"supportS6Select1": {
"message": "Webová stránka",
"message": "Webová stránka...",
"description": "Label for widget to select type of issue"
},
"supportS6Select1Option0": {
@ -188,11 +188,11 @@
"description": "A checkbox to use for NSFW sites"
},
"supportReportSpecificButton": {
"message": "Vytvořit nové hlášení",
"message": "Vytvořit nové hlášení na GitHubu",
"description": "Text for button which opens an external web page in Support pane"
},
"defaultFilteringModeSectionLabel": {
"message": "Výchozí filtrovací režim",
"message": "Výchozí režim filtrování",
"description": "The header text for the default filtering mode section"
},
"defaultFilteringModeDescription": {
@ -228,11 +228,11 @@
"description": "This describes the 'complete' filtering mode"
},
"noFilteringModeDescription": {
"message": "Seznam názvů hostitelů, pro které nebude probíhat žádné filtrování",
"message": "Seznam názvů hostitelů, pro které nebude probíhat žádné filtrování.",
"description": "A short description for the editable field which lists trusted sites"
},
"noFilteringModePlaceholder": {
"message": "[pouze názvy hostitelů]\nexample.com\ngames.example\n...",
"message": "[jen názvy hostitelů]\nexample.com\ngames.example\n...",
"description": "Default text for in edit field"
},
"behaviorSectionLabel": {
@ -252,7 +252,7 @@
"description": "Label for a checkbox in the options page"
},
"enableStrictBlockLegend": {
"message": "Navigace na potenciálně nežádoucí stránky bude zablokována a bude vám nabídnuta možnost pokračovat.",
"message": "Bude zablokována navigace na potenciálně nežádoucí stránky a bude Vám nabídnuta volba pro pokračování.",
"description": "Short description for a checkbox in the options page"
},
"developerModeLabel": {
@ -272,7 +272,7 @@
"description": "A summary description of the back up/restore section."
},
"settingsBackupRestoreLegend": {
"message": "Obnovení přepíše všechna vaše aktuální vlastní nastavení.",
"message": "Obnovení přepíše všechna Vaše aktuální vlastní nastavení.",
"description": "Important information about the back up/restore section."
},
"findListsPlaceholder": {
@ -280,7 +280,7 @@
"description": "Placeholder for the input field used to find lists"
},
"strictblockTitle": {
"message": "Stránka zablokována",
"message": "Stránka byla zablokována",
"description": "Web page title for the strict-blocked page"
},
"strictblockSentence1": {
@ -292,7 +292,7 @@
"description": "Text informing about what is causing the page to be blocked"
},
"strictblockRedirectSentence1": {
"message": "Zablokovaná stránka vás chce přesměrovat na jiný web. Pokud se rozhodnete pokračovat, přejdete přímo na: {{url}}",
"message": "Zablokovaná stránka Vás chce přesměrovat na jiný web. Pokud se rozhodnete pokračovat, přejdete přímo na: {{url}}",
"description": "Text warning about an incoming redirect"
},
"strictblockNoParamsPrompt": {
@ -304,11 +304,11 @@
"description": "A button to go back to the previous web page"
},
"strictblockClose": {
"message": "Zavřít okno",
"message": "Zavřít toto okno",
"description": "A button to close the current tab"
},
"strictblockDontWarn": {
"message": "Nevarujte mě znovu o této stránce",
"message": "Příště na tuto stránku neupozorňovat",
"description": "Label for checkbox in document-blocked page"
},
"strictblockProceed": {
@ -316,11 +316,11 @@
"description": "A button to navigate to the blocked page"
},
"zapperTipEnter": {
"message": "Přejít do režimu dočasného skrytí prvků",
"message": "Odebrat prvek",
"description": "Tooltip for the button used to enter zapper mode"
},
"zapperTipQuit": {
"message": "Opustit režim dočasného skrytí prvků",
"message": "Ukončit režim dočasného skrytí prvků",
"description": "Tooltip for the button used to exit zapper mode"
},
"pickerTipEnter": {
@ -336,7 +336,7 @@
"description": "A label of a dropdown list"
},
"developOptionFilteringModeDetails": {
"message": "Detaily filtovacího módu",
"message": "Detaily režimu filtrování",
"description": "An option in a dropdown list"
},
"developOptionCustomDnrRules": {
@ -344,7 +344,7 @@
"description": "An option in a dropdown list"
},
"developOptionDnrRulesOf": {
"message": "DNR pravidla …",
"message": "Pravidla DNR pro...",
"description": "A section header in a dropdown list"
},
"developOptionDynamicRuleset": {
@ -352,7 +352,7 @@
"description": "An option in a dropdown list"
},
"developOptionSessionRuleset": {
"message": "",
"message": "Seznam pravidel relace",
"description": "An option in a dropdown list"
},
"saveButton": {
@ -368,27 +368,27 @@
"description": "Text for buttons used to add content"
},
"importAndAppendButton": {
"message": "Importovat a připojit",
"message": "Importovat a připojit...",
"description": "Text for buttons used to import and append content"
},
"exportButton": {
"message": "Exportovat",
"message": "Exportovat...",
"description": "Text for buttons used to export content"
},
"backupButton": {
"message": "Zálohovat",
"message": "Zálohovat...",
"description": "Text for buttons used to back up content"
},
"restoreButton": {
"message": "Obnovit",
"message": "Obnovit...",
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "Resetovat do výchozího nastavení...",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "Všechna Vaše vlastní nastavení budou odebrána. Opravdu chcete resetovat do výchozího nastavení?",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {
@ -416,7 +416,7 @@
"description": "Text for the button to create the filter"
},
"unpickerUsage": {
"message": "Výběrem níže uvedeného filtru zvýrazníte odpovídající prvky na webové stránce. Kliknutím na koš filtr odstraníte.",
"message": "Výběrem níže uvedeného filtru zvýrazníte odpovídající prvky na webové stránce. Klepnutím na koš filtr odeberete.",
"description": "Summary description on how to use the tool to remove custom filters"
}
}

View file

@ -136,7 +136,7 @@
"description": "Label of 'Troubleshooting information' section in 'Report a filter issue' page"
},
"supportS6P1S1": {
"message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. <b>Hinweis:</b> Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.",
"message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. <b>Hinweis:</b> Das Anklicken der Schaltfläche übermittelt die Internetadresse an GitHub.",
"description": "A paragraph in the filter issue reporter section"
},
"supportFindSpecificButton": {
@ -156,11 +156,11 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option1": {
"message": "Zeigt Werbung oder Werbereste",
"message": "Zeigt Werbung oder deren Überreste",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option2": {
"message": "Hat Überdeckungen oder andere Belästigungen",
"message": "Enthält überdeckende oder belästigende Elemente",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option3": {
@ -168,7 +168,7 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option4": {
"message": "Hat Datenschutzprobleme",
"message": "Weist Datenschutzprobleme auf",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option5": {
@ -196,7 +196,7 @@
"description": "The header text for the default filtering mode section"
},
"defaultFilteringModeDescription": {
"message": "Der Standardfiltermodus wird durch individuelle Filtermodi für die jeweiligen Websites überschrieben. Sie können den Filtermodus auf jeder beliebigen Website entsprechend dem Modus anpassen, der auf dieser Website am besten funktioniert. Jeder Modus hat seine Vor- und Nachteile.",
"message": "Der Standardfiltermodus wird durch den eingestellten Filtermodus der jeweiligen Website überschrieben. Er kann auf jeder beliebigen Website individuell angepasst werden. Jeder Modus hat seine Vor- und Nachteile.",
"description": "This describes the default filtering mode setting"
},
"filteringMode0Name": {
@ -216,15 +216,15 @@
"description": "Name of blocking mode 3"
},
"basicFilteringModeDescription": {
"message": "Einfaches Netzwerkfiltern aus gewählten Filterlisten.\n\nErfordert keine Berechtigung zum Lesen und Ändern von Daten auf Websites.",
"message": "Einfaches Netzwerkfiltern durch ausgewählte Filterlisten.\n\nErfordert keine Berechtigung zum Lesen und Ändern von Daten auf Websites.",
"description": "This describes the 'basic' filtering mode"
},
"optimalFilteringModeDescription": {
"message": "Erweitertes Netzwerkfiltern plus spezifisches erweitertes Filtern aus ausgewählten Filterlisten.\n\nErfordert eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites.",
"message": "Erweitertes Netzwerkfiltern plus umfassendes Filtern durch ausgewählte Filterlisten.\n\nErfordert eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites.",
"description": "This describes the 'optimal' filtering mode"
},
"completeFilteringModeDescription": {
"message": "Erweitertes Netzwerkfiltern plus spezifisches und allgemeines erweitertes Filtern aus gewählten Filterlisten.\n\nErfordert eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites.\n\nDas allgemeine erweiterte Filtern kann zu einem höheren Ressourcenverbrauch der Webseite führen.",
"message": "Erweitertes Netzwerkfiltern plus umfassendes und allgemeines Filtern durch ausgewählte Filterlisten.\n\nErfordert eine weitreichende Berechtigung zum Lesen und Ändern von Daten auf allen Websites.\n\nDas allgemeine Filtern kann zu einem höheren Ressourcenverbrauch der Webseite führen.",
"description": "This describes the 'complete' filtering mode"
},
"noFilteringModeDescription": {
@ -264,7 +264,7 @@
"description": "Short description for a checkbox in the options page"
},
"settingsBackupRestoreLabel": {
"message": "Sicherung",
"message": "Backup",
"description": "The header text for the back up/restore section"
},
"settingsBackupRestoreSummary": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Malware domains",
"message": "Malware protection, security",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "תחומי תוכנות זדוניות",
"message": "הגנה מפני נוזקות, אבטחה",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Domain malware",
"message": "Perlindungan malware, keamanan",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {
@ -384,11 +384,11 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "Kembalikan ke pengaturan bawaan…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "Semua pengaturan kustom kamu akan dihapus. Apakah kamu benar ingin kembali ke pengaturan bawaan?",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Domini che diffondono virus",
"message": "Protezione dai malware, sicurezza",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "マルウェアドメイン",
"message": "マルウェアからの保護、セキュリティ",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -384,11 +384,11 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "ჩამოყრა ნაგულისხმევ პარამეტრებზე…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "ყველა მორგებული პარამეტრი მოცილდება. ნამდვილად გსურთ დაბრუნება ნაგულისხმევ პარამეტრებზე?",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {

View file

@ -52,7 +52,7 @@
"description": "English: Click to open the dashboard"
},
"popupMoreButton": {
"message": "자세히",
"message": "더 보기",
"description": "Label to be used to show popup panel sections"
},
"popupLessButton": {
@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "멀웨어 도메인",
"message": "멀웨어 및 보안",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {
@ -168,7 +168,7 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option4": {
"message": "개인정보 보호 관련 이슈가 있습니다",
"message": "개인정보 보호 관련 문제가 있습니다",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option5": {
@ -184,7 +184,7 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Checkbox1": {
"message": "웹페이지를 \"NSFW\" (<a href=\"https://wikipedia.org/wiki/Not_safe_for_work\">“Not Safe For Work”</a>)로 분류",
"message": "웹페이지를 \"NSFW\" (<a href=\"https://ko.wikipedia.org/wiki/NSFW\">“Not Safe For Work”</a>)로 분류",
"description": "A checkbox to use for NSFW sites"
},
"supportReportSpecificButton": {
@ -252,7 +252,7 @@
"description": "Label for a checkbox in the options page"
},
"enableStrictBlockLegend": {
"message": "잠재적으로 좋지 않은 사이트로의 접속을 차단하고, 사용자가 진행할지 선택하도록 합니다.",
"message": "잠재적으로 유해할 수 있는 사이트로의 접속이 차단되며, 계속 진행할지 여부를 선택할 수 있는 옵션이 제공됩니다.",
"description": "Short description for a checkbox in the options page"
},
"developerModeLabel": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Ļaunatūras domēni",
"message": "Aizsardzība pret ļaunprātīgām (inficētas vai satur vīrusus) vietnēm, drošība",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -384,7 +384,7 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "Tilbakestill til standardinnstillinger…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {

View file

@ -4,7 +4,7 @@
"description": "extension name."
},
"extShortDesc": {
"message": "Un blocant experimental, fără permisiuni. Blochează reclamele, urmăritorii, minerii de monede virtuale și multe altele imediat [...]",
"message": "Un blocant de conținut eficient. Blochează reclamele, urmăritorii, minerii și multe altele imediat după instalare.",
"description": "this will be in the Chrome web store: must be 132 characters or less"
},
"perRulesetStats": {
@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Domenii malițioase",
"message": "Domenii malițioase, securitate",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {
@ -384,11 +384,11 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "Restabilește setările implicite…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "Toate setările personalizate vor fi eliminate. Doriți cu siguranță să resetați la setările implicite?",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "ද්වේශාංග වසම්",
"message": "අනිෂ්ට මෘදුකාංග ආරක්ෂාව, ආරක්ෂාව",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {

View file

@ -72,7 +72,7 @@
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupMalware": {
"message": "Các tên miền nguy hiểm",
"message": "Bảo vệ phần mềm độc hại, bảo mật",
"description": "Header for a ruleset section in 'Filter lists pane'"
},
"3pGroupAnnoyances": {
@ -384,11 +384,11 @@
"description": "Text for buttons used to restore content"
},
"resetToDefaultButton": {
"message": "Reset to default settings…",
"message": "Đặt lại về cài đặt mặc định…",
"description": "Text for buttons used to reset configurations to default"
},
"resetToDefaultConfirm": {
"message": "All your custom settings will be removed. Do you really want to reset to default settings?",
"message": "Tất cả cài đặt tùy chỉnh của bạn sẽ bị xóa. Bạn có thực sự muốn đặt lại về cài đặt mặc định không?",
"description": "Message asking user to confirm reset to default settings"
},
"dnrRulesWarning": {

View file

@ -55,8 +55,6 @@ import {
import {
broadcastMessage,
gotoURL,
hasBroadHostPermissions,
hostnameFromMatch,
hostnamesFromMatches,
} from './utils.js';
@ -101,6 +99,11 @@ import {
ubolLog,
} from './debug.js';
import {
gotoURL,
hasBroadHostPermissions,
} from './ext-utils.js';
import { dnr } from './ext-compat.js';
import { toggleToolbarIcon } from './action.js';
@ -399,6 +402,10 @@ function onMessage(request, sender, callback) {
});
return true;
case 'getShowBlockedCount':
callback(rulesetConfig.showBlockedCount);
break;
case 'setShowBlockedCount':
rulesetConfig.showBlockedCount = request.state && true || false;
if ( canShowBlockedCount ) {
@ -592,6 +599,12 @@ function onMessage(request, sender, callback) {
});
return true;
case 'getRegisteredContentScripts':
scrmgr.getRegisteredContentScripts().then(ids => {
callback(ids);
});
return true;
case 'getConsoleOutput':
callback(getConsoleOutput());
break;
@ -662,12 +675,13 @@ async function startSession() {
}
// Permissions may have been removed while the extension was disabled
await syncWithBrowserPermissions();
const permissionsUpdated = await syncWithBrowserPermissions();
// Unsure whether the browser remembers correctly registered css/scripts
// after we quit the browser. For now uBOL will check unconditionally at
// launch time whether content css/scripts are properly registered.
registerInjectables();
const shouldInject = isNewVersion || permissionsUpdated ||
isSideloaded && rulesetConfig.developerMode;
if ( shouldInject ) {
await registerInjectables();
}
// Cosmetic filtering-related content scripts cache fitlering data in
// session storage.
@ -716,6 +730,11 @@ async function start() {
scrmgr.onWakeupRun();
}
const scripts = await scrmgr.getRegisteredContentScripts();
if ( scripts.length === 0 ) {
registerInjectables();
}
toggleDeveloperMode(rulesetConfig.developerMode);
}

View file

@ -19,21 +19,13 @@
Home: https://github.com/gorhill/uBlock
*/
import { deepEquals } from './utils.js';
export const webext = self.browser || self.chrome;
export const dnr = webext.declarativeNetRequest || {};
/******************************************************************************/
const ruleCompare = (a, b) => a.id - b.id;
const isSameRules = (a, b) => {
a.sort(ruleCompare);
b.sort(ruleCompare);
return JSON.stringify(a) === JSON.stringify(b);
};
/******************************************************************************/
export function normalizeDNRRules(rules, ruleIds) {
if ( Array.isArray(rules) === false ) { return rules; }
return Array.isArray(ruleIds)
@ -85,19 +77,23 @@ dnr.setAllowAllRules = async function(id, allowed, notAllowed, reverse, priority
}
addSessionRules.push(rule1);
}
if ( isSameRules(addDynamicRules, beforeDynamicRules) ) { return false; }
return Promise.all([
dnr.updateDynamicRules({
addRules: addDynamicRules,
removeRuleIds: beforeDynamicRules.map(r => r.id),
}),
dnr.updateSessionRules({
addRules: addSessionRules,
removeRuleIds: beforeSessionRules.map(r => r.id),
}),
]).then(( ) =>
true
).catch(( ) =>
false
);
const promises = [];
const modified = deepEquals(addDynamicRules, beforeDynamicRules) === false;
if ( modified ) {
promises.push(
dnr.updateDynamicRules({
addRules: addDynamicRules,
removeRuleIds: beforeDynamicRules.map(r => r.id),
})
);
}
if ( deepEquals(addSessionRules, beforeSessionRules) === false ) {
promises.push(
dnr.updateSessionRules({
addRules: addSessionRules,
removeRuleIds: beforeSessionRules.map(r => r.id),
})
);
}
return Promise.all(promises).then(( ) => modified).catch(( ) => false);
};

View file

@ -0,0 +1,68 @@
/*******************************************************************************
uBlock Origin Lite - a comprehensive, MV3-compliant content blocker
Copyright (C) 2022-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
import {
browser,
runtime,
} from './ext.js';
/******************************************************************************/
// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions#requested_permissions_and_user_prompts
// "Users can grant or revoke host permissions on an ad hoc basis. Therefore,
// most browsers treat host_permissions as optional."
export async function hasBroadHostPermissions() {
return browser.permissions.getAll().then(permissions =>
permissions.origins.includes('<all_urls>') ||
permissions.origins.includes('*://*/*')
).catch(( ) => false);
}
/******************************************************************************/
export async function gotoURL(url, type) {
const pageURL = new URL(url, runtime.getURL('/'));
const tabs = await browser.tabs.query({
url: pageURL.href,
windowType: type !== 'popup' ? 'normal' : 'popup'
});
if ( Array.isArray(tabs) && tabs.length !== 0 ) {
const { windowId, id } = tabs[0];
return Promise.all([
browser.windows.update(windowId, { focused: true }),
browser.tabs.update(id, { active: true }),
]);
}
if ( type === 'popup' ) {
return browser.windows.create({
type: 'popup',
url: pageURL.href,
});
}
return browser.tabs.create({
active: true,
url: pageURL.href,
});
}

View file

@ -21,7 +21,6 @@
import {
broadcastMessage,
hasBroadHostPermissions,
hostnamesFromMatches,
isDescendantHostnameOfIter,
toBroaderHostname,
@ -40,6 +39,8 @@ import {
import { adminReadEx } from './admin.js';
import { filteringModesToDNR } from './ruleset-manager.js';
import { hasBroadHostPermissions } from './ext-utils.js';
/******************************************************************************/

View file

@ -235,6 +235,7 @@ dom.on('#gotoReport', 'click', ev => {
}
if ( url === undefined ) { return; }
const reportURL = new URL(runtime.getURL('/report.html'));
reportURL.searchParams.set('tabid', currentTab.id);
reportURL.searchParams.set('url', tabURL.href);
reportURL.searchParams.set('mode', popupPanelData.level);
sendMessage({

View file

@ -50,7 +50,8 @@ const reportedPage = (( ) => {
}
return {
hostname: parsedURL.hostname.replace(/^(m|mobile|www)\./, ''),
mode: url.searchParams.get('mode'),
siteMode: parseInt(url.searchParams.get('mode'), 10),
tabId: parseInt(url.searchParams.get('tabid'), 10) || 0,
};
} catch {
}
@ -93,7 +94,7 @@ async function reportSpecificFilterIssue() {
/******************************************************************************/
getTroubleshootingInfo(reportedPage.mode).then(config => {
getTroubleshootingInfo(reportedPage).then(config => {
qs$('[data-i18n="supportS5H"] + pre').textContent = config;
dom.on('[data-url]', 'click', ev => {

View file

@ -36,7 +36,7 @@ import { ubolErr, ubolLog } from './debug.js';
import { dnr } from './ext-compat.js';
import { fetchJSON } from './fetch.js';
import { getAdminRulesets } from './admin.js';
import { hasBroadHostPermissions } from './utils.js';
import { hasBroadHostPermissions } from './ext-utils.js';
import { rulesFromText } from './dnr-parser.js';
/******************************************************************************/
@ -352,7 +352,7 @@ async function updateSessionRules() {
let ruleId = 1;
for ( const rule of addRulesUnfiltered ) {
rule.id = ruleId++;
if ( Boolean(rule?.condition.regexFilter) === false ) { continue; }
if ( Boolean(rule.condition.regexFilter) === false ) { continue; }
regexCount += 1;
if ( regexCount < maxRegexCount ) { continue; }
rule.id = 0;

View file

@ -423,6 +423,14 @@ export async function registerInjectables() {
/******************************************************************************/
export async function getRegisteredContentScripts() {
const scripts = await browser.scripting.getRegisteredContentScripts()
.catch(( ) => []);
return scripts.map(a => a.id);
}
/******************************************************************************/
export async function onWakeupRun() {
const cleanupTime = await sessionRead('scripting.manager.cleanup.time') || 0;
const now = Date.now();

View file

@ -19,7 +19,7 @@
Home: https://github.com/gorhill/uBlock
*/
import { runtime, sendMessage } from './ext.js';
import { browser, runtime, sendMessage } from './ext.js';
/******************************************************************************/
@ -49,7 +49,7 @@ function renderData(data, depth = 0) {
/******************************************************************************/
export async function getTroubleshootingInfo(siteMode) {
export async function getTroubleshootingInfo(details) {
const manifest = runtime.getManifest();
const [
platformInfo,
@ -58,6 +58,8 @@ export async function getTroubleshootingInfo(siteMode) {
defaultMode,
userRules,
consoleOutput,
showBlockedCount,
registeredScripts,
hasOmnipotence,
] = await Promise.all([
runtime.getPlatformInfo(),
@ -66,9 +68,11 @@ export async function getTroubleshootingInfo(siteMode) {
sendMessage({ what: 'getDefaultFilteringMode' }),
sendMessage({ what: 'getEffectiveUserRules' }),
sendMessage({ what: 'getConsoleOutput' }),
sendMessage({ what: 'getShowBlockedCount' }),
sendMessage({ what: 'getRegisteredContentScripts' }),
sendMessage({ what: 'hasBroadHostPermissions' }),
]);
const browser = (( ) => {
const vendor = (( ) => {
const extURL = runtime.getURL('');
let agent = '', version = '?';
if ( extURL.startsWith('moz-extension:') ) {
@ -96,17 +100,26 @@ export async function getTroubleshootingInfo(siteMode) {
})();
const modes = [ 'no filtering', 'basic', 'optimal', 'complete' ];
const filtering = {};
if ( siteMode ) {
filtering.site = `${modes[siteMode]}`
if ( details?.siteMode ) {
filtering.site = `${modes[details.siteMode]}`
}
filtering.default = `${modes[defaultMode]}`;
const config = {
name: manifest.name,
version: manifest.version,
browser,
browser: vendor,
filtering,
permission: hasOmnipotence ? 'all' : 'ask',
};
if ( details?.tabId ) {
let badge = '?';
if ( showBlockedCount ) {
badge = await browser.action.getBadgeText({ tabId: details.tabId });
}
if ( badge ) {
config.badge = badge;
}
}
if ( userRules.length !== 0 ) {
config['user rules'] = userRules.length;
}
@ -121,8 +134,11 @@ export async function getTroubleshootingInfo(siteMode) {
enabledRulesets.push(`-${id}`);
}
config.rulesets = enabledRulesets.sort();
if ( registeredScripts.length !== 0 ) {
config.scripting = registeredScripts;
}
if ( consoleOutput.length !== 0 ) {
config.console = siteMode
config.console = details?.siteMode
? consoleOutput.slice(-8)
: consoleOutput;
}

View file

@ -19,11 +19,6 @@
Home: https://github.com/gorhill/uBlock
*/
import {
browser,
runtime,
} from './ext.js';
/******************************************************************************/
function parsedURLromOrigin(origin) {
@ -135,53 +130,40 @@ export const hostnamesFromMatches = origins => {
/******************************************************************************/
const broadcastMessage = message => {
const bc = new self.BroadcastChannel('uBOL');
bc.postMessage(message);
export const deepEquals = (a, b) => {
switch ( typeof a ) {
case 'undefined':
case 'boolean':
case 'number':
case 'string':
return a === b;
}
// case 'object':
if ( typeof b !== 'object' ) { return false; }
if ( a === null || b === null ) { return a === b; }
if ( Array.isArray(a) || Array.isArray(b) ) {
if ( Array.isArray(a) === false || Array.isArray(b) === false ) { return false; }
if ( a.length !== b.length ) { return false; }
for ( let i = 0; i < a.length; i++ ) {
if ( deepEquals(a[i], b[i]) === false ) { return false; }
}
return true;
}
const akeys = Object.keys(a);
const bkeys = Object.keys(b);
if ( akeys.length !== bkeys.length ) { return false; }
for ( const k of akeys ) {
if ( deepEquals(a[k], b[k]) === false ) { return false; }
}
return true;
};
/******************************************************************************/
// https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/manifest.json/host_permissions#requested_permissions_and_user_prompts
// "Users can grant or revoke host permissions on an ad hoc basis. Therefore,
// most browsers treat host_permissions as optional."
async function hasBroadHostPermissions() {
return browser.permissions.getAll().then(permissions =>
permissions.origins.includes('<all_urls>') ||
permissions.origins.includes('*://*/*')
).catch(( ) => false);
}
/******************************************************************************/
async function gotoURL(url, type) {
const pageURL = new URL(url, runtime.getURL('/'));
const tabs = await browser.tabs.query({
url: pageURL.href,
windowType: type !== 'popup' ? 'normal' : 'popup'
});
if ( Array.isArray(tabs) && tabs.length !== 0 ) {
const { windowId, id } = tabs[0];
return Promise.all([
browser.windows.update(windowId, { focused: true }),
browser.tabs.update(id, { active: true }),
]);
}
if ( type === 'popup' ) {
return browser.windows.create({
type: 'popup',
url: pageURL.href,
});
}
return browser.tabs.create({
active: true,
url: pageURL.href,
});
}
const broadcastMessage = message => {
const bc = new self.BroadcastChannel('uBOL');
bc.postMessage(message);
};
/******************************************************************************/
@ -220,7 +202,5 @@ export {
isDescendantHostnameOfIter,
intersectHostnameIters,
subtractHostnameIters,
hasBroadHostPermissions,
gotoURL,
strArrayEq,
};

View file

@ -214,7 +214,7 @@ const rePatternFromUrlFilter = s => {
let reStr = s.replace(rePatternFromUrlFilter.rePlainChars, '\\$&')
.replace(rePatternFromUrlFilter.reSeparators, restrSeparator)
.replace(rePatternFromUrlFilter.reDanglingAsterisks, '')
.replace(rePatternFromUrlFilter.reAsterisks, '\\S*?');
.replace(rePatternFromUrlFilter.reAsterisks, '.*?');
if ( anchor & 0b100 ) {
reStr = (
reStr.startsWith('\\.') ?

View file

@ -111,7 +111,7 @@
},
{
"id": "annoyances-ai",
"name": "EasyList AI Suggestions",
"name": "EasyList AI Widgets",
"group": "annoyances",
"enabled": false,
"urls": [
@ -191,16 +191,6 @@
],
"homeURL": "https://github.com/uBlockOrigin/uAssets"
},
{
"id": "stevenblack-hosts",
"name": "Steven Blacks Unified Hosts (adware + malware)",
"enabled": false,
"excludedPlatforms": [ "safari" ],
"urls": [
"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts"
],
"homeURL": "https://github.com/StevenBlack/hosts#readme"
},
{
"id": "ubol-tests",
"name": "uBO Lite Test Filters",

View file

@ -19,6 +19,7 @@
Home: https://github.com/gorhill/uBlock
*/
import { deepEquals } from './utils.js';
export const webext = self.browser;
@ -114,14 +115,6 @@ const prepareUpdateRules = optionsBefore => {
return optionsAfter;
};
const ruleCompare = (a, b) => a.id - b.id;
const isSameRules = (a, b) => {
a.sort(ruleCompare);
b.sort(ruleCompare);
return JSON.stringify(a) === JSON.stringify(b);
};
/******************************************************************************/
export function normalizeDNRRules(rules, ruleIds) {
@ -209,7 +202,7 @@ export const dnr = {
}
addRules.push(rule0);
}
if ( isSameRules(addRules, beforeRules) ) { return false; }
if ( deepEquals(addRules, beforeRules) ) { return false; }
return this.updateDynamicRules({
addRules,
removeRuleIds: beforeRules.map(r => r.id),

View file

@ -45,10 +45,11 @@ function patchRule(rule, out) {
if ( copy.action.type === 'modifyHeaders' ) { return; }
if ( Array.isArray(copy.condition.responseHeaders) ) { return; }
// https://github.com/uBlockOrigin/uBOL-home/issues/476#issuecomment-3299309478
// https://github.com/uBlockOrigin/uBOL-home/issues/608
if ( copy.action.redirect?.transform?.queryTransform?.removeParams ) {
const resourceTypes = condition.resourceTypes;
if ( resourceTypes?.includes('main_frame') ) {
condition.resourceTypes = resourceTypes.filter(a => a !== 'main_frame');
condition.resourceTypes = resourceTypes.filter(a => a !== 'main_frame' && a !== 'image');
if ( condition.resourceTypes.length === 0 ) { return; }
}
}

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "القواعد الموضعية: هذا العمود يتعلق بالقواعد التي تنطبق فقط على الموقع المزار حاليا.\nالقواعد الموضعية تحل محل القواعد العامة.",
"message": "الشروط المؤقتة: هذا العمود يتعلق بالقواعد التي تنطبق فقط على الموقع المزار حاليا.\nالشروط المؤقتة تحل محل الشروط العامة.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -8,15 +8,15 @@
"description": "this will be in the Chrome web store: must be 132 characters or less"
},
"dashboardName": {
"message": "uBlock₀ Ovládací panel",
"message": "uBlock₀ - Ovládací panel",
"description": "English: uBlock₀ — Dashboard"
},
"dashboardUnsavedWarning": {
"message": "Varování! Máte neuložené změny",
"message": "Varování: Máte neuložené změny!",
"description": "A warning in the dashboard when navigating away from unsaved changes"
},
"dashboardUnsavedWarningStay": {
"message": "Zůstat",
"message": "Zůstat zde",
"description": "Label for button to prevent navigating away from unsaved changes"
},
"dashboardUnsavedWarningIgnore": {
@ -28,19 +28,19 @@
"description": "appears as tab name in dashboard"
},
"3pPageName": {
"message": "Filtry třetích stran",
"message": "Seznamy filtrů",
"description": "appears as tab name in dashboard"
},
"1pPageName": {
"message": "Vaše filtry",
"message": "Moje filtry",
"description": "appears as tab name in dashboard"
},
"rulesPageName": {
"message": "Vaše pravidla",
"message": "Moje pravidla",
"description": "appears as tab name in dashboard"
},
"whitelistPageName": {
"message": "Povolené domény",
"message": "Povolené stránky",
"description": "appears as tab name in dashboard"
},
"shortcutsPageName": {
@ -48,7 +48,7 @@
"description": "appears as tab name in dashboard"
},
"statsPageName": {
"message": "uBlock₀ — Protokol požadavků",
"message": "uBlock₀ - Logger",
"description": "Title for the logger window"
},
"aboutPageName": {
@ -60,7 +60,7 @@
"description": "appears as tab name in dashboard"
},
"assetViewerPageName": {
"message": "uBlock₀ Prohlížeč zdrojů",
"message": "uBlock₀ - Prohlížeč zdrojů",
"description": "Title for the asset viewer page"
},
"advancedSettingsPageName": {
@ -68,15 +68,15 @@
"description": "Title for the advanced settings page"
},
"popupPowerSwitchInfo": {
"message": "Kliknutí: trvale zakázat uBlock₀ pro celý tento web.\n\nCtrl+kliknutí: zakázat uBlock₀ pouze pro tuto stránku.",
"message": "Klepnutí: zakáže/povolí uBlock₀ pro tento web.\n\nCtrl+klepnutí: zakáže uBlock₀ jen pro tuto stránku.",
"description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page."
},
"popupPowerSwitchInfo1": {
"message": "Kliknutí: trvale zakázat uBlock₀ pro celý tento web.\n\nCtrl+kliknutí: zakázat uBlock₀ pouze pro tuto stránku.",
"message": "Klepněte pro zakázání uBlock₀ pro tento web.\n\nCtrl+klepněte pro zakázání uBlock₀ jen pro tuto stránku.",
"description": "Message to be read by screen readers"
},
"popupPowerSwitchInfo2": {
"message": "Kliknutím povolíte uBlock₀ pro tento web.",
"message": "Klepněre pro povolení uBlock₀ pro tento web.",
"description": "Message to be read by screen readers"
},
"popupBlockedRequestPrompt": {
@ -88,7 +88,7 @@
"description": "English: on this page"
},
"popupBlockedStats": {
"message": "{{count}} neboli {{percent}} %",
"message": "{{count}}, což je {{percent}} %",
"description": "Example: 15 (13%)"
},
"popupBlockedSinceInstallPrompt": {
@ -96,7 +96,7 @@
"description": "English: since install"
},
"popupOr": {
"message": "neboli",
"message": "což je",
"description": "English: or"
},
"popupBlockedOnThisPage_v2": {
@ -124,11 +124,11 @@
"description": "English: Enter element picker mode"
},
"popupTipLog": {
"message": "Otevřít protokol požadavků",
"message": "Otevřít Logger",
"description": "Tooltip used for the logger icon in the panel"
},
"popupTipReport": {
"message": "Nahlásit problém na této webové stránce",
"message": "Nahlásit problém na tomto webu",
"description": "Tooltip used for the 'chat' icon in the panel"
},
"popupTipNoPopups": {
@ -136,11 +136,11 @@
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoPopups1": {
"message": "Kliknutím zablokujete všechny popupy pro tento web",
"message": "Klepnutím zablokujete všechna vyskakovací okna na tomto webu",
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoPopups2": {
"message": "Kliknutím vypnete blokování všech popupů pro tento web",
"message": "Klepnutím vypnete blokování všech vyskakovacích oken na tomto webu",
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoLargeMedia": {
@ -148,11 +148,11 @@
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoLargeMedia1": {
"message": "Kliknutím zablokujete velké multimediální prvky na tomto webu",
"message": "Klepnutím zablokujete velké multimediální prvky na tomto webu",
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoLargeMedia2": {
"message": "Kliknutím vypnete blokování velkých multimediálních prvků na tomto webu",
"message": "Klepnutím vypnete blokování velkých multimediálních prvků na tomto webu",
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoCosmeticFiltering": {
@ -160,31 +160,31 @@
"description": "Tooltip for the no-cosmetic-filtering per-site switch"
},
"popupTipNoCosmeticFiltering1": {
"message": "Kliknutím zakážete kosmetické filtrování na tomto webu",
"message": "Klepnutím zakážete kosmetické filtrování na tomto webu",
"description": "Tooltip for the no-cosmetic-filtering per-site switch"
},
"popupTipNoCosmeticFiltering2": {
"message": "Kliknutím povolíte kosmetické filtrování na tomto webu",
"message": "Klepnutím povolíte kosmetické filtrování na tomto webu",
"description": "Tooltip for the no-cosmetic-filtering per-site switch"
},
"popupTipNoRemoteFonts": {
"message": "Přepnout blokování vzdálených fontů pro tento web",
"message": "Přepnout blokování vzdálených písem na tomto webu",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoRemoteFonts1": {
"message": "Kliknutím zablokujete externí/vzdálené fonty na tomto webu",
"message": "Klepnutím zablokujete vzdálená písma na tomto webu",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoRemoteFonts2": {
"message": "Kliknutím vypnete blokování externích/vzdálených fontů na tomto webu",
"message": "Klepnutím vypnete blokování vzdálených písem na tomto webu",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoScripting1": {
"message": "Kliknutím zakážete JavaScript na této stránce",
"message": "Klepnutím zakážete JavaScript na tomto webu",
"description": "Tooltip for the no-scripting per-site switch"
},
"popupTipNoScripting2": {
"message": "Kliknutím znovu povolíte JavaScript na této stránce",
"message": "Klepnutím znovu povolíte JavaScript na tomto webu",
"description": "Tooltip for the no-scripting per-site switch"
},
"popupNoPopups_v2": {
@ -220,15 +220,15 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Lokální pravidla: tento sloupec slouží pro pravidla, která platí pouze pro aktuální web.\nLokální pravidla přepisují globální pravidla.",
"message": "Lokální pravidla: tento sloupec slouží pro pravidla, která platí jen pro aktuální web.\nLokální pravidla přepisují globální pravidla.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {
"message": "Kliknutím natrvalo uložíte provedené změny.",
"message": "Klepnutím natrvalo uložíte provedené změny.",
"description": "Tooltip when hovering over the padlock in the dynamic filtering pane."
},
"popupTipRevertRules": {
"message": "Kliknutím zrušíte provedené změny.",
"message": "Klepnutím zrušíte provedené změny.",
"description": "Tooltip when hovering over the eraser in the dynamic filtering pane."
},
"popupAnyRulePrompt": {
@ -248,7 +248,7 @@
"description": ""
},
"popupInlineScriptRulePrompt": {
"message": "řádkové skripty",
"message": "vložené skripty",
"description": ""
},
"popup1pScriptRulePrompt": {
@ -264,7 +264,7 @@
"description": ""
},
"popupHitDomainCountPrompt": {
"message": "domén připojeno",
"message": "připojené domény",
"description": "appears in popup"
},
"popupHitDomainCount": {
@ -308,11 +308,11 @@
"description": "English: Cosmetic filters"
},
"pickerCosmeticFiltersHint": {
"message": "Kliknutí, Ctrl+Kliknutí",
"message": "Klepnutí, Ctrl+klepnutí",
"description": "English: Click, Ctrl-click"
},
"pickerContextMenuEntry": {
"message": "Zablokovat prvek",
"message": "Zablokovat prvek...",
"description": "An entry in the browser's contextual menu"
},
"settingsCollapseBlockedPrompt": {
@ -324,11 +324,11 @@
"description": "English: Show the number of blocked requests on the icon"
},
"settingsTooltipsPrompt": {
"message": "Skrýt nápovědu při najetí",
"message": "Zakázat nápovědu při najetí",
"description": "A checkbox in the Settings pane"
},
"settingsContextMenuPrompt": {
"message": "Využít kontextovou nabídku kde je to možné",
"message": "Využít kontextovou nabídku, kde je to možné",
"description": "English: Make use of context menu where appropriate"
},
"settingsColorBlindPrompt": {
@ -356,7 +356,7 @@
"description": "Checkbox to let user access advanced, technical features"
},
"settingsPrefetchingDisabledPrompt": {
"message": "Zakázat přednačítání (zakáže jakékoliv spojení pro zablokované síťové požadavky)",
"message": "Zakázat přednačítání (zakáže jakékoli spojení pro zablokované síťové požadavky)",
"description": "English: "
},
"settingsHyperlinkAuditingDisabledPrompt": {
@ -384,7 +384,7 @@
"description": ""
},
"settingsNoRemoteFontsPrompt": {
"message": "Blokovat externí fonty",
"message": "Blokovat externí písma",
"description": ""
},
"settingsNoScriptingPrompt": {
@ -396,7 +396,7 @@
"description": "background information: https://github.com/gorhill/uBlock/issues/3150"
},
"settingsUncloakCnamePrompt": {
"message": "Odkrýt kanonická jména",
"message": "Odkrýt kanonické názvy",
"description": "background information: https://github.com/uBlockOrigin/uBlock-issues/issues/1513"
},
"settingsAdvanced": {
@ -404,7 +404,7 @@
"description": "Section for controlling advanced-user settings"
},
"settingsAdvancedSynopsis": {
"message": "Funkce vhodné pouze pro pokročilé uživatele",
"message": "Funkce vhodné jen pro pokročilé uživatele",
"description": "Description of section controlling advanced-user settings"
},
"settingsAdvancedUserSettings": {
@ -428,7 +428,7 @@
"description": "Appears aside each filter list in the _3rd-party filters_ pane"
},
"3pAutoUpdatePrompt1": {
"message": "Automaticky aktualizovat seznamy filtrů.",
"message": "Automaticky aktualizovat seznamy filtrů",
"description": "A checkbox in the _3rd-party filters_ pane"
},
"3pUpdateNow": {
@ -440,7 +440,7 @@
"description": "A button in the in the _3rd-party filters_ pane"
},
"3pParseAllABPHideFiltersPrompt1": {
"message": "Zpracovat a použít kosmetické filtry.",
"message": "Analyzovat a vynucovat kosmetické filtry",
"description": "English: Parse and enforce Adblock+ element hiding filters."
},
"3pParseAllABPHideFiltersInfo": {
@ -452,11 +452,11 @@
"description": "This will cause uBO to ignore all generic cosmetic filters."
},
"3pIgnoreGenericCosmeticFiltersInfo": {
"message": "Obecné kosmetické filtry jsou takové kosmetické filtry, které jsou určeny k použití na všech webových stránkách. Povolení této možnosti odstraní nadbytečnou režii paměti a procesoru, přidanou na webové stránky v důsledku manipulace s obecnými kosmetickými filtry.\n\nTuto možnost doporučujeme povolit na méně výkonných zařízeních.",
"message": "Obecné kosmetické filtry jsou takové kosmetické filtry, které jsou určeny k použití na všech webových stránkách. Povolení této volby eliminuje nadbytečnou režii paměti a procesoru, přidanou na webové stránky v důsledku manipulace s obecnými kosmetickými filtry.\n\nTuto volbu doporučujeme povolit na méně výkonných zařízeních.",
"description": "Describes the purpose of the 'Ignore generic cosmetic filters' feature."
},
"3pSuspendUntilListsAreLoaded": {
"message": "Pozastavit síťové aktivity, dokud se nenačtou všechny seznamy filtrů.",
"message": "Pozastavit síťové aktivity, dokud se nenačtou všechny seznamy filtrů",
"description": "A checkbox in the 'Filter lists' pane"
},
"3pListsOfBlockedHostsHeader": {
@ -508,7 +508,7 @@
"description": "Filter lists section name"
},
"3pImport": {
"message": "Importovat",
"message": "Importovat...",
"description": "The label for the checkbox used to import external filter lists"
},
"3pExternalListsHint": {
@ -524,11 +524,11 @@
"description": "used as a tooltip for eye icon beside a list"
},
"3pLastUpdate": {
"message": "Poslední aktualizace: {{ago}}.\nKliknutím vynutíte aktualizaci.",
"message": "Poslední aktualizace: {{ago}}.\nKlepnutím vynutíte aktualizaci.",
"description": "used as a tooltip for the clock icon beside a list"
},
"3pUpdating": {
"message": "Aktualizuji…",
"message": "Aktualizování...",
"description": "used as a tooltip for the spinner icon beside a list"
},
"3pNetworkError": {
@ -548,15 +548,15 @@
"description": "Label for the checkbox use to trust the content of 'My filters' list"
},
"1pImport": {
"message": "Importovat a připojit",
"message": "Importovat a připojit...",
"description": "Button in the 'My filters' pane"
},
"1pExport": {
"message": "Exportovat",
"message": "Exportovat...",
"description": "Button in the 'My filters' pane"
},
"1pExportFilename": {
"message": "ublock-me-vlastni-filtry_{{datetime}}.txt",
"message": "moje-vlastni-filtry-ublock_{{datetime}}.txt",
"description": "English: my-ublock-static-filters_{{datetime}}.txt"
},
"1pApplyChanges": {
@ -564,7 +564,7 @@
"description": "English: Apply changes"
},
"rulesPermanentHeader": {
"message": "Permanentní pravidla",
"message": "Trvalá pravidla",
"description": "header"
},
"rulesTemporaryHeader": {
@ -592,23 +592,23 @@
"description": "Will discard manually-edited content and exit manual-edit mode"
},
"rulesImport": {
"message": "Načíst ze souboru…",
"message": "Importovat ze souboru...",
"description": ""
},
"rulesExport": {
"message": "Exportovat do souboru",
"message": "Exportovat do souboru...",
"description": "Button in the 'My rules' pane"
},
"rulesDefaultFileName": {
"message": "ublock-ma-dynamicka-pravidla_{{datetime}}.txt",
"message": "moje-dynamicka-pravidla-ublock_{{datetime}}.txt",
"description": "default file name to use"
},
"rulesHint": {
"message": "Seznam vašich pravidel pro dynamické filtrování.",
"message": "Seznam Vašich pravidel pro dynamické filtrování.",
"description": "English: List of your dynamic filtering rules."
},
"rulesFormatHint": {
"message": "Syntaxe pravidel: <code>zdroj destinace typ akce</code> (<a href='https://github.com/gorhill/uBlock/wiki/Dynamic-filtering:-rule-syntax'>kompletní dokumentace</a>).",
"message": "Syntaxe pravidla: <code>zdroj cíl typ akce</code> (<a href='https://github.com/gorhill/uBlock/wiki/Dynamic-filtering:-rule-syntax'>kompletní dokumentace</a>).",
"description": "English: dynamic rule syntax and full documentation."
},
"rulesSort": {
@ -628,19 +628,19 @@
"description": "English: a sort option for list of rules."
},
"whitelistPrompt": {
"message": "Pravidla v seznamu povolených domén určují, pro které webové stránky bude uBlock Origin vypnutý. Jedna položka na řádek.",
"message": "Pravidla v seznamu povolených webů určují, pro které webové stránky bude uBlock Origin vypnutý. Jedna položka na řádek.",
"description": "A concise description of the 'Trusted sites' pane."
},
"whitelistImport": {
"message": "Importovat a připojit",
"message": "Importovat a připojit...",
"description": "Button in the 'Trusted sites' pane"
},
"whitelistExport": {
"message": "Exportovat",
"message": "Exportovat...",
"description": "Button in the 'Trusted sites' pane"
},
"whitelistExportFilename": {
"message": "ublock-muj-whitelist_{{datetime}}.txt",
"message": "muj-whitelist-ublock_{{datetime}}.txt",
"description": "The default filename to use for import/export purpose"
},
"whitelistApply": {
@ -664,7 +664,7 @@
"description": "English: Filter"
},
"logAll": {
"message": "Všechny stránky",
"message": "Vše",
"description": "Appears in the logger's tab selector"
},
"logBehindTheScene": {
@ -692,7 +692,7 @@
"description": "Tooltip for the top-right info label in the logger page"
},
"loggerClearTip": {
"message": "Vyčistit logger",
"message": "Vyčistit Logger",
"description": "Tooltip for the eraser in the logger page; used to blank the content of the logger"
},
"loggerPauseTip": {
@ -704,7 +704,7 @@
"description": "Tooltip for the play button in the logger page"
},
"loggerRowFiltererButtonTip": {
"message": "Přepnout filtrování loggeru",
"message": "Přepnout filtrování Loggeru",
"description": "Tooltip for the row filterer button in the logger page"
},
"logFilterPrompt": {
@ -712,7 +712,7 @@
"description": "Placeholder string for logger output filtering input field"
},
"loggerRowFiltererBuiltinTip": {
"message": "Možnosti filtrování loggeru",
"message": "Volby filtrování Loggeru",
"description": "Tooltip for the button to bring up logger output filtering options"
},
"loggerRowFiltererBuiltinNot": {
@ -720,7 +720,7 @@
"description": "A keyword in the built-in row filtering expression"
},
"loggerRowFiltererBuiltinEventful": {
"message": "eventful",
"message": "cokoli",
"description": "A keyword in the built-in row filtering expression: all items corresponding to uBO doing something (blocked, allowed, redirected, etc.)"
},
"loggerRowFiltererBuiltinBlocked": {
@ -780,7 +780,7 @@
"description": "Label to identify the URL of an entry"
},
"loggerURLFilteringHeader": {
"message": "Dynamické filtrování URL adres",
"message": "Pravidlo URL",
"description": "Small header to identify the dynamic URL filtering section"
},
"loggerURLFilteringContextLabel": {
@ -796,7 +796,7 @@
"description": "Small header to identify the static filtering section"
},
"loggerStaticFilteringSentence": {
"message": "{{action}} síťové požadavky {{type}} {{br}}jejichž URL adresa se shoduje s {{url}} {{br}}a pochází {{origin}},{{br}}{{importance}} shodný výjimkový filtr.",
"message": "{{action}} síťové požadavky {{type}} {{br}}, jejichž URL adresa se shoduje s {{url}} {{br}}a pochází {{origin}},{{br}}{{importance}} shodný výjimkový filtr.",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartBlock": {
@ -808,19 +808,19 @@
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartType": {
"message": "typu “{{type}}”",
"message": "typu \"{{type}}\"",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartAnyType": {
"message": "jakéhokoliv typu",
"message": "jakéhokoli typu",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartOrigin": {
"message": "z “{{origin}}”",
"message": "z \"{{origin}}\"",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartAnyOrigin": {
"message": "odkudkoliv",
"message": "odkudkoli",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartNotImportant": {
@ -832,11 +832,11 @@
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringFinderSentence1": {
"message": "Statický filtr <code>{{filter}}</code> nalezen v seznamech:",
"message": "Statický filtr <code>{{filter}}</code> byl nalezen v seznamech:",
"description": "Below this sentence, the filter list(s) in which the filter was found"
},
"loggerStaticFilteringFinderSentence2": {
"message": "Statický filtr <code>{{filter}}</code> nebyl nalezen v žádném aktuálně povoleném seznamu filtrů",
"message": "Statický filtr nebyl nalezen v žádném aktuálně povoleném seznamu filtrů",
"description": "Message to show when a filter cannot be found in any filter lists"
},
"loggerSettingDiscardPrompt": {
@ -900,11 +900,11 @@
"description": "Text for button which open an external web page in Support pane"
},
"supportReportSpecificButton": {
"message": "Vytvořit nové hlášení",
"message": "Vytvořit nové hlášení na GitHubu",
"description": "Text for button which open an external web page in Support pane"
},
"supportFindSpecificButton": {
"message": "Vyhledat podobná hlášení",
"message": "Vyhledat podobná hlášení na GitHubu",
"description": "A clickable link in the filter issue reporter section"
},
"supportS1H": {
@ -924,7 +924,7 @@
"description": "First paragraph of 'Questions and support' section in Support pane"
},
"supportS3H": {
"message": "Problémy s filtrem/web. stránka je nefunkční",
"message": "Problémy s filtrem/web je nefunkční",
"description": "Header of 'Filter issues' section in Support pane"
},
"supportS3P1": {
@ -936,7 +936,7 @@
"description": "Second paragraph of 'Filter issues' section in Support pane"
},
"supportS3P3": {
"message": "<b>Tipy:</b> Ověřte, že jsou seznamy filtrů aktuální. <span data-url=\"logger-ui.html#_\">Protokol</span> je hlavní nástroj pro diagnósu problémů s filtry.",
"message": "<b>Tipy:</b> Ověřte, že jsou seznamy filtrů aktuální. <span data-url=\"logger-ui.html#_\">Logger</span> je hlavní nástroj pro diagnózu problémů s filtry.",
"description": "Third paragraph of 'Filter issues' section in Support pane"
},
"supportS4H": {
@ -944,7 +944,7 @@
"description": "Header of 'Bug report' section in Support pane"
},
"supportS4P1": {
"message": "Hlášení problémů se samotným uBlock Origin na <span data-url=\"https://github.com/uBlockOrigin/uBlock-issues/issues?q=is%3Aissue\"><code>uBlockOrigin/uBlock-issue</code> issue tracker</span>. Požaduje účet GitHub.",
"message": "Nahlaste problémy se samotným uBlock Origin do <span data-url=\"https://github.com/uBlockOrigin/uBlock-issues/issues?q=is%3Aissue\"><code>uBlockOrigin/uBlock-issue</code> sledovače problémů</span>. <u>Vyžaduje účet GitHub.</u>",
"description": "First paragraph of 'Bug report' section in Support pane"
},
"supportS5H": {
@ -952,7 +952,7 @@
"description": "Header of 'Troubleshooting Information' section in Support pane"
},
"supportS5P1": {
"message": "Níže jsou technické informace, které mohou být užitečné, když vám dobrovolníci pomáhají vyřešit nějaký problém.",
"message": "Níže jsou technické informace, které mohou být užitečné, když Vám dobrovolníci pomáhají vyřešit nějaký problém.",
"description": "First paragraph of 'Troubleshooting Information' section in Support pane"
},
"supportS6H": {
@ -960,11 +960,11 @@
"description": "Header of 'Report a filter issue' section in Support pane"
},
"supportS6P1S1": {
"message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen.",
"message": "Abyste dobrovolníky nezatěžovali duplicitními hlášeními, ověřte si, zda již problém nebyl nahlášen. <b>Poznámka:</b> Klepnutím na tlačítko bude originální stránka odeslána na GitHub.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6P2S1": {
"message": "Seznamy filtrů jsou aktualizovány denně. Ujistěte se, že váš problém již nebyl vyřešen v nejnovějších seznamech filtrů.",
"message": "Seznamy filtrů jsou aktualizovány denně. Ujistěte se, že Váš problém již nebyl vyřešen v nejnovějších seznamech filtrů.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6P2S2": {
@ -976,7 +976,7 @@
"description": "Label for the URL of the page"
},
"supportS6Select1": {
"message": "Webová stránka",
"message": "Webová stránka...",
"description": "Label for widget to select type of issue"
},
"supportS6Select1Option0": {
@ -1012,11 +1012,11 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Checkbox1": {
"message": "Označit webovou stránku jako “NSFW” (<a href=\"https://cs.wikipedia.org/wiki/Not_safe_for_work\">“Není bezpečné pro práci”</a>)",
"message": "Označit webovou stránku jako \"NSFW\" (<a href=\"https://cs.wikipedia.org/wiki/Not_safe_for_work\">“Není bezpečné pro práci”</a>)",
"description": "A checkbox to use for NSFW sites"
},
"aboutPrivacyPolicy": {
"message": "Ochrana soukromí",
"message": "Zásady ochrany osobních údajů",
"description": "Link to privacy policy on GitHub (English)"
},
"aboutChangelog": {
@ -1056,23 +1056,23 @@
"description": "Shown in the About pane"
},
"aboutBackupDataButton": {
"message": "Zálohovat do souboru",
"message": "Zálohovat do souboru...",
"description": "Text for button to create a backup of all settings"
},
"aboutBackupFilename": {
"message": "ublock-moje-zaloha_{{datetime}}.txt",
"message": "moje-zaloha-ublock_{{datetime}}.txt",
"description": "English: my-ublock-backup_{{datetime}}.txt"
},
"aboutRestoreDataButton": {
"message": "Obnovit ze souboru",
"message": "Obnovit ze souboru...",
"description": "English: Restore from file..."
},
"aboutResetDataButton": {
"message": "Obnovit výchozí nastavení",
"message": "Obnovit výchozí nastavení...",
"description": "English: Reset to default settings..."
},
"aboutRestoreDataConfirm": {
"message": "Všechna nastavení budou přepsána těmi zálohovanými {{time}} a uBlock₀ se restartuje.\n\nPřepsat všechna existující nastavení zálohovanými daty?",
"message": "Všechna nastavení budou přepsána daty, zálohovanými {{time}} a uBlock₀ se restartuje.\n\nPřepsat všechna existující nastavení zálohovanými daty?",
"description": "Message asking user to confirm restore"
},
"aboutRestoreDataError": {
@ -1080,7 +1080,7 @@
"description": "Message to display when an error occurred during restore"
},
"aboutResetDataConfirm": {
"message": "Všechna nastavení budou smazána a uBlock₀ se restaruje.\n\nObnovit uBlock₀ do továrního nastavení?",
"message": "Všechna nastavení budou smazána a uBlock₀ se restartuje.\n\nObnovit uBlock₀ do továrního nastavení?",
"description": "Message asking user to confirm reset"
},
"errorCantConnectTo": {
@ -1116,19 +1116,19 @@
"description": "English: {{value}} days ago"
},
"showDashboardButton": {
"message": "Zobrazit řídící panel",
"message": "Zobrazit ovládací panel",
"description": "Firefox/Fennec-specific: Show Dashboard"
},
"showNetworkLogButton": {
"message": "Zobrazit Zaznamenávač",
"message": "Zobrazit Logger",
"description": "Firefox/Fennec-specific: Show Logger"
},
"fennecMenuItemBlockingOff": {
"message": "vypnutý",
"message": "vypnuto",
"description": "Firefox-specific: appears as 'uBlock₀ (off)'"
},
"docblockedTitle": {
"message": "Zablokována stránka",
"message": "Stránka byla zablokována",
"description": "Used as a title for the document-blocked page"
},
"docblockedPrompt1": {
@ -1136,7 +1136,7 @@
"description": "Used in the strict-blocking page"
},
"docblockedPrompt2": {
"message": "Kvůli následujícímu filtru",
"message": "Kvůli následujícímu filtru:",
"description": "Used in the strict-blocking page"
},
"docblockedNoParamsPrompt": {
@ -1144,7 +1144,7 @@
"description": "label to be used for the parameter-less URL: https://cloud.githubusercontent.com/assets/585534/9832014/bfb1b8f0-593b-11e5-8a27-fba472a5529a.png"
},
"docblockedFoundIn": {
"message": "Nalezeno v:",
"message": "Filtr byl nalezen v:",
"description": "English: List of filter list names follows"
},
"docblockedBack": {
@ -1156,7 +1156,7 @@
"description": "English: Close this window"
},
"docblockedDontWarn": {
"message": "Nevarujte mě znovu o této stránce",
"message": "Příště na tuto stránku neupozorňovat",
"description": "Label for checkbox in document-blocked page"
},
"docblockedProceed": {
@ -1176,7 +1176,7 @@
"description": "Button text to navigate to the blocked page"
},
"docblockedRedirectPrompt": {
"message": "Zablokovaná stránka vás chce přesměrovat na jiný web. Pokud se rozhodnete pokračovat, přejdete přímo na: {{url}}",
"message": "Zablokovaná stránka Vás chce přesměrovat na jiný web. Pokud se rozhodnete pokračovat, přejdete přímo na: {{url}}",
"description": "Text warning about an incoming redirect"
},
"docblockedReasonLabel": {
@ -1184,7 +1184,7 @@
"description": "The label which prepend the actual reason why a page was blocked"
},
"docblockedReasonMalicious": {
"message": "Zlomyslný",
"message": "Škodlivá",
"description": "An actual reason why a page was blocked"
},
"docblockedReasonTracker": {
@ -1192,7 +1192,7 @@
"description": "An actual reason why a page was blocked"
},
"docblockedReasonDisreputable": {
"message": "Nereputabilní",
"message": "Pochybná",
"description": "An actual reason why a page was blocked"
},
"cloudPush": {
@ -1216,7 +1216,7 @@
"description": "used as a prompt for the user to provide a custom device name"
},
"advancedSettingsWarning": {
"message": "Pozor! Tato pokročilá nastavení měníte na vlastní nebezpečí.",
"message": "Pozor! Tato pokročilá nastavení měňte jen na vlastní nebezpečí.",
"description": "A warning to users at the top of 'Advanced settings' page"
},
"genericSubmit": {
@ -1236,11 +1236,11 @@
"description": ""
},
"contextMenuBlockElementInFrame": {
"message": "Zablokovat prvek v rámečku…",
"message": "Zablokovat prvek v rámci...",
"description": "An entry in the browser's contextual menu"
},
"contextMenuSubscribeToList": {
"message": "Přihlásit se k odběru seznamu filtrů ...",
"message": "Přihlásit se k odběru seznamu filtrů...",
"description": "An entry in the browser's contextual menu"
},
"contextMenuTemporarilyAllowLargeMediaElements": {
@ -1248,15 +1248,15 @@
"description": "A context menu entry, present when large media elements have been blocked on the current site"
},
"contextMenuViewSource": {
"message": "Zobrazit zdrojový kód",
"message": "Zobrazit zdrojový kód...",
"description": "A context menu entry, to view the source code of the target resource"
},
"shortcutCapturePlaceholder": {
"message": "Stiskněte zkratku",
"message": "Zapište zkratku",
"description": "Placeholder string for input field used to capture a keyboard shortcut"
},
"genericMergeViewScrollLock": {
"message": "Přepnout uzamčení posuvu",
"message": "Přepnout uzamčení posunu",
"description": "Tooltip for the button used to lock scrolling between the views in the 'My rules' pane"
},
"genericCopyToClipboard": {
@ -1264,7 +1264,7 @@
"description": "Label for buttons used to copy something to the clipboard"
},
"genericSelectAll": {
"message": "Vybrat vše",
"message": "Označit vše",
"description": "Label for buttons used to select all text in editor"
},
"toggleCosmeticFiltering": {
@ -1296,7 +1296,7 @@
"description": "short for 'gigabytes'"
},
"clickToLoad": {
"message": "Klikněte pro načtení",
"message": "Klepněte pro načtení",
"description": "Message used in frame placeholders"
},
"linterMainReport": {
@ -1304,11 +1304,11 @@
"description": "Summary of number of errors as reported by the linter "
},
"unprocessedRequestTooltip": {
"message": "Nebylo možné správně filtrovat při spuštění prohlížeče.\nNačtěte stránku znovu, abyste zajistili správné filtrování.",
"message": "Nebylo možné správně filtrovat při spuštění prohlížeče. Načtěte stránku znovu, abyste zajistili správné filtrování.",
"description": "A warning which will appear in the popup panel if needed"
},
"dummy": {
"message": "This entry must be the last one",
"message": "Tento záznam musí být poslední",
"description": "so we dont need to deal with comma for last entry"
}
}

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Lokale regler: Denne kolonne er til regler kun gældene dette websted.\nLokale regler tilsidesætter globale regler.",
"message": "Lokale regler: denne søjle viser de regler der gælder kun på denne side.\nLokale regler overskriver globale regler.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -216,11 +216,11 @@
"description": "Label to be used to hide popup panel sections"
},
"popupTipGlobalRules": {
"message": "Globale Regeln: Diese Spalte ist für Regeln, die für alle Websites gelten.",
"message": "Globale Regeln: Die Regeln in dieser Spalte gelten für alle Websites.",
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Lokale Regeln: Diese Spalte ist für Regeln, die nur für die aktuelle Website gelten.\nLokale Regeln überschreiben globale Regeln.",
"message": "Lokale Regeln: Die Regeln in dieser Spalte gelten nur für diese Website.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {
@ -416,7 +416,7 @@
"description": "English: Last restore:"
},
"settingsLastBackupPrompt": {
"message": "Letzte Sicherung:",
"message": "Letztes Backup:",
"description": "English: Last backup:"
},
"3pListsOfBlockedHostsPrompt": {
@ -960,7 +960,7 @@
"description": "Header of 'Report a filter issue' section in Support pane"
},
"supportS6P1S1": {
"message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. <b>Hinweis:</b> Das Anklicken der Schaltfläche übermittelt den Ursprung der Seite an GitHub.",
"message": "Um die Freiwilligen nicht mit doppelten Meldungen zu überlasten, vergewissern Sie sich bitte, dass das Problem noch nicht gemeldet wurde. <b>Hinweis:</b> Das Anklicken der Schaltfläche übermittelt die Internetadresse an GitHub.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6P2S1": {
@ -984,11 +984,11 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option1": {
"message": "Zeigt Werbung oder Werbereste",
"message": "Zeigt Werbung oder deren Überreste",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option2": {
"message": "Hat Überdeckungen oder andere Belästigungen",
"message": "Enthält überdeckende oder belästigende Elemente",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option3": {
@ -996,7 +996,7 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option4": {
"message": "Hat Datenschutzprobleme",
"message": "Weist Datenschutzprobleme auf",
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Select1Option5": {
@ -1060,7 +1060,7 @@
"description": "Text for button to create a backup of all settings"
},
"aboutBackupFilename": {
"message": "ublock-sicherung_{{datetime}}.txt",
"message": "ublock-backup_{{datetime}}.txt",
"description": "English: my-ublock-backup_{{datetime}}.txt"
},
"aboutRestoreDataButton": {
@ -1072,7 +1072,7 @@
"description": "English: Reset to default settings..."
},
"aboutRestoreDataConfirm": {
"message": "Alle Einstellungen werden überschrieben und auf den Stand vom {{time}} gebracht. Anschließend wird uBlock₀ neu gestartet.\n\nSollen die aktuellen Einstellungen durch die Sicherung ersetzt werden?",
"message": "Alle Einstellungen werden überschrieben und auf den Stand vom {{time}} gebracht. Anschließend wird uBlock₀ neu gestartet.\n\nSollen die aktuellen Einstellungen durch das Backup ersetzt werden?",
"description": "Message asking user to confirm restore"
},
"aboutRestoreDataError": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -12,7 +12,7 @@
"description": "English: uBlock₀ — Dashboard"
},
"dashboardUnsavedWarning": {
"message": "경고! 저장되지 않은 변경 사항이 있습니다",
"message": "경고: 저장되지 않은 변경 사항이 있습니다!",
"description": "A warning in the dashboard when navigating away from unsaved changes"
},
"dashboardUnsavedWarningStay": {
@ -72,7 +72,7 @@
"description": "English: Click: disable/enable uBlock₀ for this site.\n\nCtrl+click: disable uBlock₀ only on this page."
},
"popupPowerSwitchInfo1": {
"message": "클릭: 이 사이트에서 uBlock₀을 끕니다.\n\nCtrl+클릭: 이 페이지에서만 uBlock₀을 끕니다.",
"message": "클릭: 이 사이트에서 uBlock₀을 비활성화합니다.\nCtrl+클릭: 이 페이지에서만 uBlock₀을 비활성화합니다.",
"description": "Message to be read by screen readers"
},
"popupPowerSwitchInfo2": {
@ -96,7 +96,7 @@
"description": "English: since install"
},
"popupOr": {
"message": "/",
"message": "또는",
"description": "English: or"
},
"popupBlockedOnThisPage_v2": {
@ -128,7 +128,7 @@
"description": "Tooltip used for the logger icon in the panel"
},
"popupTipReport": {
"message": "이 사이트의 이슈 신고",
"message": "이 사이트의 문제 신고",
"description": "Tooltip used for the 'chat' icon in the panel"
},
"popupTipNoPopups": {
@ -136,27 +136,27 @@
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoPopups1": {
"message": "클릭하여 이 사이트에서 모든 팝업을 차단합니다.",
"message": "클릭하여 이 사이트에서 모든 팝업을 차단합니다",
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoPopups2": {
"message": "클릭하여 이 사이트에서 모든 팝업 차단을 해제합니다.",
"message": "클릭하여 이 사이트에서 팝업 차단을 해제합니다",
"description": "Tooltip for the no-popups per-site switch"
},
"popupTipNoLargeMedia": {
"message": "이 사이트에서만 적용되는 대형 미디어 구성요소 차단 기능을 켜고 끕니다.",
"message": "이 사이트에서만 적용되는 대용량 미디어 요소 차단 기능을 켜고 끕니다",
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoLargeMedia1": {
"message": "클릭하여 이 사이트에서 대용량 미디어를 차단합니다.",
"message": "클릭하여 이 사이트에서 대용량 미디어를 차단합니다",
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoLargeMedia2": {
"message": "클릭하여 이 사이트에서 대용량 미디어 차단을 해제합니다.",
"message": "클릭하여 이 사이트에서 대용량 미디어 차단을 해제합니다",
"description": "Tooltip for the no-large-media per-site switch"
},
"popupTipNoCosmeticFiltering": {
"message": "이 사이트에서 시각적 필터링 토글",
"message": "이 사이트에서 요소 숨김 필터링 토글",
"description": "Tooltip for the no-cosmetic-filtering per-site switch"
},
"popupTipNoCosmeticFiltering1": {
@ -168,23 +168,23 @@
"description": "Tooltip for the no-cosmetic-filtering per-site switch"
},
"popupTipNoRemoteFonts": {
"message": "이 사이트에서 글꼴조정 차단 토글",
"message": "이 사이트에서 외부 폰트 차단 토글",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoRemoteFonts1": {
"message": "클릭하여 이 사이트에서 외부 폰트를 차단합니다.",
"message": "클릭하여 이 사이트에서 외부 폰트를 차단합니다",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoRemoteFonts2": {
"message": "클릭하여 이 사이트에서 더 이상 외부 폰트를 차단하지 않습니다.",
"message": "클릭하여 이 사이트에서 외부 폰트 차단을 해제합니다",
"description": "Tooltip for the no-remote-fonts per-site switch"
},
"popupTipNoScripting1": {
"message": "클릭하여 이 사이트에서 JavaScript 비활성화",
"message": "클릭하여 이 사이트에서 JavaScript 비활성화합니다",
"description": "Tooltip for the no-scripting per-site switch"
},
"popupTipNoScripting2": {
"message": "클릭하여 이 사이트에서 JavaScript 활성화",
"message": "클릭하여 이 사이트에서 JavaScript 활성화합니다",
"description": "Tooltip for the no-scripting per-site switch"
},
"popupNoPopups_v2": {
@ -192,7 +192,7 @@
"description": "Caption for the no-popups per-site switch"
},
"popupNoLargeMedia_v2": {
"message": " 미디어 요소",
"message": "대용량 미디어 요소",
"description": "Caption for the no-large-media per-site switch"
},
"popupNoCosmeticFiltering_v2": {
@ -204,11 +204,11 @@
"description": "Caption for the no-remote-fonts per-site switch"
},
"popupNoScripting_v2": {
"message": "자바스크립트",
"message": "JavaScript",
"description": "Caption for the no-scripting per-site switch"
},
"popupMoreButton_v2": {
"message": "더보기",
"message": "더 보기",
"description": "Label to be used to show popup panel sections"
},
"popupLessButton_v2": {
@ -240,11 +240,11 @@
"description": ""
},
"popup3pAnyRulePrompt": {
"message": "보조 필터",
"message": "서드 파티 필터",
"description": ""
},
"popup3pPassiveRulePrompt": {
"message": "보조 CSS/이미지",
"message": "서드 파티 CSS/이미지",
"description": ""
},
"popupInlineScriptRulePrompt": {
@ -252,15 +252,15 @@
"description": ""
},
"popup1pScriptRulePrompt": {
"message": "스크립트",
"message": "스크립트",
"description": ""
},
"popup3pScriptRulePrompt": {
"message": "보조 스크립트",
"message": "서드 파티 스크립트",
"description": ""
},
"popup3pFrameRulePrompt": {
"message": "보조 프레임",
"message": "서드 파티 프레임",
"description": ""
},
"popupHitDomainCountPrompt": {
@ -300,11 +300,11 @@
"description": "Element picker preview mode: will cause the elements matching the current filter to be removed from the page"
},
"pickerNetFilters": {
"message": " 필터",
"message": "네트워크 필터",
"description": "English: header for a type of filter in the element picker dialog"
},
"pickerCosmeticFilters": {
"message": "표면 필터",
"message": "요소 숨김 필터",
"description": "English: Cosmetic filters"
},
"pickerCosmeticFiltersHint": {
@ -316,7 +316,7 @@
"description": "An entry in the browser's contextual menu"
},
"settingsCollapseBlockedPrompt": {
"message": "차단된 구성 요소의 자리 감추기",
"message": "차단된 요소의 자리 감추기",
"description": "English: Hide placeholders of blocked elements"
},
"settingsIconBadgePrompt": {
@ -332,7 +332,7 @@
"description": "English: Make use of context menu where appropriate"
},
"settingsColorBlindPrompt": {
"message": "색맹 최적화",
"message": "색맹 접근성 향상",
"description": "English: Color-blind friendly"
},
"settingsAppearance": {
@ -376,7 +376,7 @@
"description": ""
},
"settingsNoCosmeticFilteringPrompt": {
"message": "표면 필터 비활성화",
"message": "요소 숨김 필터 비활성화",
"description": ""
},
"settingsNoLargeMediaPrompt": {
@ -384,7 +384,7 @@
"description": ""
},
"settingsNoRemoteFontsPrompt": {
"message": "글꼴 조종 차단",
"message": "외부 폰트 차단",
"description": ""
},
"settingsNoScriptingPrompt": {
@ -420,7 +420,7 @@
"description": "English: Last backup:"
},
"3pListsOfBlockedHostsPrompt": {
"message": "{{netFilterCount}} 네트워크 필터 {{cosmeticFilterCount}} 표면 필터:",
"message": "{{netFilterCount}} 네트워크 필터 {{cosmeticFilterCount}} 요소 숨김 필터:",
"description": "Appears at the top of the _3rd-party filters_ pane"
},
"3pListsOfBlockedHostsPerListStats": {
@ -440,7 +440,7 @@
"description": "A button in the in the _3rd-party filters_ pane"
},
"3pParseAllABPHideFiltersPrompt1": {
"message": "표면 필터 분석 및 적용",
"message": "요소 숨김 필터 분석 및 적용",
"description": "English: Parse and enforce Adblock+ element hiding filters."
},
"3pParseAllABPHideFiltersInfo": {
@ -448,7 +448,7 @@
"description": "Describes the purpose of the 'Parse and enforce cosmetic filters' feature."
},
"3pIgnoreGenericCosmeticFilters": {
"message": "전체적 표면 필터 무시",
"message": "범용 요소 숨김 필터 무시",
"description": "This will cause uBO to ignore all generic cosmetic filters."
},
"3pIgnoreGenericCosmeticFiltersInfo": {
@ -468,7 +468,7 @@
"description": "English: Apply changes"
},
"3pGroupDefault": {
"message": "Ublock₀ 제공",
"message": "기본 내장",
"description": "Filter lists section name"
},
"3pGroupAds": {
@ -476,11 +476,11 @@
"description": "Filter lists section name"
},
"3pGroupPrivacy": {
"message": "개인정보",
"message": "개인정보 보호",
"description": "Filter lists section name"
},
"3pGroupMalware": {
"message": "멀웨어 도메인",
"message": "멀웨어 및 보안",
"description": "Filter lists section name"
},
"3pGroupSocial": {
@ -488,11 +488,11 @@
"description": "Filter lists section name"
},
"3pGroupCookies": {
"message": "쿠키 알림",
"message": "쿠키 공지",
"description": "Filter lists section name"
},
"3pGroupAnnoyances": {
"message": "골칫거리",
"message": "방해 요소",
"description": "Filter lists section name"
},
"3pGroupMultipurpose": {
@ -500,7 +500,7 @@
"description": "Filter lists section name"
},
"3pGroupRegions": {
"message": "지역, 언어",
"message": "지역 언어",
"description": "Filter lists section name"
},
"3pGroupCustom": {
@ -740,7 +740,7 @@
"description": "A keyword in the built-in row filtering expression"
},
"loggerRowFiltererBuiltin3p": {
"message": "보조",
"message": "서드 파티",
"description": "A keyword in the built-in row filtering expression"
},
"loggerEntryDetailsHeader": {
@ -796,7 +796,7 @@
"description": "Small header to identify the static filtering section"
},
"loggerStaticFilteringSentence": {
"message": "네트워크 요청이 {{type}} 일 경우,{{br}}URL 주소가 {{url}} 와 일치하고{{br}}{{origin}} 에서 비롯 되었을 경우 {{action}} 한다.{{br}}그리고 다음 예외 필터와 일치할 경우 {{importance}} 한다.",
"message": "네트워크 요청이 {{type}} 일 경우,{{br}}URL 주소가 {{url}} 와 일치하고{{br}}{{origin}} 에서 비롯되었을 경우 {{action}} 한다.{{br}}그리고 다음 예외 필터와 일치할 경우 {{importance}} 한다.",
"description": "Used in the static filtering wizard"
},
"loggerStaticFilteringSentencePartBlock": {
@ -836,7 +836,7 @@
"description": "Below this sentence, the filter list(s) in which the filter was found"
},
"loggerStaticFilteringFinderSentence2": {
"message": "활성화된 정적 필터 목록에서 <code>{{filter}}</code>를 찾지 못했습니다",
"message": "현재 활성화된 필터 목록에서 정적 필터를 찾을 수 없습니다",
"description": "Message to show when a filter cannot be found in any filter lists"
},
"loggerSettingDiscardPrompt": {
@ -928,11 +928,11 @@
"description": "Header of 'Filter issues' section in Support pane"
},
"supportS3P1": {
"message": "특정 웹사이트에서 발생하는 필터 이슈는 <span data-url=\"https://github.com/uBlockOrigin/uAssets/issues?q=is%3Aissue\"><code>uBlockOrigin/uAssets</code> 이슈 트래커</span>에 보고해주세요. GitHub 계정이 필요합니다.",
"message": "특정 웹사이트에서 발생하는 필터 문제는 <span data-url=\"https://github.com/uBlockOrigin/uAssets/issues?q=is%3Aissue\"><code>uBlockOrigin/uAssets</code> 이슈 트래커</span>에 보고해주세요. GitHub 계정이 필요합니다",
"description": "First paragraph of 'Filter issues' section in Support pane"
},
"supportS3P2": {
"message": "<b>중요:</b> uBlock Origin과 유사한 목적의 다른 차단기를 함께 사용하지 마세요. 특정 웹사이트에서 필터 문제가 발생할 수 있습니다.",
"message": "<b>중요:</b> uBlock Origin과 유사한 목적의 다른 차단기를 함께 사용하지 마세요. 일부 웹사이트에서 필터 문제가 발생할 수 있습니다.",
"description": "Second paragraph of 'Filter issues' section in Support pane"
},
"supportS3P3": {
@ -952,23 +952,23 @@
"description": "Header of 'Troubleshooting Information' section in Support pane"
},
"supportS5P1": {
"message": "다음은 자원 봉사자들이 문제를 해결하는 데에 도움을 줄 때 유용할 수 있는 기술적인 정보입니다.",
"message": "다음은 자원봉사자들이 문제를 해결을 돕는 데 유용할 수 있는 기술적인 정보입니다.",
"description": "First paragraph of 'Troubleshooting Information' section in Support pane"
},
"supportS6H": {
"message": "필터 이슈 신고",
"message": "필터 문제 신고",
"description": "Header of 'Report a filter issue' section in Support pane"
},
"supportS6P1S1": {
"message": "봉사자들이 중복 신고로 인해 부담을 겪지 않도록, 해당 이슈가 이미 신고되지는 않았는지 확인해주시기 바랍니다.",
"message": "자원봉사자들이 중복 신고로 인해 부담을 겪지 않도록, 해당 문제가 이미 신고되지는 않았는지 확인해주시기 바랍니다. <b>중요:</b> 버튼을 클릭하면 페이지의 출처가 GitHub로 전송됩니다.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6P2S1": {
"message": "필터 목록은 매일 갱신됩니다. 최신 필터 목록에서 문제가 이미 해결되진 않았는지 확인하세요.",
"message": "필터 목록은 매일 업데이트됩니다. 최신 필터 목록에서 문제가 이미 해결되었는지 확인해 주세요.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6P2S2": {
"message": "문제가 생긴 웹페이지를 새로고침해도 문제가 여전히 남아 있는지 확인하세요.",
"message": "문제가 있는 웹페이지를 새로고침한 후에도 문제가 여전히 발생하는지 확인해 주세요.",
"description": "A paragraph in the filter issue reporter section"
},
"supportS6URL": {
@ -1012,11 +1012,11 @@
"description": "An entry in the widget used to select the type of issue"
},
"supportS6Checkbox1": {
"message": "웹페이지를 \"NSFW\" (<a href=\"https://wikipedia.org/wiki/Not_safe_for_work\">“Not Safe For Work”</a>)로 분류",
"message": "웹 페이지를 “NSFW” (<a href=\"https://wikipedia.org/wiki/Not_safe_for_work\">“Not Safe For Work”</a>)로 분류",
"description": "A checkbox to use for NSFW sites"
},
"aboutPrivacyPolicy": {
"message": "개인정보취급방침",
"message": "개인정보 처리방침",
"description": "Link to privacy policy on GitHub (English)"
},
"aboutChangelog": {
@ -1092,31 +1092,31 @@
"description": "For the button used to subscribe to a filter list"
},
"elapsedOneMinuteAgo": {
"message": "1 분 전",
"message": "1분 전",
"description": "English: a minute ago"
},
"elapsedManyMinutesAgo": {
"message": "{{value}} 분 전",
"message": "{{value}}분 전",
"description": "English: {{value}} minutes ago"
},
"elapsedOneHourAgo": {
"message": "1 시간 전",
"message": "1시간 전",
"description": "English: an hour ago"
},
"elapsedManyHoursAgo": {
"message": "{{value}} 시간 전",
"message": "{{value}}시간 전",
"description": "English: {{value}} hours ago"
},
"elapsedOneDayAgo": {
"message": "1 일 전",
"message": "1일 전",
"description": "English: a day ago"
},
"elapsedManyDaysAgo": {
"message": "{{value}} 일 전",
"message": "{{value}}일 전",
"description": "English: {{value}} days ago"
},
"showDashboardButton": {
"message": "대보드 보기",
"message": "대보드 보기",
"description": "Firefox/Fennec-specific: Show Dashboard"
},
"showNetworkLogButton": {
@ -1164,7 +1164,7 @@
"description": "English: Disable strict blocking for {{hostname}} ..."
},
"docblockedDisableTemporary": {
"message": "이번만",
"message": "일시적으로",
"description": "English: Temporarily"
},
"docblockedDisablePermanent": {
@ -1244,7 +1244,7 @@
"description": "An entry in the browser's contextual menu"
},
"contextMenuTemporarilyAllowLargeMediaElements": {
"message": "이번만 대형 미디어 구성요소 허용",
"message": "일시적으로 대용량 미디어 요소 허용",
"description": "A context menu entry, present when large media elements have been blocked on the current site"
},
"contextMenuViewSource": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Lokale regels: deze kolom is voor regels die alleen op de huidige website van toepassing zijn.\nLokale regels hebben voorrang op algemene regels.",
"message": "Lokale regels: deze kolom is voor regels die alleen op de huidige website van toepassing zijn.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Local rules: this column is for rules which apply to the current site only.\nLocal rules override global rules.",
"message": "Local rules: this column is for rules which apply to the current site only.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -480,7 +480,7 @@
"description": "Filter lists section name"
},
"3pGroupMalware": {
"message": "Domenii malițioase",
"message": "Domenii malițioase, securitate",
"description": "Filter lists section name"
},
"3pGroupSocial": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Lokala regler: den här kolumnen avser endast regler som gäller för den aktuella webbplatsen.\nLokala regler åsidosätter globala regler.",
"message": "Lokala regler: denna kolumn avser endast regler som gäller för den aktuella webbplatsen.\nLokala regler åsidosätter globala regler.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -900,7 +900,7 @@
"description": "Text for button which open an external web page in Support pane"
},
"supportReportSpecificButton": {
"message": "GitHub üzerinde yeni rapor oluştur",
"message": "GitHub'da yeni rapor oluştur",
"description": "Text for button which open an external web page in Support pane"
},
"supportFindSpecificButton": {

View file

@ -220,7 +220,7 @@
"description": "Tooltip when hovering the top-most cell of the global-rules column."
},
"popupTipLocalRules": {
"message": "Локальні правила: цей стовпчик для правил, що застосовуються лише для цього сайту.\nЛокальні правила замінюють глобальні.",
"message": "Локальні правила: цей стовпчик для правил, що застосовуються лише цього сайту.\nЛокальні правила замінюють глобальні.",
"description": "Tooltip when hovering the top-most cell of the local-rules column."
},
"popupTipSaveRules": {

View file

@ -486,7 +486,10 @@ export class JSONPath {
if ( outcome ) { return k; }
}
#modifyVal(obj, key) {
const { modify, rval } = this.#compiled;
let { modify, rval } = this.#compiled;
if ( typeof rval === 'string' ) {
rval = rval.replace('${now}', `${Date.now()}`);
}
switch ( modify ) {
case undefined:
obj[key] = rval;

View file

@ -71,15 +71,12 @@ function trustedCreateHTML(
const duration = parseInt(durationStr, 10);
const domParser = new DOMParser();
const externalDoc = domParser.parseFromString(htmlStr, 'text/html');
const docFragment = new DocumentFragment();
const toRemove = [];
const toAppend = [];
while ( externalDoc.body.firstChild !== null ) {
const imported = document.adoptNode(externalDoc.body.firstChild);
docFragment.appendChild(imported);
if ( isNaN(duration) ) { continue; }
toRemove.push(imported);
toAppend.push(document.adoptNode(externalDoc.body.firstChild));
}
if ( docFragment.firstChild === null ) { return; }
if ( toAppend.length === 0 ) { return; }
const toRemove = [];
const remove = ( ) => {
for ( const node of toRemove ) {
if ( node.parentNode === null ) { continue; }
@ -87,10 +84,21 @@ function trustedCreateHTML(
}
safe.uboLog(logPrefix, 'Node(s) removed');
};
const appendOne = (target, nodes) => {
for ( const node of nodes ) {
target.append(node);
if ( isNaN(duration) ) { continue; }
toRemove.push(node);
}
};
const append = ( ) => {
const parent = document.querySelector(parentSelector);
if ( parent === null ) { return false; }
parent.append(docFragment);
const targets = document.querySelectorAll(parentSelector);
if ( targets.length === 0 ) { return false; }
const limit = Math.min(targets.length, extraArgs.limit || 1) - 1;
for ( let i = 0; i < limit; i++ ) {
appendOne(targets[i], toAppend.map(a => a.cloneNode(true)));
}
appendOne(targets[limit], toAppend);
safe.uboLog(logPrefix, 'Node(s) appended');
if ( toRemove.length === 0 ) { return true; }
setTimeout(remove, duration);

View file

@ -42,32 +42,31 @@ function jsonPrune(
const logPrefix = safe.makeLogPrefix('json-prune', rawPrunePaths, rawNeedlePaths, stackNeedle);
const stackNeedleDetails = safe.initPattern(stackNeedle, { canNegate: true });
const extraArgs = safe.getExtraArgs(Array.from(arguments), 3);
JSON.parse = new Proxy(JSON.parse, {
apply: function(target, thisArg, args) {
const objBefore = Reflect.apply(target, thisArg, args);
if ( rawPrunePaths === '' ) {
safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2));
}
const objAfter = objectPruneFn(
objBefore,
rawPrunePaths,
rawNeedlePaths,
stackNeedleDetails,
extraArgs
);
if ( objAfter === undefined ) { return objBefore; }
safe.uboLog(logPrefix, 'Pruned');
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`);
}
return objAfter;
},
proxyApplyFn('JSON.parse', function(context) {
const objBefore = context.reflect();
if ( rawPrunePaths === '' ) {
safe.uboLog(logPrefix, safe.JSON_stringify(objBefore, null, 2));
}
const objAfter = objectPruneFn(
objBefore,
rawPrunePaths,
rawNeedlePaths,
stackNeedleDetails,
extraArgs
);
if ( objAfter === undefined ) { return objBefore; }
safe.uboLog(logPrefix, 'Pruned');
if ( safe.logLevel > 1 ) {
safe.uboLog(logPrefix, `After pruning:\n${safe.JSON_stringify(objAfter, null, 2)}`);
}
return objAfter;
});
}
registerScriptlet(jsonPrune, {
name: 'json-prune.js',
dependencies: [
objectPruneFn,
proxyApplyFn,
safeSelf,
],
});

View file

@ -51,6 +51,7 @@ function preventFetchFn(
const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url');
const validResponseProps = {
ok: [ false, true ],
status: [ 403 ],
statusText: [ '', 'Not Found' ],
type: [ 'basic', 'cors', 'default', 'error', 'opaque' ],
};

View file

@ -0,0 +1,270 @@
/*******************************************************************************
uBlock Origin - a comprehensive, efficient content blocker
Copyright (C) 2019-present Raymond Hill
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see {http://www.gnu.org/licenses/}.
Home: https://github.com/gorhill/uBlock
*/
import {
generateContentFn,
matchObjectPropertiesFn,
parsePropertiesToMatchFn,
} from './utils.js';
import { proxyApplyFn } from './proxy-apply.js';
import { registerScriptlet } from './base.js';
import { safeSelf } from './safe-self.js';
// Externally added to the private namespace in which scriptlets execute.
/* global scriptletGlobals */
/******************************************************************************/
function preventXhrFn(
trusted = false,
propsToMatch = '',
directive = ''
) {
if ( typeof propsToMatch !== 'string' ) { return; }
const safe = safeSelf();
const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr';
const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive);
const xhrInstances = new WeakMap();
const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url');
const warOrigin = scriptletGlobals.warOrigin;
const safeDispatchEvent = (xhr, type) => {
try {
xhr.dispatchEvent(new Event(type));
} catch {
}
};
proxyApplyFn('XMLHttpRequest.prototype.open', function(context) {
const { thisArg, callArgs } = context;
xhrInstances.delete(thisArg);
const [ method, url, ...args ] = callArgs;
if ( warOrigin !== undefined && url.startsWith(warOrigin) ) {
return context.reflect();
}
const haystack = { method, url };
if ( propsToMatch === '' && directive === '' ) {
safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`);
return context.reflect();
}
if ( matchObjectPropertiesFn(propNeedles, haystack) ) {
const xhrDetails = Object.assign(haystack, {
xhr: thisArg,
defer: args.length === 0 || !!args[0],
directive,
headers: {
'date': '',
'content-type': '',
'content-length': '',
},
url: haystack.url,
props: {
response: { value: '' },
responseText: { value: '' },
responseXML: { value: null },
},
});
xhrInstances.set(thisArg, xhrDetails);
}
return context.reflect();
});
proxyApplyFn('XMLHttpRequest.prototype.send', function(context) {
const { thisArg } = context;
const xhrDetails = xhrInstances.get(thisArg);
if ( xhrDetails === undefined ) {
return context.reflect();
}
xhrDetails.headers['date'] = (new Date()).toUTCString();
let xhrText = '';
switch ( thisArg.responseType ) {
case 'arraybuffer':
xhrDetails.props.response.value = new ArrayBuffer(0);
xhrDetails.headers['content-type'] = 'application/octet-stream';
break;
case 'blob':
xhrDetails.props.response.value = new Blob([]);
xhrDetails.headers['content-type'] = 'application/octet-stream';
break;
case 'document': {
const parser = new DOMParser();
const doc = parser.parseFromString('', 'text/html');
xhrDetails.props.response.value = doc;
xhrDetails.props.responseXML.value = doc;
xhrDetails.headers['content-type'] = 'text/html';
break;
}
case 'json':
xhrDetails.props.response.value = {};
xhrDetails.props.responseText.value = '{}';
xhrDetails.headers['content-type'] = 'application/json';
break;
default: {
if ( directive === '' ) { break; }
xhrText = generateContentFn(trusted, xhrDetails.directive);
if ( xhrText instanceof Promise ) {
xhrText = xhrText.then(text => {
xhrDetails.props.response.value = text;
xhrDetails.props.responseText.value = text;
});
} else {
xhrDetails.props.response.value = xhrText;
xhrDetails.props.responseText.value = xhrText;
}
xhrDetails.headers['content-type'] = 'text/plain';
break;
}
}
if ( xhrDetails.defer === false ) {
xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length;
Object.defineProperties(xhrDetails.xhr, {
readyState: { value: 4 },
responseURL: { value: xhrDetails.url },
status: { value: 200 },
statusText: { value: 'OK' },
});
Object.defineProperties(xhrDetails.xhr, xhrDetails.props);
return;
}
Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 1, configurable: true },
responseURL: { value: xhrDetails.url },
});
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
xhrDetails.headers['content-length'] = `${details.props.response.value}`.length;
Object.defineProperties(details.xhr, {
readyState: { value: 2, configurable: true },
status: { value: 200 },
statusText: { value: 'OK' },
});
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 3, configurable: true },
});
Object.defineProperties(details.xhr, details.props);
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 4 },
});
safeDispatchEvent(details.xhr, 'readystatechange');
safeDispatchEvent(details.xhr, 'load');
safeDispatchEvent(details.xhr, 'loadend');
safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`);
});
});
proxyApplyFn('XMLHttpRequest.prototype.getResponseHeader', function(context) {
const { thisArg } = context;
const xhrDetails = xhrInstances.get(thisArg);
if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) {
return context.reflect();
}
const headerName = `${context.callArgs[0]}`;
const value = xhrDetails.headers[headerName.toLowerCase()];
if ( value !== undefined && value !== '' ) { return value; }
return null;
});
proxyApplyFn('XMLHttpRequest.prototype.getAllResponseHeaders', function(context) {
const { thisArg } = context;
const xhrDetails = xhrInstances.get(thisArg);
if ( xhrDetails === undefined || thisArg.readyState < thisArg.HEADERS_RECEIVED ) {
return context.reflect();
}
const out = [];
for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) {
if ( !value ) { continue; }
out.push(`${name}: ${value}`);
}
if ( out.length !== 0 ) { out.push(''); }
return out.join('\r\n');
});
}
registerScriptlet(preventXhrFn, {
name: 'prevent-xhr.fn',
dependencies: [
generateContentFn,
matchObjectPropertiesFn,
parsePropertiesToMatchFn,
proxyApplyFn,
safeSelf,
],
});
/******************************************************************************/
/**
* @scriptlet prevent-xhr
*
* @description
* Prevent a XMLHttpRequest-baesed request from being sent to a remote server.
*
* @param propsToMatch
* The fetch arguments to match for the prevention to be triggered. The
* untrusted flavor limits the realm of response to return to safe values.
*
* @param [responseBody]
* Optional. The reponse to return when the prevention occurs. The response
* must be a safe constant value.
*
* */
function preventXhr(...args) {
return preventXhrFn(false, ...args);
}
registerScriptlet(preventXhr, {
name: 'prevent-xhr.js',
aliases: [
'no-xhr-if.js',
],
dependencies: [
preventXhrFn,
],
});
/******************************************************************************/
/**
* @scriptlet trusted-prevent-xhr
*
* @description
* Prevent a XMLHttpRequest-based request from being sent to a remote server.
*
* @param propsToMatch
* The fetch arguments to match for the prevention to be triggered. The
* untrusted flavor limits the realm of response to return to safe values.
*
* @param [responseBody]
* Optional. The reponse to return when the prevention occurs. The trusted
* version allows arbitrary response.
*
* */
function trustedPreventXhr(...args) {
return preventXhrFn(true, ...args);
}
registerScriptlet(trustedPreventXhr, {
name: 'trusted-prevent-xhr.js',
dependencies: [
preventXhrFn,
],
});

View file

@ -86,27 +86,38 @@ export function proxyApplyFn(
}
};
proxyApplyFn.isCtor = new Map();
proxyApplyFn.proxies = new WeakMap();
proxyApplyFn.nativeToString = Function.prototype.toString;
const proxiedToString = new Proxy(Function.prototype.toString, {
apply(target, thisArg) {
let proxied = thisArg;
for(;;) {
const fn = proxyApplyFn.proxies.get(proxied);
if ( fn === undefined ) { break; }
proxied = fn;
}
return proxyApplyFn.nativeToString.call(proxied);
}
});
proxyApplyFn.proxies.set(proxiedToString, proxyApplyFn.nativeToString);
Function.prototype.toString = proxiedToString;
}
if ( proxyApplyFn.isCtor.has(target) === false ) {
proxyApplyFn.isCtor.set(target, fn.prototype?.constructor === fn);
}
const fnStr = fn.toString();
const toString = (function toString() { return fnStr; }).bind(null);
const proxyDetails = {
apply(target, thisArg, args) {
return handler(proxyApplyFn.ApplyContext.factory(target, thisArg, args));
},
get(target, prop) {
if ( prop === 'toString' ) { return toString; }
return Reflect.get(target, prop);
},
}
};
if ( proxyApplyFn.isCtor.get(target) ) {
proxyDetails.construct = function(target, args) {
return handler(proxyApplyFn.CtorContext.factory(target, args));
};
}
context[prop] = new Proxy(fn, proxyDetails);
const proxiedTarget = new Proxy(fn, proxyDetails);
proxyApplyFn.proxies.set(proxiedTarget, fn);
context[prop] = proxiedTarget;
}
registerScriptlet(proxyApplyFn, {
name: 'proxy-apply.fn',

View file

@ -32,12 +32,12 @@ import './prevent-dialog.js';
import './prevent-fetch.js';
import './prevent-innerHTML.js';
import './prevent-settimeout.js';
import './prevent-xhr.js';
import './replace-argument.js';
import './spoof-css.js';
import {
collateFetchArgumentsFn,
generateContentFn,
getExceptionTokenFn,
getRandomTokenFn,
matchObjectPropertiesFn,
@ -381,196 +381,6 @@ function replaceFetchResponseFn(
});
}
/******************************************************************************/
builtinScriptlets.push({
name: 'prevent-xhr.fn',
fn: preventXhrFn,
dependencies: [
'generate-content.fn',
'match-object-properties.fn',
'parse-properties-to-match.fn',
'safe-self.fn',
],
});
function preventXhrFn(
trusted = false,
propsToMatch = '',
directive = ''
) {
if ( typeof propsToMatch !== 'string' ) { return; }
const safe = safeSelf();
const scriptletName = trusted ? 'trusted-prevent-xhr' : 'prevent-xhr';
const logPrefix = safe.makeLogPrefix(scriptletName, propsToMatch, directive);
const xhrInstances = new WeakMap();
const propNeedles = parsePropertiesToMatchFn(propsToMatch, 'url');
const warOrigin = scriptletGlobals.warOrigin;
const safeDispatchEvent = (xhr, type) => {
try {
xhr.dispatchEvent(new Event(type));
} catch {
}
};
const XHRBefore = XMLHttpRequest.prototype;
self.XMLHttpRequest = class extends self.XMLHttpRequest {
open(method, url, ...args) {
xhrInstances.delete(this);
if ( warOrigin !== undefined && url.startsWith(warOrigin) ) {
return super.open(method, url, ...args);
}
const haystack = { method, url };
if ( propsToMatch === '' && directive === '' ) {
safe.uboLog(logPrefix, `Called: ${safe.JSON_stringify(haystack, null, 2)}`);
return super.open(method, url, ...args);
}
if ( matchObjectPropertiesFn(propNeedles, haystack) ) {
const xhrDetails = Object.assign(haystack, {
xhr: this,
defer: args.length === 0 || !!args[0],
directive,
headers: {
'date': '',
'content-type': '',
'content-length': '',
},
url: haystack.url,
props: {
response: { value: '' },
responseText: { value: '' },
responseXML: { value: null },
},
});
xhrInstances.set(this, xhrDetails);
}
return super.open(method, url, ...args);
}
send(...args) {
const xhrDetails = xhrInstances.get(this);
if ( xhrDetails === undefined ) {
return super.send(...args);
}
xhrDetails.headers['date'] = (new Date()).toUTCString();
let xhrText = '';
switch ( this.responseType ) {
case 'arraybuffer':
xhrDetails.props.response.value = new ArrayBuffer(0);
xhrDetails.headers['content-type'] = 'application/octet-stream';
break;
case 'blob':
xhrDetails.props.response.value = new Blob([]);
xhrDetails.headers['content-type'] = 'application/octet-stream';
break;
case 'document': {
const parser = new DOMParser();
const doc = parser.parseFromString('', 'text/html');
xhrDetails.props.response.value = doc;
xhrDetails.props.responseXML.value = doc;
xhrDetails.headers['content-type'] = 'text/html';
break;
}
case 'json':
xhrDetails.props.response.value = {};
xhrDetails.props.responseText.value = '{}';
xhrDetails.headers['content-type'] = 'application/json';
break;
default: {
if ( directive === '' ) { break; }
xhrText = generateContentFn(trusted, xhrDetails.directive);
if ( xhrText instanceof Promise ) {
xhrText = xhrText.then(text => {
xhrDetails.props.response.value = text;
xhrDetails.props.responseText.value = text;
});
} else {
xhrDetails.props.response.value = xhrText;
xhrDetails.props.responseText.value = xhrText;
}
xhrDetails.headers['content-type'] = 'text/plain';
break;
}
}
if ( xhrDetails.defer === false ) {
xhrDetails.headers['content-length'] = `${xhrDetails.props.response.value}`.length;
Object.defineProperties(xhrDetails.xhr, {
readyState: { value: 4 },
responseURL: { value: xhrDetails.url },
status: { value: 200 },
statusText: { value: 'OK' },
});
Object.defineProperties(xhrDetails.xhr, xhrDetails.props);
return;
}
Promise.resolve(xhrText).then(( ) => xhrDetails).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 1, configurable: true },
responseURL: { value: xhrDetails.url },
});
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
xhrDetails.headers['content-length'] = `${details.props.response.value}`.length;
Object.defineProperties(details.xhr, {
readyState: { value: 2, configurable: true },
status: { value: 200 },
statusText: { value: 'OK' },
});
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 3, configurable: true },
});
Object.defineProperties(details.xhr, details.props);
safeDispatchEvent(details.xhr, 'readystatechange');
return details;
}).then(details => {
Object.defineProperties(details.xhr, {
readyState: { value: 4 },
});
safeDispatchEvent(details.xhr, 'readystatechange');
safeDispatchEvent(details.xhr, 'load');
safeDispatchEvent(details.xhr, 'loadend');
safe.uboLog(logPrefix, `Prevented with response:\n${details.xhr.response}`);
});
}
getResponseHeader(headerName) {
const xhrDetails = xhrInstances.get(this);
if ( xhrDetails === undefined || this.readyState < this.HEADERS_RECEIVED ) {
return super.getResponseHeader(headerName);
}
const value = xhrDetails.headers[headerName.toLowerCase()];
if ( value !== undefined && value !== '' ) { return value; }
return null;
}
getAllResponseHeaders() {
const xhrDetails = xhrInstances.get(this);
if ( xhrDetails === undefined || this.readyState < this.HEADERS_RECEIVED ) {
return super.getAllResponseHeaders();
}
const out = [];
for ( const [ name, value ] of Object.entries(xhrDetails.headers) ) {
if ( !value ) { continue; }
out.push(`${name}: ${value}`);
}
if ( out.length !== 0 ) { out.push(''); }
return out.join('\r\n');
}
};
self.XMLHttpRequest.prototype.open.toString = function() {
return XHRBefore.open.toString();
};
self.XMLHttpRequest.prototype.send.toString = function() {
return XHRBefore.send.toString();
};
self.XMLHttpRequest.prototype.getResponseHeader.toString = function() {
return XHRBefore.getResponseHeader.toString();
};
self.XMLHttpRequest.prototype.getAllResponseHeaders.toString = function() {
return XHRBefore.getAllResponseHeaders.toString();
};
}
/*******************************************************************************
@ -992,22 +802,6 @@ function webrtcIf(
});
}
/******************************************************************************/
builtinScriptlets.push({
name: 'prevent-xhr.js',
aliases: [
'no-xhr-if.js',
],
fn: preventXhr,
dependencies: [
'prevent-xhr.fn',
],
});
function preventXhr(...args) {
return preventXhrFn(false, ...args);
}
/**
* @scriptlet prevent-window-open
*
@ -2034,7 +1828,7 @@ function trustedClickElement(
const pos2 = s2.indexOf('=');
const key = pos2 !== -1 ? s2.slice(0, pos2).trim() : s2;
const value = pos2 !== -1 ? s2.slice(pos2+1).trim() : '';
out.re = new RegExp(`^${this.escapeRegexChars(key)}=${this.escapeRegexChars(value)}`);
out.re = new RegExp(`^${safe.escapeRegexChars(key)}=${safe.escapeRegexChars(value)}`);
return out;
}).filter(details => details !== undefined);
const allCookies = assertions.some(o => o.type === 'cookie')
@ -2337,25 +2131,6 @@ function trustedSuppressNativeMethod(
});
}
/*******************************************************************************
*
* Trusted version of prevent-xhr(), which allows the use of an arbitrary
* string as response text.
*
* */
builtinScriptlets.push({
name: 'trusted-prevent-xhr.js',
requiresTrust: true,
fn: trustedPreventXhr,
dependencies: [
'prevent-xhr.fn',
],
});
function trustedPreventXhr(...args) {
return preventXhrFn(true, ...args);
}
/**
* @trustedScriptlet trusted-prevent-dom-bypass
*

View file

@ -220,6 +220,14 @@ export function generateContentFn(trusted, directive) {
warXHR.send();
}).catch(( ) => '');
}
if ( directive.startsWith('join:') ) {
const parts = directive.slice(7)
.split(directive.slice(5, 7))
.map(a => generateContentFn(trusted, a));
return parts.some(a => a instanceof Promise)
? Promise.all(parts).then(parts => parts.join(''))
: parts.join('');
}
if ( trusted ) {
return directive;
}

View file

@ -4758,6 +4758,7 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar
if ( rule.condition.resourceTypes === undefined ) {
if ( rule.condition.excludedResourceTypes === undefined ) {
rule.condition.resourceTypes = [
'image',
'main_frame',
'sub_frame',
'xmlhttprequest',
@ -4765,12 +4766,17 @@ StaticNetFilteringEngine.prototype.dnrFromCompiled = function(op, context, ...ar
}
}
// https://github.com/uBlockOrigin/uBOL-home/discussions/575
if ( rule.condition.urlFilter === undefined ) {
const { urlFilter } = rule.condition;
if ( urlFilter === undefined ) {
if ( rule.condition.regexFilter === undefined ) {
if ( paramName !== '' ) {
rule.condition.urlFilter = `^${paramName}=`;
}
}
} else if ( urlFilter.startsWith('||') ) {
if ( urlFilter.toLowerCase().includes(paramName.toLowerCase()) === false ) {
rule.condition.urlFilter = `${rule.condition.urlFilter}*^${paramName}=`;
}
}
if ( rule.__modifierAction === ALLOW_REALM ) {
dnrAddRuleError(rule, `Unsupported removeparam exception: ${rule.__modifierValue}`);