Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
15 changed files with 165 additions and 60 deletions
Showing only changes of commit d8c89c9deb - Show all commits

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ build/**
!build/*.txt !build/*.txt
!build/*.xml !build/*.xml
!build/*.php !build/*.php
app/config/*.toml

View File

@ -1,6 +1,6 @@
<main> <main>
<?php if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $urlGenerator->url('anime/add', 'anime') ?>">Add Item</a> <a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php endif ?> <?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
@ -17,7 +17,7 @@
<?php endif ?> <?php endif ?>
<?= $helper->img($item['anime']['image']); ?> <?= $helper->img($item['anime']['image']); ?>
<div class="name"> <div class="name">
<a href="<?= $escape->attr($item['anime']['url']) ?>" target="_blank"> <a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>" target="_blank">
<?= $escape->html($item['anime']['title']) ?> <?= $escape->html($item['anime']['title']) ?>
<?= ($item['anime']['alternate_title'] != "") ? "<br />({$item['anime']['alternate_title']})" : ""; ?> <?= ($item['anime']['alternate_title'] != "") ? "<br />({$item['anime']['alternate_title']})" : ""; ?>
</a> </a>

View File

@ -1,11 +1,50 @@
<main> <main class="details">
<h2><a href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2> <section class="flex flex-no-wrap">
<div>
<img class="cover" src="<?= $data['cover_image'] ?>" alt="<?= $data['title'] ?> cover image" />
<br />
<br />
<table>
<tr>
<td class="align_right">Airing Status</td>
<td><?= $data['status'] ?></td>
</tr>
<tr>
<td>Show Type</td>
<td><?= $data['show_type'] ?></td>
</tr>
<tr>
<td>Episode Count</td>
<td><?= $data['episode_count'] ?></td>
</tr>
<tr>
<td>Episode Length</td>
<td><?= $data['episode_length'] ?> minutes</td>
</tr>
<tr>
<td>Age Rating</td>
<td><?= $data['age_rating'] ?></td>
</tr>
<tr>
<td>Genres</td>
<td>
<?php
$genres = [];
foreach($data['genres'] as $g) $genres[] = $g['name'];
?>
<?= implode(', ', $genres); ?>
</td>
</tr>
</table>
</div>
<div>
<h2><a target="_blank" href="<?= $data['url'] ?>"><?= $data['title'] ?></a></h2>
<?php if( ! empty($data['alternate_title'])): ?> <?php if( ! empty($data['alternate_title'])): ?>
<h3><?= $data['alternate_title'] ?></h3> <h3><?= $data['alternate_title'] ?></h3>
<?php endif ?> <?php endif ?>
<img src="<?= $data['cover_image'] ?>" alt="<?= $data['title'] ?> cover image" /> <br />
<p><?= nl2br($data['synopsis']) ?></p> <p><?= nl2br($data['synopsis']) ?></p>
<pre><?= print_r($data, TRUE) ?></pre> </div>
</section>
</main> </main>

View File

@ -1,6 +1,6 @@
<main> <main>
<?php if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $urlGenerator->url('anime/add', 'anime') ?>">Add Item</a> <a class="bracketed" href="<?= $url->generate('anime.add.get') ?>">Add Item</a>
<?php endif ?> <?php endif ?>
<?php if (empty($sections)): ?> <?php if (empty($sections)): ?>
<h3>There's nothing here!</h3> <h3>There's nothing here!</h3>
@ -34,7 +34,7 @@
</td> </td>
<?php endif ?> <?php endif ?>
<td class="justify"> <td class="justify">
<a href="<?= $item['anime']['url'] ?>" target="_blank"> <a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>" target="_blank">
<?= $item['anime']['title'] ?> <?= $item['anime']['title'] ?>
</a> </a>
<?= ( ! empty($item['anime']['alternate_title'])) ? " <br /> " . $item['anime']['alternate_title'] : "" ?> <?= ( ! empty($item['anime']['alternate_title'])) ? " <br /> " . $item['anime']['alternate_title'] : "" ?>

View File

@ -13,7 +13,7 @@
<article class="media" id="a-<?= $item['hummingbird_id'] ?>"> <article class="media" id="a-<?= $item['hummingbird_id'] ?>">
<img src="<?= $urlGenerator->asset_url('images', 'anime', basename($item['cover_image'])) ?>" /> <img src="<?= $urlGenerator->asset_url('images', 'anime', basename($item['cover_image'])) ?>" />
<div class="name"> <div class="name">
<a href="https://hummingbird.me/anime/<?= $item['slug'] ?>"> <a href="<?= $url->generate('anime.details', ['id' => $item['slug']]) ?>">
<?= $item['title'] ?> <?= $item['title'] ?>
<?= ($item['alternate_title'] != "") ? "<br />({$item['alternate_title']})" : ""; ?> <?= ($item['alternate_title'] != "") ? "<br />({$item['alternate_title']})" : ""; ?>
</a> </a>

View File

@ -6,7 +6,8 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<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'" />
<link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php/g/base') ?>" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=0" />
<link rel="stylesheet" href="<?= $urlGenerator->asset_url('css.php/g/base/debug') ?>" />
<script src="<?= $urlGenerator->asset_url('js.php/g/base') ?>"></script> <script src="<?= $urlGenerator->asset_url('js.php/g/base') ?>"></script>
</head> </head>
<body class="<?= $escape->attr($url_type) ?> list"> <body class="<?= $escape->attr($url_type) ?> list">
@ -31,9 +32,9 @@
</span> </span>
<span class="flex-no-wrap small-font"> <span class="flex-no-wrap small-font">
<?php if ($auth->is_authenticated()): ?> <?php if ($auth->is_authenticated()): ?>
<a class="bracketed" href="<?= $urlGenerator->url("/{$url_type}/logout", $url_type) ?>">Logout</a> <a class="bracketed" href="<?= $url->generate('logout') ?>">Logout</a>
<?php else: ?> <?php else: ?>
[<a href="<?= $urlGenerator->url("/{$url_type}/login", $url_type) ?>"><?= $config->get('whose_list') ?>'s Login</a>] [<a href="<?= $url->generate('login'); ?>"><?= $config->get('whose_list') ?>'s Login</a>]
<?php endif ?> <?php endif ?>
</span> </span>
</h1> </h1>

View File

@ -1,7 +1,7 @@
<main> <main>
<h2><?= $config->get('whose_list'); ?>'s Login</h2> <h2><?= $config->get('whose_list'); ?>'s Login</h2>
<?= $message ?> <?= $message ?>
<form method="post" action="<?= $urlGenerator->full_url($urlGenerator->path(), $url_type) ?>"> <form method="post" action="<?= $url->generate('login.post') ?>">
<table class="form invisible"> <table class="form invisible">
<tr> <tr>
<td><label for="password">Password: </label></td> <td><label for="password">Password: </label></td>

View File

@ -1,5 +0,0 @@
<div class="message {{message_type}}">
<span class="icon"></span>
{{message}}
<span class="close">x</span>
</div>

View File

@ -137,6 +137,10 @@ h1 a {
text-align: right; text-align: right;
} }
.valign_top {
vertical-align: top;
}
.no_border { .no_border {
border: none; border: none;
} }
@ -307,13 +311,13 @@ h1 a {
min-width: 70%; min-width: 70%;
} }
.form.invisible tr:nth-child(odd) { .invisible tbody > tr:nth-child(odd) {
background: inherit; background: inherit;
} }
.form.invisible tr, .invisible tr,
.form.invisible td, .invisible td,
.form.invisible th { .invisible th {
border: 0; border: 0;
} }
@ -339,10 +343,6 @@ h1 a {
line-height: 1em; line-height: 1em;
} }
/*.message .close:after {
content: '☐';
}*/
.message:hover .close:after { .message:hover .close:after {
content: '☒'; content: '☒';
} }
@ -554,7 +554,7 @@ h1 a {
} }
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Page-specific styles Search page styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.media.search > .name { .media.search > .name {
@ -601,3 +601,49 @@ h1 a {
width: 100%; width: 100%;
vertical-align: middle; vertical-align: middle;
} }
/* ----------------------------------------------------------------------------
Details page styles
-----------------------------------------------------------------------------*/
.details {
margin: 1.5rem auto 0 auto;
max-width: 93rem;
padding: 1rem;
font-size: inherit;
}
.details .cover {
max-width: 300px;
max-height: 435px;
}
.details h2 {
margin-top: 0;
}
.details .flex > div {
margin: 1rem;
}
.details table {
max-width: 300px;
}
.details td {
padding: 0 1.5rem;
}
.details p {
text-align: justify;
}
.details td:nth-child(odd) {
width: 1%;
white-space: nowrap;
text-align: right;
}
.details td:nth-child(even) {
text-align: left;
}

View File

@ -79,6 +79,8 @@ a:hover, a:active {
.align_left {text-align:left} .align_left {text-align:left}
.align_right {text-align:right} .align_right {text-align:right}
.valign_top {vertical-align:top}
.no_border {border:none} .no_border {border:none}
.media-wrap { .media-wrap {
@ -159,11 +161,8 @@ a:hover, a:active {
Table sorting and form styles Table sorting and form styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.sorting, .sorting,
/*.sorting::before,*/
.sorting_asc, .sorting_asc,
/*.sorting_asc::before,*/ .sorting_desc {
.sorting_desc
/*.sorting_desc::before*/ {
vertical-align:text-bottom; vertical-align:text-bottom;
} }
.sorting::before { .sorting::before {
@ -193,10 +192,10 @@ a:hover, a:active {
min-width:70%; min-width:70%;
} }
.form.invisible tr:nth-child(odd) { .invisible tbody > tr:nth-child(odd) {
background: inherit; background: inherit;
} }
.form.invisible tr, .form.invisible td, .form.invisible th { .invisible tr, .invisible td, .invisible th {
border:0; border:0;
} }
@ -222,10 +221,6 @@ a:hover, a:active {
line-height:1em; line-height:1em;
} }
/*.message .close:after {
content: '☐';
}*/
.message:hover .close:after { .message:hover .close:after {
content: '☒'; content: '☒';
} }
@ -423,7 +418,7 @@ a:hover, a:active {
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
Page-specific styles Search page styles
------------------------------------------------------------------------------*/ ------------------------------------------------------------------------------*/
.media.search > .name { .media.search > .name {
background-color:#555; background-color:#555;
@ -467,5 +462,45 @@ a:hover, a:active {
vertical-align:middle; vertical-align:middle;
} }
/* ----------------------------------------------------------------------------
Details page styles
-----------------------------------------------------------------------------*/
.details {
margin: 1.5rem auto 0 auto;
max-width:93rem;
padding:1rem;
font-size:inherit;
}
.details .cover {
max-width: 300px;
max-height: 435px;
}
.details h2 {
margin-top: 0;
}
.details .flex > div {
margin: 1rem;
}
.details table {
max-width:300px;
}
.details td {
padding:0 1.5rem;
}
.details p {
text-align:justify;
}
.details td:nth-child(odd) {
width:1%;
white-space:nowrap;
text-align:right;
}
.details td:nth-child(even) {
text-align:left;
}

View File

@ -573,7 +573,6 @@ nav ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
padding-top: 1.6rem;
text-align: center; text-align: center;
} }

View File

@ -390,7 +390,6 @@ nav ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
padding-top: 1.6rem;
text-align: center; } text-align: center; }
nav ul li { nav ul li {
display: inline; } display: inline; }

View File

@ -4,7 +4,7 @@ suite('AnimeClient methods exist', function () {
test("AnimeClient exists", function () { test("AnimeClient exists", function () {
expect(AnimeClient).to.be.ok; expect(AnimeClient).to.be.ok;
}); });
['$', 'scrollToTop', 'showMessage', 'closestParent', 'url', 'throttle', 'on', 'ajax', 'get'].forEach((method) => { ['$', 'scrollToTop', 'showMessage', 'show', 'hide', 'closestParent', 'url', 'throttle', 'on', 'ajax', 'get'].forEach((method) => {
test("AnimeClient." + method + ' exists.', function () { test("AnimeClient." + method + ' exists.', function () {
expect(AnimeClient[method]).to.be.ok; expect(AnimeClient[method]).to.be.ok;
}); });

View File

@ -24,6 +24,7 @@ class HttpView extends BaseView {
/** /**
* Do a redirect * Do a redirect
* *
* @codeCoverageIgnore
* @param string $url * @param string $url
* @param int $code * @param int $code
* @return void * @return void
@ -35,13 +36,11 @@ class HttpView extends BaseView {
$this->setStatusCode($code); $this->setStatusCode($code);
$this->response->withHeader('Location', $url); $this->response->withHeader('Location', $url);
// @codeCoverageIgnore start
if (PHP_SAPI !== 'cli') if (PHP_SAPI !== 'cli')
{ {
header("HTTP/1.1 ${code} ${message}"); header("HTTP/1.1 ${code} ${message}");
header("Location: {$url}"); header("Location: {$url}");
} }
// @codeCoverageIgnore end
$this->hasRendered = TRUE; $this->hasRendered = TRUE;
ob_end_clean(); ob_end_clean();
@ -55,7 +54,7 @@ class HttpView extends BaseView {
*/ */
public function setStatusCode($code) public function setStatusCode($code)
{ {
$this->response->withStatus($code) $this->response = $this->response->withStatus($code)
->withProtocolVersion(1.1); ->withProtocolVersion(1.1);
return $this; return $this;
} }

View File

@ -14,14 +14,6 @@ class HttpViewTest extends AnimeClient_TestCase {
$this->friend = new Friend($this->view); $this->friend = new Friend($this->view);
} }
public function testRedirect()
{
$this->markTestSkipped();
$this->friend->redirect('/foo', 303);
$this->assertEquals(['/foo'], $this->friend->response->getHeader('Location'));
$this->assertEquals(303, $this->friend->response->getStatusCode());
}
public function testGetOutput() public function testGetOutput()
{ {
$this->friend->setOutput('foo'); $this->friend->setOutput('foo');
@ -48,8 +40,7 @@ $this->markTestSkipped();
public function testSetStatusCode() public function testSetStatusCode()
{ {
$this->markTestSkipped(); $view = $this->view->setStatusCode(404);
$this->view->setStatusCode(404); $this->assertEquals(404, $view->response->getStatusCode());
$this->assertEquals(404, $this->friend->response->getStatusCode());
} }
} }