Skip to content

Commit

Permalink
Live search WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
rnixx committed May 26, 2024
1 parent 6c3500d commit 0702999
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 2 deletions.
1 change: 1 addition & 0 deletions TODO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ TODO
- Referencebrowser widget.
- Treibstoff styles.
- Yafowil bootstrap 5 styles.
- Yafowil addon widgets.
- SCSS splitting.
- Reduce CSS class noise and add some custom rules to SCSS files.
- Check if we can retrieve Bootstrap sources other than including in this repo
Expand Down
6 changes: 5 additions & 1 deletion examples/cone.example/src/cone/example/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from cone.app import main_hook
from cone.app import register_entry
from cone.example.model import EntryFolder
from cone.example.browser import configure_resources
from cone.example.model import EntryFolder
from cone.example.model import LiveSearch


@main_hook
def example_main_hook(config, global_config, settings):
"""Function which gets called at application startup to initialize
this plugin.
"""
# register live search adapter
config.registry.registerAdapter(LiveSearch)

# add translation
config.add_translation_dirs('cone.example:locale/')

Expand Down
27 changes: 27 additions & 0 deletions examples/cone.example/src/cone/example/model.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from cone.app.browser.utils import make_url
from cone.app.interfaces import IApplicationNode
from cone.app.interfaces import ILiveSearch
from cone.app.interfaces import INavigationLeaf
from cone.app.model import AppNode
from cone.app.model import CopySupport
Expand All @@ -24,6 +27,7 @@
from pyramid.security import Deny
from pyramid.security import Everyone
from pyramid.threadlocal import get_current_request
from zope.component import adapter
from zope.interface import implementer


Expand Down Expand Up @@ -208,3 +212,26 @@ def create_content(node):
description = item.attrs['description'] = Translation()
description['en'] = f'Item Description'
description['de'] = f'Object Beschreibung'


@implementer(ILiveSearch)
@adapter(IApplicationNode)
class LiveSearch(object):

def __init__(self, model):
self.model = model

def search(self, request, query):
result = []
for child in self.model.values():
md = child.metadata
if (
md.title.lower().find(query.lower()) > -1 or
md.description.lower().find(query.lower()) > -1
):
result.append({
'value': md.title,
'target': make_url(request, node=child),
'icon': md.icon
})
return result
68 changes: 68 additions & 0 deletions js/src/livesearch.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import $ from 'jquery';
import ts from 'treibstoff';

export class LiveSearch {
Expand All @@ -15,6 +16,26 @@ export class LiveSearch {

constructor(elem) {
this.elem = elem;
this.target = `${elem.data('search-target')}/livesearch`;
this.result = $('<ul />')
.attr('id', 'livesearch-result')
.attr('class', 'dropdown-menu')
.insertAfter(elem.parents('.input-group'));

this._term = '';
this._minlen = 3;
this._delay = 250;
this._timeout_event = null;
this._in_progress = false;

this.on_keydown = this.on_keydown.bind(this);
this.on_change = this.on_change.bind(this);
this.on_result = this.on_result.bind(this);
this.on_select = this.on_select.bind(this);

elem.on('keydown', this.on_keydown);
elem.on('change', this.on_change);

// let source = new Bloodhound({
// datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
// queryTokenizer: Bloodhound.tokenizers.whitespace,
Expand All @@ -36,6 +57,53 @@ export class LiveSearch {
// elem.off(event).on(event, this.on_select);
}

search() {
this._in_progress = true;
ts.http_request({
url: this.target,
params: {term: this._term},
type: 'json',
success: this.on_result
});
this._in_progress = false;
}

on_keydown(evt) {
if (evt.keyCode === 13) {
return;
}
ts.clock.schedule_frame(() => {
if (this._term !== this.elem.val()) {
this.elem.trigger('change');
}
});
}

on_change(evt) {
if (this._in_progress) {
return;
}
const term = this.elem.val();
if (this._term === term) {
return;
}
this._term = term;
if (this._term.length < this._minlen) {
return;
}
if (this._timeout_event !== null) {
this._timeout_event.cancel();
}
this._timeout_event = ts.clock.schedule_timeout(() => {
this._timeout_event = null;
this.search();
}, this._delay);
}

on_result(data, status, request) {
console.log(data);
}

on_select(evt, suggestion, dataset) {
if (!suggestion.target) {
console.log('No suggestion target defined.');
Expand Down
59 changes: 59 additions & 0 deletions src/cone/app/browser/static/cone/cone.app.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,65 @@ var cone = (function (exports, $, ts) {
}
constructor(elem) {
this.elem = elem;
this.target = `${elem.data('search-target')}/livesearch`;
this.result = $('<ul />')
.attr('id', 'livesearch-result')
.attr('class', 'dropdown-menu')
.insertAfter(elem.parents('.input-group'));
this._term = '';
this._minlen = 3;
this._delay = 250;
this._timeout_event = null;
this._in_progress = false;
this.on_keydown = this.on_keydown.bind(this);
this.on_change = this.on_change.bind(this);
this.on_result = this.on_result.bind(this);
this.on_select = this.on_select.bind(this);
elem.on('keydown', this.on_keydown);
elem.on('change', this.on_change);
}
search() {
this._in_progress = true;
ts.http_request({
url: this.target,
params: {term: this._term},
type: 'json',
success: this.on_result
});
this._in_progress = false;
}
on_keydown(evt) {
if (evt.keyCode === 13) {
return;
}
ts.clock.schedule_frame(() => {
if (this._term !== this.elem.val()) {
this.elem.trigger('change');
}
});
}
on_change(evt) {
if (this._in_progress) {
return;
}
const term = this.elem.val();
if (this._term === term) {
return;
}
this._term = term;
if (this._term.length < this._minlen) {
return;
}
if (this._timeout_event !== null) {
this._timeout_event.cancel();
}
this._timeout_event = ts.clock.schedule_timeout(() => {
this._timeout_event = null;
this.search();
}, this._delay);
}
on_result(data, status, request) {
console.log(data);
}
on_select(evt, suggestion, dataset) {
if (!suggestion.target) {
Expand Down
2 changes: 1 addition & 1 deletion src/cone/app/browser/static/cone/cone.app.min.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/cone/app/browser/templates/livesearch.pt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
id="search-text"
placeholder="search database ..."
name="term"
data-search-target="${context.nodeurl}"
i18n:attributes="placeholder search_database" />
</div>

Expand Down

0 comments on commit 0702999

Please sign in to comment.