mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-27 17:00:52 +01:00
merge with vichan-gold
This commit is contained in:
commit
aef4425592
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,7 +14,7 @@
|
||||
/templates/cache
|
||||
|
||||
# other stuff
|
||||
.DS_Store?
|
||||
.DS_Store
|
||||
thumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
|
@ -1,6 +1,13 @@
|
||||
Tinyboard - A lightweight PHP imageboard.
|
||||
==========================================
|
||||
|
||||
Tinyboard + vichan-devel
|
||||
------------
|
||||
Tinyboard branch taking lightweightness somewhat more liberally. Running live at
|
||||
https://pl.vichan.net/ (Polish) and http://vichan.net/ (International; may be outdated).
|
||||
|
||||
It contains many changes from original Tinyboard, mainly in frontend area.
|
||||
|
||||
About
|
||||
------------
|
||||
Tinyboard is a light-weight, fast, highly configurable and user-friendly
|
||||
|
123
inc/api.php
Normal file
123
inc/api.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Tinyboard Development Group
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for generating json API compatible with 4chan API
|
||||
*/
|
||||
class Api {
|
||||
|
||||
/**
|
||||
* Translation from local fields to fields in 4chan-style API
|
||||
*/
|
||||
public static $postFields = array(
|
||||
'id' => 'no',
|
||||
'thread' => 'resto',
|
||||
'subject' => 'sub',
|
||||
'email' => 'email',
|
||||
'name' => 'name',
|
||||
'trip' => 'trip',
|
||||
'capcode' => 'capcode',
|
||||
'body' => 'com',
|
||||
'time' => 'time',
|
||||
'thumb' => 'thumb', // non-compatible field
|
||||
'thumbx' => 'tn_w',
|
||||
'thumby' => 'tn_h',
|
||||
'file' => 'file', // non-compatible field
|
||||
'filex' => 'w',
|
||||
'filey' => 'h',
|
||||
'filesize' => 'fsize',
|
||||
//'filename' => 'filename',
|
||||
'omitted' => 'omitted_posts',
|
||||
'omitted_images' => 'omitted_images',
|
||||
//'posts' => 'replies',
|
||||
//'ip' => '',
|
||||
'sticky' => 'sticky',
|
||||
'locked' => 'locked',
|
||||
//'bumplocked' => '',
|
||||
//'embed' => '',
|
||||
//'root' => '',
|
||||
//'mod' => '',
|
||||
//'hr' => '',
|
||||
);
|
||||
|
||||
static $ints = array(
|
||||
'no' => 1,
|
||||
'resto' => 1,
|
||||
'time' => 1,
|
||||
'tn_w' => 1,
|
||||
'tn_h' => 1,
|
||||
'w' => 1,
|
||||
'h' => 1,
|
||||
'fsize' => 1,
|
||||
'omitted_posts' => 1,
|
||||
'omitted_images' => 1,
|
||||
'sticky' => 1,
|
||||
'locked' => 1,
|
||||
);
|
||||
|
||||
private function translatePost($post) {
|
||||
$apiPost = array();
|
||||
foreach (self::$postFields as $local => $translated) {
|
||||
if (!isset($post->$local))
|
||||
continue;
|
||||
|
||||
$toInt = isset(self::$ints[$translated]);
|
||||
$val = $post->$local;
|
||||
if ($val !== null && $val !== '') {
|
||||
$apiPost[$translated] = $toInt ? (int) $val : $val;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($post->filename)) {
|
||||
$dotPos = strrpos($post->filename, '.');
|
||||
$apiPost['filename'] = substr($post->filename, 0, $dotPos);
|
||||
$apiPost['ext'] = substr($post->filename, $dotPos);
|
||||
}
|
||||
|
||||
return $apiPost;
|
||||
}
|
||||
|
||||
function translateThread(Thread $thread) {
|
||||
$apiPosts = array();
|
||||
$op = $this->translatePost($thread);
|
||||
$op['resto'] = 0;
|
||||
$apiPosts['posts'][] = $op;
|
||||
|
||||
foreach ($thread->posts as $p) {
|
||||
$apiPosts['posts'][] = $this->translatePost($p);
|
||||
}
|
||||
|
||||
return $apiPosts;
|
||||
}
|
||||
|
||||
function translatePage(array $threads) {
|
||||
$apiPage = array();
|
||||
foreach ($threads as $thread) {
|
||||
$apiPage['threads'][] = $this->translateThread($thread);
|
||||
}
|
||||
return $apiPage;
|
||||
}
|
||||
|
||||
function translateCatalogPage(array $threads) {
|
||||
$apiPage = array();
|
||||
foreach ($threads as $thread) {
|
||||
$ts = $this->translateThread($thread);
|
||||
$apiPage['threads'][] = current($ts['posts']);
|
||||
}
|
||||
return $apiPage;
|
||||
}
|
||||
|
||||
function translateCatalog($catalog) {
|
||||
$apiCatalog = array();
|
||||
foreach ($catalog as $page => $threads) {
|
||||
$apiPage = $this->translateCatalogPage($threads);
|
||||
$apiPage['page'] = $page;
|
||||
$apiCatalog[] = $apiPage;
|
||||
}
|
||||
|
||||
return $apiCatalog;
|
||||
}
|
||||
}
|
@ -326,6 +326,11 @@
|
||||
// Reply limit (stops bumping thread when this is reached)
|
||||
$config['reply_limit'] = 250;
|
||||
|
||||
// Image hard limit (stops allowing new image replies when this is reached if not zero)
|
||||
$config['image_hard_limit'] = 0;
|
||||
// Reply hard limit (stops allowing new replies when this is reached if not zero)
|
||||
$config['reply_hard_limit'] = 0;
|
||||
|
||||
// Strip repeating characters when making hashes
|
||||
$config['robot_enable'] = false;
|
||||
$config['robot_strip_repeating'] = true;
|
||||
@ -379,6 +384,9 @@
|
||||
// When true, a blank password will be used for files (not usable for deletion).
|
||||
$config['field_disable_password'] = false;
|
||||
|
||||
// Require users to see the ban page at least once for a ban even if it has since expired?
|
||||
$config['require_ban_view'] = false;
|
||||
|
||||
/*
|
||||
* ====================
|
||||
* Markup settings
|
||||
@ -552,6 +560,9 @@
|
||||
// Number of characters in the poster ID (maximum is 40)
|
||||
$config['poster_id_length'] = 5;
|
||||
|
||||
// Show thread subject in page title?
|
||||
$config['thread_subject_in_title'] = false;
|
||||
|
||||
// Page footer
|
||||
$config['footer'][] = 'All trademarks, copyrights, comments, and images on this page are owned by and are the responsibility of their respective parties.';
|
||||
|
||||
@ -696,6 +707,8 @@
|
||||
$config['error']['noboard'] = _('Invalid board!');
|
||||
$config['error']['nonexistant'] = _('Thread specified does not exist.');
|
||||
$config['error']['locked'] = _('Thread locked. You may not reply at this time.');
|
||||
$config['error']['reply_hard_limit'] = _('Thread has reached its maximum reply limit.');
|
||||
$config['error']['image_hard_limit'] = _('Thread has reached its maximum image limit.');
|
||||
$config['error']['nopost'] = _('You didn\'t make a post.');
|
||||
$config['error']['flood'] = _('Flood detected; Post discarded.');
|
||||
$config['error']['spam'] = _('Your request looks automated; Post discarded.');
|
||||
@ -723,6 +736,7 @@
|
||||
$config['error']['captcha'] = _('You seem to have mistyped the verification.');
|
||||
|
||||
// Moderator errors
|
||||
$config['error']['toomanyunban'] = _('You are only allowed to unban %s users at a time. You tried to unban %u users.');
|
||||
$config['error']['invalid'] = _('Invalid username and/or password.');
|
||||
$config['error']['notamod'] = _('You are not a mod…');
|
||||
$config['error']['invalidafter'] = _('Invalid username and/or password. Your user may have been deleted or changed.');
|
||||
@ -810,6 +824,9 @@
|
||||
* Mod settings
|
||||
* ====================
|
||||
*/
|
||||
|
||||
// Limit how many bans can be removed via the ban list. (Set too -1 to remove limit.)
|
||||
$config['mod']['unban_limit'] = 5;
|
||||
|
||||
// Whether or not to lock moderator sessions to the IP address that was logged in with.
|
||||
$config['mod']['lock_ip'] = true;
|
||||
@ -900,8 +917,8 @@
|
||||
$config['mod']['shadow_mesage'] = 'Moved to %s.';
|
||||
// Capcode to use when posting the above message.
|
||||
$config['mod']['shadow_capcode'] = 'Mod';
|
||||
// Name to use when posting the above message.
|
||||
$config['mod']['shadow_name'] = $config['anonymous'];
|
||||
// Name to use when posting the above message. If false, the default board name will be used. If something else, that will be used.
|
||||
$config['mod']['shadow_name'] = false;
|
||||
|
||||
// Wait indefinitely when rebuilding everything
|
||||
$config['mod']['rebuild_timelimit'] = 0;
|
||||
@ -912,6 +929,9 @@
|
||||
// Edit raw HTML in posts by default
|
||||
$config['mod']['raw_html_default'] = false;
|
||||
|
||||
// Automatically dismiss all reports regarding a thread when it is locked
|
||||
$config['mod']['dismiss_reports_on_lock'] = true;
|
||||
|
||||
// Probably best not to change these:
|
||||
if (!defined('JANITOR')) {
|
||||
define('JANITOR', 0, true);
|
||||
@ -1028,6 +1048,9 @@
|
||||
$config['mod']['createusers'] = ADMIN;
|
||||
// View the moderation log
|
||||
$config['mod']['modlog'] = ADMIN;
|
||||
// View relevant moderation log entries on IP address pages (ie. ban history, etc.)
|
||||
// Warning: Can be pretty resource exhaustive if your mod logs are huge.
|
||||
$config['mod']['modlog_ip'] = MOD;
|
||||
// Create a PM (viewing mod usernames)
|
||||
$config['mod']['create_pm'] = JANITOR;
|
||||
// Read any PM, sent to or from anybody
|
||||
|
@ -118,7 +118,7 @@ function pm_snippet($body, $len=null) {
|
||||
// calculate strlen() so we can add "..." after if needed
|
||||
$strlen = mb_strlen($body);
|
||||
|
||||
$body = substr($body, 0, $len);
|
||||
$body = mb_substr($body, 0, $len);
|
||||
|
||||
// Re-escape the characters.
|
||||
return '<em>' . utf8tohtml($body) . ($strlen > $len ? '…' : '') . '</em>';
|
||||
@ -204,7 +204,7 @@ function truncate($body, $url, $max_lines = false, $max_chars = false) {
|
||||
}
|
||||
} else {
|
||||
// remove broken HTML entity at the end (if existent)
|
||||
$body = preg_replace('/&[^;]+$/', '', $body);
|
||||
$body = preg_replace('/&[^;]*$/', '', $body);
|
||||
}
|
||||
|
||||
$body .= '<span class="toolong">Post too long. Click <a href="' . $url . '">here</a> to view the full text.</span>';
|
||||
@ -213,6 +213,25 @@ function truncate($body, $url, $max_lines = false, $max_chars = false) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
function bidi_cleanup($str){
|
||||
# Removes all embedded RTL and LTR unicode formatting blocks in a string so that
|
||||
# it can be used inside another without controlling its direction.
|
||||
# More info: http://www.iamcal.com/understanding-bidirectional-text/
|
||||
#
|
||||
# LRE - U+202A - 0xE2 0x80 0xAA
|
||||
# RLE - U+202B - 0xE2 0x80 0xAB
|
||||
# LRO - U+202D - 0xE2 0x80 0xAD
|
||||
# RLO - U+202E - 0xE2 0x80 0xAE
|
||||
#
|
||||
# PDF - U+202C - 0xE2 0x80 0xAC
|
||||
#
|
||||
$explicits = '\xE2\x80\xAA|\xE2\x80\xAB|\xE2\x80\xAD|\xE2\x80\xAE';
|
||||
$pdf = '\xE2\x80\xAC';
|
||||
|
||||
$str = preg_replace("!(?<explicits>$explicits)|(?<pdf>$pdf)!", '', $str);
|
||||
return $str;
|
||||
}
|
||||
|
||||
function secure_link_confirm($text, $title, $confirm_message, $href) {
|
||||
global $config;
|
||||
|
||||
|
@ -81,7 +81,7 @@ class Filter {
|
||||
else
|
||||
$all_boards = false;
|
||||
|
||||
$query = prepare("INSERT INTO `bans` VALUES (NULL, :ip, :mod, :set, :expires, :reason, :board)");
|
||||
$query = prepare("INSERT INTO `bans` VALUES (NULL, :ip, :mod, :set, :expires, :reason, :board, 0)");
|
||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||
$query->bindValue(':mod', -1);
|
||||
$query->bindValue(':set', time());
|
||||
|
@ -13,6 +13,7 @@ require_once 'inc/display.php';
|
||||
require_once 'inc/template.php';
|
||||
require_once 'inc/database.php';
|
||||
require_once 'inc/events.php';
|
||||
require_once 'inc/api.php';
|
||||
require_once 'inc/lib/gettext/gettext.inc';
|
||||
|
||||
// the user is not currently logged in as a moderator
|
||||
@ -78,7 +79,7 @@ function loadConfig() {
|
||||
|
||||
if ($config['debug']) {
|
||||
if (!isset($debug)) {
|
||||
$debug = array('sql' => array(), 'purge' => array(), 'cached' => array());
|
||||
$debug = array('sql' => array(), 'purge' => array(), 'cached' => array(), 'write' => array());
|
||||
$debug['start'] = microtime(true);
|
||||
}
|
||||
}
|
||||
@ -239,12 +240,12 @@ function create_antibot($board, $thread = null) {
|
||||
return _create_antibot($board, $thread);
|
||||
}
|
||||
|
||||
function rebuildThemes($action) {
|
||||
function rebuildThemes($action, $board = false) {
|
||||
// List themes
|
||||
$query = query("SELECT `theme` FROM `theme_settings` WHERE `name` IS NULL AND `value` IS NULL") or error(db_error());
|
||||
|
||||
while ($theme = $query->fetch()) {
|
||||
rebuildTheme($theme['theme'], $action);
|
||||
rebuildTheme($theme['theme'], $action, $board);
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,7 +262,7 @@ function loadThemeConfig($_theme) {
|
||||
return $theme;
|
||||
}
|
||||
|
||||
function rebuildTheme($theme, $action) {
|
||||
function rebuildTheme($theme, $action, $board = false) {
|
||||
global $config, $_theme;
|
||||
$_theme = $theme;
|
||||
|
||||
@ -270,7 +271,7 @@ function rebuildTheme($theme, $action) {
|
||||
if (file_exists($config['dir']['themes'] . '/' . $_theme . '/theme.php')) {
|
||||
require_once $config['dir']['themes'] . '/' . $_theme . '/theme.php';
|
||||
|
||||
$theme['build_function']($action, themeSettings($_theme));
|
||||
$theme['build_function']($action, themeSettings($_theme), $board);
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,11 +329,19 @@ function setupBoard($array) {
|
||||
}
|
||||
|
||||
function openBoard($uri) {
|
||||
$board = getBoardInfo($uri);
|
||||
if ($board) {
|
||||
setupBoard($board);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getBoardInfo($uri) {
|
||||
global $config;
|
||||
|
||||
if ($config['cache']['enabled'] && ($board = cache::get('board_' . $uri))) {
|
||||
setupBoard($board);
|
||||
return true;
|
||||
return $board;
|
||||
}
|
||||
|
||||
$query = prepare("SELECT * FROM `boards` WHERE `uri` = :uri LIMIT 1");
|
||||
@ -342,27 +351,16 @@ function openBoard($uri) {
|
||||
if ($board = $query->fetch()) {
|
||||
if ($config['cache']['enabled'])
|
||||
cache::set('board_' . $uri, $board);
|
||||
setupBoard($board);
|
||||
return true;
|
||||
return $board;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function boardTitle($uri) {
|
||||
global $config;
|
||||
if ($config['cache']['enabled'] && ($board = cache::get('board_' . $uri))) {
|
||||
$board = getBoardInfo($uri);
|
||||
if ($board)
|
||||
return $board['title'];
|
||||
}
|
||||
|
||||
$query = prepare("SELECT `title` FROM `boards` WHERE `uri` = :uri LIMIT 1");
|
||||
$query->bindValue(':uri', $uri);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
if ($title = $query->fetch()) {
|
||||
return $title['title'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -395,7 +393,7 @@ function purge($uri) {
|
||||
}
|
||||
|
||||
function file_write($path, $data, $simple = false, $skip_purge = false) {
|
||||
global $config;
|
||||
global $config, $debug;
|
||||
|
||||
if (preg_match('/^remote:\/\/(.+)\:(.+)$/', $path, $m)) {
|
||||
if (isset($config['remote'][$m[1]])) {
|
||||
@ -422,7 +420,7 @@ function file_write($path, $data, $simple = false, $skip_purge = false) {
|
||||
error('Unable to truncate file: ' . $path);
|
||||
|
||||
// Write data
|
||||
if (fwrite($fp, $data) === false)
|
||||
if (($bytes = fwrite($fp, $data)) === false)
|
||||
error('Unable to write to file: ' . $path);
|
||||
|
||||
// Unlock
|
||||
@ -448,6 +446,10 @@ function file_write($path, $data, $simple = false, $skip_purge = false) {
|
||||
purge($path);
|
||||
}
|
||||
|
||||
if ($config['debug']) {
|
||||
$debug['write'][] = $path . ': ' . $bytes . ' bytes';
|
||||
}
|
||||
|
||||
event('write', $path);
|
||||
}
|
||||
|
||||
@ -578,6 +580,12 @@ function ago($timestamp) {
|
||||
function displayBan($ban) {
|
||||
global $config;
|
||||
|
||||
if (!$ban['seen']) {
|
||||
$query = prepare("UPDATE `bans` SET `seen` = 1 WHERE `id` = :id");
|
||||
$query->bindValue(':id', $ban['id'], PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
}
|
||||
|
||||
$ban['ip'] = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
// Show banned page and exit
|
||||
@ -604,12 +612,12 @@ function checkBan($board = 0) {
|
||||
if (event('check-ban', $board))
|
||||
return true;
|
||||
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND `ip` = :ip ORDER BY `expires` IS NULL DESC, `expires` DESC, `expires` DESC LIMIT 1");
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND `ip` = :ip ORDER BY `expires` IS NULL DESC, `expires` DESC, `expires` DESC LIMIT 1");
|
||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||
$query->bindValue(':board', $board);
|
||||
$query->execute() or error(db_error($query));
|
||||
if ($query->rowCount() < 1 && $config['ban_range']) {
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND :ip LIKE REPLACE(REPLACE(`ip`, '%', '!%'), '*', '%') ESCAPE '!' ORDER BY `expires` IS NULL DESC, `expires` DESC LIMIT 1");
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board) AND :ip LIKE REPLACE(REPLACE(`ip`, '%', '!%'), '*', '%') ESCAPE '!' ORDER BY `expires` IS NULL DESC, `expires` DESC LIMIT 1");
|
||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||
$query->bindValue(':board', $board);
|
||||
$query->execute() or error(db_error($query));
|
||||
@ -617,7 +625,7 @@ function checkBan($board = 0) {
|
||||
|
||||
if ($query->rowCount() < 1 && $config['ban_cidr'] && !isIPv6()) {
|
||||
// my most insane SQL query yet
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board)
|
||||
$query = prepare("SELECT `set`, `expires`, `reason`, `board`, `seen`, `bans`.`id` FROM `bans` WHERE (`board` IS NULL OR `board` = :board)
|
||||
AND (
|
||||
`ip` REGEXP '^(\[0-9]+\.\[0-9]+\.\[0-9]+\.\[0-9]+\)\/(\[0-9]+)$'
|
||||
AND
|
||||
@ -634,15 +642,29 @@ function checkBan($board = 0) {
|
||||
if ($ban = $query->fetch()) {
|
||||
if ($ban['expires'] && $ban['expires'] < time()) {
|
||||
// Ban expired
|
||||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id LIMIT 1");
|
||||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
|
||||
$query->bindValue(':id', $ban['id'], PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
if ($config['require_ban_view'] && !$ban['seen']) {
|
||||
displayBan($ban);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
displayBan($ban);
|
||||
}
|
||||
|
||||
// I'm not sure where else to put this. It doesn't really matter where; it just needs to be called every now and then to keep the ban list tidy.
|
||||
purge_bans();
|
||||
}
|
||||
|
||||
// No reason to keep expired bans in the database (except those that haven't been viewed yet)
|
||||
function purge_bans() {
|
||||
$query = prepare("DELETE FROM `bans` WHERE `expires` IS NOT NULL AND `expires` < :time AND `seen` = 1");
|
||||
$query->bindValue(':time', time());
|
||||
$query->execute() or error(db_error($query));
|
||||
}
|
||||
|
||||
function threadLocked($id) {
|
||||
@ -725,13 +747,13 @@ function post(array $post) {
|
||||
$query->bindValue(':password', $post['password']);
|
||||
$query->bindValue(':ip', isset($post['ip']) ? $post['ip'] : $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
if ($post['op'] && $post['mod'] && $post['sticky']) {
|
||||
if ($post['op'] && $post['mod'] && isset($post['sticky']) && $post['sticky']) {
|
||||
$query->bindValue(':sticky', 1, PDO::PARAM_INT);
|
||||
} else {
|
||||
$query->bindValue(':sticky', 0, PDO::PARAM_INT);
|
||||
}
|
||||
|
||||
if ($post['op'] && $post['mod'] && $post['locked']) {
|
||||
if ($post['op'] && $post['mod'] && isset($post['locked']) && $post['locked']) {
|
||||
$query->bindValue(':locked', 1, PDO::PARAM_INT);
|
||||
} else {
|
||||
$query->bindValue(':locked', 0, PDO::PARAM_INT);
|
||||
@ -967,6 +989,8 @@ function index($page, $mod=false) {
|
||||
|
||||
if ($query->rowcount() < 1 && $page > 1)
|
||||
return false;
|
||||
|
||||
$threads = array();
|
||||
while ($th = $query->fetch()) {
|
||||
$thread = new Thread(
|
||||
$th['id'], $th['subject'], $th['email'], $th['name'], $th['trip'], $th['capcode'], $th['body'], $th['time'], $th['thumb'],
|
||||
@ -986,12 +1010,8 @@ function index($page, $mod=false) {
|
||||
$replies = array_reverse($posts->fetchAll(PDO::FETCH_ASSOC));
|
||||
|
||||
if (count($replies) == ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
|
||||
$count = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
|
||||
$count->bindValue(':thread', $th['id'], PDO::PARAM_INT);
|
||||
$count->execute() or error(db_error($count));
|
||||
$count = $count->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$omitted = array('post_count' => $count[0], 'image_count' => $count[1]);
|
||||
$count = numPosts($th['id']);
|
||||
$omitted = array('post_count' => $count['replies'], 'image_count' => $count['images']);
|
||||
} else {
|
||||
$omitted = false;
|
||||
}
|
||||
@ -1019,7 +1039,8 @@ function index($page, $mod=false) {
|
||||
$thread->omitted = $omitted['post_count'] - ($th['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']);
|
||||
$thread->omitted_images = $omitted['image_count'] - $num_images;
|
||||
}
|
||||
|
||||
|
||||
$threads[] = $thread;
|
||||
$body .= $thread->build(true);
|
||||
}
|
||||
|
||||
@ -1028,7 +1049,8 @@ function index($page, $mod=false) {
|
||||
'body' => $body,
|
||||
'post_url' => $config['post_url'],
|
||||
'config' => $config,
|
||||
'boardlist' => createBoardlist($mod)
|
||||
'boardlist' => createBoardlist($mod),
|
||||
'threads' => $threads
|
||||
);
|
||||
}
|
||||
|
||||
@ -1134,14 +1156,19 @@ function checkRobot($body) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns an associative array with 'replies' and 'images' keys
|
||||
function numPosts($id) {
|
||||
global $board;
|
||||
$query = prepare(sprintf("SELECT COUNT(*) as `count` FROM `posts_%s` WHERE `thread` = :thread", $board['uri']));
|
||||
$query = prepare(sprintf("SELECT COUNT(*) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(*) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $board['uri'], $board['uri']));
|
||||
$query->bindValue(':thread', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
$result = $query->fetch();
|
||||
return $result['count'];
|
||||
$num_posts = $query->fetch();
|
||||
$num_posts = $num_posts['num'];
|
||||
$num_images = $query->fetch();
|
||||
$num_images = $num_images['num'];
|
||||
|
||||
return array('replies' => $num_posts, 'images' => $num_images);
|
||||
}
|
||||
|
||||
function muteTime() {
|
||||
@ -1213,6 +1240,9 @@ function buildIndex() {
|
||||
$pages = getPages();
|
||||
$antibot = create_antibot($board['uri']);
|
||||
|
||||
$api = new Api();
|
||||
$catalog = array();
|
||||
|
||||
$page = 1;
|
||||
while ($page <= $config['max_pages'] && $content = index($page)) {
|
||||
$filename = $board['dir'] . ($page == 1 ? $config['file_index'] : sprintf($config['file_page'], $page));
|
||||
@ -1225,6 +1255,14 @@ function buildIndex() {
|
||||
$content['antibot'] = $antibot;
|
||||
|
||||
file_write($filename, Element('index.html', $content));
|
||||
|
||||
// json api
|
||||
$threads = $content['threads'];
|
||||
$json = json_encode($api->translatePage($threads));
|
||||
$jsonFilename = $board['dir'] . ($page-1) . ".json"; // pages should start from 0
|
||||
file_write($jsonFilename, $json);
|
||||
|
||||
$catalog[$page-1] = $threads;
|
||||
|
||||
$page++;
|
||||
}
|
||||
@ -1232,8 +1270,16 @@ function buildIndex() {
|
||||
for (;$page<=$config['max_pages'];$page++) {
|
||||
$filename = $board['dir'] . ($page==1 ? $config['file_index'] : sprintf($config['file_page'], $page));
|
||||
file_unlink($filename);
|
||||
|
||||
$jsonFilename = $board['dir'] . ($page-1) . ".json";
|
||||
file_unlink($jsonFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// json api catalog
|
||||
$json = json_encode($api->translateCatalog($catalog));
|
||||
$jsonFilename = $board['dir'] . "catalog.json";
|
||||
file_write($jsonFilename, $json);
|
||||
}
|
||||
|
||||
function buildJavascript() {
|
||||
@ -1246,6 +1292,12 @@ function buildJavascript() {
|
||||
'uri' => addslashes((!empty($uri) ? $config['uri_stylesheets'] : '') . $uri));
|
||||
}
|
||||
|
||||
// Check if we have translation for the javascripts; if yes, we add it to additional javascripts
|
||||
list($pure_locale) = explode(".", $config['locale']);
|
||||
if (file_exists ($jsloc = "inc/locale/".$pure_locale."/LC_MESSAGES/javascript.js")) {
|
||||
array_unshift($config['additional_javascript'], $jsloc);
|
||||
}
|
||||
|
||||
$script = Element('main.js', array(
|
||||
'config' => $config,
|
||||
'stylesheets' => $stylesheets
|
||||
@ -1365,8 +1417,8 @@ function unicodify($body) {
|
||||
// En and em- dashes are rendered exactly the same in
|
||||
// most monospace fonts (they look the same in code
|
||||
// editors).
|
||||
$body = str_replace('--', '–', $body); // en dash
|
||||
$body = str_replace('---', '—', $body); // em dash
|
||||
$body = str_replace('--', '–', $body); // en dash
|
||||
|
||||
return $body;
|
||||
}
|
||||
@ -1494,7 +1546,7 @@ function markup(&$body, $track_cites = false) {
|
||||
}
|
||||
|
||||
function utf8tohtml($utf8) {
|
||||
return mb_encode_numericentity(htmlspecialchars($utf8, ENT_NOQUOTES, 'UTF-8'), array(0x80, 0xffff, 0, 0xffff), 'UTF-8');
|
||||
return htmlspecialchars($utf8, ENT_NOQUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
function buildThread($id, $return=false, $mod=false) {
|
||||
@ -1535,8 +1587,9 @@ function buildThread($id, $return=false, $mod=false) {
|
||||
error($config['error']['nonexistant']);
|
||||
|
||||
$body = Element('thread.html', array(
|
||||
'board'=>$board,
|
||||
'body'=>$thread->build(),
|
||||
'board' => $board,
|
||||
'thread' => $thread,
|
||||
'body' => $thread->build(),
|
||||
'config' => $config,
|
||||
'id' => $id,
|
||||
'mod' => $mod,
|
||||
@ -1549,6 +1602,12 @@ function buildThread($id, $return=false, $mod=false) {
|
||||
return $body;
|
||||
|
||||
file_write($board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], $id), $body);
|
||||
|
||||
// json api
|
||||
$api = new Api();
|
||||
$json = json_encode($api->translateThread($thread));
|
||||
$jsonFilename = $board['dir'] . $config['dir']['res'] . $id . ".json";
|
||||
file_write($jsonFilename, $json);
|
||||
}
|
||||
|
||||
function rrmdir($dir) {
|
||||
|
@ -25,6 +25,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
|
||||
'until' => new Twig_Filter_Function('until'),
|
||||
'split' => new Twig_Filter_Function('twig_split_filter'),
|
||||
'push' => new Twig_Filter_Function('twig_push_filter'),
|
||||
'bidi_cleanup' => new Twig_Filter_Function('bidi_cleanup'),
|
||||
'addslashes' => new Twig_Filter_Function('addslashes')
|
||||
);
|
||||
}
|
||||
@ -57,8 +58,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
|
||||
}
|
||||
|
||||
function twig_timezone_function() {
|
||||
// there's probably a much easier way of doing this
|
||||
return sprintf("%s%02d", ($hr = (int)floor(($tz = date('Z')) / 3600)) > 0 ? '+' : '-', abs($hr)) . ':' . sprintf("%02d", (($tz / 3600) - $hr) * 60);
|
||||
return 'Z';
|
||||
}
|
||||
|
||||
function twig_split_filter($str, $delim) {
|
||||
@ -75,7 +75,7 @@ function twig_remove_whitespace_filter($data) {
|
||||
}
|
||||
|
||||
function twig_date_filter($date, $format) {
|
||||
return strftime($format, $date);
|
||||
return gmstrftime($format, $date);
|
||||
}
|
||||
|
||||
function twig_hasPermission_filter($mod, $permission, $board = null) {
|
||||
|
1
inc/locale/pl_PL/LC_MESSAGES/javascript.js
Normal file
1
inc/locale/pl_PL/LC_MESSAGES/javascript.js
Normal file
@ -0,0 +1 @@
|
||||
l10n = {"Submit":"Wy\u015blij","Quick reply":"Szybka odpowied\u017a","Posting mode: Replying to <small>>>{0}<\/small>":"Tryb postowania: Odpowied\u017a na <small>>>{0}<\/small>","Return":"Powr\u00f3t","Click reply to view.":"Kliknij Odpowied\u017a aby zobaczy\u0107.","Click to expand":"Kliknij aby rozwin\u0105\u0107","Hide expanded replies":"Schowaj rozwini\u0119te odpowiedzi","Mon":"pon","Tue":"wto","Wed":"\u015bro","Thu":"czw","Fri":"pi\u0105","Sat":"sob","Sun":"nie","Show locked threads":"Poka\u017c zablokowane tematy","Hide locked threads":"Schowaj zablokowane tematy","Forced anonymity":"Wymuszona anonimowo\u015b\u0107","enabled":"w\u0142\u0105czona","disabled":"wy\u0142\u0105czona","Password":"Has\u0142o","Delete file only":"Usu\u0144 tylko plik","File":"Plik","Delete":"Usu\u0144","Reason":"Pow\u00f3d","Report":"Zg\u0142oszenie"};
|
121
inc/locale/pl_PL/LC_MESSAGES/javascript.po
Normal file
121
inc/locale/pl_PL/LC_MESSAGES/javascript.po
Normal file
@ -0,0 +1,121 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-07-18 16:31-0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: ../../../../js/quick-reply.js:20 ../../../../js/quick-reply.js:21
|
||||
msgid "Submit"
|
||||
msgstr "Wyślij"
|
||||
|
||||
#: ../../../../js/quick-reply.js:30 ../../../../js/quick-reply.js:31
|
||||
msgid "Quick reply"
|
||||
msgstr "Szybka odpowiedź"
|
||||
|
||||
#: ../../../../js/quick-reply.js:32 ../../../../js/quick-reply.js:33
|
||||
msgid "Posting mode: Replying to <small>>>{0}</small>"
|
||||
msgstr "Tryb postowania: Odpowiedź na <small>>>{0}</small>"
|
||||
|
||||
#: ../../../../js/quick-reply.js:32 ../../../../js/quick-reply.js:33
|
||||
msgid "Return"
|
||||
msgstr "Powrót"
|
||||
|
||||
#: ../../../../js/expand.js:20
|
||||
msgid "Click reply to view."
|
||||
msgstr "Kliknij Odpowiedź aby zobaczyć."
|
||||
|
||||
#: ../../../../js/expand.js:20
|
||||
msgid "Click to expand"
|
||||
msgstr "Kliknij aby rozwinąć"
|
||||
|
||||
#: ../../../../js/expand.js:41
|
||||
msgid "Hide expanded replies"
|
||||
msgstr "Schowaj rozwinięte odpowiedzi"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Mon"
|
||||
msgstr "pon"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Tue"
|
||||
msgstr "wto"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Wed"
|
||||
msgstr "śro"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Thu"
|
||||
msgstr "czw"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Fri"
|
||||
msgstr "pią"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Sat"
|
||||
msgstr "sob"
|
||||
|
||||
#: ../../../../js/local-time.js:40
|
||||
msgid "Sun"
|
||||
msgstr "nie"
|
||||
|
||||
#: ../../../../js/toggle-locked-threads.js:39
|
||||
#: ../../../../js/toggle-locked-threads.js:54
|
||||
msgid "Show locked threads"
|
||||
msgstr "Pokaż zablokowane tematy"
|
||||
|
||||
#: ../../../../js/toggle-locked-threads.js:39
|
||||
#: ../../../../js/toggle-locked-threads.js:54
|
||||
msgid "Hide locked threads"
|
||||
msgstr "Schowaj zablokowane tematy"
|
||||
|
||||
#: ../../../../js/forced-anon.js:59 ../../../../js/forced-anon.js:65
|
||||
#: ../../../../js/forced-anon.js:69
|
||||
msgid "Forced anonymity"
|
||||
msgstr "Wymuszona anonimowość"
|
||||
|
||||
#: ../../../../js/forced-anon.js:59 ../../../../js/forced-anon.js:65
|
||||
msgid "enabled"
|
||||
msgstr "włączona"
|
||||
|
||||
#: ../../../../js/forced-anon.js:59 ../../../../js/forced-anon.js:69
|
||||
msgid "disabled"
|
||||
msgstr "wyłączona"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:27
|
||||
msgid "Password"
|
||||
msgstr "Hasło"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:29
|
||||
msgid "Delete file only"
|
||||
msgstr "Usuń tylko plik"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:30
|
||||
msgid "File"
|
||||
msgstr "Plik"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:31
|
||||
msgid "Delete"
|
||||
msgstr "Usuń"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:35
|
||||
msgid "Reason"
|
||||
msgstr "Powód"
|
||||
|
||||
#: ../../../../js/quick-post-controls.js:37
|
||||
msgid "Report"
|
||||
msgstr "Zgłoszenie"
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
inc/locale/pt_BR/LC_MESSAGES/tinyboard.mo
Normal file
BIN
inc/locale/pt_BR/LC_MESSAGES/tinyboard.mo
Normal file
Binary file not shown.
844
inc/locale/pt_BR/LC_MESSAGES/tinyboard.po
Normal file
844
inc/locale/pt_BR/LC_MESSAGES/tinyboard.po
Normal file
@ -0,0 +1,844 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2013-04-21 11:29-0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural==(n != 1);n"
|
||||
|
||||
#: ../../inc/lib/gettext/examples/pigs_dropin.php:77
|
||||
msgid ""
|
||||
"This is how the story goes.\n"
|
||||
"\n"
|
||||
msgstr "Era uma vez\n\n"
|
||||
|
||||
#: ../../inc/functions.php:1046 ../../inc/functions.php:1060
|
||||
msgid "Previous"
|
||||
msgstr "Anterior"
|
||||
|
||||
#: ../../inc/functions.php:1065 ../../inc/functions.php:1074
|
||||
msgid "Next"
|
||||
msgstr "Proximo"
|
||||
|
||||
#: ../../inc/display.php:91 ../../inc/mod/pages.php:62
|
||||
msgid "Login"
|
||||
msgstr "Login"
|
||||
|
||||
#: ../../inc/config.php:687
|
||||
msgid "Lurk some more before posting."
|
||||
msgstr "Lurke mais antes de postar."
|
||||
|
||||
#: ../../inc/config.php:688
|
||||
msgid "You look like a bot."
|
||||
msgstr "Você não parece humano."
|
||||
|
||||
#: ../../inc/config.php:689
|
||||
msgid "Your browser sent an invalid or no HTTP referer."
|
||||
msgstr "Seu browser enviou um referial HTTP inválido ou não enviou o referencial."
|
||||
|
||||
#: ../../inc/config.php:690
|
||||
#, php-format
|
||||
msgid "The %s field was too long."
|
||||
msgstr "O campo %s é longo demais."
|
||||
|
||||
#: ../../inc/config.php:691
|
||||
msgid "The body was too long."
|
||||
msgstr "O corpo do texto é longo demais."
|
||||
|
||||
#: ../../inc/config.php:692
|
||||
msgid "The body was too short or empty."
|
||||
msgstr "O corpo do texto é pequeno demais ou inexistente."
|
||||
|
||||
#: ../../inc/config.php:693
|
||||
msgid "You must upload an image."
|
||||
msgstr "Você deve fazer upload de uma imagem."
|
||||
|
||||
#: ../../inc/config.php:694
|
||||
msgid "The server failed to handle your upload."
|
||||
msgstr "O servidor não conseguiu lidar com seu upload."
|
||||
|
||||
#: ../../inc/config.php:695
|
||||
msgid "Unsupported image format."
|
||||
msgstr "Tipo de imagem não aceito."
|
||||
|
||||
#: ../../inc/config.php:696
|
||||
msgid "Invalid board!"
|
||||
msgstr "Board inválida!"
|
||||
|
||||
#: ../../inc/config.php:697
|
||||
msgid "Thread specified does not exist."
|
||||
msgstr "O tópico especificado não existe.."
|
||||
|
||||
#: ../../inc/config.php:698
|
||||
msgid "Thread locked. You may not reply at this time."
|
||||
msgstr "Tópico trancado, você não pode postar."
|
||||
|
||||
#: ../../inc/config.php:699
|
||||
msgid "You didn't make a post."
|
||||
msgstr "Você não escreveu uma mensagem."
|
||||
|
||||
#: ../../inc/config.php:700
|
||||
msgid "Flood detected; Post discarded."
|
||||
msgstr "Flood detectado; Sua mensagem foi descartada."
|
||||
|
||||
#: ../../inc/config.php:701
|
||||
msgid "Your request looks automated; Post discarded."
|
||||
msgstr "Sua requisição parece automatizada; Mensagem descartada."
|
||||
|
||||
#: ../../inc/config.php:702
|
||||
msgid "Unoriginal content!"
|
||||
msgstr "Conteudo não original!"
|
||||
|
||||
#: ../../inc/config.php:703
|
||||
#, php-format
|
||||
msgid "Unoriginal content! You have been muted for %d seconds."
|
||||
msgstr "Conteudo não original! Você está impedido de postar por %d segundos."
|
||||
|
||||
#: ../../inc/config.php:704
|
||||
#, php-format
|
||||
msgid "You are muted! Expires in %d seconds."
|
||||
msgstr "Você está impedido de postar! Expira em %d segundos."
|
||||
|
||||
#: ../../inc/config.php:705
|
||||
#, php-format
|
||||
msgid "Your IP address is listed in %s."
|
||||
msgstr "Seu IP está listado em %s."
|
||||
|
||||
#: ../../inc/config.php:706
|
||||
msgid "Too many links; flood detected."
|
||||
msgstr "Links demais; Flood detectado."
|
||||
|
||||
#: ../../inc/config.php:707
|
||||
msgid "Too many cites; post discarded."
|
||||
msgstr "Citações demais; Post descartado."
|
||||
|
||||
#: ../../inc/config.php:708
|
||||
msgid "Too many cross-board links; post discarded."
|
||||
msgstr "Links entre boards demais; Post descartado."
|
||||
|
||||
#: ../../inc/config.php:709
|
||||
msgid "You didn't select anything to delete."
|
||||
msgstr "Você não selecionou nada para deletar."
|
||||
|
||||
#: ../../inc/config.php:710
|
||||
msgid "You didn't select anything to report."
|
||||
msgstr "Você não selecionou nada para denunciar."
|
||||
|
||||
#: ../../inc/config.php:711
|
||||
msgid "You can't report that many posts at once."
|
||||
msgstr "Você não pode denunciar tantas mensagens ao mesmo tempo."
|
||||
|
||||
#: ../../inc/config.php:712
|
||||
msgid "Wrong password…"
|
||||
msgstr "Senha incorreta…"
|
||||
|
||||
#: ../../inc/config.php:713
|
||||
msgid "Invalid image."
|
||||
msgstr "Imagem inválida."
|
||||
|
||||
#: ../../inc/config.php:714
|
||||
msgid "Unknown file extension."
|
||||
msgstr "Extenção de arquivo desconhecida."
|
||||
|
||||
#: ../../inc/config.php:715
|
||||
msgid "Maximum file size: %maxsz% bytes<br>Your file's size: %filesz% bytes"
|
||||
msgstr "Tamanho maximo de arquivos: %maxsz% bytes<br>O tamanho do seu arquivo: %filesz% bytes"
|
||||
|
||||
#: ../../inc/config.php:716
|
||||
msgid "The file was too big."
|
||||
msgstr "Seu arquivo é grande demais."
|
||||
|
||||
#: ../../inc/config.php:717
|
||||
msgid "Invalid archive!"
|
||||
msgstr "Arquivo inválido!"
|
||||
|
||||
#: ../../inc/config.php:718
|
||||
#, php-format
|
||||
msgid "That file <a href=\"%s\">already exists</a>!"
|
||||
msgstr "O arquivo <a href=\"%s\">já existe</a>!"
|
||||
|
||||
#: ../../inc/config.php:719
|
||||
#, php-format
|
||||
msgid "That file <a href=\"%s\">already exists</a> in this thread!"
|
||||
msgstr "O arquivo <a href=\"%s\">já existe</a> neste tópico!"
|
||||
|
||||
#: ../../inc/config.php:720
|
||||
#, php-format
|
||||
msgid "You'll have to wait another %s before deleting that."
|
||||
msgstr "Você terá que esperar %s segundos antes de deletar isso."
|
||||
|
||||
#: ../../inc/config.php:721
|
||||
msgid "MIME type detection XSS exploit (IE) detected; post discarded."
|
||||
msgstr "Exploit XSS do tipo MIME (IE) detectado; mensagem descartada."
|
||||
|
||||
#: ../../inc/config.php:722
|
||||
msgid "Couldn't make sense of the URL of the video you tried to embed."
|
||||
msgstr "Não consegui processar a URL do video que você tentou integrar"
|
||||
|
||||
#: ../../inc/config.php:723
|
||||
msgid "You seem to have mistyped the verification."
|
||||
msgstr "Você errou o codigo de verificação."
|
||||
|
||||
#: ../../inc/config.php:726
|
||||
msgid "Invalid username and/or password."
|
||||
msgstr "Login e/ou senha inválido(s)."
|
||||
|
||||
#: ../../inc/config.php:727
|
||||
msgid "You are not a mod…"
|
||||
msgstr "Você não é mod…"
|
||||
|
||||
#: ../../inc/config.php:728
|
||||
msgid ""
|
||||
"Invalid username and/or password. Your user may have been deleted or changed."
|
||||
msgstr "Login e/ou senha inválido(s). Seu login deve ter sido mudado ou removido."
|
||||
|
||||
#: ../../inc/config.php:729
|
||||
msgid "Invalid/malformed cookies."
|
||||
msgstr "Cookies inválidos ou mal formados."
|
||||
|
||||
#: ../../inc/config.php:730
|
||||
msgid "Your browser didn't submit an input when it should have."
|
||||
msgstr "Seu browser não enviou uma entrada quando ele deveria."
|
||||
|
||||
#: ../../inc/config.php:731
|
||||
#, php-format
|
||||
msgid "The %s field is required."
|
||||
msgstr "O campo %s é necessário."
|
||||
|
||||
#: ../../inc/config.php:732
|
||||
#, php-format
|
||||
msgid "The %s field was invalid."
|
||||
msgstr "O campo %s é inválido."
|
||||
|
||||
#: ../../inc/config.php:733
|
||||
#, php-format
|
||||
msgid "There is already a %s board."
|
||||
msgstr "A board %s já existe."
|
||||
|
||||
#: ../../inc/config.php:734
|
||||
msgid "You don't have permission to do that."
|
||||
msgstr "Você não tem permissão para fazer isso."
|
||||
|
||||
#: ../../inc/config.php:735
|
||||
msgid "That post doesn't exist…"
|
||||
msgstr "Este post já existe…"
|
||||
|
||||
#: ../../inc/config.php:736
|
||||
msgid "Page not found."
|
||||
msgstr "Pagina não encontrada."
|
||||
|
||||
#: ../../inc/config.php:737
|
||||
#, php-format
|
||||
msgid "That mod <a href=\"?/users/%d\">already exists</a>!"
|
||||
msgstr "Este mod <a href=\"?/users/%d\">já existe</a>!"
|
||||
|
||||
#: ../../inc/config.php:738
|
||||
msgid "That theme doesn't exist!"
|
||||
msgstr "Este tema não existe!"
|
||||
|
||||
#: ../../inc/config.php:739
|
||||
msgid "Invalid security token! Please go back and try again."
|
||||
msgstr "Token de segurança inválido! Retorne e tente de novo."
|
||||
|
||||
#: ../../inc/mod/pages.php:66
|
||||
msgid "Confirm action"
|
||||
msgstr "Confirmar ação"
|
||||
|
||||
#: ../../inc/mod/pages.php:110
|
||||
msgid "Could not find current version! (Check .installed)"
|
||||
msgstr "Não foi possivel encontrar a versão atual! (Cheque o .installed)"
|
||||
|
||||
#: ../../inc/mod/pages.php:151
|
||||
msgid "Dashboard"
|
||||
msgstr "Dashboard"
|
||||
|
||||
#: ../../inc/mod/pages.php:228
|
||||
msgid "Edit board"
|
||||
msgstr "Editar board"
|
||||
|
||||
#: ../../inc/mod/pages.php:261
|
||||
msgid "Couldn't open board after creation."
|
||||
msgstr "Não foi possivel abrir a board após a criação."
|
||||
|
||||
#: ../../inc/mod/pages.php:276
|
||||
msgid "New board"
|
||||
msgstr "Nova board"
|
||||
|
||||
#: ../../inc/mod/pages.php:322
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:96
|
||||
msgid "Noticeboard"
|
||||
msgstr "Quadro de noticias"
|
||||
|
||||
#: ../../inc/mod/pages.php:382
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:166
|
||||
msgid "News"
|
||||
msgstr "Noticias"
|
||||
|
||||
#: ../../inc/mod/pages.php:422 ../../inc/mod/pages.php:449
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:255
|
||||
msgid "Moderation log"
|
||||
msgstr "Log da moderação"
|
||||
|
||||
#: ../../inc/mod/pages.php:592
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:247
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:65
|
||||
msgid "IP"
|
||||
msgstr "IP"
|
||||
|
||||
#: ../../inc/mod/pages.php:602 ../../inc/mod/pages.php:993
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:377
|
||||
msgid "New ban"
|
||||
msgstr "Nova expulsão"
|
||||
|
||||
#: ../../inc/mod/pages.php:670
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:224
|
||||
msgid "Ban list"
|
||||
msgstr "Lista de expulsões"
|
||||
|
||||
#: ../../inc/mod/pages.php:765
|
||||
msgid "Target and source board are the same."
|
||||
msgstr "Board alvo e fonte são as mesmas."
|
||||
|
||||
#: ../../inc/mod/pages.php:927
|
||||
msgid "Impossible to move thread; there is only one board."
|
||||
msgstr "Impossivel de mover o tópico; Só existe uma board."
|
||||
|
||||
#: ../../inc/mod/pages.php:931
|
||||
msgid "Move thread"
|
||||
msgstr "Mover tópico"
|
||||
|
||||
#: ../../inc/mod/pages.php:1045
|
||||
msgid "Edit post"
|
||||
msgstr "Editar mensagem"
|
||||
|
||||
#: ../../inc/mod/pages.php:1271 ../../inc/mod/pages.php:1320
|
||||
msgid "Edit user"
|
||||
msgstr "Editar usuário"
|
||||
|
||||
#: ../../inc/mod/pages.php:1333
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:232
|
||||
msgid "Manage users"
|
||||
msgstr "Administrar usuários"
|
||||
|
||||
#: ../../inc/mod/pages.php:1395 ../../inc/mod/pages.php:1467
|
||||
msgid "New PM for"
|
||||
msgstr "Nova MP para"
|
||||
|
||||
#: ../../inc/mod/pages.php:1399
|
||||
msgid "Private message"
|
||||
msgstr "Mensagem pessoal"
|
||||
|
||||
#: ../../inc/mod/pages.php:1420
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:171
|
||||
msgid "PM inbox"
|
||||
msgstr "Entrada de MP"
|
||||
|
||||
#: ../../inc/mod/pages.php:1531 ../../inc/mod/pages.php:1535
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:263
|
||||
msgid "Rebuild"
|
||||
msgstr "Reconstruir"
|
||||
|
||||
#: ../../inc/mod/pages.php:1621
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:207
|
||||
msgid "Report queue"
|
||||
msgstr "Fila de denuncias"
|
||||
|
||||
#: ../../inc/mod/pages.php:1743
|
||||
msgid "Config editor"
|
||||
msgstr "Editor de configurações"
|
||||
|
||||
#: ../../inc/mod/pages.php:1753
|
||||
msgid "Themes directory doesn't exist!"
|
||||
msgstr "Diretório de temas não existe!"
|
||||
|
||||
#: ../../inc/mod/pages.php:1755
|
||||
msgid "Cannot open themes directory; check permissions."
|
||||
msgstr "Não é possivel abrir diretorio de temas; reveja suas permissões."
|
||||
|
||||
#: ../../inc/mod/pages.php:1769
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:247
|
||||
msgid "Manage themes"
|
||||
msgstr "Administrar temas"
|
||||
|
||||
#: ../../inc/mod/pages.php:1831
|
||||
#, php-format
|
||||
msgid "Installed theme: %s"
|
||||
msgstr "Tema instalado: %s"
|
||||
|
||||
#: ../../inc/mod/pages.php:1841
|
||||
#, php-format
|
||||
msgid "Configuring theme: %s"
|
||||
msgstr "Configurando tema: %s"
|
||||
|
||||
#: ../../inc/mod/pages.php:1869
|
||||
#, php-format
|
||||
msgid "Rebuilt theme: %s"
|
||||
msgstr "Reconstruir tema: %s"
|
||||
|
||||
#: ../../inc/mod/pages.php:1908
|
||||
msgid "Debug: Anti-spam"
|
||||
msgstr "Debug: Anti-spam"
|
||||
|
||||
#: ../../inc/mod/pages.php:1932
|
||||
msgid "Debug: Recent posts"
|
||||
msgstr "Debug: Mensagens recentes"
|
||||
|
||||
#: ../../inc/mod/pages.php:1956
|
||||
msgid "Debug: SQL"
|
||||
msgstr ""
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:19
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:29
|
||||
msgid "Boards"
|
||||
msgstr "Boards"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:57
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:183
|
||||
msgid "edit"
|
||||
msgstr "editar"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:74
|
||||
msgid "Create new board"
|
||||
msgstr "Criar nova board"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:84
|
||||
msgid "Messages"
|
||||
msgstr "Mensagens"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:120
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:98
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:125
|
||||
msgid "no subject"
|
||||
msgstr "sem assunto"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:161
|
||||
msgid "View all noticeboard entries"
|
||||
msgstr "Ver todas as noticias do quadro de noticias"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:192
|
||||
msgid "Administration"
|
||||
msgstr "Administração"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:239
|
||||
msgid "Change password"
|
||||
msgstr "Mudar senha"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:271
|
||||
msgid "Configuration"
|
||||
msgstr "Configuração"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:282
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:293
|
||||
msgid "Search"
|
||||
msgstr "Procurar"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:289
|
||||
msgid "Phrase:"
|
||||
msgstr "Frase:"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:297
|
||||
msgid ""
|
||||
"(Search is case-insensitive, and based on keywords. To match exact phrases, "
|
||||
"use \"quotes\". Use an asterisk (*) for wildcard.)"
|
||||
msgstr ""
|
||||
"(A procura não diferencia maiúsculas de minusculas, e baseia-se em palavras chave. para procurar por frases exatas, "
|
||||
"use \"quotes\". Utilize um asterisco (*) como coringa.)"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:309
|
||||
msgid "Debug"
|
||||
msgstr "Debug"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:313
|
||||
msgid "Anti-spam"
|
||||
msgstr "Anti-spam"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:316
|
||||
msgid "Recent posts"
|
||||
msgstr "Mensagens recentes"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:322
|
||||
msgid "SQL"
|
||||
msgstr "SQL"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:360
|
||||
msgid "User account"
|
||||
msgstr "Conta de usuário"
|
||||
|
||||
#: ../../templates/cache/3a/df/ab38a77244cb9c729b4c6f99759a.php:365
|
||||
msgid "Logout"
|
||||
msgstr "Sair"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:21
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:21
|
||||
msgid "New post"
|
||||
msgstr "Nova mensagem"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:27
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:31
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:36
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:27
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:55
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:36
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:63
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:53
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:98
|
||||
msgid "Subject"
|
||||
msgstr "Assunto"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:42
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:69
|
||||
msgid "Body"
|
||||
msgstr "Mensagem"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:49
|
||||
msgid "Post to noticeboard"
|
||||
msgstr "Postar no quadro de notícias"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:73
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:100
|
||||
msgid "delete"
|
||||
msgstr "deletar"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:106
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:133
|
||||
msgid "by"
|
||||
msgstr "por"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:118
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:112
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:344
|
||||
msgid "deleted?"
|
||||
msgstr "deletado?"
|
||||
|
||||
#: ../../templates/cache/26/6f/05ca0da8ac09e2c2216cba2b6f95.php:125
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:136
|
||||
msgid "at"
|
||||
msgstr "em"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:74
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:169
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:331
|
||||
msgid "Staff"
|
||||
msgstr "Equipe"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:77
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:179
|
||||
msgid "Note"
|
||||
msgstr "Nota"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:80
|
||||
msgid "Date"
|
||||
msgstr "Data"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:86
|
||||
msgid "Actions"
|
||||
msgstr "Ações"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:142
|
||||
msgid "remove"
|
||||
msgstr "remover"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:189
|
||||
msgid "New note"
|
||||
msgstr "Nova nota"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:226
|
||||
msgid "Status"
|
||||
msgstr "Situação"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:233
|
||||
msgid "Expired"
|
||||
msgstr "Expirado"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:238
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:256
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:32
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:30
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:90
|
||||
msgid "Reason"
|
||||
msgstr "Razão"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:269
|
||||
msgid "no reason"
|
||||
msgstr "sem razão especificada"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:278
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:20
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:142
|
||||
msgid "Board"
|
||||
msgstr "Board"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:291
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:150
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:83
|
||||
msgid "all boards"
|
||||
msgstr "todas as boards"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:300
|
||||
msgid "Set"
|
||||
msgstr "Configurar"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:309
|
||||
msgid "Expires"
|
||||
msgstr "Expira em"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:322
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:137
|
||||
msgid "never"
|
||||
msgstr "nunca"
|
||||
|
||||
#: ../../templates/cache/24/a0/f1ddafed7a8f9625e747a5ca33f5.php:357
|
||||
msgid "Remove ban"
|
||||
msgstr "Remover expulsão"
|
||||
|
||||
#: ../../templates/cache/72/55/0d64283f30702de83ecfcb71f86a.php:25
|
||||
msgid "There are no reports."
|
||||
msgstr "Não há denúncias no momento."
|
||||
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:19
|
||||
msgid "Delete Post"
|
||||
msgstr "Deletar Mensagem"
|
||||
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:22
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:218
|
||||
msgid "File"
|
||||
msgstr "Arquivo"
|
||||
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:23
|
||||
#: ../../templates/cache/04/54/656aa217f895c90eae78024fa060.php:41
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:310
|
||||
msgid "Password"
|
||||
msgstr "Senha"
|
||||
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:27
|
||||
msgid "Delete"
|
||||
msgstr "Deletar"
|
||||
|
||||
#: ../../templates/cache/82/40/4c4a4b82f787181e6500ce83494d.php:36
|
||||
msgid "Report"
|
||||
msgstr "Denunciar"
|
||||
|
||||
#: ../../templates/cache/04/54/656aa217f895c90eae78024fa060.php:28
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:23
|
||||
msgid "Username"
|
||||
msgstr "Usuário"
|
||||
|
||||
#: ../../templates/cache/04/54/656aa217f895c90eae78024fa060.php:52
|
||||
msgid "Continue"
|
||||
msgstr "Prosseguir"
|
||||
|
||||
#: ../../templates/cache/f5/e3/343716327c6183713f70a3fb57f1.php:94
|
||||
#: ../../templates/cache/aa/f6/f10fd83961bcd8c947af6ddf919d.php:175
|
||||
#: ../../templates/cache/62/8c/21348d46377c3e1b3f8c476ba376.php:63
|
||||
msgid "Return to dashboard"
|
||||
msgstr "Voltar à dashboard"
|
||||
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:36
|
||||
msgid "Report date"
|
||||
msgstr "Data da denúncia"
|
||||
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:45
|
||||
msgid "Reported by"
|
||||
msgstr "Denunciado por"
|
||||
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:63
|
||||
msgid "Discard abuse report"
|
||||
msgstr "Descartar denúncia desnecessária"
|
||||
|
||||
#: ../../templates/cache/9c/7b/891291bc84f8844c30cefdb949cf.php:80
|
||||
msgid "Discard all abuse reports by this IP address"
|
||||
msgstr "Descartar todas denúncias desnecessárias deste IP"
|
||||
|
||||
#: ../../templates/cache/aa/f6/f10fd83961bcd8c947af6ddf919d.php:183
|
||||
msgid "Posting mode: Reply"
|
||||
msgstr "Modo de postagem: Resposta"
|
||||
|
||||
#: ../../templates/cache/aa/f6/f10fd83961bcd8c947af6ddf919d.php:186
|
||||
#: ../../templates/cache/aa/f6/f10fd83961bcd8c947af6ddf919d.php:232
|
||||
msgid "Return"
|
||||
msgstr "Voltar"
|
||||
|
||||
#: ../../templates/cache/c8/8b/242bf87b3b6a29a67cdd09a3afeb.php:76
|
||||
msgid "Post news entry"
|
||||
msgstr "Postar nova notícia"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:66
|
||||
msgid "(or subnet)"
|
||||
msgstr "(ou subnet)"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:80
|
||||
msgid "hidden"
|
||||
msgstr "oculto"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:107
|
||||
msgid "Message"
|
||||
msgstr "Mensagem"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:117
|
||||
msgid "public; attached to post"
|
||||
msgstr "público; anexado à mensagem"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:133
|
||||
msgid "Length"
|
||||
msgstr "Tamanho"
|
||||
|
||||
#: ../../templates/cache/18/9c/c365d711719f494c684aab98a4ae.php:192
|
||||
msgid "New Ban"
|
||||
msgstr "Nova Expulsão"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:20
|
||||
msgid "ID"
|
||||
msgstr "ID"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:26
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:35
|
||||
msgid "Last action"
|
||||
msgstr "Ultima ação"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:61
|
||||
msgid "Janitor"
|
||||
msgstr "Faxineiro"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:64
|
||||
msgid "Mod"
|
||||
msgstr "Moderador"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:67
|
||||
msgid "Admin"
|
||||
msgstr "Administrador"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:78
|
||||
msgid "none"
|
||||
msgstr "nenhum"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:153
|
||||
msgid "Promote"
|
||||
msgstr "Promover"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:163
|
||||
msgid "Demote"
|
||||
msgstr "Rebaixar"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:173
|
||||
msgid "log"
|
||||
msgstr "registro"
|
||||
|
||||
#: ../../templates/cache/c5/a7/fac83da087ee6e24edaf09e01122.php:193
|
||||
msgid "PM"
|
||||
msgstr "MP"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:105
|
||||
msgid "File:"
|
||||
msgstr "Arquivo:"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:117
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:129
|
||||
msgid "Spoiler Image"
|
||||
msgstr "Imagem Spoiler"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:463
|
||||
msgid "Reply"
|
||||
msgstr "Responder"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:490
|
||||
msgid "1 post"
|
||||
msgid_plural "%count% posts"
|
||||
msgstr[0] "1 mensagem"
|
||||
msgstr[1] "%count% mensagens"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:496
|
||||
msgid "and"
|
||||
msgstr "e"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:507
|
||||
msgid "1 image reply"
|
||||
msgid_plural "%count% image replies"
|
||||
msgstr[0] "1 resposta com imagem"
|
||||
msgstr[1] "%count% respostas com imagem"
|
||||
|
||||
#: ../../templates/cache/d8/f2/7780eb1adcdbda7e332659e3fb4f.php:512
|
||||
msgid "omitted. Click reply to view."
|
||||
msgstr "omitidas. Clique em responder para visualizar."
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:40
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:76
|
||||
msgid "Email"
|
||||
msgstr "E-mail"
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:62
|
||||
msgid "Update"
|
||||
msgstr "Atualizar"
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:69
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:138
|
||||
msgid "Comment"
|
||||
msgstr "Comentar"
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:89
|
||||
msgid "Currently editing raw HTML."
|
||||
msgstr "Editando em HTML puro."
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:96
|
||||
msgid "Edit markup instead?"
|
||||
msgstr "Editar markup em vez disso?"
|
||||
|
||||
#: ../../templates/cache/39/42/cbc36382096edfa72a8bc26e4514.php:105
|
||||
msgid "Edit raw HTML instead?"
|
||||
msgstr "Editar em HTML puro em vez disso?"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:111
|
||||
msgid "Submit"
|
||||
msgstr "Enviar"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:159
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:185
|
||||
msgid "Verification"
|
||||
msgstr "Verification"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:236
|
||||
msgid "Embed"
|
||||
msgstr "Inserir"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:259
|
||||
msgid "Flags"
|
||||
msgstr "Sinalizações"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:268
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:271
|
||||
msgid "Sticky"
|
||||
msgstr "Fixar"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:280
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:283
|
||||
msgid "Lock"
|
||||
msgstr "Trancar"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:292
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:295
|
||||
msgid "Raw HTML"
|
||||
msgstr "HTML Puro"
|
||||
|
||||
#: ../../templates/cache/0c/37/9331df01df7c2986d77a02d3beb0.php:319
|
||||
msgid "(For file deletion.)"
|
||||
msgstr "(Para excluir arquivos)"
|
@ -98,8 +98,10 @@ if (isset($_COOKIE[$config['cookies']['mod']])) {
|
||||
// Should be username:hash:salt
|
||||
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
|
||||
if (count($cookie) != 3) {
|
||||
// Malformed cookies
|
||||
destroyCookies();
|
||||
error($config['error']['malformed']);
|
||||
mod_login();
|
||||
exit;
|
||||
}
|
||||
|
||||
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1");
|
||||
@ -111,7 +113,8 @@ if (isset($_COOKIE[$config['cookies']['mod']])) {
|
||||
if ($cookie[1] !== mkhash($cookie[0], $user['password'], $cookie[2])) {
|
||||
// Malformed cookies
|
||||
destroyCookies();
|
||||
error($config['error']['malformed']);
|
||||
mod_login();
|
||||
exit;
|
||||
}
|
||||
|
||||
$mod = array(
|
||||
@ -125,7 +128,7 @@ if (isset($_COOKIE[$config['cookies']['mod']])) {
|
||||
function create_pm_header() {
|
||||
global $mod, $config;
|
||||
|
||||
if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) !== false) {
|
||||
if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) != false) {
|
||||
if ($header === true)
|
||||
return false;
|
||||
|
||||
|
@ -56,7 +56,7 @@ function parse_time($str) {
|
||||
function ban($mask, $reason, $length, $board) {
|
||||
global $mod, $pdo;
|
||||
|
||||
$query = prepare("INSERT INTO `bans` VALUES (NULL, :ip, :mod, :time, :expires, :reason, :board)");
|
||||
$query = prepare("INSERT INTO `bans` VALUES (NULL, :ip, :mod, :time, :expires, :reason, :board, 0)");
|
||||
$query->bindValue(':ip', $mask);
|
||||
$query->bindValue(':mod', $mod['id']);
|
||||
$query->bindValue(':time', time());
|
||||
@ -80,16 +80,25 @@ function ban($mask, $reason, $length, $board) {
|
||||
|
||||
modLog('Created a new ' .
|
||||
($length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent') .
|
||||
' ban (<small>#' . $pdo->lastInsertId() . '</small>) for ' .
|
||||
' ban on ' .
|
||||
($board ? '/' . $board . '/' : 'all boards') .
|
||||
' for ' .
|
||||
(filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : utf8tohtml($mask)) .
|
||||
' (<small>#' . $pdo->lastInsertId() . '</small>)' .
|
||||
' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
|
||||
}
|
||||
|
||||
function unban($id) {
|
||||
function unban($id) {
|
||||
$query = prepare("SELECT `ip` FROM `bans` WHERE `id` = :id");
|
||||
$query->bindValue(':id', $id);
|
||||
$query->execute() or error(db_error($query));
|
||||
$mask = $query->fetchColumn();
|
||||
|
||||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id");
|
||||
$query->bindValue(':id', $id);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
modLog("Removed ban #{$id}");
|
||||
if ($mask)
|
||||
modLog("Removed ban #{$id} for " . (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : utf8tohtml($mask)));
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ function mod_dashboard() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) === false) {
|
||||
if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) == false) {
|
||||
$query = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :id AND `unread` = 1');
|
||||
$query->bindValue(':id', $mod['id']);
|
||||
$query->execute() or error(db_error($query));
|
||||
@ -114,26 +114,37 @@ function mod_dashboard() {
|
||||
} else {
|
||||
$ctx = stream_context_create(array('http' => array('timeout' => 5)));
|
||||
if ($code = @file_get_contents('http://tinyboard.org/version.txt', 0, $ctx)) {
|
||||
eval($code);
|
||||
if (preg_match('/v(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) {
|
||||
$current = array(
|
||||
'massive' => (int) $matches[1],
|
||||
'major' => (int) $matches[2],
|
||||
'minor' => (int) $matches[3]
|
||||
$ver = strtok($code, "\n");
|
||||
|
||||
if (preg_match('@^// v(\d+)\.(\d+)\.(\d+)\s*?$@', $ver, $matches)) {
|
||||
$latest = array(
|
||||
'massive' => $matches[1],
|
||||
'major' => $matches[2],
|
||||
'minor' => $matches[3]
|
||||
);
|
||||
if (isset($m[4])) {
|
||||
// Development versions are always ahead in the versioning numbers
|
||||
$current['minor'] --;
|
||||
}
|
||||
// Check if it's newer
|
||||
if (!( $latest['massive'] > $current['massive'] ||
|
||||
$latest['major'] > $current['major'] ||
|
||||
($latest['massive'] == $current['massive'] &&
|
||||
$latest['major'] == $current['major'] &&
|
||||
$latest['minor'] > $current['minor']
|
||||
)))
|
||||
if (preg_match('/v(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) {
|
||||
$current = array(
|
||||
'massive' => (int) $matches[1],
|
||||
'major' => (int) $matches[2],
|
||||
'minor' => (int) $matches[3]
|
||||
);
|
||||
if (isset($m[4])) {
|
||||
// Development versions are always ahead in the versioning numbers
|
||||
$current['minor'] --;
|
||||
}
|
||||
// Check if it's newer
|
||||
if (!( $latest['massive'] > $current['massive'] ||
|
||||
$latest['major'] > $current['major'] ||
|
||||
($latest['massive'] == $current['massive'] &&
|
||||
$latest['major'] == $current['major'] &&
|
||||
$latest['minor'] > $current['minor']
|
||||
)))
|
||||
$latest = false;
|
||||
} else {
|
||||
$latest = false;
|
||||
}
|
||||
} else {
|
||||
// Couldn't get latest version
|
||||
$latest = false;
|
||||
}
|
||||
} else {
|
||||
@ -206,6 +217,19 @@ function mod_edit_board($boardName) {
|
||||
$query = prepare('DELETE FROM `antispam` WHERE `board` = :board');
|
||||
$query->bindValue(':board', $board['uri']);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Remove board from users/permissions table
|
||||
$query = query('SELECT `id`,`boards` FROM `mods`') or error(db_error());
|
||||
while ($user = $query->fetch(PDO::FETCH_ASSOC)) {
|
||||
$user_boards = explode(',', $user['boards']);
|
||||
if (in_array($board['uri'], $user_boards)) {
|
||||
unset($user_boards[array_search($board['uri'], $user_boards)]);
|
||||
$_query = prepare('UPDATE `mods` SET `boards` = :boards WHERE `id` = :id');
|
||||
$_query->bindValue(':boards', implode(',', $user_boards));
|
||||
$_query->bindValue(':id', $user['id']);
|
||||
$_query->execute() or error(db_error($_query));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$query = prepare('UPDATE `boards` SET `title` = :title, `subtitle` = :subtitle WHERE `uri` = :uri');
|
||||
$query->bindValue(':uri', $board['uri']);
|
||||
@ -589,6 +613,15 @@ function mod_page_ip($ip) {
|
||||
$args['notes'] = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
if (hasPermission($config['mod']['modlog_ip'])) {
|
||||
$query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM `modlogs` LEFT JOIN `mods` ON `mod` = `mods`.`id` WHERE `text` LIKE :search ORDER BY `time` DESC LIMIT 20");
|
||||
$query->bindValue(':search', '%' . $ip . '%');
|
||||
$query->execute() or error(db_error($query));
|
||||
$args['logs'] = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
} else {
|
||||
$args['logs'] = array();
|
||||
}
|
||||
|
||||
mod_page(sprintf('%s: %s', _('IP'), $ip), 'mod/view_ip.html', $args, $args['hostname']);
|
||||
}
|
||||
|
||||
@ -631,7 +664,8 @@ function mod_bans($page_no = 1) {
|
||||
if (preg_match('/^ban_(\d+)$/', $name, $match))
|
||||
$unban[] = $match[1];
|
||||
}
|
||||
|
||||
if (isset($config['mod']['unban_limit'])){
|
||||
if (count($unban) <= $config['mod']['unban_limit'] || $config['mod']['unban_limit'] == -1){
|
||||
if (!empty($unban)) {
|
||||
query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error());
|
||||
|
||||
@ -639,7 +673,21 @@ function mod_bans($page_no = 1) {
|
||||
modLog("Removed ban #{$id}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error(sprintf($config['error']['toomanyunban'], $config['mod']['unban_limit'], count($unban) ));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!empty($unban)) {
|
||||
query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error());
|
||||
|
||||
foreach ($unban as $id) {
|
||||
modLog("Removed ban #{$id}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
header('Location: ?/bans', true, $config['redirect_http']);
|
||||
}
|
||||
|
||||
@ -690,6 +738,13 @@ function mod_lock($board, $unlock, $post) {
|
||||
buildIndex();
|
||||
}
|
||||
|
||||
if ($config['mod']['dismiss_reports_on_lock']) {
|
||||
$query = prepare('DELETE FROM `reports` WHERE `board` = :board AND `post` = :id');
|
||||
$query->bindValue(':board', $board);
|
||||
$query->bindValue(':id', $post);
|
||||
$query->execute() or error(db_error($query));
|
||||
}
|
||||
|
||||
header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']);
|
||||
|
||||
if ($unlock)
|
||||
@ -871,8 +926,10 @@ function mod_move($originBoard, $postID) {
|
||||
|
||||
modLog("Moved thread #${postID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${newID})", $originBoard);
|
||||
|
||||
// build new hread
|
||||
// build new thread
|
||||
buildThread($newID);
|
||||
|
||||
clean();
|
||||
buildIndex();
|
||||
|
||||
// trigger themes
|
||||
@ -892,7 +949,7 @@ function mod_move($originBoard, $postID) {
|
||||
'mod' => true,
|
||||
'subject' => '',
|
||||
'email' => '',
|
||||
'name' => $config['mod']['shadow_name'],
|
||||
'name' => (!$config['mod']['shadow_name'] ? $config['anonymous'] : $config['mod']['shadow_name']),
|
||||
'capcode' => $config['mod']['shadow_capcode'],
|
||||
'trip' => '',
|
||||
'password' => '',
|
||||
@ -1834,6 +1891,7 @@ function mod_theme_configure($theme_name) {
|
||||
'result' => $result,
|
||||
'message' => $message,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = themeSettings($theme_name);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
// Installation/upgrade file
|
||||
define('VERSION', 'v0.9.6-dev-7');
|
||||
define('VERSION', 'v0.9.6-dev-8 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0.1</a>');
|
||||
|
||||
require 'inc/functions.php';
|
||||
|
||||
@ -227,6 +227,9 @@ if (file_exists($config['has_installed'])) {
|
||||
query(sprintf("CREATE INDEX `thread_id` ON `posts_%s` (`thread`, `id`)", $_board['uri'])) or error(db_error());
|
||||
query(sprintf("ALTER TABLE `posts_%s` DROP INDEX `thread`", $_board['uri'])) or error(db_error());
|
||||
}
|
||||
case 'v0.9.6-dev-7':
|
||||
case 'v0.9.6-dev-7 + <a href="https://github.com/vichan-devel/Tinyboard/">vichan-devel-4.0-gold</a>':
|
||||
query("ALTER TABLE `bans` ADD `seen` BOOLEAN NOT NULL") or error(db_error());
|
||||
case false:
|
||||
// Update version number
|
||||
file_write($config['has_installed'], VERSION);
|
||||
|
@ -51,6 +51,7 @@ CREATE TABLE IF NOT EXISTS `bans` (
|
||||
`expires` int(11) DEFAULT NULL,
|
||||
`reason` text,
|
||||
`board` varchar(120) DEFAULT NULL,
|
||||
`seen` tinyint(1) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
FULLTEXT KEY `ip` (`ip`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
|
||||
|
@ -16,6 +16,9 @@
|
||||
$(document).ready(function(){
|
||||
if($('div.banner').length == 0)
|
||||
return; // not index
|
||||
|
||||
if($(".post.op").size() != 1)
|
||||
return; //not thread page
|
||||
|
||||
var poll_interval;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
*expand.js
|
||||
* expand.js
|
||||
* https://github.com/savetheinternet/Tinyboard/blob/master/js/expand.js
|
||||
*
|
||||
* Released under the MIT license
|
||||
@ -17,7 +17,7 @@ $(document).ready(function(){
|
||||
|
||||
$('div.post.op span.omitted').each(function() {
|
||||
$(this)
|
||||
.html($(this).text().replace(/Click reply to view\.|Kliknij Odpowiedź aby zobaczyć\./, '<a href="javascript:void(0)">Click to expand</a>.'))
|
||||
.html($(this).text().replace(_("Click reply to view."), '<a href="javascript:void(0)">'+_("Click to expand")+'</a>.'))
|
||||
.find('a').click(function() {
|
||||
var thread = $(this).parent().parent().parent();
|
||||
var id = thread.attr('id').replace(/^thread_/, '');
|
||||
@ -35,9 +35,10 @@ $(document).ready(function(){
|
||||
}
|
||||
last_expanded = $(this);
|
||||
|
||||
$(document).trigger('new_post', this);
|
||||
}
|
||||
});
|
||||
$('<span class="omitted"><a href="javascript:void(0)">Hide expanded replies</a>.</span>')
|
||||
$('<span class="omitted"><a href="javascript:void(0)">' + _('Hide expanded replies') + '</a>.</span>')
|
||||
.insertAfter(thread.find('span.omitted').css('display', 'none'))
|
||||
.click(function() {
|
||||
thread.find('.expanded').remove();
|
||||
|
@ -56,17 +56,17 @@ $(document).ready(function() {
|
||||
forced_anon = localStorage['forcedanon'] ? true : false;
|
||||
|
||||
$('hr:first').before('<div id="forced-anon" style="text-align:right"><a class="unimportant" href="javascript:void(0)">-</a></div>');
|
||||
$('div#forced-anon a').text('Forced anonymity (' + (forced_anon ? 'enabled' : 'disabled') + ')');
|
||||
$('div#forced-anon a').text(_('Forced anonymity')+' (' + (forced_anon ? _('enabled') : _('disabled')) + ')');
|
||||
|
||||
$('div#forced-anon a').click(function() {
|
||||
forced_anon = !forced_anon;
|
||||
|
||||
if(forced_anon) {
|
||||
$('div#forced-anon a').text('Forced anonymity (enabled)');
|
||||
$('div#forced-anon a').text(_('Forced anonymity')+' ('+_('enabled')+')');
|
||||
localStorage.forcedanon = true;
|
||||
enable_fa();
|
||||
} else {
|
||||
$('div#forced-anon a').text('Forced anonymity (disabled)');
|
||||
$('div#forced-anon a').text(_('Forced anonymity')+' ('+_('disabled')+')');
|
||||
delete localStorage.forcedanon;
|
||||
disable_fa();
|
||||
}
|
||||
|
@ -6,42 +6,50 @@
|
||||
* Copyright (c) 2012 Michael Save <savetheinternet@tinyboard.org>
|
||||
*
|
||||
* Usage:
|
||||
* $config['additional_javascript'][] = 'js/jquery.min.js';
|
||||
* $config['additional_javascript'][] = 'js/inline-expanding.js';
|
||||
*
|
||||
*/
|
||||
|
||||
onready(function(){
|
||||
var link = document.getElementsByTagName('a');
|
||||
var inline_expand_post = function() {
|
||||
var link = this.getElementsByTagName('a');
|
||||
|
||||
for(var i = 0; i < link.length; i++) {
|
||||
if(typeof link[i] == "object" && link[i].childNodes[0].src && link[i].className != 'file') {
|
||||
link[i].childNodes[0].style.maxWidth = '95%';
|
||||
link[i].childNodes[0].style.maxHeight = '95%';
|
||||
link[i].onclick = function(e) {
|
||||
if(e.which == 2) {
|
||||
return true;
|
||||
}
|
||||
if(!this.tag) {
|
||||
this.tag = this.childNodes[0].src;
|
||||
this.childNodes[0].src = this.href;
|
||||
this.childNodes[0].style.width = 'auto';
|
||||
this.childNodes[0].style.height = 'auto';
|
||||
this.childNodes[0].style.opacity = '0.4';
|
||||
this.childNodes[0].style.filter = 'alpha(opacity=40)';
|
||||
this.childNodes[0].onload = function() {
|
||||
this.style.opacity = '1';
|
||||
this.style.filter = '';
|
||||
for(var i = 0; i < link.length; i++) {
|
||||
if(typeof link[i] == "object" && typeof link[i].childNodes[0] !== 'undefined' && link[i].childNodes[0].src && link[i].className != 'file') {
|
||||
link[i].childNodes[0].style.maxWidth = '95%';
|
||||
link[i].onclick = function(e) {
|
||||
if(e.which == 2) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
this.childNodes[0].src = this.tag;
|
||||
this.childNodes[0].style.width = 'auto';
|
||||
this.childNodes[0].style.height = 'auto';
|
||||
this.tag = '';
|
||||
if(!this.tag) {
|
||||
this.tag = this.childNodes[0].src;
|
||||
this.childNodes[0].src = this.href;
|
||||
this.childNodes[0].style.width = 'auto';
|
||||
this.childNodes[0].style.height = 'auto';
|
||||
this.childNodes[0].style.opacity = '0.4';
|
||||
this.childNodes[0].style.filter = 'alpha(opacity=40)';
|
||||
this.childNodes[0].onload = function() {
|
||||
this.style.opacity = '1';
|
||||
this.style.filter = '';
|
||||
}
|
||||
} else {
|
||||
this.childNodes[0].src = this.tag;
|
||||
this.childNodes[0].style.width = 'auto';
|
||||
this.childNodes[0].style.height = 'auto';
|
||||
this.tag = '';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$('div[id^="thread_"]').each(inline_expand_post);
|
||||
|
||||
// allow to work with auto-reload.js, etc.
|
||||
$(document).bind('new_post', function(e, post) {
|
||||
inline_expand_post.call(post);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright (c) 2012 Michael Save <savetheinternet@tinyboard.org>
|
||||
*
|
||||
* Usage:
|
||||
* $config['additional_javascript'][] = 'js/jquery.min.js';
|
||||
* $config['additional_javascript'][] = 'js/local-time.js';
|
||||
*
|
||||
*/
|
||||
@ -21,23 +22,32 @@ onready(function(){
|
||||
var zeropad = function(num, count) {
|
||||
return [Math.pow(10, count - num.toString().length), num].join('').substr(1);
|
||||
};
|
||||
|
||||
var do_localtime = function(elem) {
|
||||
var times = elem.getElementsByTagName('time');
|
||||
|
||||
var times = document.getElementsByTagName('time');
|
||||
|
||||
for(var i = 0; i < times.length; i++) {
|
||||
if(!times[i].innerHTML.match(/^\d+\/\d+\/\d+ \(\w+\) \d+:\d+:\d+$/))
|
||||
continue;
|
||||
for(var i = 0; i < times.length; i++) {
|
||||
if(typeof times[i].getAttribute('data-local') == 'undefined')
|
||||
continue;
|
||||
|
||||
var t = iso8601(times[i].getAttribute('datetime'));
|
||||
var t = iso8601(times[i].getAttribute('datetime'));
|
||||
|
||||
|
||||
|
||||
times[i].innerHTML =
|
||||
// date
|
||||
zeropad(t.getMonth() + 1, 2) + "/" + zeropad(t.getDate(), 2) + "/" + t.getFullYear().toString().substring(2) +
|
||||
" (" + ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][t.getDay()] + ") " +
|
||||
// time
|
||||
zeropad(t.getHours(), 2) + ":" + zeropad(t.getMinutes(), 2) + ":" + zeropad(t.getSeconds(), 2);
|
||||
times[i].setAttribute('data-local', 'true');
|
||||
times[i].innerHTML =
|
||||
// date
|
||||
zeropad(t.getMonth() + 1, 2) + "/" + zeropad(t.getDate(), 2) + "/" + t.getFullYear().toString().substring(2) +
|
||||
" (" + [_("Sun"), _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun")][t.getDay()] + ") " +
|
||||
// time
|
||||
zeropad(t.getHours(), 2) + ":" + zeropad(t.getMinutes(), 2) + ":" + zeropad(t.getSeconds(), 2);
|
||||
};
|
||||
};
|
||||
|
||||
do_localtime(document);
|
||||
|
||||
// allow to work with auto-reload.js, etc.
|
||||
$(document).bind('new_post', function(e, post) {
|
||||
do_localtime(post);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,45 +1,53 @@
|
||||
function phGetCookieName(id) {
|
||||
return "ph_hide_" + id;
|
||||
function phGetCookieName(board, id) {
|
||||
return "ph_hide_" + board + "_" + id;
|
||||
}
|
||||
function phPostHidden(id) {
|
||||
return (localStorage.getItem(phGetCookieName(id)) != null);
|
||||
function phPostHidden(board, id) {
|
||||
return (localStorage.getItem(phGetCookieName(board, id)) != null);
|
||||
}
|
||||
function phPostToggle(id) {
|
||||
if(phPostHidden(id)) { localStorage.removeItem(phGetCookieName(id)); }
|
||||
else { localStorage.setItem(phGetCookieName(id),"yes"); }
|
||||
function phPostToggle(board, id) {
|
||||
if(phPostHidden(board, id)) { localStorage.removeItem(phGetCookieName(board, id)); }
|
||||
else { localStorage.setItem(phGetCookieName(board, id),"yes"); }
|
||||
}
|
||||
function phGetInnerText(id) {
|
||||
if(phPostHidden(id)) { return "[+]"; }
|
||||
else { return "[-]"; }
|
||||
function phGetInnerText(board, id) {
|
||||
if(phPostHidden(board, id)) { return "[+]"; }
|
||||
else { return "[–]"; }
|
||||
}
|
||||
function phGetOpID(element) {
|
||||
return Number(element.children("div.post.op").children("p.intro").children("a.post_no.p2").text());
|
||||
}
|
||||
function phGetOpBoard(element) {
|
||||
return element.data("board");
|
||||
}
|
||||
function phPostHandle(element) {
|
||||
var id = phGetOpID(element);
|
||||
var board = phGetOpBoard(element);
|
||||
var preplies = element.children("div.post.reply");
|
||||
var pbody = element.children("div.post.op").children("div.body");
|
||||
var pimage = element.children("a:first").children("img");
|
||||
var pbutton = element.children("div.post.op").children("p.intro").children("a.posthider");
|
||||
var pomitted = element.children("div.post.op").children("span.omitted");
|
||||
if(phPostHidden(id)) { element.addClass("thread-hidden"); pomitted.hide(); preplies.hide(); pbody.hide(); pimage.hide(); pbutton.text("[+]"); }
|
||||
else { element.removeClass("thread-hidden"); pomitted.show(); preplies.show(); pbody.show(); pimage.show(); pbutton.text("[-]"); }
|
||||
if(phPostHidden(board, id)) { element.addClass("thread-hidden"); pomitted.hide(); preplies.hide(); pbody.hide(); pimage.hide(); pbutton.text("[+]"); }
|
||||
else { element.removeClass("thread-hidden"); pomitted.show(); preplies.show(); pbody.show(); pimage.show(); pbutton.text("[–]"); }
|
||||
}
|
||||
|
||||
function phHandleThread(index, element) {
|
||||
// Get thread ID.
|
||||
var pin = $(this).children("div.post.op").children("p.intro");
|
||||
var tid = phGetOpID($(this));
|
||||
if(tid != NaN) {
|
||||
$("<a href='javascript:;' class='posthider'>[?]</a>").insertAfter(pin.children('a:last')).click(function(e) {
|
||||
var eO = $(e.target);
|
||||
var par = eO.parent().parent().parent();
|
||||
phPostToggle(phGetOpBoard(par), phGetOpID(par));
|
||||
phPostHandle(par);
|
||||
return false;
|
||||
});
|
||||
phPostHandle($(this));
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$('div[id^="thread"]').each(function(index, element){
|
||||
// Get thread ID.
|
||||
var pin = $(this).children("div.post.op").children("p.intro");
|
||||
var tid = phGetOpID($(this));
|
||||
if(tid != NaN) {
|
||||
$("<a href='javascript:;' class='posthider'>[?]</a>").insertAfter(pin.children('a:last')).click(function(e) {
|
||||
var eO = $(e.target);
|
||||
var par = eO.parent().parent().parent();
|
||||
phPostToggle(phGetOpID(par));
|
||||
phPostHandle(par);
|
||||
return false;
|
||||
});
|
||||
phPostHandle($(this));
|
||||
}
|
||||
});
|
||||
if (active_page != "thread") {
|
||||
$('form[name="postcontrols"] > div[id^="thread"]').each(phHandleThread);
|
||||
}
|
||||
});
|
||||
|
@ -20,6 +20,8 @@ onready(function(){
|
||||
|
||||
if(id = $link.text().match(/^>>(\d+)$/)) {
|
||||
id = id[1];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var $post = false;
|
||||
|
@ -24,17 +24,17 @@ $(document).ready(function(){
|
||||
|
||||
'<input type="hidden" name="delete_' + id + '">' +
|
||||
|
||||
'<label for="password_' + id + '">Password</label>: ' +
|
||||
'<label for="password_' + id + '">'+_("Password")+'</label>: ' +
|
||||
'<input id="password_' + id + '" type="password" name="password" size="11" maxlength="18">' +
|
||||
'<input title="Delete file only" type="checkbox" name="file" id="delete_file_' + id + '">' +
|
||||
'<label for="delete_file_' + id + '">File</label>' +
|
||||
' <input type="submit" name="delete" value="Delete">' +
|
||||
'<input title="'+_('Delete file only')+'" type="checkbox" name="file" id="delete_file_' + id + '">' +
|
||||
'<label for="delete_file_' + id + '">'+_('File')+'</label>' +
|
||||
' <input type="submit" name="delete" value="'+_('Delete')+'">' +
|
||||
|
||||
'<br>' +
|
||||
|
||||
'<label for="reason_' + id + '">Reason</label>: ' +
|
||||
'<label for="reason_' + id + '">'+_('Reason')+'</label>: ' +
|
||||
'<input id="reason_' + id + '" type="text" name="reason" size="20" maxlength="100">' +
|
||||
' <input type="submit" name="report" value="Report">' +
|
||||
' <input type="submit" name="report" value="'+_('Report')+'">' +
|
||||
'</div>' +
|
||||
'</form>');
|
||||
post_form
|
||||
|
@ -12,12 +12,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
if (active_page == 'index') {
|
||||
$(document).ready(function(){
|
||||
if($('div.banner').length != 0)
|
||||
return; // not index
|
||||
|
||||
txt_new_topic = $('form[name=post] input[type=submit]').val();
|
||||
txt_new_reply = txt_new_topic == 'Submit' ? txt_new_topic : 'Reply';
|
||||
txt_new_reply = txt_new_topic == _('Submit') ? txt_new_topic : new_reply_string;
|
||||
|
||||
undo_quick_reply = function() {
|
||||
$('div.banner').remove();
|
||||
@ -26,10 +27,10 @@ $(document).ready(function(){
|
||||
}
|
||||
|
||||
$('div.post.op').each(function() {
|
||||
var id = $(this).children('p.intro').children('a.post_no:eq(2)').text();
|
||||
$('<a href="#">[Quick Reply]</a>').insertAfter($(this).children('p.intro').children('a:last')).click(function() {
|
||||
var id = $(this).children('p.intro').children('a.post_no:eq(1)').text();
|
||||
$('<a href="#">['+_("Quick reply")+']</a>').insertAfter($(this).children('p.intro').children('a:last')).click(function() {
|
||||
$('div.banner').remove();
|
||||
$('<div class="banner">Post Mode: Quick Reply to <small>>>' + id + '</small> <a class="unimportant" onclick="undo_quick_reply()" href="javascript:void(0)">[Return]</a></div>')
|
||||
$('<div class="banner">'+fmt(_("Posting mode: Replying to <small>>>{0}</small>"), [id])+' <a class="unimportant" onclick="undo_quick_reply()" href="javascript:void(0)">['+_("Return")+']</a></div>')
|
||||
.insertBefore('form[name=post]');
|
||||
$('form[name=post] input[type=submit]').val(txt_new_reply);
|
||||
|
||||
@ -43,4 +44,4 @@ $(document).ready(function(){
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -46,5 +46,9 @@ onready(function(){
|
||||
};
|
||||
|
||||
$('div.post.reply').each(showBackLinks);
|
||||
|
||||
$(document).bind('new_post', function(e, post) {
|
||||
showBackLinks.call(post);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -13,12 +13,21 @@
|
||||
|
||||
onready(function(){
|
||||
if(device_type == 'mobile') {
|
||||
var spoilers = document.getElementsByClassName('spoiler');
|
||||
for(var i = 0; i < spoilers.length; i++) {
|
||||
spoilers[i].onmousedown = function() {
|
||||
this.style.color = 'white';
|
||||
};
|
||||
}
|
||||
var fix_spoilers = function(where) {
|
||||
var spoilers = where.getElementsByClassName('spoiler');
|
||||
for(var i = 0; i < spoilers.length; i++) {
|
||||
spoilers[i].onmousedown = function() {
|
||||
this.style.color = 'white';
|
||||
};
|
||||
}
|
||||
};
|
||||
fix_spoilers(document);
|
||||
|
||||
// allow to work with auto-reload.js, etc.
|
||||
$(document).bind('new_post', function(e, post) {
|
||||
fix_spoilers(post);
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -36,7 +36,7 @@ $(document).ready(function(){
|
||||
|
||||
$('hr:first').before('<div id="toggle-locked-threads" style="text-align:right"><a class="unimportant" href="javascript:void(0)">-</a></div>');
|
||||
$('div#toggle-locked-threads a')
|
||||
.text((hide_locked_threads ? 'Show' : 'Hide') + ' locked threads')
|
||||
.text(hide_locked_threads ? _('Show locked threads') : _('Hide locked threads'))
|
||||
.click(function() {
|
||||
hide_locked_threads = !hide_locked_threads;
|
||||
if (hide_locked_threads) {
|
||||
@ -51,7 +51,7 @@ $(document).ready(function(){
|
||||
delete localStorage.hidelockedthreads;
|
||||
}
|
||||
|
||||
$(this).text((hide_locked_threads ? 'Show' : 'Hide') + ' locked threads')
|
||||
$(this).text(hide_locked_threads ? _('Show locked threads') : _('Hide locked threads'))
|
||||
});
|
||||
|
||||
if (hide_locked_threads) {
|
||||
|
10
mod.php
10
mod.php
@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
require 'inc/functions.php';
|
||||
require 'inc/mod/auth.php';
|
||||
require 'inc/mod/pages.php';
|
||||
require 'inc/mod/auth.php';
|
||||
|
||||
// Fix for magic quotes
|
||||
if (get_magic_quotes_gpc()) {
|
||||
@ -45,7 +45,7 @@ $pages = array(
|
||||
'/news/(\d+)' => 'news', // view news
|
||||
'/news/delete/(\d+)' => 'news_delete', // delete from news
|
||||
|
||||
'/edit/(\w+)' => 'edit_board', // edit board details
|
||||
'/edit/([\w+.]+)' => 'edit_board', // edit board details
|
||||
'/new-board' => 'new_board', // create a new board
|
||||
|
||||
'/rebuild' => 'rebuild', // rebuild static files
|
||||
@ -103,9 +103,9 @@ if (isset($config['mod']['custom_pages'])) {
|
||||
|
||||
$new_pages = array();
|
||||
foreach ($pages as $key => $callback) {
|
||||
if (preg_match('/^secure /', $callback))
|
||||
if (is_string($callback) && preg_match('/^secure /', $callback))
|
||||
$key .= '(/(?P<token>[a-f0-9]{8}))?';
|
||||
$new_pages[@$key[0] == '!' ? $key : "!^$key$!"] = $callback;
|
||||
$new_pages[@$key[0] == '!' ? $key : '!^' . $key . '(?:&[^&=]+=[^&]*)*$!'] = $callback;
|
||||
}
|
||||
$pages = $new_pages;
|
||||
|
||||
@ -113,7 +113,7 @@ foreach ($pages as $uri => $handler) {
|
||||
if (preg_match($uri, $query, $matches)) {
|
||||
$matches = array_slice($matches, 1);
|
||||
|
||||
if (preg_match('/^secure(_POST)? /', $handler, $m)) {
|
||||
if (is_string($handler) && preg_match('/^secure(_POST)? /', $handler, $m)) {
|
||||
$secure_post_only = isset($m[1]);
|
||||
if (!$secure_post_only || $_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$token = isset($matches['token']) ? $matches['token'] : (isset($_POST['token']) ? $_POST['token'] : false);
|
||||
|
34
post.php
34
post.php
@ -80,6 +80,7 @@ if (isset($_POST['delete'])) {
|
||||
$is_mod = isset($_POST['mod']) && $_POST['mod'];
|
||||
$root = $is_mod ? $config['root'] . $config['file_mod'] . '?/' : $config['root'];
|
||||
|
||||
if (!$is_mod) header('X-Associated-Content: "' . $root . $board['dir'] . $config['file_index'] . '"');
|
||||
header('Location: ' . $root . $board['dir'] . $config['file_index'], true, $config['redirect_http']);
|
||||
|
||||
} elseif (isset($_POST['report'])) {
|
||||
@ -137,6 +138,7 @@ if (isset($_POST['delete'])) {
|
||||
$is_mod = isset($_POST['mod']) && $_POST['mod'];
|
||||
$root = $is_mod ? $config['root'] . $config['file_mod'] . '?/' : $config['root'];
|
||||
|
||||
if (!$is_mod) header('X-Associated-Content: "' . $root . $board['dir'] . $config['file_index'] . '"');
|
||||
header('Location: ' . $root . $board['dir'] . $config['file_index'], true, $config['redirect_http']);
|
||||
} elseif (isset($_POST['post'])) {
|
||||
|
||||
@ -308,13 +310,21 @@ if (isset($_POST['delete'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if thread is locked
|
||||
// but allow mods to post
|
||||
if (!$post['op'] && !hasPermission($config['mod']['postinlocked'], $board['uri'])) {
|
||||
if ($thread['locked'])
|
||||
if (!$post['op']) {
|
||||
// Check if thread is locked
|
||||
// but allow mods to post
|
||||
if ($thread['locked'] && !hasPermission($config['mod']['postinlocked'], $board['uri']))
|
||||
error($config['error']['locked']);
|
||||
|
||||
$numposts = numPosts($post['thread']);
|
||||
|
||||
if ($config['reply_hard_limit'] != 0 && $config['reply_hard_limit'] <= $numposts['replies'])
|
||||
error($config['error']['reply_hard_limit']);
|
||||
|
||||
if ($post['has_file'] && $config['image_hard_limit'] != 0 && $config['image_hard_limit'] <= $numposts['images'])
|
||||
error($config['error']['image_hard_limit']);
|
||||
}
|
||||
|
||||
|
||||
if ($post['has_file']) {
|
||||
$size = $_FILES['file']['size'];
|
||||
if ($size > $config['max_filesize'])
|
||||
@ -625,10 +635,6 @@ if (isset($_POST['delete'])) {
|
||||
incrementSpamHash($post['antispam_hash']);
|
||||
}
|
||||
|
||||
if (isset($post['antispam_hash'])) {
|
||||
incrementSpamHash($post['antispam_hash']);
|
||||
}
|
||||
|
||||
if (isset($post['tracked_cites'])) {
|
||||
foreach ($post['tracked_cites'] as $cite) {
|
||||
$query = prepare('INSERT INTO `cites` VALUES (:board, :post, :target_board, :target)');
|
||||
@ -642,7 +648,7 @@ if (isset($_POST['delete'])) {
|
||||
|
||||
buildThread($post['op'] ? $id : $post['thread']);
|
||||
|
||||
if (!$post['op'] && strtolower($post['email']) != 'sage' && !$thread['sage'] && ($config['reply_limit'] == 0 || numPosts($post['thread']) < $config['reply_limit'])) {
|
||||
if (!$post['op'] && strtolower($post['email']) != 'sage' && !$thread['sage'] && ($config['reply_limit'] == 0 || $numposts['replies']+1 < $config['reply_limit'])) {
|
||||
bumpThread($post['thread']);
|
||||
}
|
||||
|
||||
@ -679,7 +685,13 @@ if (isset($_POST['delete'])) {
|
||||
_syslog(LOG_INFO, 'New post: /' . $board['dir'] . $config['dir']['res'] .
|
||||
sprintf($config['file_page'], $post['op'] ? $id : $post['thread']) . (!$post['op'] ? '#' . $id : ''));
|
||||
|
||||
rebuildThemes('post');
|
||||
if (!$post['mod']) header('X-Associated-Content: "' . $redirect . '"');
|
||||
|
||||
if ($post['op'])
|
||||
rebuildThemes('post-thread', $board['uri']);
|
||||
else
|
||||
rebuildThemes('post', $board['uri']);
|
||||
|
||||
header('Location: ' . $redirect, true, $config['redirect_http']);
|
||||
} else {
|
||||
if (!file_exists($config['has_installed'])) {
|
||||
|
67
stylesheets/gentoochan.css
Normal file
67
stylesheets/gentoochan.css
Normal file
@ -0,0 +1,67 @@
|
||||
body {
|
||||
background: #0E0E0E url(data:image/gif;base64,R0lGODlhGAAMAKEEAOXl5ebm5vDw8PHx8SH+EUNyZWF0ZWQgd2l0aCBHSU1QACwAAAAAGAAMAAACRpQiY6cLa146MyY1EJQKjG81lNGRUPOIkgMJHtquBgIO7xwvpbrpduUSuXq8ntEC0bBEylYitdDAdM1ViaobkgKgZwyDLAAAOw==) repeat 0 0!important;
|
||||
color: #000;
|
||||
}
|
||||
a:link, a:visited, p.intro a.email span.name {
|
||||
-webkit-transition: all ease-in 0.3s;
|
||||
-moz-transition: all ease-in 0.3s;
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
text-decoration:none !important;
|
||||
}
|
||||
a:link:hover {
|
||||
-moz-transition: all ease-in 0.5s;
|
||||
text-shadow: 0px 0px 2px #000;
|
||||
}
|
||||
a.post_no {
|
||||
color: #fff;
|
||||
}
|
||||
.boardlist {
|
||||
color: #ccc;
|
||||
}
|
||||
div.post.reply, input, textarea {
|
||||
background: rgba(0, 0, 0, 0.1)!important;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2)!important;
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
div.post.reply.highlighted {
|
||||
background: #f0c0b0;
|
||||
border-color: #d9bfb7;
|
||||
}
|
||||
div.post.reply p.body a {
|
||||
color: navy;
|
||||
}
|
||||
p.intro span.subject {
|
||||
color: #000;
|
||||
}
|
||||
form table tr th {
|
||||
background: #EA8;
|
||||
}
|
||||
div.ban h2 {
|
||||
background: #FCA;
|
||||
color: inherit;
|
||||
}
|
||||
div.ban {
|
||||
border-color: #000;
|
||||
}
|
||||
div.ban p {
|
||||
color: black;
|
||||
}
|
||||
div.pages {
|
||||
background: #F0E0D6;
|
||||
border-color: #D9BFB7;
|
||||
}
|
||||
div.pages a.selected {
|
||||
color: #800;
|
||||
}
|
||||
hr {
|
||||
border-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
div.boardlist {
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
div.boardlist a {
|
||||
color: #000;
|
||||
}
|
||||
table.modlog tr th {
|
||||
background: #EA8;
|
||||
}
|
@ -1,9 +1,17 @@
|
||||
{% filter remove_whitespace %}
|
||||
{# Automatically removes unnecessary whitespace #}
|
||||
<div class="ban">
|
||||
<h2>{% trans %}You are banned! ;_;{% endtrans %}</h2>
|
||||
{% if ban.expires and time() >= ban.expires %}
|
||||
<h2>{% trans %}You were banned! ;_;{% endtrans %}</h2>
|
||||
{% else %}
|
||||
<h2>{% trans %}You are banned! ;_;{% endtrans %}</h2>
|
||||
{% endif %}
|
||||
<p>
|
||||
{% trans %}You have been banned from{% endtrans %}
|
||||
{% if ban.expires and time() >= ban.expires %}
|
||||
{% trans %}You were banned from{% endtrans %}
|
||||
{% else %}
|
||||
{% trans %}You have been banned from{% endtrans %}
|
||||
{% endif %}
|
||||
{% if ban.board %}
|
||||
<strong>{{ config.board_abbreviation|sprintf(ban.board) }}</strong>
|
||||
{% else %}
|
||||
@ -23,7 +31,9 @@
|
||||
<p>
|
||||
{% trans %}Your ban was filed on{% endtrans %}
|
||||
<strong>{{ ban.set|date(config.ban_date) }}</strong> {% trans %}and{% endtrans %} <span id="expires">
|
||||
{% if ban.expires %}
|
||||
{% if ban.expires and time() >= ban.expires %}
|
||||
{% trans %} has since expired. Refresh the page to continue.{% endtrans %}
|
||||
{% elseif ban.expires %}
|
||||
{% trans %}expires{% endtrans %} <span id="countdown">{{ ban.expires|until }}</span> {% trans %}from now, which is on{% endtrans %}
|
||||
<strong>
|
||||
{{ ban.expires|date(config.ban_date) }}
|
||||
|
1
templates/boardlist.html
Normal file
1
templates/boardlist.html
Normal file
@ -0,0 +1 @@
|
||||
I'm your overboard boardlist. You can put here anything and I reside in templates/boardlist.html
|
@ -1,9 +1,21 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
{% include 'header.html' %}
|
||||
<meta charset="utf-8">
|
||||
<title>{{ board.url }} - {{ board.name }}</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
{% if config.quick_reply %}
|
||||
var new_reply_string = "{{ config.button_reply }}";
|
||||
{% endif %}
|
||||
{% if not no_post_form %}
|
||||
var active_page = "index";
|
||||
{% else %}
|
||||
var active_page = "ukko";
|
||||
{% endif %}
|
||||
</script>
|
||||
|
||||
{% include 'header.html' %}
|
||||
<title>{{ board.url }} - {{ board.title|e }}</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ boardlist.top }}
|
||||
@ -20,7 +32,11 @@
|
||||
</header>
|
||||
|
||||
{% include 'attention_bar.html' %}
|
||||
{% include 'post_form.html' %}
|
||||
{% if not no_post_form %}
|
||||
{% include 'post_form.html' %}
|
||||
{% else %}
|
||||
{% include 'boardlist.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% if config.blotter %}<hr /><div class="blotter">{{ config.blotter }}</div>{% endif %}
|
||||
<hr />
|
||||
|
@ -1,5 +1,27 @@
|
||||
{% raw %}
|
||||
|
||||
/* gettext-compatible _ function, example of usage:
|
||||
*
|
||||
* > // Loading pl_PL.json here (containing polish translation strings generated by tools/i18n_compile.php)
|
||||
* > alert(_("Hello!"));
|
||||
* Witaj!
|
||||
*/
|
||||
function _(s) {
|
||||
return (typeof l10n != 'undefined' && typeof l10n[s] != 'undefined') ? l10n[s] : s;
|
||||
}
|
||||
|
||||
/* printf-like formatting function, example of usage:
|
||||
*
|
||||
* > alert(fmt("There are {0} birds on {1} trees", [3,4]));
|
||||
* There are 3 birds on 4 trees
|
||||
* > // Loading pl_PL.json here (containing polish translation strings generated by tools/locale_compile.php)
|
||||
* > alert(fmt(_("{0} users"), [3]));
|
||||
* 3 uzytkownikow
|
||||
*/
|
||||
function fmt(s,a) {
|
||||
return s.replace(/\{([0-9]+)\}/g, function(x) { return a[x[1]]; });
|
||||
}
|
||||
|
||||
var saved = {};
|
||||
|
||||
|
||||
@ -105,7 +127,7 @@ function generatePassword() {
|
||||
|
||||
function dopost(form) {
|
||||
if (form.elements['name']) {
|
||||
localStorage.name = form.elements['name'].value.replace(/ ##.+$/, '');
|
||||
localStorage.name = form.elements['name'].value.replace(/( |^)## .+$/, '');
|
||||
}
|
||||
if (form.elements['email'] && form.elements['email'].value != 'sage') {
|
||||
localStorage.email = form.elements['email'].value;
|
||||
|
@ -10,6 +10,7 @@
|
||||
<th>{% trans 'Set' %}</th>
|
||||
<th>{% trans 'Duration' %}</th>
|
||||
<th>{% trans 'Expires' %}</th>
|
||||
<th>{% trans 'Seen' %}</th>
|
||||
<th>{% trans 'Staff' %}</th>
|
||||
</tr>
|
||||
{% for ban in bans %}
|
||||
@ -58,6 +59,13 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if ban.seen %}
|
||||
{% trans 'Yes' %}
|
||||
{% else %}
|
||||
{% trans 'No' %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if ban.username %}
|
||||
{% if mod|hasPermission(config.mod.view_banstaff) %}
|
||||
|
@ -101,6 +101,7 @@
|
||||
</ul>
|
||||
</fieldset>
|
||||
|
||||
{#
|
||||
<fieldset>
|
||||
<legend>{% trans 'Search' %}</legend>
|
||||
|
||||
@ -115,6 +116,7 @@
|
||||
</li>
|
||||
</ul>
|
||||
</fieldset>
|
||||
#}
|
||||
|
||||
{% if config.debug %}
|
||||
<fieldset>
|
||||
|
@ -136,6 +136,16 @@
|
||||
{% 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>
|
||||
@ -161,3 +171,43 @@
|
||||
{% include 'mod/ban_form.html' %}
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
||||
{% if logs|count > 0 %}
|
||||
<fieldset id="history">
|
||||
<legend>History</legend>
|
||||
<table class="modlog" style="width:100%">
|
||||
<tr>
|
||||
<th>{% trans 'Staff' %}</th>
|
||||
<th>{% trans 'Time' %}</th>
|
||||
<th>{% trans 'Board' %}</th>
|
||||
<th>{% trans 'Action' %}</th>
|
||||
</tr>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td class="minimal">
|
||||
{% if log.username %}
|
||||
<a href="?/log:{{ log.username|e }}">{{ log.username|e }}</a>
|
||||
{% elseif log.mod == -1 %}
|
||||
<em>system</em>
|
||||
{% else %}
|
||||
<em>{% trans 'deleted?' %}</em>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="minimal">
|
||||
<span title="{{ log.time|date(config.post_date) }}">{{ log.time|ago }}</span>
|
||||
</td>
|
||||
<td class="minimal">
|
||||
{% if log.board %}
|
||||
<a href="?/{{ config.board_path|sprintf(log.board) }}{{ config.file_index }}">{{ config.board_abbreviation|sprintf(log.board) }}</a>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ log.text }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</fieldset>
|
||||
{% endif %}
|
||||
|
@ -1,8 +1,8 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
{% include 'header.html' %}
|
||||
<meta charset="utf-8">
|
||||
{% include 'header.html' %}
|
||||
<title>{{ title }}</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -24,24 +24,22 @@
|
||||
<td>
|
||||
<input type="text" name="email" size="25" maxlength="40" autocomplete="off">
|
||||
{{ antibot.html() }}
|
||||
{% if not (not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
<input accesskey="s" style="margin-left:2px;" type="submit" name="post" value="{% if id %}{{ config.button_reply }}{% else %}{{ config.button_newtopic }}{% endif %}" />{% if config.spoiler_images %} <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label>{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
<tr>
|
||||
{% if not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<th>
|
||||
{% if not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||
<th>
|
||||
{% trans %}Subject{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input style="float:left;" type="text" name="subject" size="25" maxlength="100" autocomplete="off">
|
||||
{% else %}<th>
|
||||
{% trans %}Submit{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
{% endif %}
|
||||
<input accesskey="s" style="margin-left:2px;" type="submit" name="post" value="{% if id %}{{ config.button_reply }}{% else %}{{ config.button_newtopic }}{% endif %}" />{% if config.spoiler_images %} <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label>{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th>
|
||||
{% trans %}Comment{% endtrans %}
|
||||
@ -50,6 +48,11 @@
|
||||
<td>
|
||||
<textarea name="body" id="body" rows="5" cols="35"></textarea>
|
||||
{{ antibot.html() }}
|
||||
{% if not (not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
{% if not (not config.field_disable_email or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
<input accesskey="s" style="margin-left:2px;" type="submit" name="post" value="{% if id %}{{ config.button_reply }}{% else %}{{ config.button_newtopic }}{% endif %}" />{% if config.spoiler_images %} <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label>{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if config.recaptcha %}
|
||||
@ -59,7 +62,7 @@
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<script type="text/javascript" src="http://www.google.com/recaptcha/api/challenge?k={{ config.recaptcha_public }}"></script>
|
||||
<script type="text/javascript" src="//www.google.com/recaptcha/api/challenge?k={{ config.recaptcha_public }}"></script>
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -7,14 +7,14 @@
|
||||
<label for="delete_{{ post.id }}">
|
||||
{% if post.subject|length > 0 %}
|
||||
{# show subject #}
|
||||
<span class="subject">{{ post.subject }}</span>
|
||||
<span class="subject">{{ post.subject|bidi_cleanup }}</span>
|
||||
{% endif %}
|
||||
{% if post.email|length > 0 %}
|
||||
{# start email #}
|
||||
<a class="email" href="mailto:{{ post.email }}">
|
||||
{% endif %}
|
||||
{% set capcode = post.capcode|capcode %}
|
||||
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name }}</span>
|
||||
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name|bidi_cleanup }}</span>
|
||||
{% if post.trip|length > 0 %}
|
||||
<span {% if capcode.trip %}style="{{ capcode.trip }}" {% endif %}class="trip">{{ post.trip }}</span>
|
||||
{% endif %}
|
||||
@ -66,9 +66,9 @@
|
||||
{% if config.show_filename and post.filename %}
|
||||
,
|
||||
{% if post.filename|length > config.max_filename_display %}
|
||||
<span title="{{ post.filename }}">{{ post.filename|truncate(config.max_filename_display) }}</span>
|
||||
<span class="postfilename" title="{{ post.filename|bidi_cleanup }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
|
||||
{% else %}
|
||||
{{ post.filename }}
|
||||
<span class="postfilename">{{ post.filename|bidi_cleanup }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if post.thumb != 'file' and config.image_identification %}
|
||||
|
@ -1,152 +1,148 @@
|
||||
{% filter remove_whitespace %}
|
||||
{# tabs and new lines will be ignored #}
|
||||
|
||||
<div id="thread_{{ post.id }}">
|
||||
|
||||
{% if post.embed %}
|
||||
{{ post.embed }}
|
||||
{% elseif post.file == 'deleted' %}
|
||||
<img src="{{ config.image_deleted }}" alt="" />
|
||||
{% elseif post.file and post.file %}
|
||||
<p class="fileinfo">{% trans %}File:{% endtrans %} <a href="{{ config.uri_img }}{{ post.file }}">{{ post.file }}</a> <span class="unimportant">
|
||||
(
|
||||
{% if post.thumb == 'spoiler' %}
|
||||
{% trans %}Spoiler Image{% endtrans %},
|
||||
{% endif %}
|
||||
{{ post.filesize|filesize }}
|
||||
{% if post.filex and post.filey %}
|
||||
, {{ post.filex}}x{{ post.filey }}
|
||||
{% if config.show_ratio %}
|
||||
, {{ post.ratio }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if config.show_filename and post.filename %}
|
||||
,
|
||||
{% if post.filename|length > config.max_filename_display %}
|
||||
<span title="{{ post.filename }}">{{ post.filename|truncate(config.max_filename_display) }}</span>
|
||||
{% else %}
|
||||
{{ post.filename }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if post.thumb != 'file' and config.image_identification %}
|
||||
,
|
||||
<span class='image_id'>
|
||||
<a href="http://imgops.com/{{ config.domain }}{{ config.uri_img }}{{ post.file }}">io</a>
|
||||
{% if post.file|extension == 'jpg' %}
|
||||
<a href="http://regex.info/exif.cgi?url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">e</a>
|
||||
{% endif %}
|
||||
<a href="http://www.google.com/searchbyimage?image_url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">g</a>
|
||||
<a href="http://www.tineye.com/search?url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">t</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
)
|
||||
</span></p>
|
||||
<a href="{{ config.uri_img }}{{ post.file }}" target="_blank"{% if post.thumb == 'file' %} class="file"{% endif %}>
|
||||
<img src="
|
||||
{% if post.thumb == 'file' %}
|
||||
{{ config.root }}
|
||||
{% if config.file_icons[post.filename|extension] %}
|
||||
{{ config.file_thumb|sprintf(config.file_icons[post.filename|extension]) }}
|
||||
{% else %}
|
||||
{{ config.file_thumb|sprintf(config.file_icons.default) }}
|
||||
{% endif %}
|
||||
{% elseif post.thumb == 'spoiler' %}
|
||||
{{ config.root }}{{ config.spoiler_image }}
|
||||
{% else %}
|
||||
{{ config.uri_thumb }}{{ post.thumb }}
|
||||
{% endif %}" style="width:{{ post.thumbx }}px;height:{{ post.thumby }}px" alt="" /></a>
|
||||
{% endif %}
|
||||
<div class="post op"><p class="intro"{% if not index %} id="{{ post.id }}"{% endif %}>
|
||||
<input type="checkbox" class="delete" name="delete_{{ post.id }}" id="delete_{{ post.id }}" />
|
||||
<label for="delete_{{ post.id }}">
|
||||
{% if post.subject|length > 0 %}
|
||||
{# show subject #}
|
||||
<span class="subject">{{ post.subject }}</span>
|
||||
{% endif %}
|
||||
{% if post.email|length > 0 %}
|
||||
{# start email #}
|
||||
<a class="email" href="mailto:{{ post.email }}">
|
||||
{% endif %}
|
||||
{% set capcode = post.capcode|capcode %}
|
||||
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name }}</span>
|
||||
{% if post.trip|length > 0 %}
|
||||
<span {% if capcode.trip %}style="{{ capcode.trip }}" {% endif %}class="trip">{{ post.trip }}</span>
|
||||
{% endif %}
|
||||
{% if post.email|length > 0 %}
|
||||
{# end email #}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if capcode %}
|
||||
{{ capcode.cap }}
|
||||
{% endif %}
|
||||
{% if post.mod and post.mod|hasPermission(config.mod.show_ip, board.uri) %}
|
||||
[<a style="margin:0;" href="?/IP/{{ post.ip }}">{{ post.ip }}</a>]
|
||||
{% endif %}
|
||||
|
||||
<time datetime="{{ post.time|date('%Y-%m-%dT%H:%M:%S') }}{{ timezone() }}">{{ post.time|date(config.post_date) }}</time>
|
||||
</label>
|
||||
{% if config.poster_ids %}
|
||||
ID: {{ post.ip|poster_id(post.id) }}
|
||||
{% endif %}
|
||||
<a class="post_no" href="http://webchat.6irc.net/?channels=vichan-int-{{ board.uri }}-{{ post.id }}&nick=Anon....">
|
||||
#</a>
|
||||
|
||||
<a class="post_no p1" href="{{ post.link }}">No.</a>
|
||||
<a class="post_no p2"
|
||||
{% if not index %}
|
||||
onclick="citeReply({{ post.id }});"
|
||||
{% endif %}
|
||||
href="{% if index %}
|
||||
{{ post.link('q') }}
|
||||
{% else %}
|
||||
javascript:void(0);
|
||||
{% endif %}">
|
||||
{{ post.id }}
|
||||
</a>
|
||||
{% if post.sticky %}
|
||||
<img class="icon" title="Sticky" src="{{ config.image_sticky }}" alt="Sticky" />
|
||||
{% endif %}
|
||||
{% if post.locked %}
|
||||
<img class="icon" title="Locked" src="{{ config.image_locked }}" alt="Locked" />
|
||||
{% endif %}
|
||||
{% if post.bumplocked and (config.mod.view_bumplock < 0 or (post.mod and post.mod|hasPermission(config.mod.view_bumplock, board.uri))) %}
|
||||
<img class="icon" title="Bumplocked" src="{{ config.image_bumplocked }}" alt="Bumplocked" />
|
||||
{% endif %}
|
||||
{% if index %}
|
||||
<a href="{{ post.root }}{{ board.dir }}{{ config.dir.res }}{{ config.file_page|sprintf(post.id) }}">[{% trans %}Reply{% endtrans %}]</a>
|
||||
{% endif %}
|
||||
{{ post.postControls }}
|
||||
</p>
|
||||
<div class="body">
|
||||
{% endfilter %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% filter remove_whitespace %}
|
||||
</div>
|
||||
{% if post.omitted or post.omitted_images %}
|
||||
<span class="omitted">
|
||||
{% if post.omitted %}
|
||||
{% trans %}
|
||||
1 post
|
||||
{% plural post.omitted %}
|
||||
{{ count }} posts
|
||||
{% endtrans %}
|
||||
{% if post.omitted_images %}
|
||||
{% trans %}and{% endtrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if post.omitted_images %}
|
||||
{% trans %}
|
||||
1 image reply
|
||||
{% plural post.omitted_images %}
|
||||
{{ count }} image replies
|
||||
{% endtrans %}
|
||||
{% endif %} {% trans %}omitted. Click reply to view.{% endtrans %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if not index %}
|
||||
{% endif %}
|
||||
</div>{% endfilter %}
|
||||
{% set hr = post.hr %}
|
||||
{% for post in post.posts %}
|
||||
{% include 'post_reply.html' %}
|
||||
{% endfor %}
|
||||
<br class="clear"/>{% if hr %}<hr/>{% endif %}
|
||||
</div>
|
||||
{% filter remove_whitespace %}
|
||||
{# tabs and new lines will be ignored #}
|
||||
|
||||
<div id="thread_{{ post.id }}" data-board="{{ board.uri }}">
|
||||
|
||||
{% if post.embed %}
|
||||
{{ post.embed }}
|
||||
{% elseif post.file == 'deleted' %}
|
||||
<img src="{{ config.image_deleted }}" alt="" />
|
||||
{% elseif post.file and post.file %}
|
||||
<p class="fileinfo">{% trans %}File:{% endtrans %} <a href="{{ config.uri_img }}{{ post.file }}">{{ post.file }}</a> <span class="unimportant">
|
||||
(
|
||||
{% if post.thumb == 'spoiler' %}
|
||||
{% trans %}Spoiler Image{% endtrans %},
|
||||
{% endif %}
|
||||
{{ post.filesize|filesize }}
|
||||
{% if post.filex and post.filey %}
|
||||
, {{ post.filex}}x{{ post.filey }}
|
||||
{% if config.show_ratio %}
|
||||
, {{ post.ratio }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if config.show_filename and post.filename %}
|
||||
,
|
||||
{% if post.filename|length > config.max_filename_display %}
|
||||
<span class="postfilename" title="{{ post.filename|bidi_cleanup }}">{{ post.filename|truncate(config.max_filename_display)|bidi_cleanup }}</span>
|
||||
{% else %}
|
||||
<span class="postfilename">{{ post.filename|bidi_cleanup }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if post.thumb != 'file' and config.image_identification %}
|
||||
,
|
||||
<span class='image_id'>
|
||||
<a href="http://imgops.com/{{ config.domain }}{{ config.uri_img }}{{ post.file }}">io</a>
|
||||
{% if post.file|extension == 'jpg' %}
|
||||
<a href="http://regex.info/exif.cgi?url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">e</a>
|
||||
{% endif %}
|
||||
<a href="http://www.google.com/searchbyimage?image_url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">g</a>
|
||||
<a href="http://www.tineye.com/search?url={{ config.domain }}{{ config.uri_img }}{{ post.file }}">t</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
)
|
||||
</span></p>
|
||||
<a href="{{ config.uri_img }}{{ post.file }}" target="_blank"{% if post.thumb == 'file' %} class="file"{% endif %}>
|
||||
<img src="
|
||||
{% if post.thumb == 'file' %}
|
||||
{{ config.root }}
|
||||
{% if config.file_icons[post.filename|extension] %}
|
||||
{{ config.file_thumb|sprintf(config.file_icons[post.filename|extension]) }}
|
||||
{% else %}
|
||||
{{ config.file_thumb|sprintf(config.file_icons.default) }}
|
||||
{% endif %}
|
||||
{% elseif post.thumb == 'spoiler' %}
|
||||
{{ config.root }}{{ config.spoiler_image }}
|
||||
{% else %}
|
||||
{{ config.uri_thumb }}{{ post.thumb }}
|
||||
{% endif %}" style="width:{{ post.thumbx }}px;height:{{ post.thumby }}px" alt="" /></a>
|
||||
{% endif %}
|
||||
<div class="post op"><p class="intro"{% if not index %} id="{{ post.id }}"{% endif %}>
|
||||
<input type="checkbox" class="delete" name="delete_{{ post.id }}" id="delete_{{ post.id }}" />
|
||||
<label for="delete_{{ post.id }}">
|
||||
{% if post.subject|length > 0 %}
|
||||
{# show subject #}
|
||||
<span class="subject">{{ post.subject|bidi_cleanup }}</span>
|
||||
{% endif %}
|
||||
{% if post.email|length > 0 %}
|
||||
{# start email #}
|
||||
<a class="email" href="mailto:{{ post.email }}">
|
||||
{% endif %}
|
||||
{% set capcode = post.capcode|capcode %}
|
||||
<span {% if capcode.name %}style="{{ capcode.name }}" {% endif %}class="name">{{ post.name|bidi_cleanup }}</span>
|
||||
{% if post.trip|length > 0 %}
|
||||
<span {% if capcode.trip %}style="{{ capcode.trip }}" {% endif %}class="trip">{{ post.trip }}</span>
|
||||
{% endif %}
|
||||
{% if post.email|length > 0 %}
|
||||
{# end email #}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if capcode %}
|
||||
{{ capcode.cap }}
|
||||
{% endif %}
|
||||
{% if post.mod and post.mod|hasPermission(config.mod.show_ip, board.uri) %}
|
||||
[<a style="margin:0;" href="?/IP/{{ post.ip }}">{{ post.ip }}</a>]
|
||||
{% endif %}
|
||||
<time datetime="{{ post.time|date('%Y-%m-%dT%H:%M:%S') }}{{ timezone() }}">{{ post.time|date(config.post_date) }}</time>
|
||||
</label>
|
||||
{% if config.poster_ids %}
|
||||
ID: {{ post.ip|poster_id(post.id) }}
|
||||
{% endif %}
|
||||
<a class="post_no" href="{{ post.link }}">No.</a>
|
||||
<a class="post_no"
|
||||
{% if not index %}
|
||||
onclick="citeReply({{ post.id }});"
|
||||
{% endif %}
|
||||
href="{% if index %}
|
||||
{{ post.link('q') }}
|
||||
{% else %}
|
||||
javascript:void(0);
|
||||
{% endif %}">
|
||||
{{ post.id }}
|
||||
</a>
|
||||
{% if post.sticky %}
|
||||
<img class="icon" title="Sticky" src="{{ config.image_sticky }}" alt="Sticky" />
|
||||
{% endif %}
|
||||
{% if post.locked %}
|
||||
<img class="icon" title="Locked" src="{{ config.image_locked }}" alt="Locked" />
|
||||
{% endif %}
|
||||
{% if post.bumplocked and (config.mod.view_bumplock < 0 or (post.mod and post.mod|hasPermission(config.mod.view_bumplock, board.uri))) %}
|
||||
<img class="icon" title="Bumplocked" src="{{ config.image_bumplocked }}" alt="Bumplocked" />
|
||||
{% endif %}
|
||||
{% if index %}
|
||||
<a href="{{ post.root }}{{ board.dir }}{{ config.dir.res }}{{ config.file_page|sprintf(post.id) }}">[{% trans %}Reply{% endtrans %}]</a>
|
||||
{% endif %}
|
||||
{{ post.postControls }}
|
||||
</p>
|
||||
<div class="body">
|
||||
{% endfilter %}{% if index %}{{ post.body|truncate_body(post.link) }}{% else %}{{ post.body }}{% endif %}{% filter remove_whitespace %}
|
||||
</div>
|
||||
{% if post.omitted or post.omitted_images %}
|
||||
<span class="omitted">
|
||||
{% if post.omitted %}
|
||||
{% trans %}
|
||||
1 post
|
||||
{% plural post.omitted %}
|
||||
{{ count }} posts
|
||||
{% endtrans %}
|
||||
{% if post.omitted_images %}
|
||||
{% trans %}and{% endtrans %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if post.omitted_images %}
|
||||
{% trans %}
|
||||
1 image reply
|
||||
{% plural post.omitted_images %}
|
||||
{{ count }} image replies
|
||||
{% endtrans %}
|
||||
{% endif %} {% trans %}omitted. Click reply to view.{% endtrans %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if not index %}
|
||||
{% endif %}
|
||||
</div>{% endfilter %}
|
||||
{% set hr = post.hr %}
|
||||
{% for post in post.posts %}
|
||||
{% include 'post_reply.html' %}
|
||||
{% endfor %}
|
||||
<br class="clear"/>{% if hr %}<hr/>{% endif %}
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function basic_build($action, $settings) {
|
||||
function basic_build($action, $settings, $board) {
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
|
38
templates/themes/catalog/catalog.css
Normal file
38
templates/themes/catalog/catalog.css
Normal file
@ -0,0 +1,38 @@
|
||||
img {
|
||||
float:none!important;
|
||||
margin: auto;
|
||||
margin-bottom: 12px;
|
||||
max-height: 150px;
|
||||
max-width: 200px;
|
||||
box-shadow: 0 0 4px rgba(0, 0, 0, 0.55);
|
||||
border: 2px solid rgba(153, 153, 153, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
img:hover {
|
||||
border: 2px solid rgba(153, 153, 153, 0.27);
|
||||
}
|
||||
*/
|
||||
|
||||
div.thread {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom:25px;
|
||||
margin-left: 20px;
|
||||
margin-right: 15px;
|
||||
text-align:center;
|
||||
font-weight:normal;
|
||||
width:205px;
|
||||
overflow:hidden;
|
||||
position: relative;
|
||||
font-size:11px;
|
||||
padding: 15px;
|
||||
background: rgba(182, 182, 182, 0.12);
|
||||
border: 2px solid rgba(111, 111, 111, 0.34);
|
||||
max-height:300px;
|
||||
}
|
||||
|
||||
div.thread:hover {
|
||||
background: #D6DAF0;
|
||||
border-color: #B7C5D9;
|
||||
}
|
36
templates/themes/catalog/catalog.html
Normal file
36
templates/themes/catalog/catalog.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% filter remove_whitespace %}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
<title>{{ settings.title }}</title>
|
||||
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}"/>
|
||||
<link rel="stylesheet" media="screen" href="{{ config.root }}{{ settings.css }}"/>
|
||||
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}" />{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
{{ boardlist.top }}
|
||||
<header>
|
||||
<h1>{{ settings.title }} (<a href="{{link}}">/{{ board }}/</a>)</h1>
|
||||
<div class="subtitle">{{ settings.subtitle }}</div>
|
||||
</header>
|
||||
|
||||
<ul>
|
||||
{% for post in recent_posts %}
|
||||
<div class="thread">
|
||||
<a href="{{post.link}}">
|
||||
<img src="{{post.file}}" class="{{post.board}}" title="{{post.bump|date('%b %d %H:%M')}}">
|
||||
</a>
|
||||
<span class="replies">
|
||||
<strong>{% trans %}1 reply{% plural post.reply_count %}{{ count }} replies{% endtrans %}</strong><br/>
|
||||
{{ post.body }}
|
||||
</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<hr/>
|
||||
<p class="unimportant" style="margin-top:20px;text-align:center;">Powered by <a href="http://tinyboard.org/">Tinyboard</a> {{ config.version }} | <a href="http://tinyboard.org/">Tinyboard</a> Copyright © 2010-2013 Tinyboard Development Group</p>
|
||||
</body>
|
||||
</html>
|
||||
{% endfilter %}
|
42
templates/themes/catalog/info.php
Normal file
42
templates/themes/catalog/info.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
$theme = array();
|
||||
|
||||
// Theme name
|
||||
$theme['name'] = 'Catalog';
|
||||
// Description (you can use Tinyboard markup here)
|
||||
$theme['description'] = 'Show a post catalog.';
|
||||
$theme['version'] = 'v0.1';
|
||||
|
||||
// Theme configuration
|
||||
$theme['config'] = Array();
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Title',
|
||||
'name' => 'title',
|
||||
'type' => 'text',
|
||||
'default' => 'Catalog'
|
||||
);
|
||||
|
||||
$__boards = listBoards();
|
||||
$__default_boards = Array();
|
||||
foreach ($__boards as $__board)
|
||||
$__default_boards[] = $__board['uri'];
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Included boards',
|
||||
'name' => 'boards',
|
||||
'type' => 'text',
|
||||
'comment' => '(space seperated)',
|
||||
'default' => implode(' ', $__default_boards)
|
||||
);
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'CSS file',
|
||||
'name' => 'css',
|
||||
'type' => 'text',
|
||||
'default' => 'catalog.css',
|
||||
'comment' => '(eg. "catalog.css")'
|
||||
);
|
||||
|
||||
// Unique function name for building everything
|
||||
$theme['build_function'] = 'catalog_build';
|
60
templates/themes/catalog/theme.php
Normal file
60
templates/themes/catalog/theme.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function catalog_build($action, $settings, $board) {
|
||||
global $config;
|
||||
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
// - boards (board list changed)
|
||||
// - post (a reply has been made)
|
||||
// - post-thread (a thread has been made)
|
||||
|
||||
$boards = explode(' ', $settings['boards']);
|
||||
|
||||
if ($action == 'all') {
|
||||
copy('templates/themes/catalog/catalog.css', $config['dir']['home'] . $settings['css']);
|
||||
|
||||
foreach ($boards as $board) {
|
||||
$b = new Catalog();
|
||||
$b->build($settings, $board);
|
||||
}
|
||||
} elseif ($action == 'post-thread' && in_array($board, $boards)) {
|
||||
$b = new Catalog();
|
||||
$b->build($settings, $board);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap functions in a class so they don't interfere with normal Tinyboard operations
|
||||
class Catalog {
|
||||
public function build($settings, $board_name) {
|
||||
global $config, $board;
|
||||
|
||||
openBoard($board_name);
|
||||
|
||||
$recent_images = array();
|
||||
$recent_posts = array();
|
||||
$stats = array();
|
||||
|
||||
$query = query(sprintf("SELECT *, `id` AS `thread_id`, (SELECT COUNT(*) FROM `posts_%s` WHERE `thread` = `thread_id`) AS `reply_count`, '%s' AS `board` FROM `posts_%s` WHERE `thread` IS NULL ORDER BY `bump` DESC", $board_name, $board_name, $board_name)) or error(db_error());
|
||||
|
||||
while ($post = $query->fetch()) {
|
||||
$post['link'] = $config['root'] . $board['dir'] . $config['dir']['res'] . sprintf($config['file_page'], ($post['thread'] ? $post['thread'] : $post['id']));
|
||||
$post['board_name'] = $board['name'];
|
||||
$post['file'] = $config['uri_thumb'] . $post['thumb'];
|
||||
$recent_posts[] = $post;
|
||||
}
|
||||
|
||||
file_write($config['dir']['home'] . $board_name . '/catalog.html', Element('themes/catalog/catalog.html', Array(
|
||||
'settings' => $settings,
|
||||
'config' => $config,
|
||||
'boardlist' => createBoardlist(),
|
||||
'recent_images' => $recent_images,
|
||||
'recent_posts' => $recent_posts,
|
||||
'stats' => $stats,
|
||||
'board' => $board_name,
|
||||
'link' => $config['root'] . $board['dir']
|
||||
)));
|
||||
}
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function categories_build($action, $settings) {
|
||||
function categories_build($action, $settings, $board) {
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function frameset_build($action, $settings) {
|
||||
function frameset_build($action, $settings, $board) {
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
|
@ -1,12 +1,13 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function recentposts_build($action, $settings) {
|
||||
function recentposts_build($action, $settings, $board) {
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
// - boards (board list changed)
|
||||
// - post (a post has been made)
|
||||
// - post-thread (a thread has been made)
|
||||
|
||||
$b = new RecentPosts();
|
||||
$b->build($action, $settings);
|
||||
@ -23,7 +24,7 @@
|
||||
|
||||
$this->excluded = explode(' ', $settings['exclude']);
|
||||
|
||||
if ($action == 'all' || $action == 'post')
|
||||
if ($action == 'all' || $action == 'post' || $action == 'post-thread')
|
||||
file_write($config['dir']['home'] . $settings['html'], $this->homepage($settings));
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function rrdtool_build($action, $settings) {
|
||||
function rrdtool_build($action, $settings, $board) {
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
|
53
templates/themes/sitemap/info.php
Normal file
53
templates/themes/sitemap/info.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
$theme = Array();
|
||||
|
||||
// Theme name
|
||||
$theme['name'] = 'Sitemap Generator';
|
||||
// Description (you can use Tinyboard markup here)
|
||||
$theme['description'] = 'Generates an XML sitemap to help search engines find all threads and pages.';
|
||||
$theme['version'] = 'v1.0';
|
||||
|
||||
// Theme configuration
|
||||
$theme['config'] = Array();
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Sitemap Path',
|
||||
'name' => 'path',
|
||||
'type' => 'text',
|
||||
'default' => 'sitemap.xml',
|
||||
'size' => '20'
|
||||
);
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'URL prefix',
|
||||
'name' => 'url',
|
||||
'type' => 'text',
|
||||
'comment' => '(with trailing slash)',
|
||||
'default' => 'http://' . (isset ($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : "localhost") . $config['root'],
|
||||
'size' => '20'
|
||||
);
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Thread change frequency',
|
||||
'name' => 'changefreq',
|
||||
'type' => 'text',
|
||||
'comment' => '(eg. "hourly", "daily", etc.)',
|
||||
'default' => 'hourly',
|
||||
'size' => '20'
|
||||
);
|
||||
|
||||
$__boards = listBoards();
|
||||
$__default_boards = Array();
|
||||
foreach ($__boards as $__board)
|
||||
$__default_boards[] = $__board['uri'];
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Boards',
|
||||
'name' => 'boards',
|
||||
'type' => 'text',
|
||||
'comment' => '(boards to include; space seperated)',
|
||||
'size' => 24,
|
||||
'default' => implode(' ', $__default_boards)
|
||||
);
|
||||
|
||||
$theme['build_function'] = 'sitemap_build';
|
19
templates/themes/sitemap/sitemap.xml
Normal file
19
templates/themes/sitemap/sitemap.xml
Normal file
@ -0,0 +1,19 @@
|
||||
{% filter remove_whitespace %}
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
{% for board in boards %}
|
||||
<url>
|
||||
<loc>{{ settings.url ~ (config.board_path | format(board)) ~ config.file_index }}</loc>
|
||||
</url>
|
||||
{% endfor %}
|
||||
{% for board, thread_list in threads %}
|
||||
{% for thread in thread_list %}
|
||||
<url>
|
||||
<loc>{{ settings.url ~ (config.board_path | format(board)) ~ config.dir.res ~ (config.file_page | format(thread.thread_id)) }}</loc>
|
||||
<lastmod>{{ thread.lastmod | date('%Y-%m-%dT%H:%M:%S') }}{{ timezone() }}</lastmod>
|
||||
<changefreq>{{ settings.changefreq }}</changefreq>
|
||||
</url>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</urlset>
|
||||
{% endfilter %}
|
32
templates/themes/sitemap/theme.php
Normal file
32
templates/themes/sitemap/theme.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function sitemap_build($action, $settings, $board) {
|
||||
global $config;
|
||||
|
||||
// Possible values for $action:
|
||||
// - all (rebuild everything, initialization)
|
||||
// - news (news has been updated)
|
||||
// - boards (board list changed)
|
||||
// - post (a post has been made)
|
||||
// - thread (a thread has been made)
|
||||
|
||||
if ($action != 'post' && $action != 'post-thread')
|
||||
return;
|
||||
|
||||
$boards = explode(' ', $settings['boards']);
|
||||
|
||||
$threads = array();
|
||||
|
||||
foreach ($boards as $board) {
|
||||
$query = query(sprintf("SELECT `id` AS `thread_id`, (SELECT `time` FROM `posts_%s` WHERE `thread` = `thread_id` OR `id` = `thread_id` ORDER BY `time` DESC LIMIT 1) AS `lastmod` FROM `posts_%s` WHERE `thread` IS NULL", $board, $board)) or error(db_error());
|
||||
$threads[$board] = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
file_write($settings['path'], Element('themes/sitemap/sitemap.xml', Array(
|
||||
'settings' => $settings,
|
||||
'config' => $config,
|
||||
'threads' => $threads,
|
||||
'boards' => $boards,
|
||||
)));
|
||||
}
|
53
templates/themes/ukko/info.php
Normal file
53
templates/themes/ukko/info.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
$theme = Array();
|
||||
|
||||
// Theme name
|
||||
$theme['name'] = 'Ukko';
|
||||
// Description (you can use Tinyboard markup here)
|
||||
$theme['description'] = 'Board with threads and messages from all boards';
|
||||
$theme['version'] = 'v0.1';
|
||||
|
||||
// Theme configuration
|
||||
$theme['config'] = Array();
|
||||
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Board name',
|
||||
'name' => 'title',
|
||||
'type' => 'text',
|
||||
'default' => 'Ukko'
|
||||
);
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Board URI',
|
||||
'name' => 'uri',
|
||||
'type' => 'text',
|
||||
'comment' => '(ukko for example)'
|
||||
);
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Subtitle',
|
||||
'name' => 'subtitle',
|
||||
'type' => 'text',
|
||||
'comment' => '(%s = thread limit. for example "%s freshly bumped threads")'
|
||||
);
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Excluded boards',
|
||||
'name' => 'exclude',
|
||||
'type' => 'text',
|
||||
'comment' => '(space seperated)'
|
||||
);
|
||||
$theme['config'][] = Array(
|
||||
'title' => 'Number of threads',
|
||||
'name' => 'thread_limit',
|
||||
'type' => 'text',
|
||||
'default' => '15',
|
||||
);
|
||||
// Unique function name for building everything
|
||||
$theme['build_function'] = 'ukko_build';
|
||||
$theme['install_callback'] = 'ukko_install';
|
||||
|
||||
if(!function_exists('ukko_install')) {
|
||||
function ukko_install($settings) {
|
||||
if (!file_exists($settings['uri']))
|
||||
@mkdir($settings['uri'], 0777) or error("Couldn't create " . $settings['uri'] . ". Check permissions.", true);
|
||||
}
|
||||
}
|
||||
|
111
templates/themes/ukko/theme.php
Normal file
111
templates/themes/ukko/theme.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
require 'info.php';
|
||||
|
||||
function ukko_build($action, $settings) {
|
||||
$ukko = new ukko();
|
||||
$ukko->settings = $settings;
|
||||
$ukko->build();
|
||||
}
|
||||
|
||||
class ukko {
|
||||
public $settings;
|
||||
public function build($mod = false) {
|
||||
global $config;
|
||||
$boards = listBoards();
|
||||
|
||||
$body = '';
|
||||
$overflow = array();
|
||||
$board = array(
|
||||
'url' => $this->settings['uri'],
|
||||
'name' => $this->settings['title'],
|
||||
'title' => sprintf($this->settings['subtitle'], $this->settings['thread_limit'])
|
||||
);
|
||||
|
||||
$query = '';
|
||||
foreach($boards as &$_board) {
|
||||
if(in_array($_board['uri'], explode(' ', $this->settings['exclude'])))
|
||||
continue;
|
||||
$query .= sprintf("SELECT *, '%s' AS `board` FROM `posts_%s` WHERE `thread` IS NULL UNION ALL ", $_board['uri'], $_board['uri']);
|
||||
}
|
||||
$query = preg_replace('/UNION ALL $/', 'ORDER BY `bump` DESC', $query);
|
||||
$query = query($query) or error(db_error());
|
||||
|
||||
$count = 0;
|
||||
$threads = array();
|
||||
while($post = $query->fetch()) {
|
||||
|
||||
if(!isset($threads[$post['board']])) {
|
||||
$threads[$post['board']] = 1;
|
||||
} else {
|
||||
$threads[$post['board']] += 1;
|
||||
}
|
||||
|
||||
if($count < $this->settings['thread_limit']) {
|
||||
openBoard($post['board']);
|
||||
$thread = new Thread(
|
||||
$post['id'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], $post['time'],
|
||||
$post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], $post['fileheight'], $post['filesize'],
|
||||
$post['filename'], $post['ip'], $post['sticky'], $post['locked'], $post['sage'], $post['embed'], $mod ? '?/' : $config['root'], $mod
|
||||
);
|
||||
|
||||
$posts = prepare(sprintf("SELECT * FROM `posts_%s` WHERE `thread` = :id ORDER BY `id` DESC LIMIT :limit", $post['board']));
|
||||
$posts->bindValue(':id', $post['id']);
|
||||
$posts->bindValue(':limit', ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']), PDO::PARAM_INT);
|
||||
$posts->execute() or error(db_error($posts));
|
||||
|
||||
$num_images = 0;
|
||||
while ($po = $posts->fetch()) {
|
||||
if ($po['file'])
|
||||
$num_images++;
|
||||
|
||||
$thread->add(new Post(
|
||||
$po['id'], $post['id'], $po['subject'], $po['email'], $po['name'], $po['trip'], $po['capcode'], $po['body'], $po['time'],
|
||||
$po['thumb'], $po['thumbwidth'], $po['thumbheight'], $po['file'], $po['filewidth'], $po['fileheight'], $po['filesize'],
|
||||
$po['filename'], $po['ip'], $po['embed'], $mod ? '?/' : $config['root'], $mod)
|
||||
);
|
||||
|
||||
}
|
||||
if ($posts->rowCount() == ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview'])) {
|
||||
$ct = prepare(sprintf("SELECT COUNT(`id`) as `num` FROM `posts_%s` WHERE `thread` = :thread UNION ALL SELECT COUNT(`id`) FROM `posts_%s` WHERE `file` IS NOT NULL AND `thread` = :thread", $post['board'], $post['board']));
|
||||
$ct->bindValue(':thread', $post['id'], PDO::PARAM_INT);
|
||||
$ct->execute() or error(db_error($count));
|
||||
|
||||
$c = $ct->fetch();
|
||||
$thread->omitted = $c['num'] - ($post['sticky'] ? $config['threads_preview_sticky'] : $config['threads_preview']);
|
||||
|
||||
$c = $ct->fetch();
|
||||
$thread->omitted_images = $c['num'] - $num_images;
|
||||
}
|
||||
|
||||
|
||||
$thread->posts = array_reverse($thread->posts);
|
||||
$body .= '<h2><a href="' . $config['root'] . $post['board'] . '">/' . $post['board'] . '/</a></h2>';
|
||||
$body .= $thread->build(true);
|
||||
} else {
|
||||
$page = 'index';
|
||||
if(floor($threads[$post['board']] / $config['threads_per_page']) > 0) {
|
||||
$page = floor($threads[$post['board']] / $config['threads_per_page']) + 1;
|
||||
}
|
||||
$overflow[] = array('id' => $post['id'], 'board' => $post['board'], 'page' => $page . '.html');
|
||||
}
|
||||
|
||||
$count += 1;
|
||||
}
|
||||
|
||||
$body .= '<script> var overflow = ' . json_encode($overflow) . '</script>';
|
||||
$body .= '<script type="text/javascript" src="ukko.js"></script>';
|
||||
|
||||
file_write($this->settings['uri'] . '/index.html', Element('index.html', array(
|
||||
'config' => $config,
|
||||
'board' => $board,
|
||||
'no_post_form' => true,
|
||||
'body' => $body,
|
||||
'boardlist' => createBoardlist($mod)
|
||||
)));
|
||||
|
||||
file_write($this->settings['uri'] . '/ukko.js', Element('themes/ukko/ukko.js', array()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
BIN
templates/themes/ukko/thumb.png
Normal file
BIN
templates/themes/ukko/thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
37
templates/themes/ukko/ukko.js
Normal file
37
templates/themes/ukko/ukko.js
Normal file
@ -0,0 +1,37 @@
|
||||
var cache = new Array(),
|
||||
thread = false,
|
||||
loading = false;
|
||||
$(document).ready(function() {
|
||||
$(window).on('scroll', function() {
|
||||
if($(window).scrollTop() + $(window).height() + 100 > $(document).height() && !loading && overflow.length > 0) {
|
||||
var page = '../' + overflow[0].board + '/' + overflow[0].page;
|
||||
if($.inArray(page, cache) != -1) {
|
||||
thread = $('div#thread_' + overflow[0].id);
|
||||
if(thread.length > 0) {
|
||||
thread.prepend('<h2><a href="/' + overflow[0].board + '/">/' + overflow[0].board + '/</a></h2>');
|
||||
$('div[id*="thread_"]').last().after(thread.attr('data-board', overflow[0].board).css('display', 'block'));
|
||||
overflow.shift();
|
||||
}
|
||||
} else {
|
||||
loading = true;
|
||||
$.get(page, function(data) {
|
||||
cache.push(page);
|
||||
|
||||
$(data).find('div[id*="thread_"]').each(function() {
|
||||
$('body').prepend($(this).css('display', 'none').attr('data-board', overflow[0].board));
|
||||
});
|
||||
|
||||
thread = $('div#thread_' + overflow[0].id + '[data-board="' + overflow[0].board + '"]');
|
||||
if(thread.length > 0) {
|
||||
thread.prepend('<h2><a href="/' + overflow[0].board + '/">/' + overflow[0].board + '/</a></h2>');
|
||||
$('div[id*="thread_"]').last().after(thread.attr('data-board', overflow[0].board).css('display', 'block'));
|
||||
overflow.shift();
|
||||
}
|
||||
|
||||
loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
@ -2,35 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src='https://int.vichan.net/opportunistic_https.js'></script>
|
||||
<link rel="stylesheet" media="screen" href="{{ config.url_stylesheet }}">
|
||||
{% if config.url_favicon %}<link rel="shortcut icon" href="{{ config.url_favicon }}">{% endif %}
|
||||
<title>{{ board.url }} - {{ board.name }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=yes">
|
||||
{% if config.meta_keywords %}<meta name="keywords" content="{{ config.meta_keywords }}">{% endif %}
|
||||
{% if config.default_stylesheet.1 != '' %}<link rel="stylesheet" type="text/css" id="stylesheet" href="{{ config.uri_stylesheets }}{{ config.default_stylesheet.1 }}">{% endif %}
|
||||
<script type="text/javascript">var configRoot="{{ config.root }}";</script>
|
||||
{% if not nojavascript %}
|
||||
<script type="text/javascript" src="{{ config.url_javascript }}"></script>
|
||||
{% if not config.additional_javascript_compile %}
|
||||
{% for javascript in config.additional_javascript %}<script type="text/javascript" src="{{ config.additional_javascript_url }}{{ javascript }}"></script>{% endfor %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if config.recaptcha %}<style type="text/css">{% raw %}
|
||||
.recaptcha_image_cell {
|
||||
background: none !important;
|
||||
}
|
||||
table.recaptchatable {
|
||||
border: none !important;
|
||||
}
|
||||
#recaptcha_logo, #recaptcha_tagline {
|
||||
display: none;
|
||||
float: right;
|
||||
}
|
||||
.recaptchatable a {
|
||||
display: block;
|
||||
}
|
||||
{% endraw %}</style>{% endif %}
|
||||
|
||||
<script type="text/javascript">
|
||||
var active_page = "thread";
|
||||
</script>
|
||||
|
||||
{% include 'header.html' %}
|
||||
<title>{{ board.url }} - {% if config.thread_subject_in_title and thread.subject %}{{ thread.subject }}{% else %}{{ board.title|e }}{% endif %}</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ boardlist.top }}
|
||||
|
52
tools/benchmark.php
Normal file
52
tools/benchmark.php
Normal file
@ -0,0 +1,52 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
/*
|
||||
* benchmark.php - benchmarks thumbnailing methods
|
||||
*
|
||||
*/
|
||||
|
||||
require dirname(__FILE__) . '/inc/cli.php';
|
||||
require 'inc/image.php';
|
||||
|
||||
// move back to this directory
|
||||
chdir(dirname(__FILE__));
|
||||
|
||||
if(count($argv) != 2)
|
||||
die("Usage: {$argv[0]} [file]\n");
|
||||
|
||||
$file = $argv[1];
|
||||
$extension = strtolower(substr($file, strrpos($file, '.') + 1));
|
||||
$out = tempnam($config['tmp'], 'thumb');
|
||||
$count = 300;
|
||||
|
||||
function benchmark($method) {
|
||||
global $config, $file, $extension, $out, $count;
|
||||
|
||||
$config['thumb_method'] = $method;
|
||||
|
||||
printf("Method: %s\nThumbnailing %d times... ", $method, $count);
|
||||
|
||||
$start = microtime(true);
|
||||
for($i = 0; $i < $count; $i++) {
|
||||
$image = new Image($file, $extension);
|
||||
$thumb = $image->resize(
|
||||
$config['thumb_ext'] ? $config['thumb_ext'] : $extension,
|
||||
$config['thumb_width'],
|
||||
$config['thumb_height']
|
||||
);
|
||||
|
||||
$thumb->to($out);
|
||||
$thumb->_destroy();
|
||||
$image->destroy();
|
||||
}
|
||||
$end = microtime(true);
|
||||
|
||||
printf("Took %.2f seconds (%.2f/second; %.2f ms)\n", $end - $start, $rate = ($count / ($end - $start)), 1000 / $rate);
|
||||
|
||||
unlink($out);
|
||||
}
|
||||
|
||||
benchmark('gd');
|
||||
benchmark('imagick');
|
||||
benchmark('convert');
|
||||
|
44
tools/i18n_compile.php
Executable file
44
tools/i18n_compile.php
Executable file
@ -0,0 +1,44 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* i18n_compile.php - compiles the i18n
|
||||
*
|
||||
* Options:
|
||||
* -l [locale], --locale=[locale]
|
||||
* Compiles [locale] locale.
|
||||
*
|
||||
*/
|
||||
|
||||
require dirname(__FILE__) . '/inc/cli.php';
|
||||
|
||||
// parse command line
|
||||
$opts = getopt('l:', Array('locale:'));
|
||||
$options = Array();
|
||||
|
||||
$options['locale'] = isset($opts['l']) ? $opts['l'] : (isset($opts['locale']) ? $opts['locale'] : false);
|
||||
|
||||
if ($options['locale']) $locales = array($options['locale']);
|
||||
else die("Error: no locales specified; use -l switch, eg. -l pl_PL\n");
|
||||
|
||||
foreach ($locales as $loc) {
|
||||
if (file_exists ($locdir = "inc/locale/".$loc)) {
|
||||
if (!is_dir ($locdir)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
die("Error: $locdir does not exist\n");
|
||||
}
|
||||
|
||||
// Generate tinyboard.po
|
||||
if (file_exists($locdir."/LC_MESSAGES/tinyboard.po")) $join = "-j";
|
||||
else $join = "";
|
||||
passthru("cd $locdir/LC_MESSAGES;
|
||||
msgfmt tinyboard.po -o tinyboard.mo");
|
||||
|
||||
// Generate javascript.po
|
||||
passthru("cd tools/inc/lib/jsgettext/;
|
||||
php po2json.php -i ../../../../$locdir/LC_MESSAGES/javascript.po \
|
||||
-o ../../../../$locdir/LC_MESSAGES/javascript.js");
|
||||
}
|
47
tools/i18n_extract.php
Executable file
47
tools/i18n_extract.php
Executable file
@ -0,0 +1,47 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* i18n_extract.php - extracts the strings and updates all locales
|
||||
*
|
||||
* Options:
|
||||
* -l [locale], --locale=[locale]
|
||||
* Updates only [locale] locale. If it does not exist yet, we create a new directory.
|
||||
*
|
||||
*/
|
||||
|
||||
require dirname(__FILE__) . '/inc/cli.php';
|
||||
|
||||
// parse command line
|
||||
$opts = getopt('l:', Array('locale:'));
|
||||
$options = Array();
|
||||
|
||||
$options['locale'] = isset($opts['l']) ? $opts['l'] : (isset($opts['locale']) ? $opts['locale'] : false);
|
||||
|
||||
$locales = glob("inc/locale/*");
|
||||
$locales = array_map("basename", $locales);
|
||||
|
||||
if ($options['locale']) $locales = array($options['locale']);
|
||||
|
||||
|
||||
foreach ($locales as $loc) {
|
||||
if (file_exists ($locdir = "inc/locale/".$loc)) {
|
||||
if (!is_dir ($locdir)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
mkdir($locdir);
|
||||
mkdir($locdir."/LC_MESSAGES");
|
||||
}
|
||||
|
||||
// Generate tinyboard.po
|
||||
if (file_exists($locdir."/LC_MESSAGES/tinyboard.po")) $join = "-j";
|
||||
else $join = "";
|
||||
passthru("cd $locdir/LC_MESSAGES;
|
||||
xgettext -d tinyboard -L php --from-code utf-8 $join -c $(find ../../../../ -name \*.php)");
|
||||
|
||||
// Generate javascript.po
|
||||
passthru("cd $locdir/LC_MESSAGES;
|
||||
xgettext -d javascript -L Python --force-po --from-code utf-8 $join -c $(find ../../../../js/ -name \*.js)");
|
||||
}
|
100
tools/inc/cli.php
Normal file
100
tools/inc/cli.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This script will look for Tinyboard in the following places (in order):
|
||||
* - $TINYBOARD_PATH environment varaible
|
||||
* - ./
|
||||
* - ./Tinyboard/
|
||||
* - ../
|
||||
*/
|
||||
|
||||
set_time_limit(0);
|
||||
$shell_path = getcwd();
|
||||
|
||||
if(getenv('TINYBOARD_PATH') !== false)
|
||||
$dir = getenv('TINYBOARD_PATH');
|
||||
elseif(file_exists('inc/functions.php'))
|
||||
$dir = false;
|
||||
elseif(file_exists('Tinyboard') && is_dir('Tinyboard') && file_exists('Tinyboard/inc/functions.php'))
|
||||
$dir = 'Tinyboard';
|
||||
elseif(file_exists('../inc/functions.php'))
|
||||
$dir = '..';
|
||||
else
|
||||
die("Could not locate Tinyboard directory!\n");
|
||||
|
||||
if($dir && !chdir($dir))
|
||||
die("Could not change directory to {$dir}\n");
|
||||
|
||||
if(!getenv('TINYBOARD_PATH')) {
|
||||
// follow symlink
|
||||
chdir(realpath('inc') . '/..');
|
||||
}
|
||||
|
||||
putenv('TINYBOARD_PATH=' . getcwd());
|
||||
|
||||
require 'inc/functions.php';
|
||||
require 'inc/mod.php';
|
||||
|
||||
$mod = Array(
|
||||
'id' => -1,
|
||||
'type' => ADMIN,
|
||||
'username' => '?',
|
||||
'boards' => Array('*')
|
||||
);
|
||||
|
||||
function get_httpd_privileges() {
|
||||
global $config, $shell_path, $argv;
|
||||
|
||||
if(php_sapi_name() != 'cli')
|
||||
die("get_httpd_privileges(): invoked from HTTP client.\n");
|
||||
|
||||
echo "Dropping priviledges...\n";
|
||||
|
||||
if(!is_writable('.'))
|
||||
die("get_httpd_privileges(): web directory is not writable\n");
|
||||
|
||||
$filename = '.' . md5(rand()) . '.php';
|
||||
$inc_filename = '.' . md5(rand()) . '.php';
|
||||
|
||||
echo "Copying rebuilder to web directory...\n";
|
||||
|
||||
// replace "/inc/cli.php" with its new filename
|
||||
passthru("cat " . escapeshellarg($shell_path . '/' . $_SERVER['PHP_SELF']) . " | sed \"s/'\/inc\/cli\.php'/'\/{$inc_filename}'/\" > {$filename}");
|
||||
|
||||
$inc_header = "<?php\n";
|
||||
|
||||
// copy environment
|
||||
$env = explode("\n", shell_exec('printenv | grep ^TINYBOARD'));
|
||||
foreach($env as $line) {
|
||||
if(!empty($line))
|
||||
$inc_header .= "putenv('" . addslashes($line) . "');\n";
|
||||
}
|
||||
|
||||
// copy command line arguments
|
||||
$inc_header .= "\$argv = " . var_export($argv, true) . ";\n";
|
||||
|
||||
// copy this file
|
||||
file_put_contents($inc_filename, $inc_header . substr($inc = file_get_contents(__FILE__), strpos($inc, "\n")));
|
||||
|
||||
chmod($filename, 0666);
|
||||
chmod($inc_filename, 0666);
|
||||
|
||||
if(preg_match('/^https?:\/\//', $config['root'])) {
|
||||
$url = $config['root'] . $filename;
|
||||
} elseif($host = getenv('TINYBOARD_HOST')) {
|
||||
$url = 'http://' . $host . $config['root'] . $filename;
|
||||
} else {
|
||||
// assume localhost
|
||||
$url = 'http://localhost' . $config['root'] . $filename;
|
||||
}
|
||||
|
||||
echo "Downloading $url\n";
|
||||
|
||||
passthru('curl -s -N ' . escapeshellarg($url));
|
||||
|
||||
unlink($filename);
|
||||
unlink($inc_filename);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
94
tools/inc/lib/jsgettext/JSParser.php
Normal file
94
tools/inc/lib/jsgettext/JSParser.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
class JSParser {
|
||||
|
||||
protected $content;
|
||||
protected $keywords;
|
||||
protected $regs = array();
|
||||
protected $regsCounter = 0;
|
||||
protected $strings = array();
|
||||
protected $stringsCounter = 0;
|
||||
|
||||
protected function _extractRegs($match) {
|
||||
$this->regs[$this->regsCounter] = $match[1];
|
||||
$id = "<<reg{$this->regsCounter}>>";
|
||||
$this->regsCounter++;
|
||||
return $id;
|
||||
}
|
||||
protected function _extractStrings($match) {
|
||||
$this->strings[$this->stringsCounter] = $this->importRegExps($match[0]);
|
||||
$id = "<<s{$this->stringsCounter}>>";
|
||||
$this->stringsCounter++;
|
||||
return $id;
|
||||
}
|
||||
protected function importRegExps($input) {
|
||||
$regs = $this->regs;
|
||||
return preg_replace_callback("#<<reg(\d+)>>#", function ($match) use($regs) {
|
||||
return $regs[$match[1]];
|
||||
}, $input);
|
||||
}
|
||||
|
||||
protected function importStrings($input) {
|
||||
$strings = $this->strings;
|
||||
return preg_replace_callback("#<<s(\d+)>>#", function ($match) use($strings) {
|
||||
return $strings[$match[1]];
|
||||
}, $input);
|
||||
}
|
||||
|
||||
public function __construct($file, $keywords = '_') {
|
||||
$this->content = file_get_contents($file);
|
||||
$this->keywords = (array)$keywords;
|
||||
}
|
||||
|
||||
public function parse() {
|
||||
$output = $this->content; //htmlspecialchars($this->content, ENT_NOQUOTES);
|
||||
|
||||
// extract reg exps
|
||||
$output = preg_replace_callback(
|
||||
'# ( / (?: (?>[^/\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\/ )+ (?<!\\\\)/ ) [a-z]* \b #ix',
|
||||
array($this, '_extractRegs'), $output
|
||||
);
|
||||
|
||||
// extract strings
|
||||
$output = preg_replace_callback(
|
||||
array(
|
||||
'# " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" #ix',
|
||||
"# ' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)' #ix"
|
||||
), array($this, '_extractStrings'), $output
|
||||
);
|
||||
|
||||
// delete line comments
|
||||
$output = preg_replace("#(//.*?)$#m", '', $output);
|
||||
|
||||
// delete multiline comments
|
||||
$output = preg_replace('#/\*(.*?)\*/#is', '', $output);
|
||||
|
||||
$strings = $this->strings;
|
||||
$output = preg_replace_callback("#<<s(\d+)>>#", function($match) use($strings) {
|
||||
return $strings[$match[1]];
|
||||
}, $output);
|
||||
|
||||
$keywords = implode('|', $this->keywords);
|
||||
|
||||
$strings = array();
|
||||
|
||||
// extract func calls
|
||||
preg_match_all(
|
||||
'# (?:'.$keywords.') \(\\ *" ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)"\\ *\) #ix',
|
||||
$output, $matches, PREG_SET_ORDER
|
||||
);
|
||||
|
||||
foreach ($matches as $m) $strings[] = stripslashes($m[1]);
|
||||
|
||||
$matches = array();
|
||||
preg_match_all(
|
||||
"# (?:$keywords) \(\\ *' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)'\\ *\) #ix",
|
||||
$output, $matches, PREG_SET_ORDER
|
||||
);
|
||||
|
||||
foreach ($matches as $m) $strings[] = stripslashes($m[1]);
|
||||
|
||||
return $strings;
|
||||
}
|
||||
}
|
||||
?>
|
83
tools/inc/lib/jsgettext/PoeditParser.php
Normal file
83
tools/inc/lib/jsgettext/PoeditParser.php
Normal file
@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
require_once 'PoeditString.php';
|
||||
|
||||
class PoeditParser {
|
||||
|
||||
protected $file;
|
||||
protected $header = '';
|
||||
protected $strings = array();
|
||||
|
||||
protected function _fixQuotes($str) {
|
||||
return stripslashes($str);
|
||||
}
|
||||
|
||||
public function __construct($file) {
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public function parse() {
|
||||
$contents = file_get_contents($this->file);
|
||||
|
||||
$parts = preg_split('#(\r\n|\n){2}#', $contents, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
$this->header = array_shift($parts);
|
||||
|
||||
foreach ($parts as $part) {
|
||||
|
||||
// parse comments
|
||||
$comments = array();
|
||||
preg_match_all('#^\\#: (.*?)$#m', $part, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $m) $comments[] = $m[1];
|
||||
|
||||
$isFuzzy = preg_match('#^\\#, fuzzy$#im', $part) ? true : false;
|
||||
|
||||
preg_match_all('# ^ (msgid|msgstr)\ " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" $ #ixm', $part, $matches2, PREG_SET_ORDER);
|
||||
|
||||
$k = $this->_fixQuotes($matches2[0][2]);
|
||||
$v = !empty($matches2[1][2]) ? $this->_fixQuotes($matches2[1][2]) : '';
|
||||
|
||||
$this->strings[$k] = new PoeditString($k, $v, $isFuzzy, $comments);
|
||||
}
|
||||
}
|
||||
|
||||
public function merge($strings) {
|
||||
foreach ((array)$strings as $str) {
|
||||
if (!in_array($str, array_keys($this->strings))) {
|
||||
$this->strings[$str] = new PoeditString($str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getHeader() {
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
public function getStrings() {
|
||||
return $this->strings;
|
||||
}
|
||||
|
||||
public function getJSON() {
|
||||
$str = array();
|
||||
foreach ($this->strings as $s) {
|
||||
if ($s->value) $str[$s->key] = $s->value;
|
||||
}
|
||||
return json_encode($str);
|
||||
}
|
||||
|
||||
public function toJSON($outputFilename, $varName = 'l10n') {
|
||||
$str = "$varName = " . $this->getJSON() . ";";
|
||||
return file_put_contents($outputFilename, $str) !== false;
|
||||
}
|
||||
|
||||
public function save($filename = null) {
|
||||
$data = $this->header . "\n\n";
|
||||
foreach ($this->strings as $str) {
|
||||
$data .= $str;
|
||||
}
|
||||
return file_put_contents($filename ? $filename : $this->file, $data) !== false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
29
tools/inc/lib/jsgettext/PoeditString.php
Normal file
29
tools/inc/lib/jsgettext/PoeditString.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
class PoeditString {
|
||||
public $key;
|
||||
public $value;
|
||||
public $fuzzy;
|
||||
public $comments;
|
||||
|
||||
function __construct($key, $value = '', $fuzzy = false, $comments = array()) {
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
$this->fuzzy = $fuzzy;
|
||||
$this->comments = (array)$comments;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
$str ='';
|
||||
foreach ($this->comments as $c) {
|
||||
$str .= "#: $c\n";
|
||||
}
|
||||
if ($this->fuzzy) $str .= "#, fuzzy\n";
|
||||
$str .= 'msgid "'.str_replace('"', '\\"', $this->key).'"' . "\n";
|
||||
$str .= 'msgstr "'.str_replace('"', '\\"', $this->value).'"' . "\n";
|
||||
$str .= "\n";
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
63
tools/inc/lib/jsgettext/jsgettext.php
Normal file
63
tools/inc/lib/jsgettext/jsgettext.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
require_once 'JSParser.php';
|
||||
require_once 'PoeditParser.php';
|
||||
|
||||
function buildOptions($args) {
|
||||
$options = array(
|
||||
'files' => array(),
|
||||
'-o' => null,
|
||||
'-k' => '_'
|
||||
);
|
||||
$len = count($args);
|
||||
$i = 1;
|
||||
while ($i < $len) {
|
||||
if (preg_match('#^-[a-z]$#i', $args[$i])) {
|
||||
$options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true;
|
||||
$i += 2;
|
||||
}
|
||||
else {
|
||||
$options['files'][] = $args[$i];
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
$options = buildOptions($argv);
|
||||
|
||||
if (!file_exists($options['-o'])) {
|
||||
touch($options['-o']);
|
||||
}
|
||||
|
||||
if (!is_writable($options['-o'])) {
|
||||
die("Invalid output file name. Make sure it exists and is writable.");
|
||||
}
|
||||
|
||||
$inputFiles = $options['files'];
|
||||
|
||||
if (empty($inputFiles)) {
|
||||
die("You did not provide any input file.");
|
||||
}
|
||||
|
||||
$poeditParser = new PoeditParser($options['-o']);
|
||||
$poeditParser->parse();
|
||||
|
||||
$errors = array();
|
||||
|
||||
foreach ($inputFiles as $f) {
|
||||
if (!is_readable($f) || !preg_match('#\.js$#', $f)) {
|
||||
$errors[] = ("$f is not a valid javascript file.");
|
||||
continue;
|
||||
}
|
||||
$jsparser = new JSParser($f, explode(' ', $options['-k']));
|
||||
$jsStrings = $jsparser->parse();
|
||||
$poeditParser->merge($jsStrings);
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
echo "\nThe following errors occured:\n" . implode("\n", $errors) . "\n";
|
||||
}
|
||||
|
||||
$poeditParser->save();
|
||||
?>
|
42
tools/inc/lib/jsgettext/po2json.php
Normal file
42
tools/inc/lib/jsgettext/po2json.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
require_once 'PoeditParser.php';
|
||||
|
||||
function buildOptions($args) {
|
||||
$options = array(
|
||||
'-o' => null,
|
||||
'-i' => null,
|
||||
'-n' => 'l10n'
|
||||
);
|
||||
$len = count($args);
|
||||
$i = 0;
|
||||
while ($i < $len) {
|
||||
if (preg_match('#^-[a-z]$#i', $args[$i])) {
|
||||
$options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true;
|
||||
$i += 2;
|
||||
}
|
||||
else {
|
||||
$options[] = $args[$i];
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
$options = buildOptions($argv);
|
||||
|
||||
if (!file_exists($options['-i']) || !is_readable($options['-i'])) {
|
||||
die("Invalid input file. Make sure it exists and is readable.");
|
||||
}
|
||||
|
||||
$poeditParser = new PoeditParser($options['-i']);
|
||||
$poeditParser->parse();
|
||||
|
||||
if ($poeditParser->toJSON($options['-o'], $options['-n'])) {
|
||||
$strings = count($poeditParser->getStrings());
|
||||
echo "Successfully exported " . count($strings) . " strings.\n";
|
||||
}
|
||||
else {
|
||||
echo "Cannor write to file '{$options['-o']}'.\n";
|
||||
}
|
||||
?>
|
105
tools/rebuild.php
Executable file
105
tools/rebuild.php
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* rebuild.php - rebuilds all static files
|
||||
*
|
||||
* Command line arguments:
|
||||
* -q, --quiet
|
||||
* Suppress output.
|
||||
*
|
||||
* --quick
|
||||
* Do not rebuild posts.
|
||||
*
|
||||
* -b, --board <string>
|
||||
* Rebuild only the specified board.
|
||||
*
|
||||
* -f, --full
|
||||
* Rebuild replies as well as threads (re-markup).
|
||||
*
|
||||
*/
|
||||
|
||||
require dirname(__FILE__) . '/inc/cli.php';
|
||||
|
||||
if(!is_writable($config['file_script'])) {
|
||||
get_httpd_privileges();
|
||||
}
|
||||
|
||||
$start = microtime(true);
|
||||
|
||||
// parse command line
|
||||
$opts = getopt('qfb:', Array('board:', 'quick', 'full', 'quiet'));
|
||||
$options = Array();
|
||||
|
||||
$options['board'] = isset($opts['board']) ? $opts['board'] : (isset($opts['b']) ? $opts['b'] : false);
|
||||
$options['quiet'] = isset($opts['q']) || isset($opts['quiet']);
|
||||
$options['quick'] = isset($opts['quick']);
|
||||
$options['full'] = isset($opts['full']) || isset($opts['f']);
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "== Tinyboard {$config['version']} ==\n";
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "Clearing template cache...\n";
|
||||
|
||||
load_twig();
|
||||
$twig->clearCacheFiles();
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "Regenerating theme files...\n";
|
||||
rebuildThemes('all');
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "Generating Javascript file...\n";
|
||||
buildJavascript();
|
||||
|
||||
$main_js = $config['file_script'];
|
||||
|
||||
$boards = listBoards();
|
||||
|
||||
foreach($boards as &$board) {
|
||||
if($options['board'] && $board['uri'] != $options['board'])
|
||||
continue;
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "Opening board /{$board['uri']}/...\n";
|
||||
openBoard($board['uri']);
|
||||
|
||||
if($config['file_script'] != $main_js) {
|
||||
// different javascript file
|
||||
if(!$options['quiet'])
|
||||
echo "Generating Javascript file...\n";
|
||||
buildJavascript();
|
||||
}
|
||||
|
||||
|
||||
if(!$options['quiet'])
|
||||
echo "Creating index pages...\n";
|
||||
buildIndex();
|
||||
|
||||
if($options['quick'])
|
||||
continue; // do no more
|
||||
|
||||
if($options['full']) {
|
||||
$query = query(sprintf("SELECT `id` FROM `posts_%s`", $board['uri'])) or error(db_error());
|
||||
while($post = $query->fetch()) {
|
||||
if(!$options['quiet'])
|
||||
echo "Rebuilding #{$post['id']}...\n";
|
||||
rebuildPost($post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$query = query(sprintf("SELECT `id` FROM `posts_%s` WHERE `thread` IS NULL", $board['uri'])) or error(db_error());
|
||||
while($post = $query->fetch()) {
|
||||
if(!$options['quiet'])
|
||||
echo "Rebuilding #{$post['id']}...\n";
|
||||
buildThread($post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if(!$options['quiet'])
|
||||
printf("Complete! Took %g seconds\n", microtime(true) - $start);
|
||||
|
||||
unset($board);
|
||||
modLog('Rebuilt everything using tools/rebuild.php');
|
||||
|
Loading…
Reference in New Issue
Block a user