2013-03-22 16 views
6

पर कस्टम विशेषता (एचटीएमएल 5) समर्थन जोड़ना मेरे जेएसएफ/प्राइमफेस वेब-एप्लिकेशन में सरल एचटीएमएल 5 विशेषता 'ऑटोफोकस' को लागू करने की कोशिश में, मुझे इस तथ्य से सतर्क किया गया कि घटक सभी अज्ञात विशेषताओं को पास नहीं करते हैं अंतिम मार्कअप पर। मैं इसके लिए तर्क समझ सकता हूं, क्योंकि घटक एचटीएमएल मार्कअप के जटिल संयोजन हो सकते हैं और यह स्पष्ट नहीं होगा कि गुण कहां रखना है यदि वे घटक द्वारा पहले से परिभाषित नहीं हैं।प्राइमफेस (3.4)

लेकिन मेरे लिए सबसे अच्छा समाधान ऑटोफोकस के लिए समर्थन होना है (और किसी भी अन्य संभावित प्रकार के गुण जो मैं अपने आवेदन में समर्थन देना चाहता हूं कि प्राइमफेस परिभाषित नहीं किया गया है)।

मैंने Adding custom attribute (HTML5) support to JSF 2.0 UIInput component देखा है, लेकिन यह मूल जेएसएफ घटकों के लिए लागू होता है और प्राइमफेस घटकों के लिए काम नहीं करता है।

मैं इसका समर्थन करने के लिए प्राइमफेस के घटक/प्रतिपादन का विस्तार कैसे करूं?

उत्तर

10

इसके बजाय हर एक व्यक्ति घटक के लिए एक कस्टम रेंडरर homegrowing की, आप भी सिर्फ एक RenderKit जिसमें आप एक कस्टम ResponseWriter जिसमें startElement() विधि तत्व नाम और/या घटक उदाहरण जाँच और फिर अतिरिक्त लिखने के लिए ओवरराइड है प्रदान करते हैं बना सकते हैं तदनुसार गुण।

यहाँ एचटीएमएल 5 प्रस्तुत करना किट का एक किकऑफ़ उदाहरण है:

public class Html5RenderKit extends RenderKitWrapper { 

    private RenderKit wrapped; 

    public Html5RenderKit(RenderKit wrapped) { 
     this.wrapped = wrapped; 
    } 

    @Override 
    public ResponseWriter createResponseWriter(Writer writer, String contentTypeList, String characterEncoding) { 
     return new Html5ResponseWriter(super.createResponseWriter(writer, contentTypeList, characterEncoding)); 
    } 

    @Override 
    public RenderKit getWrapped() { 
     return wrapped; 
    } 

} 

एचटीएमएल 5 प्रतिक्रिया लेखक:

public class Html5ResponseWriter extends ResponseWriterWrapper { 

    private static final String[] HTML5_INPUT_ATTRIBUTES = { "autofocus" }; 

    private ResponseWriter wrapped; 

    public Html5ResponseWriter(ResponseWriter wrapped) { 
     this.wrapped = wrapped; 
    } 

    @Override 
    public ResponseWriter cloneWithWriter(Writer writer) { 
     return new Html5ResponseWriter(super.cloneWithWriter(writer)); 
    } 

    @Override 
    public void startElement(String name, UIComponent component) throws IOException { 
     super.startElement(name, component); 

     if ("input".equals(name)) { 
      for (String attributeName : HTML5_INPUT_ATTRIBUTES) { 
       String attributeValue = component.getAttributes().get(attributeName); 

       if (attributeValue != null) { 
        super.writeAttribute(attributeName, attributeValue, null); 
       } 
      } 
     } 
    } 

    @Override 
    public ResponseWriter getWrapped() { 
     return wrapped; 
    } 

} 

, इसे चलाने के लिए मिलता है इस एचटीएमएल 5 प्रस्तुत करना किट कारखाना बनाने के लिए:

public class Html5RenderKitFactory extends RenderKitFactory { 

    private RenderKitFactory wrapped; 

    public Html5RenderKitFactory(RenderKitFactory wrapped) { 
     this.wrapped = wrapped; 
    } 

    @Override 
    public void addRenderKit(String renderKitId, RenderKit renderKit) { 
     wrapped.addRenderKit(renderKitId, renderKit); 
    } 

    @Override 
    public RenderKit getRenderKit(FacesContext context, String renderKitId) { 
     RenderKit renderKit = wrapped.getRenderKit(context, renderKitId); 
     return (HTML_BASIC_RENDER_KIT.equals(renderKitId)) ? new Html5RenderKit(renderKit) : renderKit; 
    } 

    @Override 
    public Iterator<String> getRenderKitIds() { 
     return wrapped.getRenderKitIds(); 
    } 

} 

और इसे faces-config.xml में निम्नानुसार पंजीकृत करें:

<factory> 
    <render-kit-factory>com.example.Html5RenderKitFactory</render-kit-factory> 
</factory> 

JSF उपयोगिता पुस्तकालय OmniFaces भी इस तरह के एक किट प्रस्तुत करना है, Html5RenderKit (source code here) जो सैद्धांतिक रूप से भी PrimeFaces घटकों पर ठीक काम करना चाहिए। हालांकि, इस सवाल ने मुझे दो बार फिर से देखने के लिए मजबूर कर दिया और मुझे यह देखने के लिए शर्मिंदा था कि componentResponseWriter#startElement() में null<p:inputText> में line 74 of InputTextRenderer देखें, यह writer.startElement("input", inputText) इसके बजाय होना चाहिए)। मुझे यकीन नहीं है कि यह प्राइमफेस रेंडरर के डिजाइन में जानबूझकर या निरीक्षण है, लेकिन आप इसे पाने के लिए UIComponent#getCurrentComponent() का उपयोग कर सकते हैं।


अद्यतन: इस OmniFaces 1.5 में तय हो गई है।


ध्यान दिया जाना चाहिए कि आगामी JSF 2.2 को परिभाषित कस्टम नई passthrough नाम स्थान या <f:passThroughAttribute> टैग के माध्यम से ध्यान में रखते हुए विशेषताओं का समर्थन करेंगे। What's new in JSF 2.2? - HTML5 Pass-through attributes भी देखें।

इस प्रकार

, तो:

<html ... xmlns:p="http://java.sun.com/jsf/passthrough"> 
... 
<h:inputText ... p:autofocus="true" /> 

या (आप नामस्थान उपसर्ग के रूप में a बजाय p उपयोग करने के लिए PrimeFaces 'डिफ़ॉल्ट नाम स्थान के साथ टकराव से बचने के लिए चाहते हो सकता है):

<h:inputText ...> 
    <f:passThroughAttribute name="autofocus" value="true" /> 
</h:inputText> 
+0

बढ़िया, यह प्रति घटक समाधान की तुलना में काफी अच्छा लगता है। मुझे यकीन है कि विशिष्ट उपयोग के मामले किसी भी तरह से तर्क कर सकते हैं। अगर मुझे समय मिलता है तो मैं इसे आज़माउंगा क्योंकि ऐसा लगता है कि यह सभी घटकों को घर से बढ़ने से कहीं ज्यादा तेज होगा। – Rich

+0

UIComponent # getCurrentComponent (FacesContext) हस्ताक्षर प्रतीत होता है, इसलिए स्टार्ट एलीमेंट विधि के संदर्भ में जो उपलब्ध नहीं है। मैंने आपके Omnifaces में देखा है कि आपने घटक का उपयोग किया है .getCurrentCompnent() जिसे संदर्भ की आवश्यकता नहीं है, हालांकि यह ओमनीफेस क्लास है जो केवल प्राइमफेस में उपलब्ध नहीं है। उस बिंदु पर मेरे लिए किसी भी घटक को ओवरराइड करना अधिक खतरनाक होगा जो प्रारंभ करने के लिए शून्य हो सकता है। क्या आप सुझाव देते हैं कि मैं ओमनीफेस में खींचूं या क्या कोई और तरीका है? – Rich

+0

'घटक # getCurrentComponent()' फॉर्म OmniFaces सिर्फ 'UIComponent # getCurrentComponent() 'के लिए प्रतिनिधि हैं। अगर आपने इसका परीक्षण किया है या नहीं, तो आप इस बारे में स्पष्ट नहीं हैं, लेकिन यह मेरे लिए काम करता है। – BalusC

3

जो समाधान मैंने पाया वह इनपुट रेंडरर के लिए एनकोड मार्कअप विधियों को विस्तार और पुन: कार्यान्वित करना था। मैं एक और सामान्य समाधान चाहता था, लेकिन प्राइमफेस स्रोत कोड को देखने के बाद, मैंने कस्टम गुण जोड़ने के लिए घटक प्रस्तुतकर्ताओं के लिए कोई सामान्य हुक नहीं देखा। मार्कर प्रतिपादन के encodeMarkup(FacesContext context, InputText inputText) विधियों में लिखा गया है। यह कक्षा-पदानुक्रम को renderPassThruAttributes(FacesContext context, UIComponent component, String[] attributes) पर कॉल करता है लेकिन यह केवल org.primefaces.util.HTML से स्थिर अंतिम स्ट्रिंग [] सरणी में फ़ीड करता है।

मेरे मामले में मैं इनपुटमास्क, इनपुटटेक्स्ट, इनपुट टेक्स्टक्स्टा और पासवर्ड घटकों पर 'ऑटोफोकस' विशेषता के लिए समर्थन चाहता था। इसके अलावा, कार्यान्वयन प्रत्येक घटक के लिए समान है, इसलिए मैं इनपुटपुट घटक पर 'ऑटोफोकस' को लागू करने के माध्यम से चलूंगा, लेकिन यह स्पष्ट होना चाहिए कि इसे और अधिक विशेषताओं और अधिक घटकों का समर्थन करने के लिए कैसे बढ़ाया जा सकता है।

एक रेंडरर को विस्तार/ओवरराइड करने के लिए, आपको प्राइमफ़ेस स्रोत उपलब्ध होना होगा और एनकोडमार्क विधि को ढूंढना होगा और इसकी सामग्री कॉपी करना होगा।

protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException { 
    ResponseWriter writer = context.getResponseWriter(); 
    String clientId = inputText.getClientId(context); 

    writer.startElement("input", null); 
    writer.writeAttribute("id", clientId, null); 
    writer.writeAttribute("name", clientId, null); 
    writer.writeAttribute("type", inputText.getType(), null); 

    String valueToRender = ComponentUtils.getValueToRender(context, inputText); 
    if(valueToRender != null) { 
     writer.writeAttribute("value", valueToRender , null); 
    } 

    renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS); 

    if(inputText.isDisabled()) writer.writeAttribute("disabled", "disabled", null); 
    if(inputText.isReadonly()) writer.writeAttribute("readonly", "readonly", null); 
    if(inputText.getStyle() != null) writer.writeAttribute("style", inputText.getStyle(), null); 

    writer.writeAttribute("class", createStyleClass(inputText), "styleClass"); 

    writer.endElement("input"); 
} 

विस्तार/अपने स्वयं के साथ रेंडरर (महत्वपूर्ण कोड के लिए टिप्पणियों देखें) ओवरराइड करना:: यहाँ InputTextRenderer के लिए उदाहरण है

public class HTML5InputTextRenderer extends InputTextRenderer { 

    Logger log = Logger.getLogger(HTML5InputTextRenderer.class); 

    //Define your attributes to support here 
    private static final String[] html5_attributes = { "autofocus" }; 

    protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException { 
    ResponseWriter writer = context.getResponseWriter(); 
    String clientId = inputText.getClientId(context); 

    writer.startElement("input", null); 
    writer.writeAttribute("id", clientId, null); 
    writer.writeAttribute("name", clientId, null); 
    writer.writeAttribute("type", inputText.getType(), null); 

    String valueToRender = ComponentUtils.getValueToRender(context, inputText); 
    if (valueToRender != null) { 
     writer.writeAttribute("value", valueToRender, null); 
    } 

    renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS); 

    //Make an extra call to renderPassThruAttributes with your own attributes array 
    renderPassThruAttributes(context, inputText, html5_attributes); 

    if (inputText.isDisabled()) 
     writer.writeAttribute("disabled", "disabled", null); 
    if (inputText.isReadonly()) 
     writer.writeAttribute("readonly", "readonly", null); 
    if (inputText.getStyle() != null) 
     writer.writeAttribute("style", inputText.getStyle(), null); 

    writer.writeAttribute("class", createStyleClass(inputText), "styleClass"); 

    writer.endElement("input"); 
    } 
} 

में प्रतिपादन ओवरराइड का विन्यास चेहरे-config.xml

<?xml version='1.0' encoding='UTF-8'?> 
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" 
     version="2.0"> 

    <!-- snip... --> 

    <render-kit> 
     <renderer> 
      <component-family>org.primefaces.component</component-family> 
      <renderer-type>org.primefaces.component.InputTextRenderer</renderer-type> 
      <renderer-class>com.mycompany.HTML5InputTextRenderer</renderer-class> 
     </renderer> 
    </render-kit> 

    <!-- snip... --> 
</faces-config> 

और यदि आपके पास वेब.एक्सएमएल में कॉन्फ़िगर किए गए चेहरे-कॉन्फ़िगर नहीं हैं, तो बस-इन-केस जोड़ें:

<context-param> 
     <param-name>javax.faces.CONFIG_FILES</param-name> 
     <param-value> 
      /WEB-INF/faces-config.xml, /faces-config.xml 
     </param-value> 
    </context-param> 

फिर कुछ मार्कअप में इस का उपयोग करने के लिए:

<p:inputText id="activateUserName" value="${someBean.userName}" 
    autofocus="on"> 
</p:inputText> 

नोट: JSF विशेषता मानों की जरूरत नहीं है कि के साथ खुश नहीं है। जबकि एचटीएमएल 5 में ऑटोफोकस एक मान का उपयोग नहीं करता है, अगर कोई नहीं दिया जाता है तो जेएसएफ एक त्रुटि फेंक देगा, इसलिए इस तरह के गुण जोड़ने के दौरान कुछ फेंकने वाले मूल्य को परिभाषित करना सुनिश्चित करें।

+0

अपने आप को 2 मिनट के भीतर जवाब दे दिया? अच्छी नौकरी! –

+2

एसओ आपको एक क्यू एंड ए स्टाइल प्रश्न करने का विकल्प देता है जहां आप इसे शुरुआत से जवाब देते हैं। जब मैं इसे हल करने की कोशिश कर रहा था तो मुझे इसका कोई विशिष्ट जवाब नहीं मिला था, इसलिए मैंने सोचा कि मैं इसे समुदाय में योगदान दूंगा। – Rich

+0

@Rich यह आशाजनक लग रहा है। मैं सप्ताहांत पर इसका परीक्षण करूंगा। –

2

जेएसएफ 2.2 एचटीएमएल 5 और उससे आगे के लिए डिज़ाइन की गई विशेषता सुविधाओं के माध्यम से भी प्रदान करता है, जब प्राइमएफ एसेस आधिकारिक तौर पर जेएसएफ 2.2 का समर्थन करता है, आप घटक से एचटीएमएल तत्वों में किसी भी विशेषता को पारित कर सकते हैं।

+0

बढ़िया, मैं इसके लिए नजर रखूंगा। – Rich

संबंधित मुद्दे