Commit 275d7e5c authored by Bat's avatar Bat
Browse files

Allow us to use another style for visited links

parent 5added85
Pipeline #26163 passed with stage
in 49 seconds
browser.runtime.onMessage.addListener(msg => {
return new Promise(resolve => {
browser.history.search({ text: '', startTime: 0 }).then(history => {
console.log(history)
resolve({ history: history })
})
})
})
......@@ -3,14 +3,37 @@ fetch(browser.extension.getURL('default-domains.json'))
.then(res => {
const gafamHosts = res.domains
function colorGAFAMLinks (conf) {
document.querySelectorAll('a').forEach(highlight(conf))
browser.storage.local.get({
mainStyle: utils.defaultStyle,
visitedStyle: null,
useVisitedStyle: false,
domains: gafamHosts
}).then(conf => {
browser.runtime.sendMessage({ msg: 'please, give me the history' }).then(msg => {
console.log(msg)
if (conf.useVisitedStyle && conf.visitedStyle) {
color(l => !msg.history.some(h => h.url === l.href), conf.mainStyle, conf.domains)
color(l => msg.history.some(h => h.url === l.href), conf.visitedStyle, conf.domains)
} else {
color(_ => true, conf.mainStyle, conf.domains)
}
})
})
function color (filter, style, domains) {
const links = Array.prototype.slice.call(document.querySelectorAll('a')).filter(filter)
console.log(links)
links.forEach(highlight(style, domains))
const observer = new MutationObserver(muts => {
for (const mut of muts) {
mut.addedNodes.forEach(node => {
highlight(conf)(node)
node.querySelectorAll('a').forEach(highlight(conf))
highlight(style, domains)(node)
try {
Array.prototype.slice.call(node.querySelectorAll('a')).filter(filter).forEach(highlight(style, domains))
} catch (e) {
console.error(node, e)
}
})
}
})
......@@ -23,26 +46,11 @@ fetch(browser.extension.getURL('default-domains.json'))
})
}
browser.storage.local.get({
color: '#FF0000',
backgroundColor: '#FFFF00',
opacity: '1',
font: {
bold: false,
italic: false,
family: '',
decoration: 'none',
size: 1
},
domains: gafamHosts
}).then(conf => {
colorGAFAMLinks(conf)
})
function highlight (conf) {
return link => {
function highlight (conf, domains) {
return (link, i, ls) => {
// console.log(ls)
if (link.hostname && link.hostname !== window.location.hostname) {
if (conf.domains.some(h => link.hostname.endsWith(h))) {
if (domains.some(h => link.hostname.endsWith(h))) {
utils.styleLink(link, conf)
}
}
......
......@@ -14,13 +14,17 @@
"js": [ "utils.js", "index.js" ]
}
],
"background": {
"scripts": [ "history.js" ]
},
"options_ui": {
"page": "options.html",
"open_in_tab": true
},
"permissions": [
"storage",
"downloads"
"downloads",
"history"
],
"web_accessible_ressources": [
"default-configuration.json"
......
......@@ -76,3 +76,7 @@ li > p {
li > a {
text-decoration: none;
}
h2 {
margin-top: 100px;
}
......@@ -6,27 +6,8 @@
<link rel="stylesheet" href="options.css">
</head>
<body>
<div>
<div id="style-options">
<h1>Colors</h1>
<label>Text color: <input type="color" id="color"></label>
<label>Background color: <input type="color" id="background-color"></label>
<label>Opacity: <input type="range" id="opacity" min="0.1" max="1" step="0.01" value="1"></label>
<h2>Font</h2>
<label>Family:
<input type="text" id="font-family" value="" placeholder="Let it empty to use the default font">
</label>
<label><input type="checkbox" id="bold" checked>Bold</label>
<label><input type="checkbox" id="italic" checked>Italic</label>
<label>Size (factor): <input type="number" step="0.05" id="size" checked></label>
<label>
Decoration:
<select id="decoration" value="none">
<option value="none">Nothing</option>
<option value="underline">Underline</option>
<option value="line-through">Strikethrough</option>
</select>
</label>
<p><a href="#" id="example">Example link</a></p>
</div>
<div>
<h1>GAFAM and Co.</h1>
......
function watchChanges (sel) {
document.querySelector(sel).addEventListener('change', saveChanges)
}
function saveChanges () {
const example = document.getElementById('example')
const conf = {
color: document.querySelector('#color').value,
backgroundColor: document.querySelector('#background-color').value,
opacity: document.querySelector('#opacity').value,
font: {
family: document.getElementById('font-family').value,
bold: document.getElementById('bold').checked,
italic: document.getElementById('italic').checked,
decoration: document.getElementById('decoration').value,
size: document.getElementById('size').value
}
function onChange (style) {
return (example, prop, val) => {
browser.storage.local.get({
mainStyle: utils.defaultStyle,
visitedStyle: null
}).then(res => {
const stl = (!res.visitedStyle || style === 'mainStyle')
? res.mainStyle
: res.visitedStyle
stl[prop] = val
browser.storage.local.set({ [style]: stl })
const [ sProp, sVal ] = utils.confToStyle(prop, val)
example.style[sProp] = sVal
})
}
browser.storage.local.set(conf)
utils.styleLink(example, conf)
}
function restoreOptions () {
......@@ -27,40 +23,33 @@ function restoreOptions () {
.then(res => {
const defaultDomains = res.domains
watchChanges('#color')
watchChanges('#background-color')
watchChanges('#opacity')
watchChanges('#bold')
watchChanges('#font-family')
watchChanges('#decoration')
watchChanges('#italic')
watchChanges('#size')
browser.storage.local.get({
color: '#FFFF00',
backgroundColor: '#FF0000',
domains: defaultDomains,
opacity: '1',
font: {
bold: false,
italic: false,
family: '',
decoration: 'none',
size: 1
}
mainStyle: utils.defaultStyle,
visitedStyle: null,
useVisitedStyle: false,
domains: defaultDomains
}).then(result => {
document.querySelector('#color').value = result.color
document.querySelector('#background-color').value = result.backgroundColor
document.querySelector('#opacity').value = result.opacity
const styleOptions = document.getElementById('style-options')
const visitedForm = utils.buildStyleForm('Visited links', onChange('visitedStyle'), result.visitedStyle || result.mainStyle)
styleOptions.appendChild(utils.h('label', {}, [
utils.t('Use another style for already visited links'),
utils.h('input', { type: 'checkbox', checked: result.useVisitedStyle }, [], {
change: (_, checked) => {
if (checked) {
visitedForm.style.display = 'block'
browser.storage.local.set({ useVisitedStyle: true })
} else {
visitedForm.style.display = 'none'
browser.storage.local.set({ useVisitedStyle: false })
}
}
})
]))
document.getElementById('bold').checked = result.font.bold
document.getElementById('italic').checked = result.font.italic
document.getElementById('font-family').value = result.font.family
document.getElementById('decoration').value = result.font.decoration
document.getElementById('size').value = result.font.size
styleOptions.appendChild(utils.buildStyleForm('Normal style', onChange('mainStyle'), result.mainStyle))
saveChanges()
visitedForm.style.display = result.useVisitedStyle ? 'block' : 'none'
styleOptions.appendChild(visitedForm)
result.domains.forEach(createDomainLi)
document.getElementById('add-domain').addEventListener('submit', evt => {
......@@ -81,38 +70,44 @@ function restoreOptions () {
function handleImport () {
return evt => {
const fileInput = document.createElement('input')
fileInput.style.display = 'none'
fileInput.type = 'file'
fileInput.accept = '.json'
fileInput.acceptCharset = 'utf-8'
document.body.appendChild(fileInput)
fileInput.initialValue = fileInput.value
fileInput.addEventListener('change', evt => {
if (fileInput.value !== fileInput.initialValue) {
const file = fileInput.files[0]
document.body.style.cursor = 'wait'
const fReader = new FileReader()
fReader.addEventListener('loadend', event => {
fileInput.remove()
const importedDomains = JSON.parse(event.target.result).domains
browser.storage.local.get({ domains: [] }).then(res => {
const newDomains = importedDomains.filter(d => !res.domains.includes(d))
const domains = newDomains.concat(res.domains)
const list = document.getElementById('domain-list')
while (list.firstChild) {
list.removeChild(list.firstChild)
}
domains.forEach(createDomainLi)
document.body.style.cursor = ''
const fileInput = utils.h('input', {
style: {
display: 'none'
},
type: 'file',
accept: '.json',
acceptCharset: 'utf-8'
},
[],
{
change: evt => {
if (fileInput.value !== fileInput.initialValue) {
document.body.style.cursor = 'wait'
const file = fileInput.files[0]
const fReader = new FileReader()
fReader.addEventListener('loadend', event => {
fileInput.remove()
const importedDomains = JSON.parse(event.target.result).domains
browser.storage.local.get({ domains: [] }).then(res => {
const newDomains = importedDomains.filter(d => !res.domains.includes(d))
const domains = newDomains.concat(res.domains)
const list = document.getElementById('domain-list')
while (list.firstChild) {
list.removeChild(list.firstChild)
}
domains.forEach(createDomainLi)
document.body.style.cursor = ''
})
})
})
fReader.readAsText(file, 'utf-8')
fReader.readAsText(file, 'utf-8')
}
}
})
fileInput.initialValue = fileInput.value
document.body.appendChild(fileInput)
fileInput.click()
}
}
......
// eslint-disable-next-line no-unused-vars
const utils = {
defaultStyle: {
color: '#FFFF00',
backgroundColor: '#FF0000',
opacity: '1',
bold: false,
italic: false,
fontFamily: '',
decoration: 'none',
size: 1
},
styleLink: function (elt, conf) {
elt.style = elt.style || {}
Object.assign(elt.style, {
color: conf.color,
backgroundColor: conf.backgroundColor,
opacity: conf.opacity,
fontFamily: conf.font.family !== '' ? conf.font.family : null,
fontWeight: conf.font.bold ? 'bold' : null,
fontStyle: conf.font.italic ? 'italic' : null,
textDecoration: conf.font.decoration,
fontSize: `${conf.font.size}em`
fontFamily: conf.fontFamily !== '' ? conf.fontFamily : null,
fontWeight: conf.bold ? 'bold' : null,
fontStyle: conf.italic ? 'italic' : null,
textDecoration: conf.decoration,
fontSize: `${conf.fontSize}em`
})
console.log(elt.style)
}
},
confToStyle: function (prop, val) {
switch (prop) {
case 'bold':
case 'italic':
return [ prop === 'bold' ? 'font-weight' : 'font-style', val ? prop : null ]
case 'fontSize':
return [ prop, `${val}em` ]
case 'fontFamily':
return [ prop, val !== '' ? val : null ]
case 'decoration':
return [ 'text-decoration', val ]
default:
return [ prop, val ]
}
},
buildStyleForm: function (name, _onChange, style) {
const example = this.h('a', { href: '#' }, [ this.t('Example link') ])
const onChange = _onChange.bind(null, example)
for (const key in style) { // load default style
onChange(key, style[key])
}
return this.h('div', {}, [
this.h('h2', {}, [ this.t(name) ]),
this.h('h3', {}, [ this.t('Colors') ]),
this.h('label', {}, [
this.t('Text color: '),
this.h('input', { type: 'color', name: 'color', value: style.color }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Background color: '),
this.h('input', { type: 'color', name: 'backgroundColor', value: style.backgroundColor }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Opacity: '),
this.h('input', { type: 'range', min: '0.01', max: '1', step: '0.01', name: 'opacity', value: style.opacity }, [], { change: onChange })
]),
this.h('h3', {}, [ this.t('Font') ]),
this.h('label', {}, [
this.t('Font family: '),
this.h('input', { type: 'text', name: 'fontFamily', value: style.fontFamily }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Bold: '),
this.h('input', { type: 'checkbox', name: 'bold', checked: style.bold }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Italic: '),
this.h('input', { type: 'checkbox', name: 'italic', checked: style.italic }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Size (factor): '),
this.h('input', { type: 'number', step: '0.05', name: 'fontSize', value: style.size }, [], { change: onChange })
]),
this.h('label', {}, [
this.t('Decoration: '),
this.h('select', { value: style.decoration, name: 'decoration' }, [
this.h('option', { value: 'none', selected: style.decoration === 'none' }, [ this.t('Nothing') ]),
this.h('option', { value: 'underline', selected: style.decoration === 'underline' }, [ this.t('Underline') ]),
this.h('option', { value: 'line-through', selected: style.decoration === 'line-through' }, [ this.t('Strikethrough') ])
], { change: onChange })
]),
example
])
},
h: function (tag, props, children, events) {
if (!props) props = {}
if (!children) children = []
if (!events) events = {}
const elt = document.createElement(tag)
Object.assign(elt, props)
for (const ch of children) {
elt.appendChild(ch)
}
for (const evt in events) {
elt.addEventListener(evt, e => events[evt](props.name, elt.type === 'checkbox' ? elt.checked : elt.value, e))
}
return elt
},
t: txt => document.createTextNode(txt)
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment