Simplify routing

This commit is contained in:
Timothy Warren 2016-01-06 11:08:56 -05:00
parent e3af767246
commit ba94f439bb
22 changed files with 1032 additions and 400 deletions

View File

@ -34,11 +34,4 @@ $config = [
// path to public directory on the server
'asset_dir' => realpath(__DIR__ . '/../../public'),
// ----------------------------------------------------------------------------
// Included config files
// ----------------------------------------------------------------------------
// Routing paths and options
'routing' => require __DIR__ . '/routing.php',
];

View File

@ -11,15 +11,41 @@
* @license MIT
*/
use Aviat\AnimeClient\AnimeClient;
return [
'convention' => [
'default_namespace' => '\\Aviat\\AnimeClient\\Controller',
'default_controller' => '\\Aviat\\AnimeClient\\Controller\\Anime',
'default_method' => 'index',
'404_method' => 'not_found'
// -------------------------------------------------------------------------
// Routing options
//
// Specify default paths and views
// -------------------------------------------------------------------------
'route_config' => [
// Subfolder prefix for url, if in a subdirectory of the web root
'subfolder_prefix' => '',
// Path to public directory, where images/css/javascript are located,
// appended to the url
'asset_path' => '/public',
// Which list should be the default?
'default_list' => 'anime', // anime or manga
// Default pages for anime/manga
'default_anime_list_path' => "watching", // watching|plan_to_watch|on_hold|dropped|completed|all
'default_manga_list_path' => "reading", // reading|plan_to_read|on_hold|dropped|completed|all
// Default view type (cover_view/list_view)
'default_view_type' => 'cover_view',
],
// Routes on anime collection controller
'anime' => [
// -------------------------------------------------------------------------
// Routing Config
//
// Maps paths to controlers and methods
// -------------------------------------------------------------------------
'routes' => [
// ---------------------------------------------------------------------
// Anime List Routes
// ---------------------------------------------------------------------
'anime_add_form' => [
'path' => '/anime/add',
'action' => 'add_form',
@ -29,12 +55,10 @@ return [
'path' => '/anime/add',
'action' => 'add',
'verb' => 'post'
]
],
'manga' => [
],
'collection' => [
// ---------------------------------------------------------------------
// Anime Collection Routes
// ---------------------------------------------------------------------
'collection_search' => [
'path' => '/collection/search',
'action' => 'search'
@ -69,5 +93,58 @@ return [
'view' => '[a-z_]+'
]
],
// ---------------------------------------------------------------------
// Default / Shared routes
// ---------------------------------------------------------------------
'login' => [
'path' => '/{controller}/login',
'action' => 'login',
'verb' => 'get'
],
'login_post' => [
'path' => '/{controller}/login',
'action' => 'login_action',
'verb' => 'post'
],
'logout' => [
'path' => '/{controller}/logout',
'action' => 'logout'
],
'update' => [
'path' => '/{controller}/update',
'action' => 'update',
'tokens' => [
'controller' => '[a-z_]+'
]
],
'update_form' => [
'path' => '/{controller}/update_form',
'action' => 'form_update',
'verb' => 'post',
'tokens' => [
'controller' => '[a-z_]+'
]
],
'edit' => [
'path' => '/{controller}/edit/{id}/{status}',
'action' => 'edit',
'tokens' => [
'id' => '[0-9a-z_]+',
'status' => '[a-zA-z\- ]+',
]
],
'list' => [
'path' => '/{controller}/{type}{/view}',
'action' => AnimeClient::DEFAULT_CONTROLLER_METHOD,
'tokens' => [
'type' => '[a-z_]+',
'view' => '[a-z_]+'
]
],
'index_redirect' => [
'path' => '/',
'controller' => AnimeClient::DEFAULT_CONTROLLER_NAMESPACE,
'action' => 'redirect_to_default'
],
]
];

View File

@ -1,35 +0,0 @@
<?php
/**
* Hummingbird Anime Client
*
* An API client for Hummingbird to manage anime and manga watch lists
*
* @package HummingbirdAnimeClient
* @author Timothy J. Warren
* @copyright Copyright (c) 2015 - 2016
* @link https://github.com/timw4mail/HummingBirdAnimeClient
* @license MIT
*/
// ----------------------------------------------------------------------------
// Routing
// ----------------------------------------------------------------------------
return [
// Subfolder prefix for url, if in a subdirectory of the web root
'subfolder_prefix' => '',
// Path to public directory, where images/css/javascript are located,
// appended to the url
'asset_path' => '/public',
// Which list should be the default?
'default_list' => 'anime', // anime or manga
// Default pages for anime/manga
'default_anime_list_path' => "watching", // watching|plan_to_watch|on_hold|dropped|completed|all
'default_manga_list_path' => "reading", // reading|plan_to_read|on_hold|dropped|completed|all
// Default view type (cover_view/list_view)
'default_view_type' => 'cover_view',
];

View File

@ -32,13 +32,18 @@
<?php endif ?>
<?php if ($item['private'] || $item['rewatching']): ?>
<div class="row">
<?php foreach(['private', 'rereading'] as $attr): ?>
<?php foreach(['private', 'rewatching'] as $attr): ?>
<?php if($item[$attr]): ?>
<span class="item-<?= $attr ?>"><?= ucfirst($attr) ?></span>
<?php endif ?>
<?php endforeach ?>
</div>
<?php endif ?>
<?php if ($item['rewatched'] > 0): ?>
<div class="row">
<div>Rewatched <?= $item['rewatched'] ?> time(s)</div>
</div>
<?php endif ?>
<div class="row">
<div class="user_rating">Rating: <?= $item['user_rating'] ?> / 10</div>
<div class="completion">Episodes:

View File

@ -48,6 +48,9 @@
</td>
<td><?= $item['anime']['age_rating'] ?></td>
<td>
<?php if ($item['rewatched'] > 0): ?>
Rewatched <?= $item['rewatched'] ?> time(s)<br />
<?php endif ?>
<?php $attr_list = []; ?>
<?php foreach(['private','rewatching'] as $attr): ?>
<?php if($item[$attr]): ?>

5
app/views/error.php Normal file
View File

@ -0,0 +1,5 @@
<main>
<h1><?= $title ?></h1>
<h2><?= $message ?></h2>
<div><?= $log_message ?></div>
</main>

View File

@ -22,14 +22,6 @@
</tr>
</thead>
<tbody>
<tr>
<td><label for="private">Is Private?</label></td>
<td>
<input type="checkbox" name="private" id="private"
<?php if($item['private']): ?>checked="checked"<?php endif ?>
/>
</td>
</tr>
<tr>
<td><label for="status">Reading Status</label></td>
<td>

View File

@ -353,6 +353,10 @@ button {
Manga-list-specific styles
------------------------------------------------------------------------------*/
.manga .row {
padding: 1px;
}
.manga .media {
border: 1px solid #ddd;
width: 200px;
@ -362,6 +366,8 @@ button {
.manga .media > .edit_buttons {
position: absolute;
top: 86px;
top: calc(50% - 58.5px);
left: 5px;
left: calc(50% - 95px);
}

View File

@ -275,6 +275,10 @@ button {
/* -----------------------------------------------------------------------------
Manga-list-specific styles
------------------------------------------------------------------------------*/
.manga .row {
padding:1px;
}
.manga .media {
border:1px solid #ddd;
width:200px;
@ -284,6 +288,8 @@ button {
.manga .media > .edit_buttons {
position:absolute;
top: calc(50% - (117px / 2));
left: calc(50% - (190px / 2));
top: 86px;
top: calc(50% - 58.5px);
left: 5px;
left: calc(50% - 95px);
}

View File

@ -1,167 +1,229 @@
:root {
box-sizing: border-box;
cursor: default;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
font-family: 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
line-height: 1.4;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-size-adjust: 100%; }
text-size-adjust: 100%;
}
audio:not([controls]) {
display: none; }
display: none;
}
details {
display: block; }
display: block;
}
/*input[type="number"] {
width: auto; }*/
input[type="search"] {
-webkit-appearance: textfield; }
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none; }
-webkit-appearance: textfield;
}
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
main {
display: block; }
display: block;
}
summary {
display: block; }
display: block;
}
pre {
overflow: auto; }
overflow: auto;
}
progress {
display: inline-block; }
display: inline-block;
}
small {
font-size: 75%; }
font-size: 75%;
}
big {
font-size: 125%; }
font-size: 125%;
}
template {
display: none; }
display: none;
}
textarea {
overflow: auto;
resize: vertical; }
resize: vertical;
}
[hidden] {
display: none; }
display: none;
}
[unselectable] {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
user-select: none;
}
*, ::before, ::after {
*,
::before,
::after {
border-style: solid;
border-width: 0;
box-sizing: inherit; }
box-sizing: inherit;
}
* {
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0; }
padding: 0;
}
::before, ::after {
::before,
::after {
text-decoration: inherit;
vertical-align: inherit; }
vertical-align: inherit;
}
a {
text-decoration: none; }
text-decoration: none;
}
audio, canvas, iframe, img, svg, video {
vertical-align: middle; }
audio,
canvas,
iframe,
img,
svg,
video {
vertical-align: middle;
}
button, input, select, textarea {
button,
input,
select,
textarea {
/*background-color: transparent;*/
border: .1rem solid #ccc;
color: inherit;
font-family: inherit;
font-style: inherit;
font-weight: inherit;
min-height: 1.4em; }
min-height: 1.4em;
}
code, kbd, pre, samp {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, monospace; }
code,
kbd,
pre,
samp {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, monospace;
}
table {
border-collapse: collapse;
border-spacing: 0; }
border-spacing: 0;
}
::-moz-selection {
background-color: #b3d4fc;
text-shadow: none; }
text-shadow: none;
}
::selection {
background-color: #b3d4fc;
text-shadow: none; }
text-shadow: none;
}
button::-moz-focus-inner {
border: 0; }
border: 0;
}
@media screen {
[hidden~="screen"] {
display: inherit; }
display: inherit;
}
[hidden~="screen"]:not(:active):not(:focus):not(:target) {
clip: rect(0 0 0 0) !important;
position: absolute !important; } }
position: absolute !important;
}
}
body {
color: #444;
font-family: 'Open Sans', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
font-family: 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
font-size: 1.6rem;
font-style: normal;
font-weight: 400; }
font-weight: 400;
}
p {
margin: 0 0 1.6rem; }
margin: 0 0 1.6rem;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Lato', 'Open Sans', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
margin: 2rem 0 1.6rem; }
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Lato', 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
margin: 2rem 0 1.6rem;
}
h1 {
border-bottom: .1rem solid rgba(0, 0, 0, 0.2);
font-size: 3.6rem;
font-style: normal;
font-weight: 500; }
font-weight: 500;
}
h2 {
font-size: 3rem;
font-style: normal;
font-weight: 500; }
font-weight: 500;
}
h3 {
font-size: 2.4rem;
font-style: normal;
font-weight: 500;
margin: 1.6rem 0 0.4rem; }
margin: 1.6rem 0 0.4rem;
}
h4 {
font-size: 1.8rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
margin: 1.6rem 0 0.4rem;
}
h5 {
font-size: 1.6rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
margin: 1.6rem 0 0.4rem;
}
h6 {
color: #777;
font-size: 1.4rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
margin: 1.6rem 0 0.4rem;
}
small {
color: #777; }
color: #777;
}
pre {
background: #efefef;
@ -172,7 +234,8 @@ pre {
margin: 1.6rem 0;
padding: 1.6rem;
word-break: break-all;
word-wrap: break-word; }
word-wrap: break-word;
}
code {
background: #efefef;
@ -180,51 +243,73 @@ code {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size: 1.4rem;
word-break: break-all;
word-wrap: break-word; }
word-wrap: break-word;
}
a {
color: #1271db;
-webkit-transition: .25s ease;
transition: .25s ease; }
a:hover, a:focus {
text-decoration: none; }
transition: .25s ease;
}
a:hover,
a:focus {
text-decoration: none;
}
dl {
margin-bottom: 1.6rem; }
margin-bottom: 1.6rem;
}
dd {
margin-left: 4rem; }
margin-left: 4rem;
}
ul, ol {
ul,
ol {
margin-bottom: 0.8rem;
padding-left: 2rem; }
padding-left: 2rem;
}
blockquote {
border-left: .2rem solid #1271db;
font-family: Georgia, Times, 'Times New Roman', serif;
font-style: italic;
margin: 1.6rem 0;
padding-left: 1.6rem; }
padding-left: 1.6rem;
}
figcaption {
font-family: Georgia, Times, 'Times New Roman', serif; }
font-family: Georgia, Times, 'Times New Roman', serif;
}
html {
font-size: 62.5%; }
font-size: 62.5%;
}
body {
padding: 0; }
padding: 0;
}
main, header, footer, article, section, aside, details, summary {
main,
header,
footer,
article,
section,
aside,
details,
summary {
display: block;
height: auto;
margin: 0 auto;
width: 100%; }
width: 100%;
}
main {
display: block;
margin: 0 auto;
padding: 0 1.6rem 1.6rem; }
padding: 0 1.6rem 1.6rem;
}
footer {
border-top: .1rem solid rgba(0, 0, 0, 0.2);
@ -233,33 +318,57 @@ footer {
float: left;
max-width: 100%;
padding: 1rem 0;
text-align: center; }
text-align: center;
}
hr {
border-top: .1rem solid rgba(0, 0, 0, 0.2);
display: block;
margin-bottom: 1.6rem;
width: 100%; }
width: 100%;
}
img {
height: auto;
max-width: 100%;
vertical-align: baseline; }
vertical-align: baseline;
}
@media screen and (max-width: 40rem) {
article, section, aside {
article,
section,
aside {
clear: both;
display: block;
max-width: 100%; }
img {
margin-right: 1.6rem; } }
max-width: 100%;
}
input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"], select {
img {
margin-right: 1.6rem;
}
}
input[type="text"],
input[type="password"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="month"],
input[type="time"],
input[type="datetime"],
input[type="datetime-local"],
input[type="week"],
input[type="number"],
input[type="search"],
input[type="tel"],
input[type="color"],
select {
border: .1rem solid #ccc;
border-radius: 0;
display: inline-block;
padding: 0.8rem;
vertical-align: middle; }
vertical-align: middle;
}
input:not([type]) {
-webkit-appearance: none;
@ -270,59 +379,113 @@ input:not([type]) {
color: #444;
display: inline-block;
padding: 0.8rem;
text-align: left; }
text-align: left;
}
input[type="color"] {
padding: 0.8rem 1.6rem; }
padding: 0.8rem 1.6rem;
}
input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, select:focus, textarea:focus {
border-color: #b3d4fc; }
input[type="text"]:focus,
input[type="password"]:focus,
input[type="email"]:focus,
input[type="url"]:focus,
input[type="date"]:focus,
input[type="month"]:focus,
input[type="time"]:focus,
input[type="datetime"]:focus,
input[type="datetime-local"]:focus,
input[type="week"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
input[type="tel"]:focus,
input[type="color"]:focus,
select:focus,
textarea:focus {
border-color: #b3d4fc;
}
input:not([type]):focus {
border-color: #b3d4fc; }
border-color: #b3d4fc;
}
input[type="radio"], input[type="checkbox"] {
vertical-align: middle; }
input[type="radio"],
input[type="checkbox"] {
vertical-align: middle;
}
input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus {
outline: .1rem solid thin #444; }
input[type="file"]:focus,
input[type="radio"]:focus,
input[type="checkbox"]:focus {
outline: .1rem solid thin #444;
}
input[type="text"][disabled], input[type="password"][disabled], input[type="email"][disabled], input[type="url"][disabled], input[type="date"][disabled], input[type="month"][disabled], input[type="time"][disabled], input[type="datetime"][disabled], input[type="datetime-local"][disabled], input[type="week"][disabled], input[type="number"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="color"][disabled], select[disabled], textarea[disabled] {
input[type="text"][disabled],
input[type="password"][disabled],
input[type="email"][disabled],
input[type="url"][disabled],
input[type="date"][disabled],
input[type="month"][disabled],
input[type="time"][disabled],
input[type="datetime"][disabled],
input[type="datetime-local"][disabled],
input[type="week"][disabled],
input[type="number"][disabled],
input[type="search"][disabled],
input[type="tel"][disabled],
input[type="color"][disabled],
select[disabled],
textarea[disabled] {
background-color: #efefef;
color: #777;
cursor: not-allowed; }
cursor: not-allowed;
}
input:not([type])[disabled] {
background-color: #efefef;
color: #777;
cursor: not-allowed; }
cursor: not-allowed;
}
input[readonly], select[readonly], textarea[readonly] {
input[readonly],
select[readonly],
textarea[readonly] {
background-color: #efefef;
border-color: #ccc;
color: #777; }
color: #777;
}
input:focus:invalid, textarea:focus:invalid, select:focus:invalid {
input:focus:invalid,
textarea:focus:invalid,
select:focus:invalid {
border-color: #e9322d;
color: #b94a48; }
color: #b94a48;
}
input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus, input[type="checkbox"]:focus:invalid:focus {
outline-color: #ff4136; }
input[type="file"]:focus:invalid:focus,
input[type="radio"]:focus:invalid:focus,
input[type="checkbox"]:focus:invalid:focus {
outline-color: #ff4136;
}
select {
background-color: #fff;
border: .1rem solid #ccc; }
border: .1rem solid #ccc;
}
select[multiple] {
height: auto; }
height: auto;
}
label {
line-height: 2; }
line-height: 2;
}
fieldset {
border: 0;
margin: 0;
padding: 0.8rem 0; }
padding: 0.8rem 0;
}
legend {
border-bottom: .1rem solid #ccc;
@ -330,7 +493,8 @@ legend {
display: block;
margin-bottom: 0.8rem;
padding: 0.8rem 0;
width: 100%; }
width: 100%;
}
textarea {
border: .1rem solid #ccc;
@ -338,9 +502,11 @@ textarea {
display: block;
margin-bottom: 0.8rem;
padding: 0.8rem;
vertical-align: middle; }
vertical-align: middle;
}
input[type=submit], button {
input[type=submit],
button {
background-color: transparent;
border: .2rem solid #444;
border-radius: 0;
@ -360,77 +526,113 @@ input[type=submit], button {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: baseline; }
input[type=submit] a, button a {
color: #444; }
vertical-align: baseline;
}
input[type=submit]::-moz-focus-inner, button::-moz-focus-inner {
padding: 0; }
input[type=submit] a,
button a {
color: #444;
}
input[type=submit]:hover, button:hover {
input[type=submit]::-moz-focus-inner,
button::-moz-focus-inner {
padding: 0;
}
input[type=submit]:hover,
button:hover {
background: #444;
border-color: #444;
color: #fff; }
input[type=submit]:hover a, button:hover a {
color: #fff; }
color: #fff;
}
input[type=submit]:active, button:active {
input[type=submit]:hover a,
button:hover a {
color: #fff;
}
input[type=submit]:active,
button:active {
background: #6a6a6a;
border-color: #6a6a6a;
color: #fff; }
input[type=submit]:active a, button:active a {
color: #fff; }
color: #fff;
}
input[type=submit]:disabled, button:disabled {
input[type=submit]:active a,
button:active a {
color: #fff;
}
input[type=submit]:disabled,
button:disabled {
box-shadow: none;
cursor: not-allowed;
opacity: .40; }
opacity: .40;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
padding-top: 1.6rem;
text-align: center; }
text-align: center;
}
nav ul li {
display: inline; }
display: inline;
}
nav a {
border-bottom: .2rem solid transparent;
color: #444;
padding: 0.8rem 1.6rem;
text-decoration: none;
-webkit-transition: .25s ease;
transition: .25s ease; }
nav a:hover, nav li.selected a {
border-color: rgba(0, 0, 0, 0.2); }
transition: .25s ease;
}
nav a:hover,
nav li.selected a {
border-color: rgba(0, 0, 0, 0.2);
}
nav a:active {
border-color: rgba(0, 0, 0, 0.56); }
border-color: rgba(0, 0, 0, 0.56);
}
table {
margin-bottom: 1.6rem; }
margin-bottom: 1.6rem;
}
caption {
padding: 0.8rem 0; }
padding: 0.8rem 0;
}
thead th {
background: #efefef;
color: #444; }
color: #444;
}
tr {
background: #fff;
margin-bottom: 0.8rem; }
margin-bottom: 0.8rem;
}
th, td {
th,
td {
border: .1rem solid #ccc;
padding: 0.8rem 1.6rem;
text-align: center;
vertical-align: inherit; }
vertical-align: inherit;
}
tfoot tr {
background: none; }
background: none;
}
tfoot td {
color: #efefef;
font-size: 0.8rem;
font-style: italic;
padding: 1.6rem 0.4rem; }
padding: 1.6rem 0.4rem;
}

437
public/css/marx.myth.css Normal file
View File

@ -0,0 +1,437 @@
:root {
--default-font-list: 'Open Sans', 'Nimbus Sans L', 'Helvetica Neue', Helvetica, 'Lucida Grande', sans-serif;
box-sizing: border-box;
cursor: default;
font-family: var(--default-font-list);
line-height: 1.4;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-size-adjust: 100%; }
audio:not([controls]) {
display: none; }
details {
display: block; }
/*input[type="number"] {
width: auto; }*/
input[type="search"] {
-webkit-appearance: textfield; }
input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none; }
main {
display: block; }
summary {
display: block; }
pre {
overflow: auto; }
progress {
display: inline-block; }
small {
font-size: 75%; }
big {
font-size: 125%; }
template {
display: none; }
textarea {
overflow: auto;
resize: vertical; }
[hidden] {
display: none; }
[unselectable] {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
*, ::before, ::after {
border-style: solid;
border-width: 0;
box-sizing: inherit; }
* {
font-size: inherit;
line-height: inherit;
margin: 0;
padding: 0; }
::before, ::after {
text-decoration: inherit;
vertical-align: inherit; }
a {
text-decoration: none; }
audio, canvas, iframe, img, svg, video {
vertical-align: middle; }
button, input, select, textarea {
/*background-color: transparent;*/
border: .1rem solid #ccc;
color: inherit;
font-family: inherit;
font-style: inherit;
font-weight: inherit;
min-height: 1.4em; }
code, kbd, pre, samp {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, monospace; }
table {
border-collapse: collapse;
border-spacing: 0; }
::-moz-selection {
background-color: #b3d4fc;
text-shadow: none; }
::selection {
background-color: #b3d4fc;
text-shadow: none; }
button::-moz-focus-inner {
border: 0; }
@media screen {
[hidden~="screen"] {
display: inherit; }
[hidden~="screen"]:not(:active):not(:focus):not(:target) {
clip: rect(0 0 0 0) !important;
position: absolute !important; } }
body {
color: #444;
font-family: var(--default-font-list);
font-size: 1.6rem;
font-style: normal;
font-weight: 400; }
p {
margin: 0 0 1.6rem; }
h1, h2, h3, h4, h5, h6 {
font-family: 'Lato', var(--default-font-list);
margin: 2rem 0 1.6rem; }
h1 {
border-bottom: .1rem solid rgba(0, 0, 0, 0.2);
font-size: 3.6rem;
font-style: normal;
font-weight: 500; }
h2 {
font-size: 3rem;
font-style: normal;
font-weight: 500; }
h3 {
font-size: 2.4rem;
font-style: normal;
font-weight: 500;
margin: 1.6rem 0 0.4rem; }
h4 {
font-size: 1.8rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
h5 {
font-size: 1.6rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
h6 {
color: #777;
font-size: 1.4rem;
font-style: normal;
font-weight: 600;
margin: 1.6rem 0 0.4rem; }
small {
color: #777; }
pre {
background: #efefef;
color: #444;
display: block;
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size: 1.4rem;
margin: 1.6rem 0;
padding: 1.6rem;
word-break: break-all;
word-wrap: break-word; }
code {
background: #efefef;
color: #444;
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
font-size: 1.4rem;
word-break: break-all;
word-wrap: break-word; }
a {
color: #1271db;
-webkit-transition: .25s ease;
transition: .25s ease; }
a:hover, a:focus {
text-decoration: none; }
dl {
margin-bottom: 1.6rem; }
dd {
margin-left: 4rem; }
ul, ol {
margin-bottom: 0.8rem;
padding-left: 2rem; }
blockquote {
border-left: .2rem solid #1271db;
font-family: Georgia, Times, 'Times New Roman', serif;
font-style: italic;
margin: 1.6rem 0;
padding-left: 1.6rem; }
figcaption {
font-family: Georgia, Times, 'Times New Roman', serif; }
html {
font-size: 62.5%; }
body {
padding: 0; }
main, header, footer, article, section, aside, details, summary {
display: block;
height: auto;
margin: 0 auto;
width: 100%; }
main {
display: block;
margin: 0 auto;
padding: 0 1.6rem 1.6rem; }
footer {
border-top: .1rem solid rgba(0, 0, 0, 0.2);
clear: both;
display: inline-block;
float: left;
max-width: 100%;
padding: 1rem 0;
text-align: center; }
hr {
border-top: .1rem solid rgba(0, 0, 0, 0.2);
display: block;
margin-bottom: 1.6rem;
width: 100%; }
img {
height: auto;
max-width: 100%;
vertical-align: baseline; }
@media screen and (max-width: 40rem) {
article, section, aside {
clear: both;
display: block;
max-width: 100%; }
img {
margin-right: 1.6rem; } }
input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"], select {
border: .1rem solid #ccc;
border-radius: 0;
display: inline-block;
padding: 0.8rem;
vertical-align: middle; }
input:not([type]) {
-webkit-appearance: none;
background-clip: padding-box;
background-color: #fff;
border: .1rem solid #ccc;
border-radius: 0;
color: #444;
display: inline-block;
padding: 0.8rem;
text-align: left; }
input[type="color"] {
padding: 0.8rem 1.6rem; }
input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, select:focus, textarea:focus {
border-color: #b3d4fc; }
input:not([type]):focus {
border-color: #b3d4fc; }
input[type="radio"], input[type="checkbox"] {
vertical-align: middle; }
input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus {
outline: .1rem solid thin #444; }
input[type="text"][disabled], input[type="password"][disabled], input[type="email"][disabled], input[type="url"][disabled], input[type="date"][disabled], input[type="month"][disabled], input[type="time"][disabled], input[type="datetime"][disabled], input[type="datetime-local"][disabled], input[type="week"][disabled], input[type="number"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="color"][disabled], select[disabled], textarea[disabled] {
background-color: #efefef;
color: #777;
cursor: not-allowed; }
input:not([type])[disabled] {
background-color: #efefef;
color: #777;
cursor: not-allowed; }
input[readonly], select[readonly], textarea[readonly] {
background-color: #efefef;
border-color: #ccc;
color: #777; }
input:focus:invalid, textarea:focus:invalid, select:focus:invalid {
border-color: #e9322d;
color: #b94a48; }
input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus, input[type="checkbox"]:focus:invalid:focus {
outline-color: #ff4136; }
select {
background-color: #fff;
border: .1rem solid #ccc; }
select[multiple] {
height: auto; }
label {
line-height: 2; }
fieldset {
border: 0;
margin: 0;
padding: 0.8rem 0; }
legend {
border-bottom: .1rem solid #ccc;
color: #444;
display: block;
margin-bottom: 0.8rem;
padding: 0.8rem 0;
width: 100%; }
textarea {
border: .1rem solid #ccc;
border-radius: 0;
display: block;
margin-bottom: 0.8rem;
padding: 0.8rem;
vertical-align: middle; }
input[type=submit], button {
background-color: transparent;
border: .2rem solid #444;
border-radius: 0;
color: #444;
cursor: pointer;
display: inline-block;
margin-bottom: 0.8rem;
margin-right: 0.4rem;
padding: 0.8rem 1.6rem;
text-align: center;
text-decoration: none;
text-transform: uppercase;
-webkit-transition: .25s ease;
transition: .25s ease;
-webkit-user-drag: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
vertical-align: baseline; }
input[type=submit] a, button a {
color: #444; }
input[type=submit]::-moz-focus-inner, button::-moz-focus-inner {
padding: 0; }
input[type=submit]:hover, button:hover {
background: #444;
border-color: #444;
color: #fff; }
input[type=submit]:hover a, button:hover a {
color: #fff; }
input[type=submit]:active, button:active {
background: #6a6a6a;
border-color: #6a6a6a;
color: #fff; }
input[type=submit]:active a, button:active a {
color: #fff; }
input[type=submit]:disabled, button:disabled {
box-shadow: none;
cursor: not-allowed;
opacity: .40; }
nav ul {
list-style: none;
margin: 0;
padding: 0;
padding-top: 1.6rem;
text-align: center; }
nav ul li {
display: inline; }
nav a {
border-bottom: .2rem solid transparent;
color: #444;
padding: 0.8rem 1.6rem;
text-decoration: none;
-webkit-transition: .25s ease;
transition: .25s ease; }
nav a:hover, nav li.selected a {
border-color: rgba(0, 0, 0, 0.2); }
nav a:active {
border-color: rgba(0, 0, 0, 0.56); }
table {
margin-bottom: 1.6rem; }
caption {
padding: 0.8rem 0; }
thead th {
background: #efefef;
color: #444; }
tr {
background: #fff;
margin-bottom: 0.8rem; }
th, td {
border: .1rem solid #ccc;
padding: 0.8rem 1.6rem;
text-align: center;
vertical-align: inherit; }
tfoot tr {
background: none; }
tfoot td {
color: #efefef;
font-size: 0.8rem;
font-style: italic;
padding: 1.6rem 0.4rem; }

View File

@ -18,6 +18,11 @@ class AnimeClient {
use \Aviat\Ion\Di\ContainerAware;
const SESSION_SEGMENT = 'Aviat\AnimeClient\Auth';
const DEFAULT_CONTROLLER_NAMESPACE = 'Aviat\AnimeClient\Controller';
const DEFAULT_CONTROLLER = 'Aviat\AnimeClient\Controller\Anime';
const DEFAULT_CONTROLLER_METHOD = 'index';
const NOT_FOUND_METHOD = 'not_found';
const ERROR_MESSAGE_METHOD = 'error_page';
private static $form_pages = [
'edit',

View File

@ -106,7 +106,7 @@ class Controller {
*/
public function redirect_to_default()
{
$default_type = $this->config->get(['routing', 'default_list']);
$default_type = $this->config->get(['routes', 'route_config', 'default_list']);
$this->redirect($this->urlGenerator->default_url($default_type), 303);
}
@ -309,6 +309,23 @@ class Controller {
]);
}
/**
* Display a generic error page
*
* @param string $title
* @param string $message
* @param string $long_message
* @return void
*/
public function error_page($title, $message, $long_message = "")
{
$this->outputHTML('error', [
'title' => $title,
'message' => $message,
'long_message' => $long_message
]);
}
/**
* Set a session flash variable to display a message on
* next page load

View File

@ -16,6 +16,7 @@ use Aura\Web\Request;
use Aura\Web\Response;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\AnimeClient\AnimeClient;
/**
* Basic routing/ dispatch
@ -52,75 +53,6 @@ class Dispatcher extends RoutingBase {
$this->request = $container->get('request');
$this->output_routes = $this->_setup_routes();
$this->generate_convention_routes();
}
/**
* Generate routes based on controller methods
*
* @return void
*/
protected function generate_convention_routes()
{
$default_controller = $this->routes['convention']['default_controller'];
$this->output_routes[] = $this->router->addGet('login', '/{controller}/login')
->setValues([
'controller' => $default_controller,
'action' => 'login'
]);
$this->output_routes[] = $this->router->addPost('login_post', '/{controller}/login')
->setValues([
'controller' => $default_controller,
'action' => 'login_action'
]);
$this->output_routes[] = $this->router->addGet('logout', '/{controller}/logout')
->setValues([
'controller' => $default_controller,
'action' => 'logout'
]);
$this->output_routes[] = $this->router->addPost('update', '/{controller}/update')
->setValues([
'controller' => $default_controller,
'action' => 'update'
])->setTokens([
'controller' => '[a-z_]+'
]);
$this->output_routes[] = $this->router->addPost('update_form', '/{controller}/update_form')
->setValues([
'controller' => $default_controller,
'action' => 'form_update'
])->setTokens([
'controller' => '[a-z_]+'
]);
$this->output_routes[] = $this->router->addGet('edit', '/{controller}/edit/{id}/{status}')
->setValues([
'controller' => $default_controller,
'action' => 'edit'
])->setTokens([
'id' => '[0-9a-z_]+',
'status' => '[a-zA-z\- ]+',
]);
$this->output_routes[] = $this->router->addGet('list', '/{controller}/{type}{/view}')
->setValues([
'controller' => $default_controller,
'action' => $this->routes['convention']['default_method'],
])->setTokens([
'type' => '[a-z_]+',
'view' => '[a-z_]+'
]);
$this->output_routes[] = $this->router->addGet('index_redirect', '/')
->setValues([
'controller' => 'Aviat\\AnimeClient\\Controller',
'action' => 'redirect_to_default'
]);
}
/**
@ -132,7 +64,7 @@ class Dispatcher extends RoutingBase {
{
$error_handler = $this->container->get('error-handler');
$raw_route = $this->request->server->get('PATH_INFO');
$raw_route = $this->request->url->get(PHP_URL_PATH);
$route_path = "/" . trim($raw_route, '/');
$error_handler->addDataTable('Route Info', [
@ -162,8 +94,8 @@ class Dispatcher extends RoutingBase {
public function __invoke($route = NULL)
{
$error_handler = $this->container->get('error-handler');
$controller_name = $this->routes['convention']['default_controller'];
$action_method = $this->routes['convention']['404_method'];
$controller_name = AnimeClient::DEFAULT_CONTROLLER;
$action_method = AnimeClient::NOT_FOUND_METHOD;
$params = [];
if (is_null($route))
@ -176,6 +108,24 @@ class Dispatcher extends RoutingBase {
{
$failure = $this->router->getFailedRoute();
$error_handler->addDataTable('failed_route', (array)$failure);
$action_method = AnimeClient::ERROR_MESSAGE_METHOD;
switch(TRUE)
{
case $failure->failedMethod():
$params['title'] = '405 Method Not Allowed';
$params['message'] = 'Invalid HTTP Verb';
break;
case $failure->failedAccept():
$params['title'] = '406 Not Acceptable';
$params['message'] = 'Unacceptable content type';
break;
default:
$action_method = AnimeClient::NOT_FOUND_METHOD;
break;
}
}
else
{
@ -229,8 +179,7 @@ class Dispatcher extends RoutingBase {
public function get_controller()
{
$route_type = $this->__get('default_list');
$request_uri = $this->request->server->get('PATH_INFO');
$request_uri = $this->request->url->get(PHP_URL_PATH);
$path = trim($request_uri, '/');
$segments = explode('/', $path);
@ -251,8 +200,7 @@ class Dispatcher extends RoutingBase {
*/
public function get_controller_list()
{
$convention_routing = $this->routes['convention'];
$default_namespace = $convention_routing['default_namespace'];
$default_namespace = AnimeClient::DEFAULT_CONTROLLER_NAMESPACE;
$path = str_replace('\\', '/', $default_namespace);
$path = trim($path, '/');
$actual_path = \_dir(SRC_DIR, $path);
@ -278,22 +226,13 @@ class Dispatcher extends RoutingBase {
*
* @return array
*/
public function _setup_routes()
protected function _setup_routes()
{
$routes = [];
$route_type = $this->get_controller();
// Return early if invalid route array
if ( ! array_key_exists($route_type, $this->routes))
{
return [];
}
$applied_routes = $this->routes[$route_type];
// Add routes
foreach ($applied_routes as $name => &$route)
$routes = [];
foreach ($this->routes as $name => &$route)
{
$path = $route['path'];
unset($route['path']);
@ -305,7 +244,7 @@ class Dispatcher extends RoutingBase {
}
else
{
$controller_class = $this->routes['convention']['default_controller'];
$controller_class = AnimeClient::DEFAULT_CONTROLLER;
}
// Prepend the controller to the route parameters
@ -313,7 +252,8 @@ class Dispatcher extends RoutingBase {
// Select the appropriate router method based on the http verb
$add = (array_key_exists('verb', $route))
? "add" . ucfirst(strtolower($route['verb'])) : "addGet";
? "add" . ucfirst(strtolower($route['verb']))
: "addGet";
// Add the route to the router object
if ( ! array_key_exists('tokens', $route))

View File

@ -100,13 +100,13 @@ class AnimeListTransformer extends AbstractTransformer {
{
// Messy mapping of boolean values to their API string equivalents
$privacy = 'public';
if (array_key_exists('private', $item) && $item['private'] == TRUE)
if (array_key_exists('private', $item) && $item['private'])
{
$privacy = 'private';
}
$rewatching = 'false';
if (array_key_exists('rewatching', $item) && $item['rewatching'] == TRUE)
if (array_key_exists('rewatching', $item) && $item['rewatching'])
{
$rewatching = 'true';
}

View File

@ -67,7 +67,7 @@ class MangaListTransformer extends AbstractTransformer {
'notes' => $item['notes'],
'rereading' => (bool)$item['rereading'],
'reread' => $item['reread_count'],
'user_rating' => $rating
'user_rating' => $rating,
];
if (array_key_exists('english_title', $manga))
@ -92,13 +92,7 @@ class MangaListTransformer extends AbstractTransformer {
*/
public function untransform($item)
{
$private = (array_key_exists('private', $item))
? (bool)$item['private']
: FALSE;
$rereading = (array_key_exists('rereading', $item))
? (bool)$item['rereading']
: FALSE;
$rereading = (array_key_exists('rereading', $item)) && (bool)$item['rereading'];
$map = [
'id' => $item['id'],
@ -108,7 +102,6 @@ class MangaListTransformer extends AbstractTransformer {
'volumes_read' => (int)$item['volumes_read'],
'rereading' => $rereading,
'reread_count' => (int)$item['reread_count'],
'private' => $private,
'notes' => $item['notes'],
];

View File

@ -67,12 +67,10 @@ class Anime extends API {
'form_params' => $data
]);
$output = [
return [
'statusCode' => $response->getStatusCode(),
'body' => json_decode($response->getBody(), TRUE)
];
return $output;
}
/**

View File

@ -48,7 +48,8 @@ class RoutingBase {
{
$this->container = $container;
$this->config = $container->get('config');
$this->routes = $this->config->get('routes');
$this->base_routes = $this->config->get('routes');
$this->routes = $this->base_routes['routes'];
}
/**
@ -59,7 +60,7 @@ class RoutingBase {
*/
public function __get($key)
{
$routing_config = $this->config->get('routing');
$routing_config = $this->base_routes['route_config'];
if (array_key_exists($key, $routing_config))
{

View File

@ -66,19 +66,12 @@ class DispatcherTest extends AnimeClient_TestCase {
{
$default_config = array(
'routes' => [
'convention' => [
'default_namespace' => '\\Aviat\\AnimeClient\\Controller',
'default_controller' => '\\Aviat\\AnimeClient\\Controller\\Anime',
'default_method' => 'index'
],
'common' => [
'routes' => [
'login_form' => [
'path' => '/login',
'action' => 'login',
'verb' => 'get'
],
],
'anime' => [
'watching' => [
'path' => '/anime/watching{/view}',
'action' => 'anime_list',
@ -89,8 +82,6 @@ class DispatcherTest extends AnimeClient_TestCase {
'view' => '[a-z_]+'
]
],
],
'manga' => [
'plan_to_read' => [
'path' => '/manga/plan_to_read{/view}',
'action' => 'manga_list',
@ -101,13 +92,13 @@ class DispatcherTest extends AnimeClient_TestCase {
'view' => '[a-z_]+'
]
],
]
],
'routing' => [
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_list' => 'anime'
]
],
);
$data = [
@ -174,7 +165,8 @@ class DispatcherTest extends AnimeClient_TestCase {
public function testDefaultRoute()
{
$config = [
'routing' => [
'routes' => [
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_anime_list_path' => "watching",
@ -182,19 +174,11 @@ class DispatcherTest extends AnimeClient_TestCase {
'default_list' => 'manga'
],
'routes' => [
'convention' => [
'default_namespace' => '\\Aviat\\AnimeClient\\Controller',
'default_controller' => '\\Aviat\\AnimeClient\\Controller\\Anime',
'default_method' => 'index'
],
'common' => [
'login_form' => [
'path' => '/login',
'action' => ['login'],
'verb' => 'get'
],
],
'anime' => [
'index' => [
'path' => '/',
'action' => ['redirect'],
@ -203,8 +187,6 @@ class DispatcherTest extends AnimeClient_TestCase {
'code' => '301'
]
],
],
'manga' => [
'index' => [
'path' => '/',
'action' => ['redirect'],
@ -213,7 +195,7 @@ class DispatcherTest extends AnimeClient_TestCase {
'code' => '301',
'type' => 'manga'
]
],
]
]
]
];
@ -231,19 +213,17 @@ class DispatcherTest extends AnimeClient_TestCase {
return array(
'controller_list_sanity_check' => [
'config' => [
'routing' => [
'routes' => [
'routes' => [
],
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_anime_list_path' => "watching",
'default_manga_list_path' => 'all',
'default_list' => 'manga'
],
'routes' => [
'convention' => [
'default_namespace' => '\\Aviat\\AnimeClient\\Controller',
'default_controller' => '\\Aviat\\AnimeClient\\Controller\\Anime',
'default_method' => 'index'
]
]
],
'expected' => [
@ -254,22 +234,24 @@ class DispatcherTest extends AnimeClient_TestCase {
],
'empty_controller_list' => [
'config' => [
'routing' => [
'routes' => [
'routes' => [
],
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_anime_path' => "/anime/watching",
'default_manga_path' => '/manga/all',
'default_list' => 'manga'
],
'routes' => [
'convention' => [
'default_namespace' => '\\Aviat\\Ion\\Controller',
'default_controller' => '\\Aviat\\Ion\\Controller\\Anime',
'default_method' => 'index'
]
]
],
'expected' => []
'expected' => [
'anime' => 'Aviat\AnimeClient\Controller\Anime',
'manga' => 'Aviat\AnimeClient\Controller\Manga',
'collection' => 'Aviat\AnimeClient\Controller\Collection',
]
]
);
}

View File

@ -41,13 +41,16 @@ class UrlGeneratorTest extends AnimeClient_TestCase {
return [
'default_view' => [
'config' => [
'routing' => [
'routes' => [
'routes' => [],
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_list' => 'manga',
'default_anime_path' => '/anime/watching',
'default_manga_path' => '/manga/all',
'default_to_list_view' => FALSE,
]
],
],
'path' => '',
@ -56,13 +59,16 @@ class UrlGeneratorTest extends AnimeClient_TestCase {
],
'default_view_list' => [
'config' => [
'routing' => [
'routes' => [
'routes' => [],
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_list' => 'manga',
'default_anime_path' => '/anime/watching',
'default_manga_path' => '/manga/all',
'default_to_list_view' => TRUE,
]
],
],
'path' => '',
@ -89,7 +95,9 @@ class UrlGeneratorTest extends AnimeClient_TestCase {
public function dataBaseUrl()
{
$config = [
'routing' => [
'routes' => [
'routes' => [],
'route_config' => [
'anime_path' => 'anime',
'manga_path' => 'manga',
'default_list' => 'manga',
@ -97,6 +105,7 @@ class UrlGeneratorTest extends AnimeClient_TestCase {
'default_manga_path' => '/all',
'default_to_list_view' => TRUE,
],
]
];
return [

View File

@ -48,17 +48,13 @@ class AnimeClient_TestCase extends PHPUnit_Framework_TestCase {
'file' => ':memory:',
]
],
'routing' => [
'routes' => [
'route_config' => [
'asset_path' => '/assets'
],
'routes' => [
'convention' => [
'default_controller' => '',
'default_method' => '',
],
'common' => [],
'anime' => [],
'manga' => []
]
]
];