Confirm with ConfirmDialog and escaped message

UI Components for JSF
Post Reply
Jorge
Posts: 25
Joined: 21 Sep 2011, 14:00

14 Nov 2017, 16:04

Hey guys,

I have here a confirm action that calls a confirmDialog setted with global=true And I wanted to show the formatted message so I discovered that there is a facet to that, my problem is when the message comes from a p:confirm, how do I get the message?

This is my button with the confirm component

Code: Select all

<p:commandButton id="btToTest"
                          action="#{myBean.doSomething}"
                          value="#{messagesBundle['switch.off']}">
	<p:confirm header="#{messagesBundle['modalgenericconfirm.header']}"
	                                 message="#{jsfUtil.getBundledMessage('test.remove_message', varDataTable.name)}"/>
</p:commandButton>
This is my genericModal:

Code: Select all

<p:confirmDialog id="genericDialogConfirm" global="true" showEffect="fade" hideEffect="fade" style="width:350px !important;" closable="false" 
					widgetVar="wvDialogConfirm">
	    <div align="center">
		    <p:commandButton value="#{messagesBundle['button.cancel']}" 
		     				 type="button"
		     				 styleClass="ui-confirmdialog-no ui-button redRoman-button"
		     				 icon="fa fa-close"/>
		    <p:commandButton value="#{messagesBundle['button.confirm']}"
				       		 type="button"
				       		 styleClass="ui-confirmdialog-yes ui-button light-green-button"
				       		 icon="fa fa-check"/>
	    </div>
</p:confirmDialog>
In my messagesBundle my propertie is like this:

Code: Select all

test.remove_message = You will remove <b>"{0}"</b>. Do you want to continue?
The "jsfUtil.getBundledMessage" will get the bundle passing through the parameter.

The issue here is how I properly use the facet so I can show a escaped message, something like this:

Code: Select all

<p:confirmDialog id="genericDialogConfirm" global="true" showEffect="fade" hideEffect="fade" style="width:350px !important;" closable="false" 
					widgetVar="wvDialogConfirm">
          <f:facet name="message">
                   <h:outputText value="HOW TO GET THE MESSAGE FROM P:CONFIRM HERE???" escape="false"/>
          </f:facet>
	    .... buttons
</p:confirmDialog>
I found this open issue here (https://github.com/primefaces/primefaces/issues/60) from 2015 but nothing more to it

Thanks.
Jorge Campos
--
Eclipse Juno
Primefaces 6.1.RC3
JSF 2.2.8
Apache Tomcat 8.5.14

Melloware
Posts: 3717
Joined: 22 Apr 2013, 15:48

14 Nov 2017, 23:04

It looks like that issue is still open and was never actually fixed which is why you are seeing this behavior.

See @tandrashcko's post in that ticket it says "On p:confirm, a facet can NOT be used."

So this would need to be fixed in the p:confirm code.
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

Jorge
Posts: 25
Joined: 21 Sep 2011, 14:00

16 Nov 2017, 20:35

Ok,

I've done it here. In case someone need it. I may have done an overkill to solve this, but it was the faster way I find without having to recompile the whole Primefaces.

1 - Copied both classes ConfirmBehavior and ConfirmBehaviorHandler from Primefaces to my project renaming both to CustomConfirmBehavior and CustomConfirmBehaviorHandler

In the CustomConfirmBehavior class the changes were:

Code: Select all

    //changed the id
    public final static String BEHAVIOR_ID = "org.primefaces.behavior.MyConfirmBehavior";
    
    public enum PropertyKeys {
        //... ,
    	escape(Boolean.class);  // Added this attribute
        // ...
    }
    
    //in the method:
    @Override
    public String getScript(ClientBehaviorContext behaviorContext) {
            //...
            String messageText = JSONObject.quote(this.getMessage());
            String escape = JSONObject.quote(String.valueOf(this.isDisabled()));
            
            if(component instanceof Confirmable) {
                String sourceProperty = (source == null) ? "source:this" : "source:\"" + source + "\"";
                String script = "PrimeFaces.confirm({" + sourceProperty + ",escape:" + escape + ",header:" + headerText + ",message:" + messageText + ",icon:\"" + getIcon()  + "\"});return false;";
                ((Confirmable) component).setConfirmationScript(script);
                return null;
            }
            else {
                throw new FacesException("Component " + source + " is not a Confirmable. ConfirmBehavior can only be attached to components that implement org.primefaces.component.api.Confirmable interface");
            }
            
            //....
            // Added get and set to the new attribute
            public boolean isEscape() {
                  return eval(PropertyKeys.escape, Boolean.FALSE);
            }
            public void setEscape(boolean escape) {
                  setLiteral(PropertyKeys.escape, escape);
            }
     }
In the CustomConfirmBehaviorHandler class the changes were:

Code: Select all

       public class CustomConfirmBehaviorHandler extends AbstractBehaviorHandler<CustomConfirmBehavior> {
              //...
              private final TagAttribute escape;
              
              //added in the constructor:
                   this.escape = this.getAttribute(CustomConfirmBehavior.PropertyKeys.escape.name());
                   
             //added in the createBehavior method:
                  setBehaviorAttribute(ctx, behavior, this.escape, CustomConfirmBehavior.PropertyKeys.escape.expectedType);
Then I created a custom tag lib adding it in my web.xml

Code: Select all

    <context-param>
        <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
        <param-value>/WEB-INF/my.taglib.xml</param-value> <!-- if you have others, separate it with ; --> 
    </context-param>
And the contents of my.taglib.xml

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
									http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
				version="2.0">
    
	<namespace>http://primefaces.org/my</namespace>
    
    <tag>
        <tag-name>myconfirm</tag-name>
        <behavior>
            <behavior-id>org.primefaces.behavior.MyConfirmBehavior</behavior-id>
            <handler-class>com.myproject.customcomponents.CustomConfirmBehaviorHandler</handler-class>
        </behavior>
		<attribute>
			<description>Header text of the confirmation dialog.</description>
			<name>header</name>
			<required>false</required>
			<type>java.lang.String</type>
		</attribute>
        <attribute>
			<description>Detail text of the confirmation dialog.</description>
			<name>message</name>
			<required>false</required>
			<type>java.lang.String</type>
		</attribute>
        <attribute>
			<description>Icon to display inside the confirm dialog.</description>
			<name>icon</name>
			<required>false</required>
			<type>java.lang.String</type>
		</attribute>
        <attribute>
			<description>Disables confirm behavior.</description>
			<name>disabled</name>
			<required>false</required>
			<type>java.lang.Boolean</type>
		</attribute>
		<attribute>
			<description>Escape the message attribute.</description>
			<name>escape</name>
			<required>false</required>
			<type>java.lang.Boolean</type>
		</attribute>
    </tag>
</facelet-taglib>
And in faces-config.xml file I registered it:

Code: Select all

    <!-- .... -->
    </application>
    <behavior>
        <behavior-id>org.primefaces.behavior.MyConfirmBehavior</behavior-id>
        <behavior-class>com.myproject.customcomponents.CustomConfirmBehavior</behavior-class>
    </behavior> 
And in order to use it in a xthml file I added my namespace:

Code: Select all

<ui:composition 
     xmlns="http://www.w3.org/1999/xhtml"
     xmlns:f="http://xmlns.jcp.org/jsf/core"
     xmlns:h="http://xmlns.jcp.org/jsf/html"
     xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
     xmlns:p="http://primefaces.org/ui"
     xmlns:my="http://primefaces.org/my"
     template="../templates/masterTemplate.xhtml">
      <!-- .... -->
      <p:commandButton action="#{bean.someAction}">
            <my:myconfirm escape="false" message="#{messageBundle['some.key']}" header="some header"/>
      </p:commandButton>
</ui:composition>
The last step is to override the primefaces confirmDialog javascript, In my master template I added in the h:header section

Code: Select all

<h:outputScript name="js/my-components-override.js"/>
And the code is:

Code: Select all

/**
 * PrimeFaces ConfirmDialog Widget Override to CMConfirm
 * that understand the escape parameter.
 */
PrimeFaces.widget.ConfirmDialog = PrimeFaces.widget.Dialog.extend({

    init: function(cfg) {
        cfg.draggable = false;
        cfg.resizable = false;
        cfg.modal = true;

        if (!cfg.appendTo && cfg.global) {
        	cfg.appendTo = '@(body)';
        }

        this._super(cfg);

        this.title = this.titlebar.children('.ui-dialog-title');
        this.message = this.content.children('.ui-confirm-dialog-message');
        this.icon = this.content.children('.ui-confirm-dialog-severity');

        if(this.cfg.global) {
            PrimeFaces.confirmDialog = this;

            this.jq.find('.ui-confirmdialog-yes').on('click.ui-confirmdialog', function(e) {
                if(PrimeFaces.confirmSource) {
                    var fn = new Function('event',PrimeFaces.confirmSource.data('pfconfirmcommand'));

                    fn.call(PrimeFaces.confirmSource.get(0),e);
                    PrimeFaces.confirmDialog.hide();
                    PrimeFaces.confirmSource = null;
                }

                e.preventDefault();
            });

            this.jq.find('.ui-confirmdialog-no').on('click.ui-confirmdialog', function(e) {
                PrimeFaces.confirmDialog.hide();
                PrimeFaces.confirmSource = null;

                e.preventDefault();
            });
        }
    },

    applyFocus: function() {
        this.jq.find(':button,:submit').filter(':visible:enabled').eq(0).focus();
    },

    showMessage: function(msg) {
        var icon = (msg.icon === 'null') ? 'ui-icon-alert' : msg.icon;
        this.icon.removeClass().addClass('ui-icon ui-confirm-dialog-severity ' + icon);

        if(msg.header)
            this.title.text(msg.header);


        // THE CHANGE WAS MADE HERE 
        if(msg.message){
            if (msg.escape == "false"){
            	this.message.html(msg.message);
            }else{
            	this.message.text(msg.message);
            }
        }

        this.show();
    }

});
And that's it :)
Jorge Campos
--
Eclipse Juno
Primefaces 6.1.RC3
JSF 2.2.8
Apache Tomcat 8.5.14

Melloware
Posts: 3717
Joined: 22 Apr 2013, 15:48

16 Nov 2017, 21:53

Jorge you should submit this as a Github Pull Request for this ticket...

https://github.com/primefaces/primefaces/issues/60
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

Jorge
Posts: 25
Joined: 21 Sep 2011, 14:00

19 Jan 2018, 08:32

Hello @melloware!

Done it. Here it is: https://github.com/primefaces/primefaces/pull/3181

Sorry for the delay.
Jorge Campos
--
Eclipse Juno
Primefaces 6.1.RC3
JSF 2.2.8
Apache Tomcat 8.5.14

Melloware
Posts: 3717
Joined: 22 Apr 2013, 15:48

19 Jan 2018, 14:20

Nice work. I reviewed it and it looks good!
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: Google [Bot] and 16 guests