Skip to content

Commit 35b7f01

Browse files
committed
implements lookup search parameter
1 parent eb93a9b commit 35b7f01

File tree

6 files changed

+421
-4
lines changed

6 files changed

+421
-4
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace PlumSearch\FormParameter;
5+
6+
use Cake\Routing\Router;
7+
8+
/**
9+
* Class LookupParameter
10+
*
11+
* A custom parameter for autocomplete lookups using existing endpoints
12+
*
13+
* @package App\FormParameter
14+
*/
15+
class LookupParameter extends BaseParameter
16+
{
17+
/**
18+
* Default configuration
19+
*
20+
* @var array
21+
*/
22+
protected $_defaultConfig = [
23+
'visible' => true,
24+
'autocompleteUrl' => null,
25+
'idName' => 'id',
26+
'valueName' => 'name',
27+
'query' => 'search=%QUERY',
28+
'wildcard' => '%QUERY',
29+
'minLength' => 2,
30+
'delay' => 300,
31+
];
32+
33+
/**
34+
* Constructor
35+
*
36+
* @param \PlumSearch\FormParameter\ParameterRegistry $registry ParameterRegistry object.
37+
* @param array $config Object settings.
38+
*/
39+
public function __construct(\PlumSearch\FormParameter\ParameterRegistry $registry, array $config = [])
40+
{
41+
parent::__construct($registry, $config);
42+
$config['field'] = $config['name'] . '_lookup';
43+
$this->setConfig($config);
44+
}
45+
46+
/**
47+
* Get autocomplete URL
48+
*
49+
* @return string
50+
*/
51+
public function autocompleteUrl(): string
52+
{
53+
$url = $this->getConfig('autocompleteUrl');
54+
if (is_array($url)) {
55+
return Router::url($url);
56+
}
57+
return (string)$url;
58+
}
59+
60+
/**
61+
* Initialize inner parameters
62+
*
63+
* @return void
64+
*/
65+
public function initializeInnerParameters(): void
66+
{
67+
$paramName = $this->getConfig('name');
68+
$this->_dependentParameters[$paramName] = new \PlumSearch\FormParameter\HiddenParameter($this->_registry, [
69+
'name' => $paramName,
70+
]);
71+
}
72+
73+
/**
74+
* Build values list
75+
*
76+
* @return array
77+
*/
78+
public function values(): array
79+
{
80+
$name = $this->getConfig('field');
81+
$paramName = $this->getConfig('name');
82+
$param = $this->_dependentParameters[$paramName];
83+
84+
return [
85+
$name => $this->value(),
86+
$paramName => $param->value(),
87+
];
88+
}
89+
90+
/**
91+
* Get form input configuration
92+
*
93+
* @return array
94+
*/
95+
public function formInputConfig(): array
96+
{
97+
$config = parent::formInputConfig();
98+
$config['data-id-name'] = $this->getConfig('idName');
99+
$config['data-value-name'] = $this->getConfig('valueName');
100+
$config['data-query'] = $this->getConfig('query');
101+
$config['data-wildcard'] = $this->getConfig('wildcard');
102+
$config['data-min-length'] = $this->getConfig('minLength');
103+
$config['data-delay'] = $this->getConfig('delay');
104+
$config['data-url'] = $this->autocompleteUrl();
105+
$config['class'] = 'lookup-autocomplete';
106+
107+
return $config;
108+
}
109+
}

src/FormParameter/SelectParameter.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public function __construct(ParameterRegistry $registry, array $config = [])
4747
if ($this->_allowedEmptyOptions()) {
4848
return;
4949
}
50-
if ((!isset($config['options']) || !is_array($config['options'])) && empty($config['finder'])) {
50+
if ((!isset($config['bypass']) || !isset($config['options']) || !is_array($config['options'])) && empty($config['finder'])) {
5151
throw new MissingParameterException(
5252
__('Missed "finder" configuration setting for select param `{0}`', $this->getConfig('name'))
5353
);
@@ -72,8 +72,8 @@ public function hasOptions(): bool
7272
public function formInputConfig(): array
7373
{
7474
$formConfig = parent::formInputConfig();
75-
76-
if (!array_key_exists('options', $formConfig)) {
75+
$bypass = $this->getConfig('bypass') ?? false;
76+
if (!array_key_exists('options', $formConfig) && !$bypass) {
7777
$options = $this->getConfig('options');
7878
$finder = $this->getConfig('finder');
7979
if (!empty($options) && is_array($options)) {

src/View/Helper/SearchHelper.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Cake\View\Helper;
1919
use PlumSearch\FormParameter\AutocompleteParameter;
2020
use PlumSearch\FormParameter\BaseParameter;
21+
use PlumSearch\FormParameter\LookupParameter;
2122
use PlumSearch\FormParameter\ParameterRegistry;
2223

2324
/**
@@ -160,6 +161,16 @@ protected function _applyAutocompleteOptions(array &$input, BaseParameter $param
160161
$input['class'] = 'autocomplete';
161162
$input['data-name'] = $param->getConfig('name');
162163
}
164+
if ($param instanceof LookupParameter) {
165+
$input['data-url'] = $param->autocompleteUrl();
166+
$input['data-id-name'] = $param->getConfig('idName');
167+
$input['data-value-name'] = $param->getConfig('valueName');
168+
$input['data-query'] = $param->getConfig('query');
169+
$input['data-wildcard'] = $param->getConfig('wildcard');
170+
$input['data-min-length'] = $param->getConfig('minLength');
171+
$input['data-delay'] = $param->getConfig('delay');
172+
$input['class'] = 'lookup-autocomplete';
173+
}
163174

164175
return $input;
165176
}

tests/bootstrap.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
'default' => [
5151
'engine' => 'File',
5252
],
53-
'_cake_core_' => [
53+
'_cake_translations_' => [
5454
'className' => 'File',
5555
'prefix' => 'search_myapp_cake_core_',
5656
'path' => CACHE . 'persistent/',

webroot/css/lookup.css

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
.lookup-suggestions {
2+
position: absolute;
3+
z-index: 1000;
4+
max-height: 200px;
5+
overflow-y: auto;
6+
border: 1px solid #ced4da;
7+
border-radius: 0.25rem;
8+
background-color: white;
9+
width: 100%;
10+
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
11+
}
12+
13+
.lookup-item {
14+
padding: 8px 10px;
15+
cursor: pointer;
16+
}
17+
18+
.lookup-item:hover, .lookup-item.active {
19+
background-color: #f8f9fa;
20+
}
21+
22+
.lookup-autocomplete {
23+
position: relative;
24+
}
25+
26+
:root {
27+
--search-color-white: #fff;
28+
--search-color-gray-100: #f8f9fa;
29+
--search-color-gray-200: #e9ecef;
30+
--search-color-gray-800: #343a40;
31+
--search-color-gray-900: #212529;
32+
}
33+
34+
35+
/* lookup widget */
36+
.lookup-wrapper {
37+
position: relative;
38+
display: inline-block;
39+
}
40+
41+
.lookup-wrapper input {
42+
width: 100%;
43+
}
44+
45+
.suggestions-list {
46+
position: absolute;
47+
top: 100%;
48+
left: 0;
49+
right: 0;
50+
z-index: 1000;
51+
display: block;
52+
padding: 0.3125rem 0;
53+
margin: 0.125rem 0 0;
54+
font-size: 14px;
55+
text-align: left;
56+
list-style: none;
57+
background-color: var(--search-color-white);
58+
background-clip: padding-box;
59+
border: 1px solid rgba(0,0,0,.15);
60+
border-radius: 4px;
61+
box-shadow: 0 6px 12px rgba(0,0,0,.175);
62+
max-height: 12.5rem;
63+
overflow-y: auto;
64+
}
65+
66+
.suggestions-list li {
67+
padding: 0.2rem 1.25rem;
68+
clear: both;
69+
font-weight: 400;
70+
line-height: 1.5;
71+
color: var(--search-color-gray-900);
72+
white-space: nowrap;
73+
cursor: pointer;
74+
}
75+
76+
.suggestions-list li:hover {
77+
color: var(--search-color-gray-800);
78+
text-decoration: none;
79+
background-color: var(--search-color-gray-100);
80+
}
81+
82+
.suggestions-list .is-active {
83+
background-color: var(--search-color-gray-200);
84+
}
85+
.lookup-wrapper {
86+
position: relative;
87+
}
88+
.input-wrapper {
89+
position: relative;
90+
}
91+
.loading-icon {
92+
position: absolute;
93+
right: 10px;
94+
top: 50%;
95+
transform: translateY(-50%);
96+
}
97+
.loading-spinner {
98+
border: 2px solid #f3f3f3;
99+
border-top: 2px solid #3498db;
100+
border-radius: 50%;
101+
width: 20px;
102+
height: 20px;
103+
animation: spin 1s linear infinite;
104+
}
105+
@keyframes spin {
106+
0% { transform: rotate(0deg); }
107+
100% { transform: rotate(360deg); }
108+
}

0 commit comments

Comments
 (0)