Override ui:insert and ui:include-Handler

南笙酒味 提交于 2019-12-01 22:32:29
BalusC

... without changing any of the existing code

You can't. At least, not without being tight coupled to a specific implementation (Mojarra or MyFaces). The alternative would be to bite the bullet and replace all <ui:include> and <ui:define> by <my:include> and <my:define>. Facelets is not fully abstracted/standardized into JSF specification yet. There's only a Facelet cache factory, but no Facelet context factory, otherwise it'd have been easy. Generally, forget about customizing <ui:xxx> tags in an abstract way. You'd need to hack the implementation.

Given that you're using Mojarra 2.1.19, you'd need to copypaste its com.sun.faces.facelets.impl.DefaultFaceletContext class into your web application project, maintaining its com.sun.faces.facelets.impl package. Classes in WAR have higher classloading precedence than those in WAR's /WEB-INF/lib and server's /lib. So this one in your WAR would be used instead.

Given that you'd like to achieve the same as asked in Customize ui:include rendering to add prefix/postfix on <ui:include> and <ui:define>:

Example, supposing a blank file.xhtml:

Input

<ui:include src="file.xhtml" />

Output

<!-- START file.xhtml -->
<!-- END file.xhtml -->

Here's how you can achieve it by editing the copypasted DefaultFaceletContext class:

  1. Add a helper method to the class which creates a comment component (which is just a plain output text component).

    private static UIComponent createComment(String comment) {
        UIOutput text = new UIOutput();
        text.setValue("\n<!-- " + comment + " -->\n");
        return text;
    }
    
  2. Extend the oneliner method includeFacelet(UIComponent, String) at line 199 as below:

    parent.getChildren().add(createComment("START INCLUDE " + relativePath));
    facelet.include(this, parent, relativePath);
    parent.getChildren().add(createComment("END INCLUDE " + relativePath));
    
  3. Extend the includeDefinition(UIComponent, String) around line 366 with client.apply(this, parent, name) as below:

    int start = parent.getChildCount();
    found = client.apply(this, parent, name);
    
    if (found) {
        parent.getChildren().add(start, createComment("START DEFINE " + name));
        parent.getChildren().add(createComment("END DEFINE " + name));
    }
    

During testing I however found a caveat. I have my HTML <title> templated like below:

<h:head>
    <title><ui:insert name="title">#{view.viewId}</ui:insert></title>
</h:head>

Comments thus also end up inside <title> element. Unfortunately comments in a HTML title is invalid syntax (only PCDATA allowed) and they are interpreted literally and thus show up in the document title. You might want to create a blacklist based on name of the definition or perhaps the parent.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!