2

PrimeFaces 3.4、JSF 2.0、Tomcat7.0で開発を始めています。フォームページを作成するときに、すべてのPrimeFaces入力コンポーネントのタブボタンでナビゲートできるという問題に直面しています<p:selectBooleanButton>。例えば、

<h:form id="formId">
    <p:inputText id="inputId1" />
    <p:inputText id="inputId2" />
    <p:selectBooleanButton id="buttonId" onLabel="Yes" offLabel="No" />
    <p:inputText id="inputId3" />
    <p:inputText id="inputId4" />
</h:form>

タブを押すと、inputId2に直接移動しinputId3ます。これは予想される動作ですか?回避策はありますか?

4

2 に答える 2

7

これは、の状態を表すチェックボックス<p:selectBooleanButton>が実際にPrimeFacesによってレンダリングされた方法によるものSelectBooleanButtonRendererです。

<div id="formId:buttonId" type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
    <input id="formId:buttonId_input" name="formId:buttonId_input" type="checkbox" class="ui-helper-hidden">
    <span class="ui-button-text">no</span>
</div>

チェックボックスはクラスのCSSdisplay:noneプロパティによって完全に非表示になっているため、フォーカスを受け取る.ui-helper-hiddenことはできません。

チェックボックスを<p:selectBooleanCheckbox>、実際にフォーカス可能な視覚的により魅力的なウィジェットに置き換えるチェックボックスの対応物を見ると、チェックボックスはCSSによって完全に非表示にされているのではなく、絶対にラップされているために非表示になっていることがわかります。クラス内のCSSによって配置されるため、チェックボックスウィジェットによってオーバーレイされます。<div>position:absolute.ui-helper-hidden-accessible

<div id="formId:checkboxId" class="ui-chkbox ui-widget">
    <div class="ui-helper-hidden-accessible">
        <input id="formId:checkboxId_input" name="formId:checkboxId_input" type="checkbox">
    </div>
    <div class="ui-chkbox-box ui-widget ui-corner-all ui-state-default">
        <span class="ui-chkbox-icon"></span>
    </div>
</div>

焦点が定まらない「予想される」または「直感的な」動作であるとは考えていません<p:selectBooleanButton>。もし私があなたなら、このUXの問題をPrimeFacesに報告するでしょう。


それまでの間、これを回避する最善の策は、次のようにencodeMarkup()PrimeFacesのメソッドをオーバーライドするカスタムレンダラーを作成して、チェックボックスからを削除し、それをとまったく同じようにラップすることです。SelectBooleanButtonRendererclass="ui-helper-hidden"<div class="ui-helper-hidden-accessible><p:selectBooleanCheckbox>

public class MySelectBooleanButtonRenderer extends SelectBooleanButtonRenderer {

    @Override
    protected void encodeMarkup(FacesContext context, SelectBooleanButton button) throws IOException {
        ResponseWriter writer = context.getResponseWriter();
        String clientId = button.getClientId(context);
        boolean checked = Boolean.valueOf(ComponentUtils.getValueToRender(context, button));
        boolean disabled = button.isDisabled();
        String inputId = clientId + "_input";
        String label = checked ? button.getOnLabel() : button.getOffLabel();
        String icon = checked ? button.getOnIcon() : button.getOffIcon();

        //button
        writer.startElement("div", null);
        writer.writeAttribute("id", clientId, "id");
        writer.writeAttribute("type", "button", null);
        writer.writeAttribute("class", button.resolveStyleClass(checked, disabled), null);
        if(disabled) writer.writeAttribute("disabled", "disabled", null);
        if(button.getTitle()!= null) writer.writeAttribute("title", button.getTitle(), null);
        if(button.getStyle() != null) writer.writeAttribute("style", button.getStyle(), "style");

        //input
        writer.startElement("div", null); // <-- Added.
        writer.writeAttribute("class", "ui-helper-hidden-accessible", null); // <-- Added.
        writer.startElement("input", null);
        writer.writeAttribute("id", inputId, "id");
        writer.writeAttribute("name", inputId, null);
        writer.writeAttribute("type", "checkbox", null);
        // writer.writeAttribute("class", "ui-helper-hidden", null); <-- Removed.

        if(checked) writer.writeAttribute("checked", "checked", null);
        if(disabled) writer.writeAttribute("disabled", "disabled", null);
        if(button.getOnchange() != null) writer.writeAttribute("onchange", button.getOnchange(), null);

        writer.endElement("input");
        writer.endElement("div"); // <-- Added.

        //icon
        if(icon != null) {
            writer.startElement("span", null);
            writer.writeAttribute("class", HTML.BUTTON_LEFT_ICON_CLASS + " " + icon, null);
            writer.endElement("span");
        }

        //label
        writer.startElement("span", null);
        writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null);
        writer.writeText(label, "value");
        writer.endElement("span");

        writer.endElement("div");
    }

}

//inputセクションを見て、<--コピーペーストされた元のソースコードに追加/削除した行を説明するコメントを追加しました)

実行するには、次のように登録しますfaces-config.xml

<render-kit>
    <renderer>
        <component-family>org.primefaces.component</component-family>
        <renderer-type>org.primefaces.component.SelectBooleanButtonRenderer</renderer-type>
        <renderer-class>com.example.MySelectBooleanButtonRenderer</renderer-class>
    </renderer>
</render-kit>

component-familyおよびrenderer-type値はSelectBooleanButtonコンポーネントから抽出されます)

これは私にとってはうまくいきます。がフォーカスを取得し、<p:selectBooleanButton>スペースバーを使用してブール状態を切り替えることができます。ただし、フォーカスは視覚的には見えません。これはJavaScript側で解決する必要があります。非表示のチェックボックスがフォーカス<div class="ui-button">を取得すると、ボタンを表すものはクラスを取得する必要があります。.ui-state-focus次のjQueryは、それを実現します。

$(".ui-button input[type=checkbox]").focus(function() {
    $(this).closest(".ui-button").addClass("ui-state-focus");
}).blur(function() {
    $(this).closest(".ui-button").removeClass("ui-state-focus");
});

今では完全に機能します

実際のPrimeFacesソースコードでは、これはファイルの機能の機能で解決する必要がありinit()ます。PrimeFaces.widget.SelectBooleanButtonforms.js

于 2012-09-24T13:30:43.087 に答える
0

BalusCによって提案されたまったく同じ回避策を適用する別の方法は次のとおりです。

利点:

  • レンダラークラスを作成して宣言するだけで済みます。フォーカスされた状態の視覚的な手がかりを追加するために、フェイスレットにJavaScriptコードを追加する必要はありません。
  • レンダラー拡張機能は、スーパーencodeMarkup実装全体を置き換えるのではなく、それを装飾します。DOM構造やinputIdの計算方法を完全に変更しない限り、PFアップグレードによってスーパー実装がわずかに変更された場合に備えて、これはもう少し堅牢になるはずです。

アイデアは、BalusCによって提案されたのと同じ手法(適切なCSSクラスの適用に基づく)を使用して、コンポーネントにフォーカス可能性を提供するために元のマークアップを操作するJavaScriptスクリプトを追加することです。

package com.example;

import java.io.IOException;

import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;

import org.primefaces.component.selectbooleanbutton.SelectBooleanButton;
import org.primefaces.component.selectbooleanbutton.SelectBooleanButtonRenderer;

public class MySelectBooleanButtonRenderer extends SelectBooleanButtonRenderer {

    @Override
    protected void
            encodeMarkup(FacesContext context, SelectBooleanButton button)
                    throws IOException {
        super.encodeMarkup(context, button);
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement("script", null);
        writer.writeAttribute("type", "text/javascript", null);
        writer.append(getMakeButtonFocusableScript(button.getClientId(context)));
        writer.endElement("script");
    }

    protected String getMakeButtonFocusableScript(final String clientId) {
        String inputId = clientId + "_input";
        return "{\r\n"
                + "  var input = document.getElementById('"
                + inputId
                + "');\r\n"
                + "  input.classList.remove('ui-helper-hidden');\r\n"
                + "  var mainDiv = document.getElementById('"
                + clientId
                + "');\r\n"
                + "  var newDiv = document.createElement('div');\r\n"
                + "  newDiv.setAttribute('class', 'ui-helper-hidden-accessible');\r\n"
                + "  newDiv.appendChild(input);\r\n"
                + "  mainDiv.appendChild(newDiv);\r\n"
                + "  input.onfocus = function() {document.getElementById('"
                + clientId + "').classList.add('ui-state-focus'); };\r\n"
                + "  input.onblur = function() { document.getElementById('"
                + clientId + "').classList.remove('ui-state-focus'); };\r\n"
                + "}";
    }
}
于 2014-12-18T14:47:36.407 に答える