テンプレート処理中にエラーが発生しました。
The following has evaluated to null or missing:
==> themeDisplay.getCanonicalURL [in template "8911408109993434201#23484949#LEARN-ARTICLE" at line 184, column 120]
----
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: ${themeDisplay.getCanonicalURL()} [in template "8911408109993434201#23484949#LEARN-ARTICLE" at line 184, column 118]
----
1<@liferay_aui.script>
2 const _addEventListener = (selectors) => {
3 var elements = document.querySelectorAll(selectors);
4
5 elements.forEach((element) => {
6 element.addEventListener("click", (event) => {
7 event.preventDefault();
8
9 const anchorElement = document.getElementById(element.getAttribute("id").replace("toc-", ""));
10
11 if (anchorElement) {
12 window.history.pushState(
13 {},
14 "",
15 "#" + element.getAttribute("id").replace("toc-", "")
16 );
17 scrollToElement(anchorElement);
18 }
19 });
20 });
21 }
22
23 const scrollToElement = (element) => {
24 if (!element) return;
25
26 window.scrollTo({
27 behavior: "smooth",
28 top: element.getBoundingClientRect().top + window.scrollY - 190,
29 });
30 };
31
32 window.addEventListener('load', function() {
33 _addEventListener("h1 a, h2 a, h3 a");
34 _addEventListener(".toc li a");
35
36 if (window.location.hash) {
37 const hashLocation = document.getElementById(window.location.hash.substring(1));
38
39 if (hashLocation) {
40 setTimeout(() => {
41 scrollToElement(hashLocation);
42 }, 100);
43 }
44 }
45 });
46 </@>
47
48<#assign
49 journalArticleId = .vars["reserved-article-id"].data
50
51 structuredContent = restClient.get("/headless-delivery/v1.0/sites/${groupId}/structured-contents/by-key/${journalArticleId}?nestedFields=embeddedTaxonomyCategory")
52
53 showChildrenCards = showChildrenCards.getData()?boolean
54 taxonomyCategoriesMap = {}
55 taxonomyVocabularies = []
56 taxonomyCategoryBriefs = structuredContent.taxonomyCategoryBriefs
57
58 navigationJSONObject = jsonFactoryUtil.createJSONObject(htmlUtil.unescape(navigation.getData()?trim))
59
60 breadcrumbJSONArray = navigationJSONObject.getJSONArray("breadcrumb")
61 childrenJSONArray = navigationJSONObject.getJSONArray("children")
62/>
63
64<#list taxonomyCategoryBriefs as taxonomyCategoryBrief>
65 <#assign taxonomyVocabularyName = taxonomyCategoryBrief.embeddedTaxonomyCategory.parentTaxonomyVocabulary.name />
66
67 <#if !taxonomyVocabularies?seq_contains(taxonomyVocabularyName)>
68 <#assign taxonomyVocabularies = taxonomyVocabularies + [taxonomyVocabularyName] />
69 </#if>
70
71 <#if taxonomyCategoriesMap[taxonomyVocabularyName]?has_content>
72 <#assign taxonomyCategoriesMap = taxonomyCategoriesMap +
73 {
74 taxonomyVocabularyName:
75 taxonomyCategoriesMap[taxonomyVocabularyName] + [{
76 "categoryId": taxonomyCategoryBrief.taxonomyCategoryId,
77 "categoryName": taxonomyCategoryBrief.taxonomyCategoryName
78 }]
79 }
80 />
81 <#else>
82 <#assign taxonomyCategoriesMap = taxonomyCategoriesMap +
83 {
84 taxonomyVocabularyName:
85 [{
86 "categoryId": taxonomyCategoryBrief.taxonomyCategoryId,
87 "categoryName": taxonomyCategoryBrief.taxonomyCategoryName
88 }]
89 }
90 />
91 </#if>
92</#list>
93
94<article class="learn-article">
95 <div class="d-flex flex-column">
96 <div class="learn-article-wrapper">
97 <div class="language-log learn-article-content">
98 <#if (content.getData())??>
99 ${content.getData()}
100 </#if>
101
102 <#if showChildrenCards && childrenJSONArray.length() gt 0>
103 <div class="learn-card-container">
104 <#list 0..childrenJSONArray.length()-1 as i>
105 <#assign childJSONObject = childrenJSONArray.getJSONObject(i) />
106
107 <div class="learn-card">
108 <a href="${childJSONObject.getString("url")}">
109 <h4>${childJSONObject.getString("title")}</h4>
110 </a>
111
112 <#if childJSONObject.getJSONArray("children")?has_content>
113 <#assign grandchildrenJSONArray = childJSONObject.getJSONArray("children") />
114
115 <div class="mt-2 subsection">
116 <#list 0..grandchildrenJSONArray.length()-1 as j>
117 <#assign grandchildJSONObject = grandchildrenJSONArray.getJSONObject(j)! />
118
119 <#if grandchildJSONObject?? && grandchildJSONObject["title"]?has_content && grandchildJSONObject["url"]?has_content>
120 <a href="${grandchildJSONObject["url"]!}">
121 ${grandchildJSONObject["title"]!}
122 </a>
123 </#if>
124 </#list>
125 </div>
126 </#if>
127 </div>
128 </#list>
129 </div>
130 <#else>
131 <div class="learn-article-categories-tags">
132 <#list taxonomyVocabularies as vocabulary>
133 <div class="align-items-baseline d-flex mt-2">
134 <div class="learn-article-category-title mr-2">
135 ${vocabulary}:
136 </div>
137 <#list taxonomyCategoriesMap[vocabulary]?sort_by("categoryName") as taxonomyCategory>
138 <div class="learn-article-category-tag mr-2">
139 <a
140 class="label tag-container"
141 href="/search?${vocabulary?lower_case?replace(" ", "-", "r")}=${taxonomyCategory.categoryId}"
142 >
143 <span>${taxonomyCategory.categoryName}</span>
144 </a>
145 </div>
146 </#list>
147 </div>
148 </#list>
149 </div>
150
151 <div class="article-related-how-to">
152 <#setting url_escaping_charset='UTF-8' />
153
154 <#if (structuredContent.keywords?has_content && structuredContent.keywords?size > 0)>
155 <#assign
156 queryParams = {
157 "fields": "dateModified,id,title",
158 "filter": "(knowledgeArticleType eq 'howTo') and (status eq 0) and (sourceTeam eq 'Enablement')",
159 "pageSize": "3",
160 "search": structuredContent.keywords[0],
161 "sort": "dateModified:desc"
162 }
163 queryParts = []
164 />
165
166 <#list queryParams?keys as key>
167 <#assign
168 value = queryParams[key]
169
170 queryParts = queryParts + ["${key?url}=${value?url}"]
171 />
172 </#list>
173
174 <#assign knowledgeArticles = restClient.get("/c/p2s3knowledgearticles/?" + queryParts?join('&')) />
175
176 <#if (knowledgeArticles.totalCount)?has_content && (knowledgeArticles.totalCount > 0)>
177 <div class="how-to-container">
178 <div class="how-to-container-header">
179 ${languageUtil.get(locale, 'how-to-related-to-this-article')}
180 </div>
181
182 <div class="how-to-cards-container" id="how-to-cards-container">
183 <#list knowledgeArticles.items as knowledgeArticle>
184 <a class="how-to-card" href="${themeDisplay.getCanonicalURL()}/l/${knowledgeArticle.id}/">
185 <div class="how-to-card-header">
186 ${knowledgeArticle.title}
187 </div>
188
189 <div class="how-to-card-date-published">
190 <#assign date = knowledgeArticle.dateModified?datetime("MMM dd, yy hh:mm")?string />
191
192 ${languageUtil.get(locale, 'published-date')}: ${date}
193 </div>
194 </a>
195 </#list>
196 </div>
197 </div>
198 </#if>
199 </#if>
200 </div>
201 </#if>
202 </div>
203 </div>
204 </div>
205</article>
206
207<style>
208 .how-to-card {
209 align-items: flex-start;
210 background: var(--color-brand-primary-lighten-6, #FBFCFE);
211 border: 1px solid var(--color-brand-primary-lighten-5, #E7EFFF);
212 border-radius: 0.75rem;
213 box-sizing: border-box;
214 cursor: pointer;
215 display: flex;
216 flex-direction: column;
217 gap: 0.5rem;
218 isolation: isolate;
219 justify-content: space-between;
220 order: 0;
221 padding: 1rem;
222 width: 100%;
223 }
224
225 .how-to-card:hover {
226 background: var(--color-action-primary-hover-10, #EDF3FE);
227 border: 1px solid var(--color-action-primary-hover, #0053F0);
228 border-radius: 0.625rem;
229 }
230
231 .how-to-card-date-published {
232 align-items: center;
233 align-self: stretch;
234 color: var(--color-neutral-8, #54555F);
235 display: flex;
236 flex: none;
237 flex-grow: 0;
238 font-family: 'Source Sans 3';
239 font-size: 0.75rem;
240 font-style: normal;
241 font-weight: 400;
242 line-height: 1rem;
243 }
244
245 .how-to-card-header {
246 align-items: center;
247 align-self: stretch;
248 color: var(--color-brand-primary, #0B5FFF);
249 display: flex;
250 flex: none;
251 flex-grow: 0;
252 font-family: 'Source Sans 3';
253 font-size: 1rem;
254 font-style: normal;
255 font-weight: 600;
256 line-height: 1.5rem;
257 }
258
259 .how-to-cards-container {
260 display: flex;
261 flex-direction: row;
262 gap: 1rem;
263 width: 100%;
264 }
265
266 .how-to-container {
267 align-items: flex-start;
268 align-self: stretch;
269 background: var(--color-neutral-1, #F7F7F8);
270 border-radius: 0.75rem;
271 display: flex;
272 flex: none;
273 flex-direction: column;
274 flex-grow: 0;
275 gap: 1.5rem;
276 isolation: isolate;
277 margin: 1.5rem 0px;
278 order: 0;
279 padding: 1.5rem;
280 width: 100%;
281 }
282
283 .how-to-container-header {
284 align-items: center;
285 color: var(--color-neutral-10, #282934);
286 display: flex;
287 flex: none;
288 flex-grow: 0;
289 font-family: 'Source Sans 3';
290 font-size: 1.5rem;
291 font-style: normal;
292 font-weight: 700;
293 line-height: 1.75rem;
294 }
295
296 .learn-article {
297 max-width: 900px !important;
298 }
299
300 @media only screen and (max-width: 1200px) {
301 .how-to-cards-container {
302 flex-direction: column;
303 }
304 }
305
306 @media (max-width: 1024px) {
307 .learn-article {
308 margin-top: 2.5rem;
309 }
310 }
311</style>
Capabilities
Product
Education
Knowledge Base
Contact Us