<?xml-stylesheet href="xsltforms.xsl" type="text/xsl"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xf="http://www.w3.org/2002/xforms"	xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:ixml="http://invisiblexml.org/NS" lang="en">
  <head>
    <meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover"/>
    <title>Invisible XML Tester</title>
    <script type="text/javascript" src="fleur.js"></script>
    <style>
      /*
      @media screen and (prefers-color-scheme: dark) {
        body, textarea {
        background-color: black;
        color: lightgrey;
        }
      }
      @media screen and (prefers-color-scheme: light) {
        body, textarea {
        background-color: white;
        color: black;
        }
      }
      */
      .container {
        width: 50%;
        margin: 0 auto;
        position: relative;
        height: 100vh;
      }
      .ixml_grammar textarea {
        width: 800px;
        height: 200px;
      }
      .ixml_input textarea {
        width: 800px;
        height: 200px;
      }
      pre {
        font-family: inherit;
        font-size: inherit;
        font-weight: inherit;
      }
      h1 {
        text-align: center;
        font-size: 2em;
      }
    </style>
    <xf:model>
      <xf:instance id="context">
        <context xmlns="">
          <ixml-grammar>
            <group>
              <source/>
            </group>
          </ixml-grammar>
          <xml-grammar/>
          <input/>
          <serialized/>
        </context>
      </xf:instance>
      <xf:instance id="grammars">
        <ixml-grammars xmlns="">
          <ixml-grammar name="">
            <group>
              <source/>
            </group>
          </ixml-grammar>
          <ixml-grammar name="classes">
            <group>
              <source>input: line*.
-line: name, s, amount, newline.
name: word++([Zs]+).
-word:[L]+.
amount: currency, number.
@currency: [Sc].
-number: [Nd]+.
-newline: s?, (-#a; -#d)+.
-s: -[Zs]+.</source>
              <test name=""></test>
            </group>
          </ixml-grammar>
          <ixml-grammar name="data">
            <group>
              <source>data: value++-",", @source.
source: +"ixml".
value: pos; neg.
-pos: +"+", digit+.
-neg: +"-", -"(", digit+, -")".
-digit: ["0"-"9"].</source>
              <test name=""></test>
            </group>
          </ixml-grammar>
          <ixml-grammar name="date">
            <group>
              <source>date: day, -" ", month, -" ", year.
@day: digit, digit?.
-digit: "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9".
@month: "January"; "February"; "March"; "April"; "May"; "June";
        "July"; "August"; "September"; "October"; "November"; "December".
@year: digit, digit, digit, digit.</source>
            </group>
          </ixml-grammar>
          <ixml-grammar name="dates">
            <group>
              <source>dates: s?, date+.
date: day, s, month, s, year, s?.
day: digit, digit?.
-digit: "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9".
month: "January"; "February"; "March";
       "April"; "May"; "June";
       "July"; "August"; "September";
       "October"; "November"; "December".
year: digit, digit, digit, digit.
-s: (-" "; -#d; -#9; -#a)+.</source>
            </group>
          </ixml-grammar>
          <ixml-grammar name="strings">
            <group>
              <source>strings: s?, string**(-",", s).
string: -'"', ~['"']*, -'"'.
-s: -" "*.</source>
            </group>
          </ixml-grammar>
          <ixml-grammar name="url">
            <group>
              <source>url: scheme, ":", authority, path.
scheme: letter+.
authority: "//", host.
host: sub++".".
sub: letter+.
path: ("/", seg)+.
seg: fletter*.
-letter: ["a"-"z"]; ["A"-"Z"]; ["0"-"9"].
-fletter: letter; ".".</source>
            </group>
          </ixml-grammar>
          <ixml-grammar name="expr">
            <group>
              <source>expr: open, -arith, @close, -";".
@open: "(".
close: ")".
arith: left, op, ^right>second.
left&gt;first: operand.
-right: operand.
-operand: name; -number.
@name: ["a"-"z"].
@number: ["0"-"9"].
-op: sign.
@sign&gt;operator: "+"; "-".</source>
            </group>
          </ixml-grammar>
          <ixml-grammar name="ixml">
            <group>
              <source>         ixml: s, (prolog, RS)?, rule++RS, s.

                -s: (whitespace; comment)*. {Optional spacing}
               -RS: (whitespace; comment)+. {Required spacing}
       -whitespace: -[Zs]; tab; lf; cr.
              -tab: -#9.
               -lf: -#a.
               -cr: -#d.
           comment: -"{", (cchar; comment)*, -"}".
            -cchar: ~["{}"].
     
            prolog: version.
           version: -"ixml", RS, -"version", RS, string, s, -'.' .
     
              rule: naming, -["=:"], s, -alts, -".".
           -naming: (mark, s)?, name, s, (-">", s, alias, s)?.
             @name: namestart, namefollower*.
        -namestart: ["_"; L].
     -namefollower: namestart; ["-.·‿⁀"; Nd; Mn].
     
            @alias: name.
              alts: alt++(-[";|"], s).
               alt: term**(-",", s).
             -term: factor;
                    option;
                    repeat0;
                    repeat1.
           -factor: terminal;
                    nonterminal;
                    insertion;
                    -"(", s, alts, -")", s.
           repeat0: factor, (-"*", s; -"**", s, sep).
           repeat1: factor, (-"+", s; -"++", s, sep).
            option: factor, -"?", s.
             @mark: ["@^-"].
               sep: factor.
       nonterminal: naming.
         -terminal: literal; 
                    charset.
           literal: quoted;
                    encoded.
           -quoted: (tmark, s)?, string, s.
     
            @tmark: ["^-"].
           @string: -'"', dchar+, -'"';
                    -"'", schar+, -"'".
             dchar: ~['"'; Cc];
                    '"', -'"'. {all characters except controls; quotes must be doubled}
             schar: ~["'"; Cc];
                    "'", -"'". {all characters except controls; quotes must be doubled}
          -encoded: (tmark, s)?, -"#", hex, s.
              @hex: ["0"-"9"; "a"-"f"; "A"-"F"]+.
     
          -charset: inclusion; 
                    exclusion.
         inclusion: (tmark, s)?,          set.
         exclusion: (tmark, s)?, -"~", s, set.
              -set: -"[", s,  (member, s)**(-[";|"], s), -"]", s.
            member: string;
                    -"#", hex;
                    range;
                    class.
            -range: from, s, -"-", s, to.
             @from: character.
               @to: character.
        -character: -'"', dchar, -'"';
                    -"'", schar, -"'";
                    "#", hex.
            -class: code.
             @code: capital, letter?.
          -capital: ["A"-"Z"].
           -letter: ["A"-"Z"; "a"-"z"].
         insertion: -"+", s, (string; -"#", hex), s.
                   </source>
            </group>
          </ixml-grammar>
        </ixml-grammars>
      </xf:instance>
      <xf:bind ref="/context/ixml-grammar/group/source" constraint="normalize-space(/context/ixml-grammar/group/source) eq '' or empty(invisible-xml(())(/context/ixml-grammar/group/source)/ixml[@ixml:state eq 'failed'])"/>
      <xf:bind ref="/context/input" constraint="if (normalize-space(/context/ixml-grammar/group/source) eq '' or empty(/context/xml-grammar/ixml[@ixml:state eq 'failed'])) then empty(invisible-xml(/context/xml-grammar/ixml)(/context/input)/ixml[@ixml:state eq 'failed']) else true()"/>
      <xf:bind ref="/context/xml-grammar" readonly="empty(ixml)"/>
    </xf:model>
  </head>
  <body>
    <h1>Invisible XML Tester</h1>
    <div class="container">
      <xf:select1 ref="ixml-grammar">
        <xf:label>Grammar Samples</xf:label>
        <xf:itemset ref="instance('grammars')/ixml-grammar">
          <xf:label ref="@name"/>
          <xf:copy ref="group"/>
        </xf:itemset>
        <xf:action ev:event="xforms-value-changed">
          <xf:setvalue ref="../serialized" value="''"/>
          <xf:delete ref="../xml-grammar/*"/>
          <xf:insert context="../xml-grammar" if="normalize-space(../ixml-grammar/group/source) ne ''" origin="invisible-xml(())(../ixml-grammar/group/source)/*"/>
        </xf:action>
      </xf:select1>
      <br/>
      <xf:textarea ref="ixml-grammar/group/source" class="ixml_grammar" incremental="true">
        <xf:label>Invisible XML Grammar</xf:label>
        <xf:help>Refer to Invisible XML Specification, Community Group Editorial Draft, 2024-08-20</xf:help>
        <xf:hint>When empty, iXML grammar is used as default value</xf:hint>
        <xf:alert>Syntax error in grammar</xf:alert>
        <xf:action ev:event="xforms-value-changed">
          <xf:setvalue ref="../../../serialized" value="''"/>
          <xf:delete ref="../../../xml-grammar/*"/>
          <xf:insert context="../../../xml-grammar" if="normalize-space(../../../ixml-grammar/group/source) ne ''" origin="invisible-xml(())(../ixml-grammar/group/source)/*"/>
        </xf:action>
      </xf:textarea>
      <br/>
      <xf:trigger>
        <xf:label>Clear</xf:label>
        <xf:action ev:event="DOMActivate">
          <xf:setvalue ref="ixml-grammar/group/source" value="''"/>
          <xf:delete ref="../../../xml-grammar/*"/>
        </xf:action>
      </xf:trigger>
      &#160;
      <xf:trigger ref="xml-grammar">
        <xf:label>XML Notation</xf:label>
        <xf:setvalue ev:event="DOMActivate" ref="../serialized" value="serialize(../xml-grammar/ixml, map{{'indent': 'yes'}})"/>
      </xf:trigger>
      &#160;
      <xf:trigger ref="xml-grammar">
        <xf:label>Compiled JSON for Nearley</xf:label>
        <xf:setvalue ev:event="DOMActivate" ref="../serialized" value="serialize(../xml-grammar/ixml, map{{'media-type': 'text/nearley'}})"/>
      </xf:trigger>
  <br/>
      <xf:textarea ref="input" class="ixml_input" incremental="true">
        <xf:label>Input</xf:label>
        <xf:help>This is the input text to be parsed</xf:help>
        <xf:alert>Unsuccessful parsing</xf:alert>
        <xf:setvalue ev:event="xforms-value-changed" ref="../serialized" value="''"/>
      </xf:textarea>
      <div>
        <xf:trigger>
          <xf:label>Clear</xf:label>
          <xf:setvalue ev:event="DOMActivate" ref="input" value="''"/>
        </xf:trigger>
        &#160;
        <xf:trigger ref="ixml-grammar/group/source">
          <xf:label>Raw Parsing Result</xf:label>
          <xf:setvalue ev:event="DOMActivate" ref="../../../serialized" value="serialize(invisible-xml(../xml-grammar/ixml)(../input), map{{'indent': 'no'}})"/>
        </xf:trigger>
        &#160;
        <xf:trigger ref="ixml-grammar/group/source">
          <xf:label>Indented Parsing Result</xf:label>
          <xf:setvalue ev:event="DOMActivate" ref="../../../serialized" value="serialize(invisible-xml(../xml-grammar/ixml)(../input), map{{'indent': 'yes'}})"/>
        </xf:trigger>
      </div>
      <pre>
        <xf:output value="serialized"/>
      </pre>
    </div>
  </body>
</html>