Report abuse

<html xmlns:xforms="http://www.w3.org/2002/xforms"
      xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns="http://www.w3.org/1999/xhtml">

    <head>
        <title>XForms Password Strength Checker</title>
        <xforms:model>
            <!-- This instance contains the password and its check -->
            <xforms:instance id="password">
                <instance xmlns="">
                    <password/>
                    <password-check/>
                </instance>
            </xforms:instance>

            <!-- This instance contains a description of the constraints as well as elements marked as valid/invalid -->
            <xforms:instance id="conditions">
                <conditions xmlns="">
                    <condition>8-32 characters in length</condition>
                    <condition>1 or more numeric characters</condition>
                    <condition>Mix of upper- and lower-case alphabet characters</condition>
                    <condition>1 or more of the following punctuation symbols: &lt;b>!@#$%^&amp;*()_+|=\`{}[]:";'&lt;>?,./&lt;/b></condition>
                    <condition>No disallowed characters</condition>
                    <condition>Password valid</condition>
                    <condition>Password confirmed</condition>
                </conditions>
            </xforms:instance>

            <!-- Convenient constants/variables -->
            <xxforms:variable name="numbers" select="(string-to-codepoints('0') to string-to-codepoints('9'))" as="xs:integer+"/>
            <xxforms:variable name="lowercase" select="(string-to-codepoints('a') to string-to-codepoints('z'))" as="xs:integer+"/>
            <xxforms:variable name="uppercase" select="(string-to-codepoints('A') to string-to-codepoints('Z'))" as="xs:integer+"/>
            <xxforms:variable name="special" select="string-to-codepoints('!@#$%^&amp;*()_+|=\`{}[]:&quot;;''&lt;>?,./')" as="xs:integer+"/>
            <xxforms:variable name="all" select="($numbers, $lowercase, $uppercase, $special)" as="xs:integer+"/>

            <xxforms:variable name="password" select="string-to-codepoints(instance('password')/password)" as="xs:integer+"/>
            <xxforms:variable name="length" select="string-length(instance('password')/password)" as="xs:integer"/>

            <!-- Compute validity for all conditions -->
            <xforms:bind nodeset="instance('conditions')">
                <xforms:bind nodeset="condition[1]" constraint="$length ge 8 and $length lt 32"/>
                <!-- NOTE: Sequence comparison is at work here: condition is true iif at least one character is present in the set -->
                <xforms:bind nodeset="condition[2]" constraint="$password = $numbers"/>
                <xforms:bind nodeset="condition[3]" constraint="$password = $lowercase and $password = $uppercase"/>
                <xforms:bind nodeset="condition[4]" constraint="$password = $special"/>
                <xforms:bind nodeset="condition[5]" constraint="$length gt 0 and not((for $c in $password return $c = $all) = false())"/>
                <!-- NOTE: Evaluation order is important here because the validity of the previous elements must have been determined first -->
                <xforms:bind nodeset="condition[6]" constraint="not((for $v in preceding-sibling::condition return xxforms:valid($v)) = false())"/>
                <xforms:bind nodeset="condition[7]" constraint="instance('password')/password = instance('password')/password-check and xxforms:valid(preceding-sibling::condition[1])"/>
            </xforms:bind>

            <!-- Compute validity of password and check -->
            <xforms:bind nodeset="password" constraint="xxforms:valid(instance('conditions')/condition[6])"/>
            <xforms:bind nodeset="password-check" constraint="xxforms:valid(instance('conditions')/condition[7])"/>

        </xforms:model>
        <style type="text/css">
            .xforms-label { font-weight: bold; margin-right: 1em; display: block }
            .my-valid { background-color: green; color: white }
            .my-invalid { background-color: red; color: white }
            table td, table th { padding: .3em }
            .xforms-repeat-selected-item-1 { background-color: transparent } 
        </style>
    </head>
    <body>

        <p>
            The following example checks a set of conditions on your password:
        </p>

        <table>
            <tbody>
                <tr>
                    <th>Requirement</th>
                    <th>Validated</th>
                </tr>
                <!-- Repeat over all condition elements -->
                <xforms:repeat nodeset="instance('conditions')/condition">
                    <tr>
                        <td>
                            <!-- Output condition description -->
                            <xforms:output value="." mediatype="text/html"/>
                        </td>
                        <!-- Note the dynamic CSS class based on the current condition element's validity -->
                        <td align="center" class="my-{if (xxforms:valid()) then 'valid' else 'invalid'}">
                            <!--  Output "true" or "false" based on the current condition element's validity -->
                            <xforms:output value="xxforms:valid()"/>
                        </td>
                    </tr>
                </xforms:repeat>
            </tbody>
        </table>

        <hr/>

        <!-- Password field -->
        <xforms:input ref="password" incremental="true">
            <xforms:label>New password</xforms:label>
            <xforms:alert>Password invalid</xforms:alert>
        </xforms:input>
        <br/>
        <!-- Password confirmation -->
        <xforms:input ref="password-check" incremental="true">
            <xforms:label>Confirm new password</xforms:label>
            <xforms:alert>Password confirmation invalid</xforms:alert>
        </xforms:input>

    </body>
</html>