From 0f63a864f87308492b910ddb98ff2055d0ecba15 Mon Sep 17 00:00:00 2001 From: parallels Date: Fri, 14 Jun 2024 16:20:10 +1000 Subject: [PATCH] Dropdown selection list for advanced search keywords --- .../controllers/public/Public_ajax.php | 9 +++++ application/models/Keyword_model.php | 34 +++++++++++++++++++ .../catalog/partials/advanced_search.php | 28 +++++++++++++-- public_html/js/common/autocomplete.js | 31 ++++++++++++++--- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/application/controllers/public/Public_ajax.php b/application/controllers/public/Public_ajax.php index 23608786..811ab54e 100644 --- a/application/controllers/public/Public_ajax.php +++ b/application/controllers/public/Public_ajax.php @@ -15,6 +15,15 @@ function autocomplete_author() $this->load->model('author_model'); echo json_encode($this->author_model->autocomplete($term, $search_field)); } + + function autocomplete_keywords() + { + $term = $this->input->post('term'); + $this->load->model('keyword_model'); + $data = json_encode($this->keyword_model->autocomplete($term)); + echo $data; + + } function autocomplete_user() { diff --git a/application/models/Keyword_model.php b/application/models/Keyword_model.php index 9ab13cb7..5c407b73 100644 --- a/application/models/Keyword_model.php +++ b/application/models/Keyword_model.php @@ -9,6 +9,40 @@ public function get_applied($list_keywords) } + + public function autocomplete($term) + { + // Escaping -- https://www.codeigniter.com/userguide3/database/queries.html#escaping-queries + $escaped_term = $this->db->escape_like_str($term); + + // For extra safety, parameterise the query as well + + $params = []; + array_push($params, $escaped_term . "%"); + array_push($params, $escaped_term); + array_push($params, "%" . $escaped_term . "%"); + array_push($params, $escaped_term . "%"); + + $sql = 'SELECT DISTINCT k.value, "A" AS priority + FROM keywords k + JOIN project_keywords pk + ON k.id = pk.keyword_id + WHERE k.value LIKE ? + UNION + SELECT "=== some other keywords containing \"?\" ===" AS value, "B" AS priority + UNION + SELECT DISTINCT k.value, "C" AS priority + FROM keywords k + JOIN project_keywords pk + ON k.id = pk.keyword_id + WHERE k.value LIKE ? + AND k.value NOT LIKE ? + ORDER BY priority ASC, value ASC + LIMIT 200'; + + $query = $this->db->query($sql, $params); + return $query->result_array(); + } //return comma delimited list of keywords from project public function create_keyword_list($project_id) diff --git a/application/views/catalog/partials/advanced_search.php b/application/views/catalog/partials/advanced_search.php index ec0cef2d..0c04866b 100644 --- a/application/views/catalog/partials/advanced_search.php +++ b/application/views/catalog/partials/advanced_search.php @@ -1,5 +1,7 @@ + +
@@ -47,7 +49,7 @@
@@ -111,4 +113,26 @@ -
+ + + + + + + + + + + diff --git a/public_html/js/common/autocomplete.js b/public_html/js/common/autocomplete.js index bdbd255d..4d19f127 100644 --- a/public_html/js/common/autocomplete.js +++ b/public_html/js/common/autocomplete.js @@ -1,8 +1,27 @@ set_autocomplete(); +/** + * Set up auto-complete boxes using jQuery Autocomplete. + * + * Input elements need to define the following attributes: + * + * - data-search_func - The backend ajax function to call + * - data-search_field - The name of the field + * - data-search_area - Which area on the page is being auto-completed + * - data-array_index - Used when you've got multiple inputs in one area (e.g. multiple authors) + * + * In the pages where this script is included, you'll also need to define two + * functions: + * + * - autocomplete_assign_vars - Maps backend results to values to show in the drop-down + * - autocomplete_assign_elements - Handles updating inputs when a value is selected + * + * See also: https://api.jqueryui.com/autocomplete/ + */ + function set_autocomplete() { var search_area; - var array_index; + var array_index; $( ".autocomplete" ).autocomplete({ source: function(request, response) { @@ -10,18 +29,18 @@ function set_autocomplete() { var element = this.element; var search_func = element.attr('data-search_func'); var search_field = element.attr('data-search_field'); - array_index = element.attr('data-array_index'); + array_index = element.attr('data-array_index'); search_area = element.attr('data-search_area'); $.ajax({ url: CI_ROOT + 'public/public_ajax/' + search_func, data: { 'term': element.val(), 'search_field': search_field}, dataType: "json", type: "POST", - global: false, // prevent modal loader dialog + global: false, // prevent modal loader dialog success: function (data) { if (data != null) { response($.map(data, function (item) { - return autocomplete_assign_vars(item); + return autocomplete_assign_vars(item); })) } else $(".ui-autocomplete").css({ "display": "none" @@ -38,7 +57,9 @@ function set_autocomplete() { return false; } }); -} + +} + /* .data('autocomplete')._renderItem() = function (ul, item) {