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