This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

enhanced search

  • Loading branch information...
codemasher committed Sep 9, 2013
1 parent ce83c02 commit e097013db02077a146c8c6f9c0bedd71869627ae
Showing with 130 additions and 49 deletions.
  1. +52 −27 examples/gw2itemsearch.html
  2. +59 −17 examples/gw2itemsearch.php
  3. +19 −5 inc/utils.inc.php
@@ -19,7 +19,8 @@
#resultlist > div { white-space:pre; cursor:pointer; }
#resultlist > div:hover { background-color:rgba(0,0,0,0.1); }
#details { padding-left:0.5em; }
.highlight{ color:red; background-color:rgba(0,0,0,0.2);}
.highlight { color:red; background-color:rgba(0,0,0,0.2);}
.selectable { width:35em; }
/* pagination-links */
.p-links-container { line-height:1.25em; text-align:center; margin:1em 0; }
@@ -35,19 +36,49 @@
</style>
</head>
<body>
<form id="gw2_search">
<input id="search" type="search" placeholder="item search" /><br />
<form id="gw2_search">
<input id="search" name="search" type="search" placeholder="item search (name/id)" /><br />
<span>
<img src="https://chillerlan.net/img/flags/de.png"><input type="radio" name="search_lang" value="de" checked="checked" />
<img src="https://chillerlan.net/img/flags/en.png"><input type="radio" name="search_lang" value="en" />
<img src="https://chillerlan.net/img/flags/es.png"><input type="radio" name="search_lang" value="es" />
<img src="https://chillerlan.net/img/flags/fr.png"><input type="radio" name="search_lang" value="fr" />
<img src="https://chillerlan.net/img/flags/de.png"><input class="options" type="radio" name="lang" value="de" checked="checked" />
<img src="https://chillerlan.net/img/flags/en.png"><input class="options" type="radio" name="lang" value="en" />
<img src="https://chillerlan.net/img/flags/es.png"><input class="options" type="radio" name="lang" value="es" />
<img src="https://chillerlan.net/img/flags/fr.png"><input class="options" type="radio" name="lang" value="fr" />
</span>
</form>
<div id="results"></div>
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script>
<div>
Level: <input class="options" name="min-level" type="number" min="0" max="80" value="" placeholder="0" /> - <input class="options" name="max-level" type="number" min="0" max="80" value="" placeholder="80" />
<select class="options" name="type">
<option value="">-- type --</option>
<option value="Armor">Armor</option>
<option value="Back">Back</option>
<option value="Bag">Bag</option>
<option value="Consumable">Consumable</option>
<option value="Container">Container</option>
<option value="CraftingMaterial">CraftingMaterial</option>
<option value="Gathering">Gathering</option>
<option value="Gizmo">Gizmo</option>
<option value="MiniPet">MiniPet</option>
<option value="Tool">Tool</option>
<option value="Trinket">Trinket</option>
<option value="Trophy">Trophy</option>
<option value="UpgradeComponent">UpgradeComponent</option>
<option value="Weapon">Weapon</option>
</select>
<select class="options" name="rarity">
<option value="">-- rarity --</option>
<option value="Junk" style="color: #808080;">Junk</option>
<option value="Basic" style="color: #000000;">Basic</option>
<option value="Fine" style="color: #4f9dfe;">Fine</option>
<option value="Masterwork" style="color: #2dc50e;">Masterwork</option>
<option value="Rare" style="color: #f4c900;">Rare</option>
<option value="Exotic" style="color: #fda500;">Exotic</option>
<option value="Ascended" style="color: #fb3e8d;">Ascended</option>
<option value="Legendary" style="color: #800080;">Legendary</option>
</select>
</div>
</form>
<div id="results"></div>
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script>
<script>
$("gw2_search").observe("submit", function(e){
Event.stop(e);
@@ -58,11 +89,15 @@
itemSearch(1);
});
$$(".options").invoke("observe", "change", function(){
itemSearch(1);
});
function itemSearch(page){
new Ajax.Request("gw2itemsearch.php",{
method:"post",
// base64_encode the search string to not break umlauts, accented chars etc.
parameters:{search:Object.toJSON({str:base64_encode($("search").value), lang:$$("input[name=search_lang]:checked")[0].value, p:page})},
parameters:{search:Object.toJSON({str:base64_encode($F("search")), form:$("gw2_search").serialize(true), p:page})},
onSuccess:function(r){
$("results").update(r.responseText);
observeResults();
@@ -71,16 +106,16 @@
}
function observeResults(){
$$(".p-links").invoke("stopObserving").invoke("observe","click",function(e){
$$(".p-links").invoke("stopObserving").invoke("observe","click", function(e){
Event.stop(e);
itemSearch(this.dataset.page);
});
$("resultlist").childElements().invoke("stopObserving").invoke("observe", "click", function(){
new Ajax.Request("gw2itemsearch.php",{
parameters:{details:Object.toJSON({id:this.dataset.id, lang:$$("input[name=search_lang]:checked")[0].value})},
parameters:{details:Object.toJSON({id:this.dataset.id, lang:$$("input[name=lang]:checked")[0].value})},
onSuccess: function(r){
$("details").update(r.responseText);
$$(".selectable").invoke("stopObserving").invoke("observe","click",function(){
$$(".selectable").invoke("stopObserving").invoke("observe", "click", function(){
this.select();
});
}
@@ -107,32 +142,22 @@
//}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc, tmp_arr = [];
if(!data){
return data;
}
if(!data){return data;}
do{ // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);
bits = o1 << 16|o2 << 8|o3;
h1 = bits >> 18&0x3f;
h2 = bits >> 12&0x3f;
h3 = bits >> 6&0x3f;
h4 = bits&0x3f;
// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1)+b64.charAt(h2)+b64.charAt(h3)+b64.charAt(h4);
}
while(i < data.length);
enc = tmp_arr.join('');
var r = data.length%3;
return (r ? enc.slice(0, r-3) : enc)+'==='.slice(r || 3);
}
</script>
View
@@ -19,9 +19,8 @@
// search text
$str = utf8_encode(base64_decode($data['str']));
$search = '%'.mb_strtolower($str).'%';
// language colum names (whitelist)
// language column names (whitelist)
$cols = [
'de' => 'name_de',
'en' => 'name_en',
@@ -30,11 +29,38 @@
];
// determine the correct language column / else set a default
$col = array_key_exists($data['lang'], $cols) ? $cols[$data['lang']] : 'name_de';
$col = array_key_exists($data['form']['lang'], $cols) ? $cols[$data['form']['lang']] : 'name_de';
// build the WHERE clause for the SQL statement and add the corresponding values to an array
$values = [];
// if the search string is integer, use the id column else the item name (is_int() doesn't work here!)
$where = check_int($str) ? '`item_id` LIKE ?' : 'LOWER(`'.$col.'`) LIKE ?';
$values[] = '%'.(check_int($str) ? intval($str) : mb_strtolower($str)).'%';
if(isset($data['form']['type']) && !empty($data['form']['type'])){
$where .= ' AND `type` = ?';
$values[] = $data['form']['type'];
}
if(isset($data['form']['rarity']) && !empty($data['form']['rarity'])){
$where .= ' AND `rarity` = ?';
$values[] = $data['form']['rarity'];
}
if(isset($data['form']['min-level'])){
$where .= ' AND `level` >= ?';
$values[] = isset($data['form']['max-level']) && intval($data['form']['max-level']) < intval($data['form']['min-level']) ? intval($data['form']['max-level']) : intval($data['form']['min-level']);
}
if(isset($data['form']['max-level'])){
$where .= ' AND `level` <= ?';
$values[] = isset($data['form']['min-level']) && intval($data['form']['min-level']) > intval($data['form']['max-level']) ? intval($data['form']['min-level']) : intval($data['form']['max-level']);
}
// first count the results to create the pagination
$sql = 'SELECT COUNT(*) FROM `gw2_items` WHERE LOWER(`'.$col.'`) LIKE ?';
$count = sql_query($sql, [$search], false);
$sql = 'SELECT COUNT(*) FROM `gw2_items` WHERE '.$where;
$count = sql_query($sql, $values, false);
// determine the current page number
$page = (isset($data['p']) && !empty($data['p']) && intval($data['p']) > 0) ? intval($data['p']) : 1;
@@ -47,17 +73,30 @@
$sql_start = (empty($pagination['pages']) || !isset($pagination['pages'][$page])) ? 0 : $pagination['pages'][$page];
// get the item result
$sql = 'SELECT `'.$col.'`, `item_id`, `level` FROM `gw2_items` WHERE LOWER(`'.$col.'`) LIKE ? ORDER BY `gw2_items`.`'.$col.'` LIMIT '.$sql_start.', '.$limit;
$result = sql_query($sql, [$search]);
$sql = 'SELECT `'.$col.'`, `item_id`, `level` FROM `gw2_items` WHERE '.$where.' ORDER BY `gw2_items`.`'.(check_int($str) ? 'item_id' : $col).'` LIMIT '.$sql_start.', '.$limit;
$result = sql_query($sql, $values);
// process the result
$list = '';
if(count($result) > 0){
if(is_array($result) && count($result) > 0){
foreach($result as $row){
// TODO: improve text highlighting
$list .= '<div data-id="'.$row['item_id'].'">'.(mb_strlen($str) > 0 ? mb_eregi_replace('('.$str.')', '<span class="highlight">\\1</span>', $row[$col]) : $row[$col]).' ('.$row['level'].')</div>';
$list .= '<div data-id="'.$row['item_id'].'">';
if(mb_strlen($str) > 0){
if(check_int($str)){
$list .= preg_replace('/('.$str.')/U', '<span class="highlight">$1</span>', $row['item_id']).': ';
}
$list .= mb_eregi_replace('('.$str.')', '<span class="highlight">\\1</span>', $row[$col]);
}
else{
$list .= $row[$col];
}
$list .= ' ('.$row['level'].')</div>';
}
}
else{
$list .= 'no results';
}
header('Content-type: text/html;charset=utf-8;');
echo $pagination['pagination'].'
@@ -79,25 +118,28 @@
$response = '';
if(count($details) > 0){
$d = $details[0];
$n = "\n";
$flag_url = 'https://chillerlan.net/img/flags/';
$textarea = 'style="width:35em;" cols="20" rows="3" readonly="readonly" class="selectable"';
$icon_url = 'http://gw2wbot.darthmaim.de/icon/'.$d['signature'].'/'.$d['file_id'].'.png'; // https://render.guildwars2.com/file/
$textarea = 'cols="20" rows="3" readonly="readonly" class="selectable"';
// TODO: display item details, icon download, wikicode for recipes (or even full pages), list of ingredients
$response = '
<img src="'.$flag_url.'de.png"> <a href="http://wiki-de.guildwars2.com/wiki/'.str_replace(' ', '_', $d['name_de']).'" target="wiki-de">'.$d['name_de'].'</a><br />
<textarea '.$textarea.'>[[en:'.$d['name_en'].']]'."\n".'[[es:'.$d['name_es'].']]'."\n".'[[fr:'.$d['name_fr'].']]</textarea><br />
<textarea '.$textarea.'>[[en:'.$d['name_en'].']]'.$n.'[[es:'.$d['name_es'].']]'.$n.'[[fr:'.$d['name_fr'].']]</textarea><br />
<img src="'.$flag_url.'en.png"> <a href="http://wiki.guildwars2.com/wiki/'.str_replace(' ', '_', $d['name_en']).'" target="wiki-en">'.$d['name_en'].'</a><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'."\n".'[[es:'.$d['name_es'].']]'."\n".'[[fr:'.$d['name_fr'].']]</textarea><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'.$n.'[[es:'.$d['name_es'].']]'.$n.'[[fr:'.$d['name_fr'].']]</textarea><br />
<img src="'.$flag_url.'es.png"> <a href="http://wiki-es.guildwars2.com/wiki/'.str_replace(' ', '_', $d['name_es']).'" target="wiki-es">'.$d['name_es'].'</a><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'."\n".'[[en:'.$d['name_en'].']]'."\n".'[[fr:'.$d['name_fr'].']]</textarea><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'.$n.'[[en:'.$d['name_en'].']]'.$n.'[[fr:'.$d['name_fr'].']]</textarea><br />
<img src="'.$flag_url.'fr.png"> <a href="http://wiki-fr.guildwars2.com/wiki/'.str_replace(' ', '_', $d['name_fr']).'" target="wiki-fr">'.$d['name_fr'].'</a><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'."\n".'[[en:'.$d['name_en'].']]'."\n".'[[es:'.$d['name_es'].']]</textarea><br />
<textarea '.$textarea.'>[[de:'.$d['name_de'].']]'.$n.'[[en:'.$d['name_en'].']]'.$n.'[[es:'.$d['name_es'].']]</textarea><br />
chat code<br />
<input type="text" readonly="readonly" style="width:35em;" value="'.item_code($d['item_id']).'" class="selectable" /><br />
<input type="text" readonly="readonly" value="'.item_code($d['item_id']).'" class="selectable" /><br />
item id<br />
<input type="text" readonly="readonly" style="width:35em;" value="'.$d['item_id'].'" class="selectable" /><br />
<input type="text" readonly="readonly" value="'.$d['item_id'].'" class="selectable" /><br />
icon<br />
...<br />
<img src="'.$icon_url.'"><br />
<input type="text" readonly="readonly" value="'.$icon_url.'" class="selectable" /><br />
';
}
View
@@ -4,6 +4,19 @@
* created: 07.09.13
*/
/**
* Check if a string is really int
* @kink http://php.net/manual/function.is-int.php#87670
*
* @param $val
*
* @return bool
*/
function check_int($val){
return ($val !== true) && ((string)(int)$val) === ((string)$val);
}
/**
* Get the chatcode for an item
*
@@ -83,6 +96,7 @@ function pagination($total, $start, $limit, $request = null, $firstpage = 1, $ad
for($i = 0, $j = $firstpage; $i < $total; $i += $limit, $j++){
//...and build some links in between
$pages['pages'][$j] = $i;
$href = ($request === null ? '#' : $request.$j.$ext);
//current page
if($j == $currentpage){
$pages['links'] .= '<span class="p-links p-current">'.$j.'</span>';
@@ -92,27 +106,27 @@ function pagination($total, $start, $limit, $request = null, $firstpage = 1, $ad
else if($j >= ($firstpage+$adjacents) && $j < ($currentpage-$adjacents_mid)){
//jump-to links between start and current page
if($j >= floor((($firstpage+$currentpage+$adjacents_mid)-$adjacents)/2)-$adjacents_jump && $j <= floor((($firstpage+$currentpage+$adjacents_mid)-$adjacents)/2)+$adjacents_jump){
$pages['links'] .= '<a class="p-links p-middle" href="'.($request === null ? '#' : $request.$j.$ext).'" data-page="'.$j.'">'.$j.'</a>';
$pages['links'] .= '<a class="p-links p-middle" href="'.$href.'" data-page="'.$j.'">'.$j.'</a>';
}
//spaces in between - we can hide them by adding a nodisplay style ;)
# else{
# $pages['links'] .= '<a class="p-links p-middle hidden" href="'.($request === null ? '#' : $request.$j.$ext).'" data-page="'.$j.'">'.$j.'</a>';
# $pages['links'] .= '<a class="p-links p-middle hidden" href="'.$href.'" data-page="'.$j.'">'.$j.'</a>';
# }
}
//pages between current and last
else if($j > ($currentpage+$adjacents_mid) && $j <= ($lastpage-$adjacents)){
//jump-to links between current and last page
if($j >= ceil((($lastpage+$currentpage+$adjacents_mid)-$adjacents)/2)-$adjacents_jump && $j <= ceil((($lastpage+$currentpage+$adjacents_mid)-$adjacents)/2)+$adjacents_jump){
$pages['links'] .= '<a class="p-links p-middle" href="'.($request === null ? '#' : $request.$j.$ext).'" data-page="'.$j.'">'.$j.'</a>';
$pages['links'] .= '<a class="p-links p-middle" href="'.$href.'" data-page="'.$j.'">'.$j.'</a>';
}
//spaces in between
# else{
# $pages['links'] .= '<a class="p-links p-middle hidden" href="'.($request === null ? '#' : $request.$j.$ext).'" data-page="'.$j.'">'.$j.'</a>';
# $pages['links'] .= '<a class="p-links p-middle hidden" href="'.$href.'" data-page="'.$j.'">'.$j.'</a>';
# }
}
//first/last page & adjacents
else{
$pages['links'] .= '<a class="p-links" href="'.($request === null ? '#' : $request.$j.$ext).'" data-page="'.$j.'">'.$j.'</a>';
$pages['links'] .= '<a class="p-links" href="'.$href.'" data-page="'.$j.'">'.$j.'</a>';
}
}
$pages['pagination'] = $pages['total'] > 1 ? '<div class="p-links-container">'.$pages['prev'].$pages['links'].$pages['next'].'</div>' : '';

0 comments on commit e097013

Please sign in to comment.