Add list views and additional configuration options
This commit is contained in:
parent
aedfc743c6
commit
9afe5379aa
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Base API Model
|
||||
*/
|
||||
|
||||
use \GuzzleHttp\Client;
|
||||
use \GuzzleHttp\Cookie\CookieJar;
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Base Controller
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base class for controllers, defines output methods
|
||||
@ -24,26 +27,30 @@ class BaseController {
|
||||
* Output a template to HTML, using the provided data
|
||||
*
|
||||
* @param string $template
|
||||
* @param array/object $data
|
||||
* @param array|object $data
|
||||
* @return void
|
||||
*/
|
||||
public function outputHTML($template, $data=[])
|
||||
{
|
||||
global $router;
|
||||
global $router, $defaultHandler;
|
||||
$route = $router->get_route();
|
||||
$data['route_path'] = ($route) ? $router->get_route()->path : "";
|
||||
|
||||
$path = _dir(APP_DIR, 'views', "{$template}.php");
|
||||
$defaultHandler->addDataTable('Template Data', $data);
|
||||
|
||||
if ( ! is_file($path))
|
||||
$template_path = _dir(APP_DIR, 'views', "{$template}.php");
|
||||
|
||||
if ( ! is_file($template_path))
|
||||
{
|
||||
throw new Exception("Invalid template : {$path}");
|
||||
die();
|
||||
}
|
||||
|
||||
ob_start();
|
||||
extract($data);
|
||||
include _dir(APP_DIR, 'views', 'header.php');
|
||||
include $path;
|
||||
include $template_path;
|
||||
include _dir(APP_DIR, 'views', 'footer.php');
|
||||
$buffer = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
@ -55,7 +62,7 @@ class BaseController {
|
||||
/**
|
||||
* Output json with the proper content type
|
||||
*
|
||||
* @param mixed data
|
||||
* @param mixed $data
|
||||
* @return void
|
||||
*/
|
||||
public function outputJSON($data)
|
||||
@ -68,5 +75,27 @@ class BaseController {
|
||||
header("Content-type: application/json");
|
||||
echo $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the selected page
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $code
|
||||
* @return void
|
||||
*/
|
||||
public function redirect($url, $code, $type="anime")
|
||||
{
|
||||
$url = full_url($url, $type);
|
||||
|
||||
$codes = [
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other'
|
||||
];
|
||||
|
||||
header("HTTP/1.1 {$code} {$codes[$code]}");
|
||||
header("Location: {$url}");
|
||||
die();
|
||||
}
|
||||
}
|
||||
// End of BaseController.php
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Base DB model
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base model for database interaction
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Base for base models
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common base for all Models
|
||||
@ -35,6 +38,12 @@ class BaseModel {
|
||||
$path = current($path_parts);
|
||||
$ext_parts = explode('.', $path);
|
||||
$ext = end($ext_parts);
|
||||
|
||||
// Workaround for some broken extensions
|
||||
if ($ext == "jjpg") $ext = "jpg";
|
||||
|
||||
// Failsafe for weird urls
|
||||
if (strlen($ext) > 3) return $api_path;
|
||||
|
||||
$cached_image = "{$series_slug}.{$ext}";
|
||||
$cached_path = "{$this->config->img_cache_path}/{$type}/{$cached_image}";
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Routing logic
|
||||
*/
|
||||
|
||||
use Aura\Router\RouterFactory;
|
||||
|
||||
@ -90,11 +93,23 @@ class Router {
|
||||
$controller_name = $route->params['controller'];
|
||||
$action_method = $route->params['action'];
|
||||
$params = (isset($route->params['params'])) ? $route->params['params'] : [];
|
||||
|
||||
if ( ! empty($route->tokens))
|
||||
{
|
||||
foreach($route->tokens as $key => $v)
|
||||
{
|
||||
if (array_key_exists($key, $route->params))
|
||||
{
|
||||
$params[$key] = $route->params[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$controller = new $controller_name();
|
||||
|
||||
// Run the appropriate controller method
|
||||
$defaultHandler->addDataTable('controller_args', $params);
|
||||
call_user_func_array([$controller, $action_method], $params);
|
||||
}
|
||||
|
||||
@ -123,7 +138,20 @@ class Router {
|
||||
{
|
||||
$path = $route['path'];
|
||||
unset($route['path']);
|
||||
$this->router->add($name, $path)->addValues($route);
|
||||
|
||||
if ( ! array_key_exists('tokens', $route))
|
||||
{
|
||||
$this->router->add($name, $path)->addValues($route);
|
||||
}
|
||||
else
|
||||
{
|
||||
$tokens = $route['tokens'];
|
||||
unset($route['tokens']);
|
||||
|
||||
$this->router->add($name, $path)
|
||||
->addValues($route)
|
||||
->addTokens($tokens);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,25 +17,50 @@ function is_selected($a, $b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate full url path from the route path based on config
|
||||
* Inverse of selected helper function
|
||||
*
|
||||
* @param string $path - The route path
|
||||
* @param [string] $host - The controller (anime or manga), defaults to anime
|
||||
* @param string $a - First item to compare
|
||||
* @param string $b - Second item to compare
|
||||
* @return string
|
||||
*/
|
||||
function full_url($path, $type="anime")
|
||||
function is_not_selected($a, $b)
|
||||
{
|
||||
return ($a !== $b) ? 'selected' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate full url path from the route path based on config
|
||||
*
|
||||
* @param string $path - (optional) The route path
|
||||
* @param string $type - (optional) The controller (anime or manga), defaults to anime
|
||||
* @return string
|
||||
*/
|
||||
function full_url($path="", $type="anime")
|
||||
{
|
||||
global $config;
|
||||
|
||||
$config_path = $config->{"{$type}_path"};
|
||||
$config_host = $config->{"{$type}_host"};
|
||||
$config_default_route = $config->{"default_{$type}_path"};
|
||||
|
||||
// Remove beginning/trailing slashes
|
||||
$config_path = trim($config_path, '/');
|
||||
$path = trim($path, '/');
|
||||
|
||||
// Remove any optional parameters from the route
|
||||
$path = preg_replace('`{/.*?}`i', '', $path);
|
||||
|
||||
// Set the default view
|
||||
if ($path === '')
|
||||
{
|
||||
$path .= trim($config_default_route, '/');
|
||||
if ($config->default_to_list_view) $path .= '/list';
|
||||
}
|
||||
|
||||
// Set the appropriate HTTP host
|
||||
$host = ($config_host !== '') ? $config_host : $_SERVER['HTTP_HOST'];
|
||||
|
||||
// Set an leading folder
|
||||
if ($config_path !== '')
|
||||
{
|
||||
$path = "{$config_path}/{$path}";
|
||||
@ -44,4 +69,16 @@ function full_url($path, $type="anime")
|
||||
return "//{$host}/{$path}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last segment of the current url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function last_segment()
|
||||
{
|
||||
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||
$segments = explode('/', $path);
|
||||
return end($segments);
|
||||
}
|
||||
|
||||
// End of functions.php
|
@ -3,6 +3,10 @@ return (object)[
|
||||
// Username for feeds
|
||||
'hummingbird_username' => 'timw4mail',
|
||||
|
||||
// Included config files
|
||||
'routes' => require _dir(CONF_DIR, 'routes.php'),
|
||||
'database' => require _dir(CONF_DIR, 'database.php'),
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Routing
|
||||
//
|
||||
@ -15,11 +19,14 @@ return (object)[
|
||||
'anime_path' => '',
|
||||
'manga_path' => '',
|
||||
|
||||
// Default pages for anime/manga
|
||||
'default_anime_path' => '/watching',
|
||||
'default_manga_path' => '/all',
|
||||
|
||||
// Default to list view?
|
||||
'default_to_list_view' => FALSE,
|
||||
|
||||
// Cache paths
|
||||
'data_cache_path' => _dir(APP_DIR, 'cache'),
|
||||
'img_cache_path' => _dir(ROOT_DIR, 'public/images'),
|
||||
|
||||
// Included config files
|
||||
'routes' => require _dir(CONF_DIR, 'routes.php'),
|
||||
'database' => require _dir(CONF_DIR, 'database.php'),
|
||||
];
|
@ -2,120 +2,178 @@
|
||||
|
||||
return [
|
||||
'anime' => [
|
||||
'index' => [
|
||||
'path' => '/',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'redirect',
|
||||
'params' => [
|
||||
'url' => '', // Determined by config
|
||||
'code' => '301'
|
||||
]
|
||||
],
|
||||
'all' => [
|
||||
'path' => '/all',
|
||||
'path' => '/all{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'all',
|
||||
'title' => WHOSE . " Anime List · All"
|
||||
'title' => WHOSE . " Anime List · All"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'index' => [
|
||||
'path' => '/',
|
||||
'watching' => [
|
||||
'path' => '/watching{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'currently-watching',
|
||||
'title' => WHOSE . " Anime List · Watching"
|
||||
'title' => WHOSE . " Anime List · Watching"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'plan_to_watch' => [
|
||||
'path' => '/plan_to_watch',
|
||||
'path' => '/plan_to_watch{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'plan-to-watch',
|
||||
'title' => WHOSE . " Anime List · Plan to Watch"
|
||||
'title' => WHOSE . " Anime List · Plan to Watch"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'on_hold' => [
|
||||
'path' => '/on_hold',
|
||||
'path' => '/on_hold{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'on-hold',
|
||||
'title' => WHOSE . " Anime List · On Hold"
|
||||
'title' => WHOSE . " Anime List · On Hold"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'dropped' => [
|
||||
'path' => '/dropped',
|
||||
'path' => '/dropped{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'dropped',
|
||||
'title' => WHOSE . " Anime List · Dropped"
|
||||
'title' => WHOSE . " Anime List · Dropped"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'completed' => [
|
||||
'path' => '/completed',
|
||||
'path' => '/completed{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'anime_list',
|
||||
'params' => [
|
||||
'type' => 'completed',
|
||||
'title' => WHOSE . " Anime List · Completed"
|
||||
'title' => WHOSE . " Anime List · Completed"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'collection' => [
|
||||
'path' => '/collection',
|
||||
'path' => '/collection{/view}',
|
||||
'controller' => 'AnimeController',
|
||||
'action' => 'collection',
|
||||
'params' => []
|
||||
'params' => [],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
]
|
||||
],
|
||||
'manga' => [
|
||||
'index' => [
|
||||
'path' => '/',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'redirect',
|
||||
'params' => [
|
||||
'url' => '', // Determined by config
|
||||
'code' => '301',
|
||||
'type' => 'manga'
|
||||
]
|
||||
],
|
||||
'all' => [
|
||||
'path' => '/all',
|
||||
'path' => '/all{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'all',
|
||||
'title' => WHOSE . " Manga List · All"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'index' => [
|
||||
'path' => '/',
|
||||
'reading' => [
|
||||
'path' => '/reading{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'Reading',
|
||||
'title' => WHOSE . " Manga List · Reading"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'plan_to_read' => [
|
||||
'path' => '/plan_to_read',
|
||||
'path' => '/plan_to_read{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'Plan to Read',
|
||||
'title' => WHOSE . " Manga List · Plan to Read"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'on_hold' => [
|
||||
'path' => '/on_hold',
|
||||
'path' => '/on_hold{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'On Hold',
|
||||
'title' => WHOSE . " Manga List · On Hold"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'dropped' => [
|
||||
'path' => '/dropped',
|
||||
'path' => '/dropped{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'Dropped',
|
||||
'title' => WHOSE . " Manga List · Dropped"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
'completed' => [
|
||||
'path' => '/completed',
|
||||
'path' => '/completed{/view}',
|
||||
'controller' => 'MangaController',
|
||||
'action' => 'manga_list',
|
||||
'params' => [
|
||||
'type' => 'Completed',
|
||||
'title' => WHOSE . " Manga List · Completed"
|
||||
],
|
||||
'tokens' => [
|
||||
'view' => '[a-z_]+'
|
||||
]
|
||||
],
|
||||
]
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Anime Controller
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controller for Anime-related pages
|
||||
@ -17,18 +20,24 @@ class AnimeController extends BaseController {
|
||||
*/
|
||||
private $collection_model;
|
||||
|
||||
/**
|
||||
* Data to ve sent to all routes in this controller
|
||||
* @var array $base_data
|
||||
*/
|
||||
private $base_data;
|
||||
|
||||
/**
|
||||
* Route mapping for main navigation
|
||||
* @var array $nav_routes
|
||||
*/
|
||||
private $nav_routes = [
|
||||
'Watching' => '/',
|
||||
'Plan to Watch' => '/plan_to_watch',
|
||||
'On Hold' => '/on_hold',
|
||||
'Dropped' => '/dropped',
|
||||
'Completed' => '/completed',
|
||||
'Collection' => '/collection',
|
||||
'All' => '/all'
|
||||
'Watching' => '/watching{/view}',
|
||||
'Plan to Watch' => '/plan_to_watch{/view}',
|
||||
'On Hold' => '/on_hold{/view}',
|
||||
'Dropped' => '/dropped{/view}',
|
||||
'Completed' => '/completed{/view}',
|
||||
'Collection' => '/collection{/view}',
|
||||
'All' => '/all{/view}'
|
||||
];
|
||||
|
||||
/**
|
||||
@ -39,6 +48,12 @@ class AnimeController extends BaseController {
|
||||
parent::__construct();
|
||||
$this->model = new AnimeModel();
|
||||
$this->collection_model = new AnimeCollectionModel();
|
||||
|
||||
$this->base_data = [
|
||||
'url_type' => 'anime',
|
||||
'other_type' => 'manga',
|
||||
'nav_routes' => $this->nav_routes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,17 +63,21 @@ class AnimeController extends BaseController {
|
||||
* @param string $title - The title of the page
|
||||
* @return void
|
||||
*/
|
||||
public function anime_list($type, $title)
|
||||
public function anime_list($type, $title, $view)
|
||||
{
|
||||
$view_map = [
|
||||
'' => 'cover',
|
||||
'list' => 'list'
|
||||
];
|
||||
|
||||
$data = ($type != 'all')
|
||||
? $this->model->get_list($type)
|
||||
: $this->model->get_all_lists();
|
||||
|
||||
$this->outputHTML('anime/list', [
|
||||
$this->outputHTML('anime/' . $view_map[$view], array_merge($this->base_data, [
|
||||
'title' => $title,
|
||||
'nav_routes' => $this->nav_routes,
|
||||
'sections' => $data
|
||||
]);
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,15 +85,19 @@ class AnimeController extends BaseController {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function collection()
|
||||
public function collection($view)
|
||||
{
|
||||
$view_map = [
|
||||
'' => 'collection',
|
||||
'list' => 'collection_list'
|
||||
];
|
||||
|
||||
$data = $this->collection_model->get_collection();
|
||||
|
||||
$this->outputHTML('anime/collection', [
|
||||
$this->outputHTML('anime/' . $view_map[$view], array_merge($this->base_data, [
|
||||
'title' => WHOSE . " Anime Collection",
|
||||
'nav_routes' => $this->nav_routes,
|
||||
'sections' => $data
|
||||
]);
|
||||
]));
|
||||
}
|
||||
}
|
||||
// End of AnimeController.php
|
@ -1,56 +1,67 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Controller for manga list
|
||||
*/
|
||||
class MangaController extends BaseController {
|
||||
|
||||
/**
|
||||
* The manga model
|
||||
* @var object $model
|
||||
*/
|
||||
private $model;
|
||||
|
||||
/**
|
||||
* Route mapping for main navigation
|
||||
* @var array $nav_routes
|
||||
*/
|
||||
private $nav_routes = [
|
||||
'Reading' => '/',
|
||||
'Plan to Read' => '/plan_to_read',
|
||||
'On Hold' => '/on_hold',
|
||||
'Dropped' => '/dropped',
|
||||
'Completed' => '/completed',
|
||||
'All' => '/all'
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new MangaModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a section of the manga list
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $title
|
||||
* @return void
|
||||
*/
|
||||
public function manga_list($status, $title)
|
||||
{
|
||||
$data = ($status !== 'all')
|
||||
? [$status => $this->model->get_list($status)]
|
||||
: $this->model->get_all_lists();
|
||||
|
||||
$this->outputHTML('manga/list', [
|
||||
'title' => $title,
|
||||
'nav_routes' => $this->nav_routes,
|
||||
'sections' => $data
|
||||
]);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* Manga Controller
|
||||
*/
|
||||
|
||||
/**
|
||||
* Controller for manga list
|
||||
*/
|
||||
class MangaController extends BaseController {
|
||||
|
||||
/**
|
||||
* The manga model
|
||||
* @var object $model
|
||||
*/
|
||||
private $model;
|
||||
|
||||
/**
|
||||
* Route mapping for main navigation
|
||||
* @var array $nav_routes
|
||||
*/
|
||||
private $nav_routes = [
|
||||
'Reading' => '/reading{/view}',
|
||||
'Plan to Read' => '/plan_to_read{/view}',
|
||||
'On Hold' => '/on_hold{/view}',
|
||||
'Dropped' => '/dropped{/view}',
|
||||
'Completed' => '/completed{/view}',
|
||||
'All' => '/all{/view}'
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = new MangaModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a section of the manga list
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $title
|
||||
* @param string $view
|
||||
* @return void
|
||||
*/
|
||||
public function manga_list($status, $title, $view)
|
||||
{
|
||||
$view_map = [
|
||||
'' => 'cover',
|
||||
'list' => 'list'
|
||||
];
|
||||
|
||||
$data = ($status !== 'all')
|
||||
? [$status => $this->model->get_list($status)]
|
||||
: $this->model->get_all_lists();
|
||||
|
||||
$this->outputHTML('manga/' . $view_map[$view], [
|
||||
'url_type' => 'manga',
|
||||
'other_type' => 'anime',
|
||||
'title' => $title,
|
||||
'nav_routes' => $this->nav_routes,
|
||||
'sections' => $data
|
||||
]);
|
||||
}
|
||||
}
|
||||
// End of MangaController.php
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Anime Collection DB Model
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model for getting anime collection data
|
||||
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Anime API Model
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model for handling requests dealing with the anime list
|
||||
@ -203,7 +206,7 @@ class AnimeModel extends BaseApiModel {
|
||||
/**
|
||||
* Sort the list by title
|
||||
*
|
||||
* @param array &$array
|
||||
* @param array $array
|
||||
* @return void
|
||||
*/
|
||||
private function sort_by_name(&$array)
|
||||
|
@ -1,164 +1,168 @@
|
||||
<?php
|
||||
/**
|
||||
* Model for handling requests dealing with the manga list
|
||||
*/
|
||||
class MangaModel extends BaseApiModel {
|
||||
|
||||
/**
|
||||
* @var string $base_url - The base url for api requests
|
||||
*/
|
||||
protected $base_url = "https://hummingbird.me";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full set of anime lists
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_lists()
|
||||
{
|
||||
$data = $this->_get_list();
|
||||
|
||||
foreach ($data as $key => &$val)
|
||||
{
|
||||
$this->sort_by_name($val);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a category out of the full list
|
||||
*
|
||||
* @param string $status
|
||||
* @return array
|
||||
*/
|
||||
public function get_list($status)
|
||||
{
|
||||
$data = $this->_get_list($status);
|
||||
|
||||
$this->sort_by_name($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Massage the list of manga entries into something more usable
|
||||
*
|
||||
* @param string $status
|
||||
* @return array
|
||||
*/
|
||||
private function _get_list($status="all")
|
||||
{
|
||||
global $defaultHandler;
|
||||
|
||||
$cache_file = _dir($this->config->data_cache_path, 'manga.json');
|
||||
|
||||
$config = [
|
||||
'query' => [
|
||||
'user_id' => $this->config->hummingbird_username
|
||||
],
|
||||
'allow_redirects' => false
|
||||
];
|
||||
|
||||
$response = $this->client->get($this->_url('/manga_library_entries'), $config);
|
||||
|
||||
$defaultHandler->addDataTable('response', (array)$response);
|
||||
|
||||
if ($response->getStatusCode() != 200)
|
||||
{
|
||||
if ( ! file_exists($cache_file))
|
||||
{
|
||||
throw new Exception($response->getEffectiveUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
$raw_data = json_decode(file_get_contents($cache_file), TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reorganize data to be more usable
|
||||
$raw_data = $response->json();
|
||||
|
||||
// Cache data in case of downtime
|
||||
file_put_contents($cache_file, json_encode($raw_data));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'Reading' => [],
|
||||
'Plan to Read' => [],
|
||||
'On Hold' => [],
|
||||
'Dropped' => [],
|
||||
'Completed' => [],
|
||||
];
|
||||
$manga_data = [];
|
||||
|
||||
// Massage the two lists into one
|
||||
foreach($raw_data['manga'] as $manga)
|
||||
{
|
||||
$manga_data[$manga['id']] = $manga;
|
||||
}
|
||||
|
||||
// Filter data by status
|
||||
foreach($raw_data['manga_library_entries'] as &$entry)
|
||||
{
|
||||
$entry['manga'] = $manga_data[$entry['manga_id']];
|
||||
|
||||
// Cache poster images
|
||||
$entry['manga']['poster_image'] = $this->get_cached_image($entry['manga']['poster_image'], $entry['manga_id'], 'manga');
|
||||
|
||||
switch($entry['status'])
|
||||
{
|
||||
case "Plan to Read":
|
||||
$data['Plan to Read'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Dropped":
|
||||
$data['Dropped'][] = $entry;
|
||||
break;
|
||||
|
||||
case "On Hold":
|
||||
$data['On Hold'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Currently Reading":
|
||||
$data['Reading'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Completed":
|
||||
default:
|
||||
$data['Completed'][] = $entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (array_key_exists($status, $data)) ? $data[$status] : $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the manga entries by their title
|
||||
*
|
||||
* @param array $array
|
||||
* @return void
|
||||
*/
|
||||
private function sort_by_name(&$array)
|
||||
{
|
||||
$sort = array();
|
||||
|
||||
foreach($array as $key => $item)
|
||||
{
|
||||
$sort[$key] = $item['manga']['romaji_title'];
|
||||
}
|
||||
|
||||
array_multisort($sort, SORT_ASC, $array);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
/**
|
||||
* Manga API Model
|
||||
*/
|
||||
|
||||
/**
|
||||
* Model for handling requests dealing with the manga list
|
||||
*/
|
||||
class MangaModel extends BaseApiModel {
|
||||
|
||||
/**
|
||||
* @var string $base_url - The base url for api requests
|
||||
*/
|
||||
protected $base_url = "https://hummingbird.me";
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full set of anime lists
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_all_lists()
|
||||
{
|
||||
$data = $this->_get_list();
|
||||
|
||||
foreach ($data as $key => &$val)
|
||||
{
|
||||
$this->sort_by_name($val);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a category out of the full list
|
||||
*
|
||||
* @param string $status
|
||||
* @return array
|
||||
*/
|
||||
public function get_list($status)
|
||||
{
|
||||
$data = $this->_get_list($status);
|
||||
|
||||
$this->sort_by_name($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Massage the list of manga entries into something more usable
|
||||
*
|
||||
* @param string $status
|
||||
* @return array
|
||||
*/
|
||||
private function _get_list($status="all")
|
||||
{
|
||||
global $defaultHandler;
|
||||
|
||||
$cache_file = _dir($this->config->data_cache_path, 'manga.json');
|
||||
|
||||
$config = [
|
||||
'query' => [
|
||||
'user_id' => $this->config->hummingbird_username
|
||||
],
|
||||
'allow_redirects' => false
|
||||
];
|
||||
|
||||
$response = $this->client->get($this->_url('/manga_library_entries'), $config);
|
||||
|
||||
$defaultHandler->addDataTable('response', (array)$response);
|
||||
|
||||
if ($response->getStatusCode() != 200)
|
||||
{
|
||||
if ( ! file_exists($cache_file))
|
||||
{
|
||||
throw new Exception($response->getEffectiveUrl());
|
||||
}
|
||||
else
|
||||
{
|
||||
$raw_data = json_decode(file_get_contents($cache_file), TRUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reorganize data to be more usable
|
||||
$raw_data = $response->json();
|
||||
|
||||
// Cache data in case of downtime
|
||||
file_put_contents($cache_file, json_encode($raw_data));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'Reading' => [],
|
||||
'Plan to Read' => [],
|
||||
'On Hold' => [],
|
||||
'Dropped' => [],
|
||||
'Completed' => [],
|
||||
];
|
||||
$manga_data = [];
|
||||
|
||||
// Massage the two lists into one
|
||||
foreach($raw_data['manga'] as $manga)
|
||||
{
|
||||
$manga_data[$manga['id']] = $manga;
|
||||
}
|
||||
|
||||
// Filter data by status
|
||||
foreach($raw_data['manga_library_entries'] as &$entry)
|
||||
{
|
||||
$entry['manga'] = $manga_data[$entry['manga_id']];
|
||||
|
||||
// Cache poster images
|
||||
$entry['manga']['poster_image'] = $this->get_cached_image($entry['manga']['poster_image'], $entry['manga_id'], 'manga');
|
||||
|
||||
switch($entry['status'])
|
||||
{
|
||||
case "Plan to Read":
|
||||
$data['Plan to Read'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Dropped":
|
||||
$data['Dropped'][] = $entry;
|
||||
break;
|
||||
|
||||
case "On Hold":
|
||||
$data['On Hold'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Currently Reading":
|
||||
$data['Reading'][] = $entry;
|
||||
break;
|
||||
|
||||
case "Completed":
|
||||
default:
|
||||
$data['Completed'][] = $entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (array_key_exists($status, $data)) ? $data[$status] : $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the manga entries by their title
|
||||
*
|
||||
* @param array $array
|
||||
* @return void
|
||||
*/
|
||||
private function sort_by_name(&$array)
|
||||
{
|
||||
$sort = array();
|
||||
|
||||
foreach($array as $key => $item)
|
||||
{
|
||||
$sort[$key] = $item['manga']['romaji_title'];
|
||||
}
|
||||
|
||||
array_multisort($sort, SORT_ASC, $array);
|
||||
}
|
||||
}
|
||||
// End of MangaModel.php
|
@ -1,32 +1,27 @@
|
||||
<body class="anime collection">
|
||||
<h1><?= WHOSE ?> Anime Collection [<a href="<?= full_url('', 'manga') ?>">Manga List</a>]</h1>
|
||||
<?php include 'nav.php' ?>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<a href="https://hummingbird.me/anime/<?= $item['slug'] ?>">
|
||||
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
||||
<img src="<?= $item['cover_image'] ?>" />
|
||||
<div class="name">
|
||||
<?= $item['title'] ?>
|
||||
<?= ($item['alternate_title'] != "") ? "<br />({$item['alternate_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="completion">Episodes: <?= $item['episode_count'] ?></div>
|
||||
</div>
|
||||
<div class="medium_metadata">
|
||||
<div class="media_type"><?= $item['show_type'] ?></div>
|
||||
<div class="age_rating"><?= $item['age_rating'] ?></div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<a href="https://hummingbird.me/anime/<?= $item['slug'] ?>">
|
||||
<article class="media" id="a-<?= $item['hummingbird_id'] ?>">
|
||||
<img src="<?= $item['cover_image'] ?>" />
|
||||
<div class="name">
|
||||
<?= $item['title'] ?>
|
||||
<?= ($item['alternate_title'] != "") ? "<br />({$item['alternate_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="completion">Episodes: <?= $item['episode_count'] ?></div>
|
||||
</div>
|
||||
<div class="medium_metadata">
|
||||
<div class="media_type"><?= $item['show_type'] ?></div>
|
||||
<div class="age_rating"><?= $item['age_rating'] ?></div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
43
app/views/anime/collection_list.php
Normal file
43
app/views/anime/collection_list.php
Normal file
@ -0,0 +1,43 @@
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<h2><?= $name ?></h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Alternate Title</th>
|
||||
<th>Episode Count</th>
|
||||
<th>Episode Length</th>
|
||||
<th>Show Type</th>
|
||||
<th>Age Rating</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($items as $item): ?>
|
||||
<tr>
|
||||
<td class="align_left">
|
||||
<a href="https://hummingbird.me/anime/<?= $item['slug'] ?>">
|
||||
<?= $item['title'] ?>
|
||||
</a>
|
||||
</td>
|
||||
<td class="align_left"><?= $item['alternate_title'] ?></td>
|
||||
<td><?= $item['episode_count'] ?></td>
|
||||
<td><?= $item['episode_length'] ?></td>
|
||||
<td><?= $item['show_type'] ?></td>
|
||||
<td><?= $item['age_rating'] ?></td>
|
||||
<td class="align_left"><?= $item['notes'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script src="/public/js/table_sorter/jquery.tablesorter.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('table').tablesorter();
|
||||
});
|
||||
</script>
|
29
app/views/anime/cover.php
Normal file
29
app/views/anime/cover.php
Normal file
@ -0,0 +1,29 @@
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<a href="<?= $item['anime']['url'] ?>">
|
||||
<article class="media" id="a-<?= $item['anime']['id'] ?>">
|
||||
<img class="round_all" src="<?= $item['anime']['cover_image'] ?>" />
|
||||
<div class="round_all name">
|
||||
<?= $item['anime']['title'] ?>
|
||||
<?= ($item['anime']['alternate_title'] != "") ? "<br />({$item['anime']['alternate_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="round_top airing_status"><?= $item['anime']['status'] ?></div>
|
||||
<div class="user_rating"><?= (int)($item['rating']['value'] * 2) ?> / 10</div>
|
||||
<div class="round_bottom completion">Episodes: <?= $item['episodes_watched'] ?> / <?= $item['anime']['episode_count'] ?></div>
|
||||
</div>
|
||||
<div class="medium_metadata">
|
||||
<div class="round_top media_type"><?= $item['anime']['show_type'] ?></div>
|
||||
<div class="round_bottom age_rating"><?= $item['anime']['age_rating'] ?></div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
@ -1,34 +1,42 @@
|
||||
<body class="anime list">
|
||||
<h1><?= WHOSE ?> Anime List [<a href="<?= full_url('', 'manga') ?>">Manga List</a>]</h1>
|
||||
<?php include 'nav.php' ?>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<h2><?= $name ?></h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Alternate Title</th>
|
||||
<th>Airing Status</th>
|
||||
<th>Score</th>
|
||||
<th>Type</th>
|
||||
<th>Progress</th>
|
||||
<th>Rated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($items as $item): ?>
|
||||
<tr id="a-<?= $item['anime']['id'] ?>">
|
||||
<td class="align_left">
|
||||
<a href="<?= $item['anime']['url'] ?>">
|
||||
<article class="media" id="a-<?= $item['anime']['id'] ?>">
|
||||
<img class="round_all" src="<?= $item['anime']['cover_image'] ?>" />
|
||||
<div class="round_all name">
|
||||
<?= $item['anime']['title'] ?>
|
||||
<?= ($item['anime']['alternate_title'] != "") ? "<br />({$item['anime']['alternate_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="round_top airing_status"><?= $item['anime']['status'] ?></div>
|
||||
<div class="user_rating"><?= (int)($item['rating']['value'] * 2) ?> / 10</div>
|
||||
<div class="round_bottom completion">Episodes: <?= $item['episodes_watched'] ?> / <?= $item['anime']['episode_count'] ?></div>
|
||||
</div>
|
||||
<div class="medium_metadata">
|
||||
<div class="round_top media_type"><?= $item['anime']['show_type'] ?></div>
|
||||
<div class="round_bottom age_rating"><?= $item['anime']['age_rating'] ?></div>
|
||||
</div>
|
||||
</article>
|
||||
<?= $item['anime']['title'] ?>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</td>
|
||||
<td class="align_left"><?= $item['anime']['alternate_title'] ?></td>
|
||||
<td class="align_left"><?= $item['anime']['status'] ?></td>
|
||||
<td><?= (int)($item['rating']['value'] * 2) ?> / 10 </td>
|
||||
<td><?= $item['anime']['show_type'] ?></td>
|
||||
<td>Episodes: <?= $item['episodes_watched'] ?> / <?= $item['anime']['episode_count'] ?></td>
|
||||
<td><?= $item['anime']['age_rating'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script src="/public/js/table_sorter/jquery.tablesorter.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('table').tablesorter();
|
||||
});
|
||||
</script>
|
@ -1,7 +0,0 @@
|
||||
<nav>
|
||||
<ul>
|
||||
<?php foreach($nav_routes as $title => $path): ?>
|
||||
<li class="<?= is_selected($path, $route_path) ?>"><a href="<?= full_url($path) ?>"><?= $title ?></a></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</nav>
|
2
app/views/footer.php
Normal file
2
app/views/footer.php
Normal file
@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
@ -1,7 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><?= $title ?></title>
|
||||
<link rel="stylesheet" href="/public/css/marx.css" />
|
||||
<link rel="stylesheet" href="/public/css/base.css" />
|
||||
</head>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title><?= $title ?></title>
|
||||
<link rel="stylesheet" href="/public/css/marx.css" />
|
||||
<link rel="stylesheet" href="/public/css/base.css" />
|
||||
</head>
|
||||
<body class="<?= $url_type ?> list">
|
||||
<h1><?= WHOSE ?> <?= ucfirst($url_type) ?> <?= (strpos($route_path, 'collection') !== FALSE) ? 'Collection' : 'List' ?> [<a href="<?= full_url("", $other_type) ?>"><?= ucfirst($other_type) ?> List</a>]</h1>
|
||||
<nav>
|
||||
<ul>
|
||||
<?php foreach($nav_routes as $title => $nav_path): ?>
|
||||
<li class="<?= is_selected($nav_path, $route_path) ?>"><a href="<?= full_url($nav_path, $url_type) ?>"><?= $title ?></a></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<br />
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="<?= is_not_selected('list', last_segment()) ?>"><a href="<?= full_url($route_path, $url_type) ?>">Cover View</a></li>
|
||||
<li class="<?= is_selected('list', last_segment()) ?>"><a href="<?= full_url("{$route_path}/list", $url_type) ?>">List View</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<br />
|
30
app/views/manga/cover.php
Normal file
30
app/views/manga/cover.php
Normal file
@ -0,0 +1,30 @@
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<a href="https://hummingbird.me/manga/<?= $item['manga']['id'] ?>">
|
||||
<article class="media" id="manga-<?= $item['manga']['id'] ?>">
|
||||
<img src="<?= $item['manga']['poster_image'] ?>" />
|
||||
<div class="name">
|
||||
<?= $item['manga']['romaji_title'] ?>
|
||||
<?= (isset($item['manga']['english_title'])) ? "<br />({$item['manga']['english_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="user_rating"><?= ($item['rating'] > 0) ? (int)($item['rating'] * 2) : '-' ?> / 10</div>
|
||||
<div class="completion">
|
||||
Chapters: <?= $item['chapters_read'] ?> / <?= ($item['manga']['chapter_count'] > 0) ? $item['manga']['chapter_count'] : "-" ?><?php /*<br />
|
||||
Volumes: <?= $item['volumes_read'] ?> / <?= ($item['manga']['volume_count'] > 0) ? $item['manga']['volume_count'] : "-" ?>*/ ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php /*<div class="medium_metadata">
|
||||
<div class="media_type"><?= $item['manga']['manga_type'] ?></div>
|
||||
</div> */ ?>
|
||||
</article>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
@ -1,35 +1,40 @@
|
||||
<body class="manga list">
|
||||
<h1><?= WHOSE ?> Manga List [<a href="<?= full_url("", "anime") ?>">Anime List</a>]</h1>
|
||||
<?php include 'nav.php' ?>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<section class="status">
|
||||
<h2><?= $name ?></h2>
|
||||
<section class="media-wrap">
|
||||
<?php foreach($items as $item): ?>
|
||||
<a href="https://hummingbird.me/manga/<?= $item['manga']['id'] ?>">
|
||||
<article class="media" id="manga-<?= $item['manga']['id'] ?>">
|
||||
<img src="<?= $item['manga']['poster_image'] ?>" />
|
||||
<div class="name">
|
||||
<?= $item['manga']['romaji_title'] ?>
|
||||
<?= (isset($item['manga']['english_title'])) ? "<br />({$item['manga']['english_title']})" : ""; ?>
|
||||
</div>
|
||||
<div class="media_metadata">
|
||||
<div class="user_rating"><?= ($item['rating'] > 0) ? (int)($item['rating'] * 2) : '-' ?> / 10</div>
|
||||
<div class="completion">
|
||||
Chapters: <?= $item['chapters_read'] ?> / <?= ($item['manga']['chapter_count'] > 0) ? $item['manga']['chapter_count'] : "-" ?><?php /*<br />
|
||||
Volumes: <?= $item['volumes_read'] ?> / <?= ($item['manga']['volume_count'] > 0) ? $item['manga']['volume_count'] : "-" ?>*/ ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php /*<div class="medium_metadata">
|
||||
<div class="media_type"><?= $item['manga']['manga_type'] ?></div>
|
||||
</div> */ ?>
|
||||
</article>
|
||||
</a>
|
||||
<?php endforeach ?>
|
||||
</section>
|
||||
</section>
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
<main>
|
||||
<?php foreach ($sections as $name => $items): ?>
|
||||
<h2><?= $name ?></h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Alternate Title</th>
|
||||
<th>Rating</th>
|
||||
<th>Chapters</th>
|
||||
<!-- <th>Volumes</th> -->
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($items as $item): ?>
|
||||
<tr id="manga-<?= $item['manga']['id'] ?>">
|
||||
<td class="align_left">
|
||||
<a href="https://hummingbird.me/manga/<?= $item['manga']['id'] ?>">
|
||||
<?= $item['manga']['romaji_title'] ?>
|
||||
</a>
|
||||
</td>
|
||||
<td class="align_left"><?= (array_key_exists('english_title', $item['manga'])) ? $item['manga']['english_title'] : "" ?></td>
|
||||
<td><?= ($item['rating'] > 0) ? (int)($item['rating'] * 2) : '-' ?> / 10</td>
|
||||
<td><?= $item['chapters_read'] ?> / <?= ($item['manga']['chapter_count'] > 0) ? $item['manga']['chapter_count'] : "-" ?></td>
|
||||
<!-- <td><?= $item['volumes_read'] ?> / <?= ($item['manga']['volume_count'] > 0) ? $item['manga']['volume_count'] : "-" ?></td> -->
|
||||
<td><?= $item['manga']['manga_type'] ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endforeach ?>
|
||||
</main>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script src="/public/js/table_sorter/jquery.tablesorter.min.js"></script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('table').tablesorter();
|
||||
});
|
||||
</script>
|
@ -1,7 +0,0 @@
|
||||
<nav>
|
||||
<ul>
|
||||
<?php foreach($nav_routes as $title => $path): ?>
|
||||
<li class="<?= is_selected($path, $route_path) ?>"><a href="<?= full_url($path, 'manga') ?>"><?= $title ?></a></li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</nav>
|
@ -1,4 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* Here begins everything!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Joins paths together. Variadic to take an
|
||||
@ -8,13 +11,15 @@
|
||||
*/
|
||||
function _dir() { return implode(DIRECTORY_SEPARATOR, func_get_args()); }
|
||||
|
||||
// Base paths
|
||||
|
||||
define('ROOT_DIR', __DIR__);
|
||||
define('APP_DIR', _dir(ROOT_DIR, 'app'));
|
||||
define('CONF_DIR', _dir(APP_DIR, 'config'));
|
||||
define('BASE_DIR', _dir(APP_DIR, 'base'));
|
||||
|
||||
// Who's list is it?
|
||||
/**
|
||||
* Well, whose list is it?
|
||||
*/
|
||||
define('WHOSE', "Tim's");
|
||||
|
||||
// Load config and global functions
|
||||
|
@ -2,6 +2,23 @@ body {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
table {
|
||||
width:85%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
tbody > tr:nth-child(odd) {
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.align_left {
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.align_right {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
.round_all {
|
||||
border-radius:0.5em;
|
||||
}
|
||||
|
122
public/js/table_sorter/jquery.metadata.js
Normal file
122
public/js/table_sorter/jquery.metadata.js
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Metadata - jQuery plugin for parsing metadata from elements
|
||||
*
|
||||
* Copyright (c) 2006 John Resig, Yehuda Katz, J<EFBFBD>örn Zaefferer, Paul McLanahan
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Revision: $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
|
||||
* in the JSON will become a property of the element itself.
|
||||
*
|
||||
* There are three supported types of metadata storage:
|
||||
*
|
||||
* attr: Inside an attribute. The name parameter indicates *which* attribute.
|
||||
*
|
||||
* class: Inside the class attribute, wrapped in curly braces: { }
|
||||
*
|
||||
* elem: Inside a child element (e.g. a script tag). The
|
||||
* name parameter indicates *which* element.
|
||||
*
|
||||
* The metadata for an element is loaded the first time the element is accessed via jQuery.
|
||||
*
|
||||
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
|
||||
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
|
||||
*
|
||||
* @name $.metadata.setType
|
||||
*
|
||||
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("class")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from the class attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("attr", "data")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a "data" attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
|
||||
* @before $.metadata.setType("elem", "script")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a nested script element
|
||||
*
|
||||
* @param String type The encoding type
|
||||
* @param String name The name of the attribute to be used to get metadata (optional)
|
||||
* @cat Plugins/Metadata
|
||||
* @descr Sets the type of encoding to be used when loading metadata for the first time
|
||||
* @type undefined
|
||||
* @see metadata()
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.extend({
|
||||
metadata : {
|
||||
defaults : {
|
||||
type: 'class',
|
||||
name: 'metadata',
|
||||
cre: /({.*})/,
|
||||
single: 'metadata'
|
||||
},
|
||||
setType: function( type, name ){
|
||||
this.defaults.type = type;
|
||||
this.defaults.name = name;
|
||||
},
|
||||
get: function( elem, opts ){
|
||||
var settings = $.extend({},this.defaults,opts);
|
||||
// check for empty string in single property
|
||||
if ( !settings.single.length ) settings.single = 'metadata';
|
||||
|
||||
var data = $.data(elem, settings.single);
|
||||
// returned cached data if it already exists
|
||||
if ( data ) return data;
|
||||
|
||||
data = "{}";
|
||||
|
||||
if ( settings.type == "class" ) {
|
||||
var m = settings.cre.exec( elem.className );
|
||||
if ( m )
|
||||
data = m[1];
|
||||
} else if ( settings.type == "elem" ) {
|
||||
if( !elem.getElementsByTagName )
|
||||
return undefined;
|
||||
var e = elem.getElementsByTagName(settings.name);
|
||||
if ( e.length )
|
||||
data = $.trim(e[0].innerHTML);
|
||||
} else if ( elem.getAttribute != undefined ) {
|
||||
var attr = elem.getAttribute( settings.name );
|
||||
if ( attr )
|
||||
data = attr;
|
||||
}
|
||||
|
||||
if ( data.indexOf( '{' ) <0 )
|
||||
data = "{" + data + "}";
|
||||
|
||||
data = eval("(" + data + ")");
|
||||
|
||||
$.data( elem, settings.single, data );
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the metadata object for the first member of the jQuery object.
|
||||
*
|
||||
* @name metadata
|
||||
* @descr Returns element's metadata object
|
||||
* @param Object opts An object contianing settings to override the defaults
|
||||
* @type jQuery
|
||||
* @cat Plugins/Metadata
|
||||
*/
|
||||
$.fn.metadata = function( opts ){
|
||||
return $.metadata.get( this[0], opts );
|
||||
};
|
||||
|
||||
})(jQuery);
|
1031
public/js/table_sorter/jquery.tablesorter.js
Normal file
1031
public/js/table_sorter/jquery.tablesorter.js
Normal file
File diff suppressed because it is too large
Load Diff
4
public/js/table_sorter/jquery.tablesorter.min.js
vendored
Normal file
4
public/js/table_sorter/jquery.tablesorter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user