mirror of
https://github.com/gorhill/uMatrix.git
synced 2024-05-20 12:13:19 +12:00
add contributor mode and tools to contribute ruleset recipes (need more)
This commit is contained in:
parent
a88a301d81
commit
55b9f1c645
|
@ -551,6 +551,14 @@
|
|||
"message": "Import...",
|
||||
"description": ""
|
||||
},
|
||||
"assetsInlineHostsLabel": {
|
||||
"message": "My hosts",
|
||||
"description": ""
|
||||
},
|
||||
"assetsInlineRecipesLabel": {
|
||||
"message": "My recipes",
|
||||
"description": ""
|
||||
},
|
||||
|
||||
"rawSettingsWarning" : {
|
||||
"message": "Warning! Change these raw configuration settings at your own risk.",
|
||||
|
|
|
@ -139,20 +139,29 @@ body.updating li.listEntry.obsolete > input[type="checkbox"]:checked ~ span.upda
|
|||
.dim {
|
||||
opacity: 0.5;
|
||||
}
|
||||
li.listEntry.importURL > input[type="checkbox"] ~ textarea {
|
||||
li.listEntry.notAnAsset > input[type="checkbox"] ~ textarea {
|
||||
display: none;
|
||||
margin-left: 1.6em;
|
||||
}
|
||||
li.listEntry.importURL > input[type="checkbox"]:checked ~ textarea {
|
||||
li.listEntry.notAnAsset > input[type="checkbox"]:checked ~ textarea {
|
||||
display: block;
|
||||
}
|
||||
li.listEntry.importURL > textarea {
|
||||
li.listEntry.notAnAsset > textarea {
|
||||
border: 1px solid #ddd;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
font-size: smaller;
|
||||
width: calc(100% - 4em);
|
||||
height: 6em;
|
||||
resize: none;
|
||||
resize: vertical;
|
||||
white-space: pre;
|
||||
}
|
||||
#recipes li.listEntry.toInline {
|
||||
display: none;
|
||||
}
|
||||
body.contributor #recipes li.listEntry.toInline {
|
||||
display: block;
|
||||
}
|
||||
#recipes li.listEntry.toInline > textarea {
|
||||
height: 18em;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<p data-i18n="hostsFilesPrompt"></p>
|
||||
<p id="listsOfBlockedHostsPrompt"></p>
|
||||
<ul id="hosts">
|
||||
<li class="listEntry importURL"><input type="checkbox" id="importHosts"><label for="importHosts"data-i18n="assetsImportLabel"></label><!--
|
||||
<li class="listEntry notAnAsset toImport"><input type="checkbox" id="importHosts"><label for="importHosts" data-i18n="assetsImportLabel"></label><!--
|
||||
--><textarea dir="ltr" spellcheck="false" placeholder="hostsFilesExternalListsHint"></textarea>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -35,8 +35,10 @@
|
|||
<div>
|
||||
<p data-i18n="assetsRecipesSummary"></p>
|
||||
<ul id="recipes">
|
||||
<li class="listEntry importURL"><input type="checkbox" id="importRecipes"><label for="importRecipes"data-i18n="assetsImportLabel"></label><!--
|
||||
<li class="listEntry notAnAsset toImport"><input type="checkbox" id="importRecipes"><label for="importRecipes" data-i18n="assetsImportLabel"></label><!--
|
||||
--><textarea dir="ltr" spellcheck="false" placeholder="hostsFilesExternalListsHint"></textarea>
|
||||
<li class="listEntry notAnAsset toInline"><input type="checkbox" id="inlineRecipes"><label for="inlineRecipes" data-i18n="assetsInlineRecipesLabel"></label><!--
|
||||
--><textarea dir="ltr" spellcheck="false" placeholder="assetsInlineRecipesHint"></textarea>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -101,6 +101,7 @@ var requestStatsFactory = function() {
|
|||
*/
|
||||
|
||||
var rawSettingsDefault = {
|
||||
contributorMode: false,
|
||||
disableCSPReportInjection: false,
|
||||
placeholderBackground:
|
||||
[
|
||||
|
@ -188,7 +189,15 @@ return {
|
|||
processHyperlinkAuditing: true,
|
||||
processReferer: false,
|
||||
selectedHostsFiles: [ '' ],
|
||||
selectedRecipeFiles: [ '' ]
|
||||
selectedRecipeFiles: [ '' ],
|
||||
userHosts: {
|
||||
enabled: false,
|
||||
content: ''
|
||||
},
|
||||
userRecipes: {
|
||||
enabled: false,
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
|
||||
rawSettingsDefault: rawSettingsDefault,
|
||||
|
|
|
@ -145,22 +145,23 @@ var renderHostsFiles = function(soft) {
|
|||
});
|
||||
|
||||
let ulList = document.querySelector(listSelector),
|
||||
liImport = ulList.querySelector('.importURL');
|
||||
if ( liImport.parentNode !== null ) {
|
||||
liImport.parentNode.removeChild(liImport);
|
||||
}
|
||||
liLast = ulList.querySelector('.notAnAsset');
|
||||
|
||||
for ( let i = 0; i < assetKeys.length; i++ ) {
|
||||
let liEntry = liFromListEntry(
|
||||
collection,
|
||||
assetKeys[i],
|
||||
ulList.children[i]
|
||||
);
|
||||
let liReuse = i < ulList.childElementCount ?
|
||||
ulList.children[i] :
|
||||
null;
|
||||
if (
|
||||
liReuse !== null &&
|
||||
liReuse.classList.contains('notAnAsset')
|
||||
) {
|
||||
liReuse = null;
|
||||
}
|
||||
let liEntry = liFromListEntry(collection, assetKeys[i], liReuse);
|
||||
if ( liEntry.parentElement === null ) {
|
||||
ulList.appendChild(liEntry);
|
||||
ulList.insertBefore(liEntry, liLast);
|
||||
}
|
||||
}
|
||||
|
||||
ulList.appendChild(liImport);
|
||||
};
|
||||
|
||||
var onAssetDataReceived = function(details) {
|
||||
|
@ -171,9 +172,14 @@ var renderHostsFiles = function(soft) {
|
|||
// Before all, set context vars
|
||||
listDetails = details;
|
||||
|
||||
document.body.classList.toggle(
|
||||
'contributor',
|
||||
listDetails.contributor === true
|
||||
);
|
||||
|
||||
// Incremental rendering: this will allow us to easily discard unused
|
||||
// DOM list entries.
|
||||
uDom('#hosts .listEntry:not(.importURL)').addClass('discard');
|
||||
uDom('#hosts .listEntry:not(.notAnAsset)').addClass('discard');
|
||||
|
||||
onRenderAssetFiles(details.hosts, '#hosts');
|
||||
onRenderAssetFiles(details.recipes, '#recipes');
|
||||
|
@ -188,6 +194,12 @@ var renderHostsFiles = function(soft) {
|
|||
);
|
||||
uDom('#autoUpdate').prop('checked', listDetails.autoUpdate === true);
|
||||
|
||||
uDom.nodeFromSelector('#recipes .toInline > input[type="checkbox"]').checked =
|
||||
listDetails.userRecipes.enabled === true;
|
||||
uDom.nodeFromSelector('#recipes .toInline > textarea').value =
|
||||
listDetails.userRecipes.content;
|
||||
|
||||
|
||||
if ( !soft ) {
|
||||
hostsFilesSettingsHash = hashFromCurrentFromSettings();
|
||||
}
|
||||
|
@ -231,31 +243,50 @@ var updateAssetStatus = function(details) {
|
|||
|
||||
/*******************************************************************************
|
||||
|
||||
Compute a hash from all the settings affecting how filter lists are loaded
|
||||
Compute a hash from all the settings affecting how assets are loaded
|
||||
in memory.
|
||||
|
||||
**/
|
||||
|
||||
var hashFromCurrentFromSettings = function() {
|
||||
var hash = [],
|
||||
listHash = [],
|
||||
listEntries = document.querySelectorAll('.assets .listEntry[data-listkey]:not(.toRemove)'),
|
||||
i = listEntries.length;
|
||||
while ( i-- ) {
|
||||
let liEntry = listEntries[i];
|
||||
let listHash = [],
|
||||
listEntries = document.querySelectorAll(
|
||||
'.assets .listEntry[data-listkey]:not(.toRemove)'
|
||||
);
|
||||
for ( let liEntry of listEntries ) {
|
||||
if ( liEntry.querySelector('input[type="checkbox"]:checked') !== null ) {
|
||||
listHash.push(liEntry.getAttribute('data-listkey'));
|
||||
}
|
||||
}
|
||||
let textarea1 = document.querySelector('.assets .importURL > input[type="checkbox"]:checked ~ textarea');
|
||||
let textarea2 = document.querySelector('#recipes .importURL > input[type="checkbox"]:checked ~ textarea');
|
||||
hash.push(
|
||||
listHash.sort().join(),
|
||||
textarea1 !== null && reValidExternalList.test(textarea1.value),
|
||||
textarea2 !== null && reValidExternalList.test(textarea2.value),
|
||||
document.querySelector('.listEntry.toRemove') !== null
|
||||
);
|
||||
return hash.join();
|
||||
return [
|
||||
listHash.join(),
|
||||
document.querySelector('.listEntry.toRemove') !== null,
|
||||
reValidExternalList.test(
|
||||
textFromTextarea(
|
||||
'#hosts .toImport > input[type="checkbox"]:checked ~ textarea'
|
||||
)
|
||||
),
|
||||
textFromTextarea(
|
||||
'#hosts .toInline > input[type="checkbox"]:checked ~ textarea'
|
||||
),
|
||||
reValidExternalList.test(
|
||||
textFromTextarea(
|
||||
'#recipes .toImport > input[type="checkbox"]:checked ~ textarea'
|
||||
)
|
||||
),
|
||||
textFromTextarea(
|
||||
'#recipes .toInline > input[type="checkbox"]:checked ~ textarea'
|
||||
),
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var textFromTextarea = function(textarea) {
|
||||
if ( typeof textarea === 'string' ) {
|
||||
textarea = document.querySelector(textarea);
|
||||
}
|
||||
return textarea !== null ? textarea.value.trim() : '';
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -300,36 +331,44 @@ var selectAssets = function(callback) {
|
|||
var out = {
|
||||
toSelect: [],
|
||||
toImport: '',
|
||||
toRemove: []
|
||||
toRemove: [],
|
||||
toInline: {
|
||||
enabled: false,
|
||||
content: ''
|
||||
}
|
||||
};
|
||||
|
||||
let root = document.querySelector(listSelector);
|
||||
|
||||
let liEntries = root.querySelectorAll('.listEntry[data-listkey]:not(.toRemove)'),
|
||||
i = liEntries.length;
|
||||
while ( i-- ) {
|
||||
let liEntry = liEntries[i];
|
||||
if ( liEntry.querySelector('input[type="checkbox"]:checked') !== null ) {
|
||||
// Lists to select or remove
|
||||
let liEntries = root.querySelectorAll(
|
||||
'.listEntry[data-listkey]:not(.notAnAsset)'
|
||||
);
|
||||
for ( let liEntry of liEntries ) {
|
||||
if ( liEntry.classList.contains('toRemove') ) {
|
||||
out.toRemove.push(liEntry.getAttribute('data-listkey'));
|
||||
} else if ( liEntry.querySelector('input[type="checkbox"]:checked') ) {
|
||||
out.toSelect.push(liEntry.getAttribute('data-listkey'));
|
||||
}
|
||||
}
|
||||
|
||||
// External hosts files to remove
|
||||
liEntries = root.querySelectorAll('.listEntry.toRemove[data-listkey]');
|
||||
i = liEntries.length;
|
||||
while ( i-- ) {
|
||||
out.toRemove.push(liEntries[i].getAttribute('data-listkey'));
|
||||
}
|
||||
|
||||
// External hosts files to import
|
||||
let input = root.querySelector('.importURL > input[type="checkbox"]:checked');
|
||||
let input = root.querySelector(
|
||||
'.toImport > input[type="checkbox"]:checked'
|
||||
);
|
||||
if ( input !== null ) {
|
||||
let textarea = root.querySelector('.importURL textarea');
|
||||
let textarea = root.querySelector('.toImport textarea');
|
||||
out.toImport = textarea.value.trim();
|
||||
textarea.value = '';
|
||||
input.checked = false;
|
||||
}
|
||||
|
||||
// Inline data
|
||||
out.toInline.enabled = root.querySelector(
|
||||
'.toInline > input[type="checkbox"]:checked'
|
||||
) !== null;
|
||||
out.toInline.content = textFromTextarea('.toInline > textarea');
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
|
@ -406,7 +445,7 @@ uDom('#buttonApply').on('click', buttonApplyHandler);
|
|||
uDom('#buttonUpdate').on('click', buttonUpdateHandler);
|
||||
uDom('#buttonPurgeAll').on('click', buttonPurgeAllHandler);
|
||||
uDom('.assets').on('change', '.listEntry > input', onHostsFilesSettingsChanged);
|
||||
uDom('.assets').on('input', '.listEntry.importURL textarea', onHostsFilesSettingsChanged);
|
||||
uDom('.assets').on('input', '.listEntry > textarea', onHostsFilesSettingsChanged);
|
||||
uDom('.assets').on('click', '.listEntry > a.remove', onRemoveExternalAsset);
|
||||
uDom('.assets').on('click', 'span.cache', onPurgeClicked);
|
||||
|
||||
|
|
|
@ -736,7 +736,9 @@ var getAssets = function(callback) {
|
|||
blockedHostnameCount: µm.ubiquitousBlacklist.count,
|
||||
hosts: null,
|
||||
recipes: null,
|
||||
cache: null
|
||||
userRecipes: µm.userSettings.userRecipes,
|
||||
cache: null,
|
||||
contributor: µm.rawSettings.contributorMode
|
||||
};
|
||||
var onMetadataReady = function(entries) {
|
||||
r.cache = entries;
|
||||
|
|
|
@ -292,6 +292,14 @@
|
|||
for ( let assetKey of µm.userSettings.selectedRecipeFiles ) {
|
||||
this.assets.get(assetKey, onLoaded);
|
||||
}
|
||||
|
||||
let userRecipes = µm.userSettings.userRecipes;
|
||||
if ( userRecipes.enabled ) {
|
||||
µm.recipeManager.fromString(
|
||||
'! uMatrix: Ruleset recipes 1.0\n' + userRecipes.content
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -572,7 +580,8 @@
|
|||
metadata,
|
||||
details,
|
||||
propSelectedAssetKeys,
|
||||
propImportedAssetKeys
|
||||
propImportedAssetKeys,
|
||||
propInlineAsset
|
||||
) {
|
||||
let µmus = µm.userSettings;
|
||||
let selectedAssetKeys = new Set();
|
||||
|
@ -629,14 +638,35 @@
|
|||
}
|
||||
|
||||
let bin = {},
|
||||
changed = false;
|
||||
needReload = false;
|
||||
|
||||
if ( details.toInline instanceof Object ) {
|
||||
let newInline = details.toInline;
|
||||
let oldInline = µmus[propInlineAsset];
|
||||
newInline.content = newInline.content.trim();
|
||||
if ( newInline.content.length !== 0 ) {
|
||||
newInline.content += '\n';
|
||||
}
|
||||
let newContent = newInline.enabled ? newInline.content : '';
|
||||
let oldContent = oldInline.enabled ? oldInline.content : '';
|
||||
if ( newContent !== oldContent ) {
|
||||
needReload = true;
|
||||
}
|
||||
if (
|
||||
newInline.enabled !== oldInline.enabled ||
|
||||
newInline.content !== oldInline.content
|
||||
) {
|
||||
µmus[propInlineAsset] = newInline;
|
||||
bin[propInlineAsset] = newInline;
|
||||
}
|
||||
}
|
||||
|
||||
selectedAssetKeys = Array.from(selectedAssetKeys).sort();
|
||||
µmus[propSelectedAssetKeys].sort();
|
||||
if ( selectedAssetKeys.join() !== µmus[propSelectedAssetKeys].join() ) {
|
||||
µmus[propSelectedAssetKeys] = selectedAssetKeys;
|
||||
bin[propSelectedAssetKeys] = selectedAssetKeys;
|
||||
changed = true;
|
||||
needReload = true;
|
||||
}
|
||||
|
||||
importedAssetKeys = Array.from(importedAssetKeys).sort();
|
||||
|
@ -644,14 +674,14 @@
|
|||
if ( importedAssetKeys.join() !== µmus[propImportedAssetKeys].join() ) {
|
||||
µmus[propImportedAssetKeys] = importedAssetKeys;
|
||||
bin[propImportedAssetKeys] = importedAssetKeys;
|
||||
changed = true;
|
||||
needReload = true;
|
||||
}
|
||||
|
||||
if ( changed ) {
|
||||
if ( Object.keys(bin).length !== 0 ) {
|
||||
vAPI.storage.set(bin);
|
||||
}
|
||||
|
||||
return changed;
|
||||
return needReload;
|
||||
};
|
||||
|
||||
var onMetadataReady = function(response) {
|
||||
|
@ -660,7 +690,8 @@
|
|||
metadata,
|
||||
details.hosts,
|
||||
'selectedHostsFiles',
|
||||
'externalHostsFiles'
|
||||
'externalHostsFiles',
|
||||
'userHosts'
|
||||
);
|
||||
if ( hostsChanged ) {
|
||||
µm.hostsFilesSelfie.destroy();
|
||||
|
@ -669,7 +700,8 @@
|
|||
metadata,
|
||||
details.recipes,
|
||||
'selectedRecipeFiles',
|
||||
'externalRecipeFiles'
|
||||
'externalRecipeFiles',
|
||||
'userRecipes'
|
||||
);
|
||||
if ( recipesChanged ) {
|
||||
µm.recipeManager.reset();
|
||||
|
|
Loading…
Reference in a new issue