1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-01-30 19:03:04 +00:00

chore: bump web client deps (#1698)

* chore: bump web client dependencies
This commit is contained in:
Charles Kerr 2021-05-19 08:43:46 -05:00 committed by GitHub
parent 95a45b0bad
commit d2473f4c2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 2148 additions and 2719 deletions

View file

@ -119,7 +119,8 @@ module.exports = {
"sonarjs/no-duplicate-string": "off",
"sort-keys": "error",
"strict": "error",
'unicorn/consistent-function-scoping': 'off',
"unicorn/consistent-function-scoping": "off",
"unicorn/no-array-reduce": "off",
"unicorn/no-fn-reference-in-iterator": "off",
"unicorn/no-null": "off",
"unicorn/no-reduce": "off",

View file

@ -18,36 +18,36 @@
"lint:stylelint:fix": "stylelint --fix style/*scss"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/eslint-parser": "^7.11.5",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"css-loader": "^4.3.0",
"eslint": "^7.11.0",
"eslint-plugin-sonarjs": "^0.5.0",
"eslint-plugin-unicorn": "^23.0.0",
"file-loader": "^6.1.0",
"@babel/core": "^7.14.3",
"@babel/eslint-parser": "^7.14.3",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"css-loader": "^5.2.4",
"css-minimizer-webpack-plugin": "^3.0.0",
"eslint": "^7.26.0",
"eslint-plugin-sonarjs": "^0.7.0",
"eslint-plugin-unicorn": "^32.0.1",
"file-loader": "^6.2.0",
"img-optimize-loader": "^1.0.7",
"mini-css-extract-plugin": "^0.11.3",
"node-sass": "^4.14.1",
"mini-css-extract-plugin": "^1.6.0",
"node-sass": "^6.0.0",
"npm-run-all": "^4.1.5",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"prettier": "^2.1.2",
"sass": "^1.26.11",
"sass-loader": "^10.0.2",
"style-loader": "^1.2.1",
"stylelint": "^13.7.1",
"prettier": "^2.3.0",
"sass": "^1.32.13",
"sass-loader": "^11.1.1",
"style-loader": "^2.0.0",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-primer": "^9.2.1",
"stylelint-config-sass-guidelines": "^7.1.0",
"stylelint-config-standard": "^20.0.0",
"svgo": "^1.3.2",
"svgo-loader": "^2.2.1",
"terser-webpack-plugin": "^4.2.2",
"url-loader": "^4.1.0",
"webpack": "^4.44.2",
"webpack-bundle-analyzer": "^3.9.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0"
"stylelint-config-primer": "^11.0.1",
"stylelint-config-sass-guidelines": "^8.0.0",
"stylelint-config-standard": "^22.0.0",
"svgo": "^2.3.0",
"svgo-loader": "^3.0.0",
"terser-webpack-plugin": "^5.1.2",
"url-loader": "^4.1.1",
"webpack": "^5.37.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"lodash.isequal": "^4.5.0"

File diff suppressed because one or more lines are too long

View file

@ -137,11 +137,12 @@ export class ActionManager extends EventTarget {
}
static _recount(selected, nonselected) {
const test = (tor) => tor.isStopped();
const total = selected.length + nonselected.length;
const selected_paused = selected.filter(test).length;
const selected_paused = selected.filter((tor) => tor.isStopped()).length;
const selected_active = selected.length - selected_paused;
const nonselected_paused = nonselected.filter(test).length;
const nonselected_paused = nonselected.filter((tor) =>
tor.isStopped()
).length;
const nonselected_active = nonselected.length - nonselected_paused;
const paused = selected_paused + nonselected_paused;
const active = selected_active + nonselected_active;

View file

@ -30,15 +30,21 @@ const fmt_MBps = new Intl.NumberFormat(current_locale, {
unit: 'megabyte-per-second',
});
export class Formatter {
static countString(msgid, msgid_plural, n) {
export const Formatter = {
/** Round a string of a number to a specified number of decimal places */
_toTruncFixed(number, places) {
const returnValue = Math.floor(number * 10 ** places) / 10 ** places;
return returnValue.toFixed(places);
},
countString(msgid, msgid_plural, n) {
return `${this.number(n)} ${this.ngettext(msgid, msgid_plural, n)}`;
}
},
// Formats the a memory size into a human-readable string
// @param {Number} bytes the filesize in bytes
// @return {String} human-readable string
static mem(bytes) {
mem(bytes) {
if (bytes < 0) {
return 'Unknown';
}
@ -55,22 +61,26 @@ export class Formatter {
}
return 'E2BIG';
}
},
static ngettext(msgid, msgid_plural, n) {
ngettext(msgid, msgid_plural, n) {
return plural_rules.select(n) === 'one' ? msgid : msgid_plural;
}
},
number(number) {
return number_format.format(number);
},
// format a percentage to a string
static percentString(x) {
percentString(x) {
const decimal_places = x < 100 ? 1 : 0;
return this._toTruncFixed(x, decimal_places);
}
},
/*
* Format a ratio to a string
*/
static ratioString(x) {
ratioString(x) {
if (x === -1) {
return 'None';
}
@ -78,32 +88,32 @@ export class Formatter {
return '&infin;';
}
return this.percentString(x);
}
},
/**
* Formats the a disk capacity or file size into a human-readable string
* @param {Number} bytes the filesize in bytes
* @return {String} human-readable string
*/
static size(bytes) {
size(bytes) {
return this.mem(bytes);
}
},
static speed(KBps) {
speed(KBps) {
return KBps < 999.95 ? fmt_kBps.format(KBps) : fmt_MBps.format(KBps / 1000);
}
},
static speedBps(Bps) {
speedBps(Bps) {
return this.speed(this.toKBps(Bps));
}
},
static timeInterval(seconds) {
const days = Math.floor(seconds / 86400);
timeInterval(seconds) {
const days = Math.floor(seconds / 86_400);
if (days) {
return this.countString('day', 'days', days);
}
const hours = Math.floor((seconds % 86400) / 3600);
const hours = Math.floor((seconds % 86_400) / 3600);
if (hours) {
return this.countString('hour', 'hours', hours);
}
@ -115,9 +125,9 @@ export class Formatter {
seconds = Math.floor(seconds % 60);
return this.countString('second', 'seconds', seconds);
}
},
static timestamp(seconds) {
timestamp(seconds) {
if (!seconds) {
return 'N/A';
}
@ -168,19 +178,9 @@ export class Formatter {
time = [hours, minutes, seconds].join(':');
return [date, time, period].join(' ');
}
},
static toKBps(Bps) {
toKBps(Bps) {
return Math.floor(Bps / kilo);
}
static number(number) {
return number_format.format(number);
}
/** Round a string of a number to a specified number of decimal places */
static _toTruncFixed(number, places) {
const returnValue = Math.floor(number * 10 ** places) / 10 ** places;
return returnValue.toFixed(places);
}
}
},
};

View file

@ -150,7 +150,7 @@ export class Inspector extends EventTarget {
const thead = document.createElement('thead');
const tr = document.createElement('tr');
const names = ['', 'Up', 'Down', 'Done', 'Status', 'Address', 'Client'];
names.forEach((name, index) => {
for (const [index, name] of names.entries()) {
const th = document.createElement('th');
const classname = peer_column_classes[index];
if (classname === 'encryption') {
@ -159,7 +159,7 @@ export class Inspector extends EventTarget {
th.classList.add(classname);
setTextContent(th, name);
tr.append(th);
});
}
const tbody = document.createElement('tbody');
thead.append(tr);
table.append(thead);
@ -201,9 +201,13 @@ export class Inspector extends EventTarget {
// update the inspector when a selected torrent's data changes.
const key = 'dataChanged';
const callback = this.torrent_listener;
this.torrents.forEach((t) => t.removeEventListener(key, callback));
for (const t of this.torrents) {
t.removeEventListener(key, callback);
}
this.torrents = [...torrents];
this.torrents.forEach((t) => t.addEventListener(key, callback));
for (const t of this.torrents) {
t.addEventListener(key, callback);
}
this._refreshTorrents();
this._updateCurrentPage();
@ -228,8 +232,8 @@ export class Inspector extends EventTarget {
}
_updateCurrentPage() {
const { elements } = this;
switch (this.current_page) {
const { current_page, elements } = this;
switch (current_page) {
case elements.files.root:
this._updateFiles();
break;
@ -244,7 +248,7 @@ export class Inspector extends EventTarget {
break;
default:
console.warn('unexpected page');
console.log(this.current_page);
console.log(current_page);
}
}
@ -254,8 +258,7 @@ export class Inspector extends EventTarget {
const unknown = 'Unknown';
const fmt = Formatter;
const now = Date.now();
const { torrents } = this;
const e = this.elements;
const { elements: e, torrents } = this;
const sizeWhenDone = torrents.reduce(
(accumulator, t) => accumulator + t.getSizeWhenDone(),
0
@ -502,7 +505,7 @@ export class Inspector extends EventTarget {
const date = get(torrents[0]);
const mixed_date = !torrents.every((t) => get(t) === date);
const empty_creator = !creator || !creator.length;
const empty_creator = !creator || creator.length === 0;
const empty_date = !date;
if (mixed_creator || mixed_date) {
string = mixed;
@ -557,8 +560,8 @@ export class Inspector extends EventTarget {
_updatePeers() {
const fmt = Formatter;
const { torrents } = this;
const { tbody } = this.elements.peers;
const { elements, torrents } = this;
const { tbody } = elements.peers;
const cell_setters = [
(peer, td) => {
@ -598,12 +601,12 @@ export class Inspector extends EventTarget {
for (const peer of tor.getPeers()) {
const tr = document.createElement('tr');
tr.classList.add('peer-row');
cell_setters.forEach((setter, index) => {
for (const [index, setter] of cell_setters.entries()) {
const td = document.createElement('td');
td.classList.add(peer_column_classes[index]);
setter(peer, td);
tr.append(td);
});
}
rows.push(tr);
}
@ -624,7 +627,7 @@ export class Inspector extends EventTarget {
case Torrent._TrackerWaiting: {
const timeUntilAnnounce = Math.max(
0,
tracker.nextAnnounceTime - new Date().getTime() / 1000
tracker.nextAnnounceTime - Date.now() / 1000
);
return `Next announce in ${Formatter.timeInterval(timeUntilAnnounce)}`;
}
@ -706,7 +709,7 @@ export class Inspector extends EventTarget {
rows.push(title);
}
tor.getTrackers().forEach((tracker, index) => {
for (const [index, tracker] of tor.getTrackers().entries()) {
const announceState = Inspector.getAnnounceState(tracker);
const lastAnnounceStatusHash = Inspector.lastAnnounceStatus(tracker);
const lastScrapeStatusHash = Inspector.lastScrapeStatus(tracker);
@ -773,7 +776,7 @@ export class Inspector extends EventTarget {
tier_div.append(element);
rows.push(tier_div);
});
}
}
// TODO: modify instead of rebuilding wholesale?
@ -836,7 +839,7 @@ export class Inspector extends EventTarget {
file_indices: [],
};
tor.getFiles().forEach((file, index) => {
for (const [index, file] of tor.getFiles().entries()) {
const { name } = file;
const tokens = name.split('/');
let walk = tree;
@ -856,7 +859,7 @@ export class Inspector extends EventTarget {
walk.file_index = index;
delete walk.children;
leaves.push(walk);
});
}
for (const leaf of leaves) {
const { file_index } = leaf;
@ -901,7 +904,7 @@ export class Inspector extends EventTarget {
_updateFiles() {
const { list } = this.elements.files;
const { torrents } = this;
const { file_rows, file_torrent, file_torrent_n, torrents } = this;
// only show one torrent at a time
if (torrents.length !== 1) {
@ -911,7 +914,7 @@ export class Inspector extends EventTarget {
const [tor] = torrents;
const n = tor.getFiles().length;
if (tor !== this.file_torrent || n !== this.file_torrent_n) {
if (tor !== file_torrent || n !== file_torrent_n) {
// rebuild the file list...
this._clearFileList();
this.file_torrent = tor;
@ -923,7 +926,9 @@ export class Inspector extends EventTarget {
list.append(fragment);
} else {
// ...refresh the already-existing file list
this.file_rows.forEach((row) => row.refresh());
for (const row of file_rows) {
row.refresh();
}
}
}
}

View file

@ -53,8 +53,8 @@ export class OpenDialog extends EventTarget {
}
_onConfirm() {
const { remote } = this;
const { file_input, folder_input, start_input, url_input } = this.elements;
const { controller, elements, remote } = this;
const { file_input, folder_input, start_input, url_input } = elements;
const paused = !start_input.checked;
const destination = folder_input.value.trim();
@ -79,7 +79,7 @@ export class OpenDialog extends EventTarget {
remote.sendRequest(o, (response) => {
if (response.result !== 'success') {
alert(`Error adding "${file.name}": ${response.result}`);
this.controller.setCurrentPopup(
controller.setCurrentPopup(
new AlertDialog({
heading: `Error adding "${file.name}"`,
message: response.result,
@ -93,7 +93,7 @@ export class OpenDialog extends EventTarget {
let url = url_input.value.trim();
if (url.length > 0) {
if (url.match(/^[\da-f]{40}$/i)) {
if (/^[\da-f]{40}$/i.test(url)) {
url = `magnet:?xt=urn:btih:${url}`;
}
const o = {
@ -107,7 +107,7 @@ export class OpenDialog extends EventTarget {
console.log(o);
remote.sendRequest(o, (payload, response) => {
if (response.result !== 'success') {
this.controller.setCurrentPopup(
controller.setCurrentPopup(
new AlertDialog({
heading: `Error adding "${url}"`,
message: response.result,

View file

@ -318,7 +318,7 @@ export class OverflowMenu extends EventTarget {
select.addEventListener('change', (event_) => {
const { value } = event_.target;
console.log(event_);
if (event_.target.value === unlimited) {
if (value === unlimited) {
this.remote.savePrefs({ [RPC._UpSpeedLimited]: false });
} else {
this.remote.savePrefs({
@ -361,7 +361,7 @@ export class OverflowMenu extends EventTarget {
select.addEventListener('change', (event_) => {
const { value } = event_.target;
console.log(event_);
if (event_.target.value === unlimited) {
if (value === unlimited) {
this.remote.savePrefs({ [RPC._DownSpeedLimited]: false });
} else {
this.remote.savePrefs({
@ -460,7 +460,8 @@ export class OverflowMenu extends EventTarget {
e.textContent = 'Source Code';
options.append(e);
Object.values(actions).forEach(this._updateElement.bind(this));
this._updateElement = this._updateElement.bind(this);
return { actions, elements, root };
}
}

View file

@ -66,6 +66,7 @@ export class Prefs extends EventTarget {
static _setCookie(key, value) {
const date = new Date();
date.setFullYear(date.getFullYear() + 1);
// eslint-disable-next-line unicorn/no-document-cookie
document.cookie = `${key}=${value}; SameSite=Strict; expires=${date.toGMTString()}; path=/`;
}
@ -80,7 +81,7 @@ export class Prefs extends EventTarget {
if (value === 'false') {
return false;
}
if (value.match(/^\d+$/)) {
if (/^\d+$/.test(value)) {
return Number.parseInt(value, 10);
}
return value;

View file

@ -246,7 +246,7 @@ export class Remote {
);
}
addTorrentByUrl(url, options) {
if (url.match(/^[\da-f]{40}$/i)) {
if (/^[\da-f]{40}$/i.test(url)) {
url = `magnet:?xt=urn:btih:${url}`;
}
const o = {

View file

@ -38,12 +38,12 @@ export class RemoveDialog extends EventTarget {
}
_onConfirm() {
const { torrents } = this.options;
const { remote, torrents, trash } = this.options;
if (torrents.length > 0) {
if (this.options.trash) {
this.options.remote.removeTorrentsAndData(torrents);
if (trash) {
remote.removeTorrentsAndData(torrents);
} else {
this.options.remote.removeTorrents(torrents);
remote.removeTorrents(torrents);
}
}
@ -64,13 +64,13 @@ export class RemoveDialog extends EventTarget {
static _createMessage(options) {
let heading = null;
let message = null;
const { torrents } = options;
const { torrents, trash } = options;
const [torrent] = torrents;
if (options.trash && torrents.length === 1) {
if (trash && torrents.length === 1) {
heading = `Remove ${torrent.getName()} and delete data?`;
message =
'All data downloaded for this torrent will be deleted. Are you sure you want to remove it?';
} else if (options.trash) {
} else if (trash) {
heading = `Remove ${torrents.length} transfers and delete data?`;
message =
'All data downloaded for these torrents will be deleted. Are you sure you want to remove them?';

View file

@ -72,14 +72,14 @@ export class StatisticsDialog extends EventTarget {
static _create() {
const elements = createDialogContainer('statistics-dialog');
const { workarea } = elements;
elements.confirm.remove();
elements.dismiss.textContent = 'Close';
const { confirm, dismiss, heading, root, workarea } = elements;
confirm.remove();
dismiss.textContent = 'Close';
delete elements.confirm;
const heading_text = 'Statistics';
elements.root.setAttribute('aria-label', heading_text);
elements.heading.textContent = heading_text;
root.setAttribute('aria-label', heading_text);
heading.textContent = heading_text;
const labels = ['Uploaded:', 'Downloaded:', 'Ratio:', 'Running time:'];
let section = createInfoSection('Current session', labels);

View file

@ -11,8 +11,21 @@ import { Formatter } from './formatter.js';
import { Torrent } from './torrent.js';
import { setTextContent } from './utils.js';
class TorrentRendererHelper {
static getProgressInfo(controller, t) {
const TorrentRendererHelper = {
formatDL: (t) => {
return `${Formatter.speedBps(t.getDownloadSpeed())}`;
},
formatETA: (t) => {
const eta = t.getETA();
if (eta < 0 || eta >= 999 * 60 * 60) {
return '';
}
return `ETA: ${Formatter.timeInterval(eta)}`;
},
formatUL: (t) => {
return `${Formatter.speedBps(t.getUploadSpeed())}`;
},
getProgressInfo: (controller, t) => {
const status = t.getStatus();
const classList = ['torrent-progress-bar'];
let percent = null;
@ -46,29 +59,14 @@ class TorrentRendererHelper {
classList,
percent,
};
}
},
static renderProgressbar(controller, t, progressbar) {
renderProgressbar: (controller, t, progressbar) => {
const info = TorrentRendererHelper.getProgressInfo(controller, t);
progressbar.className = info.classList.join(' ');
progressbar.style['background-size'] = `${info.percent}% 100%, 100% 100%`;
}
static formatUL(t) {
return `${Formatter.speedBps(t.getUploadSpeed())}`;
}
static formatDL(t) {
return `${Formatter.speedBps(t.getDownloadSpeed())}`;
}
static formatETA(t) {
const eta = t.getETA();
if (eta < 0 || eta >= 999 * 60 * 60) {
return '';
}
return `ETA: ${Formatter.timeInterval(eta)}`;
}
}
},
};
///

View file

@ -256,9 +256,9 @@ export class Transmission extends EventTarget {
this.prefs.addEventListener('change', ({ key, value }) =>
this._onPrefChanged(key, value)
);
this.prefs
.entries()
.forEach(([key, value]) => this._onPrefChanged(key, value));
for (const [key, value] of this.prefs.entries()) {
this._onPrefChanged(key, value);
}
}
loadDaemonPrefs() {
@ -419,9 +419,9 @@ export class Transmission extends EventTarget {
_dispatchSelectionChanged() {
const nonselected = [];
const selected = [];
this._rows.forEach((r) =>
(r.isSelected() ? selected : nonselected).push(r.getTorrent())
);
for (const r of this._rows) {
(r.isSelected() ? selected : nonselected).push(r.getTorrent());
}
const event = new Event('torrent-selection-changed');
event.nonselected = nonselected;
@ -455,7 +455,7 @@ export class Transmission extends EventTarget {
// Process key events
_keyDown(event_) {
const { keyCode } = event_;
const { ctrlKey, keyCode, metaKey, shiftKey, target } = event_;
// look for a shortcut
const aria_keys = Transmission._createKeyShortcutFromKeyboardEvent(event_);
@ -474,19 +474,14 @@ export class Transmission extends EventTarget {
}
const any_popup_active = document.querySelector('.popup:not(.hidden)');
const is_input_focused = event_.target.matches('input');
const is_input_focused = target.matches('input');
const rows = this._rows;
// Some shortcuts can only be used if the following conditions are met:
// 1. when no input fields are focused
// 2. when no other dialogs are visible
// 3. when the meta or ctrl key isn't pressed (i.e. opening dev tools shouldn't trigger the info panel)
if (
!is_input_focused &&
!any_popup_active &&
!event_.metaKey &&
!event_.ctrlKey
) {
if (!is_input_focused && !any_popup_active && !metaKey && !ctrlKey) {
const shift_key = keyCode === 16; // shift key pressed
const up_key = keyCode === 38; // up key pressed
const dn_key = keyCode === 40; // down key pressed
@ -520,7 +515,7 @@ export class Transmission extends EventTarget {
this._deselectRow(rows[last]);
}
} else {
if (event_.shiftKey) {
if (shiftKey) {
this._selectRange(r);
} else {
this._setSelectedRow(r);
@ -582,12 +577,13 @@ export class Transmission extends EventTarget {
const type = event_.data.Transfer.types
.filter((t) => ['text/uri-list', 'text/plain'].contains(t))
.pop();
event_.dataTransfer
for (const uri of event_.dataTransfer
.getData(type)
.split('\n')
.map((string) => string.trim())
.filter((string) => Transmission._isValidURL(string))
.forEach((uri) => this.remote.addTorrentByUrl(uri, paused));
.filter((string) => Transmission._isValidURL(string))) {
this.remote.addTorrentByUrl(uri, paused);
}
event_.preventDefault();
return false;
@ -632,9 +628,9 @@ export class Transmission extends EventTarget {
const keys = table.shift();
const o = {};
for (const row of table) {
keys.forEach((key, index) => {
for (const [index, key] of keys.entries()) {
o[key] = row[index];
});
}
const { id } = o;
let t = this._torrents[id];
if (t) {
@ -656,10 +652,11 @@ export class Transmission extends EventTarget {
if (needinfo.length > 0) {
// whee, new torrents! get their initial information.
const more_fields = ['id'].concat(
Torrent.Fields.Metadata,
Torrent.Fields.Stats
);
const more_fields = [
'id',
...Torrent.Fields.Metadata,
...Torrent.Fields.Stats,
];
this.updateTorrents(needinfo, more_fields);
this.refilterSoon();
}
@ -691,12 +688,12 @@ TODO: fix this when notifications get fixed
*/
refreshTorrents() {
const fields = ['id'].concat(Torrent.Fields.Stats);
const fields = ['id', ...Torrent.Fields.Stats];
this.updateTorrents('recently-active', fields);
}
_initializeTorrents() {
const fields = ['id'].concat(Torrent.Fields.Metadata, Torrent.Fields.Stats);
const fields = ['id', ...Torrent.Fields.Metadata, ...Torrent.Fields.Stats];
this.updateTorrents(null, fields);
}
@ -910,7 +907,9 @@ TODO: fix this when notifications get fixed
this.prefs.sort_mode,
this.prefs.sort_direction
);
torrents.forEach((tor, index) => (rows[index] = id2row[tor.getId()]));
for (const [index, tor] of torrents.entries()) {
rows[index] = id2row[tor.getId()];
}
}
_refilter(rebuildEverything) {
@ -1036,13 +1035,11 @@ TODO: fix this when notifications get fixed
this.dirtyTorrents.clear();
// set the odd/even property
rows
.map((row) => row.getElement())
.forEach((e, index) => {
const even = index % 2 === 0;
e.classList.toggle('even', even);
e.classList.toggle('odd', !even);
});
for (const [index, e] of rows.map((row) => row.getElement()).entries()) {
const even = index % 2 === 0;
e.classList.toggle('even', even);
e.classList.toggle('odd', !even);
}
this._updateStatusbar();
if (

View file

@ -9,26 +9,9 @@
import isEqual from 'lodash.isequal';
export class Utils {
/**
* Checks to see if the content actually changed before poking the DOM.
*/
static setInnerHTML(e, html) {
if (!e) {
return;
}
/* innerHTML is listed as a string, but the browser seems to change it.
* For example, "&infin;" gets changed to "∞" somewhere down the line.
* So, let's use an arbitrary different field to test our state... */
if (e.currentHTML !== html) {
e.currentHTML = html;
e.innerHTML = html;
}
}
export const Utils = {
/** Given a numerator and denominator, return a ratio string */
static ratio(numerator, denominator) {
ratio(numerator, denominator) {
let result = Math.floor((100 * numerator) / denominator) / 100;
// check for special cases
@ -42,8 +25,25 @@ export class Utils {
}
return result;
}
}
},
/**
* Checks to see if the content actually changed before poking the DOM.
*/
setInnerHTML(e, html) {
if (!e) {
return;
}
/* innerHTML is listed as a string, but the browser seems to change it.
* For example, "&infin;" gets changed to "∞" somewhere down the line.
* So, let's use an arbitrary different field to test our state... */
if (e.currentHTML !== html) {
e.currentHTML = html;
e.innerHTML = html;
}
},
};
export function createTabsContainer(id, tabs, callback) {
const root = document.createElement('div');

View file

@ -1,7 +1,7 @@
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack');
@ -45,11 +45,7 @@ const config = {
optimization: {
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],
}
})
new CssMinimizerPlugin(),
],
},
output: {

File diff suppressed because it is too large Load diff