Skip to content

Commit

Permalink
Réécriture de la fonctionnalité de search #539
Browse files Browse the repository at this point in the history
  • Loading branch information
christophehenry authored Feb 14, 2022
2 parents b88d93b + 3fc44b7 commit da4cff4
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 56 deletions.
8 changes: 8 additions & 0 deletions aidants_connect_web/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,14 @@ class Usager(models.Model):
class Meta:
ordering = ["family_name", "given_name"]

@property
def search_terms(self):
search_term = [self.family_name, self.given_name]
if self.preferred_username:
search_term.append(self.preferred_username)

return search_term

def __str__(self):
return f"{self.given_name} {self.family_name}"

Expand Down
85 changes: 46 additions & 39 deletions aidants_connect_web/static/js/users_search.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,55 +19,62 @@
return _constructor;
}

const FilterController = extend(Stimulus.Controller);
// We create the collator once because it is a costly operation
const collator = new Intl.Collator(navigator.language, {
usage: "search",
sensitivity: "base",
})

// Inspired by https://github.com/idmadj/locale-includes/blob/master/src/index.js
function localeIncludes(haystack, needle) {
const haystackLength = haystack.length
const needleLength = needle.length
const lengthDiff = haystackLength - needleLength

for (var i = 0; i <= lengthDiff; i++) {
const subHaystack = haystack.substring(i, i + needleLength)
if (collator.compare(subHaystack, needle) === 0) {
return true
}
}
return false
}

/*
* This was made with Stimulus framework
* https://stimulus.hotwired.dev
*/
FilterController.prototype.onInputValueChanged = function (evt) {
this.searchValue = evt.target.value.trim();
const SearchController = extend(Stimulus.Controller)
SearchController.prototype.connect = function () {
this.searchBarTargets.forEach(function (searchBar) {
searchBar.removeAttribute("hidden")
})
}

/** Returns true if the second string contians the first, case-agnostic */
FilterController.prototype.stringContains = function (first, second) {
return first.toLocaleLowerCase().indexOf(second.toLocaleLowerCase()) !== -1;
}

FilterController.prototype.searchValueChanged = function () {
if (this.searchValue.length === 0) {
this.element.classList.remove(this.irrelevantResultClass);
return;
}

var matchedResult = (
this.stringContains(this.familynameValue, this.searchValue) ||
this.stringContains(this.firstnameValue, this.searchValue)
);

if (!matchedResult) {
this.element.classList.add(this.irrelevantResultClass);
} else {
this.element.classList.remove(this.irrelevantResultClass);
}
}

FilterController.prototype.connect = function () {
SearchController.prototype.search = function (evt) {
const self = this
document
.getElementById("filter-input")
.addEventListener("input", function (evt) {
self.onInputValueChanged(evt);
});
const searchQuery = evt.target.value.trim()
this.itemTargets.forEach(function (item) {
if (searchQuery.length === 0) {
item.classList.remove(self.irrelevantResultClass)
return
}

const searchTerms = JSON.parse(item.dataset.searchTerms)
const hasMatchingTerms = searchTerms.some(function (term) {
return localeIncludes(term, searchQuery)
})
if (hasMatchingTerms) {
item.classList.remove(self.irrelevantResultClass)
} else {
item.classList.add(self.irrelevantResultClass)
}
})
}

/* Static fields */
FilterController.classes = ["irrelevantResult"]
FilterController.values = {
firstname: String,
familyname: String,
search: String
}
SearchController.targets = ["searchBar", "item"]
SearchController.classes = ["irrelevantResult"]

function init() {
// Make search bar visible
Expand All @@ -77,7 +84,7 @@
}

const application = Stimulus.Application.start();
application.register("filter", FilterController);
application.register("search", SearchController);
}

window.addEventListener("load", init);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% extends 'layouts/main.html' %}

{% load static %}
{% load static ac_extras %}

{% block title %}Aidants Connect - Sélectionnez l'usager{% endblock %}

Expand All @@ -15,7 +15,11 @@
<h1 id="welcome_aidant">Bienvenue sur votre Espace Aidants Connect, {{ aidant.first_name }}</h1>
</div>
</div>
<section class="section section-grey mandat-select__section">
<section
class="section section-grey mandat-select__section"
data-controller="search"
data-search-irrelevant-result-class="irrelevant-result"
>
<div class="container">
<form method="post">
<h2>Sélectionnez l'usager que vous souhaitez FranceConnecter</h2>
Expand All @@ -27,11 +31,8 @@ <h2>Sélectionnez l'usager que vous souhaitez FranceConnecter</h2>
{% for usager in usagers %}
<div
class="tile usager"
data-controller="filter"
data-filter-firstname-value="{% if usager.preferred_username %}{{ usager.preferred_username }}&nbsp;{% endif %}{{ usager.family_name }}"
data-filter-familyname-value="{{ usager.given_name }}"
data-filter-search-value=""
data-filter-irrelevant-result-class="irrelevant-result"
data-search-target="item"
data-search-terms='{{ usager.search_terms|json_attribute }}'
>
<input
id="button-{{ usager.id }}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
<tr
data-controller="filter"
data-filter-firstname-value="{% if usager.preferred_username %}{{ usager.preferred_username }}&nbsp;{% endif %}{{ usager.family_name }}"
data-filter-familyname-value="{{ usager.given_name }}"
data-filter-search-value=""
data-filter-irrelevant-result-class="irrelevant-result"
>
{% load ac_extras %}

<tr data-search-target="item" data-search-terms='{{ usager.search_terms|json_attribute }}'>
<td>
<a href="{% url 'usager_details' usager_id=usager.id %}">
{% if usager.preferred_username %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
{% endblock %}

{% block content %}
<section class="section">
<section
class="section"
data-controller="search"
data-search-irrelevant-result-class="irrelevant-result"
>
<div class="container">
<div class="row">
<h1 class="margin-bottom-0">Vos usagères et usagers</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
- aidants_connect_web/static/css/users_search.css
- aidants_connect_web/static/js/users_search.js
{% endcomment %}
<div class="user-search row" hidden>
<div class="user-search row" hidden data-search-target="searchBar">
<label id="filter-input-label" for="filter-input">
Rechercher un usager ou une usagère
</label>
<input id="filter-input" type="text" />
<input id="filter-input" type="text" data-action="search#search" />
</div>
6 changes: 6 additions & 0 deletions aidants_connect_web/templatetags/ac_extras.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
from re import sub as re_sub

from django import template
Expand All @@ -7,6 +8,11 @@
register = template.Library()


@register.filter
def json_attribute(value):
return json.dumps(value)


@register.filter
def get_dict_key(dict, key):
return dict[key]
Expand Down

0 comments on commit da4cff4

Please sign in to comment.