diff --git a/inc/8chan-mod-pages.php b/inc/8chan-mod-pages.php index a8e44311..f080c70f 100644 --- a/inc/8chan-mod-pages.php +++ b/inc/8chan-mod-pages.php @@ -384,13 +384,18 @@ FLAGS; $possible_languages = array_diff(scandir('inc/locale/'), array('..', '.', '.tx', 'README.md')); if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $board_type = $_POST['board_type']; + $imgboard = $board_type == 'imgboard'; + $txtboard = $board_type == 'txtboard'; + $fileboard = $board_type == 'fileboard'; + $title = $_POST['title']; $subtitle = $_POST['subtitle']; $country_flags = isset($_POST['country_flags']) ? 'true' : 'false'; $field_disable_name = isset($_POST['field_disable_name']) ? 'true' : 'false'; $enable_embedding = isset($_POST['enable_embedding']) ? 'true' : 'false'; - $force_image_op = isset($_POST['force_image_op']) ? 'true' : 'false'; - $disable_images = isset($_POST['disable_images']) ? 'true' : 'false'; + $force_image_op = $imgboard && isset($_POST['force_image_op']) ? 'true' : 'false'; + $disable_images = $txtboard ? 'true' : 'false'; $poster_ids = isset($_POST['poster_ids']) ? 'true' : 'false'; $show_sages = isset($_POST['show_sages']) ? 'true' : 'false'; $auto_unicode = isset($_POST['auto_unicode']) ? 'true' : 'false'; @@ -400,8 +405,8 @@ FLAGS; $image_reject_repost_in_thread = isset($_POST['image_reject_repost_in_thread']) ? 'true' : 'false'; $early_404 = isset($_POST['early_404']) ? 'true' : 'false'; $allow_delete = isset($_POST['allow_delete']) ? 'true' : 'false'; - $allow_flash = isset($_POST['allow_flash']) ? '$config[\'allowed_ext_files\'][] = \'swf\';' : ''; - $allow_pdf = isset($_POST['allow_pdf']) ? '$config[\'allowed_ext_files\'][] = \'pdf\';' : ''; + $allow_flash = $imgboard && isset($_POST['allow_flash']) ? '$config[\'allowed_ext_files\'][] = \'swf\';' : ''; + $allow_pdf = $imgboard && isset($_POST['allow_pdf']) ? '$config[\'allowed_ext_files\'][] = \'pdf\';' : ''; $code_tags = isset($_POST['code_tags']) ? '$config[\'additional_javascript\'][] = \'js/code_tags/run_prettify.js\';$config[\'markup\'][] = array("/\[code\](.+?)\[\/code\]/ms", "
\$1
");' : ''; $katex = isset($_POST['katex']) ? '$config[\'katex\'] = true;$config[\'additional_javascript\'][] = \'js/katex/katex.min.js\'; $config[\'markup\'][] = array("/\[tex\](.+?)\[\/tex\]/ms", "\$1"); $config[\'additional_javascript\'][] = \'js/katex-enable.js\';' : ''; $user_flags = isset($_POST['user_flags']) ? "if (file_exists('$b/flags.php')) { include 'flags.php'; }\n" : ''; @@ -410,7 +415,7 @@ FLAGS; $force_flag = isset($_POST['force_flag']) ? 'true' : 'false'; $tor_posting = isset($_POST['tor_posting']) ? 'true' : 'false'; $new_thread_capt = isset($_POST['new_thread_capt']) ? 'true' : 'false'; - $oekaki = isset($_POST['oekaki']) ? 'true' : 'false'; + $oekaki = ($imgboard || $fileboard) && isset($_POST['oekaki']) ? 'true' : 'false'; if ($_POST['locale'] !== 'en' && in_array($_POST['locale'], $possible_languages)) { $locale = "\$config['locale'] = '{$_POST['locale']}.UTF-8';"; @@ -426,6 +431,52 @@ FLAGS; $multiimage = ''; } + $file_board = ''; + if ($fileboard) { + $force_image_op = true; + + $file_board = "\$config['threads_per_page'] = 30; + \$config['file_board'] = true; + \$config['threads_preview'] = 0; + \$config['threads_preview_sticky'] = 0; + \$config['allowed_ext_files'] = array();\n"; + + + if (isset ($_POST['allowed_type'])) { + foreach ($_POST['allowed_type'] as $val) { + if (in_array ($val, $config['fileboard_allowed_types'])) { + $file_board .= "\$config['allowed_ext_files'][] = '$val';\n"; + } + } + } + + if (isset ($_POST['allowed_ext_op'])) { + $file_board .= "\$config['allowed_ext_op'] = \$config['allowed_ext_files'];\n"; + + if (isset ($_POST['allowed_ext_op_video'])) { + $file_board .= "\$config['allowed_ext_op'][] = 'webm'; + \$config['allowed_ext_op'][] = 'mp4';\n"; + } + } + + if (isset ($_POST['tag_id'])) { + $file_board .= "\$config['allowed_tags'] = array();\n"; + foreach ($_POST['tag_id'] as $id => $v) { + $file_board .= "\$config['allowed_tags']["; + $file_board .= 'base64_decode("'; + $file_board .= base64_encode($_POST['tag_id'][$id]); + $file_board .= '")'; + $file_board .= "] = "; + $file_board .= 'base64_decode("'; + $file_board .= base64_encode($_POST['tag_desc'][$id]); + $file_board .= '")'; + $file_board .= ";\n"; + } + } + } + + $anal_filenames = ($imgboard || $fileboard) && isset($_POST['anal_filenames']) ? "\$config['filename_func'] = 'filename_func';\n" : ''; + $anonymous = base64_encode($_POST['anonymous']); $blotter = base64_encode(purify_html(html_entity_decode($_POST['blotter']))); $add_to_config = @file_get_contents($b.'/extra_config.php'); @@ -461,7 +512,7 @@ FLAGS; if (isset($_POST['max_pages'])) { $mp = (int)$_POST['max_pages']; - if ($mp > 25 || $mp < 2) { + if ($mp > 25 || $mp < 1) { $max_pages = 15; } else { $max_pages = $mp; @@ -538,10 +589,13 @@ FLAGS; \$config['max_newlines'] = $max_newlines; \$config['oekaki'] = $oekaki; $code_tags $katex $replace $multiimage $allow_flash $allow_pdf $user_flags +$locale +$anal_filenames +$file_board + if (\$config['disable_images']) \$config['max_pages'] = 10000; -$locale $add_to_config EOT; diff --git a/inc/config.php b/inc/config.php index e1ad3eec..5a046d91 100644 --- a/inc/config.php +++ b/inc/config.php @@ -279,7 +279,8 @@ 'file_url', 'json_response', 'user_flag', - 'no_country' + 'no_country', + 'tag' ); @@ -793,6 +794,9 @@ // Details: https://github.com/savetheinternet/Tinyboard/issues/20 $config['ie_mime_type_detection'] = '/<(?:body|head|html|img|plaintext|pre|script|table|title|a href|channel|scriptlet)/i'; + // Config panel, fileboard: allowed upload extensions + $config['fileboard_allowed_types'] = array('zip', '7z', 'tar', 'gz', 'bz2', 'xz', 'swf', 'txt', 'pdf', 'torrent'); + // Allowed image file extensions. $config['allowed_ext'][] = 'jpg'; $config['allowed_ext'][] = 'jpeg'; @@ -800,6 +804,11 @@ $config['allowed_ext'][] = 'png'; // $config['allowed_ext'][] = 'svg'; + // Allowed extensions for OP. Inherits from the above setting if set to false. Otherwise, it overrides both allowed_ext and + // allowed_ext_files (filetypes for downloadable files should be set in allowed_ext_files as well). This setting is useful + // for creating fileboards. + $config['allowed_ext_op'] = false; + // Allowed additional file extensions (not images; downloadable files). // $config['allowed_ext_files'][] = 'txt'; // $config['allowed_ext_files'][] = 'zip'; @@ -1604,6 +1613,13 @@ // Allow OP to remove arbitrary posts in his thread $config['user_moderation'] = false; + // File board. Like 4chan /f/ + $config['file_board'] = false; + + // Thread tags. Set to false to disable + // Example: array('A' => 'Chinese cartoons', 'M' => 'Music', 'P' => 'Pornography'); + $config['allowed_tags'] = false; + /* * ==================== * Public post search diff --git a/inc/display.php b/inc/display.php index 0f8e3e68..7dd0ffc2 100644 --- a/inc/display.php +++ b/inc/display.php @@ -511,7 +511,9 @@ class Thread extends Post { event('show-thread', $this); - $built = Element('post_thread.html', array( + $file = ($index && $config['file_board']) ? 'post_thread_fileboard.html' : 'post_thread.html'; + + $built = Element($file, array( 'config' => $config, 'board' => $board, 'post' => &$this, diff --git a/inc/functions.php b/inc/functions.php index 38fe902d..adf6cdb0 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -1568,6 +1568,10 @@ function index($page, $mod=false) { $body .= $thread->build(true); } + if ($config['file_board']) { + $body = Element('fileboard.html', array('body' => $body, 'mod' => $mod)); + } + return array( 'board' => $board, 'body' => $body, diff --git a/inc/instance-config.php b/inc/instance-config.php index d75cefe3..14ba4833 100644 --- a/inc/instance-config.php +++ b/inc/instance-config.php @@ -141,6 +141,7 @@ $config['additional_javascript'][] = 'js/auto-scroll.js'; $config['additional_javascript'][] = 'js/twemoji/twemoji.js'; $config['additional_javascript'][] = 'js/file-selector.js'; + $config['additional_javascript'][] = 'js/gallery-view.js'; $config['additional_javascript'][] = 'js/board-directory.js'; // Oekaki (now depends on config.oekaki so can be in all scripts) $config['additional_javascript'][] = 'js/jquery-ui.custom.min.js'; diff --git a/inc/instance-functions.php b/inc/instance-functions.php index 71e933d1..aa4bf010 100644 --- a/inc/instance-functions.php +++ b/inc/instance-functions.php @@ -22,3 +22,9 @@ function max_posts_per_hour($post) { function page_404() { include('404.php'); } + +function filename_func($a) { + $f = basename($a['filename'], '.'.$a['extension']); + $f = str_replace(array("\0", "\n", "<", ">", "/", "&"), array("?", "?", "«", "»", "⁄", "and"), $f); + return $f; +} diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 45cb92ba..3d78fb31 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -3340,7 +3340,7 @@ function mod_theme_configure($theme_name) { // Clean cache Cache::delete("themes"); - Cache::delete("theme_settings_".$theme); + Cache::delete("theme_settings_".$theme_name); $result = true; $message = false; diff --git a/js/gallery-view.js b/js/gallery-view.js new file mode 100644 index 00000000..2d7d85b4 --- /dev/null +++ b/js/gallery-view.js @@ -0,0 +1,165 @@ +if (active_page == 'index' || active_page == 'thread') +$(function(){ + + var gallery_view = false; + + $('hr:first').before(''); + $('#gallery-view a').html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode")).click(function() { + gallery_view = !gallery_view; + $(this).html(gallery_view ? _("Disable gallery mode") : _("Enable gallery mode")); + toggle_gview(document); + }); + + var toggle_gview = function(elem) { + if (gallery_view) { + $(elem).find('img.post-image').parent().each(function() { + this.oldonclick = this.onclick; + this.onclick = handle_click; + $(this).attr('data-galid', Math.random()); + }); + } + else { + $(elem).find('img.post-image').parent().each(function() { + if (this.onclick == handle_click) this.onclick = this.oldonclick; + }); + } + }; + + $(document).on('new_post', toggle_gview); + + var gallery_opened = false; + + var handle_click = function(e) { + e.stopPropagation(); + e.preventDefault(); + + if (!gallery_opened) open_gallery(); + + gallery_setimage($(this).attr('data-galid')); + }; + + var handler, images, active, toolbar; + + var open_gallery = function() { + $('body').css('overflow', 'hidden'); + + gallery_opened = true; + + handler = $("
").hide().appendTo('body').css('text-align', 'left'); + + $("
").click(close_gallery).appendTo(handler); + + images = $("").appendTo(handler); + toolbar = $("").appendTo(handler); + active = $("").appendTo(handler); + + active.on('click', function() { + close_gallery(); + }); + + $('img.post-image').parent().each(function() { + var thumb = $(this).find('img').attr('src'); + + var i = $('').appendTo(images); + i.attr('src', thumb); + i.attr('data-galid-th', $(this).attr('data-galid')); + + i.on('click', function(e) { + gallery_setimage($(this).attr('data-galid-th')); + }); + }); + + $("") + .click(close_gallery).appendTo(toolbar); + + $('body').on('keydown.gview', function(e) { + if (e.which == 39 || e.which == 40) { // right or down arrow + gallery_setimage(+1); + e.preventDefault(); + } + else if (e.which == 37 || e.which == 38) { // left or up arrow + gallery_setimage(-1); + e.preventDefault(); + } + }); + + handler.fadeIn(400); + }; + + var gallery_setimage = function(a) { + if (a == +1 || a == -1) { + var meth = (a == -1) ? 'prev' : 'next'; + a = $('#gallery_images img.active')[meth]().attr('data-galid-th'); + if (!a) return; + } + + $('#gallery_images img.active').removeClass('active'); + + var thumb = $('#gallery_images [data-galid-th="'+a+'"]'); + var elem = $('a[data-galid="'+a+'"]'); + + thumb.addClass('active'); + + var topscroll = thumb.position().top + images.scrollTop(); + topscroll -= images.height() / 2; + topscroll += thumb.height() / 2; + images.animate({'scrollTop': topscroll}, 300); + + var img = elem.attr('href'); + + active.find('img, video').fadeOut(200, function() { $(this).remove(); }); + + var i; + if (img.match(/player\.php/)) { + img = img.replace(/.*player\.php\?v=|&t=.*/g, ''); + } + if (img.match(/\.webm$|\.mp4$|\.ogv$/i)) { // We are handling video nao + i = $('

{% if not config.disable_images %} - {% trans %}Allowed file types:{% endtrans %} {{ config.allowed_ext|join(', ') }}{% if config.allowed_ext_files %}, {{ config.allowed_ext_files|join(', ') }}{% endif %}
+ {% trans %}Allowed file types:{% endtrans %} + {% if config.allowed_ext_op and not id %} + {{ config.allowed_ext_op|join(', ') }} + {% else %} + {{ config.allowed_ext|join(', ') }}{% if config.allowed_ext_files %}, {{ config.allowed_ext_files|join(', ') }}{% endif %} + {% endif %}
{% trans %}Max filesize is{% endtrans %} {{ config.max_filesize|filesize }}.
{% trans %}Max image dimensions are{% endtrans %} {{ config.max_height }} x {{ config.max_width }}.
{% set max_images = config.max_images %} {# workaround for "The text to be translated with "trans" can only contain references to simple variables" #} diff --git a/templates/post_thread_fileboard.html b/templates/post_thread_fileboard.html new file mode 100644 index 00000000..3f17907d --- /dev/null +++ b/templates/post_thread_fileboard.html @@ -0,0 +1,41 @@ +{% filter remove_whitespace %} +{# tabs and new lines will be ignored #} + +{# we are intentionally breaking the thread_ID convention: the jses need to handle this case differently #} + + + +
{{ post.id }} +{% include 'post/name.html' %} + {% include 'post/flag.html' %} +[{{ post.files[0].filename|e|bidi_cleanup }}] +{% if post.modifiers['tag'] %}[{{ post.modifiers['tag']|e }}]{% endif %} +{% include 'post/subject.html' %} + {% if post.sticky %} + {% if config.font_awesome %} + + {% else %} + Sticky + {% endif %} + {% endif %} + {% if post.locked %} + {% if config.font_awesome %} + + {% else %} + Locked + {% endif %} + {% endif %} + {% if post.bumplocked and (config.mod.view_bumplock < 0 or (post.mod and post.mod|hasPermission(config.mod.view_bumplock, board.uri))) %} + {% if config.font_awesome %} + + {% else %} + Bumplocked + {% endif %} + {% endif %} +{{ post.files[0].size|filesize }} +{% include 'post/time.html' %} +{{ post.omitted }} +{% include 'post/post_controls.html' %} + [{% trans %}Reply{% endtrans %}] + +{% endfilter %}