build($overboard)); file_write($overboard['uri'] . '/overboard.js', Element('themes/overboards/overboard.js', array())); } } } /** * Encapsulation of the theme's internals */ class overboards { private $settings; function __construct($settings) { $this->settings = $this->parseSettings($settings); } /** * Parse and validate configuration parameters passed from the UI */ private function parseSettings(&$settings) { foreach ($settings as &$overboard) { if (!is_int($overboard['thread_limit']) || $overboard['thread_limit'] < 1) { error('thread_limit must be an integer above 1.', true); } if (!is_array($overboard['exclude'])) { error('Exclude list must be array of strings.', true); } foreach ($overboard['exclude'] as &$board) { if (!is_string($board)){ error('Exclude list must be array of strings.', true); } } } return $settings; } /** * Obtain list of all threads from all non-excluded boards */ private function fetchThreads($overboard) { $query = ''; $boards = listBoards(true); foreach ($boards as $b) { if (in_array($b, $overboard['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 = '