- board-search.php Now properly calculates tag weight.

- boards.php Passes $search parameters into Twig.
- js/board-reictory.js Stores last search parameters and handles tag click events.
- Twig now passes old search parameters into the search form.
- Tags now link in such a way that they will preserve form data and other tags when clicked in a browser without JavaScript.

Signed-off-by: 8n-tech <8n-tech@users.noreply.github.com>
This commit is contained in:
8n-tech 2015-04-16 05:46:48 +10:00
parent 67bab31510
commit ec90c96459
6 changed files with 139 additions and 45 deletions

View File

@ -25,6 +25,7 @@ $languages = array(
$search = array( $search = array(
'lang' => false, 'lang' => false,
'nsfw' => true, 'nsfw' => true,
'page' => 0,
'tags' => false, 'tags' => false,
'time' => ( (int)( time() / 3600 ) * 3600 ) - 3600, 'time' => ( (int)( time() / 3600 ) * 3600 ) - 3600,
'title' => false, 'title' => false,
@ -37,6 +38,15 @@ if (isset( $_GET['sfw'] ) && $_GET['sfw'] != "") {
$search['nsfw'] = !$_GET['sfw']; $search['nsfw'] = !$_GET['sfw'];
} }
// Bringing up more results
if (isset( $_GET['page'] ) && $_GET['page'] != "") {
$search['page'] = (int) $_GET['page'];
if ($search['page'] < 0) {
$search['page'] = 0;
}
}
// Include what language (if the language is not blank and we recognize it)? // Include what language (if the language is not blank and we recognize it)?
if (isset( $_GET['lang'] ) && $_GET['lang'] != "" && isset($languages[$search['lang']])) { if (isset( $_GET['lang'] ) && $_GET['lang'] != "" && isset($languages[$search['lang']])) {
$search['lang'] = $_GET['lang']; $search['lang'] = $_GET['lang'];
@ -44,7 +54,8 @@ if (isset( $_GET['lang'] ) && $_GET['lang'] != "" && isset($languages[$search['l
// Include what tag? // Include what tag?
if (isset( $_GET['tags'] ) && $_GET['tags'] != "") { if (isset( $_GET['tags'] ) && $_GET['tags'] != "") {
$search['tags'] = $_GET['tags']; $search['tags'] = explode( " ", $_GET['tags'] );
$search['tags'] = array_splice( $search['tags'], 0, 5 );
} }
// What time range? // What time range?
@ -73,6 +84,31 @@ foreach ($boards as $board) {
continue; continue;
} }
// Are we searching by title?
if ($search['title'] !== false) {
// This checks each component of the board's identity against our search terms.
// The weight determines order.
// "left" would match /leftypol/ and /nkvd/ which has /leftypol/ in the title.
// /leftypol/ would always appear above it but it would match both.
if (strpos("/{$board['uri']}/", $search['title']) !== false) {
$board['weight'] = 30;
}
else if (strpos($board['title'], $search['title']) !== false) {
$board['weight'] = 20;
}
else if (strpos($board['subtitle'], $search['title']) !== false) {
$board['weight'] = 10;
}
else {
continue;
}
unset( $boardTitleString );
}
else {
$board['weight'] = 0;
}
// Load board config. // Load board config.
$boardConfig = loadBoardConfig( $board['uri'] ); $boardConfig = loadBoardConfig( $board['uri'] );
@ -101,7 +137,7 @@ $boardTags = fetchBoardTags( array_keys( $response['boards'] ) );
// Loop through each board and determine if there are tag matches. // Loop through each board and determine if there are tag matches.
foreach ($response['boards'] as $boardUri => &$board) { foreach ($response['boards'] as $boardUri => &$board) {
// If we are filtering by tag and there is no match, remove from the response. // 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 ] )) ) { if ( $search['tags'] !== false && ( !isset( $boardTags[ $boardUri ] ) || count(array_intersect($search['tags'], $boardTags[ $boardUri ])) !== count($search['tags']) ) ) {
unset( $response['boards'][$boardUri] ); unset( $response['boards'][$boardUri] );
} }
// If we aren't filtering / there is a match AND we have tags, set the tags. // If we aren't filtering / there is a match AND we have tags, set the tags.
@ -145,13 +181,16 @@ foreach ($response['boards'] as $boardUri => &$board) {
// Sort boards by their popularity, then by their total posts. // Sort boards by their popularity, then by their total posts.
$boardActivityValues = array(); $boardActivityValues = array();
$boardTotalPostsValues = array(); $boardTotalPostsValues = array();
$boardWeightValues = array();
foreach ($response['boards'] as $boardUri => &$board) { foreach ($response['boards'] as $boardUri => &$board) {
$boardActivityValues[$boardUri] = (int) $board['active']; $boardActivityValues[$boardUri] = (int) $board['active'];
$boardTotalPostsValues[$boardUri] = (int) $board['posts_total']; $boardTotalPostsValues[$boardUri] = (int) $board['posts_total'];
$boardWeightValues[$boardUri] = (int) $board['weight'];
} }
array_multisort( array_multisort(
$boardWeightValues, SORT_DESC, SORT_NUMERIC, // Sort by weight
$boardActivityValues, SORT_DESC, SORT_NUMERIC, // Sort by number of active posters $boardActivityValues, SORT_DESC, SORT_NUMERIC, // Sort by number of active posters
$boardTotalPostsValues, SORT_DESC, SORT_NUMERIC, // Then, sort by total number of posts $boardTotalPostsValues, SORT_DESC, SORT_NUMERIC, // Then, sort by total number of posts
$response['boards'] $response['boards']
@ -159,8 +198,8 @@ array_multisort(
$boardLimit = $search['index'] ? 50 : 100; $boardLimit = $search['index'] ? 50 : 100;
$response['omitted'] = $search['index'] ? 0 : count( $response['boards'] ) - $boardLimit; $response['omitted'] = count( $response['boards'] ) - $boardLimit;
$response['boards'] = array_splice( $response['boards'], 0, $boardLimit ); $response['boards'] = array_splice( $response['boards'], $search['page'], $boardLimit );
$response['order'] = array_keys( $response['boards'] ); $response['order'] = array_keys( $response['boards'] );
@ -216,8 +255,13 @@ if (count($response['tags']) > 0) {
} }
foreach ($tagUsage['users'] as $tagName => $tagUsers) { foreach ($tagUsage['users'] as $tagName => $tagUsers) {
$weightDeparture = abs( $tagUsers - $tagsAvgUsers ); if ($weightDepartureFurthest != 0) {
$response['tagWeight'][$tagName] = 75 + round( 100 * ( $weightDeparture / $weightDepartureFurthest ), 0); $weightDeparture = abs( $tagUsers - $tagsAvgUsers );
$response['tagWeight'][$tagName] = 75 + round( 100 * ( $weightDeparture / $weightDepartureFurthest ), 0);
}
else {
$response['tagWeight'][$tagName] = 0;
}
} }
} }

View File

@ -36,6 +36,16 @@ $boards_omitted = (int) $searchJson['omitted'];
$posts_hour = number_format( fetchBoardActivity(), 0 ); $posts_hour = number_format( fetchBoardActivity(), 0 );
$posts_total = number_format( $boardResult['posts_total'], 0 ); $posts_total = number_format( $boardResult['posts_total'], 0 );
// This incredibly stupid looking chunk of code builds a query string using existing information.
// It's used to make clickable tags for users without JavaScript for graceful degredation.
// Because of how it orders tags, what you end up with is a prefix that always ends in tags=x+
// ?tags= or ?sfw=1&tags= or ?title=foo&tags=bar+ - etc
$tagQueryGet = $_GET;
$tagQueryTags = isset($tagQueryGet['tags']) ? $tagQueryGet['tags'] : "";
unset($tagQueryGet['tags']);
$tagQueryGet['tags'] = $tagQueryTags;
$tag_query = "?" . http_build_query( $tagQueryGet ) . ($tagQueryTags != "" ? "+" : "");
/* Create and distribute page */ /* Create and distribute page */
$config['additional_javascript'] = array( $config['additional_javascript'] = array(
'js/jquery.min.js', 'js/jquery.min.js',
@ -43,19 +53,24 @@ $config['additional_javascript'] = array(
); );
$boardsHTML = Element("8chan/boards-table.html", array( $boardsHTML = Element("8chan/boards-table.html", array(
"config" => $config, "config" => $config,
"boards" => $boards, "boards" => $boards,
"tag_query" => $tag_query,
) )
); );
$tagsHTML = Element("8chan/boards-tags.html", array( $tagsHTML = Element("8chan/boards-tags.html", array(
"config" => $config, "config" => $config,
"tags" => $tags, "tags" => $tags,
"tag_query" => $tag_query,
) )
); );
$searchHTML = Element("8chan/boards-search.html", array( $searchHTML = Element("8chan/boards-search.html", array(
"config" => $config, "config" => $config,
"search" => $searchJson['search'],
"boards_total" => $boards_total, "boards_total" => $boards_total,
"boards_public" => $boards_public, "boards_public" => $boards_public,

View File

@ -22,6 +22,8 @@
'search-tag' : "#search-tag-input", 'search-tag' : "#search-tag-input",
'search-title' : "#search-title-input", 'search-title' : "#search-title-input",
'search-submit' : "#search-submit", 'search-submit' : "#search-submit",
'tag-link' : ".tag-link"
}, },
// HTML Templates for dynamic construction // HTML Templates for dynamic construction
@ -50,6 +52,8 @@
} }
}, },
lastSearch : {},
bind : { bind : {
form : function() { form : function() {
var selectors = boardlist.options.selector; var selectors = boardlist.options.selector;
@ -71,11 +75,17 @@
'searchSubmit' : $searchSubmit 'searchSubmit' : $searchSubmit
}; };
if ($search.length > 0) { if ($search.length > 0) {
// Bind form events. // Bind form events.
$search.on( 'submit', searchForms, boardlist.events.searchSubmit ); boardlist.$boardlist
$searchSubmit.prop( 'disabled', false ).on( 'click', searchForms, boardlist.events.searchSubmit ); // Tag click
.on( 'click', selectors['tag-link'], searchForms, boardlist.events.tagClick )
// Form Submission
.on( 'submit', selectors['search'], searchForms, boardlist.events.searchSubmit )
// Submit click
.on( 'click', selectors['search-submit'], searchForms, boardlist.events.searchSubmit );
$searchSubmit.prop( 'disabled', false );
} }
} }
}, },
@ -83,6 +93,7 @@
build : { build : {
boardlist : function(data) { boardlist : function(data) {
boardlist.build.boards(data['boards'], data['order']); boardlist.build.boards(data['boards'], data['order']);
boardlist.build.lastSearch(data['search']);
boardlist.build.tags(data['tags']); boardlist.build.tags(data['tags']);
}, },
@ -101,12 +112,10 @@
boardlist.build.board( row, col ).appendTo( $row ); boardlist.build.board( row, col ).appendTo( $row );
} ); } );
if( index >= 100 ) return false;
$row.appendTo( $body ); $row.appendTo( $body );
} ); } );
}, },
board : function( row, col ) { board : function(row, col) {
var $col = $(col), var $col = $(col),
column = $col.attr('data-column'), column = $col.attr('data-column'),
value = row[column] value = row[column]
@ -150,10 +159,10 @@
return $cell; return $cell;
}, },
boardcell : { boardcell : {
'meta' : function( row, value ) { 'meta' : function(row, value) {
return $( boardlist.options.template['board-datum-lang'] ).text( row['locale'] ); return $( boardlist.options.template['board-datum-lang'] ).text( row['locale'] );
}, },
'uri' : function( row, value ) { 'uri' : function(row, value) {
var $link = $( boardlist.options.template['board-datum-uri'] ), var $link = $( boardlist.options.template['board-datum-uri'] ),
$sfw = $( boardlist.options.template['board-datum-' + (row['sfw'] == 1 ? "sfw" : "nsfw")] ); $sfw = $( boardlist.options.template['board-datum-' + (row['sfw'] == 1 ? "sfw" : "nsfw")] );
@ -172,8 +181,18 @@
} }
}, },
tags : function(data) { lastSearch : function(search) {
return boardlist.lastSearch = {
'lang' : search.lang === false ? "" : search.lang,
'page' : search.page,
'tags' : search.tags === false ? "" : search.tags.join(" "),
'time' : search.time,
'title' : search.title === false ? "" : search.title,
'sfw' : search.nsfw ? 0 : 1
};
},
tags : function(data) {
} }
}, },
@ -181,32 +200,49 @@
searchSubmit : function(event) { searchSubmit : function(event) {
event.preventDefault(); event.preventDefault();
var $boardlist = event.data.boardlist, boardlist.submit( {
$boardbody = $( boardlist.options.selector['board-body'], $boardlist ), 'lang' : event.data.searchLang.val(),
$boardload = $( boardlist.options.selector['board-loading'], $boardlist ); 'tags' : event.data.searchTag.val(),
'title' : event.data.searchTitle.val(),
'sfw' : event.data.searchSfw.prop('checked') ? 1 : 0
} );
$boardbody.html(""); return false;
$boardload.show(); },
$.get( tagClick : function(event) {
"/board-search.php", event.preventDefault();
{
'lang' : event.data.searchLang.val(), var $this = $(this),
'tags' : event.data.searchTag.val(), $input = $( boardlist.options.selector['search-tag'] );
//'time' : event.data.searchTag.val(),
'title' : event.data.searchTitle.val(), $input
'sfw' : event.data.searchSfw.prop('checked') ? 1 : 0 .val( ( $input.val() + " " + $this.text() ).replace(/\s+/g, " ").trim() )
}, .trigger( 'change' )
function(data) { .focus();
$boardload.hide();
boardlist.build.boardlist( $.parseJSON(data) );
}
);
return false; return false;
} }
}, },
submit : function( parameters ) {
var $boardlist = boardlist.$boardlist,
$boardbody = $( boardlist.options.selector['board-body'], $boardlist ),
$boardload = $( boardlist.options.selector['board-loading'], $boardlist );
$boardbody.html("");
$boardload.show();
$.get(
"/board-search.php",
parameters,
function(data) {
$boardload.hide();
boardlist.build.boardlist( $.parseJSON(data) );
}
);
},
init : function( target ) { init : function( target ) {
if (typeof target !== "string") { if (typeof target !== "string") {
target = boardlist.options.selector.boardlist; target = boardlist.options.selector.boardlist;
@ -217,7 +253,6 @@
if ($boardlist.length > 0 ) { if ($boardlist.length > 0 ) {
$( boardlist.options.selector['board-loading'], $boardlist ).hide(); $( boardlist.options.selector['board-loading'], $boardlist ).hide();
boardlist.$boardlist = $boardlist; boardlist.$boardlist = $boardlist;
boardlist.bind.form(); boardlist.bind.form();
} }

View File

@ -8,16 +8,16 @@
<div class="board-list"> <div class="board-list">
<aside class="search-container col col-2"> <aside class="search-container col col-2">
<form id="search-form" class="box" method="get" target="/board-search.php"> <form id="search-form" class="box" method="get" action="/boards.php">
<h2 class="box-title">Search</h2> <h2 class="box-title">Search</h2>
<div class="board-search box-content"> <div class="board-search box-content">
<label class="search-item search-sfw"> <label class="search-item search-sfw">
<input type="checkbox" id="search-sfw-input" name="sfw" value="1" />&nbsp;Hide NSFW boards <input type="checkbox" id="search-sfw-input" name="sfw" value="1" {% if not search.nsfw %}checked="checked"{% endif %} />&nbsp;Hide NSFW boards
</label> </label>
<div class="search-item search-title"> <div class="search-item search-title">
<input type="text" id="search-title-input" name="title" name="title" value="" placeholder="Search titles..." /> <input type="text" id="search-title-input" name="title" name="title" value="{{search.title}}" placeholder="Search titles..." />
</div> </div>
<div class="search-item search-lang"> <div class="search-item search-lang">
@ -34,7 +34,7 @@
</div> </div>
<div class="search-item search-tag"> <div class="search-item search-tag">
<input type="text" id="search-tag-input" name="tags" value="" placeholder="Search tags..." /> <input type="text" id="search-tag-input" name="tags" value="{{ search.tags|join(' ') }}" placeholder="Search tags..." />
</div> </div>
<div class="search-item search-submit"> <div class="search-item search-submit">

View File

@ -9,6 +9,6 @@
<td class="board-pph"><div class="board-cell">{{board['pph']}}</td> <td class="board-pph"><div class="board-cell">{{board['pph']}}</td>
<td class="board-max"><div class="board-cell">{{board['posts_total']}}</td> <td class="board-max"><div class="board-cell">{{board['posts_total']}}</td>
<td class="board-unique"><div class="board-cell">{{board['active']}}</td> <td class="board-unique"><div class="board-cell">{{board['active']}}</td>
<td class="board-tags"><div class="board-cell">{% for tag in board.tags %}<a class="tag-link" href="#">{{ tag }}</a>{% endfor %}</div></td> <td class="board-tags"><div class="board-cell">{% for tag in board.tags %}<a class="tag-link" href="{{ tag_query }}{{ tag }}">{{ tag }}</a>{% endfor %}</div></td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -1,5 +1,5 @@
{% for tag, weight in tags %} {% for tag, weight in tags %}
<li class="tag-item"> <li class="tag-item">
<a class="tag-link" href="#" style="font-size: {{weight}}%;">{{tag}}</a> <a class="tag-link" href="{{ tag_query }}{{ tag }}" style="font-size: {{weight}}%;">{{tag}}</a>
</li> </li>
{% endfor %} {% endfor %}