- Added board-search.php with improved board directory searching.

- Added new functions to functions.php for fetching board meta.
- Added new styling for non-index page 12-col layouts.
- Modified templating for board directories.
- Moved CSS from the index page to CSS files.


Signed-off-by: 8n-tech <8n-tech@users.noreply.github.com>
This commit is contained in:
8n-tech 2015-04-13 14:24:55 +10:00
parent ee7c624517
commit 0ceb814ab3
7 changed files with 609 additions and 327 deletions

162
board-search.php Normal file
View File

@ -0,0 +1,162 @@
<?php
include "inc/functions.php";
$CanViewUnindexed = isset($mod["type"]) && $mod["type"] <= GlobalVolunteer;
/* The expected output of this page is JSON. */
$response = array();
/* Prefetch some information. */
$languages = array(
"en",
"es",
);
/* Determine search parameters from $_GET */
$search = array(
'lang' => false,
'nsfw' => true,
'tags' => false,
);
// Include NSFW boards?
if (isset( $_GET['nsfw'] )) {
$search['nsfw'] = (bool) $_GET['nsfw'];
}
// Include what language (if the language is not blank and we recognize it)?
if (isset( $_GET['lang'] ) && isset($languages[$search['lang']])) {
$search['lang'] = $_GET['lang'];
}
// Include what tag?
if (isset( $_GET['tags'] )) {
$search['tags'] = $_GET['tags'];
}
/* Search boards */
$boards = listBoards();
$response['boards'] = array();
// Loop through our available boards and filter out inapplicable ones based on standard filtering.
foreach ($boards as $board) {
// Checks we can do without looking at config.
if (
// Indexed, or we are staff,
( $CanViewUnindexed !== true && !$board['indexed'] )
// Not filtering NSFW, or board is SFW.
|| ( $search['nsfw'] !== true && $board['sfw'] != 1 )
) {
continue;
}
// Load board config.
$boardConfig = loadBoardConfig( $board['uri'] );
// Determine language/locale and tags.
$boardLang = strtolower( array_slice( explode( "_", $boardConfig['locale'] ?: "" ), 0 )[0] ); // en_US -> en OR en -> en
// Check against our config search options.
if ( $search['lang'] !== false && $search['lang'] != $boardLang ) {
continue;
}
$board['locale'] = $boardLang;
$response['boards'][ $board['uri'] ] = $board;
}
/* Tag Fetching */
// (We have do this even if we're not filtering by tags so that we know what each board's tags are)
// Fetch all board tags for our boards.
$boardTags = fetchBoardTags( array_keys( $response['boards'] ) );
// Loop through each board and determine if there are tag matches.
foreach ($response['boards'] as $boardUri => &$board) {
// If we are filtering by tag and there is no match, remove from the response.
if ( $search['tags'] !== false && ( !isset( $boardTags[ $boardUri ] ) || !in_array( $search['tags'], $boardTags[ $boardUri ] )) ) {
unset( $response['boards'][$boardUri] );
}
// If we aren't filtering / there is a match AND we have tags, set the tags.
else if ( isset( $boardTags[ $boardUri ] ) && $boardTags[ $boardUri ] ) {
$board['tags'] = $boardTags[ $boardUri ];
}
// Othrwise, just declare our tag array blank.
else {
$board['tags'] = array();
}
}
/* Activity Fetching */
$boardActivity = fetchBoardActivity( array_keys( $response['boards'] ) );
// Loop through each board and record activity to it.
// We will also be weighing and building a tag list.
foreach ($response['boards'] as $boardUri => &$board) {
$board['active'] = (int) $boardActivity['active'][ $boardUri ];
$board['pph'] = (int) $boardActivity['average'][ $boardUri ];
if (isset($board['tags']) && count($board['tags']) > 0) {
foreach ($board['tags'] as $tag) {
if (isset($response['tag'][$tag])) {
$response['tag'][$tag] += $board['active'];
}
else {
$response['tag'][$tag] = $board['active'];
}
}
}
}
// Get the top most popular tags.
if (count($response['tag']) > 0) {
// Sort by most active tags.
arsort( $response['tag'] );
// Get the first n most active tags.
$response['tag'] = array_splice( $response['tag'], 0, 200 );
$tagLightest = end( array_keys( $response['tag'] ) );
}
/* (Please) Respond */
$json = json_encode( $response );
// Error Handling
switch (json_last_error()) {
case JSON_ERROR_NONE:
$jsonError = false;
break;
case JSON_ERROR_DEPTH:
$jsonError = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$jsonError = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$jsonError = 'Unexpected control character found';
break;
case JSON_ERROR_SYNTAX:
$jsonError = 'Syntax error, malformed JSON';
break;
case JSON_ERROR_UTF8:
$jsonError = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$jsonError = 'Unknown error';
break;
}
if ($jsonError) {
$json = "{\"error\":\"{$jsonError}\"}";
}
// Successful output
echo $json;

View File

@ -122,7 +122,7 @@ $body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards"
$html = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on &infin;chan"));
$boards_top2k = $boards;
array_splice($boards_top2k, 2000);
array_splice($boards_top2k, 100);
$boards_top2k = array_values($boards_top2k);
$body = Element("8chan/boards-tags.html", array("config" => $config, "n_boards" => $n_boards, "t_boards" => $t_boards, "hidden_boards_total" => $hidden_boards_total, "total_posts" => $total_posts, "total_posts_hour" => $total_posts_hour, "boards" => $boards_top2k, "last_update" => date('r'), "uptime_p" => shell_exec('uptime -p'), 'tags' => $all_tags, 'top2k' => true));
$html_top2k = Element("page.html", array("config" => $config, "body" => $body, "title" => "Boards on &infin;chan"));
@ -133,10 +133,10 @@ if ($admin) {
foreach ($boards as $i => &$b) { unset($b['img']); }
file_write("boards.json", json_encode($boards));
file_write("tags.json", json_encode($all_tags));
foreach ($boards as $i => $b) {
foreach ($boards as $i => $b) {/*
if (in_array($b['uri'], $config['no_top_bar_boards'])) {
unset($boards[$i]);
}
}*/
unset($boards[$i]['img']);
}
@ -147,6 +147,5 @@ if ($admin) {
file_write("boards-top20.json", json_encode($boards));
file_write("boards.html", $html_top2k);
file_write("boards_full.html", $html);
echo 'Done';
}
echo $html;
}

View File

@ -516,9 +516,9 @@ function setupBoard($array) {
$board = array(
'uri' => $array['uri'],
'title' => $array['title'],
'subtitle' => $array['subtitle'],
'indexed' => $array['indexed'],
'public_logs' => $array['public_logs']
'subtitle' => isset($array['subtitle']) ? $array['subtitle'] : "",
'indexed' => isset($array['indexed']) ? $array['indexed'] : true,
'public_logs' => isset($array['public_logs']) ? $array['public_logs'] : true,
);
// older versions
@ -804,6 +804,84 @@ function listBoards($just_uri = false, $indexed_only = false) {
return $boards;
}
function loadBoardConfig( $uri ) {
$config = array(
"locale" => "en_US",
);
$configPath = "/{$uri}/config.php";
if (file_exists( $configPath ) && is_readable( $configPath )) {
include( $configPath );
}
// **DO NOT** use $config outside of this local scope.
// It's used by our global config array.
return $config;
}
function fetchBoardActivity( $uris ) {
$boardActivity = array();
/*
$uris = "\"" . implode( (array) $uris, "\",\"" ) . "\"";
$tagQuery = prepare("SELECT * FROM ``board_tags`` WHERE `uri` IN ({$uris})");
$tagQuery->execute() or error(db_error($tagQuery));
$tagResult = $tagQuery->fetchAll(PDO::FETCH_ASSOC);
if ($tagResult) {
foreach ($tagResult as $tagRow) {
$tag = $tagRow['tag'];
$tag = trim($tag);
$tag = strtolower($tag);
$tag = str_replace(['_', ' '], '-', $tag);
if (!isset($boardTags[ $tagRow['uri'] ])) {
$boardTags[ $tagRow['uri'] ] = array();
}
$boardTags[ $tagRow['uri'] ][] = htmlentities( utf8_encode( $tag ) );
}
}
*/
foreach( (array) $uris as $uri ) {
$random = rand( -1000, 1000 );
if( $random < 0 ) $random = 0;
$boardActivity['active'][ $uri ] = $random;
$boardActivity['average'][ $uri ] = $random * 72;
}
return $boardActivity;
}
function fetchBoardTags( $uris ) {
$boardTags = array();
$uris = "\"" . implode( (array) $uris, "\",\"" ) . "\"";
$tagQuery = prepare("SELECT * FROM ``board_tags`` WHERE `uri` IN ({$uris})");
$tagQuery->execute() or error(db_error($tagQuery));
$tagResult = $tagQuery->fetchAll(PDO::FETCH_ASSOC);
if ($tagResult) {
foreach ($tagResult as $tagRow) {
$tag = $tagRow['tag'];
$tag = trim($tag);
$tag = strtolower($tag);
$tag = str_replace(['_', ' '], '-', $tag);
if (!isset($boardTags[ $tagRow['uri'] ])) {
$boardTags[ $tagRow['uri'] ] = array();
}
$boardTags[ $tagRow['uri'] ][] = htmlentities( utf8_encode( $tag ) );
}
}
return $boardTags;
}
function until($timestamp) {
$difference = $timestamp - time();
switch(TRUE){

View File

@ -1,3 +1,6 @@
/* === GENERAL TAG SETTINGS === */
/* Page Layouts */
body {
background: #EEF2FF url('img/fade-blue.png') repeat-x 50% 0%;
color: black;
@ -8,6 +11,69 @@ body {
padding-right: 4px;
}
main,
aside,
section {
display: block;
margin: 0 auto;
width: 100%;
}
main {
max-width: 1110px;
}
/* Tables */
table {
margin: auto;
width: 100%;
}
table {
margin: auto;
width: 100%;
}
table tbody td {
margin: 0;
padding: 4px 15px 4px 4px;
text-align: left;
}
table thead th {
border: 1px solid #000333;
padding: 4px 15px 5px 5px;
background: #98E;
color: #000333;
text-align: left;
white-space: nowrap;
}
table tbody tr:nth-of-type( even ) {
background-color: #D6DAF0;
}
td.minimal,th.minimal {
width: 1%;
white-space: nowrap;
}
table.mod.config-editor {
font-size: 9pt;
width: 100%;
}
table.mod.config-editor td {
text-align: left;
padding: 5px;
border-bottom: 1px solid #98e;
}
table.mod.config-editor input[type="text"] {
width: 98%;
}
/* Uncategorized */
#post-form-outer {
text-align: center;
}
@ -538,50 +604,10 @@ hr {
clear: left;
}
div.boardlist {
color: #89A;
font-size: 9pt;
margin-top: 3px;
}
div.boardlist.bottom {
margin-top: 20px;
}
div.boardlist a {
text-decoration: none;
}
div.report {
color: #333;
}
table.modlog {
margin: auto;
width: 100%;
}
table.modlog tr td {
text-align: left;
margin: 0;
padding: 4px 15px 0 0;
}
table.modlog tr th {
text-align: left;
padding: 4px 15px 5px 5px;
white-space: nowrap;
}
table.modlog tr th {
background: #98E;
}
td.minimal,th.minimal {
width: 1%;
white-space: nowrap;
}
div.top_notice {
text-align: center;
margin: 5px auto;
@ -605,21 +631,6 @@ div.blotter {
text-align: center;
}
table.mod.config-editor {
font-size: 9pt;
width: 100%;
}
table.mod.config-editor td {
text-align: left;
padding: 5px;
border-bottom: 1px solid #98e;
}
table.mod.config-editor input[type="text"] {
width: 98%;
}
.desktop-style div.boardlist:not(.bottom) {
position: fixed;
top: 0;
@ -1012,7 +1023,6 @@ span.pln {
color:grey;
}
@media screen and (min-width: 768px) {
p.intro {
clear: none;
@ -1023,8 +1033,67 @@ span.pln {
}
}
/* threadwatcher */
/* === GENERAL CLASSES === */
.loading {
background: none;
background-color: none;
background-image: url('/static/infinity.gif');
background-position: center center;
background-repeat: no-repeat;
min-height: 76px;
min-width: 128px;
}
/* Responsive helpers */
.col {
box-sizing: border-box;
float: left;
}
.col-12 { width: 100%; }
.col-11 { width: 91.66666667%; }
.col-10 { width: 83.33333333%; }
.col-9 { width: 75%; }
.col-8 { width: 66.66666667%; }
.col-7 { width: 58.33333333%; }
.col-6 { width: 50%; }
.col-5 { width: 41.66666667%; }
.col-4 { width: 33.33333333%; }
.col-3 { width: 25%; }
.col-2 { width: 16.66666667%; }
.col-1 { width: 8.33333333%; }
.left-push {
float: left;
}
.right-push {
float: right;
}
/* Layout design */
.box {
background: #D6DAF0;
border: 1px solid #000333;
color: #000333;
margin: 0 0 12px 0;
}
.box-title {
background: #98E;
color: #000333;
font-size: 120%;
font-weight: bold;
padding: 4px 8px;
}
.box-content {
padding: 0 8px;
margin: 4px 0;
}
/* === SPECIFIC PAGES & FEATURES === */
/* threadwatcher */
#watchlist {
display: none;
max-height: 250px;
@ -1067,25 +1136,25 @@ div.mix {
}
/* Mona Font */
.aa {
font-family: Mona, "MS PGothic", " Pゴシック", sans-serif;
display: block!important;
font-size: 12pt;
}
.dx,.dy,.dz {
.dx,
.dy,
.dz {
width: 30px;
text-align: right;
display: inline-block;
}
/* Dice */
.dice-option table {
border: 1px dotted black;
margin: 0;
border-collapse: collapse;
}
.dice-option table td {
text-align: center;
border-left: 1px dotted black;
@ -1095,7 +1164,6 @@ div.mix {
}
/* Quick reply (why was most of this ever in the script?) */
#quick-reply {
position: fixed;
right: 5%;
@ -1261,3 +1329,109 @@ div.mix {
.dropzone .remove-btn:hover {
color: rgba(125, 125, 125, 1);
}
/* Board List */
div.boardlist {
margin-top: 3px;
color: #89A;
font-size: 9pt;
}
div.boardlist.bottom {
margin-top: 20px;
}
div.boardlist a {
text-decoration: none;
}
table.board-list-table {
display: table;
margin: -2px;
overflow: hidden;
table-layout: fixed;
}
table.board-list-table .board-meta {
padding-right: 4px;
width: 44px;
}
table.board-list-table .board-uri {
max-width: 196px;
}
table.board-list-table .board-title {
width: auto;
}
table.board-list-table .board-pph {
width: 55px;
}
table.board-list-table .board-max {
width: 90px;
}
table.board-list-table .board-unique {
width: 100px;
}
table.board-list-table .board-tags {
width: auto;
}
table.board-list-table div.board-cell {
max-width: 100%;
overflow: hidden;
}
aside.search-container {
}
aside.search-container .box {
margin-right: 12px;
}
.board-search {
padding: 0 0 8px 0;
margin: 8px;
border-bottom: 1px solid #000333;
}
.search-item {
margin: 8px 0;
}
.search-sfw {
cursor: pointer;
font-size: 110%;
line-height: 120%;
vertical-align: bottom;
}
#search-sfw-input {
margin: 0;
padding: 0;
transform: scale(1.20);
}
#search-lang-input,
#search-tag-input {
box-sizing: border-box;
font-size: 110%;
line-height: 120%;
vertical-align: top;
padding: 2px 0 2px 4px;
max-width: 100%;
min-width: 100%;
width: 100%:
}
ul.tag-list {
display: block;
list-style: none;
padding: 0;
margin: 0 8px;
}
ul.tag-list::after {
content: ' ';
display: block;
clear: both;
}
li.tag-item {
display: inline-block;
float: left;
font-size: 100%;
list-style: none;
margin: 0;
padding: 0 0.6em 0 0;
}

View File

@ -1,162 +1,90 @@
<style>
th.header {
background-image: url(/static/bg.gif);
cursor: pointer;
background-repeat: no-repeat;
background-position: center right;
padding-left: 20px;
margin-left: -1px;
}
th.headerSortUp {
background-image: url(/static/asc.gif);
}
th.headerSortDown {
background-image: url(/static/desc.gif);
}
table.modlog tr td.expand-td {
position: relative;
}
table.modlog tr td.expand-td:hover div{
background-color: #FFF;
position: absolute;
width: auto;
box-shadow: 0px 0px 5px #000;
padding: 0px 0 3px;
top: 5px;
left: 0;
z-index: 100;
}
.flag-eo {
background-image: url(/static/eo.png);
}
.flag-en {
background-image: url(/static/en.png);
}
.flag-jbo {
background-image: url(/static/jbo.png);
}
.uri {
overflow: hidden; width: 75px; white-space: nowrap;
}
.tags {
overflow: hidden; width: 150px; white-space: nowrap;
}
.board-name {
overflow: hidden; width: 200px; white-space: nowrap;
}
tr:nth-child(even) { background-color: #D6DAF0 }
</style>
<p style='text-align:center'>{% trans %}There are currently <strong>{{n_boards}}</strong> boards + <strong>{{hidden_boards_total}}</strong> unindexed boards = <strong>{{t_boards}}</strong> total boards. Site-wide, {{total_posts_hour}} posts have been made in the last hour, with {{total_posts}} being made on all active boards since October 23, 2013.{% endtrans %}</p>
{% if top2k %}
<p style='text-align:center'><a href="/boards_full.html">{% trans %}This list only shows the top 2000 boards. Until we can move tag searching onto the server side, click here for the full list.{% endtrans %}</a></p>
{% endif %}
<div style='height:100px; overflow-y:scroll' class="tags-container">
<strong class="tags-strong">Tags:</strong>&nbsp;
{% for tag, pop in tags %}
{% if pop > 1000 %}
<a class="tag" href="#" style="font-size:1.75em">{{ tag }}</a>
{% elseif pop > 500 %}
<a class="tag" href="#" style="font-size:1.5em">{{ tag }}</a>
{% elseif pop > 100 %}
<a class="tag" href="#" style="font-size:1.25em">{{ tag }}</a>
{% else %}
<a class="tag" href="#">{{ tag }}</a>
{% endif %}
{% endfor %}
</div>
<table class="modlog" style="width:auto"><thead>
<tr>
<th>B</th>
<th>{% trans %}Board{% endtrans %}</th>
<th>{% trans %}Title{% endtrans %}</th>
<th title="Posts per hour">{% trans %}PPH{% endtrans %}</th>
<th>{% trans %}Total posts{% endtrans %}</th>
<th title="Unique IPs to post in the last 72 hours">{% trans %}Active users{% endtrans %}</th>
<th>{% trans %}Tags{% endtrans %}</th>
</tr></thead><tbody>
{% for board in boards %}
<tr>
<td>{{ board.img|raw }} {% if board['sfw'] %}<img src="/static/sfw.png" title="Safe for work">{% else %}<img src="/static/nsfw.png" title="Not safe for work">{% endif %}</td>
<td><div class="uri"><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</div></td>
<td class="expand-td" title="Created {{board['time']}} ({{board['ago']}} ago)"><div class="board-name">{{ board['title'] }}</div></td>
<td style='text-align:right'>{{board['pph']}}</td>
<td style='text-align:right'>{{board['max']}}</td>
<td style='text-align:right'>{{board['uniq_ip']}}</td>
<td class="expand-td"><div class="tags">{% for tag in board.tags %}<span class="board-tag">{{ tag }}</span>&nbsp;{% endfor %}</div></td>
{% endfor %}
</tbody></table>
<p style='text-align:center'><em>Page last updated: {{last_update}}</em></p>
<p style='text-align:center'>{{uptime_p}} without interruption (read)</p>
<script>
$(function() {
$('table').tablesorter({sortList: [[5,1]],
textExtraction: function(node) {
childNode = node.childNodes[0];
if (!childNode) { return node.innerHTML; }
if (childNode.tagName == 'IMG') {
return childNode.getAttribute('class');
} else {
return (childNode.innerHTML ? childNode.innerHTML : childNode.textContent);
}
}
});
function filter_table(search) {
$("tbody>tr").css("display", "table-row");
if ($('#clear-selection').length === 0) {
$('.tags-strong').before('<a href="#" id="clear-selection">[clear selection]</a>');
$('#clear-selection').on('click', function(e){
e.preventDefault();
$("tbody>tr").css("display", "table-row");
window.location.hash = '';
});
}
window.location.hash = search;
var tags = $(".board-tag").filter(function() {
return $(this).text() === search;
});
$("tbody>tr").css("display", "none");
tags.parents("tr").css("display", "table-row");
}
$("a.tag").on("click", function(e) {
e.preventDefault();
filter_table($(this).text());
});
$('.tags-strong').before('<label>Filter tags: <input type="text" id="filter-tags"></label> ');
$('#filter-tags').on('keyup', function(e) {
$("a.tag").css("display", "inline-block");
var search = $(this).val();
if (!search) return;
var tags = $("a.tag").filter(function() {
return (new RegExp(search)).test($(this).text());
});
$("a.tag").css("display", "none");
tags.css("display", "inline-block");
});
if (window.location.hash) {
filter_table(window.location.hash.replace('#',''));
}
});
</script>
<main id="boardlist">
<section class="description box col col-12">
<h2 class="box-title">Global Statistics</h2>
<p class="box-content">{% trans %}There are currently <strong>{{t_boards}}</strong> total boards, <strong>{{hidden_boards_total}}</strong> of which are unindexed. Site-wide, {{total_posts_hour}} posts have been made in the last hour, with {{total_posts}} being made on all active boards since October 23, 2013.{% endtrans %}</p>
{% if uptime %}<p class="box-content">{{uptime_p}} without interruption</p>{% endif %}
<p class="box-content">This page last updated <time>{{last_update}}</time>.</p>
</section>
<div class="board-list">
<aside class="search-container col col-2">
<form id="search-form" class="box" method="post" target="/board-search.php">
<h2 class="box-title">Search</h2>
<div class="board-search box-content">
<label class="search-item search-sfw">
<input type="checkbox" id="search-sfw-input" checked="checked" />&nbsp;NSFW boards
</label>
<div class="search-item search-lang">
<select id="search-lang-input">
<optgroup label="Popular">
<option>All languages</option>
<option>English</option>
<option>Spanish</option>
</optgroup>
<optgroup label="All">
<option>Chinese</option>
</optgroup>
</select>
</div>
<div class="search-item search-tag">
<input type="text" id="search-tag-input" placeholder="Search tags..." />
</div>
<div class="search-item search-submit">
<button id="search-submit">Search</button>
</div>
</div>
<ul class="tag-list box-content">
{% for tag, pop in tags %}
<li class="tag-item">
<a class="tag-link" href="#">{{ tag }}</a>
</li>
{% endfor %}
</ul>
</form>
</aside>
<section class="board-list col col-10">
<table class="board-list-table">
<colgroup>
<col class="board-meta" />
<col class="board-uri" />
<col class="board-title" />
<col class="board-pph" />
<col class="board-max" />
<col class="board-unique" />
<col class="board-tags" />
</colgroup>
<thead>
<tr>
<th class="board-meta"></th>
<th class="board-uri">{% trans %}Board{% endtrans %}</th>
<th class="board-title">{% trans %}Title{% endtrans %}</th>
<th class="board-pph" title="Posts per hour">{% trans %}PPH{% endtrans %}</th>
<th class="board-max">{% trans %}Total posts{% endtrans %}</th>
<th class="board-unique" title="Unique IPs to post in the last 72 hours">{% trans %}Active users{% endtrans %}</th>
<th class="board-tags">{% trans %}Tags{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td class="board-meta">{{ board.img|raw }} {% if board['sfw'] %}<img src="/static/sfw.png" title="Safe for work">{% else %}<img src="/static/nsfw.png" title="Not safe for work">{% endif %}</td>
<td class="board-uri"><div class="board-list-wrapper uri"><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</div></td>
<td class="board-title"><div class="board-cell" title="Created {{board['time']}} ({{board['ago']}} ago)">{{ board['title'] }}</div></td>
<td class="board-pph"><div class="board-cell">{{board['pph']}}</td>
<td class="board-max"><div class="board-cell">{{board['max']}}</td>
<td class="board-unique"><div class="board-cell">{{board['uniq_ip']}}</td>
<td class="board-tags"><div class="board-cell">{% for tag in board.tags %}<span class="board-tag">{{ tag }}</span>&nbsp;{% endfor %}</div></td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
</div>
</main>

View File

@ -1,68 +1,36 @@
<style>
th.header {
background-image: url(/static/bg.gif);
cursor: pointer;
background-repeat: no-repeat;
background-position: center right;
padding-left: 20px;
margin-left: -1px;
}
th.headerSortUp {
background-image: url(/static/asc.gif);
}
th.headerSortDown {
background-image: url(/static/desc.gif);
}
.flag-eo {
background-image: url(/static/eo.png);
}
.flag-en {
background-image: url(/static/en.png);
}
.flag-jbo {
background-image: url(/static/jbo.png);
}
</style>
<p style='text-align:center'>{% trans %}There are currently <strong>{{n_boards}}</strong> boards + <strong>{{hidden_boards_total}}</strong> unindexed boards = <strong>{{t_boards}}</strong> total boards. Site-wide, {{total_posts_hour}} posts have been made in the last hour, with {{total_posts}} being made on all active boards since October 23, 2013.{% endtrans %}</p>
<table class="modlog" style="width:auto"><thead>
<tr>
<th>L</th>
<th>{% trans %}Board{% endtrans %}</th>
<th>{% trans %}Board title{% endtrans %}</th>
<th>{% trans %}Posts in last hour{% endtrans %}</th>
<th>{% trans %}Total posts{% endtrans %}</th>
<th>{% trans %}Unique IPs{% endtrans %}</th>
<th>{% trans %}Created{% endtrans %}</th>
</tr></thead><tbody>
{% for board in boards %}
<tr>
<td>{{ board.img|raw }}</td>
<td><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</td>
<td>{{ board['title'] }}</td>
<td style='text-align:right'>{{board['pph']}}</td>
<td style='text-align:right'>{{board['max']}}</td>
<td style='text-align:right'>{{board['uniq_ip']}}</td>
<td>{{board['time']}} ({{board['ago']}} ago)</td></tr>
{% endfor %}
</tbody></table>
<p style='text-align:center'><em>Page last updated: {{last_update}}</em></p>
<p style='text-align:center'>{{uptime_p}} without interruption</p>
<script>
$(function() {
$('table').tablesorter({sortList: [[5,1]],
textExtraction: function(node) {
childNode = node.childNodes[0];
if (!childNode) { return node.innerHTML; }
if (childNode.tagName == 'IMG') {
return childNode.getAttribute('class');
} else {
return (childNode.innerHTML ? childNode.innerHTML : childNode.textContent);
}
}
});
});
</script>
<div class="boardlist">
<p>{% trans %}There are currently <strong>{{n_boards}}</strong> boards + <strong>{{hidden_boards_total}}</strong> unindexed boards = <strong>{{t_boards}}</strong> total boards. Site-wide, {{total_posts_hour}} posts have been made in the last hour, with {{total_posts}} being made on all active boards since October 23, 2013.{% endtrans %}</p>
<table>
<thead>
<tr>
<th>L</th>
<th>{% trans %}Board{% endtrans %}</th>
<th>{% trans %}Board title{% endtrans %}</th>
<th>{% trans %}Posts in last hour{% endtrans %}</th>
<th>{% trans %}Total posts{% endtrans %}</th>
<th>{% trans %}Unique IPs{% endtrans %}</th>
<th>{% trans %}Created{% endtrans %}</th>
</tr>
</thead>
<tbody class="loading">
</tbody>
<tbody>
{% for board in boards %}
<tr>
<td>{{ board.img|raw }}</td>
<td><a href='/{{board['uri']}}/'>/{{board['uri']}}/</a>{{lock|raw}}</td>
<td>{{ board['title'] }}</td>
<td>{{board['pph']}}</td>
<td style='text-align:right'>{{board['max']}}</td>
<td style='text-align:right'>{{board['uniq_ip']}}</td>
<td>{{board['time']}} ({{board['ago']}} ago)</td>
</tr>
{% endfor %}
</tbody>
</table>
<p><em>Page last updated: {{last_update}}</em></p>
<p>{{uptime_p}} without interruption</p>
</div>

View File

@ -4,33 +4,6 @@
<meta charset="utf-8">
<title>∞chan</title>
<style type="text/css">
/* Responsive helpers */
.col {
float: left;
}
.col-12 { width: 100%; }
.col-11 { width: 91.66666667%; }
.col-10 { width: 83.33333333%; }
.col-9 { width: 75%; }
.col-8 { width: 66.66666667%; }
.col-7 { width: 58.33333333%; }
.col-6 { width: 50%; }
.col-5 { width: 41.66666667%; }
.col-4 { width: 33.33333333%; }
.col-3 { width: 25%; }
.col-2 { width: 16.66666667%; }
.col-1 { width: 8.33333333%; }
.left-push {
float: left;
}
.right-push {
float: right;
}
/* Main */
* {