ICEfaces
  1. ICEfaces
  2. ICE-8213

Syntax error when embedding some ACE components inside an f:ajax tag

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1.0.BETA2, 3.1
    • Fix Version/s: 3.1.0.RC1, 3.1, EE-3.0.0.GA_P01
    • Component/s: ACE-Components
    • Labels:
      None
    • Environment:
      ICEfaces3 Trunk Revision# 29244
      Firefox, Chrome, IE
    • Assignee Priority:
      P1

      Description

      When embedding some ace components inside an f:ajax tag there is a JS error and the component doesn't function. (So far this has been reproduced with ace:tooltip and ace:panel and can not be reproduced with ace:menu)

      ace:tooltip:
      Error: syntax error
      Source File: http://localhost:8080/Case10868Example/
      Line: 17, Column: 579
      Source Code:
      ice.ace.jq(function() {widget_form_testTooltip = new ice.ace.Tooltip({"global":false,"id":"form:testTooltip","displayListener":false,"forComponent":"form:output",content:document.getElementById('form:testTooltip_content').innerHTML,"show":{"when":{"event":"mouseover"},"delay":140,"effect":{"length":500,"type":"fade"}},"hide":{"when":{"event":"mouseout"},"delay":0,"fixed":true,"effect":{"length":500,"type":"fade"}},"position":{"container":ice.ace.jq(ice.ace.escapeClientId('form:output')).parent(),"corner":{"target":"bottomRight","tooltip":"topLeft"}},"behaviors":{"display":}});});

      ace:panel:
      Error: syntax error
      Source File: http://localhost:8080/panel/panelFAjax.jsf
      Line: 9, Column: 176
      Source Code:
      widget_frm_panel = new ice.ace.Panel("frm:panel",{"visible":true,"toggleable":true,"toggleSpeed":1000,"collapsed":false,"closable":true,"closeSpeed":1000,"behaviors":{"toggle":}});

      I've attached a simplified test case.

        Activity

        Hide
        Mark Collette added a comment -

        From what I understand, we don't support f:ajax within ACE components. And when you wrap a block of components with f:ajax, it's as if you put the f:ajax with every component in that block that is a ClientBehaviorHolder that supports the eventName that the f:ajax is using. So really it's not valid to wrap ACE components with an f:ajax.

        If there is some scenario where we're trying to make the f:ajax only apply to some h: components in the block and not any ACE components, then I would first examine if an event name had been specified, instead of being set to null, so that could keep it from being set on the ACE components, which hopefully wouldn't share that event name. If that's not doable, then we could modify the ACE generator so that our generated Base classes, which are ClientBehaviorHolder implementators, would override UIComponentBase.addClientBehavior(String eventName, ClientBehavior behavior) to specifically not add javax.faces.component.behavior.AjaxBehavior, while allowing org.icefaces.ace.component.ajax.AjaxBehavior.

        Show
        Mark Collette added a comment - From what I understand, we don't support f:ajax within ACE components. And when you wrap a block of components with f:ajax, it's as if you put the f:ajax with every component in that block that is a ClientBehaviorHolder that supports the eventName that the f:ajax is using. So really it's not valid to wrap ACE components with an f:ajax. If there is some scenario where we're trying to make the f:ajax only apply to some h: components in the block and not any ACE components, then I would first examine if an event name had been specified, instead of being set to null, so that could keep it from being set on the ACE components, which hopefully wouldn't share that event name. If that's not doable, then we could modify the ACE generator so that our generated Base classes, which are ClientBehaviorHolder implementators, would override UIComponentBase.addClientBehavior(String eventName, ClientBehavior behavior) to specifically not add javax.faces.component.behavior.AjaxBehavior, while allowing org.icefaces.ace.component.ajax.AjaxBehavior.
        Hide
        Mark Collette added a comment -

        In CoreRenderer, there are noticeable differences between
        encodeClientBehaviors(FacesContext context, ClientBehaviorHolder component, JSONBuilder jb)
        and
        encodeClientBehaviors(FacesContext context, ClientBehaviorHolder component)

        Unfortunately, the JSONBuilder version that most of our components use handles things worse than the ResponseWriter one. For a given event, there may be no ClientBehavior(s), there may be one, or there may be several, any may be disabled, and any of them may be f:ajax, which we attempt to ignore. The ResponseWriter code handles there being none, there being noe that are enabled, and there being none that are not f:ajax equivalently, and won't output the event key/value pair. The JSONBuilder one confuses those scenarios, and so can render the key/value pair when there is no value due to eliminating the f:ajax.

        As well, there is the issue of the ResponseWriter omitting the key/value pair when there is no javascipt, and the JSONBuilder trying to render a key/value pair with a value of undefined when there is no javascript. It's not clear to me which is better. Only that omitting uses less bandwidth.

        Show
        Mark Collette added a comment - In CoreRenderer, there are noticeable differences between encodeClientBehaviors(FacesContext context, ClientBehaviorHolder component, JSONBuilder jb) and encodeClientBehaviors(FacesContext context, ClientBehaviorHolder component) Unfortunately, the JSONBuilder version that most of our components use handles things worse than the ResponseWriter one. For a given event, there may be no ClientBehavior(s), there may be one, or there may be several, any may be disabled, and any of them may be f:ajax, which we attempt to ignore. The ResponseWriter code handles there being none, there being noe that are enabled, and there being none that are not f:ajax equivalently, and won't output the event key/value pair. The JSONBuilder one confuses those scenarios, and so can render the key/value pair when there is no value due to eliminating the f:ajax. As well, there is the issue of the ResponseWriter omitting the key/value pair when there is no javascipt, and the JSONBuilder trying to render a key/value pair with a value of undefined when there is no javascript. It's not clear to me which is better. Only that omitting uses less bandwidth.
        Hide
        Mark Collette added a comment -

        From talking with Nils, we'll go with omitting.

        Show
        Mark Collette added a comment - From talking with Nils, we'll go with omitting.
        Hide
        Mark Collette added a comment -

        Another reason to not allow adding f:ajax at all to ACE components, is that there's a possibility that it will decode and queue/broadcast events when the ACE component has an ace:ajax submit, if the event names happen to match up.

        Show
        Mark Collette added a comment - Another reason to not allow adding f:ajax at all to ACE components, is that there's a possibility that it will decode and queue/broadcast events when the ACE component has an ace:ajax submit, if the event names happen to match up.
        Hide
        Mark Collette added a comment - - edited

        Fixed ACE CoreRenderer so it will not render the event/script key/value pair if the script isn't valid.

        trunk
        Subversion 29556

        Merged the change to the maintenance branch, which required a bit of an adaptation, since some dependent code wasn't there.

        icefaces3-maintenance
        Subversion 30622

        Show
        Mark Collette added a comment - - edited Fixed ACE CoreRenderer so it will not render the event/script key/value pair if the script isn't valid. trunk Subversion 29556 Merged the change to the maintenance branch, which required a bit of an adaptation, since some dependent code wasn't there. icefaces3-maintenance Subversion 30622
        Hide
        Mark Collette added a comment - - edited

        Now, if f:ajax is added inside an ACE component, or wraps it, it just won't be added to the component at all.

        Augmented the generator and ClientBehaviorHolder annotation to support the new allowFAjax field. By default it's false, and so results in the Base class overriding addClientBehavior(String eventName, ClientBehavior behavior) and not allowing an exact class match of javax.faces.component.behavior.AjaxBehavior, that f:ajax adds. This way, if third parties using ACEnvironment want their components to work with f:ajax they can, while our ACE components won't. And if we ever need to sub-class javax.faces.component.behavior.AjaxBehavior to use it for something, then that will work too.

        Fixed up some whitespace and code placement in the generated Base classes while I was in there.

        trunk
        Subversion 29557

        icefaces3-maintenance
        Subversion 30623

        Show
        Mark Collette added a comment - - edited Now, if f:ajax is added inside an ACE component, or wraps it, it just won't be added to the component at all. Augmented the generator and ClientBehaviorHolder annotation to support the new allowFAjax field. By default it's false, and so results in the Base class overriding addClientBehavior(String eventName, ClientBehavior behavior) and not allowing an exact class match of javax.faces.component.behavior.AjaxBehavior, that f:ajax adds. This way, if third parties using ACEnvironment want their components to work with f:ajax they can, while our ACE components won't. And if we ever need to sub-class javax.faces.component.behavior.AjaxBehavior to use it for something, then that will work too. Fixed up some whitespace and code placement in the generated Base classes while I was in there. trunk Subversion 29557 icefaces3-maintenance Subversion 30623
        Hide
        Mark Collette added a comment -

        We can verify the f:ajax AjaxBehavior class isn't being added at all anymore by seeing this:

        Map<String,List<ClientBehavior>> behaviorEvents = component.getClientBehaviors();
        System.out.println("behaviorEvents: " + behaviorEvents);

        The output used to look like this:

        behaviorEvents:

        {toggle=[javax.faces.component.behavior.AjaxBehavior@d0eaeda]}

        Now it looks like this:

        behaviorEvents: {}

        Show
        Mark Collette added a comment - We can verify the f:ajax AjaxBehavior class isn't being added at all anymore by seeing this: Map<String,List<ClientBehavior>> behaviorEvents = component.getClientBehaviors(); System.out.println("behaviorEvents: " + behaviorEvents); The output used to look like this: behaviorEvents: {toggle=[javax.faces.component.behavior.AjaxBehavior@d0eaeda]} Now it looks like this: behaviorEvents: {}
        Hide
        Mark Collette added a comment -

        Backported, and original comments edited to reflect the maintenance branch subversion numbers.

        Show
        Mark Collette added a comment - Backported, and original comments edited to reflect the maintenance branch subversion numbers.

          People

          • Assignee:
            Mark Collette
            Reporter:
            Cruz Miraback
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: