Services
حصل خطأ عند معالجة القالب.
The string doesn't match the expected date/time/date-time format. The string to parse was: "الأربعاء, 12 فبراير 2025 12:05:14 +0000". The expected format was: "EEE, dd MMM yyyy HH:mm:ss Z". The nested reason given follows: Unparseable date: "الأربعاء, 12 فبراير 2025 12:05:14 +0000" ---- FTL stack trace ("~" means nesting-related): - Failed at: #assign formattedDate = displayDateSt... [in template "70645677960193#20119#72398" at line 24, column 1] ----
1<#assign articleClassPk = .vars["reserved-article-resource-prim-key"].data />
2<#assign assetEntryService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryService") />
3
4
5<#assign monthArr = ['january','february','march','april','may','june','july','august','september','october','november','december'] />
6<#assign articleId = .vars['reserved-article-id'].data />
7<#assign vocabLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
8<#assign assetEntryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") />
9<#assign journalArticleLocalService = serviceLocator.findService("com.liferay.journal.service.JournalArticleLocalService") />
10<#assign article = journalArticleLocalService.getArticle(getterUtil.getLong(scopeGroupId), articleId) />
11<#assign asset = assetEntryLocalService.getEntry('com.liferay.journal.model.JournalArticle', article.resourcePrimKey) />
12<#assign constVocabOfContentType = "Entity" />
13
14<#assign displayDateStr="" />
15<#if article.displayDate??>
16 <#assign displayDateStr=.vars["reserved-article-display-date"].data>
17<#else>
18 <#assign displayDateStr=.vars["reserved-article-modified-date"].data>
19</#if>
20
21
22<#assign formattedDate = displayDateStr?date("EEE, dd MMM yyyy HH:mm:ss Z")>
23<#assign month = formattedDate?string("MMMM")> <!-- Extract month -->
24<#assign year = formattedDate?string("yyyy")> <!-- Extract year -->
25<#assign date = formattedDate?string("dd")> <!-- Extract day -->
26
27<article class="service-detail news-detail">
28 <section class="service-info service-info header-gradient-bg mb-0 news-spacing pl-0 pr-0 pb-4">
29 <div class="breadcrumb-container container-fluid container-fluid-max-xl mt-4 pt-2 mb-4 pb-2 container-padding">
30 <@liferay_portlet["runtime"]
31 instanceId="page_breadcrumb"
32 portletName="com_liferay_site_navigation_breadcrumb_web_portlet_SiteNavigationBreadcrumbPortlet"
33 />
34 </div>
35 <div class="container-fluid container-fluid-max-xl container-padding">
36 <div class="service-and-entitylist">
37 <div class="d-flex flex-column">
38 <div class="title-container">
39 <span><@liferay.language key="news.story" /></span>
40 <h1 class="title h2 mb-0"><#assign text= .vars["reserved-article-title"].data />
41 <#assign truncatedText = text?substring(0, (text?length > 60)?then(60, text?length))>
42 ${truncatedText}<#if text?length gt 60>...</#if></h1>
43 </div>
44 <div class="description">
45 ${.vars["reserved-article-description"].data}
46 </div>
47 </div>
48 <div class="entities">
49 <#list asset.getCategories() as category>
50 <#assign vocabName = vocabLocalService.getVocabulary(category.vocabularyId).getTitle("en_US") />
51 <#if vocabName == constVocabOfContentType>
52 <#assign EntityName = category.getTitle(themeDisplay.getLocale()) />
53 </#if>
54 </#list>
55 <#if EntityName??>
56 <p>
57 <@liferay.language key="from" />: <span class="text-decoration-underline">${EntityName}</span>
58 </p>
59 <#else>
60 <p><@liferay.language key="from" />: <span class="text-decoration-underline"><@liferay.language key="gup.news.filter.oman.gup" /></span></p>
61 </#if>
62 <time datetime="${formattedDate}">
63 <@liferay.language key="gup-published-label" />
64 ${languageUtil.get(locale, month?c_lower_case)} ${date}, ${year}
65 </time>
66 </div>
67 </div>
68 </div>
69 </section>
70 <div class="container-fluid container-fluid-max-xl container-padding">
71 <div class="row">
72 <div class="news-container content-spacing col-lg-8">
73 <#if (image.getData())?? && image.getData() != "">
74 <div class="news-image">
75 <img alt="${image.getAttribute('alt')}" data-fileentryid="${image.getAttribute('fileEntryId')}" src="${image.getData()}" />
76 <figcaption>${image.getAttribute("alt")}</figcaption>
77 </div>
78 </#if>
79
80 <#if (description.getData())??>
81 <div class="news-content">
82 ${description.getData()}
83 </div>
84 </#if>
85 <div class="news-save">
86 <a href="/news-and-communications">${languageUtil.get(locale, "return.to.news")}</a>
87 <div class="news-buttons">
88 <#assign hideCls = "" />
89 <#if themeDisplay.isSignedIn()>
90 <#assign hideCls = "" />
91 <#else>
92 <#assign hideCls = "hide" />
93 </#if>
94
95 <button class="btn btn-nm btn-outline-primary save ${hideCls}" style="display: none;"><i class="ri-heart-line"></i> ${languageUtil.get(locale, "gup.save")}</button>
96 <button class="btn btn-nm btn-outline-primary unsave ${hideCls}" style="display: none;"><i class="ri-heart-fill"></i> ${languageUtil.get(locale, "gup.unsave")}</button>
97 <#if !themeDisplay.isSignedIn()>
98 <a href="/sign-in" class="btn btn-nm btn-outline-primary"><i class="ri-heart-line"></i> ${languageUtil.get(locale, "gup.save")}</a>
99 </#if>
100
101 <button class="btn btn-nm btn-outline-primary" id="share"><i class="ri-share-forward-line"></i> ${languageUtil.get(locale, "gup.share")}</button>
102
103 <div class="share-dropdown" style="display: none;">
104 <#assign preferences = freeMarkerPortletPreferences.getPreferences("portletSetupPortletDecoratorId", "barebone") />
105 <@liferay_portlet["runtime"]
106 defaultPreferences="${preferences}"
107 instanceId="SocialMediaShare"
108 portletName="com_liferay_journal_content_web_portlet_JournalContentPortlet"
109 />
110 </div>
111 </div>
112 </div>
113
114
115 <#assign newsVocabName = "News" />
116 <#assign newsTitles = [] />
117
118 <#list asset.getCategories() as category>
119 <#assign vocabName = vocabLocalService.getVocabulary(category.vocabularyId).getTitle("en_US") />
120 <#if vocabName == newsVocabName>
121 <#assign newsName = category.getTitle(themeDisplay.getLocale()) />
122 <#assign newsTitles = newsTitles + [ newsName ] />
123 </#if>
124 </#list>
125
126 <#if (newsTitles?size) gt 0>
127 <div class="news-footer">
128 <h2><@liferay.language key="tags" /></h2>
129 <div class="news-tags">
130 <#list newsTitles as newsName>
131 <button class="btn btn-outline-primary"><#assign text= newsName />
132 <#assign truncatedText = text?substring(0, (text?length > 30)?then(30, text?length))>
133 ${truncatedText}</button>
134 </#list>
135 </div>
136 </div>
137 </#if>
138 </div>
139 <aside class="recent-content content-spacing col-lg-4">
140 <h2 class="hide">${languageUtil.get(locale, "related.content")}</h2>
141 </aside>
142 </div>
143 </div>
144</article>
145
146
147<script>
148(function() {
149const baseUrl = window.location.origin;
150const saveButton = document.querySelector('.save');
151 const unsaveButton = document.querySelector('.unsave');
152initHeaderEvents();
153 function getSavedArticles(articleId, userId){
154 // Fetch current user's Save for this article
155 fetch(baseUrl + '/o/c/newsratings/scopes/${themeDisplay.getScopeGroupId()}?filter=primaryKey eq ' + articleId + ' and userId eq ' + userId, {
156 headers: {
157 'accept': 'application/json',
158 'x-csrf-token': Liferay.authToken
159 }
160 })
161 .then(response => response.json())
162 .then(data => {
163 if (data.totalCount > 0) {
164 saveButton.style.display = 'none';
165 unsaveButton.style.display = 'inline-block';
166 unsaveButton.dataset.ratingId = data.items[0].id;
167 } else {
168 saveButton.style.display = 'inline-block';
169 unsaveButton.style.display = 'none';
170 }
171 })
172 .catch(error => {
173 console.error('Error fetching ratings:', error);
174 });
175};
176
177function updatedArticleToSave(articleId){
178 fetch(baseUrl + '/o/c/newsratings/scopes/' + ${themeDisplay.getScopeGroupId()}, {
179 method: 'POST',
180 headers: {
181 'accept': 'application/json',
182 'Content-Type': 'application/json',
183 'x-csrf-token': Liferay.authToken
184 },
185 body: JSON.stringify({
186 'primaryKey': articleId
187 })
188 })
189 .then(response => response.json())
190 .then(data => {
191
192 saveButton.style.display = 'none';
193 unsaveButton.style.display = 'inline-block';
194 unsaveButton.dataset.ratingId = data.id;
195 })
196 .catch(error => {
197 console.error('Error saving rating:', error);
198 });
199};
200
201function updatedArticleToUnSave(ratingId){
202 fetch(baseUrl + '/o/c/newsratings/' + ratingId, {
203 method: 'DELETE',
204 headers: {
205 'accept': 'application/json',
206 'x-csrf-token': Liferay.authToken
207 }
208 })
209 .then(response => {
210 if (response.ok) {
211
212 unsaveButton.style.display = 'none';
213 saveButton.style.display = 'inline-block';
214 } else {
215 console.error('Error unsaving rating:', response.statusText);
216 }
217 })
218 .catch(error => {
219 console.error('Error unsaving rating:', error);
220 });
221};
222
223function getRelatedContents(articleId, strutureKey){
224 // First API call to get relatedContents
225 fetch(baseUrl + '/o/headless-delivery/v1.0/sites/${themeDisplay.getScopeGroupId()}/structured-contents/by-key/' + articleId + '?restrictFields=actions%2Ccreator', {
226 headers: {
227 'accept': 'application/json',
228 'x-csrf-token': Liferay.authToken
229 }
230 })
231 .then(function(response) {
232 return response.json();
233 })
234 .then(function(data) {
235 var relatedContents = data.relatedContents;
236
237 if (relatedContents && relatedContents.length > 0) {
238 var ids = relatedContents.map(function(content) {
239 return "'" + content.id + "'";
240 }).join(',');
241
242 // Construct the URL for the second API call
243 var url = baseUrl + '/o/headless-delivery/v1.0/content-structures/'+strutureKey+'/structured-contents?fields=friendlyUrlPath,title&restrictFields=actions,creator&filter=(id in (' + ids + '))';
244
245
246 return fetch(url, {
247 headers: {
248 'accept': 'application/json',
249 'x-csrf-token': Liferay.authToken
250 }
251 });
252
253 } else {
254 $(document).find(".recent-content h2").addClass("hide");
255 }
256 })
257 .then(function(response) {
258
259 if (response && !response?.ok) {
260 throw new Error('Network response was not ok: ');
261 }
262 return response?.json();
263 })
264 .then(function(data) {
265 if (data && data.items) {
266 var items = data.items;
267 if($(document).find(".recent-content").length > 0){
268 var asideElement = document.querySelector('.recent-content');
269 items.forEach(function(item) {
270 var anchor = document.createElement('a');
271 anchor.href = item.friendlyUrlPath;
272 anchor.textContent = item.title;
273 asideElement.appendChild(anchor);
274 });
275 $(".recent-content h2").removeClass("hide");
276 }
277 } else {
278
279 $(document).find(".recent-content h2").addClass("hide");
280 }
281 })
282 .catch(function(error) {
283 console.error('Error:', error);
284 });
285}
286
287function initHeaderEvents() {
288 const articleId = ${.vars["reserved-article-resource-prim-key"].data};
289 const articleKey = ${.vars["reserved-article-id"].data};
290 const strutureKey = ${article.getDDMStructure().getStructureKey()};
291
292 const userId = ${themeDisplay.user.getUserId()};
293 const saveButton = document.querySelector('.save');
294 const unsaveButton = document.querySelector('.unsave');
295 const baseUrl = window.location.origin;
296
297 getSavedArticles(articleId, userId);
298 // click event listener for Save button
299 saveButton.addEventListener('click', () => {
300 updatedArticleToSave(articleId)
301 });
302
303 // click event listener for Unsave button
304 unsaveButton.addEventListener('click', () => {
305 const ratingId = unsaveButton.dataset.ratingId;
306 updatedArticleToUnSave(ratingId)
307 });
308 getRelatedContents(articleKey, strutureKey);
309}
310})();
311
312
313$("#share").click(function(){
314 $(".share-dropdown").toggle();
315 });
316
317 $('#copy-link').on('click', function() {
318 var tempInput = $('<input>');
319 $('body').append(tempInput);
320 tempInput.val(window.location.href).select();
321 document.execCommand('copy');
322 tempInput.remove();
323
324 $(this).html('<span><i class="ri-link"></i></span> <@liferay.language key="gup-linkCopied" />');
325});
326
327</script>
هل أنت راضي عن هذه الصفحة؟