Browse Source

add contributor mode and tools to contribute ruleset recipes (need more)

pull/2/head
Raymond Hill 7 years ago
parent
commit
55b9f1c645
No known key found for this signature in database GPG Key ID: 25E1490B761470C2
  1. 8
      src/_locales/en/messages.json
  2. 17
      src/css/hosts-files.css
  3. 6
      src/hosts-files.html
  4. 11
      src/js/background.js
  5. 129
      src/js/hosts-files.js
  6. 4
      src/js/messaging.js
  7. 48
      src/js/storage.js

8
src/_locales/en/messages.json

@ -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.",

17
src/css/hosts-files.css

@ -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;
}

6
src/hosts-files.html

@ -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>

11
src/js/background.js

@ -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,

129
src/js/hosts-files.js

@ -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);

4
src/js/messaging.js

@ -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;

48
src/js/storage.js

@ -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…
Cancel
Save