Skip to content
This repository has been archived by the owner on Feb 3, 2018. It is now read-only.

Commit

Permalink
enhanced search
Browse files Browse the repository at this point in the history
  • Loading branch information
codemasher committed Sep 9, 2013
1 parent ce83c02 commit e097013
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 49 deletions.
79 changes: 52 additions & 27 deletions examples/gw2itemsearch.html
Expand Up @@ -19,7 +19,8 @@
#resultlist > div { white-space:pre; cursor:pointer; } #resultlist > div { white-space:pre; cursor:pointer; }
#resultlist > div:hover { background-color:rgba(0,0,0,0.1); } #resultlist > div:hover { background-color:rgba(0,0,0,0.1); }
#details { padding-left:0.5em; } #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 */ /* pagination-links */
.p-links-container { line-height:1.25em; text-align:center; margin:1em 0; } .p-links-container { line-height:1.25em; text-align:center; margin:1em 0; }
Expand All @@ -35,19 +36,49 @@
</style> </style>
</head> </head>
<body> <body>
<form id="gw2_search"> <form id="gw2_search">
<input id="search" type="search" placeholder="item search" /><br /> <input id="search" name="search" type="search" placeholder="item search (name/id)" /><br />
<span> <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/de.png"><input class="options" type="radio" name="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/en.png"><input class="options" type="radio" name="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/es.png"><input class="options" type="radio" name="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/fr.png"><input class="options" type="radio" name="lang" value="fr" />
</span> </span>
</form> <div>
<div id="results"></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">
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script> <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> <script>
$("gw2_search").observe("submit", function(e){ $("gw2_search").observe("submit", function(e){
Event.stop(e); Event.stop(e);
Expand All @@ -58,11 +89,15 @@
itemSearch(1); itemSearch(1);
}); });


$$(".options").invoke("observe", "change", function(){
itemSearch(1);
});

function itemSearch(page){ function itemSearch(page){
new Ajax.Request("gw2itemsearch.php",{ new Ajax.Request("gw2itemsearch.php",{
method:"post", method:"post",
// base64_encode the search string to not break umlauts, accented chars etc. // 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){ onSuccess:function(r){
$("results").update(r.responseText); $("results").update(r.responseText);
observeResults(); observeResults();
Expand All @@ -71,16 +106,16 @@
} }


function observeResults(){ function observeResults(){
$$(".p-links").invoke("stopObserving").invoke("observe","click",function(e){ $$(".p-links").invoke("stopObserving").invoke("observe","click", function(e){
Event.stop(e); Event.stop(e);
itemSearch(this.dataset.page); itemSearch(this.dataset.page);
}); });
$("resultlist").childElements().invoke("stopObserving").invoke("observe", "click", function(){ $("resultlist").childElements().invoke("stopObserving").invoke("observe", "click", function(){
new Ajax.Request("gw2itemsearch.php",{ 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){ onSuccess: function(r){
$("details").update(r.responseText); $("details").update(r.responseText);
$$(".selectable").invoke("stopObserving").invoke("observe","click",function(){ $$(".selectable").invoke("stopObserving").invoke("observe", "click", function(){
this.select(); this.select();
}); });
} }
Expand All @@ -107,32 +142,22 @@
//} //}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc, tmp_arr = []; 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 do{ // pack three octets into four hexets
o1 = data.charCodeAt(i++); o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++); o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++); o3 = data.charCodeAt(i++);

bits = o1 << 16|o2 << 8|o3; bits = o1 << 16|o2 << 8|o3;

h1 = bits >> 18&0x3f; h1 = bits >> 18&0x3f;
h2 = bits >> 12&0x3f; h2 = bits >> 12&0x3f;
h3 = bits >> 6&0x3f; h3 = bits >> 6&0x3f;
h4 = bits&0x3f; h4 = bits&0x3f;

// use hexets to index into b64, and append result to encoded string // 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); tmp_arr[ac++] = b64.charAt(h1)+b64.charAt(h2)+b64.charAt(h3)+b64.charAt(h4);
} }
while(i < data.length); while(i < data.length);

enc = tmp_arr.join(''); enc = tmp_arr.join('');

var r = data.length%3; var r = data.length%3;

return (r ? enc.slice(0, r-3) : enc)+'==='.slice(r || 3); return (r ? enc.slice(0, r-3) : enc)+'==='.slice(r || 3);
} }
</script> </script>
Expand Down
76 changes: 59 additions & 17 deletions examples/gw2itemsearch.php
Expand Up @@ -19,9 +19,8 @@


// search text // search text
$str = utf8_encode(base64_decode($data['str'])); $str = utf8_encode(base64_decode($data['str']));
$search = '%'.mb_strtolower($str).'%';


// language colum names (whitelist) // language column names (whitelist)
$cols = [ $cols = [
'de' => 'name_de', 'de' => 'name_de',
'en' => 'name_en', 'en' => 'name_en',
Expand All @@ -30,11 +29,38 @@
]; ];


// determine the correct language column / else set a default // 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 // first count the results to create the pagination
$sql = 'SELECT COUNT(*) FROM `gw2_items` WHERE LOWER(`'.$col.'`) LIKE ?'; $sql = 'SELECT COUNT(*) FROM `gw2_items` WHERE '.$where;
$count = sql_query($sql, [$search], false); $count = sql_query($sql, $values, false);


// determine the current page number // determine the current page number
$page = (isset($data['p']) && !empty($data['p']) && intval($data['p']) > 0) ? intval($data['p']) : 1; $page = (isset($data['p']) && !empty($data['p']) && intval($data['p']) > 0) ? intval($data['p']) : 1;
Expand All @@ -47,17 +73,30 @@
$sql_start = (empty($pagination['pages']) || !isset($pagination['pages'][$page])) ? 0 : $pagination['pages'][$page]; $sql_start = (empty($pagination['pages']) || !isset($pagination['pages'][$page])) ? 0 : $pagination['pages'][$page];


// get the item result // 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; $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, [$search]); $result = sql_query($sql, $values);


// process the result // process the result
$list = ''; $list = '';
if(count($result) > 0){ if(is_array($result) && count($result) > 0){
foreach($result as $row){ foreach($result as $row){
// TODO: improve text highlighting // 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;'); header('Content-type: text/html;charset=utf-8;');
echo $pagination['pagination'].' echo $pagination['pagination'].'
Expand All @@ -79,25 +118,28 @@
$response = ''; $response = '';
if(count($details) > 0){ if(count($details) > 0){
$d = $details[0]; $d = $details[0];
$n = "\n";
$flag_url = 'https://chillerlan.net/img/flags/'; $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 // TODO: display item details, icon download, wikicode for recipes (or even full pages), list of ingredients
$response = ' $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 /> <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 /> <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 /> <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 /> <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 /> 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 /> 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 /> icon<br />
...<br /> <img src="'.$icon_url.'"><br />
<input type="text" readonly="readonly" value="'.$icon_url.'" class="selectable" /><br />
'; ';
} }


Expand Down
24 changes: 19 additions & 5 deletions inc/utils.inc.php
Expand Up @@ -4,6 +4,19 @@
* created: 07.09.13 * 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 * Get the chatcode for an item
* *
Expand Down Expand Up @@ -83,6 +96,7 @@ function pagination($total, $start, $limit, $request = null, $firstpage = 1, $ad
for($i = 0, $j = $firstpage; $i < $total; $i += $limit, $j++){ for($i = 0, $j = $firstpage; $i < $total; $i += $limit, $j++){
//...and build some links in between //...and build some links in between
$pages['pages'][$j] = $i; $pages['pages'][$j] = $i;
$href = ($request === null ? '#' : $request.$j.$ext);
//current page //current page
if($j == $currentpage){ if($j == $currentpage){
$pages['links'] .= '<span class="p-links p-current">'.$j.'</span>'; $pages['links'] .= '<span class="p-links p-current">'.$j.'</span>';
Expand All @@ -92,27 +106,27 @@ function pagination($total, $start, $limit, $request = null, $firstpage = 1, $ad
else if($j >= ($firstpage+$adjacents) && $j < ($currentpage-$adjacents_mid)){ else if($j >= ($firstpage+$adjacents) && $j < ($currentpage-$adjacents_mid)){
//jump-to links between start and current page //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){ 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 ;) //spaces in between - we can hide them by adding a nodisplay style ;)
# else{ # 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 //pages between current and last
else if($j > ($currentpage+$adjacents_mid) && $j <= ($lastpage-$adjacents)){ else if($j > ($currentpage+$adjacents_mid) && $j <= ($lastpage-$adjacents)){
//jump-to links between current and last page //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){ 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 //spaces in between
# else{ # 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 //first/last page & adjacents
else{ 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>' : ''; $pages['pagination'] = $pages['total'] > 1 ? '<div class="p-links-container">'.$pages['prev'].$pages['links'].$pages['next'].'</div>' : '';
Expand Down

0 comments on commit e097013

Please sign in to comment.