Access portlet namespace in Freemarker template - liferay

I'm using a freemarker template to display web contents listed in an asset publisher.
In the template I'm trying to assign the portlet-namespace in order to use some asset features (like printing the entry) like this
<#attempt>
<#assign namespace = request["portlet-namespace"]>
<#recover>
<#assign namespace = 'undefined'>
</#attempt>
So, the print button is holding te code below
<a href="javascript:${namespace}printPage_0();" title='Print'>
printPage is the method used in liferay asset publisher code in asset_print.jspf
Well, everything is working fine: when inspecting the page in a browser, I verified that the namespace has been calculated and assigned to namespace variable as well (and no error displayed in UI). However, liferay portal logs the following each time a user tries to see the whole web content (ie. clicks on read more) from the asset publisher
Expression request["portlet-namespace"] is undefined on line
Anyone has seen this problem ? Is there another way to get the portlet-namespace in a freemarker template ?

#attempt/#recover is not for recovering from normal situations, and by default it logs the error when it recovers (so that the operators will be alerted). You should instead use the exp!default operator:
<#assign namespace = request["portlet-namespace"]!'undefined'>
(Though I'm not sure why printing undefinedprintPage_0(); makes sense, but that's a different issue.)

Related

Azure B2C injects different html despite LoadUri having the same html content

I am using custom policies and all is working great except that I do not understand the following wierd behavior of the injected html. I am working on a password reset flow and adapted the starterpack.
In a ContentDefinition and indpendent from the layout version (here 2.1.2, but the problem occurs also for 2.1.0)
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.2</DataUri>
I get a different injected html based only on whether I use the default page
<LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
or my custom one,
<LoadUri>https://mytenant.blob.core.windows.net/b2cweb/selfasserted.html</LoadUri>
But this custom page contains excatly the same html as the AzureBlue one. Specifically,
I navigated to the page /tenant/templates/AzureBlue/selfAsserted.cshtml , copied the html content and pasted it in my custom file in blobstorage.
Expected result
I expect the html page where the id="api" div is injected to be exactly the same if I call the LoadUri one or two. Nothing else in the custom policy files is changed.
Result
If I use the default LoadUri, the cancel button is shown just below the div id="api", as expected for a proper html document format
If I use my custom page, which again contains the same html but lives in blobstorage, the cancel button appears below the continue button in the html (but is rendered on top via css absolute positioning)
Also notice the appeareance of an empty div with class="buttons" at the beginning of the div id="api".
I need to understand what is happening for the purpose of understanding and ideally I would like the generated cancel button to appear just like the default AzureBlue.
I checked out that the old, classic userflow puts the button at the bottom, so it is as if I am using version 1.2.0 but only for my custom page, whereas my content definition is always 2.1.2 or 2.1.1.
Thanks Octopus and please find the same response here.
This is expected because of policy engine and location of storage with predefined CORS server and corresponding linked metadata files for rendering. So please use as best practices provided in the document - https://learn.microsoft.com/en-us/azure/active-directory-b2c/page-layout

Liferay 7.3: How to preconfigure a portlet embedded in a page fragment?

We're using Liferay 7.3 (CE) and are trying to embrace the relatively new feature of "Content Pages" with "Page Fragments". We're able to develop page fragments that already include portlets (named "widgets" in the context of content pages), using the <lfr-widget-WIDGETALIAS> tag. So far, that works.
Now we're trying to prepare page fragments that embed portlets with special portlet configuration applied. For example, we want to prepare a page fragment that just shows an asset publisher portlet configured to list WebContent articles from a pre-defined category. The user should be able to just put that fragment onto the page without having to care about the configuration of the asset publisher portlet.
We did not find any direct way to achieve that -- our first guess that the configuration could be written as attributes or content of the <lfr-widget-...> tag was deterred by a hint in the liferay docs that there are no valid attributes or content to attach to that tag.
Does anybody have an inkling of an idea on how to achieve embedding portlets in page fragments with pre-defined portlet configuration applied? (including out-of-the-box Liferay portlets?)
I figured it out myself.
That one thing that the Fragment Editor does not tell you is that the HTML part of a fragment actually is interpreted as a Freemarker template, with the caveat that only Freemarkers alternative syntax is allowed.
That, in turn, means that Liferays taglibs are available, which means we can use the tag <liferay-portlet:runtime> (ported to freemarker alternative syntax, of course), which does accept a defaultPreferences attribute. Now we can just configure the portlet once, find its portletPreferences XML data in the DB (see table PortletPreferences), remove values we do not want to preconfigure and then just use the resulting preferences XML as a value for the defaultPreferences attribute of the <liferay-portlet:runtime> tag.
Care has to be taken for any IDs (e.g. if you want to preconfigure an AssetCategory filter). Better fetch the corresponding object from the corresponding service and get the ID from that object.
This example provides the HTML part for a page fragment that places an AssetPublisher onto the page, preconfigured to show 12 items (instead of the default 20). (CSS, JS and Configuration of the fragment is the default as given by the Page Fragment editor.)
<div class="fragment-12345">
[#assign assetPublisherPortletPreferences="<portlet-preferences>
<preference>
<name>delta</name>
<value>12</value>
</preference>
</portlet-preferences>" /]
[#liferay_portlet["runtime"]
instanceId="${fragmentEntryLinkNamespace}assets"
portletName="com_liferay_asset_publisher_web_portlet_AssetPublisherPortlet"
defaultPreferences="${assetPublisherPortletPreferences}"
/]
</div>
Thank you for this, #orithena. You saved me a lot of trouble.
Another option, to achieve the same result but with simpler syntax, is to use the built-in freeMarkerPortletPreferences:
[#assign assetPublisherPortletPreferences=freeMarkerPortletPreferences.getPreferences({
"delta": "12",
} /]

I want to create an angular app to show live code preview like Jsbin

I'm creating the Angular app which lets user save his html code (maybe it has style and script tag to control the view) and there is a live preview next to it. User can save the code and other users can come to see the code and the preview. I also worry about the security because of script tag and I want the script to work only with the code that user provides (Not allow to control or get the data in the parent frame). So I need some suggesting of how to do it.
I have tried the preview with iFrame by giving the value through the 'srcdoc' property, but it looks like the security is bad.
You would not need to use an iframe in that situation, you can just render an HTML string inside of a div element using the innerHtml input like so:
<div [innerHTML]="htmlString"></div>
Where htmlString is a string containing the HTML code. You will have to sanitize the content of that variable with the DomSanitizer.
constructor(private domSanitizer: DomSanitizer){}
...
ngOnInit() {
this.htmlString = this.domSanitizer.bypassSecurityTrustHtml(yourHTMLString);
}

Page template - Object reference not set to an instance of an object

I have a page template that has this line of code below:
<div id="<%= CurrentDocument.NodeAlias %>" class="lvl3">
Things work - the id value shows correctly. However, when using the Page Templates module Design tab, there's an error. In Event log, I saw the error message "Object reference not set to an instance of an object". Taking the id snippet out, the error is gone. I'm not sure what the error means and how to fix it. Could you help?
I do need some page-specific unique identifier in there (NodeAlias in this case) for other purposes.
The answer is pretty simple - if you open your page template in Kentico Page Templates application - your CurrentDocument is always null (because you are editing Template itself without specific document).
You could do absolutely the same thing in Pages application with the Design tab. It's also possible to edit all the template properties from there, including the Layout:
Using code blocks on page template layout is not supported. I assume you are using ASCX layout. Moreover your code looks more like a macro - so, maybe you are using HTML layout type? If yes, then the syntax should be {%CurrentDocument.NodeAlias%}
If you are using ASCX layout you may face also this issue: https://devnet.kentico.com/articles/the-controls-collection-cannot-be-modified-because-the-control-contains-code-blocks
Note that in portal engine the life cycle is bit modified, so we cannot ensure the code blocks will work every time - it may work sometimes. It mainly depends on what other web parts/controls and in what order are placed in the page template. I would rather recommend using the workaround from the article.
Or, you can give it a try, with no guarantee, this may work in certain cases, you need to specify the full namespace:
<%= CMS.MacroEngine.MacroResolver.Resolve("{%CurrentDocument.NodeAlias#%}") %>

Expression Engine template variable passing

I'm building in Expression Engine 2.3 a user profile system using Solspace's User and Friends modules. They work fine, but I'm having an incredibly difficult time with passing embedded variables around.
I've got a .profile_head template that's called from each template. The profile page, the friends page, the private messaging page, etc. It builds a user navigation, displays the avatar, all the common user stuff. All of this is based off of the user ID passed through {segment_3}. This allows me to display a different user's info by changing this segment.
The problem is doing this makes my URLs far too precise. I can't have users going to /users, they have to go to /users/profile/UID or the best possible scenario is an error page or redirect to the home page.
I tried to solve this problem through variables in my template:
{embed="/users/.profile_head" uid="{segment_3}"}
or......
{embed="/users/.profile_head" uid="{logged_in_member_id}"}
In the .profile_head template file, I can print out {embed:uid} just fine, but when I try to assign it to anything (i.e. a loop or another template), it breaks:
<!-- /users/.profile_head -->
{exp:friends:members member_id="{embed:uid}" dynamic="off" limit="1"}
or.....
{embed="users/.profile_column" uid="{embed:uid}"}
For instance, if {embed:uid} is set as {logged_in_member_id}, I get the following error:
Parse error: syntax error, unexpected T_LNUMBER in /var/www/system/expressionengine/libraries/Functions.php(656) : eval()'d code on line 9
This is line 9:
{if logged_in_member_id == "{embed:uid}"} <span class="this_is_you">This is you!</span>{/if}
I really am at my wits end. I need to be able to use this profile header in templates without requiring a user id in the URL for things like the user messaging and settings pages. But nothing I try seems to be working in the least.
I believe that {logged_in_member_id} is a late-parsed variable, which means it may not be available in some of your tags at the point they're processed - hence it's passed as literally {logged_in_member_id}.
Try using the CURRENT_USER constant instead.

Resources