Ensure that we set the _PageRef_ for a handler

:Namespace _JQ
    (⎕IO ⎕ML)←1

    :section Common Code

    quote←{0∊⍴⍵: '' ⋄ '⍎"'∊⍨⍬⍴⍵:⍵ ⋄ '"',(('"' ⎕R '\\\0')⍵),'"'}
    fmtSelector←{{'this'≡⍵:⍵ ⋄quote ⍵}¯2↓enlist{⍵,', '}¨eis ⍵}

    ∇ r←opt(sel Update jqfn)val
    ⍝ update an option for a widget
      r←#.JQ.Execute'$(',(fmtSelector sel),').',jqfn,'("option","',(quote opt),'",',(quote val),');'
    ∇
    :endsection

    :section Base Classes
    :class _jqObject : #.HtmlElement
        :field public Selector←''      ⍝ Selector to apply the JQuery function to
        :field public JavaScript←''    ⍝ additional JavaScript to run AFTER the jQuery function, can be function chain, separate code or both
        :field public PreJavaScript←'' ⍝ additional JavaScript to run BEFORE the jQuery function
        :field public Var←''           ⍝ JavaScript variable name for created object
        :field public JQueryFn←''      ⍝ JQuery function to apply
        :field public JQPars←''        ⍝ JQuery function parameters
        :field public shared readonly _true←#.JSON.true     ⍝ same definition as in #.JSON
        :field public shared readonly _false←#.JSON.false   ⍝ same definition as in #.JSON
        :field public ScriptOptions←1 1 ⍝ determines how script will be rendered [1] wrap with <script>...</script>, [2] wrap with $(function(){...})

        ∇ Make0
          :Access public
          :Implements constructor
        ∇

        ∇ Make1 pars
          :Access public
          :Implements constructor
          pars←eis pars
          JQueryFn Selector JQPars JavaScript Var PreJavaScript←6↑pars,(⍴pars)↓'' '' '' '' '' ''
        ∇

        ∇ r←Render
          :Access public
          SetUse
          r←ScriptOptions #.JQ.JQueryfn JQueryFn Selector JQPars JavaScript Var PreJavaScript
        ∇

        ∇ r←isSelector str ⍝ checks if str is probably a jQuery selector
          :Access public shared
          r←∨/str∊'''"*[]:>+~()#.'
        ∇

        :section APLJax

        ∇ r←selector Replace content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('replace'selector)('data'content)
        ∇
        ∇ r←selector Append content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('append'selector)('data'content)
        ∇
        ∇ r←selector Prepend content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('prepend'selector)('data'content)
        ∇
        ∇ r←Execute content
          :Access public
          r←⊂('execute'content)
        ∇

        ∇ r←name Assign data
          :Access public
          r←⊂('assign'name)('data'data)
        ∇
        :EndSection

    :endclass

    :class _jqWidget : _jqObject

        :field public Options←''    ⍝ options for the object to be created
        :field public ContainerTag←'div' ⍝ default container type
        :field public Container
        :field public InternalEvents←'' ⍝ list of events the widget "knows" about
        :field _build←0                 ⍝ if 0, we build any HTML infrastructure for the widget, otherwise, assume the user built it
        :field public WidgetSyntax←''
        :field public shared readonly WidgetDef←'event,ui' 'event'  'ui' '$(event.currentTarget)'  ⍝ see _JQ.RenderHandlerCore for details

        ∇ r←{a}rand w;rnd
          :Access public
          rnd←{⍺←⊢ ⋄ t←16807⌶2 ⋄ r←⍺?⍵ ⋄ t←16807⌶t ⋄ r}
          :If 0=⎕NC'a' ⋄ r←rnd w
          :Else ⋄ r←a rnd w ⋄ :EndIf
        ∇

        ∇ Make
          :Access public
          Options←⎕NS''
          Container←⎕NEW #.HtmlElement
          :Implements constructor
          WidgetSyntax←WidgetDef
        ∇

        ∇ r←Render;build;html;handlers;js;opts
          :Access public

          r←html←js←''
          SetUse

          _build∨←0∊⍴Selector ⍝ if the user explicitly specifies a selector, assume he's built the content himself

          :If _build
              Container.(id name type style class title)←Container.(id name type style class title){UNDEF≡⍵:⍺ ⋄ UNDEF≢⍺:⍺ ⋄ ⍵}¨⎕THIS.(id name type style class title)
              :If Container.id≡UNDEF
                  :If Container.name≢UNDEF
                      Container.id←Container.name
                  :Else
                      Container.id←SetId
                  :EndIf
              :EndIf
              Selector←'#',Container.id
          :EndIf

          handlers←''
          :If ~0∊⍴Handlers
              handlers←';',⍨∊¯1↓¨Handlers.Render
          :EndIf

          opts←{0::⍬ ⋄ 1 0≥_PageRef._Request.isAPLJax}⍬
          js←opts #.JQ.JQueryfn JQueryFn Selector Options(JavaScript,handlers)Var PreJavaScript

          :If _build≥0∊⍴Container.Content
              :Select ⊃Selector
              :Case '#' ⍝ id?
                  Container.id←1↓Selector
              :Case '.' ⍝ class?
                  Container.class←1↓Selector
              :EndSelect
              :If ContainerTag{⍵≡(⍴⍵)↑⍺}'input'
              :AndIf UNDEF≡Container.name
                  Container.name←('.#'∊⍨⊃Selector)↓Selector
              :EndIf
              Container.Tag←ContainerTag
              html←Container.Render
          :EndIf
          r←html,js
        ∇

        ∇ {handler}←On args
          :Access public
          ⍝ args - event callback clientData javascript
          handler←⎕BASE.On args
          handler.InternalEvents←InternalEvents
          handler.(WidgetDef←WidgetRef.WidgetDef)
        ∇

        ∇ {name}Set value
          :Access public
          →(0∊⍴value)⍴0
          :If 326≠⎕DR Options ⋄ Options←⎕NS'' ⋄ :EndIf
          :If 0=⎕NC'name'
              :Trap 11
                  (name value)←ParseValue value
              :Else
                  ⎕SIGNAL/⎕DMX.(EM EN)
              :EndTrap
          :EndIf
          name(Options SetOption)value
        ∇

        ∇ name SetIfNotSet value
          :Access public
          :If 0∊⍴GetOption name
              name Set value
          :EndIf
        ∇

        ∇ name(ref SetOption)value;set;parent;i;ind;newref;chunk;pos;n;now;new;chunkroot
          →(0∊⍴value)⍴0
          :If 1<|≡name ⍝ multiple names?
              value←(⊂⍣((⎕DR value)∊80 82))value
              name(ref SetOption)¨value
          :Else

              set←{⍺⍺⍎'(',⍺,')←⍵'}

              :If 0∊⍴parent←(i←-'.'⍳⍨⌽name)↓name
                  name(ref set)value ⍝ single name: assign directly (may be more than 1 name)
              :Else
                  ind←name⍳'.'
                  chunk←¯1↓ind↑name
                  (chunkroot pos)←'[]'#.Utils.penclose chunk
                  pos←2⊃⎕VFI pos
                  :Trap 3 6
                      newref←ref⍎chunk
                  :Case 3 ⍝ index error
                      n←⍴now←ref⍎chunkroot
                      new←⎕NS¨(pos-n)⍴⊂⍬
                      chunkroot(ref set)now,new
                      newref←ref⍎chunk
                  :Case 6 ⍝ value error
                      chunkroot ref.⎕NS''
                      :If ~0∊pos
                          new←⎕NS¨pos⍴⊂⍬
                          chunkroot(ref set)new
                      :EndIf
                      newref←ref⍎chunk
                  :EndTrap
                  (ind↓name)(newref SetOption)value
              :EndIf
          :EndIf
        ∇

        ∇ r←ParseValue value
          :Access shared public
          :If 2=⍴⍴value
          :AndIf 2=¯1↑⍴value
          :ElseIf 2<|≡value
          :AndIf ∧/(,2)∘≡∘⍴¨value
              value←↑value
          :ElseIf 0=2|⍴value
              value←((0.5×⍴value),2)⍴value
          :Else
              'Invalid option format'⎕SIGNAL 11
          :EndIf
          r←↓[1]value
        ∇

        ∇ r←GetOption names
          :Access public
          r←{6::'' ⋄ Options.⍎⍵}¨{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          :If 1=⍴r ⋄ r←⊃r ⋄ :EndIf ⍝ if single setting requested
        ∇

        ∇ r←name Update value;v
          :Access public
          r←name(Selector #._JQ.Update JQueryFn)value
          name Set value
        ∇
    :endclass

    :class _jqUIWidget : _jqWidget

        :field public Force←0

        :field public WidgetSyntax ←⊂'event,ui' 'event'  'ui' '$(event.target)' ⍝ see Handler class below

        ∇ make
          :Access public
          :If 0=⎕NC⊂'Uses' ⋄ Uses←'' ⋄ :EndIf
          :If 0∊⍴Uses ⋄ Uses←'JQueryUI' ⋄ :EndIf
          :Implements constructor
        ∇

        ∇ make1 pars
          :Access public
          :If 0=⎕NC⊂'Uses' ⋄ Uses←'' ⋄ :EndIf
          :If 0∊⍴Uses ⋄ Uses←'JQueryUI' ⋄ :EndIf
          :Implements constructor :base pars
        ∇

        ∇ {r}←opts RenderHandler handler
          :Access public
          r←opts ⎕BASE.RenderHandler(handler WidgetDef Force)
        ∇

    :endclass

    :class _jqUITabbedWidget : _jqUIWidget
        :field public Titles←''
        :field public Id←''
        :field public Tabs←''
        :field public Widget

        ∇ Make0
          :Access public
          :Implements constructor
          Widget←⎕NS''
          Widget._function←{}
        ∇

        ∇ Make1 pars;t
          :Access public
          :Implements constructor
          :Select |≡pars
          :Case 2
              :If 2=⍴pars ⍝ could be title/tab or title/title
                  :If (10|⎕DR t←2⊃pars)∊0 2 ⍝ if the second element is character
                  :AndIf 1=⍴⍴t ⍝ and it's a vector
                  :AndIf 20>⍴t ⍝ and it's relatively short
                      pars←,⊂pars
                  :Else
                      pars←#.HtmlElement.eis¨pars
                  :EndIf
              :EndIf
          :Case 0 1
              pars←#.HtmlElement.eis pars
          :EndSelect
          Titles Tabs Options JavaScript Var←5↑pars,(⍴pars)↓'' '' '' '' ''
          Widget←⎕NS''
          Widget._function←{}
        ∇

        ∇ r←Render;opts
          :Access public
          'Title and Contents lengths do not match'⎕SIGNAL((⍴Titles)≠⍴Tabs)/5
          opts←Options
          :If 2≤|≡Options ⋄ opts←#.JSON.toJQueryParameters Options ⋄ :EndIf
          r←Widget._function Id Titles(RenderTab¨Tabs)opts JavaScript Var
          r,←⎕BASE.Render
        ∇

        ∇ r←RenderTab tab;e;t
          :Access public
          :If 326=⎕DR tab
              r←''
              :For e :In tab
                  t←⊃e
                  :If isInstance t
                  :AndIf isHtmlElement t
                      r,←e.Render
                  :ElseIf isClass t
                  :AndIf isHtmlElement t
                      r,←(⎕NEW∘{2<⍴,⍵:(⊃⍵)(1↓⍵) ⋄ ⍵}eis e).Render
                  :Else
                      r,←e
                  :EndIf
              :EndFor
          :Else
              r←,⍕tab
          :EndIf
        ∇

    :endclass
    :endsection

⍝ --- Events ---
    :Section Events

    :Class Handler
        :Field public Selector←''        ⍝ CSS/jQuery selector to bind handler to
        :Field public Delegates←''       ⍝ See jQuery.On for information about delegates
        :Field public Events←''          ⍝ events to bind
        :Field public ClientData←''      ⍝ any additional client data to send to server
        :Field public Callback←1         ⍝ execute AJAX callback to server?  or the name of the server-side callback function
        :Field public JavaScript←''      ⍝ JavaScript to execute prior to server callback
        :Field public Page←''            ⍝ server URL to request for an AJAX callback
        :Field public jQueryWrap←1       ⍝ wrap handler in $(function(){...});
        :Field public ScriptWrap←1       ⍝ wrap handler in <script>...</script>
        :Field public WidgetDef←''       ⍝ widget definitions (e.g. jQuery or Syncfusion, others libraries may different)
                                         ⍝                                          jQuery            Syncfusion
                                         ⍝ [1] event handler syntax:                'event,ui'        'argument'
                                         ⍝ [2] syntax to access the event object:   'event'           'argument'
                                         ⍝ [3] syntax to access the object's model: 'ui'              'argument.model'
                                         ⍝ [4] syntax to access the widget itself:  '$(event.target)' 'this.element'
        :Field public ForceInternal←¯1   ⍝ indicates whether to "force" the event to be treated as a widget internal event
        :Field public WidgetRef←''       ⍝ ref to widget instance if this handler is on
        :Field public Hourglass←¯1       ⍝ indicates whether to display hourglass during callback execution
                                         ⍝ 1 - yes, 0 - no, ¯1 - only if calling back to APL

        :Field public Uses←'JQuery'
        :Field public _PageRef_←''

        quote←{0∊⍴⍵: '' ⋄ '⍎"'∊⍨⍬⍴⍵:⍵~'⍎' ⋄ '"',(('"' ⎕R '\\\0')⍵),'"'} ⍝ quote unless already quoted or begins with ⍎
        ine←{0∊⍴⍺:'' ⋄ ⍵} ⍝ if not empty
        eis←{(,∘⊂)⍣((326∊⎕DR ⍵)<2>|≡⍵),⍵} ⍝ Enclose if simple

        ∇ Make0
          :Access public
          :Implements constructor
          CommonSetup
        ∇

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←#.HtmlElement.eis params
          (Selector Events Callback ClientData Delegates JavaScript Page)←7↑params,(⍴params)↓7⍴⊂''
          :If #.HtmlPage #.HtmlElement.isInstance Page ⋄ Page←Page.Page ⋄ :EndIf ⍝ if request object passed
          CommonSetup
        ∇

        ∇ CommonSetup;c
          :Access public
          :Trap 0
              c←#.HtmlElement.context'_PageRef'
              :If ~0∊⍴c
                  (c⍎'_PageRef').Use Uses
                  _PageRef_←c._PageRef
              :EndIf
          :EndTrap
          WidgetDef←'event,ui' 'event' 'ui' '$(event.target)'
        ∇

        ∇ r←Render;sel;syn_handler;syn_event;syn_model;syn_this;data;useajax;force;cd;selector;arg;verb;name;phrase;datasel;JQfn;jqfn;hg;removehg;dtype;success;status;ajax;widget;syn_value;delegates;v
          :Access public
          r←''
          :If ~0∊⍴Events ⍝ skip if no events specified

              :If #.MiPage #.HtmlElement.isInstance Page
                  Page←Page._PageName
              :EndIf

              (selector delegates)←2↑(eis Selector),'' ''

              :If ~0∊⍴Delegates
                  delegates←Delegates
              :EndIf

              :If useajax←(,0)≢,Callback ⍝ callback=0 → don't make callback to server; =1 → use APLJax, =charvec → call ⍎charvec
              :AndIf 0∊⍴Page
                  Page←_PageRef_._PageName
              :EndIf

              force←0
              :If widget←#.HtmlElement.isWidget WidgetRef ⍝ is this a widget handler?
                  :If ForceInternal=¯1
                      force←(⊂Events)∊WidgetRef.InternalEvents
                  :Else
                      force←ForceInternal
                  :EndIf
              :EndIf

              :If 0∊⍴selector  ⍝ empty selector → use entire page
                  :If widget
                      selector←WidgetRef.Selector
                  :ElseIf #.HtmlElement #.HtmlElement.isInstance ##
                      :If #.MiPage #.HtmlElement.isInstance ##
                          selector←'⍎document'
                      :Else
                          selector←'#',##.id
                      :EndIf
                  :Else
                      selector←'⍎document'
                  :EndIf
              :EndIf

              (syn_handler syn_event syn_model syn_this)←WidgetDef

              data←'_event: ',syn_event,'.type, '
              data,←'_what: ',syn_this,'.attr("id"), '
              data,←'_value: ',syn_this,'.val(), '
              data,←'_selector: ',(quote selector~'⍎'),', '

              :If #.HtmlElement.isString Callback ⍝ numeric Callback 1-call APLJax, 0-no callback to server
              :AndIf ~0∊⍴Callback
                  data,←'_callback: ',(quote Callback),', '
              :EndIf

              :If 0∊⍴ClientData ⍝ if you don't specify any clientdata, we serialize any forms on the page
                  data,←'_serialized: $("form").serialize(), '
              :EndIf

              data←¯2↓data

              :Select |≡ClientData

              :CaseList 0 1  ⍝ simple vector
                  ClientData←,⊂2⍴⊂ClientData ⍝ name/id are set to the same
              :Case 2
                  ClientData←,⊂ClientData
              :EndSelect

              :For cd :In ClientData
                  cd←#.HtmlElement.eis cd
                  (name verb arg sel)←4↑cd,(⍴cd)↓4⍴⊂''
                  :If ~0∊⍴name
                  :AndIf ~0∊⍴verb
                      jqfn←'' ⍝ jQuery function to call if this client data element refers to a widget

                      :If (⊂verb)∊'html' 'val'  ⍝ neither html or val take an argument
                      :AndIf 0∊⍴sel
                          sel←arg
                      :EndIf

⍝ build the selector for the data element
                      :If sel≡'' ⍝ it's for the current element/widget
                          :If #.HtmlElement.isWidget WidgetRef
                              datasel←'$(',(quote WidgetRef.Selector),').'
                              :If ~0∊⍴jqfn←WidgetRef.JQueryFn
                                  datasel,←WidgetRef.JQueryFn
                              :EndIf
                          :Else
                              datasel←syn_this,'.'
                          :EndIf
                      :ElseIf #.HtmlElement #.HtmlElement.isInstance sel ⍝ selector is reference to other element
                          :If #._JQ._jqObject #.HtmlElement.isInstance sel ⍝ is it a jQuery-based object?
                              :If 0∊⍴sel.Selector ⍝ no Selector?
                                  sel.SetId
                                  sel.Selector←'#',sel.id
                              :EndIf
                              datasel←'$(',(quote sel.Selector),').'
                              :If ~0∊⍴jqfn←sel.JQueryFn
                                  datasel,←sel.JQueryFn
                              :EndIf
                          :Else ⍝ not a jQuery-based object
                              sel.SetId
                              datasel←'$(',(quote'#',sel.id),').'
                          :EndIf
                      :Else ⍝ sel is not an HtmlElement
                          :Select |≡sel
                          :CaseList 0 1
                              datasel←'$(',(quote sel),').'
                          :Case 2
                              datasel←'$(',(quote(1⊃sel)),').',jqfn←2⊃sel
                          :EndSelect
                      :EndIf

⍝ now figure out what data to generate
                      phrase←''
                      :Select verb

                      :CaseList 'attr' 'css' 'is' 'prop'
                          datasel,←'().'/⍨~0∊⍴jqfn
                          phrase←datasel,verb,'(',(quote arg),')'

                      :CaseList 'html' 'val'
                          datasel,←'().'/⍨~0∊⍴jqfn
                          phrase←datasel,verb,'()'

                      :Case 'option' ⍝ jQueryUI and Syncfusion widgets
                          :If 0∊⍴arg
                              phrase←'JSON.stringify(',datasel,'("option"))'
                          :Else
                              phrase←datasel,'("option",',(quote arg),')'
                          :EndIf

                      :CaseList 'event' 'this'
                          v←('event' 'this'⍳⊂verb)⊃syn_event syn_this
                          :If 0∊⍴arg
                              phrase←'JSON.stringify(',v,')'
                          :Else
                              phrase←v,'.',arg
                          :EndIf

                      :Case 'model' ⍝ widgets only
                          :If ~0∊⍴jqfn
                              datasel,←'().'
                              :If 0∊⍴arg
                                  phrase←'JSON.stringify(',syn_model,')'
                              :Else
                                  phrase←syn_model,'.',arg
                              :EndIf
                          :EndIf

                      :Case 'eval'
                          sel←'' ⍝ ignore selector on eval
                          phrase←'eval(',(quote arg),')'

⍝                      :CaseList syn_event syn_model syn_this
⍝                          :If ~0∊⍴jqfn ⍝ these verbs only apply to widgets
⍝                              :If 0∊⍴arg
⍝                                  phrase←'JSON.stringify(',verb,')'
⍝                              :Else
⍝                                  phrase←verb,'.',arg
⍝                              :EndIf
⍝                          :EndIf

                      :Case 'string'
                          phrase←quote arg

                      :Case 'serialize'
                          :If 0∊⍴sel
                              :If 0∊⍴arg
                                  sel←'form'
                              :Else
                                  sel←arg
                              :EndIf
                          :EndIf
                          phrase←'$(',(quote sel),').serialize()'
                          name,←'_serialized'
                      :Else
                          #.Boot.Log'Unknown event handler verb: "',verb,'"',{0::'' ⋄ ' on page ',##._PageRef._PageName}⍬
                          phrase←quote phrase
                      :EndSelect

                      data,←',',name,': ',phrase
                  :EndIf
              :EndFor

              (hg removehg)←((1+Hourglass=¯1)⊃Hourglass useajax)∘{⍺:'document.body.style.cursor="',⍵,'";' ⋄ ''}¨'wait' 'default'

              dtype←'"json"'
              success←'success: function(obj){APLJaxReturn(obj);document.body.style.cursor="default";}'
              status←'statusCode:{ 408: function(){alert("Session timed out");',removehg,'}}'
              ajax←(JavaScript ine JavaScript,';'),useajax/hg,'$.ajax({url: ',(quote Page),', cache: false, type: "POST", dataType: ',dtype,', data: {',data,'}, ',success,', ',status,'});'

              :If widget
                  :If force
                      Events(WidgetRef.Options{⍺⍺⍎⍺,'←⍵'})'function(',syn_handler,'){',ajax,'}'
                  :Else
                      r←'.on(',(quote Events),', function(event,ui){',ajax,'});'
                  :EndIf
              :Else
                  r←'$(',(quote selector),').on(',(quote Events),(delegates ine', ',quote delegates),', function(event,ui){',ajax,'});'
                  :If jQueryWrap ⋄ r←'$(function(){',r,'});' ⋄ :EndIf
                  :If ScriptWrap ⋄ r←#.HTMLInput.JS r ⋄ :EndIf
              :EndIf
          :EndIf
        ∇

    :endclass
    :endsection

:EndNamespace

:Namespace _JQ
    (⎕IO ⎕ML)←1

    :section Common Code

    quote←{0∊⍴⍵: '' ⋄ '⍎"'∊⍨⍬⍴⍵:⍵ ⋄ '"',(('"' ⎕R '\\\0')⍵),'"'}
    fmtSelector←{{'this'≡⍵:⍵ ⋄quote ⍵}¯2↓enlist{⍵,', '}¨eis ⍵}

    ∇ r←opt(sel Update jqfn)val
    ⍝ update an option for a widget
      r←#.JQ.Execute'$(',(fmtSelector sel),').',jqfn,'("option","',(quote opt),'",',(quote val),');'
    ∇
    :endsection

    :section Base Classes
    :class _jqObject : #.HtmlElement
        :field public Selector←''      ⍝ Selector to apply the JQuery function to
        :field public JavaScript←''    ⍝ additional JavaScript to run AFTER the jQuery function, can be function chain, separate code or both
        :field public PreJavaScript←'' ⍝ additional JavaScript to run BEFORE the jQuery function
        :field public Var←''           ⍝ JavaScript variable name for created object
        :field public JQueryFn←''      ⍝ JQuery function to apply
        :field public JQPars←''        ⍝ JQuery function parameters
        :field public shared readonly _true←#.JSON.true     ⍝ same definition as in #.JSON
        :field public shared readonly _false←#.JSON.false   ⍝ same definition as in #.JSON
        :field public ScriptOptions←1 1 ⍝ determines how script will be rendered [1] wrap with <script>...</script>, [2] wrap with $(function(){...})

        ∇ Make0
          :Access public
          :Implements constructor
        ∇

        ∇ Make1 pars
          :Access public
          :Implements constructor
          pars←eis pars
          JQueryFn Selector JQPars JavaScript Var PreJavaScript←6↑pars,(⍴pars)↓'' '' '' '' '' ''
        ∇

        ∇ r←Render
          :Access public
          SetUse
          r←ScriptOptions #.JQ.JQueryfn JQueryFn Selector JQPars JavaScript Var PreJavaScript
        ∇

        ∇ r←isSelector str ⍝ checks if str is probably a jQuery selector
          :Access public shared
          r←∨/str∊'''"*[]:>+~()#.'
        ∇

        :section APLJax

        ∇ r←selector Replace content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('replace'selector)('data'content)
        ∇
        ∇ r←selector Append content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('append'selector)('data'content)
        ∇
        ∇ r←selector Prepend content
          :Access public
          :If isClass content ⋄ content←(⎕NEW content).Render ⋄ :EndIf
          r←⊂('prepend'selector)('data'content)
        ∇
        ∇ r←Execute content
          :Access public
          r←⊂('execute'content)
        ∇

        ∇ r←name Assign data
          :Access public
          r←⊂('assign'name)('data'data)
        ∇
        :EndSection

    :endclass

    :class _jqWidget : _jqObject

        :field public Options←''    ⍝ options for the object to be created
        :field public ContainerTag←'div' ⍝ default container type
        :field public Container
        :field public InternalEvents←'' ⍝ list of events the widget "knows" about
        :field _build←0                 ⍝ if 0, we build any HTML infrastructure for the widget, otherwise, assume the user built it
        :field public WidgetSyntax←''
        :field public shared readonly WidgetDef←'event,ui' 'event'  'ui' '$(event.currentTarget)'  ⍝ see _JQ.RenderHandlerCore for details

        ∇ r←{a}rand w;rnd
          :Access public
          rnd←{⍺←⊢ ⋄ t←16807⌶2 ⋄ r←⍺?⍵ ⋄ t←16807⌶t ⋄ r}
          :If 0=⎕NC'a' ⋄ r←rnd w
          :Else ⋄ r←a rnd w ⋄ :EndIf
        ∇

        ∇ Make
          :Access public
          Options←⎕NS''
          Container←⎕NEW #.HtmlElement
          :Implements constructor
          WidgetSyntax←WidgetDef
        ∇

        ∇ r←Render;build;html;handlers;js;opts
          :Access public

          r←html←js←''
          SetUse

          _build∨←0∊⍴Selector ⍝ if the user explicitly specifies a selector, assume he's built the content himself

          :If _build
              Container.(id name type style class title)←Container.(id name type style class title){UNDEF≡⍵:⍺ ⋄ UNDEF≢⍺:⍺ ⋄ ⍵}¨⎕THIS.(id name type style class title)
              :If Container.id≡UNDEF
                  :If Container.name≢UNDEF
                      Container.id←Container.name
                  :Else
                      Container.id←SetId
                  :EndIf
              :EndIf
              Selector←'#',Container.id
          :EndIf

          handlers←''
          :If ~0∊⍴Handlers
              handlers←';',⍨∊¯1↓¨Handlers.Render
          :EndIf

          opts←{0::⍬ ⋄ 1 0≥_PageRef._Request.isAPLJax}⍬
          js←opts #.JQ.JQueryfn JQueryFn Selector Options(JavaScript,handlers)Var PreJavaScript

          :If _build≥0∊⍴Container.Content
              :Select ⊃Selector
              :Case '#' ⍝ id?
                  Container.id←1↓Selector
              :Case '.' ⍝ class?
                  Container.class←1↓Selector
              :EndSelect
              :If ContainerTag{⍵≡(⍴⍵)↑⍺}'input'
              :AndIf UNDEF≡Container.name
                  Container.name←('.#'∊⍨⊃Selector)↓Selector
              :EndIf
              Container.Tag←ContainerTag
              html←Container.Render
          :EndIf
          r←html,js
        ∇

        ∇ {handler}←On args
          :Access public
          ⍝ args - event callback clientData javascript
          handler←⎕BASE.On args
          handler.InternalEvents←InternalEvents
          handler.(WidgetDef←WidgetRef.WidgetDef)
        ∇

        ∇ {name}Set value
          :Access public
          →(0∊⍴value)⍴0
          :If 326≠⎕DR Options ⋄ Options←⎕NS'' ⋄ :EndIf
          :If 0=⎕NC'name'
              :Trap 11
                  (name value)←ParseValue value
              :Else
                  ⎕SIGNAL/⎕DMX.(EM EN)
              :EndTrap
          :EndIf
          name(Options SetOption)value
        ∇

        ∇ name SetIfNotSet value
          :Access public
          :If 0∊⍴GetOption name
              name Set value
          :EndIf
        ∇

        ∇ name(ref SetOption)value;set;parent;i;ind;newref;chunk;pos;n;now;new;chunkroot
          →(0∊⍴value)⍴0
          :If 1<|≡name ⍝ multiple names?
              value←(⊂⍣((⎕DR value)∊80 82))value
              name(ref SetOption)¨value
          :Else

              set←{⍺⍺⍎'(',⍺,')←⍵'}

              :If 0∊⍴parent←(i←-'.'⍳⍨⌽name)↓name
                  name(ref set)value ⍝ single name: assign directly (may be more than 1 name)
              :Else
                  ind←name⍳'.'
                  chunk←¯1↓ind↑name
                  (chunkroot pos)←'[]'#.Utils.penclose chunk
                  pos←2⊃⎕VFI pos
                  :Trap 3 6
                      newref←ref⍎chunk
                  :Case 3 ⍝ index error
                      n←⍴now←ref⍎chunkroot
                      new←⎕NS¨(pos-n)⍴⊂⍬
                      chunkroot(ref set)now,new
                      newref←ref⍎chunk
                  :Case 6 ⍝ value error
                      chunkroot ref.⎕NS''
                      :If ~0∊pos
                          new←⎕NS¨pos⍴⊂⍬
                          chunkroot(ref set)new
                      :EndIf
                      newref←ref⍎chunk
                  :EndTrap
                  (ind↓name)(newref SetOption)value
              :EndIf
          :EndIf
        ∇

        ∇ r←ParseValue value
          :Access shared public
          :If 2=⍴⍴value
          :AndIf 2=¯1↑⍴value
          :ElseIf 2<|≡value
          :AndIf ∧/(,2)∘≡∘⍴¨value
              value←↑value
          :ElseIf 0=2|⍴value
              value←((0.5×⍴value),2)⍴value
          :Else
              'Invalid option format'⎕SIGNAL 11
          :EndIf
          r←↓[1]value
        ∇

        ∇ r←GetOption names
          :Access public
          r←{6::'' ⋄ Options.⍎⍵}¨{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          :If 1=⍴r ⋄ r←⊃r ⋄ :EndIf ⍝ if single setting requested
        ∇

        ∇ r←name Update value;v
          :Access public
          r←name(Selector #._JQ.Update JQueryFn)value
          name Set value
        ∇
    :endclass

    :class _jqUIWidget : _jqWidget

        :field public Force←0

        :field public WidgetSyntax ←⊂'event,ui' 'event'  'ui' '$(event.target)' ⍝ see Handler class below

        ∇ make
          :Access public
          :If 0=⎕NC⊂'Uses' ⋄ Uses←'' ⋄ :EndIf
          :If 0∊⍴Uses ⋄ Uses←'JQueryUI' ⋄ :EndIf
          :Implements constructor
        ∇

        ∇ make1 pars
          :Access public
          :If 0=⎕NC⊂'Uses' ⋄ Uses←'' ⋄ :EndIf
          :If 0∊⍴Uses ⋄ Uses←'JQueryUI' ⋄ :EndIf
          :Implements constructor :base pars
        ∇

        ∇ {r}←opts RenderHandler handler
          :Access public
          r←opts ⎕BASE.RenderHandler(handler WidgetDef Force)
        ∇

    :endclass

    :class _jqUITabbedWidget : _jqUIWidget
        :field public Titles←''
        :field public Id←''
        :field public Tabs←''
        :field public Widget

        ∇ Make0
          :Access public
          :Implements constructor
          Widget←⎕NS''
          Widget._function←{}
        ∇

        ∇ Make1 pars;t
          :Access public
          :Implements constructor
          :Select |≡pars
          :Case 2
              :If 2=⍴pars ⍝ could be title/tab or title/title
                  :If (10|⎕DR t←2⊃pars)∊0 2 ⍝ if the second element is character
                  :AndIf 1=⍴⍴t ⍝ and it's a vector
                  :AndIf 20>⍴t ⍝ and it's relatively short
                      pars←,⊂pars
                  :Else
                      pars←#.HtmlElement.eis¨pars
                  :EndIf
              :EndIf
          :Case 0 1
              pars←#.HtmlElement.eis pars
          :EndSelect
          Titles Tabs Options JavaScript Var←5↑pars,(⍴pars)↓'' '' '' '' ''
          Widget←⎕NS''
          Widget._function←{}
        ∇

        ∇ r←Render;opts
          :Access public
          'Title and Contents lengths do not match'⎕SIGNAL((⍴Titles)≠⍴Tabs)/5
          opts←Options
          :If 2≤|≡Options ⋄ opts←#.JSON.toJQueryParameters Options ⋄ :EndIf
          r←Widget._function Id Titles(RenderTab¨Tabs)opts JavaScript Var
          r,←⎕BASE.Render
        ∇

        ∇ r←RenderTab tab;e;t
          :Access public
          :If 326=⎕DR tab
              r←''
              :For e :In tab
                  t←⊃e
                  :If isInstance t
                  :AndIf isHtmlElement t
                      r,←e.Render
                  :ElseIf isClass t
                  :AndIf isHtmlElement t
                      r,←(⎕NEW∘{2<⍴,⍵:(⊃⍵)(1↓⍵) ⋄ ⍵}eis e).Render
                  :Else
                      r,←e
                  :EndIf
              :EndFor
          :Else
              r←,⍕tab
          :EndIf
        ∇

    :endclass
    :endsection

⍝ --- Events ---
    :Section Events

    :Class Handler
        :Field public Selector←''        ⍝ CSS/jQuery selector to bind handler to
        :Field public Delegates←''       ⍝ See jQuery.On for information about delegates
        :Field public Events←''          ⍝ events to bind
        :Field public ClientData←''      ⍝ any additional client data to send to server
        :Field public Callback←1         ⍝ execute AJAX callback to server?  or the name of the server-side callback function
        :Field public JavaScript←''      ⍝ JavaScript to execute prior to server callback
        :Field public Page←''            ⍝ server URL to request for an AJAX callback
        :Field public jQueryWrap←1       ⍝ wrap handler in $(function(){...});
        :Field public ScriptWrap←1       ⍝ wrap handler in <script>...</script>
        :Field public WidgetDef←''       ⍝ widget definitions (e.g. jQuery or Syncfusion, others libraries may different)
                                         ⍝                                          jQuery            Syncfusion
                                         ⍝ [1] event handler syntax:                'event,ui'        'argument'
                                         ⍝ [2] syntax to access the event object:   'event'           'argument'
                                         ⍝ [3] syntax to access the object's model: 'ui'              'argument.model'
                                         ⍝ [4] syntax to access the widget itself:  '$(event.target)' 'this.element'
        :Field public ForceInternal←¯1   ⍝ indicates whether to "force" the event to be treated as a widget internal event
        :Field public WidgetRef←''       ⍝ ref to widget instance if this handler is on
        :Field public Hourglass←¯1       ⍝ indicates whether to display hourglass during callback execution
                                         ⍝ 1 - yes, 0 - no, ¯1 - only if calling back to APL

        :Field public Uses←'JQuery'

        quote←{0∊⍴⍵: '' ⋄ '⍎"'∊⍨⍬⍴⍵:⍵~'⍎' ⋄ '"',(('"' ⎕R '\\\0')⍵),'"'} ⍝ quote unless already quoted or begins with ⍎
        ine←{0∊⍴⍺:'' ⋄ ⍵} ⍝ if not empty
        eis←{(,∘⊂)⍣((326∊⎕DR ⍵)<2>|≡⍵),⍵} ⍝ Enclose if simple

        ∇ Make0
          :Access public
          :Implements constructor
          CommonSetup
        ∇

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←#.HtmlElement.eis params
          (Selector Events Callback ClientData Delegates JavaScript Page)←7↑params,(⍴params)↓7⍴⊂''
          :If #.HtmlPage #.HtmlElement.isInstance Page ⋄ Page←Page.Page ⋄ :EndIf ⍝ if request object passed
          CommonSetup
        ∇

        ∇ CommonSetup;c
          :Access public
          :Trap 0
              c←#.HtmlElement.context'_PageRef'
              :If ~0∊⍴c
                  (c⍎'_PageRef').Use Uses
              :EndIf
          :EndTrap
          WidgetDef←'event,ui' 'event' 'ui' '$(event.target)'
        ∇

        ∇ r←Render;sel;syn_handler;syn_event;syn_model;syn_this;data;useajax;force;cd;selector;arg;verb;name;phrase;datasel;JQfn;jqfn;hg;removehg;dtype;success;status;ajax;widget;syn_value;delegates;v
          :Access public
          r←''
          :If ~0∊⍴Events ⍝ skip if no events specified

              :If #.MiPage #.HtmlElement.isInstance Page
                  Page←Page._PageName
              :EndIf

              (selector delegates)←2↑(eis Selector),'' ''

              :If ~0∊⍴Delegates
                  delegates←Delegates
              :EndIf

              useajax←(,0)≢,Callback ⍝ callback=0 → don't make callback to server; =1 → use APLJax, =charvec → call ⍎charvec

              force←0
              :If widget←#.HtmlElement.isWidget WidgetRef ⍝ is this a widget handler?
                  :If ForceInternal=¯1
                      force←(⊂Events)∊WidgetRef.InternalEvents
                  :Else
                      force←ForceInternal
                  :EndIf
              :EndIf

              :If 0∊⍴selector  ⍝ empty selector → use entire page
                  :If widget
                      selector←WidgetRef.Selector
                  :ElseIf #.HtmlElement #.HtmlElement.isInstance ##
                      :If #.MiPage #.HtmlElement.isInstance ##
                          selector←'⍎document'
                      :Else
                          selector←'#',##.id
                      :EndIf
                  :Else
                      selector←'⍎document'
                  :EndIf
              :EndIf

              (syn_handler syn_event syn_model syn_this)←WidgetDef

              data←'_event: ',syn_event,'.type, '
              data,←'_what: ',syn_this,'.attr("id"), '
              data,←'_value: ',syn_this,'.val(), '
              data,←'_selector: ',(quote selector~'⍎'),', '

              :If #.HtmlElement.isString Callback ⍝ numeric Callback 1-call APLJax, 0-no callback to server
              :AndIf ~0∊⍴Callback
                  data,←'_callback: ',(quote Callback),', '
              :EndIf

              :If 0∊⍴ClientData ⍝ if you don't specify any clientdata, we serialize any forms on the page
                  data,←'_serialized: $("form").serialize(), '
              :EndIf

              data←¯2↓data

              :Select |≡ClientData

              :CaseList 0 1  ⍝ simple vector
                  ClientData←,⊂2⍴⊂ClientData ⍝ name/id are set to the same
              :Case 2
                  ClientData←,⊂ClientData
              :EndSelect

              :For cd :In ClientData
                  cd←#.HtmlElement.eis cd
                  (name verb arg sel)←4↑cd,(⍴cd)↓4⍴⊂''
                  :If ~0∊⍴name
                  :AndIf ~0∊⍴verb
                      jqfn←'' ⍝ jQuery function to call if this client data element refers to a widget

                      :If (⊂verb)∊'html' 'val'  ⍝ neither html or val take an argument
                      :AndIf 0∊⍴sel
                          sel←arg
                      :EndIf

⍝ build the selector for the data element
                      :If sel≡'' ⍝ it's for the current element/widget
                          :If #.HtmlElement.isWidget WidgetRef
                              datasel←'$(',(quote WidgetRef.Selector),').'
                              :If ~0∊⍴jqfn←WidgetRef.JQueryFn
                                  datasel,←WidgetRef.JQueryFn
                              :EndIf
                          :Else
                              datasel←syn_this,'.'
                          :EndIf
                      :ElseIf #.HtmlElement #.HtmlElement.isInstance sel ⍝ selector is reference to other element
                          :If #._JQ._jqObject #.HtmlElement.isInstance sel ⍝ is it a jQuery-based object?
                              :If 0∊⍴sel.Selector ⍝ no Selector?
                                  sel.SetId
                                  sel.Selector←'#',sel.id
                              :EndIf
                              datasel←'$(',(quote sel.Selector),').'
                              :If ~0∊⍴jqfn←sel.JQueryFn
                                  datasel,←sel.JQueryFn
                              :EndIf
                          :Else ⍝ not a jQuery-based object
                              sel.SetId
                              datasel←'$(',(quote'#',sel.id),').'
                          :EndIf
                      :Else ⍝ sel is not an HtmlElement
                          :Select |≡sel
                          :CaseList 0 1
                              datasel←'$(',(quote sel),').'
                          :Case 2
                              datasel←'$(',(quote(1⊃sel)),').',jqfn←2⊃sel
                          :EndSelect
                      :EndIf

⍝ now figure out what data to generate
                      phrase←''
                      :Select verb

                      :CaseList 'attr' 'css' 'is' 'prop'
                          datasel,←'().'/⍨~0∊⍴jqfn
                          phrase←datasel,verb,'(',(quote arg),')'

                      :CaseList 'html' 'val'
                          datasel,←'().'/⍨~0∊⍴jqfn
                          phrase←datasel,verb,'()'

                      :Case 'option' ⍝ jQueryUI and Syncfusion widgets
                          :If 0∊⍴arg
                              phrase←'JSON.stringify(',datasel,'("option"))'
                          :Else
                              phrase←datasel,'("option",',(quote arg),')'
                          :EndIf

                      :CaseList 'event' 'this'
                          v←('event' 'this'⍳⊂verb)⊃syn_event syn_this
                          :If 0∊⍴arg
                              phrase←'JSON.stringify(',v,')'
                          :Else
                              phrase←v,'.',arg
                          :EndIf

                      :Case 'model' ⍝ widgets only
                          :If ~0∊⍴jqfn
                              datasel,←'().'
                              :If 0∊⍴arg
                                  phrase←'JSON.stringify(',syn_model,')'
                              :Else
                                  phrase←syn_model,'.',arg
                              :EndIf
                          :EndIf

                      :Case 'eval'
                          sel←'' ⍝ ignore selector on eval
                          phrase←'eval(',(quote arg),')'

⍝                      :CaseList syn_event syn_model syn_this
⍝                          :If ~0∊⍴jqfn ⍝ these verbs only apply to widgets
⍝                              :If 0∊⍴arg
⍝                                  phrase←'JSON.stringify(',verb,')'
⍝                              :Else
⍝                                  phrase←verb,'.',arg
⍝                              :EndIf
⍝                          :EndIf

                      :Case 'string'
                          phrase←quote arg

                      :Case 'serialize'
                          :If 0∊⍴sel
                              :If 0∊⍴arg
                                  sel←'form'
                              :Else
                                  sel←arg
                              :EndIf
                          :EndIf
                          phrase←'$(',(quote sel),').serialize()'
                          name,←'_serialized'
                      :Else
                          #.Boot.Log'Unknown event handler verb: "',verb,'"',{0::'' ⋄ ' on page ',##._PageRef._PageName}⍬
                          phrase←quote phrase
                      :EndSelect

                      data,←',',name,': ',phrase
                  :EndIf
              :EndFor

              (hg removehg)←((1+Hourglass=¯1)⊃Hourglass useajax)∘{⍺:'document.body.style.cursor="',⍵,'";' ⋄ ''}¨'wait' 'default'

              dtype←'"json"'
              success←'success: function(obj){APLJaxReturn(obj);document.body.style.cursor="default";}'
              status←'statusCode:{ 408: function(){alert("Session timed out");',removehg,'}}'
              ajax←(JavaScript ine JavaScript,';'),useajax/hg,'$.ajax({url: ',(quote Page),', cache: false, type: "POST", dataType: ',dtype,', data: {',data,'}, ',success,', ',status,'});'

              :If widget
                  :If force
                      Events(WidgetRef.Options{⍺⍺⍎⍺,'←⍵'})'function(',syn_handler,'){',ajax,'}'
                  :Else
                      r←'.on(',(quote Events),', function(event,ui){',ajax,'});'
                  :EndIf
              :Else
                  r←'$(',(quote selector),').on(',(quote Events),(delegates ine', ',quote delegates),', function(event,ui){',ajax,'});'
                  :If jQueryWrap ⋄ r←'$(function(){',r,'});' ⋄ :EndIf
                  :If ScriptWrap ⋄ r←#.HTMLInput.JS r ⋄ :EndIf
              :EndIf
          :EndIf
        ∇

    :endclass
    :endsection

:EndNamespace


id/name fix for _HTML.(Datalist Select)

id/name fix for _HTML.(Datalist Select)

:Namespace _HTML

    :class Form : #._html.form

        :field public Method←'post'
        :field public Action←''
        :field public Serialize←0

        ∇ make;c
          :Access public
          :Implements constructor
          :If {6::0 ⋄ ''≢c∘←##.context ⍵}'_Request'
              Action←c._Request.Page
          :EndIf
        ∇

        ∇ make1 action
          :Access public
          :Implements constructor
          Action←action
        ∇

        ∇ r←Render
          :Access public
          Attr['action' 'method']←Action Method
          r←⎕BASE.Render
        ∇
    :endclass

    :class Select : #._html.select
        :field public Options←0 2⍴⊂''  ⍝ vector or matrix [;1] display, [;2] value

        ∇ make
          :Access public
          :Implements constructor
        ∇

        ∇ make1 args;attr
          :Access public
          :Implements constructor
          args←eis args
          (name Options attr)←3↑args,(⍴args)↓UNDEF'' ''
          SetAttr attr
        ∇

        ∇ r←Render
          :Access public
          :If name≡UNDEF
              name←id
          :ElseIf id≡UNDEF
              id←name
          :EndIf
          :If ~0∊⍴Options
              :If 1=⍴⍴Options
                  Options←Options,⍪Options
              :EndIf
              Add∊{'<option value="',(HtmlSafeText ⍵),'">',(⍕⍺),'</option>'}/¨↓Options
              ⍝{(Add #._html.option ⍺).value←⍵}/¨↓Options
          :EndIf
          r←⎕BASE.Render
        ∇
    :endclass

    :class Datalist : #._html.input
        :field public Options←0 2⍴⊂''

        ∇ make
          :Access public
          :Implements constructor
        ∇

        ∇ make1 args;attr
          :Access public
          :Implements constructor
          args←eis args
          (name Options attr)←3↑args,(⍴args)↓UNDEF'' ''
          SetAttr attr
        ∇

        ∇ r←Render;dl
          :Access public
          :If name≡UNDEF
          :AndIf id≢UNDEF
              name←id
          :ElseIf id≡UNDEF
              id←name
          :EndIf
          :If ~0∊⍴Options
              :If 1=⍴⍴Options
                  Options←Options,⍪Options
              :EndIf
              (dl←Add #._html.datalist).id←name,'_datalist'
              dl.Add∊{'<option value="',(HtmlSafeText ⍵),'">',(⍕⍺),'</option>'}/¨↓Options
              ⍝{(dl.Add #._html.option ⍺).value←⍵}/¨↓Options
              'list'SetAttr dl.id
          :EndIf
          r←⎕BASE.Render
        ∇

    :endclass

    :class InputSubmit : #._html.input

        ∇ Make
          :Access public
          :Implements constructor :base
          (name value)←'submit' 'submit'
          SetAttr('type' 'submit')
        ∇

        ∇ Make1 args;n;v
          :Access public
          :Implements constructor :base
          args←eis args
          (n v)←2↑args,(⍴args)↓'submit' 'submit'
          (name value)←n v
          SetAttr('type' 'submit')
        ∇
    :endclass

    :class Input : #._html.input

        :field public Label←''

        ∇ Make1 args;l;n;t;v
          :Access public
          :Implements constructor
          args←eis args
          t n v l←4↑args,(⍴args)↓'text' '' '' ''
          (type value Label)←t v l
          :If ~0∊⍴n ⋄ name←id←n ⋄ :EndIf
        ∇

        ∇ html←Render
          :Access public
          html←''
          :If ~0∊⍴Label
              :If id≡⎕NULL ⋄ id←'gen',⍕?1000 ⋄ :EndIf
              html,←'<label for="',(⍕id),'">',Label,'</label>'
          :EndIf
          html,←⎕BASE.Render
        ∇
    :endclass

    :class InputGrid : #._html.table

        :field public Border←0
        :field public Labels←''
        :field public Inputs←''
        :field public Headings←''

        ∇ html←Render;cells;rows
          :Access public
          cells←{⎕NEW #._html.td(⍵)}¨renderIt¨Labels,[1.1]Inputs
          cells[;1].style←⊂'text-align:right'
          rows←⎕NEW¨(⊃⍴cells)⍴#._html.tr
          rows.Add↓cells
          Content←rows.Render
          SetAttr'border'(⍕Border)
          html←⎕BASE.Render
        ∇
    :endclass

    :class EditField : #._html.input

        ∇ make1 nm
          :Access public
          :Implements constructor
          name←nm
          id←name
          type←'text'
        ∇
        ∇ make2(nm val)
          :Access public
          :Implements constructor
          :If ~1=≡name←nm val    ⍝ handle 2-character names
              (name value)←nm val
          :EndIf
          id←name
          type←'text'
        ∇
        ∇ make3(nm val att)
          :Access public
          :Implements constructor
          :If ~1=≡name←nm val att    ⍝ handle 3-character names
              (name value)←nm val
              SetAttr att
          :EndIf
          id←name
          type←'text'
        ∇
    :endclass

    :class Button : #._html.button

        :field _content←''

        ∇ Make0
          :Access public
          :Implements constructor :base
          SetAttr('type' 'button')
        ∇

        ∇ Make args;n;v
          :Access public
          :Implements constructor :base
          ⍝ arguments are name value {content}
          args←eis args
          (n v _content)←3↑args,(⍴args)↓'button' 'button' ''
          :If 0∊⍴_content ⋄ _content←v ⋄ :EndIf
          (name value)←n v
          id←name
          SetAttr('type' 'button')
        ∇

        ∇ html←Render
          :Access public
          :If 0∊⍴Content
              Content←_content
          :EndIf
          html←⎕BASE.Render
        ∇

    :endclass

    :class Script : #._html.script

        :field public File←''
        :field public Code←''

        ∇ Make0
          :Access public
          :Implements constructor
          SetAttr'type="text/javascript"'
        ∇

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←eis params
          Code File←2↑params,(⍴params)↓'' ''
          SetAttr'type="text/javascript"'
        ∇

        ∇ html←Render
          :Access public
          :If ~0∊⍴File
              SetAttr('src'File)
          :ElseIf ~0∊⍴Code
              Content←Code
          :EndIf
          html←⎕BASE.Render
        ∇

    :endclass

    :class Style : #._html.style

        :field public Selector←''
        :field public Styles←''

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←eis params
          (Selector Styles)←2↑params,(⍴params)↓'' ''
        ∇

        ∇ html←Render
          :Access public
          Content←Selector,#.HTMLUtils.Styles Styles
          html←⎕BASE.Render
        ∇
    :endclass

    :class StyleSheet : #._html.link

        :field public href←''

        ∇ Make1 params
          :Access public
          :Implements constructor
          href←params
        ∇

        ∇ html←Render
          :Access public
          SetAttr(('href'href)('rel' 'stylesheet')('type' 'text/css'))
          html←⎕BASE.Render
        ∇
    :endclass

    :class Table : #._html.table
        :field public Data←0 0⍴⊂''
        :field public CellAttr←''
        :field public HeaderRows←0
        :field public HeaderAttr←''
        :field public MakeCellIds←0
        :field public MakeRowIds←0

        ∇ Make0
          :Access public
          :Implements constructor
        ∇

        ∇ Make1 data
          :Access public
          :Implements constructor
          :If 1<⍴⍴data ⋄ data←,⊂data ⋄ :EndIf
          (Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)←6↑data,(⍴data)↓Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
        ∇

        ∇ html←Render;data;atts;tda;tha;hdrrows;cellids;rowids;rows;x;head;body;table;thead;tbody
          :Access public
          data tda tha hdrrows cellids rowids←Data CellAttr HeaderAttr HeaderRows MakeCellIds MakeRowIds
          hdrrows←⍬⍴hdrrows
          data←((rows←×/¯1↓⍴data),¯1↑⍴data)⍴data
          head←body←(0 1×⍴data)⍴⊂''
          :If 0≠hdrrows
              head←{⎕NEW #._html.th ⍵}¨hdrrows↑data
              :If cellids
                  head.id←{∊'rc',¨⍕¨⍵}¨⍳⍴head
              :EndIf
              :If ~0∊⍴tha
                  head.SetAttr¨(⍴head)⍴⊂¨eis tha
              :EndIf
          :EndIf
          :If 0<(⊃⍴data)-hdrrows
              body←{⎕NEW #._html.td ⍵}¨hdrrows↓data
              :If cellids
                  body.id←{∊'rc',¨⍕¨⍵}¨hdrrows↓⍳⍴data
              :EndIf
              :If ~0∊⍴tda
                  body.SetAttr¨(⍴body)⍴⊂¨eis tda
              :EndIf
          :EndIf
          (table←⎕NEW¨rows⍴#._html.tr).Add↓head⍪body
          :If rowids
              table.id←{'row',⍕⍵}⍳rows
          :EndIf
          thead←tbody←''
          :If 0≠hdrrows
              (thead←⎕NEW #._html.thead).Add hdrrows↑table
          :EndIf
          :If 0<(⊃⍴data)-hdrrows
              (tbody←⎕NEW #._html.tbody).Add hdrrows↓table
          :EndIf
          Content←thead,tbody
          html←⎕BASE.Render
        ∇
    :endclass

:EndNamespace

:Namespace _HTML

    :class Form : #._html.form

        :field public Method←'post'
        :field public Action←''
        :field public Serialize←0

        ∇ make;c
          :Access public
          :Implements constructor
          :If {6::0 ⋄ ''≢c∘←##.context ⍵}'_Request'
              Action←c._Request.Page
          :EndIf
        ∇

        ∇ make1 action
          :Access public
          :Implements constructor
          Action←action
        ∇

        ∇ r←Render
          :Access public
          Attr['action' 'method']←Action Method
          r←⎕BASE.Render
        ∇
    :endclass

    :class Select : #._html.select
        :field public Options←0 2⍴⊂''  ⍝ vector or matrix [;1] display, [;2] value

        ∇ make
          :Access public
          :Implements constructor
        ∇

        ∇ make1 args;attr
          :Access public
          :Implements constructor
          args←eis args
          (name Options attr)←3↑args,(⍴args)↓UNDEF'' ''
          SetAttr attr
        ∇

        ∇ r←Render
          :Access public
          :If name≡UNDEF
              name←id
          :EndIf
          :If ~0∊⍴Options
              :If 1=⍴⍴Options
                  Options←Options,⍪Options
              :EndIf
              Add∊{'<option value="',(HtmlSafeText ⍵),'">',(⍕⍺),'</option>'}/¨↓Options
              ⍝{(Add #._html.option ⍺).value←⍵}/¨↓Options
          :EndIf
          r←⎕BASE.Render
        ∇
    :endclass

    :class Datalist : #._html.input
        :field public Options←0 2⍴⊂''

        ∇ make
          :Access public
          :Implements constructor
        ∇

        ∇ make1 args;attr
          :Access public
          :Implements constructor
          args←eis args
          (name Options attr)←3↑args,(⍴args)↓UNDEF'' ''
          SetAttr attr
        ∇

        ∇ r←Render;dl
          :Access public
          :If name≡UNDEF
          :AndIf id≢UNDEF
              name←id
          :EndIf
          :If ~0∊⍴Options
              :If 1=⍴⍴Options
                  Options←Options,⍪Options
              :EndIf
              (dl←Add #._html.datalist).id←name,'_datalist'
              dl.Add∊{'<option value="',(HtmlSafeText ⍵),'">',(⍕⍺),'</option>'}/¨↓Options
              ⍝{(dl.Add #._html.option ⍺).value←⍵}/¨↓Options
              'list'SetAttr dl.id
          :EndIf
          r←⎕BASE.Render
        ∇

    :endclass

    :class InputSubmit : #._html.input

        ∇ Make
          :Access public
          :Implements constructor :base
          (name value)←'submit' 'submit'
          SetAttr('type' 'submit')
        ∇

        ∇ Make1 args;n;v
          :Access public
          :Implements constructor :base
          args←eis args
          (n v)←2↑args,(⍴args)↓'submit' 'submit'
          (name value)←n v
          SetAttr('type' 'submit')
        ∇
    :endclass

    :class Input : #._html.input

        :field public Label←''

        ∇ Make1 args;l;n;t;v
          :Access public
          :Implements constructor
          args←eis args
          t n v l←4↑args,(⍴args)↓'text' '' '' ''
          (type value Label)←t v l
          :If ~0∊⍴n ⋄ name←id←n ⋄ :EndIf
        ∇

        ∇ html←Render
          :Access public
          html←''
          :If ~0∊⍴Label
              :If id≡⎕NULL ⋄ id←'gen',⍕?1000 ⋄ :EndIf
              html,←'<label for="',(⍕id),'">',Label,'</label>'
          :EndIf
          html,←⎕BASE.Render
        ∇
    :endclass

    :class InputGrid : #._html.table

        :field public Border←0
        :field public Labels←''
        :field public Inputs←''
        :field public Headings←''

        ∇ html←Render;cells;rows
          :Access public
          cells←{⎕NEW #._html.td(⍵)}¨renderIt¨Labels,[1.1]Inputs
          cells[;1].style←⊂'text-align:right'
          rows←⎕NEW¨(⊃⍴cells)⍴#._html.tr
          rows.Add↓cells
          Content←rows.Render
          SetAttr'border'(⍕Border)
          html←⎕BASE.Render
        ∇
    :endclass

    :class EditField : #._html.input

        ∇ make1 nm
          :Access public
          :Implements constructor
          name←nm
          id←name
          type←'text'
        ∇
        ∇ make2(nm val)
          :Access public
          :Implements constructor
          :If ~1=≡name←nm val    ⍝ handle 2-character names
              (name value)←nm val
          :EndIf
          id←name
          type←'text'
        ∇
        ∇ make3(nm val att)
          :Access public
          :Implements constructor
          :If ~1=≡name←nm val att    ⍝ handle 3-character names
              (name value)←nm val
              SetAttr att
          :EndIf
          id←name
          type←'text'
        ∇
    :endclass

    :class Button : #._html.button

        :field _content←''

        ∇ Make0
          :Access public
          :Implements constructor :base
          SetAttr('type' 'button')
        ∇

        ∇ Make args;n;v
          :Access public
          :Implements constructor :base
          ⍝ arguments are name value {content}
          args←eis args
          (n v _content)←3↑args,(⍴args)↓'button' 'button' ''
          :If 0∊⍴_content ⋄ _content←v ⋄ :EndIf
          (name value)←n v
          id←name
          SetAttr('type' 'button')
        ∇

        ∇ html←Render
          :Access public
          :If 0∊⍴Content
              Content←_content
          :EndIf
          html←⎕BASE.Render
        ∇

    :endclass

    :class Script : #._html.script

        :field public File←''
        :field public Code←''

        ∇ Make0
          :Access public
          :Implements constructor
          SetAttr'type="text/javascript"'
        ∇

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←eis params
          Code File←2↑params,(⍴params)↓'' ''
          SetAttr'type="text/javascript"'
        ∇

        ∇ html←Render
          :Access public
          :If ~0∊⍴File
              SetAttr('src'File)
          :ElseIf ~0∊⍴Code
              Content←Code
          :EndIf
          html←⎕BASE.Render
        ∇

    :endclass

    :class Style : #._html.style

        :field public Selector←''
        :field public Styles←''

        ∇ Make1 params
          :Access public
          :Implements constructor
          params←eis params
          (Selector Styles)←2↑params,(⍴params)↓'' ''
        ∇

        ∇ html←Render
          :Access public
          Content←Selector,#.HTMLUtils.Styles Styles
          html←⎕BASE.Render
        ∇
    :endclass

    :class StyleSheet : #._html.link

        :field public href←''

        ∇ Make1 params
          :Access public
          :Implements constructor
          href←params
        ∇

        ∇ html←Render
          :Access public
          SetAttr(('href'href)('rel' 'stylesheet')('type' 'text/css'))
          html←⎕BASE.Render
        ∇
    :endclass

    :class Table : #._html.table
        :field public Data←0 0⍴⊂''
        :field public CellAttr←''
        :field public HeaderRows←0
        :field public HeaderAttr←''
        :field public MakeCellIds←0
        :field public MakeRowIds←0

        ∇ Make0
          :Access public
          :Implements constructor
        ∇

        ∇ Make1 data
          :Access public
          :Implements constructor
          :If 1<⍴⍴data ⋄ data←,⊂data ⋄ :EndIf
          (Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds)←6↑data,(⍴data)↓Data CellAttr HeaderRows HeaderAttr MakeCellIds MakeRowIds
        ∇

        ∇ html←Render;data;atts;tda;tha;hdrrows;cellids;rowids;rows;x;head;body;table;thead;tbody
          :Access public
          data tda tha hdrrows cellids rowids←Data CellAttr HeaderAttr HeaderRows MakeCellIds MakeRowIds
          hdrrows←⍬⍴hdrrows
          data←((rows←×/¯1↓⍴data),¯1↑⍴data)⍴data
          head←body←(0 1×⍴data)⍴⊂''
          :If 0≠hdrrows
              head←{⎕NEW #._html.th ⍵}¨hdrrows↑data
              :If cellids
                  head.id←{∊'rc',¨⍕¨⍵}¨⍳⍴head
              :EndIf
              :If ~0∊⍴tha
                  head.SetAttr¨(⍴head)⍴⊂¨eis tha
              :EndIf
          :EndIf
          :If 0<(⊃⍴data)-hdrrows
              body←{⎕NEW #._html.td ⍵}¨hdrrows↓data
              :If cellids
                  body.id←{∊'rc',¨⍕¨⍵}¨hdrrows↓⍳⍴data
              :EndIf
              :If ~0∊⍴tda
                  body.SetAttr¨(⍴body)⍴⊂¨eis tda
              :EndIf
          :EndIf
          (table←⎕NEW¨rows⍴#._html.tr).Add↓head⍪body
          :If rowids
              table.id←{'row',⍕⍵}⍳rows
          :EndIf
          thead←tbody←''
          :If 0≠hdrrows
              (thead←⎕NEW #._html.thead).Add hdrrows↑table
          :EndIf
          :If 0<(⊃⍴data)-hdrrows
              (tbody←⎕NEW #._html.tbody).Add hdrrows↓table
          :EndIf
          Content←thead,tbody
          html←⎕BASE.Render
        ∇
    :endclass

:EndNamespace


Added _JSS.RemoveClass

Added _JSS.RemoveClass

:Namespace _JSS ⍝ Javascript Snippets

    (⎕ML ⎕IO)←1
⍝ this list will grow over time as usage patterns are discovered
    eis←{(,∘⊂)⍣((326∊⎕DR ⍵)<2>|≡⍵),⍵} ⍝ Enclose if simple
    quote←{0∊⍴⍵: '' ⋄ '"',(('"' ⎕R '\\\0')⍕⍵),'"'}
    ine←{0∊⍴⍺:'' ⋄ ⍵} ⍝ if not empty
    fmtSelector←{{'this'≡⍵:⍵ ⋄quote ⍵}¯2↓∊{⍵,', '}¨eis ⍵}
    fmtData←#.JSON.fromAPL ⍝ {{(326=⍵)<0=2|⍵}⎕DR ⍵:quote ⍵ ⋄ ⍕⍵}
    JAchars←#.JSON.JAchars

    ∇ r←Alert txt
    ⍝ popup alert text
      r←'alert(',(quote txt),');'
    ∇

    ∇ r←CloseWindow
    ⍝ close the browser window
      r←'var w=window.open(window.location,''_self''); w.close();'
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      r←(sel JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      r←(sel JQuery'val')args
    ∇

    ∇ r←sel Prop args ⍝ JQuery prop cover
      r←(sel JQuery'prop')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      r←(sel JQuery'attr')args
    ∇

    ∇ r←sel RemoveClass args
      r←(sel JQuery'removeClass')args
    ∇

    ∇ r←sel RemoveAttr args
      r←(sel JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      r←(sel JQuery'html')args
    ∇

    ∇ r←sel Show args
      r←(sel JQuery'show')args
    ∇

    ∇ r←sel Hide args
      r←(sel JQuery'hide')args
    ∇

    ∇ r←sel Toggle args
      r←(sel JQuery'toggle')args
    ∇

    ∇ r←sel Trigger args
      r←(sel JQuery'trigger')args
    ∇

    ∇ r←Submit sel
      r←(sel JQuery'submit')''
    ∇

    ∇ r←sel Position args;Position;inds;parameters;q;mask
      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      Position←⎕NS ⍬
      :If 2=⍴⍴args ⍝ matrix
          args←,args
      :ElseIf 3=≡args
          args←⊃,/args
      :EndIf
      args←eis args
      inds←parameters⍳args
      :If ∨/mask←inds≤⍴parameters
          :If mask≡(2×+/mask)⍴1 0
              parameters←mask/args
              args←(1⌽mask)/args
          :EndIf
      :Else
          parameters←(⍴args)↑parameters
      :EndIf
      mask←⍬∘≢¨args
      args←mask/args
      parameters←mask/parameters
      parameters({⍎'Position.',⍺,'←',q ⍵})¨args
      :If ~0∊⍴Position.⎕NL-2
          r←0 #.JQ.JQueryfn'position'sel Position
      :EndIf
    ∇

    ∇ r←{eval}JSDate date
    ⍝ snippet to create a JS date (JavaScript months are 0-11!!!)
    ⍝ date is in 6↑⎕TS form
    ⍝ eval is optional Boolean to indicate whether to prepend '⍎' to the snippet (default is 0=do not prepend)
    ⍝         prepending ⍎ tells MiServer that this is an executable phrase and not simply a string

      :If 0=⎕NC'eval' ⋄ eval←0 ⋄ :EndIf
      :If 0 2∊⍨10|⎕DR date  ⍝ char?
          date←'"',date,'"'
      :Else
          date←1↓∊','∘,∘⍕¨0 ¯1 0 0 0 0+6↑date
      :EndIf
⍝      r←(~eval)↓'⍎new Date(',date,')'
⍝ ⍝ 180221, MBaas: ⍎ no longer supported
      :If eval
          r←⊂'new Date(',date,')'
      :Else
          r←'new Date(',date,')'
      :EndIf
    ∇

    ∇ r←{varname}JSData data
    ⍝ return var definition to build a JavaScript object based on data
    ⍝ varname is the name of the variable
    ⍝ data is either a matrix of [1;] column names, (1↓) data
    ⍝      or a vector of namespaces
      :If 0=⎕NC'varname' ⋄ varname←'' ⋄ :EndIf
      :If 2=⍴⍴data
          data←#.JSON.fromTable data
      :EndIf
      r←(((~0∊⍴varname)/'var ',varname,' = '),0 0 1 #.JSON.fromAPL data),';'
    ∇

    ∇ r←{val}(sel JQuery fn)args;opt
    ⍝ construct JavaScript to call a jQuery function - eg val(), html(), css(), prop(), or attr()
    ⍝ optionally setting a value for
    ⍝ Get a jQuery parameter:
    ⍝    ('"#id"' JQuery 'attr') '"data-role"'
    ⍝ Set a jQuery parameter:
    ⍝    '"blue"' ('#id' JQuery 'css') 'background-color'
    ⍝
      args←eis args
      :If 0=⎕NC'val'
          (opt val)←2↑args,(⍴args)↓''⎕NULL
      :Else
          opt←⊃args
      :EndIf
      :If val≡⎕NULL
          r←'$(',(fmtSelector sel),').',fn,'(',(quote opt),');'
      :Else
          r←'$(',(fmtSelector sel),').',fn,'(',(quote opt),',',(fmtData val),');'
      :EndIf
    ∇

    ∇ r←{val}(fn JQueryOpt sel)opt
      :If 0=⎕NC'val'
          r←'$(',(fmtSelector sel),').',fn,'("option",',(quote opt),');'
      :Else
          r←'$(',(fmtSelector sel),').',fn,'("option",',(quote opt),',',(fmtData val),');'
      :EndIf
    ∇

    :Class StorageObject
    ⍝ !!!Prototype!!!

        ∇ r←{what}Set(type value);name;w;v
          :Access public shared
        ⍝ value may be
          :Access public shared
          r←''
          :If 9.1=⎕NC⊂'value' ⍝ namespace?
              :For name :In value.⎕NL-2
                  r,←formatSet(type name(value⍎name))
              :EndFor
          :Else
              value←eis value
              :If 2=⎕NC'what' ⍝ value is list of name value pairs
                  what←eis what
              :Else
                  (what value)←↓[1]((⌊0.5×⍴value),2)⍴value
              :EndIf
              :For (w v) :InEach (what value)
                  r,←formatSet(type w v)
              :EndFor
          :EndIf
        ∇

        ∇ r←formatSet(type what value)
          :Access public shared
          r←type,'.setItem("',what,'",JSON.stringify(',(#.JSON.fromAPL value),');'
        ∇

        ∇ r←type Remove what;w;ww
          :Access public shared
          what←eis what
          r←''
          :For w :In what
              :If ' '∊w←#.Strings.deb w
                  :For ww :In ' '#.Utils.penclose w
                      r,←type,'.removeItem("',w,'");'
                  :EndFor
              :Else
                  r,←type,'.removeItem("',w,'");'
              :EndIf
          :EndFor
        ∇

        ∇ r←type Get what
          :Access public shared
          r←''
          r,←'<input type="hidden" name="',w,'" value="',JSON
        ∇
    :endclass

    :class localStorage : StorageObject

        ∇ r←{what}Set value
          :If 0=⎕NC'what'
              r←⎕BASE.Set('localStorage'value)
          :Else
              r←what ⎕BASE.Set('localStorage'value)
          :EndIf
        ∇

        ∇ r←Remove what
          :Access public shared
          r←
        ∇

        ∇ r←{name}Get what
          :Access public shared
        ∇

    :EndClass

    :Class sessionStorage
        ∇ r←{what}Set value
          :Access public shared
        ∇
    :endclass

    :class sessionStorage
    :endclass

:EndNamespace

:Namespace _JSS ⍝ Javascript Snippets

    (⎕ML ⎕IO)←1
⍝ this list will grow over time as usage patterns are discovered
    eis←{(,∘⊂)⍣((326∊⎕DR ⍵)<2>|≡⍵),⍵} ⍝ Enclose if simple
    quote←{0∊⍴⍵: '' ⋄ '"',(('"' ⎕R '\\\0')⍕⍵),'"'}
    ine←{0∊⍴⍺:'' ⋄ ⍵} ⍝ if not empty
    fmtSelector←{{'this'≡⍵:⍵ ⋄quote ⍵}¯2↓∊{⍵,', '}¨eis ⍵}
    fmtData←#.JSON.fromAPL ⍝ {{(326=⍵)<0=2|⍵}⎕DR ⍵:quote ⍵ ⋄ ⍕⍵}
    JAchars←#.JSON.JAchars

    ∇ r←Alert txt
    ⍝ popup alert text
      r←'alert(',(quote txt),');'
    ∇

    ∇ r←CloseWindow
    ⍝ close the browser window
      r←'var w=window.open(window.location,''_self''); w.close();'
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      r←(sel JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      r←(sel JQuery'val')args
    ∇

    ∇ r←sel Prop args ⍝ JQuery prop cover
      r←(sel JQuery'prop')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      r←(sel JQuery'attr')args
    ∇

    ∇ r←sel RemoveAttr args
      r←(sel JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      r←(sel JQuery'html')args
    ∇

    ∇ r←sel Show args
      r←(sel JQuery'show')args
    ∇

    ∇ r←sel Hide args
      r←(sel JQuery'hide')args
    ∇

    ∇ r←sel Toggle args
      r←(sel JQuery'toggle')args
    ∇

    ∇ r←sel Trigger args
      r←(sel JQuery'trigger')args
    ∇

    ∇ r←Submit sel
      r←(sel JQuery'submit')''
    ∇

    ∇ r←sel Position args;Position;inds;parameters;q;mask
      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      Position←⎕NS ⍬
      :If 2=⍴⍴args ⍝ matrix
          args←,args
      :ElseIf 3=≡args
          args←⊃,/args
      :EndIf
      args←eis args
      inds←parameters⍳args
      :If ∨/mask←inds≤⍴parameters
          :If mask≡(2×+/mask)⍴1 0
              parameters←mask/args
              args←(1⌽mask)/args
          :EndIf
      :Else
          parameters←(⍴args)↑parameters
      :EndIf
      mask←⍬∘≢¨args
      args←mask/args
      parameters←mask/parameters
      parameters({⍎'Position.',⍺,'←',q ⍵})¨args
      :If ~0∊⍴Position.⎕NL-2
          r←0 #.JQ.JQueryfn'position'sel Position
      :EndIf
    ∇

    ∇ r←{eval}JSDate date
    ⍝ snippet to create a JS date (JavaScript months are 0-11!!!)
    ⍝ date is in 6↑⎕TS form
    ⍝ eval is optional Boolean to indicate whether to prepend '⍎' to the snippet (default is 0=do not prepend)
    ⍝         prepending ⍎ tells MiServer that this is an executable phrase and not simply a string

      :If 0=⎕NC'eval' ⋄ eval←0 ⋄ :EndIf
      :If 0 2∊⍨10|⎕DR date  ⍝ char?
          date←'"',date,'"'
      :Else
          date←1↓∊','∘,∘⍕¨0 ¯1 0 0 0 0+6↑date
      :EndIf
⍝      r←(~eval)↓'⍎new Date(',date,')'
⍝ ⍝ 180221, MBaas: ⍎ no longer supported
      :If eval
          r←⊂'new Date(',date,')'
      :Else
          r←'new Date(',date,')'
      :EndIf
    ∇

    ∇ r←{varname}JSData data
    ⍝ return var definition to build a JavaScript object based on data
    ⍝ varname is the name of the variable
    ⍝ data is either a matrix of [1;] column names, (1↓) data
    ⍝      or a vector of namespaces
      :If 0=⎕NC'varname' ⋄ varname←'' ⋄ :EndIf
      :If 2=⍴⍴data
          data←#.JSON.fromTable data
      :EndIf
      r←(((~0∊⍴varname)/'var ',varname,' = '),0 0 1 #.JSON.fromAPL data),';'
    ∇

    ∇ r←{val}(sel JQuery fn)args;opt
    ⍝ construct JavaScript to call a jQuery function - eg val(), html(), css(), prop(), or attr()
    ⍝ optionally setting a value for
    ⍝ Get a jQuery parameter:
    ⍝    ('"#id"' JQuery 'attr') '"data-role"'
    ⍝ Set a jQuery parameter:
    ⍝    '"blue"' ('#id' JQuery 'css') 'background-color'
    ⍝
      args←eis args
      :If 0=⎕NC'val'
          (opt val)←2↑args,(⍴args)↓''⎕NULL
      :Else
          opt←⊃args
      :EndIf
      :If val≡⎕NULL
          r←'$(',(fmtSelector sel),').',fn,'(',(quote opt),');'
      :Else
          r←'$(',(fmtSelector sel),').',fn,'(',(quote opt),',',(fmtData val),');'
      :EndIf
    ∇

    ∇ r←{val}(fn JQueryOpt sel)opt
      :If 0=⎕NC'val'
          r←'$(',(fmtSelector sel),').',fn,'("option",',(quote opt),');'
      :Else
          r←'$(',(fmtSelector sel),').',fn,'("option",',(quote opt),',',(fmtData val),');'
      :EndIf
    ∇

    :Class StorageObject
    ⍝ !!!Prototype!!!

        ∇ r←{what}Set(type value);name;w;v
          :Access public shared
        ⍝ value may be
          :Access public shared
          r←''
          :If 9.1=⎕NC⊂'value' ⍝ namespace?
              :For name :In value.⎕NL-2
                  r,←formatSet(type name(value⍎name))
              :EndFor
          :Else
              value←eis value
              :If 2=⎕NC'what' ⍝ value is list of name value pairs
                  what←eis what
              :Else
                  (what value)←↓[1]((⌊0.5×⍴value),2)⍴value
              :EndIf
              :For (w v) :InEach (what value)
                  r,←formatSet(type w v)
              :EndFor
          :EndIf
        ∇

        ∇ r←formatSet(type what value)
          :Access public shared
          r←type,'.setItem("',what,'",JSON.stringify(',(#.JSON.fromAPL value),');'
        ∇

        ∇ r←type Remove what;w;ww
          :Access public shared
          what←eis what
          r←''
          :For w :In what
              :If ' '∊w←#.Strings.deb w
                  :For ww :In ' '#.Utils.penclose w
                      r,←type,'.removeItem("',w,'");'
                  :EndFor
              :Else
                  r,←type,'.removeItem("',w,'");'
              :EndIf
          :EndFor
        ∇

        ∇ r←type Get what
          :Access public shared
          r←''
          r,←'<input type="hidden" name="',w,'" value="',JSON
        ∇
    :endclass

    :class localStorage : StorageObject

        ∇ r←{what}Set value
          :If 0=⎕NC'what'
              r←⎕BASE.Set('localStorage'value)
          :Else
              r←what ⎕BASE.Set('localStorage'value)
          :EndIf
        ∇

        ∇ r←Remove what
          :Access public shared
          r←
        ∇

        ∇ r←{name}Get what
          :Access public shared
        ∇

    :EndClass

    :Class sessionStorage
        ∇ r←{what}Set value
          :Access public shared
        ∇
    :endclass

    :class sessionStorage
    :endclass

:EndNamespace


DirectoryBrowser improvements based on discussions with Adam

:Class DirectoryBrowser : #._JS.DataTable

    :field public Folder←''
    :field public Filter←''
    :field public Down←0
    :field public Up←0

    ∇ make
      :Access public
      :Implements constructor
      makeCommon
    ∇

    ∇ make1 args
      :Access public
      :Implements constructor
      (Folder Filter Down Up)←args defaultArgs Folder Filter Down Up
      makeCommon
    ∇

    ∇ makeCommon
      :Trap 6
          Root←#.Boot.AppRoot
      :Else
          Root←#.Utils.WSRoot
      :EndTrap
    ∇

    ∇ r←Render;files;filenames;links;sizes
      :Access public
      files←{⍵⌿⍨Down≥⍵[;4]}Filter #.Files.List Root,Folder  ⍝ remove folder entrie if no drilldown
      :If Down>0∊⍴Filter                       ⍝ if filtered and drilldown...
          files⍪←{⍵⌿⍨⍵[;4]}#.Files.List Root,Folder ⍝ ...add in folders
      :EndIf
      Data←0 3⍴⊂''
      files⌿⍨←'.'≠⊃¨files[;1] ⍝ remove current and parent entries
      :If ~0∊⍴files
          files←{⍵[⍒⍵[;4];]}{⍵[⍋#.Strings.lc↑⍵[;1];]}files
          filenames←files[;1]{(⍵/'./'),⍺,⍵/'/'}¨files[;4]
          links←files[;4](Folder{'<a ',((~⍺)/'target="_blank" '),'href="',(⍺⍺,⍵),'">',⍵,'</a>'})¨filenames
          sizes←#.Strings.commaFmt files[;2]
          (files[;4]/sizes)←⊂'[dir]'
          Data←links,sizes,⍪#.Dates.TSFmt¨files[;3]
      :EndIf
      :If Up>0∊⍴Folder
          Data⍪⍨←((New #._DC.A'..'({⍵↓⍨-⊥⍨'/'≠⍵}¯1↓Folder)).Render)'' ''
      :EndIf
      Data⍪⍨←'Name' 'Size' 'Timestamp'
      'autoWidth'Set _true
      'columns'Set'⍎[{"type":"html","className":"db-left"},{"type":"num-fmt","className":"db-right"},{"type":"date","className":"db-left"}]'
      AddClass'display'
      r←(⎕NEW #._DC.Style((('.db-left')('text-align' 'left'))(('.db-center')('text-align' 'center'))(('.db-right')('text-align' 'right')))).Render
      r,←⎕BASE.Render
    ∇

:EndClass

:Class DirectoryBrowser : #._JS.DataTable

    :field public Folder←''
    :field public Filter←''
    :field public Down←0
    :field public Up←0

    ∇ make
      :Access public
      :Implements constructor
      makeCommon
    ∇

    ∇ make1 args
      :Access public
      :Implements constructor
      (Folder Filter Down Up)←args defaultArgs Folder Filter Down Up
      makeCommon
    ∇

    ∇ makeCommon
      :Trap 6
          Root←#.Boot.AppRoot
      :Else
          Root←#.Utils.WSRoot
      :EndTrap
    ∇

    ∇ r←Render;files;filenames;links;sizes
      :Access public
      files←{⍵⌿⍨Down≥⍵[;4]}Filter #.Files.List Root,Folder  ⍝ remove folder entrie if no drilldown
      :If Down>0∊⍴Filter                       ⍝ if filtered and drilldown...
          files⍪←{⍵⌿⍨⍵[;4]}#.Files.List Root,Folder ⍝ ...add in folders
      :EndIf
      Data←0 3⍴⊂''
      files⌿⍨←'.'≠⊃¨files[;1] ⍝ remove current and parent entries
      :If ~0∊⍴files
          files←{⍵[⍒⍵[;4];]}{⍵[⍋#.Strings.lc↑⍵[;1];]}files
          filenames←files[;1]{⍺,⍵/'/'}¨files[;4]
          links←Folder∘{New #._DC.A ⍵(⍺,⍵)}¨filenames
          :If ∨/~files[;4]
              ((~files[;4])/links).Set¨⊂'target' '_blank'
          :EndIf
          sizes←(~files[;4]){⍺\⍺/#.Strings.commaFmt ⍵}files[;2]
          Data←links,sizes,⍪#.Dates.TSFmt¨files[;3]
      :EndIf
      :If Up>0∊⍴Folder
          Data⍪⍨←((New #._DC.A'..'({⍵↓⍨-⊥⍨'/'≠⍵}¯1↓Folder)).Render)'' ''
      :EndIf
      Data⍪⍨←'Name' 'Size' 'Timestamp'
      'autoWidth'Set _true
      'columns'Set'⍎[{"type":"html","className":"db-left"},{"type":"num-fmt","className":"db-center"},{"type":"date","className":"db-center"}]'
      AddClass'display'
      r←(⎕NEW #._DC.Style((('.db-left')('text-align' 'left'))(('.db-center')('text-align' 'center')))).Render
      r,←⎕BASE.Render
    ∇

:EndClass


Cleanup merged MiPage

Cleanup merged MiPage

:Class MiPage : #.HtmlPage

    ⍝∇:require =\HtmlPage.dyalog
    ⍝∇:require =\JSON.dyalog

    :Field Public _PageName←'' ⍝ Page file name
    :Field Public _PageDate←'' ⍝ Page saved date
    :field Public _Request     ⍝ HTTPRequest
    :field Public _Scripts←''
    :field Public _Styles←''
    :field public _Serialized←1 ⍝ serialized forms to return in _PageData
    :field Public _event        ⍝ set by APLJAX callback - event that was triggered
    :field Public _what         ⍝ set by APLJAX callback - name or id of the triggering element
    :field Public _value        ⍝ set by APLJAX callback - value of the triggering element
    :field public _PageData
    :field public _AjaxResponse←''
    :field public _DebugCallbacks←0
    :field public OnLoad←''     ⍝ page equivalent to ⎕LX
    :field public shared _true←#.JSON.true     ⍝ same definition as in #.JSON
    :field public shared _false←#.JSON.false   ⍝ same definition as in #.JSON

    _used←'' ⍝ keep track of what's been used

    ∇ Make
      :Access public
      :Implements constructor :Base
      MakeCommon
    ∇

    ∇ Make1 req
      :Access public
      _Request←req
      :Implements constructor :base
      MakeCommon
    ∇

    ∇ MakeCommon
      _PageData←⎕NS''
    ∇

    ∇ {r}←Render;b
      :Access public
      :If ''≢OnLoad
          Use'JQuery'
      :EndIf
      b←RenderBody
      :If ~0∊⍴_Styles
          {(Head.Insert _html.link).Set(('href=',⍵)('rel' 'stylesheet')('type' 'text/css'))}¨∪⌽_Styles
      :EndIf
      :If ~0∊⍴_Scripts
          {(Head.Add _html.script).Set('src=',⍵)}¨∪_Scripts
      :EndIf
      :If ~0∊⍴Handlers
          b,←∊Handlers.Render
      :EndIf
      :If ''≢OnLoad
          b,←(⎕NEW #._html.script('$(function(){',OnLoad,'});')).Render
      :EndIf
      r←RenderPage b
      :If 0≠⎕NC⊂'_Request.Response'
          _Request.Response.HTML←r
      :EndIf
    ∇

    ∇ {r}←Wrap
      :Access public
      r←Render
    ∇

    ∇ Use resources;n;ind;t;x
      :Access public
      resources←eis resources
      :For x :In resources
          :If ~(⊂x)∊_used
              :Select ⊃x
              :Case '⍎' ⍝ script
                  _Scripts,←⊂1↓x
              :Case '⍕' ⍝ style sheet
                  _Styles,←⊂1↓x
              :Else
                  :If 0≠⎕NC⊂'_Request.Server.Config.Resources'
                  :AndIf ~0∊n←1↑⍴_Request.Server.Config.Resources
                      :If n≥ind←_Request.Server.Config.Resources[;1]⍳⊂x
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 2)⊃_Request.Server.Config.Resources
                              _Scripts,←t
                          :EndIf
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 3)⊃_Request.Server.Config.Resources
                              _Styles,←t
                          :EndIf
                      :Else
                          1 _Request.Server.Log _PageName,' references unknown resource: ',x
                      :EndIf
                  :EndIf
              :EndSelect
              _used,←⊂x
          :EndIf
      :EndFor
    ∇

    ∇ r←{proto}Get names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘Get¨names
      :ElseIf 2≠_PageData.⎕NC names
          r←,proto
      :Else
          r←_PageData⍎names
⍝!!! BPB - not sure if we need this - it messes up multiple values for select(combolist) controls
⍝          :If 1<|≡r
⍝              r←∊r
⍝          :EndIf
          :If 0 2∊⍨10|⎕DR proto
              r←∊r
          :Else
              r←{0::⍵ ⋄ 0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ r←{proto}SessionGet names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘SessionGet¨names
      :ElseIf 2≠_Request.Session.⎕NC names
          r←proto
      :Else
          r←_Request.Session⍎names
          :If 1<|≡r ⋄ r←∊r ⋄ :EndIf
          :If ~0 2∊⍨10|⎕DR proto
              r←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ Close session ⍝ Called when the session ends
      :Access Public Overridable
    ∇

    :section APLJax  ⍝ used for building APLJAX responses
    ∇ _resetAjax
      :Access public
      _AjaxResponse←''
    ∇

    ∇ Respond arg
      :Access public
      ∘∘∘
    ∇
    ∇ r←renderContent content
      :If isInstance⊃content
          r←content.Render
      :ElseIf isClass⊃content
          r←(⎕NEW content).Render
      :Else
          r←(⎕NEW #.HtmlElement(''content)).Render
      :EndIf
    ∇

    ∇ r←selector Replace content
      :Access public
      r←⊂('replace'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Append content
      :Access public
      r←⊂('append'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Prepend content
      :Access public
      r←⊂('prepend'selector)('data'(renderContent content))
    ∇
    ∇ r←Execute content
      :Access public
      r←⊂('execute'content)
    ∇

    ∇ r←name Assign data
      :Access public
      r←⊂('assign'name)('data'data)
    ∇

    :endsection

    :section Position
    ∇ ref Position args;inds;mask;parameters;my;at;of;collision;within;q
      :Access public shared
      ⍝ ref  - a reference to an instance of anything based on HtmlElement
      ⍝ args - position information per jQueryUI's Position widget http://api.jqueryui.com/position/
      ⍝        can be in any of the following forms
      ⍝      1) positional (my at of collision within)  N.B. we don't use the "using" parameter
      ⍝         example:  myDiv Position 'left top' 'right bottom' '#otherElement'
      ⍝                   positions myDiv's top left corner at the bottom right corner of the element with id "otherElement"
      ⍝      2) paired
      ⍝                   myDiv Position 'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝                   myDiv Position ('my' 'left top') ('at' 'right bottom') ('of' '#otherElement')
      ⍝                   myDiv Position 3 2⍴'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝ Note: positional arguments are in form horizontal (left center right) vertical (top center bottom)

      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      :If isInstance ref
          :If 2=⍴⍴args ⍝ matrix
              args←,args
          :ElseIf 3=≡args
              args←⊃,/args
          :EndIf
          args←eis args
          inds←parameters⍳args
          :If ∨/mask←inds≤⍴parameters
              :If mask≡(2×+/mask)⍴1 0
                  parameters←mask/args
                  args←(1⌽mask)/args
              :EndIf
          :Else
              parameters←(⍴args)↑parameters
          :EndIf
          parameters(ref{⍺⍺⍎'Position.',⍺,'←',q ⍵})¨args
          ref.Uses,←⊂'JQueryUI'
          ref.Use
      :EndIf
    ∇
    :endsection

    :section Event Handling Support
    ∇ r←isPost
      :Access public
      r←{0::0 ⋄ _Request.isPost}⍬
    ∇

    ∇ r←isAPLJax
      :Access public
      r←{0::0 ⋄ _Request.isAPLJAX}⍬
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      :Access public
      r←(sel #._JSS.JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      :Access public
      r←(sel #._JSS.JQuery'val')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      :Access public
      r←(sel #._JSS.JQuery'attr')args
    ∇

    ∇ r←sel RemoveAttr args ⍝ JQuery removeAttr cover
      :Access public
      r←(sel #._JSS.JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      :Access public
      r←(sel #._JSS.JQuery'html')args
    ∇

    :endsection

    ∇ Debug;⎕TRAP
      :Access public
      ⎕TRAP←0⍴⎕TRAP
      ∘∘∘
    ∇

:EndClass

:Class MiPage : #.HtmlPage

    ⍝∇:require =\HtmlPage.dyalog
    ⍝∇:require =\JSON.dyalog

    :Field Public _PageName←'' ⍝ Page file name
    :Field Public _PageDate←'' ⍝ Page saved date
    :field Public _Request     ⍝ HTTPRequest
    :field Public _Scripts←''
    :field Public _Styles←''
    :field public _Serialized←1 ⍝ serialized forms to return in _PageData
    :field Public _event        ⍝ set by APLJAX callback - event that was triggered
    :field Public _what         ⍝ set by APLJAX callback - name or id of the triggering element
    :field Public _value        ⍝ set by APLJAX callback - value of the triggering element
    :field public _PageData
    :field public _AjaxResponse←''
    :field public _DebugCallbacks←0
    :field public OnLoad←''     ⍝ page equivalent to ⎕LX
    :field public shared _true←#.JSON.true     ⍝ same definition as in #.JSON
    :field public shared _false←#.JSON.false   ⍝ same definition as in #.JSON

    _used←'' ⍝ keep track of what's been used

    ∇ Make
      :Access public
      :Implements constructor :Base
      MakeCommon
    ∇

    ∇ Make1 req
      :Access public
      _Request←req
      :Implements constructor :base
      MakeCommon
    ∇

    ∇ MakeCommon
<<<<<<< Updated upstream
=======
⍝already defined in HtmlElement:
      (_html _HTML _JQ _SF _JQM _JSS _DC _)←#.(_html _HTML _JQ _SF _JQM _JSS _DC _)
>>>>>>> Stashed changes
      _PageData←⎕NS''
    ∇

    ∇ {r}←Render;b
      :Access public
      :If ''≢OnLoad
          Use'JQuery'
      :EndIf
      b←RenderBody
      :If ~0∊⍴_Styles
          {(Head.Insert _html.link).Set(('href=',⍵)('rel' 'stylesheet')('type' 'text/css'))}¨∪⌽_Styles
      :EndIf
      :If ~0∊⍴_Scripts
          {(Head.Add _html.script).Set('src=',⍵)}¨∪_Scripts
      :EndIf
      :If ~0∊⍴Handlers
          b,←∊Handlers.Render
      :EndIf
      :If ''≢OnLoad
          b,←(⎕NEW #._html.script('$(function(){',OnLoad,'});')).Render
      :EndIf
      r←RenderPage b
      :If 0≠⎕NC⊂'_Request.Response'
          _Request.Response.HTML←r
      :EndIf
    ∇

    ∇ {r}←Wrap
      :Access public
      r←Render
    ∇

    ∇ Use resources;n;ind;t;x
      :Access public
      resources←eis resources
      :For x :In resources
          :If ~(⊂x)∊_used
              :Select ⊃x
              :Case '⍎' ⍝ script
                  _Scripts,←⊂1↓x
              :Case '⍕' ⍝ style sheet
                  _Styles,←⊂1↓x
              :Else
                  :If 0≠⎕NC⊂'_Request.Server.Config.Resources'
                  :AndIf ~0∊n←1↑⍴_Request.Server.Config.Resources
                      :If n≥ind←_Request.Server.Config.Resources[;1]⍳⊂x
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 2)⊃_Request.Server.Config.Resources
                              _Scripts,←t
                          :EndIf
                          :If ~0∊⍴t←{(~0∘∊∘⍴¨⍵)/⍵}(⊂ind 3)⊃_Request.Server.Config.Resources
                              _Styles,←t
                          :EndIf
                      :Else
                          1 _Request.Server.Log _PageName,' references unknown resource: ',x
                      :EndIf
                  :EndIf
              :EndSelect
              _used,←⊂x
          :EndIf
      :EndFor
    ∇

    ∇ r←{proto}Get names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘Get¨names
      :ElseIf 2≠_PageData.⎕NC names
          r←,proto
      :Else
          r←_PageData⍎names
⍝!!! BPB - not sure if we need this - it messes up multiple values for select(combolist) controls
⍝          :If 1<|≡r
⍝              r←∊r
⍝          :EndIf
          :If 0 2∊⍨10|⎕DR proto
              r←∊r
          :Else
              r←{0::⍵ ⋄ 0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ r←{proto}SessionGet names
      :Access public
      proto←{6::⍵ ⋄ proto}''
      names←,⍕names
      names←#.Strings.deb names
      :If ' '∊names
          names←{⎕ML←3 ⋄ ⍵⊂⍨⍵≠' '}names
          r←proto∘SessionGet¨names
      :ElseIf 2≠_Request.Session.⎕NC names
          r←proto
      :Else
          r←_Request.Session⍎names
          :If 1<|≡r ⋄ r←∊r ⋄ :EndIf
          :If ~0 2∊⍨10|⎕DR proto
              r←{0∊⍴⍵:⍬ ⋄ w←⍵ ⋄ ((w='-')/w)←'¯' ⋄ ⊃(//)⎕VFI w}r
          :EndIf
      :EndIf
    ∇

    ∇ Close session ⍝ Called when the session ends
      :Access Public Overridable
    ∇

    :section APLJax  ⍝ used for building APLJAX responses
    ∇ _resetAjax
      :Access public
      _AjaxResponse←''
    ∇

    ∇ Respond arg
      :Access public
      ∘∘∘
    ∇
    ∇ r←renderContent content
      :If isInstance⊃content
          r←content.Render
      :ElseIf isClass⊃content
          r←(⎕NEW content).Render
      :Else
          r←(⎕NEW #.HtmlElement(''content)).Render
      :EndIf
    ∇

    ∇ r←selector Replace content
      :Access public
      r←⊂('replace'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Append content
      :Access public
      r←⊂('append'selector)('data'(renderContent content))
    ∇
    ∇ r←selector Prepend content
      :Access public
      r←⊂('prepend'selector)('data'(renderContent content))
    ∇
    ∇ r←Execute content
      :Access public
      r←⊂('execute'content)
    ∇

    ∇ r←name Assign data
      :Access public
      r←⊂('assign'name)('data'data)
    ∇

    :endsection

    :section Position
    ∇ ref Position args;inds;mask;parameters;my;at;of;collision;within;q
      :Access public shared
      ⍝ ref  - a reference to an instance of anything based on HtmlElement
      ⍝ args - position information per jQueryUI's Position widget http://api.jqueryui.com/position/
      ⍝        can be in any of the following forms
      ⍝      1) positional (my at of collision within)  N.B. we don't use the "using" parameter
      ⍝         example:  myDiv Position 'left top' 'right bottom' '#otherElement'
      ⍝                   positions myDiv's top left corner at the bottom right corner of the element with id "otherElement"
      ⍝      2) paired
      ⍝                   myDiv Position 'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝                   myDiv Position ('my' 'left top') ('at' 'right bottom') ('of' '#otherElement')
      ⍝                   myDiv Position 3 2⍴'my' 'left top' 'at' 'right bottom' 'of' '#otherElement'
      ⍝ Note: positional arguments are in form horizontal (left center right) vertical (top center bottom)

      parameters←'my' 'at' 'of' 'collision' 'within'
      q←{1⌽'''''',{⍵/⍨1+''''=⍵}⍕⍵}
      :If isInstance ref
          :If 2=⍴⍴args ⍝ matrix
              args←,args
          :ElseIf 3=≡args
              args←⊃,/args
          :EndIf
          args←eis args
          inds←parameters⍳args
          :If ∨/mask←inds≤⍴parameters
              :If mask≡(2×+/mask)⍴1 0
                  parameters←mask/args
                  args←(1⌽mask)/args
              :EndIf
          :Else
              parameters←(⍴args)↑parameters
          :EndIf
          parameters(ref{⍺⍺⍎'Position.',⍺,'←',q ⍵})¨args
          ref.Uses,←⊂'JQueryUI'
          ref.Use
      :EndIf
    ∇
    :endsection

    :section Event Handling Support
    ∇ r←isPost
      :Access public
      r←{0::0 ⋄ _Request.isPost}⍬
    ∇

    ∇ r←isAPLJax
      :Access public
      r←{0::0 ⋄ _Request.isAPLJAX}⍬
    ∇

    ∇ r←sel Css args ⍝ JQuery css cover
      :Access public
      r←(sel #._JSS.JQuery'css')args
    ∇

    ∇ r←sel Val args ⍝ JQuery val cover
      :Access public
      r←(sel #._JSS.JQuery'val')args
    ∇

    ∇ r←sel Attr args ⍝ JQuery attr cover
      :Access public
      r←(sel #._JSS.JQuery'attr')args
    ∇

    ∇ r←sel RemoveAttr args ⍝ JQuery removeAttr cover
      :Access public
      r←(sel #._JSS.JQuery'removeAttr')args
    ∇

    ∇ r←sel Html args ⍝ JQuery html cover
      :Access public
      r←(sel #._JSS.JQuery'html')args
    ∇

    :endsection

    ∇ Debug;⎕TRAP
      :Access public
      ⎕TRAP←0⍴⎕TRAP
      ∘∘∘
    ∇

:EndClass
⍝)(!Position!!0 0 0 0 0 0 0