liferay-ui:captcha customization/localization in Liferay 6.2 - liferay

After migration to Liferay 6.2 <liferay-ui:captcha> customization stopped working:
original input is no longer hidden
refresh link appeared (we need it hidden, or translate label and remove bugged tooltip - it flickers on hover)
LFR 6.1 code:
xmlns:form="http://www.springframework.org/tags/form"
xmlns:liferay-ui="http://liferay.com/tld/ui"
<liferay-ui:captcha url="${captchaURL}"/>
<label for="captchaText" >
Opiste text z obrazku
</label>
<form:input id="captchaText" path="captcha" />
What is the proper way to customize captcha component?
I tried replacing our ids to match ids of fields generated by Liferay, but it did not work.
Code generated by Liferay:
<div class="taglib-captcha" id="yui_patched_v3_11_0_1_1425121596007_13262">
<img alt="Text to Identify" class="captcha"
id="_pspmlmuserportlet_WAR_pspmlmuserportlet_captcha"
src="..."/>
<span class="refresh" onmouseover="Liferay.Portal.ToolTip.show(this, 'Refresh CAPTCHA')"
data-title="" id="yui_patched_v3_11_0_1_1425121596007_13261">
<a href="javascript:;" class=" taglib-icon" id="_pspmlmuserportlet_WAR_pspmlmuserportlet_refreshCaptcha">
<img id="refreshCaptcha" src=".../refresh.png" alt="Refresh CAPTCHA" title="Refresh CAPTCHA"/>
<span class="taglib-text hide-accessible">Refresh CAPTCHA</span>
</a>
</span>
<div class="form-group" id="yui_patched_v3_11_0_1_1425121596007_14890">
<label class="control-label" for="_pspmlmuserportlet_WAR_pspmlmuserportlet_captchaText">
Text Verification <span class="label-required">(Required)</span>
</label>
<input class="field form-control" id="_pspmlmuserportlet_WAR_pspmlmuserportlet_captchaText"
name="_pspmlmuserportlet_WAR_pspmlmuserportlet_captchaText" type="text" value="" size="10"/>
</div>
</div>
I can probably do it by jQuery, but I would be interested in a proper way to do it.
Thanks

I think the best way should be working in ext environment, for modify your UI taglib code... I'm not sure you can hook a taglib.

You can customize the UI taglib: captcha via hook. Here's an example enter link description here. In this example I set the theme of the reCaptcha via properties.

Liferay 6.2 code for create a simple captcha
<%# taglib uri="http://alloy.liferay.com/tld/aui" prefix="aui"%>
<%# taglib uri="http://liferay.com/tld/ui" prefix="liferay-ui" %>
<%# taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
This URL will be invoked before showing the CAPTCHA image
<portlet:resourceURL var="captchaURL"/>
This is the Html code to display the image
<aui:column columnWidth="10" first="true">
<div class="input-piwest-captcha">
<liferay-ui:captcha url="<%=captchaURL%>" />
</div>
<div class="input-piwest-captchaError">
<liferay-ui:error key="errorMessage" message="Code does not match. Please try again."/>
</div>
</aui:column>
Java Code
import com.liferay.portal.kernel.captcha.CaptchaException;
import com.liferay.portal.kernel.captcha.CaptchaUtil;
#ResourceMapping
public void serveResource(ResourceRequest resourceRequest,
ResourceResponse resourceResponse) throws IOException {
CaptchaUtil.serveImage(resourceRequest, resourceResponse);
}
private String getCaptchaValueFromSession(PortletSession session) {
Enumeration<String> atNames = session.getAttributeNames();
while (atNames.hasMoreElements()) {
String name = atNames.nextElement();
if (name.contains("CAPTCHA_TEXT")) {
return (String) session.getAttribute(name);
}
}
return null;
}
Validate the CAPTCHA TEXT
PortletSession session = actionRequest.getPortletSession();
String enteredCaptchaText = ParamUtil.getString(actionRequest, "captchaText");
String captchaText = getCaptchaValueFromSession(session);
if (Validator.isNull(captchaText) || !StringUtils.equals(captchaText, enteredCaptchaText)) {
throw new CaptchaException("Invalid captcha text. Please reenter.");
}

Related

EJS check if status is 200

I am looping over an array of objects, these objects contains links to images. Some of these images return with status 403 and do not display.
Here is what I have in ejs
<% Recipes.forEach(recipe => { %>
<div class="basis-2/12 min-w-max">
<% if (recipe.image) { %>
<img class="w-60 h-40 object-cover bg-slate-100 rounded-xl" src="<%= recipe.image %>" />
<% } else { %>
<img class="w-60 h-40 object-cover bg-slate-100 rounded-xl" src="/images/placeholder.png" /> <% } %>
</div>
<% }) %>
The if (recipe.name) itself only check whether there is a link or not, which is always true.
How should I go for this?
This solution works, the recipe.image (in this case) must have a value of null
You'd have to actually fetch the image on the server before rendering the page, which would slow down the loading.
If using JavaScript on the client side is possible, consider implementing the fallback there. See for example this answer: https://stackoverflow.com/a/1588899/240963
<img
src="<%= recipe.image %>"
onerror='this.onerror = null; this.src="/images/placeholder.png"'
/>
Alternatively you could implement a proxy on the server, and serve the fallback in case the image on the origin is not found; useful package for this is for example: https://github.com/http-party/node-http-proxy

How to change the pop html on button click

I am trying to find a way to change the pop up HTML on a chrome extension to another one when you click a button. I have tried to make a onclick function href but nothing works. I am new to both HTML and chrome extensions so I am sorry if this problem seems easy to the more experience developers.
<form id="gform" method="POST" class="pure-form pure-form-stacked" data-email="from_email#example.com"
action="https://script.google.com/a/cvsd356.org/macros/s/AKfycbxb4ZyUUQCnTN-7iYF-YRViDSy/exec">
<div class="name">
name: <input type="text" name="Name" id= "inputbox"><br>
</div>
<div class="id">
ID# <input type="text" name= "ID" id= "inputbox"><br>
</div>
<div class="MailingAddress">
Mailing Address: <input type="text" name= "Mailing Adresss" id= "inputbox" style=width:350px;><br>
</div>
<div class="sendToTr">
Send Transcript to: <input type ="text" name="College" style=width:350px; id= "inputbox" ><br>
</div>
<div class="emailmy">
<label for="email"><em>Your</em> Email Address:</label>
<input id="inputbox" name="email" type="email" value=""
required placeholder="your.name#email.com" />
</div>
<div class="sButton">
<button style=height:30px;width:70px;border-radius: 3px; class="button-success pure-button button-xlarge">
send
</button>
</div>
I think there are quite a few ways to achieve what you are asking. If I were you, I would add a JavaScript file to my project to do this.
Step 1:
I would tell my HTML page where to find this JS file. The sample below can be included near the end of your HTML file, right before </body></html>. The sample below assumes your new popup.js file is in the root folder of your project:
<script src="popup.js" type="text/javascript"></script>
Step 2:
In the popup.js file, I would create a function that tells the popup how it should be modified. In the sample below, I'm going to hide the element with an ID of "theOldElement" and show the element with an ID of "theNewElement". I'm also going to attach this function to the click event of "theButton" element.
popup.js
function updatePopup(){
document.getElementById("theNewElement").style.display = "block";
document.getElementById("theOldElement").style.display = "none";
}
document.getElementById('theButton').addEventListener('click', updatePopup);
Step 3:
I like referring to my HTML elements by ID (as I've been doing above - note the "getElementById" references), so I would:
add id="theNewElement" to the element I want to reveal
add id="theOldElement" to the element I want to hide
add id="theButton" to the button that I want to trigger this change
Note: you can insert these IDs as the first attribute within the tag you want to identify. E.g., <div id="theNewElement" ...

Processing dynamically added elements Material Design Lite

First, the code:
$(document).ready(function() {
$('#member_pattern').hide();
$('.add-member').click(function() {
var clone = $('#member_pattern').clone(), cont = $('.members-cont');
$(cont).append(clone);
$(cont).find('#member_pattern').show(200, function() {
$(this).attr('id', '');
componentHandler.upgradeAllRegistered();
});
});
});
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<link rel="stylesheet" href="https://storage.googleapis.com/code.getmdl.io/1.0.2/material.blue-indigo.min.css" />
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://storage.googleapis.com/code.getmdl.io/1.0.0/material.min.js"></script>
<div class="members-cont">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="first_name_<?php echo $member->id; ?>" value="<?php echo $member['first_name']; ?>"/>
<label class="mdl-textfield__label" for="first_name_<?php echo $member->id; ?>">Имя</label>
</div>
</div>
<button class="add-member add-member-top mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
<i class="material-icons">add</i>
</button>
<div id="member_pattern" class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="[name]_[id]" value=""/>
<label class="mdl-textfield__label" for="[name]_[id]">Имя</label>
</div>
Objective:
By pressing a button on the page dynamically insert another field [.mdl-textfield], you want to apply the "material design" on Google
All is good, but the methods
componentHandler.upgradeAllRegistered ();
or
componentHandler.upgradeDom ();
in any does not want to renew, re-emerged, the elements on the page.
I also was having problems cloning an element and getting it to work correctly. What I did was to remove the MDL specific classes from the div and change it to a generic class name that I could select on.
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
became
<div class="upgradeTextField">
Then in javascript, after cloning the element, I selected for those divs within the cloned element and added the MDL specific classes to them. After that, running componentHandler.upgradeDom() seemed to work.
var textFieldUpgrades = cloned.querySelectorAll('.upgradeTextField');
if(textFieldUpgrades) {
for(var i=0;i<textFieldUpgrades.length;++i) {
textFieldUpgrades[i].className = 'mdl-textfield mdl-js-textfield mdl-textfield--floating-label';
}
}
componentHandler.upgradeDom();
I haven't verified this, but it seems that when you clone an existing element within the dom that has been upgraded by MDL previously, it won't upgrade it when you add the cloned object to the DOM. So that's why I simply removed the MDL classes so it wouldn't be upgraded beforehand.
Alternatively, if you need it upgraded beforehand and still want to clone it. Then what you can do is to remove the attribute 'data-upgraded' and class 'is-upgraded' from your element after you clone it. Then when you run the componentHandler.upgradeDom() it should upgrade it. So, instead of just setting the class name as in the above snippet, you'd simply remove the upgrade info:
textFieldUpgrades[i].setAttribute('data-upgraded','');
textFieldUpgrades[i].className = textFieldUpgrades[i].className.replace(/is-upgraded/g,'');
This seemed to work for me.
Thanks for the answer, but it turned out to solve it more concise way
var index = $('.member-section').length;
var clone = $('.member-section-pattern').clone();
$(clone)
.removeClass('member-section-pattern')
.find(':not([data-upgraded=""])').attr('data-upgraded', '');
$('.members-cont').append(clone);
$(clone).show(200, function() {
componentHandler.upgradeAllRegistered();
});

"The requested resource was not found" When submitting a form in liferay portlet

I'm developing a liferay portlet. This is not my first time doing that, but a get a simple error that I can't understand why I'm getting this error. When I click submit button I get this error
The requested resource was not found. "http://localhost:8081/addProduct"
It's more than hours I'm trying to solve it and I know that I have made a silly mistake. Can any body help me solve this problem? Any help is appreciated in advance. Here is my jsp code:
<%# taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
<%# taglib uri="http://liferay.com/tld/aui" prefix="aui" %>
<%# page import="javax.portlet.PortletURL" %>
<portlet:defineObjects />
This is the <b>ServiceBuilderTest</b> portlet.
<portlet:actionURL var="addProduct" name="addProductAction"/>
<aui:form method="post" action="addProduct">
<aui:fieldset>
<aui:input name="productName" label="Product Name"></aui:input>
<aui:input name="userID" label="User ID"></aui:input>
<aui:input name="companyID" label="company ID"></aui:input>
<aui:input name="groupID" label="Group ID"></aui:input>
<aui:input name="serialNumber" label="Serial Number"></aui:input>
<aui:button type="submit" value="Submit"></aui:button>
</aui:fieldset>
</aui:form>
And this is my portlet class code:
public class ServiceBuilderPortlet extends MVCPortlet{
public void addProductAction(ActionRequest actionReauest, ActionResponse actionResponse) throws SystemException, PortalException
{
String productName = actionReauest.getParameter("productName");
String userID = actionReauest.getParameter("userID");
String companyID = actionReauest.getParameter("companyID");
String groupID = actionReauest.getParameter("groupID");
String serialNumber = actionReauest.getParameter("serialNumber");
PRProduct product = PRProductLocalServiceUtil.addProduct(Long.parseLong(companyID), Long.parseLong(groupID), productName,
serialNumber, Long.parseLong(userID));
}
}
make it
<portlet:actionURL var="addProduct" name="addProductAction"/>
<aui:form method="post" action="<%=addProduct%>">
...
actually, I'd see it as best practice to not name the action "addProductAction", but just "addProduct", so the changes would be as such (including one line of java, the rest looks good (visually, not tried/tested):
<portlet:actionURL var="addProduct" name="addProduct"/>
<aui:form method="post" action="<%=addProduct%>">
....
and
public class ServiceBuilderPortlet extends MVCPortlet{
public void addProduct(ActionRequest request, ActionResponse response) throws SystemException, PortalException {
// ...
}
}

nested template rendering in backbone.js

I have a template like
script type: "text/template", id: "list-template", '''
<div class="display">
<div id="list-name"><%= name %></div>
<span class="list-destroy"></span>
</div>
<div>
<ul id="ul-cards">
</ul>
</div>
<div class="edit">
<input class="list-input" type="text" value="<%= name %>" />
<input id="btnEdit" type="button" value="Save" class="primary wide js-add-list" />
<input id="hdnListId" type="hidden" value="<%= listId%>" />
</div>
<form class="add-list-card js-add-list-card clearfix">
<textarea placeholder="Add card" class="new-card"></textarea>
<input type="button" value="Add" class="primary js-add-card">
<a class="app-icon close-icon dark-hover cancel js-cancel-add-card" href="#" id="closeCard"></a>
</form>
'''
in this template i have <ul id="ul-cards"> element in which i want to render another template which display list inside this ul.
this template is :
script type: "text/template", id: "card-template", '''
<div>
<span class="card-name"><%= name %></span>
</div>
'''
is it possible or i have to do it in another way?
please help me if anyone have idea.
thanks in advace.
it is worked but still i have one problem in data display in
<ul id="ul-cards"> there sholud be 2 as per records in my database but it will display only 1 . data fetch properly but display only last data.
There are two ways to do this: the DOM way and the template way.
The DOM way involves adding your views using DOM methods: you have your ListView and your CardView; the ListView invokes individual CardViews that fill in the ListView's element.
The template way requires that you remember this: backbone's views are policy frameworks, not policy templates. Render doesn't have to render into the DOM. You can use render() to return a string, for example. If your event manager is on the ListView object only (possible; I've done this), then you can have ListView invoke "the resulting array of an array of CardView renders" and insert that directly into ListView's template. This is actually faster, as you only require the browser to analyze the entire ListView HTML blob once, when it's inserted into the innerHTML of the parent DOM object.

Resources