2481 lines
220 KiB
HTML
2481 lines
220 KiB
HTML
|
<!DOCTYPE html><html lang="fr">
|
|||
|
<head><meta charset="utf-8">
|
|||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Compléments Firefox et Thunderbird - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="Firefox ERREUR “Échec de la connexion sécurisée” Configuration de base Préférences Modules –> Extensions Ajout moteur de rech...">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2018/09/27/Complements-Firefox-Thunderbird.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
|
|||
|
|
|||
|
<!-- - include head/favicon.html - -->
|
|||
|
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
|
|||
|
<!-- end custom head snippets --><script>(function() {
|
|||
|
window.isArray = function(val) {
|
|||
|
return Object.prototype.toString.call(val) === '[object Array]';
|
|||
|
};
|
|||
|
window.isString = function(val) {
|
|||
|
return typeof val === 'string';
|
|||
|
};
|
|||
|
|
|||
|
window.hasEvent = function(event) {
|
|||
|
return 'on'.concat(event) in window.document;
|
|||
|
};
|
|||
|
|
|||
|
window.isOverallScroller = function(node) {
|
|||
|
return node === document.documentElement || node === document.body || node === window;
|
|||
|
};
|
|||
|
|
|||
|
window.isFormElement = function(node) {
|
|||
|
var tagName = node.tagName;
|
|||
|
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
|
|||
|
};
|
|||
|
|
|||
|
window.pageLoad = (function () {
|
|||
|
var loaded = false, cbs = [];
|
|||
|
window.addEventListener('load', function () {
|
|||
|
var i;
|
|||
|
loaded = true;
|
|||
|
if (cbs.length > 0) {
|
|||
|
for (i = 0; i < cbs.length; i++) {
|
|||
|
cbs[i]();
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
return {
|
|||
|
then: function(cb) {
|
|||
|
cb && (loaded ? cb() : (cbs.push(cb)));
|
|||
|
}
|
|||
|
};
|
|||
|
})();
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
window.throttle = function(func, wait) {
|
|||
|
var args, result, thisArg, timeoutId, lastCalled = 0;
|
|||
|
|
|||
|
function trailingCall() {
|
|||
|
lastCalled = new Date;
|
|||
|
timeoutId = null;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
}
|
|||
|
return function() {
|
|||
|
var now = new Date,
|
|||
|
remaining = wait - (now - lastCalled);
|
|||
|
|
|||
|
args = arguments;
|
|||
|
thisArg = this;
|
|||
|
|
|||
|
if (remaining <= 0) {
|
|||
|
clearTimeout(timeoutId);
|
|||
|
timeoutId = null;
|
|||
|
lastCalled = now;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
} else if (!timeoutId) {
|
|||
|
timeoutId = setTimeout(trailingCall, remaining);
|
|||
|
}
|
|||
|
return result;
|
|||
|
};
|
|||
|
};
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var Set = (function() {
|
|||
|
var add = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (data[i] === item) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
this.size ++;
|
|||
|
data.push(item);
|
|||
|
return data;
|
|||
|
};
|
|||
|
|
|||
|
var Set = function(data) {
|
|||
|
this.size = 0;
|
|||
|
this._data = [];
|
|||
|
var i;
|
|||
|
if (data.length > 0) {
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
add.call(this, data[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
Set.prototype.add = add;
|
|||
|
Set.prototype.get = function(index) { return this._data[index]; };
|
|||
|
Set.prototype.has = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (this.get(i) === item) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
};
|
|||
|
Set.prototype.is = function(map) {
|
|||
|
if (map._data.length !== this._data.length) { return false; }
|
|||
|
var i, j, flag, tData = this._data, mData = map._data;
|
|||
|
for (i = 0; i < tData.length; i++) {
|
|||
|
for (flag = false, j = 0; j < mData.length; j++) {
|
|||
|
if (tData[i] === mData[j]) {
|
|||
|
flag = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!flag) { return false; }
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
Set.prototype.values = function() {
|
|||
|
return this._data;
|
|||
|
};
|
|||
|
return Set;
|
|||
|
})();
|
|||
|
|
|||
|
window.Lazyload = (function(doc) {
|
|||
|
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
|
|||
|
var createNode = function(name, attrs) {
|
|||
|
var node = doc.createElement(name), attr;
|
|||
|
for (attr in attrs) {
|
|||
|
if (attrs.hasOwnProperty(attr)) {
|
|||
|
node.setAttribute(attr, attrs[attr]);
|
|||
|
}
|
|||
|
}
|
|||
|
return node;
|
|||
|
};
|
|||
|
var end = function(type, url) {
|
|||
|
var s, q, qi, cbs, i, j, cur, val, flag;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
s[url] = true;
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (cur.urls.has(url)) {
|
|||
|
qi = cur, val = qi.urls.values();
|
|||
|
qi && (cbs = qi.callbacks);
|
|||
|
for (flag = true, j = 0; j < val.length; j++) {
|
|||
|
cur = val[j];
|
|||
|
if (!s[cur]) {
|
|||
|
flag = false;
|
|||
|
}
|
|||
|
}
|
|||
|
if (flag && cbs && cbs.length > 0) {
|
|||
|
for (j = 0; j < cbs.length; j++) {
|
|||
|
cbs[j].call(context);
|
|||
|
}
|
|||
|
qi.load = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
var load = function(type, urls, callback) {
|
|||
|
var s, q, qi, node, i, cur,
|
|||
|
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (_urls.is(cur.urls)) {
|
|||
|
qi = cur;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
val = _urls.values();
|
|||
|
if (qi) {
|
|||
|
callback && (qi.load || qi.callbacks.push(callback));
|
|||
|
callback && (qi.load && callback());
|
|||
|
} else {
|
|||
|
q.push({
|
|||
|
urls: _urls,
|
|||
|
callbacks: callback ? [callback] : [],
|
|||
|
load: false
|
|||
|
});
|
|||
|
for (i = 0; i < val.length; i++) {
|
|||
|
node = null, url = val[i];
|
|||
|
if (s[url] === undefined) {
|
|||
|
(type === 'js' ) && (node = createNode('script', { src: url }));
|
|||
|
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
|
|||
|
if (node) {
|
|||
|
node.onload = (function(type, url) {
|
|||
|
return function() {
|
|||
|
end(type, url);
|
|||
|
};
|
|||
|
})(type, url);
|
|||
|
(doc.head || doc.body).appendChild(node);
|
|||
|
s[url] = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
return {
|
|||
|
js: function(url, callback) {
|
|||
|
load('js', url, callback);
|
|||
|
},
|
|||
|
css: function(url, callback) {
|
|||
|
load('css', url, callback);
|
|||
|
}
|
|||
|
};
|
|||
|
})(this.document);
|
|||
|
})();
|
|||
|
</script><script>
|
|||
|
(function() {
|
|||
|
var TEXT_VARIABLES = {
|
|||
|
version: '2.2.6',
|
|||
|
sources: {
|
|||
|
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
|
|||
|
jquery: '/assets/js/jquery.min.js',
|
|||
|
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
|
|||
|
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
|
|||
|
gitalk: {
|
|||
|
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
|
|||
|
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
|
|||
|
},
|
|||
|
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
|
|||
|
},
|
|||
|
site: {
|
|||
|
toc: {
|
|||
|
selectors: 'h1,h2,h3'
|
|||
|
}
|
|||
|
},
|
|||
|
paths: {
|
|||
|
search_js: '/assets/search.js'
|
|||
|
}
|
|||
|
};
|
|||
|
window.TEXT_VARIABLES = TEXT_VARIABLES;
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="root" data-is-touch="false">
|
|||
|
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
|
|||
|
|
|||
|
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
|
|||
|
<div class="header__title">
|
|||
|
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
|
|||
|
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
|
|||
|
<!-- Champ de recherche -->
|
|||
|
<div id="searchbox" class="search search--dark" style="visibility: visible">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header"></div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<!-- <div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div> -->
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
json: '/search.json',
|
|||
|
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a></li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
|
|||
|
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
|
|||
|
</nav></div>
|
|||
|
</header>
|
|||
|
|
|||
|
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
|
|||
|
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
|
|||
|
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Compléments Firefox et Thunderbird</h1></header></div><meta itemprop="headline" content="Compléments Firefox et Thunderbird"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=navigateur">navigateur</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF">27 sept. 2018</span>
|
|||
|
|
|||
|
<span title="Modification" style="color:#00FF7F">14 mai 2024</span></li></ul></div><meta itemprop="datePublished" content="2024-05-14T00:00:00+02:00">
|
|||
|
<meta itemprop="keywords" content="navigateur"><div class="js-article-content">
|
|||
|
<div class="layout--article"><!-- start custom article top snippet -->
|
|||
|
<style>
|
|||
|
#myBtn {
|
|||
|
display: none;
|
|||
|
position: fixed;
|
|||
|
bottom: 10px;
|
|||
|
right: 10px;
|
|||
|
z-index: 99;
|
|||
|
font-size: 12px;
|
|||
|
font-weight: bold;
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background-color: white;
|
|||
|
color: black;
|
|||
|
cursor: pointer;
|
|||
|
padding: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
#myBtn:hover {
|
|||
|
background-color: #555;
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<button onclick="topFunction()" id="myBtn" title="Haut de page">⇧</button>
|
|||
|
|
|||
|
<script>
|
|||
|
//Get the button
|
|||
|
var mybutton = document.getElementById("myBtn");
|
|||
|
|
|||
|
// When the user scrolls down 20px from the top of the document, show the button
|
|||
|
window.onscroll = function() {scrollFunction()};
|
|||
|
|
|||
|
function scrollFunction() {
|
|||
|
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|||
|
mybutton.style.display = "block";
|
|||
|
} else {
|
|||
|
mybutton.style.display = "none";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// When the user clicks on the button, scroll to the top of the document
|
|||
|
function topFunction() {
|
|||
|
document.body.scrollTop = 0;
|
|||
|
document.documentElement.scrollTop = 0;
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
<!-- end custom article top snippet -->
|
|||
|
<div class="article__content" itemprop="articleBody"><details>
|
|||
|
<summary><b>Afficher/cacher Sommaire</b></summary>
|
|||
|
<!-- affichage sommaire -->
|
|||
|
<div class="toc-aside js-toc-root"></div>
|
|||
|
</details><ul>
|
|||
|
<li><a href="#firefox">Firefox</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#erreur-échec-de-la-connexion-sécurisée">ERREUR “Échec de la connexion sécurisée”</a></li>
|
|||
|
<li><a href="#configuration-de-base">Configuration de base</a></li>
|
|||
|
<li><a href="#préférences">Préférences</a></li>
|
|||
|
<li><a href="#modules----extensions">Modules –> Extensions</a></li>
|
|||
|
<li><a href="#ajout-moteur-de-recherche">Ajout moteur de recherche</a></li>
|
|||
|
<li><a href="#aboutconfig">about:config</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#désactiver-la-géolication">Désactiver la géolication</a></li>
|
|||
|
<li><a href="#désactivation-lecture-auto-contenu-html5">Désactivation lecture auto contenu HTML5</a></li>
|
|||
|
<li><a href="#ne-stock-rien-dans-le-cache">Ne stock rien dans le cache:</a></li>
|
|||
|
<li><a href="#désactivation-du-prefetching-dns">Désactivation du prefetching DNS</a></li>
|
|||
|
<li><a href="#désactivation-des-données-hors-connexion">Désactivation des données hors connexion</a></li>
|
|||
|
<li><a href="#désactivation-de-pocket">Désactivation de Pocket</a></li>
|
|||
|
<li><a href="#ne-pas-avertir-lors-de-la-fermeture-de-plusieurs-onglets">Ne pas avertir lors de la fermeture de plusieurs onglets</a></li>
|
|||
|
<li><a href="#désactivation-du-popup-et-de-lalerte-de-connexion-non-sécurisée">Désactivation du popup et de l’alerte de connexion non sécurisée</a></li>
|
|||
|
<li><a href="#désactivation-du-préchargement-des-url">Désactivation du préchargement des URL</a></li>
|
|||
|
<li><a href="#retrouver-le-mode-compact-de-firefox">Retrouver le mode compact de Firefox</a></li>
|
|||
|
<li><a href="#firefox-user-agent">Firefox user-agent</a></li>
|
|||
|
<li><a href="#webrtc">WebRTC</a></li>
|
|||
|
<li><a href="#désactiver-les-suggestions-des-moteurs-de-recherche">Désactiver les suggestions des moteurs de recherche</a></li>
|
|||
|
<li><a href="#autres-suggestions">Autres suggestions</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#firefox---importer-un-certificat-client">Firefox - Importer un certificat client</a></li>
|
|||
|
<li><a href="#liens">Liens</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#thunderbird">Thunderbird</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#modules-complémentaires-thunderbird">Modules complémentaires Thunderbird</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#cardbook">CardBook</a></li>
|
|||
|
<li><a href="#enigmail">Enigmail</a></li>
|
|||
|
<li><a href="#lightning">Lightning</a></li>
|
|||
|
<li><a href="#importexport-filtres-de-message">Import/Export filtres de message</a></li>
|
|||
|
<li><a href="#firetray">Firetray</a></li>
|
|||
|
<li><a href="#birdtray-firetray-alternative">Birdtray (Firetray Alternative)</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#contacts">Contacts</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
<li><a href="#thunderbird-102">Thunderbird 102+</a>
|
|||
|
<ul>
|
|||
|
<li><a href="#erreur-trycreate-mailbox-does-not-exist">Erreur (TRYCREATE) Mailbox does not exist</a></li>
|
|||
|
<li><a href="#erreur-certificat-invalide-port-587">Erreur Certificat invalide (port 587)</a></li>
|
|||
|
<li><a href="#erreur-certificat-imap">Erreur certificat imap</a></li>
|
|||
|
<li><a href="#erreur-copie-dossier-envoyés">Erreur copie dossier “Envoyés”</a></li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="firefox">Firefox</h2>
|
|||
|
|
|||
|
<h3 id="erreur-échec-de-la-connexion-sécurisée">ERREUR “Échec de la connexion sécurisée”</h3>
|
|||
|
|
|||
|
<p>Au <strong>premier appel</strong> sur un lien https vers un site ayant validé OCSP , on a l’erreur suivante</p>
|
|||
|
|
|||
|
<p><img src="/images/firefox-echec-connexion-securisee.png" alt="Navigation privée" width="600" /></p>
|
|||
|
|
|||
|
<p>Au <strong>second appel</strong> avec le même lien , tout est ok !!!</p>
|
|||
|
|
|||
|
<p>On peut reproduire le problème en ligne de commande<br />
|
|||
|
Au <strong>premier appel</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -connect xoyize.xyz:443 -status < /dev/null |grep -i ocsp
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
|
|||
|
verify return:1
|
|||
|
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
|
|||
|
verify return:1
|
|||
|
depth=0 CN = xoyize.xyz
|
|||
|
verify return:1
|
|||
|
DONE
|
|||
|
OCSP response: no response sent
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Au <strong>second appel</strong></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -connect xoyize.xyz:443 -status < /dev/null |grep -i ocsp
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>depth=2 O = Digital Signature Trust Co., CN = DST Root CA X3
|
|||
|
verify return:1
|
|||
|
depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
|
|||
|
verify return:1
|
|||
|
depth=0 CN = xoyize.xyz
|
|||
|
verify return:1
|
|||
|
DONE
|
|||
|
OCSP response:
|
|||
|
OCSP Response Data:
|
|||
|
OCSP Response Status: successful (0x0)
|
|||
|
Response Type: Basic OCSP Response
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Solutions</strong> :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>A chaque redémarrage de nginx , il faut lancer la commande openssl s_client 2 fois sur chaque domaine !!!</li>
|
|||
|
<li><a href="https://serverfault.com/questions/806329/can-i-make-nginx-automatically-ocsp-staple-certificates-at-reload-restart">Can I make Nginx automatically OCSP staple certificates at reload/restart?</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="configuration-de-base">Configuration de base</h3>
|
|||
|
|
|||
|
<p>Si <strong>ecryptfs</strong> est installé , il faut lier le dossier <em>.mozilla</em> à Private</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># en mode utilisateur
|
|||
|
cd $HOME
|
|||
|
mv .mozilla $HOME/Private/
|
|||
|
ln -s $HOME/Private/.mozilla .mozilla
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Il faut installer “Adobe Flash Plugin”</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yaourt -S flashplugin
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="préférences">Préférences</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Au démarrage de firefox : <strong>Afficher une page vide</strong></li>
|
|||
|
<li>Moteur de recherche par défaut : <strong>DuckDuckGo</strong></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Navigation :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Décocher : Défilement automatique
|
|||
|
Décocher : Défilement doux
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><strong>Vie privée et sécurité</strong> :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://www.kali-linux.fr/configuration/configurer-firefox-optimiser-securite-performances">Configurer Firefox pour optimiser les performances et laisser moins de traces</a></li>
|
|||
|
<li>
|
|||
|
<p><a href="/files/proteger-sa-vie-privee-sur-le-web-exemple-avec-firefox.epub">Protéger sa vie privée sur le web</a></p>
|
|||
|
</li>
|
|||
|
<li>Formulaires et mots de passe : <strong>NE PAS ENREGISTRER identifiants et mots de passe</strong></li>
|
|||
|
<li>Protection contre le pistage : <strong>toujours</strong> , Envoyer aux sites web un signal « Ne pas me pister » :<strong>toujours</strong></li>
|
|||
|
<li>Protection contre les contenus trompeurs et les logiciels dangereux , <strong>tout valider</strong></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><img src="/images/private-navigation.png" alt="Navigation privée" width="60%" /></p>
|
|||
|
|
|||
|
<h3 id="modules--extensions">Modules –> Extensions</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://blog.seboss666.info/2018/12/les-extensions-firefox-que-jutilise-en-cette-fin-dannee-et-probablement-pour-2019/">Les extensions Firefox que j’utilise en cette fin d’année, et probablement pour 2019</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/i-dont-care-about-cookies/">I don’t care about cookies</a><br />
|
|||
|
<em>La réglementation de l’UE exige que tout site Web utilisant des cookies de suivi doit obtenir l’autorisation de l’utilisateur avant de les installer. Ces avertissements apparaissent sur la plupart des sites Web jusqu’à ce que le visiteur accepte les termes et conditions du site Web. Imaginez à quel point cela devient irritant lorsque vous naviguez de façon anonyme ou si vous supprimez automatiquement les cookies à chaque fois que vous fermez votre navigateur.</em></p>
|
|||
|
|
|||
|
<p><em>Ce module complémentaire supprimera ces avertissements ennuyeux de cookies de presque tous les sites Web ! Vous pouvez signaler tout site Web qui vous avertit encore des cookies : faites un clic droit et choisissez’Signaler un avertissement de cookie’ dans le menu.</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/qookiefix/">QookieFix</a><br />
|
|||
|
<em>Beaucoup de sites intègrent la solution de consentement de Quantcast mais ne proposent pas de solution simple d’opposition. Cette extension fait juste apparaitre le bouton “Je refuse”.</em><br />
|
|||
|
<em>Cette extension simplifie le choix sur les bandeaux cookies Quantcast en faisant apparaitre un bouton « Je refuse » en plus du bouton j’accepte.</em>
|
|||
|
<em>Cliquer sur « Je refuse » permet de s’opposer à toutes les finalités d’un coup.</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/flagfox/">Flagfox</a><br />
|
|||
|
<em>Affiche le drapeau du pays où est situé le serveur du site parcouru, et procure de multiples outils : vérification de la sécurité des sites, informations whois, traduction, sites semblables, validation, adresses URL courtes, et d’autres encore…</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/ghostery/">Ghostery</a><br />
|
|||
|
<strong>TrackMeNot</strong> (FACULTATIF ,nécessite un redémarrage firefox)</p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/ublock-origin/">Ublock Origin</a><br />
|
|||
|
<em>bloqueur de requêtes qui se veut léger et performant. Son fonctionnement « avancé » permet d’avoir un résultat similaire à RequestPolicy Continued (voir ci-dessous). Le mode de fonctionnement « normal » est celui habituellement utilisé par les bloqueurs de publicités, à savoir l’utilisation de listes noires. Les listes chargées par défaut sont EasyList, Peter Lowe’s Adservers, EasyPrivacy et Malware domains et certaines de ces listes ont pour objet de contrecarrer le pistage. Il permet également d’empêcher les fuites d’adresse IP liées à l’utilisation de WebRTC</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/i-dont-care-about-cookies/">Cookies autorisation</a><br />
|
|||
|
<em>La réglementation européenne exige que tout site web utilisant des cookies doit obtenir l’autorisation de l’utilisateur avant de les installer. Ces avertissements apparaissent sur la plupart des sites Web jusqu’ à ce que le visiteur accepte les termes et conditions du site Web. Imaginez à quel point cela devient irritant lorsque vous surfez anonymement ou si vous supprimez automatiquement les cookies chaque fois que vous fermez le navigateur.</em><br />
|
|||
|
<em>Ce module supprimera ces avertissements de cookies ennuyeux de presque tous les sites Web! Vous pouvez signaler tout site Web qui vous avertit encore des cookies: faites un clic droit et choisissez “Signaler un avertissement de cookie” dans le menu.</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/lightbeam/">Lightbeam</a>
|
|||
|
<em>Lightbeam est un module complémentaire pour Firefox vous permettant de voir avec quels sites de première et tierce-partie vous interagissez sur le Web. Il vous montre les relations existant entre ces tierces parties et les sites que vous visitez.</em></p>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/smart-referer/">Smart Referer</a><br />
|
|||
|
<em>Désactiver la transmission du référent par une extension Smart Referer qui n’autorise l’usage du référent que sur le site courant).</em></p>
|
|||
|
|
|||
|
<h3 id="ajout-moteur-de-recherche">Ajout moteur de recherche</h3>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/firefox/addon/qwant/">Qwant</a></p>
|
|||
|
|
|||
|
<p><strong>Ixquick</strong> : Aller sur le lien <a href="https://www.ixquick.fr/fra">https://www.ixquick.fr/fra</a> et cliquer sur le bouton <strong>Ajouter à Firefox</strong> et il sera dans la liste des moteurs de recherche du navigateur.</p>
|
|||
|
|
|||
|
<p>Moteur de recherche à supprimer :<br />
|
|||
|
Préférences –> Recherche –> Moteur de recherche<br />
|
|||
|
Décocher Yahoo ,Bing ,Portail Lexical</p>
|
|||
|
|
|||
|
<h3 id="aboutconfig">about:config</h3>
|
|||
|
|
|||
|
<h4 id="désactiver-la-géolication">Désactiver la géolication</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>geo.enabled : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactivation-lecture-auto-contenu-html5">Désactivation lecture auto contenu HTML5</h4>
|
|||
|
|
|||
|
<p>Paramètre avancé ,saisir <strong>about:config</strong> dans la barre d’adresses, valider le fait qu’on fera attention, et chercher la clé <strong>media.autoplay.enabled</strong><br />
|
|||
|
Par défaut, la valeur est sur <strong>True</strong>, double-cliquez dessus pour la passer à <strong>False</strong> (prise en compte immédiate).</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>ATTENTION!!! Pas de lecture possible des vidéos VIMEO</strong></p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h4 id="ne-stock-rien-dans-le-cache">Ne stock rien dans le cache:</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>network.prefetch-next : False
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactivation-du-prefetching-dns">Désactivation du prefetching DNS</h4>
|
|||
|
|
|||
|
<p>Hautement recommandé :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>network.dns.disablePrefetch : true
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Un bon serveur DNS vous retournera l’information sous 10ms alors pourquoi requêter inutilement et potentiellement vous vendre gratuitement dans le cas d’utilisation de serveur DNS peu regardant sur la vie privée.</p>
|
|||
|
|
|||
|
<h4 id="désactivation-des-données-hors-connexion">Désactivation des données hors connexion</h4>
|
|||
|
|
|||
|
<p>Certains sites tels que office365 stockent des données sans notre avis, afin de forcer la demande à l’utilisateur :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>offline-apps.allow_by_default : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactivation-de-pocket">Désactivation de Pocket</h4>
|
|||
|
|
|||
|
<p>Facultatif ,si cette fonctionnalité ne vous sert pas :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>extensions.pocket.enabled : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="ne-pas-avertir-lors-de-la-fermeture-de-plusieurs-onglets">Ne pas avertir lors de la fermeture de plusieurs onglets</h4>
|
|||
|
|
|||
|
<p>Facultatif :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>browser.tabs.warnOnClose : false
|
|||
|
browser.tabs.warnOnCloseOtherTabs : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactivation-du-popup-et-de-lalerte-de-connexion-non-sécurisée">Désactivation du popup et de l’alerte de connexion non sécurisée</h4>
|
|||
|
|
|||
|
<p>Facultatif :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>security.insecure_field_warning.contextual.enabled : false
|
|||
|
security.insecure_password.ui.enabled : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactivation-du-préchargement-des-url">Désactivation du préchargement des URL</h4>
|
|||
|
|
|||
|
<p>Facultatif :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>browser.urlbar.speculativeConnect.enabled : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="retrouver-le-mode-compact-de-firefox">Retrouver le mode compact de Firefox</h4>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Saisissez <strong>about:config</strong> dans la barre d’adresse de Firefox, puis appuyez sur <strong>Entrée</strong><br />
|
|||
|
Une page d’avertissement peut apparaître. Cliquez sur <strong>Accepter le risque et poursuivre</strong> pour accéder à la page about:config.</li>
|
|||
|
<li>Recherchez la préférence <code class="language-plaintext highlighter-rouge">browser.compactmode.show</code></li>
|
|||
|
<li>Basculez la préférence à <strong>true</strong> et fermez l’onglet.</li>
|
|||
|
<li>Cliquez sur le <strong>bouton de menu</strong> pour ouvrir le panneau de menu.</li>
|
|||
|
<li>Cliquez sur Outils supplémentaires</li>
|
|||
|
<li>Choisissez <strong>Personnaliser la barre d’outils…</strong></li>
|
|||
|
<li>En bas du panneau, cliquez sur <strong>Densité</strong></li>
|
|||
|
<li>Choisissez <strong>Compacte (non prise en charge)</strong> dans le menu d’options.</li>
|
|||
|
<li>Cliquez sur <strong>Terminé</strong></li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<h4 id="firefox-user-agent">Firefox user-agent</h4>
|
|||
|
|
|||
|
<p><a href="https://lehollandaisvolant.net/?d=2014/01/19/17/30/43-changer-luser-agent-dans-firefox">Changer l’user-agent dans Firefox</a><br />
|
|||
|
<em>L’user-agent est une chaîne de caractères que votre navigateur envoie au site que vous visitez, et qui contient diverses informations sur le navigateur et l’ordinateur.</em><br />
|
|||
|
Saisir « <strong>about:config</strong> » dans la barre d’adresses de firefox puis taper « <strong>useragent</strong> » dans le champ de recherche.<br />
|
|||
|
Si la clé <strong>general.useragent.override</strong> n’existe pas déjà (auquel cas un double clic dessus suffit), faites un clic-droit sur la page, puis « <strong>nouvelle</strong> » puis « <strong>chaîne de caractères</strong> » et mettez <strong>general.useragent.override</strong> pour le nom.<br />
|
|||
|
Pour la valeur, mettez ce que vous voulez.<br />
|
|||
|
Si vous voulez vous identifier comme <u>Chrome sous Windows 8</u>, mettez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour <u>Firefox Mobile sous Android</u>, mettez :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mozilla/5.0 (Android; Mobile; rv:26.0) Gecko/26.0 Firefox/26.0
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour <u>Opera sous GNU/Linux</u> :</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Opera/9.80 (X11; Linux x86_64; Edition Linux Mint) Presto/2.12.388 Version/12.16
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Pour revenir à la valeur par défaut, faites un clic droit sur cette clé et « <strong>réinitialiser</strong> ».</p>
|
|||
|
|
|||
|
<h4 id="webrtc">WebRTC</h4>
|
|||
|
|
|||
|
<p>Désactiver le WebRTC «Web Real-Time Communication» qui permet le partage vocal, vidéo et P2P via votre navigateur, cette fonctionnalité peut également révéler votre adresse IP réelle via les requêtes STUN du navigateur, même si vous utilisez un service VPN</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>media.peerconnection.enabled = false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h4 id="désactiver-les-suggestions-des-moteurs-de-recherche">Désactiver les suggestions des moteurs de recherche</h4>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>browser.search.suggest.enabled : false
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/desactive-suggestion.png" alt="Moteur de recherche" /></p>
|
|||
|
|
|||
|
<h4 id="autres-suggestions">Autres suggestions</h4>
|
|||
|
|
|||
|
<p><strong>About config</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>browser.cache.disk.enable = false (désactive le cache disk)</li>
|
|||
|
<li>browser.cache.disk.capacity = 0 (interdit le cache disk)</li>
|
|||
|
<li>browser.cache.memory.enable = true (active le cache de la ram, accélère Mozilla)</li>
|
|||
|
<li>browser.cache.memory.capacity ou browser.cache.memory.max_entry_size = 20000 (Ram pour le cache)</li>
|
|||
|
<li>browser.cache.offline.enable = false (Désactive le cache offline)</li>
|
|||
|
<li>browser.cache.offline.capacity = 0 (interdit le cache offline)</li>
|
|||
|
<li>network.http.sendRefererHeader = 0 (n’informe pas le site de vos ancien site visité)</li>
|
|||
|
<li>browser.sessionhistory.max_entries = 5 (Nombre de pages pour revenir en arrière sur le même onglet)</li>
|
|||
|
<li>browser.display.use_document_fonts = 0 (Ne pas utiliser les polices du pays)</li>
|
|||
|
<li>privacy.trackingprotection.enabled = true (activer la protection contre le pistage)</li>
|
|||
|
<li>extensions.getAddons.cache.enabled = false (ne pas autoriser les add-ons a utiliser le cache)</li>
|
|||
|
<li>network.dns.disableIPv6 = True (accélère la connexion)</li>
|
|||
|
<li>browser.tabs.closeWindowWithLastTab = false (Ne pas fermer Firefox à la fermeture du dernier onglet, si vous trouvez cela pratique)</li>
|
|||
|
<li>network.manage-offline-status = false (Empêcher la mise « hors connexion » en cas de coupure réseau)</li>
|
|||
|
<li>browser.urlbar.maxRichResults = 0 (Désactiver la barre intelligente)</li>
|
|||
|
<li>browser.urlbar.matchOnlyTyped = true (plus là?)</li>
|
|||
|
<li>xpinstall.signatures.required = False (pour accepter les extensions non signées)</li>
|
|||
|
<li>xpinstall.whitelist.required = False (pour ne pas utiliser la liste blanche)</li>
|
|||
|
<li>extensions.legacy.enabled = true (si l’on veut faire fonctionner des anciens add-ons qui n’ont pas encore évolué vers le format WebExtensions)</li>
|
|||
|
<li>privacy.resistFingerprinting = true (rendre Firefox plus résistant aux empreintes digitales des navigateurs)</li>
|
|||
|
<li>privacy.firstparty.isolate = true (isoler les cookies dans le premier domaine de la partie, ce qui empêche le suivi sur plusieurs domaines mais fait aussi beaucoup plus)</li>
|
|||
|
<li>media.navigator.enabled = false (empêchera les sites Web de suivre l’état du microphone et de la caméra de votre appareil)</li>
|
|||
|
<li>webgl.disabled = true (WebGL représente un risque de sécurité potentiel. C’est pourquoi il est préférable de le désactiver, de plus il peut être utilisé pour identifier votre appareil par des empreintes digitales)</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>Extensions</strong></p>
|
|||
|
|
|||
|
<p>Les Add-ons Firefox pour une navigation sécurisée</p>
|
|||
|
|
|||
|
<p>Pour bien faire, il y en a 3 qui sont absolument obligatoires, pour votre sécurité et le respect de votre vie privée:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>uBlock Origin : Bloque les pubs, bloque les malwares et accélère la navigation. Vous pouvez vous rendre ici afin de rajouter des filtres: https://filterlists.com/</li>
|
|||
|
<li>HTTPS Everywhere : active automatiquement le chiffrement HTTPS sur les sites le prenant en charge, même lorsque vous saisissez une URL ou cliquez sur un lien sans préfixe « https: ».</li>
|
|||
|
<li>NoScript : L’indispensable. La meilleure sécurité possible pour un navigateur web. Ce module autorise le contenu actif des sites auxquels vous faites confiance et protège des attaques par XSS et détournement de clic, « Spectre », « Meltdown » et d’autres failles JavaScript. Un peu contraignant au début, mais vous vous y ferez vite (pensez à mettre en fiable les sites sûr).</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Ceci étant dit, je rajoute aussi, en règle générale:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Cookies Autodelete : Efface les cookies a chaque fermeture d’un onglet.</li>
|
|||
|
<li>Clear Flash Cookies : Efface les cookies LSO, les cookies caché pas connu. (remplace le regretté Better Privacy).</li>
|
|||
|
<li>Files MD5 SHA1 Calculate & Compare : Qui est utile aussi, pour voir si le fichier que vous avez téléchargé est le bon et s’il est complet.</li>
|
|||
|
<li>Privacy Badger : Bloque les traceurs invisibles.</li>
|
|||
|
<li>Ghostery : Ghostery est une puissante extension de protection de la vie privée.
|
|||
|
Bloquez les publicités, déjouez les outils de pistage et accélérez les sites Web.</li>
|
|||
|
<li>Requestblock : Permet de bloquer les requêtes “cross-site” nécessite Noscript (remplace Request Policy).</li>
|
|||
|
<li>Referer Modifier : Permet de mentir sur la page d’où nous venons (remplace RefControl).</li>
|
|||
|
<li>Show-my-ip : pour voir son ip (Pratique lorsque l’on a un vpn).</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Ensuite en option, vous pouvez aussi rajouter:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Wot : Il vous renseigne les sites Web fiables, sur la base de l’expérience de millions d’utilisateurs à travers le monde.</li>
|
|||
|
<li>Lightbeam : Il permet de voir avec quels sites de première et tierce-partie vous interagissez sur le Web. Il vous montre les relations existant entre ces tierces parties et les sites que vous visitez. Avec protection contre le pistage.</li>
|
|||
|
<li>User Agent Switcher : Pour faire croire que vous utiliser un autre OS/navigateur ou un autre appareil.</li>
|
|||
|
<li>AnonymoX : Si vous n’avez pas de VPN, vous avez plusieurs de choix de proxies anonymes.</li>
|
|||
|
<li>Tap Translate : Si, comme moi, vous êtes pas trop doué avec l’anglais, et les autres langues aussi.</li>
|
|||
|
<li>Decentraleyes : Protège du pistage lié aux diffuseurs de contenus « gratuits », centralisés (attention peut avoir conflit avec Ghostery).</li>
|
|||
|
<li>French Spelling Dictionary : Pour se faire corriger ses fautes d’orthographe, afin de participer proprement à notre forum par exemple…</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h3 id="firefox---importer-un-certificat-client">Firefox - Importer un certificat client</h3>
|
|||
|
|
|||
|
<p>Ouvrir le navigateur firefox <br />
|
|||
|
<img src="/images/ff001.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff002.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff003.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff004.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff005.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff006.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff007.png" alt="ff" width="600" /><br />
|
|||
|
<img src="/images/ff008.png" alt="ff" width="600" /></p>
|
|||
|
|
|||
|
<p>Lors de l’ouverture d’un site “sensible” ,le certificat client s’affiche , cliquer sur OK<br />
|
|||
|
<img src="/images/ff009.png" alt="ff" width="200" /></p>
|
|||
|
|
|||
|
<p>Si vous ne souhaitez plus valider le certificat à chaque ouverture<br />
|
|||
|
<img src="/images/ff010.png" alt="ff" width="600" /></p>
|
|||
|
|
|||
|
<h3 id="liens">Liens</h3>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://lehollandaisvolant.net/?d=2020/01/02/11/28/39-ma-liste-des-tweaks-aboutconfig-dans-firefox">Ma liste des tweaks « about:config » dans Firefox (Le Hollandais Volant)</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="thunderbird">Thunderbird</h2>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>ATTENTION version 60 et + de Thunderbird</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="modules-complémentaires-thunderbird">Modules complémentaires Thunderbird</h3>
|
|||
|
|
|||
|
<h4 id="cardbook">CardBook</h4>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/thunderbird/addon/cardbook/">CardBook</a><br />
|
|||
|
<em>Un nouveau carnet d’adresses pour Thunderbird basé sur les standards vCard et CardDAV.</em></p>
|
|||
|
|
|||
|
<h4 id="enigmail">Enigmail</h4>
|
|||
|
|
|||
|
<p><a href="https://addons.mozilla.org/fr/thunderbird/addon/enigmail/">Enigmail</a><br />
|
|||
|
<em>Chiffrement et vérification OpenPGP de messages, pour Thunderbird et Seamonkey.</em></p>
|
|||
|
|
|||
|
<h4 id="lightning">Lightning</h4>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Calendar/Calendar_Versions">Calendar version</a></li>
|
|||
|
<li><a href="https://ftp.mozilla.org/pub/calendar/lightning/candidates/">Index of /pub/calendar/lightning/candidates/</a></li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Lightning en français :</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Thunderbird version >=60 → lightning version 6.2 → télécharger : <code class="language-plaintext highlighter-rouge">cd ~/Private && wget https://ftp.mozilla.org/pub/calendar/lightning/candidates/6.2b6-candidates/build1/linux-x86_64/lightning-6.2b6.fr.xpi</code></li>
|
|||
|
<li>Sur Thunderbird, aller sur <strong>Outils → Modules complémentaires</strong> et cliquer sur la fenêtre déroulante , petite roue (Outils pour tous les modules) → <strong>Installer un module depuis un fichier</strong></li>
|
|||
|
<li>Sélectionner le fichier <strong>lightning-6.2b6.fr.xpi</strong> , <em>Ouvrir</em> et <em>Installer maintenant</em></li>
|
|||
|
<li><em>Redémarrer maintenant</em> pour la prise en charge</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h4 id="importexport-filtres-de-message">Import/Export filtres de message</h4>
|
|||
|
|
|||
|
<p><em>Exporter puis importer les filtres des mails sous Thunderbird. Il faut savoir que par défaut, la fonctionnalité n’est pas présente dans Thunderbird, nous allons donc passer par le téléchargement du module <a href="https://addons.mozilla.org/fr/thunderbird/addon/tb-import-export-wind-li-port/">Thunderbird Message Filter Import/Export</a></em></p>
|
|||
|
|
|||
|
<p>Une fois le fichier téléchargé, se rendre dans le Gestionnaire de modules Thunderbird, cliquer sur l’engrenage en haut à droite puis sélectionner <strong>Installer un module depuis un fichier…</strong><br />
|
|||
|
Sélectionner le fichier que nous venons de télécharger, celui-ci doit avoir une extension “.xpi” et dans la fenêtre “Installation d’un logiciel” on devra cliquer sur “Thunderbird…” et “Installer Mainetenant” pour valider l’installation.<br />
|
|||
|
Un redémarrage est nécessaire pour la prise encharge du module.</p>
|
|||
|
|
|||
|
<p>Dans la fenêtre “Filtres de messages” (Menu -> Outils -> Filtres de messages) , un bouton <strong>Exporter</strong> est présent</p>
|
|||
|
|
|||
|
<h4 id="firetray">Firetray</h4>
|
|||
|
|
|||
|
<p><em>Une extension de la barre d’état système pour Linux et Windows, permettant de configurer des icônes personnalisées, se cacher dans la barre au lieu de la fermer, afficher le nombre de messages non lus dans les applications de messagerie, et d’autres fonctionnalités…</em></p>
|
|||
|
|
|||
|
<p>Les dernières mises à jour : <a href="https://github.com/Ximi1970/FireTray/releases">https://github.com/Ximi1970/FireTray/releases</a><br />
|
|||
|
Extension <strong>firetray-0.6.5.xpi</strong> (février 2019)</p>
|
|||
|
|
|||
|
<p><strong>Caractéristiques :</strong></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>pour toutes les applications :
|
|||
|
* afficher/masquer une seule fenêtre ou toutes les fenêtres
|
|||
|
* restaurer l’état, la position et la taille des fenêtres à leur état, leur taille et leur position d’origine
|
|||
|
* restaurer chaque fenêtre sur son bureau/espace de travail virtuel d’origine
|
|||
|
* activer les fenêtres restaurées
|
|||
|
* hide to tray on close
|
|||
|
* hide to tray on minimize
|
|||
|
* Début minimisé dans le plateau
|
|||
|
* afficher l’icône seulement lorsqu’elle est cachée dans la barre d’état système
|
|||
|
* la souris fait défiler sur l’icône de la barre d’état-civil montre/masque
|
|||
|
* icônes thématiques
|
|||
|
* menu déroulant (afficher/masquer les fenêtres individuelles, ouvrir de nouvelles fenêtres, quitter)
|
|||
|
* raccourcis clavier</li>
|
|||
|
<li>pour les applications de courrier :
|
|||
|
* afficher le nombre de messages non lus dans l’icône de la barre d’état système
|
|||
|
* affichage de l’icône biff dans la barre des tâches lorsque de nouveaux messages sont affichés
|
|||
|
* Icône personnalisable dans la barre d’état système pour mail biff
|
|||
|
* inclure/exclure les comptes de messagerie de/vers le nombre de messages
|
|||
|
* inclure/exclure les types de dossiers de/vers le nombre de messages</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p><strong>Préférences :</strong></p>
|
|||
|
|
|||
|
<p><img src="/images/firetray01.png" alt="Texte alternatif" width="400" /></p>
|
|||
|
|
|||
|
<p><img src="/images/firetray02.png" alt="Texte alternatif" width="400" /><br />
|
|||
|
icône <strong>email-309491_640.png</strong> <img src="/images/email-309491_640.png" alt="Texte alternatif" width="30" /><br />
|
|||
|
<a href="/files/email-309491_640.png">Télécharger icône “email-309491_640.png”</a></p>
|
|||
|
|
|||
|
<p><img src="/images/firetray03.png" alt="Texte alternatif" width="700" /></p>
|
|||
|
|
|||
|
<p><img src="/images/firetray04.png" alt="Texte alternatif" width="400" /></p>
|
|||
|
|
|||
|
<h4 id="birdtray-firetray-alternative">Birdtray (Firetray Alternative)</h4>
|
|||
|
|
|||
|
<p><em>icône Thunderbird Tray avec de nouvelles notifications par courrier électronique pour Linux</em></p>
|
|||
|
|
|||
|
<p>Birdtray ajoute une icône de barre d’état système pour le client de messagerie Thunderbird sous Linux (Xorg) ou Windows, qui indique le nombre de courriers électroniques non lus. <br />
|
|||
|
En plus de cela, Birdtray prend en charge la mise en attente des nouvelles notifications par e-mail, configurez les comptes / dossiers de messagerie pour notifier les nouveaux e-mails, etc.</p>
|
|||
|
|
|||
|
<p>FireTray et d’autres solutions pour ajouter une icône de plateau pour Thunderbird qui affiche un nombre d’e-mails non lus ont cessé de fonctionner avec Thunderbird 60. <br />
|
|||
|
Birdtray vérifie l’état des e-mails non lus directement en lisant la base de données de recherche d’e-mails de Thunderbird, ce qui le rend immunisé contre les modifications de l’API Thunderbird. En conséquence, Birdtray est une excellente alternative à Firetray qui ne devrait pas se casser sur les mises à jour de Thunderbird.</p>
|
|||
|
|
|||
|
<p>L’outil nécessite Qt5 (5.6 ou supérieur) et est actuellement considéré comme un logiciel alpha - ce n’est plus le cas, Birdtray est maintenant considéré comme stable.</p>
|
|||
|
|
|||
|
<p>Caractéristiques de Birdtray:</p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Icône de plateau Thunderbird avec compteur de courrier électronique non lu</li>
|
|||
|
<li>L’icône de la barre d’état peut clignoter (clignoter) lorsque de nouveaux e-mails sont reçus. avec vitesse de clignotement configurable</li>
|
|||
|
<li>Comptes configurables / dossier de messagerie pour lequel il doit vérifier les nouveaux e-mails</li>
|
|||
|
<li>Couleurs de police de comptage non lues configurables pour différents comptes de messagerie</li>
|
|||
|
<li>Peut masquer et restaurer la fenêtre Thunderbird en double-cliquant sur l’icône de la barre d’état ou à partir du menu contextuel de l’icône de la barre d’état</li>
|
|||
|
<li>Peut démarrer automatiquement Thunderbird lors du lancement de Birdtray et fermer Thunderbird lorsque vous quittez l’icône de la barre d’état</li>
|
|||
|
<li>Icône de plateau configurable (pour les icônes normales et non lues)</li>
|
|||
|
<li>Peut détecter si Thunderbird a été accidentellement fermé</li>
|
|||
|
<li>Répéter les nouvelles notifications par e-mail pendant une durée prédéfinie</li>
|
|||
|
<li>Permet d’ajouter des modèles d’e-mails préconfigurés dans la barre d’état pour un accès rapide (nouvel onglet E-mail dans Birdtray - nécessite de redémarrer Birdtray après l’ajout de nouveaux e-mails préconfigurés)</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Il convient également de noter que cela peut prendre quelques secondes jusqu’à ce que l’icône de la barre d’état vous avertisse des nouveaux e-mails, car Thunderbird doit mettre à jour la base de données avant que Birdtray ne puisse “voir” qu’un nouvel e-mail est arrivé.</p>
|
|||
|
|
|||
|
<p>L’onglet des versions de Birdtray GitHub ne contient que des fichiers binaires pour Windows (et source).</p>
|
|||
|
|
|||
|
<p>Birdtray est disponible dans les référentiels pour les récentes versions de distribution Linux basées sur Debian, y compris Debian Buster et les versions plus récentes, Ubuntu 19.04, 19.10 et 20.04, Linux Mint 19. *, et plus encore. Cependant, il peut y avoir une ou deux versions derrière la dernière version. Vous pouvez l’installer en utilisant:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo apt install birdtray
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Birdtray est également disponible dans le <a href="https://aur.archlinux.org/packages/?O=0&SeB=nd&K=birdtray&outdated=&SB=n&SO=a&PP=50&do_Search=Go">référentiel Arch User</a></p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yay -S birdtray # birdtray-git
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Et enfin, si vous êtes sous Linux, vous pouvez également <a href="https://github.com/gyunaev/birdtray#building">construire Birdtray</a> vous-même si vous le souhaitez.</p>
|
|||
|
|
|||
|
<p><strong>Comment configurer l’icône de la barre d’état Birdtray Thunderbird</strong></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Avant de commencer avec Birdtray, assurez-vous que votre adresse e-mail est déjà configurée dans Thunderbird, sinon cela ne fonctionnera pas.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>La première chose que vous devrez faire est d’ajouter votre profil Thunderbird dans Birdtray.<br />
|
|||
|
Pour ce faire, lancez <strong>Birdtray</strong> et dans le menu d’icônes de la barre d’état, sélectionnez <strong>Settings</strong></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Birdtray prend en charge 2 méthodes d’analyse de vos e-mails pour afficher les notifications par e-mail non lues:</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li>Utilisation de Mork Parser pour indexer des fichiers.<br />
|
|||
|
Avec Thunderbird 68+, l’analyseur basé sur sqlite ne fonctionne plus, vous devrez donc changer l’option d’ <strong>Unread notification parser</strong> de <em>sqlite</em> à <em>mork</em><br />
|
|||
|
Pour ce faire, ouvrez <strong>Birdtray</strong>, passez à l’onglet Surveillance et sélectionnez à l’ <strong>using Mork index files</strong> sous <strong>Method to parse unread notifications</strong> . Ensuite, cliquez sur <strong>Add</strong> :</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<p>Avec Birdtray 1.7.0 et plus récent, vos comptes de messagerie de votre profil ~/.thunderbird devraient être répertoriés, vous permettant de sélectionner ceux pour lesquels vous souhaitez être averti:</p>
|
|||
|
|
|||
|
<p><img src="/images/birdtray170-setup-mock.png" alt=" " width="500" /><br />
|
|||
|
<img src="/images/mail-accounts.png" alt=" " width="400" /> <br />
|
|||
|
<img src="/images/mail-accounts1.png" alt=" " width="400" /></p>
|
|||
|
|
|||
|
<p>C’est tout ce que vous devez faire pour que Birdtray fonctionne. Vous voudrez peut-être modifier certains de ses autres paramètres, selon vos besoins.</p>
|
|||
|
|
|||
|
<p>Il convient également de noter que par défaut, Birdtray n’est pas configuré pour démarrer automatiquement Thunderbird au démarrage de Birdtray, pour masquer / afficher la fenêtre Thunderbird lorsque vous cliquez sur l’icône de la barre d’état, masquer la fenêtre Thunderbird lorsqu’elle est minimisée, etc. Vous pouvez activer toutes ces options dans les paramètres Birdtray, sous l’onglet Hiding .</p>
|
|||
|
|
|||
|
<p><img src="/images/birdtray-settings.png" alt=" " width="400" /> <br />
|
|||
|
Icône : <img src="/images/email-309491_640.png" alt="" width="50" /></p>
|
|||
|
|
|||
|
<h3 id="contacts">Contacts</h3>
|
|||
|
|
|||
|
<p>A partir de la version 68, de nombreux modules ne sont plus valides notamment cardbook et firetray.</p>
|
|||
|
|
|||
|
<p><img src="/images/tb6801.png" alt="" width="400" /></p>
|
|||
|
|
|||
|
<p>Remplacement de cardbook , on va installer les modules “tbSync” et “Provider caldav carddav”</p>
|
|||
|
|
|||
|
<p><img src="/images/tb6802.png" alt="" width="400" /></p>
|
|||
|
|
|||
|
<p>Paramétrage : Outils → Préférences des modules → TbSync</p>
|
|||
|
|
|||
|
<p><img src="/images/tb6803.png" alt="" width="400" /><br />
|
|||
|
Cliquer sur “Account actions”<br />
|
|||
|
<img src="/images/tb6804.png" alt="" /><br />
|
|||
|
Sélection “Caldav…”<br />
|
|||
|
<img src="/images/tb6805.png" alt="" width="300" /><br />
|
|||
|
Sélection “Manual configuration” et suivant<br />
|
|||
|
<img src="/images/tb6806.png" alt="" width="300" /><br />
|
|||
|
Remplir et cliquer sur “Terminer”<br />
|
|||
|
<em>on n’est pas obligé d’utiliser calendrier (caldav) et contacts (carddav)</em></p>
|
|||
|
|
|||
|
<p><img src="/images/tb6807.png" alt="" width="400" /></p>
|
|||
|
|
|||
|
<p>Vous avez un nouveau carnet d’adresses</p>
|
|||
|
|
|||
|
<p><img src="/images/tb6808.png" alt="" width="400" /></p>
|
|||
|
|
|||
|
<h2 id="thunderbird-102">Thunderbird 102+</h2>
|
|||
|
|
|||
|
<h3 id="erreur-trycreate-mailbox-does-not-exist">Erreur (TRYCREATE) Mailbox does not exist</h3>
|
|||
|
|
|||
|
<p><em>La commande courante n’a pas abouti. Le serveur de courrier pour le compte XXXXXXX@laposte.net a répondu : (TRYCREATE) Mailbox does not exist.</em></p>
|
|||
|
|
|||
|
<p>Correction</p>
|
|||
|
|
|||
|
<p>Je demande à Thunderbird d’envoyer une copie des mails sortants dans le dossier adéquat, idem pour les brouillons.</p>
|
|||
|
|
|||
|
<ol>
|
|||
|
<li>Aller dans les paramètres de votre compte laposte.net dans Thunderbird
|
|||
|
<ul>
|
|||
|
<li>Aller à la rubrique “Copies et dossiers” de votre compte SFR</li>
|
|||
|
</ul>
|
|||
|
</li>
|
|||
|
</ol>
|
|||
|
|
|||
|
<p><img src="/images/thunderbird-laposte.png" alt="" /></p>
|
|||
|
|
|||
|
<h3 id="erreur-certificat-invalide-port-587">Erreur Certificat invalide (port 587)</h3>
|
|||
|
|
|||
|
<p>Lors de l’envoi d’un message en utilisant le smtp xoyaz.xyz, j’ai une erreur<br />
|
|||
|
<img src="/images/erreur-smtp.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Le certificat SSL est valide<br />
|
|||
|
<img src="/images/erreur-smtp01.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Par contre il n’est pas valide sur le port 587</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -starttls smtp -showcerts -connect xoyaz.xyz:587 -servername xoyaz.xyz --quiet
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/erreur-smtp02.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Pour la solution, il faut exécuter le commande suivante sur le serveur</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo postmap -F hash:/etc/postfix/sni
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérification</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -starttls smtp -showcerts -connect xoyaz.xyz:587 -servername xoyaz.xyz --quiet
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/erreur-smtp03.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Voir forum yunohost <a href="https://forum.yunohost.org/t/probleme-certificat-sur-serveur-smtp/20883">https://forum.yunohost.org/t/probleme-certificat-sur-serveur-smtp/20883</a></p>
|
|||
|
|
|||
|
<h3 id="erreur-certificat-imap">Erreur certificat imap</h3>
|
|||
|
|
|||
|
<p>Lors de la configuration thunderbird j’ai une erreur<br />
|
|||
|
<img src="/images/erreur-smtp04.png" alt="" /></p>
|
|||
|
|
|||
|
<p>Erreur qui concerne le domaine , il est différent xoyize.xyz au lieu de cinay.eu</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -connect cinay.eu:993 -quiet
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
|||
|
verify return:1
|
|||
|
depth=1 C = US, O = Let's Encrypt, CN = R3
|
|||
|
verify return:1
|
|||
|
depth=0 CN = xoyize.xyz
|
|||
|
verify return:1
|
|||
|
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot (Debian) ready.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><img src="/images/erreur-smtp05.png" alt="" /></p>
|
|||
|
|
|||
|
<p>La configuration dovecot est incomplète, le domaine cinay.eu n’y est pas ? (fichier /etc/dovecot/dovecot.conf)</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl = required
|
|||
|
|
|||
|
ssl_cert = </etc/yunohost/certs/xoyize.xyz/crt.pem
|
|||
|
ssl_key = </etc/yunohost/certs/xoyize.xyz/key.pem
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p><code class="language-plaintext warning highlighter-rouge">ATTENTION Une simple commande peut corriger le problème : yunohost tools regen-conf dovecot --force</code></p>
|
|||
|
|
|||
|
<p>Il faut ajouter le domaine cinay.eu en local_name, ce qui donne au final</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ssl = required
|
|||
|
|
|||
|
ssl_cert = </etc/yunohost/certs/xoyize.xyz/crt.pem
|
|||
|
ssl_key = </etc/yunohost/certs/xoyize.xyz/key.pem
|
|||
|
|
|||
|
local_name cinay.eu {
|
|||
|
ssl_cert = </etc/yunohost/certs/cinay.eu/crt.pem
|
|||
|
ssl_key = </etc/yunohost/certs/cinay.eu/key.pem
|
|||
|
}
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Relancer dovecot</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sudo systemctl restart dovecot
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Vérifier</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl s_client -connect cinay.eu:993 -quiet
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
|
|||
|
verify return:1
|
|||
|
depth=1 C = US, O = Let's Encrypt, CN = R3
|
|||
|
verify return:1
|
|||
|
depth=0 CN = cinay.eu
|
|||
|
verify return:1
|
|||
|
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot (Debian) ready.
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<h3 id="erreur-copie-dossier-envoyés">Erreur copie dossier “Envoyés”</h3>
|
|||
|
|
|||
|
<p>Le message d’erreur<br />
|
|||
|
<code class="language-plaintext warning highlighter-rouge">Votre message a été envoyé, mais une copie n’a pas été placée dans votre dossier Envoyés (Envoyés) en raison d’un problème d’accès au réseau ou au fichier.
|
|||
|
Vous pouvez recommencer ou enregistrer le message en local dans Dossiers locaux...</code></p>
|
|||
|
|
|||
|
<p>Aller dans <strong>Paramètres du compte → Copie et dossiers</strong><br />
|
|||
|
Placer une copie dans : → Autre dossier<br />
|
|||
|
Sélectionner le compte de messagerie → Courrier entrant → et en fin le dossier “Envoyés” ou “Sent” suivant le compte</p>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2018-09-27T00:00:00+02:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2018/09/22/Ruby-Jekyll-serveur-statique.html">Debian Ruby via les dépôts ou Rbenv + Jekyll (serveur statique)</a></div><div class="next"><span>SUIVANT</span><a href="/2018/10/02/DocFetcher-recherche-de-contenu.html">DocFetcher, application Open Source pour la recherche de contenu</a></div></div></div>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
$(function() {
|
|||
|
var $this ,$scroll;
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
|
|||
|
$scroll = $(scroll);
|
|||
|
|
|||
|
$articleContent.find('.highlight').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.attr('data-lang', $this.find('code').attr('data-lang'));
|
|||
|
});
|
|||
|
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
|
|||
|
});
|
|||
|
$articleContent.on('click', '.anchor', function() {
|
|||
|
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
|
|||
|
<!-- end custom main bottom snippet -->
|
|||
|
</div>
|
|||
|
</div></div></div></div>
|
|||
|
</div><script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $body = $('body'), $window = $(window);
|
|||
|
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
|
|||
|
var activeCount = 0;
|
|||
|
function modal(options) {
|
|||
|
var $root = this, visible, onChange, hideWhenWindowScroll = false;
|
|||
|
var scrollTop;
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
visible = _options.initialVisible === undefined ? false : show;
|
|||
|
onChange = _options.onChange;
|
|||
|
hideWhenWindowScroll = _options.hideWhenWindowScroll;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
setState(visible);
|
|||
|
}
|
|||
|
function setState(isShow) {
|
|||
|
if (isShow === visible) {
|
|||
|
return;
|
|||
|
}
|
|||
|
visible = isShow;
|
|||
|
if (visible) {
|
|||
|
activeCount++;
|
|||
|
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
|
|||
|
$root.addClass('modal--show');
|
|||
|
$pageMain.scrollTop(scrollTop);
|
|||
|
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
|
|||
|
$window.on('keyup', handleKeyup);
|
|||
|
} else {
|
|||
|
activeCount > 0 && activeCount--;
|
|||
|
$root.removeClass('modal--show');
|
|||
|
$window.scrollTop(scrollTop);
|
|||
|
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
|
|||
|
$window.off('keyup', handleKeyup);
|
|||
|
}
|
|||
|
onChange && onChange(visible);
|
|||
|
}
|
|||
|
function show() {
|
|||
|
setState(true);
|
|||
|
}
|
|||
|
function hide() {
|
|||
|
setState(false);
|
|||
|
}
|
|||
|
function handleKeyup(e) {
|
|||
|
// Char Code: 27 ESC
|
|||
|
if (e.which === 27) {
|
|||
|
hide();
|
|||
|
}
|
|||
|
}
|
|||
|
setOptions(options);
|
|||
|
init();
|
|||
|
return {
|
|||
|
show: show,
|
|||
|
hide: hide,
|
|||
|
$el: $root
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.modal = modal;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
|
|||
|
(function () {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
// search panel
|
|||
|
var search = (window.search || (window.search = {}));
|
|||
|
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
|
|||
|
true : window.useDefaultSearchBox ;
|
|||
|
|
|||
|
var $searchModal = $('.js-page-search-modal');
|
|||
|
var $searchToggle = $('.js-search-toggle');
|
|||
|
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
|
|||
|
var modalVisible = false;
|
|||
|
search.searchModal = searchModal;
|
|||
|
|
|||
|
var $searchBox = null;
|
|||
|
var $searchInput = null;
|
|||
|
var $searchClear = null;
|
|||
|
|
|||
|
function getModalVisible() {
|
|||
|
return modalVisible;
|
|||
|
}
|
|||
|
search.getModalVisible = getModalVisible;
|
|||
|
|
|||
|
function handleModalChange(visible) {
|
|||
|
modalVisible = visible;
|
|||
|
if (visible) {
|
|||
|
search.onShow && search.onShow();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
|
|||
|
} else {
|
|||
|
search.onShow && search.onHide();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
|
|||
|
setTimeout(function() {
|
|||
|
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
|
|||
|
search.clear && search.clear();
|
|||
|
window.pageAsideAffix && window.pageAsideAffix.refresh();
|
|||
|
}, 400);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$searchToggle.on('click', function() {
|
|||
|
modalVisible ? searchModal.hide() : searchModal.show();
|
|||
|
});
|
|||
|
// Char Code: 83 S, 191 /
|
|||
|
$(window).on('keyup', function(e) {
|
|||
|
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
|
|||
|
modalVisible || searchModal.show();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
if (useDefaultSearchBox) {
|
|||
|
$searchBox = $('.js-search-box');
|
|||
|
$searchInput = $searchBox.children('input');
|
|||
|
$searchClear = $searchBox.children('.js-icon-clear');
|
|||
|
search.getSearchInput = function() {
|
|||
|
return $searchInput.get(0);
|
|||
|
};
|
|||
|
search.getVal = function() {
|
|||
|
return $searchInput.val();
|
|||
|
};
|
|||
|
search.setVal = function(val) {
|
|||
|
$searchInput.val(val);
|
|||
|
};
|
|||
|
|
|||
|
$searchInput.on('focus', function() {
|
|||
|
$(this).addClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('blur', function() {
|
|||
|
$(this).removeClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('input', window.throttle(function() {
|
|||
|
var val = $(this).val();
|
|||
|
if (val === '' || typeof val !== 'string') {
|
|||
|
search.clear && search.clear();
|
|||
|
} else {
|
|||
|
$searchBox.addClass('not-empty');
|
|||
|
search.onInputNotEmpty && search.onInputNotEmpty(val);
|
|||
|
}
|
|||
|
}, 400));
|
|||
|
$searchClear.on('click', function() {
|
|||
|
$searchInput.val(''); $searchBox.removeClass('not-empty');
|
|||
|
search.clear && search.clear();
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="search search--dark">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header">Recherche</div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
|
|||
|
Annuler</button>
|
|||
|
</div>
|
|||
|
<div id="results-container" class="search-result js-search-result"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
noResultsText: '<p>Aucun résultat!</p>',
|
|||
|
json: '/search.json',
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a> (Création {create})</li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
</div></div>
|
|||
|
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function scrollToAnchor(anchor, duration, callback) {
|
|||
|
var $root = this;
|
|||
|
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
|
|||
|
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
|
|||
|
callback && callback();
|
|||
|
});
|
|||
|
}
|
|||
|
$.fn.scrollToAnchor = scrollToAnchor;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function affix(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroll,
|
|||
|
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
|
|||
|
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
|
|||
|
hasInit = false, curState;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroll && (scroll = _options.scroll);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
|
|||
|
$scroll = $(scroll);
|
|||
|
}
|
|||
|
function preCalc() {
|
|||
|
top();
|
|||
|
rootHeight = $root.outerHeight();
|
|||
|
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
|
|||
|
rootLeft = $root.offset().left;
|
|||
|
}
|
|||
|
function calc(needPreCalc) {
|
|||
|
needPreCalc && preCalc();
|
|||
|
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
|
|||
|
rootBottomTop = scrollBottom - rootTop;
|
|||
|
}
|
|||
|
function top() {
|
|||
|
if (curState !== 'top') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'top';
|
|||
|
}
|
|||
|
}
|
|||
|
function fixed() {
|
|||
|
if (curState !== 'fixed') {
|
|||
|
$root.addClass('fixed').css({
|
|||
|
left: rootLeft + 'px',
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'fixed';
|
|||
|
}
|
|||
|
}
|
|||
|
function bottom() {
|
|||
|
if (curState !== 'bottom') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: rootBottomTop + 'px'
|
|||
|
});
|
|||
|
curState = 'bottom';
|
|||
|
}
|
|||
|
}
|
|||
|
function setState() {
|
|||
|
var scrollTop = $scrollTarget.scrollTop();
|
|||
|
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
|
|||
|
fixed();
|
|||
|
} else if (scrollTop < rootTop) {
|
|||
|
top();
|
|||
|
} else {
|
|||
|
bottom();
|
|||
|
}
|
|||
|
}
|
|||
|
function init() {
|
|||
|
if(!hasInit) {
|
|||
|
var interval, timeout;
|
|||
|
calc(true); setState();
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState();
|
|||
|
});
|
|||
|
$window.on('resize', function() {
|
|||
|
disabled || (calc(true), setState());
|
|||
|
});
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions,
|
|||
|
refresh: function() {
|
|||
|
calc(true, { animation: false }); setState();
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.affix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function toc(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
|
|||
|
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
|
|||
|
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.selectors && (selectors = _options.selectors);
|
|||
|
_options.container && (container = _options.container);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroller && (scroller = _options.scroller);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$headings = $(container).find(selectors).filter('[id]');
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
$scroller = $(scroller);
|
|||
|
}
|
|||
|
function calc() {
|
|||
|
headingsPos = [];
|
|||
|
$headings.each(function() {
|
|||
|
headingsPos.push(Math.floor($(this).position().top));
|
|||
|
});
|
|||
|
}
|
|||
|
function setState(element, disabled) {
|
|||
|
var scrollTop = $scrollTarget.scrollTop(), i;
|
|||
|
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
|
|||
|
if (element) {
|
|||
|
$activeCur = element;
|
|||
|
} else {
|
|||
|
for (i = 0; i < headingsPos.length; i++) {
|
|||
|
if (scrollTop >= headingsPos[i]) {
|
|||
|
$activeCur = $tocLi.eq(i);
|
|||
|
} else {
|
|||
|
$activeCur || ($activeCur = $tocLi.eq(i));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
$activeLast && $activeLast.removeClass('active');
|
|||
|
($activeLast = $activeCur).addClass('active');
|
|||
|
}
|
|||
|
function render() {
|
|||
|
if(!hasRendered) {
|
|||
|
$root.append($tocUl);
|
|||
|
$headings.each(function() {
|
|||
|
var $this = $(this);
|
|||
|
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
|
|||
|
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
|
|||
|
});
|
|||
|
$tocLi = $tocUl.children('li');
|
|||
|
$tocUl.on('click', 'a', function(e) {
|
|||
|
e.preventDefault();
|
|||
|
var $this = $(this);
|
|||
|
scrolling = true;
|
|||
|
setState($this.parent());
|
|||
|
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
|
|||
|
scrolling = false;
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
hasRendered = true;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
var interval, timeout;
|
|||
|
if(!hasInit) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState(null, scrolling);
|
|||
|
});
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
if (!disabled) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
}
|
|||
|
}, 100));
|
|||
|
}
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.toc = toc;
|
|||
|
});
|
|||
|
})();
|
|||
|
/*(function () {
|
|||
|
|
|||
|
})();*/
|
|||
|
</script><script>
|
|||
|
/* toc must before affix, since affix need to konw toc' height. */(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window);
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
|
|||
|
var toc;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
|
|||
|
|
|||
|
function disabled() {
|
|||
|
return $col2.css('display') === 'none' || !hasToc;
|
|||
|
}
|
|||
|
|
|||
|
tocDisabled = disabled();
|
|||
|
|
|||
|
toc = $tocRoot.toc({
|
|||
|
selectors: TOC_SELECTOR,
|
|||
|
container: $articleContent,
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
tocDisabled = disabled();
|
|||
|
toc && toc.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window), $pageFooter = $('.js-page-footer');
|
|||
|
var $pageAside = $('.js-page-aside');
|
|||
|
var affix;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
|
|||
|
affix = $pageAside.affix({
|
|||
|
offsetBottom: $pageFooter.outerHeight(),
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroll: hasSidebar ? $('.js-page-main').children() : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
affix && affix.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
window.pageAsideAffix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><!---->
|
|||
|
|
|||
|
</div>
|
|||
|
<script>(function () {
|
|||
|
var $root = document.getElementsByClassName('root')[0];
|
|||
|
if (window.hasEvent('touchstart')) {
|
|||
|
$root.dataset.isTouch = true;
|
|||
|
document.addEventListener('touchstart', function(){}, false);
|
|||
|
}
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|
|||
|
|