The new interface is completely in Ajax. Feel a lot faster. re #73

Uses pushState / popState to keep browser history correct and allow using back in the browser.
This commit is contained in:
Sébastien Lucas 2013-06-15 08:03:22 +02:00
parent c7c6524cce
commit a509e3389d
5 changed files with 186 additions and 197 deletions

View file

@ -218,7 +218,7 @@ class LinkNavigation extends Link
parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle); parent::__construct ($phref, Link::OPDS_NAVIGATION_TYPE, $prel, $ptitle);
if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB)); if (!is_null (GetUrlParam (DB))) $this->href = addURLParameter ($this->href, DB, GetUrlParam (DB));
if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href; if (!preg_match ("#^\?(.*)#", $this->href) && !empty ($this->href)) $this->href = "?" . $this->href;
if (preg_match ("/bookdetail.php/", $_SERVER["SCRIPT_NAME"])) { if (preg_match ("/(bookdetail|getJSON).php/", $_SERVER["SCRIPT_NAME"])) {
$this->href = "index.php" . $this->href; $this->href = "index.php" . $this->href;
} else { } else {
$this->href = $_SERVER["SCRIPT_NAME"] . $this->href; $this->href = $_SERVER["SCRIPT_NAME"] . $this->href;
@ -266,6 +266,16 @@ class Entry
return date (DATE_ATOM, self::$updated); return date (DATE_ATOM, self::$updated);
} }
public function getContentArray () {
$navlink = "#";
foreach ($this->linkArray as $link) {
if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; }
$navlink = $link->hrefXhtml ();
}
return array ( "title" => $this->title, "content" => $this->content, "navlink" => $navlink );
}
public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray) { public function __construct($ptitle, $pid, $pcontent, $pcontentType, $plinkArray) {
global $config; global $config;
$this->title = $ptitle; $this->title = $ptitle;
@ -299,6 +309,14 @@ class EntryBook extends Entry
$this->localUpdated = $pbook->timestamp; $this->localUpdated = $pbook->timestamp;
} }
public function getContentArray () {
$entry = array ( "title" => $this->title);
$entry ["coverurl"] = $this->getCover ();
$entry ["thumbnailurl"] = $this->getCoverThumbnail ();
$entry ["book"] = $this->book->getContentArray ();
return $entry;
}
public function getCoverThumbnail () { public function getCoverThumbnail () {
foreach ($this->linkArray as $link) { foreach ($this->linkArray as $link) {
if ($link->rel == Link::OPDS_THUMBNAIL_TYPE) if ($link->rel == Link::OPDS_THUMBNAIL_TYPE)
@ -417,6 +435,61 @@ class Page
} }
} }
public function getContentArray ()
{
global $config;
$database = GetUrlParam (DB);
$page = getURLParam ("page", Base::PAGE_INDEX);
$out = array ( "title" => $this->title, "version" => VERSION);
$entries = array ();
foreach ($this->entryArray as $entry) {
array_push ($entries, $entry->getContentArray ());
}
$out ["databaseId"] = GetUrlParam (DB, "");
$out ["databaseName"] = Base::getDbName ();
$out ["page"] = $page;
$out ["entries"] = $entries;
$out ["isPaginated"] = 0;
if ($this->isPaginated ()) {
$prevLink = $this->getPrevLink ();
$nextLink = $this->getNextLink ();
$out ["isPaginated"] = 1;
$out ["prevLink"] = "";
if (!is_null ($prevLink)) {
$out ["prevLink"] = $prevLink->hrefXhtml ();
}
$out ["nextLink"] = "";
if (!is_null ($nextLink)) {
$out ["nextLink"] = $nextLink->hrefXhtml ();
}
$out ["maxPage"] = $this->getMaxPage ();
$out ["currentPage"] = $this->n;
}
$out ["i18n"] = array ("coverAlt" => localize("i18n.coversection"),
"authorsTitle" => localize("authors.title"),
"tagsTitle" => localize("tags.title"),
"seriesTitle" => localize("series.title"),
"customizeTitle" => localize ("customize.title"),
"aboutTitle" => localize ("about.title"),
"previousAlt" => localize ("paging.previous.alternate"),
"nextAlt" => localize ("paging.next.alternate"),
"searchAlt" => localize ("search.alternate"),
"homeAlt" => localize ("home.alternate"));
$out ["containsBook"] = 0;
if ($this->containsBook ()) {
$out ["containsBook"] = 1;
}
$out["abouturl"] = "about.xml";
if (getCurrentOption ('use_fancyapps') == 0) {
$out["abouturl"] = "index.php" . str_replace ("&", "&", addURLParameter ("?page=16", DB, $database));
}
$out ["homeurl"] = "index.php";
if ($page != Base::PAGE_INDEX && !is_null ($database)) $out ["homeurl"] = $out ["homeurl"] . "?" . addURLParameter ("", DB, $database);
return $out;
}
public function isPaginated () public function isPaginated ()
{ {
global $config; global $config;

View file

@ -102,6 +102,31 @@ class Book extends Base {
return "?page=".parent::PAGE_BOOK_DETAIL."&id=$this->id"; return "?page=".parent::PAGE_BOOK_DETAIL."&id=$this->id";
} }
public function getContentArray () {
global $config;
$i = 0;
$preferedData = array ();
foreach ($config['cops_prefered_format'] as $format)
{
if ($i == 2) { break; }
if ($data = $this->getDataFormat ($format)) {
$i++;
array_push ($preferedData, array ("url" => $data->getHtmlLink (), "name" => $format));
}
}
$serie = $this->getSerie ();
if (is_null ($serie)) $serie = "";
return array ("hasCover" => $this->hasCover,
"preferedData" => $preferedData,
"detailUrl" => $this->getDetailUrl (),
"rating" => $this->getRating (),
"pubDate" => $this->getPubDate (),
"authorsName" => $this->getAuthorsName (),
"tagsName" => $this->getTagsName (),
"seriesName" => $serie);
}
public function getDetailUrl ($permalink = false) { public function getDetailUrl ($permalink = false) {
global $config; global $config;
$urlParam = $this->getUri (); $urlParam = $this->getUri ();

31
getJSON.php Normal file
View file

@ -0,0 +1,31 @@
<?php
/**
* COPS (Calibre OPDS PHP Server) HTML main script
*
* @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author Sébastien Lucas <sebastien@slucas.fr>
*
*/
require_once ("config.php");
require_once ("base.php");
require_once ("author.php");
require_once ("serie.php");
require_once ("tag.php");
require_once ("language.php");
require_once ("customcolumn.php");
require_once ("book.php");
header ("Content-Type:application/json;charset=utf-8");
$page = getURLParam ("page", Base::PAGE_INDEX);
$query = getURLParam ("query");
$qid = getURLParam ("id");
$n = getURLParam ("n", "1");
$database = GetUrlParam (DB);
$currentPage = Page::getPage ($page, $qid, $query, $n);
$currentPage->InitializeContent ();
echo json_encode ($currentPage->getContentArray ());
?>

240
index.php
View file

@ -32,9 +32,6 @@
$n = getURLParam ("n", "1"); $n = getURLParam ("n", "1");
$database = GetUrlParam (DB); $database = GetUrlParam (DB);
$currentPage = Page::getPage ($page, $qid, $query, $n);
$currentPage->InitializeContent ();
/* Test to see if pages are opened on an Eink screen /* Test to see if pages are opened on an Eink screen
* test Kindle, Kobo Touch and Sony PRS-T1 Ereader. * test Kindle, Kobo Touch and Sony PRS-T1 Ereader.
* HTTP_USER_AGENT = "Mozilla/5.0 (Linux; U; en-us; EBRD1101; EXT) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1" * HTTP_USER_AGENT = "Mozilla/5.0 (Linux; U; en-us; EBRD1101; EXT) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"
@ -52,7 +49,7 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><?php echo htmlspecialchars ($currentPage->title) ?></title> <title>COPS</title>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery-1.9.1.min.js") ?>"></script> <script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery-1.9.1.min.js") ?>"></script>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.cookies.js") ?>"></script> <script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.cookies.js") ?>"></script>
<?php if (getCurrentOption ('use_fancyapps') == 1) { ?> <?php if (getCurrentOption ('use_fancyapps') == 1) { ?>
@ -60,12 +57,44 @@
<link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("resources/fancybox/jquery.fancybox.css") ?>" media="screen" /> <link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("resources/fancybox/jquery.fancybox.css") ?>" media="screen" />
<?php } ?> <?php } ?>
<script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.sortElements.js") ?>"></script> <script type="text/javascript" src="<?php echo getUrlWithVersion("js/jquery.sortElements.js") ?>"></script>
<script type="text/javascript" src="<?php echo getUrlWithVersion("resources/doT/doT.min.js") ?>"></script>
<script type="text/javascript" src="<?php echo getUrlWithVersion("util.js") ?>"></script>
<link rel="related" href="<?php echo $config['cops_full_url'] ?>feed.php" type="application/atom+xml;profile=opds-catalog" title="<?php echo $config['cops_title_default']; ?>" /> <link rel="related" href="<?php echo $config['cops_full_url'] ?>feed.php" type="application/atom+xml;profile=opds-catalog" title="<?php echo $config['cops_title_default']; ?>" />
<link rel="icon" type="image/vnd.microsoft.icon" href="<?php echo $currentPage->favicon ?>" /> <link rel="icon" type="image/vnd.microsoft.icon" href="favicon.ico" />
<link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Open+Sans:400,300italic,800,300,400italic,600,600italic,700,700italic,800italic' /> <link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Open+Sans:400,300italic,800,300,400italic,600,600italic,700,700italic,800italic' />
<link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion(getCurrentCss ()) ?>" media="screen" /> <link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion(getCurrentCss ()) ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("resources/normalize/normalize.css") ?>" /> <link rel="stylesheet" type="text/css" href="<?php echo getUrlWithVersion("resources/normalize/normalize.css") ?>" />
<script type="text/javascript"> <script type="text/javascript">
var template, result;
function ajaxifyLinks () {
if (history.pushState) {
$("a[href^='index']").click (function (event) {
event.preventDefault();
var url = $(this).attr('href');
jsonurl = url.replace ("index", "getJSON");
$.getJSON(jsonurl, function(data) {
history.pushState(data, "", url);
result = template (data);
document.title = data.title;
$(".container").html (result);
ajaxifyLinks ();
});
});
}
}
window.onpopstate = function(event) {
//alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
result = template (event.state);
document.title = event.state.title;
$(".container").html (result);
ajaxifyLinks ();
};
$(document).ready(function() { $(document).ready(function() {
// Handler for .ready() called. // Handler for .ready() called.
@ -114,202 +143,25 @@
} }
}); });
$.get('templates/default/frontpage.html', function(data){
template = doT.template(data);
$.getJSON('<?php echo "getJSON.php?" . str_replace ("&", "&amp;", $_SERVER["QUERY_STRING"]); ?>', function(data) {
result = template (data);
document.title = data.title;
$(".container").html (result);
ajaxifyLinks ();
});
});
}); });
<?php
if ($currentPage->isPaginated ()) {
$prevLink = $currentPage->getPrevLink ();
$nextLink = $currentPage->getNextLink ();
?>
$(document).keydown(function(e){
<?php
if (!is_null ($prevLink)) {
echo "if (e.keyCode == 37) {\$(location).attr('href','" . $prevLink->hrefXhtml () . "');}";
}
if (!is_null ($nextLink)) {
echo "if (e.keyCode == 39) {\$(location).attr('href','" . $nextLink->hrefXhtml () . "');}";
}
?>
});
<?php
}
?>
</script> </script>
</head> </head>
<body> <body>
<div class="container">
<header>
<a class="headleft" href="<?php echo $_SERVER["SCRIPT_NAME"]; if ($page != Base::PAGE_INDEX && !is_null ($database)) echo "?" . addURLParameter ("", DB, $database); ?>">
<img src="<?php echo getUrlWithVersion("images/home.png") ?>" alt="<?php echo localize ("home.alternate") ?>" />
</a>
<img class="headright" id="searchImage" src="<?php echo getUrlWithVersion("images/setting64.png") ?>" alt="Settings and menu" />
<div class="headcenter">
<h1><?php echo htmlspecialchars ($currentPage->title) ?></h1>
</div>
<div id="tool" <?php if ($withToolbar) echo 'style="display: none"' ?>>
<div style="float: left; width: 60%">
<form action="index.php" method="get">
<div style="float: right">
<input type="image" src="images/search32.png" alt="<?php echo localize ("search.alternate") ?>" />
</div>
<div class="stop">
<input type="hidden" name="current" value="<?php echo $page ?>" />
<input type="hidden" name="page" value="9" />
<?php if (!is_null ($database)) { ?>
<input type="hidden" name="<?php echo DB ?>" value="<?php echo $database ?>" />
<?php } ?>
<input type="search" name="query" />
</div>
</form>
</div>
<?php if ($currentPage->containsBook ()) { ?>
<div style="float: right; width: 35%">
<div style="float: right">
<img id="sort" src="images/sort32.png" alt="<?php echo localize ("sort.alternate") ?>" />
</div>
<div class="stop">
<select id="sortchoice">
<option value="st"><?php echo localize("bookword.title") ?></option>
<option value="sa"><?php echo localize("authors.title") ?></option>
<option value="ss"><?php echo localize("series.title") ?></option>
<option value="sp"><?php echo localize("content.published") ?></option>
</select>
<select id="sortorder">
<option value="asc"><?php echo localize("search.sortorder.asc") ?></option>
<option value="desc"><?php echo localize("search.sortorder.desc") ?></option>
</select>
</div>
</div>
<?php } ?>
</div>
</header>
<div id="content" style="display: none;"></div> <div id="content" style="display: none;"></div>
<section> <div class="container">
<?php
if ($page == Base::PAGE_BOOK_DETAIL) {
include ("bookdetail.php");
} else if ($page == Base::PAGE_ABOUT) {
readfile ("about.xml");
}
foreach ($currentPage->entryArray as $entry) {
if (get_class ($entry) != "EntryBook") {
?>
<article>
<div class="frontpage">
<?php foreach ($entry->linkArray as $link) { if ($link->type != Link::OPDS_NAVIGATION_TYPE) { continue; } ?> <a href="<?php echo $link->hrefXhtml () ?>">
<h2><?php echo htmlspecialchars ($entry->title) ?></h2>
<?php } ?>
<h4><?php echo htmlspecialchars ($entry->content) ?></h4>
</a>
</div>
</article>
<?php
}
else
{
?>
<article class="books">
<span class="cover">
<?php
if ($entry->book->hasCover) {
?>
<a data-fancybox-group="group" class="fancycover" href="<?php echo $entry->getCover () ?>"><img src="<?php echo $entry->getCoverThumbnail () ?>" alt="<?php echo localize("i18n.coversection") ?>" /></a>
<?php
}
?>
</span>
<h2 class="download">
<?php
$i = 0;
foreach ($config['cops_prefered_format'] as $format)
{
if ($i == 2) { break; }
if ($data = $entry->book->getDataFormat ($format)) {
$i++;
?>
<a href="<?php echo $data->getHtmlLink () ?>"><?php echo $format ?></a><br />
<?php
}
}
?>
</h2>
<a class="fancydetail" href="<?php echo $entry->book->getDetailUrl () ?>">
<div class="fullclickpopup">
<h2><span class="st"><?php echo htmlspecialchars ($entry->title) ?></span>
<?php
if ($entry->book->getPubDate() != "")
{
?>
<span class="sp">(<?php echo $entry->book->getPubDate() ?>)</span>
<?php
}
?>
<?php
if (!is_null ($entry->book->rating)) {
?>
<span class="sr"><?php echo $entry->book->getRating () ?></span>
<?php
}
?>
</h2>
<h4><?php echo localize("authors.title") . " : " ?></h4><span class="sa"><?php echo htmlspecialchars ($entry->book->getAuthorsName ()) ?></span><br />
<?php
$tags = $entry->book->getTagsName ();
if (!empty ($tags)) {
?>
<h4><?php echo localize("tags.title") . " : </h4>" . htmlspecialchars ($tags) ?><br />
<?php
}
?>
<?php
$serie = $entry->book->getSerie ();
if (!is_null ($serie)) {
?>
<h4><?php echo localize("series.title") . " : " ?></h4><span class="ss"><?php echo htmlspecialchars ($serie->name) . " (" . $entry->book->seriesIndex . ")" ?></span><br />
<?php
}
?>
</div></a>
</article>
<?php
}
}
?>
</section>
<footer>
<div class="footleft">
<a href="customize.php"><img src="<?php echo getUrlWithVersion("images/theme.png") ?>" alt="<?php echo localize ("customize.title") ?>" /></a>
</div>
<div class="footright">
<a class="fancyabout" href="<?php if (getCurrentOption ('use_fancyapps') == 1) { echo "about.xml"; } else { echo $_SERVER["SCRIPT_NAME"] . str_replace ("&", "&amp;", addURLParameter ("?page=16", DB, $database)); } ?>"><img src="<?php echo getUrlWithVersion("images/info.png") ?>" alt="<?php echo localize ("about.title") ?>" /></a>
</div>
<?php
if ($currentPage->isPaginated ()) {
?>
<div class="footcenter">
<?php
if (!is_null ($prevLink)) {
?>
<a href="<?php echo $prevLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/previous.png") ?>" alt="<?php echo localize ("paging.previous.alternate") ?>" /></a>
<?php
}
?>
<p><?php echo " " . $currentPage->n . " / " . $currentPage->getMaxPage () . " " ?></p>
<?php
if (!is_null ($nextLink)) {
?>
<a href="<?php echo $nextLink->hrefXhtml () ?>" ><img src="<?php echo getUrlWithVersion("images/next.png") ?>" alt="<?php echo localize ("paging.next.alternate") ?>" /></a>
<?php
}
?>
</div>
<?php
}
?>
</footer>
</div> </div>
</body> </body>
</html> </html>

8
util.js Normal file
View file

@ -0,0 +1,8 @@
function htmlEscape(str) {
return String(str)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}