2022-01-20 18:27:56 +00:00
|
|
|
/* @license This file Copyright (C) 2020-2022 Mnemosyne LLC.
|
2022-02-07 16:25:02 +00:00
|
|
|
It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
or any future license endorsed by Mnemosyne LLC.
|
|
|
|
License text can be found in the licenses/ folder. */
|
2020-10-24 01:04:25 +00:00
|
|
|
|
|
|
|
import { Formatter } from './formatter.js';
|
|
|
|
import {
|
|
|
|
OutsideClickListener,
|
|
|
|
createTabsContainer,
|
|
|
|
makeUUID,
|
|
|
|
setEnabled,
|
|
|
|
setTextContent,
|
|
|
|
} from './utils.js';
|
|
|
|
|
|
|
|
export class PrefsDialog extends EventTarget {
|
|
|
|
static _initTimeDropDown(e) {
|
|
|
|
for (let index = 0; index < 24 * 4; ++index) {
|
|
|
|
const hour = Number.parseInt(index / 4, 10);
|
|
|
|
const mins = (index % 4) * 15;
|
|
|
|
const value = index * 15;
|
|
|
|
const content = `${hour}:${mins || '00'}`;
|
|
|
|
e.options[index] = new Option(content, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static _initDayDropDown(e) {
|
|
|
|
const options = [
|
|
|
|
['Everyday', '127'],
|
|
|
|
['Weekdays', '62'],
|
|
|
|
['Weekends', '65'],
|
|
|
|
['Sunday', '1'],
|
|
|
|
['Monday', '2'],
|
|
|
|
['Tuesday', '4'],
|
|
|
|
['Wednesday', '8'],
|
|
|
|
['Thursday', '16'],
|
|
|
|
['Friday', '32'],
|
|
|
|
['Saturday', '64'],
|
|
|
|
];
|
|
|
|
for (let index = 0; options[index]; ++index) {
|
|
|
|
const [text, value] = options[index];
|
|
|
|
e.options[index] = new Option(text, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_checkPort() {
|
|
|
|
const element = this.elements.network.port_status_label;
|
2022-05-16 01:49:25 +00:00
|
|
|
delete element.dataset.open;
|
2020-10-24 01:04:25 +00:00
|
|
|
setTextContent(element, 'Checking...');
|
|
|
|
this.remote.checkPort(this._onPortChecked, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
_onPortChecked(response) {
|
|
|
|
const element = this.elements.network.port_status_label;
|
|
|
|
const is_open = response.arguments['port-is-open'];
|
|
|
|
element.dataset.open = is_open;
|
|
|
|
setTextContent(element, is_open ? 'Open' : 'Closed');
|
|
|
|
}
|
|
|
|
|
|
|
|
_setBlocklistButtonEnabled(b) {
|
|
|
|
const e = this.elements.peers.blocklist_update_button;
|
|
|
|
setEnabled(e, b);
|
|
|
|
e.value = b ? 'Update' : 'Updating...';
|
|
|
|
}
|
|
|
|
|
|
|
|
static _getValue(e) {
|
2022-02-20 17:54:20 +00:00
|
|
|
if (e.tagName === 'TEXTAREA') {
|
|
|
|
return e.value;
|
|
|
|
}
|
|
|
|
|
2020-10-24 01:04:25 +00:00
|
|
|
switch (e.type) {
|
|
|
|
case 'checkbox':
|
|
|
|
case 'radio':
|
|
|
|
return e.checked;
|
|
|
|
|
|
|
|
case 'number':
|
|
|
|
case 'text':
|
|
|
|
case 'url': {
|
|
|
|
const string = e.value;
|
|
|
|
if (Number.parseInt(string, 10).toString() === string) {
|
|
|
|
return Number.parseInt(string, 10);
|
|
|
|
}
|
|
|
|
if (Number.parseFloat(string).toString() === string) {
|
|
|
|
return Number.parseFloat(string);
|
|
|
|
}
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// this callback is for controls whose changes can be applied
|
|
|
|
// immediately, like checkboxs, radioboxes, and selects
|
|
|
|
_onControlChanged(event_) {
|
|
|
|
const { key } = event_.target.dataset;
|
|
|
|
this.remote.savePrefs({
|
|
|
|
[key]: PrefsDialog._getValue(event_.target),
|
|
|
|
});
|
|
|
|
if (key === 'peer-port' || key === 'port-forwarding-enabled') {
|
|
|
|
this._checkPort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_onDialogClosed() {
|
|
|
|
this.dispatchEvent(new Event('closed'));
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the dialog's controls
|
|
|
|
_update(o) {
|
|
|
|
if (!o) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._setBlocklistButtonEnabled(true);
|
|
|
|
|
|
|
|
for (const [key, value] of Object.entries(o)) {
|
|
|
|
for (const element of this.elements.root.querySelectorAll(
|
|
|
|
`[data-key="${key}"]`
|
|
|
|
)) {
|
|
|
|
if (key === 'blocklist-size') {
|
|
|
|
const n = Formatter.number(value);
|
|
|
|
element.innerHTML = `Blocklist has <span class="blocklist-size-number">${n}</span> rules`;
|
|
|
|
setTextContent(this.elements.peers.blocklist_update_button, 'Update');
|
|
|
|
} else {
|
|
|
|
switch (element.type) {
|
|
|
|
case 'checkbox':
|
|
|
|
case 'radio':
|
|
|
|
if (element.checked !== value) {
|
|
|
|
element.checked = value;
|
|
|
|
element.dispatchEvent(new Event('change'));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'text':
|
2022-02-20 19:33:53 +00:00
|
|
|
case 'textarea':
|
2020-10-24 01:04:25 +00:00
|
|
|
case 'url':
|
|
|
|
case 'email':
|
|
|
|
case 'number':
|
|
|
|
case 'search':
|
|
|
|
// don't change the text if the user's editing it.
|
|
|
|
// it's very annoying when that happens!
|
|
|
|
if (
|
|
|
|
// eslint-disable-next-line eqeqeq
|
|
|
|
element.value != value &&
|
|
|
|
element !== document.activeElement
|
|
|
|
) {
|
|
|
|
element.value = value;
|
|
|
|
element.dispatchEvent(new Event('change'));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'select-one':
|
|
|
|
if (element.value !== value) {
|
|
|
|
element.value = value;
|
|
|
|
element.dispatchEvent(new Event('change'));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2022-02-20 19:33:53 +00:00
|
|
|
console.log(element.type);
|
2020-10-24 01:04:25 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
shouldAddedTorrentsStart() {
|
|
|
|
return this.data.elements.root.find('#start-added-torrents')[0].checked;
|
|
|
|
}
|
|
|
|
|
|
|
|
static _createCheckAndLabel(id, text) {
|
|
|
|
const root = document.createElement('div');
|
|
|
|
root.id = id;
|
|
|
|
|
|
|
|
const check = document.createElement('input');
|
|
|
|
check.id = makeUUID();
|
|
|
|
check.type = 'checkbox';
|
|
|
|
root.append(check);
|
|
|
|
|
|
|
|
const label = document.createElement('label');
|
|
|
|
label.textContent = text;
|
|
|
|
label.setAttribute('for', check.id);
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
return { check, label, root };
|
|
|
|
}
|
|
|
|
|
|
|
|
static _enableIfChecked(element, check) {
|
|
|
|
const callback = () => {
|
|
|
|
if (element.tagName === 'INPUT') {
|
|
|
|
setEnabled(element, check.checked);
|
|
|
|
} else {
|
|
|
|
element.classList.toggle('disabled', !check.checked);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
check.addEventListener('change', callback);
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
|
|
|
|
static _createTorrentsPage() {
|
|
|
|
const root = document.createElement('div');
|
|
|
|
root.classList.add('prefs-torrents-page');
|
|
|
|
|
|
|
|
let label = document.createElement('div');
|
|
|
|
label.textContent = 'Downloading';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Download to:';
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
let input = document.createElement('input');
|
|
|
|
input.type = 'text';
|
|
|
|
input.id = makeUUID();
|
|
|
|
input.dataset.key = 'download-dir';
|
|
|
|
label.setAttribute('for', input.id);
|
|
|
|
root.append(input);
|
|
|
|
const download_dir = input;
|
|
|
|
|
|
|
|
let cal = PrefsDialog._createCheckAndLabel(
|
2022-01-27 04:31:02 +00:00
|
|
|
'incomplete-dir-div',
|
|
|
|
'Use temporary folder:'
|
|
|
|
);
|
|
|
|
cal.check.title =
|
|
|
|
'Separate folder to temporarily store downloads until they are complete.';
|
|
|
|
cal.check.dataset.key = 'incomplete-dir-enabled';
|
|
|
|
cal.label.title = cal.check.title;
|
|
|
|
root.append(cal.root);
|
|
|
|
const incomplete_dir_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'text';
|
|
|
|
input.dataset.key = 'incomplete-dir';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const incomplete_dir_input = input;
|
|
|
|
|
2022-01-27 04:31:57 +00:00
|
|
|
cal = PrefsDialog._createCheckAndLabel('autostart-div', 'Start when added');
|
2020-10-24 01:04:25 +00:00
|
|
|
cal.check.dataset.key = 'start-added-torrents';
|
|
|
|
root.append(cal.root);
|
|
|
|
const autostart_check = cal.check;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'suffix-div',
|
|
|
|
`Append "part" to incomplete files' names`
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'rename-partial-files';
|
|
|
|
root.append(cal.root);
|
|
|
|
const suffix_check = cal.check;
|
|
|
|
|
2021-11-15 16:20:07 +00:00
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'download-queue-div',
|
|
|
|
'Download queue size:'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'download-queue-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const download_queue_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'download-queue-size';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const download_queue_input = input;
|
|
|
|
|
2020-10-24 01:04:25 +00:00
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent = 'Seeding';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'stop-ratio-div',
|
|
|
|
'Stop seeding at ratio:'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'seedRatioLimited';
|
|
|
|
root.append(cal.root);
|
|
|
|
const stop_ratio_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
2022-02-13 15:58:59 +00:00
|
|
|
input.min = '0.1';
|
|
|
|
input.step = 'any';
|
2020-10-24 01:04:25 +00:00
|
|
|
input.dataset.key = 'seedRatioLimit';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const stop_ratio_input = input;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'stop-idle-div',
|
|
|
|
'Stop seeding if idle for N mins:'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'idle-seeding-limit-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const stop_idle_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
2022-02-13 15:58:59 +00:00
|
|
|
input.min = '0.1';
|
|
|
|
input.step = 'any';
|
2020-10-24 01:04:25 +00:00
|
|
|
input.dataset.key = 'idle-seeding-limit';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const stop_idle_input = input;
|
|
|
|
|
|
|
|
return {
|
|
|
|
autostart_check,
|
|
|
|
download_dir,
|
2021-11-15 16:20:07 +00:00
|
|
|
download_queue_check,
|
|
|
|
download_queue_input,
|
2022-01-27 04:31:02 +00:00
|
|
|
incomplete_dir_check,
|
|
|
|
incomplete_dir_input,
|
2020-10-24 01:04:25 +00:00
|
|
|
root,
|
|
|
|
stop_idle_check,
|
|
|
|
stop_idle_input,
|
|
|
|
stop_ratio_check,
|
|
|
|
stop_ratio_input,
|
|
|
|
suffix_check,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static _createSpeedPage() {
|
|
|
|
const root = document.createElement('div');
|
|
|
|
root.classList.add('prefs-speed-page');
|
|
|
|
|
|
|
|
let label = document.createElement('div');
|
|
|
|
label.textContent = 'Speed Limits';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
let cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'upload-speed-div',
|
|
|
|
'Upload (kB/s):'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'speed-limit-up-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const upload_speed_check = cal.check;
|
|
|
|
|
|
|
|
let input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'speed-limit-up';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const upload_speed_input = input;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'download-speed-div',
|
|
|
|
'Download (kB/s):'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'speed-limit-down-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const download_speed_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'speed-limit-down';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const download_speed_input = input;
|
|
|
|
|
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent = 'Alternative Speed Limits';
|
|
|
|
label.classList.add('section-label', 'alt-speed-section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent =
|
|
|
|
'Override normal speed limits manually or at scheduled times';
|
|
|
|
label.classList.add('alt-speed-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Upload (kB/s):';
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'alt-speed-up';
|
|
|
|
input.id = makeUUID();
|
|
|
|
label.setAttribute('for', input.id);
|
|
|
|
root.append(input);
|
|
|
|
const alt_upload_speed_input = input;
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Download (kB/s):';
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'alt-speed-down';
|
|
|
|
input.id = makeUUID();
|
|
|
|
label.setAttribute('for', input.id);
|
|
|
|
root.append(input);
|
|
|
|
const alt_download_speed_input = input;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel('alt-times-div', 'Scheduled times');
|
|
|
|
cal.check.dataset.key = 'alt-speed-time-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const alt_times_check = cal.check;
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'From:';
|
|
|
|
PrefsDialog._enableIfChecked(label, cal.check);
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
let select = document.createElement('select');
|
|
|
|
select.id = makeUUID();
|
|
|
|
select.dataset.key = 'alt-speed-time-begin';
|
|
|
|
PrefsDialog._initTimeDropDown(select);
|
|
|
|
label.setAttribute('for', select.id);
|
|
|
|
root.append(select);
|
|
|
|
PrefsDialog._enableIfChecked(select, cal.check);
|
|
|
|
const alt_from_select = select;
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'To:';
|
|
|
|
PrefsDialog._enableIfChecked(label, cal.check);
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
select = document.createElement('select');
|
|
|
|
select.id = makeUUID();
|
|
|
|
select.dataset.key = 'alt-speed-time-end';
|
|
|
|
PrefsDialog._initTimeDropDown(select);
|
|
|
|
label.setAttribute('for', select.id);
|
|
|
|
root.append(select);
|
|
|
|
PrefsDialog._enableIfChecked(select, cal.check);
|
|
|
|
const alt_to_select = select;
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'On days:';
|
|
|
|
PrefsDialog._enableIfChecked(label, cal.check);
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
select = document.createElement('select');
|
|
|
|
select.id = makeUUID();
|
|
|
|
select.dataset.key = 'alt-speed-time-day';
|
|
|
|
PrefsDialog._initDayDropDown(select);
|
|
|
|
label.setAttribute('for', select.id);
|
|
|
|
root.append(select);
|
|
|
|
PrefsDialog._enableIfChecked(select, cal.check);
|
|
|
|
const alt_days_select = select;
|
|
|
|
|
|
|
|
return {
|
|
|
|
alt_days_select,
|
|
|
|
alt_download_speed_input,
|
|
|
|
alt_from_select,
|
|
|
|
alt_times_check,
|
|
|
|
alt_to_select,
|
|
|
|
alt_upload_speed_input,
|
|
|
|
download_speed_check,
|
|
|
|
download_speed_input,
|
|
|
|
root,
|
|
|
|
upload_speed_check,
|
|
|
|
upload_speed_input,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static _createPeersPage() {
|
|
|
|
const root = document.createElement('div');
|
|
|
|
root.classList.add('prefs-peers-page');
|
|
|
|
|
|
|
|
let label = document.createElement('div');
|
|
|
|
label.textContent = 'Connections';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
let cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'max-peers-per-torrent-div',
|
|
|
|
'Max peers per torrent:'
|
|
|
|
);
|
|
|
|
root.append(cal.root);
|
|
|
|
const max_peers_per_torrent_check = cal.check;
|
|
|
|
|
|
|
|
let input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'peer-limit-per-torrent';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const max_peers_per_torrent_input = input;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'max-peers-overall-div',
|
|
|
|
'Max peers overall:'
|
|
|
|
);
|
|
|
|
root.append(cal.root);
|
|
|
|
const max_peers_overall_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'peer-limit-global';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const max_peers_overall_input = input;
|
|
|
|
|
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent = 'Options';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Encryption mode:';
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
const select = document.createElement('select');
|
|
|
|
select.id = makeUUID();
|
|
|
|
select.dataset.key = 'encryption';
|
|
|
|
select.options[0] = new Option('Prefer encryption', 'preferred');
|
|
|
|
select.options[1] = new Option('Allow encryption', 'tolerated');
|
|
|
|
select.options[2] = new Option('Require encryption', 'required');
|
|
|
|
root.append(select);
|
|
|
|
const encryption_select = select;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'use-pex-div',
|
|
|
|
'Use PEX to find more peers'
|
|
|
|
);
|
|
|
|
cal.check.title =
|
|
|
|
"PEX is a tool for exchanging peer lists with the peers you're connected to.";
|
|
|
|
cal.check.dataset.key = 'pex-enabled';
|
|
|
|
cal.label.title = cal.check.title;
|
|
|
|
root.append(cal.root);
|
|
|
|
const pex_check = cal.check;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'use-dht-div',
|
|
|
|
'Use DHT to find more peers'
|
|
|
|
);
|
|
|
|
cal.check.title = 'DHT is a tool for finding peers without a tracker.';
|
|
|
|
cal.check.dataset.key = 'dht-enabled';
|
|
|
|
cal.label.title = cal.check.title;
|
|
|
|
root.append(cal.root);
|
|
|
|
const dht_check = cal.check;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'use-lpd-div',
|
|
|
|
'Use LPD to find more peers'
|
|
|
|
);
|
|
|
|
cal.check.title = 'LPD is a tool for finding peers on your local network.';
|
|
|
|
cal.check.dataset.key = 'lpd-enabled';
|
|
|
|
cal.label.title = cal.check.title;
|
|
|
|
root.append(cal.root);
|
|
|
|
const lpd_check = cal.check;
|
|
|
|
|
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent = 'Blocklist';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'blocklist-enabled-div',
|
|
|
|
'Enable blocklist:'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'blocklist-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const blocklist_enabled_check = cal.check;
|
|
|
|
|
|
|
|
input = document.createElement('input');
|
|
|
|
input.type = 'url';
|
|
|
|
input.value = 'http://www.example.com/blocklist';
|
|
|
|
input.dataset.key = 'blocklist-url';
|
|
|
|
root.append(input);
|
|
|
|
PrefsDialog._enableIfChecked(input, cal.check);
|
|
|
|
const blocklist_url_input = input;
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Blocklist has {n} rules';
|
|
|
|
label.dataset.key = 'blocklist-size';
|
|
|
|
label.classList.add('blocklist-size-label');
|
|
|
|
PrefsDialog._enableIfChecked(label, cal.check);
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
const button = document.createElement('button');
|
|
|
|
button.classList.add('blocklist-update-button');
|
|
|
|
button.textContent = 'Update';
|
|
|
|
root.append(button);
|
|
|
|
PrefsDialog._enableIfChecked(button, cal.check);
|
|
|
|
const blocklist_update_button = button;
|
|
|
|
|
|
|
|
return {
|
|
|
|
blocklist_enabled_check,
|
|
|
|
blocklist_update_button,
|
|
|
|
blocklist_url_input,
|
|
|
|
dht_check,
|
|
|
|
encryption_select,
|
|
|
|
lpd_check,
|
|
|
|
max_peers_overall_check,
|
|
|
|
max_peers_overall_input,
|
|
|
|
max_peers_per_torrent_check,
|
|
|
|
max_peers_per_torrent_input,
|
|
|
|
pex_check,
|
|
|
|
root,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static _createNetworkPage() {
|
|
|
|
const root = document.createElement('div');
|
|
|
|
root.classList.add('prefs-network-page');
|
|
|
|
|
|
|
|
let label = document.createElement('div');
|
|
|
|
label.textContent = 'Listening Port';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Peer listening port:';
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
const input = document.createElement('input');
|
|
|
|
input.type = 'number';
|
|
|
|
input.dataset.key = 'peer-port';
|
|
|
|
input.id = makeUUID();
|
|
|
|
label.setAttribute('for', input.id);
|
|
|
|
root.append(input);
|
|
|
|
const port_input = input;
|
|
|
|
|
|
|
|
const port_status_div = document.createElement('div');
|
|
|
|
port_status_div.classList.add('port-status');
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.textContent = 'Port is';
|
|
|
|
port_status_div.append(label);
|
|
|
|
const port_status_label = document.createElement('label');
|
|
|
|
port_status_label.textContent = '?';
|
|
|
|
port_status_label.classList.add('port-status-label');
|
|
|
|
port_status_div.append(port_status_label);
|
|
|
|
root.append(port_status_div);
|
|
|
|
|
|
|
|
let cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'randomize-port',
|
|
|
|
'Randomize port on launch'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'peer-port-random-on-start';
|
|
|
|
root.append(cal.root);
|
|
|
|
const random_port_check = cal.check;
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'port-forwarding',
|
|
|
|
'Use port forwarding from my router'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'port-forwarding-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const port_forwarding_check = cal.check;
|
|
|
|
|
|
|
|
label = document.createElement('div');
|
|
|
|
label.textContent = 'Options';
|
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
|
|
|
cal = PrefsDialog._createCheckAndLabel(
|
|
|
|
'utp-enabled',
|
|
|
|
'Enable uTP for peer communication'
|
|
|
|
);
|
|
|
|
cal.check.dataset.key = 'utp-enabled';
|
|
|
|
root.append(cal.root);
|
|
|
|
const utp_check = cal.check;
|
|
|
|
|
2022-02-20 17:54:20 +00:00
|
|
|
label = document.createElement('div');
|
2022-02-20 19:33:53 +00:00
|
|
|
label.textContent = 'Default Public Trackers';
|
2022-02-20 17:54:20 +00:00
|
|
|
label.classList.add('section-label');
|
|
|
|
root.append(label);
|
|
|
|
|
2022-02-20 19:33:53 +00:00
|
|
|
const tracker_labels = [
|
|
|
|
'Trackers to use on all public torrents.',
|
|
|
|
'To add a backup URL, add it on the next line after a primary URL.',
|
|
|
|
'To add a new primary URL, add it after a blank line.',
|
|
|
|
];
|
|
|
|
for (const text of tracker_labels) {
|
|
|
|
label = document.createElement('label');
|
|
|
|
label.classList.add('default-trackers-label');
|
|
|
|
label.textContent = text;
|
|
|
|
label.setAttribute('for', 'default-trackers');
|
|
|
|
root.append(label);
|
|
|
|
}
|
2022-02-20 17:54:20 +00:00
|
|
|
|
|
|
|
const textarea = document.createElement('textarea');
|
|
|
|
textarea.dataset.key = 'default-trackers';
|
|
|
|
textarea.id = 'default-trackers';
|
|
|
|
root.append(textarea);
|
|
|
|
const default_trackers_textarea = textarea;
|
|
|
|
|
2020-10-24 01:04:25 +00:00
|
|
|
return {
|
2022-02-20 17:54:20 +00:00
|
|
|
default_trackers_textarea,
|
2020-10-24 01:04:25 +00:00
|
|
|
port_forwarding_check,
|
|
|
|
port_input,
|
|
|
|
port_status_label,
|
|
|
|
random_port_check,
|
|
|
|
root,
|
|
|
|
utp_check,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static _create() {
|
|
|
|
const pages = {
|
|
|
|
network: PrefsDialog._createNetworkPage(),
|
|
|
|
peers: PrefsDialog._createPeersPage(),
|
|
|
|
speed: PrefsDialog._createSpeedPage(),
|
|
|
|
torrents: PrefsDialog._createTorrentsPage(),
|
|
|
|
};
|
|
|
|
|
|
|
|
const elements = createTabsContainer('prefs-dialog', [
|
|
|
|
['prefs-tab-torrent', pages.torrents.root],
|
|
|
|
['prefs-tab-speed', pages.speed.root],
|
|
|
|
['prefs-tab-peers', pages.peers.root],
|
|
|
|
['prefs-tab-network', pages.network.root],
|
|
|
|
]);
|
|
|
|
|
|
|
|
return { ...elements, ...pages };
|
|
|
|
}
|
|
|
|
|
|
|
|
constructor(session_manager, remote) {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.closed = false;
|
|
|
|
this.session_manager = session_manager;
|
|
|
|
this.remote = remote;
|
|
|
|
this.update_soon = () =>
|
|
|
|
this._update(this.session_manager.session_properties);
|
|
|
|
|
|
|
|
this.elements = PrefsDialog._create();
|
|
|
|
this.elements.peers.blocklist_update_button.addEventListener(
|
|
|
|
'click',
|
|
|
|
(event_) => {
|
|
|
|
setTextContent(event_.target, 'Updating blocklist...');
|
|
|
|
this.remote.updateBlocklist();
|
|
|
|
this._setBlocklistButtonEnabled(false);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
this.outside = new OutsideClickListener(this.elements.root);
|
|
|
|
this.outside.addEventListener('click', () => this.close());
|
|
|
|
|
|
|
|
Object.seal(this);
|
|
|
|
|
|
|
|
// listen for user input
|
|
|
|
const on_change = this._onControlChanged.bind(this);
|
|
|
|
const walk = (o) => {
|
|
|
|
for (const element of Object.values(o)) {
|
|
|
|
if (element.tagName === 'INPUT') {
|
|
|
|
switch (element.type) {
|
|
|
|
case 'checkbox':
|
|
|
|
case 'radio':
|
|
|
|
case 'number':
|
|
|
|
case 'text':
|
|
|
|
case 'url':
|
|
|
|
element.addEventListener('change', on_change);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.trace(`unhandled input: ${element.type}`);
|
|
|
|
break;
|
|
|
|
}
|
2022-02-20 17:54:20 +00:00
|
|
|
} else if (element.tagName === 'TEXTAREA') {
|
|
|
|
element.addEventListener('change', on_change);
|
2020-10-24 01:04:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
walk(this.elements.network);
|
|
|
|
walk(this.elements.peers);
|
|
|
|
walk(this.elements.speed);
|
|
|
|
walk(this.elements.torrents);
|
|
|
|
|
|
|
|
this.session_manager.addEventListener('session-change', this.update_soon);
|
|
|
|
this.update_soon();
|
|
|
|
|
|
|
|
document.body.append(this.elements.root);
|
|
|
|
}
|
|
|
|
|
|
|
|
close() {
|
|
|
|
if (!this.closed) {
|
|
|
|
this.outside.stop();
|
|
|
|
this.session_manager.removeEventListener(
|
|
|
|
'session-change',
|
|
|
|
this.update_soon
|
|
|
|
);
|
|
|
|
this.elements.root.remove();
|
|
|
|
dispatchEvent(new Event('close'));
|
|
|
|
for (const key of Object.keys(this)) {
|
|
|
|
this[key] = null;
|
|
|
|
}
|
|
|
|
this.closed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|