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;
}
#sidebar nav {
#around {
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;
}
#sidebar nav .right {
#around .right {
float: right;
}
#sidebar nav a.disabled {
#around a.disabled {
color: silver;
}
#sidebar nav a.disabled i[class*='icon-'] {
#around a.disabled i[class*='icon-'] {
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
$.fn.hasAttr = function(name)
{
@ -56,6 +90,7 @@ $(function()
{
$('body').bind('dom-update', function()
{
//event confirmations
function confirmEvent(e)
{
if (!confirm($(this).attr('data-confirm-text')))
@ -68,12 +103,15 @@ $(function()
$('form[data-confirm-text]').submit(confirmEvent);
$('a[data-confirm-text]').click(confirmEvent);
//simple action buttons
$('a.simple-action').click(function(e)
{
if(e.isPropagationStopped())
return;
e.preventDefault();
rememberLastSearchQuery();
var aDom = $(this);
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)
{
e.preventDefault();
rememberLastSearchQuery();
var formDom = $(this);
if (formDom.hasClass('inactive'))
@ -102,6 +103,7 @@ $(function()
$('form.add-comment').submit(function(e)
{
e.preventDefault();
rememberLastSearchQuery();
var formDom = $(this);
if (formDom.hasClass('inactive'))
@ -166,7 +168,7 @@ $(function()
$.ajax(ajaxData);
});
Mousetrap.bind('a', function() { var url = $('#sidebar .left a').attr('href'); if (typeof url !== 'undefined') 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('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 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');
});

View file

@ -66,15 +66,14 @@ class PostController
*/
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-list.css';
$this->context->stylesheets []= 'tabs.css';
$this->context->stylesheets []= 'paginator.css';
$this->context->viewName = 'post-list-wrapper';
$this->context->scripts []= 'post-list.js';
if ($this->context->user->hasEnabledEndlessScrolling())
$this->context->scripts []= 'paginator-endless.js';
if ($source == 'mass-tag')
$this->context->scripts []= 'mass-tag.js';
$this->context->source = $source;
$this->context->additionalInfo = $additionalInfo;
@ -83,6 +82,7 @@ class PostController
if ($formQuery !== null)
{
$this->context->transport->searchQuery = $formQuery;
$this->context->transport->lastSearchQuery = $formQuery;
if (strpos($formQuery, '/') !== false)
throw new SimpleException('Search query contains invalid characters');
$url = \Chibi\UrlHelper::route('post', 'list', ['source' => $source, 'additionalInfo' => $additionalInfo, 'query' => $formQuery]);
@ -95,6 +95,7 @@ class PostController
$postsPerPage = intval($this->config->browsing->postsPerPage);
$this->context->subTitle = 'posts';
$this->context->transport->searchQuery = $query;
$this->context->transport->lastSearchQuery = $query;
PrivilegesHelper::confirmWithException(Privilege::ListPosts);
if ($source == 'mass-tag')
{
@ -444,38 +445,19 @@ class PostController
'comment',
'ownComment.commenter' => 'user']);
$this->context->transport->lastSearchQuery = InputHelper::get('last-search-query');
if ($post->hidden)
PrivilegesHelper::confirmWithException(Privilege::ViewPost, 'hidden');
PrivilegesHelper::confirmWithException(Privilege::ViewPost);
PrivilegesHelper::confirmWithException(Privilege::ViewPost, PostSafety::toString($post->safety));
$buildNextPostQuery = function($dbQuery, $id, $next)
{
$dbQuery->select('id')
->from('post')
->where($next ? 'id > ?' : 'id < ?')
->put($id);
$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');
Model_Post_QueryBuilder::enableTokenLimit(false);
$prevPostQuery = $this->context->transport->lastSearchQuery . ' prev:' . $id;
$nextPostQuery = $this->context->transport->lastSearchQuery . ' next:' . $id;
$prevPost = current(Model_Post::getEntities($prevPostQuery, 1, 1));
$nextPost = current(Model_Post::getEntities($nextPostQuery, 1, 1));
Model_Post_QueryBuilder::enableTokenLimit(true);
$favorite = $this->context->user->hasFavorited($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-small.css';
$this->context->stylesheets []= 'paginator.css';
$this->context->scripts []= 'post-list.js';
if ($this->context->user->hasEnabledEndlessScrolling())
$this->context->scripts []= 'paginator-endless.js';
@ -442,6 +443,7 @@ class UserController
$posts = Model_Post::getEntities($query, $postsPerPage, $page);
$this->context->transport->tab = $tab;
$this->context->transport->lastSearchQuery = $query;
$this->context->transport->paginator = new StdClass;
$this->context->transport->paginator->page = $page;
$this->context->transport->paginator->pageCount = $pageCount;

View file

@ -268,11 +268,44 @@ class Model_Post_QueryBuilder implements AbstractQueryBuilder
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)

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') ?>"/>
</form>
</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>
<div class="clear"></div>
</div>

View file

@ -1,5 +1,5 @@
<div id="sidebar">
<nav>
<nav id="around">
<div class="left">
<?php if ($this->context->transport->nextPostId): ?>
<a href="<?php echo \Chibi\UrlHelper::route('post', 'view', ['id' => $this->context->transport->nextPostId]) ?>">
@ -23,6 +23,13 @@
</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>
<div class="unit tags">