Next/prev links are bound to latest search query

This commit is contained in:
Marcin Kurczewski 2013-11-24 21:50:46 +01:00
parent d461a88001
commit 20022ea4ab
9 changed files with 121 additions and 40 deletions

View file

@ -31,19 +31,26 @@ embed {
color: silver; color: silver;
} }
#sidebar nav { #around {
margin-bottom: 2em; margin-bottom: 2em;
} }
#sidebar nav .left { #around .text {
font-size: 90%;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-top: 0.75em;
}
#around .left {
float: left; float: left;
} }
#sidebar nav .right { #around .right {
float: right; float: right;
} }
#sidebar nav a.disabled { #around a.disabled {
color: silver; color: silver;
} }
#sidebar nav a.disabled i[class*='icon-'] { #around a.disabled i[class*='icon-'] {
background-color: silver; background-color: silver;
} }

View file

@ -1,3 +1,37 @@
function setCookie(name, value, exdays)
{
var exdate = new Date();
exdate.setDate(exdate.getDate() + exdays);
value = escape(value) + '; path=/' + ((exdays == null) ? '' : '; expires=' + exdate.toUTCString());
document.cookie = name + '=' + value;
}
function getCookie(name)
{
console.log(document.cookie);
var value = document.cookie;
var start = value.indexOf(' ' + name + '=');
if (start == -1)
start = value.indexOf(name + '=');
if (start == -1)
return null;
start = value.indexOf('=', start) + 1;
var end = value.indexOf(";", start);
if (end == -1)
end = value.length;
return unescape(value.substring(start, end));
}
function rememberLastSearchQuery()
{
//lastSearchQuery variable is obtained from layout
setCookie('last-search-query', lastSearchQuery);
}
//core functionalities, prototypes //core functionalities, prototypes
$.fn.hasAttr = function(name) $.fn.hasAttr = function(name)
{ {
@ -56,6 +90,7 @@ $(function()
{ {
$('body').bind('dom-update', function() $('body').bind('dom-update', function()
{ {
//event confirmations
function confirmEvent(e) function confirmEvent(e)
{ {
if (!confirm($(this).attr('data-confirm-text'))) if (!confirm($(this).attr('data-confirm-text')))
@ -68,12 +103,15 @@ $(function()
$('form[data-confirm-text]').submit(confirmEvent); $('form[data-confirm-text]').submit(confirmEvent);
$('a[data-confirm-text]').click(confirmEvent); $('a[data-confirm-text]').click(confirmEvent);
//simple action buttons
$('a.simple-action').click(function(e) $('a.simple-action').click(function(e)
{ {
if(e.isPropagationStopped()) if(e.isPropagationStopped())
return; return;
e.preventDefault(); e.preventDefault();
rememberLastSearchQuery();
var aDom = $(this); var aDom = $(this);
if (aDom.hasClass('inactive')) if (aDom.hasClass('inactive'))
@ -116,6 +154,10 @@ $(function()
}); });
}); });
}); });
//try to remember last search query
window.onbeforeunload = rememberLastSearchQuery;
}); });

View file

@ -57,6 +57,7 @@ $(function()
$('form.edit-post').submit(function(e) $('form.edit-post').submit(function(e)
{ {
e.preventDefault(); e.preventDefault();
rememberLastSearchQuery();
var formDom = $(this); var formDom = $(this);
if (formDom.hasClass('inactive')) if (formDom.hasClass('inactive'))
@ -102,6 +103,7 @@ $(function()
$('form.add-comment').submit(function(e) $('form.add-comment').submit(function(e)
{ {
e.preventDefault(); e.preventDefault();
rememberLastSearchQuery();
var formDom = $(this); var formDom = $(this);
if (formDom.hasClass('inactive')) if (formDom.hasClass('inactive'))
@ -166,7 +168,7 @@ $(function()
$.ajax(ajaxData); $.ajax(ajaxData);
}); });
Mousetrap.bind('a', function() { var url = $('#sidebar .left a').attr('href'); if (typeof url !== 'undefined') window.location.href = url; }, 'keyup'); Mousetrap.bind('a', function() { var a = $('#sidebar .left a'); var url = a.attr('href'); if (typeof url !== 'undefined') { a.click(); window.location.href = url; } }, 'keyup');
Mousetrap.bind('d', function() { var url = $('#sidebar .right a').attr('href'); if (typeof url !== 'undefined') window.location.href = url; }, 'keyup'); Mousetrap.bind('d', function() { var a = $('#sidebar .right a'); var url = a.attr('href'); if (typeof url !== 'undefined') { a.click(); window.location.href = url; } }, 'keyup');
Mousetrap.bind('e', function() { $('li.edit a').trigger('click'); return false; }, 'keyup'); Mousetrap.bind('e', function() { $('li.edit a').trigger('click'); return false; }, 'keyup');
}); });

View file

@ -66,15 +66,14 @@ class PostController
*/ */
public function listAction($query = null, $page = 1, $source = 'posts', $additionalInfo = null) public function listAction($query = null, $page = 1, $source = 'posts', $additionalInfo = null)
{ {
$this->context->viewName = 'post-list-wrapper';
$this->context->stylesheets []= 'post-small.css'; $this->context->stylesheets []= 'post-small.css';
$this->context->stylesheets []= 'post-list.css'; $this->context->stylesheets []= 'post-list.css';
$this->context->stylesheets []= 'tabs.css'; $this->context->stylesheets []= 'tabs.css';
$this->context->stylesheets []= 'paginator.css'; $this->context->stylesheets []= 'paginator.css';
$this->context->viewName = 'post-list-wrapper'; $this->context->scripts []= 'post-list.js';
if ($this->context->user->hasEnabledEndlessScrolling()) if ($this->context->user->hasEnabledEndlessScrolling())
$this->context->scripts []= 'paginator-endless.js'; $this->context->scripts []= 'paginator-endless.js';
if ($source == 'mass-tag')
$this->context->scripts []= 'mass-tag.js';
$this->context->source = $source; $this->context->source = $source;
$this->context->additionalInfo = $additionalInfo; $this->context->additionalInfo = $additionalInfo;
@ -83,6 +82,7 @@ class PostController
if ($formQuery !== null) if ($formQuery !== null)
{ {
$this->context->transport->searchQuery = $formQuery; $this->context->transport->searchQuery = $formQuery;
$this->context->transport->lastSearchQuery = $formQuery;
if (strpos($formQuery, '/') !== false) if (strpos($formQuery, '/') !== false)
throw new SimpleException('Search query contains invalid characters'); throw new SimpleException('Search query contains invalid characters');
$url = \Chibi\UrlHelper::route('post', 'list', ['source' => $source, 'additionalInfo' => $additionalInfo, 'query' => $formQuery]); $url = \Chibi\UrlHelper::route('post', 'list', ['source' => $source, 'additionalInfo' => $additionalInfo, 'query' => $formQuery]);
@ -95,6 +95,7 @@ class PostController
$postsPerPage = intval($this->config->browsing->postsPerPage); $postsPerPage = intval($this->config->browsing->postsPerPage);
$this->context->subTitle = 'posts'; $this->context->subTitle = 'posts';
$this->context->transport->searchQuery = $query; $this->context->transport->searchQuery = $query;
$this->context->transport->lastSearchQuery = $query;
PrivilegesHelper::confirmWithException(Privilege::ListPosts); PrivilegesHelper::confirmWithException(Privilege::ListPosts);
if ($source == 'mass-tag') if ($source == 'mass-tag')
{ {
@ -444,38 +445,19 @@ class PostController
'comment', 'comment',
'ownComment.commenter' => 'user']); 'ownComment.commenter' => 'user']);
$this->context->transport->lastSearchQuery = InputHelper::get('last-search-query');
if ($post->hidden) if ($post->hidden)
PrivilegesHelper::confirmWithException(Privilege::ViewPost, 'hidden'); PrivilegesHelper::confirmWithException(Privilege::ViewPost, 'hidden');
PrivilegesHelper::confirmWithException(Privilege::ViewPost); PrivilegesHelper::confirmWithException(Privilege::ViewPost);
PrivilegesHelper::confirmWithException(Privilege::ViewPost, PostSafety::toString($post->safety)); PrivilegesHelper::confirmWithException(Privilege::ViewPost, PostSafety::toString($post->safety));
$buildNextPostQuery = function($dbQuery, $id, $next) Model_Post_QueryBuilder::enableTokenLimit(false);
{ $prevPostQuery = $this->context->transport->lastSearchQuery . ' prev:' . $id;
$dbQuery->select('id') $nextPostQuery = $this->context->transport->lastSearchQuery . ' next:' . $id;
->from('post') $prevPost = current(Model_Post::getEntities($prevPostQuery, 1, 1));
->where($next ? 'id > ?' : 'id < ?') $nextPost = current(Model_Post::getEntities($nextPostQuery, 1, 1));
->put($id); Model_Post_QueryBuilder::enableTokenLimit(true);
$allowedSafety = array_filter(PostSafety::getAll(), function($safety)
{
return PrivilegesHelper::confirm(Privilege::ListPosts, PostSafety::toString($safety)) and
$this->context->user->hasEnabledSafety($safety);
});
$dbQuery->and('safety')->in('(' . R::genSlots($allowedSafety) . ')');
foreach ($allowedSafety as $s)
$dbQuery->put($s);
if (!PrivilegesHelper::confirm(Privilege::ListPosts, 'hidden'))
$dbQuery->andNot('hidden');
$dbQuery->orderBy($next ? 'id asc' : 'id desc')
->limit(1);
};
$prevPostQuery = R::$f->begin();
$buildNextPostQuery($prevPostQuery, $id, false);
$prevPost = $prevPostQuery->get('row');
$nextPostQuery = R::$f->begin();
$buildNextPostQuery($nextPostQuery, $id, true);
$nextPost = $nextPostQuery->get('row');
$favorite = $this->context->user->hasFavorited($post); $favorite = $this->context->user->hasFavorited($post);
$score = $this->context->user->getScore($post); $score = $this->context->user->getScore($post);

View file

@ -425,6 +425,7 @@ class UserController
$this->context->stylesheets []= 'post-list.css'; $this->context->stylesheets []= 'post-list.css';
$this->context->stylesheets []= 'post-small.css'; $this->context->stylesheets []= 'post-small.css';
$this->context->stylesheets []= 'paginator.css'; $this->context->stylesheets []= 'paginator.css';
$this->context->scripts []= 'post-list.js';
if ($this->context->user->hasEnabledEndlessScrolling()) if ($this->context->user->hasEnabledEndlessScrolling())
$this->context->scripts []= 'paginator-endless.js'; $this->context->scripts []= 'paginator-endless.js';
@ -442,6 +443,7 @@ class UserController
$posts = Model_Post::getEntities($query, $postsPerPage, $page); $posts = Model_Post::getEntities($query, $postsPerPage, $page);
$this->context->transport->tab = $tab; $this->context->transport->tab = $tab;
$this->context->transport->lastSearchQuery = $query;
$this->context->transport->paginator = new StdClass; $this->context->transport->paginator = new StdClass;
$this->context->transport->paginator->page = $page; $this->context->transport->paginator->page = $page;
$this->context->transport->paginator->pageCount = $pageCount; $this->context->transport->paginator->pageCount = $pageCount;

View file

@ -268,11 +268,44 @@ class Model_Post_QueryBuilder implements AbstractQueryBuilder
return self::filterTokenSubmit($context, $dbQuery, $val); return self::filterTokenSubmit($context, $dbQuery, $val);
} }
protected static function filterTokenUploaded($dbQuery, $val) protected static function filterTokenPrev($context, $dbQuery, $val)
{ {
return self::filterTokenSubmit($dbQuery, $val); self::__filterTokenPrevNext($context, $dbQuery, $val);
} }
protected static function filterTokenNext($context, $dbQuery, $val)
{
$context->orderDir *= -1;
self::__filterTokenPrevNext($context, $dbQuery, $val);
}
protected static function __filterTokenPrevNext($context, $dbQuery, $val)
{
$op1 = $context->orderDir == 1 ? '<' : '>';
$op2 = $context->orderDir != 1 ? '<' : '>';
$dbQuery
->open()
->open()
->addSql($context->orderColumn . ' ' . $op1 . ' ')
->open()
->select($context->orderColumn)
->from('post p2')
->where('p2.id = ?')->put(intval($val))
->close()
->and('id != ?')->put($val)
->close()
->or()
->open()
->addSql($context->orderColumn . ' = ')
->open()
->select($context->orderColumn)
->from('post p2')
->where('p2.id = ?')->put(intval($val))
->close()
->and('id ' . $op1 . ' ?')->put(intval($val))
->close()
->close();
}
protected static function parseOrderToken($context, $val) protected static function parseOrderToken($context, $val)

View file

@ -90,6 +90,12 @@
<input type="search" name="query" placeholder="Search&hellip;" value="<?php echo isset($this->context->transport->searchQuery) ? htmlspecialchars($this->context->transport->searchQuery) : '' ?>" data-autocomplete-url="<?php echo \Chibi\UrlHelper::route('tag', 'list') ?>"/> <input type="search" name="query" placeholder="Search&hellip;" value="<?php echo isset($this->context->transport->searchQuery) ? htmlspecialchars($this->context->transport->searchQuery) : '' ?>" data-autocomplete-url="<?php echo \Chibi\UrlHelper::route('tag', 'list') ?>"/>
</form> </form>
</li> </li>
<?php if (isset($this->context->transport->lastSearchQuery)): ?>
<script type="text/javascript">
var lastSearchQuery = <?php echo json_encode($this->context->transport->lastSearchQuery) ?>;
</script>
<?php endif ?>
</ul> </ul>
<div class="clear"></div> <div class="clear"></div>
</div> </div>

View file

@ -1,5 +1,5 @@
<div id="sidebar"> <div id="sidebar">
<nav> <nav id="around">
<div class="left"> <div class="left">
<?php if ($this->context->transport->nextPostId): ?> <?php if ($this->context->transport->nextPostId): ?>
<a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $this->context->transport->nextPostId]) ?>"> <a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $this->context->transport->nextPostId]) ?>">
@ -23,6 +23,13 @@
</div> </div>
<div class="clear"></div> <div class="clear"></div>
<?php if (!empty($this->context->transport->lastSearchQuery)): ?>
<div class="text">
Current&nbsp;search:<br/>
<a href="<?php echo \Chibi\UrlHelper::route('post', 'list', ['query' => $this->context->transport->lastSearchQuery]) ?>"><?php echo $this->context->transport->lastSearchQuery ?></a>
</div>
<?php endif ?>
</nav> </nav>
<div class="unit tags"> <div class="unit tags">