Add eslint and style fix

This commit is contained in:
Alex Ling 2022-08-19 11:40:41 +00:00
parent e4af194d0c
commit 28c098a56e
19 changed files with 1795 additions and 1677 deletions

11
.eslintrc.js Normal file
View File

@ -0,0 +1,11 @@
module.exports = {
parser: '@babel/eslint-parser',
parserOptions: { requireConfigFile: false },
plugins: ['prettier'],
rules: {
eqeqeq: ['error', 'always'],
'object-shorthand': ['error', 'always'],
'prettier/prettier': 'error',
'no-var': 'error',
},
};

6
.prettierrc Normal file
View File

@ -0,0 +1,6 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2
}

View File

@ -5,12 +5,16 @@ const minifyCss = require('gulp-minify-css');
const less = require('gulp-less'); const less = require('gulp-less');
gulp.task('copy-img', () => { gulp.task('copy-img', () => {
return gulp.src('node_modules/uikit/src/images/backgrounds/*.svg') return gulp
.src('node_modules/uikit/src/images/backgrounds/*.svg')
.pipe(gulp.dest('public/img')); .pipe(gulp.dest('public/img'));
}); });
gulp.task('copy-font', () => { gulp.task('copy-font', () => {
return gulp.src('node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff**') return gulp
.src(
'node_modules/@fortawesome/fontawesome-free/webfonts/fa-solid-900.woff**',
)
.pipe(gulp.dest('public/webfonts')); .pipe(gulp.dest('public/webfonts'));
}); });
@ -19,48 +23,59 @@ gulp.task('node-modules-copy', gulp.parallel('copy-img', 'copy-font'));
// Compile less // Compile less
gulp.task('less', () => { gulp.task('less', () => {
return gulp.src([ return gulp
'public/css/mango.less', .src(['public/css/mango.less', 'public/css/tags.less'])
'public/css/tags.less'
])
.pipe(less()) .pipe(less())
.pipe(gulp.dest('public/css')); .pipe(gulp.dest('public/css'));
}); });
// Transpile and minify JS files and output to dist // Transpile and minify JS files and output to dist
gulp.task('babel', () => { gulp.task('babel', () => {
return gulp.src(['public/js/*.js', '!public/js/*.min.js']) return gulp
.pipe(babel({ .src(['public/js/*.js', '!public/js/*.min.js'])
.pipe(
babel({
presets: [ presets: [
['@babel/preset-env', { [
targets: '>0.25%, not dead, ios>=9' '@babel/preset-env',
}] {
targets: '>0.25%, not dead, ios>=9',
},
], ],
})) ],
.pipe(minify({ }),
)
.pipe(
minify({
removeConsole: true, removeConsole: true,
builtIns: false builtIns: false,
})) }),
)
.pipe(gulp.dest('dist/js')); .pipe(gulp.dest('dist/js'));
}); });
// Minify CSS and output to dist // Minify CSS and output to dist
gulp.task('minify-css', () => { gulp.task('minify-css', () => {
return gulp.src('public/css/*.css') return gulp
.src('public/css/*.css')
.pipe(minifyCss()) .pipe(minifyCss())
.pipe(gulp.dest('dist/css')); .pipe(gulp.dest('dist/css'));
}); });
// Copy static files (includeing images) to dist // Copy static files (includeing images) to dist
gulp.task('copy-files', () => { gulp.task('copy-files', () => {
return gulp.src([ return gulp
.src(
[
'public/*.*', 'public/*.*',
'public/img/**', 'public/img/**',
'public/webfonts/*', 'public/webfonts/*',
'public/js/*.min.js' 'public/js/*.min.js',
], { ],
base: 'public' {
}) base: 'public',
},
)
.pipe(gulp.dest('dist')); .pipe(gulp.dest('dist'));
}); });

View File

@ -6,17 +6,22 @@
"author": "Alex Ling <hkalexling@gmail.com>", "author": "Alex Ling <hkalexling@gmail.com>",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.18.9",
"@babel/preset-env": "^7.11.5", "@babel/preset-env": "^7.11.5",
"all-contributors-cli": "^6.19.0", "all-contributors-cli": "^6.19.0",
"eslint": "^8.22.0",
"eslint-plugin-prettier": "^4.2.1",
"gulp": "^4.0.2", "gulp": "^4.0.2",
"gulp-babel": "^8.0.0", "gulp-babel": "^8.0.0",
"gulp-babel-minify": "^0.5.1", "gulp-babel-minify": "^0.5.1",
"gulp-less": "^4.0.1", "gulp-less": "^4.0.1",
"gulp-minify-css": "^1.2.4", "gulp-minify-css": "^1.2.4",
"less": "^3.11.3" "less": "^3.11.3",
"prettier": "^2.7.1"
}, },
"scripts": { "scripts": {
"uglify": "gulp" "uglify": "gulp",
"lint": "eslint public/js *.js --ext .js"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.14.0", "@fortawesome/fontawesome-free": "^5.14.0",

View File

@ -27,11 +27,11 @@ const component = () => {
this.scanMs = -1; this.scanMs = -1;
this.scanTitles = 0; this.scanTitles = 0;
$.post(`${base_url}api/admin/scan`) $.post(`${base_url}api/admin/scan`)
.then(data => { .then((data) => {
this.scanMs = data.milliseconds; this.scanMs = data.milliseconds;
this.scanTitles = data.titles; this.scanTitles = data.titles;
}) })
.catch(e => { .catch((e) => {
alert('danger', `Failed to trigger a scan. Error: ${e}`); alert('danger', `Failed to trigger a scan. Error: ${e}`);
}) })
.always(() => { .always(() => {
@ -42,14 +42,12 @@ const component = () => {
if (this.generating) return; if (this.generating) return;
this.generating = true; this.generating = true;
this.progress = 0.0; this.progress = 0.0;
$.post(`${base_url}api/admin/generate_thumbnails`) $.post(`${base_url}api/admin/generate_thumbnails`).then(() => {
.then(() => { this.getProgress();
this.getProgress()
}); });
}, },
getProgress() { getProgress() {
$.get(`${base_url}api/admin/thumbnail_progress`) $.get(`${base_url}api/admin/thumbnail_progress`).then((data) => {
.then(data => {
this.progress = data.progress; this.progress = data.progress;
this.generating = data.progress > 0; this.generating = data.progress > 0;
}); });

View File

@ -2,5 +2,5 @@ const alert = (level, text) => {
$('#alert').empty(); $('#alert').empty();
const html = `<div class="uk-alert-${level}" uk-alert><a class="uk-alert-close" uk-close></a><p>${text}</p></div>`; const html = `<div class="uk-alert-${level}" uk-alert><a class="uk-alert-close" uk-close></a><p>${text}</p></div>`;
$('#alert').append(html); $('#alert').append(html);
$("html, body").animate({ scrollTop: 0 }); $('html, body').animate({ scrollTop: 0 });
}; };

View File

@ -41,7 +41,10 @@ const getProp = (key, selector = '#root') => {
* @return {bool} * @return {bool}
*/ */
const preferDarkMode = () => { const preferDarkMode = () => {
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; return (
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches
);
}; };
/** /**
@ -87,7 +90,7 @@ const loadTheme = () => {
* @function saveThemeSetting * @function saveThemeSetting
* @param {string} setting - A theme setting * @param {string} setting - A theme setting
*/ */
const saveThemeSetting = setting => { const saveThemeSetting = (setting) => {
if (!validThemeSetting(setting)) setting = 'system'; if (!validThemeSetting(setting)) setting = 'system';
localStorage.setItem('theme', setting); localStorage.setItem('theme', setting);
}; };
@ -134,8 +137,9 @@ $(() => {
// on system dark mode setting change // on system dark mode setting change
if (window.matchMedia) { if (window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)') window
.addEventListener('change', event => { .matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (event) => {
if (loadThemeSetting() === 'system') if (loadThemeSetting() === 'system')
setTheme(event.matches ? 'dark' : 'light'); setTheme(event.matches ? 'dark' : 'light');
}); });

View File

@ -14,7 +14,7 @@ const truncate = (e) => {
} else { } else {
$(e).removeAttr('uk-tooltip'); $(e).removeAttr('uk-tooltip');
} }
} },
}); });
}; };

View File

@ -7,22 +7,22 @@ const component = () => {
ws: undefined, ws: undefined,
wsConnect(secure = true) { wsConnect(secure = true) {
const url = `${secure ? 'wss' : 'ws'}://${location.host}${base_url}api/admin/mangadex/queue`; const url = `${secure ? 'wss' : 'ws'}://${
location.host
}${base_url}api/admin/mangadex/queue`;
console.log(`Connecting to ${url}`); console.log(`Connecting to ${url}`);
this.ws = new WebSocket(url); this.ws = new WebSocket(url);
this.ws.onmessage = event => { this.ws.onmessage = (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
this.jobs = data.jobs; this.jobs = data.jobs;
this.paused = data.paused; this.paused = data.paused;
}; };
this.ws.onclose = () => { this.ws.onclose = () => {
if (this.ws.failed) if (this.ws.failed) return this.wsConnect(false);
return this.wsConnect(false);
alert('danger', 'Socket connection closed'); alert('danger', 'Socket connection closed');
}; };
this.ws.onerror = () => { this.ws.onerror = () => {
if (secure) if (secure) return (this.ws.failed = true);
return this.ws.failed = true;
alert('danger', 'Socket connection failed'); alert('danger', 'Socket connection failed');
}; };
}, },
@ -35,18 +35,24 @@ const component = () => {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: base_url + 'api/admin/mangadex/queue', url: base_url + 'api/admin/mangadex/queue',
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (!data.success && data.error) { if (!data.success && data.error) {
alert('danger', `Failed to fetch download queue. Error: ${data.error}`); alert(
'danger',
`Failed to fetch download queue. Error: ${data.error}`,
);
return; return;
} }
this.jobs = data.jobs; this.jobs = data.jobs;
this.paused = data.paused; this.paused = data.paused;
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to fetch download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to fetch download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}) })
.always(() => { .always(() => {
this.loading = false; this.loading = false;
@ -55,26 +61,36 @@ const component = () => {
jobAction(action, event) { jobAction(action, event) {
let url = `${base_url}api/admin/mangadex/queue/${action}`; let url = `${base_url}api/admin/mangadex/queue/${action}`;
if (event) { if (event) {
const id = event.currentTarget.closest('tr').id.split('-').slice(1).join('-'); const id = event.currentTarget
.closest('tr')
.id.split('-')
.slice(1)
.join('-');
url = `${url}?${$.param({ url = `${url}?${$.param({
id: id id,
})}`; })}`;
} }
console.log(url); console.log(url);
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: url, url,
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (!data.success && data.error) { if (!data.success && data.error) {
alert('danger', `Failed to ${action} job from download queue. Error: ${data.error}`); alert(
'danger',
`Failed to ${action} job from download queue. Error: ${data.error}`,
);
return; return;
} }
this.load(); this.load();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to ${action} job from download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to ${action} job from download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}, },
toggle() { toggle() {
@ -83,11 +99,14 @@ const component = () => {
const url = `${base_url}api/admin/mangadex/queue/${action}`; const url = `${base_url}api/admin/mangadex/queue/${action}`;
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: url, url,
dataType: 'json' dataType: 'json',
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to ${action} download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to ${action} download queue. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}) })
.always(() => { .always(() => {
this.load(); this.load();
@ -111,6 +130,6 @@ const component = () => {
break; break;
} }
return cls; return cls;
} },
}; };
}; };

View File

@ -7,9 +7,9 @@ const component = () => {
load() { load() {
this.loading = true; this.loading = true;
this.request('GET', `${base_url}api/admin/titles/missing`, data => { this.request('GET', `${base_url}api/admin/titles/missing`, (data) => {
this.titles = data.titles; this.titles = data.titles;
this.request('GET', `${base_url}api/admin/entries/missing`, data => { this.request('GET', `${base_url}api/admin/entries/missing`, (data) => {
this.entries = data.entries; this.entries = data.entries;
this.loading = false; this.loading = false;
this.empty = this.entries.length === 0 && this.titles.length === 0; this.empty = this.entries.length === 0 && this.titles.length === 0;
@ -19,22 +19,33 @@ const component = () => {
rm(event) { rm(event) {
const rawID = event.currentTarget.closest('tr').id; const rawID = event.currentTarget.closest('tr').id;
const [type, id] = rawID.split('-'); const [type, id] = rawID.split('-');
const url = `${base_url}api/admin/${type === 'title' ? 'titles' : 'entries'}/missing/${id}`; const url = `${base_url}api/admin/${
type === 'title' ? 'titles' : 'entries'
}/missing/${id}`;
this.request('DELETE', url, () => { this.request('DELETE', url, () => {
this.load(); this.load();
}); });
}, },
rmAll() { rmAll() {
UIkit.modal.confirm('Are you sure? All metadata associated with these items, including their tags and thumbnails, will be deleted from the database.', { UIkit.modal
.confirm(
'Are you sure? All metadata associated with these items, including their tags and thumbnails, will be deleted from the database.',
{
labels: { labels: {
ok: 'Yes, delete them', ok: 'Yes, delete them',
cancel: 'Cancel' cancel: 'Cancel',
} },
}).then(() => { },
)
.then(() => {
this.request('DELETE', `${base_url}api/admin/titles/missing`, () => { this.request('DELETE', `${base_url}api/admin/titles/missing`, () => {
this.request('DELETE', `${base_url}api/admin/entries/missing`, () => { this.request(
'DELETE',
`${base_url}api/admin/entries/missing`,
() => {
this.load(); this.load();
}); },
);
}); });
}); });
}, },
@ -42,10 +53,10 @@ const component = () => {
console.log(url); console.log(url);
$.ajax({ $.ajax({
type: method, type: method,
url: url, url,
contentType: 'application/json' contentType: 'application/json',
}) })
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', `Failed to ${method} ${url}. Error: ${data.error}`); alert('danger', `Failed to ${method} ${url}. Error: ${data.error}`);
return; return;
@ -53,8 +64,11 @@ const component = () => {
if (cb) cb(data); if (cb) cb(data);
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to ${method} ${url}. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to ${method} ${url}. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
} },
}; };
}; };

View File

@ -8,8 +8,8 @@ const component = () => {
manga: undefined, // undefined: not searched yet, []: empty manga: undefined, // undefined: not searched yet, []: empty
mid: undefined, // id of the selected manga mid: undefined, // id of the selected manga
allChapters: [], allChapters: [],
query: "", query: '',
mangaTitle: "", mangaTitle: '',
searching: false, searching: false,
adding: false, adding: false,
sortOptions: [], sortOptions: [],
@ -18,16 +18,16 @@ const component = () => {
chaptersLimit: 500, chaptersLimit: 500,
listManga: false, listManga: false,
subscribing: false, subscribing: false,
subscriptionName: "", subscriptionName: '',
init() { init() {
const tableObserver = new MutationObserver(() => { const tableObserver = new MutationObserver(() => {
console.log("table mutated"); console.log('table mutated');
$("#selectable").selectable({ $('#selectable').selectable({
filter: "tr", filter: 'tr',
}); });
}); });
tableObserver.observe($("table").get(0), { tableObserver.observe($('table').get(0), {
childList: true, childList: true,
subtree: true, subtree: true,
}); });
@ -37,25 +37,21 @@ const component = () => {
if (!data.success) throw new Error(data.error); if (!data.success) throw new Error(data.error);
this.plugins = data.plugins; this.plugins = data.plugins;
const pid = localStorage.getItem("plugin"); const pid = localStorage.getItem('plugin');
if (pid && this.plugins.map((p) => p.id).includes(pid)) if (pid && this.plugins.map((p) => p.id).includes(pid))
return this.loadPlugin(pid); return this.loadPlugin(pid);
if (this.plugins.length > 0) if (this.plugins.length > 0) this.loadPlugin(this.plugins[0].id);
this.loadPlugin(this.plugins[0].id);
}) })
.catch((e) => { .catch((e) => {
alert( alert('danger', `Failed to list the available plugins. Error: ${e}`);
"danger",
`Failed to list the available plugins. Error: ${e}`
);
}); });
}, },
loadPlugin(pid) { loadPlugin(pid) {
fetch( fetch(
`${base_url}api/admin/plugin/info?${new URLSearchParams({ `${base_url}api/admin/plugin/info?${new URLSearchParams({
plugin: pid, plugin: pid,
})}` })}`,
) )
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
@ -65,10 +61,7 @@ const component = () => {
this.pid = pid; this.pid = pid;
}) })
.catch((e) => { .catch((e) => {
alert( alert('danger', `Failed to get plugin metadata. Error: ${e}`);
"danger",
`Failed to get plugin metadata. Error: ${e}`
);
}); });
}, },
pluginChanged() { pluginChanged() {
@ -76,12 +69,12 @@ const component = () => {
this.chapters = undefined; this.chapters = undefined;
this.mid = undefined; this.mid = undefined;
this.loadPlugin(this.pid); this.loadPlugin(this.pid);
localStorage.setItem("plugin", this.pid); localStorage.setItem('plugin', this.pid);
}, },
get chapterKeys() { get chapterKeys() {
if (this.allChapters.length < 1) return []; if (this.allChapters.length < 1) return [];
return Object.keys(this.allChapters[0]).filter( return Object.keys(this.allChapters[0]).filter(
(k) => !["manga_title"].includes(k) (k) => !['manga_title'].includes(k),
); );
}, },
searchChapters(query) { searchChapters(query) {
@ -93,8 +86,8 @@ const component = () => {
fetch( fetch(
`${base_url}api/admin/plugin/list?${new URLSearchParams({ `${base_url}api/admin/plugin/list?${new URLSearchParams({
plugin: this.pid, plugin: this.pid,
query: query, query,
})}` })}`,
) )
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
@ -110,7 +103,7 @@ const component = () => {
this.chapters = data.chapters; this.chapters = data.chapters;
}) })
.catch((e) => { .catch((e) => {
alert("danger", `Failed to list chapters. Error: ${e}`); alert('danger', `Failed to list chapters. Error: ${e}`);
}) })
.finally(() => { .finally(() => {
this.searching = false; this.searching = false;
@ -124,8 +117,8 @@ const component = () => {
fetch( fetch(
`${base_url}api/admin/plugin/search?${new URLSearchParams({ `${base_url}api/admin/plugin/search?${new URLSearchParams({
plugin: this.pid, plugin: this.pid,
query: query, query,
})}` })}`,
) )
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
@ -134,7 +127,7 @@ const component = () => {
this.listManga = true; this.listManga = true;
}) })
.catch((e) => { .catch((e) => {
alert("danger", `Search failed. Error: ${e}`); alert('danger', `Search failed. Error: ${e}`);
}) })
.finally(() => { .finally(() => {
this.searching = false; this.searching = false;
@ -153,37 +146,35 @@ const component = () => {
} }
}, },
selectAll() { selectAll() {
$("tbody > tr").each((i, e) => { $('tbody > tr').each((i, e) => {
$(e).addClass("ui-selected"); $(e).addClass('ui-selected');
}); });
}, },
clearSelection() { clearSelection() {
$("tbody > tr").each((i, e) => { $('tbody > tr').each((i, e) => {
$(e).removeClass("ui-selected"); $(e).removeClass('ui-selected');
}); });
}, },
download() { download() {
const selected = $("tbody > tr.ui-selected").get(); const selected = $('tbody > tr.ui-selected').get();
if (selected.length === 0) return; if (selected.length === 0) return;
UIkit.modal UIkit.modal
.confirm(`Download ${selected.length} selected chapters?`) .confirm(`Download ${selected.length} selected chapters?`)
.then(() => { .then(() => {
const ids = selected.map((e) => e.id); const ids = selected.map((e) => e.id);
const chapters = this.chapters.filter((c) => const chapters = this.chapters.filter((c) => ids.includes(c.id));
ids.includes(c.id)
);
console.log(chapters); console.log(chapters);
this.adding = true; this.adding = true;
fetch(`${base_url}api/admin/plugin/download`, { fetch(`${base_url}api/admin/plugin/download`, {
method: "POST", method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
chapters, chapters,
plugin: this.pid, plugin: this.pid,
title: this.mangaTitle, title: this.mangaTitle,
}), }),
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
}) })
.then((res) => res.json()) .then((res) => res.json())
@ -192,16 +183,16 @@ const component = () => {
const successCount = parseInt(data.success); const successCount = parseInt(data.success);
const failCount = parseInt(data.fail); const failCount = parseInt(data.fail);
alert( alert(
"success", 'success',
`${successCount} of ${ `${successCount} of ${
successCount + failCount successCount + failCount
} chapters added to the download queue. You can view and manage your download queue on the <a href="${base_url}admin/downloads">download manager page</a>.` } chapters added to the download queue. You can view and manage your download queue on the <a href="${base_url}admin/downloads">download manager page</a>.`,
); );
}) })
.catch((e) => { .catch((e) => {
alert( alert(
"danger", 'danger',
`Failed to add chapters to the download queue. Error: ${e}` `Failed to add chapters to the download queue. Error: ${e}`,
); );
}) })
.finally(() => { .finally(() => {
@ -210,7 +201,7 @@ const component = () => {
}); });
}, },
thClicked(event) { thClicked(event) {
const idx = parseInt(event.currentTarget.id.split("-")[1]); const idx = parseInt(event.currentTarget.id.split('-')[1]);
if (idx === undefined || isNaN(idx)) return; if (idx === undefined || isNaN(idx)) return;
const curOption = this.sortOptions[idx]; const curOption = this.sortOptions[idx];
let option; let option;
@ -233,51 +224,46 @@ const component = () => {
get filteredChapters() { get filteredChapters() {
let ary = this.allChapters.slice(); let ary = this.allChapters.slice();
console.log("initial size:", ary.length); console.log('initial size:', ary.length);
for (let filter of this.appliedFilters) { for (let filter of this.appliedFilters) {
if (!filter.value) continue; if (!filter.value) continue;
if (filter.type === "array" && filter.value === "all") continue; if (filter.type === 'array' && filter.value === 'all') continue;
if (filter.type.startsWith("number") && isNaN(filter.value)) if (filter.type.startsWith('number') && isNaN(filter.value)) continue;
continue;
if (filter.type === "string") { if (filter.type === 'string') {
ary = ary.filter((ch) =>
ch[filter.key].toLowerCase().includes(filter.value.toLowerCase()),
);
}
if (filter.type === 'number-min') {
ary = ary.filter(
(ch) => Number(ch[filter.key]) >= Number(filter.value),
);
}
if (filter.type === 'number-max') {
ary = ary.filter(
(ch) => Number(ch[filter.key]) <= Number(filter.value),
);
}
if (filter.type === 'date-min') {
ary = ary.filter(
(ch) => Number(ch[filter.key]) >= Number(filter.value),
);
}
if (filter.type === 'date-max') {
ary = ary.filter(
(ch) => Number(ch[filter.key]) <= Number(filter.value),
);
}
if (filter.type === 'array') {
ary = ary.filter((ch) => ary = ary.filter((ch) =>
ch[filter.key] ch[filter.key]
.toLowerCase() .map((s) => (typeof s === 'string' ? s.toLowerCase() : s))
.includes(filter.value.toLowerCase()) .includes(filter.value.toLowerCase()),
);
}
if (filter.type === "number-min") {
ary = ary.filter(
(ch) => Number(ch[filter.key]) >= Number(filter.value)
);
}
if (filter.type === "number-max") {
ary = ary.filter(
(ch) => Number(ch[filter.key]) <= Number(filter.value)
);
}
if (filter.type === "date-min") {
ary = ary.filter(
(ch) => Number(ch[filter.key]) >= Number(filter.value)
);
}
if (filter.type === "date-max") {
ary = ary.filter(
(ch) => Number(ch[filter.key]) <= Number(filter.value)
);
}
if (filter.type === "array") {
ary = ary.filter((ch) =>
ch[filter.key]
.map((s) =>
typeof s === "string" ? s.toLowerCase() : s
)
.includes(filter.value.toLowerCase())
); );
} }
console.log("filtered size:", ary.length); console.log('filtered size:', ary.length);
} }
return ary; return ary;
@ -304,59 +290,58 @@ const component = () => {
if (!isNaN(a) && !isNaN(b)) return Number(a) - Number(b); if (!isNaN(a) && !isNaN(b)) return Number(a) - Number(b);
const preprocessString = (val) => { const preprocessString = (val) => {
if (typeof val !== "string") return val; if (typeof val !== 'string') return val;
return val.toLowerCase().replace(/\s\s/g, " ").trim(); return val.toLowerCase().replace(/\s\s/g, ' ').trim();
}; };
return preprocessString(a) > preprocessString(b) ? 1 : -1; return preprocessString(a) > preprocessString(b) ? 1 : -1;
}, },
fieldType(values) { fieldType(values) {
if (values.every((v) => this.numIsDate(v))) return "date"; if (values.every((v) => this.numIsDate(v))) return 'date';
if (values.every((v) => !isNaN(v))) return "number"; if (values.every((v) => !isNaN(v))) return 'number';
if (values.every((v) => Array.isArray(v))) return "array"; if (values.every((v) => Array.isArray(v))) return 'array';
return "string"; return 'string';
}, },
get filters() { get filters() {
if (this.allChapters.length < 1) return []; if (this.allChapters.length < 1) return [];
const keys = Object.keys(this.allChapters[0]).filter( const keys = Object.keys(this.allChapters[0]).filter(
(k) => !["manga_title", "id"].includes(k) (k) => !['manga_title', 'id'].includes(k),
); );
return keys.map((k) => { return keys.map((k) => {
let values = this.allChapters.map((c) => c[k]); let values = this.allChapters.map((c) => c[k]);
const type = this.fieldType(values); const type = this.fieldType(values);
if (type === "array") { if (type === 'array') {
// if the type is an array, return the list of available elements // if the type is an array, return the list of available elements
// example: an array of groups or authors // example: an array of groups or authors
values = Array.from( values = Array.from(
new Set( new Set(
values.flat().map((v) => { values.flat().map((v) => {
if (typeof v === "string") if (typeof v === 'string') return v.toLowerCase();
return v.toLowerCase(); }),
}) ),
)
); );
} }
return { return {
key: k, key: k,
type: type, type,
values: values, values,
}; };
}); });
}, },
get filterSettings() { get filterSettings() {
return $("#filter-form input:visible, #filter-form select:visible") return $('#filter-form input:visible, #filter-form select:visible')
.get() .get()
.map((i) => { .map((i) => {
const type = i.getAttribute("data-filter-type"); const type = i.getAttribute('data-filter-type');
let value = i.value.trim(); let value = i.value.trim();
if (type.startsWith("date")) if (type.startsWith('date'))
value = value ? Date.parse(value).toString() : ""; value = value ? Date.parse(value).toString() : '';
return { return {
key: i.getAttribute("data-filter-key"), key: i.getAttribute('data-filter-key'),
value: value, value,
type: type, type,
}; };
}); });
}, },
@ -366,23 +351,23 @@ const component = () => {
this.sortOptions = []; this.sortOptions = [];
}, },
clearFilters() { clearFilters() {
$("#filter-form input") $('#filter-form input')
.get() .get()
.forEach((i) => (i.value = "")); .forEach((i) => (i.value = ''));
$("#filter-form select").val("all"); $('#filter-form select').val('all');
this.appliedFilters = []; this.appliedFilters = [];
this.chapters = this.filteredChapters; this.chapters = this.filteredChapters;
this.sortOptions = []; this.sortOptions = [];
}, },
mangaSelected(event) { mangaSelected(event) {
const mid = event.currentTarget.getAttribute("data-id"); const mid = event.currentTarget.getAttribute('data-id');
this.mid = mid; this.mid = mid;
this.searchChapters(mid); this.searchChapters(mid);
}, },
subscribe(modal) { subscribe(modal) {
this.subscribing = true; this.subscribing = true;
fetch(`${base_url}api/admin/plugin/subscriptions`, { fetch(`${base_url}api/admin/plugin/subscriptions`, {
method: "POST", method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
filters: this.filterSettings, filters: this.filterSettings,
plugin: this.pid, plugin: this.pid,
@ -391,16 +376,16 @@ const component = () => {
manga_id: this.mid, manga_id: this.mid,
}), }),
headers: { headers: {
"Content-Type": "application/json", 'Content-Type': 'application/json',
}, },
}) })
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
if (!data.success) throw new Error(data.error); if (!data.success) throw new Error(data.error);
alert("success", "Subscription created"); alert('success', 'Subscription created');
}) })
.catch((e) => { .catch((e) => {
alert("danger", `Failed to subscribe. Error: ${e}`); alert('danger', `Failed to subscribe. Error: ${e}`);
}) })
.finally(() => { .finally(() => {
this.subscribing = false; this.subscribing = false;
@ -412,14 +397,12 @@ const component = () => {
}, },
renderCell(value) { renderCell(value) {
if (this.numIsDate(value)) if (this.numIsDate(value))
return `<span>${moment(Number(value)).format( return `<span>${moment(Number(value)).format('MMM D, YYYY')}</span>`;
"MMM D, YYYY"
)}</span>`;
const maxLength = 40; const maxLength = 40;
if (value && value.length > maxLength) if (value && value.length > maxLength)
return `<span>${value.substr( return `<span>${value.substr(
0, 0,
maxLength maxLength,
)}...</span><div uk-dropdown>${value}</div>`; )}...</span><div uk-dropdown>${value}</div>`;
return `<span>${value}</span>`; return `<span>${value}</span>`;
}, },
@ -427,24 +410,24 @@ const component = () => {
const key = ft.key; const key = ft.key;
let type = ft.type; let type = ft.type;
switch (type) { switch (type) {
case "number-min": case 'number-min':
type = "number (minimum value)"; type = 'number (minimum value)';
break; break;
case "number-max": case 'number-max':
type = "number (maximum value)"; type = 'number (maximum value)';
break; break;
case "date-min": case 'date-min':
type = "minimum date"; type = 'minimum date';
break; break;
case "date-max": case 'date-max':
type = "maximum date"; type = 'maximum date';
break; break;
} }
let value = ft.value; let value = ft.value;
if (ft.type.startsWith("number") && isNaN(value)) value = ""; if (ft.type.startsWith('number') && isNaN(value)) value = '';
else if (ft.type.startsWith("date") && value) else if (ft.type.startsWith('date') && value)
value = moment(Number(value)).format("MMM D, YYYY"); value = moment(Number(value)).format('MMM D, YYYY');
return `<td>${key}</td><td>${type}</td><td>${value}</td>`; return `<td>${key}</td><td>${type}</td><td>${value}</td>`;
}, },

View File

@ -21,24 +21,24 @@ const readerComponent = () => {
*/ */
init(nextTick) { init(nextTick) {
$.get(`${base_url}api/dimensions/${tid}/${eid}`) $.get(`${base_url}api/dimensions/${tid}/${eid}`)
.then(data => { .then((data) => {
if (!data.success && data.error) if (!data.success && data.error) throw new Error(resp.error);
throw new Error(resp.error);
const dimensions = data.dimensions; const dimensions = data.dimensions;
this.items = dimensions.map((d, i) => { this.items = dimensions.map((d, i) => {
return { return {
id: i + 1, id: i + 1,
url: `${base_url}api/page/${tid}/${eid}/${i + 1}`, url: `${base_url}api/page/${tid}/${eid}/${i + 1}`,
width: d.width == 0 ? "100%" : d.width, width: d.width === 0 ? '100%' : d.width,
height: d.height == 0 ? "100%" : d.height, height: d.height === 0 ? '100%' : d.height,
}; };
}); });
// Note: for image types not supported by image_size.cr, the width and height will be 0, and so `avgRatio` will be `Infinity`. // Note: for image types not supported by image_size.cr, the width and height will be 0, and so `avgRatio` will be `Infinity`.
// TODO: support more image types in image_size.cr // TODO: support more image types in image_size.cr
const avgRatio = dimensions.reduce((acc, cur) => { const avgRatio =
return acc + cur.height / cur.width dimensions.reduce((acc, cur) => {
return acc + cur.height / cur.width;
}, 0) / dimensions.length; }, 0) / dimensions.length;
console.log(avgRatio); console.log(avgRatio);
@ -60,8 +60,13 @@ const readerComponent = () => {
} }
// Preload Images // Preload Images
this.preloadLookahead = +(localStorage.getItem('preloadLookahead') ?? 3); this.preloadLookahead = +(
const limit = Math.min(page + this.preloadLookahead, this.items.length); localStorage.getItem('preloadLookahead') ?? 3
);
const limit = Math.min(
page + this.preloadLookahead,
this.items.length,
);
for (let idx = page + 1; idx <= limit; idx++) { for (let idx = page + 1; idx <= limit; idx++) {
this.preloadImage(this.items[idx - 1].url); this.preloadImage(this.items[idx - 1].url);
} }
@ -71,28 +76,31 @@ const readerComponent = () => {
this.fitType = savedFitType; this.fitType = savedFitType;
$('#fit-select').val(savedFitType); $('#fit-select').val(savedFitType);
} }
const savedFlipAnimation = localStorage.getItem('enableFlipAnimation'); const savedFlipAnimation = localStorage.getItem(
this.enableFlipAnimation = savedFlipAnimation === null || savedFlipAnimation === 'true'; 'enableFlipAnimation',
);
this.enableFlipAnimation =
savedFlipAnimation === null || savedFlipAnimation === 'true';
const savedRightToLeft = localStorage.getItem('enableRightToLeft'); const savedRightToLeft = localStorage.getItem('enableRightToLeft');
if (savedRightToLeft === null) { if (savedRightToLeft === null) {
this.enableRightToLeft = false; this.enableRightToLeft = false;
} else { } else {
this.enableRightToLeft = (savedRightToLeft === 'true'); this.enableRightToLeft = savedRightToLeft === 'true';
} }
}) })
.catch(e => { .catch((e) => {
const errMsg = `Failed to get the page dimensions. ${e}`; const errMsg = `Failed to get the page dimensions. ${e}`;
console.error(e); console.error(e);
this.alertClass = 'uk-alert-danger'; this.alertClass = 'uk-alert-danger';
this.msg = errMsg; this.msg = errMsg;
}) });
}, },
/** /**
* Preload an image, which is expected to be cached * Preload an image, which is expected to be cached
*/ */
preloadImage(url) { preloadImage(url) {
(new Image()).src = url; new Image().src = url;
}, },
/** /**
* Handles the `change` event for the page selector * Handles the `change` event for the page selector
@ -156,10 +164,8 @@ const readerComponent = () => {
this.toPage(newIdx); this.toPage(newIdx);
if (this.enableFlipAnimation) { if (this.enableFlipAnimation) {
if (isNext ^ this.enableRightToLeft) if (isNext ^ this.enableRightToLeft) this.flipAnimation = 'right';
this.flipAnimation = 'right'; else this.flipAnimation = 'left';
else
this.flipAnimation = 'left';
} }
setTimeout(() => { setTimeout(() => {
@ -196,7 +202,7 @@ const readerComponent = () => {
ary.unshift(window.location.origin); ary.unshift(window.location.origin);
const url = ary.join('/'); const url = ary.join('/');
this.saveProgress(idx); this.saveProgress(idx);
history.replaceState(null, "", url); history.replaceState(null, '', url);
}, },
/** /**
* Updates the backend reading progress if: * Updates the backend reading progress if:
@ -211,22 +217,25 @@ const readerComponent = () => {
*/ */
saveProgress(idx, cb) { saveProgress(idx, cb) {
idx = parseInt(idx); idx = parseInt(idx);
if (Math.abs(idx - this.lastSavedPage) >= 5 || if (
Math.abs(idx - this.lastSavedPage) >= 5 ||
this.longPages || this.longPages ||
idx === 1 || idx === this.items.length idx === 1 ||
idx === this.items.length
) { ) {
this.lastSavedPage = idx; this.lastSavedPage = idx;
console.log('saving progress', idx); console.log('saving progress', idx);
const url = `${base_url}api/progress/${tid}/${idx}?${$.param({eid: eid})}`; const url = `${base_url}api/progress/${tid}/${idx}?${$.param({
eid,
})}`;
$.ajax({ $.ajax({
method: 'PUT', method: 'PUT',
url: url, url,
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.error) if (data.error) alert('danger', data.error);
alert('danger', data.error);
if (cb) cb(); if (cb) cb();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
@ -358,4 +367,4 @@ const readerComponent = () => {
localStorage.setItem('enableRightToLeft', this.enableRightToLeft); localStorage.setItem('enableRightToLeft', this.enableRightToLeft);
}, },
}; };
} };

View File

@ -1,27 +1,25 @@
$(function () { $(function () {
var filter = []; let filter = [];
var result = []; let result = [];
$('.uk-card-title').each(function () { $('.uk-card-title').each(function () {
filter.push($(this).text()); filter.push($(this).text());
}); });
$('.uk-search-input').keyup(function () { $('.uk-search-input').keyup(function () {
var input = $('.uk-search-input').val(); let input = $('.uk-search-input').val();
var regex = new RegExp(input, 'i'); let regex = new RegExp(input, 'i');
if (input === '') { if (input === '') {
$('.item').each(function () { $('.item').each(function () {
$(this).removeAttr('hidden'); $(this).removeAttr('hidden');
}); });
} } else {
else {
filter.forEach(function (text, i) { filter.forEach(function (text, i) {
result[i] = text.match(regex); result[i] = text.match(regex);
}); });
$('.item').each(function (i) { $('.item').each(function (i) {
if (result[i]) { if (result[i]) {
$(this).removeAttr('hidden'); $(this).removeAttr('hidden');
} } else {
else {
$(this).attr('hidden', ''); $(this).attr('hidden', '');
} }
}); });

View File

@ -8,7 +8,7 @@ $(() => {
const url = `${location.protocol}//${location.host}${location.pathname}`; const url = `${location.protocol}//${location.host}${location.pathname}`;
const newURL = `${url}?${$.param({ const newURL = `${url}?${$.param({
sort: by, sort: by,
ascend: dir === 'up' ? 1 : 0 ascend: dir === 'up' ? 1 : 0,
})}`; })}`;
window.location.href = newURL; window.location.href = newURL;
}); });

View File

@ -13,36 +13,30 @@ const component = () => {
if (!data.success) throw new Error(data.error); if (!data.success) throw new Error(data.error);
this.plugins = data.plugins; this.plugins = data.plugins;
const pid = localStorage.getItem("plugin"); const pid = localStorage.getItem('plugin');
if (pid && this.plugins.map((p) => p.id).includes(pid)) if (pid && this.plugins.map((p) => p.id).includes(pid))
this.pid = pid; this.pid = pid;
else if (this.plugins.length > 0) else if (this.plugins.length > 0) this.pid = this.plugins[0].id;
this.pid = this.plugins[0].id;
this.list(pid); this.list(pid);
}) })
.catch((e) => { .catch((e) => {
alert( alert('danger', `Failed to list the available plugins. Error: ${e}`);
"danger",
`Failed to list the available plugins. Error: ${e}`
);
}); });
}, },
pluginChanged() { pluginChanged() {
localStorage.setItem("plugin", this.pid); localStorage.setItem('plugin', this.pid);
this.list(this.pid); this.list(this.pid);
}, },
list(pid) { list(pid) {
if (!pid) return; if (!pid) return;
fetch( fetch(
`${base_url}api/admin/plugin/subscriptions?${new URLSearchParams( `${base_url}api/admin/plugin/subscriptions?${new URLSearchParams({
{
plugin: pid, plugin: pid,
} })}`,
)}`,
{ {
method: "GET", method: 'GET',
} },
) )
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
@ -50,10 +44,7 @@ const component = () => {
this.subscriptions = data.subscriptions; this.subscriptions = data.subscriptions;
}) })
.catch((e) => { .catch((e) => {
alert( alert('danger', `Failed to list subscriptions. Error: ${e}`);
"danger",
`Failed to list subscriptions. Error: ${e}`
);
}); });
}, },
renderStrCell(str) { renderStrCell(str) {
@ -61,7 +52,7 @@ const component = () => {
if (str.length > maxLength) if (str.length > maxLength)
return `<td><span>${str.substring( return `<td><span>${str.substring(
0, 0,
maxLength maxLength,
)}...</span><div uk-dropdown>${str}</div></td>`; )}...</span><div uk-dropdown>${str}</div></td>`;
return `<td>${str}</td>`; return `<td>${str}</td>`;
}, },
@ -71,7 +62,7 @@ const component = () => {
.humanize(true)}</td>`; .humanize(true)}</td>`;
}, },
selected(event, modal) { selected(event, modal) {
const id = event.currentTarget.getAttribute("sid"); const id = event.currentTarget.getAttribute('sid');
this.subscription = this.subscriptions.find((s) => s.id === id); this.subscription = this.subscriptions.find((s) => s.id === id);
UIkit.modal(modal).show(); UIkit.modal(modal).show();
}, },
@ -79,36 +70,41 @@ const component = () => {
const key = ft.key; const key = ft.key;
let type = ft.type; let type = ft.type;
switch (type) { switch (type) {
case "number-min": case 'number-min':
type = "number (minimum value)"; type = 'number (minimum value)';
break; break;
case "number-max": case 'number-max':
type = "number (maximum value)"; type = 'number (maximum value)';
break; break;
case "date-min": case 'date-min':
type = "minimum date"; type = 'minimum date';
break; break;
case "date-max": case 'date-max':
type = "maximum date"; type = 'maximum date';
break; break;
} }
let value = ft.value; let value = ft.value;
if (ft.type.startsWith("number") && isNaN(value)) value = ""; if (ft.type.startsWith('number') && isNaN(value)) value = '';
else if (ft.type.startsWith("date") && value) else if (ft.type.startsWith('date') && value)
value = moment(Number(value)).format("MMM D, YYYY"); value = moment(Number(value)).format('MMM D, YYYY');
return `<td>${key}</td><td>${type}</td><td>${value}</td>`; return `<td>${key}</td><td>${type}</td><td>${value}</td>`;
}, },
actionHandler(event, type) { actionHandler(event, type) {
const id = $(event.currentTarget).closest("tr").attr("sid"); const id = $(event.currentTarget).closest('tr').attr('sid');
if (type !== 'delete') return this.action(id, type); if (type !== 'delete') return this.action(id, type);
UIkit.modal.confirm('Are you sure you want to delete the subscription? This cannot be undone.', { UIkit.modal
.confirm(
'Are you sure you want to delete the subscription? This cannot be undone.',
{
labels: { labels: {
ok: 'Yes, delete it', ok: 'Yes, delete it',
cancel: 'Cancel' cancel: 'Cancel',
} },
}).then(() => { },
)
.then(() => {
this.action(id, type); this.action(id, type);
}); });
}, },
@ -116,27 +112,27 @@ const component = () => {
if (this.loading) return; if (this.loading) return;
this.loading = true; this.loading = true;
fetch( fetch(
`${base_url}api/admin/plugin/subscriptions${type === 'update' ? '/update' : ''}?${new URLSearchParams( `${base_url}api/admin/plugin/subscriptions${
{ type === 'update' ? '/update' : ''
}?${new URLSearchParams({
plugin: this.pid, plugin: this.pid,
subscription: id, subscription: id,
} })}`,
)}`,
{ {
method: type === 'delete' ? "DELETE" : 'POST' method: type === 'delete' ? 'DELETE' : 'POST',
} },
) )
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
if (!data.success) throw new Error(data.error); if (!data.success) throw new Error(data.error);
if (type === 'update') if (type === 'update')
alert("success", `Checking updates for subscription ${id}. Check the log for the progress or come back to this page later.`); alert(
'success',
`Checking updates for subscription ${id}. Check the log for the progress or come back to this page later.`,
);
}) })
.catch((e) => { .catch((e) => {
alert( alert('danger', `Failed to ${type} subscription. Error: ${e}`);
"danger",
`Failed to ${type} subscription. Error: ${e}`
);
}) })
.finally(() => { .finally(() => {
this.loading = false; this.loading = false;

View File

@ -7,30 +7,45 @@ const component = () => {
$.getJSON(`${base_url}api/admin/mangadex/expires`) $.getJSON(`${base_url}api/admin/mangadex/expires`)
.done((data) => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', 'Failed to check MangaDex integration status. Error: ' + data.error); alert(
'danger',
'Failed to check MangaDex integration status. Error: ' +
data.error,
);
return; return;
} }
this.available = Boolean(data.expires && data.expires > Math.floor(Date.now() / 1000)); this.available = Boolean(
data.expires && data.expires > Math.floor(Date.now() / 1000),
);
if (this.available) this.getSubscriptions(); if (this.available) this.getSubscriptions();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to check MangaDex integration status. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
}) 'danger',
`Failed to check MangaDex integration status. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
});
}, },
getSubscriptions() { getSubscriptions() {
$.getJSON(`${base_url}api/admin/mangadex/subscriptions`) $.getJSON(`${base_url}api/admin/mangadex/subscriptions`)
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', 'Failed to get subscriptions. Error: ' + data.error); alert(
'danger',
'Failed to get subscriptions. Error: ' + data.error,
);
return; return;
} }
this.subscriptions = data.subscriptions; this.subscriptions = data.subscriptions;
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to get subscriptions. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
}) 'danger',
`Failed to get subscriptions. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
});
}, },
rm(event) { rm(event) {
@ -38,16 +53,22 @@ const component = () => {
$.ajax({ $.ajax({
type: 'DELETE', type: 'DELETE',
url: `${base_url}api/admin/mangadex/subscriptions/${id}`, url: `${base_url}api/admin/mangadex/subscriptions/${id}`,
contentType: 'application/json' contentType: 'application/json',
}) })
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', `Failed to delete subscription. Error: ${data.error}`); alert(
'danger',
`Failed to delete subscription. Error: ${data.error}`,
);
} }
this.getSubscriptions(); this.getSubscriptions();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to delete subscription. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to delete subscription. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}, },
@ -56,17 +77,26 @@ const component = () => {
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: `${base_url}api/admin/mangadex/subscriptions/check/${id}`, url: `${base_url}api/admin/mangadex/subscriptions/check/${id}`,
contentType: 'application/json' contentType: 'application/json',
}) })
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', `Failed to check subscription. Error: ${data.error}`); alert(
'danger',
`Failed to check subscription. Error: ${data.error}`,
);
return; return;
} }
alert('success', 'Mango is now checking the subscription for updates. This might take a while, but you can safely leave the page.'); alert(
'success',
'Mango is now checking the subscription for updates. This might take a while, but you can safely leave the page.',
);
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to check subscription. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to check subscription. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}, },
@ -77,6 +107,6 @@ const component = () => {
if (min === max) return `= ${min}`; if (min === max) return `= ${min}`;
return `${min} - ${max}`; return `${min} - ${max}`;
} },
}; };
}; };

View File

@ -14,12 +14,20 @@ const setupAcard = () => {
$(card).attr('data-encoded-book-title'), $(card).attr('data-encoded-book-title'),
$(card).attr('data-encoded-title'), $(card).attr('data-encoded-title'),
$(card).attr('data-book-id'), $(card).attr('data-book-id'),
$(card).attr('data-id') $(card).attr('data-id'),
); );
}); });
}; };
function showModal(encodedPath, pages, percentage, encodedeTitle, encodedEntryTitle, titleID, entryID) { function showModal(
encodedPath,
pages,
percentage,
encodedeTitle,
encodedEntryTitle,
titleID,
entryID,
) {
const zipPath = decodeURIComponent(encodedPath); const zipPath = decodeURIComponent(encodedPath);
const title = decodeURIComponent(encodedeTitle); const title = decodeURIComponent(encodedeTitle);
const entry = decodeURIComponent(encodedEntryTitle); const entry = decodeURIComponent(encodedEntryTitle);
@ -55,7 +63,10 @@ function showModal(encodedPath, pages, percentage, encodedeTitle, encodedEntryTi
$('#modal-edit-btn').attr('onclick', `edit("${entryID}")`); $('#modal-edit-btn').attr('onclick', `edit("${entryID}")`);
$('#modal-download-btn').attr('href', `${base_url}api/download/${titleID}/${entryID}`); $('#modal-download-btn').attr(
'href',
`${base_url}api/download/${titleID}/${entryID}`,
);
UIkit.modal($('#modal')).show(); UIkit.modal($('#modal')).show();
} }
@ -66,19 +77,18 @@ UIkit.util.on(document, 'hidden', '#modal', () => {
}); });
const updateProgress = (tid, eid, page) => { const updateProgress = (tid, eid, page) => {
let url = `${base_url}api/progress/${tid}/${page}` let url = `${base_url}api/progress/${tid}/${page}`;
const query = $.param({ const query = $.param({
eid: eid eid,
}); });
if (eid) if (eid) url += `?${query}`;
url += `?${query}`;
$.ajax({ $.ajax({
method: 'PUT', method: 'PUT',
url: url, url,
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.success) { if (data.success) {
location.reload(); location.reload();
} else { } else {
@ -101,19 +111,18 @@ const renameSubmit = (name, eid) => {
} }
const query = $.param({ const query = $.param({
eid: eid eid,
}); });
let url = `${base_url}api/admin/display_name/${titleId}/${name}`; let url = `${base_url}api/admin/display_name/${titleId}/${name}`;
if (eid) if (eid) url += `?${query}`;
url += `?${query}`;
$.ajax({ $.ajax({
type: 'PUT', type: 'PUT',
url: url, url,
contentType: "application/json", contentType: 'application/json',
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', `Failed to update display name. Error: ${data.error}`); alert('danger', `Failed to update display name. Error: ${data.error}`);
return; return;
@ -121,7 +130,10 @@ const renameSubmit = (name, eid) => {
location.reload(); location.reload();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to update display name. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to update display name. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}; };
@ -139,9 +151,9 @@ const renameSortNameSubmit = (name, eid) => {
type: 'PUT', type: 'PUT',
url, url,
contentType: 'application/json', contentType: 'application/json',
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.error) { if (data.error) {
alert('danger', `Failed to update sort title. Error: ${data.error}`); alert('danger', `Failed to update sort title. Error: ${data.error}`);
return; return;
@ -149,7 +161,10 @@ const renameSortNameSubmit = (name, eid) => {
location.reload(); location.reload();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to update sort title. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to update sort title. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}; };
@ -176,7 +191,7 @@ const edit = (eid) => {
const displayNameField = $('#display-name-field'); const displayNameField = $('#display-name-field');
displayNameField.attr('value', displayName); displayNameField.attr('value', displayName);
displayNameField.attr('placeholder', fileTitle); displayNameField.attr('placeholder', fileTitle);
displayNameField.keyup(event => { displayNameField.keyup((event) => {
if (event.keyCode === 13) { if (event.keyCode === 13) {
renameSubmit(displayNameField.val() || fileTitle, eid); renameSubmit(displayNameField.val() || fileTitle, eid);
} }
@ -188,7 +203,7 @@ const edit = (eid) => {
const sortTitleField = $('#sort-title-field'); const sortTitleField = $('#sort-title-field');
sortTitleField.val(sortTitle); sortTitleField.val(sortTitle);
sortTitleField.attr('placeholder', fileTitle); sortTitleField.attr('placeholder', fileTitle);
sortTitleField.keyup(event => { sortTitleField.keyup((event) => {
if (event.keyCode === 13) { if (event.keyCode === 13) {
renameSortNameSubmit(sortTitleField.val(), eid); renameSortNameSubmit(sortTitleField.val(), eid);
} }
@ -217,14 +232,13 @@ const setupUpload = (eid) => {
const bar = $('#upload-progress').get(0); const bar = $('#upload-progress').get(0);
const titleId = upload.attr('data-title-id'); const titleId = upload.attr('data-title-id');
const queryObj = { const queryObj = {
tid: titleId tid: titleId,
}; };
if (eid) if (eid) queryObj['eid'] = eid;
queryObj['eid'] = eid;
const query = $.param(queryObj); const query = $.param(queryObj);
const url = `${base_url}api/admin/upload/cover?${query}`; const url = `${base_url}api/admin/upload/cover?${query}`;
UIkit.upload('.upload-field', { UIkit.upload('.upload-field', {
url: url, url,
name: 'file', name: 'file',
error: (e) => { error: (e) => {
alert('danger', `Failed to upload cover image: ${e.toString()}`); alert('danger', `Failed to upload cover image: ${e.toString()}`);
@ -245,7 +259,7 @@ const setupUpload = (eid) => {
completeAll: () => { completeAll: () => {
$(bar).attr('hidden', ''); $(bar).attr('hidden', '');
location.reload(); location.reload();
} },
}); });
}; };
@ -287,22 +301,28 @@ const bulkProgress = (action, el) => {
const url = `${base_url}api/bulk_progress/${action}/${tid}`; const url = `${base_url}api/bulk_progress/${action}/${tid}`;
$.ajax({ $.ajax({
type: 'PUT', type: 'PUT',
url: url, url,
contentType: "application/json", contentType: 'application/json',
dataType: 'json', dataType: 'json',
data: JSON.stringify({ data: JSON.stringify({
ids: ids ids,
}),
}) })
}) .done((data) => {
.done(data => {
if (data.error) { if (data.error) {
alert('danger', `Failed to mark entries as ${action}. Error: ${data.error}`); alert(
'danger',
`Failed to mark entries as ${action}. Error: ${data.error}`,
);
return; return;
} }
location.reload(); location.reload();
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to mark entries as ${action}. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to mark entries as ${action}. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}) })
.always(() => { .always(() => {
deselectAll(); deselectAll();
@ -325,29 +345,32 @@ const tagsComponent = () => {
disabled: !this.isAdmin, disabled: !this.isAdmin,
templateSelection(state) { templateSelection(state) {
const a = document.createElement('a'); const a = document.createElement('a');
a.setAttribute('href', `${base_url}tags/${encodeURIComponent(state.text)}`); a.setAttribute(
'href',
`${base_url}tags/${encodeURIComponent(state.text)}`,
);
a.setAttribute('class', 'uk-link-reset'); a.setAttribute('class', 'uk-link-reset');
a.onclick = event => { a.onclick = (event) => {
event.stopPropagation(); event.stopPropagation();
}; };
a.innerText = state.text; a.innerText = state.text;
return a; return a;
} },
}); });
this.request(`${base_url}api/tags`, 'GET', (data) => { this.request(`${base_url}api/tags`, 'GET', (data) => {
const allTags = data.tags; const allTags = data.tags;
const url = `${base_url}api/tags/${this.tid}`; const url = `${base_url}api/tags/${this.tid}`;
this.request(url, 'GET', data => { this.request(url, 'GET', (data) => {
this.tags = data.tags; this.tags = data.tags;
allTags.forEach(t => { allTags.forEach((t) => {
const op = new Option(t, t, false, this.tags.indexOf(t) >= 0); const op = new Option(t, t, false, this.tags.indexOf(t) >= 0);
$('.tag-select').append(op); $('.tag-select').append(op);
}); });
$('.tag-select').on('select2:select', e => { $('.tag-select').on('select2:select', (e) => {
this.onAdd(e); this.onAdd(e);
}); });
$('.tag-select').on('select2:unselect', e => { $('.tag-select').on('select2:unselect', (e) => {
this.onDelete(e); this.onDelete(e);
}); });
$('.tag-select').on('change', () => { $('.tag-select').on('change', () => {
@ -359,25 +382,31 @@ const tagsComponent = () => {
}); });
}, },
onChange() { onChange() {
this.tags = $('.tag-select').select2('data').map(o => o.text); this.tags = $('.tag-select')
.select2('data')
.map((o) => o.text);
}, },
onAdd(event) { onAdd(event) {
const tag = event.params.data.text; const tag = event.params.data.text;
const url = `${base_url}api/admin/tags/${this.tid}/${encodeURIComponent(tag)}`; const url = `${base_url}api/admin/tags/${this.tid}/${encodeURIComponent(
tag,
)}`;
this.request(url, 'PUT'); this.request(url, 'PUT');
}, },
onDelete(event) { onDelete(event) {
const tag = event.params.data.text; const tag = event.params.data.text;
const url = `${base_url}api/admin/tags/${this.tid}/${encodeURIComponent(tag)}`; const url = `${base_url}api/admin/tags/${this.tid}/${encodeURIComponent(
tag,
)}`;
this.request(url, 'DELETE'); this.request(url, 'DELETE');
}, },
request(url, method, cb) { request(url, method, cb) {
$.ajax({ $.ajax({
url: url, url,
method: method, method,
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.success) { if (data.success) {
if (cb) cb(data); if (cb) cb(data);
} else { } else {
@ -387,6 +416,6 @@ const tagsComponent = () => {
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert('danger', `Error: [${jqXHR.status}] ${jqXHR.statusText}`);
}); });
} },
}; };
}; };

View File

@ -1,5 +1,5 @@
$(() => { $(() => {
var target = base_url + 'admin/user/edit'; let target = base_url + 'admin/user/edit';
if (username) target += username; if (username) target += username;
$('form').attr('action', target); $('form').attr('action', target);
if (error) alert('danger', error); if (error) alert('danger', error);

View File

@ -2,15 +2,16 @@ const remove = (username) => {
$.ajax({ $.ajax({
url: `${base_url}api/admin/user/delete/${username}`, url: `${base_url}api/admin/user/delete/${username}`,
type: 'DELETE', type: 'DELETE',
dataType: 'json' dataType: 'json',
}) })
.done(data => { .done((data) => {
if (data.success) if (data.success) location.reload();
location.reload(); else alert('danger', data.error);
else
alert('danger', data.error);
}) })
.fail((jqXHR, status) => { .fail((jqXHR, status) => {
alert('danger', `Failed to delete the user. Error: [${jqXHR.status}] ${jqXHR.statusText}`); alert(
'danger',
`Failed to delete the user. Error: [${jqXHR.status}] ${jqXHR.statusText}`,
);
}); });
}; };