Completed implementation of search v2. It is not posible to find discarded products via search at this time.
This commit is contained in:
parent
f6b8258a14
commit
eb1987d83a
@ -261,8 +261,10 @@
|
||||
|
||||
¤¤ tag ¤¤
|
||||
<p>
|
||||
<span class="tag"
|
||||
data-name="¤tag¤">
|
||||
<span class="tag">
|
||||
<input type="hidden"
|
||||
name="tag[]"
|
||||
value="¤tag¤" />
|
||||
¤tag¤
|
||||
<a class="tagremove"
|
||||
onClick="JavaScript:removeTag(event)">
|
||||
@ -578,55 +580,41 @@
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
¤¤ search_help ¤¤
|
||||
<p>
|
||||
Sökfunktionen matchar normalt på låntagares namn och användarnamn,
|
||||
samt artiklars namn. Alla ord måste matcha för att generera en
|
||||
träff. Flera sökningar kan kombineras mha nyckelordet 'or'.
|
||||
¤¤ search_form ¤¤
|
||||
|
||||
<form onSubmit="JavaScript:doSearch(event)"
|
||||
id="search"
|
||||
class="dark">
|
||||
<p>
|
||||
<input type="hidden"
|
||||
name="page"
|
||||
value="search" />
|
||||
<input type="text"
|
||||
onKeyPress="JavaScript:searchInput(event)"
|
||||
name="q"
|
||||
placeholder="Vad letar du efter?"
|
||||
value="" />
|
||||
<button type="submit">
|
||||
Sök
|
||||
</button>
|
||||
</p>
|
||||
<div id="terms">
|
||||
¤terms¤
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
</form>
|
||||
|
||||
¤¤ search_term ¤¤
|
||||
|
||||
<p class="left">
|
||||
<span class="term">
|
||||
<input type="hidden"
|
||||
name="¤key¤"
|
||||
value="¤value¤" />
|
||||
¤term¤
|
||||
<a class="termremove"
|
||||
onClick="JavaScript:removeTerm(event)">
|
||||
x
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
<p>
|
||||
Övriga fält är sökbara med syntaxen [fält]:[värde]. Saknas [värde]
|
||||
så returneras alla träffar som överhuvud taget har fältet.
|
||||
</p>
|
||||
<p>
|
||||
Alla sökningar matchar på delar av ord, utom taggar som bara matchas exakt.
|
||||
</p>
|
||||
<p>
|
||||
De fält som alltid finns är:
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Artikel:</strong> id, namn, serienummer, fakturanummer, status<br/>
|
||||
Giltiga värden för status är: inne, ute, utlånad, sen, försenad
|
||||
</li>
|
||||
<li>
|
||||
<strong>Låntagare:</strong> id, namn, användarnamn, anteckningar
|
||||
</li>
|
||||
</ul>
|
||||
Artiklar kan ha fler fält beroende på vad som lagts till.
|
||||
</p>
|
||||
<h3>Lite exempel:</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>"mac"</strong>
|
||||
- sök efter artiklar och låntagare vars namn eller användarnamn
|
||||
innehåller strängen 'mac'
|
||||
</li>
|
||||
<li>
|
||||
<strong>"tag:trasig"</strong>
|
||||
- sök efter artiklar med taggen "trasig"<br/>
|
||||
(Det är bara artiklar som kan ha taggar)
|
||||
</li>
|
||||
<li>
|
||||
<strong>"anteckning:"</strong>
|
||||
- sök efter artiklar som har ett fält vid namn "anteckning"<br/>
|
||||
(Anteckningsfältet för låntagare heter 'anteckningar', så bara
|
||||
artiklar kommer hittas)
|
||||
</li>
|
||||
<li>
|
||||
<strong>"mac or tag:trasig"</strong>
|
||||
- sök efter artiklar och låntagare som matchar "mac", samt
|
||||
artiklar som har taggen "trasig"<br/>
|
||||
(Bara artiklar kan ha taggar, men eftersom 'mac' är fritext så
|
||||
kan den matcha både artiklar och låntagare)
|
||||
</li>
|
||||
</ul>
|
||||
|
146
include/db.php
146
include/db.php
@ -120,6 +120,20 @@ function suggest($type) {
|
||||
return $out;
|
||||
}
|
||||
|
||||
function match($testvalues, $matchvalues) {
|
||||
if(!is_array($testvalues)) {
|
||||
$testvalues = array($testvalues);
|
||||
}
|
||||
foreach($testvalues as $value) {
|
||||
foreach($matchvalues as $candidate) {
|
||||
if(fnmatch($value, $candidate, FNM_CASEFOLD)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class Product {
|
||||
private $id = 0;
|
||||
private $name = '';
|
||||
@ -228,61 +242,31 @@ class Product {
|
||||
}
|
||||
|
||||
public function matches($terms) {
|
||||
foreach($terms as $fieldtype => $values) {
|
||||
$testfield = null;
|
||||
switch($fieldtype) {
|
||||
case 'tag':
|
||||
foreach($values as $value) {
|
||||
if(!in_array($value, $this->tags)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'status':
|
||||
$loan = $this->get_active_loan();
|
||||
foreach($values as $value) {
|
||||
switch($value) {
|
||||
case 'on_loan':
|
||||
if(!$loan) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'no_loan':
|
||||
if($loan) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'overdue':
|
||||
if(!$loan || !$loan->is_overdue()) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'words':
|
||||
$testfield = $this->name;
|
||||
break;
|
||||
default:
|
||||
if(property_exists($this, $fieldtype)) {
|
||||
$testfield = $this->$fieldtype;
|
||||
} elseif(array_key_exists($fieldtype, $this->info)) {
|
||||
$tesfield = $this->info[$fieldtype];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if($testfield !== null) {
|
||||
foreach($values as $value) {
|
||||
$test = strtolower($testfield);
|
||||
if(strpos($test, $value) === false) {
|
||||
return false;
|
||||
}
|
||||
foreach($terms as $field => $values) {
|
||||
$matchvalues = array();
|
||||
if(property_exists($this, $field)) {
|
||||
$matchvalues[] = $this->$field;
|
||||
} else if(array_key_exists($field, $this->get_info())) {
|
||||
$matchvalues[] = $this->get_info()[$field];
|
||||
} else {
|
||||
switch($field) {
|
||||
case 'tag':
|
||||
$matchvalues = $this->get_tags();
|
||||
case 'status':
|
||||
$matchvalues[] = $this->get_loan_status();
|
||||
case 'fritext':
|
||||
$matchvalues[] = $this->name;
|
||||
$matchvalues[] = $this->serial;
|
||||
$matchvalues[] = $this->invoice;
|
||||
$matchvalues = array_merge($matchvalues,
|
||||
$this->get_tags(),
|
||||
array_values(
|
||||
$this->get_info()));
|
||||
}
|
||||
}
|
||||
if(!match($values, $matchvalues)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -427,6 +411,20 @@ class Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get_loan_status() {
|
||||
if($this->get_discardtime(false)) {
|
||||
return 'discarded';
|
||||
}
|
||||
$loan = $this->get_active_loan();
|
||||
if(!$loan) {
|
||||
return 'no_loan';
|
||||
}
|
||||
if($loan->is_overdue()) {
|
||||
return 'overdue';
|
||||
}
|
||||
return 'on_loan';
|
||||
}
|
||||
|
||||
public function get_active_loan() {
|
||||
$find = prepare('select `id` from `loan`
|
||||
where `returntime` is null and product=?');
|
||||
@ -694,35 +692,27 @@ class User {
|
||||
}
|
||||
|
||||
public function matches($terms) {
|
||||
foreach($terms as $fieldtype => $values) {
|
||||
switch($fieldtype) {
|
||||
case 'words':
|
||||
foreach($values as $value) {
|
||||
if(strpos($this->name, $value) !== false) {
|
||||
continue;
|
||||
}
|
||||
$name = strtolower($this->get_displayname());
|
||||
if(strpos($name, $value) !== false) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(!property_exists($this, $fieldtype)) {
|
||||
return false;
|
||||
}
|
||||
foreach($values as $value) {
|
||||
if($this->$fieldtype != $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
foreach($terms as $field => $values) {
|
||||
$matchvalues = array();
|
||||
if($field == 'name') {
|
||||
$matchvalues[] = $this->name;
|
||||
$matchvalues[] = $this->get_displayname();
|
||||
} else if(property_exists($this, $field)) {
|
||||
$matchvalues[] = $this->$field;
|
||||
} else if($field == 'fritext') {
|
||||
$matchvalues[] = $this->name;
|
||||
$matchvalues[] = $this->get_displayname();
|
||||
$matchvalues[] = $this->notes;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if(!match($values, $matchvalues)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function get_displayname() {
|
||||
global $ldap;
|
||||
try {
|
||||
|
268
include/view.php
268
include/view.php
@ -32,6 +32,28 @@ abstract class Responder {
|
||||
public function __construct() {
|
||||
$this->fragments = get_fragments('./html/fragments.html');
|
||||
}
|
||||
|
||||
final protected function escape_tags($tags) {
|
||||
foreach($tags as $key => $tag) {
|
||||
$tags[$key] = str_replace(array("'",
|
||||
'"'),
|
||||
array(''',
|
||||
'"'),
|
||||
strtolower($tag));
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
final protected function unescape_tags($tags) {
|
||||
foreach($tags as $key => $tag) {
|
||||
$tags[$key] = str_replace(array(''',
|
||||
'"'),
|
||||
array("'",
|
||||
'"'),
|
||||
strtolower($tag));
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Page extends Responder {
|
||||
@ -46,7 +68,8 @@ abstract class Page extends Responder {
|
||||
'products' => 'Artiklar',
|
||||
'users' => 'Låntagare',
|
||||
'inventory' => 'Inventera',
|
||||
'history' => 'Historik');
|
||||
'history' => 'Historik',
|
||||
'search' => 'Sök');
|
||||
private $template_parts = array();
|
||||
|
||||
public function __construct() {
|
||||
@ -94,12 +117,17 @@ abstract class Page extends Responder {
|
||||
private function build_menu() {
|
||||
$menu = '';
|
||||
foreach($this->menuitems as $page => $title) {
|
||||
$align = 'left';
|
||||
$active = '';
|
||||
if($this->page == $page) {
|
||||
$active = 'active';
|
||||
}
|
||||
if($page == 'search') {
|
||||
$align = 'right';
|
||||
}
|
||||
$menu .= replace(array('title' => $title,
|
||||
'page' => $page,
|
||||
'align' => $align,
|
||||
'active' => $active),
|
||||
$this->template_parts['menuitem']);
|
||||
}
|
||||
@ -334,121 +362,152 @@ abstract class Page extends Responder {
|
||||
}
|
||||
|
||||
class SearchPage extends Page {
|
||||
private $querystr = '';
|
||||
private $terms = array();
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->subtitle = 'Sökresultat för ';
|
||||
if(isset($_GET['q'])) {
|
||||
$this->querystr = $_GET['q'];
|
||||
$this->subtitle .= "'$this->querystr'";
|
||||
$orterms = preg_split('/[[:space:]]+or[[:space:]]+/',
|
||||
strtolower($this->querystr),
|
||||
-1,
|
||||
PREG_SPLIT_NO_EMPTY);
|
||||
foreach($orterms as $orterm) {
|
||||
$searchpart = array();
|
||||
$terms = preg_split('/[[:space:]]+/',
|
||||
$orterm,
|
||||
-1,
|
||||
PREG_SPLIT_NO_EMPTY);
|
||||
foreach($terms as $term) {
|
||||
$key = '';
|
||||
$value = '';
|
||||
if(strpos($term, ':') !== false) {
|
||||
$pair = explode(':', $term);
|
||||
$key = $pair[0];
|
||||
switch($key) {
|
||||
case 'namn':
|
||||
$key = 'name';
|
||||
break;
|
||||
case 'fakturanummer':
|
||||
$key = 'invoice';
|
||||
break;
|
||||
case 'serienummer':
|
||||
$key = 'serial';
|
||||
break;
|
||||
case 'anteckningar':
|
||||
$key = 'notes';
|
||||
break;
|
||||
}
|
||||
$value = $pair[1];
|
||||
if($key == 'status') {
|
||||
switch($value) {
|
||||
case 'inne':
|
||||
$value = 'no_loan';
|
||||
break;
|
||||
case 'ute':
|
||||
case 'utlånad':
|
||||
$value = 'on_loan';
|
||||
break;
|
||||
case 'sen':
|
||||
case 'försenad':
|
||||
case 'försenat':
|
||||
$value = 'overdue';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$key = 'words';
|
||||
$value = $term;
|
||||
}
|
||||
if(!isset($searchpart[$key])) {
|
||||
$searchpart[$key] = array();
|
||||
}
|
||||
$searchpart[$key][] = $value;
|
||||
}
|
||||
$this->terms[] = $searchpart;
|
||||
}
|
||||
}
|
||||
$this->terms = $_GET;
|
||||
unset($this->terms['q'], $this->terms['page']);
|
||||
}
|
||||
|
||||
private function do_search() {
|
||||
$out = array('users' => array(),
|
||||
'products' => array());
|
||||
if(!$this->querystr) {
|
||||
$out = array();
|
||||
if(!$this->terms) {
|
||||
return $out;
|
||||
}
|
||||
$out['users'] = $this->search('user');
|
||||
$out['products'] = $this->search('product');
|
||||
$terms = $this->translate_keys($this->terms);
|
||||
foreach(array('user', 'product') as $type) {
|
||||
$result = $this->search($type, $terms);
|
||||
if($result) {
|
||||
$out[$type] = $result;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
private function search($type) {
|
||||
private function translate_keys($terms) {
|
||||
$translated = array();
|
||||
foreach($terms as $key => $value) {
|
||||
$newkey = $key;
|
||||
switch($key) {
|
||||
case 'namn':
|
||||
$newkey = 'name';
|
||||
break;
|
||||
case 'faktura':
|
||||
case 'fakturanummer':
|
||||
$newkey = 'invoice';
|
||||
break;
|
||||
case 'serienummer':
|
||||
$newkey = 'serial';
|
||||
break;
|
||||
case 'tagg':
|
||||
$newkey = 'tag';
|
||||
break;
|
||||
case 'status':
|
||||
$value = $this->translate_values($value);
|
||||
break;
|
||||
}
|
||||
if(!array_key_exists($newkey, $translated)) {
|
||||
$translated[$newkey] = $value;
|
||||
} else {
|
||||
$temp = $translated[$newkey];
|
||||
$translated[$newkey] = array_merge((array)$temp, (array)$value);
|
||||
}
|
||||
}
|
||||
return $translated;
|
||||
}
|
||||
|
||||
private function translate_values($value) {
|
||||
if(!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
$translated = array();
|
||||
foreach($value as $item) {
|
||||
$newitem = $item;
|
||||
switch($item) {
|
||||
case 'ute':
|
||||
case 'utlånad':
|
||||
case 'utlånat':
|
||||
case 'lånad':
|
||||
case 'lånat':
|
||||
$newitem = 'on_loan';
|
||||
break;
|
||||
case 'inne':
|
||||
case 'ledig':
|
||||
case 'ledigt':
|
||||
case 'tillgänglig':
|
||||
case 'tillgängligt':
|
||||
$newitem = 'no_loan';
|
||||
break;
|
||||
case 'sen':
|
||||
case 'sent':
|
||||
case 'försenad':
|
||||
case 'försenat':
|
||||
case 'överdraget':
|
||||
$newitem = 'overdue';
|
||||
break;
|
||||
case 'skrotad':
|
||||
case 'skrotat':
|
||||
case 'slängd':
|
||||
case 'slängt':
|
||||
$newitem = 'discarded';
|
||||
break;
|
||||
}
|
||||
$translated[] = $newitem;
|
||||
}
|
||||
return $translated;
|
||||
}
|
||||
|
||||
private function search($type, $terms) {
|
||||
$items = get_items($type);
|
||||
$out = array();
|
||||
foreach($items as $item) {
|
||||
foreach($this->terms as $term) {
|
||||
if($item->matches($term)) {
|
||||
$out[] = $item;
|
||||
}
|
||||
if($item->matches($terms)) {
|
||||
$out[] = $item;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
protected function render_body() {
|
||||
$hits = $this->do_search();
|
||||
$nohits = true;
|
||||
if($hits['users']) {
|
||||
print(replace(array('title' => 'Låntagare'),
|
||||
$this->fragments['subtitle']));
|
||||
print($this->build_user_table($hits['users']));
|
||||
$nohits = false;
|
||||
$terms = '';
|
||||
foreach($this->terms as $key => $value) {
|
||||
if(!is_array($value)) {
|
||||
$terms .= replace(array('term' => ucfirst($key).": $value",
|
||||
'key' => $key,
|
||||
'value' => $value),
|
||||
$this->fragments['search_term']);
|
||||
} else {
|
||||
foreach($value as $item) {
|
||||
$terms .= replace(array('term' => ucfirst($key).": $item",
|
||||
'key' => $key,
|
||||
'value' => $item),
|
||||
$this->fragments['search_term']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if($hits['products']) {
|
||||
print(replace(array('title' => 'Artiklar'),
|
||||
$this->fragments['subtitle']));
|
||||
print($this->build_product_table($hits['products']));
|
||||
$nohits = false;
|
||||
print(replace(array('terms' => $terms),
|
||||
$this->fragments['search_form']));
|
||||
if($this->terms) {
|
||||
$hits = $this->do_search();
|
||||
print(replace(array('title' => 'Sökresultat'),
|
||||
$this->fragments['title']));
|
||||
$result = '';
|
||||
if(isset($hits['user'])) {
|
||||
$result = replace(array('title' => 'Låntagare'),
|
||||
$this->fragments['subtitle']);
|
||||
$result .= $this->build_user_table($hits['user']);
|
||||
}
|
||||
if(isset($hits['product'])) {
|
||||
$result .= replace(array('title' => 'Artiklar'),
|
||||
$this->fragments['subtitle']);
|
||||
$result .= $this->build_product_table($hits['product']);
|
||||
}
|
||||
if(!$result) {
|
||||
$result = 'Inga träffar.';
|
||||
}
|
||||
print($result);
|
||||
}
|
||||
if($nohits) {
|
||||
print('Inga träffar.');
|
||||
}
|
||||
print(replace(array('title' => 'Hjälp'),
|
||||
$this->fragments['subtitle']));
|
||||
print($this->fragments['search_help']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,7 +581,7 @@ class ProductPage extends Page {
|
||||
$this->fragments['info_item']);
|
||||
}
|
||||
$tags = '';
|
||||
foreach($this->product->get_tags() as $tag) {
|
||||
foreach($this->escape_tags($this->product->get_tags()) as $tag) {
|
||||
$tags .= replace(array('tag' => ucfirst($tag)),
|
||||
$this->fragments['tag']);
|
||||
}
|
||||
@ -962,8 +1021,8 @@ class Ajax extends Responder {
|
||||
$name = $info['name'];
|
||||
$serial = $info['serial'];
|
||||
$invoice = $info['invoice'];
|
||||
$tags = $this->extract_tags($info['tags']);
|
||||
foreach(array('id', 'name', 'serial', 'invoice', 'tags') as $key) {
|
||||
$tags = $this->unescape_tags($info['tag']);
|
||||
foreach(array('id', 'name', 'serial', 'invoice', 'tag') as $key) {
|
||||
unset($info[$key]);
|
||||
}
|
||||
if(!$name) {
|
||||
@ -1062,7 +1121,7 @@ class Ajax extends Responder {
|
||||
private function save_template() {
|
||||
$info = $_POST;
|
||||
$name = $info['template'];
|
||||
$tags = $this->extract_tags($info['tags']);
|
||||
$tags = $this->unescape_tags($info['tag']);
|
||||
foreach(array('template',
|
||||
'id',
|
||||
'name',
|
||||
@ -1137,21 +1196,6 @@ class Ajax extends Responder {
|
||||
return new Failure('Artikeln är redan skrotad.');
|
||||
}
|
||||
}
|
||||
|
||||
private function extract_tags($string) {
|
||||
$tags = explode(',', strtolower($string));
|
||||
# Unescape specials
|
||||
foreach($tags as $key => $tag) {
|
||||
$tags[$key] = str_replace(array(',',
|
||||
''',
|
||||
'"'),
|
||||
array(',',
|
||||
"'",
|
||||
'"'),
|
||||
$tag);
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
|
||||
class Result {
|
||||
|
95
script.js
95
script.js
@ -61,9 +61,31 @@ function reloadOrError(result) {
|
||||
}
|
||||
}
|
||||
|
||||
function ucfirst(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase()
|
||||
}
|
||||
|
||||
function fixDuplicateInputNames(fields) {
|
||||
var names = {}
|
||||
for(var i = 0; i < fields.length; i++) {
|
||||
var name = fields[i].name
|
||||
if(name.endsWith('[]')) {
|
||||
continue
|
||||
}
|
||||
if(names.hasOwnProperty(name)) {
|
||||
fields[i].name = name + '[]'
|
||||
fields[names[name]].name = name + '[]'
|
||||
} else {
|
||||
names[name] = i
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function dataListFromForm(form, filter = function(field) {return true}) {
|
||||
var out = []
|
||||
var fields = form.querySelectorAll('input,textarea')
|
||||
fixDuplicateInputNames(fields)
|
||||
for(var i = 0; i < fields.length; i++) {
|
||||
if(filter(fields[i])) {
|
||||
out.push([fields[i].name, fields[i].value])
|
||||
@ -166,9 +188,9 @@ function suggest(input, type) {
|
||||
}
|
||||
break
|
||||
case 'tag':
|
||||
var taglist = document.querySelectorAll('#tags > p')
|
||||
var taglist = document.querySelectorAll('#tags .tag > input')
|
||||
for(var i = 0; i < taglist.length; i++) {
|
||||
var tag = taglist[i].firstElementChild.dataset.name
|
||||
var tag = taglist[i].name
|
||||
existing.push(tag.toLowerCase())
|
||||
}
|
||||
break
|
||||
@ -191,8 +213,7 @@ function suggest(input, type) {
|
||||
}
|
||||
var next = document.createElement('option')
|
||||
if(capitalize) {
|
||||
next.value = suggestion.charAt(0).toUpperCase()
|
||||
+ suggestion.slice(1)
|
||||
next.value = ucfirst(suggestion)
|
||||
} else {
|
||||
next.value = suggestion
|
||||
}
|
||||
@ -220,7 +241,7 @@ function addField(event) {
|
||||
{'type': 'error',
|
||||
'message': 'Det finns redan ett fält med det namnet.'})
|
||||
}
|
||||
var name = key.charAt(0).toUpperCase() + key.slice(1)
|
||||
var name = ucfirst(key)
|
||||
var render = function(fragment) {
|
||||
var temp = document.createElement('template')
|
||||
fragment = replace(fragment, [
|
||||
@ -245,9 +266,8 @@ function addField(event) {
|
||||
getFragment('info_item', render)
|
||||
}
|
||||
|
||||
function escapeTag(tag) {
|
||||
return tag
|
||||
.replace(/,/, ',')
|
||||
function escapeText(text) {
|
||||
return text
|
||||
.replace(/'/, ''')
|
||||
.replace(/"/, '"')
|
||||
}
|
||||
@ -259,15 +279,15 @@ function addTag(event) {
|
||||
event.preventDefault()
|
||||
var tr = event.currentTarget.parentNode.parentNode
|
||||
var field = tr.querySelector('.newtag')
|
||||
var tagname = escapeTag(field.value)
|
||||
var tagname = escapeText(field.value)
|
||||
if(!tagname) {
|
||||
return showResult({'type': 'error',
|
||||
'message': 'Taggen måste ha ett namn.'})
|
||||
}
|
||||
tagname = tagname.charAt(0).toUpperCase() + tagname.slice(1)
|
||||
var tagElements = tr.querySelectorAll('.tag')
|
||||
tagname = ucfirst(tagname)
|
||||
var tagElements = tr.querySelectorAll('.tag > input')
|
||||
for(var i = 0; i < tagElements.length; i++) {
|
||||
var oldtag = tagElements[i].dataset['name']
|
||||
var oldtag = tagElements[i].name
|
||||
if(tagname.toLowerCase() == oldtag.toLowerCase()) {
|
||||
return showResult({'type': 'error',
|
||||
'message': 'Det finns redan en sån tagg på artikeln.'})
|
||||
@ -383,12 +403,6 @@ function productDataList(form) {
|
||||
return true
|
||||
}
|
||||
var datalist = dataListFromForm(form, filter)
|
||||
var tagElements = form.querySelectorAll('.tag')
|
||||
var tags = []
|
||||
for(var i = 0; i < tagElements.length; i++) {
|
||||
tags.push(escapeTag(tagElements[i].dataset['name']))
|
||||
}
|
||||
datalist.push(['tags', tags])
|
||||
return datalist
|
||||
}
|
||||
|
||||
@ -419,3 +433,48 @@ function discardProduct(event) {
|
||||
}
|
||||
ajaxRequest('discardproduct', dataListFromForm(form), render)
|
||||
}
|
||||
|
||||
function searchInput(event) {
|
||||
if(event.key != "Enter") {
|
||||
return
|
||||
}
|
||||
var input = event.target
|
||||
var term = input.value.toLowerCase()
|
||||
if(term === '') {
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
var terms = document.querySelector('#terms')
|
||||
var parts = escapeText(term).trim().split(':')
|
||||
var parsedTerm = 'Fritext: ' + parts[0]
|
||||
var key = 'fritext'
|
||||
var value = parts[0]
|
||||
if(parts.length > 1) {
|
||||
key = parts[0].trim()
|
||||
value = parts.slice(1).join(':').trim()
|
||||
parsedTerm = ucfirst(key) + ': ' + value
|
||||
}
|
||||
var render = function(fragment) {
|
||||
var temp = document.createElement('template')
|
||||
fragment = replace(fragment, [['term', parsedTerm],
|
||||
['key', key],
|
||||
['value', value]])
|
||||
temp.innerHTML = fragment
|
||||
terms.append(temp.content.firstChild)
|
||||
input.value = ''
|
||||
}
|
||||
getFragment('search_term', render)
|
||||
}
|
||||
|
||||
function doSearch(event) {
|
||||
var form = document.querySelector('#search')
|
||||
var fields = form.querySelectorAll('input,textarea')
|
||||
fixDuplicateInputNames(fields)
|
||||
}
|
||||
|
||||
function removeTerm(event) {
|
||||
event.preventDefault()
|
||||
var term = event.currentTarget.parentNode
|
||||
var parent = term.parentNode
|
||||
parent.remove(term)
|
||||
}
|
||||
|
10
style.css
10
style.css
@ -118,14 +118,20 @@ input[type="text"].newtemplate {
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.tagremove {
|
||||
.tagremove, .termremove {
|
||||
background-color: #e17e33;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tagremove:hover {
|
||||
.tagremove:hover, .termremove:hover {
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.term {
|
||||
background-color: #ebf0f5;
|
||||
margin: 5px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
10
template.css
10
template.css
@ -220,28 +220,22 @@ button:disabled, input[type="submit"]:disabled {
|
||||
background-color: #002E5F;
|
||||
margin: 0px;
|
||||
font-size: 130%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#menu .item {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding: 8px 12px;
|
||||
margin-left:6px;
|
||||
margin-right: 6px;
|
||||
text-decoration: none;
|
||||
color: #005B7F;
|
||||
height: 100%;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
#menu .active {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
#menu #search {
|
||||
padding-top: 7px;
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
#contents {
|
||||
font-family: Georgia, "Times New Roman", Times, serif;
|
||||
margin-left: auto;
|
||||
|
Loading…
x
Reference in New Issue
Block a user