Double-escaped label in SelectOneMenu in PrimeFaces 12 - primefaces

In PrimeFaces’ SelectOneMenu, I use options (often placeholders) like <please select>, loaded from controller via f:selectItems and escaped automatically by the SelectOneMenu component. After updating PrimeFaces 11 to version 12, the component started to double-escape the characters <, >, & in its label, while the option list is still rendered as expected. (When I click <please select>, the label shows <please select>.)
I tried all combinations of these settings:
view: f:selectItems.itemLabelEscaped = "true"/"false"
controller: SelectItem.escape = "true"/"false"
controller: SelectItem.label is/isn’t escaped manually
The attribute itemLabelEscaped has no effect. Other combinations work as follows:
No.
SelectItem.escape
SelectItem.label
Option in dropdown
Shown label in PF 11
Shown label in PF 12
1
false
< <i>italics</i>
< italics
italics
italics
2
false
< <i>italics</i>
< <i>italics</i>
< italics
< <i>italics</i>
3
true
< <i>italics</i>
< <i>italics</i>
< <i>italics</i>
< <i>italics</i>
4
true
< <i>italics</i>
< <i>italics</i>
< <i>italics</i>
(even more escaped)
In PrimeFaces 11, I used the setting No. 3, and the label was the same as the option in dropdown. After the update, the label gets broken and the only working setting seems to be No. 2, but I don’t want to update all occurrences of selectItems unless necessary.
As I did not find any relevant info in PrimeFaces’ release notes, I would consider it a bug, but I wonder nobody has reported it yet, so I’m not sure: is it a bug, or a feature? This old question seems to be relevant, but how come it worked in PrimeFaces 11?

This is a known and fixed issue. Until PrimeFaces 13 is released, you can MonkeyPatch the workaround.

OK it should be fixed for good in PF 13.0 and this MonkeyPatch should solve all your current issues.
if (PrimeFaces.widget.SelectOneMenu) {
PrimeFaces.widget.SelectOneMenu.prototype.renderSelectItem = function(item, isGrouped) {
var content = "";
var $item = $(item);
var label;
var title = $item.data("title");
var escape = $item.data("escape");
var cssClass;
if (item.tagName === "OPTGROUP") {
label = $item.attr("label");
if (escape) {
label = $("<div>").text(label).html();
}
cssClass = "ui-selectonemenu-item-group ui-corner-all";
} else { //OPTION
if (escape) {
label = $item.html();
if ($item.text() === " ") {
label = $item.text();
}
} else {
label = $item.text();
}
cssClass = "ui-selectonemenu-item ui-selectonemenu-list-item ui-corner-all";
if (isGrouped) {
cssClass += " ui-selectonemenu-item-group-children";
}
}
var dataLabel = escape ? label.replaceAll('"', '"') : this.escapeHTMLIfNecessary(label);
if ($item.data("noselection-option")) {
cssClass += " ui-noselection-option";
}
content += '<li class="' + cssClass + '" tabindex="-1" role="option"';
if (title) {
content += ' title="' + title + '"';
}
if ($item.is(':disabled')) {
content += ' disabled';
}
content += ' data-label="' + dataLabel + '"';
content += '>';
content += label;
content += '</li>';
if (item.tagName === "OPTGROUP") {
content += this.renderSelectItems($item, true);
}
return content;
};
PrimeFaces.widget.SelectOneMenu.prototype.escapeHTMLIfNecessary = function(value) {
return String(value).replace(/[<>"'`=\/]/g, function(s) {
return PrimeFaces.entityMap[s];
});
};
}

Related

Using jQuery to find <em> tags and adding content within them

The users on my review type of platform highlight titles (of movies, books etc) in <em class="title"> tags. So for example, it could be:
<em class="title">Pacific Rim</em>
Using jQuery, I want to grab the content within this em class and add it inside a hyperlink. To clarify, with jQuery, I want to get this result:
<em class="title">Pacific Rim</em>
How can I do this?
Try this:
var ems = document.querySelectorAll("em.title");
for (var i = 0; i < ems.length; ++i) {
if (ems[i].querySelector("a") === null) {
var em = ems[i],
text = jQuery(em).text();
var before = text[0] == " ";
var after = text[text.length-1] == " ";
text = text.trim();
while (em.nextSibling && em.nextSibling.className && em.nextSibling.className.indexOf("title") != -1) {
var tmp = em;
em = em.nextSibling;
tmp.parentNode.removeChild(tmp);
text += jQuery(em).text().trim();
++i;
}
var link = text.replace(/[^a-z \-\d']+/gi, "").replace(/\s+/g, "+");
var innerHTML = "<a target=\"_blank\" href=\"http://domain.com/?=" + link + "\">" + text + "</a>";
innerHTML = before ? " " + innerHTML: innerHTML;
innerHTML = after ? innerHTML + " " : innerHTML;
ems[i].innerHTML = innerHTML;
}
}
Here's a fiddle
Update: http://jsfiddle.net/1t5efadk/14/
Final: http://jsfiddle.net/186hwg04/8/
$("em.title").each(function() {
var content = $(this).text();
var parameter_string = content.replace(/ /g, "+").trim();
parameter_string = encodeURIComponent(parameter_string);
var new_content = '' + content + '';
$(this).html(new_content);
});
If you want to remove any kind of punctuation, refer to this other question.
$('em.title').html(function(i,html) {
return $('<a/>',{href:'http://domain.com/?='+html.trim().replace(/\s/g,'+'),text:html});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<em class="title">Pacific Rim</em>
UPDATE 1
The following updated version will perform the following:
Grab the contents of the em element
Combine with the contents of the next element, if em and remove that element
Create a query string parameter from this with the following properties
Remove the characters ,.&
Remove html
Append the query parameter to a predetermined URL and wrap the unmodified contents in an e element with the new URL.
DEMO
$('em.title:not(:has(a))').html(function() {
$(this).append( $(this).next('em').html() ).next('em').remove();
var text = $(this).text().trim().replace(/[\.,&]/g,'');
return $('<a/>',{href:'http://domain.com/?par='+encodeURIComponent(text),html:$(this).html()});
});
Or DEMO
$('em.title:not(:has(a))').html(function() {
$(this).append( $(this).next('em').html() ).next('em').remove();
var text = $(this).text().trim().replace(/[\.,&]/g,'').replace(/\s/g,'+');
return $('<a/>',{href:'http://domain.com/?par='+text,html:$(this).html()});
});
UPDATE 2
Per the comments, the above versions have two issues:
Merge two elements that may be separated by a text node.
Process an em element that's wrapped in an a element.
The following version resolves those two issues:
DEMO
$('em.title:not(:has(a))').filter(function() {
return !$(this).parent().is('a');
}).html(function() {
var nextNode = this.nextSibling;
nextNode && nextNode.nodeType != 3 &&
$(this).append( $(this).next('em').html() ).next('em').remove();
var text = $(this).text().trim().replace(/[\.,&]/g,'').replace(/\s/g,'+');
return $('<a/>',{href:'http://domain.com/?par='+text,html:$(this).html()});
});
Actually,if you just want to add a click event on em.title,I suggest you use like this:
$("em.title").click(function(){
q = $(this).text()
window.location.href = "http://www.domain.com/?="+q.replace(/ /g,"+")
}
you will use less html code on browser and this seems simply.
In addition you may need to add some css on em.title,like:
em.title{
cursor:pointer;
}
Something like this?
$(document).ready(function(){
var link = $('em').text(); //or $('em.title') if you want
var link2 = link.replace(/\s/g,"+");
$('em').html('' + link + '');
});
Ofcourse you can replace the document ready with any type of handler
$('.title').each(function() {
var $this = $(this),
text = $this.text(),
textEnc = encodeURIComponent(text);
$this.empty().html('' + text + '');
});
DEMO

How do I make a JSON object produce HTML on the page

Here is my JSON
var gal = [
{
"folder":"nu_images",
"pic":"gd_42.jpg",
"boxclass":"pirobox_gall",
"alt":"Rand Poster 1",
"title":"Rand Poster 1",
"thfolder":"th",
"thumbpic":"th_gd_42.jpg"
},
{
"folder":"nu_images",
"pic":"gd_13.jpg",
"boxclass":"pirobox_gall",
"alt":"Explosive Pixel Design",
"title":"Explosive Pixel Design",
"thfolder":"th",
"thumbpic":"th_gd_13.jpg"
}
];
and here is my for loop
for (i = 0; i < gal.length; i++) {
document.getElementById("gallery").innerHTML = "" + "<img src=\"" + "http:\/\/galnova.com\/" + gal[i].folder + "\/" + "th\/" + gal[i].thumbpic + "\"" + "border=\"0\"" + "alt=\"" + gal[i].alt + "\"" + "title=\"" + gal[i].title + "\"\/>" + ""
};
I am trying to make my JSON show all of the objects in HTML one after the other. I can get it to show the first one or whatever number I put into the array but I don't know how to make it generate a list of them.
Here is a link to my jsfiddle. Any help you can offer would be greatly appreciated.
http://jsfiddle.net/o7cuxyhb/10/
It's being generated here <p id="gallery"></p> just not correctly.
You're overwriting your html with every loop iteration:
document.getElementById("gallery").innerHTML = ...
^---
Perhaps you want something more like
document.getElementById("gallery").innerHTML += ...
^---
which will concatenation the original html contents with your new stuff.
And technically, you shouldn't be doing this in a loop. Changing .innerHTML like that causes the document to be reflowed/re-rendered each time you change .innerHTML, which gets very expensive when you do it in a loop. You should be building your html as a plain string, THEN adding it to the dom.
e.g.
var str = '';
foreach(...) {
str += 'new html here';
}
document.getElementById("gallery").innerHTML += str;
for (i = 0; i < gal.length; i++) {
document.getElementById("gallery").innerHTML += "" + "<img src=\"" + "http:\/\/galnova.com\/" + gal[i].folder + "\/" + "th\/" + gal[i].thumbpic + "\"" + "border=\"0\"" + "alt=\"" + gal[i].alt + "\"" + "title=\"" + gal[i].title + "\"\/>" + "" };
Add a += instead of an = after innerHTML
Try this:
function displayJson(jsonArray){
var container = document.getElementById("gallery");
for (var i=0; i<jsonArray.length; i++){
var newElement = document.createElement("a").innerHTML = jsonToHtml(jsonArray[i])
container.appendChild(newElement);
}
}
function jsonToHtml(jsonObj){
//Define your dom object here
var el = document.createElement("a").innerHTML = '' // you code here
...
return el;
}
displayJson(gal);

ActionScript String Concatenation in for loop

So I am struggling with loops.
I have a mobile app with dynamic controls that I add from a sqlite database, it is a list of questions and based on the question type, I add the relevant type of control to the page along with the question, this all works fine.
I then loop through all the controls looking for answers, so I can loop through 60 quesitons and return the values from the relevant textboxes, checkboxes and toggle switches.
The for loop runs like this
if (displayObject is DisplayObjectContainer && currentDepth < maxDepth)
{
for (var i:int = 0; i < DisplayObjectContainer(displayObject).numChildren; i++)
{
traceDisplayList(DisplayObjectContainer(displayObject).getChildAt(i), maxDepth, skipClass, levelSpace + " ", currentDepth + 1);
if (displayObject is TextInput ||displayObject is CheckBox || displayObject is Label || displayObject is ToggleSwitch )
{
if(displayObject["id"] =="QuestionText"&& (i==0))
{
if(displayObject["text"] != null)
{
questionString= (displayObject["text"]);
trace ("Question: " + questionString);
}
}
else if (displayObject["id"] == "QuestionResponse")
{
if(displayObject["text"] != null)
{
answerString = (displayObject["text"]);
trace ("Answer: " + answerString);
}
}
else if (displayObject["id"]== "CheckboxResult")
{
if(displayObject["selected"] != null)
{
checkboxAnswer = (displayObject["selected"]);
trace ("Check / Toggle: " + checkboxAnswer);
}
}
}
}
}
My question is, the results I get back look like this;
questionstring value
answerstring value
checkbox value
what I want is
questionstring value, answerstring value, checkbox value
I cannot for the life of me see how I get these values into 1 row.
Any tips appreciated
Trace just prints info to the console mainly for debugging if you really want all of that on one line in the console you just need to create a string and then add "Question: " + questionString + " Answer: " + answerString + " Check / Toggle: " + checkboxAnswer to the string after you have found them all and then call trace with your string you made. something like this
var mystring:String
mystring="";
if(displayObject["id"] =="QuestionText"&& (i==0))
{
if(displayObject["text"] != null)
{
questionString= (displayObject["text"]);
mystring += "Question: " + questionString;
}
}
else if (displayObject["id"] == "QuestionResponse")
{
if(displayObject["text"] != null)
{
answerString = (displayObject["text"]);
mystring += "Answer: " + answerString;
}
}
else if (displayObject["id"]== "CheckboxResult")
{
if(displayObject["selected"] != null)
{
checkboxAnswer = (displayObject["selected"]);
mystring += "Check / Toggle: " + checkboxAnswer;
}
}
trace(mystring);

Issue with adding a image at the end of tabs

I am trying to add add a button called shopping cart to my Tabs script. The new button is controlled if a checkbox is clicked. (Show). Im confused why the image is not showing. Any answers would be helpful.
Thank you.
Copy code
$(function() {
var $tabs = $('#tabs').tabs({cookie:{expires:1}});
$(".ui-tabs-panel").each(function(i){
var totalSize = $(".ui-tabs-panel").size() - 1;
var prevImage = "custom/images/prev.png";
var nextImage = "custom/images/next.png";
var atcImage = "custom/images/cart.jpg";
if (i != 0) {
prev = i;
$(this).append("<img href='#' class='prev-tab mover' rel='" + prev + "' src='" + prevImage + "'></img>");
}
if (i != totalSize) {
next = i + 2;
$(this).append("<img href='#' class='next-tab mover' rel='" + next + "' src='" + nextImage + "'></img>");
}
if (i > 1) {
atc = i + 2;
$(this).append("<img href='#' class='atc-tab mover' rel='" + next + "' src='" + atcImage + "'></img>");
}
$('input[name=FIELD_469]').click(function() {
if (this.checked) {
$("img[src*=cart]").show();
}
else {
$("img[src*=cart]").hide();
}
});
$('.next-tab, .prev-tab, .atc-tab').click(function() {
$tabs.tabs('select', $(this).attr("rel"));
return false;
});
});
Sorry, I can not ask for clarification because of low level of my rating, but there are several things that I have noticed and some recomendations.
1) Your selector should look like 'img[src~="cart"]'
http://api.jquery.com/attribute-contains-word-selector/
2) If you use class 'mover' only for that images, you can use '.mover' selector, otherwise just add new class name.
3) Test your JQuery objects with Google Chrome using console.log($("selector")) (Tools->Developer Tools->Console)
4) I think it should be not 'this' but $(this)
$('input[name=FIELD_469]').click(function() {
if (this.checked) {
$("img[src*=cart]").show();
}
If recommendations don't help, please provide more info about your form preferrably with example to see. Thanks

How to serialize HTML DOM to XML in IE 8?

Is there a way to do it(serialization of HTML DOM into XML) in IE 8 or any other older version of IE.
In firefox :
var xmlString = new XMLSerializer().serializeToString( doc );
does it.I haven't tried it, though.
XMLSerializer causes error in IE 8, that it is not defined.
var objSerializeDOM = {
//Variable to hold generated XML.
msg : "",
serializeDOM : function() {
dv = document.createElement('div'); // create dynamically div tag
dv.setAttribute('id', "lyr1"); // give id to it
dv.className = "top"; // set the style classname
// set the inner styling of the div tag
dv.style.position = "absolute";
// set the html content inside the div tag
dv.innerHTML = "<input type='button' value='Serialize' onClick='objSerializeDOM.createXML()'/>"
"<br>";
// finally add the div id to ur form
document.body.insertBefore(dv, document.body.firstChild);
},
/**
* XML creation takes place here.
*/
createXML : function() {
objSerializeDOM.msg += "";
objSerializeDOM.msg += "<?xml version='1.0' encoding='UTF-8'?>\n\n";
// Get all the forms in a document.
var forms = document.forms;
for ( var i = 0; i < forms.length; i++) {
// Get all the elements on per form basis.
elements = document.forms[i].elements;
objSerializeDOM.msg += "<FORM name=\"" + forms[i].name + "\" method=\""
+ forms[i].method + "\" action=\"" + forms[i].action + "\">\n\n";
for ( var j = 0; j < elements.length; j++) {
objSerializeDOM.msg += " <" + elements[j].tagName + " type=\""
+ elements[j].type + "\"" + " name=\""
+ elements[j].name + "\"" + " Value =\""
+ elements[j].value + "\" />\n";
}
alert(document.forms[i].elements[1].event);
}
objSerializeDOM.msg += "\n\n</FORM>\n\n";
alert(objSerializeDOM.msg);
objSerializeDOM.writeToFile(objSerializeDOM.msg);
},
/**
* Writes the msg to file at pre-specified location.
* #param msg
* the XML file created.
*/
writeToFile : function(msg) {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fh = fso.CreateTextFile("c:\\myXML.xml", true);
fh.WriteLine(msg);
fh.Close();
}
};
objSerializeDOM.serializeDOM();
I wrote this JS, I run this javascript using GreaseMonkey4IE. This simply puts a button on every page of the domain you specify in GM4IE. On click of that button it will parse the HTML document and create an XML file. It will also display the same as an alert first and will save the XML in your local drive on path specified.
There a still many improvements I am planning to do, but yes it works and may be give you guys an idea.The program is self-explanatory, I hope.
please have a look here How to get Events associated with DOM elements?Thanks