From 8a840a4550bebe8a3c534bdf93471681a7f23ed4 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Tue, 1 Sep 2020 01:40:17 +0300 Subject: [PATCH 01/14] Search frontend Closes #500 --- www/.eslintrc | 5 +- www/application/classes/Controller/Search.php | 46 +++-- www/application/views/main.php | 191 +++++++++--------- .../templates/components/esir_navigator.php | 15 +- .../views/templates/components/search.php | 17 ++ .../app/css/components/search-modal.css | 90 +++++++++ www/public/app/js/main.js | 3 +- www/public/app/js/modules/search.js | 96 +++++++++ www/public/app/svg/escape-cross.svg | 3 + www/public/app/svg/search.svg | 15 +- 10 files changed, 357 insertions(+), 124 deletions(-) create mode 100644 www/application/views/templates/components/search.php create mode 100644 www/public/app/css/components/search-modal.css create mode 100644 www/public/app/js/modules/search.js create mode 100644 www/public/app/svg/escape-cross.svg diff --git a/www/.eslintrc b/www/.eslintrc index 9f0369133..e911e5f1e 100644 --- a/www/.eslintrc +++ b/www/.eslintrc @@ -76,6 +76,7 @@ "XMLHttpRequest": true, "ActiveXObject": true, "FileReader": true, - "process": true + "process": true, + "setTimeout": true } -} \ No newline at end of file +} diff --git a/www/application/classes/Controller/Search.php b/www/application/classes/Controller/Search.php index 9713cdddd..8b622ac1a 100644 --- a/www/application/classes/Controller/Search.php +++ b/www/application/classes/Controller/Search.php @@ -16,20 +16,40 @@ public function action_search() * Perform search for specified phrase using *query* pattern */ $query = htmlspecialchars(Arr::get($_GET, 'query', '')); - $response = $this->elastic->searchByField( - Model_Page::ELASTIC_TYPE, - self::MAX_SEARCH_RESULTS, - Model_Page::ELASTIC_SEARCH_FIELD, - $query - ); - /** - * Return Model_Page[] to user - */ - $result = array_map(function ($item) { - return new Model_Page($item['_id']); - }, $response['hits']['hits']); + $response = []; + $success = 0; + $error = ""; + + try { + $response = $this->elastic->searchByField( + Model_Page::ELASTIC_TYPE, + self::MAX_SEARCH_RESULTS, + Model_Page::ELASTIC_SEARCH_FIELD, + $query + ); + + $success = 1; + } catch (Exception $err) { + $error = $err->getMessage(); + } + + if ($success) { + /** + * Return Model_Page[] to user + */ + $result = array_map(function ($item) { + return new Model_Page($item['_id']); + }, $response['hits']['hits']); + + $search_result['html'] = View::factory( + 'templates/pages/list', + array('pages' => $result, 'active_tab' => Model_Feed_Pages::ALL) + )->render(); + } else { + $search_result['error'] = $error; + } - $this->response->body(@json_encode($result)); + $this->response->body(@json_encode($search_result)); } } diff --git a/www/application/views/main.php b/www/application/views/main.php index 203b71735..658f631d1 100644 --- a/www/application/views/main.php +++ b/www/application/views/main.php @@ -1,35 +1,35 @@ - - - - - - - - - - - - - - +<!DOCTYPE html> +<html> +<head> + + <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> + <meta name="language" content="<?= I18n::$lang ?>"> + + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <meta name="apple-mobile-web-app-capable" content="yes"> + <meta name="apple-mobile-web-app-status-bar-style" content="black"> + <meta name="format-detection" content="telephone=no"> + <meta property="og:site_name" content="<?= Arr::get($site_info, 'title', 'CodeX Media') ?>" /> + + <title> <?= $title ?: Arr::get($site_info, 'title', 'CodeX Media') . ': ' . Arr::get($site_info, 'description', '') ?> - - - - - - - - - + + + + + + + + + - - + + - - - - + + + + - - + + render(); ?> - + render(); ?> + render(); ?> - + render(); ?> - -
- -
- + +
+ +
+ -
+
render(); ?> -
- +
+ -
+
-
- +
+ render(); ?> - -
- -
- - - - + +
+ +
+ + + + - + - - - + + + - + - + - + - - - - + + + + - + - - - + + + diff --git a/www/application/views/templates/components/esir_navigator.php b/www/application/views/templates/components/esir_navigator.php index ef8765c51..662c9e10c 100644 --- a/www/application/views/templates/components/esir_navigator.php +++ b/www/application/views/templates/components/esir_navigator.php @@ -1,4 +1,17 @@ -
+
+
Сайт включен в каталог ЕСИР
diff --git a/www/application/views/templates/components/search.php b/www/application/views/templates/components/search.php new file mode 100644 index 000000000..100b48973 --- /dev/null +++ b/www/application/views/templates/components/search.php @@ -0,0 +1,17 @@ + diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css new file mode 100644 index 000000000..c8538dc0b --- /dev/null +++ b/www/public/app/css/components/search-modal.css @@ -0,0 +1,90 @@ +.search-modal { + position: absolute; + box-sizing: border-box; + z-index: 6; + top: 143px; + left: 50%; + transform: translateX(-50%); + background: #eef0f5; + font-size: 15.5px; + padding: 10px; + border-radius: 8px; + width: 670px; + + &-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, .7); + z-index: 5; + } + + &__results { + &-placeholder { + padding: 21px 14px; + color: #6e758a; + } + + &-data { + padding: 10px 0; + overflow-y: scroll; + } + } + + & input[type='search'] { + height: 56px; + border-radius: 8px; + background: #fff; + text-indent: 42px; + + &::placeholder { + color: transparent; + text-shadow: 0 0 0 var(--color-gray); + } + } + + &__exit { + &-button { + position: absolute; + left: 100%; + margin-left: 18px; + color: #e1e3eb; + text-align: center; + font-size: 12px; + font-weight: bold; + top: 7px; + cursor: pointer; + } + + &-icon { + display: block; + background: url(/public/app/svg/escape-cross.svg) no-repeat center; + border: 2px solid white; + border-radius: 50%; + width: 28px; + height: 28px; + margin-bottom: 10px; + } + } + + &__input-wrapper { + display: flex; + position: relative; + } + + label { + display: block; + background: url(/public/app/svg/search.svg) no-repeat; + height: 16px; + line-height: 16px; + width: 16px; + background-size: 16px; + color: #7b8999; + position: absolute; + left: 21px; + top: 50%; + transform: translateY(-50%); + } +} diff --git a/www/public/app/js/main.js b/www/public/app/js/main.js index 304cebed9..b252e4cf2 100644 --- a/www/public/app/js/main.js +++ b/www/public/app/js/main.js @@ -153,5 +153,6 @@ codex.avatarUploader = require('./modules/avatarUploader'); codex.layout = require('./modules/layout'); codex.pageTypeSelector = require('./modules/pageTypeSelector'); codex.datePicker = require('./modules/datePicker'); +codex.search = require('./modules/search'); -module.exports = codex; \ No newline at end of file +module.exports = codex; diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js new file mode 100644 index 000000000..3368b2c4c --- /dev/null +++ b/www/public/app/js/modules/search.js @@ -0,0 +1,96 @@ +const ajax = require('@codexteam/ajax'); + +const MIN_SEARCH_LENGTH = 3; +const SEARCH_TIMEOUT = 1000; + +const SEARCH_PLACEHOLDER = 'Начните вводить поисковый запрос'; +const NO_RESULTS_PLACEHOLDER = 'Ничего не найдено'; + +const search = { + + elements: { + modal: null, + placeholder: null, + input: null, + searchResults: null, + closer: null, + }, + + wait: false, + + init: function ({elementId, closerId, inputId, resultsId, placeholderId}) { + + this.elements.modal = document.getElementById(elementId); + this.elements.closer = document.getElementById(closerId); + this.elements.input = document.getElementById(inputId); + this.elements.searchResults = document.getElementById(resultsId); + this.elements.placeholder = document.getElementById(placeholderId); + + }, + + show: function () { + + if (this.elements.modal) { + + this.elements.modal.removeAttribute('hidden'); + document.body.style.overflow = 'hidden'; + + } + + this.elements.closer && this.elements.closer.addEventListener('click', () => this.hide()); + + this.elements.input && this.elements.input.addEventListener( + 'keydown', (event) => this.search(event.target.value) + ); + + }, + + hide: function () { + + this.elements.modal.setAttribute('hidden', true); + document.body.style.overflow = 'auto'; + + this.elements.searchResults.innerHTML = SEARCH_PLACEHOLDER; + this.elements.input.value = ''; + + }, + + search: function (value) { + + if (value.length < MIN_SEARCH_LENGTH || this.wait) { + + return; + + } + + ajax.get({ + url: '/search', + data: { + query: value + }, + type: ajax.contentType.FORM + }).then(response => { + + if (response.body['html']) { + + this.elements.searchResults.removeAttribute('hidden'); + this.elements.searchResults.innerHTML = response.body['html']; + + this.elements.placeholder.hidden = true; + + } else { + + this.elements.placeholder.innerText = NO_RESULTS_PLACEHOLDER; + + } + + }); + + this.wait = true; + + setTimeout(() => this.wait = false, SEARCH_TIMEOUT); + + } +}; + +module.exports = search; diff --git a/www/public/app/svg/escape-cross.svg b/www/public/app/svg/escape-cross.svg new file mode 100644 index 000000000..86074453d --- /dev/null +++ b/www/public/app/svg/escape-cross.svg @@ -0,0 +1,3 @@ + + + diff --git a/www/public/app/svg/search.svg b/www/public/app/svg/search.svg index e424187d4..5461a0e47 100644 --- a/www/public/app/svg/search.svg +++ b/www/public/app/svg/search.svg @@ -1,12 +1,3 @@ - - - Created with Sketch. - - - - - - - - - \ No newline at end of file + + + From 47865834dd6b067538ad8c1bb5a9277323a48278 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Fri, 11 Sep 2020 20:40:16 +0300 Subject: [PATCH 02/14] Add empty placeholder --- www/application/classes/Controller/Search.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/www/application/classes/Controller/Search.php b/www/application/classes/Controller/Search.php index 8b622ac1a..efaf84bcf 100644 --- a/www/application/classes/Controller/Search.php +++ b/www/application/classes/Controller/Search.php @@ -44,7 +44,11 @@ public function action_search() $search_result['html'] = View::factory( 'templates/pages/list', - array('pages' => $result, 'active_tab' => Model_Feed_Pages::ALL) + array( + 'pages' => $result, + 'active_tab' => Model_Feed_Pages::ALL, + 'emptyListMessage' => 'Ничего не найдено' + ) )->render(); } else { $search_result['error'] = $error; From 859dc518e06794185fe60dc11ad1483f837e9715 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Fri, 11 Sep 2020 20:59:32 +0300 Subject: [PATCH 03/14] Fix placeholders stuff --- www/public/app/css/components/search-modal.css | 3 ++- www/public/app/js/modules/search.js | 12 +++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css index c8538dc0b..8dffec81d 100644 --- a/www/public/app/css/components/search-modal.css +++ b/www/public/app/css/components/search-modal.css @@ -28,7 +28,8 @@ } &-data { - padding: 10px 0; + padding-top: 10px; + max-height: 315px; overflow-y: scroll; } } diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index 3368b2c4c..15e6b673a 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -3,9 +3,6 @@ const ajax = require('@codexteam/ajax'); const MIN_SEARCH_LENGTH = 3; const SEARCH_TIMEOUT = 1000; -const SEARCH_PLACEHOLDER = 'Начните вводить поисковый запрос'; -const NO_RESULTS_PLACEHOLDER = 'Ничего не найдено'; - const search = { elements: { @@ -50,7 +47,8 @@ const search = { this.elements.modal.setAttribute('hidden', true); document.body.style.overflow = 'auto'; - this.elements.searchResults.innerHTML = SEARCH_PLACEHOLDER; + this.elements.searchResults.setAttribute('hidden', true); + this.elements.placeholder.removeAttribute('hidden'); this.elements.input.value = ''; }, @@ -76,11 +74,7 @@ const search = { this.elements.searchResults.removeAttribute('hidden'); this.elements.searchResults.innerHTML = response.body['html']; - this.elements.placeholder.hidden = true; - - } else { - - this.elements.placeholder.innerText = NO_RESULTS_PLACEHOLDER; + this.elements.placeholder.setAttribute('hidden', true); } From 4902500577a3720d095dd14c14117eb13f8271cb Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sat, 12 Sep 2020 22:01:59 +0300 Subject: [PATCH 04/14] Use throttle --- www/public/app/js/modules/core.js | 43 +++++++++++++++++++++++++++++ www/public/app/js/modules/search.js | 14 ++++------ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/www/public/app/js/modules/core.js b/www/public/app/js/modules/core.js index 3b61a9bf5..577dfe7af 100644 --- a/www/public/app/js/modules/core.js +++ b/www/public/app/js/modules/core.js @@ -316,4 +316,47 @@ module.exports = { }, + /** + * Throttling method + * Call method after passed time + * + * @param {Function} func - function that we're throttling + * @param {Number} wait - time in milliseconds + * @param {Boolean} immediate - call now + * @return {Function} + */ + throttle: function (func, wait, immediate) { + + let timeout; + + return function () { + + let context = this, + args = arguments; + + let later = function () { + + timeout = null; + if (!immediate) { + + func.apply(context, args); + + } + + }; + + let callNow = immediate && !timeout; + + window.clearTimeout(timeout); + timeout = window.setTimeout(later, wait); + if (callNow) { + + func.apply(context, args); + + } + + }; + + } + }; diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index 15e6b673a..c117cbb39 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -13,8 +13,6 @@ const search = { closer: null, }, - wait: false, - init: function ({elementId, closerId, inputId, resultsId, placeholderId}) { this.elements.modal = document.getElementById(elementId); @@ -36,8 +34,12 @@ const search = { this.elements.closer && this.elements.closer.addEventListener('click', () => this.hide()); + const delayedSearch = codex.core.throttle( + (value) => this.search(value), SEARCH_TIMEOUT, true + ); + this.elements.input && this.elements.input.addEventListener( - 'keydown', (event) => this.search(event.target.value) + 'keydown', (event) => delayedSearch(event.target.value) ); }, @@ -55,7 +57,7 @@ const search = { search: function (value) { - if (value.length < MIN_SEARCH_LENGTH || this.wait) { + if (value.length < MIN_SEARCH_LENGTH) { return; @@ -80,10 +82,6 @@ const search = { }); - this.wait = true; - - setTimeout(() => this.wait = false, SEARCH_TIMEOUT); - } }; From 44f72a10b07b30bfc9fb55772d377ef404285491 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sat, 12 Sep 2020 22:07:49 +0300 Subject: [PATCH 05/14] Padding -> margin --- www/public/app/css/components/search-modal.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css index 8dffec81d..ffc60a3f0 100644 --- a/www/public/app/css/components/search-modal.css +++ b/www/public/app/css/components/search-modal.css @@ -28,7 +28,7 @@ } &-data { - padding-top: 10px; + margin-top: 10px; max-height: 315px; overflow-y: scroll; } From 0cc687a481323a666f7da4c11f95e518cf1a38e4 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sat, 12 Sep 2020 22:48:41 +0300 Subject: [PATCH 06/14] Change event type --- www/public/app/js/modules/search.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index c117cbb39..1ea40a169 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -1,7 +1,7 @@ const ajax = require('@codexteam/ajax'); const MIN_SEARCH_LENGTH = 3; -const SEARCH_TIMEOUT = 1000; +const SEARCH_TIMEOUT = 500; const search = { @@ -35,11 +35,11 @@ const search = { this.elements.closer && this.elements.closer.addEventListener('click', () => this.hide()); const delayedSearch = codex.core.throttle( - (value) => this.search(value), SEARCH_TIMEOUT, true + (value) => this.search(value), SEARCH_TIMEOUT, false ); this.elements.input && this.elements.input.addEventListener( - 'keydown', (event) => delayedSearch(event.target.value) + 'input', (event) => delayedSearch(event.target.value) ); }, From 5443dd0c2e3b89c0be065dcace2c0f662543fcd4 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sat, 12 Sep 2020 23:19:51 +0300 Subject: [PATCH 07/14] Change search query --- www/application/classes/Model/Elastic.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/application/classes/Model/Elastic.php b/www/application/classes/Model/Elastic.php index f31043d9e..4c7c9b542 100644 --- a/www/application/classes/Model/Elastic.php +++ b/www/application/classes/Model/Elastic.php @@ -70,8 +70,8 @@ public function searchByField($type, $size, $field, $query) 'type' => $type, 'body' => [ 'query' => [ - 'match' => [ - $field => '*' . $query . '*' + 'prefix' => [ + $field => $query ] ] ] From 1200ed82992840af8ca6ad28cc6e0705a9f46329 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sun, 13 Sep 2020 00:34:27 +0300 Subject: [PATCH 08/14] Add loader --- .../app/css/components/search-modal.css | 35 +++++++++++++++++++ www/public/app/js/modules/search.js | 21 +++++++++-- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css index ffc60a3f0..c65fe6035 100644 --- a/www/public/app/css/components/search-modal.css +++ b/www/public/app/css/components/search-modal.css @@ -29,8 +29,19 @@ &-data { margin-top: 10px; + min-height: 185px; max-height: 315px; overflow-y: scroll; + + .post-list-item { + border-radius: 8px; + } + + &.loading { + opacity: 0.5; + position: relative; + overflow: hidden; + } } } @@ -88,4 +99,28 @@ top: 50%; transform: translateY(-50%); } + + .loader { + &::before { + content: ''; + box-sizing: border-box; + position: absolute; + top: 50%; + left: 50%; + width: 60px; + height: 60px; + margin-top: -30px; + margin-left: -30px; + border-radius: 50%; + border: 3px solid #ccc; + border-top-color: #7b8999; + animation: spinner 0.6s linear infinite; + } + } + + @keyframes spinner { + to { + transform: rotate(360deg); + } + } } diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index 1ea40a169..32b005499 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -11,6 +11,7 @@ const search = { input: null, searchResults: null, closer: null, + loader: null, }, init: function ({elementId, closerId, inputId, resultsId, placeholderId}) { @@ -20,6 +21,7 @@ const search = { this.elements.input = document.getElementById(inputId); this.elements.searchResults = document.getElementById(resultsId); this.elements.placeholder = document.getElementById(placeholderId); + this.elements.loader = this.createLoader(); }, @@ -44,6 +46,16 @@ const search = { }, + createLoader: function () { + + const loader = document.createElement('div'); + + loader.classList.add('loader'); + + return loader; + + }, + hide: function () { this.elements.modal.setAttribute('hidden', true); @@ -63,6 +75,11 @@ const search = { } + this.elements.placeholder.setAttribute('hidden', true); + this.elements.searchResults.removeAttribute('hidden'); + this.elements.searchResults.classList.add('loading'); + this.elements.searchResults.appendChild(this.elements.loader); + ajax.get({ url: '/search', data: { @@ -73,10 +90,8 @@ const search = { if (response.body['html']) { - this.elements.searchResults.removeAttribute('hidden'); this.elements.searchResults.innerHTML = response.body['html']; - - this.elements.placeholder.setAttribute('hidden', true); + this.elements.searchResults.classList.remove('loading'); } From 6a2b64cedfe0b492bdce77e6bb711e08ac0c3dc1 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sun, 13 Sep 2020 00:39:26 +0300 Subject: [PATCH 09/14] Decrease margin --- www/public/app/css/components/search-modal.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css index c65fe6035..b3e5509b4 100644 --- a/www/public/app/css/components/search-modal.css +++ b/www/public/app/css/components/search-modal.css @@ -35,6 +35,10 @@ .post-list-item { border-radius: 8px; + + &:last-of-type { + margin-bottom: 0; + } } &.loading { From 29c7c53e59334b3b075c8707cd3d148145b605fe Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Sun, 27 Sep 2020 23:49:50 +0300 Subject: [PATCH 10/14] Fix search engine --- www/application/classes/Controller/Search.php | 9 ++++++++- www/application/classes/Model/Elastic.php | 9 +++++---- www/application/classes/Model/Page.php | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/www/application/classes/Controller/Search.php b/www/application/classes/Controller/Search.php index efaf84bcf..452647dd2 100644 --- a/www/application/classes/Controller/Search.php +++ b/www/application/classes/Controller/Search.php @@ -25,7 +25,7 @@ public function action_search() $response = $this->elastic->searchByField( Model_Page::ELASTIC_TYPE, self::MAX_SEARCH_RESULTS, - Model_Page::ELASTIC_SEARCH_FIELD, + Model_Page::ELASTIC_SEARCH_FIELDS, $query ); @@ -42,6 +42,13 @@ public function action_search() return new Model_Page($item['_id']); }, $response['hits']['hits']); + /** + * Sort by date: display newest first + */ + usort($result, function($first, $second){ + return $first->date < $second->date; + }); + $search_result['html'] = View::factory( 'templates/pages/list', array( diff --git a/www/application/classes/Model/Elastic.php b/www/application/classes/Model/Elastic.php index 4c7c9b542..dcc55d451 100644 --- a/www/application/classes/Model/Elastic.php +++ b/www/application/classes/Model/Elastic.php @@ -56,12 +56,12 @@ public function get($type, $id) /** * @param $type - entity type (table in elastic db) * @param $size - maximum search results to return - * @param $field - in what entity field to search + * @param $fields - in what entity fields to search * @param $query - what occurrence to search * * @return array - search result */ - public function searchByField($type, $size, $field, $query) + public function searchByField($type, $size, $fields, $query) { return $this->client->search( [ @@ -70,8 +70,9 @@ public function searchByField($type, $size, $field, $query) 'type' => $type, 'body' => [ 'query' => [ - 'prefix' => [ - $field => $query + 'simple_query_string' => [ + 'query' => $query . '*', + 'fields' => $fields ] ] ] diff --git a/www/application/classes/Model/Page.php b/www/application/classes/Model/Page.php index 4916955cd..fd83fc43b 100644 --- a/www/application/classes/Model/Page.php +++ b/www/application/classes/Model/Page.php @@ -84,7 +84,7 @@ class Model_Page extends Model /** * Field in elastic db used to store searchable page content: paragraphs, headings and lists */ - const ELASTIC_SEARCH_FIELD = 'text'; + const ELASTIC_SEARCH_FIELDS = ['text', 'title']; private $modelCacheKey; From de0889652ee9a0e0c2f911b1eec79a8645387762 Mon Sep 17 00:00:00 2001 From: Taly Date: Tue, 6 Oct 2020 15:57:02 +0300 Subject: [PATCH 11/14] Update docker-compose.yml --- docker-compose.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 02cdfbd9a..6ebe77582 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '2' services: mysql: image: 'mysql:5.7' - restart: always + restart: unless-stopped volumes: - './dump/mysql:/dump' - mysqldata:/var/lib/mysql @@ -15,14 +15,14 @@ services: redis: image: 'redis:6.0.5-alpine' - restart: always + restart: unless-stopped command: ["redis-server", "--save 900 1", "--save 300 10", "--save 60 10000"] volumes: - ./dump/redis:/data elasticsearch: image: 'elasticsearch:7.4.0' - restart: always + restart: unless-stopped environment: - xpack.security.enabled=false - discovery.type=single-node @@ -42,7 +42,7 @@ services: build: dockerfile: 'docker/php/Dockerfile' context: '.' - restart: always + restart: unless-stopped depends_on: - redis - mysql @@ -58,7 +58,7 @@ services: nginx: image: 'nginx:1.19.1-alpine' - restart: always + restart: unless-stopped ports: - "127.0.0.1:${APP_PORT}:8080" links: From 727b6526afdb15566fa96d59e7c9b69a40f86394 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Wed, 11 Nov 2020 02:04:37 +0300 Subject: [PATCH 12/14] Use class instead of commonJS module --- www/public/app/js/main.js | 5 +- www/public/app/js/modules/core.js | 6 +-- www/public/app/js/modules/search.js | 81 +++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 26 deletions(-) diff --git a/www/public/app/js/main.js b/www/public/app/js/main.js index b252e4cf2..82af81765 100644 --- a/www/public/app/js/main.js +++ b/www/public/app/js/main.js @@ -153,6 +153,9 @@ codex.avatarUploader = require('./modules/avatarUploader'); codex.layout = require('./modules/layout'); codex.pageTypeSelector = require('./modules/pageTypeSelector'); codex.datePicker = require('./modules/datePicker'); -codex.search = require('./modules/search'); + +const SearchModule = require('./modules/search').default; + +codex.search = new SearchModule(); module.exports = codex; diff --git a/www/public/app/js/modules/core.js b/www/public/app/js/modules/core.js index 577dfe7af..6bc535089 100644 --- a/www/public/app/js/modules/core.js +++ b/www/public/app/js/modules/core.js @@ -317,15 +317,15 @@ module.exports = { }, /** - * Throttling method + * Debounce method * Call method after passed time * - * @param {Function} func - function that we're throttling + * @param {Function} func - function which call is delayed * @param {Number} wait - time in milliseconds * @param {Boolean} immediate - call now * @return {Function} */ - throttle: function (func, wait, immediate) { + debounce: function (func, wait, immediate) { let timeout; diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index 32b005499..4e5143e3e 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -3,18 +3,33 @@ const ajax = require('@codexteam/ajax'); const MIN_SEARCH_LENGTH = 3; const SEARCH_TIMEOUT = 500; -const search = { +export default class Search { + + constructor() { + + /** + * DOM elements involved in search process + */ + this.elements = { + modal: null, + placeholder: null, + input: null, + searchResults: null, + closer: null, + loader: null, + }; - elements: { - modal: null, - placeholder: null, - input: null, - searchResults: null, - closer: null, - loader: null, - }, + } - init: function ({elementId, closerId, inputId, resultsId, placeholderId}) { + /** + * Prepare DOM elements to work with + * @param elementId - search modal id + * @param closerId - modal close button id + * @param inputId - search input id + * @param resultsId - search results element id + * @param placeholderId - search placeholder id + */ + init({elementId, closerId, inputId, resultsId, placeholderId}) { this.elements.modal = document.getElementById(elementId); this.elements.closer = document.getElementById(closerId); @@ -23,9 +38,12 @@ const search = { this.elements.placeholder = document.getElementById(placeholderId); this.elements.loader = this.createLoader(); - }, + } - show: function () { + /** + * Reveals search modal to user & sets up event listeners + */ + show() { if (this.elements.modal) { @@ -36,7 +54,7 @@ const search = { this.elements.closer && this.elements.closer.addEventListener('click', () => this.hide()); - const delayedSearch = codex.core.throttle( + const delayedSearch = codex.core.debounce( (value) => this.search(value), SEARCH_TIMEOUT, false ); @@ -44,9 +62,13 @@ const search = { 'input', (event) => delayedSearch(event.target.value) ); - }, + }; - createLoader: function () { + /** + * Creates loader to show while search is in progress + * @returns {HTMLDivElement} + */ + createLoader() { const loader = document.createElement('div'); @@ -54,9 +76,12 @@ const search = { return loader; - }, + }; - hide: function () { + /** + * Hide modal and reset related DOM elements appearance + */ + hide() { this.elements.modal.setAttribute('hidden', true); document.body.style.overflow = 'auto'; @@ -65,16 +90,26 @@ const search = { this.elements.placeholder.removeAttribute('hidden'); this.elements.input.value = ''; - }, + }; - search: function (value) { + /** + * Perform search on user input + * @param value + */ + search(value) { + /** + * Don't search if input is too short + */ if (value.length < MIN_SEARCH_LENGTH) { return; } + /** + * Adjust related DOM elements appearance + */ this.elements.placeholder.setAttribute('hidden', true); this.elements.searchResults.removeAttribute('hidden'); this.elements.searchResults.classList.add('loading'); @@ -88,6 +123,9 @@ const search = { type: ajax.contentType.FORM }).then(response => { + /** + * Show search results to user + */ if (response.body['html']) { this.elements.searchResults.innerHTML = response.body['html']; @@ -97,7 +135,6 @@ const search = { }); - } -}; + }; -module.exports = search; +} From 374f5d2da7738e8e78bede805516315b40719049 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Thu, 19 Nov 2020 01:23:19 +0300 Subject: [PATCH 13/14] Review corrections --- www/application/classes/Controller/Search.php | 2 +- .../app/css/components/search-modal.css | 19 +++++++++++++------ www/public/app/js/modules/search.js | 11 ++++++++++- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/www/application/classes/Controller/Search.php b/www/application/classes/Controller/Search.php index 452647dd2..e99fd7b13 100644 --- a/www/application/classes/Controller/Search.php +++ b/www/application/classes/Controller/Search.php @@ -36,7 +36,7 @@ public function action_search() if ($success) { /** - * Return Model_Page[] to user + * Return pages search result to user */ $result = array_map(function ($item) { return new Model_Page($item['_id']); diff --git a/www/public/app/css/components/search-modal.css b/www/public/app/css/components/search-modal.css index b3e5509b4..7c5422c0b 100644 --- a/www/public/app/css/components/search-modal.css +++ b/www/public/app/css/components/search-modal.css @@ -1,3 +1,10 @@ +:root { + --overlay-bg: rgba(0, 0, 0, .7); + --placeholder-color: #6e758a; + --loader-color: #ccc; + --blue-gray: #7b8999; +} + .search-modal { position: absolute; box-sizing: border-box; @@ -17,14 +24,14 @@ left: 0; width: 100%; height: 100%; - background: rgba(0, 0, 0, .7); + background: var(--overlay-bg); z-index: 5; } &__results { &-placeholder { padding: 21px 14px; - color: #6e758a; + color: var(--placeholder-color); } &-data { @@ -52,7 +59,7 @@ & input[type='search'] { height: 56px; border-radius: 8px; - background: #fff; + background: var(--color-white); text-indent: 42px; &::placeholder { @@ -97,7 +104,7 @@ line-height: 16px; width: 16px; background-size: 16px; - color: #7b8999; + color: var(--blue-gray); position: absolute; left: 21px; top: 50%; @@ -116,8 +123,8 @@ margin-top: -30px; margin-left: -30px; border-radius: 50%; - border: 3px solid #ccc; - border-top-color: #7b8999; + border: 3px solid var(--loader-color); + border-top-color: var(--blue-gray); animation: spinner 0.6s linear infinite; } } diff --git a/www/public/app/js/modules/search.js b/www/public/app/js/modules/search.js index 4e5143e3e..04437a301 100644 --- a/www/public/app/js/modules/search.js +++ b/www/public/app/js/modules/search.js @@ -1,8 +1,17 @@ const ajax = require('@codexteam/ajax'); +/** + * Allow text search starting from the following input length + */ const MIN_SEARCH_LENGTH = 3; +/** + * Search debounce timeout — prevents from sending search requests during user input + */ const SEARCH_TIMEOUT = 500; +/** + * This allows the user to perform a text search on the site's articles. + */ export default class Search { constructor() { @@ -94,7 +103,7 @@ export default class Search { /** * Perform search on user input - * @param value + * @param value - input string to search for */ search(value) { From 302d392cf61adacac82267d47a799867c790be92 Mon Sep 17 00:00:00 2001 From: Polina Shneider Date: Wed, 23 Dec 2020 03:02:53 +0300 Subject: [PATCH 14/14] Work in progress --- .../templates/components/esir_navigator.php | 3 +- .../views/templates/components/search.php | 6 +- .../app/css/components/search-modal.css | 144 ++++++++++-------- www/public/app/js/modules/search.js | 86 +++++++---- 4 files changed, 145 insertions(+), 94 deletions(-) diff --git a/www/application/views/templates/components/esir_navigator.php b/www/application/views/templates/components/esir_navigator.php index 662c9e10c..ab7f12924 100644 --- a/www/application/views/templates/components/esir_navigator.php +++ b/www/application/views/templates/components/esir_navigator.php @@ -5,7 +5,8 @@ class="schools-navigator" >