From eb652322a274035f72aa9d622d0b33b54eb09c54 Mon Sep 17 00:00:00 2001 From: discomrade Date: Tue, 1 Jun 2021 02:14:48 -0200 Subject: [PATCH] Revert "Add SFW overboard and its catalog option" This reverts commit 24fcb96404e80b6d309c6d4696ccf348d2727b05. --- templates/themes/catalog/info.php | 7 - templates/themes/catalog/theme.php | 46 +---- templates/themes/sfwoverboard/info.php | 56 ------ templates/themes/sfwoverboard/semirand.js | 158 --------------- templates/themes/sfwoverboard/theme.php | 223 ---------------------- templates/themes/sfwoverboard/thumb.png | Bin 13085 -> 0 bytes 6 files changed, 1 insertion(+), 489 deletions(-) delete mode 100644 templates/themes/sfwoverboard/info.php delete mode 100644 templates/themes/sfwoverboard/semirand.js delete mode 100644 templates/themes/sfwoverboard/theme.php delete mode 100644 templates/themes/sfwoverboard/thumb.png diff --git a/templates/themes/catalog/info.php b/templates/themes/catalog/info.php index d971f2a9..67999c88 100644 --- a/templates/themes/catalog/info.php +++ b/templates/themes/catalog/info.php @@ -76,13 +76,6 @@ 'default' => false, 'comment' => 'Enable catalog for the Rand theme. This requires the Rand theme to be enabled.' ); - $theme['config'][] = Array( - 'title' => 'Enable SFW overboard catalog', - 'name' => 'enable_sfwoverboard', - 'type' => 'checkbox', - 'default' => false, - 'comment' => 'Enable catalog for the sfwoverboard theme. This requires the sfwoverboard theme to be enabled.' - ); $theme['config'][] = Array( 'title' => 'Use tooltipster', 'name' => 'use_tooltipster', diff --git a/templates/themes/catalog/theme.php b/templates/themes/catalog/theme.php index 3c89148f..0ec58259 100644 --- a/templates/themes/catalog/theme.php +++ b/templates/themes/catalog/theme.php @@ -92,14 +92,6 @@ { $b->buildRand(); } - // FIXME: Check that sfwoverboard is actually enabled - if ($settings['enable_sfwoverboard'] && ( - $action === 'all' || $action === 'post' || - $action === 'post-thread' || $action === 'post-delete' || $action === 'rebuild')) - { - $b->buildsfwoverboard(); - } - } // Wrap functions in a class so they don't interfere with normal Tinyboard operations @@ -305,43 +297,7 @@ $recent_posts = $this->generateRecentPosts($threads); $this->saveForBoard($randSettings['uri'], $recent_posts, - $config['root'] . $randSettings['uri'], true); - } - public function buildsfwoverboard() { - global $config; - print_err("Catalog.buildsfwoverboard"); - - $sfwoverboardSettings = themeSettings('sfwoverboard'); - $queries = array(); - $threads = array(); - - $exclusions = explode(' ', $sfwoverboardSettings['exclude']); - $boards = array_diff(listBoards(true), $exclusions); - - foreach ($boards as $b) { - if (array_key_exists($b, $this->threadsCache)) { - $threads = array_merge($threads, $this->threadsCache[$b]); - } else { - $queries[] = $this->buildThreadsQuery($b); - } - } - - // Fetch threads from boards that haven't beenp processed yet - if (!empty($queries)) { - $sql = implode(' UNION ALL ', $queries); - $res = query($sql) or error(db_error()); - $threads = array_merge($threads, $res->fetchAll(PDO::FETCH_ASSOC)); - } - - // Sort in bump order - usort($threads, function($a, $b) { - return strcmp($b['bump'], $a['bump']); - }); - // Generate data for the template - $recent_posts = $this->generateRecentPosts($threads); - - $this->saveForBoard($sfwoverboardSettings['uri'], $recent_posts, - $config['root'] . $sfwoverboardSettings['uri'], true); + $config['root'] . $randSettings['uri']); } /** diff --git a/templates/themes/sfwoverboard/info.php b/templates/themes/sfwoverboard/info.php deleted file mode 100644 index d641571b..00000000 --- a/templates/themes/sfwoverboard/info.php +++ /dev/null @@ -1,56 +0,0 @@ - 'SFW Overboard', - // Description (you can use Tinyboard markup here) - 'description' => 'An additional overboard, intended to list a different set of boards.', - 'version' => 'v0.1', - // Unique function name for building and installing whatever's necessary - 'build_function' => 'sfwoverboard_build', - 'install_callback' => 'sfwoverboard_install', - ); - - // Theme configuration - $theme['config'] = array( - array( - 'title' => 'Board name', - 'name' => 'title', - 'type' => 'text', - 'default' => 'SFW Overboard', - ), - array( - 'title' => 'Board URI', - 'name' => 'uri', - 'type' => 'text', - 'default' => '.', - 'comment' => '("mixed", for example)', - ), - array( - 'title' => 'Subtitle', - 'name' => 'subtitle', - 'type' => 'text', - 'comment' => '(%s = thread limit, for example "%s coolest threads")', - ), - array( - 'title' => 'Excluded boards', - 'name' => 'exclude', - 'type' => 'text', - 'comment' => '(space seperated)', - ), - array( - 'title' => 'Number of threads', - 'name' => 'thread_limit', - 'type' => 'text', - 'default' => '15', - ), - ); - - if (!function_exists('sfwoverboard_install')) { - function sfwoverboard_install($settings) { - if (!file_exists($settings['uri'])) { - @mkdir($settings['uri'], 0777) or error("Couldn't create {$settings['uri']}. Check permissions.", true); - } - } - } - diff --git a/templates/themes/sfwoverboard/semirand.js b/templates/themes/sfwoverboard/semirand.js deleted file mode 100644 index c07e8452..00000000 --- a/templates/themes/sfwoverboard/semirand.js +++ /dev/null @@ -1,158 +0,0 @@ -$(document).ready(function() { - var cachedPages = [], - loading = false, - timer = null; - - // Load data from HTML5 localStorage - var hiddenBoards = JSON.parse(localStorage.getItem('hiddenboards')); - - var storeHiddenBoards = function() { - localStorage.setItem('hiddenboards', JSON.stringify(hiddenBoards)); - }; - - // No board are hidden by default - if (!hiddenBoards) { - hiddenBoards = {}; - storeHiddenBoards(); - } - - // Hide threads from the same board and remember for next time - var onHideClick = function(e) { - e.preventDefault(); - var board = $(this).parent().next().data('board'), - threads = $('[data-board="'+board+'"]:not([data-cached="yes"])'), - btns = threads.prev().find('.threads-toggle'), - hrs = btns.next(); - - if (hiddenBoards[board]) { - threads.show(); - btns.find('.threads-toggle').html(_('(hide threads from this board)')); - hrs.hide(); - } else { - threads.hide(); - btns.html(_('(show threads from this board)')); - hrs.show(); - } - - hiddenBoards[board] = !hiddenBoards[board]; - storeHiddenBoards(); - }; - - // Add a hiding link and horizontal separator to each thread - var addHideButton = function() { - var board = $(this).next().data('board'), - // Create the link and separator - button = $('') - .click(onHideClick), - myHr = $('
'); - - // Insert them after the board name - $(this).append(' ').append(button).append(myHr); - - if (hiddenBoards[board]) { - button.html(_('(show threads from this board)')); - $(this).next().hide(); - } else { - button.html(_('(hide threads from this board)')); - myHr.hide(); - } - }; - - $('h2').each(addHideButton); - - var appendThread = function(elem, data) { - var boardLink = $('

/' + - data.board + '/

'); - - // Push the thread after the currently last one - $('div[id*="thread_"]').last() - .after(elem.data('board', data.board) - .data('cached', 'no') - .show()); - // Add the obligatory board link - boardLink.insertBefore(elem); - // Set up the hiding link - addHideButton.call(boardLink); - // Trigger an event to let the world know that we have a new thread aboard - $(document).trigger('new_post', elem); - }; - - var attemptLoadNext = function() { - if (!ukko_overflow.length) { - $('.pages').show().html(_('No more threads to display')); - return; - } - - var viewHeight = $(window).scrollTop() + $(window).height(), - pageHeight = $(document).height(); - // Keep loading deferred threads as long as we're close to the bottom of the - // page and there are threads remaining - while(viewHeight + 1000 > pageHeight && !loading && ukko_overflow.length > 0) { - // Take the first unloaded post - var post = ukko_overflow.shift(), - page = modRoot + post.board + '/' + post.page; - - var thread = $('div#thread_' + post.id + '[data-board="' + post.board + '"]'); - // Check that the thread hasn't been inserted yet - if (thread.length && thread.data('cached') !== 'yes') { - continue; - } - - // Check if we've already downloaded the index page on which this thread - // is located - if ($.inArray(page, cachedPages) !== -1) { - if (thread.length) { - appendThread(thread, post); - } - // Otherwise just load the page and cache its threads - } else { - // Make sure that no other thread does the job that we're about to do - loading = true; - $('.pages').show().html(_('Loading…')); - - // Retrieve the page from the server - $.get(page, function(data) { - cachedPages.push(page); - - // Cache each retrieved thread - $(data).find('div[id*="thread_"]').each(function() { - var thread_id = $(this).attr('id').replace('thread_', ''); - - // Check that this thread hasn't already been loaded somehow - if ($('div#thread_' + thread_id + '[data-board="' + - post.board + '"]').length) - { - return; - } - - // Hide the freshly loaded threads somewhere at the top - // of the page for now - $('form[name="postcontrols"]') - .prepend($(this).hide() - .data('cached', 'yes') - .data('data-board', post.board)); - }); - - // Find the current thread in the newly retrieved ones - thread = $('div#thread_' + post.id + '[data-board="' + - post.board + '"][data-cached="yes"]'); - - if (thread.length) { - appendThread(thread, post); - } - - // Release the lock - loading = false; - $('.pages').hide().html(''); - }); - break; - } - } - - clearTimeout(timer); - // Check again in one second - timer = setTimeout(attemptLoadNext, 1000); - }; - - attemptLoadNext(); -}); diff --git a/templates/themes/sfwoverboard/theme.php b/templates/themes/sfwoverboard/theme.php deleted file mode 100644 index 993e7fd0..00000000 --- a/templates/themes/sfwoverboard/theme.php +++ /dev/null @@ -1,223 +0,0 @@ -build()); - file_write($settings['uri'] . '/semirand.js', - Element('themes/sfwoverboard/semirand.js', array())); - } - } - - /** - * Encapsulation of the theme's internals - */ - class sfwoverboard { - private $settings; - - function __construct($settings) { - $this->settings = $this->parseSettings($settings); - } - - /** - * Parse and validate configuration parameters passed from the UI - */ - private function parseSettings($settings) { - if (!is_numeric($settings['thread_limit'])) - { - error('Invalid configuration parameters.', true); - } - - $settings['exclude'] = explode(' ', $settings['exclude']); - $settings['thread_limit'] = intval($settings['thread_limit']); - - if ($settings['thread_limit'] < 1) - { - error('Invalid configuration parameters.', true); - } - - return $settings; - } - - /** - * Obtain list of all threads from all non-excluded boards - */ - private function fetchThreads() { - $query = ''; - $boards = listBoards(true); - - foreach ($boards as $b) { - if (in_array($b, $this->settings['exclude'])) - continue; - // Threads are those posts that have no parent thread - $query .= "SELECT *, '$b' AS `board` FROM ``posts_$b`` " . - "WHERE `thread` IS NULL UNION ALL "; - } - - $query = preg_replace('/UNION ALL $/', 'ORDER BY `bump` DESC', $query); - $result = query($query) or error(db_error()); - - return $result->fetchAll(PDO::FETCH_ASSOC); - } - - /** - * Retrieve all replies to a given thread - */ - private function fetchReplies($board, $thread_id, $preview_count) { - $query = prepare("SELECT * FROM (SELECT * FROM ``posts_$board`` WHERE `thread` = :id ORDER BY `time` DESC LIMIT :limit) as - t ORDER BY t.time ASC"); - $query->bindValue(':id', $thread_id, PDO::PARAM_INT); - $query->bindValue(':limit', $preview_count, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - - return $query->fetchAll(PDO::FETCH_ASSOC); - } - - /** - * Retrieve count of images and posts in a thread - */ - private function fetchThreadCount($board, $thread_id, $preview_count) { - $query = prepare("SELECT SUM(t.num_files) as file_count, COUNT(t.id) as post_count FROM (SELECT * FROM ``posts_$board`` WHERE `thread` = :id ORDER BY `time` DESC LIMIT :offset , 18446744073709551615) as t;"); - $query->bindValue(':id', $thread_id, PDO::PARAM_INT); - $query->bindValue(':offset', $preview_count, PDO::PARAM_INT); - $query->execute() or error(db_error($query)); - - return $query->fetch(PDO::FETCH_ASSOC); - } - - /** - * Build the HTML of a single thread in the catalog - */ - private function buildOne($post, $mod = false) { - global $config; - - openBoard($post['board']); - $thread = new Thread($post, $mod ? '?/' : $config['root'], $mod); - // Number of replies to a thread that are displayed beneath it - $preview_count = $post['sticky'] ? $config['threads_preview_sticky'] : - $config['threads_preview']; - $replies = $this->fetchReplies($post['board'], $post['id'], $preview_count); - - $disp_replies = $replies; - foreach ($disp_replies as $reply) { - // Append the reply to the thread as it's being built - $thread->add(new Post($reply, $mod ? '?/' : $config['root'], $mod)); - } - - $threadCount = $this->fetchThreadCount($post['board'], $post['id'], $preview_count); - $thread->omitted = $threadCount['post_count']; - $thread->omitted_images = $threadCount['file_count']; - - // Board name and link - $html = '

/' . - $post['board'] . '/

'; - // The thread itself - $html .= $thread->build(true); - - return $html; - } - - /** - * Query the required information and generate the HTML - */ - public function build($mod = false) { - if (!isset($this->settings)) { - error('Theme is not configured properly.'); - } - - global $config; - - $html = ''; - $overflow = array(); - - // Fetch threads from all boards and chomp the first 'n' posts, depending - // on the setting - $threads = $this->fetchThreads(); - $total_count = count($threads); - // Top threads displayed on load - $top_threads = array_splice($threads, 0, $this->settings['thread_limit']); - // Number of processed threads by board - $counts = array(); - - // Output threads up to the specified limit - foreach ($top_threads as $post) { - if (array_key_exists($post['board'], $counts)) { - ++$counts[$post['board']]; - } else { - $counts[$post['board']] = 1; - } - - $html .= $this->buildOne($post, $mod); - } - - foreach ($threads as $post) { - if (array_key_exists($post['board'], $counts)) { - ++$counts[$post['board']]; - } else { - $counts[$post['board']] = 1; - } - - $page = 'index'; - $board_page = floor($counts[$post['board']] / $config['threads_per_page']); - if ($board_page > 0) { - $page = $board_page + 1; - } - $overflow[] = array( - 'id' => $post['id'], - 'board' => $post['board'], - 'page' => $page . '.html' - ); - } - - $html .= ''; - $html .= ''; - - return Element('index.html', array( - 'config' => $config, - 'board' => array( - 'dir' => $this->settings['uri'] . "/", - 'url' => $this->settings['uri'], - 'title' => $this->settings['title'], - 'subtitle' => str_replace('%s', $this->settings['thread_limit'], - strval(min($this->settings['subtitle'], $total_count))), - ), - 'no_post_form' => true, - 'body' => $html, - 'mod' => $mod, - 'boardlist' => createBoardlist($mod), - )); - } - - }; - - if (!function_exists('array_column')) { - /** - * Pick out values from subarrays by given key - */ - function array_column($array, $key) { - $result = []; - foreach ($array as $val) { - $result[] = $val[$key]; - } - return $result; - } - } - diff --git a/templates/themes/sfwoverboard/thumb.png b/templates/themes/sfwoverboard/thumb.png deleted file mode 100644 index eb616ef7d662bddc7b4fec8311ee52df55772aab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13085 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