将设置添加到自定义控件的“基本设置”对话框中

时间:2015-12-22 17:28:32

标签: orbeon

希望没有太多的Orbeon-noob问题。我已经为Orbeon构建了一个自定义控件(现在是一个简单的滑块),并希望在“基本设置”对话框中添加更改范围输入的最小,最大和步长参数的功能。我已经看过动态驱动下拉列表并在控件元数据中添加了控件详细信息部分,但我很难理解如何让它们显示以及如何在实际输入元素上使用该值。任何帮助/示例代码都将非常受欢迎。

<xbl:xbl xmlns:xh="http://www.w3.org/1999/xhtml"
        xmlns:xf="http://www.w3.org/2002/xforms"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:ev="http://www.w3.org/2001/xml-events"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
        xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
        xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
        xmlns:saxon="http://saxon.sf.net/"
        xmlns:oxf="http://www.orbeon.com/oxf/processors"
        xmlns:xbl="http://www.w3.org/ns/xbl"
        xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xbl:binding id="fr-slider" element="fr|slider"
           xxf:external-events="fr-value-changed"
           xxbl:mode="lhha binding value">
        <metadata xmlns="http://orbeon.org/oxf/xml/form-builder">
            <display-name lang="en">Slider</display-name>
            <icon lang="en">
                <small-icon>/forms/orbeon/builder/images/timeline_marker.png</small-icon>
                <large-icon>/forms/orbeon/builder/images/timeline_marker.png</large-icon>
            </icon>
            <datatype>xf:number</datatype>
            <template>
                <fr:slider>
                    <xf:label ref=""/>
                    <xf:hint ref=""/>
                    <xf:help ref=""/>
                    <xf:alert ref=""/>
                    <xf:min ref=""/>
                    <xf:max ref=""/>
                    <xf:step ref=""/>
                </fr:slider>
            </template>
            <control-details>
            <xf:input ref="xf:min/@ref" type="number">
                <xf:label>Minimum Value</xf:label>
                <xf:hint />
            </xf:input>
            <xf:input ref="xf:max/@ref" type="number">
                <xf:label>Maximum Value</xf:label>
                <xf:hint />
            </xf:input>
            <xf:input ref="xf:step/@ref" type="number">
                <xf:label>Step Size</xf:label>
                <xf:hint>Smallest change in value the slider will allow</xf:hint>
            </xf:input>
            </control-details>
        </metadata>
        <xbl:resource>
            <xbl:style>
                input.fr-slider { width: 100% };
            </xbl:style>
        </xbl:resource>
        <xbl:template xxbl:transform="oxf:unsafe-xslt">
            <xsl:transform version="2.0">
            <xsl:import href="oxf:/oxf/xslt/utils/xbl.xsl"/>
            <xsl:template match="/*">
                <xh:input type="range" min="0" max="10" step="1" class="fr-slider"/>
            </xsl:template>
            </xsl:transform>
        </xbl:template>
    </xbl:binding>
</xbl:xbl>

1 个答案:

答案 0 :(得分:1)

要获取要在“基本设置”对话框中显示的<control-detail>中的输入,您需要向<xf:label><xf:hint>元素添加一个lang参数(感谢@avernet解决这一点)。

下面是一个自定义控件cust的完整示例:betterinput,它使用xhtml输入元素作为其输入。它使用自定义设置(以及数据类型[在控制设置中设置 - >验证和警报 - >数据类型])来配置html元素的参数(请注意,自定义参数已更改为控制参数)。 Javascript用于同步xhtml输入和xforms输入之间的值(以便Orbeon捕获该值)。该示例基于Orbeon中包含的number control

XBL / CUST / betterinput / betterinput.xbl

<xbl:xbl xmlns:xh="http://www.w3.org/1999/xhtml"
        xmlns:xf="http://www.w3.org/2002/xforms"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:ev="http://www.w3.org/2001/xml-events"
        xmlns:xi="http://www.w3.org/2001/XInclude"
        xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
        xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
        xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
        xmlns:saxon="http://saxon.sf.net/"
    xmlns:exf="http://www.exforms.org/exf/1-0"
        xmlns:oxf="http://www.orbeon.com/oxf/processors"
        xmlns:xbl="http://www.w3.org/ns/xbl"
        xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:cust="http://www.cust.com/">

  <xbl:script src="/xbl/cust/betterinput/betterinput.js"/>
    <xbl:binding
          id="cust-betterinput"
            element="cust|betterinput"
            xxbl:mode="lhha binding value focus"
            xxbl:label-for="html-input">
        <metadata xmlns="http://orbeon.org/oxf/xml/form-builder">
            <display-name lang="en">Better Input</display-name>
            <icon lang="en">
                <small-icon>/forms/orbeon/builder/images/input.png</small-icon>
                <large-icon>/forms/orbeon/builder/images/input.png</large-icon>
            </icon>
            <description lang="en"/>
            <templates>
                <view>
                    <cust:betterinput type="" prefix="" suffix="">
                        <xf:label ref=""/>
                        <xf:hint ref=""/>
                        <xf:help ref=""/>
                        <xf:alert ref=""/>
                    </cust:betterinput>
                </view>
            </templates>
            <control-details>
                <xf:input ref="@type">
                    <xf:label lang="en">Input Type</xf:label>
                    <xf:hint lang="en">HTML5 Input Type</xf:hint>
                </xf:input>
                <xf:input ref="@prefix">
                    <xf:label lang="en">Input Prefix</xf:label>
                    <xf:hint/>
                </xf:input>
                <xf:input ref="@suffix">
                    <xf:label lang="en">Input Suffix</xf:label>
                    <xf:hint/>
                </xf:input>
            </control-details>
        </metadata>
    <xbl:resources>
      <xbl:style src="/xbl/cust/betterinput/betterinput.css"/>
    </xbl:resources>
        <xbl:template xxbl:transform="oxf:unsafe-xslt">
            <xsl:transform version="2.0">
                <xsl:import href="oxf:/oxf/xslt/utils/xbl.xsl"/>
                <xsl:template match="/*">
          <xsl:variable
              name="js-object"
              as="xs:string"
              select="'YAHOO.xbl.cust.BetterInput.instance(this)'"/>
                    <xf:group>
            <xf:action type="javascript" ev:event="xforms-disabled" ev:target="#observer">
                            <xsl:value-of select="$js-object"/>.destroy();
                        </xf:action>
                        <xf:var name="binding" value="xxf:binding('cust-betterinput')"/>
                        <xf:var name="view"
                                value="exf:readonly($binding) and property('xxf:readonly-appearance') = 'static'"/>
            <xf:action
                ev:target="#observer"
                ev:event="xforms-enabled xforms-value-changed">
                            <xxf:script>
                                <xsl:value-of select="$js-object"/>.updateWithServerValue();
                            </xxf:script>
                        </xf:action>
            <xf:action
                ev:target="#observer"
                ev:event="DOMFocusOut">
                            <xxf:script>
                                <xsl:value-of select="$js-object"/>.updateWithServerValue();
                            </xxf:script>
                        </xf:action>
                        <xf:var name="htmlinputs" value="' email url color number datetime-local '" />
                        <xsl:copy-of select="xxbl:parameter(., 'type')"/>
            <xsl:copy-of select="xxbl:parameter(., 'prefix')"/>
            <xsl:copy-of select="xxbl:parameter(., 'suffix')"/>
            <xf:group ref="$binding[not($view)]">
                            <xf:input ref="." class="betterinput-xform-input xforms-hidden">
                <xf:action type="javascript" id="xf-ro" ev:event="xforms-readonly"><xsl:value-of select="$js-object"/>.readonly();</xf:action>
                <xf:action type="javascript" id="xf-rw" ev:event="xforms-readwrite"><xsl:value-of select="$js-object"/>.readwrite();</xf:action>
                            </xf:input>
                <xh:span class="{{(if ($prefix) then 'input-prepend' else (), if ($suffix) then 'input-append' else ())}}">
                    <xf:group class="add-on" ref=".[$prefix]"><xf:output value="$prefix"/></xf:group>
                                        <xh:input  id="html-input" class="betterinput-html-input" type="{{
                                            if (not(type = '') and contains($htmlinputs, concat(' ', $type, ' '))) then
                                                $type
                                            else
                                                if (contains(' decimal integer double ', concat(' ', xxf:type($binding), ' '))) then
                                                    'number'
                                                else
                                                    if (contains($htmlinputs, concat(' ', xxf:type($binding), ' '))) then
                                                        xxf:type($binding)
                                                    else
                                                    'text'
                                        }}"/>
                    <xf:group class="add-on" ref=".[$suffix]"><xf:output value="$suffix"/></xf:group>
                </xh:span>
                        </xf:group>
            <!-- Static readonly mode -->
            <xf:group ref="$binding[$view]" class="{{(if ($prefix) then 'input-prepend' else (), if ($suffix) then 'input-append' else ())}}">
                <xf:group class="add-on" ref=".[$prefix]"><xf:output value="$prefix"/></xf:group>
                <xf:input ref="$binding[$view]" class="betterinput-html-input" />
                <xf:group class="add-on" ref=".[$suffix]"><xf:output value="$suffix"/></xf:group>
                        </xf:group>
                    </xf:group>
                </xsl:template>
            </xsl:transform>
        </xbl:template>
    </xbl:binding>
</xbl:xbl>

XBL / CUST / betterinput / betterinput.js

(function() {

    var $ = ORBEON.jQuery;
    var AS = ORBEON.xforms.server.AjaxServer;
    var Document = ORBEON.xforms.Document;

    YAHOO.namespace("xbl.cust");
    YAHOO.xbl.cust.BetterInput = function() {};
    ORBEON.xforms.XBL.declareClass(YAHOO.xbl.cust.BetterInput, "xbl-cust-betterinput");
    YAHOO.xbl.cust.BetterInput.prototype = {

        xformsInputElement: null,
        visibleInputElement: null,

        prefixElement: null,
        prefix: null,

        init: function() {
            // Get information from the DOM
            console.log('betterinput init');

            this.xformsInputElement = YAHOO.util.Dom.getElementsByClassName("betterinput-xform-input", null, this.container)[0];
            this.visibleInputElement = YAHOO.util.Dom.getElementsByClassName("betterinput-html-input", null, this.container)[0];

            // Properties
            // Find prefix based on class/control name, as this JS can be used with fr:number and fr:currency and properties use the control name
            var controlClassPrefix = null;
            var containerClasses = this.container.className.split(" ");
            for (var classIndex = 0; classIndex < containerClasses.length; classIndex++) {
                var currentClass = containerClasses[classIndex];
                if (currentClass.indexOf("xbl-cust-") == 0) {
                    controlClassPrefix = currentClass;
                    break;
                }
            }

            this.prefixElement            = YAHOO.util.Dom.getElementsByClassName(controlClassPrefix + "-prefix", null, this.container)[0];
            this.prefix                   = Document.getValue(this.prefixElement.id);

            // Register listeners

            // Restore input type, send the value to the server, and updates value after server response
            $(this.visibleInputElement).on('change blur', _.bind(function(e) {
                this.sendValueToServer();
                var formId = $(this.container).parents('form').attr('id');

                // Always update visible value with XForms value
                // - relying just value change event from server is not enough
                // - value change not dispatched if server value hasn't changed
                // - if visible changed, but XForms hasn't, we still need to show XForms value
                // - see: https://github.com/orbeon/orbeon-forms/issues/1026
                AS.nextAjaxResponse(formId).then(_.bind(this.updateWithServerValue, this));
            }, this));

            $(this.visibleInputElement).on('keypress', _.bind(function(e) {
                if (e.which == 13)
                    this.sendValueToServer();
            }, this));
        },

        setFocus: function() {
            this.visibleInputElement.focus();
         },

        sendValueToServer: function() {
            var newValue = this.visibleInputElement.value;
            Document.setValue(this.xformsInputElement.id, newValue);
        },

        updateWithServerValue: function() {
            var value = Document.getValue(this.xformsInputElement.id);

            this.visibleInputElement.value = value;

            // Also update disabled because this might be called upon an iteration being moved, in which case all the control properties must be updated
            this.visibleInputElement.disabled = YAHOO.util.Dom.hasClass(this.xformsInputElement, "xforms-readonly");
        },

        readonly: function() {
            this.visibleInputElement.disabled = true;
        },

        readwrite: function() {
            this.visibleInputElement.disabled = false;
        },
    };
})();