Version 5.1 - All the GraphQL #32
@ -4,7 +4,6 @@ install:
|
|||||||
- composer install --ignore-platform-reqs
|
- composer install --ignore-platform-reqs
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 7.3
|
|
||||||
- 7.4
|
- 7.4
|
||||||
- nightly
|
- nightly
|
||||||
|
|
||||||
@ -12,13 +11,6 @@ script:
|
|||||||
- mkdir -p build/logs
|
- mkdir -p build/logs
|
||||||
- php vendor/bin/phpunit -c build
|
- php vendor/bin/phpunit -c build
|
||||||
|
|
||||||
#after_script:
|
|
||||||
# - CODECLIMATE_REPO_TOKEN=2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058 vendor/bin/test-reporter
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- php: nightly
|
- php: nightly
|
||||||
|
|
||||||
#addons:
|
|
||||||
# code_climate:
|
|
||||||
# repo_token: 2cbddcebcb9256b3402867282e119dbe61de0b31039325356af3c7d72ed6d058
|
|
@ -1,8 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Version 5
|
||||||
|
* Updated PHP requirement to 7.4
|
||||||
|
* Added anime watching history view
|
||||||
|
* Added manga reading history view
|
||||||
|
* Updated anime collection to have more media types
|
||||||
|
|
||||||
## Version 4.2
|
## Version 4.2
|
||||||
* Updated dependencies
|
* Updated dependencies
|
||||||
* Updated PHP requirement to 7.3
|
* Updated PHP requirement to 7.3
|
||||||
|
* Added option to automatically set dark mode based on the OS setting
|
||||||
|
|
||||||
## Version 4.1
|
## Version 4.1
|
||||||
* Added optional dark theme
|
* Added optional dark theme
|
||||||
|
12
Jenkinsfile
vendored
12
Jenkinsfile
vendored
@ -10,18 +10,6 @@ pipeline {
|
|||||||
sh 'php composer.phar install --ignore-platform-reqs'
|
sh 'php composer.phar install --ignore-platform-reqs'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage('PHP 7.3') {
|
|
||||||
agent {
|
|
||||||
docker {
|
|
||||||
image 'php:7.3-alpine'
|
|
||||||
args '-u root --privileged'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
sh 'apk add --no-cache git'
|
|
||||||
sh 'php ./vendor/bin/phpunit --colors=never'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('PHP 7.4') {
|
stage('PHP 7.4') {
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# Hummingbird Anime Client
|
# Hummingbird Anime Client
|
||||||
|
|
||||||
Update your anime/manga list on Kitsu.io and MyAnimeList.net
|
Update your anime/manga list on Kitsu.io and Anilist
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.org/timw4mail/HummingBirdAnimeClient)
|
[![Build Status](https://travis-ci.com/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.com/github/timw4mail/HummingBirdAnimeClient)
|
||||||
[![Build Status](https://jenkins.timshomepage.net/buildStatus/icon?job=timw4mail/HummingBirdAnimeClient/develop)](https://jenkins.timshomepage.net/job/timw4mail/HummingBirdAnimeClient/develop)
|
[![Build Status](https://jenkins.timshomepage.net/buildStatus/icon?job=timw4mail/HummingBirdAnimeClient/develop)](https://jenkins.timshomepage.net/job/timw4mail/HummingBirdAnimeClient/develop)
|
||||||
|
|
||||||
[[Hosted Example](https://list.timshomepage.net)]
|
[[Hosted Example](https://list.timshomepage.net)]
|
||||||
@ -31,7 +31,7 @@ Update your anime/manga list on Kitsu.io and MyAnimeList.net
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
* PHP 7.3+
|
* PHP 7.4+
|
||||||
* PDO SQLite or PDO PostgreSQL (For collection tab)
|
* PDO SQLite or PDO PostgreSQL (For collection tab)
|
||||||
* GD extension for caching images
|
* GD extension for caching images
|
||||||
|
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
[anime_list]
|
[anime_list]
|
||||||
route_prefix = "/anime"
|
route_prefix = ""
|
||||||
[anime_list.items]
|
[anime_list.items]
|
||||||
watching = '/watching'
|
watch_history = '/history/anime'
|
||||||
plan_to_watch = '/plan_to_watch'
|
watching = '/anime/watching'
|
||||||
on_hold = '/on_hold'
|
plan_to_watch = '/anime/plan_to_watch'
|
||||||
dropped = '/dropped'
|
on_hold = '/anime/on_hold'
|
||||||
completed = '/completed'
|
dropped = '/anime/dropped'
|
||||||
all = '/all'
|
completed = '/anime/completed'
|
||||||
|
all = '/anime/all'
|
||||||
|
|
||||||
[manga_list]
|
[manga_list]
|
||||||
route_prefix = "/manga"
|
route_prefix = ""
|
||||||
[manga_list.items]
|
[manga_list.items]
|
||||||
reading = '/reading'
|
reading_history = '/history/manga'
|
||||||
plan_to_read = '/plan_to_read'
|
reading = '/manga/reading'
|
||||||
on_hold = '/on_hold'
|
plan_to_read = '/manga/plan_to_read'
|
||||||
dropped = '/dropped'
|
on_hold = '/manga/on_hold'
|
||||||
completed = '/completed'
|
dropped = '/manga/dropped'
|
||||||
all = '/all'
|
completed = '/manga/completed'
|
||||||
|
all = '/manga/all'
|
@ -279,6 +279,13 @@ $routes = [
|
|||||||
'view' => ALPHA_SLUG_PATTERN,
|
'view' => ALPHA_SLUG_PATTERN,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
'history' => [
|
||||||
|
'controller' => 'history',
|
||||||
|
'path' => '/history/{type}',
|
||||||
|
'tokens' => [
|
||||||
|
'type' => SLUG_PATTERN
|
||||||
|
]
|
||||||
|
],
|
||||||
'index_redirect' => [
|
'index_redirect' => [
|
||||||
'path' => '/',
|
'path' => '/',
|
||||||
'action' => 'redirectToDefaultRoute',
|
'action' => 'redirectToDefaultRoute',
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -28,14 +28,15 @@ use Aviat\AnimeClient\Model;
|
|||||||
use Aviat\Banker\Pool;
|
use Aviat\Banker\Pool;
|
||||||
use Aviat\Ion\Config;
|
use Aviat\Ion\Config;
|
||||||
use Aviat\Ion\Di\Container;
|
use Aviat\Ion\Di\Container;
|
||||||
|
use Aviat\Ion\Di\ContainerInterface;
|
||||||
|
use Laminas\Diactoros\{Response, ServerRequestFactory};
|
||||||
use Monolog\Handler\RotatingFileHandler;
|
use Monolog\Handler\RotatingFileHandler;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
use Zend\Diactoros\{Response, ServerRequestFactory};
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Setup DI container
|
// Setup DI container
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
return static function ($configArray = []) {
|
return static function (array $configArray = []): Container {
|
||||||
$container = new Container();
|
$container = new Container();
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@ -60,26 +61,20 @@ return static function ($configArray = []) {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
// Create Config Object
|
// Create Config Object
|
||||||
$container->set('config', static function() use ($configArray) {
|
$container->set('config', fn () => new Config($configArray));
|
||||||
return new Config($configArray);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create Cache Object
|
// Create Cache Object
|
||||||
$container->set('cache', static function($container): Pool {
|
$container->set('cache', static function(ContainerInterface $container): Pool {
|
||||||
$logger = $container->getLogger();
|
$logger = $container->getLogger();
|
||||||
$config = $container->get('config')->get('cache');
|
$config = $container->get('config')->get('cache');
|
||||||
return new Pool($config, $logger);
|
return new Pool($config, $logger);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create List Cache
|
|
||||||
|
|
||||||
// Create Aura Router Object
|
// Create Aura Router Object
|
||||||
$container->set('aura-router', static function() {
|
$container->set('aura-router', fn() => new RouterContainer);
|
||||||
return new RouterContainer;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create Html helper Object
|
// Create Html helper Object
|
||||||
$container->set('html-helper', static function($container) {
|
$container->set('html-helper', static function(ContainerInterface $container) {
|
||||||
$htmlHelper = (new HelperLocatorFactory)->newInstance();
|
$htmlHelper = (new HelperLocatorFactory)->newInstance();
|
||||||
$htmlHelper->set('menu', static function() use ($container) {
|
$htmlHelper->set('menu', static function() use ($container) {
|
||||||
$menuHelper = new Helper\Menu();
|
$menuHelper = new Helper\Menu();
|
||||||
@ -101,31 +96,23 @@ return static function ($configArray = []) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Create Request/Response Objects
|
// Create Request/Response Objects
|
||||||
$container->set('request', static function() {
|
$container->set('request', fn () => ServerRequestFactory::fromGlobals(
|
||||||
return ServerRequestFactory::fromGlobals(
|
$_SERVER,
|
||||||
$_SERVER,
|
$_GET,
|
||||||
$_GET,
|
$_POST,
|
||||||
$_POST,
|
$_COOKIE,
|
||||||
$_COOKIE,
|
$_FILES
|
||||||
$_FILES
|
));
|
||||||
);
|
$container->set('response', fn () => new Response);
|
||||||
});
|
|
||||||
$container->set('response', static function() {
|
|
||||||
return new Response;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create session Object
|
// Create session Object
|
||||||
$container->set('session', static function() {
|
$container->set('session', fn () => (new SessionFactory())->newInstance($_COOKIE));
|
||||||
return (new SessionFactory())->newInstance($_COOKIE);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Miscellaneous helper methods
|
// Miscellaneous helper methods
|
||||||
$container->set('util', static function($container): Util {
|
$container->set('util', fn ($container) => new Util($container));
|
||||||
return new Util($container);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
$container->set('kitsu-model', static function($container): Kitsu\Model {
|
$container->set('kitsu-model', static function(ContainerInterface $container): Kitsu\Model {
|
||||||
$requestBuilder = new KitsuRequestBuilder();
|
$requestBuilder = new KitsuRequestBuilder();
|
||||||
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
$requestBuilder->setLogger($container->getLogger('kitsu-request'));
|
||||||
|
|
||||||
@ -141,7 +128,7 @@ return static function ($configArray = []) {
|
|||||||
$model->setCache($cache);
|
$model->setCache($cache);
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
$container->set('anilist-model', static function($container): Anilist\Model {
|
$container->set('anilist-model', static function(ContainerInterface $container): Anilist\Model {
|
||||||
$requestBuilder = new Anilist\AnilistRequestBuilder();
|
$requestBuilder = new Anilist\AnilistRequestBuilder();
|
||||||
$requestBuilder->setLogger($container->getLogger('anilist-request'));
|
$requestBuilder->setLogger($container->getLogger('anilist-request'));
|
||||||
|
|
||||||
@ -155,39 +142,24 @@ return static function ($configArray = []) {
|
|||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
|
$container->set('anime-model', fn ($container) => new Model\Anime($container));
|
||||||
$container->set('anime-model', static function($container) {
|
$container->set('manga-model', fn ($container) => new Model\Manga($container));
|
||||||
return new Model\Anime($container);
|
$container->set('anime-collection-model', fn ($container) => new Model\AnimeCollection($container));
|
||||||
});
|
$container->set('manga-collection-model', fn ($container) => new Model\MangaCollection($container));
|
||||||
$container->set('manga-model', static function($container) {
|
|
||||||
return new Model\Manga($container);
|
|
||||||
});
|
|
||||||
$container->set('anime-collection-model', static function($container) {
|
|
||||||
return new Model\AnimeCollection($container);
|
|
||||||
});
|
|
||||||
$container->set('manga-collection-model', static function($container) {
|
|
||||||
return new Model\MangaCollection($container);
|
|
||||||
});
|
|
||||||
$container->set('settings-model', static function($container) {
|
$container->set('settings-model', static function($container) {
|
||||||
$model = new Model\Settings($container->get('config'));
|
$model = new Model\Settings($container->get('config'));
|
||||||
$model->setContainer($container);
|
$model->setContainer($container);
|
||||||
return $model;
|
return $model;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Miscellaneous Classes
|
// Miscellaneous Classes
|
||||||
$container->set('auth', static function($container) {
|
$container->set('auth', fn ($container) => new Kitsu\Auth($container));
|
||||||
return new Kitsu\Auth($container);
|
$container->set('url-generator', fn ($container) => new UrlGenerator($container));
|
||||||
});
|
|
||||||
$container->set('url-generator', static function($container) {
|
|
||||||
return new UrlGenerator($container);
|
|
||||||
});
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Dispatcher
|
// Dispatcher
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
$container->set('dispatcher', static function($container) {
|
$container->set('dispatcher', fn ($container) => new Dispatcher($container));
|
||||||
return new Dispatcher($container);
|
|
||||||
});
|
|
||||||
|
|
||||||
return $container;
|
return $container;
|
||||||
};
|
};
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2>Add Anime to your List</h2>
|
<h2>Add Anime to your List</h2>
|
||||||
<form action="<?= $action_url ?>" method="post">
|
<form action="<?= $action_url ?>" method="post">
|
||||||
|
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
|
||||||
<section>
|
<section>
|
||||||
<div class="cssload-loader" hidden="hidden">
|
<div class="cssload-loader" hidden="hidden">
|
||||||
<div class="cssload-inner cssload-one"></div>
|
<div class="cssload-inner cssload-one"></div>
|
||||||
|
@ -75,20 +75,20 @@
|
|||||||
<?php foreach($item['anime']['streaming_links'] as $link): ?>
|
<?php foreach($item['anime']['streaming_links'] as $link): ?>
|
||||||
<?php if ($link['meta']['link'] !== FALSE): ?>
|
<?php if ($link['meta']['link'] !== FALSE): ?>
|
||||||
<a href="<?= $link['link'] ?>" title="Stream '<?= $item['anime']['title'] ?>' on <?= $link['meta']['name'] ?>">
|
<a href="<?= $link['link'] ?>" title="Stream '<?= $item['anime']['title'] ?>' on <?= $link['meta']['name'] ?>">
|
||||||
<?= $helper->picture("images/{$link['meta']['image']}", 'svg', [
|
<?= $helper->img("/public/images/{$link['meta']['image']}", [
|
||||||
'class' => 'streaming-logo',
|
'class' => 'streaming-logo',
|
||||||
'width' => 50,
|
'width' => 50,
|
||||||
'height' => 50,
|
'height' => 50,
|
||||||
'alt' => "{$link['meta']['name']} logo",
|
'alt' => "{$link['meta']['name']} logo",
|
||||||
]); ?>
|
]) ?>
|
||||||
</a>
|
</a>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= $helper->picture("images/{$link['meta']['image']}", 'svg', [
|
<?= $helper->img("/public/images/{$link['meta']['image']}", [
|
||||||
'class' => 'streaming-logo',
|
'class' => 'streaming-logo',
|
||||||
'width' => 50,
|
'width' => 50,
|
||||||
'height' => 50,
|
'height' => 50,
|
||||||
'alt' => "{$link['meta']['name']} logo",
|
'alt' => "{$link['meta']['name']} logo",
|
||||||
]); ?>
|
]) ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</td>
|
</td>
|
||||||
|
11
app/views/collection/_media-list.php
Normal file
11
app/views/collection/_media-list.php
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<select name="media_id[]" id="media_id" multiple size="13">
|
||||||
|
<?php foreach ($media_items as $group => $items): ?>
|
||||||
|
<optgroup label='<?= $group ?>'>
|
||||||
|
<?php foreach ($items as $id => $name): ?>
|
||||||
|
<option <?= in_array($id, ($item['media_id'] ?? []), FALSE) ? 'selected="selected"' : '' ?> value="<?= $id ?>">
|
||||||
|
<?= $name ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</optgroup>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select>
|
@ -2,6 +2,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2>Add <?= ucfirst($collection_type) ?> to your Collection</h2>
|
<h2>Add <?= ucfirst($collection_type) ?> to your Collection</h2>
|
||||||
<form action="<?= $action_url ?>" method="post">
|
<form action="<?= $action_url ?>" method="post">
|
||||||
|
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
|
||||||
<section>
|
<section>
|
||||||
<div class="cssload-loader" hidden="hidden">
|
<div class="cssload-loader" hidden="hidden">
|
||||||
<div class="cssload-inner cssload-one"></div>
|
<div class="cssload-inner cssload-one"></div>
|
||||||
@ -16,13 +17,9 @@
|
|||||||
<table class="invisible form">
|
<table class="invisible form">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><label for="media_id">Media</label></td>
|
<td class="align-right"><label for="media_id">Media</label></td>
|
||||||
<td>
|
<td class='align-left'>
|
||||||
<select name="media_id" id="media_id">
|
<?php include '_media-list.php' ?>
|
||||||
<?php foreach($media_items as $id => $name): ?>
|
|
||||||
<option value="<?= $id ?>"><?= $name ?></option>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</select>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -24,11 +24,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="align-right"><label for="media_id">Media</label></td>
|
<td class="align-right"><label for="media_id">Media</label></td>
|
||||||
<td class="align-left">
|
<td class="align-left">
|
||||||
<select name="media_id" id="media_id">
|
<?php include '_media-list.php' ?>
|
||||||
<?php foreach($media_items as $id => $name): ?>
|
|
||||||
<option <?= $item['media_id'] === $id ? 'selected="selected"' : '' ?> value="<?= $id ?>"><?= $name ?></option>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</select>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
</section>
|
</section>
|
||||||
<script nomodule="nomodule" src="https://polyfill.io/v3/polyfill.min.js?features=es5%2CObject.assign"></script>
|
<script nomodule="nomodule" src="https://polyfill.io/v3/polyfill.min.js?features=es5%2CObject.assign"></script>
|
||||||
<?php if ($auth->isAuthenticated()): ?>
|
<?php if ($auth->isAuthenticated()): ?>
|
||||||
<script nomodule='nomodule' async="async" defer="defer" src="<?= $urlGenerator->assetUrl('js/scripts-authed.min.js') ?>"></script>
|
<script nomodule='nomodule' async="async" defer="defer" src="<?= $urlGenerator->assetUrl('js/scripts.min.js') ?>"></script>
|
||||||
<script type="module" src="<?= $urlGenerator->assetUrl('js/src/index-authed.js') ?>"></script>
|
<script type="module" src="<?= $urlGenerator->assetUrl('es/scripts.js') ?>"></script>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<script nomodule="nomodule" async="async" defer="defer" src="<?= $urlGenerator->assetUrl('js/scripts.min.js') ?>"></script>
|
<script nomodule="nomodule" async="async" defer="defer" src="<?= $urlGenerator->assetUrl('js/anon.min.js') ?>"></script>
|
||||||
<script type="module" src="<?= $urlGenerator->assetUrl('js/src/index.js') ?>"></script>
|
<script type="module" src="<?= $urlGenerator->assetUrl('es/anon.js') ?>"></script>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -6,11 +6,7 @@
|
|||||||
<meta http-equiv="cache-control" content="no-store" />
|
<meta http-equiv="cache-control" content="no-store" />
|
||||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
|
<meta http-equiv="Content-Security-Policy" content="script-src 'self'" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=1" />
|
||||||
<?php if ($config->get('theme') !== 'auto'): ?>
|
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/' . $config->get('theme') . '.min.css') ?>" />
|
||||||
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/app.min.css') ?>" />
|
|
||||||
<?php elseif ($config->get('theme') === 'auto'): ?>
|
|
||||||
<link rel="stylesheet" href="<?= $urlGenerator->assetUrl('css/dark-auto.min.css') ?>" />
|
|
||||||
<?php endif ?>
|
|
||||||
<link rel="<?= $config->get('theme') === 'dark' ? '' : 'alternate ' ?>stylesheet" title="Dark Theme" href="<?= $urlGenerator->assetUrl('css/dark.min.css') ?>" />
|
<link rel="<?= $config->get('theme') === 'dark' ? '' : 'alternate ' ?>stylesheet" title="Dark Theme" href="<?= $urlGenerator->assetUrl('css/dark.min.css') ?>" />
|
||||||
<link rel="icon" href="<?= $urlGenerator->assetUrl('images/icons/favicon.ico') ?>" />
|
<link rel="icon" href="<?= $urlGenerator->assetUrl('images/icons/favicon.ico') ?>" />
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-57x57.png') ?>">
|
<link rel="apple-touch-icon" sizes="57x57" href="<?= $urlGenerator->assetUrl('images/icons/apple-icon-57x57.png') ?>">
|
||||||
|
49
app/views/history.php
Normal file
49
app/views/history.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<main class="details fixed">
|
||||||
|
<?php if (empty($items)): ?>
|
||||||
|
<h3>No recent history.</h3>
|
||||||
|
<?php else: ?>
|
||||||
|
<section>
|
||||||
|
<?php foreach ($items as $name => $item): ?>
|
||||||
|
<article class="flex flex-no-wrap flex-justify-start">
|
||||||
|
<section class="flex-self-center history-img">
|
||||||
|
<a href="<?= $item['url'] ?>">
|
||||||
|
<?= $helper->picture(
|
||||||
|
$item['coverImg'],
|
||||||
|
'jpg',
|
||||||
|
['width' => '110px', 'height' => '156px'],
|
||||||
|
['width' => '110px', 'height' => '156px']
|
||||||
|
) ?>
|
||||||
|
</a>
|
||||||
|
</section>
|
||||||
|
<section class="flex-self-center">
|
||||||
|
<?= $helper->a($item['url'], $item['title']) ?>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<?= $item['action'] ?>
|
||||||
|
<br />
|
||||||
|
<small>
|
||||||
|
<?php if ( ! empty($item['dateRange'])):
|
||||||
|
[$startDate, $endDate] = array_map(
|
||||||
|
fn ($date) => $date->format('l, F d'),
|
||||||
|
$item['dateRange']
|
||||||
|
);
|
||||||
|
[$startTime, $endTime] = array_map(
|
||||||
|
fn ($date) => $date->format('h:i:s A'),
|
||||||
|
$item['dateRange']
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<?php if ($startDate === $endDate): ?>
|
||||||
|
<?= "{$startDate}, {$startTime} – {$endTime}" ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= "{$startDate} {$startTime} – {$endDate} {$endTime}" ?>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?= $item['updated']->format('l, F d h:i:s A') ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</small>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</section>
|
||||||
|
<?php endif ?>
|
||||||
|
</main>
|
6
app/views/js-warning.php
Normal file
6
app/views/js-warning.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<noscript>
|
||||||
|
<div class="message error">
|
||||||
|
<span class="icon"></span>
|
||||||
|
This feature requires Javascript to function :(
|
||||||
|
</div>
|
||||||
|
</noscript>
|
@ -79,10 +79,12 @@ $hasManga = stripos($_SERVER['REQUEST_URI'], 'manga') !== FALSE;
|
|||||||
<nav>
|
<nav>
|
||||||
<?php if ($container->get('util')->isViewPage() && ($hasAnime || $hasManga)): ?>
|
<?php if ($container->get('util')->isViewPage() && ($hasAnime || $hasManga)): ?>
|
||||||
<?= $helper->menu($menu_name) ?>
|
<?= $helper->menu($menu_name) ?>
|
||||||
|
<?php if (stripos($_SERVER['REQUEST_URI'], 'history') === FALSE): ?>
|
||||||
<br />
|
<br />
|
||||||
<ul>
|
<ul>
|
||||||
<li class="<?= Util::isNotSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url($route_path) ?>">Cover View</a></li>
|
<li class="<?= Util::isNotSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url($route_path) ?>">Cover View</a></li>
|
||||||
<li class="<?= Util::isSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url("{$route_path}/list") ?>">List View</a></li>
|
<li class="<?= Util::isSelected('list', $lastSegment) ?>"><a href="<?= $urlGenerator->url("{$route_path}/list") ?>">List View</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<?php endif ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<main>
|
<main>
|
||||||
<h2>Add Manga to your List</h2>
|
<h2>Add Manga to your List</h2>
|
||||||
<form action="<?= $action_url ?>" method="post">
|
<form action="<?= $action_url ?>" method="post">
|
||||||
|
<?php include realpath(__DIR__ . '/../js-warning.php') ?>
|
||||||
<section>
|
<section>
|
||||||
<div class="cssload-loader" hidden="hidden">
|
<div class="cssload-loader" hidden="hidden">
|
||||||
<div class="cssload-inner cssload-one"></div>
|
<div class="cssload-inner cssload-one"></div>
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
"config": {
|
"config": {
|
||||||
"lock": false,
|
"lock": false,
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "7.3"
|
"php": "7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"aura/router": "^3.0",
|
"aura/router": "^3.0",
|
||||||
"aura/session": "^2.0",
|
"aura/session": "^2.0",
|
||||||
"aviat/banker": "^2.0.0",
|
"aviat/banker": "^2.0.0",
|
||||||
"aviat/query": "^2.5.1",
|
"aviat/query": "^3.0.0",
|
||||||
"danielstjules/stringy": "^3.1.0",
|
"danielstjules/stringy": "^3.1.0",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-iconv": "*",
|
"ext-iconv": "*",
|
||||||
@ -50,7 +50,7 @@
|
|||||||
"laminas/laminas-httphandlerrunner": "^1.0",
|
"laminas/laminas-httphandlerrunner": "^1.0",
|
||||||
"maximebf/consolekit": "^1.0",
|
"maximebf/consolekit": "^1.0",
|
||||||
"monolog/monolog": "^2.0.1",
|
"monolog/monolog": "^2.0.1",
|
||||||
"php": "^7.3",
|
"php": ">=7.4",
|
||||||
"psr/container": "~1.0",
|
"psr/container": "~1.0",
|
||||||
"psr/http-message": "~1.0",
|
"psr/http-message": "~1.0",
|
||||||
"psr/log": "~1.0",
|
"psr/log": "~1.0",
|
||||||
@ -60,14 +60,14 @@
|
|||||||
"consolidation/robo": "^2.0.0",
|
"consolidation/robo": "^2.0.0",
|
||||||
"filp/whoops": "^2.1",
|
"filp/whoops": "^2.1",
|
||||||
"pdepend/pdepend": "^2.2",
|
"pdepend/pdepend": "^2.2",
|
||||||
"phploc/phploc": "^5.0",
|
"phploc/phploc": "^6.0.2",
|
||||||
"phpmd/phpmd": "^2.8",
|
"phpmd/phpmd": "^2.8",
|
||||||
"phpstan/phpstan": "^0.12.0",
|
"phpstan/phpstan": "^0.12.0",
|
||||||
"phpunit/phpunit": "^8.4.3",
|
"phpunit/phpunit": "^9.1.1",
|
||||||
"roave/security-advisories": "dev-master",
|
"roave/security-advisories": "dev-master",
|
||||||
"robmorgan/phinx": "^0.10.6",
|
"robmorgan/phinx": "^0.10.6",
|
||||||
"sebastian/phpcpd": "^4.1.0",
|
"sebastian/phpcpd": "^5.0.2",
|
||||||
"spatie/phpunit-snapshot-assertions": "^2.2.1",
|
"spatie/phpunit-snapshot-assertions": "^4.1.0",
|
||||||
"squizlabs/php_codesniffer": "^3.2.2",
|
"squizlabs/php_codesniffer": "^3.2.2",
|
||||||
"symfony/var-dumper": "^5",
|
"symfony/var-dumper": "^5",
|
||||||
"theseer/phpdox": "*"
|
"theseer/phpdox": "*"
|
||||||
|
4
console
4
console
@ -15,14 +15,12 @@ $_SERVER['HTTP_HOST'] = 'localhost';
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
(new Console([
|
(new Console([
|
||||||
'cache:clear' => Command\CacheClear::class,
|
|
||||||
'cache:refresh' => Command\CachePrime::class,
|
|
||||||
'clear:cache' => Command\CacheClear::class,
|
'clear:cache' => Command\CacheClear::class,
|
||||||
'clear:thumbnails' => Command\ClearThumbnails::class,
|
'clear:thumbnails' => Command\ClearThumbnails::class,
|
||||||
'refresh:cache' => Command\CachePrime::class,
|
'refresh:cache' => Command\CachePrime::class,
|
||||||
'refresh:thumbnails' => Command\UpdateThumbnails::class,
|
'refresh:thumbnails' => Command\UpdateThumbnails::class,
|
||||||
'regenerate-thumbnails' => Command\UpdateThumbnails::class,
|
|
||||||
'lists:sync' => Command\SyncLists::class,
|
'lists:sync' => Command\SyncLists::class,
|
||||||
|
'sync:lists' => Command\SyncLists::class
|
||||||
]))->run();
|
]))->run();
|
||||||
}
|
}
|
||||||
catch (\Exception $e)
|
catch (\Exception $e)
|
||||||
|
68
frontEndSrc/build-js.js
Normal file
68
frontEndSrc/build-js.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import compiler from '@ampproject/rollup-plugin-closure-compiler';
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
compiler({
|
||||||
|
assumeFunctionWrapper: true,
|
||||||
|
compilationLevel: 'WHITESPACE_ONLY', //'ADVANCED',
|
||||||
|
createSourceMap: true,
|
||||||
|
env: 'BROWSER',
|
||||||
|
languageIn: 'ECMASCRIPT_2018',
|
||||||
|
languageOut: 'ES3'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
const defaultOutput = {
|
||||||
|
format: 'iife',
|
||||||
|
sourcemap: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
const nonModules = [{
|
||||||
|
input: './js/anon.js',
|
||||||
|
output: {
|
||||||
|
...defaultOutput,
|
||||||
|
file: '../public/js/anon.min.js',
|
||||||
|
sourcemapFile: '../public/js/anon.min.js.map',
|
||||||
|
},
|
||||||
|
plugins,
|
||||||
|
}, {
|
||||||
|
input: './js/index.js',
|
||||||
|
output: {
|
||||||
|
...defaultOutput,
|
||||||
|
file: '../public/js/scripts.min.js',
|
||||||
|
sourcemapFile: '../public/js/scripts.min.js.map',
|
||||||
|
},
|
||||||
|
plugins,
|
||||||
|
}, {
|
||||||
|
input: './js/base/sort-tables.js',
|
||||||
|
output: {
|
||||||
|
...defaultOutput,
|
||||||
|
file: '../public/js/tables.min.js',
|
||||||
|
sourcemapFile: '../public/js/tables.min.js.map',
|
||||||
|
},
|
||||||
|
plugins,
|
||||||
|
}];
|
||||||
|
|
||||||
|
const moduleOutput = {
|
||||||
|
format: 'es',
|
||||||
|
sourcemap: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
let modules = [{
|
||||||
|
input: './js/anon.js',
|
||||||
|
output: {
|
||||||
|
...moduleOutput,
|
||||||
|
file: '../public/es/anon.js',
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
input: './js/index.js',
|
||||||
|
output: {
|
||||||
|
...moduleOutput,
|
||||||
|
file: '../public/es/scripts.js',
|
||||||
|
},
|
||||||
|
}];
|
||||||
|
|
||||||
|
// Return the config array for rollup
|
||||||
|
export default [
|
||||||
|
...nonModules,
|
||||||
|
...modules,
|
||||||
|
];
|
70
frontEndSrc/css.js
Normal file
70
frontEndSrc/css.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Script for optimizing css
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const postcss = require('postcss');
|
||||||
|
const atImport = require('postcss-import');
|
||||||
|
const cssNext = require('postcss-preset-env');
|
||||||
|
const cssNano = require('cssnano');
|
||||||
|
|
||||||
|
const lightCss = fs.readFileSync('css/light.css', 'utf-8');
|
||||||
|
const darkCss = fs.readFileSync('css/src/dark-override.css', 'utf-8');
|
||||||
|
const fullDarkCss = fs.readFileSync('css/dark.css', 'utf-8');
|
||||||
|
|
||||||
|
const minOptions = {
|
||||||
|
autoprefixer: false,
|
||||||
|
colormin: false,
|
||||||
|
minifyFontValues: false,
|
||||||
|
options: {
|
||||||
|
sourcemap: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const processOptions = {
|
||||||
|
browser: '> 0.5%',
|
||||||
|
features: {
|
||||||
|
'custom-properties': true,
|
||||||
|
},
|
||||||
|
stage: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
(async () => {
|
||||||
|
// Basic theme
|
||||||
|
const lightMin = await postcss()
|
||||||
|
.use(atImport())
|
||||||
|
.use(cssNext(processOptions))
|
||||||
|
.use(cssNano(minOptions))
|
||||||
|
.process(lightCss, {
|
||||||
|
from: 'css/light.css',
|
||||||
|
to: '/public/css/light.min.css',
|
||||||
|
}).catch(console.error);
|
||||||
|
fs.writeFileSync('../public/css/light.min.css', lightMin.css);
|
||||||
|
|
||||||
|
// Dark theme
|
||||||
|
const darkFullMin = await postcss()
|
||||||
|
.use(atImport())
|
||||||
|
.use(cssNext(processOptions))
|
||||||
|
.use(cssNano(minOptions))
|
||||||
|
.process(fullDarkCss, {
|
||||||
|
from: 'css/dark.css',
|
||||||
|
to: '/public/css/dark.min.css',
|
||||||
|
});
|
||||||
|
fs.writeFileSync('../public/css/dark.min.css', darkFullMin.css);
|
||||||
|
|
||||||
|
// Dark override
|
||||||
|
const darkMin = await postcss()
|
||||||
|
.use(atImport())
|
||||||
|
.use(cssNext(processOptions))
|
||||||
|
.use(cssNano(minOptions))
|
||||||
|
.process(darkCss, {
|
||||||
|
from: 'css/dark-override.css',
|
||||||
|
to: '/public/css/dark.min.css',
|
||||||
|
}).catch(console.error);
|
||||||
|
const autoDarkCss = `${lightMin} @media (prefers-color-scheme: dark) { ${darkMin.css} }`
|
||||||
|
fs.writeFileSync('../public/css/auto.min.css', autoDarkCss)
|
||||||
|
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
3
frontEndSrc/css/auto.css
Normal file
3
frontEndSrc/css/auto.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
@import "src/dark-override.css";
|
||||||
|
}
|
5
frontEndSrc/css/dark.css
Normal file
5
frontEndSrc/css/dark.css
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
@import "src/-marx-.css";
|
||||||
|
@import "src/general.css";
|
||||||
|
@import "src/components.css";
|
||||||
|
@import "src/responsive.css";
|
||||||
|
@import "src/dark-override.css";
|
4
frontEndSrc/css/light.css
Normal file
4
frontEndSrc/css/light.css
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
@import "src/-marx-.css";
|
||||||
|
@import "src/general.css";
|
||||||
|
@import "src/components.css";
|
||||||
|
@import "src/responsive.css";
|
@ -87,6 +87,10 @@ tbody > tr:nth-child(odd) {
|
|||||||
background: #ddd;
|
background: #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select[multiple] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
a:hover, a:active {
|
a:hover, a:active {
|
||||||
color: var(--link-hover-color)
|
color: var(--link-hover-color)
|
||||||
}
|
}
|
||||||
@ -888,6 +892,11 @@ aside picture, aside img {
|
|||||||
filter: drop-shadow(0 -1px 4px #fff);
|
filter: drop-shadow(0 -1px 4px #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.history-img {
|
||||||
|
width: 110px;
|
||||||
|
height: 156px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------------
|
/* ----------------------------------------------------------------------------
|
||||||
Settings Form
|
Settings Form
|
||||||
-----------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------*/
|
@ -3,9 +3,9 @@
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
const matches = (elm, selector) => {
|
const matches = (elm, selector) => {
|
||||||
let matches = (elm.document || elm.ownerDocument).querySelectorAll(selector),
|
let m = (elm.document || elm.ownerDocument).querySelectorAll(selector);
|
||||||
i = matches.length;
|
let i = matches.length;
|
||||||
while (--i >= 0 && matches.item(i) !== elm) {};
|
while (--i >= 0 && m.item(i) !== elm) {};
|
||||||
return i > -1;
|
return i > -1;
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
import _ from './base/AnimeClient.js'
|
import _ from './anime-client.js'
|
||||||
import { renderAnimeSearchResults } from './template-helpers.js'
|
import { renderAnimeSearchResults } from './template-helpers.js'
|
||||||
|
|
||||||
const search = (query) => {
|
const search = (query) => {
|
@ -1,4 +1,4 @@
|
|||||||
import './base/events.js';
|
import './events.js';
|
||||||
|
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.register('/sw.js').then(reg => {
|
navigator.serviceWorker.register('/sw.js').then(reg => {
|
@ -1,31 +1,61 @@
|
|||||||
import _ from './AnimeClient.js';
|
import _ from './anime-client.js';
|
||||||
/**
|
|
||||||
* Event handlers
|
|
||||||
*/
|
|
||||||
// Close event for messages
|
|
||||||
_.on('header', 'click', '.message', (e) => {
|
|
||||||
_.hide(e.target);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Confirm deleting of list or library items
|
// ----------------------------------------------------------------------------
|
||||||
_.on('form.js-delete', 'submit', (event) => {
|
// Event subscriptions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
_.on('header', 'click', '.message', hide);
|
||||||
|
_.on('form.js-delete', 'submit', confirmDelete);
|
||||||
|
_.on('.js-clear-cache', 'click', clearAPICache);
|
||||||
|
_.on('.vertical-tabs input', 'change', scrollToSection);
|
||||||
|
_.on('.media-filter', 'input', filterMedia);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Handler functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the html element attached to the event
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function hide (event) {
|
||||||
|
_.hide(event.target)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm deletion of an item
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function confirmDelete (event) {
|
||||||
const proceed = confirm('Are you ABSOLUTELY SURE you want to delete this item?');
|
const proceed = confirm('Are you ABSOLUTELY SURE you want to delete this item?');
|
||||||
|
|
||||||
if (proceed === false) {
|
if (proceed === false) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Clear the api cache
|
/**
|
||||||
_.on('.js-clear-cache', 'click', () => {
|
* Clear the API cache, and show a message if the cache is cleared
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function clearAPICache () {
|
||||||
_.get('/cache_purge', () => {
|
_.get('/cache_purge', () => {
|
||||||
_.showMessage('success', 'Successfully purged api cache');
|
_.showMessage('success', 'Successfully purged api cache');
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// Alleviate some page jumping
|
/**
|
||||||
_.on('.vertical-tabs input', 'change', (event) => {
|
* Scroll to the accordion/vertical tab section just opened
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function scrollToSection (event) {
|
||||||
const el = event.currentTarget.parentElement;
|
const el = event.currentTarget.parentElement;
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
@ -35,10 +65,15 @@ _.on('.js-clear-cache', 'click', () => {
|
|||||||
top,
|
top,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
// Filter the current page (cover view)
|
/**
|
||||||
_.on('.media-filter', 'input', (event) => {
|
* Filter an anime or manga list
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function filterMedia (event) {
|
||||||
const rawFilter = event.target.value;
|
const rawFilter = event.target.value;
|
||||||
const filter = new RegExp(rawFilter, 'i');
|
const filter = new RegExp(rawFilter, 'i');
|
||||||
|
|
||||||
@ -72,4 +107,4 @@ _.on('.media-filter', 'input', (event) => {
|
|||||||
_.show('article.media');
|
_.show('article.media');
|
||||||
_.show('table.media-wrap tbody tr');
|
_.show('table.media-wrap tbody tr');
|
||||||
}
|
}
|
||||||
});
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import './index.js';
|
import './anon.js';
|
||||||
|
|
||||||
import './anime.js';
|
import './anime.js';
|
||||||
import './manga.js';
|
import './manga.js';
|
@ -1,4 +1,4 @@
|
|||||||
import _ from './base/AnimeClient.js'
|
import _ from './anime-client.js'
|
||||||
import { renderMangaSearchResults } from './template-helpers.js'
|
import { renderMangaSearchResults } from './template-helpers.js'
|
||||||
|
|
||||||
const search = (query) => {
|
const search = (query) => {
|
@ -1,4 +1,4 @@
|
|||||||
import _ from './base/AnimeClient.js';
|
import _ from './anime-client.js';
|
||||||
|
|
||||||
// Click on hidden MAL checkbox so
|
// Click on hidden MAL checkbox so
|
||||||
// that MAL id is passed
|
// that MAL id is passed
|
||||||
@ -12,9 +12,7 @@ export function renderAnimeSearchResults (data) {
|
|||||||
|
|
||||||
data.forEach(x => {
|
data.forEach(x => {
|
||||||
const item = x.attributes;
|
const item = x.attributes;
|
||||||
const titles = item.titles.reduce((prev, current) => {
|
const titles = item.titles.join('<br />');
|
||||||
return prev + `${current}<br />`;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
results.push(`
|
results.push(`
|
||||||
<article class="media search">
|
<article class="media search">
|
||||||
@ -27,7 +25,6 @@ export function renderAnimeSearchResults (data) {
|
|||||||
<source srcset="/public/images/anime/${x.id}.jpg" type="image/jpeg" />
|
<source srcset="/public/images/anime/${x.id}.jpg" type="image/jpeg" />
|
||||||
<img src="/public/images/anime/${x.id}.jpg" alt="" width="220" />
|
<img src="/public/images/anime/${x.id}.jpg" alt="" width="220" />
|
||||||
</picture>
|
</picture>
|
||||||
|
|
||||||
<span class="name">
|
<span class="name">
|
||||||
${item.canonicalTitle}<br />
|
${item.canonicalTitle}<br />
|
||||||
<small>${titles}</small>
|
<small>${titles}</small>
|
||||||
@ -53,9 +50,7 @@ export function renderMangaSearchResults (data) {
|
|||||||
|
|
||||||
data.forEach(x => {
|
data.forEach(x => {
|
||||||
const item = x.attributes;
|
const item = x.attributes;
|
||||||
const titles = item.titles.reduce((prev, current) => {
|
const titles = item.titles.join('<br />');
|
||||||
return prev + `${current}<br />`;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
results.push(`
|
results.push(`
|
||||||
<article class="media search">
|
<article class="media search">
|
21
frontEndSrc/package.json
Normal file
21
frontEndSrc/package.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"license": "MIT",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npm run build:css && npm run build:js",
|
||||||
|
"build:css": "node ./css.js",
|
||||||
|
"build:js": "rollup -c ./build-js.js",
|
||||||
|
"watch:css": "watch 'npm run build:css' --filter=./cssfilter.js",
|
||||||
|
"watch:js": "watch 'npm run build:js' ./js",
|
||||||
|
"watch": "concurrently \"npm:watch:css\" \"npm:watch:js\" --kill-others"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@ampproject/rollup-plugin-closure-compiler": "^0.25.2",
|
||||||
|
"concurrently": "^5.1.0",
|
||||||
|
"cssnano": "^4.1.10",
|
||||||
|
"postcss": "^7.0.27",
|
||||||
|
"postcss-import": "^12.0.1",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"rollup": "^2.4.0",
|
||||||
|
"watch": "^1.0.2"
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Hummingbird AnimeClient Front-end Testsuite</title>
|
<title>Hummingbird AnimeClient Front-end Testsuite</title>
|
||||||
<link rel="stylesheet" href="lib/mocha.css">
|
<link rel="stylesheet" href='lib/mocha.css'>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<section id="parentTest">
|
<section id="parentTest">
|
||||||
@ -20,8 +20,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<ul id="mocha-report"></ul>
|
<ul id="mocha-report"></ul>
|
||||||
</div>
|
</div>
|
||||||
<script src="../js/src/base/classList.js"></script>
|
<script src='../js/base/class-list.js'></script>
|
||||||
<script src="lib/testBundle.js"></script>
|
<script src='lib/testBundle.js'></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var expect = chai.expect;
|
var expect = chai.expect;
|
||||||
@ -29,11 +29,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- include source files here... -->
|
<!-- include source files here... -->
|
||||||
<script src="../js/src/base/AnimeClient.js"></script>
|
<script src='../js/anime-client.js'></script>
|
||||||
|
|
||||||
<!-- include test files here... -->
|
<!-- include test files here... -->
|
||||||
<script src="tests/AnimeClient.js"></script>
|
<script src='tests/AnimeClient.js'></script>
|
||||||
<script src="tests/ajax.js"></script>
|
<script src='tests/ajax.js'></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
mocha.checkLeaks();
|
mocha.checkLeaks();
|
File diff suppressed because it is too large
Load Diff
33
index.php
33
index.php
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -24,17 +24,10 @@ use function Aviat\Ion\_dir;
|
|||||||
|
|
||||||
setlocale(LC_CTYPE, 'en_US');
|
setlocale(LC_CTYPE, 'en_US');
|
||||||
|
|
||||||
// Work around the silly timezone error
|
|
||||||
$timezone = ini_get('date.timezone');
|
|
||||||
if ($timezone === '' || $timezone === FALSE)
|
|
||||||
{
|
|
||||||
ini_set('date.timezone', 'GMT');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load composer autoloader
|
// Load composer autoloader
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// if (array_key_exists('ENV', $_ENV) && $_ENV['ENV'] === 'development')
|
if (array_key_exists('ENV', $_SERVER) && $_SERVER['ENV'] === 'development')
|
||||||
{
|
{
|
||||||
$whoops = new Run;
|
$whoops = new Run;
|
||||||
$whoops->pushHandler(new PrettyPageHandler);
|
$whoops->pushHandler(new PrettyPageHandler);
|
||||||
@ -61,7 +54,25 @@ $overrideConfig = file_exists($overrideFile)
|
|||||||
|
|
||||||
$configArray = array_replace_recursive($baseConfig, $config, $overrideConfig);
|
$configArray = array_replace_recursive($baseConfig, $config, $overrideConfig);
|
||||||
|
|
||||||
$checkedConfig = (new ConfigType($configArray))->toArray();
|
$checkedConfig = ConfigType::check($configArray);
|
||||||
|
|
||||||
|
// Set the timezone for date display
|
||||||
|
// First look in app config, then PHP config, and at last
|
||||||
|
// resort, just set to UTC.
|
||||||
|
$timezone = ini_get('date.timezone');
|
||||||
|
if (array_key_exists('timezone', $checkedConfig) && ! empty($checkedConfig['timezone']))
|
||||||
|
{
|
||||||
|
date_default_timezone_set($checkedConfig['timezone']);
|
||||||
|
}
|
||||||
|
else if ($timezone !== '')
|
||||||
|
{
|
||||||
|
date_default_timezone_set($timezone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
date_default_timezone_set('UTC');
|
||||||
|
}
|
||||||
|
|
||||||
$container = $di($checkedConfig);
|
$container = $di($checkedConfig);
|
||||||
|
|
||||||
// Unset 'constants'
|
// Unset 'constants'
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddMangaCollectionTables extends AbstractMigration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Change Method.
|
|
||||||
*
|
|
||||||
* Write your reversible migrations using this method.
|
|
||||||
*
|
|
||||||
* More information on writing migrations is available here:
|
|
||||||
* http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
|
|
||||||
*
|
|
||||||
* The following commands can be used in this method and Phinx will
|
|
||||||
* automatically reverse them when rolling back:
|
|
||||||
*
|
|
||||||
* createTable
|
|
||||||
* renameTable
|
|
||||||
* addColumn
|
|
||||||
* renameColumn
|
|
||||||
* addIndex
|
|
||||||
* addForeignKey
|
|
||||||
*
|
|
||||||
* Remember to call "create()" or "update()" and NOT "save()" when working
|
|
||||||
* with the Table class.
|
|
||||||
*/
|
|
||||||
public function change()
|
|
||||||
{
|
|
||||||
// Create manga_set table
|
|
||||||
$manga_set = $this->table('manga_set', ['id' => FALSE, 'primary_key' => ['hummingbird_id']]);
|
|
||||||
$manga_set->addColumn('hummingbird_id', 'biginteger')
|
|
||||||
->addColumn('slug', 'string', ['comment' => "URL slug used for image caching and generating links"])
|
|
||||||
->addColumn('title', 'string')
|
|
||||||
->addColumn('alternate_title', 'string', ['null' => TRUE])
|
|
||||||
->addColumn('media_id', 'integer', ['default' => 3, 'null' => TRUE])
|
|
||||||
->addColumn('show_type', 'string', ['default' => 'TV', 'null' => TRUE, 'comment' => "TV Series/OVA/etc"])
|
|
||||||
->addColumn('age_rating', 'string', ['default' => 'PG13', 'null' => TRUE])
|
|
||||||
->addColumn('cover_image', 'string', ['null' => TRUE])
|
|
||||||
->addColumn('episode_count', 'integer', ['null' => TRUE])
|
|
||||||
->addColumn('episode_length', 'integer', ['null' => TRUE])
|
|
||||||
->addColumn('notes', 'text', ['null' => TRUE])
|
|
||||||
->addForeignKey('media_id', 'media', 'id')
|
|
||||||
->create();
|
|
||||||
|
|
||||||
// Create genre_manga_set_link table
|
|
||||||
$genre_manga_set_link = $this->table('genre_manga_set_link', ['id' => FALSE, 'primary_key' => ['hummingbird_id', 'genre_id']]);
|
|
||||||
$genre_manga_set_link->addColumn('hummingbird_id', 'biginteger')
|
|
||||||
->addColumn('genre_id', 'integer')
|
|
||||||
->addForeignKey('hummingbird_id', 'manga_set', 'hummingbird_id')
|
|
||||||
->addForeignKey('genre_id', 'genres', 'id')
|
|
||||||
->create();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
class ReorganizeAnimeCollectionMedia extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// Create the new link table
|
||||||
|
if ( ! $this->hasTable('anime_set_media_link'))
|
||||||
|
{
|
||||||
|
$newLinkTable = $this->table('anime_set_media_link', [
|
||||||
|
'id' => FALSE,
|
||||||
|
'primary_key' => ['hummingbird_id', 'media_id']
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newLinkTable->addColumn('hummingbird_id', 'biginteger')
|
||||||
|
->addColumn('media_id', 'biginteger')
|
||||||
|
->addForeignKey('media_id', 'media', 'id')
|
||||||
|
->addForeignKey('hummingbird_id', 'anime_set', 'hummingbird_id')
|
||||||
|
->create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the old link entries
|
||||||
|
$insertRows = [];
|
||||||
|
$rows = ($this->table('anime_set')->hasColumn('media_id'))
|
||||||
|
? $this->fetchAll('SELECT hummingbird_id, media_id from anime_set')
|
||||||
|
: [];
|
||||||
|
|
||||||
|
// Filter the numeric keys out of the row results
|
||||||
|
foreach ($rows as $row)
|
||||||
|
{
|
||||||
|
$keys = array_keys($row);
|
||||||
|
foreach ($keys as $k)
|
||||||
|
{
|
||||||
|
if (is_numeric($k))
|
||||||
|
{
|
||||||
|
unset($row[$k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$insertRows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And put them in the new table
|
||||||
|
$linkTable = $this->table('anime_set_media_link');
|
||||||
|
$linkTable->insert($insertRows)->save();
|
||||||
|
|
||||||
|
// Get the rows where you have the combined media type (DVD & Bluray)
|
||||||
|
// and replace those rows with the individual entries
|
||||||
|
$linkRows = $this->fetchAll('SELECT hummingbird_id FROM anime_set_media_link WHERE media_id=1');
|
||||||
|
$insertRows = [];
|
||||||
|
foreach ($linkRows as $row)
|
||||||
|
{
|
||||||
|
$insertRows[] = [
|
||||||
|
'hummingbird_id' => $row['hummingbird_id'],
|
||||||
|
'media_id' => 2,
|
||||||
|
];
|
||||||
|
$insertRows[] = [
|
||||||
|
'hummingbird_id' => $row['hummingbird_id'],
|
||||||
|
'media_id' => 3,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$linkTable->insert($insertRows)->save();
|
||||||
|
|
||||||
|
// Finally, delete the old combined media type rows
|
||||||
|
$this->execute('DELETE FROM anime_set_media_link WHERE media_id=1');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
if ($this->hasTable('anime_set_media_link'))
|
||||||
|
{
|
||||||
|
$this->table('anime_set_media_link')->drop()->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Phinx\Migration\AbstractMigration;
|
||||||
|
|
||||||
|
class AnimeCollectionRefactorCleanup extends AbstractMigration
|
||||||
|
{
|
||||||
|
protected array $newMediaTypes = [
|
||||||
|
'LaserDisc',
|
||||||
|
'VHS',
|
||||||
|
'Digital',
|
||||||
|
'Video CD',
|
||||||
|
'Betamax',
|
||||||
|
'UMD',
|
||||||
|
'Other',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
// Add some new media types
|
||||||
|
$moreMediaTypes = [];
|
||||||
|
foreach ($this->newMediaTypes as $id => $medium)
|
||||||
|
{
|
||||||
|
$moreMediaTypes[] = [
|
||||||
|
'id' => $id + 5,
|
||||||
|
'type' => $medium,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$this->table('media')->insert($moreMediaTypes)->save();
|
||||||
|
|
||||||
|
// Remove foreign key and media_id column from anime_set
|
||||||
|
$animeSet = $this->table('anime_set');
|
||||||
|
if ($animeSet->hasColumn('media_id'))
|
||||||
|
{
|
||||||
|
$animeSet->dropForeignKey('media_id')->save();
|
||||||
|
$animeSet->removeColumn('media_id')->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup existing media types a bit
|
||||||
|
$this->execute("UPDATE media SET type='Bootleg' WHERE id=4");
|
||||||
|
$this->execute('DELETE FROM media WHERE id=1');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
// Restore the original values for existing media
|
||||||
|
$this->execute("INSERT INTO media (id, type) VALUES (1, 'DVD & Blu-ray')");
|
||||||
|
$this->execute("UPDATE media SET type='Bootleg DVD' WHERE id=4");
|
||||||
|
|
||||||
|
// Remove the new media types
|
||||||
|
$values = array_map(fn ($medium) => "'{$medium}'", $this->newMediaTypes);
|
||||||
|
$valueList = implode(',', $values);
|
||||||
|
$this->execute("DELETE FROM media WHERE type IN ({$valueList})");
|
||||||
|
}
|
||||||
|
}
|
1
public/css/app.min.css
vendored
1
public/css/app.min.css
vendored
File diff suppressed because one or more lines are too long
1
public/css/auto.min.css
vendored
Normal file
1
public/css/auto.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
public/css/dark-auto.min.css
vendored
1
public/css/dark-auto.min.css
vendored
File diff suppressed because one or more lines are too long
2
public/css/dark.min.css
vendored
2
public/css/dark.min.css
vendored
File diff suppressed because one or more lines are too long
1
public/css/light.min.css
vendored
Normal file
1
public/css/light.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,4 +0,0 @@
|
|||||||
@import "./marx.css";
|
|
||||||
@import "./general.css";
|
|
||||||
@import "./components.css";
|
|
||||||
@import "./responsive.css";
|
|
460
public/es/anon.js
Normal file
460
public/es/anon.js
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Base
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const matches = (elm, selector) => {
|
||||||
|
let m = (elm.document || elm.ownerDocument).querySelectorAll(selector);
|
||||||
|
let i = matches.length;
|
||||||
|
while (--i >= 0 && m.item(i) !== elm) {} return i > -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnimeClient = {
|
||||||
|
/**
|
||||||
|
* Placeholder function
|
||||||
|
*/
|
||||||
|
noop: () => {},
|
||||||
|
/**
|
||||||
|
* DOM selector
|
||||||
|
*
|
||||||
|
* @param {string} selector - The dom selector string
|
||||||
|
* @param {object} [context]
|
||||||
|
* @return {[HTMLElement]} - array of dom elements
|
||||||
|
*/
|
||||||
|
$(selector, context = null) {
|
||||||
|
if (typeof selector !== 'string') {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = (context !== null && context.nodeType === 1)
|
||||||
|
? context
|
||||||
|
: document;
|
||||||
|
|
||||||
|
let elements = [];
|
||||||
|
if (selector.match(/^#([\w]+$)/)) {
|
||||||
|
elements.push(document.getElementById(selector.split('#')[1]));
|
||||||
|
} else {
|
||||||
|
elements = [].slice.apply(context.querySelectorAll(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Does the selector exist on the current page?
|
||||||
|
*
|
||||||
|
* @param {string} selector
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
hasElement (selector) {
|
||||||
|
return AnimeClient.$(selector).length > 0;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Scroll to the top of the Page
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
scrollToTop () {
|
||||||
|
const el = AnimeClient.$('header')[0];
|
||||||
|
el.scrollIntoView(true);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Hide the selected element
|
||||||
|
*
|
||||||
|
* @param {string|Element} sel - the selector of the element to hide
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
hide (sel) {
|
||||||
|
if (typeof sel === 'string') {
|
||||||
|
sel = AnimeClient.$(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(sel)) {
|
||||||
|
sel.forEach(el => el.setAttribute('hidden', 'hidden'));
|
||||||
|
} else {
|
||||||
|
sel.setAttribute('hidden', 'hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* UnHide the selected element
|
||||||
|
*
|
||||||
|
* @param {string|Element} sel - the selector of the element to hide
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
show (sel) {
|
||||||
|
if (typeof sel === 'string') {
|
||||||
|
sel = AnimeClient.$(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(sel)) {
|
||||||
|
sel.forEach(el => el.removeAttribute('hidden'));
|
||||||
|
} else {
|
||||||
|
sel.removeAttribute('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Display a message box
|
||||||
|
*
|
||||||
|
* @param {string} type - message type: info, error, success
|
||||||
|
* @param {string} message - the message itself
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
showMessage (type, message) {
|
||||||
|
let template =
|
||||||
|
`<div class='message ${type}'>
|
||||||
|
<span class='icon'></span>
|
||||||
|
${message}
|
||||||
|
<span class='close'></span>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
let sel = AnimeClient.$('.message');
|
||||||
|
if (sel[0] !== undefined) {
|
||||||
|
sel[0].remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeClient.$('header')[0].insertAdjacentHTML('beforeend', template);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Finds the closest parent element matching the passed selector
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} current - the current HTMLElement
|
||||||
|
* @param {string} parentSelector - selector for the parent element
|
||||||
|
* @return {HTMLElement|null} - the parent element
|
||||||
|
*/
|
||||||
|
closestParent (current, parentSelector) {
|
||||||
|
if (Element.prototype.closest !== undefined) {
|
||||||
|
return current.closest(parentSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (current !== document.documentElement) {
|
||||||
|
if (matches(current, parentSelector)) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Generate a full url from a relative path
|
||||||
|
*
|
||||||
|
* @param {string} path - url path
|
||||||
|
* @return {string} - full url
|
||||||
|
*/
|
||||||
|
url (path) {
|
||||||
|
let uri = `//${document.location.host}`;
|
||||||
|
uri += (path.charAt(0) === '/') ? path : `/${path}`;
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throttle execution of a function
|
||||||
|
*
|
||||||
|
* @see https://remysharp.com/2010/07/21/throttling-function-calls
|
||||||
|
* @see https://jsfiddle.net/jonathansampson/m7G64/
|
||||||
|
* @param {Number} interval - the minimum throttle time in ms
|
||||||
|
* @param {Function} fn - the function to throttle
|
||||||
|
* @param {Object} [scope] - the 'this' object for the function
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
throttle (interval, fn, scope) {
|
||||||
|
let wait = false;
|
||||||
|
return function (...args) {
|
||||||
|
const context = scope || this;
|
||||||
|
|
||||||
|
if ( ! wait) {
|
||||||
|
fn.apply(context, args);
|
||||||
|
wait = true;
|
||||||
|
setTimeout(function() {
|
||||||
|
wait = false;
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Events
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function addEvent(sel, event, listener) {
|
||||||
|
// Recurse!
|
||||||
|
if (! event.match(/^([\w\-]+)$/)) {
|
||||||
|
event.split(' ').forEach((evt) => {
|
||||||
|
addEvent(sel, evt, listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sel.addEventListener(event, listener, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delegateEvent(sel, target, event, listener) {
|
||||||
|
// Attach the listener to the parent
|
||||||
|
addEvent(sel, event, (e) => {
|
||||||
|
// Get live version of the target selector
|
||||||
|
AnimeClient.$(target, sel).forEach((element) => {
|
||||||
|
if(e.target == element) {
|
||||||
|
listener.call(element, e);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event listener
|
||||||
|
*
|
||||||
|
* @param {string|HTMLElement} sel - the parent selector to bind to
|
||||||
|
* @param {string} event - event name(s) to bind
|
||||||
|
* @param {string|HTMLElement|function} target - the element to directly bind the event to
|
||||||
|
* @param {function} [listener] - event listener callback
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
AnimeClient.on = (sel, event, target, listener) => {
|
||||||
|
if (listener === undefined) {
|
||||||
|
listener = target;
|
||||||
|
AnimeClient.$(sel).forEach((el) => {
|
||||||
|
addEvent(el, event, listener);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
AnimeClient.$(sel).forEach((el) => {
|
||||||
|
delegateEvent(el, target, event, listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Ajax
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url encoding for non-get requests
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @returns {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function ajaxSerialize(data) {
|
||||||
|
let pairs = [];
|
||||||
|
|
||||||
|
Object.keys(data).forEach((name) => {
|
||||||
|
let value = data[name].toString();
|
||||||
|
|
||||||
|
name = encodeURIComponent(name);
|
||||||
|
value = encodeURIComponent(value);
|
||||||
|
|
||||||
|
pairs.push(`${name}=${value}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return pairs.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an ajax request
|
||||||
|
*
|
||||||
|
* Config:{
|
||||||
|
* data: // data to send with the request
|
||||||
|
* type: // http verb of the request, defaults to GET
|
||||||
|
* success: // success callback
|
||||||
|
* error: // error callback
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param {string} url - the url to request
|
||||||
|
* @param {Object} config - the configuration object
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
AnimeClient.ajax = (url, config) => {
|
||||||
|
// Set some sane defaults
|
||||||
|
const defaultConfig = {
|
||||||
|
data: {},
|
||||||
|
type: 'GET',
|
||||||
|
dataType: '',
|
||||||
|
success: AnimeClient.noop,
|
||||||
|
mimeType: 'application/x-www-form-urlencoded',
|
||||||
|
error: AnimeClient.noop
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
...defaultConfig,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
|
let request = new XMLHttpRequest();
|
||||||
|
let method = String(config.type).toUpperCase();
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
|
url += (url.match(/\?/))
|
||||||
|
? ajaxSerialize(config.data)
|
||||||
|
: `?${ajaxSerialize(config.data)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.open(method, url);
|
||||||
|
|
||||||
|
request.onreadystatechange = () => {
|
||||||
|
if (request.readyState === 4) {
|
||||||
|
let responseText = '';
|
||||||
|
|
||||||
|
if (request.responseType === 'json') {
|
||||||
|
responseText = JSON.parse(request.responseText);
|
||||||
|
} else {
|
||||||
|
responseText = request.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.status > 299) {
|
||||||
|
config.error.call(null, request.status, responseText, request.response);
|
||||||
|
} else {
|
||||||
|
config.success.call(null, responseText, request.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.dataType === 'json') {
|
||||||
|
config.data = JSON.stringify(config.data);
|
||||||
|
config.mimeType = 'application/json';
|
||||||
|
} else {
|
||||||
|
config.data = ajaxSerialize(config.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.setRequestHeader('Content-Type', config.mimeType);
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
|
request.send(null);
|
||||||
|
} else {
|
||||||
|
request.send(config.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a get request
|
||||||
|
*
|
||||||
|
* @param {string} url
|
||||||
|
* @param {object|function} data
|
||||||
|
* @param {function} [callback]
|
||||||
|
*/
|
||||||
|
AnimeClient.get = (url, data, callback = null) => {
|
||||||
|
if (callback === null) {
|
||||||
|
callback = data;
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimeClient.ajax(url, {
|
||||||
|
data,
|
||||||
|
success: callback
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Event subscriptions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
AnimeClient.on('header', 'click', '.message', hide);
|
||||||
|
AnimeClient.on('form.js-delete', 'submit', confirmDelete);
|
||||||
|
AnimeClient.on('.js-clear-cache', 'click', clearAPICache);
|
||||||
|
AnimeClient.on('.vertical-tabs input', 'change', scrollToSection);
|
||||||
|
AnimeClient.on('.media-filter', 'input', filterMedia);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Handler functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the html element attached to the event
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function hide (event) {
|
||||||
|
AnimeClient.hide(event.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm deletion of an item
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function confirmDelete (event) {
|
||||||
|
const proceed = confirm('Are you ABSOLUTELY SURE you want to delete this item?');
|
||||||
|
|
||||||
|
if (proceed === false) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the API cache, and show a message if the cache is cleared
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function clearAPICache () {
|
||||||
|
AnimeClient.get('/cache_purge', () => {
|
||||||
|
AnimeClient.showMessage('success', 'Successfully purged api cache');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll to the accordion/vertical tab section just opened
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function scrollToSection (event) {
|
||||||
|
const el = event.currentTarget.parentElement;
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
|
const top = rect.top + window.pageYOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter an anime or manga list
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function filterMedia (event) {
|
||||||
|
const rawFilter = event.target.value;
|
||||||
|
const filter = new RegExp(rawFilter, 'i');
|
||||||
|
|
||||||
|
// console.log('Filtering items by: ', filter);
|
||||||
|
|
||||||
|
if (rawFilter !== '') {
|
||||||
|
// Filter the cover view
|
||||||
|
AnimeClient.$('article.media').forEach(article => {
|
||||||
|
const titleLink = AnimeClient.$('.name a', article)[0];
|
||||||
|
const title = String(titleLink.textContent).trim();
|
||||||
|
if ( ! filter.test(title)) {
|
||||||
|
AnimeClient.hide(article);
|
||||||
|
} else {
|
||||||
|
AnimeClient.show(article);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter the list view
|
||||||
|
AnimeClient.$('table.media-wrap tbody tr').forEach(tr => {
|
||||||
|
const titleCell = AnimeClient.$('td.align-left', tr)[0];
|
||||||
|
const titleLink = AnimeClient.$('a', titleCell)[0];
|
||||||
|
const linkTitle = String(titleLink.textContent).trim();
|
||||||
|
const textTitle = String(titleCell.textContent).trim();
|
||||||
|
if ( ! (filter.test(linkTitle) || filter.test(textTitle))) {
|
||||||
|
AnimeClient.hide(tr);
|
||||||
|
} else {
|
||||||
|
AnimeClient.show(tr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
AnimeClient.show('article.media');
|
||||||
|
AnimeClient.show('table.media-wrap tbody tr');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/sw.js').then(reg => {
|
||||||
|
console.log('Service worker registered', reg.scope);
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Failed to register service worker', error);
|
||||||
|
});
|
||||||
|
}
|
716
public/es/scripts.js
Normal file
716
public/es/scripts.js
Normal file
@ -0,0 +1,716 @@
|
|||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Base
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const matches = (elm, selector) => {
|
||||||
|
let m = (elm.document || elm.ownerDocument).querySelectorAll(selector);
|
||||||
|
let i = matches.length;
|
||||||
|
while (--i >= 0 && m.item(i) !== elm) {} return i > -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AnimeClient = {
|
||||||
|
/**
|
||||||
|
* Placeholder function
|
||||||
|
*/
|
||||||
|
noop: () => {},
|
||||||
|
/**
|
||||||
|
* DOM selector
|
||||||
|
*
|
||||||
|
* @param {string} selector - The dom selector string
|
||||||
|
* @param {object} [context]
|
||||||
|
* @return {[HTMLElement]} - array of dom elements
|
||||||
|
*/
|
||||||
|
$(selector, context = null) {
|
||||||
|
if (typeof selector !== 'string') {
|
||||||
|
return selector;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = (context !== null && context.nodeType === 1)
|
||||||
|
? context
|
||||||
|
: document;
|
||||||
|
|
||||||
|
let elements = [];
|
||||||
|
if (selector.match(/^#([\w]+$)/)) {
|
||||||
|
elements.push(document.getElementById(selector.split('#')[1]));
|
||||||
|
} else {
|
||||||
|
elements = [].slice.apply(context.querySelectorAll(selector));
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Does the selector exist on the current page?
|
||||||
|
*
|
||||||
|
* @param {string} selector
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
hasElement (selector) {
|
||||||
|
return AnimeClient.$(selector).length > 0;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Scroll to the top of the Page
|
||||||
|
*
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
scrollToTop () {
|
||||||
|
const el = AnimeClient.$('header')[0];
|
||||||
|
el.scrollIntoView(true);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Hide the selected element
|
||||||
|
*
|
||||||
|
* @param {string|Element} sel - the selector of the element to hide
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
hide (sel) {
|
||||||
|
if (typeof sel === 'string') {
|
||||||
|
sel = AnimeClient.$(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(sel)) {
|
||||||
|
sel.forEach(el => el.setAttribute('hidden', 'hidden'));
|
||||||
|
} else {
|
||||||
|
sel.setAttribute('hidden', 'hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* UnHide the selected element
|
||||||
|
*
|
||||||
|
* @param {string|Element} sel - the selector of the element to hide
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
show (sel) {
|
||||||
|
if (typeof sel === 'string') {
|
||||||
|
sel = AnimeClient.$(sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(sel)) {
|
||||||
|
sel.forEach(el => el.removeAttribute('hidden'));
|
||||||
|
} else {
|
||||||
|
sel.removeAttribute('hidden');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Display a message box
|
||||||
|
*
|
||||||
|
* @param {string} type - message type: info, error, success
|
||||||
|
* @param {string} message - the message itself
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
showMessage (type, message) {
|
||||||
|
let template =
|
||||||
|
`<div class='message ${type}'>
|
||||||
|
<span class='icon'></span>
|
||||||
|
${message}
|
||||||
|
<span class='close'></span>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
let sel = AnimeClient.$('.message');
|
||||||
|
if (sel[0] !== undefined) {
|
||||||
|
sel[0].remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeClient.$('header')[0].insertAdjacentHTML('beforeend', template);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Finds the closest parent element matching the passed selector
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} current - the current HTMLElement
|
||||||
|
* @param {string} parentSelector - selector for the parent element
|
||||||
|
* @return {HTMLElement|null} - the parent element
|
||||||
|
*/
|
||||||
|
closestParent (current, parentSelector) {
|
||||||
|
if (Element.prototype.closest !== undefined) {
|
||||||
|
return current.closest(parentSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (current !== document.documentElement) {
|
||||||
|
if (matches(current, parentSelector)) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.parentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Generate a full url from a relative path
|
||||||
|
*
|
||||||
|
* @param {string} path - url path
|
||||||
|
* @return {string} - full url
|
||||||
|
*/
|
||||||
|
url (path) {
|
||||||
|
let uri = `//${document.location.host}`;
|
||||||
|
uri += (path.charAt(0) === '/') ? path : `/${path}`;
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Throttle execution of a function
|
||||||
|
*
|
||||||
|
* @see https://remysharp.com/2010/07/21/throttling-function-calls
|
||||||
|
* @see https://jsfiddle.net/jonathansampson/m7G64/
|
||||||
|
* @param {Number} interval - the minimum throttle time in ms
|
||||||
|
* @param {Function} fn - the function to throttle
|
||||||
|
* @param {Object} [scope] - the 'this' object for the function
|
||||||
|
* @return {Function}
|
||||||
|
*/
|
||||||
|
throttle (interval, fn, scope) {
|
||||||
|
let wait = false;
|
||||||
|
return function (...args) {
|
||||||
|
const context = scope || this;
|
||||||
|
|
||||||
|
if ( ! wait) {
|
||||||
|
fn.apply(context, args);
|
||||||
|
wait = true;
|
||||||
|
setTimeout(function() {
|
||||||
|
wait = false;
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Events
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function addEvent(sel, event, listener) {
|
||||||
|
// Recurse!
|
||||||
|
if (! event.match(/^([\w\-]+)$/)) {
|
||||||
|
event.split(' ').forEach((evt) => {
|
||||||
|
addEvent(sel, evt, listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sel.addEventListener(event, listener, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delegateEvent(sel, target, event, listener) {
|
||||||
|
// Attach the listener to the parent
|
||||||
|
addEvent(sel, event, (e) => {
|
||||||
|
// Get live version of the target selector
|
||||||
|
AnimeClient.$(target, sel).forEach((element) => {
|
||||||
|
if(e.target == element) {
|
||||||
|
listener.call(element, e);
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event listener
|
||||||
|
*
|
||||||
|
* @param {string|HTMLElement} sel - the parent selector to bind to
|
||||||
|
* @param {string} event - event name(s) to bind
|
||||||
|
* @param {string|HTMLElement|function} target - the element to directly bind the event to
|
||||||
|
* @param {function} [listener] - event listener callback
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
AnimeClient.on = (sel, event, target, listener) => {
|
||||||
|
if (listener === undefined) {
|
||||||
|
listener = target;
|
||||||
|
AnimeClient.$(sel).forEach((el) => {
|
||||||
|
addEvent(el, event, listener);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
AnimeClient.$(sel).forEach((el) => {
|
||||||
|
delegateEvent(el, target, event, listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ! Ajax
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Url encoding for non-get requests
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @returns {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function ajaxSerialize(data) {
|
||||||
|
let pairs = [];
|
||||||
|
|
||||||
|
Object.keys(data).forEach((name) => {
|
||||||
|
let value = data[name].toString();
|
||||||
|
|
||||||
|
name = encodeURIComponent(name);
|
||||||
|
value = encodeURIComponent(value);
|
||||||
|
|
||||||
|
pairs.push(`${name}=${value}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return pairs.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make an ajax request
|
||||||
|
*
|
||||||
|
* Config:{
|
||||||
|
* data: // data to send with the request
|
||||||
|
* type: // http verb of the request, defaults to GET
|
||||||
|
* success: // success callback
|
||||||
|
* error: // error callback
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param {string} url - the url to request
|
||||||
|
* @param {Object} config - the configuration object
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
AnimeClient.ajax = (url, config) => {
|
||||||
|
// Set some sane defaults
|
||||||
|
const defaultConfig = {
|
||||||
|
data: {},
|
||||||
|
type: 'GET',
|
||||||
|
dataType: '',
|
||||||
|
success: AnimeClient.noop,
|
||||||
|
mimeType: 'application/x-www-form-urlencoded',
|
||||||
|
error: AnimeClient.noop
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
...defaultConfig,
|
||||||
|
...config,
|
||||||
|
};
|
||||||
|
|
||||||
|
let request = new XMLHttpRequest();
|
||||||
|
let method = String(config.type).toUpperCase();
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
|
url += (url.match(/\?/))
|
||||||
|
? ajaxSerialize(config.data)
|
||||||
|
: `?${ajaxSerialize(config.data)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.open(method, url);
|
||||||
|
|
||||||
|
request.onreadystatechange = () => {
|
||||||
|
if (request.readyState === 4) {
|
||||||
|
let responseText = '';
|
||||||
|
|
||||||
|
if (request.responseType === 'json') {
|
||||||
|
responseText = JSON.parse(request.responseText);
|
||||||
|
} else {
|
||||||
|
responseText = request.responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.status > 299) {
|
||||||
|
config.error.call(null, request.status, responseText, request.response);
|
||||||
|
} else {
|
||||||
|
config.success.call(null, responseText, request.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.dataType === 'json') {
|
||||||
|
config.data = JSON.stringify(config.data);
|
||||||
|
config.mimeType = 'application/json';
|
||||||
|
} else {
|
||||||
|
config.data = ajaxSerialize(config.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.setRequestHeader('Content-Type', config.mimeType);
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
|
request.send(null);
|
||||||
|
} else {
|
||||||
|
request.send(config.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do a get request
|
||||||
|
*
|
||||||
|
* @param {string} url
|
||||||
|
* @param {object|function} data
|
||||||
|
* @param {function} [callback]
|
||||||
|
*/
|
||||||
|
AnimeClient.get = (url, data, callback = null) => {
|
||||||
|
if (callback === null) {
|
||||||
|
callback = data;
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimeClient.ajax(url, {
|
||||||
|
data,
|
||||||
|
success: callback
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Event subscriptions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
AnimeClient.on('header', 'click', '.message', hide);
|
||||||
|
AnimeClient.on('form.js-delete', 'submit', confirmDelete);
|
||||||
|
AnimeClient.on('.js-clear-cache', 'click', clearAPICache);
|
||||||
|
AnimeClient.on('.vertical-tabs input', 'change', scrollToSection);
|
||||||
|
AnimeClient.on('.media-filter', 'input', filterMedia);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Handler functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the html element attached to the event
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function hide (event) {
|
||||||
|
AnimeClient.hide(event.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm deletion of an item
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function confirmDelete (event) {
|
||||||
|
const proceed = confirm('Are you ABSOLUTELY SURE you want to delete this item?');
|
||||||
|
|
||||||
|
if (proceed === false) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the API cache, and show a message if the cache is cleared
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function clearAPICache () {
|
||||||
|
AnimeClient.get('/cache_purge', () => {
|
||||||
|
AnimeClient.showMessage('success', 'Successfully purged api cache');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll to the accordion/vertical tab section just opened
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function scrollToSection (event) {
|
||||||
|
const el = event.currentTarget.parentElement;
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
|
||||||
|
const top = rect.top + window.pageYOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top,
|
||||||
|
behavior: 'smooth',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter an anime or manga list
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function filterMedia (event) {
|
||||||
|
const rawFilter = event.target.value;
|
||||||
|
const filter = new RegExp(rawFilter, 'i');
|
||||||
|
|
||||||
|
// console.log('Filtering items by: ', filter);
|
||||||
|
|
||||||
|
if (rawFilter !== '') {
|
||||||
|
// Filter the cover view
|
||||||
|
AnimeClient.$('article.media').forEach(article => {
|
||||||
|
const titleLink = AnimeClient.$('.name a', article)[0];
|
||||||
|
const title = String(titleLink.textContent).trim();
|
||||||
|
if ( ! filter.test(title)) {
|
||||||
|
AnimeClient.hide(article);
|
||||||
|
} else {
|
||||||
|
AnimeClient.show(article);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter the list view
|
||||||
|
AnimeClient.$('table.media-wrap tbody tr').forEach(tr => {
|
||||||
|
const titleCell = AnimeClient.$('td.align-left', tr)[0];
|
||||||
|
const titleLink = AnimeClient.$('a', titleCell)[0];
|
||||||
|
const linkTitle = String(titleLink.textContent).trim();
|
||||||
|
const textTitle = String(titleCell.textContent).trim();
|
||||||
|
if ( ! (filter.test(linkTitle) || filter.test(textTitle))) {
|
||||||
|
AnimeClient.hide(tr);
|
||||||
|
} else {
|
||||||
|
AnimeClient.show(tr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
AnimeClient.show('article.media');
|
||||||
|
AnimeClient.show('table.media-wrap tbody tr');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.register('/sw.js').then(reg => {
|
||||||
|
console.log('Service worker registered', reg.scope);
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Failed to register service worker', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click on hidden MAL checkbox so
|
||||||
|
// that MAL id is passed
|
||||||
|
AnimeClient.on('main', 'change', '.big-check', (e) => {
|
||||||
|
const id = e.target.id;
|
||||||
|
document.getElementById(`mal_${id}`).checked = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderAnimeSearchResults (data) {
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
data.forEach(x => {
|
||||||
|
const item = x.attributes;
|
||||||
|
const titles = item.titles.join('<br />');
|
||||||
|
|
||||||
|
results.push(`
|
||||||
|
<article class="media search">
|
||||||
|
<div class="name">
|
||||||
|
<input type="radio" class="mal-check" id="mal_${item.slug}" name="mal_id" value="${x.mal_id}" />
|
||||||
|
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${x.id}" />
|
||||||
|
<label for="${item.slug}">
|
||||||
|
<picture width="220">
|
||||||
|
<source srcset="/public/images/anime/${x.id}.webp" type="image/webp" />
|
||||||
|
<source srcset="/public/images/anime/${x.id}.jpg" type="image/jpeg" />
|
||||||
|
<img src="/public/images/anime/${x.id}.jpg" alt="" width="220" />
|
||||||
|
</picture>
|
||||||
|
<span class="name">
|
||||||
|
${item.canonicalTitle}<br />
|
||||||
|
<small>${titles}</small>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="table">
|
||||||
|
<div class="row">
|
||||||
|
<span class="edit">
|
||||||
|
<a class="bracketed" href="/anime/details/${item.slug}">Info Page</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderMangaSearchResults (data) {
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
data.forEach(x => {
|
||||||
|
const item = x.attributes;
|
||||||
|
const titles = item.titles.join('<br />');
|
||||||
|
|
||||||
|
results.push(`
|
||||||
|
<article class="media search">
|
||||||
|
<div class="name">
|
||||||
|
<input type="radio" id="mal_${item.slug}" name="mal_id" value="${x.mal_id}" />
|
||||||
|
<input type="radio" class="big-check" id="${item.slug}" name="id" value="${x.id}" />
|
||||||
|
<label for="${item.slug}">
|
||||||
|
<picture width="220">
|
||||||
|
<source srcset="/public/images/manga/${x.id}.webp" type="image/webp" />
|
||||||
|
<source srcset="/public/images/manga/${x.id}.jpg" type="image/jpeg" />
|
||||||
|
<img src="/public/images/manga/${x.id}.jpg" alt="" width="220" />
|
||||||
|
</picture>
|
||||||
|
<span class="name">
|
||||||
|
${item.canonicalTitle}<br />
|
||||||
|
<small>${titles}</small>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="table">
|
||||||
|
<div class="row">
|
||||||
|
<span class="edit">
|
||||||
|
<a class="bracketed" href="/manga/details/${item.slug}">Info Page</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
const search = (query) => {
|
||||||
|
// Show the loader
|
||||||
|
AnimeClient.show('.cssload-loader');
|
||||||
|
|
||||||
|
// Do the api search
|
||||||
|
AnimeClient.get(AnimeClient.url('/anime-collection/search'), { query }, (searchResults, status) => {
|
||||||
|
searchResults = JSON.parse(searchResults);
|
||||||
|
|
||||||
|
// Hide the loader
|
||||||
|
AnimeClient.hide('.cssload-loader');
|
||||||
|
|
||||||
|
// Show the results
|
||||||
|
AnimeClient.$('#series-list')[ 0 ].innerHTML = renderAnimeSearchResults(searchResults.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AnimeClient.hasElement('.anime #search')) {
|
||||||
|
AnimeClient.on('#search', 'input', AnimeClient.throttle(250, (e) => {
|
||||||
|
const query = encodeURIComponent(e.target.value);
|
||||||
|
if (query === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search(query);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Action to increment episode count
|
||||||
|
AnimeClient.on('body.anime.list', 'click', '.plus-one', (e) => {
|
||||||
|
let parentSel = AnimeClient.closestParent(e.target, 'article');
|
||||||
|
let watchedCount = parseInt(AnimeClient.$('.completed_number', parentSel)[ 0 ].textContent, 10) || 0;
|
||||||
|
let totalCount = parseInt(AnimeClient.$('.total_number', parentSel)[ 0 ].textContent, 10);
|
||||||
|
let title = AnimeClient.$('.name a', parentSel)[ 0 ].textContent;
|
||||||
|
|
||||||
|
// Setup the update data
|
||||||
|
let data = {
|
||||||
|
id: parentSel.dataset.kitsuId,
|
||||||
|
mal_id: parentSel.dataset.malId,
|
||||||
|
data: {
|
||||||
|
progress: watchedCount + 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the episode count is 0, and incremented,
|
||||||
|
// change status to currently watching
|
||||||
|
if (isNaN(watchedCount) || watchedCount === 0) {
|
||||||
|
data.data.status = 'current';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you increment at the last episode, mark as completed
|
||||||
|
if ((!isNaN(watchedCount)) && (watchedCount + 1) === totalCount) {
|
||||||
|
data.data.status = 'completed';
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeClient.show('#loading-shadow');
|
||||||
|
|
||||||
|
// okay, lets actually make some changes!
|
||||||
|
AnimeClient.ajax(AnimeClient.url('/anime/increment'), {
|
||||||
|
data,
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'POST',
|
||||||
|
success: (res) => {
|
||||||
|
const resData = JSON.parse(res);
|
||||||
|
|
||||||
|
if (resData.errors) {
|
||||||
|
AnimeClient.hide('#loading-shadow');
|
||||||
|
AnimeClient.showMessage('error', `Failed to update ${title}. `);
|
||||||
|
AnimeClient.scrollToTop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resData.data.attributes.status === 'completed') {
|
||||||
|
AnimeClient.hide(parentSel);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeClient.hide('#loading-shadow');
|
||||||
|
|
||||||
|
AnimeClient.showMessage('success', `Successfully updated ${title}`);
|
||||||
|
AnimeClient.$('.completed_number', parentSel)[ 0 ].textContent = ++watchedCount;
|
||||||
|
AnimeClient.scrollToTop();
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
AnimeClient.hide('#loading-shadow');
|
||||||
|
AnimeClient.showMessage('error', `Failed to update ${title}. `);
|
||||||
|
AnimeClient.scrollToTop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const search$1 = (query) => {
|
||||||
|
AnimeClient.show('.cssload-loader');
|
||||||
|
AnimeClient.get(AnimeClient.url('/manga/search'), { query }, (searchResults, status) => {
|
||||||
|
searchResults = JSON.parse(searchResults);
|
||||||
|
AnimeClient.hide('.cssload-loader');
|
||||||
|
AnimeClient.$('#series-list')[ 0 ].innerHTML = renderMangaSearchResults(searchResults.data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AnimeClient.hasElement('.manga #search')) {
|
||||||
|
AnimeClient.on('#search', 'input', AnimeClient.throttle(250, (e) => {
|
||||||
|
let query = encodeURIComponent(e.target.value);
|
||||||
|
if (query === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
search$1(query);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Javascript for editing manga, if logged in
|
||||||
|
*/
|
||||||
|
AnimeClient.on('.manga.list', 'click', '.edit-buttons button', (e) => {
|
||||||
|
let thisSel = e.target;
|
||||||
|
let parentSel = AnimeClient.closestParent(e.target, 'article');
|
||||||
|
let type = thisSel.classList.contains('plus-one-chapter') ? 'chapter' : 'volume';
|
||||||
|
let completed = parseInt(AnimeClient.$(`.${type}s_read`, parentSel)[ 0 ].textContent, 10) || 0;
|
||||||
|
let total = parseInt(AnimeClient.$(`.${type}_count`, parentSel)[ 0 ].textContent, 10);
|
||||||
|
let mangaName = AnimeClient.$('.name', parentSel)[ 0 ].textContent;
|
||||||
|
|
||||||
|
if (isNaN(completed)) {
|
||||||
|
completed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the update data
|
||||||
|
let data = {
|
||||||
|
id: parentSel.dataset.kitsuId,
|
||||||
|
mal_id: parentSel.dataset.malId,
|
||||||
|
data: {
|
||||||
|
progress: completed
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the episode count is 0, and incremented,
|
||||||
|
// change status to currently reading
|
||||||
|
if (isNaN(completed) || completed === 0) {
|
||||||
|
data.data.status = 'current';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If you increment at the last chapter, mark as completed
|
||||||
|
if ((!isNaN(completed)) && (completed + 1) === total) {
|
||||||
|
data.data.status = 'completed';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the total count
|
||||||
|
data.data.progress = ++completed;
|
||||||
|
|
||||||
|
AnimeClient.show('#loading-shadow');
|
||||||
|
|
||||||
|
AnimeClient.ajax(AnimeClient.url('/manga/increment'), {
|
||||||
|
data,
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'POST',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
success: () => {
|
||||||
|
if (data.data.status === 'completed') {
|
||||||
|
AnimeClient.hide(parentSel);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeClient.hide('#loading-shadow');
|
||||||
|
|
||||||
|
AnimeClient.$(`.${type}s_read`, parentSel)[ 0 ].textContent = completed;
|
||||||
|
AnimeClient.showMessage('success', `Successfully updated ${mangaName}`);
|
||||||
|
AnimeClient.scrollToTop();
|
||||||
|
},
|
||||||
|
error: () => {
|
||||||
|
AnimeClient.hide('#loading-shadow');
|
||||||
|
AnimeClient.showMessage('error', `Failed to update ${mangaName}`);
|
||||||
|
AnimeClient.scrollToTop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
14
public/js/anon.min.js
vendored
Normal file
14
public/js/anon.min.js
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
(function(){var matches=function(elm,selector){var m=(elm.document||elm.ownerDocument).querySelectorAll(selector);var i=matches.length;while(--i>=0&&m.item(i)!==elm);return i>-1};var AnimeClient={noop:function(){},$:function(selector,context){context=context===undefined?null:context;if(typeof selector!=="string")return selector;context=context!==null&&context.nodeType===1?context:document;var elements=[];if(selector.match(/^#([\w]+$)/))elements.push(document.getElementById(selector.split("#")[1]));
|
||||||
|
else elements=[].slice.apply(context.querySelectorAll(selector));return elements},hasElement:function(selector){return AnimeClient.$(selector).length>0},scrollToTop:function(){var el=AnimeClient.$("header")[0];el.scrollIntoView(true)},hide:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);if(Array.isArray(sel))sel.forEach(function(el){return el.setAttribute("hidden","hidden")});else sel.setAttribute("hidden","hidden")},show:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);
|
||||||
|
if(Array.isArray(sel))sel.forEach(function(el){return el.removeAttribute("hidden")});else sel.removeAttribute("hidden")},showMessage:function(type,message){var template="<div class='message "+type+"'>\n\t\t\t\t<span class='icon'></span>\n\t\t\t\t"+message+"\n\t\t\t\t<span class='close'></span>\n\t\t\t</div>";var sel=AnimeClient.$(".message");if(sel[0]!==undefined)sel[0].remove();AnimeClient.$("header")[0].insertAdjacentHTML("beforeend",template)},closestParent:function(current,parentSelector){if(Element.prototype.closest!==
|
||||||
|
undefined)return current.closest(parentSelector);while(current!==document.documentElement){if(matches(current,parentSelector))return current;current=current.parentElement}return null},url:function(path){var uri="//"+document.location.host;uri+=path.charAt(0)==="/"?path:"/"+path;return uri},throttle:function(interval,fn,scope){var wait=false;return function(args){var $jscomp$restParams=[];for(var $jscomp$restIndex=0;$jscomp$restIndex<arguments.length;++$jscomp$restIndex)$jscomp$restParams[$jscomp$restIndex-
|
||||||
|
0]=arguments[$jscomp$restIndex];{var args$0=$jscomp$restParams;var context=scope||this;if(!wait){fn.apply(context,args$0);wait=true;setTimeout(function(){wait=false},interval)}}}}};function addEvent(sel,event,listener){if(!event.match(/^([\w\-]+)$/))event.split(" ").forEach(function(evt){addEvent(sel,evt,listener)});sel.addEventListener(event,listener,false)}function delegateEvent(sel,target,event,listener){addEvent(sel,event,function(e){AnimeClient.$(target,sel).forEach(function(element){if(e.target==
|
||||||
|
element){listener.call(element,e);e.stopPropagation()}})})}AnimeClient.on=function(sel,event,target,listener){if(listener===undefined){listener=target;AnimeClient.$(sel).forEach(function(el){addEvent(el,event,listener)})}else AnimeClient.$(sel).forEach(function(el){delegateEvent(el,target,event,listener)})};function ajaxSerialize(data){var pairs=[];Object.keys(data).forEach(function(name){var value=data[name].toString();name=encodeURIComponent(name);value=encodeURIComponent(value);pairs.push(name+
|
||||||
|
"="+value)});return pairs.join("&")}AnimeClient.ajax=function(url,config){var defaultConfig={data:{},type:"GET",dataType:"",success:AnimeClient.noop,mimeType:"application/x-www-form-urlencoded",error:AnimeClient.noop};config=Object.assign({},defaultConfig,config);var request=new XMLHttpRequest;var method=String(config.type).toUpperCase();if(method==="GET")url+=url.match(/\?/)?ajaxSerialize(config.data):"?"+ajaxSerialize(config.data);request.open(method,url);request.onreadystatechange=function(){if(request.readyState===
|
||||||
|
4){var responseText="";if(request.responseType==="json")responseText=JSON.parse(request.responseText);else responseText=request.responseText;if(request.status>299)config.error.call(null,request.status,responseText,request.response);else config.success.call(null,responseText,request.status)}};if(config.dataType==="json"){config.data=JSON.stringify(config.data);config.mimeType="application/json"}else config.data=ajaxSerialize(config.data);request.setRequestHeader("Content-Type",config.mimeType);if(method===
|
||||||
|
"GET")request.send(null);else request.send(config.data)};AnimeClient.get=function(url,data,callback){callback=callback===undefined?null:callback;if(callback===null){callback=data;data={}}return AnimeClient.ajax(url,{data:data,success:callback})};AnimeClient.on("header","click",".message",hide);AnimeClient.on("form.js-delete","submit",confirmDelete);AnimeClient.on(".js-clear-cache","click",clearAPICache);AnimeClient.on(".vertical-tabs input","change",scrollToSection);AnimeClient.on(".media-filter",
|
||||||
|
"input",filterMedia);function hide(event){AnimeClient.hide(event.target)}function confirmDelete(event){var proceed=confirm("Are you ABSOLUTELY SURE you want to delete this item?");if(proceed===false){event.preventDefault();event.stopPropagation()}}function clearAPICache(){AnimeClient.get("/cache_purge",function(){AnimeClient.showMessage("success","Successfully purged api cache")})}function scrollToSection(event){var el=event.currentTarget.parentElement;var rect=el.getBoundingClientRect();var top=
|
||||||
|
rect.top+window.pageYOffset;window.scrollTo({top:top,behavior:"smooth"})}function filterMedia(event){var rawFilter=event.target.value;var filter=new RegExp(rawFilter,"i");if(rawFilter!==""){AnimeClient.$("article.media").forEach(function(article){var titleLink=AnimeClient.$(".name a",article)[0];var title=String(titleLink.textContent).trim();if(!filter.test(title))AnimeClient.hide(article);else AnimeClient.show(article)});AnimeClient.$("table.media-wrap tbody tr").forEach(function(tr){var titleCell=
|
||||||
|
AnimeClient.$("td.align-left",tr)[0];var titleLink=AnimeClient.$("a",titleCell)[0];var linkTitle=String(titleLink.textContent).trim();var textTitle=String(titleCell.textContent).trim();if(!(filter.test(linkTitle)||filter.test(textTitle)))AnimeClient.hide(tr);else AnimeClient.show(tr)})}else{AnimeClient.show("article.media");AnimeClient.show("table.media-wrap tbody tr")}}if("serviceWorker"in navigator)navigator.serviceWorker.register("/sw.js").then(function(reg){console.log("Service worker registered",
|
||||||
|
reg.scope)})["catch"](function(error){console.error("Failed to register service worker",error)})})()
|
||||||
|
//# sourceMappingURL=anon.min.js.map
|
1
public/js/anon.min.js.map
Normal file
1
public/js/anon.min.js.map
Normal file
File diff suppressed because one or more lines are too long
26
public/js/scripts-authed.min.js
vendored
26
public/js/scripts-authed.min.js
vendored
@ -1,26 +0,0 @@
|
|||||||
(function(){var matches=function(elm,selector){var matches=(elm.document||elm.ownerDocument).querySelectorAll(selector),i=matches.length;while(--i>=0&&matches.item(i)!==elm);return i>-1};var AnimeClient={noop:function(){},$:function(selector,context){context=context===undefined?null:context;if(typeof selector!=="string")return selector;context=context!==null&&context.nodeType===1?context:document;var elements=[];if(selector.match(/^#([\w]+$)/))elements.push(document.getElementById(selector.split("#")[1]));
|
|
||||||
else elements=[].slice.apply(context.querySelectorAll(selector));return elements},hasElement:function(selector){return AnimeClient.$(selector).length>0},scrollToTop:function(){var el=AnimeClient.$("header")[0];el.scrollIntoView(true)},hide:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);if(Array.isArray(sel))sel.forEach(function(el){return el.setAttribute("hidden","hidden")});else sel.setAttribute("hidden","hidden")},show:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);
|
|
||||||
if(Array.isArray(sel))sel.forEach(function(el){return el.removeAttribute("hidden")});else sel.removeAttribute("hidden")},showMessage:function(type,message){var template="<div class='message "+type+"'>\n\t\t\t\t<span class='icon'></span>\n\t\t\t\t"+message+"\n\t\t\t\t<span class='close'></span>\n\t\t\t</div>";var sel=AnimeClient.$(".message");if(sel[0]!==undefined)sel[0].remove();AnimeClient.$("header")[0].insertAdjacentHTML("beforeend",template)},closestParent:function(current,parentSelector){if(Element.prototype.closest!==
|
|
||||||
undefined)return current.closest(parentSelector);while(current!==document.documentElement){if(matches(current,parentSelector))return current;current=current.parentElement}return null},url:function(path){var uri="//"+document.location.host;uri+=path.charAt(0)==="/"?path:"/"+path;return uri},throttle:function(interval,fn,scope){var wait=false;return function(args){var $jscomp$restParams=[];for(var $jscomp$restIndex=0;$jscomp$restIndex<arguments.length;++$jscomp$restIndex)$jscomp$restParams[$jscomp$restIndex-
|
|
||||||
0]=arguments[$jscomp$restIndex];{var args$0=$jscomp$restParams;var context=scope||this;if(!wait){fn.apply(context,args$0);wait=true;setTimeout(function(){wait=false},interval)}}}}};function addEvent(sel,event,listener){if(!event.match(/^([\w\-]+)$/))event.split(" ").forEach(function(evt){addEvent(sel,evt,listener)});sel.addEventListener(event,listener,false)}function delegateEvent(sel,target,event,listener){addEvent(sel,event,function(e){AnimeClient.$(target,sel).forEach(function(element){if(e.target==
|
|
||||||
element){listener.call(element,e);e.stopPropagation()}})})}AnimeClient.on=function(sel,event,target,listener){if(listener===undefined){listener=target;AnimeClient.$(sel).forEach(function(el){addEvent(el,event,listener)})}else AnimeClient.$(sel).forEach(function(el){delegateEvent(el,target,event,listener)})};function ajaxSerialize(data){var pairs=[];Object.keys(data).forEach(function(name){var value=data[name].toString();name=encodeURIComponent(name);value=encodeURIComponent(value);pairs.push(name+
|
|
||||||
"="+value)});return pairs.join("&")}AnimeClient.ajax=function(url,config){var defaultConfig={data:{},type:"GET",dataType:"",success:AnimeClient.noop,mimeType:"application/x-www-form-urlencoded",error:AnimeClient.noop};config=Object.assign({},defaultConfig,config);var request=new XMLHttpRequest;var method=String(config.type).toUpperCase();if(method==="GET")url+=url.match(/\?/)?ajaxSerialize(config.data):"?"+ajaxSerialize(config.data);request.open(method,url);request.onreadystatechange=function(){if(request.readyState===
|
|
||||||
4){var responseText="";if(request.responseType==="json")responseText=JSON.parse(request.responseText);else responseText=request.responseText;if(request.status>299)config.error.call(null,request.status,responseText,request.response);else config.success.call(null,responseText,request.status)}};if(config.dataType==="json"){config.data=JSON.stringify(config.data);config.mimeType="application/json"}else config.data=ajaxSerialize(config.data);request.setRequestHeader("Content-Type",config.mimeType);if(method===
|
|
||||||
"GET")request.send(null);else request.send(config.data)};AnimeClient.get=function(url,data,callback){callback=callback===undefined?null:callback;if(callback===null){callback=data;data={}}return AnimeClient.ajax(url,{data:data,success:callback})};AnimeClient.on("header","click",".message",function(e){AnimeClient.hide(e.target)});AnimeClient.on("form.js-delete","submit",function(event){var proceed=confirm("Are you ABSOLUTELY SURE you want to delete this item?");if(proceed===false){event.preventDefault();
|
|
||||||
event.stopPropagation()}});AnimeClient.on(".js-clear-cache","click",function(){AnimeClient.get("/cache_purge",function(){AnimeClient.showMessage("success","Successfully purged api cache")})});AnimeClient.on(".vertical-tabs input","change",function(event){var el=event.currentTarget.parentElement;var rect=el.getBoundingClientRect();var top=rect.top+window.pageYOffset;window.scrollTo({top:top,behavior:"smooth"})});AnimeClient.on(".media-filter","input",function(event){var rawFilter=event.target.value;
|
|
||||||
var filter=new RegExp(rawFilter,"i");if(rawFilter!==""){AnimeClient.$("article.media").forEach(function(article){var titleLink=AnimeClient.$(".name a",article)[0];var title=String(titleLink.textContent).trim();if(!filter.test(title))AnimeClient.hide(article);else AnimeClient.show(article)});AnimeClient.$("table.media-wrap tbody tr").forEach(function(tr){var titleCell=AnimeClient.$("td.align-left",tr)[0];var titleLink=AnimeClient.$("a",titleCell)[0];var linkTitle=String(titleLink.textContent).trim();
|
|
||||||
var textTitle=String(titleCell.textContent).trim();if(!(filter.test(linkTitle)||filter.test(textTitle)))AnimeClient.hide(tr);else AnimeClient.show(tr)})}else{AnimeClient.show("article.media");AnimeClient.show("table.media-wrap tbody tr")}});if("serviceWorker"in navigator)navigator.serviceWorker.register("/sw.js").then(function(reg){console.log("Service worker registered",reg.scope)})["catch"](function(error){console.error("Failed to register service worker",error)});AnimeClient.on("main","change",
|
|
||||||
".big-check",function(e){var id=e.target.id;document.getElementById("mal_"+id).checked=true});function renderAnimeSearchResults(data){var results=[];data.forEach(function(x){var item=x.attributes;var titles=item.titles.reduce(function(prev,current){return prev+(current+"<br />")},[]);results.push('\n\t\t\t<article class="media search">\n\t\t\t\t<div class="name">\n\t\t\t\t\t<input type="radio" class="mal-check" id="mal_'+item.slug+'" name="mal_id" value="'+x.mal_id+'" />\n\t\t\t\t\t<input type="radio" class="big-check" id="'+
|
|
||||||
item.slug+'" name="id" value="'+x.id+'" />\n\t\t\t\t\t<label for="'+item.slug+'">\n\t\t\t\t\t\t<picture width="220">\n\t\t\t\t\t\t\t<source srcset="/public/images/anime/'+x.id+'.webp" type="image/webp" />\n\t\t\t\t\t\t\t<source srcset="/public/images/anime/'+x.id+'.jpg" type="image/jpeg" />\n\t\t\t\t\t\t\t<img src="/public/images/anime/'+x.id+'.jpg" alt="" width="220" />\n\t\t\t\t\t\t</picture>\n\t\t\t\t\t\t\n\t\t\t\t\t\t<span class="name">\n\t\t\t\t\t\t\t'+item.canonicalTitle+"<br />\n\t\t\t\t\t\t\t<small>"+
|
|
||||||
titles+'</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div class="table">\n\t\t\t\t\t<div class="row">\n\t\t\t\t\t\t<span class="edit">\n\t\t\t\t\t\t\t<a class="bracketed" href="/anime/details/'+item.slug+'">Info Page</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t')});return results.join("")}function renderMangaSearchResults(data){var results=[];data.forEach(function(x){var item=x.attributes;var titles=item.titles.reduce(function(prev,
|
|
||||||
current){return prev+(current+"<br />")},[]);results.push('\n\t\t\t<article class="media search">\n\t\t\t\t<div class="name">\n\t\t\t\t\t<input type="radio" id="mal_'+item.slug+'" name="mal_id" value="'+x.mal_id+'" />\n\t\t\t\t\t<input type="radio" class="big-check" id="'+item.slug+'" name="id" value="'+x.id+'" />\n\t\t\t\t\t<label for="'+item.slug+'">\n\t\t\t\t\t\t<picture width="220">\n\t\t\t\t\t\t\t<source srcset="/public/images/manga/'+x.id+'.webp" type="image/webp" />\n\t\t\t\t\t\t\t<source srcset="/public/images/manga/'+
|
|
||||||
x.id+'.jpg" type="image/jpeg" />\n\t\t\t\t\t\t\t<img src="/public/images/manga/'+x.id+'.jpg" alt="" width="220" />\n\t\t\t\t\t\t</picture>\n\t\t\t\t\t\t<span class="name">\n\t\t\t\t\t\t\t'+item.canonicalTitle+"<br />\n\t\t\t\t\t\t\t<small>"+titles+'</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div class="table">\n\t\t\t\t\t<div class="row">\n\t\t\t\t\t\t<span class="edit">\n\t\t\t\t\t\t\t<a class="bracketed" href="/manga/details/'+item.slug+'">Info Page</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t')});
|
|
||||||
return results.join("")}var search=function(query){AnimeClient.show(".cssload-loader");AnimeClient.get(AnimeClient.url("/anime-collection/search"),{query:query},function(searchResults,status){searchResults=JSON.parse(searchResults);AnimeClient.hide(".cssload-loader");AnimeClient.$("#series-list")[0].innerHTML=renderAnimeSearchResults(searchResults.data)})};if(AnimeClient.hasElement(".anime #search"))AnimeClient.on("#search","input",AnimeClient.throttle(250,function(e){var query=encodeURIComponent(e.target.value);
|
|
||||||
if(query==="")return;search(query)}));AnimeClient.on("body.anime.list","click",".plus-one",function(e){var parentSel=AnimeClient.closestParent(e.target,"article");var watchedCount=parseInt(AnimeClient.$(".completed_number",parentSel)[0].textContent,10)||0;var totalCount=parseInt(AnimeClient.$(".total_number",parentSel)[0].textContent,10);var title=AnimeClient.$(".name a",parentSel)[0].textContent;var data={id:parentSel.dataset.kitsuId,mal_id:parentSel.dataset.malId,data:{progress:watchedCount+1}};
|
|
||||||
if(isNaN(watchedCount)||watchedCount===0)data.data.status="current";if(!isNaN(watchedCount)&&watchedCount+1===totalCount)data.data.status="completed";AnimeClient.show("#loading-shadow");AnimeClient.ajax(AnimeClient.url("/anime/increment"),{data:data,dataType:"json",type:"POST",success:function(res){var resData=JSON.parse(res);if(resData.errors){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+title+". ");AnimeClient.scrollToTop();return}if(resData.data.attributes.status===
|
|
||||||
"completed")AnimeClient.hide(parentSel);AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("success","Successfully updated "+title);AnimeClient.$(".completed_number",parentSel)[0].textContent=++watchedCount;AnimeClient.scrollToTop()},error:function(){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+title+". ");AnimeClient.scrollToTop()}})});var search$1=function(query){AnimeClient.show(".cssload-loader");AnimeClient.get(AnimeClient.url("/manga/search"),
|
|
||||||
{query:query},function(searchResults,status){searchResults=JSON.parse(searchResults);AnimeClient.hide(".cssload-loader");AnimeClient.$("#series-list")[0].innerHTML=renderMangaSearchResults(searchResults.data)})};if(AnimeClient.hasElement(".manga #search"))AnimeClient.on("#search","input",AnimeClient.throttle(250,function(e){var query=encodeURIComponent(e.target.value);if(query==="")return;search$1(query)}));AnimeClient.on(".manga.list","click",".edit-buttons button",function(e){var thisSel=e.target;
|
|
||||||
var parentSel=AnimeClient.closestParent(e.target,"article");var type=thisSel.classList.contains("plus-one-chapter")?"chapter":"volume";var completed=parseInt(AnimeClient.$("."+type+"s_read",parentSel)[0].textContent,10)||0;var total=parseInt(AnimeClient.$("."+type+"_count",parentSel)[0].textContent,10);var mangaName=AnimeClient.$(".name",parentSel)[0].textContent;if(isNaN(completed))completed=0;var data={id:parentSel.dataset.kitsuId,mal_id:parentSel.dataset.malId,data:{progress:completed}};if(isNaN(completed)||
|
|
||||||
completed===0)data.data.status="current";if(!isNaN(completed)&&completed+1===total)data.data.status="completed";data.data.progress=++completed;AnimeClient.show("#loading-shadow");AnimeClient.ajax(AnimeClient.url("/manga/increment"),{data:data,dataType:"json",type:"POST",mimeType:"application/json",success:function(){if(data.data.status==="completed")AnimeClient.hide(parentSel);AnimeClient.hide("#loading-shadow");AnimeClient.$("."+type+"s_read",parentSel)[0].textContent=completed;AnimeClient.showMessage("success",
|
|
||||||
"Successfully updated "+mangaName);AnimeClient.scrollToTop()},error:function(){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+mangaName);AnimeClient.scrollToTop()}})})})();
|
|
||||||
//# sourceMappingURL=scripts-authed.min.js.map
|
|
File diff suppressed because one or more lines are too long
23
public/js/scripts.min.js
vendored
23
public/js/scripts.min.js
vendored
@ -1,4 +1,4 @@
|
|||||||
(function(){var matches=function(elm,selector){var matches=(elm.document||elm.ownerDocument).querySelectorAll(selector),i=matches.length;while(--i>=0&&matches.item(i)!==elm);return i>-1};var AnimeClient={noop:function(){},$:function(selector,context){context=context===undefined?null:context;if(typeof selector!=="string")return selector;context=context!==null&&context.nodeType===1?context:document;var elements=[];if(selector.match(/^#([\w]+$)/))elements.push(document.getElementById(selector.split("#")[1]));
|
(function(){var matches=function(elm,selector){var m=(elm.document||elm.ownerDocument).querySelectorAll(selector);var i=matches.length;while(--i>=0&&m.item(i)!==elm);return i>-1};var AnimeClient={noop:function(){},$:function(selector,context){context=context===undefined?null:context;if(typeof selector!=="string")return selector;context=context!==null&&context.nodeType===1?context:document;var elements=[];if(selector.match(/^#([\w]+$)/))elements.push(document.getElementById(selector.split("#")[1]));
|
||||||
else elements=[].slice.apply(context.querySelectorAll(selector));return elements},hasElement:function(selector){return AnimeClient.$(selector).length>0},scrollToTop:function(){var el=AnimeClient.$("header")[0];el.scrollIntoView(true)},hide:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);if(Array.isArray(sel))sel.forEach(function(el){return el.setAttribute("hidden","hidden")});else sel.setAttribute("hidden","hidden")},show:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);
|
else elements=[].slice.apply(context.querySelectorAll(selector));return elements},hasElement:function(selector){return AnimeClient.$(selector).length>0},scrollToTop:function(){var el=AnimeClient.$("header")[0];el.scrollIntoView(true)},hide:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);if(Array.isArray(sel))sel.forEach(function(el){return el.setAttribute("hidden","hidden")});else sel.setAttribute("hidden","hidden")},show:function(sel){if(typeof sel==="string")sel=AnimeClient.$(sel);
|
||||||
if(Array.isArray(sel))sel.forEach(function(el){return el.removeAttribute("hidden")});else sel.removeAttribute("hidden")},showMessage:function(type,message){var template="<div class='message "+type+"'>\n\t\t\t\t<span class='icon'></span>\n\t\t\t\t"+message+"\n\t\t\t\t<span class='close'></span>\n\t\t\t</div>";var sel=AnimeClient.$(".message");if(sel[0]!==undefined)sel[0].remove();AnimeClient.$("header")[0].insertAdjacentHTML("beforeend",template)},closestParent:function(current,parentSelector){if(Element.prototype.closest!==
|
if(Array.isArray(sel))sel.forEach(function(el){return el.removeAttribute("hidden")});else sel.removeAttribute("hidden")},showMessage:function(type,message){var template="<div class='message "+type+"'>\n\t\t\t\t<span class='icon'></span>\n\t\t\t\t"+message+"\n\t\t\t\t<span class='close'></span>\n\t\t\t</div>";var sel=AnimeClient.$(".message");if(sel[0]!==undefined)sel[0].remove();AnimeClient.$("header")[0].insertAdjacentHTML("beforeend",template)},closestParent:function(current,parentSelector){if(Element.prototype.closest!==
|
||||||
undefined)return current.closest(parentSelector);while(current!==document.documentElement){if(matches(current,parentSelector))return current;current=current.parentElement}return null},url:function(path){var uri="//"+document.location.host;uri+=path.charAt(0)==="/"?path:"/"+path;return uri},throttle:function(interval,fn,scope){var wait=false;return function(args){var $jscomp$restParams=[];for(var $jscomp$restIndex=0;$jscomp$restIndex<arguments.length;++$jscomp$restIndex)$jscomp$restParams[$jscomp$restIndex-
|
undefined)return current.closest(parentSelector);while(current!==document.documentElement){if(matches(current,parentSelector))return current;current=current.parentElement}return null},url:function(path){var uri="//"+document.location.host;uri+=path.charAt(0)==="/"?path:"/"+path;return uri},throttle:function(interval,fn,scope){var wait=false;return function(args){var $jscomp$restParams=[];for(var $jscomp$restIndex=0;$jscomp$restIndex<arguments.length;++$jscomp$restIndex)$jscomp$restParams[$jscomp$restIndex-
|
||||||
@ -6,8 +6,21 @@ undefined)return current.closest(parentSelector);while(current!==document.docume
|
|||||||
element){listener.call(element,e);e.stopPropagation()}})})}AnimeClient.on=function(sel,event,target,listener){if(listener===undefined){listener=target;AnimeClient.$(sel).forEach(function(el){addEvent(el,event,listener)})}else AnimeClient.$(sel).forEach(function(el){delegateEvent(el,target,event,listener)})};function ajaxSerialize(data){var pairs=[];Object.keys(data).forEach(function(name){var value=data[name].toString();name=encodeURIComponent(name);value=encodeURIComponent(value);pairs.push(name+
|
element){listener.call(element,e);e.stopPropagation()}})})}AnimeClient.on=function(sel,event,target,listener){if(listener===undefined){listener=target;AnimeClient.$(sel).forEach(function(el){addEvent(el,event,listener)})}else AnimeClient.$(sel).forEach(function(el){delegateEvent(el,target,event,listener)})};function ajaxSerialize(data){var pairs=[];Object.keys(data).forEach(function(name){var value=data[name].toString();name=encodeURIComponent(name);value=encodeURIComponent(value);pairs.push(name+
|
||||||
"="+value)});return pairs.join("&")}AnimeClient.ajax=function(url,config){var defaultConfig={data:{},type:"GET",dataType:"",success:AnimeClient.noop,mimeType:"application/x-www-form-urlencoded",error:AnimeClient.noop};config=Object.assign({},defaultConfig,config);var request=new XMLHttpRequest;var method=String(config.type).toUpperCase();if(method==="GET")url+=url.match(/\?/)?ajaxSerialize(config.data):"?"+ajaxSerialize(config.data);request.open(method,url);request.onreadystatechange=function(){if(request.readyState===
|
"="+value)});return pairs.join("&")}AnimeClient.ajax=function(url,config){var defaultConfig={data:{},type:"GET",dataType:"",success:AnimeClient.noop,mimeType:"application/x-www-form-urlencoded",error:AnimeClient.noop};config=Object.assign({},defaultConfig,config);var request=new XMLHttpRequest;var method=String(config.type).toUpperCase();if(method==="GET")url+=url.match(/\?/)?ajaxSerialize(config.data):"?"+ajaxSerialize(config.data);request.open(method,url);request.onreadystatechange=function(){if(request.readyState===
|
||||||
4){var responseText="";if(request.responseType==="json")responseText=JSON.parse(request.responseText);else responseText=request.responseText;if(request.status>299)config.error.call(null,request.status,responseText,request.response);else config.success.call(null,responseText,request.status)}};if(config.dataType==="json"){config.data=JSON.stringify(config.data);config.mimeType="application/json"}else config.data=ajaxSerialize(config.data);request.setRequestHeader("Content-Type",config.mimeType);if(method===
|
4){var responseText="";if(request.responseType==="json")responseText=JSON.parse(request.responseText);else responseText=request.responseText;if(request.status>299)config.error.call(null,request.status,responseText,request.response);else config.success.call(null,responseText,request.status)}};if(config.dataType==="json"){config.data=JSON.stringify(config.data);config.mimeType="application/json"}else config.data=ajaxSerialize(config.data);request.setRequestHeader("Content-Type",config.mimeType);if(method===
|
||||||
"GET")request.send(null);else request.send(config.data)};AnimeClient.get=function(url,data,callback){callback=callback===undefined?null:callback;if(callback===null){callback=data;data={}}return AnimeClient.ajax(url,{data:data,success:callback})};AnimeClient.on("header","click",".message",function(e){AnimeClient.hide(e.target)});AnimeClient.on("form.js-delete","submit",function(event){var proceed=confirm("Are you ABSOLUTELY SURE you want to delete this item?");if(proceed===false){event.preventDefault();
|
"GET")request.send(null);else request.send(config.data)};AnimeClient.get=function(url,data,callback){callback=callback===undefined?null:callback;if(callback===null){callback=data;data={}}return AnimeClient.ajax(url,{data:data,success:callback})};AnimeClient.on("header","click",".message",hide);AnimeClient.on("form.js-delete","submit",confirmDelete);AnimeClient.on(".js-clear-cache","click",clearAPICache);AnimeClient.on(".vertical-tabs input","change",scrollToSection);AnimeClient.on(".media-filter",
|
||||||
event.stopPropagation()}});AnimeClient.on(".js-clear-cache","click",function(){AnimeClient.get("/cache_purge",function(){AnimeClient.showMessage("success","Successfully purged api cache")})});AnimeClient.on(".vertical-tabs input","change",function(event){var el=event.currentTarget.parentElement;var rect=el.getBoundingClientRect();var top=rect.top+window.pageYOffset;window.scrollTo({top:top,behavior:"smooth"})});AnimeClient.on(".media-filter","input",function(event){var rawFilter=event.target.value;
|
"input",filterMedia);function hide(event){AnimeClient.hide(event.target)}function confirmDelete(event){var proceed=confirm("Are you ABSOLUTELY SURE you want to delete this item?");if(proceed===false){event.preventDefault();event.stopPropagation()}}function clearAPICache(){AnimeClient.get("/cache_purge",function(){AnimeClient.showMessage("success","Successfully purged api cache")})}function scrollToSection(event){var el=event.currentTarget.parentElement;var rect=el.getBoundingClientRect();var top=
|
||||||
var filter=new RegExp(rawFilter,"i");if(rawFilter!==""){AnimeClient.$("article.media").forEach(function(article){var titleLink=AnimeClient.$(".name a",article)[0];var title=String(titleLink.textContent).trim();if(!filter.test(title))AnimeClient.hide(article);else AnimeClient.show(article)});AnimeClient.$("table.media-wrap tbody tr").forEach(function(tr){var titleCell=AnimeClient.$("td.align-left",tr)[0];var titleLink=AnimeClient.$("a",titleCell)[0];var linkTitle=String(titleLink.textContent).trim();
|
rect.top+window.pageYOffset;window.scrollTo({top:top,behavior:"smooth"})}function filterMedia(event){var rawFilter=event.target.value;var filter=new RegExp(rawFilter,"i");if(rawFilter!==""){AnimeClient.$("article.media").forEach(function(article){var titleLink=AnimeClient.$(".name a",article)[0];var title=String(titleLink.textContent).trim();if(!filter.test(title))AnimeClient.hide(article);else AnimeClient.show(article)});AnimeClient.$("table.media-wrap tbody tr").forEach(function(tr){var titleCell=
|
||||||
var textTitle=String(titleCell.textContent).trim();if(!(filter.test(linkTitle)||filter.test(textTitle)))AnimeClient.hide(tr);else AnimeClient.show(tr)})}else{AnimeClient.show("article.media");AnimeClient.show("table.media-wrap tbody tr")}});if("serviceWorker"in navigator)navigator.serviceWorker.register("/sw.js").then(function(reg){console.log("Service worker registered",reg.scope)})["catch"](function(error){console.error("Failed to register service worker",error)})})();
|
AnimeClient.$("td.align-left",tr)[0];var titleLink=AnimeClient.$("a",titleCell)[0];var linkTitle=String(titleLink.textContent).trim();var textTitle=String(titleCell.textContent).trim();if(!(filter.test(linkTitle)||filter.test(textTitle)))AnimeClient.hide(tr);else AnimeClient.show(tr)})}else{AnimeClient.show("article.media");AnimeClient.show("table.media-wrap tbody tr")}}if("serviceWorker"in navigator)navigator.serviceWorker.register("/sw.js").then(function(reg){console.log("Service worker registered",
|
||||||
|
reg.scope)})["catch"](function(error){console.error("Failed to register service worker",error)});AnimeClient.on("main","change",".big-check",function(e){var id=e.target.id;document.getElementById("mal_"+id).checked=true});function renderAnimeSearchResults(data){var results=[];data.forEach(function(x){var item=x.attributes;var titles=item.titles.join("<br />");results.push('\n\t\t\t<article class="media search">\n\t\t\t\t<div class="name">\n\t\t\t\t\t<input type="radio" class="mal-check" id="mal_'+
|
||||||
|
item.slug+'" name="mal_id" value="'+x.mal_id+'" />\n\t\t\t\t\t<input type="radio" class="big-check" id="'+item.slug+'" name="id" value="'+x.id+'" />\n\t\t\t\t\t<label for="'+item.slug+'">\n\t\t\t\t\t\t<picture width="220">\n\t\t\t\t\t\t\t<source srcset="/public/images/anime/'+x.id+'.webp" type="image/webp" />\n\t\t\t\t\t\t\t<source srcset="/public/images/anime/'+x.id+'.jpg" type="image/jpeg" />\n\t\t\t\t\t\t\t<img src="/public/images/anime/'+x.id+'.jpg" alt="" width="220" />\n\t\t\t\t\t\t</picture>\n\t\t\t\t\t\t<span class="name">\n\t\t\t\t\t\t\t'+
|
||||||
|
item.canonicalTitle+"<br />\n\t\t\t\t\t\t\t<small>"+titles+'</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div class="table">\n\t\t\t\t\t<div class="row">\n\t\t\t\t\t\t<span class="edit">\n\t\t\t\t\t\t\t<a class="bracketed" href="/anime/details/'+item.slug+'">Info Page</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t')});return results.join("")}function renderMangaSearchResults(data){var results=[];data.forEach(function(x){var item=x.attributes;
|
||||||
|
var titles=item.titles.join("<br />");results.push('\n\t\t\t<article class="media search">\n\t\t\t\t<div class="name">\n\t\t\t\t\t<input type="radio" id="mal_'+item.slug+'" name="mal_id" value="'+x.mal_id+'" />\n\t\t\t\t\t<input type="radio" class="big-check" id="'+item.slug+'" name="id" value="'+x.id+'" />\n\t\t\t\t\t<label for="'+item.slug+'">\n\t\t\t\t\t\t<picture width="220">\n\t\t\t\t\t\t\t<source srcset="/public/images/manga/'+x.id+'.webp" type="image/webp" />\n\t\t\t\t\t\t\t<source srcset="/public/images/manga/'+
|
||||||
|
x.id+'.jpg" type="image/jpeg" />\n\t\t\t\t\t\t\t<img src="/public/images/manga/'+x.id+'.jpg" alt="" width="220" />\n\t\t\t\t\t\t</picture>\n\t\t\t\t\t\t<span class="name">\n\t\t\t\t\t\t\t'+item.canonicalTitle+"<br />\n\t\t\t\t\t\t\t<small>"+titles+'</small>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</label>\n\t\t\t\t</div>\n\t\t\t\t<div class="table">\n\t\t\t\t\t<div class="row">\n\t\t\t\t\t\t<span class="edit">\n\t\t\t\t\t\t\t<a class="bracketed" href="/manga/details/'+item.slug+'">Info Page</a>\n\t\t\t\t\t\t</span>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</article>\n\t\t')});
|
||||||
|
return results.join("")}var search=function(query){AnimeClient.show(".cssload-loader");AnimeClient.get(AnimeClient.url("/anime-collection/search"),{query:query},function(searchResults,status){searchResults=JSON.parse(searchResults);AnimeClient.hide(".cssload-loader");AnimeClient.$("#series-list")[0].innerHTML=renderAnimeSearchResults(searchResults.data)})};if(AnimeClient.hasElement(".anime #search"))AnimeClient.on("#search","input",AnimeClient.throttle(250,function(e){var query=encodeURIComponent(e.target.value);
|
||||||
|
if(query==="")return;search(query)}));AnimeClient.on("body.anime.list","click",".plus-one",function(e){var parentSel=AnimeClient.closestParent(e.target,"article");var watchedCount=parseInt(AnimeClient.$(".completed_number",parentSel)[0].textContent,10)||0;var totalCount=parseInt(AnimeClient.$(".total_number",parentSel)[0].textContent,10);var title=AnimeClient.$(".name a",parentSel)[0].textContent;var data={id:parentSel.dataset.kitsuId,mal_id:parentSel.dataset.malId,data:{progress:watchedCount+1}};
|
||||||
|
if(isNaN(watchedCount)||watchedCount===0)data.data.status="current";if(!isNaN(watchedCount)&&watchedCount+1===totalCount)data.data.status="completed";AnimeClient.show("#loading-shadow");AnimeClient.ajax(AnimeClient.url("/anime/increment"),{data:data,dataType:"json",type:"POST",success:function(res){var resData=JSON.parse(res);if(resData.errors){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+title+". ");AnimeClient.scrollToTop();return}if(resData.data.attributes.status===
|
||||||
|
"completed")AnimeClient.hide(parentSel);AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("success","Successfully updated "+title);AnimeClient.$(".completed_number",parentSel)[0].textContent=++watchedCount;AnimeClient.scrollToTop()},error:function(){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+title+". ");AnimeClient.scrollToTop()}})});var search$1=function(query){AnimeClient.show(".cssload-loader");AnimeClient.get(AnimeClient.url("/manga/search"),
|
||||||
|
{query:query},function(searchResults,status){searchResults=JSON.parse(searchResults);AnimeClient.hide(".cssload-loader");AnimeClient.$("#series-list")[0].innerHTML=renderMangaSearchResults(searchResults.data)})};if(AnimeClient.hasElement(".manga #search"))AnimeClient.on("#search","input",AnimeClient.throttle(250,function(e){var query=encodeURIComponent(e.target.value);if(query==="")return;search$1(query)}));AnimeClient.on(".manga.list","click",".edit-buttons button",function(e){var thisSel=e.target;
|
||||||
|
var parentSel=AnimeClient.closestParent(e.target,"article");var type=thisSel.classList.contains("plus-one-chapter")?"chapter":"volume";var completed=parseInt(AnimeClient.$("."+type+"s_read",parentSel)[0].textContent,10)||0;var total=parseInt(AnimeClient.$("."+type+"_count",parentSel)[0].textContent,10);var mangaName=AnimeClient.$(".name",parentSel)[0].textContent;if(isNaN(completed))completed=0;var data={id:parentSel.dataset.kitsuId,mal_id:parentSel.dataset.malId,data:{progress:completed}};if(isNaN(completed)||
|
||||||
|
completed===0)data.data.status="current";if(!isNaN(completed)&&completed+1===total)data.data.status="completed";data.data.progress=++completed;AnimeClient.show("#loading-shadow");AnimeClient.ajax(AnimeClient.url("/manga/increment"),{data:data,dataType:"json",type:"POST",mimeType:"application/json",success:function(){if(data.data.status==="completed")AnimeClient.hide(parentSel);AnimeClient.hide("#loading-shadow");AnimeClient.$("."+type+"s_read",parentSel)[0].textContent=completed;AnimeClient.showMessage("success",
|
||||||
|
"Successfully updated "+mangaName);AnimeClient.scrollToTop()},error:function(){AnimeClient.hide("#loading-shadow");AnimeClient.showMessage("error","Failed to update "+mangaName);AnimeClient.scrollToTop()}})})})()
|
||||||
//# sourceMappingURL=scripts.min.js.map
|
//# sourceMappingURL=scripts.min.js.map
|
||||||
|
File diff suppressed because one or more lines are too long
2
public/js/tables.min.js
vendored
2
public/js/tables.min.js
vendored
@ -1,4 +1,4 @@
|
|||||||
(function(){var LightTableSorter=function(){var th=null;var cellIndex=null;var order="";var text=function(row){return row.cells.item(cellIndex).textContent.toLowerCase()};var sort=function(a,b){var textA=text(a);var textB=text(b);var n=parseInt(textA,10);if(n){textA=n;textB=parseInt(textB,10)}if(textA>textB)return 1;if(textA<textB)return-1;return 0};var toggle=function(){var c=order!=="sorting-asc"?"sorting-asc":"sorting-desc";th.className=(th.className.replace(order,"")+" "+c).trim();return order=
|
(function(){var LightTableSorter=function(){var th=null;var cellIndex=null;var order="";var text=function(row){return row.cells.item(cellIndex).textContent.toLowerCase()};var sort=function(a,b){var textA=text(a);var textB=text(b);var n=parseInt(textA,10);if(n){textA=n;textB=parseInt(textB,10)}if(textA>textB)return 1;if(textA<textB)return-1;return 0};var toggle=function(){var c=order!=="sorting-asc"?"sorting-asc":"sorting-desc";th.className=(th.className.replace(order,"")+" "+c).trim();return order=
|
||||||
c};var reset=function(){th.classList.remove("sorting-asc","sorting-desc");th.classList.add("sorting");return order=""};var onClickEvent=function(e){if(th&&cellIndex!==e.target.cellIndex)reset();th=e.target;if(th.nodeName.toLowerCase()==="th"){cellIndex=th.cellIndex;var tbody=th.offsetParent.getElementsByTagName("tbody")[0];var rows=Array.from(tbody.rows);if(rows){rows.sort(sort);if(order==="sorting-asc")rows.reverse();toggle();tbody.innerHtml="";rows.forEach(function(row){tbody.appendChild(row)})}}};
|
c};var reset=function(){th.classList.remove("sorting-asc","sorting-desc");th.classList.add("sorting");return order=""};var onClickEvent=function(e){if(th&&cellIndex!==e.target.cellIndex)reset();th=e.target;if(th.nodeName.toLowerCase()==="th"){cellIndex=th.cellIndex;var tbody=th.offsetParent.getElementsByTagName("tbody")[0];var rows=Array.from(tbody.rows);if(rows){rows.sort(sort);if(order==="sorting-asc")rows.reverse();toggle();tbody.innerHtml="";rows.forEach(function(row){tbody.appendChild(row)})}}};
|
||||||
return{init:function(){var ths=document.getElementsByTagName("th");var results=[];for(var i=0,len=ths.length;i<len;i++){var th$0=ths[i];th$0.classList.add("sorting");results.push(th$0.onclick=onClickEvent)}return results}}}();LightTableSorter.init()})();
|
return{init:function(){var ths=document.getElementsByTagName("th");var results=[];for(var i=0,len=ths.length;i<len;i++){var th$0=ths[i];th$0.classList.add("sorting");results.push(th$0.onclick=onClickEvent)}return results}}}();LightTableSorter.init()})()
|
||||||
//# sourceMappingURL=tables.min.js.map
|
//# sourceMappingURL=tables.min.js.map
|
||||||
|
@ -1 +1 @@
|
|||||||
{"version":3,"file":"tables.min.js.map","sources":["src/base/sort_tables.js"],"sourcesContent":["const LightTableSorter = (() => {\n\tlet th = null;\n\tlet cellIndex = null;\n\tlet order = '';\n\tconst text = (row) => row.cells.item(cellIndex).textContent.toLowerCase();\n\tconst sort = (a, b) => {\n\t\tlet textA = text(a);\n\t\tlet textB = text(b);\n\t\tconst n = parseInt(textA, 10);\n\t\tif (n) {\n\t\t\ttextA = n;\n\t\t\ttextB = parseInt(textB, 10);\n\t\t}\n\t\tif (textA > textB) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (textA < textB) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn 0;\n\t};\n\tconst toggle = () => {\n\t\tconst c = order !== 'sorting-asc' ? 'sorting-asc' : 'sorting-desc';\n\t\tth.className = (th.className.replace(order, '') + ' ' + c).trim();\n\t\treturn order = c;\n\t};\n\tconst reset = () => {\n\t\tth.classList.remove('sorting-asc', 'sorting-desc');\n\t\tth.classList.add('sorting');\n\t\treturn order = '';\n\t};\n\tconst onClickEvent = (e) => {\n\t\tif (th && (cellIndex !== e.target.cellIndex)) {\n\t\t\treset();\n\t\t}\n\t\tth = e.target;\n\t\tif (th.nodeName.toLowerCase() === 'th') {\n\t\t\tcellIndex = th.cellIndex;\n\t\t\tconst tbody = th.offsetParent.getElementsByTagName('tbody')[0];\n\t\t\tlet rows = Array.from(tbody.rows);\n\t\t\tif (rows) {\n\t\t\t\trows.sort(sort);\n\t\t\t\tif (order === 'sorting-asc') {\n\t\t\t\t\trows.reverse();\n\t\t\t\t}\n\t\t\t\ttoggle();\n\t\t\t\ttbody.innerHtml = '';\n\n\t\t\t\trows.forEach(row => {\n\t\t\t\t\ttbody.appendChild(row);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\treturn {\n\t\tinit: () => {\n\t\t\tlet ths = document.getElementsByTagName('th');\n\t\t\tlet results = [];\n\t\t\tfor (let i = 0, len = ths.length; i < len; i++) {\n\t\t\t\tlet th = ths[i];\n\t\t\t\tth.classList.add('sorting');\n\t\t\t\tresults.push(th.onclick = onClickEvent);\n\t\t\t}\n\t\t\treturn results;\n\t\t}\n\t};\n})();\n\nLightTableSorter.init();"],"names":["th","cellIndex","order","text","row","cells","item","textContent","toLowerCase","sort","a","b","textA","textB","n","parseInt","toggle","c","className","trim","replace","reset","classList","remove","add","onClickEvent","e","target","nodeName","tbody","offsetParent","getElementsByTagName","rows","Array","from","reverse","innerHtml","forEach","appendChild","init","ths","document","results","i","len","length","push","onclick","LightTableSorter"],"mappings":"YAAA,gCACC,IAAIA,GAAK,IACT,KAAIC,UAAY,IAChB,KAAIC,MAAQ,EACZ,KAAMC,KAAOA,QAAA,CAACC,GAAD,CAAS,CAAA,MAAAA,IAAAC,MAAAC,KAAA,CAAeL,SAAf,CAAAM,YAAAC,YAAA,EAAA,CACtB,KAAMC,KAAOA,QAAA,CAACC,CAAD,CAAIC,CAAJ,CAAU,CACtB,IAAIC,MAAQT,IAAA,CAAKO,CAAL,CACZ,KAAIG,MAAQV,IAAA,CAAKQ,CAAL,CACZ,KAAMG,EAAIC,QAAA,CAASH,KAAT,CAAgB,EAAhB,CACV,IAAIE,CAAJ,CAAO,CACNF,KAAA,CAAQE,CACRD,MAAA,CAAQE,QAAA,CAASF,KAAT,CAAgB,EAAhB,CAFF,CAIP,GAAID,KAAJ,CAAYC,KAAZ,CACC,MAAO,EAER,IAAID,KAAJ,CAAYC,KAAZ,CACC,MAAQ,EAET,OAAO,EAde,CAgBvB,KAAMG,OAASA,QAAA,EAAM,CACpB,IAAMC,EAAIf,KAAA,GAAU,aAAV,CAA0B,aAA1B,CAA0C,cACpDF,GAAAkB,UAAA,CAAeC,CAACnB,EAAAkB,UAAAE,QAAA,CAAqBlB,KAArB,CAA4B,EAA5B,CAADiB,CAAmC,GAAnCA,CAAyCF,CAAzCE,MAAA,EACf,OAAOjB,MAAP;AAAee,CAHK,CAKrB,KAAMI,MAAQA,QAAA,EAAM,CACnBrB,EAAAsB,UAAAC,OAAA,CAAoB,aAApB,CAAmC,cAAnC,CACAvB,GAAAsB,UAAAE,IAAA,CAAiB,SAAjB,CACA,OAAOtB,MAAP,CAAe,EAHI,CAKpB,KAAMuB,aAAeA,QAAA,CAACC,CAAD,CAAO,CAC3B,GAAI1B,EAAJ,EAAWC,SAAX,GAAyByB,CAAAC,OAAA1B,UAAzB,CACCoB,KAAA,EAEDrB,GAAA,CAAK0B,CAAAC,OACL,IAAI3B,EAAA4B,SAAApB,YAAA,EAAJ,GAAkC,IAAlC,CAAwC,CACvCP,SAAA,CAAYD,EAAAC,UACZ,KAAM4B,MAAQ7B,EAAA8B,aAAAC,qBAAA,CAAqC,OAArC,CAAA,CAA8C,CAA9C,CACd,KAAIC,KAAOC,KAAAC,KAAA,CAAWL,KAAAG,KAAX,CACX,IAAIA,IAAJ,CAAU,CACTA,IAAAvB,KAAA,CAAUA,IAAV,CACA,IAAIP,KAAJ,GAAc,aAAd,CACC8B,IAAAG,QAAA,EAEDnB,OAAA,EACAa,MAAAO,UAAA,CAAkB,EAElBJ,KAAAK,QAAA,CAAa,QAAA,CAAAjC,GAAA,CAAO,CACnByB,KAAAS,YAAA,CAAkBlC,GAAlB,CADmB,CAApB,CARS,CAJ6B,CALb,CAuB5B;MAAO,CACNmC,KAAMA,QAAA,EAAM,CACX,IAAIC,IAAMC,QAAAV,qBAAA,CAA8B,IAA9B,CACV,KAAIW,QAAU,EACd,KAAK,IAAIC,EAAI,CAAR,CAAWC,IAAMJ,GAAAK,OAAtB,CAAkCF,CAAlC,CAAsCC,GAAtC,CAA2CD,CAAA,EAA3C,CAAgD,CAC/C,IAAI3C,KAAKwC,GAAA,CAAIG,CAAJ,CACT3C,KAAAsB,UAAAE,IAAA,CAAiB,SAAjB,CACAkB,QAAAI,KAAA,CAAa9C,IAAA+C,QAAb,CAA0BtB,YAA1B,CAH+C,CAKhD,MAAOiB,QARI,CADN,IAcRM,iBAAAT,KAAA;"}
|
{"version":3,"file":"tables.min.js.map","sources":["../../frontEndSrc/js/base/sort-tables.js"],"sourcesContent":["const LightTableSorter = (() => {\n\tlet th = null;\n\tlet cellIndex = null;\n\tlet order = '';\n\tconst text = (row) => row.cells.item(cellIndex).textContent.toLowerCase();\n\tconst sort = (a, b) => {\n\t\tlet textA = text(a);\n\t\tlet textB = text(b);\n\t\tconst n = parseInt(textA, 10);\n\t\tif (n) {\n\t\t\ttextA = n;\n\t\t\ttextB = parseInt(textB, 10);\n\t\t}\n\t\tif (textA > textB) {\n\t\t\treturn 1;\n\t\t}\n\t\tif (textA < textB) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn 0;\n\t};\n\tconst toggle = () => {\n\t\tconst c = order !== 'sorting-asc' ? 'sorting-asc' : 'sorting-desc';\n\t\tth.className = (th.className.replace(order, '') + ' ' + c).trim();\n\t\treturn order = c;\n\t};\n\tconst reset = () => {\n\t\tth.classList.remove('sorting-asc', 'sorting-desc');\n\t\tth.classList.add('sorting');\n\t\treturn order = '';\n\t};\n\tconst onClickEvent = (e) => {\n\t\tif (th && (cellIndex !== e.target.cellIndex)) {\n\t\t\treset();\n\t\t}\n\t\tth = e.target;\n\t\tif (th.nodeName.toLowerCase() === 'th') {\n\t\t\tcellIndex = th.cellIndex;\n\t\t\tconst tbody = th.offsetParent.getElementsByTagName('tbody')[0];\n\t\t\tlet rows = Array.from(tbody.rows);\n\t\t\tif (rows) {\n\t\t\t\trows.sort(sort);\n\t\t\t\tif (order === 'sorting-asc') {\n\t\t\t\t\trows.reverse();\n\t\t\t\t}\n\t\t\t\ttoggle();\n\t\t\t\ttbody.innerHtml = '';\n\n\t\t\t\trows.forEach(row => {\n\t\t\t\t\ttbody.appendChild(row);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t};\n\treturn {\n\t\tinit: () => {\n\t\t\tlet ths = document.getElementsByTagName('th');\n\t\t\tlet results = [];\n\t\t\tfor (let i = 0, len = ths.length; i < len; i++) {\n\t\t\t\tlet th = ths[i];\n\t\t\t\tth.classList.add('sorting');\n\t\t\t\tresults.push(th.onclick = onClickEvent);\n\t\t\t}\n\t\t\treturn results;\n\t\t}\n\t};\n})();\n\nLightTableSorter.init();"],"names":["th","cellIndex","order","text","row","cells","item","textContent","toLowerCase","sort","a","b","textA","textB","n","parseInt","toggle","c","className","trim","replace","reset","classList","remove","add","onClickEvent","e","target","nodeName","tbody","offsetParent","getElementsByTagName","rows","Array","from","reverse","innerHtml","forEach","appendChild","init","ths","document","results","i","len","length","push","onclick","LightTableSorter"],"mappings":"YAAA,gCACC,IAAIA,GAAK,IACT,KAAIC,UAAY,IAChB,KAAIC,MAAQ,EACZ,KAAMC,KAAOA,QAAA,CAACC,GAAD,CAAS,CAAA,MAAAA,IAAAC,MAAAC,KAAA,CAAeL,SAAf,CAAAM,YAAAC,YAAA,EAAA,CACtB,KAAMC,KAAOA,QAAA,CAACC,CAAD,CAAIC,CAAJ,CAAU,CACtB,IAAIC,MAAQT,IAAA,CAAKO,CAAL,CACZ,KAAIG,MAAQV,IAAA,CAAKQ,CAAL,CACZ,KAAMG,EAAIC,QAAA,CAASH,KAAT,CAAgB,EAAhB,CACV,IAAIE,CAAJ,CAAO,CACNF,KAAA,CAAQE,CACRD,MAAA,CAAQE,QAAA,CAASF,KAAT,CAAgB,EAAhB,CAFF,CAIP,GAAID,KAAJ,CAAYC,KAAZ,CACC,MAAO,EAER,IAAID,KAAJ,CAAYC,KAAZ,CACC,MAAO,EAER,OAAO,EAde,CAgBvB,KAAMG,OAASA,QAAA,EAAM,CACpB,IAAMC,EAAIf,KAAA,GAAU,aAAV,CAA0B,aAA1B,CAA0C,cACpDF,GAAAkB,UAAA,CAAeC,CAACnB,EAAAkB,UAAAE,QAAA,CAAqBlB,KAArB,CAA4B,EAA5B,CAADiB,CAAmC,GAAnCA,CAAyCF,CAAzCE,MAAA,EACf,OAAOjB,MAAP;AAAee,CAHK,CAKrB,KAAMI,MAAQA,QAAA,EAAM,CACnBrB,EAAAsB,UAAAC,OAAA,CAAoB,aAApB,CAAmC,cAAnC,CACAvB,GAAAsB,UAAAE,IAAA,CAAiB,SAAjB,CACA,OAAOtB,MAAP,CAAe,EAHI,CAKpB,KAAMuB,aAAeA,QAAA,CAACC,CAAD,CAAO,CAC3B,GAAI1B,EAAJ,EAAWC,SAAX,GAAyByB,CAAAC,OAAA1B,UAAzB,CACCoB,KAAA,EAEDrB,GAAA,CAAK0B,CAAAC,OACL,IAAI3B,EAAA4B,SAAApB,YAAA,EAAJ,GAAkC,IAAlC,CAAwC,CACvCP,SAAA,CAAYD,EAAAC,UACZ,KAAM4B,MAAQ7B,EAAA8B,aAAAC,qBAAA,CAAqC,OAArC,CAAA,CAA8C,CAA9C,CACd,KAAIC,KAAOC,KAAAC,KAAA,CAAWL,KAAAG,KAAX,CACX,IAAIA,IAAJ,CAAU,CACTA,IAAAvB,KAAA,CAAUA,IAAV,CACA,IAAIP,KAAJ,GAAc,aAAd,CACC8B,IAAAG,QAAA,EAEDnB,OAAA,EACAa,MAAAO,UAAA,CAAkB,EAElBJ,KAAAK,QAAA,CAAa,QAAA,CAAAjC,GAAA,CAAO,CACnByB,KAAAS,YAAA,CAAkBlC,GAAlB,CADmB,CAApB,CARS,CAJ6B,CALb,CAuB5B;MAAO,CACNmC,KAAMA,QAAA,EAAM,CACX,IAAIC,IAAMC,QAAAV,qBAAA,CAA8B,IAA9B,CACV,KAAIW,QAAU,EACd,KAAK,IAAIC,EAAI,CAAR,CAAWC,IAAMJ,GAAAK,OAAtB,CAAkCF,CAAlC,CAAsCC,GAAtC,CAA2CD,CAAA,EAA3C,CAAgD,CAC/C,IAAI3C,KAAKwC,GAAA,CAAIG,CAAJ,CACT3C,KAAAsB,UAAAE,IAAA,CAAiB,SAAjB,CACAkB,QAAAI,KAAA,CAAa9C,IAAA+C,QAAb,CAA0BtB,YAA1B,CAH+C,CAKhD,MAAOiB,QARI,CADN,IAcRM,iBAAAT,KAAA;"}
|
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"license": "MIT",
|
|
||||||
"scripts": {
|
|
||||||
"build": "npm run build:css && npm run build:js",
|
|
||||||
"build:css": "node ./tools/css.js",
|
|
||||||
"build:js": "rollup -c ./tools/build-js.js",
|
|
||||||
"watch:css": "watch 'npm run build:css' --filter=./tools/cssfilter.js",
|
|
||||||
"watch:js": "watch 'npm run build:js' ./js/src",
|
|
||||||
"watch": "concurrently \"npm:watch:css\" \"npm:watch:js\" --kill-others"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@ampproject/rollup-plugin-closure-compiler": "^0.9.0",
|
|
||||||
"concurrently": "^4.1.1",
|
|
||||||
"cssnano": "^4.1.10",
|
|
||||||
"postcss": "^7.0.17",
|
|
||||||
"postcss-import": "^12.0.1",
|
|
||||||
"postcss-preset-env": "^6.7.0",
|
|
||||||
"rollup": "^1.16.7",
|
|
||||||
"watch": "^1.0.2"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
import compiler from '@ampproject/rollup-plugin-closure-compiler';
|
|
||||||
|
|
||||||
const plugins = [
|
|
||||||
compiler({
|
|
||||||
assumeFunctionWrapper: true,
|
|
||||||
compilationLevel: 'WHITESPACE_ONLY', //'ADVANCED',
|
|
||||||
createSourceMap: true,
|
|
||||||
env: 'BROWSER',
|
|
||||||
languageIn: 'ECMASCRIPT_2018',
|
|
||||||
languageOut: 'ES3'
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
const defaultOutput = {
|
|
||||||
format: 'iife',
|
|
||||||
sourcemap: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [{
|
|
||||||
input: './js/src/index.js',
|
|
||||||
output: {
|
|
||||||
...defaultOutput,
|
|
||||||
file: './js/scripts.min.js',
|
|
||||||
sourcemapFile: './js/scripts.min.js.map',
|
|
||||||
},
|
|
||||||
plugins,
|
|
||||||
}, {
|
|
||||||
input: './js/src/index-authed.js',
|
|
||||||
output: {
|
|
||||||
...defaultOutput,
|
|
||||||
file: './js/scripts-authed.min.js',
|
|
||||||
sourcemapFile: './js/scripts-authed.min.js.map',
|
|
||||||
},
|
|
||||||
plugins,
|
|
||||||
}, {
|
|
||||||
input: './js/src/base/sort_tables.js',
|
|
||||||
output: {
|
|
||||||
...defaultOutput,
|
|
||||||
file: './js/tables.min.js',
|
|
||||||
sourcemapFile: './js/tables.min.js.map',
|
|
||||||
},
|
|
||||||
plugins,
|
|
||||||
}];
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
/**
|
|
||||||
* Script for optimizing css
|
|
||||||
*/
|
|
||||||
const fs = require('fs');
|
|
||||||
const postcss = require('postcss');
|
|
||||||
const atImport = require('postcss-import');
|
|
||||||
const cssNext = require('postcss-preset-env');
|
|
||||||
const cssNano = require('cssnano');
|
|
||||||
|
|
||||||
const css = fs.readFileSync('css/src/all.css', 'utf-8');
|
|
||||||
const darkCss = fs.readFileSync('css/src/dark-override.css', 'utf-8');
|
|
||||||
|
|
||||||
const minOptions = {
|
|
||||||
autoprefixer: false,
|
|
||||||
colormin: false,
|
|
||||||
minifyFontValues: false,
|
|
||||||
options: {
|
|
||||||
sourcemap: false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const processOptions = {
|
|
||||||
browser: '> 0.5%',
|
|
||||||
features: {
|
|
||||||
'custom-properties': true,
|
|
||||||
},
|
|
||||||
stage: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
(async () => {
|
|
||||||
// Basic theme
|
|
||||||
const light = await postcss()
|
|
||||||
.use(atImport())
|
|
||||||
.use(cssNext(processOptions))
|
|
||||||
.use(cssNano(minOptions))
|
|
||||||
.process(css, {
|
|
||||||
from: 'css/src/all.css',
|
|
||||||
to: 'css/app.min.css',
|
|
||||||
});
|
|
||||||
fs.writeFileSync('css/app.min.css', light);
|
|
||||||
|
|
||||||
// Dark theme
|
|
||||||
const dark = await postcss()
|
|
||||||
.use(atImport())
|
|
||||||
.use(cssNext(processOptions))
|
|
||||||
.use(cssNano(minOptions))
|
|
||||||
.process(darkCss, {
|
|
||||||
from: 'css/dark-override.css',
|
|
||||||
to: 'css/dark.min.css',
|
|
||||||
});
|
|
||||||
fs.writeFileSync('css/dark.min.css', dark);
|
|
||||||
|
|
||||||
const autoDarkCss = `${light} @media (prefers-color-scheme: dark) { ${dark} }`
|
|
||||||
fs.writeFileSync('css/dark-auto.min.css', autoDarkCss)
|
|
||||||
|
|
||||||
})();
|
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,37 +38,37 @@ abstract class APIRequestBuilder {
|
|||||||
* Url prefix for making url requests
|
* Url prefix for making url requests
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $baseUrl = '';
|
protected string $baseUrl = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Url path of the request
|
* Url path of the request
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $path = '';
|
protected string $path = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query string for the request
|
* Query string for the request
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $query = '';
|
protected string $query = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default request headers
|
* Default request headers
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultHeaders = [];
|
protected array $defaultHeaders = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid HTTP request methods
|
* Valid HTTP request methods
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
|
protected array $validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current request
|
* The current request
|
||||||
* @var Request
|
* @var Request
|
||||||
*/
|
*/
|
||||||
protected $request;
|
protected Request $request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do a basic minimal GET request
|
* Do a basic minimal GET request
|
||||||
@ -78,8 +78,10 @@ abstract class APIRequestBuilder {
|
|||||||
*/
|
*/
|
||||||
public static function simpleRequest(string $uri): Request
|
public static function simpleRequest(string $uri): Request
|
||||||
{
|
{
|
||||||
return (new Request($uri))
|
$request = (new Request($uri));
|
||||||
->setHeader('User-Agent', USER_AGENT);
|
$request->setHeader('User-Agent', USER_AGENT);
|
||||||
|
|
||||||
|
return $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -26,20 +26,20 @@ final class AnilistRequestBuilder extends APIRequestBuilder {
|
|||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
* @var string $base_url
|
* @var string $base_url
|
||||||
*/
|
*/
|
||||||
protected $baseUrl = 'https://graphql.anilist.co';
|
protected string $baseUrl = 'https://graphql.anilist.co';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Valid HTTP request methods
|
* Valid HTTP request methods
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $validMethods = ['POST'];
|
protected array $validMethods = ['POST'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP headers to send with every request
|
* HTTP headers to send with every request
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultHeaders = [
|
protected array $defaultHeaders = [
|
||||||
'User-Agent' => USER_AGENT,
|
'User-Agent' => USER_AGENT,
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
'Content-Type' => 'application/json',
|
'Content-Type' => 'application/json',
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,20 +38,20 @@ trait AnilistTrait {
|
|||||||
* The request builder for the Anilist API
|
* The request builder for the Anilist API
|
||||||
* @var AnilistRequestBuilder
|
* @var AnilistRequestBuilder
|
||||||
*/
|
*/
|
||||||
protected $requestBuilder;
|
protected AnilistRequestBuilder $requestBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
* @var string $base_url
|
* @var string $base_url
|
||||||
*/
|
*/
|
||||||
protected $baseUrl = Anilist::BASE_URL;
|
protected string $baseUrl = Anilist::BASE_URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP headers to send with every request
|
* HTTP headers to send with every request
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultHeaders = [
|
protected array $defaultHeaders = [
|
||||||
'Accept' => 'application/json',
|
'Accept' => 'application/json',
|
||||||
'Accept-Encoding' => 'gzip',
|
'Accept-Encoding' => 'gzip',
|
||||||
'Content-type' => 'application/json',
|
'Content-type' => 'application/json',
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ final class ListItem extends AbstractListItem {
|
|||||||
*/
|
*/
|
||||||
public function create(array $data): Request
|
public function create(array $data): Request
|
||||||
{
|
{
|
||||||
$checkedData = (new Types\MediaListEntry($data))->toArray();
|
$checkedData = Types\MediaListEntry::check($data);
|
||||||
return $this->mutateRequest('CreateMediaListEntry', $checkedData);
|
return $this->mutateRequest('CreateMediaListEntry', $checkedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ final class ListItem extends AbstractListItem {
|
|||||||
*/
|
*/
|
||||||
public function createFull(array $data): Request
|
public function createFull(array $data): Request
|
||||||
{
|
{
|
||||||
$checkedData = (new Types\MediaListEntry($data))->toArray();
|
$checkedData = Types\MediaListEntry::check($data);
|
||||||
return $this->mutateRequest('CreateFullMediaListEntry', $checkedData);
|
return $this->mutateRequest('CreateFullMediaListEntry', $checkedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,10 +85,10 @@ final class ListItem extends AbstractListItem {
|
|||||||
*/
|
*/
|
||||||
public function increment(string $id, FormItemData $data): Request
|
public function increment(string $id, FormItemData $data): Request
|
||||||
{
|
{
|
||||||
$checkedData = (new Types\MediaListEntry([
|
$checkedData = Types\MediaListEntry::check([
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'progress' => $data->progress,
|
'progress' => $data->progress,
|
||||||
]))->toArray();
|
]);
|
||||||
|
|
||||||
return $this->mutateRequest('IncrementMediaListEntry', $checkedData);
|
return $this->mutateRequest('IncrementMediaListEntry', $checkedData);
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ final class ListItem extends AbstractListItem {
|
|||||||
? AnilistStatus::REPEATING
|
? AnilistStatus::REPEATING
|
||||||
: AnimeWatchingStatus::KITSU_TO_ANILIST[$data->status];
|
: AnimeWatchingStatus::KITSU_TO_ANILIST[$data->status];
|
||||||
|
|
||||||
$updateData = (new Types\MediaListEntry([
|
$updateData = Types\MediaListEntry::check([
|
||||||
'id' => (int)$id,
|
'id' => (int)$id,
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'score' => $rating * 5,
|
'score' => $rating * 5,
|
||||||
@ -118,7 +118,7 @@ final class ListItem extends AbstractListItem {
|
|||||||
'repeat' => (int)$data['reconsumeCount'],
|
'repeat' => (int)$data['reconsumeCount'],
|
||||||
'private' => $private,
|
'private' => $private,
|
||||||
'notes' => $notes,
|
'notes' => $notes,
|
||||||
]))->toArray();
|
]);
|
||||||
|
|
||||||
return $this->mutateRequest('UpdateMediaListEntry', $updateData);
|
return $this->mutateRequest('UpdateMediaListEntry', $updateData);
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,18 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API\Anilist;
|
namespace Aviat\AnimeClient\API\Anilist;
|
||||||
|
|
||||||
class MissingIdException extends \InvalidArgumentException {}
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class MissingIdException extends InvalidArgumentException {}
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ final class Model
|
|||||||
/**
|
/**
|
||||||
* @var ListItem
|
* @var ListItem
|
||||||
*/
|
*/
|
||||||
private $listItem;
|
private ListItem $listItem;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class AnimeListTransformer extends AbstractTransformer {
|
|||||||
{
|
{
|
||||||
$reconsuming = $item['status'] === AnilistStatus::REPEATING;
|
$reconsuming = $item['status'] === AnilistStatus::REPEATING;
|
||||||
|
|
||||||
return new FormItem([
|
return FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $item['media']['idMal'],
|
'mal_id' => $item['media']['idMal'],
|
||||||
'data' => [
|
'data' => [
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
|
|
||||||
public function transform($item)
|
public function transform($item)
|
||||||
{
|
{
|
||||||
return new MangaListItem([]);
|
return MangaListItem::from([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,7 +40,7 @@ class MangaListTransformer extends AbstractTransformer {
|
|||||||
*/
|
*/
|
||||||
public function untransform(array $item): FormItem
|
public function untransform(array $item): FormItem
|
||||||
{
|
{
|
||||||
return new FormItem([
|
return FormItem::from([
|
||||||
'id' => $item['id'],
|
'id' => $item['id'],
|
||||||
'mal_id' => $item['media']['idMal'],
|
'mal_id' => $item['media']['idMal'],
|
||||||
'data' => [
|
'data' => [
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ trait CacheTrait {
|
|||||||
/**
|
/**
|
||||||
* @var Pool
|
* @var Pool
|
||||||
*/
|
*/
|
||||||
protected $cache;
|
protected Pool $cache;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject the cache object
|
* Inject the cache object
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,18 +4,20 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Aviat\AnimeClient\API;
|
namespace Aviat\AnimeClient\API;
|
||||||
|
|
||||||
|
use function in_array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class encapsulating Json API data structure for a request or response
|
* Class encapsulating Json API data structure for a request or response
|
||||||
*/
|
*/
|
||||||
@ -105,7 +107,7 @@ final class JsonAPI {
|
|||||||
$relationship =& $item['relationships'][$relType];
|
$relationship =& $item['relationships'][$relType];
|
||||||
unset($relationship['data']);
|
unset($relationship['data']);
|
||||||
|
|
||||||
if (\in_array($relType, $singular, TRUE))
|
if (in_array($relType, $singular, TRUE))
|
||||||
{
|
{
|
||||||
$relationship = $included[$dataType][$idKey];
|
$relationship = $included[$dataType][$idKey];
|
||||||
continue;
|
continue;
|
||||||
@ -202,11 +204,11 @@ final class JsonAPI {
|
|||||||
{
|
{
|
||||||
foreach($items as $id => $item)
|
foreach($items as $id => $item)
|
||||||
{
|
{
|
||||||
if (array_key_exists('relationships', $item) && \is_array($item['relationships']))
|
if (array_key_exists('relationships', $item) && is_array($item['relationships']))
|
||||||
{
|
{
|
||||||
foreach($item['relationships'] as $relType => $props)
|
foreach($item['relationships'] as $relType => $props)
|
||||||
{
|
{
|
||||||
if (array_key_exists('data', $props) && \is_array($props['data']) && array_key_exists('id', $props['data']))
|
if (array_key_exists('data', $props) && is_array($props['data']) && array_key_exists('id', $props['data']))
|
||||||
{
|
{
|
||||||
$idKey = $props['data']['id'];
|
$idKey = $props['data']['id'];
|
||||||
$dataType = $props['data']['type'];
|
$dataType = $props['data']['type'];
|
||||||
@ -340,7 +342,7 @@ final class JsonAPI {
|
|||||||
|
|
||||||
foreach ($data['data'] as $item)
|
foreach ($data['data'] as $item)
|
||||||
{
|
{
|
||||||
if (\is_array($item) && array_key_exists('id', $item))
|
if (is_array($item) && array_key_exists('id', $item))
|
||||||
{
|
{
|
||||||
$organized[$key][] = $item['id'];
|
$organized[$key][] = $item['id'];
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -164,9 +164,7 @@ final class Kitsu {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
usort($links, function ($a, $b) {
|
usort($links, fn ($a, $b) => $a['meta']['name'] <=> $b['meta']['name']);
|
||||||
return $a['meta']['name'] <=> $b['meta']['name'];
|
|
||||||
});
|
|
||||||
|
|
||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -42,14 +42,14 @@ final class Auth {
|
|||||||
*
|
*
|
||||||
* @var Model
|
* @var Model
|
||||||
*/
|
*/
|
||||||
private $model;
|
private Model $model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Session object
|
* Session object
|
||||||
*
|
*
|
||||||
* @var Segment
|
* @var Segment
|
||||||
*/
|
*/
|
||||||
private $segment;
|
private Segment $segment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -91,9 +91,9 @@ final class Auth {
|
|||||||
$cacheItem->save();
|
$cacheItem->save();
|
||||||
|
|
||||||
// Set the token expiration in the cache
|
// Set the token expiration in the cache
|
||||||
$expire_time = $auth['created_at'] + $auth['expires_in'];
|
$expireTime = $auth['created_at'] + $auth['expires_in'];
|
||||||
$cacheItem = $this->cache->getItem(K::AUTH_TOKEN_EXP_CACHE_KEY);
|
$cacheItem = $this->cache->getItem(K::AUTH_TOKEN_EXP_CACHE_KEY);
|
||||||
$cacheItem->set($expire_time);
|
$cacheItem->set($expireTime);
|
||||||
$cacheItem->save();
|
$cacheItem->save();
|
||||||
|
|
||||||
// Set the refresh token in the cache
|
// Set the refresh token in the cache
|
||||||
@ -103,7 +103,7 @@ final class Auth {
|
|||||||
|
|
||||||
// Set the session values
|
// Set the session values
|
||||||
$this->segment->set('auth_token', $auth['access_token']);
|
$this->segment->set('auth_token', $auth['access_token']);
|
||||||
$this->segment->set('auth_token_expires', $expire_time);
|
$this->segment->set('auth_token_expires', $expireTime);
|
||||||
$this->segment->set('refresh_token', $auth['refresh_token']);
|
$this->segment->set('refresh_token', $auth['refresh_token']);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -25,14 +25,14 @@ final class KitsuRequestBuilder extends APIRequestBuilder {
|
|||||||
* The base url for api requests
|
* The base url for api requests
|
||||||
* @var string $base_url
|
* @var string $base_url
|
||||||
*/
|
*/
|
||||||
protected $baseUrl = 'https://kitsu.io/api/edge/';
|
protected string $baseUrl = 'https://kitsu.io/api/edge/';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP headers to send with every request
|
* HTTP headers to send with every request
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $defaultHeaders = [
|
protected array $defaultHeaders = [
|
||||||
'User-Agent' => USER_AGENT,
|
'User-Agent' => USER_AGENT,
|
||||||
'Accept' => 'application/vnd.api+json',
|
'Accept' => 'application/vnd.api+json',
|
||||||
'Content-Type' => 'application/vnd.api+json',
|
'Content-Type' => 'application/vnd.api+json',
|
||||||
|
@ -4,13 +4,13 @@
|
|||||||
*
|
*
|
||||||
* An API client for Kitsu to manage anime and manga watch lists
|
* An API client for Kitsu to manage anime and manga watch lists
|
||||||
*
|
*
|
||||||
* PHP version 7.3
|
* PHP version 7.4
|
||||||
*
|
*
|
||||||
* @package HummingbirdAnimeClient
|
* @package HummingbirdAnimeClient
|
||||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||||
* @copyright 2015 - 2020 Timothy J. Warren
|
* @copyright 2015 - 2020 Timothy J. Warren
|
||||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||||
* @version 4.2
|
* @version 5
|
||||||
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
* @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ trait KitsuTrait {
|
|||||||
* The request builder for the Kitsu API
|
* The request builder for the Kitsu API
|
||||||
* @var KitsuRequestBuilder
|
* @var KitsuRequestBuilder
|
||||||
*/
|
*/
|
||||||
protected $requestBuilder;
|
protected KitsuRequestBuilder $requestBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request builder object
|
* Set the request builder object
|
||||||
@ -176,7 +176,7 @@ trait KitsuTrait {
|
|||||||
$logger->warning('Non 200 response for api call', (array)$response);
|
$logger->warning('Non 200 response for api call', (array)$response);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new FailedResponseException('Failed to get the proper response from the API');
|
// throw new FailedResponseException('Failed to get the proper response from the API');
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user