Compare commits

...

24 Commits

Author SHA1 Message Date
discomrade bedfc79337 Set default webm volume to 0.75 1 year ago
discomrade 602b621330 Add overboard support to mod catalog 1 year ago
perdedora ba33252223 feat: edit pre-existing bans (#528) 1 year ago
discomrade c0c3b76d74 Allow exclamation point after cite 1 year ago
discomrade 32f029eed9 Add default value for flood_cache 1 year ago
discomrade 8dc865a607 Handle statistics case where query returns no posts 1 year ago
discomrade fc87d86345 Replace deprecated raw tags 1 year ago
Majin Bejitto eda0f27190 fix "scandir should not need to sort in b.php (banner code)" 1 year ago
deysu 3de654eb77 Add banners as default functionality & display them on mod login / dashboard when enabled (#513) 1 year ago
runit 5362afd373 I'd just like to interject for a moment. 2 years ago
清靈語 74ace5c69c Replace Google reCAPTCHA API's domain (#507) 1 year ago
Fred Brennan ed1f4ae927 Use ENT_QUOTES when converting UTF-8 to HTML (#448) 2 years ago
sshscp15 a95ef60ee1 fixes boardlist in catalog when in mod mode 2 years ago
sshscp15 8fd8c34d8b Fix display warning/errors (#496) 2 years ago
sshscp15 bc2ad99715 fix mod.php. check if key is there and is valid 2 years ago
27chan 69f0d545a9 Removed regex with possibiblity of XSS 2 years ago
Fred Brennan f2bdf130dc Flip insane default for non-developers 2 years ago
Fred Brennan d86311b0cc Add support for APC(u) 2 years ago
C Hatfield 7719a9d06e Moved hardcoded html filepaths into config file for extensibility (#354) 2 years ago
haruhianon609 67efcda1b4 Add yandex images as image identification option (#430) 2 years ago
Fredrick Brennan 9de2ceaf61 Change illogical default of $config[force_body] 2 years ago
sshscp15 10ca344e64 simple catalog support for moderators 2 years ago
370chan 3b01f084a0 Fix files not being saved in certain cases (#483) 2 years ago
PVNFU-28 886742cefe Update style.css 3 years ago
  1. 9
      README.md
  2. 19
      b.php
  3. 11
      inc/bans.php
  4. 11
      inc/cache.php
  5. 92
      inc/config.php
  6. 14
      inc/display.php
  7. 2
      inc/filters.php
  8. 37
      inc/functions.php
  9. 178
      inc/mod/pages.php
  10. 3
      inc/statistics.php
  11. 9
      js/mod/ban-list.js
  12. 2
      js/webm-settings.js
  13. 4
      mod.php
  14. 23
      post.php
  15. 4
      report.php
  16. 6
      search.php
  17. BIN
      static/banners/defaultbanner.png
  18. 166
      stylesheets/style.css
  19. 2
      templates/header.html
  20. 7
      templates/index.html
  21. 17
      templates/mod/ban_form.html
  22. 70
      templates/mod/ban_history.html
  23. 1
      templates/mod/dashboard.html
  24. 14
      templates/mod/edit_ban.html
  25. 1
      templates/mod/login.html
  26. 16
      templates/mod/statistics.html
  27. 72
      templates/mod/view_ip.html
  28. 4
      templates/post/image_identification.html
  29. 6
      templates/themes/catalog/catalog.html
  30. 68
      templates/themes/catalog/theme.php
  31. 2
      templates/thread.html

9
README.md

@ -3,6 +3,8 @@ vichan - A lightweight and full featured PHP imageboard.
**Vichan has next to no active development<!--, however you can still pay for support. Basic support costs $40/hr, and is only payable in BTC. New features depend on what you want. Email COPYPASTE &lt;AT&gt; KITTENS &lt;DOT&gt; PH if you're interested&mdash;Vichan forks such as OpenIB are included in this offer-->.**
As of 29 August 2022, though, it supports PHP8.1.
About
------------
vichan is a free light-weight, fast, highly configurable and user-friendly
@ -37,14 +39,15 @@ Requirements
3. [mbstring](http://www.php.net/manual/en/mbstring.installation.php)
4. [PHP GD](http://www.php.net/manual/en/intro.image.php)
5. [PHP PDO](http://www.php.net/manual/en/intro.pdo.php)
6. A Unix-like OS, preferrably FreeBSD or Linux
6. A Unix-like OS, preferrably FreeBSD or GNU/Linux
We try to make sure vichan is compatible with all major web servers. vichan does not include an Apache ```.htaccess``` file nor does it need one.
We try to make sure vichan is compatible with all major web servers. vichan does not include an Apache `.htaccess` file nor does it need one.
### Recommended
1. MySQL/MariaDB server >= 5.5.3
2. ImageMagick (command-line ImageMagick or GraphicsMagick preferred).
3. [APC (Alternative PHP Cache)](http://php.net/manual/en/book.apc.php),
3. ~~[APC (Alternative PHP Cache)](http://php.net/manual/en/book.apc.php)~~,
[APCu (Alternative PHP Cache)](http://php.net/manual/en/book.apcu.php),
[XCache](http://xcache.lighttpd.net/),
[Memcached](http://www.php.net/manual/en/intro.memcached.php) or
[Redis](https://redis.io/docs/about/)

19
b.php

@ -0,0 +1,19 @@
<?php
$dir = "static/banners/";
$files = scandir($dir, SCANDIR_SORT_NONE);
$images = array_diff($files, array('.', '..'));
$name = $images[array_rand($images)];
// open the file in a binary mode
$fp = fopen($dir . $name, 'rb');
// send the right headers
header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1
header('Pragma: no-cache'); // HTTP 1.0
header('Expires: 0'); // Proxies
header('Content-Type: ' . $fp['type']);
header('Content-Length: ' . $fp['bytes']);
// dump the picture and stop the script
fpassthru($fp);
exit;
?>

11
inc/bans.php

@ -113,20 +113,22 @@ class Bans {
return array($ipstart, $ipend);
}
static public function find($ip, $board = false, $get_mod_info = false) {
static public function find($ip, $board = false, $get_mod_info = false, $banid = null) {
global $config;
$query = prepare('SELECT ``bans``.*' . ($get_mod_info ? ', `username`' : '') . ' FROM ``bans``
' . ($get_mod_info ? 'LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`' : '') . '
WHERE
(' . ($board !== false ? '(`board` IS NULL OR `board` = :board) AND' : '') . '
(`ipstart` = :ip OR (:ip >= `ipstart` AND :ip <= `ipend`)))
(`ipstart` = :ip OR (:ip >= `ipstart` AND :ip <= `ipend`)) OR (``bans``.id = :id))
ORDER BY `expires` IS NULL, `expires` DESC');
if ($board !== false)
$query->bindValue(':board', $board, PDO::PARAM_STR);
$query->bindValue(':id', $banid);
$query->bindValue(':ip', inet_pton($ip));
$query->execute() or error(db_error($query));
$ban_list = array();
@ -318,6 +320,9 @@ class Bans {
$query->bindValue(':board', null, PDO::PARAM_NULL);
if ($post) {
if (!isset($board['uri']))
openBoard($post['board']);
$post['board'] = $board['uri'];
$query->bindValue(':post', json_encode($post));
} else

11
inc/cache.php

@ -44,6 +44,9 @@ class Cache {
case 'apc':
$data = apc_fetch($key);
break;
case 'apcu':
$data = apcu_fetch($key);
break;
case 'xcache':
$data = xcache_get($key);
break;
@ -95,6 +98,9 @@ class Cache {
case 'apc':
apc_store($key, $value, $expires);
break;
case 'apcu':
apcu_store($key, $value, $expires);
break;
case 'xcache':
xcache_set($key, $value, $expires);
break;
@ -130,6 +136,9 @@ class Cache {
case 'apc':
apc_delete($key);
break;
case 'apcu':
apcu_delete($key);
break;
case 'xcache':
xcache_unset($key);
break;
@ -156,6 +165,8 @@ class Cache {
return self::$cache->flush();
case 'apc':
return apc_clear_cache('user');
case 'apcu':
return apcu_clear_cache('user');
case 'php':
self::$cache = array();
break;

92
inc/config.php

@ -44,7 +44,7 @@
// Shows some extra information at the bottom of pages. Good for development/debugging.
$config['debug'] = false;
// For development purposes. Displays (and "dies" on) all errors and warnings. Turn on with the above.
$config['verbose_errors'] = true;
$config['verbose_errors'] = false;
// Warn about deprecations? See vichan-devel/vichan#363 and https://www.youtube.com/watch?v=9crnlHLVdno
$config['deprecation_errors'] = false;
@ -488,7 +488,9 @@
// outside the current board. This means that if you have a special flood condition for a specific board
// (contained in a board configuration file) which has a flood-time greater than any of those in the
// global configuration, you need to set the following variable to the maximum flood-time condition value.
// Set to -1 to disable.
// $config['flood_cache'] = 60 * 60 * 24; // 24 hours
$config['flood_cache'] = -1;
/*
* ====================
@ -497,7 +499,7 @@
*/
// Do you need a body for your reply posts?
$config['force_body'] = false;
$config['force_body'] = true;
// Do you need a body for new threads?
$config['force_body_op'] = true;
// Require an image for threads?
@ -919,6 +921,7 @@
$config['image_identification_imgops'] = true;
$config['image_identification_exif'] = true;
$config['image_identification_google'] = true;
$config['image_identification_yandex'] = true;
// Anime/manga search engine.
$config['image_identification_iqdb'] = false;
@ -1037,12 +1040,13 @@
// Characters used to generate a random password (with Javascript).
$config['genpassword_chars'] = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+';
// Optional banner image at the top of every page.
// $config['url_banner'] = '/banner.php';
// Banner dimensions are also optional. As the banner loads after the rest of the page, everything may be
// shifted down a few pixels when it does. Making the banner a fixed size will prevent this.
// $config['banner_width'] = 300;
// $config['banner_height'] = 100;
// Banner settings.
// Banners are rotating, random images displayed to users at the top of thread pages and the catalog.
// You should upload your banners to static/banners.
$config['url_banner'] = '/b.php'; // Custom script may be used.
// Setting the banner dimensions stops the page shifting as it loads. If you have banners of various different sizes, unset these.
$config['banner_width'] = 300;
$config['banner_height'] = 100;
// Custom stylesheets available for the user to choose. See the "stylesheets/" folder for a list of
// available stylesheets (or create your own).
@ -1187,9 +1191,10 @@
// Custom embedding (YouTube, vimeo, etc.)
// It's very important that you match the entire input (with ^ and $) or things will not work correctly.
// Be careful when creating a new embed, because depending on the URL you end up exposing yourself to an XSS.
$config['embedding'] = array(
array(
'/^https?:\/\/(\w+\.)?youtube\.com\/watch\?v=([a-zA-Z0-9\-_]{10,11})(&.+)?$/i',
'/^https?:\/\/(\w+\.)?youtube\.com\/watch\?v=([a-zA-Z0-9\-_]{10,11})?$/i',
'<iframe style="float: left; margin: 10px 20px;" width="%%tb_width%%" height="%%tb_height%%" frameborder="0" id="ytplayer" src="https://www.youtube.com/embed/$2"></iframe>'
),
array(
@ -1298,6 +1303,9 @@
$config['error']['captcha_incorrect'] = _('You seem to have mistyped the verification.');
$config['error']['captcha_expired'] = _('That captcha has expired.');
$config['error']['captcha'] = _('Captcha failed.');
$config['error']['flag_undefined'] = _('The flag %s is undefined, your PHP version is too old!');
$config['error']['flag_wrongtype'] = _('defined_flags_accumulate(): The flag %s is of the wrong type!');
// Moderator errors
$config['error']['toomanyunban'] = _('You are only allowed to unban %s users at a time. You tried to unban %u users.');
@ -1344,10 +1352,11 @@
// enter the directory path here. Otherwise, keep it false.
$config['root_file'] = false;
// Location of files.
// Location of primary files.
$config['file_index'] = 'index.html';
$config['file_catalog'] = 'catalog.html'; // Catalog page (used in preg_match for post referer)
$config['file_page'] = '%d.html'; // NB: page is both an index page and a thread
$config['file_catalog'] = 'catalog.html';
$config['file_page50'] = '%d+50.html';
$config['file_page_slug'] = '%d-%s.html';
$config['file_page50_slug'] = '%d-%s+50.html';
@ -1355,6 +1364,67 @@
$config['file_post'] = 'post.php';
$config['file_script'] = 'main.js';
$config['file_board_index'] = 'index.html';
$config['file_page_template'] = 'page.html';
$config['file_report'] = 'report.html';
$config['file_error'] = 'error.html';
$config['file_login'] = 'login.html';
$config['file_banned'] = 'banned.html';
$config['file_fileboard'] = 'fileboard.html';
$config['file_thread'] = 'thread.html';
$config['file_post_reply'] = 'post_reply.html';
$config['file_post_thread'] = 'post_thread.html';
$config['file_post_thread_fileboard'] = 'post_thread_fileboard.html';
// Mod page file settings
$config['file_mod_dashboard'] = 'mod/dashboard.html';
$config['file_mod_login'] = 'mod/login.html';
$config['file_mod_confim'] = 'mod/confirm.html';
$config['file_mod_board'] = 'mod/board.html';
$config['file_mod_news'] = 'mod/news.html';
$config['file_mod_log'] = 'mod/log.html';
$config['file_mod_view_ip'] = 'mod/view_ip.html';
$config['file_mod_ban_form'] = 'mod/ban_form.html';
$config['file_mod_ban_list'] = 'mod/ban_list.html';
$config['file_mod_ban_appeals'] = 'mod/ban_appeals.html';
$config['file_mod_noticeboard'] = 'mod/noticeboard.html';
$config['file_mod_search_results'] = 'mod/search_results.html';
$config['file_mod_move'] = 'mod/move.html';
$config['file_mod_move_reply'] = 'mod/move_reply.html';
$config['file_mod_edit_post_form'] = 'mod/edit_post_form.html';
$config['file_mod_user'] = 'mod/user.html';
$config['file_mod_users'] = 'mod/users.html';
$config['file_mod_pm'] = 'mod/pm.html';
$config['file_mod_new_pm'] = 'mod/new_pm.html';
$config['file_mod_inbox'] = 'mod/inbox.html';
$config['file_mod_rebuilt'] = 'mod/rebuilt.html';
$config['file_mod_rebuild'] = 'mod/rebuild.html';
$config['file_mod_report'] = 'mod/report.html';
$config['file_mod_reports'] = 'mod/reports.html';
$config['file_mod_recent_posts'] = 'mod/recent_posts.html';
$config['file_mod_config_editor'] = 'mod/config-editor.html';
$config['file_mod_config_editor_php'] = 'mod/config-editor-php.html';
$config['file_mod_themes'] = 'mod/themes.html';
$config['file_mod_theme_installed'] = 'mod/theme_installed.html';
$config['file_mod_theme_config'] = 'mod/theme_config.html';
$config['file_mod_theme_rebuilt'] = 'mod/theme_rebuilt.html';
$config['file_mod_pages'] = 'mod/pages.html';
$config['file_mod_edit_page'] = 'mod/edit_page.html';
$config['file_mod_debug_antispam'] = 'mod/debug/antispam.html';
$config['file_mod_debug_recent_posts'] = 'mod/debug/recent_posts.html';
$config['file_mod_debug_sql'] = 'mod/debug/sql.html';
$config['file_mod_debug_apc'] = 'mod/debug/apc.html';
// Board directory, followed by a forward-slash (/).
$config['board_path'] = '%s/';
// Misc directories.
@ -1660,6 +1730,8 @@
$config['mod']['unban'] = MOD;
// Spoiler image
$config['mod']['spoilerimage'] = JANITOR;
// Edit bans
$config['mod']['edit_ban'] = &$config['mod']['ban'];
// Delete file (and keep post)
$config['mod']['deletefile'] = JANITOR;
// Delete all posts by IP

14
inc/display.php

@ -105,7 +105,7 @@ function error($message, $priority = true, $debug_stuff = false) {
}
$pw = $config['db']['password'];
$debug_callback = function(&$item) use (&$debug_callback, $pw) {
$debug_callback = function($item) use (&$debug_callback, $pw) {
if (is_array($item)) {
$item = array_filter($item, $debug_callback);
}
@ -116,11 +116,11 @@ function error($message, $priority = true, $debug_stuff = false) {
if ($debug_stuff)
$debug_stuff = array_filter($debug_stuff, $debug_callback);
die(Element('page.html', array(
die(Element($config['file_page_template'], array(
'config' => $config,
'title' => _('Error'),
'subtitle' => _('An error has occured.'),
'body' => Element('error.html', array(
'body' => Element($config['file_error'], array(
'config' => $config,
'message' => $message,
'mod' => $mod,
@ -133,11 +133,11 @@ function error($message, $priority = true, $debug_stuff = false) {
function loginForm($error=false, $username=false, $redirect=false) {
global $config;
die(Element('page.html', array(
die(Element($config['file_page_template'], array(
'index' => $config['root'],
'title' => _('Login'),
'config' => $config,
'body' => Element('login.html', array(
'body' => Element($config['file_login'], array(
'config'=>$config,
'error'=>$error,
'username'=>utf8tohtml($username),
@ -384,7 +384,7 @@ class Post {
public function build($index=false) {
global $board, $config;
return Element('post_reply.html', array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'mod' => $this->mod));
return Element($config['file_post_reply'], array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'mod' => $this->mod));
}
};
@ -473,7 +473,7 @@ class Thread {
event('show-thread', $this);
$file = ($index && $config['file_board']) ? 'post_thread_fileboard.html' : 'post_thread.html';
$file = ($index && $config['file_board']) ? $config['file_post_thread_fileboard'] : $config['file_post_thread'];
$built = Element($file, array('config' => $config, 'board' => $board, 'post' => &$this, 'index' => $index, 'hasnoko50' => $hasnoko50, 'isnoko50' => $isnoko50, 'mod' => $this->mod));
return $built;

2
inc/filters.php

@ -192,7 +192,7 @@ function purge_flood_table() {
// aware of flood filters in other board configurations. You can solve this problem by settings the
// config variable $config['flood_cache'] (seconds).
if (isset($config['flood_cache'])) {
if ($config['flood_cache'] != -1) {
$max_time = &$config['flood_cache'];
} else {
$max_time = 0;

37
inc/functions.php

@ -894,11 +894,11 @@ function displayBan($ban) {
// Show banned page and exit
die(
Element('page.html', array(
Element($config['file_page_template'], array(
'title' => _('Banned!'),
'config' => $config,
'boardlist' => createBoardlist(isset($mod) ? $mod : false),
'body' => Element('banned.html', array(
'body' => Element($config['file_banned'], array(
'config' => $config,
'ban' => $ban,
'board' => $board,
@ -1422,7 +1422,7 @@ function deletePost($id, $error_if_doesnt_exist=true, $rebuild_after=true, $dele
// Delete posts and maybe replies
while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
event('delete', $post);
$thread_id = $post['thread'];
if (!$post['thread']) {
// Delete thread HTML page
@ -1644,7 +1644,7 @@ function index($page, $mod=false, $brief = false) {
}
if ($config['file_board']) {
$body = Element('fileboard.html', array('body' => $body, 'mod' => $mod));
$body = Element($config['file_fileboard'], array('body' => $body, 'mod' => $mod));
}
return array(
@ -2004,7 +2004,7 @@ function buildIndex($global_api = "yes") {
$content['btn'] = getPageButtons($content['pages']);
$content['antibot'] = $antibot;
file_write($filename, Element('index.html', $content));
file_write($filename, Element($config['file_board_index'], $content));
}
elseif ($action == 'delete' || $catalog_api_action == 'delete') {
file_unlink($filename);
@ -2354,7 +2354,7 @@ function markup(&$body, $track_cites = false, $op = false) {
$tracked_cites = array();
// Cites
if (isset($board) && preg_match_all('/(^|[\s(])&gt;&gt;(\d+?)(?=$|[\s,.?)])/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
if (isset($board) && preg_match_all('/(^|[\s(])&gt;&gt;(\d+?)(?=$|[\s,.?!)])/m', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
if (count($cites[0]) > $config['max_cites']) {
error($config['error']['toomanycites']);
}
@ -2401,7 +2401,7 @@ function markup(&$body, $track_cites = false, $op = false) {
}
// Cross-board linking
if (preg_match_all('/(^|[\s(])&gt;&gt;&gt;\/(' . $config['board_regex'] . ')\/(?:(\d+)\/?)?(?=$|[\s,.?)])/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
if (preg_match_all('/(^|[\s(])&gt;&gt;&gt;\/(' . $config['board_regex'] . ')\/(?:(\d+)\/?)?(?=$|[\s,.?!)])/um', $body, $cites, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
if (count($cites[0]) > $config['max_cites']) {
error($config['error']['toomanycross']);
}
@ -2556,8 +2556,25 @@ function escape_markup_modifiers($string) {
return preg_replace('@<(tinyboard) ([\w\s]+)>@mi', '<$1 escape $2>', $string);
}
function defined_flags_accumulate($desired_flags) {
$output_flags = 0x0;
foreach ($desired_flags as $flagname) {
if (defined($flagname)) {
$flag = constant($flagname);
if (gettype($flag) != 'integer')
error(sprintf($config['error']['flag_wrongtype'], $flagname));
$output_flags |= $flag;
} else {
if ($config['deprecation_errors'])
error(sprintf($config['error']['flag_undefined'], $flagname));
}
}
return $output_flags;
}
function utf8tohtml($utf8) {
return htmlspecialchars($utf8, ENT_NOQUOTES, 'UTF-8');
$flags = defined_flags_accumulate(['ENT_QUOTES', 'ENT_SUBSTITUTE', 'ENT_DISALLOWED']);
return htmlspecialchars($utf8, $flags, 'UTF-8');
}
function ordutf8($string, &$offset) {
@ -2628,7 +2645,7 @@ function buildThread($id, $return = false, $mod = false) {
$hasnoko50 = $thread->postCount() >= $config['noko50_min'];
$antibot = $mod || $return ? false : create_antibot($board['uri'], $id);
$body = Element('thread.html', array(
$body = Element($config['file_thread'], array(
'board' => $board,
'thread' => $thread,
'body' => $thread->build(),
@ -2731,7 +2748,7 @@ function buildThread50($id, $return = false, $mod = false, $thread = null, $anti
$hasnoko50 = $thread->postCount() >= $config['noko50_min'];
$body = Element('thread.html', array(
$body = Element($config['file_thread'], array(
'board' => $board,
'thread' => $thread,
'body' => $thread->build(false, true),

178
inc/mod/pages.php

@ -9,10 +9,10 @@ defined('TINYBOARD') or exit;
function mod_page($title, $template, $args, $subtitle = false) {
global $config, $mod;
echo Element('page.html', array(
echo Element($config['file_page_template'], array(
'config' => $config,
'mod' => $mod,
'hide_dashboard_link' => $template == 'mod/dashboard.html',
'hide_dashboard_link' => $template == $config['file_mod_dashboard'],
'title' => $title,
'subtitle' => $subtitle,
'boardlist' => createBoardlist($mod),
@ -57,11 +57,11 @@ function mod_login($redirect = false) {
if (isset($_POST['username']))
$args['username'] = $_POST['username'];
mod_page(_('Login'), 'mod/login.html', $args);
mod_page(_('Login'), $config['file_mod_login'], $args);
}
function mod_confirm($request) {
mod_page(_('Confirm action'), 'mod/confirm.html', array('request' => $request, 'token' => make_secure_link_token($request)));
mod_page(_('Confirm action'), $config['file_mod_confim'], array('request' => $request, 'token' => make_secure_link_token($request)));
}
function mod_logout() {
@ -163,7 +163,7 @@ function mod_dashboard() {
$args['logout_token'] = make_secure_link_token('logout');
mod_page(_('Dashboard'), 'mod/dashboard.html', $args);
mod_page(_('Dashboard'), $config['file_mod_dashboard'], $args);
}
function mod_search_redirect() {
@ -335,7 +335,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) {
// $results now contains the search results
mod_page(_('Search results'), 'mod/search_results.html', array(
mod_page(_('Search results'), $config['file_mod_search_results'], array(
'search_type' => $type,
'search_query' => $search_query,
'search_query_escaped' => $search_query_escaped,
@ -439,7 +439,7 @@ function mod_edit_board($boardName) {
header('Location: ?/', true, $config['redirect_http']);
} else {
mod_page(sprintf('%s: ' . $config['board_abbreviation'], _('Edit board'), $board['uri']), 'mod/board.html', array(
mod_page(sprintf('%s: ' . $config['board_abbreviation'], _('Edit board'), $board['uri']), $config['file_mod_board'], array(
'board' => $board,
'token' => make_secure_link_token('edit/' . $board['uri'])
));
@ -509,7 +509,7 @@ function mod_new_board() {
header('Location: ?/' . $board['uri'] . '/' . $config['file_index'], true, $config['redirect_http']);
}
mod_page(_('New board'), 'mod/board.html', array('new' => true, 'token' => make_secure_link_token('new-board')));
mod_page(_('New board'), $config['file_mod_board'], array('new' => true, 'token' => make_secure_link_token('new-board')));
}
function mod_noticeboard($page_no = 1) {
@ -560,7 +560,7 @@ function mod_noticeboard($page_no = 1) {
$query->execute() or error(db_error($query));
$count = $query->fetchColumn();
mod_page(_('Noticeboard'), 'mod/noticeboard.html', array(
mod_page(_('Noticeboard'), $config['file_mod_noticeboard'], array(
'noticeboard' => $noticeboard,
'count' => $count,
'token' => make_secure_link_token('noticeboard')
@ -629,7 +629,7 @@ function mod_news($page_no = 1) {
$query->execute() or error(db_error($query));
$count = $query->fetchColumn();
mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news')));
mod_page(_('News'), $config['file_mod_news'], array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news')));
}
function mod_news_delete($id) {
@ -669,7 +669,7 @@ function mod_log($page_no = 1) {
$query->execute() or error(db_error($query));
$count = $query->fetchColumn();
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count));
mod_page(_('Moderation log'), $config['file_mod_log'], array('logs' => $logs, 'count' => $count));
}
function mod_user_log($username, $page_no = 1) {
@ -696,7 +696,7 @@ function mod_user_log($username, $page_no = 1) {
$query->execute() or error(db_error($query));
$count = $query->fetchColumn();
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'username' => $username));
mod_page(_('Moderation log'), $config['file_mod_log'], array('logs' => $logs, 'count' => $count, 'username' => $username));
}
function mod_board_log($board, $page_no = 1, $hide_names = false, $public = false) {
@ -734,7 +734,31 @@ function mod_board_log($board, $page_no = 1, $hide_names = false, $public = fals
$query->execute() or error(db_error($query));
$count = $query->fetchColumn();
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'board' => $board, 'hide_names' => $hide_names, 'public' => $public));
mod_page(_('Board log'), $config['file_mod_log'], array('logs' => $logs, 'count' => $count, 'board' => $board, 'hide_names' => $hide_names, 'public' => $public));
}
function mod_view_catalog($boardName) {
global $config, $mod;
require_once($config['dir']['themes'].'/catalog/theme.php');
$settings = array();
$settings['boards'] = $boardName;
$settings['update_on_posts'] = true;
$settings['title'] = 'Catalog';
$settings['use_tooltipster'] = true;
$catalog = new Catalog($settings);
$query = prepare(sprintf('SELECT * FROM ``theme_settings`` WHERE `name` = "uri" AND `value` = :uri', $board));
$query->bindValue(':uri', $boardName);
$query->execute() or error(db_error($query));
if ($theme = $query->fetch(PDO::FETCH_ASSOC)){
if ($theme['theme'] == "rand")
echo $catalog->buildRand($mod);
if ($theme['theme'] == "ukko")
echo $catalog->buildUkko($mod);
} else {
echo $catalog->build($boardName, $mod);
}
}
function mod_view_board($boardName, $page_no = 1) {
@ -778,7 +802,7 @@ function mod_view_board($boardName, $page_no = 1) {
$page['mod'] = true;
$page['config'] = $config;
echo Element('index.html', $page);
echo Element($config['file_board_index'], $page);
}
function mod_view_thread($boardName, $thread) {
@ -858,6 +882,14 @@ function mod_page_ip($cip) {
header('Location: ?/IP/' . $cip . '#bans', true, $config['redirect_http']);
return;
}
if (isset($_POST['ban_id'], $_POST['edit_ban'])) {
if (!hasPermission($config['mod']['edit_ban']))
error($config['error']['noaccess']);
header('Location: ?/edit_ban/' . $_POST['ban_id'], true, $config['redirect_http']);
return;
}
if (isset($_POST['note'])) {
if (!hasPermission($config['mod']['create_notes']))
@ -959,7 +991,7 @@ function mod_page_ip($cip) {
$args['security_token'] = make_secure_link_token('IP/' . $cip);
mod_page(sprintf('%s: %s', _('IP'), htmlspecialchars($cip)), 'mod/view_ip.html', $args, $args['hostname'] ?? null);
mod_page(sprintf('%s: %s', _('IP'), htmlspecialchars($cip)), $config['file_mod_view_ip'], $args, $args['hostname']);
}
function mod_announcements() {
@ -1004,7 +1036,7 @@ function mod_ban() {
error($config['error']['noaccess']);
if (!isset($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'])) {
mod_page(_('New ban'), 'mod/ban_form.html', array('token' => make_secure_link_token('ban')));
mod_page(_('New ban'), $config['file_mod_ban_form'], array('token' => make_secure_link_token('ban')));
return;
}
@ -1045,7 +1077,7 @@ function mod_bans() {
return;
}
mod_page(_('Ban list'), 'mod/ban_list.html', array(
mod_page(_('Ban list'), $config['file_mod_ban_list'], array(
'mod' => $mod,
'boards' => json_encode($mod['boards']),
'token' => make_secure_link_token('bans'),
@ -1065,6 +1097,56 @@ function mod_bans_json() {
Bans::stream_json(false, false, !hasPermission($config['mod']['view_banstaff']), $mod['boards']);
}
function mod_edit_ban($ban_id) {
global $mod, $config;
if (!hasPermission($config['mod']['edit_ban']))
error($config['error']['noaccess']);
$args['bans'] = Bans::find(null, false, true, $ban_id);
$args['ban_id'] = $ban_id;
$args['boards'] = listBoards();
$args['current_board'] = isset($args['bans'][0]['board']) ? $args['bans'][0]['board'] : false;
if (!$args['bans'])
error($config['error']['404']);
if (isset($_POST['new_ban'])) {
$new_ban['mask'] = $args['bans'][0]['mask'];
$new_ban['post'] = isset($args['bans'][0]['post']) ? $args['bans'][0]['post'] : false;
$new_ban['board'] = $args['current_board'];
if (isset($_POST['reason']))
$new_ban['reason'] = $_POST['reason'];
else
$new_ban['reason'] = $args['bans'][0]['reason'];
if (isset($_POST['length']) && !empty($_POST['length']))
$new_ban['length'] = $_POST['length'];
else
$new_ban['length'] = false;
if (isset($_POST['board'])) {
if ($_POST['board'] == '*')
$new_ban['board'] = false;
else
$new_ban['board'] = $_POST['board'];
}
Bans::new_ban($new_ban['mask'], $new_ban['reason'], $new_ban['length'], $new_ban['board'], false, $new_ban['post']);
Bans::delete($ban_id);
header('Location: ?/', true, $config['redirect_http']);
}
$args['token'] = make_secure_link_token('edit_ban/' . $ban_id);
mod_page(_('Edit ban'), 'mod/edit_ban.html', $args);
}
function mod_ban_appeals() {
global $config, $board;
@ -1139,7 +1221,7 @@ function mod_ban_appeals() {
}
}
mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array(
mod_page(_('Ban appeals'), $config['file_mod_ban_appeals'], array(
'ban_appeals' => $ban_appeals,
'token' => make_secure_link_token('ban-appeals')
));
@ -1358,7 +1440,7 @@ function mod_move_reply($originBoard, $postID) {
$security_token = make_secure_link_token($originBoard . '/move_reply/' . $postID);
mod_page(_('Move reply'), 'mod/move_reply.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
mod_page(_('Move reply'), $config['file_mod_move_reply'], array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
}
@ -1598,7 +1680,7 @@ function mod_move($originBoard, $postID) {
$security_token = make_secure_link_token($originBoard . '/move/' . $postID);
mod_page(_('Move thread'), 'mod/move.html', array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
mod_page(_('Move thread'), $config['file_mod_move'], array('post' => $postID, 'board' => $originBoard, 'boards' => $boards, 'token' => $security_token));
}
function mod_merge($originBoard, $postID) {
@ -1934,7 +2016,7 @@ function mod_ban_post($board, $delete, $post, $token = false) {
'token' => $security_token
);
mod_page(_('New ban'), 'mod/ban_form.html', $args);
mod_page(_('New ban'), $config['file_mod_ban_form'], $args);
}
function mod_warning_post($board, $delete, $post, $token = false) {
@ -2092,7 +2174,7 @@ function mod_edit_post($board, $edit_raw_html, $postID) {
$post['body'] = str_replace("\t", '&#09;', $post['body']);
}
mod_page(_('Edit post'), 'mod/edit_post_form.html', array('token' => $security_token, 'board' => $board, 'raw' => $edit_raw_html, 'post' => $post));
mod_page(_('Edit post'), $config['file_mod_edit_post_form'], array('token' => $security_token, 'board' => $board, 'raw' => $edit_raw_html, 'post' => $post));
}
}
@ -2490,7 +2572,7 @@ function mod_user($uid) {
$user['boards'] = explode(',', $user['boards']);
mod_page(_('Edit user'), 'mod/user.html', array(
mod_page(_('Edit user'), $config['file_mod_user'], array(
'user' => $user,
'logs' => $log,
'boards' => listBoards(),
@ -2547,7 +2629,7 @@ function mod_user_new() {
return;
}
mod_page(_('New user'), 'mod/user.html', array('new' => true, 'boards' => listBoards(), 'token' => make_secure_link_token('users/new')));
mod_page(_('New user'), $config['file_mod_user'], array('new' => true, 'boards' => listBoards(), 'token' => make_secure_link_token('users/new')));
}
@ -2569,7 +2651,7 @@ function mod_users() {
$user['demote_token'] = make_secure_link_token("users/{$user['id']}/demote");
}
mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), 'mod/users.html', array('users' => $users));
mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), $config['file_mod_users'], array('users' => $users));
}
function mod_user_promote($uid, $action) {
@ -2659,14 +2741,14 @@ function mod_pm($id, $reply = false) {
if (!$pm['to_username'])
error($config['error']['404']); // deleted?
mod_page(sprintf('%s %s', _('New PM for'), $pm['to_username']), 'mod/new_pm.html', array(
mod_page(sprintf('%s %s', _('New PM for'), $pm['to_username']), $config['file_mod_new_pm'], array(
'username' => $pm['username'],
'id' => $pm['sender'],
'message' => quote($pm['message']),
'token' => make_secure_link_token('new_PM/' . $pm['username'])
));
} else {
mod_page(sprintf('%s &ndash; #%d', _('Private message'), $id), 'mod/pm.html', $pm);
mod_page(sprintf('%s &ndash; #%d', _('Private message'), $id), $config['file_mod_pm'], $pm);
}
}
@ -2687,7 +2769,7 @@ function mod_inbox() {
$message['snippet'] = pm_snippet($message['message']);
}
mod_page(sprintf('%s (%s)', _('PM inbox'), count($messages) > 0 ? $unread . ' unread' : 'empty'), 'mod/inbox.html', array(
mod_page(sprintf('%s (%s)', _('PM inbox'), count($messages) > 0 ? $unread . ' unread' : 'empty'), $config['file_mod_inbox'], array(
'messages' => $messages,
'unread' => $unread
));
@ -2735,7 +2817,7 @@ function mod_new_pm($username) {
header('Location: ?/', true, $config['redirect_http']);
}
mod_page(sprintf('%s %s', _('New PM for'), $username), 'mod/new_pm.html', array(
mod_page(sprintf('%s %s', _('New PM for'), $username), $config['file_mod_new_pm'], array(
'username' => $username,
'id' => $id,
'token' => make_secure_link_token('new_PM/' . $username)
@ -2808,11 +2890,11 @@ function mod_rebuild() {
}
}
mod_page(_('Rebuild'), 'mod/rebuilt.html', array('logs' => $log));
mod_page(_('Rebuild'), $config['file_mod_rebuilt'], array('logs' => $log));
return;
}
mod_page(_('Rebuild'), 'mod/rebuild.html', array(
mod_page(_('Rebuild'), $config['file_mod_rebuild'], array(
'boards' => listBoards(),
'token' => make_secure_link_token('rebuild')
));
@ -2870,7 +2952,7 @@ function mod_reports() {
}
// a little messy and inefficient
$append_html = Element('mod/report.html', array(
$append_html = Element($config['file_mod_report'], array(
'report' => $report,
'config' => $config,
'mod' => $mod,
@ -2897,7 +2979,7 @@ function mod_reports() {
$count++;
}
mod_page(sprintf('%s (%d)', _('Report queue'), $count), 'mod/reports.html', array('reports' => $body, 'count' => $count));
mod_page(sprintf('%s (%d)', _('Report queue'), $count), $config['file_mod_reports'], array('reports' => $body, 'count' => $count));
}
function mod_report_dismiss($id, $all = false) {
@ -3022,7 +3104,7 @@ function mod_report_dismiss($id, $all = false) {
echo $jsondata;
}
else {
echo mod_page(_('Recent posts'), 'mod/recent_posts.html', array(
echo mod_page(_('Recent posts'), $config['file_mod_recent_posts'], array(
'posts' => $posts,
'limit' => $limit,
'last_time' => $last_time
@ -3116,7 +3198,7 @@ function mod_config($board_config = false) {
}
$instance_config = str_replace("\n", '&#010;', utf8tohtml($instance_config));
mod_page(_('Config editor'), 'mod/config-editor-php.html', array(
mod_page(_('Config editor'), $config['file_mod_config_editor_php'], array(
'php' => $instance_config,
'readonly' => $readonly,
'boards' => listBoards(),
@ -3200,7 +3282,7 @@ function mod_config($board_config = false) {
<p style="text-align:center">You may proceed with these changes manually by copying and pasting the following code to the end of <strong>' . $config_file . '</strong>:</p>
<textarea style="width:700px;height:370px;margin:auto;display:block;background:white;color:black" readonly>' . $config_append . '</textarea>
';
echo Element('page.html', $page);
echo Element($config['file_page_template'], $page);
exit;
}
}
@ -3211,7 +3293,7 @@ function mod_config($board_config = false) {
}
mod_page(_('Config editor') . ($board_config ? ': ' . sprintf($config['board_abbreviation'], $board_config) : ''),
'mod/config-editor.html', array(
$config['file_mod_config_editor'], array(
'boards' => listBoards(),
'board' => $board_config,
'conf' => $conf,
@ -3248,7 +3330,7 @@ function mod_themes_list() {
$theme['uninstall_token'] = make_secure_link_token('themes/' . $theme_name . '/uninstall');
}
mod_page(_('Manage themes'), 'mod/themes.html', array(
mod_page(_('Manage themes'), $config['file_mod_themes'], array(
'themes' => $themes,
'themes_in_use' => $themes_in_use,
));
@ -3317,7 +3399,7 @@ function mod_theme_configure($theme_name) {
// Build themes
rebuildThemes('all');
mod_page(sprintf(_($result ? 'Installed theme: %s' : 'Installation failed: %s'), $theme['name']), 'mod/theme_installed.html', array(
mod_page(sprintf(_($result ? 'Installed theme: %s' : 'Installation failed: %s'), $theme['name']), $config['file_mod_theme_installed'], array(
'theme_name' => $theme_name,
'theme' => $theme,
'result' => $result,
@ -3328,7 +3410,7 @@ function mod_theme_configure($theme_name) {
$settings = themeSettings($theme_name);
mod_page(sprintf(_('Configuring theme: %s'), $theme['name']), 'mod/theme_config.html', array(
mod_page(sprintf(_('Configuring theme: %s'), $theme['name']), $config['file_mod_theme_config'], array(
'theme_name' => $theme_name,
'theme' => $theme,
'settings' => $settings,
@ -3361,7 +3443,7 @@ function mod_theme_rebuild($theme_name) {
rebuildTheme($theme_name, 'all');
mod_page(sprintf(_('Rebuilt theme: %s'), $theme_name), 'mod/theme_rebuilt.html', array(
mod_page(sprintf(_('Rebuilt theme: %s'), $theme_name), $config['file_mod_theme_rebuilt'], array(
'theme_name' => $theme_name,
));
}
@ -3459,7 +3541,7 @@ function mod_edit_page($id) {
$fn = (isset($board['uri']) ? ($board['uri'] . '/') : '') . $page['name'] . '.html';
$body = "<div class='ban'>$write</div>";
$html = Element('page.html', array('config' => $config, 'boardlist' => createBoardlist(), 'body' => $body, 'title' => utf8tohtml($page['title'])));
$html = Element($config['file_page_template'], array('config' => $config, 'boardlist' => createBoardlist(), 'body' => $body, 'title' => utf8tohtml($page['title'])));
file_write($fn, $html);
}
@ -3470,7 +3552,7 @@ function mod_edit_page($id) {
$content = $query->fetchColumn();
}
mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board));
mod_page(sprintf(_('Editing static page: %s'), $page['name']), $config['file_mod_edit_page'], array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board));
}
function mod_pages($board = false) {
@ -3524,7 +3606,7 @@ function mod_pages($board = false) {
$p['delete_token'] = make_secure_link_token('edit_pages/delete/' . $p['name'] . ($board ? ('/' . $board) : ''));
}
mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board));
mod_page(_('Pages'), $config['file_mod_pages'], array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board));
}
function mod_debug_antispam() {
@ -3561,7 +3643,7 @@ function mod_debug_antispam() {
$query = query('SELECT * FROM ``antispam`` ' . ($where ? "WHERE $where" : '') . ' ORDER BY `created` DESC LIMIT 20') or error(db_error());
$args['recent'] = $query->fetchAll(PDO::FETCH_ASSOC);
mod_page(_('Debug: Anti-spam'), 'mod/debug/antispam.html', $args);
mod_page(_('Debug: Anti-spam'), $config['file_mod_debug_antispam'], $args);
}
function mod_debug_recent_posts() {
@ -3595,7 +3677,7 @@ function mod_debug_recent_posts() {
}
}
mod_page(_('Debug: Recent posts'), 'mod/debug/recent_posts.html', array('posts' => $posts, 'flood_posts' => $flood_posts));
mod_page(_('Debug: Recent posts'), $config['file_mod_debug_recent_posts'], array('posts' => $posts, 'flood_posts' => $flood_posts));
}
function mod_debug_sql() {
@ -3619,7 +3701,7 @@ function mod_debug_sql() {
}
}
mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args);
mod_page(_('Debug: SQL'), $config['file_mod_debug_sql'], $args);
}
function mod_debug_apc() {
@ -3641,6 +3723,6 @@ function mod_debug_apc() {
$cached_vars[] = $var;
}
mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars));
mod_page(_('Debug: APC'), $config['file_mod_debug_apc'], array('cached_vars' => $cached_vars));
}

3
inc/statistics.php

@ -30,6 +30,9 @@ class Statistics {
$query = query($query) or error(db_error($query));
$query_result = $query->fetchAll(PDO::FETCH_ASSOC);
if(empty($query_result))
$query_result = [['hour' => 0, 'count' => "0"]];
// Get 24h array over post count
$statistics_hour = array_fill(0,24,0);
foreach ($query_result as &$hour_data) {

9
js/mod/ban-list.js

@ -37,7 +37,7 @@ var banlist_init = function(token, my_boards, inMod) {
}
return pre+f.mask;
} },
reason: {name: _("Reason"), width: "calc(100% - 715px - 6 * 4px)", fmt: function(f) {
reason: {name: _("Reason"), width: "calc(100% - 770px - 6 * 4px)", fmt: function(f) {
var add = "", suf = '';
if (f.seen == 1) add += "<i class='fa fa-check' title='"+_("Seen")+"'></i>";
if (f.message) {
@ -73,7 +73,12 @@ var banlist_init = function(token, my_boards, inMod) {
un = "<em>"+_("system")+"</em>";
}
return pre + un + suf;
} }
} },
id: {
name: (inMod)?_("Edit"):"&nbsp;", width: (inMod)?"35px":"0px", fmt: function(f) {
if (!inMod) return '';
return "<a href='?/edit_ban/"+f.id+"'>Edit</a>";
} }
}, {}, t);
$("#select-all").click(function(e) {

2
js/webm-settings.js

@ -8,7 +8,7 @@ if (typeof _ == 'undefined') {
var defaultSettings = {
"videoexpand": true,
"videohover": false,
"videovolume": 1.0
"videovolume": 0.75
};
// Non-persistent settings for when localStorage is absent/disabled

4
mod.php

@ -66,6 +66,7 @@ $pages = array(
'/ban' => 'secure_POST ban', // new ban
'/bans' => 'secure_POST bans', // ban list
'/bans.json' => 'secure bans_json', // ban list JSON
'/edit_ban/(\d+)' => 'secure_POST edit_ban',
'/ban-appeals' => 'secure_POST ban_appeals', // view ban appeals
'/recent/(\d+)' => 'recent_posts', // view recent posts
@ -112,6 +113,7 @@ $pages = array(
// This should always be at the end:
'/(\%b)/' => 'view_board',
'/(\%b)/' . preg_quote($config['file_index'], '!') => 'view_board',
'/(\%b)/' . preg_quote($config['file_catalog'], '!') => 'view_catalog',
'/(\%b)/' . str_replace('%d', '(\d+)', preg_quote($config['file_page'], '!')) => 'view_board',
'/(\%b)/' . preg_quote($config['dir']['res'], '!') .
str_replace('%d', '(\d+)', preg_quote($config['file_page50'], '!')) => 'view_thread50',
@ -141,7 +143,7 @@ foreach ($pages as $key => $callback) {
if (is_string($callback) && preg_match('/^secure /', $callback))
$key .= '(/(?P<token>[a-f0-9]{8}))?';
$key = str_replace('\%b', '?P<board>' . sprintf(substr($config['board_path'], 0, -1), $config['board_regex']), $key);
$new_pages[(!empty($key) && @$key[0] == '!') ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback;
$new_pages[(!empty($key) and $key[0] == '!') ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!u'] = $callback;
}
$pages = $new_pages;

23
post.php

@ -395,7 +395,7 @@ if (isset($_POST['delete'])) {
if (!isset($_POST['json_response'])) {
$index = $root . $board['dir'] . $config['file_index'];
echo Element('page.html', array('config' => $config, 'body' => '<div style="text-align:center"><a href="javascript:window.close()">[ ' . _('Close window') ." ]</a> <a href='$index'>[ " . _('Return') . ' ]</a></div>', 'title' => _('Report submitted!')));
echo Element($config['file_page_template'], array('config' => $config, 'body' => '<div style="text-align:center"><a href="javascript:window.close()">[ ' . _('Close window') ." ]</a> <a href='$index'>[ " . _('Return') . ' ]</a></div>', 'title' => _('Report submitted!')));
} else {
header('Content-Type: text/json');
echo json_encode(array('success' => true));
@ -444,7 +444,7 @@ if (isset($_POST['delete'])) {
error($config['error']['bot']);
// Check what reCAPTCHA has to say...
$resp = json_decode(file_get_contents(sprintf('https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s&remoteip=%s',
$resp = json_decode(file_get_contents(sprintf('https://www.recaptcha.net/recaptcha/api/siteverify?secret=%s&response=%s&remoteip=%s',
$config['recaptcha_private'],
urlencode($_POST['g-recaptcha-response']),
$_SERVER['REMOTE_ADDR'])), true);
@ -1046,6 +1046,8 @@ if (isset($_POST['delete'])) {
$thumb->_destroy();
}
$dont_copy_file = false;
if ($config['redraw_image'] || (!array_key_exists('exif_stripped', $file) && $config['strip_exif'] && ($file['extension'] == 'jpg' || $file['extension'] == 'jpeg'))) {
if (!$config['redraw_image'] && $config['use_exiftool']) {
@ -1079,16 +1081,15 @@ if (isset($_POST['delete'])) {
$file['thumbheight'] = $size[1];
$file['width'] = $size[0];
$file['height'] = $size[1];
}
else {
// not an image
$file['thumb'] = 'file';
$size = @getimagesize(sprintf($config['file_thumb'],
} else {
// not an image
$file['thumb'] = 'file';
$size = @getimagesize(sprintf($config['file_thumb'],
isset($config['file_icons'][$file['extension']]) ?
$config['file_icons'][$file['extension']] : $config['file_icons']['default']));
$file['thumbwidth'] = $size[0];
$file['thumbheight'] = $size[1];
$file['thumbwidth'] = $size[0];
$file['thumbheight'] = $size[1];
$dont_copy_file = false;
}
}
@ -1121,7 +1122,7 @@ if (isset($_POST['delete'])) {
}
}
if (!isset($dont_copy_file) || !$dont_copy_file) {
if (!$dont_copy_file) {
if (isset($file['file_tmp'])) {
if (!@rename($file['tmp_name'], $file['file_path']))
error($config['error']['nomove']);

4
report.php

@ -15,5 +15,5 @@ if ($config['report_captcha']) {
$captcha = null;
}
$body = Element('report.html', ['global' => $global, 'post' => $post, 'board' => $board, 'captcha' => $captcha, 'config' => $config]);
echo Element('page.html', ['config' => $config, 'body' => $body]);
$body = Element($config['file_report'], ['global' => $global, 'post' => $post, 'board' => $board, 'captcha' => $captcha, 'config' => $config]);
echo Element($config['file_page_template'], ['config' => $config, 'body' => $body]);

6
search.php

@ -72,7 +72,7 @@
if(!preg_match('/[^*^\s]/', $phrase) && empty($filters)) {
_syslog(LOG_WARNING, 'Query too broad.');
$body .= '<p class="unimportant" style="text-align:center">(Query too broad.)</p>';
echo Element('page.html', Array(
echo Element($config['file_page_template'], Array(
'config'=>$config,
'title'=>'Search',
'body'=>$body,
@ -133,7 +133,7 @@
if($query->rowCount() == $search_limit) {
_syslog(LOG_WARNING, 'Query too broad.');
$body .= '<p class="unimportant" style="text-align:center">('._('Query too broad.').')</p>';
echo Element('page.html', Array(
echo Element($config['file_page_template'], Array(
'config'=>$config,
'title'=>'Search',
'body'=>$body,
@ -167,7 +167,7 @@
$body .= '<p style="text-align:center" class="unimportant">('._('No results.').')</p>';
}
echo Element('page.html', Array(
echo Element($config['file_page_template'], Array(
'config'=>$config,
'title'=>_('Search'),
'boardlist'=>createBoardlist(),

BIN
static/banners/defaultbanner.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

166
stylesheets/style.css

@ -9,7 +9,7 @@ body {
}
.hidden {
display:none;
display: none;
}
a,a:visited {
@ -420,13 +420,13 @@ fieldset label {
}
div.pages {
color: #89A;
background: #D6DAF0;
display: inline-block;
padding: 8px;
margin: 8px 0 4px 0;
border-right: 1px solid #B7C5D9;
border-bottom: 1px solid #B7C5D9;
color: #89A;
background: #D6DAF0;
display: inline-block;
padding: 8px;
margin: 8px 0 4px 0;
border-right: 1px solid #B7C5D9;
border-bottom: 1px solid #B7C5D9;
}
div.pages.top {
@ -862,8 +862,6 @@ pre {
border: 1px solid;
}
#alert_div {
width: 500px;
}
@ -964,19 +962,18 @@ pre {
pre {
/* Better code tags */
max-width:inherit;
word-wrap:normal;
overflow:auto;
max-width: inherit;
word-wrap: normal;
overflow: auto;
display: block!important;
font-size:9pt;
font-family:monospace;
font-size: 9pt;
font-family: monospace;
}
span.pln {
color:grey;
coflor: grey;
}
@media screen and (min-width: 768px) {
.intro {
clear: none;
@ -988,38 +985,37 @@ span.pln {
}
.clearfix {
display: block;
clear: both;
visibility: hidden;
overflow: hidden;
font-size: 0px;
line-height: 0px;
box-sizing: border-box;
border: none;
height: 0;
margin: 0;
padding: 0;
width: 100%;
zoom: 1;
display: block;
clear: both;
visibility: hidden;
overflow: hidden;
font-size: 0px;
line-height: 0px;
box-sizing: border-box;
border: none;
height: 0;
margin: 0;
padding: 0;
width: 100%;
zoom: 1;
}
/* === SPECIFIC PAGES & FEATURES === */
/* Board List */
div.boardlist {
margin-top: 3px;
color: #89A;
font-size: 9pt;
margin-top: 3px;
color: #89A;
font-size: 9pt;
}
div.boardlist.bottom {
margin-top: 12px;
clear: both;
margin-top: 12px;
clear: both;
}
div.boardlist a {
text-decoration: none;
text-decoration: none;
}
/* Index Footer */
@ -1034,66 +1030,63 @@ div.boardlist a {
/* Threads */
/* Thread Footer */
#thread-interactions {
margin: 8px 0;
clear: both;
margin: 8px 0;
clear: both;
}
.thread-links {
#thread-links {
float: left;
}
.thread-links > a {
padding-left: none;
padding-right: 10px;
#thread-links > a {
padding-left: none;
padding-right: 10px;
}
#thread-quick-reply {
display: none;
position: absolute;
left: 50%;
right: 50%;
text-align: center;
width: 100px;
margin-left: -50px;
display: none;
position: absolute;
left: 50%;
right: 50%;
text-align: center;
width: 100px;
margin-left: -50px;
}
#thread_stats {
float: right;
float: right;
}
#post-moderation-fields {
float: right;
text-align: right;
}
#delete-fields {
}
#report-fields {
float: right;
text-align: right;
}
/* threadwatcher */
#watchlist {
display: none;
max-height: 250px;
overflow: auto;
border: 1px solid;
border-style: none solid solid none;
width: 50%;
margin: 0 auto;
margin-bottom: 10px;
display: none;
max-height: 250px;
overflow: auto;
border: 1px solid;
border-style: none solid solid none;
width: 50%;
margin: 0 auto;
margin-bottom: 10px;
}
.watchlist-inner, .watchlist-controls {
margin: 0 auto;
margin-top: 10px;
margin-bottom: 10px;
text-align: center;
margin: 0 auto;
margin-top: 10px;
margin-bottom: 10px;
text-align: center;
}
#watchlist-toggle, .watchThread, .watchlist-remove, #clearList, #clearGhosts {
cursor: pointer;
cursor: pointer;
}
#youtube-size input {
width: 50px;
width: 50px;
}
/* File selector */
@ -1109,9 +1102,11 @@ div.boardlist a {
background-color: rgba(200, 200, 200, 0.5);
overflow-y: auto;
}
.dropzone-wrap {
width: 100%;
}
.dropzone .file-hint {
color: rgba(0, 0, 0, 0.5);
cursor: pointer;
@ -1122,22 +1117,27 @@ div.boardlist a {
transition: 0.2s;
border: 2px dashed rgba(125, 125, 125, 0.4);
}
.file-hint:hover, .dropzone.dragover .file-hint {
color: rgba(0, 0, 0, 1);
border-color: rgba(125, 125, 125, 0.8);
}
.dropzone.dragover {
background-color: rgba(200, 200, 200, 1);
}
.dropzone .file-thumbs {
text-align: left;
width: 100%;
}
.dropzone .tmb-container {
padding: 3px;
overflow-x: hidden;
white-space: nowrap;
}
.dropzone .file-tmb {
height: 40px;
width: 70px;
@ -1148,11 +1148,13 @@ div.boardlist a {
background-size: cover;
background-position: center;
}
.dropzone .file-tmb span {
font-weight: 600;
position: relative;
top: 13px;
}
.dropzone .tmb-filename {
display: inline-block;
vertical-align: bottom;
@ -1160,6 +1162,7 @@ div.boardlist a {
position: relative;
margin-left: 5px;
}
.dropzone .remove-btn {
cursor: pointer;
color: rgba(125, 125, 125, 0.5);
@ -1170,6 +1173,7 @@ div.boardlist a {
margin-right: 5px;
font-size: 20px
}
.dropzone .remove-btn:hover {
color: rgba(125, 125, 125, 1);
}
@ -1185,6 +1189,7 @@ table.fileboard th, table.fileboard td {
padding: 2px;
text-align: center;
}
table.fileboard .intro a {
margin-left: 0px;
}
@ -1199,6 +1204,7 @@ table.fileboard .intro a {
background-color: rgba(0, 0, 0, 0.4);
overflow: auto;
}
#gallery_toolbar {
position: absolute;
right: 12%;
@ -1208,13 +1214,16 @@ table.fileboard .intro a {
background-color: rgba(0, 0, 0, 0.4);
text-align: right;
}
#gallery_images img {
width: 100%;
}
#gallery_toolbar a {
font-size: 28px;
padding-right: 5px;
}
#gallery_main {
position: absolute;
left: 0px;
@ -1229,25 +1238,30 @@ table.fileboard .intro a {
-webkit-transition: all 0.5s;
transition: all 0.5s;
}
#gallery_images img:hover, #gallery_images img.active {
opacity: 1;
}
#gallery_images img.active {
-webkit-box-shadow: 0px 0px 29px 2px rgba(255,255,255,1);
-moz-box-shadow: 0px 0px 29px 2px rgba(255,255,255,1);
box-shadow: 0px 0px 29px 2px rgba(255,255,255,1);
z-index: 1;
}
#gallery_main img, #gallery_main video {
max-width: 100%;
max-height: 100%;
position: absolute;
}
.own_post {
font-style: italic;
font-weight: normal;
opacity: .666;
}
div.mix {
display: inline-block;
}

2
templates/header.html

@ -21,7 +21,7 @@
<script type="text/javascript" src="/js/mod/mod_snippets.js"></script>
{% endif %}
{% endif %}
{% if config.recaptcha %}<script src="//www.google.com/recaptcha/api.js"></script>
{% if config.recaptcha %}<script src="//www.recaptcha.net/recaptcha/api.js"></script>
<style type="text/css">{% verbatim %}
#recaptcha_area {
float: none !important;

7
templates/index.html

@ -78,7 +78,7 @@
<span id="index-links-top" class="index-links">
<a id="index-bottom" href="#bottom">[{% trans %}Go to bottom{% endtrans %}]</a>
{% if config.catalog_link %}
<a id="index-catalog-top" href="{{ config.root }}{{ board.dir }}{{ config.catalog_link }}">[{% trans %}Catalog{% endtrans %}]</a>
<a id="index-catalog-top" href="{{ config.root }}{{ board.dir }}{% if mod %}{{ config.file_mod }}?/{% endif %}{{ config.catalog_link }}">[{% trans %}Catalog{% endtrans %}]</a>
{% endif %}
{% if config.board_search %}
{% if board.uri %}
@ -99,7 +99,7 @@
<span id="index-links-bottom" class="index-links">
<a id="index-top" href="#top">[{% trans %}Go to top{% endtrans %}]</a>
{% if config.catalog_link %}
<a id="index-catalog-bottom" href="{{ config.root }}{{ board.dir }}{{ config.catalog_link }}">[{% trans %}Catalog{% endtrans %}]</a>
<a id="index-catalog-bottom" href="{{ config.root }}{% if mod %}{{ config.file_mod }}?/{% endif %}{{ board.dir }}{{ config.catalog_link }}">[{% trans %}Catalog{% endtrans %}]</a>
{% endif %}
</span>
</div>
@ -110,6 +110,9 @@
{{ btn.prev }} {% for page in pages %}
[<a {% if page.selected %}class="selected"{% endif %}{% if not page.selected %}href="{{ page.link }}"{% endif %}>{{ page.num }}</a>]{% if loop.last %} {% endif %}
{% endfor %} {{ btn.next }}
{% if config.catalog_link %}
| <a href="{{ config.root }}{% if mod %}{{ config.file_mod }}?/{% endif %}{{ board.dir }}{{ config.catalog_link }}">{% trans %}Catalog{% endtrans %}</a>
{% endif %}
</div>
<a name="bottom"></a>
{{ boardlist.bottom }}

17
templates/mod/ban_form.html

@ -1,5 +1,7 @@
{% if post and board %}
{% set action = '?/' ~ board ~ '/ban/' ~ post %}
{% elseif edit_ban %}
{% set action = '' %}
{% else %}
{% set action = '?/ban' %}
{% endif %}
@ -24,7 +26,7 @@ $(document).ready(function(){
{% endif %}
<table>
{% if not edit_ban %}
<tr>
<th>
<label for="ip">{% trans 'IP' %} <span class="unimportant">{% trans '(or subnet)' %}</span></label>
@ -37,6 +39,7 @@ $(document).ready(function(){
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<th>
<label for="reason">{% trans 'Reason' %}</label>
@ -76,17 +79,17 @@ $(document).ready(function(){
<td>
<ul style="list-style:none;padding:2px 5px">
<li>
<input type="radio" name="board" value="*" id="ban-allboards"{% if not board %} checked{% endif %}>
<input type="radio" name="board" value="*" id="ban-allboards" {% if (edit_ban and not current_board) or not edit_ban %}checked{% endif %}>
<label style="display:inline" for="ban-allboards">
<em>{% trans 'all boards' %}</em>
</label>
</li>
{% for b in boards %}
{% for board in boards %}
<li>
<input type="radio" name="board" value="{{ b.uri }}" id="ban-board-{{ b.uri }}"{% if board == b.uri %} checked{% endif %}>
<label style="display:inline" for="ban-board-{{ b.uri }}">
{{ config.board_abbreviation|sprintf(b.uri) }} - {{ b.title|e }}
<input type="radio" name="board" value="{{ board.uri }}" id="ban-board-{{ board.uri }}" {% if edit_ban and current_board == board.uri %}checked{% endif %}>
<label style="display:inline" for="ban-board-{{ board.uri }}">
{{ config.board_abbreviation|sprintf(board.uri) }} - {{ board.title|e }}
</label>
</li>
{% endfor %}
@ -95,7 +98,7 @@ $(document).ready(function(){
</tr>
<tr>
<td></td>
<td><input name="new_ban" type="submit" value="{% trans 'New Ban' %}"></td>
<td><input name="new_ban" type="submit" value="{% if edit_ban %}{% trans 'Edit Ban' %}{% else %}{% trans 'New Ban' %}{% endif %}"></td>
</tr>
</table>
</form>

70
templates/mod/ban_history.html

@ -0,0 +1,70 @@
<table style="width:400px;margin-bottom:10px;border-bottom:1px solid #ddd;padding:5px">
<tr>
<th>{% trans 'Status' %}</th>
<td>
{% if config.mod.view_banexpired and ban.expires != 0 and ban.expires < time() %}
{% trans 'Expired' %}
{% else %}
{% trans 'Active' %}
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'IP' %}</th>
<td>{{ ban.cmask }}</td>
</tr>
<tr>
<th>{% trans 'Reason' %}</th>
<td>
{% if ban.reason %}
{{ ban.reason }}
{% else %}
<em>{% trans 'no reason' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Board' %}</th>
<td>
{% if ban.board %}
{{ config.board_abbreviation|sprintf(ban.board) }}
{% else %}
<em>{% trans 'all boards' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Set' %}</th>
<td>{{ ban.created|date(config.post_date) }}</td>
</tr>
<tr>
<th>{% trans 'Expires' %}</th>
<td>
{% if ban.expires %}
{{ ban.expires|date(config.post_date) }}
{% else %}
<em>{% trans 'never' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Seen' %}</th>
<td>
{% if ban.seen %}
{% trans 'Yes' %}
{% else %}
{% trans 'No' %}
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Staff' %}</th>
<td>
{% if ban.username %}
{{ ban.username|e }}
{% else %}
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
</tr>
</table>

1
templates/mod/dashboard.html

@ -1,3 +1,4 @@
{% if config.url_banner %}<img class="board_image" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %}
<fieldset>
<legend>{% trans 'Boards' %}</legend>

14
templates/mod/edit_ban.html

@ -0,0 +1,14 @@
<p style="text-align: center">
{% trans %}The previous ban will be replaced by the edited ban and the ban duration will start from the time of the edit.<br/>
The ban public message will <strong>not</strong> be changed.{% endtrans %}
</p>
<hr>
{% for ban in bans %}
<h2 style="text-align:center">{% trans %}Current ban{% endtrans %}</h2>
<form style="text-align:center; margin-bottom: unset"> {# dummy form to trigger css rules #}
{% include 'mod/ban_history.html' %}
</form>
<hr>
<h2 style="text-align:center">{% trans %}New ban{% endtrans %}</h2>
{% include 'mod/ban_form.html' with {'edit_ban': true} %}
{% endfor %}

1
templates/mod/login.html

@ -1,4 +1,5 @@
{% if error %}<h2 style="text-align:center">{{ error }}</h2>{% endif %}
{% if config.url_banner %}<img class="board_image" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %}
<form action="" method="post">
<table style="margin-top:25px;">
<tr>

16
templates/mod/statistics.html

@ -84,14 +84,14 @@
{% endif %}
</section>
<script type="text/javascript">{% raw %}
<script type="text/javascript">{% verbatim %}
{% endraw %}{% if (mod) or (public_hourly) %}{% raw %}
{% endverbatim %}{% if (mod) or (public_hourly) %}{% verbatim %}
var data_24h = {
labels: [ "AM", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11",
"PM", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" ],
series: [
[{% endraw %}{{ statistics_24h }}{% raw %}]
[{% endverbatim %}{{ statistics_24h }}{% verbatim %}]
]
};
@ -101,14 +101,14 @@ var options_24h = {
};
new Chartist.Line('#hourly', data_24h, options_24h);
{% endraw %}{% endif %}{% raw %}
{% endverbatim %}{% endif %}{% verbatim %}
var data_week = {
labels: [{% endraw %}{{ statistics_week_labels }}{% raw %}],
labels: [{% endverbatim %}{{ statistics_week_labels }}{% verbatim %}],
series: [
[{% endraw %}{{ statistics_week_past }}{% raw %}],
[{% endraw %}{{ statistics_week }}{% raw %}]
[{% endverbatim %}{{ statistics_week_past }}{% verbatim %}],
[{% endverbatim %}{{ statistics_week }}{% verbatim %}]
]
};
@ -126,4 +126,4 @@ var options_week = {
new Chartist.Bar('#week', data_week, options_week);
{% endraw %}</script>
{% endverbatim %}</script>

72
templates/mod/view_ip.html

@ -154,78 +154,10 @@
{% for ban in bans %}
<form action="" method="post" style="text-align:center">
<input type="hidden" name="token" value="{{ security_token }}">
<table style="width:400px;margin-bottom:10px;border-bottom:1px solid #ddd;padding:5px">
<tr>
<th>{% trans 'Status' %}</th>
<td>
{% if config.mod.view_banexpired and ban.expires != 0 and ban.expires < time() %}
{% trans 'Expired' %}
{% else %}
{% trans 'Active' %}
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'IP' %}</th>
<td>{{ ban.cmask }}</td>
</tr>
<tr>
<th>{% trans 'Reason' %}</th>
<td>
{% if ban.reason %}
{{ ban.reason }}
{% else %}
<em>{% trans 'no reason' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Board' %}</th>
<td>
{% if ban.board %}
{{ config.board_abbreviation|sprintf(ban.board) }}
{% else %}
<em>{% trans 'all boards' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Set' %}</th>
<td>{{ ban.created|date(config.post_date) }}</td>
</tr>
<tr>
<th>{% trans 'Expires' %}</th>
<td>
{% if ban.expires %}
{{ ban.expires|date(config.post_date) }}
{% else %}
<em>{% trans 'never' %}</em>
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Seen' %}</th>
<td>
{% if ban.seen %}
{% trans 'Yes' %}
{% else %}
{% trans 'No' %}
{% endif %}
</td>
</tr>
<tr>
<th>{% trans 'Staff' %}</th>
<td>
{% if ban.username %}
{{ ban.username|e }}
{% else %}
<em>{% trans 'deleted?' %}</em>
{% endif %}
</td>
</tr>
</table>
{% include 'mod/ban_history.html' %}
<input type="hidden" name="ban_id" value="{{ ban.id }}">
<input type="submit" name="unban" value="{% trans 'Remove ban' %}">
<input type="submit" name="edit_ban" value="{% trans 'Edit ban' %}">
</form>
{% endfor %}
</fieldset>

4
templates/post/image_identification.html

@ -1,5 +1,4 @@
{% if file.thumb != 'file' and config.image_identification %}
<span class='image_id'>
{% if config.image_identification_imgops %}
<a href="http://imgops.com/{{ config.domain }}{{ config.uri_img }}{{ file.file }}" target="_blank">ImgOps</a>
@ -13,5 +12,8 @@
{% if config.image_identification_iqdb %}
<a href="http://iqdb.org/?url={{ config.domain }}{{ config.uri_img }}{{ file.file }}" target="_blank">iqdb</a>
{% endif %}
{% if config.image_identification_yandex %}
<a rel="noreferrer" href="https://yandex.com/images/search?url={{ config.domain }}{{ config.uri_img }}{{ file.file }}&rpt=imagelike" target="_blank">Yandex</a>
{% endif %}
</span>
{% endif %}

6
templates/themes/catalog/catalog.html

@ -13,8 +13,10 @@
<body class="8chan vichan {% if mod %}is-moderator{% else %}is-not-moderator{% endif %} theme-catalog active-catalog" data-stylesheet="{% if config.default_stylesheet.1 != '' %}{{ config.default_stylesheet.1 }}{% else %}default{% endif %}">
{{ boardlist.top }}
<header>
<h1>/<a style="text-decoration:none;" href="./index.html">{{ board.uri }}</a>/ - {{ board.title|e }}</h1>
<div class="subtitle">{{ settings.subtitle }}</div>
<h1>/<a style="text-decoration:none;" href="{{link}}">{{ board.uri }}</a>/ - {{ board.title|e }}</h1>
<div class="subtitle">{{ settings.subtitle }}
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %}
</div>
</header>
{% if not no_post_form %}

68
templates/themes/catalog/theme.php

@ -67,7 +67,7 @@
/**
* Build and save the HTML of the catalog for the Ukko theme
*/
public function buildUkko() {
public function buildUkko($mod = false) {
global $board, $config;
$ukkoSettings = themeSettings('ukko');
@ -97,7 +97,7 @@
return strcmp($b['bump'], $a['bump']);
});
// Generate data for the template
$recent_posts = $this->generateRecentPosts($threads);
$recent_posts = $this->generateRecentPosts($threads, $mod);
// Generate board data for building
$board_original = $board;
@ -106,16 +106,18 @@
$board['title'] = $ukkoSettings['title'];
$board['subtitle'] = $ukkoSettings['subtitle'];
$this->saveForBoard($ukkoSettings['uri'], $recent_posts,
$config['root'] . $ukkoSettings['uri']);
$ret = $this->saveForBoard($ukkoSettings['uri'], $recent_posts,
$config['root'] . $ukkoSettings['uri'], $mod);
$board = $board_original;
return $ret;
}
/**
* Build and save the HTML of the catalog for the Rand theme
*/
public function buildRand() {
public function buildRand($mod = false) {
global $board, $config;
$randSettings = themeSettings('rand');
@ -143,7 +145,7 @@
// Randomize order
shuffle($threads);
// Generate data for the template
$recent_posts = $this->generateRecentPosts($threads);
$recent_posts = $this->generateRecentPosts($threads, $mod);
// Generate board data for building
$board_original = $board;
@ -152,16 +154,18 @@
$board['title'] = $randSettings['title'];
$board['subtitle'] = $randSettings['subtitle'];
$this->saveForBoard($randSettings['uri'], $recent_posts,
$config['root'] . $randSettings['uri']);
$ret = $this->saveForBoard($randSettings['uri'], $recent_posts,
$config['root'] . $randSettings['uri'], $mod);
$board = $board_original;
return $ret;
}
/**
* Build and save the HTML of the catalog for the given board
*/
public function build($board_name) {
public function build($board_name, $mod = false) {
if (!openBoard($board_name)) {
error(sprintf(_("Board %s doesn't exist"), $post['board']));
}
@ -177,9 +181,9 @@
}
// Generate data for the template
$recent_posts = $this->generateRecentPosts($threads);
$recent_posts = $this->generateRecentPosts($threads, $mod);
$this->saveForBoard($board_name, $recent_posts);
return $this->saveForBoard($board_name, $recent_posts, null, $mod);
}
private function buildThreadsQuery($board) {
@ -213,7 +217,7 @@
}
}
private function generateRecentPosts($threads) {
private function generateRecentPosts($threads, $mod = false) {
global $config, $board;
$posts = array();
@ -222,7 +226,10 @@
openBoard($post['board']);
}
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post);
if ($mod)
$post['link'] = $config['root'] . $config['file_mod'] . '?/'. $board['dir'] . $config['dir']['res'] . link_for($post);
else
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . link_for($post);
$post['board_name'] = $board['name'];
if ($post['embed'] && preg_match('/^https?:\/\/(\w+\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([a-zA-Z0-9\-_]{10,11})(&.+)?$/i', $post['embed'], $matches)) {
@ -260,13 +267,9 @@
return $posts;
}
private function saveForBoard($board_name, $recent_posts, $board_link = null) {
private function saveForBoard($board_name, $recent_posts, $board_link = null, $mod = false) {
global $board, $config;
if ($board_link === null) {
$board_link = $config['root'] . $board['dir'];
}
$required_scripts = array('js/jquery.min.js', 'js/jquery.mixitup.min.js',
'js/catalog.js');
@ -279,23 +282,34 @@
$antibot = create_antibot($board_name);
$antibot->reset();
file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', Array(
if ($board_link === null) {
$board_link = ($mod) ? $config['root'] . $config['file_mod'] . '?/' . $board['dir'] : $config['root'] . $board['dir'];
}
$element = Element('themes/catalog/catalog.html', Array(
'settings' => $this->settings,
'config' => $config,
'boardlist' => createBoardlist(),
'boardlist' => createBoardlist($mod),
'recent_images' => array(),
'recent_posts' => $recent_posts,
'stats' => array(),
'board_name' => $board_name,
'board' => $board,
'antibot' => $antibot,
'link' => $board_link
)));
'link' => $board_link,
'mod' => $mod
));
file_write($config['dir']['home'] . $board_name . '/index.rss', Element('themes/catalog/index.rss', Array(
'config' => $config,
'recent_posts' => $recent_posts,
'board' => $board
)));
if ($mod) {
return $element;
} else {
file_write($config['dir']['home'] . $board_name . '/catalog.html', $element);
file_write($config['dir']['home'] . $board_name . '/index.rss', Element('themes/catalog/index.rss', Array(
'config' => $config,
'recent_posts' => $recent_posts,
'board' => $board
)));
}
}
}

2
templates/thread.html

@ -74,7 +74,7 @@
<span id="thread-links-bottom" class="thread-links">
<a id="thread-goto-top" href="#top">[{% trans %}Go to top{% endtrans %}]</a>
{% if config.catalog_link %}
<a id="thread-catalog-bottom" href="{{ config.root }}{{ board.dir }}{{ config.catalog_link }}">[{% trans %}Catalog{% endtrans %}]</a>
<a id="thread-catalog-bottom" href="{{ config.root }}{% if mod %}{{ config.file_mod }}?/{% endif %}{{ board.dir }}{{ config.catalog_link }}">{% trans %}Catalog{% endtrans %}</a>
{% endif %}
<a id="thread-return-bottom" href="{{ return }}">[{% trans %}Return{% endtrans %}]</a>
</span>

Loading…
Cancel
Save