diff --git a/aleksis/core/models.py b/aleksis/core/models.py index e1eb5858da9b42150f75c31f762d0bc720a0a335..6c994a9fe983c8034630abc1bb8fb239f3c48379 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -95,6 +95,8 @@ class Person(ExtensibleModel): verbose_name = _("Person") verbose_name_plural = _("Persons") + icon_ = "person" + SEX_CHOICES = [("f", _("female")), ("m", _("male"))] user = models.OneToOneField( @@ -227,6 +229,8 @@ class Group(ExtensibleModel): verbose_name = _("Group") verbose_name_plural = _("Groups") + icon_ = "group" + name = models.CharField(verbose_name=_("Long name of group"), max_length=255, unique=True) short_name = models.CharField(verbose_name=_("Short name of group"), max_length=255, unique=True, blank=True, null=True) diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js index f3439d2a573a93a094e189c142e0d9fc6ee41cf8..275e3ae6e7765823308ba3f4bc91c2c462211b16 100644 --- a/aleksis/core/static/js/main.js +++ b/aleksis/core/static/js/main.js @@ -64,4 +64,8 @@ $(document).ready( function () { "paging": false }); }); + + // Initialise auto-completion for search bar + window.autocomplete = new Autocomplete({}); + window.autocomplete.setup(); }); diff --git a/aleksis/core/static/js/search.js b/aleksis/core/static/js/search.js new file mode 100644 index 0000000000000000000000000000000000000000..304f7f639010bba61b84479088c9a2da6a3db0d6 --- /dev/null +++ b/aleksis/core/static/js/search.js @@ -0,0 +1,63 @@ +/* + * Based on: https://django-haystack.readthedocs.io/en/master/autocomplete.html + * + * © Copyright 2009-2016, Daniel Lindsley + * Licensed under the 3-clause BSD license + */ + +var Autocomplete = function(options) { + this.form_selector = options.form_selector || '.autocomplete'; + this.url = options.url || Urls.searchbarSnippets(); + this.delay = parseInt(options.delay || 300); + this.minimum_length = parseInt(options.minimum_length || 3); + this.form_elem = null; + this.query_box = null; +} + +Autocomplete.prototype.setup = function() { + var self = this; + + this.form_elem = $(this.form_selector); + this.query_box = this.form_elem.find('input[name=q]'); + + // Watch the input box. + this.query_box.on('keyup', function() { + var query = self.query_box.val(); + + if(query.length < self.minimum_length) { + return false; + } + + self.fetch(query); + }); + + // On selecting a result, remove result box + this.form_elem.on('click', '#search-results', function(ev) { + $('#search-results').remove(); + return true; + }); + + // Disable browser's own autocomplete + // We do this here so users without JavaScript can keep it enabled + this.query_box.attr('autocomplete', 'off'); +} + +Autocomplete.prototype.fetch = function(query) { + var self = this; + + $.ajax({ + url: this.url + , data: { + 'q': query + } + , success: function(data) { + self.show_results(data); + } + }) +} + +Autocomplete.prototype.show_results = function(data) { + $('#search-results').remove(); + var results_wrapper = $('<div id="search-results">' + data + '</div>'); + this.query_box.after(results_wrapper); +} diff --git a/aleksis/core/static/style.scss b/aleksis/core/static/style.scss index d36fd43423b85d8e29a5e7630ee165311aa2f0c8..4f91d3a3dfae93bc8672cefb6c987b183942a809 100644 --- a/aleksis/core/static/style.scss +++ b/aleksis/core/static/style.scss @@ -168,7 +168,7 @@ li.active > a > .sidenav-badge { box-shadow: none; } -.sidenav li.search .search-wrapper i.material-icons { +.sidenav li.search .search-wrapper > i.material-icons { position: absolute; top: 21px; right: 10px; @@ -532,3 +532,12 @@ main .alert p:first-child, main .alert div:first-child { width: 100%; } +div#search-results { + position: absolute; + width: 100%; +} + +.search-result-icon { + position: absolute; + right: 10px; +} diff --git a/aleksis/core/templates/core/base.html b/aleksis/core/templates/core/base.html index ef8d9c77f90b549c1d8b0ec732caaa81c4900c09..491cc0b8689e8232d66fd83faeaa68fdbf3dbb17 100644 --- a/aleksis/core/templates/core/base.html +++ b/aleksis/core/templates/core/base.html @@ -32,6 +32,8 @@ {# Include jQuery to provide $(document).ready #} {% include_js "jQuery" %} + <script type="text/javascript" src="{% static 'js/search.js' %}"></script> + {% block extra_head %}{% endblock %} </head> <body> @@ -70,10 +72,12 @@ </a> </li> <li class="search"> - <div class="search-wrapper"> - <input id="search" placeholder="{% trans "Search" %}"> - <i class="material-icons">search</i> - </div> + <form method="post" action="#" class="autocomplete"> + <div class="search-wrapper"> + <input id="search" name="q" placeholder="{% trans "Search" %}"> + <i class="material-icons">search</i> + </div> + </form> </li> <li class="no-padding"> {% include "core/sidenav.html" %} diff --git a/aleksis/core/templates/search/searchbar_snippet.html b/aleksis/core/templates/search/searchbar_snippet.html index 88c8411bf2fd14f0ab9f120cb3dc0b3788df5f7d..c191317a3596a97d3f87d1f2c617be8c4f75d33a 100644 --- a/aleksis/core/templates/search/searchbar_snippet.html +++ b/aleksis/core/templates/search/searchbar_snippet.html @@ -1,7 +1,4 @@ <a href="{{ result.object.get_absolute_url|default:"#" }}" class="collection-item"> - <span class="secondary-content"> - <i class="material-icons">{{ result.object.icon }}</i> - </span> {{ result.object }} + <i class="material-icons secondary-content search-result-icon">{{ result.object.icon_ }}</i> </a> - \ No newline at end of file