1<#-- Variables -->
2<#assign specificationName = 'ics' />
3<#assign paramNameSpecificationName = cpSpecificationOptionsSearchFacetDisplayContext.getParameterName() />
4<#assign isDebug = false />
5<#assign showAllSpecificationsName = false />
6<#assign staticHost = getCXConfig("ecom-static-files") />
7
8<#-- ========================= -->
9<#-- Functions freemaker -->
10<#-- ========================= -->
11<#function getCXConfig clientExtensionName field="webApiUrl">
12 <#if !clientExtensionName?has_content><#return "" /></#if>
13 <#local encoded = urlCodec.encodeURL(clientExtensionName) />
14 <#local items = restClient.get("/c/customconfigs/?fields=clientExtensionConfig&filter=clientExtensionName eq '" + encoded + "'").items![] />
15 <#return items?has_content?then(items[0].clientExtensionConfig?eval[field]!"", "") />
16</#function>
17
18
19<#if paramNameSpecificationName == specificationName || showAllSpecificationsName>
20
21 <#-- ------------------------------------- -->
22
23<#assign taxonomyResponse = restClient.get("/headless-admin-taxonomy/v1.0/taxonomy-vocabularies/39789900/taxonomy-categories?pageSize=50")!{} />
24<#assign organismoMap = {} />
25<#list taxonomyResponse.items![] as cat>
26 <#assign categoryKey = "39789900-" + cat.id />
27 <#assign organismoMap = organismoMap + {categoryKey: cat.name} />
28</#list>
29
30<#assign sharedSearchResponse = renderRequest.getAttribute("LIFERAY_SHARED_PortletSharedSearchResponse") />
31<#assign searchResponse = sharedSearchResponse.get() />
32<#assign esResponse = searchResponse.getSearchResponse() />
33<#assign icsOrgAggResult = esResponse.getAggregationResult("ics_with_organismos") />
34
35<#assign icsOrganismosMap = {} />
36<#list icsOrgAggResult.getBuckets() as icsBucket>
37 <#assign icsKey = icsBucket.getKey() />
38 <#assign organismoAgg = icsBucket.getChildAggregationResult("organismos") />
39 <#assign orgNames = [] />
40 <#list organismoAgg.getBuckets() as orgBucket>
41 <#assign orgName = organismoMap[orgBucket.getKey()]!"?" />
42 <#assign orgNames = orgNames + [orgName] />
43 </#list>
44 <#assign icsOrganismosMap = icsOrganismosMap + {icsKey: orgNames} />
45</#list>
46
47<#-- Debug -->
48<#list icsOrganismosMap?keys as ics>
49 <p>${ics}: ${icsOrganismosMap[ics]?join(", ")}</p>
50</#list>
51
52 <#-- ------------------------------------- -->
53
54
55 <#-- Variables -->
56 <#assign facetId = "facet-" + paramNameSpecificationName + "-" + renderResponse.getNamespace() />
57 <#assign facetClass = "facet-" + paramNameSpecificationName + "-combo-search-wrapper" />
58
59 <#-- ========================= -->
60 <#-- TOM SELECT framework -->
61 <#-- ========================= -->
62 <@liferay_util["html-top"] outputKey="tom-select">
63 <link href="${staticHost}/scripts/vendor/tom-select/tom-select.css" rel="stylesheet">
64 <script src="${staticHost}/scripts/vendor/tom-select/tom-select.complete.min.js"></script>
65 </@>
66
67 <#-- ========================= -->
68 <#-- CSS -->
69 <#-- ========================= -->
70 <style>
71 /* ===========================
72 Variables de fuente compartidas
73 =========================== */
74 #${facetId} {
75 --facet-font-family: Inter;
76 --facet-font-size: 14px;
77 --facet-font-weight: 400;
78 --facet-line-height: 18px;
79 --facet-letter-spacing: 0.5px;
80 --facet-color: #66757f;
81 }
82
83 /* ===========================
84 Select original — oculto desde el inicio
85 =========================== */
86 #${facetId}-select {
87 appearance: none;
88 -webkit-appearance: none;
89 visibility: hidden;
90 position: absolute;
91 }
92
93 /* ===========================
94 TomSelect — wrapper oculto hasta inicializar
95 =========================== */
96 #${facetId} .ts-wrapper {
97 width: 100%;
98 margin-bottom: 16px;
99 opacity: 0;
100 transition: opacity 0.1s ease;
101 }
102
103 #${facetId} .ts-wrapper .ts-control {
104 padding: 15.5px 16px;
105 font-family: var(--facet-font-family);
106 font-size: var(--facet-font-size);
107 font-weight: var(--facet-font-weight);
108 line-height: var(--facet-line-height);
109 letter-spacing: var(--facet-letter-spacing);
110 color: var(--facet-color);
111 text-align: left;
112 height: 55px;
113 width: 100%;
114 border-radius: 4px;
115 border: none;
116 background-color: #F5F5F5;
117 background-image: url(/documents/d/global/ico-chevron-down-2);
118 background-repeat: no-repeat;
119 background-position: right 1rem center;
120 background-size: 18px 10px;
121 box-shadow: none;
122 cursor: pointer;
123 box-sizing: border-box;
124 }
125
126 #${facetId} .ts-wrapper .ts-control:focus,
127 #${facetId} .ts-wrapper .ts-control:focus-visible {
128 background-image: url(/documents/d/global/ico-chevron-down-2);
129 background-position: right 1rem center;
130 background-size: 18px 10px;
131 outline: none;
132 box-shadow: none;
133 }
134
135 #${facetId} .ts-wrapper .ts-control .item {
136 padding-right: 0.75rem;
137 overflow: hidden;
138 text-overflow: ellipsis;
139 max-width: calc(100% - 0.75rem);
140 }
141
142 /* Ocultar flecha nativa de TomSelect */
143 #${facetId} .ts-wrapper.single .ts-control::after {
144 display: none;
145 }
146
147 /* Input de búsqueda del dropdown */
148 #${facetId} .ts-dropdown .dropdown-input-wrap .dropdown-input {
149 font-family: var(--facet-font-family);
150 font-size: var(--facet-font-size);
151 font-weight: var(--facet-font-weight);
152 line-height: var(--facet-line-height);
153 letter-spacing: var(--facet-letter-spacing);
154 color: var(--facet-color);
155 padding: 8px 16px;
156 border: none;
157 border-bottom: 1px solid #d9d9d9;
158 background-color: #fff;
159 width: 100%;
160 box-sizing: border-box;
161 }
162
163 #${facetId} .ts-dropdown .dropdown-input-wrap .dropdown-input:focus {
164 outline: none;
165 box-shadow: none;
166 }
167
168 /* Opciones del dropdown */
169 #${facetId} .ts-dropdown .ts-dropdown-content .option {
170 font-family: var(--facet-font-family);
171 font-size: var(--facet-font-size);
172 font-weight: var(--facet-font-weight);
173 line-height: var(--facet-line-height);
174 letter-spacing: var(--facet-letter-spacing);
175 color: var(--facet-color);
176 padding: 8px 16px;
177 }
178
179 #${facetId} .ts-dropdown .ts-dropdown-content .option:hover,
180 #${facetId} .ts-dropdown .ts-dropdown-content .option.active {
181 background-color: #6a9bd3;
182 color: #fff;
183 }
184 </style>
185
186 <div class="checks-container ${facetClass}" id="${facetId}">
187 <div class="d-flex flex-column w-100">
188 <label class="panel-title mb-2" for="${facetId}-select">
189 ${languageUtil.get(locale, "norma." + paramNameSpecificationName)}
190 <#if isDebug>
191 <p style="font-size:11px;color:#999;font-weight:normal;">
192 (total options: ${entries?size})
193 </p>
194 <p style="font-size:11px;color:#999;font-weight:normal;">
195 (facetId: ${facetId})
196 </p>
197 </#if>
198 </label>
199
200 <#-- ========================= -->
201 <#-- SELECT UI -->
202 <#-- ========================= -->
203 <select id="${facetId}-select" data-parameter-name="${paramNameSpecificationName}">
204 <option value="">${languageUtil.get(locale, "search.cualquiera")}</option>
205 <#list entries?sort_by("displayName") as entry>
206 <option value="${htmlUtil.escape(entry.getDisplayName())}"
207 <#if entry.isSelected()>selected</#if>>
208 ${htmlUtil.escape(entry.getDisplayName())} (${entry.getFrequency()})
209 </option>
210 </#list>
211 </select>
212 </div>
213 </div>
214
215 <#-- ========================= -->
216 <#-- SCRIPT -->
217 <#-- ========================= -->
218 <script>
219 (function () {
220 var FACET_ID = '${facetId}';
221 var PARAM_NAME = '${paramNameSpecificationName}';
222
223 function applyUrlFilter(value) {
224 var url = new URL(window.location.href);
225 if (value) {
226 url.searchParams.set(PARAM_NAME, value);
227 } else {
228 url.searchParams.delete(PARAM_NAME);
229 }
230 window.location.href = url.toString();
231 }
232
233 function initFacet() {
234 var select = document.getElementById(FACET_ID + '-select');
235 if (!select) return;
236
237 if (select.tomselect) select.tomselect.destroy();
238 if (select.dataset.bound === 'true') return;
239 select.dataset.bound = 'true';
240
241 new TomSelect(select, {
242 allowEmptyOption: true,
243 maxItems: 1,
244 create: false,
245 render: {
246 no_results: function(data, escape) {
247 return '<div class="no-results">${languageUtil.get(locale, "occurrence-not-found")}</div>';
248 }
249 },
250 plugins: {
251 dropdown_input: {}
252 },
253 onDelete: function(value) {
254 this.isDelete = true;
255 },
256 onChange: function(value) {
257 if (value) {
258 this.lastValidValue = value;
259 applyUrlFilter(value);
260 return;
261 }
262 this.lastValidValue = '';
263 applyUrlFilter('');
264 },
265 onInitialize: function() {
266 this.lastValidValue = this.getValue() || '';
267 this.isDelete = false;
268 var wrapper = document.querySelector('#' + FACET_ID + ' .ts-wrapper');
269 if (wrapper) wrapper.style.opacity = '1';
270 }
271 });
272 }
273
274 if (document.readyState === 'loading') {
275 document.addEventListener('DOMContentLoaded', initFacet);
276 } else {
277 initFacet();
278 }
279 })();
280 </script>
281</#if>