Skip to content

Commit

Permalink
Merge pull request #393 from FriendsOfREDAXO/tyrant88-patch-161
Browse files Browse the repository at this point in the history
integrated autocomplete without jQuery into AddOn
  • Loading branch information
tyrant88 authored Jul 28, 2024
2 parents f196974 + 4801dea commit 9c459d7
Show file tree
Hide file tree
Showing 18 changed files with 772 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

- autocomplete Plugin is deprecated, use the new subpage instead
- added autocomplete as function without jquery on subpage
- documentation plugin removed, turned into subpages thx @alexplusde
- Fix Link to SysLog in Backend thx @godsdog

Expand Down
File renamed without changes.
211 changes: 211 additions & 0 deletions assets/suggest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
document.addEventListener('DOMContentLoaded', function () {
function suggest(input, options) {
var cache = [],
cacheSize = 0,
results = document.createElement('ul'),
timeout = null,
prevLength = 0;

results.className = options.resultsClass;
document.body.appendChild(results);

function getPosition(el) {
var rect = el.getBoundingClientRect();
return {
top: rect.top + window.scrollY,
left: rect.left + window.scrollX
};
}

function updatePosition() {
var pos = getPosition(input);
results.style.top = pos.top + input.offsetHeight + 'px';
results.style.left = pos.left + 'px';
}

function handleKeyup(e) {
if (/27$|38$|40$/.test(e.keyCode) && results.style.display !== 'none' || /^13$|^9$/.test(e.keyCode) && getCurrentResult()) {
e.preventDefault();
e.stopPropagation();
switch (e.keyCode) {
case 38:
selectPrevious();
break;
case 40:
selectNext();
break;
case 9:
case 13:
chooseResult();
break;
case 27:
results.style.display = 'none';
break;
}
} else {
if (input.value.length !== prevLength) {
clearTimeout(timeout);
timeout = setTimeout(fetchSuggestions, options.delay);
prevLength = input.value.length;
}
}
}

function fetchSuggestions() {
var query = input.value.trim();
if (query.length >= options.minchars) {
var cached = getCached(query);
if (cached) {
displayResults(cached.items);
} else {
fetch(options.source + '&q=' + encodeURIComponent(query))
.then(response => response.text())
.then(data => {
var items = parseResults(data, query);
displayResults(items);
addToCache(query, items, data.length);
});
}
} else {
results.style.display = 'none';
}
}

function getCached(query) {
for (var i = 0; i < cache.length; i++) {
if (cache[i].q === query) {
cache.unshift(cache.splice(i, 1)[0]);
return cache[0];
}
}
return false;
}

function addToCache(query, items, size) {
while (cache.length && cacheSize + size > options.maxCacheSize) {
var cached = cache.pop();
cacheSize -= cached.size;
}
cache.push({q: query, size: size, items: items});
cacheSize += size;
}

function displayResults(items) {
if (items.length) {
results.innerHTML = '';
for (var i = 0; i < items.length; i++) {
var li = document.createElement('li');
li.innerHTML = items[i];
li.addEventListener('mouseover', function () {
var children = results.children;
for (var j = 0; j < children.length; j++) {
children[j].classList.remove(options.selectClass);
}
this.classList.add(options.selectClass);
});
li.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
chooseResult();
});
results.appendChild(li);
}
results.style.display = 'block';
} else {
results.style.display = 'none';
}
}

function parseResults(data, query) {
var items = data.split(options.delimiter).map(item => item.trim()).filter(item => item);
var regex = new RegExp(query, 'ig');
return items.map(item => item.replace(regex, function (match) {
return '<span class="' + options.matchClass + '">' + match + '</span>';
}));
}

function getCurrentResult() {
var selected = results.querySelector('.' + options.selectClass);
return selected || false;
}

function chooseResult() {
var currentResult = getCurrentResult();
if (currentResult) {
input.value = currentResult.textContent;
results.style.display = 'none';
if (options.onSelect) {
options.onSelect.apply(input, [currentResult.textContent]);
}
}
}

function selectNext() {
var currentResult = getCurrentResult();
if (currentResult) {
var next = currentResult.nextElementSibling;
currentResult.classList.remove(options.selectClass);
if (next) {
next.classList.add(options.selectClass);
} else {
results.firstElementChild.classList.add(options.selectClass);
}
} else {
results.firstElementChild.classList.add(options.selectClass);
}
}

function selectPrevious() {
var currentResult = getCurrentResult();
if (currentResult) {
var prev = currentResult.previousElementSibling;
currentResult.classList.remove(options.selectClass);
if (prev) {
prev.classList.add(options.selectClass);
} else {
results.lastElementChild.classList.add(options.selectClass);
}
} else {
results.lastElementChild.classList.add(options.selectClass);
}
}

input.addEventListener('keyup', handleKeyup);
input.addEventListener('blur', function () {
setTimeout(function () {
results.style.display = 'none';
}, 200);
});
window.addEventListener('resize', updatePosition);
window.addEventListener('load', updatePosition);

updatePosition();
}

function initSuggest() {
var searchInput = document.querySelector(".search_it-form input[name=search]");

if (searchInput) {
suggest(searchInput, {
source: 'index.php?rex-api-call=search_it_autocomplete&rnd=' + Math.random(),
delay: 100,
resultsClass: 'ac_results',
selectClass: 'ac_over',
matchClass: 'ac_match',
minchars: 2,
delimiter: '\n',
onSelect: function (value) {
var searchForm = searchInput.closest('.search_it-form');
if (searchForm.classList.contains('search_it-form-autocomplete')) {
searchForm.submit();
return false;
}

},
maxCacheSize: 65536
});
}
}

initSuggest();
});
27 changes: 27 additions & 0 deletions boot.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,33 @@
}
}

// autocomplete
if ($this->getConfig('autoComplete') == 1) {
if (rex::isBackend()) {

rex_view::addCssFile($this->getAssetsUrl('suggest.css'));
rex_view::addJsFile($this->getAssetsUrl('suggest.js'));

if (!$this->hasConfig()) {
$this->setConfig(array(
'modus' => 'keywords',
'maxSuggestion' => 10,
'similarwordsmode' => '0',
'autoSubmitForm' => 1
));
}
} else {
if ($this->getConfig('autoSubmitForm') == 1) {
rex_extension::register('OUTPUT_FILTER', function (rex_extension_point $ep) {
$subject = $ep->getSubject();
return str_replace(['search_it-form', '###AUTOSUBMIT###'],
['search_it-form search_it-form-autocomplete', ''],
$subject);
});
}
}
}

if (rex::isBackend() && rex::getUser()) {
// automatic indexing
if (rex_addon::get('search_it')->getConfig('automaticindex') == true) {
Expand Down
41 changes: 41 additions & 0 deletions docs/30_autocomplete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Installation Autocomplete

Es stellt ein "Suggest"-PlugIn für die Autovervollständigung bei
der Suche im Frontend zur Verfügung und generiert einen Code welcher im Template
eingebunden werden muss.

## Requirements

* Funktionierendes Suchformular, das die HTML-Klasse "search_it-form",
sowie ein HTML-Eingabefeld für die Suche mit dem Namen "search" beinhaltet.

## Installation

1. Autocomplete und aktivieren
2. Konfiguration im Plugin vornehmen und speichern
3. Den generierten Code für das Template herauskopieren und in das Template,
welches für das Suchfeld verwendet wird, vor dem schließenden `</body>` Tag
hinzufügen
4. Sollte das Suchfeld überall verwendet werden, beispielsweise im Kopf der
Seite, muss der generierte Code in das entsprechende Template hinzugefügt
werden
5. Optional: CSS und JS Datei in den eigenen Frontend_prozess einbauen ( z.B.
per Minify oder im Bimmelbam )

## Lizenz

"Autocomplete" von Manétage steht unter MIT Lizenz.

## Rechtliches

Verwendung auf eigene Gefahr.

## Autor

**Manetage** - Ronny Kemmereit / Pascal Schuchmann
Norbert Micheel

**Friends Of REDAXO**

* http://www.redaxo.org
* https://github.com/FriendsOfREDAXO
23 changes: 23 additions & 0 deletions lang/de_de.lang
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,26 @@ search_it_docs_module-pagination = Paginierung
search_it_docs_module-simsearch = Ähnlichkeitssuche
search_it_docs_module-url = URL-Addon
search_it_docs_faq = FAQ


search_it_autocomplete_title = Autocomplete
search_it_autocomplete_info = Autocomplete für Search it

search_it_autocomplete_config = Konfiguration
search_it_autocomplete_config_saved = Einstellungen gespeichert.
search_it_autocomplete_config_save = Einstellungen speichern

search_it_autocomplete_config_autoComplete = Autovervollständigung aktivieren
search_it_autocomplete_config_modus = Modus der Ausgabe
search_it_autocomplete_config_maxSuggestion = Maximale Trefferanzahl
search_it_autocomplete_config_similarwords_label = Ähnlichkeitssuche
search_it_autocomplete_config_similarwords_none = Deaktivieren
search_it_autocomplete_config_similarwords_soundex = Soundex (Allgemein)
search_it_autocomplete_config_similarwords_metaphone = Metaphone (EN)
search_it_autocomplete_config_similarwords_cologne = Kölner Phonetik (DE)
search_it_autocomplete_config_similarwords_all = Alle

search_it_autocomplete_config_autoSubmitForm = Auto Submit Form

search_it_autocomplete_config_install = Installation
search_it_autocomplete_config_codesnippet = Generierter Code zum Einbinden in Template
22 changes: 22 additions & 0 deletions lang/en_gb.lang
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,25 @@ search_it_docs_module-pagination = Paging
search_it_docs_module-simsearch = similarity search
search_it_docs_module-url = URL-AddOn
search_it_docs_faq = FAQ

search_it_autocomplete_title = Autocomplete
search_it_autocomplete_info = Autocomplete for Search it

search_it_autocomplete_config = Configuration
search_it_autocomplete_config_saved = Settings saved.
search_it_autocomplete_config_save = Save settings

search_it_autocomplete_config_autoComplete = Activate autocomplete
search_it_autocomplete_config_modus = Output mode
search_it_autocomplete_config_maxSuggestion = Maximum number of hits
search_it_autocomplete_config_similarwords_label = Similarity search
search_it_autocomplete_config_similarwords_none = Deactivate
search_it_autocomplete_config_similarwords_soundex = Soundex (General)
search_it_autocomplete_config_similarwords_metaphone = Metaphone (EN)
search_it_autocomplete_config_similarwords_cologne = Cologne Phonetics (DE)
search_it_autocomplete_config_similarwords_all = All

search_it_autocomplete_config_autoSubmitForm = Auto Submit Form

search_it_autocomplete_config_install = Installation
search_it_autocomplete_config_codesnippet = Generated code for insert in template
23 changes: 23 additions & 0 deletions lang/es_es.lang
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,26 @@ search_it_docs_module-pagination = Paging
search_it_docs_module-simsearch = similarity search
search_it_docs_module-url = URL-AddOn
search_it_docs_faq = FAQ


search_it_autocomplete_title = Autocomplete
search_it_autocomplete_info = Autocomplete für Search it

search_it_autocomplete_config = Konfiguration
search_it_autocomplete_config_saved = Einstellungen gespeichert.
search_it_autocomplete_config_save = Einstellungen speichern

search_it_autocomplete_config_autoComplete = Autovervollständigung aktivieren
search_it_autocomplete_config_modus = Modus der Ausgabe
search_it_autocomplete_config_maxSuggestion = Maximale Trefferanzahl
search_it_autocomplete_config_similarwords_label = Ähnlichkeitssuche
search_it_autocomplete_config_similarwords_none = Deaktivieren
search_it_autocomplete_config_similarwords_soundex = Soundex (Allgemein)
search_it_autocomplete_config_similarwords_metaphone = Metaphone (EN)
search_it_autocomplete_config_similarwords_cologne = Kölner Phonetik (DE)
search_it_autocomplete_config_similarwords_all = Alle

search_it_autocomplete_config_autoSubmitForm = Auto Submit Form

search_it_autocomplete_config_install = Installation
search_it_autocomplete_config_codesnippet = Código generado para su inclusión en la plantilla
Loading

0 comments on commit 9c459d7

Please sign in to comment.