mirror of
https://github.com/vichan-devel/vichan.git
synced 2025-01-19 01:24:05 +01:00
commit
79e972945f
3
404.php
3
404.php
@ -32,7 +32,10 @@ if (preg_match('!'.$config['board_regex'].'/'.$config['dir']['res'].'\d+\.html!u
|
||||
$return_link = '';
|
||||
}
|
||||
|
||||
$ad = Element("ad_top.html", array());
|
||||
|
||||
$page = <<<EOT
|
||||
<div style="text-align:center">$ad</div>
|
||||
<div class="ban">
|
||||
<p style="text-align:center"><img src="/static/404/{$errorimage}" style="width:100%"></p>
|
||||
<p style="text-align:center"><a href="/index.html">[ Home ]</a>{$return_link}</p>
|
||||
|
@ -31,7 +31,7 @@ function last_activity($board) {
|
||||
} else {// no one ever logged in, try board creation time
|
||||
$query = query("SELECT UNIX_TIMESTAMP(time) AS time FROM board_create WHERE uri = '$board'");
|
||||
$crt = $query->fetchAll(PDO::FETCH_COLUMN);
|
||||
$last_activity_date->setTimestamp($crt[0]);
|
||||
if ($crt) $last_activity_date->setTimestamp($crt[0]);
|
||||
$last_mod_date = false;
|
||||
}
|
||||
}
|
||||
|
45
dnsbls_bypass.php
Normal file
45
dnsbls_bypass.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
include 'inc/functions.php';
|
||||
include "inc/lib/recaptcha/recaptchalib.php";
|
||||
require_once 'Net/DNS2.php';
|
||||
checkBan('*');
|
||||
// My nameserver was broken and I couldn't edit resolv.conf so I just did this instead
|
||||
$dns = new Net_DNS2_Resolver(array('nameservers' => array('8.8.8.8')));
|
||||
$result = $dns->query(RECAPTCHA_VERIFY_SERVER, "A");
|
||||
if ($result and $result->answer[0]) {
|
||||
$RECAPTCHA_VERIFY_SERVER_IP = $result->answer[0]->address;
|
||||
} else {
|
||||
$RECAPTCHA_VERIFY_SERVER_IP = RECAPTCHA_VERIFY_SERVER;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
$ayah_html = recaptcha_get_html($config['recaptcha_public'], NULL, TRUE);
|
||||
$body = Element("8chan/dnsbls.html", array("config" => $config, "ayah_html" => $ayah_html));
|
||||
|
||||
echo Element("page.html", array("config" => $config, "body" => $body, "title" => _("Bypass DNSBL"), "subtitle" => _("Post even if blocked")));
|
||||
} else {
|
||||
$score = recaptcha_check_answer($config['recaptcha_private'],
|
||||
$_SERVER["REMOTE_ADDR"],
|
||||
$_POST["recaptcha_challenge_field"],
|
||||
$_POST["recaptcha_response_field"],
|
||||
array(),
|
||||
$RECAPTCHA_VERIFY_SERVER_IP);
|
||||
|
||||
if ($score->is_valid) {
|
||||
$tor = checkDNSBL($_SERVER['REMOTE_ADDR']);
|
||||
if (!$tor) {
|
||||
$query = prepare('INSERT INTO ``dnsbl_bypass`` VALUES(:ip, NOW()) ON DUPLICATE KEY UPDATE `created`=NOW()');
|
||||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
|
||||
$query->execute() or error(db_error($query));
|
||||
} else {
|
||||
$cookie = bin2hex(openssl_random_pseudo_bytes(16));
|
||||
$query = prepare('INSERT INTO ``tor_cookies`` VALUES(:cookie, NOW(), 0)');
|
||||
$query->bindValue(':cookie', $cookie);
|
||||
$query->execute() or error(db_error($query));
|
||||
setcookie("tor", $cookie);
|
||||
}
|
||||
echo Element("page.html", array("config" => $config, "body" => '', "title" => _("Success!"), "subtitle" => _("You may now go back and make your post.")));
|
||||
} else {
|
||||
error(_('You failed the CAPTCHA') . _('. <a href="https://8ch.net/dnsbls_bypass.php">Try again.</a> If it\'s not working, email admin@8chan.co for support.'));
|
||||
}
|
||||
}
|
9
faq.php
9
faq.php
@ -79,8 +79,9 @@ $body = <<<EOT
|
||||
<li>__underline__ -> <u>underline</u></li>
|
||||
<li>==heading== -> <span class='heading'>heading</span> (must be on own line)</li>
|
||||
<li>~~strikethrough~~ -> <s>strikethrough</s></li>
|
||||
<li>[aa] tags for ASCII/JIS art (escape formatting)</li>
|
||||
<li>[code] tags if enabled by board owner</li>
|
||||
<li>[tex] tags if enabled by board owner</li>
|
||||
<li>[tex] tags if enabled by board owner (currently globally disabled)</li>
|
||||
</ul>
|
||||
|
||||
<h2>How are featured boards chosen?</h2>
|
||||
@ -110,10 +111,14 @@ $body = <<<EOT
|
||||
<li>claim at 8chan dot co</li>
|
||||
</ul>
|
||||
|
||||
<h2>I would like to send you an encrypted message.</h2>
|
||||
<p>The current admin contact private key can always be found at <a href="https://8ch.net/pubkey.txt">https://8ch.net/pubkey.txt</a>.</p>
|
||||
<p>The current key fingerprint is <tt>6F12 EC72 A82A BCA3 5235 063A 10DD C983 901A A183</tt>.</p>
|
||||
|
||||
<h2>How do I donate?</h2>
|
||||
<p>Donations can be sent to 1NpQaXqmCBji6gfX8UgaQEmEstvVY7U32C (Bitcoin) or LUPgSCJt3iGeJXUETVhmnbQ89Riaq1yjZm (Litecoin).</p>
|
||||
<p>I am also a big fan of Monero (XMR). You can send XMR to our <a href="http://openalias.org">OpenAlias</a> in the simplewallet client, or simply send to 49dBJhGhYFxJEfydS6hH6GRyg1W4cDgupdNVtw7j1WtcUY7xPXwNLw6fUVay644viaCcEhMFG1Z7SjjxRXEFDdNWJdvH9kS.</p>
|
||||
<p>You may also donate monthly via Patreon at <a href="http://www.patreon.com/user?u=162165">http://www.patreon.com/user?u=162165</a>.
|
||||
<p>If you would like to support development of the engine that 8chan runs on (infinity), you may also <a href="https://gratipay.com/infinitechan">donate via Gratipay</a>.</p>
|
||||
<h2>Are you really a cripple?</h2>
|
||||
<p>Yes.</p>
|
||||
|
||||
|
@ -14,6 +14,28 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('is_billion_laughs')){
|
||||
function is_billion_laughs($arr1, $arr2) {
|
||||
$arr = array();
|
||||
foreach ($arr1 as $k => $v) {
|
||||
$arr[$v] = $arr2[$k];
|
||||
}
|
||||
|
||||
for ($i = 0; $i <= sizeof($arr); $i++) {
|
||||
$cur = array_slice($arr, $i, 1);
|
||||
$pst = array_slice($arr, 0, $i);
|
||||
if (!$cur) continue;
|
||||
$kk = array_keys($cur)[0];
|
||||
$vv = array_values($cur)[0];
|
||||
foreach ($pst as $k => $v) {
|
||||
if (str_replace($kk, $vv, $v) != $v)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$config['mod']['show_ip'] = GLOBALVOLUNTEER;
|
||||
$config['mod']['show_ip_less'] = BOARDVOLUNTEER;
|
||||
$config['mod']['manageusers'] = GLOBALVOLUNTEER;
|
||||
@ -27,6 +49,7 @@
|
||||
$config['mod']['debug_antispam'] = ADMIN;
|
||||
$config['mod']['noticeboard_post'] = ADMIN;
|
||||
$config['mod']['modlog'] = GLOBALVOLUNTEER;
|
||||
$config['mod']['mod_board_log'] = MOD;
|
||||
$config['mod']['editpost'] = BOARDVOLUNTEER;
|
||||
$config['mod']['edit_banners'] = MOD;
|
||||
$config['mod']['edit_flags'] = MOD;
|
||||
@ -54,6 +77,8 @@
|
||||
$config['mod']['view_ban_appeals'] = BOARDVOLUNTEER;
|
||||
$config['mod']['view_ban'] = BOARDVOLUNTEER;
|
||||
$config['mod']['reassign_board'] = ADMIN;
|
||||
$config['mod']['move'] = GLOBALVOLUNTEER;
|
||||
$config['mod']['shadow_capcode'] = 'Global Volunteer';
|
||||
|
||||
$config['mod']['custom_pages']['/tags/(\%b)'] = function ($b) {
|
||||
global $board, $config;
|
||||
@ -408,7 +433,7 @@ FLAGS;
|
||||
$user_flags = isset($_POST['user_flags']) ? "if (file_exists('$b/flags.php')) { include 'flags.php'; }\n" : '';
|
||||
$captcha = isset($_POST['captcha']) ? 'true' : 'false';
|
||||
$force_subject_op = isset($_POST['force_subject_op']) ? 'true' : 'false';
|
||||
/*New thread captcha*/
|
||||
$tor_posting = isset($_POST['tor_posting']) ? 'true' : 'false';
|
||||
$new_thread_capt = isset($_POST['new_thread_capt']) ? 'true' : 'false';
|
||||
|
||||
|
||||
@ -461,6 +486,9 @@ OEKAKI;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_billion_laughs($_POST['replace'], $_POST['with'])) {
|
||||
error(_('Wordfilters may not wordfilter previous wordfilters. For example, if a filters to bb and b filters to cc, that is not allowed.'));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['hour_max_threads']) && in_array($_POST['hour_max_threads'], ['10', '25', '50', '100'])) {
|
||||
@ -504,7 +532,7 @@ OEKAKI;
|
||||
\$config['default_stylesheet'] = array('Custom', \$config['stylesheets']['Custom']);
|
||||
\$config['captcha']['enabled'] = $captcha;
|
||||
\$config['force_subject_op'] = $force_subject_op;
|
||||
/*New thread captcha*/
|
||||
\$config['tor_posting'] = $tor_posting;
|
||||
\$config['new_thread_capt'] = $new_thread_capt;
|
||||
\$config['hour_max_threads'] = $hour_max_threads;
|
||||
$code_tags $katex $oekaki $replace $multiimage $allow_flash $allow_pdf $user_flags
|
||||
@ -518,8 +546,7 @@ EOT;
|
||||
// Clean up our CSS...no more expression() or off-site URLs.
|
||||
$clean_css = preg_replace('/expression\s*\(/', '', $_POST['css']);
|
||||
|
||||
// URL matcher from SO:
|
||||
$match_urls = '(?xi)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))';
|
||||
$match_urls = '((?:(?:https?:)?\/\/|ftp:\/\/|irc:\/\/)[^\s<>()"]+?(?:\([^\s<>()"]*?\)[^\s<>()"]*?)*)((?:\s|<|>|"|\.|\]|!|\?|,|&\#44;|")*(?:[\s<>()"]|$))';
|
||||
|
||||
$matched = array();
|
||||
|
||||
@ -529,7 +556,7 @@ EOT;
|
||||
foreach ($matched[0] as $match) {
|
||||
$match_okay = false;
|
||||
foreach ($allowed_urls as $allowed_url) {
|
||||
if (strpos($match, $allowed_url) !== false) {
|
||||
if (strpos($match, $allowed_url) !== false && strpos($match, '#') === false) {
|
||||
$match_okay = true;
|
||||
}
|
||||
}
|
||||
@ -540,10 +567,9 @@ EOT;
|
||||
}
|
||||
|
||||
//Filter out imports from sites with potentially unsafe content
|
||||
$css_no_comments = preg_replace('|\/\*.*\*\/|', '', $clean_css); //I can't figure out how to ignore comments in the match
|
||||
$match_imports = '@import[^;]*';
|
||||
$matched = array();
|
||||
preg_match_all("#$match_imports#im", $css_no_comments, $matched);
|
||||
preg_match_all("#$match_imports#im", $clean_css, $matched);
|
||||
|
||||
$unsafe_import_urls = array('https://a.pomf.se/');
|
||||
|
||||
@ -551,7 +577,7 @@ EOT;
|
||||
foreach ($matched[0] as $match) {
|
||||
$match_okay = true;
|
||||
foreach ($unsafe_import_urls as $unsafe_import_url) {
|
||||
if (strpos($match, $unsafe_import_url) !== false) {
|
||||
if (strpos($match, $unsafe_import_url) !== false && strpos($match, '#') === false) {
|
||||
$match_okay = false;
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ class Api {
|
||||
$fields = $threadsPage ? $this->threadsPageFields : $this->postFields;
|
||||
$this->translateFields($fields, $post, $apiPost);
|
||||
|
||||
//if (isset($config['poster_ids'])) $apiPost['id'] = poster_id($post->ip, $post->thread, $board['uri']);
|
||||
if ($this->config['poster_ids']) $apiPost['id'] = poster_id($post->ip, $post->thread, $board['uri']);
|
||||
if ($threadsPage) return $apiPost;
|
||||
|
||||
// Handle country field
|
||||
|
11
inc/bans.php
11
inc/bans.php
@ -156,17 +156,18 @@ class Bans {
|
||||
|
||||
static public function stream_json($out = false, $filter_ips = false, $filter_staff = false, $board_access = false) {
|
||||
global $config, $pdo;
|
||||
|
||||
|
||||
if ($board_access && $board_access[0] == '*') $board_access = false;
|
||||
|
||||
$query_addition = "";
|
||||
if ($board_access !== FALSE) {
|
||||
$query_addition .= "WHERE `public_bans` OR `public_bans` IS NULL";
|
||||
}
|
||||
if ($board_access) {
|
||||
$boards = implode(", ", array_map(array($pdo, "quote"), $board_access));
|
||||
$query_addition .= " OR `board` IN (".$boards.")";
|
||||
$query_addition .= "WHERE `board` IN (".$boards.")";
|
||||
}
|
||||
if ($board_access !== FALSE) {
|
||||
if (!$query_addition) {
|
||||
$query_addition .= " WHERE (`public_bans` IS TRUE)";
|
||||
}
|
||||
}
|
||||
|
||||
$query = query("SELECT ``bans``.*, `username`, `type` FROM ``bans``
|
||||
|
@ -559,7 +559,7 @@
|
||||
$config['field_disable_password'] = false;
|
||||
|
||||
// When true, users are instead presented a selectbox for email. Contains, blank, noko and sage.
|
||||
$config['field_email_selectbox'] = false;
|
||||
$config['field_email_selectbox'] = &$config['field_disable_name'];
|
||||
|
||||
// When true, the sage won't be displayed
|
||||
$config['hide_sage'] = false;
|
||||
@ -1110,7 +1110,7 @@
|
||||
$config['error']['webmerror'] = _('There was a problem processing your webm.');//Is this error used anywhere ?
|
||||
$config['error']['invalidwebm'] = _('Invalid webm uploaded.');
|
||||
$config['error']['webmhasaudio'] = _('The uploaded webm contains an audio or another type of additional stream.');
|
||||
$config['error']['webmtoolong'] = _('The uploaded webm is longer than ' . $config['webm']['max_length'] . ' seconds.');
|
||||
$config['error']['webmtoolong'] = _('The uploaded webm is longer than %d seconds.');
|
||||
$config['error']['fileexists'] = _('That file <a href="%s">already exists</a>!');
|
||||
$config['error']['fileexistsinthread'] = _('That file <a href="%s">already exists</a> in this thread!');
|
||||
$config['error']['delete_too_soon'] = _('You\'ll have to wait another %s before deleting that.');
|
||||
|
@ -73,6 +73,9 @@ function createBoardlist($mod=false) {
|
||||
|
||||
function error($message, $priority = true, $debug_stuff = false) {
|
||||
global $board, $mod, $config, $db_error;
|
||||
|
||||
if (isset($debug_stuff['file']))
|
||||
$message .= " {$debug_stuff['file']}";
|
||||
|
||||
if ($config['syslog'] && $priority !== false) {
|
||||
// Use LOG_NOTICE instead of LOG_ERR or LOG_WARNING because most error message are not significant.
|
||||
|
@ -1050,19 +1050,22 @@ function deleteFile($id, $remove_entirely_if_already=true, $file=null) {
|
||||
|
||||
// rebuild post (markup)
|
||||
function rebuildPost($id) {
|
||||
global $board;
|
||||
global $board, $mod;
|
||||
|
||||
$query = prepare(sprintf("SELECT `body_nomarkup`, `thread` FROM ``posts_%s`` WHERE `id` = :id", $board['uri']));
|
||||
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE `id` = :id", $board['uri']));
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
if ((!$post = $query->fetch(PDO::FETCH_ASSOC)) || !$post['body_nomarkup'])
|
||||
return false;
|
||||
|
||||
markup($body = &$post['body_nomarkup']);
|
||||
markup($post['body'] = &$post['body_nomarkup']);
|
||||
$post = (object)$post;
|
||||
event('rebuildpost', $post);
|
||||
$post = (array)$post;
|
||||
|
||||
$query = prepare(sprintf("UPDATE ``posts_%s`` SET `body` = :body WHERE `id` = :id", $board['uri']));
|
||||
$query->bindValue(':body', $body);
|
||||
$query->bindValue(':body', $post['body']);
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
@ -1580,20 +1583,22 @@ function buildJavascript() {
|
||||
file_write($config['file_script'], $script);
|
||||
}
|
||||
|
||||
function checkDNSBL() {
|
||||
function checkDNSBL($use_ip = false) {
|
||||
global $config;
|
||||
|
||||
|
||||
if (isIPv6())
|
||||
return; // No IPv6 support yet.
|
||||
|
||||
if (!isset($_SERVER['REMOTE_ADDR']))
|
||||
if (!$use_ip && !isset($_SERVER['REMOTE_ADDR']))
|
||||
return; // Fix your web server configuration
|
||||
|
||||
if (in_array($_SERVER['REMOTE_ADDR'], $config['dnsbl_exceptions']))
|
||||
$ip = ($use_ip ? $use_ip : $_SERVER['REMOTE_ADDR']);
|
||||
if ($ip == '127.0.0.2') return true;
|
||||
|
||||
if (isIPv6($ip))
|
||||
return; // No IPv6 support yet.
|
||||
|
||||
if (in_array($ip, $config['dnsbl_exceptions']))
|
||||
return;
|
||||
|
||||
$ipaddr = ReverseIPOctets($_SERVER['REMOTE_ADDR']);
|
||||
$ipaddr = ReverseIPOctets($ip);
|
||||
|
||||
foreach ($config['dnsbl'] as $blacklist) {
|
||||
if (!is_array($blacklist))
|
||||
@ -1609,24 +1614,31 @@ function checkDNSBL() {
|
||||
|
||||
if (!isset($blacklist[1])) {
|
||||
// If you're listed at all, you're blocked.
|
||||
error(sprintf($config['error']['dnsbl'], $blacklist_name));
|
||||
if ($use_ip) {
|
||||
return true;
|
||||
} else {
|
||||
error(sprintf($config['error']['dnsbl'], $blacklist_name));
|
||||
}
|
||||
} elseif (is_array($blacklist[1])) {
|
||||
foreach ($blacklist[1] as $octet) {
|
||||
if ($ip == $octet || $ip == '127.0.0.' . $octet)
|
||||
error(sprintf($config['error']['dnsbl'], $blacklist_name));
|
||||
if ($ip == $octet || $ip == '127.0.0.' . $octet) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} elseif (is_callable($blacklist[1])) {
|
||||
if ($blacklist[1]($ip))
|
||||
error(sprintf($config['error']['dnsbl'], $blacklist_name));
|
||||
if ($blacklist[1]($ip)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if ($ip == $blacklist[1] || $ip == '127.0.0.' . $blacklist[1])
|
||||
error(sprintf($config['error']['dnsbl'], $blacklist_name));
|
||||
if ($ip == $blacklist[1] || $ip == '127.0.0.' . $blacklist[1]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isIPv6() {
|
||||
return strstr($_SERVER['REMOTE_ADDR'], ':') !== false;
|
||||
function isIPv6($ip = false) {
|
||||
return strstr(($ip ? $ip : $_SERVER['REMOTE_ADDR']), ':') !== false;
|
||||
}
|
||||
|
||||
function ReverseIPOctets($ip) {
|
||||
@ -1816,7 +1828,7 @@ function markup(&$body, $track_cites = false, $op = false) {
|
||||
}
|
||||
|
||||
if (isset($cited_posts[$cite])) {
|
||||
$replacement = '<a onclick="highlightReply(\''.$cite.'\');" href="' .
|
||||
$replacement = '<a onclick="highlightReply(\''.$cite.'\', event);" href="' .
|
||||
$config['root'] . $board['dir'] . $config['dir']['res'] .
|
||||
($cited_posts[$cite] ? $cited_posts[$cite] : $cite) . '.html#' . $cite . '">' .
|
||||
'>>' . $cite .
|
||||
@ -1915,7 +1927,7 @@ function markup(&$body, $track_cites = false, $op = false) {
|
||||
|
||||
$replacement = '<a ' .
|
||||
($_board == $board['uri'] ?
|
||||
'onclick="highlightReply(\''.$cite.'\');" '
|
||||
'onclick="highlightReply(\''.$cite.'\', event);" '
|
||||
: '') . 'href="' . $link . '">' .
|
||||
'>>>/' . $_board . '/' . $cite .
|
||||
'</a>';
|
||||
@ -2216,7 +2228,7 @@ function generate_tripcode($name) {
|
||||
if (isset($config['custom_tripcode']["##{$trip}"]))
|
||||
$trip = $config['custom_tripcode']["##{$trip}"];
|
||||
else
|
||||
$trip = '!!' . substr(crypt($trip, '_..A.' . substr(base64_encode(sha1($trip . $config['secure_trip_salt'], true)), 0, 4)), -10);
|
||||
$trip = '!!' . substr(crypt($trip, str_replace('+', '.', '_..A.' . substr(base64_encode(sha1($trip . $config['secure_trip_salt'], true)), 0, 4))), -10);
|
||||
} else {
|
||||
if (isset($config['custom_tripcode']["#{$trip}"]))
|
||||
$trip = $config['custom_tripcode']["#{$trip}"];
|
||||
|
@ -51,7 +51,7 @@
|
||||
require "secrets.php";
|
||||
|
||||
// Image shit
|
||||
$config['thumb_method'] = 'gm';
|
||||
$config['thumb_method'] = 'convert';
|
||||
$config['thumb_ext'] = 'jpg';
|
||||
$config['thumb_keep_animation_frames'] = 1;
|
||||
$config['show_ratio'] = true;
|
||||
@ -64,7 +64,7 @@
|
||||
$config['allowed_ext_files'][] = 'mp4';
|
||||
$config['webm']['use_ffmpeg'] = true;
|
||||
$config['webm']['allow_audio'] = true;
|
||||
$config['webm']['max_length'] = 60 * 15;
|
||||
$config['webm']['max_length'] = 60 * 30;
|
||||
|
||||
// Mod shit
|
||||
$config['mod']['groups'][25] = 'GlobalVolunteer';
|
||||
@ -103,7 +103,6 @@
|
||||
$config['additional_javascript'][] = 'js/update_boards.js';
|
||||
$config['additional_javascript'][] = 'js/favorites.js';
|
||||
$config['additional_javascript'][] = 'js/show-op.js';
|
||||
$config['additional_javascript'][] = 'js/hide-threads.js';
|
||||
$config['additional_javascript'][] = 'js/smartphone-spoiler.js';
|
||||
$config['additional_javascript'][] = 'js/inline-expanding.js';
|
||||
$config['additional_javascript'][] = 'js/show-backlinks.js';
|
||||
@ -143,11 +142,14 @@
|
||||
$config['additional_javascript'][] = 'js/quote-selection.js';
|
||||
$config['additional_javascript'][] = 'js/twemoji/twemoji.js';
|
||||
$config['additional_javascript'][] = 'js/flag-previews.js';
|
||||
$config['additional_javascript'][] = 'js/post-filter.js';
|
||||
$config['additional_javascript'][] = 'js/image-hover.js';
|
||||
|
||||
//$config['font_awesome_css'] = '/netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css';
|
||||
|
||||
$config['stylesheets']['Dark'] = 'dark.css';
|
||||
$config['stylesheets']['Photon'] = 'photon.css';
|
||||
$config['stylesheets']['Redchanit'] = 'redchanit.css';
|
||||
|
||||
$config['stylesheets_board'] = true;
|
||||
$config['markup'][] = array("/^[ |\t]*==(.+?)==[ |\t]*$/m", "<span class=\"heading\">\$1</span>");
|
||||
@ -156,7 +158,7 @@
|
||||
$config['markup'][] = array("/__(.+?)__/", "<u>\$1</u>");
|
||||
$config['markup'][] = array("/###([^\s']+)###/", "<a href='/boards.html#\$1'>###\$1###</a>");
|
||||
|
||||
$config['boards'] = array(array('<i class="fa fa-home" title="Home"></i>' => '/', '<i class="fa fa-tags" title="Boards"></i>' => '/boards.html', '<i class="fa fa-question" title="FAQ"></i>' => '/faq.html', '<i class="fa fa-random" title="Random"></i>' => '/random.php', '<i class="fa fa-plus" title="New board"></i>' => '/create.php', '<i class="fa fa-ban" title="Public ban list"></i>' => '/bans.html', '<i class="fa fa-search" title="Search"></i>' => '/search.php', '<i class="fa fa-cog" title="Manage board"></i>' => '/mod.php', '<i class="fa fa-quote-right" title="Chat"></i>' => 'https://qchat.rizon.net/?channels=#8chan'), array('b', 'meta', 'news+'), array('<i class="fa fa-twitter" title="Twitter"></i>'=>'https://twitter.com/infinitechan'));
|
||||
$config['boards'] = array(array('<i class="fa fa-home" title="Home"></i>' => '/', '<i class="fa fa-tags" title="Boards"></i>' => '/boards.html', '<i class="fa fa-question" title="FAQ"></i>' => '/faq.html', '<i class="fa fa-random" title="Random"></i>' => '/random.php', '<i class="fa fa-plus" title="New board"></i>' => '/create.php', '<i class="fa fa-ban" title="Public ban list"></i>' => '/bans.html', '<i class="fa fa-search" title="Search"></i>' => '/search.php', '<i class="fa fa-cog" title="Manage board"></i>' => '/mod.php', '<i class="fa fa-quote-right" title="Chat"></i>' => 'https://qchat.rizon.net/?channels=#8chan'), array('b', 'news+', 'boards'), array('operate', 'meta'), array('<i class="fa fa-twitter" title="Twitter"></i>'=>'https://twitter.com/infinitechan'));
|
||||
//$config['boards'] = array(array('<i class="fa fa-home" title="Home"></i>' => '/', '<i class="fa fa-tags" title="Boards"></i>' => '/boards.html', '<i class="fa fa-question" title="FAQ"></i>' => '/faq.html', '<i class="fa fa-random" title="Random"></i>' => '/random.php', '<i class="fa fa-plus" title="New board"></i>' => '/create.php', '<i class="fa fa-search" title="Search"></i>' => '/search.php', '<i class="fa fa-cog" title="Manage board"></i>' => '/mod.php', '<i class="fa fa-quote-right" title="Chat"></i>' => 'https://qchat.rizon.net/?channels=#8chan'), array('b', 'meta', 'int'), array('v', 'a', 'tg', 'fit', 'pol', 'tech', 'mu', 'co', 'sp', 'boards'), array('<i class="fa fa-twitter" title="Twitter"></i>'=>'https://twitter.com/infinitechan'));
|
||||
|
||||
$config['footer'][] = 'All posts on 8chan are the responsibility of the individual poster and not the administration of 8chan, pursuant to 47 U.S.C. § 230.';
|
||||
|
@ -50,7 +50,7 @@ function is_valid_webm($ffprobe_out) {
|
||||
return array('code' => 2, 'msg' => $config['error']['invalidwebm']);
|
||||
|
||||
if ($ffprobe_out['format']['duration'] > $config['webm']['max_length'])
|
||||
return array('code' => 4, 'msg' => $config['error']['webmtoolong']);
|
||||
return array('code' => 4, 'msg' => sprintf($config['error']['webmtoolong'], $config['webm']['max_length']));
|
||||
}
|
||||
|
||||
function make_webm_thumbnail($filename, $thumbnail, $width, $height, $duration) {
|
||||
|
@ -639,7 +639,7 @@ function mod_log($page_no = 1) {
|
||||
$query->execute() or error(db_error($query));
|
||||
$count = $query->fetchColumn();
|
||||
|
||||
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count));
|
||||
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count));
|
||||
}
|
||||
|
||||
function mod_user_log($username, $page_no = 1) {
|
||||
@ -666,7 +666,43 @@ function mod_user_log($username, $page_no = 1) {
|
||||
$query->execute() or error(db_error($query));
|
||||
$count = $query->fetchColumn();
|
||||
|
||||
mod_page(_('Moderation log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'username' => $username));
|
||||
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'username' => $username));
|
||||
}
|
||||
|
||||
function mod_board_log($board, $page_no = 1) {
|
||||
global $config;
|
||||
|
||||
if ($page_no < 1)
|
||||
error($config['error']['404']);
|
||||
|
||||
if (!hasPermission($config['mod']['mod_board_log'], $board))
|
||||
error($config['error']['noaccess']);
|
||||
|
||||
$query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `board` = :board ORDER BY `time` DESC LIMIT :offset, :limit");
|
||||
$query->bindValue(':board', $board);
|
||||
$query->bindValue(':limit', $config['mod']['modlog_page'], PDO::PARAM_INT);
|
||||
$query->bindValue(':offset', ($page_no - 1) * $config['mod']['modlog_page'], PDO::PARAM_INT);
|
||||
$query->execute() or error(db_error($query));
|
||||
$logs = $query->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($logs) && $page_no > 1)
|
||||
error($config['error']['404']);
|
||||
|
||||
if (!hasPermission($config['mod']['show_ip'])) {
|
||||
// Supports ipv4 only!
|
||||
foreach ($logs as $i => &$log) {
|
||||
$log['text'] = preg_replace_callback('/(?:<a href="\?\/IP\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}">)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:<\/a>)?/', function($matches) {
|
||||
return less_ip($matches[1]);
|
||||
}, $log['text']);
|
||||
}
|
||||
}
|
||||
|
||||
$query = prepare("SELECT COUNT(*) FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `board` = :board");
|
||||
$query->bindValue(':board', $board);
|
||||
$query->execute() or error(db_error($query));
|
||||
$count = $query->fetchColumn();
|
||||
|
||||
mod_page(_('Board log'), 'mod/log.html', array('logs' => $logs, 'count' => $count, 'board' => $board));
|
||||
}
|
||||
|
||||
function mod_view_board($boardName, $page_no = 1) {
|
||||
@ -1361,8 +1397,10 @@ function mod_move($originBoard, $postID) {
|
||||
if ($post['has_file']) {
|
||||
// copy image
|
||||
foreach ($post['files'] as $i => &$file) {
|
||||
$clone($file['file_path'], sprintf($config['board_path'], $config['dir']['img_root'] . $board['uri']) . $config['dir']['img'] . $file['file']);
|
||||
$clone($file['thumb_path'], sprintf($config['board_path'], $config['dir']['img_root'] . $board['uri']) . $config['dir']['thumb'] . $file['thumb']);
|
||||
if ($file['file'] !== 'deleted')
|
||||
$clone($file['file_path'], sprintf($config['board_path'], $config['dir']['img_root'] . $board['uri']) . $config['dir']['img'] . $file['file']);
|
||||
if (isset($file['thumb']) && !in_array($file['thumb'], array('spoiler', 'deleted', 'file')))
|
||||
$clone($file['thumb_path'], sprintf($config['board_path'], $config['dir']['img_root'] . $board['uri']) . $config['dir']['thumb'] . $file['thumb']);
|
||||
}
|
||||
}
|
||||
// insert reply
|
||||
@ -1464,6 +1502,7 @@ function mod_ban_post($board, $delete, $post, $token = false) {
|
||||
|
||||
$thread = $_post['thread'];
|
||||
$ip = $_post['ip'];
|
||||
$tor = checkDNSBL($ip);
|
||||
|
||||
if (isset($_POST['new_ban'], $_POST['reason'], $_POST['length'], $_POST['board'])) {
|
||||
require_once 'inc/mod/ban.php';
|
||||
@ -1510,6 +1549,7 @@ function mod_ban_post($board, $delete, $post, $token = false) {
|
||||
'hide_ip' => !hasPermission($config['mod']['show_ip'], $board),
|
||||
'post' => $post,
|
||||
'board' => $board,
|
||||
'tor' => $tor,
|
||||
'delete' => (bool)$delete,
|
||||
'boards' => listBoards(),
|
||||
'token' => $security_token
|
||||
@ -1837,6 +1877,9 @@ function mod_user($uid) {
|
||||
|
||||
if (!hasPermission($config['mod']['editusers']) && !(hasPermission($config['mod']['change_password']) && $uid == $mod['id']))
|
||||
error($config['error']['noaccess']);
|
||||
|
||||
if (in_array($mod['boards'][0], array('infinity', 'z')))
|
||||
error('This board has password changing disabled.');
|
||||
|
||||
$query = prepare('SELECT * FROM ``mods`` WHERE `id` = :id');
|
||||
$query->bindValue(':id', $uid);
|
||||
|
25
install.sql
25
install.sql
@ -331,6 +331,31 @@ CREATE TABLE `board_tags` (
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `tor_cookies`
|
||||
--
|
||||
|
||||
CREATE TABLE `tor_cookies` (
|
||||
`cookie` varchar(255) NOT NULL,
|
||||
`created` datetime NOT NULL,
|
||||
`uses` tinyint(3) unsigned DEFAULT '0',
|
||||
PRIMARY KEY (`cookie`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
|
||||
--
|
||||
-- Table structure for table `dnsbl_bypass`
|
||||
--
|
||||
|
||||
CREATE TABLE `dnsbl_bypass` (
|
||||
`ip` varchar(255) NOT NULL,
|
||||
`created` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`ip`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
|
@ -34,16 +34,16 @@ if (active_page == 'catalog') {
|
||||
}
|
||||
|
||||
function searchToggle() {
|
||||
var button = $('#catalog_search_button')[0];
|
||||
var button = $('#catalog_search_button');
|
||||
|
||||
if (!button.dataset.expanded) {
|
||||
button.dataset.expanded = '1';
|
||||
button.innerText = 'Close';
|
||||
if (!button.data('expanded')) {
|
||||
button.data('expanded', '1');
|
||||
button.text('Close');
|
||||
$('.catalog_search').append(' <input id="search_field" style="border: inset 1px;">');
|
||||
$('#search_field').focus();
|
||||
} else {
|
||||
delete button.dataset.expanded;
|
||||
button.innerText = 'Search';
|
||||
button.removeData('expanded');
|
||||
button.text('Search');
|
||||
$('.catalog_search').children().last().remove();
|
||||
$('div[id="Grid"]>.mix').each(function () { $(this).css('display', 'inline-block'); });
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
if (active_page == 'catalog') $(function(){
|
||||
|
||||
if (localStorage.catalog !== undefined) {
|
||||
var catalog = JSON.parse(localStorage.catalog);
|
||||
} else {
|
||||
@ -15,8 +14,18 @@ if (active_page == 'catalog') $(function(){
|
||||
$('a[href$="/'+k+'.html"]').parents('.mix').remove();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
hidden_data = {};
|
||||
}
|
||||
|
||||
$(document).on('click', '.mix', function(e) {
|
||||
if (e.shiftKey) {
|
||||
hidden_data[board_name][$(this).data('id')] = Math.round(Date.now() / 1000);
|
||||
$(this).remove();
|
||||
localStorage.hiddenthreads = JSON.stringify(hidden_data);
|
||||
}
|
||||
});
|
||||
|
||||
$("#sort_by").change(function(){
|
||||
var value = this.value;
|
||||
$('#Grid').mixItUp('sort', value);
|
||||
@ -46,5 +55,4 @@ if (active_page == 'catalog') $(function(){
|
||||
if (catalog.image_size !== undefined) {
|
||||
$('#image_size').val(catalog.image_size).trigger('change');
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ onready(function(){
|
||||
if (/^\/player\.php\?/.test($(this).parent().attr('href')))
|
||||
return;
|
||||
|
||||
if (!$(this).parent()[0].dataset.expanded)
|
||||
if (!$(this).parent().data('expanded'))
|
||||
$(this).parent().click();
|
||||
});
|
||||
|
||||
@ -43,7 +43,7 @@ onready(function(){
|
||||
.text(_('Shrink all images'))
|
||||
.click(function(){
|
||||
$('a img.full-image').each(function() {
|
||||
if ($(this).parent()[0].dataset.expanded)
|
||||
if ($(this).parent().data('expanded'))
|
||||
$(this).parent().click();
|
||||
});
|
||||
$(this).parent().remove();
|
||||
|
@ -41,15 +41,15 @@ function handle_boards(data) {
|
||||
return $('<span class="favorite-boards"></span>').append(' [ '+boards.join(" / ")+' ] ');
|
||||
} else {
|
||||
return $('<span class="favorite-boards"></span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function add_favorites() {
|
||||
$('.favorite-boards').empty();
|
||||
|
||||
$('.favorite-boards').remove();
|
||||
|
||||
var boards = handle_boards(localStorage.favorites);
|
||||
|
||||
$('.favorite-boards').append(boards);
|
||||
$('.boardlist').append(boards);
|
||||
};
|
||||
|
||||
if (active_page == 'thread' || active_page == 'index' || active_page == 'catalog') {
|
||||
|
@ -77,7 +77,7 @@ $(document).ready(function(){
|
||||
|
||||
$(this).hide().after(show_link);
|
||||
|
||||
if ($(img).parent()[0].dataset.expanded == 'true') {
|
||||
if ($(img).parent().data('expanded') == 'true') {
|
||||
$(img).parent().click();
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,18 @@
|
||||
if (active_page == 'thread' || active_page == 'index') {
|
||||
$(document).ready(function(){
|
||||
if (window.Options && Options.get_tab('general')) {
|
||||
selector = '#color-ids>input';
|
||||
event = 'change';
|
||||
var selector = '#color-ids>input';
|
||||
var e = 'change';
|
||||
Options.extend_tab("general", "<label id='color-ids'><input type='checkbox' /> "+_('Color IDs')+"</label>");
|
||||
}
|
||||
|
||||
else {
|
||||
selector = '#color-ids';
|
||||
event = 'click';
|
||||
var selector = '#color-ids';
|
||||
var e = 'click';
|
||||
$('hr:first').before('<div id="color-ids" style="text-align:right"><a class="unimportant" href="javascript:void(0)">'+_('Color IDs')+'</a></div>')
|
||||
}
|
||||
|
||||
$(selector).on(event, function() {
|
||||
$(selector).on(e, function() {
|
||||
if (localStorage.color_ids === 'true') {
|
||||
localStorage.color_ids = 'false';
|
||||
} else {
|
||||
|
186
js/image-hover.js
Normal file
186
js/image-hover.js
Normal file
@ -0,0 +1,186 @@
|
||||
/* image-hover.js
|
||||
* This script is copied almost verbatim from https://github.com/Pashe/8chanX/blob/2-0/8chan-x.user.js
|
||||
* All I did was remove the sprintf dependency and integrate it into 8chan's Options as opposed to Pashe's.
|
||||
* I also changed initHover() to also bind on new_post.
|
||||
* Thanks Pashe for using WTFPL.
|
||||
*/
|
||||
|
||||
if (active_page === "catalog" || active_page === "thread" || active_page === "index") {
|
||||
$(document).on('ready', function(){
|
||||
|
||||
if (window.Options && Options.get_tab('general')) {
|
||||
Options.extend_tab("general",
|
||||
"<fieldset><legend>Image hover</legend>"
|
||||
+ ("<label class='image-hover' id='imageHover'><input type='checkbox' /> "+_('Image hover')+"</label>")
|
||||
+ ("<label class='image-hover' id='catalogImageHover'><input type='checkbox' /> "+_('Image hover on catalog')+"</label>")
|
||||
+ ("<label class='image-hover' id='imageHoverFollowCursor'><input type='checkbox' /> "+_('Image hover should follow cursor')+"</label>")
|
||||
+ "</fieldset>");
|
||||
}
|
||||
|
||||
$('.image-hover').on('change', function(){
|
||||
var setting = $(this).attr('id');
|
||||
|
||||
localStorage[setting] = $(this).children('input').is(':checked');
|
||||
});
|
||||
|
||||
if (!localStorage.imageHover || !localStorage.catalogImageHover || !localStorage.imageHoverFollowCursor) {
|
||||
localStorage.imageHover = 'false';
|
||||
localStorage.catalogImageHover = 'false';
|
||||
localStorage.imageHoverFollowCursor = 'false';
|
||||
}
|
||||
|
||||
if (getSetting('imageHover')) $('#imageHover>input').prop('checked', 'checked');
|
||||
if (getSetting('catalogImageHover')) $('#catalogImageHover>input').prop('checked', 'checked');
|
||||
if (getSetting('imageHoverFollowCursor')) $('#imageHoverFollowCursor>input').prop('checked', 'checked');
|
||||
|
||||
function getFileExtension(filename) { //Pashe, WTFPL
|
||||
if (filename.match(/\.([a-z0-9]+)(&loop.*)?$/i) !== null) {
|
||||
return filename.match(/\.([a-z0-9]+)(&loop.*)?$/i)[1];
|
||||
} else if (filename.match(/https?:\/\/(www\.)?youtube.com/)) {
|
||||
return 'Youtube';
|
||||
} else {
|
||||
return "unknown: " + filename;
|
||||
}
|
||||
}
|
||||
|
||||
function isImage(fileExtension) { //Pashe, WTFPL
|
||||
return ($.inArray(fileExtension, ["jpg", "jpeg", "gif", "png"]) !== -1);
|
||||
}
|
||||
|
||||
function isVideo(fileExtension) { //Pashe, WTFPL
|
||||
return ($.inArray(fileExtension, ["webm", "mp4"]) !== -1);
|
||||
}
|
||||
|
||||
function isOnCatalog() {
|
||||
return window.active_page === "catalog";
|
||||
}
|
||||
|
||||
function isOnThread() {
|
||||
return window.active_page === "thread";
|
||||
}
|
||||
|
||||
function getSetting(key) {
|
||||
return (localStorage[key] == 'true');
|
||||
}
|
||||
|
||||
function initImageHover() { //Pashe, influenced by tux, et al, WTFPL
|
||||
if (!getSetting("imageHover") && !getSetting("catalogImageHover")) {return;}
|
||||
|
||||
var selectors = [];
|
||||
|
||||
if (getSetting("imageHover")) {selectors.push("img.post-image", "canvas.post-image");}
|
||||
if (getSetting("catalogImageHover") && isOnCatalog()) {
|
||||
selectors.push(".thread-image");
|
||||
$(".theme-catalog div.thread").css("position", "inherit");
|
||||
}
|
||||
|
||||
function bindEvents(el) {
|
||||
$(el).find(selectors.join(", ")).each(function () {
|
||||
if ($(this).parent().data("expanded")) {return;}
|
||||
|
||||
var $this = $(this);
|
||||
|
||||
$this.on("mousemove", imageHoverStart);
|
||||
$this.on("mouseout", imageHoverEnd);
|
||||
$this.on("click", imageHoverEnd);
|
||||
});
|
||||
}
|
||||
|
||||
bindEvents(document.body);
|
||||
$(document).on('new_post', function(e, post) {
|
||||
bindEvents(post);
|
||||
});
|
||||
}
|
||||
|
||||
function imageHoverStart(e) { //Pashe, anonish, WTFPL
|
||||
var hoverImage = $("#chx_hoverImage");
|
||||
|
||||
if (hoverImage.length) {
|
||||
if (getSetting("imageHoverFollowCursor")) {
|
||||
var scrollTop = $(window).scrollTop();
|
||||
var imgY = e.pageY;
|
||||
var imgTop = imgY;
|
||||
var windowWidth = $(window).width();
|
||||
var imgWidth = hoverImage.width() + e.pageX;
|
||||
|
||||
if (imgY < scrollTop + 15) {
|
||||
imgTop = scrollTop;
|
||||
} else if (imgY > scrollTop + $(window).height() - hoverImage.height() - 15) {
|
||||
imgTop = scrollTop + $(window).height() - hoverImage.height() - 15;
|
||||
}
|
||||
|
||||
if (imgWidth > windowWidth) {
|
||||
hoverImage.css({
|
||||
'left': (e.pageX + (windowWidth - imgWidth)),
|
||||
'top' : imgTop,
|
||||
});
|
||||
} else {
|
||||
hoverImage.css({
|
||||
'left': e.pageX,
|
||||
'top' : imgTop,
|
||||
});
|
||||
}
|
||||
|
||||
hoverImage.appendTo($("body"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var $this = $(this);
|
||||
|
||||
var fullUrl;
|
||||
if ($this.parent().attr("href").match("src")) {
|
||||
fullUrl = $this.parent().attr("href");
|
||||
} else if (isOnCatalog()) {
|
||||
$this.css("cursor", "progress");
|
||||
fullUrl = $this.attr("src");
|
||||
$.ajax(($this.parent().attr("href").replace(/\.html$/, ".json")), {
|
||||
success: function (result) {
|
||||
$this.css("cursor", "unset");
|
||||
fullUrl = result.posts[0].tim + result.posts[0].ext;
|
||||
if (!isImage(getFileExtension(fullUrl))) {return;}
|
||||
$("#chx_hoverImage").attr("src", "/" + thisBoard + "/" + fullUrl);
|
||||
$("#chx_hoverImage").on("load", function() {$this.css("cursor", "none")});
|
||||
},
|
||||
async: true,
|
||||
cache: true
|
||||
});
|
||||
}
|
||||
|
||||
if (isVideo(getFileExtension(fullUrl))) {return;}
|
||||
|
||||
hoverImage = $('<img id="chx_hoverImage" src="'+fullUrl+'" />');
|
||||
if (getSetting("imageHoverFollowCursor")) {
|
||||
hoverImage.css({
|
||||
"position" : "absolute",
|
||||
"z-index" : 101,
|
||||
"pointer-events": "none",
|
||||
"max-width" : $(window).width(),
|
||||
"max-height" : $(window).height(),
|
||||
'left' : e.pageX,
|
||||
'top' : imgTop,
|
||||
});
|
||||
} else {
|
||||
hoverImage.css({
|
||||
"position" : "fixed",
|
||||
"top" : 0,
|
||||
"right" : 0,
|
||||
"z-index" : 101,
|
||||
"pointer-events": "none",
|
||||
"max-width" : "100%",
|
||||
"max-height" : "100%",
|
||||
});
|
||||
}
|
||||
hoverImage.appendTo($("body"));
|
||||
if (isOnThread()) {$this.css("cursor", "none");}
|
||||
}
|
||||
|
||||
function imageHoverEnd() { //Pashe, WTFPL
|
||||
$("#chx_hoverImage").remove();
|
||||
}
|
||||
|
||||
initImageHover();
|
||||
});
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ $(document).ready(function(){
|
||||
if (i > -1) {
|
||||
waiting.splice(i, 1);
|
||||
}
|
||||
if (ele.dataset.imageLoading === 'true') {
|
||||
ele.dataset.imageLoading = 'false';
|
||||
if ($(ele).data('imageLoading') === 'true') {
|
||||
$(ele).data('imageLoading', 'false');
|
||||
clearTimeout(ele.timeout);
|
||||
--loading;
|
||||
}
|
||||
@ -73,7 +73,7 @@ $(document).ready(function(){
|
||||
$.when($loadstart).done(function () {
|
||||
// once fully loaded, update the waiting queue
|
||||
--loading;
|
||||
ele.dataset.imageLoading = 'false';
|
||||
$(ele).data('imageLoading', 'false');
|
||||
update();
|
||||
});
|
||||
});
|
||||
@ -83,7 +83,7 @@ $(document).ready(function(){
|
||||
});
|
||||
|
||||
img.setAttribute('src', ele.href);
|
||||
ele.dataset.imageLoading = 'true';
|
||||
$(ele).data('imageLoading', 'true');
|
||||
ele.timeout = onLoadStart(img);
|
||||
});
|
||||
|
||||
@ -112,9 +112,9 @@ $(document).ready(function(){
|
||||
return false;
|
||||
if (e.which == 2 || e.ctrlKey) // open in new tab
|
||||
return true;
|
||||
if (!this.dataset.expanded) {
|
||||
if (!$(this).data('expanded')) {
|
||||
this.parentNode.removeAttribute('style');
|
||||
this.dataset.expanded = 'true';
|
||||
$(this).data('expanded', 'true');
|
||||
|
||||
if (thumb.tagName === 'CANVAS') {
|
||||
canvas = thumb;
|
||||
@ -144,12 +144,12 @@ $(document).ready(function(){
|
||||
}
|
||||
|
||||
if (~this.parentNode.className.indexOf('multifile'))
|
||||
this.parentNode.style.width = (parseInt(this.dataset.width)+40)+'px';
|
||||
this.parentNode.style.width = (parseInt($(this).data('width'))+40)+'px';
|
||||
|
||||
thumb.style.opacity = '';
|
||||
thumb.style.display = '';
|
||||
if (thumb.nextSibling) this.removeChild(thumb.nextSibling); //full image loaded or loading
|
||||
delete this.dataset.expanded;
|
||||
$(this).removeData('expanded');
|
||||
delete thumb.style.filter;
|
||||
|
||||
// do the scrolling after page reflow
|
||||
|
799
js/post-filter.js
Normal file
799
js/post-filter.js
Normal file
@ -0,0 +1,799 @@
|
||||
if (active_page === 'thread' || active_page === 'index') {
|
||||
$(document).ready(function () {
|
||||
'use strict';
|
||||
// returns blacklist object from storage
|
||||
function getList() {
|
||||
return JSON.parse(localStorage.postFilter);
|
||||
}
|
||||
|
||||
// stores blacklist into storage and reruns the filter
|
||||
function setList(blacklist) {
|
||||
localStorage.postFilter = JSON.stringify(blacklist);
|
||||
$(document).trigger('filter_page');
|
||||
}
|
||||
|
||||
// unit: seconds
|
||||
function timestamp() {
|
||||
return Math.floor((new Date()).getTime() / 1000);
|
||||
}
|
||||
|
||||
function initList(list, boardId, threadId) {
|
||||
if (typeof list.postFilter[boardId] == 'undefined')
|
||||
list.postFilter[boardId] = {};
|
||||
list.nextPurge[boardId] = {};
|
||||
if (typeof list.postFilter[boardId][threadId] == 'undefined') {
|
||||
list.postFilter[boardId][threadId] = [];
|
||||
}
|
||||
list.nextPurge[boardId][threadId] = {timestamp: timestamp(), interval: 86400}; // 86400 seconds == 1 day
|
||||
}
|
||||
|
||||
var blacklist = {
|
||||
add: {
|
||||
name: function (posterName) {
|
||||
var list = getList();
|
||||
var filter = list.nameFilter;
|
||||
|
||||
for (var i in filter) {
|
||||
if (filter[i].name == posterName) return;
|
||||
}
|
||||
filter.push({
|
||||
name: posterName
|
||||
});
|
||||
setList(list);
|
||||
drawFilterList();
|
||||
},
|
||||
trip: function (posterTrip) {
|
||||
var list = getList();
|
||||
var filter = list.nameFilter;
|
||||
|
||||
for (var i in filter) {
|
||||
if (filter[i].trip == posterTrip) return;
|
||||
}
|
||||
filter.push({
|
||||
trip: posterTrip
|
||||
});
|
||||
setList(list);
|
||||
drawFilterList();
|
||||
},
|
||||
post: function (boardId, threadId, postId, hideReplies) {
|
||||
var list = getList();
|
||||
var filter = list.postFilter;
|
||||
|
||||
initList(list, boardId, threadId);
|
||||
|
||||
for (var i in filter[boardId][threadId]) {
|
||||
if (filter[boardId][threadId][i].post == postId) return;
|
||||
}
|
||||
filter[boardId][threadId].push({
|
||||
post: postId,
|
||||
hideReplies: hideReplies
|
||||
});
|
||||
setList(list);
|
||||
},
|
||||
uid: function (boardId, threadId, uniqueId, hideReplies) {
|
||||
var list = getList();
|
||||
var filter = list.postFilter;
|
||||
|
||||
initList(list, boardId, threadId);
|
||||
|
||||
for (var i in filter[boardId][threadId]) {
|
||||
if (filter[boardId][threadId][i].uid == uniqueId) return;
|
||||
}
|
||||
filter[boardId][threadId].push({
|
||||
uid: uniqueId,
|
||||
hideReplies: hideReplies
|
||||
});
|
||||
setList(list);
|
||||
}
|
||||
},
|
||||
remove: {
|
||||
name: function (posterName) {
|
||||
var list = getList();
|
||||
var filter = list.nameFilter;
|
||||
|
||||
for (var i=0; i<filter.length; i++) {
|
||||
if (filter[i].name == posterName) {
|
||||
filter.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setList(list);
|
||||
drawFilterList();
|
||||
},
|
||||
trip: function (posterTrip) {
|
||||
var list = getList();
|
||||
var filter = list.nameFilter;
|
||||
|
||||
for (var i=0; i<filter.length; i++) {
|
||||
if (filter[i].trip == posterTrip) {
|
||||
filter.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
setList(list);
|
||||
drawFilterList();
|
||||
},
|
||||
post: function (boardId, threadId, postId) {
|
||||
var list = getList();
|
||||
var filter = list.postFilter;
|
||||
|
||||
// thread already pruned
|
||||
if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
|
||||
return;
|
||||
|
||||
for (var i=0; i<filter[boardId][threadId].length; i++) {
|
||||
if (filter[boardId][threadId][i].post == postId) {
|
||||
filter[boardId][threadId].splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($.isEmptyObject(filter[boardId][threadId])) {
|
||||
delete filter[boardId][threadId];
|
||||
delete list.nextPurge[boardId][threadId];
|
||||
|
||||
if ($.isEmptyObject(filter[boardId])) {
|
||||
delete filter[boardId];
|
||||
delete list.nextPurge[boardId];
|
||||
}
|
||||
}
|
||||
setList(list);
|
||||
},
|
||||
uid: function (boardId, threadId, uniqueId) {
|
||||
var list = getList();
|
||||
var filter = list.postFilter;
|
||||
|
||||
// thread already pruned
|
||||
if (typeof filter[boardId] == 'undefined' || typeof filter[boardId][threadId] == 'undefined')
|
||||
return;
|
||||
|
||||
for (var i=0; i<filter[boardId][threadId].length; i++) {
|
||||
if (filter[boardId][threadId][i].uid == uniqueId) {
|
||||
filter[boardId][threadId].splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($.isEmptyObject(filter[boardId][threadId])) {
|
||||
delete filter[boardId][threadId];
|
||||
delete list.nextPurge[boardId][threadId];
|
||||
|
||||
if ($.isEmptyObject(filter[boardId])) {
|
||||
delete filter[boardId];
|
||||
delete list.nextPurge[boardId];
|
||||
}
|
||||
}
|
||||
setList(list);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* hide/show the specified thread/post
|
||||
*/
|
||||
function hide(ele) {
|
||||
var $ele = $(ele);
|
||||
|
||||
if ($(ele).data('hidden') === '1')
|
||||
return;
|
||||
|
||||
$(ele).data('hidden', '1');
|
||||
if ($ele.hasClass('op')) {
|
||||
$ele.parent().find('.body, .files, .video-container').not($ele.children('.reply').children()).hide();
|
||||
|
||||
// hide thread replies on index view
|
||||
if (active_page == 'index') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').hide();
|
||||
} else {
|
||||
// normal posts
|
||||
$ele.children('.body, .files, .video-container').hide();
|
||||
}
|
||||
}
|
||||
function show(ele) {
|
||||
var $ele = $(ele);
|
||||
|
||||
$(ele).data('hidden', '0');
|
||||
if ($ele.hasClass('op')) {
|
||||
$ele.parent().find('.body, .files, .video-container').show();
|
||||
if (active_page == 'index') $ele.parent().find('.omitted, .reply:not(.hidden), post_no, .mentioned, br').show();
|
||||
} else {
|
||||
// normal posts
|
||||
$ele.children('.body, .files, .video-container').show();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* create filter menu when the button is clicked
|
||||
*/
|
||||
function addMenu(e, ele, threadId, pageData) {
|
||||
|
||||
var $ele = $(ele);
|
||||
var $buffer;
|
||||
|
||||
var postId = $ele.find('.post_no').not('[id]').text();
|
||||
if (pageData.hasUID) {
|
||||
var postUid = $ele.find('.poster_id').text();
|
||||
}
|
||||
var postName;
|
||||
var postTrip = '';
|
||||
if (!pageData.forcedAnon) {
|
||||
postName = (typeof $ele.find('.name').contents()[0] == 'undefined') ? '' : $ele.find('.name').contents()[0].nodeValue.trim();
|
||||
postTrip = $ele.find('.trip').text();
|
||||
}
|
||||
|
||||
// get the button's position
|
||||
var pos = $(e.target).offset();
|
||||
|
||||
$buffer = $('<div class="filter-menu"></div>').append(
|
||||
$('<ul>').append(
|
||||
$('<li>', {id: 'filter-menu-unhide'}).text('Unhide post'),
|
||||
$('<li>', {id: 'filter-menu-add'}).append(
|
||||
$('<ul>').append(
|
||||
$('<li>', {class: 'filter-post'}).text('Post'),
|
||||
$('<li>', {class: 'filter-post-plus', title: 'Hide post and all replies'}).text('Post +'),
|
||||
$('<li>', {class: 'filter-id'}).text('ID'),
|
||||
$('<li>', {class: 'filter-id-plus', title: 'Hide ID and all replies'}).text('ID +'),
|
||||
$('<li>', {class: 'filter-name'}).text('Name'),
|
||||
$('<li>', {class: 'filter-trip'}).text('Tripcode')
|
||||
),
|
||||
'Add filter',
|
||||
$('<span>', {class: 'filter-menu-arrow'}).append('»')
|
||||
),
|
||||
$('<li>', {id: 'filter-menu-remove'}).append(
|
||||
$('<ul>').append(
|
||||
$('<li>', {class: 'filter-id'}).text('ID'),
|
||||
$('<li>', {class: 'filter-name'}).text('Name'),
|
||||
$('<li>', {class: 'filter-trip'}).text('Tripcode')
|
||||
),
|
||||
'Remove filter',
|
||||
$('<span>', {class: 'filter-menu-arrow'}).append('»')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/* display logic and bind click handlers
|
||||
*/
|
||||
|
||||
// unhide button
|
||||
if ($(ele).data('hidden') == '1' && $(ele).data('hiddenByUid') == '0' &&
|
||||
$(ele).data('hiddenByName') == '0' && $(ele).data('hiddenByTrip') == '0') {
|
||||
$buffer.find('#filter-menu-unhide').click(function () {
|
||||
// if hidden due to post id, remove it from blacklist
|
||||
// otherwise just show this post
|
||||
blacklist.remove.post(pageData.boardId, threadId, postId);
|
||||
show(ele);
|
||||
});
|
||||
} else {
|
||||
$buffer.find('#filter-menu-unhide').addClass('hidden');
|
||||
}
|
||||
|
||||
// post id
|
||||
if ($(ele).data('hiddenByPost') == '0') {
|
||||
$buffer.find('#filter-menu-add .filter-post').click(function () {
|
||||
blacklist.add.post(pageData.boardId, threadId, postId, false);
|
||||
});
|
||||
$buffer.find('#filter-menu-add .filter-post-plus').click(function () {
|
||||
blacklist.add.post(pageData.boardId, threadId, postId, true);
|
||||
});
|
||||
} else {
|
||||
$buffer.find('#filter-menu-add .filter-post').addClass('hidden');
|
||||
$buffer.find('#filter-menu-add .filter-post-plus').addClass('hidden');
|
||||
}
|
||||
|
||||
// UID
|
||||
if (pageData.hasUID && $(ele).data('hiddenByUid') == '0') {
|
||||
$buffer.find('#filter-menu-add .filter-id').click(function () {
|
||||
blacklist.add.uid(pageData.boardId, threadId, postUid, false);
|
||||
});
|
||||
$buffer.find('#filter-menu-add .filter-id-plus').click(function () {
|
||||
blacklist.add.uid(pageData.boardId, threadId, postUid, true);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-remove .filter-id').addClass('hidden');
|
||||
} else if (pageData.hasUID) {
|
||||
$buffer.find('#filter-menu-remove .filter-id').click(function () {
|
||||
blacklist.remove.uid(pageData.boardId, threadId, postUid);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-add .filter-id').addClass('hidden');
|
||||
$buffer.find('#filter-menu-add .filter-id-plus').addClass('hidden');
|
||||
} else {
|
||||
// board doesn't use UID
|
||||
$buffer.find('#filter-menu-add .filter-id').addClass('hidden');
|
||||
$buffer.find('#filter-menu-add .filter-id-plus').addClass('hidden');
|
||||
$buffer.find('#filter-menu-remove .filter-id').addClass('hidden');
|
||||
}
|
||||
|
||||
// name
|
||||
if (!pageData.forcedAnon && $(ele).data('hiddenByName') == '0') {
|
||||
$buffer.find('#filter-menu-add .filter-name').click(function () {
|
||||
blacklist.add.name(postName);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-remove .filter-name').addClass('hidden');
|
||||
} else if (!pageData.forcedAnon) {
|
||||
$buffer.find('#filter-menu-remove .filter-name').click(function () {
|
||||
blacklist.remove.name(postName);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-add .filter-name').addClass('hidden');
|
||||
} else {
|
||||
// board has forced anon
|
||||
$buffer.find('#filter-menu-remove .filter-name').addClass('hidden');
|
||||
$buffer.find('#filter-menu-add .filter-name').addClass('hidden');
|
||||
}
|
||||
|
||||
// tripcode
|
||||
if (!pageData.forcedAnon && $(ele).data('hiddenByTrip') == '0' && postTrip !== '') {
|
||||
$buffer.find('#filter-menu-add .filter-trip').click(function () {
|
||||
blacklist.add.trip(postTrip);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-remove .filter-trip').addClass('hidden');
|
||||
} else if (!pageData.forcedAnon && postTrip !== '') {
|
||||
$buffer.find('#filter-menu-remove .filter-trip').click(function () {
|
||||
blacklist.remove.trip(postTrip);
|
||||
});
|
||||
|
||||
$buffer.find('#filter-menu-add .filter-trip').addClass('hidden');
|
||||
} else {
|
||||
// board has forced anon
|
||||
$buffer.find('#filter-menu-remove .filter-trip').addClass('hidden');
|
||||
$buffer.find('#filter-menu-add .filter-trip').addClass('hidden');
|
||||
}
|
||||
|
||||
/* hide sub menus if all items are hidden
|
||||
*/
|
||||
if (!$buffer.find('#filter-menu-remove > ul').children().not('.hidden').length) {
|
||||
$buffer.find('#filter-menu-remove').addClass('hidden');
|
||||
}
|
||||
if (!$buffer.find('#filter-menu-add > ul').children().not('.hidden').length) {
|
||||
$buffer.find('#filter-menu-add').addClass('hidden');
|
||||
}
|
||||
|
||||
/* set menu position
|
||||
*/
|
||||
$buffer.css({top: pos.top + 20, left: pos.left});
|
||||
|
||||
/* finally append to page
|
||||
*/
|
||||
$('body').append($buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* add menu button to the thread/post
|
||||
*/
|
||||
function addMenuButton(ele, threadId, pageData) {
|
||||
if ($(ele).find('.filter-btn').length)
|
||||
$('.filter-btn').remove();
|
||||
/*if ($(ele).find('.hide-thread-link').length)
|
||||
$('.hide-thread-link').remove();*/
|
||||
|
||||
$(ele).find('.intro')
|
||||
.append(
|
||||
$('<a>', {href: '#', class: 'filter-btn', title: 'Filter menu'})
|
||||
.text('▶')
|
||||
.click(function (e) {
|
||||
// button toggle
|
||||
e.preventDefault();
|
||||
// remove existing menu
|
||||
$('.filter-menu').remove();
|
||||
|
||||
if ($(e.target).hasClass('filter-btn-open')) {
|
||||
$('.filter-btn-open').removeClass('filter-btn-open');
|
||||
} else {
|
||||
// close previous button
|
||||
$('.filter-btn-open').removeClass('filter-btn-open');
|
||||
// mark the menu button as open
|
||||
$(ele).find('.filter-btn').addClass('filter-btn-open');
|
||||
addMenu(e, ele, threadId, pageData);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if ($(ele).hasClass('op') && !$(ele).find('.hide-thread-link').length) {
|
||||
$('<a class="hide-thread-link" style="float:left;margin-right:5px" href="javascript:void(0)">[' + ($(ele).data('hidden') == '1' ? '+' : '–') + ']</a>')
|
||||
.insertBefore($(ele).find(':not(h2,h2 *):first'))
|
||||
.click(function() {
|
||||
var postId = $(ele).find('.post_no').not('[id]').text();
|
||||
var hidden = ($(ele).data('hidden') == '1');
|
||||
|
||||
if (hidden) {
|
||||
blacklist.remove.post(pageData.boardId, threadId, postId, false);
|
||||
$(this).html('[–]');
|
||||
} else {
|
||||
blacklist.add.post(pageData.boardId, threadId, postId, false);
|
||||
$(this).text('[+]');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* determine whether the reply post should be hidden
|
||||
* - applies to all posts on page load or filtering rule change
|
||||
* - apply to new posts on thread updates
|
||||
* - must explicitly set the state of each attributes because filter will reapply to all posts after filtering rule change
|
||||
*/
|
||||
function filter(post, threadId, pageData) {
|
||||
var $post = $(post);
|
||||
var list = getList();
|
||||
var postId = $post.find('.post_no').not('[id]').text();
|
||||
var name, trip, uid;
|
||||
var i, array; // temp variables
|
||||
|
||||
var boardId = pageData.boardId;
|
||||
var localList = pageData.localList;
|
||||
var noReplyList = pageData.noReplyList;
|
||||
var hasUID = pageData.hasUID;
|
||||
var forcedAnon = pageData.forcedAnon;
|
||||
|
||||
$post.data('hidden', '0');
|
||||
$post.data('hiddenByUid', '0');
|
||||
$post.data('hiddenByPost', '0');
|
||||
$post.data('hiddenByName', '0');
|
||||
$post.data('hiddenByTrip', '0');
|
||||
|
||||
// add post with matched UID to localList
|
||||
if (hasUID &&
|
||||
typeof list.postFilter[boardId] != 'undefined' &&
|
||||
typeof list.postFilter[boardId][threadId] != 'undefined') {
|
||||
uid = $post.find('.poster_id').text();
|
||||
array = list.postFilter[boardId][threadId];
|
||||
|
||||
for (i=0; i<array.length; i++) {
|
||||
if (array[i].uid == uid) {
|
||||
$post.data('hiddenByUid', '1');
|
||||
localList.push(postId);
|
||||
if (array[i].hideReplies) noReplyList.push(postId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// match localList
|
||||
if (localList.length) {
|
||||
if ($.inArray(postId, localList) != -1) {
|
||||
if ($post.data('hiddenByUid') != '1') $post.data('hiddenByPost', '1');
|
||||
hide(post);
|
||||
}
|
||||
}
|
||||
|
||||
// match poster name and tripcode
|
||||
if (!forcedAnon) {
|
||||
name = (typeof $post.find('.name').contents()[0] == 'undefined') ? '' : $post.find('.name').contents()[0].nodeValue.trim();
|
||||
if ($(list.nameFilter).filter(function(){if (this.name == name) return true;}).length) {
|
||||
$post.data('hiddenByName', '1');
|
||||
hide(post);
|
||||
}
|
||||
if ($post.find('.trip').length) {
|
||||
trip = $post.find('.trip').text();
|
||||
if ($(list.nameFilter).filter(function(){if (this.trip == trip) return true;}).length) {
|
||||
$post.data('hiddenByTrip', '1');
|
||||
hide(post);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for link to filtered posts
|
||||
$post.find('.body a').not('[rel="nofollow"]').each(function () {
|
||||
var replyId = $(this).text().match(/^>>(\d+)$/);
|
||||
|
||||
if (!replyId)
|
||||
return;
|
||||
|
||||
replyId = replyId[1];
|
||||
if ($.inArray(replyId, noReplyList) != -1) {
|
||||
hide(post);
|
||||
}
|
||||
});
|
||||
|
||||
// post didn't match any filters
|
||||
if ((typeof $post.data('hidden') == 'undefined' || $post.data('hidden') == '0') &&
|
||||
$post.data('hiddenByUid') === '0' &&
|
||||
$post.data('hiddenByUid') == $post.data('hiddenByPost') == $post.data('hiddenByName') == $post.data('hiddenByTrip')) {
|
||||
show(post);
|
||||
}
|
||||
}
|
||||
/* (re)runs the filter on the entire page
|
||||
*/
|
||||
function filterPage(pageData) {
|
||||
var list = getList();
|
||||
|
||||
// empty the local and no-reply list
|
||||
pageData.localList = [];
|
||||
pageData.noReplyList = [];
|
||||
|
||||
$('.thread').each(function () {
|
||||
var $thread = $(this);
|
||||
// disregard the hidden threads constructed by post-hover.js
|
||||
if ($thread.css('display') == 'none')
|
||||
return;
|
||||
|
||||
var threadId = $thread.attr('id').replace('thread_', '');
|
||||
var op = $thread.children('.op')[0];
|
||||
var i, array; // temp variables
|
||||
|
||||
// add posts to localList and noReplyList
|
||||
if (typeof list.postFilter[pageData.boardId] != 'undefined') {
|
||||
array = list.postFilter[pageData.boardId][threadId];
|
||||
if (typeof array != 'undefined') {
|
||||
for (i=0; i<array.length; i++) {
|
||||
if ( typeof array[i].post == 'undefined')
|
||||
continue;
|
||||
|
||||
pageData.localList.push(array[i].post);
|
||||
if (array[i].hideReplies) pageData.noReplyList.push(array[i].post);
|
||||
}
|
||||
}
|
||||
}
|
||||
// run filter on OP
|
||||
filter(op, threadId, pageData);
|
||||
addMenuButton(op, threadId, pageData);
|
||||
|
||||
// iterate filter over each post
|
||||
if ($(op).data('hidden') != '1' || active_page == 'thread') {
|
||||
$thread.find('.reply').not('.hidden').each(function () {
|
||||
filter(this, threadId, pageData);
|
||||
addMenuButton(this, threadId, pageData);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
function initStyle() {
|
||||
var $ele, cssStyle, cssString;
|
||||
|
||||
$ele = $('<div>').addClass('post reply').hide().appendTo('body');
|
||||
cssStyle = $ele.css(['background-color', 'border-color']);
|
||||
cssStyle.hoverBg = $('body').css('background-color');
|
||||
$ele.remove();
|
||||
|
||||
cssString =
|
||||
'\n/*** Generated by post-filter ***/\n' +
|
||||
'.filter-menu {position: absolute; font-size: 12px; line-height: 1.3em;}\n' +
|
||||
'.filter-menu ul {\n' +
|
||||
' background-color: '+ cssStyle['background-color'] +'; border: 1px solid '+ cssStyle['border-color'] +'; border-right-width: 2px;\n' +
|
||||
' list-style: none; padding: 0; margin: 0; white-space: nowrap;\n}\n' +
|
||||
'.filter-menu li {cursor: pointer; position: relative; padding: 4px 4px; vertical-align: middle; border-bottom: 1px solid '+ cssStyle['border-color'] +'; white-space: normal; width: 90px;}\n' +
|
||||
'.filter-menu li:hover {background-color: '+ cssStyle.hoverBg +';}\n' +
|
||||
'.filter-menu ul ul {display: none; position: absolute;}\n' +
|
||||
'.filter-menu li:hover ul {display: block; left: 100%; margin-top: -3px;}\n' +
|
||||
'.filter-menu li ul li {white-space: nowrap; width: auto;}\n' +
|
||||
'.filter-menu-arrow {float: right; margin-left: 10px;}\n' +
|
||||
'.filter-menu.hidden, .filter-menu .hidden {display: none;}\n' +
|
||||
'.filter-btn {transition: transform 0.1s; width: 15px; text-align: center; font-size: 12pt; opacity: 0.8; text-decoration: none; margin: -6px 0px; display: inline-block;}\n' +
|
||||
'.filter-btn:hover {opacity: 1;}\n' +
|
||||
'.filter-btn-open {transform: rotate(90deg);}\n';
|
||||
cssString +=
|
||||
'#filter-control #clear {float: right;}\n' +
|
||||
'#filter-container {margin-top: 20px; border: 1px solid; height: 270px; overflow: auto;}\n' +
|
||||
'#filter-list {width: 100%; border-collapse: collapse;}\n' +
|
||||
'#filter-list th {text-align: center; height: 20px; font-size: 14px; border-bottom: 1px solid;}\n' +
|
||||
'#filter-list th:nth-child(1) {text-align: center; width: 70px;}\n' +
|
||||
'#filter-list th:nth-child(2) {text-align: left;}\n' +
|
||||
'#filter-list th:nth-child(3) {text-align: center; width: 58px;}\n' +
|
||||
'#filter-list tr:not(#header) {height: 22px;}\n' +
|
||||
'#filter-list tr:nth-child(even) {background-color:rgba(255, 255, 255, 0.5);}\n' +
|
||||
'#filter-list td:nth-child(1) {text-align: center; width: 70px;}\n' +
|
||||
'#filter-list td:nth-child(3) {text-align: center; width: 58px;}\n' +
|
||||
'#confirm {text-align: right; margin-bottom: -18px; padding-top: 2px; font-size: 14px; color: #FF0000;}';
|
||||
|
||||
if (!$('style.generated-css').length) $('<style class="generated-css">').appendTo('head');
|
||||
$('style.generated-css').html($('style.generated-css').html() + cssString);
|
||||
}
|
||||
|
||||
function drawFilterList() {
|
||||
var list = getList().nameFilter;
|
||||
var $ele = $('#filter-list');
|
||||
var $row;
|
||||
var type, val;
|
||||
var i, length, obj;
|
||||
|
||||
$ele.empty();
|
||||
|
||||
$ele.append('<tr id="header"><th>Type</th><th>Content</th><th>Remove</th></tr>');
|
||||
for (i = 0, length = list.length; i < length; i++) {
|
||||
obj = list[i];
|
||||
for (type in obj) {
|
||||
val = obj[type];
|
||||
$row = $('<tr>');
|
||||
$row.append(
|
||||
'<td>'+ type +'</td>',
|
||||
'<td>'+ val +'</td>',
|
||||
$('<td>').append(
|
||||
$('<a>').html('X')
|
||||
.addClass('del-btn')
|
||||
.attr('href', '#')
|
||||
.attr('data-type', type)
|
||||
.attr('data-val', val)
|
||||
)
|
||||
);
|
||||
$ele.append($row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initOptionsPanel() {
|
||||
if (window.Options && !Options.get_tab('filter')) {
|
||||
Options.add_tab('filter', 'list', 'Filters');
|
||||
Options.extend_tab('filter',
|
||||
'<div id="filter-control">' +
|
||||
'<input id="input" type="text"></input>' +
|
||||
'<button id="name">Add Name</button>' +
|
||||
'<button id="trip">Add Tripcode</button>' +
|
||||
'<button id="clear">Clear all filters</button>' +
|
||||
'<div id="confirm" class="hidden">' +
|
||||
'This will clear all filtering rules including hidden posts. <a id="confirm-y" href="#">yes</a> | <a id="confirm-n" href="#">no</a>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div id="filter-container"><table id="filter-list"></table></div>'
|
||||
);
|
||||
drawFilterList();
|
||||
|
||||
// control buttons
|
||||
$('#filter-control').on('click', '#name', function () {
|
||||
var str = $('#filter-control #input').val().trim();
|
||||
$('#filter-control #input').val('');
|
||||
blacklist.add.name(str);
|
||||
});
|
||||
$('#filter-control').on('click', '#trip', function () {
|
||||
var str = $('#filter-control #input').val().trim();
|
||||
$('#filter-control #input').val('');
|
||||
blacklist.add.trip(str);
|
||||
});
|
||||
$('#filter-control').on('click', '#clear', function () {
|
||||
$('#filter-control #clear').addClass('hidden');
|
||||
$('#filter-control #confirm').removeClass('hidden');
|
||||
});
|
||||
$('#filter-control').on('click', '#confirm-y', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('#filter-control #clear').removeClass('hidden');
|
||||
$('#filter-control #confirm').addClass('hidden');
|
||||
setList({
|
||||
nameFilter: [],
|
||||
postFilter: {},
|
||||
nextPurge: {},
|
||||
lastPurge: timestamp()
|
||||
});
|
||||
drawFilterList();
|
||||
});
|
||||
$('#filter-control').on('click', '#confirm-n', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('#filter-control #clear').removeClass('hidden');
|
||||
$('#filter-control #confirm').addClass('hidden');
|
||||
});
|
||||
|
||||
|
||||
// remove button
|
||||
$('#filter-list').on('click', '.del-btn', function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var $ele = $(e.target);
|
||||
var type = $ele.attr('data-type');
|
||||
var val = $ele.attr('data-val');
|
||||
blacklist.remove[type](val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* clear out pruned threads
|
||||
*/
|
||||
function purge() {
|
||||
var list = getList();
|
||||
var board, thread, boardId, threadId;
|
||||
var deferred;
|
||||
var requestArray = [];
|
||||
|
||||
var successHandler = function (boardId, threadId) {
|
||||
return function () {
|
||||
// thread still alive, keep it in the list and increase the time between checks.
|
||||
var list = getList();
|
||||
var thread = list.nextPurge[boardId][threadId];
|
||||
|
||||
thread.timestamp = timestamp();
|
||||
thread.interval = Math.floor(thread.interval * 1.5);
|
||||
setList(list);
|
||||
};
|
||||
};
|
||||
var errorHandler = function (boardId, threadId) {
|
||||
return function (xhr) {
|
||||
if (xhr.status == 404) {
|
||||
var list = getList();
|
||||
|
||||
delete list.nextPurge[boardId][threadId];
|
||||
delete list.postFilter[boardId][threadId];
|
||||
if ($.isEmptyObject(list.nextPurge[boardId])) delete list.nextPurge[boardId];
|
||||
if ($.isEmptyObject(list.postFilter[boardId])) delete list.postFilter[boardId];
|
||||
setList(list);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if ((timestamp() - list.lastPurge) < 86400) // less than 1 day
|
||||
return;
|
||||
|
||||
for (boardId in list.nextPurge) {
|
||||
board = list.nextPurge[boardId];
|
||||
for (threadId in board) {
|
||||
thread = board[threadId];
|
||||
if (timestamp() > (thread.timestamp + thread.interval)) {
|
||||
// check if thread is pruned
|
||||
deferred = $.ajax({
|
||||
cache: false,
|
||||
url: '/'+ boardId +'/res/'+ threadId +'.json',
|
||||
success: successHandler(boardId, threadId),
|
||||
error: errorHandler(boardId, threadId)
|
||||
});
|
||||
requestArray.push(deferred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// when all requests complete
|
||||
$.when.apply($, requestArray).always(function () {
|
||||
var list = getList();
|
||||
list.lastPurge = timestamp();
|
||||
setList(list);
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (typeof localStorage.postFilter === 'undefined') {
|
||||
localStorage.postFilter = JSON.stringify({
|
||||
nameFilter: [],
|
||||
postFilter: {},
|
||||
nextPurge: {},
|
||||
lastPurge: timestamp()
|
||||
});
|
||||
}
|
||||
|
||||
var pageData = {
|
||||
boardId: board_name, // get the id from the global variable
|
||||
localList: [], // all the blacklisted post IDs or UIDs that apply to the current page
|
||||
noReplyList: [], // any posts that replies to the contents of this list shall be hidden
|
||||
hasUID: (document.getElementsByClassName('poster_id').length > 0),
|
||||
forcedAnon: ($('th:contains(Name)').length === 0) // tests by looking for the Name label on the reply form
|
||||
};
|
||||
|
||||
initStyle();
|
||||
initOptionsPanel();
|
||||
filterPage(pageData);
|
||||
|
||||
// menu close click handler
|
||||
$(document).on('click', function (e){
|
||||
if ($(e.target).hasClass('filter-btn'))
|
||||
return;
|
||||
|
||||
$('.filter-menu').remove();
|
||||
$('.filter-btn-open').removeClass('filter-btn-open');
|
||||
});
|
||||
|
||||
// on new posts
|
||||
$(document).on('new_post', function (e, post) {
|
||||
if ($(post).hasClass('reply')) {
|
||||
var threadId = $(post).parent().attr('id').replace('thread_', '');
|
||||
} else {
|
||||
var threadId = $(post).attr('id').replace('thread_', '');
|
||||
}
|
||||
|
||||
filter(post, threadId, pageData);
|
||||
addMenuButton(post, threadId, pageData);
|
||||
});
|
||||
|
||||
$(document).on('filter_page', function () {
|
||||
filterPage(pageData);
|
||||
});
|
||||
|
||||
// clear out the old threads
|
||||
purge();
|
||||
}
|
||||
init();
|
||||
});
|
||||
}
|
@ -39,7 +39,7 @@ onready(function(){
|
||||
if ($mentioned.find('a.mentioned-' + reply_id).length != 0)
|
||||
return;
|
||||
|
||||
var $link = $('<a class="mentioned-' + reply_id + '" onclick="highlightReply(\'' + reply_id + '\');" href="#' + reply_id + '">>>' +
|
||||
var $link = $('<a class="mentioned-' + reply_id + '" onclick="highlightReply(\'' + reply_id + '\', event);" href="#' + reply_id + '">>>' +
|
||||
reply_id + '</a>');
|
||||
$link.appendTo($mentioned);
|
||||
$link.after(" ");
|
||||
|
@ -20,7 +20,7 @@ $(document).ready(function(){
|
||||
$('<style type="text/css"> img.hidden{ opacity: 0.1; background: grey; border: 1px solid #000; } </style>').appendTo($('head'));
|
||||
|
||||
var hideImage = function() {
|
||||
if ($(this).parent()[0].dataset.expanded == 'true') {
|
||||
if ($(this).parent().data('expanded') == 'true') {
|
||||
$(this).parent().click();
|
||||
}
|
||||
$(this)
|
||||
|
@ -24,13 +24,11 @@ if (window.Options && Options.get_tab('general')) {
|
||||
|
||||
function handle_boards(data) {
|
||||
$.each(data, function(k, v) {
|
||||
if (v.uri != 'meta' && v.uri != 'b') {
|
||||
boards.push('<a href="/'+v.uri+(window.active_page === 'catalog' ? '/catalog.html' : '/index.html')+'" title="'+v.title+'">'+v.uri+'</a>');
|
||||
}
|
||||
boards.push('<a href="/'+v.uri+(window.active_page === 'catalog' ? '/catalog.html' : '/index.html')+'" title="'+v.title+'">'+v.uri+'</a>');
|
||||
})
|
||||
|
||||
if (boards[0]) {
|
||||
$('.sub[data-description="2"]').after('<span class="sub" data-description="3"> [ '+boards.slice(0,25).join(" / ")+' ] </span>');
|
||||
$('.sub[data-description="3"]').after('<span class="sub" data-description="4"> [ '+boards.slice(0,25).join(" / ")+' ] </span>');
|
||||
}
|
||||
}
|
||||
|
||||
|
6
mod.php
6
mod.php
@ -29,8 +29,10 @@ $pages = array(
|
||||
|
||||
'/log' => 'log', // modlog
|
||||
'/log/(\d+)' => 'log', // modlog
|
||||
'/log:([^/]+)' => 'user_log', // modlog
|
||||
'/log:([^/]+)/(\d+)' => 'user_log', // modlog
|
||||
'/log:([^/:]+)' => 'user_log', // modlog
|
||||
'/log:([^/:]+)/(\d+)' => 'user_log', // modlog
|
||||
'/log:b:([^/]+)' => 'board_log', // modlog
|
||||
'/log:b:([^/]+)/(\d+)' => 'board_log', // modlog
|
||||
'/edit_news' => 'secure_POST news', // view news
|
||||
'/edit_news/(\d+)' => 'secure_POST news', // view news
|
||||
'/edit_news/delete/(\d+)' => 'secure news_delete', // delete from news
|
||||
|
17
post.php
17
post.php
@ -38,7 +38,7 @@ if (isset($_POST['delete'])) {
|
||||
}
|
||||
}
|
||||
|
||||
checkDNSBL();
|
||||
if (checkDNSBL()) error("Tor users may not delete posts.");
|
||||
|
||||
// Check if board exists
|
||||
if (!openBoard($_POST['board']))
|
||||
@ -116,7 +116,7 @@ elseif (isset($_POST['report'])) {
|
||||
}
|
||||
}
|
||||
|
||||
checkDNSBL();
|
||||
if (checkDNSBL()) error("Tor users may not report posts.");
|
||||
|
||||
// Check if board exists
|
||||
if (!openBoard($_POST['board']))
|
||||
@ -329,6 +329,9 @@ elseif (isset($_POST['post'])) {
|
||||
|
||||
if ($config['field_disable_email'])
|
||||
$_POST['email'] = '';
|
||||
|
||||
if ($config['field_email_selectbox'] && $_POST['email'] != 'sage')
|
||||
$_POST['email'] = '';
|
||||
|
||||
if ($config['field_disable_password'])
|
||||
$_POST['password'] = '';
|
||||
@ -394,8 +397,14 @@ elseif (isset($_POST['post'])) {
|
||||
$post['password'] = $_POST['password'];
|
||||
$post['has_file'] = (!isset($post['embed']) && (($post['op'] && !isset($post['no_longer_require_an_image_for_op']) && $config['force_image_op']) || !empty($_FILES['file']['name'])));
|
||||
|
||||
if ($post['has_file'])
|
||||
checkDNSBL();
|
||||
// Handle our Tor users
|
||||
$tor = checkDNSBL();
|
||||
if ($tor && !(isset($_SERVER['HTTP_X_TOR'], $_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] == '127.0.0.2' && $_SERVER['HTTP_X_TOR'] = 'true'))
|
||||
error('To post on 8chan over Tor, you must use the hidden service for security reasons. You can find it at <a href="http://fullchan4jtta4sx.onion">http://fullchan4jtta4sx.onion</a>.');
|
||||
if ($tor && $post['has_file'])
|
||||
error('Sorry. Tor users can\'t upload files.');
|
||||
if ($tor && !$config['tor_posting'])
|
||||
error('Sorry. The owner of this board has decided not to allow Tor posters for some reason...');
|
||||
|
||||
if (!($post['has_file'] || isset($post['embed'])) || (($post['op'] && $config['force_body_op']) || (!$post['op'] && $config['force_body']))) {
|
||||
// http://stackoverflow.com/a/4167053
|
||||
|
60
stylesheets/redchanit.css
Normal file
60
stylesheets/redchanit.css
Normal file
@ -0,0 +1,60 @@
|
||||
body {
|
||||
background: #3B4357;
|
||||
color: white;
|
||||
font-family: verdana,arial,sans-serif;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.desktop-style div.boardlist:not(.bottom) {
|
||||
background-color: #7F8CA8;
|
||||
}
|
||||
|
||||
.desktop-style .sub {
|
||||
font-family: arial,helvetica,sans-serif;
|
||||
font-size: 8pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
header div.subtitle, h1 {
|
||||
font-family: verdana,arial,sans-serif;
|
||||
}
|
||||
|
||||
div.banner {
|
||||
background-color: #7F8CA8;
|
||||
}
|
||||
|
||||
form table tr th {
|
||||
background: #7F8CA8;
|
||||
}
|
||||
|
||||
div.blotter {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.thread {
|
||||
background: #7F8CA8;
|
||||
}
|
||||
|
||||
div.post.reply {
|
||||
background: #343C4E;
|
||||
border: none;
|
||||
display: table;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img.post-image {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
p.intro span.name {
|
||||
color: #5C5484;
|
||||
}
|
||||
|
||||
p.intro a.email span.name {
|
||||
color: #8080FF;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #8020FF;
|
||||
}
|
@ -578,7 +578,7 @@ table.mod.config-editor input[type="text"] {
|
||||
width: 98%;
|
||||
}
|
||||
|
||||
.desktop-style div.boardlist:nth-child(1) {
|
||||
.desktop-style div.boardlist:not(.bottom) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@ -1017,6 +1017,9 @@ span.pln {
|
||||
div.mix {
|
||||
display: inline-block;
|
||||
}
|
||||
.theme-catalog div.thread:hover {
|
||||
overflow-y: auto; width: 100%
|
||||
}
|
||||
|
||||
/* Mona Font */
|
||||
|
||||
|
9
templates/8chan/dnsbls.html
Normal file
9
templates/8chan/dnsbls.html
Normal file
@ -0,0 +1,9 @@
|
||||
<form method="POST">
|
||||
<p>{% trans %}Your IP is listed in our DNSBL. To stop attackers, we require users who use certain IP ranges to pass a test which proves they are human every 24 hours.{% endtrans %}</p>
|
||||
|
||||
<p>{% trans %}It is also possible that the site is currently under attack and we are requiring everyone to pass the test right now. Sorry for the inconvenience.{% endtrans %}</p>
|
||||
|
||||
{{ ayah_html|raw }}
|
||||
|
||||
<ul style="padding:0;text-align:center;list-style:none"><li><input type="submit" value="{% trans %}Let me post!{% endtrans %}"></li></ul>
|
||||
</form>
|
@ -235,10 +235,10 @@
|
||||
<div class="col col-9 header_text">
|
||||
<em>{% trans %}Welcome to 8chan, the infinitely expanding imageboard.{% endtrans %}</em>
|
||||
<br>
|
||||
<span>[ <a href="/b/">/b/ - Random</a> | <a href="/meta/">/meta/ - Help & Support</a> | <a href="/news+/">/news+/ - News</a> ]</span>
|
||||
<span>[ <a href="/b/">/b/ - Random</a> | <a href="/news+/">/news+/ - News</a> | <a href="/boards/">/boards/ - Boards</a>]</span>
|
||||
<br>
|
||||
<strong>{% trans %}Top 25 boards:{% endtrans %}</strong>
|
||||
<span class="sub" data-description="2"></span>
|
||||
<span class="sub" data-description="3"></span>
|
||||
<br>
|
||||
<strong>
|
||||
{% trans %}Boards of the week:{% endtrans %} [
|
||||
@ -261,7 +261,7 @@
|
||||
|
||||
<div class="content_menu">
|
||||
<ul class="content_menu_head">
|
||||
<li><em><a href="https://kiwiirc.com/client/irc.rizon.net/#8chan" target="_blank">IRC:#8chan @ irc.rizon.net</a></em></li>
|
||||
<li><em><a href="https://qchat2.rizon.net/?channels=8chan&uio=OT0xMTE05" target="_blank">IRC:#8chan @ irc.rizon.net</a></em></li>
|
||||
<li><a href="/faq.html">{% trans %}Frequently Asked Questions{% endtrans %}</a></li>
|
||||
<li><a href="/random.php">{% trans %}View random board{% endtrans %}</a></li>
|
||||
<li><a href="/mod.php" >{% trans %}Manage your board{% endtrans %}</a></li>
|
||||
@ -305,8 +305,13 @@
|
||||
</div>
|
||||
<br>
|
||||
<!-- START RIZON PASTE / NEWS SCRIPT CODE HERE -->
|
||||
<iframe src="https://kiwiirc.com/client/irc.rizon.net/#8chan"></iframe>
|
||||
<iframe src="https://qchat2.rizon.net/?channels=8chan&uio=OT0xMTE05" height="400" width="793"></iframe>
|
||||
<!--END PASTE CODE -->
|
||||
<!-- Start spooks.me code
|
||||
<div style="height:400px;width:793px;border:1px solid black" onclick="this.innerHTML='<iframe src="https://8chan.spooks.me" width="793" height="400" style="margin-top:0px"></iframe>';">
|
||||
<h1>Click inside this box to load chat</h1>
|
||||
</div>
|
||||
End spooks.me code -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -37,7 +37,9 @@
|
||||
|
||||
{% include 'attention_bar.html' %}
|
||||
|
||||
{{ config.ad.top }}
|
||||
{% if board.uri not in config.banned_ad_boards %}
|
||||
{% include 'ad_top.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% if not no_post_form %}
|
||||
{% include 'post_form.html' %}
|
||||
@ -74,7 +76,9 @@
|
||||
|
||||
{{ boardlist.bottom }}
|
||||
|
||||
{{ config.ad.bottom }}
|
||||
{% if board.uri not in config.banned_ad_boards %}
|
||||
{% include 'ad_bottom.html' %}
|
||||
{% endif %}
|
||||
|
||||
<footer>
|
||||
<p class="unimportant" style="margin-top:20px;text-align:center;">- <a href="http://tinyboard.org/">Tinyboard</a> +
|
||||
|
@ -12,6 +12,9 @@
|
||||
{% if post and board %}
|
||||
<input type="hidden" name="delete" value="{% if delete %}1{% else %}0{% endif %}">
|
||||
{% endif %}
|
||||
{% if tor %}
|
||||
<p style="color:red;font-size:2em">Warning! This IP is a Tor exit node. Tor is a global network that allows for truly anonymous posting by obfuscating the user's real IP address. Please do not ban it, all bans on Tor exit nodes are globally undone every week. On 8chan, Tor users are allowed to post five times per CAPTCHA they complete, and image uploads are not allowed. <em>If the global restrictions on Tor users are not enough and you would really like to stop Tor users, there is a setting in your board options. Please think carefully before enabling it.</em></p>
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
|
||||
|
@ -13,9 +13,6 @@
|
||||
{% endif %}
|
||||
<div class='banlist-opts'>
|
||||
<div class='checkboxes'>
|
||||
{% if mod and mod.boards[0] != '*' %}
|
||||
<label><input type="checkbox" id="only_mine"> {% trans %}Show only bans from boards I moderate{% endtrans %}</label>
|
||||
{% endif %}
|
||||
<label><input type="checkbox" id="only_not_expired"> {% trans %}Show only active bans{% endtrans %}</label>
|
||||
</div>
|
||||
<div class='buttons'>
|
||||
|
@ -72,7 +72,9 @@
|
||||
<li><a href="?/themes">{% trans 'Manage themes' %}</a></li>
|
||||
{% endif %}
|
||||
{% if mod|hasPermission(config.mod.modlog) %}
|
||||
<li><a href="?/log">{% trans 'Moderation log' %}</a></li>
|
||||
<li><a href="?/log">{% trans 'User actions log' %}</a></li>
|
||||
{% elseif mod.boards[0] != '*' and mod.boards[0] and mod|hasPermission(config.mod.mod_board_log, mod.boards[0]) %}
|
||||
<li><a href="?/log:b:{{ mod.boards[0] }}">{% trans 'Board log' %}</a></li>
|
||||
{% endif %}
|
||||
{% if mod|hasPermission(config.mod.recent) %}
|
||||
<li><a href="?/recent/25">{% trans 'Recent posts' %}</a></li>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<table class="modlog">
|
||||
<tr>
|
||||
<th>{% trans 'Staff' %}</th>
|
||||
<th>{% trans 'Username' %}</th>
|
||||
<th>{% trans 'IP address' %}</th>
|
||||
<th>{% trans 'Time' %}</th>
|
||||
<th>{% trans 'Board' %}</th>
|
||||
@ -10,7 +10,11 @@
|
||||
<tr>
|
||||
<td class="minimal">
|
||||
{% if log.username %}
|
||||
<a href="?/log:{{ log.username|e }}">{{ log.username|e }}</a>
|
||||
{% if not mod|hasPermission(config.mod.modlog) %}
|
||||
<a href="?/new_PM/{{ log.username|e }}">{{ log.username|e }}</a>
|
||||
{% else %}
|
||||
<a href="?/log:{{ log.username|e }}">{{ log.username|e }}</a>
|
||||
{% endif %}
|
||||
{% elseif log.mod == -1 %}
|
||||
<em>system</em>
|
||||
{% else %}
|
||||
@ -44,7 +48,7 @@
|
||||
{% if count > logs|count %}
|
||||
<p class="unimportant" style="text-align:center;word-wrap:break-word">
|
||||
{% for i in range(0, (count - 1) / config.mod.modlog_page) %}
|
||||
<a href="?/log{% if username %}:{{ username }}{% endif %}/{{ i + 1 }}">[{{ i + 1 }}]</a>
|
||||
<a href="?/log{% if username %}:{{ username }}{% elseif board %}:b:{{ board }}{% endif %}/{{ i + 1 }}">[{{ i + 1 }}]</a>
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
@ -45,9 +45,8 @@
|
||||
<tr><th>{% trans %}Enable dice rolling{% endtrans %}</th><td><input type="checkbox" name="allow_roll" {% if config.allow_roll %}checked{% endif %}></td></tr>
|
||||
<tr><th>{% trans %}Don't allow users to repost images{% endtrans %}</th><td><input type="checkbox" name="image_reject_repost" {% if config.image_reject_repost %}checked{% endif %}></td></tr>
|
||||
<tr><th>{% trans %}Allow a poster to delete his own posts{% endtrans %}</th><td><input type="checkbox" name="allow_delete" {% if config.allow_delete %}checked{% endif %}></td></tr>
|
||||
<!--Added explanation to clarify purpose of "Enable CAPTCHA" now that "Enable CAPTCHA for new thread creation only" also exists-->
|
||||
<tr><th>{% trans %}Allow posters to post via the Tor onion router{% endtrans %}<br/><span class="unimportant">Disabling this is evil, but if you really care about "ban evasion", here you go.</span></th><td><input type="checkbox" name="tor_posting" {% if config.tor_posting %}checked{% endif %}></td></tr>
|
||||
<tr><th>{% trans %}Enable CAPTCHA{% endtrans %}<br/><span class="unimportant">Users must solve a CAPTCHA in order to post.<br> This is not ReCAPTCHA, it is custom to 8chan.</span></th><td><input type="checkbox" name="captcha" {% if config.captcha.enabled %}checked{% endif %}></td></tr>
|
||||
<!--New thread captcha start-->
|
||||
<tr><th>{% trans %}Enable CAPTCHA for thread creation only{% endtrans %}<br/><span class="unimportant">Users must solve a CAPTCHA in order to create new threads,<br>but do not have to solve a CAPTCHA in order to post replies.</span></th><td><input type="checkbox" name="new_thread_capt" {% if config.new_thread_capt %}checked{% endif %}></td></tr>
|
||||
<tr><th>{% trans %}Language{% endtrans %}<br/><span class="unimportant">{% trans %}To contribute translations, register at <a href="https://www.transifex.com/projects/p/tinyboard-vichan-devel/">Transifex</a>{% endtrans %}</span></th><td>
|
||||
<select name="locale">
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% if post.mod and post.mod|hasPermission(config.mod.show_ip, board.uri) %}
|
||||
[<a class="ip-link" style="margin:0;" href="?/IP/{{ post.ip }}">{{ post.ip }}</a>]
|
||||
[<a class="ip-link" style="margin:0;" href="?/IP_less/{{ board.dir }}{{ post.id }}">{{ post.ip }}</a>]
|
||||
{% elseif post.mod and post.mod|hasPermission(config.mod.show_ip_less, board.uri) %}
|
||||
[<a class="ip-link" style="margin:0;" href="?/IP_less/{{ board.dir }}{{ post.id }}">{{ post.ip|less_ip }}</a>]
|
||||
{% endif %}
|
||||
|
@ -1,5 +1,7 @@
|
||||
{% if config.poster_ids or (mod|hasPermission(config.mod.show_ip_less, board.uri)) %}
|
||||
{% if post.thread %}
|
||||
{% if post.ip == '127.0.0.2' %}
|
||||
<span class="poster_id" title="This user is posting via the Tor hidden service.">000000</span>
|
||||
{% elseif post.thread %}
|
||||
<span class="poster_id">{{ poster_id(post.ip, post.thread, board.uri) }}</span>
|
||||
{% else %}
|
||||
<span class="poster_id">{{ poster_id(post.ip, post.id, board.uri) }}</span>
|
||||
|
@ -15,7 +15,7 @@
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="name" size="25" maxlength="35" autocomplete="off"> {% if config.allow_no_country and config.country_flags %}<input id="no_country" name="no_country" type="checkbox"> <label for="no_country">{% trans %}Don't show my flag{% endtrans %}</label>{% endif %}
|
||||
<input type="text" name="name" size="25" maxlength="35" autocomplete="off">
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
@ -25,7 +25,7 @@
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
{% if config.field_email_selectbox %}
|
||||
{% if config.field_email_selectbox and not (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}
|
||||
<select name="email" id="email_selectbox" autocomplete="off">
|
||||
<option value=""></option>
|
||||
<option value="sage">sage</option>
|
||||
@ -144,12 +144,18 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if mod and ((not id and post.mod|hasPermission(config.mod.sticky, board.uri)) or (not id and post.mod|hasPermission(config.mod.lock, board.uri)) or post.mod|hasPermission(config.mod.rawhtml, board.uri)) %}
|
||||
{% if (mod and ((not id and post.mod|hasPermission(config.mod.sticky, board.uri)) or (not id and post.mod|hasPermission(config.mod.lock, board.uri)) or post.mod|hasPermission(config.mod.rawhtml, board.uri))) or (config.allow_no_country and config.country_flags) %}
|
||||
<tr>
|
||||
<th>
|
||||
{% trans %}Flags{% endtrans %}
|
||||
</th>
|
||||
<td>
|
||||
{% if config.allow_no_country and config.country_flags %}<div class="center">
|
||||
<label for="no_country">{% trans %}No country flag{% endtrans %}</label>
|
||||
<input title="No country flag" id="no_country" name="no_country" type="checkbox">
|
||||
</div>{% endif %}
|
||||
|
||||
{% if mod %}
|
||||
{% if not id and post.mod|hasPermission(config.mod.sticky, board.uri) %}<div class="center">
|
||||
<label for="sticky">{% trans %}Sticky{% endtrans %}</label>
|
||||
<input title="{% trans %}Sticky{% endtrans %}" type="checkbox" name="sticky" id="sticky"><br>
|
||||
@ -162,6 +168,7 @@
|
||||
<label for="raw">{% trans %}Raw HTML{% endtrans %}</label><br>
|
||||
<input title="{% trans %}Raw HTML{% endtrans %}" type="checkbox" name="raw" id="raw">
|
||||
</div>{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
@ -15,7 +15,9 @@
|
||||
<h1>{{ settings.title }} (<a href="{{link}}">/{{ board }}/</a>)</h1>
|
||||
<div class="subtitle">{{ settings.subtitle }}</div>
|
||||
</header>
|
||||
{{ config.ad.top }}
|
||||
{% if board.uri not in config.banned_ad_boards %}
|
||||
{% include 'ad_top.html' %}
|
||||
{% endif %}
|
||||
|
||||
<span>{% trans 'Sort by' %}: </span>
|
||||
<select id="sort_by" style="display: inline-block">
|
||||
@ -38,6 +40,7 @@
|
||||
data-reply="{{ post.reply_count }}"
|
||||
data-bump="{{ post.bump }}"
|
||||
data-time="{{ post.time }}"
|
||||
data-id="{{ post.id }}"
|
||||
>
|
||||
<div class="thread grid-li grid-size-small">
|
||||
<a href="{{post.link}}">
|
||||
|
@ -59,17 +59,7 @@
|
||||
|
||||
if ($files[0]) {
|
||||
if ($files[0]->file == 'deleted') {
|
||||
if (count($files) > 1) {
|
||||
foreach ($files as $file) {
|
||||
if (($file == $files[0]) || ($file->file == 'deleted')) continue;
|
||||
$post['file'] = $config['uri_thumb'] . $file->thumb;
|
||||
}
|
||||
|
||||
if (empty($post['file'])) $post['file'] = $config['image_deleted'];
|
||||
}
|
||||
else {
|
||||
$post['file'] = $config['image_deleted'];
|
||||
}
|
||||
$post['file'] = $config['image_deleted'];
|
||||
}
|
||||
else if($files[0]->thumb == 'spoiler') {
|
||||
$post['file'] = '/' . $config['spoiler_image'];
|
||||
|
@ -8,7 +8,18 @@
|
||||
</script>
|
||||
|
||||
{% include 'header.html' %}
|
||||
<title>{{ board.url }} - {% if config.thread_subject_in_title and thread.subject %}{{ thread.subject }}{% else %}{{ thread.body_nomarkup[:256]|e }}{% endif %}</title>
|
||||
|
||||
{% set meta_subject %}{% if config.thread_subject_in_title and thread.subject %}{{ thread.subject|e }}{% else %}{{ thread.body_nomarkup[:256]|e }}{% endif %}{% endset %}
|
||||
|
||||
<meta name="description" content="8chan /{{ board.uri }}/ - {{ board.title|e }} - {{ meta_subject }}" />
|
||||
<meta name="twitter:card" value="summary">
|
||||
<meta property="og:title" content="{{ meta_subject }}" />
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://8ch.net/{{ board.uri }}/{{ config.dir.res }}{{ thread.id }}.html" />
|
||||
{% if thread.files.0.thumb %}<meta property="og:image" content="https://8ch.net/{{ board.uri }}/{{ config.dir.thumb }}{{ thread.files.0.thumb }}" />{% endif %}
|
||||
<meta property="og:description" content="{{ thread.body_nomarkup|e }}" />
|
||||
|
||||
<title>{{ board.url }} - {{ meta_subject }}</title>
|
||||
</head>
|
||||
<body class="8chan {% if mod %}is-moderator{% else %}is-not-moderator{% endif %}" data-stylesheet="{% if config.default_stylesheet.1 != '' and not mod %}{{ config.default_stylesheet.1 }}{% else %}default{% endif %}">
|
||||
{{ boardlist.top }}
|
||||
@ -34,7 +45,9 @@
|
||||
<div class="banner">{% trans %}Posting mode: Reply{% endtrans %} <a class="unimportant" href="{{ return }}">[{% trans %}Return{% endtrans %}]</a> <a class="unimportant" href="javascript:window.scrollTo(0,document.body.scrollHeight);
|
||||
">[{% trans %}Go to bottom {% endtrans %}]</a></div>
|
||||
|
||||
{{ config.ad.top }}
|
||||
{% if board.uri not in config.banned_ad_boards %}
|
||||
{% include 'ad_top.html' %}
|
||||
{% endif %}
|
||||
|
||||
{% include 'post_form.html' %}
|
||||
|
||||
@ -55,7 +68,9 @@
|
||||
|
||||
{{ boardlist.bottom }}
|
||||
|
||||
{{ config.ad.bottom }}
|
||||
{% if board.uri not in config.banned_ad_boards %}
|
||||
{% include 'ad_bottom.html' %}
|
||||
{% endif %}
|
||||
|
||||
<footer>
|
||||
<p class="unimportant" style="margin-top:20px;text-align:center;">- <a href="http://tinyboard.org/">Tinyboard</a> +
|
||||
|
140
tools/rebuild2.php
Executable file
140
tools/rebuild2.php
Executable file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* rebuild.php - rebuilds all static files
|
||||
* This is much different than the one in vichan because we have way more static files. It will not work without pcntl_fork.
|
||||
* You must specify the things you want to rebuild. By default the script does nothing.
|
||||
* Example of how to use:
|
||||
* php rebuild.php --cache --js --indexes --processes 5
|
||||
* That will clear the cache, rebuild all JS files and all indexes, and fork 5 processes to do it faster.
|
||||
* I removed the quiet option, it's useless. Just use output redirection.
|
||||
*/
|
||||
|
||||
require dirname(__FILE__) . '/inc/cli.php';
|
||||
|
||||
$start = microtime(true);
|
||||
|
||||
// parse command line
|
||||
$opts = getopt('', Array('board:', 'themes', 'js', 'indexes', 'threads', 'processes:', 'cache', 'postmarkup', 'api'));
|
||||
$options = Array();
|
||||
$global_locale = $config['locale'];
|
||||
|
||||
// Do only one board?
|
||||
$options['board'] = isset($opts['board']) ? $opts['board'] : (isset($opts['b']) ? $opts['b'] : false);
|
||||
// Clear the cache?
|
||||
$options['cache'] = isset($opts['cache']);
|
||||
// Rebuild themes (catalogs)?
|
||||
$options['themes'] = isset($opts['themes']);
|
||||
// Rebuild JS?
|
||||
$options['js'] = isset($opts['js']);
|
||||
// Rebuild indexes? (e.g. /b/index.html)
|
||||
$options['indexes'] = isset($opts['indexes']);
|
||||
// Rebuild threads? (e.g. /b/res/1.html)
|
||||
$options['threads'] = isset($opts['threads']);
|
||||
// Rebuild all post markup? (e.g. /b/res/1.html#2)
|
||||
$options['postmarkup'] = isset($opts['postmarkup']);
|
||||
// Rebuild API pages? (e.g. /b/res/1.json')
|
||||
$options['api'] = isset($opts['api']);
|
||||
// How many processes?
|
||||
$options['processes'] = isset($opts['processes']) ? $opts['processes'] : 1;
|
||||
|
||||
echo "== Tinyboard + vichan {$config['version']} ==\n";
|
||||
|
||||
if ($options['cache']) {
|
||||
echo "Clearing template cache...\n";
|
||||
load_twig();
|
||||
$twig->clearCacheFiles();
|
||||
}
|
||||
|
||||
if($options['themes']) {
|
||||
echo "Regenerating theme files...\n";
|
||||
rebuildThemes('all');
|
||||
}
|
||||
|
||||
if($options['js']) {
|
||||
echo "Generating Javascript file...\n";
|
||||
buildJavascript();
|
||||
}
|
||||
|
||||
$main_js = $config['file_script'];
|
||||
|
||||
$boards = listBoards();
|
||||
//$boards = array(array('uri'=>'test'), array('uri'=>'tester'), array('uri'=>'testing'));
|
||||
$boards_m = array_chunk($boards, floor(sizeof($boards)/$options['processes']));
|
||||
|
||||
function doboard($board) {
|
||||
global $global_locale, $config, $main_js, $options;
|
||||
$config['mask_db_error'] = false;
|
||||
if (!$options['api']) $config['api']['enabled'] = false;
|
||||
|
||||
echo "Opening board /{$board['uri']}/...\n";
|
||||
// Reset locale to global locale
|
||||
$config['locale'] = $global_locale;
|
||||
init_locale($config['locale'], 'error');
|
||||
openBoard($board['uri']);
|
||||
$config['try_smarter'] = false;
|
||||
|
||||
if($config['file_script'] != $main_js && $options['js']) {
|
||||
// different javascript file
|
||||
echo "(/{$board['uri']}/) Generating Javascript file...\n";
|
||||
buildJavascript();
|
||||
}
|
||||
|
||||
|
||||
if ($options['indexes']) {
|
||||
echo "(/{$board['uri']}/) Creating index pages...\n";
|
||||
buildIndex();
|
||||
}
|
||||
|
||||
if($options['postmarkup']) {
|
||||
$query = query(sprintf("SELECT `id` FROM ``posts_%s``", $board['uri'])) or error(db_error());
|
||||
while($post = $query->fetch()) {
|
||||
echo "(/{$board['uri']}/) Rebuilding #{$post['id']}...\n";
|
||||
rebuildPost($post['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['threads']) {
|
||||
$query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $board['uri'])) or error(db_error());
|
||||
while($post = $query->fetch()) {
|
||||
echo "(/{$board['uri']}/) Rebuilding #{$post['id']}...\n";
|
||||
@buildThread($post['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$children = array();
|
||||
foreach ($boards_m as $i => $bb) {
|
||||
$pid = pcntl_fork();
|
||||
|
||||
if ($pid == -1) {
|
||||
die('Fork failed?');
|
||||
} else if ($pid) {
|
||||
echo "Started PID #$pid...\n";
|
||||
$children[] = $pid;
|
||||
} else {
|
||||
unset($pdo);
|
||||
$i = 0;
|
||||
$total = sizeof($bb);
|
||||
sql_open();
|
||||
foreach ($bb as $i => $b) {
|
||||
$i++;
|
||||
doboard($b);
|
||||
echo "I'm on board $i/$total\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
printf("Complete! Took %g seconds\n", microtime(true) - $start);
|
||||
|
||||
unset($board);
|
||||
|
||||
foreach ($children as $child) {
|
||||
pcntl_waitpid($child, $status);
|
||||
unset($children[$child]);
|
||||
}
|
||||
|
||||
//modLog('Rebuilt everything using tools/rebuild.php');
|
Loading…
x
Reference in New Issue
Block a user