6

バナナと outputText の 2 つの要素があり、バナナはカスタム JSF コンポーネントであり、バナナ レンダラーでは、指定された要素を囲む HTML を生成したいと考えています。

xhtml:

<h:outputText id="theApple" value="This is an Apple" />
.
.
.
<my:banana for="theApple" link="http://www.banana.com" />

バナナレンダラー(ターゲット要素をアンカーリンクで囲みます):

@Override
public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
    ResponseWriter responseWriter = context.getResponseWriter();
    Banana banana = Banana.class.cast(component);
    responseWriter.startElement("a", null);
    responseWriter.writeAttribute("id", banana.getClientId(context), null);
    responseWriter.writeAttribute("href", banana.getLink(), null);
}

@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
    ResponseWriter responseWriter = context.getResponseWriter();
    Banana banana = Banana.class.cast(component);
    responseWriter.endElement("a");
}

私が達成したいこと:

<a href="http://www.banana.com">This is an Apple</a>
.
.
.

ご覧のとおり、バナナ コンポーネントではなく、「for」属性を使用して対象となる要素をエンコードしたいと考えています。私が見た最も近い例は PrimeFaces のツールチップですが、「for」属性がどのように使用されているかはよくわかりません。 http://www.primefaces.org/showcase/ui/overlay/tooltip/tooltipOptions.xhtml#

誰かが私を正しい方向に向けることができれば、本当に感謝しています。ありがとうございました。

4

2 に答える 2

5

中にコンポーネント ツリーを操作できますPreRenderViewEvent。その瞬間、すべてのコンポーネントがツリーに存在することが保証され、ツリー内のコンポーネントを追加/移動/削除してコンポーネント ツリーを安全に操作できることが保証されます。でツリー内の他のコンポーネントを見つけることができますUIComponent#findComponent()UIComponent#getParent()およびを使用して、コンポーネント ツリーをトラバースできますUIComponent#getChildren()。はgetChildren()、 中に安全に操作できることが保証されている変更可能なリストを返しますPreRenderViewEvent

特定のコンポーネントをハイパーリンクでラップする必要があり、JSF ハイパーリンク コンポーネント が既に存在する場合<h:outputLink>、コードをシンプルで DRY に保つために、それを拡張して再利用する方が簡単です。基本的なキックオフの例を次に示します。

@FacesComponent(createTag=true)
public class Banana extends HtmlOutputLink implements SystemEventListener {

    public Banana() {
        getFacesContext().getViewRoot().subscribeToViewEvent(PreRenderViewEvent.class, this);
    }

    @Override
    public boolean isListenerForSource(Object source) {
        return source instanceof UIViewRoot;
    }

    @Override
    public void processEvent(SystemEvent event) throws AbortProcessingException {
        String forClientId = (String) getAttributes().get("for");

        if (forClientId != null) {
            UIComponent forComponent = findComponent(forClientId);
            List<UIComponent> forComponentSiblings = forComponent.getParent().getChildren();
            int originalPosition = forComponentSiblings.indexOf(forComponent);
            forComponentSiblings.add(originalPosition, this);
            getChildren().add(forComponent);
        }
    }

}

<!DOCTYPE html>
<html lang="en"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:my="http://xmlns.jcp.org/jsf/component"
>
    <h:head>
        <title>SO question 38197494</title>
    </h:head>
    <h:body>
        <h:outputText id="theApple" value="This is an Apple" />
        <my:banana for="theApple" value="http://www.banana.com" />
    </h:body>
</html>

children.remove()をすでに実行している場合は、明示的な呼び出しは必要ないことに注意してくださいchildren.add()。それは自動的に子供の親を世話します。

于 2016-07-05T08:42:15.277 に答える