作为 JSF 2.0 复合组件的 CodeMirror 无法在选项卡或对话框中正确呈现

CodeMirror as a JSF 2.0 composite component doesn't render properly in tab or dialog

我刚刚将 CodeMirror(带有一些插件)实现为 JSF 2.0 复合组件(参见下面的代码)。只要该组件未放置在某些选项卡或对话框中(任何在页面加载后不可见的内容),该组件就可以正常工作。在选项卡或对话框中时,组件似乎已呈现,但内容和行号在单击组件之前不可见。

点击前:

点击后:

这是我的 JSF 复合组件模板代码:

<!-- INTERFACE -->
<cc:interface>
    <cc:attribute name="styleClass" type="java.lang.String" required="true" />
    <cc:attribute name="value" type="java.lang.Object" />
    <cc:attribute name="converter" type="java.lang.String" />
    <cc:attribute name="mode" type="java.lang.String" />
    <cc:attribute name="theme" type="java.lang.String" default="eclipse" />
    <cc:attribute name="lineNumbers" type="java.lang.String" default="false" />
    <cc:attribute name="matchBrackets" type="java.lang.String" default="false" />
    <cc:attribute name="matchTags" type="java.lang.String" default="false" />
    <cc:attribute name="closeBrackets" type="java.lang.String" default="false" />
    <cc:attribute name="closeTag" type="java.lang.String" default="false" />
    <cc:attribute name="activeLine" type="java.lang.String" default="false" />
    <cc:attribute name="indentUnit" type="java.lang.Integer" default="2" />
    <cc:attribute name="smartIndent" type="java.lang.Boolean" default="true" />
    <cc:attribute name="readOnly" type="java.lang.Boolean" default="false" />
    <cc:attribute name="electricChars" type="java.lang.Boolean" default="true" />
    <cc:attribute name="lineWrapping" type="java.lang.Boolean" default="false" />
    <cc:attribute name="firstLineNumber" type="java.lang.Integer" default="1" />
    <cc:attribute name="tabIndex" type="java.lang.Integer" default="0" />
    <cc:attribute name="undoDepth" type="java.lang.Integer" default="40" />
    <cc:attribute name="pollInterval" type="java.lang.Integer" default="100" />
    <cc:attribute name="extraKeys" type="java.lang.String" default="{}" />
</cc:interface>

<!-- IMPLEMENTATION -->
<cc:implementation>

<!-- required imports -->

<h:inputTextarea id="cmTextArea" value="#{cc.attrs.value}"
    styleClass="#{cc.attrs.styleClass}">
    <c:if test="#{not empty cc.attrs.converter}">
        <f:converter converterId="#{cc.attrs.converter}" />
    </c:if>
</h:inputTextarea>

<script type="text/javascript">
    $(function() {
        var cmTextArea = $('.#{cc.attrs.styleClass}'),
        myCodeMirror = CodeMirror.fromTextArea(cmTextArea[0], {
            value: cmTextArea.val(),
            mode: '#{cc.attrs.mode}',
            theme: '#{cc.attrs.theme}',
            lineNumbers: #{cc.attrs.lineNumbers},
            matchBrackets: '#{cc.attrs.matchBrackets}',
            matchTags: {bothTags: #{cc.attrs.matchTags}},
            autoCloseBrackets: #{cc.attrs.closeBrackets},
            autoCloseTags: #{cc.attrs.closeTag},
            styleActiveLine: #{cc.attrs.activeLine},
            indentUnit: #{cc.attrs.indentUnit},
            smartIndent: #{cc.attrs.smartIndent},
            readOnly: #{cc.attrs.readOnly},
            electricChars: #{cc.attrs.electricChars},
            lineWrapping: #{cc.attrs.lineWrapping},
            firstLineNumber: #{cc.attrs.firstLineNumber},
            tabindex: #{cc.attrs.tabIndex},
            undoDepth: #{cc.attrs.undoDepth},
            pollInterval: #{cc.attrs.pollInterval},
            extraKeys: #{cc.attrs.extraKeys}
        }); 
    });

</script>

复合组件使用示例:

<t:codeMirror mode="text/xml" theme="cobalt"
                value="#{bean.content}" tabIndex="1" lineNumbers="true"
                converter="escapeConverter" electricChars="true" lineWrapping="true"
                extraKeys="{ 'F11': function(cm) {cm.setOption('fullScreen', !cm.getOption('fullScreen'));}, 'Ctrl-J': 'toMatchingTag','Ctrl-Space': 'autocomplete' }"
                matchBrackets="true" closeBrackets="true" matchTags="true"
                closeTag="true" styleClass="sampleClass" />

正如我所说,我无法理解,为什么我的组件中没有(立即)显示内容(无需单击它),而组件位于(第二个 - 在页面加载时不可见)选项卡中,而组件位于 Primefaces 的外部tabView 正确呈现(包含内容和行号)。

如有任何帮助,我们将不胜感激。谢谢!

编辑: 我想我需要在 codemirror 对象可见时调用 refresh(在选项卡显示上)。太好了,它是这样工作的,但是有什么方法可以将该调用包含在复合组件本身中吗?

参见 CodeMirror 的 refresh 方法。编辑器需要可见才能绘制自身,如果在隐藏元素中初始化它,则必须在它第一次可见时调用 refresh