mirror of
https://github.com/rr-/szurubooru.git
synced 2025-07-17 08:26:24 +00:00
Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
78d0b07c5c | |||
a2b647432c | |||
87806bd015 | |||
73fc1830ff | |||
fba6a50251 | |||
394c06a1c5 | |||
f4d0230166 | |||
e48826dd72 | |||
4879ba94b0 | |||
f7837dc190 | |||
fdb7d57cf0 | |||
1ce0429280 | |||
d6f02fb724 | |||
2e3fdf98a0 | |||
c633118774 | |||
2c73f60824 | |||
ada131a7c5 | |||
b13c221a96 | |||
806aa0f197 | |||
95bcc89aa6 | |||
b86362b366 | |||
6470704f43 | |||
1081dfb718 | |||
aad6393f9a | |||
b9a50f9e14 | |||
2af8a941ff |
@ -32,6 +32,7 @@ usersPerPage=8
|
||||
postsPerPage=20
|
||||
logsPerPage=250
|
||||
tagsPerPage=100
|
||||
tagsRelated=15
|
||||
thumbWidth=150
|
||||
thumbHeight=150
|
||||
thumbStyle=outside
|
||||
@ -73,11 +74,11 @@ uploadPost=registered
|
||||
listPosts=anonymous
|
||||
listPosts.sketchy=registered
|
||||
listPosts.unsafe=registered
|
||||
listPosts.hidden=admin
|
||||
listPosts.hidden=moderator
|
||||
viewPost=anonymous
|
||||
viewPost.sketchy=registered
|
||||
viewPost.unsafe=registered
|
||||
viewPost.hidden=admin
|
||||
viewPost.hidden=moderator
|
||||
retrievePost=anonymous
|
||||
favoritePost=registered
|
||||
editPostSafety.own=registered
|
||||
|
85
data/help.md
85
data/help.md
@ -6,44 +6,67 @@ If you’re not a registered user, you will only see public (Safe) posts. Lo
|
||||
|
||||
You can use your keyboard to navigate around the site. There are a few shortcuts:
|
||||
|
||||
- focus search field: `[Q]`
|
||||
- scroll up/down: `[W]` and `[S]`
|
||||
- go to newer/older post or page: `[A]` and `[D]`
|
||||
- edit post: `[E]`
|
||||
- focus first post in post list: `[P]`
|
||||
Hotkey | Description
|
||||
--------------- | -----------
|
||||
`[Q]` | Focus search field
|
||||
`[W]` and `[S]` | Scroll up / down
|
||||
`[A]` and `[D]` | Go to newer/older post or page
|
||||
`[E]` | Edit post
|
||||
`[P]` | Focus first post in post list
|
||||
|
||||
# Search syntax
|
||||
|
||||
- contatining tag "Haruhi": [search]Haruhi[/search]
|
||||
- **not** contatining tag "Kyon": [search]-Kyon[/search]
|
||||
- uploaded by David: [search]submit:David[/search] (note no spaces)
|
||||
- favorited by David: [search]fav:David[/search]
|
||||
- favorited by at least four users: [search]favmin:4[/search]
|
||||
- commented by David: [search]comment:David[/search]
|
||||
- having at least three comments: [search]commentmin:3[/search]
|
||||
- having minimum score of 4: [search]scoremin:4[/search]
|
||||
- tagged with at least seven tags: [search]tagmin:7[/search]
|
||||
- exactly from the specified date: [search]date:2001[/search], [search]date:2012-09-29[/search] (yyyy-mm-dd format)
|
||||
- from the specified date onwards: [search]datemin:2001-01-01[/search]
|
||||
- up to the specified date: [search]datemax:2004-07[/search]
|
||||
- having specific ID: [search]id:1,2,3,8[/search]
|
||||
- having ID no less than specified value: [search]idmin:28[/search]
|
||||
- by content type: [search]type:img[/search], [search]type:swf[/search], [search]type:yt[/search] (images, flash files and YouTube videos, respectively)
|
||||
- scored up/down by currently logged in user: [search]special:likes[/search] and [search]special:dislikes[/search]
|
||||
Command | Description | Aliases |
|
||||
--------------------------------- | --------------------------------------------------------- | ----------------------------------------------- |
|
||||
[search]Haruhi[/search] | containing tag "Haruhi" | - |
|
||||
[search]-Kyon[/search] | **not** containing tag "Kyon" | - |
|
||||
[search]submit:David[/search] | uploaded by user David | `upload`, `uploads`, `uploaded`, `uploader` |
|
||||
[search]comment:David[/search] | commented by David | `comments`, `commenter`, `commented` |
|
||||
[search]fav:David[/search] | favorited by David | `favs`, `favd` |
|
||||
[search]favmin:4[/search] | favorited by at least four users | `fav_min` |
|
||||
[search]favmax:4[/search] | favorited by at most four users | `fax_max` |
|
||||
[search]commentmin:3[/search] | having at least three comments | `comment_min` |
|
||||
[search]commentmax:3[/search] | having at most three comments | `comment_max` |
|
||||
[search]scoremin:4[/search] | having minimum score of 4 | `score_min` |
|
||||
[search]scoremax:4[/search] | having maximum score of 4 | `score_max` |
|
||||
[search]tagmin:7[/search] | tagged with at least seven tags | `tag_min` |
|
||||
[search]tagmax:7[/search] | tagged with at most seven tags | `tax_max` |
|
||||
[search]date:2000[/search] | posted in year 2000 | - |
|
||||
[search]date:2000-01[/search] | posted in January, 2000 | - |
|
||||
[search]date:2000-01-01[/search] | posted on January 1st, 2000 | - |
|
||||
[search]datemin:...[/search] | posted on `...` or later (format like in `date:`) | `date_min` |
|
||||
[search]datemax:...[/search] | posted on `...` or earlier (format like in `date:`) | `date_max` |
|
||||
[search]id:1,2,3[/search] | having specific post ID | `ids` |
|
||||
[search]idmin:5[/search] | posts with ID greater than or equal to @5 | `id_min` |
|
||||
[search]idmax:5[/search] | posts with ID less than or equal to @5 | `id_max` |
|
||||
[search]type:img[/search] | only image posts | - |
|
||||
[search]type:swf[/search] | only Flash posts | - |
|
||||
[search]type:yt[/search] | only Youtube posts | `type:youtube` |
|
||||
[search]special:liked[/search] | posts liked by currently logged in user | `special:likes`, `special:like` |
|
||||
[search]special:disliked[/search] | posts disliked by currently logged in user | `special:dislikes`, `special:dislike` |
|
||||
[search]special:fav[/search] | posts added to favorites by currently logged in user | `special:favs`, `special:favd` |
|
||||
[search]special:hidden[/search] | hidden (soft-deleted) posts; moderators only | - |
|
||||
|
||||
You can combine tags and negate any of them for interesting results. [search]sea -favmin:8 type:swf submit:Pirate[/search] will show you **flash files** tagged as **sea**, that were **liked by seven people** at most, uploaded by user **Pirate**.
|
||||
|
||||
All of the above can be sorted using additional sorting tags:
|
||||
All of the above can be sorted using additional tag in form of `order:...`:
|
||||
|
||||
- as random as it can get: [search]order:random[/search]
|
||||
- newest to oldest: [search]order:date[/search] (pretty much default browse view)
|
||||
- oldest to newest: [search]-order:date[/search]
|
||||
- most commented first: [search]order:comments[/search]
|
||||
- loved by most: [search]order:favs[/search]
|
||||
- highest scored: [search]order:score[/search]
|
||||
- with most tags: [search]order:tags[/search]
|
||||
Command | Description | Aliases (`order:...`) |
|
||||
--------------------------------- | -------------------------------------------------------- | ------------------------------------------ |
|
||||
[search]order:random[/search] | as random as it can get | - |
|
||||
[search]order:id[/search] | highest to lowest post ID (default browse view) | - |
|
||||
[search]order:date[/search] | newest to oldest (pretty much same as above) | - |
|
||||
[search]-order:date[/search] | oldest to newest | - |
|
||||
[search]order:date,asc[/search] | oldest to newest (ascending order, default = descending) | - |
|
||||
[search]order:score[/search] | highest scored | - |
|
||||
[search]order:comments[/search] | most commented first | `comment`, `commentcount`, `comment_count` |
|
||||
[search]order:favs[/search] | loved by most | `fav`, `favcount`, `fav_count` |
|
||||
[search]order:tags[/search] | with most tags | `tag`, `tagcount`, `tag_count` |
|
||||
[search]order:commentdate[/search] | recently commented | `comment_date` |
|
||||
[search]order:favdate[/search] | recently added to favorites | `fav_date` |
|
||||
[search]order:filesize[/search] | largest files first | `file_size` |
|
||||
|
||||
As shown with [search]-order:date[/search], any of them can be reversed in the same way as negating other tags: by placing a dash before the tag. If there is a "min" tag, there’s also its "max" counterpart, e.g. [search]favmax:7[/search].
|
||||
As shown with [search]-order:date[/search], any of them can be reversed in the same way as negating other tags: by placing a dash before the tag.
|
||||
|
||||
# Registration
|
||||
|
||||
@ -62,3 +85,5 @@ Registered users can post comments. Comments support [Markdown syntax](http://da
|
||||
# Uploads
|
||||
|
||||
After registering and activating your account, you gain the power to upload files to the service for everyone else to see.
|
||||
|
||||
Remember to follow the [rules](/help/rules)!
|
||||
|
Submodule lib/chibi-sql updated: a5d7a03965...9b27422f78
@ -3,8 +3,8 @@
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
#content form label {
|
||||
width: 35%;
|
||||
#content form.register label {
|
||||
width: 12em;
|
||||
}
|
||||
|
||||
#content form p {
|
||||
|
@ -320,6 +320,28 @@ ul.tagit input {
|
||||
height: auto !important;
|
||||
margin: -4px 0 !important;
|
||||
}
|
||||
.related-tags {
|
||||
padding: 0.5em;
|
||||
background: rgba(255,255,255,0.7);
|
||||
border-radius: 3px;
|
||||
margin: 0.4em 0 0.2em 0;
|
||||
font-size: 95%;
|
||||
}
|
||||
.related-tags ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.related-tags p {
|
||||
float: left;
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
.related-tags li {
|
||||
display: inline-block;
|
||||
margin: 0 1em 0 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -408,6 +430,9 @@ ul.tagit input {
|
||||
.spoiler:hover {
|
||||
color: black;
|
||||
}
|
||||
.spoiler:not(:hover) a {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
@ -427,7 +452,6 @@ blockquote>*:last-child {
|
||||
}
|
||||
|
||||
.ui-state-default,
|
||||
.ui-widget-content .ui-state-default,
|
||||
.ui-widget-header .ui-state-default {
|
||||
.ui-state-default a {
|
||||
color: hsla(0,70%,45%,0.8) !important;
|
||||
}
|
||||
|
@ -1,7 +1,22 @@
|
||||
code {
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border: 3px solid #eee;
|
||||
}
|
||||
table th {
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
table td {
|
||||
padding: 0.1em 0.5em;
|
||||
}
|
||||
table th {
|
||||
text-align: left;
|
||||
background: #eee;
|
||||
}
|
||||
table td:first-child {
|
||||
white-space: pre;
|
||||
font-family: verdana;
|
||||
}
|
||||
|
@ -88,7 +88,10 @@ embed {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#sidebar .left a,
|
||||
#sidebar .right a {
|
||||
display: inline-block;
|
||||
}
|
||||
i.icon-prev {
|
||||
background-position: -12px -1px;
|
||||
margin-left: 8px;
|
||||
|
@ -17,17 +17,13 @@ nav.sort-styles li.active {
|
||||
.users-wrapper {
|
||||
text-align: center;
|
||||
}
|
||||
.users {
|
||||
column-width: 20em;
|
||||
-moz-column-width: 20em;
|
||||
-webkit-column-width: 20em;
|
||||
}
|
||||
|
||||
.user {
|
||||
text-align: initial;
|
||||
line-height: 1.5em;
|
||||
margin-bottom: 1em;
|
||||
margin-right: 1em;
|
||||
float: left;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
|
@ -199,15 +199,10 @@ function split(val)
|
||||
return val.split(/\s+/);
|
||||
}
|
||||
|
||||
function extractLast(term)
|
||||
{
|
||||
return split(term).pop();
|
||||
}
|
||||
|
||||
function retrieveTags(searchTerm, cb)
|
||||
{
|
||||
var options = { filter: searchTerm + ' order:popularity,desc' };
|
||||
$.getJSON('/tags?json', options, function(data)
|
||||
var options = { search: searchTerm };
|
||||
$.getJSON('/tags-autocomplete?json', options, function(data)
|
||||
{
|
||||
var tags = $.map(data.tags.slice(0, 15), function(tag)
|
||||
{
|
||||
@ -232,7 +227,8 @@ $(function()
|
||||
minLength: 1,
|
||||
source: function(request, response)
|
||||
{
|
||||
var term = extractLast(request.term);
|
||||
var terms = split(request.term);
|
||||
var term = terms.pop();
|
||||
if (term != '')
|
||||
retrieveTags(term, response);
|
||||
},
|
||||
@ -272,17 +268,61 @@ $(function()
|
||||
});
|
||||
});
|
||||
|
||||
function attachTagIt(element)
|
||||
function attachTagIt(target)
|
||||
{
|
||||
var tagItOptions =
|
||||
{
|
||||
caseSensitive: false,
|
||||
onTagClicked: function(e, ui)
|
||||
{
|
||||
var targetTagit = ui.tag.parents('.tagit');
|
||||
var context = target.tagit('assignedTags');
|
||||
options = { context: context, tag: ui.tagLabel };
|
||||
if (targetTagit.siblings('.related-tags:eq(0)').data('for') == options.tag)
|
||||
{
|
||||
targetTagit.siblings('.related-tags').slideUp(function()
|
||||
{
|
||||
$(this).remove();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$.getJSON('/tags-related?json', options, function(data)
|
||||
{
|
||||
var list = $('<ul>');
|
||||
$.each(data.tags, function(i, tag)
|
||||
{
|
||||
var link = $('<a>');
|
||||
link.attr('href', '/posts/' + tag.name + '/');
|
||||
link.text('#' + tag.name);
|
||||
link.click(function(e)
|
||||
{
|
||||
e.preventDefault();
|
||||
target.tagit('createTag', tag.name);
|
||||
});
|
||||
list.append(link.wrap('<li/>').parent());
|
||||
});
|
||||
targetTagit.siblings('.related-tags').slideUp(function()
|
||||
{
|
||||
$(this).remove();
|
||||
});
|
||||
var div = $('<div>');
|
||||
div.data('for', options.tag);
|
||||
div.addClass('related-tags');
|
||||
div.append('<p>Related tags:</p>');
|
||||
div.append(list);
|
||||
div.append('<div class="clear"></div>');
|
||||
div.insertAfter(targetTagit).hide().slideDown();
|
||||
});
|
||||
},
|
||||
|
||||
autocomplete:
|
||||
{
|
||||
source:
|
||||
function(request, response)
|
||||
{
|
||||
var tagit = this;
|
||||
//var context = tagit.element.tagit('assignedTags');
|
||||
retrieveTags(request.term.toLowerCase(), function(tags)
|
||||
{
|
||||
if (!tagit.options.allowDuplicates)
|
||||
@ -298,21 +338,65 @@ function attachTagIt(element)
|
||||
}
|
||||
};
|
||||
|
||||
tagItOptions.placeholderText = element.attr('placeholder');
|
||||
element.tagit(tagItOptions);
|
||||
tagItOptions.placeholderText = target.attr('placeholder');
|
||||
target.tagit(tagItOptions);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//prevent keybindings from executing when flash posts are focused
|
||||
var oldMousetrapBind = Mousetrap.bind;
|
||||
Mousetrap.bind = function(key, func, args)
|
||||
{
|
||||
oldMousetrapBind(key, function()
|
||||
{
|
||||
if ($(document.activeElement).parents('.post-type-flash').length > 0)
|
||||
return false;
|
||||
|
||||
func();
|
||||
}, args);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//hotkeys
|
||||
$(function()
|
||||
{
|
||||
Mousetrap.bind('q', function() { $('#top-nav input').focus(); return false; }, 'keyup');
|
||||
Mousetrap.bind('w', function() { $('body,html').animate({scrollTop: '-=150px'}, 200); });
|
||||
Mousetrap.bind('s', function() { $('body,html').animate({scrollTop: '+=150px'}, 200); });
|
||||
Mousetrap.bind('a', function() { var url = $('.paginator:visible .prev:not(.disabled) a').attr('href'); if (typeof url !== 'undefined') window.location.href = url; }, 'keyup');
|
||||
Mousetrap.bind('d', function() { var url = $('.paginator:visible .next:not(.disabled) a').attr('href'); if (typeof url !== 'undefined') window.location.href = url; }, 'keyup');
|
||||
Mousetrap.bind('p', function() { $('.post a').eq(0).focus(); return false; }, 'keyup');
|
||||
Mousetrap.bind('q', function()
|
||||
{
|
||||
$('#top-nav input').focus();
|
||||
return false;
|
||||
}, 'keyup');
|
||||
|
||||
Mousetrap.bind('w', function()
|
||||
{
|
||||
$('body,html').animate({scrollTop: '-=150px'}, 200);
|
||||
});
|
||||
|
||||
Mousetrap.bind('s', function()
|
||||
{
|
||||
$('body,html').animate({scrollTop: '+=150px'}, 200);
|
||||
});
|
||||
|
||||
Mousetrap.bind('a', function()
|
||||
{
|
||||
var url = $('.paginator:visible .prev:not(.disabled) a').attr('href');
|
||||
if (typeof url !== 'undefined')
|
||||
window.location.href = url;
|
||||
}, 'keyup');
|
||||
|
||||
Mousetrap.bind('d', function()
|
||||
{
|
||||
var url = $('.paginator:visible .next:not(.disabled) a').attr('href');
|
||||
if (typeof url !== 'undefined')
|
||||
window.location.href = url;
|
||||
}, 'keyup');
|
||||
|
||||
Mousetrap.bind('p', function()
|
||||
{
|
||||
$('.post a').eq(0).focus();
|
||||
return false;
|
||||
}, 'keyup');
|
||||
});
|
||||
|
||||
|
||||
|
@ -1,7 +1,10 @@
|
||||
function scrolled()
|
||||
{
|
||||
var margin = 150;
|
||||
if ($(document).height() <= $(window).scrollTop() + $(window).height() + margin)
|
||||
var target = $('.paginator-content:eq(0)');
|
||||
var y = $(window).scrollTop() + $(window).height();
|
||||
var maxY = target.height() + target.position().top;
|
||||
if (y >= maxY - margin)
|
||||
{
|
||||
var pageNext = $(document).data('page-next');
|
||||
var pageDone = $(document).data('page-done');
|
||||
@ -17,7 +20,13 @@ function scrolled()
|
||||
var dom = $(response);
|
||||
var nextPage = dom.find('.paginator .next:not(.disabled) a').attr('href');
|
||||
$(document).data('page-next', nextPage);
|
||||
$('.paginator-content').append($(response).find('.paginator-content').children().css({opacity: 0}).animate({opacity: 1}, 'slow'));
|
||||
|
||||
var source = $(response).find('.paginator-content');
|
||||
target.append(source
|
||||
.children()
|
||||
.css({opacity: 0})
|
||||
.animate({opacity: 1}, 'slow'));
|
||||
|
||||
$('body').trigger('dom-update');
|
||||
scrolled();
|
||||
});
|
||||
|
@ -140,7 +140,31 @@ $(function()
|
||||
$.ajax(ajaxData);
|
||||
});
|
||||
|
||||
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() { $('a.edit-post').trigger('click'); return false; }, '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()
|
||||
{
|
||||
$('a.edit-post').trigger('click');
|
||||
return false;
|
||||
}, 'keyup');
|
||||
});
|
||||
|
@ -14,11 +14,11 @@ class Bootstrap
|
||||
public function workWrapper($workCallback)
|
||||
{
|
||||
$this->config->chibi->baseUrl = 'http://' . rtrim($_SERVER['HTTP_HOST'], '/') . '/';
|
||||
session_start();
|
||||
|
||||
$this->context->handleExceptions = false;
|
||||
$this->context->viewDecorators []= new CustomAssetViewDecorator();
|
||||
$this->context->viewDecorators []= new \Chibi\PrettyPrintViewDecorator();
|
||||
CustomAssetViewDecorator::setTitle($this->config->main->title);
|
||||
|
||||
$this->context->handleExceptions = false;
|
||||
$this->context->json = isset($_GET['json']);
|
||||
$this->context->layoutName = $this->context->json
|
||||
? 'layout-json'
|
||||
@ -26,6 +26,7 @@ class Bootstrap
|
||||
$this->context->transport = new StdClass;
|
||||
StatusHelper::init();
|
||||
|
||||
session_start();
|
||||
AuthController::doLogIn();
|
||||
|
||||
if (empty($this->context->route))
|
||||
@ -36,8 +37,6 @@ class Bootstrap
|
||||
return;
|
||||
}
|
||||
|
||||
$this->context->viewDecorators []= new CustomAssetViewDecorator();
|
||||
$this->context->viewDecorators []= new \Chibi\PrettyPrintViewDecorator();
|
||||
try
|
||||
{
|
||||
$this->render($workCallback);
|
||||
|
@ -104,8 +104,8 @@ class AuthController
|
||||
if (!empty($context->user) and $context->user->id)
|
||||
{
|
||||
$dbUser = UserModel::findById($context->user->id);
|
||||
$context->user->lastLoginDate = time();
|
||||
UserModel::save($context->user);
|
||||
$dbUser->lastLoginDate = time();
|
||||
UserModel::save($dbUser);
|
||||
$_SESSION['user'] = serialize($dbUser);
|
||||
}
|
||||
else
|
||||
|
@ -42,7 +42,7 @@ class IndexController
|
||||
|
||||
//check if too old
|
||||
if (!$featuredPostId or $featuredPostDate + $featuredPostRotationTime < time())
|
||||
return $this->featureNewPost();
|
||||
return PropertyModel::featureNewPost();
|
||||
|
||||
//check if post was deleted
|
||||
$featuredPost = PostModel::findById($featuredPostId, false);
|
||||
|
@ -151,7 +151,15 @@ class PostController
|
||||
$this->listAction('favmin:1', $page);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @route /upvoted
|
||||
* @route /upvoted/{page}
|
||||
* @validate page \d*
|
||||
*/
|
||||
public function upvotedAction($page = 1)
|
||||
{
|
||||
$this->listAction('scoremin:1', $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /random
|
||||
|
@ -14,7 +14,7 @@ class TagController
|
||||
$this->context->viewName = 'tag-list-wrapper';
|
||||
PrivilegesHelper::confirmWithException(Privilege::ListTags);
|
||||
|
||||
$suppliedFilter = $filter ?: InputHelper::get('filter') ?: 'order:alpha,asc';
|
||||
$suppliedFilter = $filter ?: 'order:alpha,asc';
|
||||
$page = max(1, intval($page));
|
||||
$tagsPerPage = intval($this->config->browsing->tagsPerPage);
|
||||
|
||||
@ -43,6 +43,53 @@ class TagController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /tags-autocomplete
|
||||
*/
|
||||
public function autoCompleteAction()
|
||||
{
|
||||
PrivilegesHelper::confirmWithException(Privilege::ListTags);
|
||||
|
||||
$suppliedSearch = InputHelper::get('search');
|
||||
|
||||
$filter = $suppliedSearch . ' order:popularity,desc';
|
||||
$tags = TagSearchService::getEntitiesRows($filter, 15, 1);
|
||||
|
||||
$this->context->transport->tags =
|
||||
array_values(array_map(
|
||||
function($tag)
|
||||
{
|
||||
return [
|
||||
'name' => $tag['name'],
|
||||
'count' => $tag['post_count']
|
||||
];
|
||||
}, $tags));
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /tags-related
|
||||
*/
|
||||
public function relatedAction()
|
||||
{
|
||||
PrivilegesHelper::confirmWithException(Privilege::ListTags);
|
||||
|
||||
$suppliedContext = (array) InputHelper::get('context');
|
||||
$suppliedTag = InputHelper::get('tag');
|
||||
|
||||
$limit = intval($this->config->browsing->tagsRelated);
|
||||
$tags = TagSearchService::getRelatedTagRows($suppliedTag, $suppliedContext, $limit);
|
||||
|
||||
$this->context->transport->tags =
|
||||
array_values(array_map(
|
||||
function($tag)
|
||||
{
|
||||
return [
|
||||
'name' => $tag['name'],
|
||||
'count' => $tag['post_count']
|
||||
];
|
||||
}, $tags));
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /tag/merge
|
||||
*/
|
||||
|
@ -552,7 +552,7 @@ class UserController
|
||||
public function activationAction($token)
|
||||
{
|
||||
$this->context->viewName = 'message';
|
||||
LayoutHelper::setSubTitle('account activation');
|
||||
CustomAssetViewDecorator::setSubTitle('account activation');
|
||||
|
||||
$dbToken = TokenModel::findByToken($token);
|
||||
TokenModel::checkValidity($dbToken);
|
||||
@ -585,7 +585,7 @@ class UserController
|
||||
public function passwordResetAction($token)
|
||||
{
|
||||
$this->context->viewName = 'message';
|
||||
LayoutHelper::setSubTitle('password reset');
|
||||
CustomAssetViewDecorator::setSubTitle('password reset');
|
||||
|
||||
$dbToken = TokenModel::findByToken($token);
|
||||
TokenModel::checkValidity($dbToken);
|
||||
@ -619,7 +619,7 @@ class UserController
|
||||
public function passwordResetProxyAction()
|
||||
{
|
||||
$this->context->viewName = 'user-select';
|
||||
LayoutHelper::setSubTitle('password reset');
|
||||
CustomAssetViewDecorator::setSubTitle('password reset');
|
||||
|
||||
if (InputHelper::get('submit'))
|
||||
{
|
||||
@ -639,7 +639,7 @@ class UserController
|
||||
public function activationProxyAction()
|
||||
{
|
||||
$this->context->viewName = 'user-select';
|
||||
LayoutHelper::setSubTitle('account activation');
|
||||
CustomAssetViewDecorator::setSubTitle('account activation');
|
||||
|
||||
if (InputHelper::get('submit'))
|
||||
{
|
||||
|
@ -1,17 +1,17 @@
|
||||
<?php
|
||||
class CustomMarkdown extends \Michelf\Markdown
|
||||
class CustomMarkdown extends \Michelf\MarkdownExtra
|
||||
{
|
||||
protected $simple = false;
|
||||
|
||||
public function __construct($simple = false)
|
||||
{
|
||||
$this->simple = $simple;
|
||||
$this->no_markup = true;
|
||||
$this->span_gamut += ['doSpoilers' => 71];
|
||||
$this->span_gamut += ['doSearchPermalinks' => 72];
|
||||
$this->no_markup = $simple;
|
||||
$this->span_gamut += ['doStrike' => 6];
|
||||
$this->span_gamut += ['doUsers' => 7];
|
||||
$this->span_gamut += ['doPosts' => 8];
|
||||
$this->span_gamut += ['doSpoilers' => 8.5];
|
||||
$this->span_gamut += ['doSearchPermalinks' => 8.75];
|
||||
$this->span_gamut += ['doTags' => 9];
|
||||
$this->span_gamut += ['doAutoLinks2' => 29];
|
||||
|
||||
@ -28,11 +28,11 @@ class CustomMarkdown extends \Michelf\Markdown
|
||||
}
|
||||
|
||||
//make atx-style headers require space after hash
|
||||
protected function doHeaders($text)
|
||||
protected function _doHeaders_callback_atx($matches)
|
||||
{
|
||||
$text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', [&$this, '_doHeaders_callback_setext'], $text);
|
||||
$text = preg_replace_callback('{^(\#{1,6})[ ]+(.+?)[ ]*\#*\n+}xm', [&$this, '_doHeaders_callback_atx'], $text);
|
||||
return $text;
|
||||
if (!preg_match('/^#+\s/', $matches[0]))
|
||||
return $matches[0];
|
||||
return parent::_doHeaders_callback_atx($matches);
|
||||
}
|
||||
|
||||
//disable paragraph forming when using simple markdown
|
||||
@ -80,7 +80,7 @@ class CustomMarkdown extends \Michelf\Markdown
|
||||
$url = &$matches[4];
|
||||
else
|
||||
$url = &$matches[3];
|
||||
if (!preg_match('/^((https?|ftp):|)\/\//', $url))
|
||||
if (!preg_match('/^((https?|ftp):|)\//', $url))
|
||||
$url = 'http://' . $url;
|
||||
return parent::_doAnchors_inline_callback($matches);
|
||||
}
|
||||
@ -122,7 +122,7 @@ class CustomMarkdown extends \Michelf\Markdown
|
||||
{
|
||||
if (is_array($text))
|
||||
$text = $this->hashBlock('<span class="spoiler">') . $this->runSpanGamut($text[1]) . $this->hashBlock('</span>');
|
||||
return preg_replace_callback('{\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\])|(?R))+)\[\/spoiler\]}is', [__CLASS__, 'doSpoilers'], $text);
|
||||
return preg_replace_callback('{(?<!#)\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\])|(?R))+)\[\/spoiler\]}is', [__CLASS__, 'doSpoilers'], $text);
|
||||
}
|
||||
|
||||
protected function doPosts($text)
|
||||
@ -130,7 +130,7 @@ class CustomMarkdown extends \Michelf\Markdown
|
||||
$link = \Chibi\UrlHelper::route('post', 'view', ['id' => '_post_']);
|
||||
return preg_replace_callback('/(?:(?<![^\s\(\)\[\]]))@(\d+)/', function($x) use ($link)
|
||||
{
|
||||
return $this->hashPart('<a href="' . str_replace('_post_', $x[1], $link) . '">' . $x[0] . '</a>');
|
||||
return $this->hashPart('<a href="' . str_replace('_post_', $x[1], $link) . '"><code>' . $x[0] . '</code></a>');
|
||||
}, $text);
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ abstract class AbstractSearchParser
|
||||
{
|
||||
$arr = preg_split('/[;,]/', $orderToken);
|
||||
if (count($arr) == 1)
|
||||
$arr []= 'asc';
|
||||
$arr []= 'desc';
|
||||
|
||||
if (count($arr) != 2)
|
||||
throw new SimpleException('Invalid search order token: ' . $orderToken);
|
||||
|
@ -65,7 +65,7 @@ class PostSearchParser extends AbstractSearchParser
|
||||
return Sql\InFunctor::fromArray('post.id', Sql\Binding::fromArray($ids));
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['fav', 'favs']))
|
||||
elseif (in_array($key, ['fav', 'favs', 'favd']))
|
||||
{
|
||||
$user = UserModel::findByNameOrEmail($value);
|
||||
$innerStmt = (new Sql\SelectStatement)
|
||||
@ -76,7 +76,7 @@ class PostSearchParser extends AbstractSearchParser
|
||||
return new Sql\ExistsFunctor($innerStmt);
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['comment', 'commenter']))
|
||||
elseif (in_array($key, ['comment', 'comments', 'commenter', 'commented']))
|
||||
{
|
||||
$user = UserModel::findByNameOrEmail($value);
|
||||
$innerStmt = (new Sql\SelectStatement)
|
||||
@ -87,10 +87,10 @@ class PostSearchParser extends AbstractSearchParser
|
||||
return new Sql\ExistsFunctor($innerStmt);
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['submit', 'upload', 'uploader', 'uploaded']))
|
||||
elseif (in_array($key, ['submit', 'upload', `uploads`, 'uploader', 'uploaded']))
|
||||
{
|
||||
$user = UserModel::findByNameOrEmail($value);
|
||||
return new Sql\EqualsFunctor('uploader_id', new Sql\Binding($user->id));
|
||||
return new Sql\EqualsFunctor('post.uploader_id', new Sql\Binding($user->id));
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['idmin', 'id_min']))
|
||||
@ -100,54 +100,54 @@ class PostSearchParser extends AbstractSearchParser
|
||||
return new Sql\EqualsOrLesserFunctor('post.id', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['scoremin', 'score_min']))
|
||||
return new Sql\EqualsOrGreaterFunctor('score', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrGreaterFunctor('post.score', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['scoremax', 'score_max']))
|
||||
return new Sql\EqualsOrLesserFunctor('score', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrLesserFunctor('post.score', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['tagmin', 'tag_min']))
|
||||
return new Sql\EqualsOrGreaterFunctor('tag_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrGreaterFunctor('post.tag_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['tagmax', 'tag_max']))
|
||||
return new Sql\EqualsOrLesserFunctor('tag_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrLesserFunctor('post.tag_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['favmin', 'fav_min']))
|
||||
return new Sql\EqualsOrGreaterFunctor('fav_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrGreaterFunctor('post.fav_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['favmax', 'fav_max']))
|
||||
return new Sql\EqualsOrLesserFunctor('fav_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrLesserFunctor('post.fav_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['commentmin', 'comment_min']))
|
||||
return new Sql\EqualsOrGreaterFunctor('comment_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrGreaterFunctor('post.comment_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['commentmax', 'comment_max']))
|
||||
return new Sql\EqualsOrLesserFunctor('comment_count', new Sql\Binding(intval($value)));
|
||||
return new Sql\EqualsOrLesserFunctor('post.comment_count', new Sql\Binding(intval($value)));
|
||||
|
||||
elseif (in_array($key, ['date']))
|
||||
{
|
||||
list ($dateMin, $dateMax) = self::parseDate($value);
|
||||
return (new Sql\ConjunctionFunctor)
|
||||
->add(new Sql\EqualsOrLesserFunctor('upload_date', new Sql\Binding($dateMax)))
|
||||
->add(new Sql\EqualsOrGreaterFunctor('upload_date', new Sql\Binding($dateMin)));
|
||||
->add(new Sql\EqualsOrLesserFunctor('post.upload_date', new Sql\Binding($dateMax)))
|
||||
->add(new Sql\EqualsOrGreaterFunctor('post.upload_date', new Sql\Binding($dateMin)));
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['datemin', 'date_min']))
|
||||
{
|
||||
list ($dateMin, $dateMax) = self::parseDate($value);
|
||||
return new Sql\EqualsOrGreaterFunctor('upload_date', new Sql\Binding($dateMin));
|
||||
return new Sql\EqualsOrGreaterFunctor('post.upload_date', new Sql\Binding($dateMin));
|
||||
}
|
||||
|
||||
elseif (in_array($key, ['datemax', 'date_max']))
|
||||
{
|
||||
list ($dateMin, $dateMax) = self::parseDate($value);
|
||||
return new Sql\EqualsOrLesserFunctor('upload_date', new Sql\Binding($dateMax));
|
||||
return new Sql\EqualsOrLesserFunctor('post.upload_date', new Sql\Binding($dateMax));
|
||||
}
|
||||
|
||||
elseif ($key == 'special')
|
||||
{
|
||||
$context = \Chibi\Registry::getContext();
|
||||
$value = strtolower($value);
|
||||
if (in_array($value, ['fav', 'favs', 'favd', 'favorite', 'favorites']))
|
||||
if (in_array($value, ['fav', 'favs', 'favd']))
|
||||
{
|
||||
return $this->prepareCriterionForComplexToken('fav', $context->user->name);
|
||||
}
|
||||
@ -224,22 +224,28 @@ class PostSearchParser extends AbstractSearchParser
|
||||
$orderColumn = 'post.id';
|
||||
|
||||
elseif (in_array($orderByString, ['date']))
|
||||
$orderColumn = 'upload_date';
|
||||
|
||||
elseif (in_array($orderByString, ['comment', 'comments', 'commentcount', 'comment_count']))
|
||||
$orderColumn = 'comment_count';
|
||||
|
||||
elseif (in_array($orderByString, ['fav', 'favs', 'favcount', 'fav_count']))
|
||||
$orderColumn = 'fav_count';
|
||||
$orderColumn = 'post.upload_date';
|
||||
|
||||
elseif (in_array($orderByString, ['score']))
|
||||
$orderColumn = 'score';
|
||||
$orderColumn = 'post.score';
|
||||
|
||||
elseif (in_array($orderByString, ['comment', 'comments', 'commentcount', 'comment_count']))
|
||||
$orderColumn = 'post.comment_count';
|
||||
|
||||
elseif (in_array($orderByString, ['fav', 'favs', 'favcount', 'fav_count']))
|
||||
$orderColumn = 'post.fav_count';
|
||||
|
||||
elseif (in_array($orderByString, ['tag', 'tags', 'tagcount', 'tag_count']))
|
||||
$orderColumn = 'tag_count';
|
||||
$orderColumn = 'post.tag_count';
|
||||
|
||||
elseif (in_array($orderByString, ['commentdate', 'comment_date']))
|
||||
$orderColumn = 'comment_date';
|
||||
$orderColumn = 'post.comment_date';
|
||||
|
||||
elseif (in_array($orderByString, ['favdate', 'fav_date']))
|
||||
$orderColumn = 'post.fav_date';
|
||||
|
||||
elseif (in_array($orderByString, ['filesize', 'file_size']))
|
||||
$orderColumn = 'post.file_size';
|
||||
|
||||
elseif ($orderByString == 'random')
|
||||
{
|
||||
@ -270,11 +276,14 @@ class PostSearchParser extends AbstractSearchParser
|
||||
protected static function parseDate($value)
|
||||
{
|
||||
list ($year, $month, $day) = explode('-', $value . '-0-0');
|
||||
$yearMin = $yearMax = intval($year);
|
||||
$monthMin = $monthMax = intval($month);
|
||||
$year = intval($year);
|
||||
$month = intval($month);
|
||||
$day = intval($day);
|
||||
$yearMin = $yearMax = $year;
|
||||
$monthMin = $monthMax = $month;
|
||||
$monthMin = $monthMin ?: 1;
|
||||
$monthMax = $monthMax ?: 12;
|
||||
$dayMin = $dayMax = intval($day);
|
||||
$dayMin = $dayMax = $day;
|
||||
$dayMin = $dayMin ?: 1;
|
||||
$dayMax = $dayMax ?: intval(date('t', mktime(0, 0, 0, $monthMax, 1, $year)));
|
||||
$timeMin = mktime(0, 0, 0, $monthMin, $dayMin, $yearMin);
|
||||
|
@ -9,15 +9,73 @@ class TagSearchService extends AbstractSearchService
|
||||
$stmt->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'));
|
||||
}
|
||||
|
||||
public static function getRelatedTagRows($parentTagName, $context, $limit)
|
||||
{
|
||||
$parentTagEntity = TagModel::findByName($parentTagName, false);
|
||||
if (empty($parentTagEntity))
|
||||
return [];
|
||||
$parentTagId = $parentTagEntity->id;
|
||||
|
||||
//get tags that appear with selected tag along with their occurence frequency
|
||||
$stmt = (new Sql\SelectStatement)
|
||||
->setTable('tag')
|
||||
->addColumn('tag.*')
|
||||
->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'))
|
||||
->addInnerJoin('post_tag', new Sql\EqualsFunctor('post_tag.tag_id', 'tag.id'))
|
||||
->setGroupBy('tag.id')
|
||||
->setOrderBy('post_count', Sql\SelectStatement::ORDER_DESC)
|
||||
->setCriterion(new Sql\ExistsFunctor((new Sql\SelectStatement)
|
||||
->setTable('post_tag pt2')
|
||||
->setCriterion((new Sql\ConjunctionFunctor)
|
||||
->add(new Sql\EqualsFunctor('pt2.post_id', 'post_tag.post_id'))
|
||||
->add(new Sql\EqualsFunctor('pt2.tag_id', new Sql\Binding($parentTagId)))
|
||||
)));
|
||||
|
||||
$rows1 = [];
|
||||
foreach (Database::fetchAll($stmt) as $row)
|
||||
$rows1[$row['id']] = $row;
|
||||
|
||||
//get the same tags, but this time - get global occurence frequency
|
||||
$stmt = (new Sql\SelectStatement)
|
||||
->setTable('tag')
|
||||
->addColumn('tag.*')
|
||||
->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'))
|
||||
->addInnerJoin('post_tag', new Sql\EqualsFunctor('post_tag.tag_id', 'tag.id'))
|
||||
->setCriterion(Sql\InFunctor::fromArray('tag.id', Sql\Binding::fromArray(array_keys($rows1))))
|
||||
->setGroupBy('tag.id');
|
||||
|
||||
$rows2 = [];
|
||||
foreach (Database::fetchAll($stmt) as $row)
|
||||
$rows2[$row['id']] = $row;
|
||||
|
||||
$rows = [];
|
||||
foreach ($rows1 as $i => $row)
|
||||
{
|
||||
//multiply own occurences by two because we are going to subtract them
|
||||
$row['sort'] = $row['post_count'] * 2;
|
||||
//subtract global occurencecount
|
||||
$row['sort'] -= isset($rows2[$i]) ? $rows2[$i]['post_count'] : 0;
|
||||
|
||||
if ($row['id'] != $parentTagId)
|
||||
$rows []= $row;
|
||||
}
|
||||
|
||||
usort($rows, function($a, $b) { return intval($b['sort']) - intval($a['sort']); });
|
||||
$rows = array_filter($rows, function($row) use ($context) { return !in_array($row['name'], $context); });
|
||||
$rows = array_slice($rows, 0, $limit);
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
public static function getMostUsedTag()
|
||||
{
|
||||
$stmt = new Sql\SelectStatement();
|
||||
$stmt->setTable('post_tag');
|
||||
$stmt->addColumn('tag_id');
|
||||
$stmt->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'));
|
||||
$stmt->setGroupBy('post_tag.tag_id');
|
||||
$stmt->setOrderBy('post_count', Sql\SelectStatement::ORDER_DESC);
|
||||
$stmt->setLimit(1, 0);
|
||||
$stmt = (new Sql\SelectStatement)
|
||||
->setTable('post_tag')
|
||||
->addColumn('tag_id')
|
||||
->addColumn(new Sql\AliasFunctor(new Sql\CountFunctor('post_tag.post_id'), 'post_count'))
|
||||
->setGroupBy('post_tag.tag_id')
|
||||
->setOrderBy('post_count', Sql\SelectStatement::ORDER_DESC)
|
||||
->setLimit(1, 0);
|
||||
return Database::fetchOne($stmt);
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ class UserModel extends AbstractCrudModel
|
||||
$stmt->setTable('favoritee');
|
||||
$stmt->setColumn('post_id', new Sql\Binding($post->id));
|
||||
$stmt->setColumn('user_id', new Sql\Binding($user->id));
|
||||
$stmt->setColumn('fav_date', time());
|
||||
Database::exec($stmt);
|
||||
});
|
||||
}
|
||||
|
17
src/Upgrades/mysql/Upgrade13.sql
Normal file
17
src/Upgrades/mysql/Upgrade13.sql
Normal file
@ -0,0 +1,17 @@
|
||||
ALTER TABLE favoritee ADD COLUMN fav_date INTEGER DEFAULT NULL;
|
||||
ALTER TABLE post ADD COLUMN fav_date INTEGER DEFAULT NULL;
|
||||
|
||||
CREATE TRIGGER favoritee_update_date AFTER UPDATE ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER favoritee_insert_date AFTER INSERT ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER favoritee_delete_date AFTER DELETE ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
17
src/Upgrades/sqlite/Upgrade13.sql
Normal file
17
src/Upgrades/sqlite/Upgrade13.sql
Normal file
@ -0,0 +1,17 @@
|
||||
ALTER TABLE favoritee ADD COLUMN fav_date INTEGER DEFAULT NULL;
|
||||
ALTER TABLE post ADD COLUMN fav_date INTEGER DEFAULT NULL;
|
||||
|
||||
CREATE TRIGGER favoritee_update_date AFTER UPDATE ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER favoritee_insert_date AFTER INSERT ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER favoritee_delete_date AFTER DELETE ON favoritee FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE post SET fav_date = (SELECT MAX(fav_date) FROM favoritee WHERE favoritee.post_id = post.id);
|
||||
END;
|
@ -2,24 +2,41 @@
|
||||
CustomAssetViewDecorator::setSubTitle('posts');
|
||||
|
||||
$tabs = [];
|
||||
$activeTab = 0;
|
||||
if (PrivilegesHelper::confirm(Privilege::ListPosts))
|
||||
$tabs []= ['All posts', \Chibi\UrlHelper::route('post', 'list')];
|
||||
|
||||
if (PrivilegesHelper::confirm(Privilege::ListPosts))
|
||||
{
|
||||
$tabs []= ['Random', \Chibi\UrlHelper::route('post', 'random')];
|
||||
if ($this->context->route->simpleActionName == 'random')
|
||||
$activeTab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
if (PrivilegesHelper::confirm(Privilege::ListPosts))
|
||||
{
|
||||
$tabs []= ['Favorites', \Chibi\UrlHelper::route('post', 'favorites')];
|
||||
if ($this->context->route->simpleActionName == 'favorites')
|
||||
$activeTab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
if (PrivilegesHelper::confirm(Privilege::ListPosts))
|
||||
{
|
||||
$tabs []= ['Upvoted', \Chibi\UrlHelper::route('post', 'upvoted')];
|
||||
if ($this->context->route->simpleActionName == 'upvoted')
|
||||
$activeTab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
if (PrivilegesHelper::confirm(Privilege::MassTag))
|
||||
{
|
||||
$tabs []= ['Mass tag', \Chibi\UrlHelper::route('post', 'list', [
|
||||
'source' => 'mass-tag',
|
||||
'query' => isset($this->context->transport->searchQuery) ? htmlspecialchars($this->context->transport->searchQuery) : '',
|
||||
'page' => isset($this->context->transport->paginator) ? $this->context->transport->paginator->page : 1])];
|
||||
if ($this->context->source == 'mass-tag')
|
||||
$activeTab = count($tabs) - 1;
|
||||
}
|
||||
|
||||
$activeTab = 0;
|
||||
if ($this->context->route->simpleActionName == 'random') $activeTab = 1;
|
||||
if ($this->context->route->simpleActionName == 'favorites') $activeTab = 2;
|
||||
if ($this->context->source == 'mass-tag') $activeTab = 3;
|
||||
?>
|
||||
|
||||
<nav class="tabs">
|
||||
|
@ -65,6 +65,7 @@ if ($this->context->user->hasEnabledEndlessScrolling())
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
|
||||
<?php $this->renderFile('paginator') ?>
|
||||
|
@ -9,7 +9,7 @@ CustomAssetViewDecorator::setSubTitle('registration form');
|
||||
CustomAssetViewDecorator::addStylesheet('auth.css');
|
||||
?>
|
||||
|
||||
<form action="<?php echo \Chibi\UrlHelper::route('auth', 'register') ?>" class="auth" method="post">
|
||||
<form action="<?php echo \Chibi\UrlHelper::route('auth', 'register') ?>" class="auth register" method="post">
|
||||
<p>Registered users can view more content,<br/>upload files and add posts to favorites.</p>
|
||||
|
||||
<div class="form-row">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
define('SZURU_VERSION', '0.7.0');
|
||||
define('SZURU_VERSION', '0.7.1');
|
||||
define('SZURU_LINK', 'http://github.com/rr-/szurubooru');
|
||||
|
||||
//basic settings and preparation
|
||||
@ -12,6 +12,7 @@ ini_set('memory_limit', '128M');
|
||||
|
||||
//basic include calls, autoloader init
|
||||
require_once $rootDir . 'lib' . DS . 'php-markdown' . DS . 'Michelf' . DS . 'Markdown.php';
|
||||
require_once $rootDir . 'lib' . DS . 'php-markdown' . DS . 'Michelf' . DS . 'MarkdownExtra.php';
|
||||
require_once $rootDir . 'lib' . DS . 'chibi-core' . DS . 'Facade.php';
|
||||
\Chibi\AutoLoader::init([__DIR__, $rootDir . 'lib' . DS . 'chibi-sql']);
|
||||
|
||||
|
Reference in New Issue
Block a user