Fel uppstod under bearbetning av mallen.
The following has evaluated to null or missing:
==> product.images [in template "3192443#3192485#null" at line 17, column 24]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: productImage = product.images?filter(... [in template "3192443#3192485#null" at line 17, column 9]
----
1<#if themeDisplay?has_content>
2 <#assign scopeGroupId = themeDisplay.getScopeGroupId() />
3</#if>
4
5<#assign channel = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?accountId=-1&filter=name eq 'Marketplace Channel' and siteGroupId eq '${scopeGroupId}'") />
6
7<#if channel?has_content>
8 <#assign channelId = channel.items[0].id />
9</#if>
10
11<#if (CPDefinition_cProductId.getData())??>
12 <#assign productId = CPDefinition_cProductId.getData() />
13</#if>
14
15<#assign
16 product = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/"+ channelId +"/products/"+ productId +"?accountId=-1&images.accountId=-1&nestedFields=images")
17 productImage = product.images?filter(item -> item.tags?seq_contains("app icon"))![]
18/>
19
20<#if productImage?has_content>
21 <#assign productThumbnail = productImage[0].src?split("/o") />
22 <#if productThumbnail?has_content && productThumbnail?size gte 2>
23 <#assign productThumbnail1 = "/o/${productThumbnail[1]}"!"" />
24 <#else>
25 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
26 </#if>
27<#else>
28 <#if product.urlImage?has_content>
29 <#assign productThumbnail = product.urlImage?split("/o") />
30 <#if productThumbnail?has_content && productThumbnail?size gte 2>
31 <#assign productThumbnail1 = "/o/${productThumbnail[1]}"!"" />
32 <#else>
33 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
34 </#if>
35 <#else>
36 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
37 </#if>
38</#if>
39
40${productThumbnail1}
The following has evaluated to null or missing:
==> product.images [in template "3192443#3192485#null" at line 17, column 24]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: productImage = product.images?filter(... [in template "3192443#3192485#null" at line 17, column 9]
----
1<#if themeDisplay?has_content>
2 <#assign scopeGroupId = themeDisplay.getScopeGroupId() />
3</#if>
4
5<#assign channel = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?accountId=-1&filter=name eq 'Marketplace Channel' and siteGroupId eq '${scopeGroupId}'") />
6
7<#if channel?has_content>
8 <#assign channelId = channel.items[0].id />
9</#if>
10
11<#if (CPDefinition_cProductId.getData())??>
12 <#assign productId = CPDefinition_cProductId.getData() />
13</#if>
14
15<#assign
16 product = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/"+ channelId +"/products/"+ productId +"?accountId=-1&images.accountId=-1&nestedFields=images")
17 productImage = product.images?filter(item -> item.tags?seq_contains("app icon"))![]
18/>
19
20<#if productImage?has_content>
21 <#assign productThumbnail = productImage[0].src?split("/o") />
22 <#if productThumbnail?has_content && productThumbnail?size gte 2>
23 <#assign productThumbnail1 = "/o/${productThumbnail[1]}"!"" />
24 <#else>
25 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
26 </#if>
27<#else>
28 <#if product.urlImage?has_content>
29 <#assign productThumbnail = product.urlImage?split("/o") />
30 <#if productThumbnail?has_content && productThumbnail?size gte 2>
31 <#assign productThumbnail1 = "/o/${productThumbnail[1]}"!"" />
32 <#else>
33 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
34 </#if>
35 <#else>
36 <#assign productThumbnail1 = "/o/commerce-media/default/?groupId=${scopeGroupId}" />
37 </#if>
38</#if>
39
40${productThumbnail1}
NTLM (NT LAN Manager) is a suite of Microsoft protocols that provide authentication, integrity, and confidentiality for users. Though Microsoft has adopted Kerberos in modern versions of Windows server, NTLM is still used when authenticating to a workgroup. @product@ supports NTLM v2 authentication. NTLM v2 is more secure and has a stronger authentication process than NTLMv1.
Note: NTLM authentication is deprecated in Liferay 7.1 and may be removed in future versions. Users should migrate to Kerberos.
NTLM (NT LAN Manager) is a suite of Microsoft protocols that provide authentication, integrity, and confidentiality for users. Though Microsoft has adopted Kerberos in modern versions of Windows server, NTLM is still used when authenticating to a workgroup. @product@ supports NTLM v2 authentication. NTLM v2 is more secure and has a stronger authentication process than NTLMv1.
Note: NTLM authentication is deprecated in Liferay 7.1 and may be removed in future versions. Users should migrate to Kerberos.
The string doesn't match the expected date/time/date-time format. The string to parse was: "0". The expected format was: "yyyy-MM-dd'T'HH:mm:ss'Z'".
The nested reason given follows:
Unparseable date: "0"
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign parsedDate = createDate?datet... [in template "3192443#3192485#null" at line 58, column 17]
~ Reached through: #nested [in template "3192443#3192485#null" in macro "section" at line 243, column 17]
~ Reached through: @section title=languageUtil.get(local... [in template "3192443#3192485#null" at line 56, column 1]
----
1<#assign
2 channel = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?accountId=-1&filter=name eq 'Marketplace Channel' and siteGroupId eq '${themeDisplay.getScopeGroupId()}'")
3
4 product = restClient.get(
5 "/headless-commerce-delivery-catalog/v1.0/channels/" + channel.items[0].id +
6 "/products/" + CPDefinition_cProductId.getData() +
7 "?accountId=-1&nestedFields=categories,productSpecifications,skus&skus.accountId=-1&skus.currencyCode=USD"
8 )
9
10 catalogName = product.catalogName!""
11 categories = product.categories![]
12 createDate = product.createDate!0
13 productSpecifications = product.productSpecifications![]
14
15 liferayVersions = productSpecifications?filter(item -> stringUtil.equals(item.specificationKey, "liferay-version"))
16 platformOffering = categories?filter(item -> stringUtil.equals(item.vocabulary?replace(" ", "-"), "marketplace-liferay-platform-offering"))
17>
18
19<#assign
20 publisherDetailsResponse = restClient.get("/c/publisherdetailses?filter=publisherName eq '${catalogName}'")
21 redirectPath = "https://marketplace.liferay.com/e/publisher-details/29282497"
22/>
23
24<#if publisherDetailsResponse.items?has_content>
25 <#assign
26 publisherDetails = publisherDetailsResponse.items[0]
27 profileImageURL = publisherDetails.publisherProfileImage?replace("https://", "http://")
28 />
29</#if>
30
31<#assign
32 appDocumentationURL = getSpecificationValue("appdocumentationurl")
33 appInstallationGuideURL = getSpecificationValue("appinstallationguideurl")
34 appUsageTerms = getSpecificationValue("appusagetermsurl")
35 cpuValue = getSpecificationValue("cpu")
36 developerName = getSpecificationValue("developer-name", catalogName)
37 publisherURL = (getSpecificationValue("publisherwebsiteurl")?trim?replace(" ", ""))!""
38 ramValue = getSpecificationValue("ram")
39 sourceCode = getSpecificationValue("source-code-url")
40 supportEmail = getSpecificationValue("supportemailaddress")
41 supportPhone = getSpecificationValue("supportphone")
42 type = getSpecificationValue("type")?lower_case
43>
44<@section title = languageUtil.get(locale, "developer")>
45 <#if publisherDetails?has_content>
46 <a class = "bg-neutral-8" href = "${redirectPath}/${publisherDetails.id}">
47 ${developerName}
48 </a>
49 <#else>
50 <a class = "bg-neutral-8" href = "/?developer-name=${developerName}">
51 ${developerName}
52 </a>
53 </#if>
54</@section>
55
56<@section title = languageUtil.get(locale, "publisher-date", "Publisher Date")>
57 <#if createDate?has_content>
58 <#assign parsedDate = createDate?datetime("yyyy-MM-dd'T'HH:mm:ss'Z'") />
59
60 <p>${parsedDate?string("MMMM d, yyyy")}</p>
61 </#if>
62</@section>
63
64<@section title = languageUtil.get(locale, "deployment-method", "Deployment Method")>
65 <#list platformOffering as offering>
66 <p>${offering.name}</p>
67 </#list>
68</@section>
69
70<@section title = languageUtil.get(locale, "app-type", "App Type")>
71 <#if type == 'client-extension'> Client Extension </#if>
72 <#if type == 'cloud'> Cloud </#if>
73 <#if type == 'composite-app'> Composite App </#if>
74 <#if type == 'dxp'> DXP </#if>
75 <#if type == 'low-code-configuration'> Low Code Configuration </#if>
76</@section>
77
78<@section title = languageUtil.get(locale, "version")>
79 ${getSpecificationValue("latest-version", "1.0.0")}
80</@section>
81
82<#if liferayVersions?has_content>
83 <@section title = languageUtil.get(locale, "supported-versions", "Supported Versions")>
84 <#list liferayVersions as version>
85 ${version.value}<#if version?has_next>, </#if>
86 </#list>
87 </@section>
88</#if>
89
90<#if cpuValue?has_content>
91 <@section title = languageUtil.get(locale, "resource-requirements", "Resource Requirements")>
92 <p>
93 <#if cpuValue?has_content>
94 ${cpuValue}
95 <#assign cpuNumber = cpuValue?number?default(0) />
96 <#if cpuValue?eval gt 1>
97 CPUS
98 </#if>
99 <#if cpuValue?eval lt 2>
100 CPU
101 </#if>
102 </#if>, <#if ramValue?has_content>${ramValue} GB RAM</#if>
103 </p>
104 </@section>
105</#if>
106
107<@section title = languageUtil.get(locale, "standard-price", "Standard Price")>
108 <div>
109 <#assign purchasableSkus = [] />
110
111 <#list product.skus as sku>
112 <#if sku.purchasable?? && sku.purchasable>
113 <#assign purchasableSkus = purchasableSkus + [sku] />
114 </#if>
115 </#list>
116
117 <#assign standardSku = {} />
118
119 <#list purchasableSkus as sku>
120 <#assign matched = false />
121
122 <#list sku.skuOptions as opt>
123 <#if stringUtil.equals(opt.skuOptionValueKey, "standard")>
124 <#assign
125 matched = true
126 standardSku = sku
127 />
128
129 <#break>
130 </#if>
131 </#list>
132 <#if matched><#break></#if>
133 </#list>
134
135 <#if standardSku.price?? && standardSku.price.price?eval gt 0>
136 <div class="bg-neutral-8">${standardSku.price.priceFormatted!""}</div>
137 <#else>
138 ${languageUtil.get(locale, "free", "Free")}
139 </#if>
140 </div>
141</@section>
142
143<@section title = languageUtil.get(locale, "help-and-support", "Help and Support")>
144 <div class="d-flex flex-column mt-4">
145 <#if (appDocumentationURL?has_content || appInstallationGuideURL?has_content)>
146 <div class="d-flex mb-4">
147 <span class="support-modal-icon" id="app-documentation">
148 <@clay["icon"] symbol="document" />
149 </span>
150
151 <a class="d-flex support-modal justify-content-between w-100" href="javascript:void(0)" onClick="openInstallationDocsModal();">
152 <span class="ml-1 ">
153 ${languageUtil.get(locale, "app-documentation", "App Documentation")}
154 </span>
155 </a>
156 </div>
157 </#if>
158
159 <div class="d-flex mb-4">
160 <span class="support-modal-icon" id="publisher-support">
161 <@clay["icon"] symbol="envelope-closed" />
162 </span>
163
164 <a class="d-flex justify-content-between support-modal w-100" href="javascript:void(0)" onClick="openPublisherSupportModal();">
165 <span class="ml-1 ">
166 ${languageUtil.get(locale, "publisher-support", "Publisher Support")}
167 </span>
168 </a>
169 </div>
170
171 <#if sourceCode?has_content>
172 <div class="d-flex mb-4">
173 <span class="support-link-icon">
174 <@clay["icon"] symbol="code" />
175 </span>
176
177 <a
178 class="d-flex justify-content-between support-link w-100"
179 href="${sourceCode}"
180 target="_blank"
181 >
182 <span class="ml-1">
183 ${languageUtil.get(locale, "source-code", "Source Code")}
184
185 <span class="d-none ml-1 support-link-icon-arrow-container">
186 <@clay["icon"] className="support-link-icon-arrow" symbol="tap-ahead" />
187 </span>
188 </span>
189 </a>
190 </div>
191 </#if>
192
193 <div class="d-flex">
194 <span class="support-link-icon">
195 <@clay["icon"] symbol="check-square" />
196 </span>
197
198 <a
199 class="d-flex justify-content-between support-link w-100"
200 href="https://marketplace.liferay.com/documents/d/marketplace/end_user_license_agreement-1"
201 target="_blank">
202
203 <span class="ml-1">
204 ${languageUtil.get(locale, "eula", "EULA")}
205
206 <span class="d-none support-link-icon-arrow-container ml-1">
207 <@clay["icon"] className="support-link-icon-arrow" symbol="tap-ahead" />
208 </span>
209 </span>
210 </a>
211 </div>
212 </div>
213</@section>
214
215<@section
216 showLine = false
217 title = languageUtil.get(locale, "share-link")
218>
219 <a class="align-items-center d-flex font-weight-bold ml-1 support-link text-primary" href="#copy-share-link" onclick="copyToClipboard(Liferay.ThemeDisplay.getCanonicalURL())">
220 <span class="link-icon mr-1">
221 <@clay["icon"] symbol="link" />
222 </span>
223 Copy & Share
224 </a>
225</@section>
226
227<#function getSpecificationValue key default="">
228 <#local spec = productSpecifications?filter(productSpecification ->
229 stringUtil.equals(productSpecification.specificationKey, key)) />
230
231 <#return (spec?first.value)!default />
232</#function>
233
234<#macro section
235 title
236 showLine=true
237>
238 <p>
239 <strong>${title}</strong>
240 </p>
241
242 <div>
243 <#nested>
244 </div>
245
246 <#if showLine>
247 <hr />
248 </#if>
249</#macro>
250
251<script ${nonceAttribute}>
252 function installationDocsModalBody() {
253 return `
254 <#if appDocumentationURL?has_content>
255 <div class="d-flex flex-row align-items-center mb-3">
256 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:57px;">
257 <@clay["icon"]
258 style="fill:#6B6C7E;"
259 symbol="document-code"
260 />
261 </span>
262
263 <div class="d-flex flex-column" style="min-width: 0;">
264 <span class="text-black-50">${languageUtil.get(locale, "app-documentation-url", "App Documentation URL")}</span>
265
266 <a class="font-weight-bold" href="${appDocumentationURL}" target="_blank">
267 ${appDocumentationURL}
268 </a>
269 </div>
270 </div>
271 </#if>
272
273 <#if appInstallationGuideURL?has_content>
274 <div class="d-flex flex-row align-items-center mb-4">
275 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:57px;">
276 <@clay["icon"]
277 style="fill:#6B6C7E;"
278 symbol="document"
279 />
280 </span>
281
282 <div class="d-flex flex-column" style="min-width: 0;">
283 <span class="text-black-50">${languageUtil.get(locale, "app-installation-guide-url", "App Installation Guide URL")}</span>
284
285 <a class="font-weight-bold" href="${appInstallationGuideURL}" target="_blank">
286${appInstallationGuideURL}
287 </a>
288 </div>
289 </div>
290 </#if>
291 `;
292 }
293
294 function publisherSupportModalBody() {
295 return `
296 <div class="align-items-center d-flex flex-row mb-3">
297 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:40px;">
298 <#if profileImageURL?? && profileImageURL?length gt 0>
299 <img src="${profileImageURL}" alt="Publisher Image" style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;" />
300 <#else>
301 <@clay["icon"]
302 style="fill:#6B6C7E;"
303 symbol="picture"
304 />
305 </#if>
306 </span>
307
308 <div class="d-flex flex-column">
309 <h3 class="font-weight-bold mb-0">
310 ${catalogName}
311 </h3>
312 </div>
313 </div>
314
315 <#if publisherURL?has_content>
316 <div class="align-items-center d-flex flex-row mb-3">
317 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:40px;">
318 <@clay["icon"]
319 style="fill:#6B6C7E;"
320 symbol="globe"
321 />
322 </span>
323
324 <div class="d-flex flex-column">
325 <span class="text-black-50">${languageUtil.get(locale, "publisher-website", "Publisher Website")}</span>
326
327 <a href="${publisherURL}" target="_blank" class="font-weight-bold">
328 ${publisherURL}
329 </a>
330 </div>
331 </div>
332 </#if>
333
334 <#if supportEmail?has_content>
335 <div class="align-items-center d-flex flex-row mb-3">
336 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:40px;">
337 <@clay["icon"] style="fill:#6B6C7E;"symbol="envelope-closed" />
338 </span>
339
340 <div class="d-flex flex-column">
341 <span class="text-black-50">${languageUtil.get(locale, "support-email", "Support Email")}</span>
342
343 <a class="font-weight-bold" href="mailto:${supportEmail}" target="_blank">
344 ${supportEmail}
345 </a>
346 </div>
347 </div>
348 </#if>
349
350 <#if supportPhone?has_content>
351 <div class="d-flex flex-row align-items-center mb-3">
352 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:40px;">
353 <@clay["icon"]
354 style="fill:#6B6C7E;"
355 symbol="phone"
356 />
357 </span>
358
359 <div class="d-flex flex-column">
360 <span class="text-black-50">${languageUtil.get(locale, "phone")}</span>
361
362 <a class="font-weight-bold" href="tel:${supportPhone}" target="_blank">
363 ${supportPhone}
364 </a>
365 </div>
366 </div>
367 </#if>
368 `;
369 }
370
371 function openInstallationDocsModal() {
372 Liferay.Util.openModal({
373 bodyHTML: installationDocsModalBody(),
374 center: true,
375 headerHTML: "<h2>Installation Guide</h2>",
376 size: "md"
377 });
378 }
379
380 function openPublisherSupportModal() {
381 Liferay.Util.openModal({
382 bodyHTML: publisherSupportModalBody(),
383 center: true,
384 headerHTML: "<h2>Publisher Support Info</h2>",
385 size: "md"
386 });
387 }
388</script>
389
390<script ${nonceAttribute}>
391 function copyToClipboard(text) {
392 if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
393 navigator.clipboard.writeText(text);
394
395 Liferay.Util.openToast({ message: "Copied link to the clipboard" });
396 }
397 }
398</script>
399
400<style ${nonceAttribute}>
401 .support-link,
402 .support-modal {
403 font-size: 16px;
404 }
405
406 .support-link-icon {
407 color: #0B5FFF;#54555F
408 }
409
410 .support-link-icon-arrow {
411 height: 12px !important;
412 width: 12px !important;
413 }
414
415 .support-link:hover,
416 .support-modal:hover {
417 transform: translateY(-0.75px);
418 }
419
420 .support-link:hover .support-link-icon-arrow-container {
421 display: inline-block !important;
422 transform: rotate(90deg);
423 }
424
425 .support-modal-icon,
426 .support-modal {
427 color: #54555F;
428 }
429
430 .support-modal:hover {
431 color: #272833;
432 }
433
434 .support-svg mask,
435 .link-arrow mask {
436 mask-type: alpha;
437 }
438
439 .tempCSS{
440 min-width: 0;
441 }
442</style>
The following has evaluated to null or missing:
==> product.catalogName [in template "3192443#3192485#null" at line 69, column 23]
----
Tip: It's the step after the last dot that caused this error, not those before it.
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: catalogName = product.catalogName [in template "3192443#3192485#null" at line 69, column 9]
----
1<style>
2 .help-and-support-link {
3 color: inherit;
4 cursor: pointer;
5 text-decoration: none;
6 }
7
8 .help-and-support-link:hover {
9 color: inherit;
10 text-decoration: none;
11 }
12
13 .help-and-support-link-icon {
14 color: rgb(133, 140, 148);
15 }
16
17 .help-and-support-link-arrow {
18 fill: rgb(133, 140, 148);
19 }
20</style>
21
22<#if (_CUSTOM_FIELD_Documentation.getData())?has_content && (_CUSTOM_FIELD_Documentation.getData())?starts_with("https")>
23 <a class="bg-whiteColor pb-2 pl-4 pr-4 pt-2" href="${_CUSTOM_FIELD_Documentation.getData()}" style="border-color: var(--neutral-9);border-style: solid; border-width: 0 0 2px 0;align-items:center;color:var(--body-color);cursor:pointer;display:flex;justify-content:space-between;text-decoration:none;" target="_blank">
24 <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="doc" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="2" y="1" width="12" height="14"><path fill-rule="evenodd" clip-rule="evenodd" d="M2.673 2.666c0-.733.594-1.333 1.327-1.333h4.78c.353 0 .693.14.94.393l3.22 3.22c.253.247.393.587.393.94v7.447c0 .733-.6 1.333-1.333 1.333H3.993c-.733 0-1.326-.6-1.326-1.333l.006-10.667Zm5.994-.333v3c0 .367.3.667.666.667h3L8.667 2.333Z" fill="#000"/></mask><g mask="url(#doc)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
25
26 <span class="copy-text ml-1">${languageUtil.get(locale, "installation-documentation", "Installation Documentation")}</span>
27
28 <svg class="link-arrow" style="margin-left:auto;" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="arrow" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="5" y="4" width="6" height="8"><path d="m6 10.584 2.587-2.587L6 5.41a.664.664 0 1 1 .94-.94L10 7.53c.26.26.26.68 0 .94l-3.06 3.06c-.26.26-.68.26-.94 0a.678.678 0 0 1 0-.946Z" fill="#000"/></mask><g mask="url(#arrow)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
29 </a>
30</#if>
31
32<#if (_CUSTOM_FIELD_Source.getData())?has_content && (_CUSTOM_FIELD_Source.getData())?starts_with("https")>
33 <a class="bg-whiteColor pb-2 pl-4 pr-4 pt-2" href="${_CUSTOM_FIELD_Source.getData()}" style="border-color: var(--neutral-9);border-style: solid; border-width: 0 0 2px 0;align-items:center;color:var(--body-color);cursor:pointer;display:flex;justify-content:space-between;text-decoration:none;" target="_blank">
34 <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="code" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="1" y="4" width="14" height="8"><path fill-rule="evenodd" clip-rule="evenodd" d="m12.8 8-2.6 2.6a.656.656 0 0 0 0 .933c.26.26.673.26.933 0l3.06-3.067c.26-.26.26-.68 0-.94l-3.06-3.06a.656.656 0 0 0-.933 0 .656.656 0 0 0 0 .934L12.8 8ZM3.2 8l2.6 2.6c.26.26.26.673 0 .933a.656.656 0 0 1-.933 0l-3.06-3.067a.664.664 0 0 1 0-.94l3.06-3.06a.656.656 0 0 1 .933 0c.26.26.26.674 0 .934L3.2 8Z" fill="#000"/></mask><g mask="url(#code)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
35
36 <span class="copy-text ml-1">${languageUtil.get(locale, "source-code", "Source Code")}</span>
37
38 <svg class="link-arrow" style="margin-left:auto;" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="arrow" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="5" y="4" width="6" height="8"><path d="m6 10.584 2.587-2.587L6 5.41a.664.664 0 1 1 .94-.94L10 7.53c.26.26.26.68 0 .94l-3.06 3.06c-.26.26-.68.26-.94 0a.678.678 0 0 1 0-.946Z" fill="#000"/></mask><g mask="url(#arrow)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
39 </a>
40</#if>
41
42<#if (_CUSTOM_FIELD_Support.getData())?has_content && (_CUSTOM_FIELD_Terms.getData())?starts_with("https")>
43 <a class="bg-whiteColor pb-2 pl-4 pr-4 pt-2" href="${_CUSTOM_FIELD_Terms.getData()}" style="border-color: var(--neutral-9);border-style: solid; border-width: 0 0 2px 0;align-items:center;color:var(--body-color);cursor:pointer;display:flex;justify-content:space-between;text-decoration:none;" target="_blank">
44 <svg width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="support" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="2" y="1" width="12" height="14"><path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.333A5.67 5.67 0 0 0 2.333 7 5.67 5.67 0 0 0 8 12.666h.333v2C11.573 13.106 13.667 10 13.667 7A5.67 5.67 0 0 0 8 1.333ZM7.333 11V9.666h1.334V11H7.333Zm1.58-3.154c.007-.013.014-.026.02-.033.182-.266.435-.488.69-.712.592-.519 1.202-1.053.997-2.188-.193-1.127-1.093-2.053-2.22-2.22a2.668 2.668 0 0 0-2.953 1.86.61.61 0 0 0 .58.78h.133c.273 0 .493-.193.587-.433.213-.594.84-1 1.533-.854.64.134 1.107.767 1.047 1.42-.045.51-.41.79-.813 1.103-.251.195-.519.402-.734.684l-.007-.007c-.011.012-.02.028-.03.044-.007.013-.015.025-.023.036-.01.017-.022.034-.033.05l-.034.05c-.06.094-.106.187-.146.294a.104.104 0 0 1-.017.033.104.104 0 0 0-.017.033c-.006.007-.006.014-.006.02-.08.24-.134.527-.134.867h1.34a1.406 1.406 0 0 1 .12-.593.239.239 0 0 1 .027-.074c.027-.053.06-.106.093-.16Z" fill="#000"/></mask><g mask="url(#support)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
45
46 <span class="copy-text ml-1">${languageUtil.get(locale, "support-levels-and-informations", "Support Levels & Information")}</span>
47
48 <svg class="link-arrow" style="margin-left:auto;" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="arrow" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="5" y="4" width="6" height="8"><path d="m6 10.584 2.587-2.587L6 5.41a.664.664 0 1 1 .94-.94L10 7.53c.26.26.26.68 0 .94l-3.06 3.06c-.26.26-.68.26-.94 0a.678.678 0 0 1 0-.946Z" fill="#000"/></mask><g mask="url(#arrow)"><path fill="var(--neutral-5)" d="M0 0h16v16H0z"/></g></svg>
49 </a>
50</#if>
51
52<#if (CPDefinition_cProductId.getData())??>
53 <#assign productId = CPDefinition_cProductId.getData() />
54</#if>
55
56<#if themeDisplay?has_content>
57 <#assign scopeGroupId = themeDisplay.getScopeGroupId() />
58</#if>
59
60<#assign channel = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels?accountId=-1&filter=name eq 'Marketplace Channel' and siteGroupId eq '${scopeGroupId}'") />
61
62<#if channel?has_content>
63 <#assign channelId = channel.items[0].id />
64</#if>
65
66<#assign
67 productId = CPDefinition_cProductId.getData()
68 product = restClient.get("/headless-commerce-delivery-catalog/v1.0/channels/"+ channelId +"/products/"+ productId +"?accountId=-1&images.accountId=-1&nestedFields=categories,images,productSpecifications")
69 catalogName = product.catalogName
70 productImage = product.images![]
71 solutionHeaderImages = productImage?filter(image -> image.tags?seq_contains("app icon"))
72/>
73
74<#if product.productSpecifications?has_content>
75 <#assign
76 productSpecifications = product.productSpecifications
77 publisherUrlFiltered = productSpecifications?filter(specification -> stringUtil.equals(specification.specificationKey, "publisherwebsiteurl"))
78 supportEmailFiltered = productSpecifications?filter(specification -> stringUtil.equals(specification.specificationKey, "supportemailaddress"))
79 supportPhoneFiltered = productSpecifications?filter(specification -> stringUtil.equals(specification.specificationKey, "supportphone"))
80 />
81
82 <#if supportEmailFiltered?has_content>
83 <#assign
84 supportEmail = supportEmailFiltered[0].value
85 />
86 </#if>
87
88 <#if publisherUrlFiltered?has_content>
89 <#assign publisherUrl = publisherUrlFiltered[0].value?trim?replace(' ', '') />
90
91 <#if publisherUrl?starts_with("http://") || publisherUrl?starts_with("https://")>
92 <#assign sanitizedUrl = publisherUrl />
93 <#else>
94 <#assign sanitizedUrl = "https://" + publisherUrl />
95 </#if>
96 </#if>
97
98 <#if supportPhoneFiltered?has_content>
99 <#assign
100 supportPhone = supportPhoneFiltered[0].value
101 />
102 </#if>
103</#if>
104
105<div class="d-flex flex-column">
106 <div class="d-flex mb-3">
107 <span class="help-and-support-link-icon">
108 <@clay["icon"] symbol="envelope-closed" />
109 </span>
110
111 <a class="d-flex help-and-support-link justify-content-between w-100" id="help-and-support-link-contact-button" onClick="openModal()">
112 <span class="copy-text help-and-support-link ml-1">
113 ${languageUtil.get(locale, "publisher-support", "Publisher Support")}
114 </span>
115
116 <svg class="link-arrow help-and-support-link-arrow" fill="none" height="16" style="margin-left: auto" width="16" xmlns="http://www.w3.org/2000/svg">
117 <mask height="8"id="arrow" maskUnits="userSpaceOnUse" style="mask-type: alpha" width="6" x="5" y="4">
118 <path d="m6 10.584 2.587-2.587L6 5.41a.664.664 0 1 1 .94-.94L10 7.53c.26.26.26.68 0 .94l-3.06 3.06c-.26.26-.68.26-.94 0a.678.678 0 0 1 0-.946Z" fill="#000" />
119 </mask>
120
121 <g mask="url(#arrow)">
122 <path d="M0 0h16v16H0z" fill="var(--neutral-5)" />
123 </g>
124 </svg>
125 </a>
126 </div>
127
128 <div class="d-flex">
129 <span class="help-and-support-link-icon">
130 <@clay["icon"] symbol="document" />
131 </span>
132
133 <a class="d-flex w-100 justify-content-between help-and-support-link" href="https://www.liferay.com/en/legal/marketplace-terms-of-service" target="_blank">
134 <span class="copy-text ml-1 help-and-support-link">
135 ${languageUtil.get(locale, "terms-and-conditions", "Terms & Conditions")}
136 </span>
137
138 <svg class="link-arrow help-and-support-link-arrow" fill="none" height="16" style="margin-left: auto" width="16" xmlns="http://www.w3.org/2000/svg">
139 <mask height="8"id="arrow" maskUnits="userSpaceOnUse" style="mask-type: alpha" width="6" x="5" y="4">
140 <path d="m6 10.584 2.587-2.587L6 5.41a.664.664 0 1 1 .94-.94L10 7.53c.26.26.26.68 0 .94l-3.06 3.06c-.26.26-.68.26-.94 0a.678.678 0 0 1 0-.946Z" fill="#000" />
141 </mask>
142
143 <g mask="url(#arrow)">
144 <path fill="var(--neutral-5)" d="M0 0h16v16H0z" />
145 </g>
146 </svg>
147 </a>
148 </div>
149</div>
150
151<script>
152 function modalBody(){
153 return `
154 <#if catalogName?has_content>
155 <div class="align-items-center d-flex flex-row mb-3">
156 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; overflow:hidden; width:40px;">
157 <#if solutionHeaderImages?has_content>
158 <#list solutionHeaderImages as image>
159 <#assign imageSourceSplitedUrl = image.src?split("/o") />
160
161 <#if imageSourceSplitedUrl?has_content>
162 <#assign productThumbnail = "/o/${imageSourceSplitedUrl[1]}" />
163
164 <img alt="Slide ${image?index}" class="catalog-icon" src="${productThumbnail}" style="height: 40px; object-fit: contain; width: 40px;">
165 </#if>
166 </#list>
167 <#else>
168 <@clay["icon"]
169 style="fill:#6B6C7E;"
170 symbol="picture"
171 />
172 </#if>
173 </span>
174
175 <div class="d-flex flex-column">
176 <#if catalogName?has_content>
177 <h3 class="font-weight-bold mb-0">
178 ${catalogName}
179 </h3>
180 </#if>
181 </div>
182 </div>
183 </#if>
184
185 <#if sanitizedUrl?has_content && publisherUrl?has_content>
186 <div class="align-items-center d-flex flex-row mb-3">
187 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; width:40px;">
188 <@clay["icon"]
189 style="fill:#6B6C7E;"
190 symbol="globe"
191 />
192 </span>
193
194 <div class="d-flex flex-column">
195 <span class="text-black-50">Publisher website URL</span>
196
197 <a href="${sanitizedUrl}" target="_blank" class="font-weight-bold">
198 ${publisherUrl}
199 </a>
200 </div>
201 </div>
202 </#if>
203
204 <#if supportEmail?has_content>
205 <div class="align-items-center d-flex flex-row mb-3">
206 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; width:40px;">
207 <@clay["icon"] style="fill:#6B6C7E;"symbol="envelope-closed" />
208 </span>
209
210 <div class="d-flex flex-column">
211 <span class="text-black-50">Support Email</span>
212
213 <a class="font-weight-bold" href="mailto:${supportEmail}" target="_blank">
214 ${supportEmail}
215 </a>
216 </div>
217 </div>
218 </#if>
219
220 <#if supportPhone?has_content>
221 <div class="d-flex flex-row align-items-center mb-3">
222 <span class="align-items-center d-flex justify-content-center modal-icon-background mr-3" style="background: #E2E2E4; border-radius:50%; height:40px; width:40px;">
223 <@clay["icon"]
224 style="fill:#6B6C7E;"
225 symbol="phone"
226 />
227 </span>
228
229 <div class="d-flex flex-column">
230 <span class="text-black-50">Phone</span>
231
232 <a class="font-weight-bold" href="tel:${supportPhone}" target="_blank">
233 ${supportPhone}
234 </a>
235 </div>
236 </div>
237 </#if>
238 `
239 }
240
241 function openModal() {
242 Liferay.Util.openModal({
243 bodyHTML:modalBody(),
244 center: true,
245 headerCssClass:"pt-2",
246 headerHTML: "<h2>Publisher Support Contact Info</h2>",
247 size: "md",
248 })
249 }
250
251</script>
HTML Example
A paragraph is a self-contained unit of a discourse in writing dealing with a particular point or idea. Paragraphs are usually an expected part of formal writing, used to organize longer prose.