dba/html  library module

Summary

HTML components.
Tags

Author: Christian Grün, BaseX Team 2005-21, BSD License

__source : lib/html.xqm

Related documents
ViewDescriptionFormat
xqdocxqDoc xml file from the source modulexml
xqparsexqparse xml file from the source modulexml

Imports

This module is imported by 21 modules. It imports 3 modules.

dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/databases 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
dba/files 2 3 4 5 6 7 8
dba/users 2 3 4 5 6 7
dba/users 2 3 4 5 6 7
dba/users 2 3 4 5 6 7
dba/users 2 3 4 5 6 7
imports
this
imports

Variables

3.1 $html:NUMBER

Summary
Type
item()*

Functions

4.1 html:button

Arities: html:button#2html:button#3html:button#4

Summary
Creates a button.
Signature
html:button ( $value as xs:string, $label as xs:string )  as element(button)
html:button ( $value as xs:string, $label as xs:string, $confirm as xs:boolean )  as element(button)
html:button ( $value as xs:string, $label as xs:string, $confirm as xs:boolean, $atts as map(xs:string, xs:string)? )  as element(button)
Parameters
  • value as xs:string button value
  • label as xs:string label
Return
  • element(button)button
Invoked by 17 functions from 17 modules
Source ( 0 lines)

4.2 html:checkbox

Arities: html:checkbox#2html:checkbox#4

Summary
Creates a checkbox.
Signature
html:checkbox ( $label as xs:string, $map as map(*) )  as node()+
html:checkbox ( $name as xs:string, $value as xs:string, $checked as xs:boolean, $label as xs:string )  as node()+
Parameters
  • label as xs:string label of checkbox
  • map as map(*) additional attributes
Return
  • node() +checkbox
Invoked by 2 functions from 2 modules
Source ( 0 lines)

4.3 html:date

Arities: html:date#1

Summary
Formats a date.
Signature
html:date ( $date as xs:dateTime )  as xs:string
Parameters
  • date as xs:dateTime date
Return
  • xs:stringstring
Invoked by 0 functions from 0 modules
    Source ( 0 lines)

    4.4 html:duration

    Arities: html:duration#1

    Summary
    Formats a duration.
    Signature
    html:duration ( $seconds as xs:decimal )  as xs:string
    Parameters
    • seconds as xs:decimal seconds
    Return
    • xs:stringstring
    Invoked by 1 functions from 1 modules
    Source ( 0 lines)

    4.5 html:focus

    Arities: html:focus#1

    Summary
    Focuses the specified field via Javascript.
    Signature
    html:focus ( $element as xs:string )  as element(script)
    Parameters
    • element as xs:string element to be focused
    Return
    • element(script)script element
    Invoked by 13 functions from 13 modules
    Source ( 0 lines)

    4.6 html:js

    Arities: html:js#1

    Summary
    Creates an embedded JavaScript snippet.
    Signature
    html:js ( $js as xs:string )  as element(script)
    Parameters
    • js as xs:string JavaScript string
    Return
    • element(script)script element
    Invoked by 5 functions from 5 modules
    Source ( 0 lines)

    4.7 html:link

    Arities: html:link#2html:link#3

    Summary
    Creates a link to the specified target.
    Signature
    html:link ( $text as xs:string, $href as xs:string )  as element(a)
    html:link ( $text as xs:string, $href as xs:string, $params as map(*)* )  as element(a)
    Parameters
    • text as xs:string link text
    • href as xs:string link reference
    Return
    • element(a)link
    Invoked by 13 functions from 12 modules
    Source ( 0 lines)

    4.8 html:option

    Arities: html:option#3

    Summary
    Creates an option checkbox.
    Signature
    html:option ( $value as xs:string, $label as xs:string, $opts as xs:string* )  as node()+
    Parameters
    • value as xs:string value
    • label as xs:string label
    • opts as xs:string* checked options
    Return
    • node() +checkbox
    Invoked by 3 functions from 3 modules
    Source ( 0 lines)

    4.9 html:parameters

    Arities: html:parameters#0html:parameters#1

    Summary
    Creates a new map with the current query parameters.
    Signature
    html:parameters ( )  as map(*)
    html:parameters ( $map as map(*)? )  as map(*)
    Return
    • map(*)map with query parameters
    Invoked by 1 functions from 1 modules
    Source ( 0 lines)

    4.10 html:properties

    Arities: html:properties#1

    Summary
    Creates a property list.
    Signature
    html:properties ( $props as element() )  as element(table)
    Parameters
    • props as element() properties
    Return
    • element(table)table
    Invoked by 2 functions from 2 modules
    Source ( 0 lines)

    4.11 html:table

    Arities: html:table#5

    Summary
    Creates a table for the specified entries. * The table format is specified by the table headers: * The element names serve as column keys. * The string values are the header labels. * The 'type' attribute defines how the values are formatted and sorted: * 'number': sorted as numbers * 'decimal': sorted as numbers, output with two decimal digits * 'bytes': sorted as numbers, output in a human-readable format * 'date', 'dateTime', 'time': sorted and output as dates * 'dynamic': function generating dynamic input; sorted as strings * 'id': suppressed (only used for creating checkboxes) * otherwise, sorted and output as strings * The 'order' attribute defines how sorted values will be ordered: * 'desc': descending order * otherwise, ascending order * The 'main' attribute indicates which column is the main column * The supplied table rows are supplied as elements. Values are contained in attributes; their names represents the column key. * Supplied buttons will placed on top of the table. * Query parameters will be included in table links. * The options argument can have the following keys: * 'sort': key of the ordered column. if empty, sorting will be disabled * 'presort': key of pre-sorted column. if identical to sort, entries will not be resorted * 'link': function for generating a link reference. * 'page': currently displayed page * 'count': maximum number of results
    Signature
    html:table ( $headers as map(*)*, $entries as map(*)*, $buttons as element(button)*, $params as map(*), $options as map(*) )  as element()+
    Parameters
    • headers as map(*)* table headers
    • entries as map(*)* table entries
    • buttons as element(button)* buttons
    • params as map(*) additional query parameters
    • options as map(*) additional options
    Return
    • element() +table
    Invoked by 8 functions from 7 modules
    Source ( 0 lines)

    4.12 html:wrap

    Arities: html:wrap#1html:wrap#2

    Summary
    Extends the specified table rows with the page template.
    Signature
    html:wrap ( $rows as element(tr)+ )  as element(html)
    html:wrap ( $options as map(*), $rows as element(tr)+ )  as element(html)
    Parameters
    • rows as element(tr)+ tr elements
    Return
    • element(html)HTML page
    Invoked by 18 functions from 18 modules
    Source ( 0 lines)

    Namespaces

    The following namespaces are defined:

    PrefixUri
    configdba/config
    htmldba/html
    optionsdba/options
    utildba/util

    6 RestXQ

    None

    Source Code

    (:~
     : HTML components.
     :
     : @author Christian Grün, BaseX Team 2005-21, BSD License
     :)
    module namespace html = 'dba/html';
    
    import module namespace options = 'dba/options' at 'options.xqm';
    import module namespace config = 'dba/config' at 'config.xqm';
    import module namespace util = 'dba/util' at 'util.xqm';
    
    (: Number formats. :)
    declare variable $html:NUMBER := ('decimal', 'number', 'bytes');
    
    (:~
     : Extends the specified table rows with the page template.
     : @param  $rows  tr elements
     : @return HTML page
     :)
    declare function html:wrap(
      $rows  as element(tr)+
    ) as element(html) {
      html:wrap(map { }, $rows)
    };
    
    (:~
     : Extends the specified table rows with the page template.
     : The following options can be specified:
     : <ul>
     :   <li><b>header</b>: page headers</li>
     :   <li><b>error</b>: error string</li>
     :   <li><b>css</b>: CSS files</li>
     :   <li><b>scripts</b>: JavaScript files</li>
     : </ul>
     : @param  $options  options
     : @param  $rows     tr elements
     : @return page
     :)
    declare function html:wrap(
      $options  as map(*),
      $rows     as element(tr)+
    ) as element(html) {
      let $header := head($options?header) ! util:capitalize(.)
      let $user := session:get($config:SESSION-KEY)
      return <html xml:space='preserve'>
        <head>
          <meta charset='utf-8'/>
          <title>DBA{ ($header, tail($options?header)) ! (' » ' || .) }</title>
          <meta name='description' content='Database Administration'/>
          <meta name='author' content='BaseX Team 2005-21, BSD License'/>
          <link rel='stylesheet' type='text/css' href='static/style.css'/>
          { $options?css ! <link rel='stylesheet' type='text/css' href='static/{ . }'/> }
          <script type='text/javascript' src='static/js.js'/>
          { $options?scripts ! <script type='text/javascript' src='static/{ . }'/> }
        </head>
        <body>
          <table cellpadding='0' cellspacing='0'>
            <tr>
              <td class='slick'>
                <table width='100%' cellpadding='0' cellspacing='0'>
                  <tr>
                    <td>{
                      <span style='float:left'>
                        <h1>BaseX Database Administration</h1>
                      </span>,
                      if($user) then (
                        <span style='float:right'>
                          <b>{ $user }</b> (<a href='logout'>logout</a>)
                        </span>
                      ) else ()
                    }</td>
                  </tr>
                  <tr>
                    <td>
                      <div class='ellipsis'>{
                        if($user) then (
                          let $cats := (
                            for $cat in ('Logs', 'Databases', 'Queries', 'Files', 'Jobs',
                              'Users', 'Sessions', 'Settings')
                            let $link := <a href='{ lower-case($cat) }'>{ $cat }</a>
                            return if($link = $header) then (
                              <b>{ $link }</b>
                            ) else (
                              $link
                            )
                          )
                          return (
                            head($cats),
                            tail($cats) ! (' · ', .),
                            (1 to 3) ! '&#x2000;'
                          )
                        ) else (
                          <div class='note'>
                            Please enter your admin credentials:
                          </div>
                        ),
                        <span>{
                          element b {
                            attribute id { 'info' },
                            let $error := $options?error[.], $info := $options?info[.]
                            return if($error) then (
                              attribute class { 'error' }, $error
                            ) else if($info) then (
                              attribute class { 'info' }, $info
                            ) else ()
                          }
                        }</span>
                      }</div>
                      <hr/>
                    </td>
                  </tr>
                </table>
              </td>
              <td class='slick'>
                <a href='/'><img src='static/basex.svg'/></a>
              </td>
            </tr>
          </table>
          <table width='100%'>{ $rows }</table>
          <hr/>
          <div class='right'><sup>BaseX Team 2005-21, BSD License</sup></div>
          <div class='small'/>
          { html:js('buttons();') }
        </body>
      </html>
    };
    
    (:~
     : Creates an option checkbox.
     : @param  $value  value
     : @param  $label  label
     : @param  $opts   checked options
     : @return checkbox
     :)
    declare function html:option(
      $value  as xs:string,
      $label  as xs:string,
      $opts   as xs:string*
    ) as node()+ {
      html:checkbox('opts', $value, $opts = $value, $label)
    };
    
    (:~
     : Creates a checkbox.
     : @param  $name     name of checkbox
     : @param  $value    value
     : @param  $checked  checked state
     : @param  $label    label
     : @return checkbox
     :)
    declare function html:checkbox(
      $name     as xs:string,
      $value    as xs:string,
      $checked  as xs:boolean,
      $label    as xs:string
    ) as node()+ {
      html:checkbox($label, map:merge((
        map { 'name':  $name },
        map { 'value': $value },
        if($checked) then map { 'checked': $checked } else ()
      )))
    };
    
    (:~
     : Creates a checkbox.
     : @param  $label  label of checkbox
     : @param  $map    additional attributes
     : @return checkbox
     :)
    declare function html:checkbox(
      $label   as xs:string,
      $map     as map(*)
    ) as node()+ {
      element input {
        attribute type { 'checkbox' },
        map:for-each($map, function($key, $value) { attribute { $key } { $value } })
      },
      text { $label },
      element br { }
    };
    
    (:~
     : Creates a button.
     : @param  $value  button value
     : @param  $label  label
     : @return button
     :)
    declare function html:button(
      $value  as xs:string,
      $label  as xs:string
    ) as element(button) {
      html:button($value, $label, false())
    };
    
    (:~
     : Creates a button.
     : @param  $value    button value
     : @param  $label    label
     : @param  $confirm  confirm click
     : @return button
     :)
    declare function html:button(
      $value    as xs:string,
      $label    as xs:string,
      $confirm  as xs:boolean
    ) as element(button) {
      html:button($value, $label, $confirm, ())
    };
    
    (:~
     : Creates a button.
     : @param  $value    button value
     : @param  $label    label
     : @param  $confirm  confirm click
     : @param  $atts     additional attributes
     : @return button
     :)
    declare function html:button(
      $value    as xs:string,
      $label    as xs:string,
      $confirm  as xs:boolean,
      $atts     as map(xs:string, xs:string)?
    ) as element(button) {
      element button {
        attribute name { 'action' },
        attribute value { $value },
        if($confirm) then (
          attribute onclick { 'return confirm("Are you sure?");' }
        ) else (),
        if(exists($atts)) then (
          map:for-each($atts, function($key, $value) { attribute { $key } { $value } })
        ) else (),
        $label
      }
    };
    
    (:~
     : Creates a property list.
     : @param  $props  properties
     : @return table
     :)
    declare function html:properties(
      $props  as element()
    ) as element(table) {
      <table>{
        for $header in $props/*
        return (
          <tr>
            <th colspan='2' align='left'>
              <h3>{ upper-case(name($header)) }</h3>
            </th>
          </tr>,
          for $option in $header/*
          let $value := $option/data()
          return <tr>
            <td><b>{ upper-case($option/name()) }</b></td>
            <td>{
              if($value = 'true') then '✓'
              else if($value = 'false') then '–'
              else $value
            }</td>
          </tr>
        )
      }</table>
    };
    
    (:~
     : Creates a table for the specified entries.
     : * The table format is specified by the table headers:
     :   * The element names serve as column keys.
     :   * The string values are the header labels.
     :   * The 'type' attribute defines how the values are formatted and sorted:
     :     * 'number': sorted as numbers
     :     * 'decimal': sorted as numbers, output with two decimal digits
     :     * 'bytes': sorted as numbers, output in a human-readable format
     :     * 'date', 'dateTime', 'time': sorted and output as dates
     :     * 'dynamic': function generating dynamic input; sorted as strings
     :     * 'id': suppressed (only used for creating checkboxes)
     :     * otherwise, sorted and output as strings
     :   * The 'order' attribute defines how sorted values will be ordered:
     :     * 'desc': descending order
     :     * otherwise, ascending order
     :   * The 'main' attribute indicates which column is the main column
     : * The supplied table rows are supplied as elements. Values are contained in attributes; their
     :   names represents the column key.
     : * Supplied buttons will placed on top of the table.
     : * Query parameters will be included in table links.
     : * The options argument can have the following keys:
     :   * 'sort': key of the ordered column. if empty, sorting will be disabled
     :   * 'presort': key of pre-sorted column. if identical to sort, entries will not be resorted
     :   * 'link': function for generating a link reference.
     :   * 'page': currently displayed page
     :   * 'count': maximum number of results
     :
     : @param  $headers  table headers
     : @param  $entries  table entries
     : @param  $buttons  buttons
     : @param  $params   additional query parameters
     : @param  $options  additional options
     : @return table
     :)
    declare function html:table(
      $headers  as map(*)*,
      $entries  as map(*)*,
      $buttons  as element(button)*,
      $params   as map(*),
      $options  as map(*)
    ) as element()+ {
      (: display buttons :)
      if($buttons) then (
        for $button in $buttons
        return ($button, <span> </span>),
        <br/>,
        <div class='small'/>
      ) else (),
    
      (: sort entries :)
      let $sort := $options?sort
      let $sort-key := head(($sort[.], $headers[1]?key))
      let $sorted-entries := if($sort and not($sort-key = $options?presort)) then (
        let $sort-header := $headers[?key = $sort-key]
        let $sort-value := (
          let $sort-desc := $sort-header?order = 'desc'
          return switch($sort-header?type)
            case 'decimal' case 'number' case 'bytes' return
              if($sort-desc)
              then function($v) { 0 - number($v) }
              else function($v) { number($v) }
            case 'time' return
              if($sort-desc)
              then function($v) { xs:time('00:00:00') - xs:time($v) }
              else function($v) { $v }
            case 'date' return
              if($sort-desc)
              then function($v) { xs:date('0001-01-01') - xs:date($v) }
              else function($v) { $v }
            case 'dateTime' return
              if($sort-desc)
              then function($v) { xs:dateTime('0001-01-01T00:00:00Z') - xs:dateTime($v) }
              else function($v) { $v }
            case 'dynamic' return
              function($v) { if($v instance of function(*)) then string-join($v()) else $v }
            default return
              function($v) { $v }
        )
        for $entry in $entries
        order by $sort-value($entry($sort-key)) empty greatest collation '?lang=en'
        return $entry
      ) else (
        $entries
      )
    
      (: show results :)
      let $count := if($sort) then () else $options?count
      let $page := $options?page
      let $max := options:get($options:MAXROWS)
      let $start := head((($page - 1) * $max + 1, 1))
      return (
        (: result summary :)
        let $count := head(($count, count($sorted-entries)))
        let $single-page := not($page) or ($page = 1 and $count < $start + $max)
        return element h4 {
          $count,
          if($count = 1) then ' Entry' else 'Entries',
    
          if($single-page) then () else (
            '(Page: ',
            let $last := ($count - 1) idiv $max + 1
            let $pages := sort(distinct-values((
              1, $page - ($last idiv 10), $page - 1, $page, $page + 1, $page + ($last idiv 10), $last
            ))[. >= 1 and . <= $last])
            for $p at $pos in $pages
            let $suffix := (if($p = $last) then ')' else ' ') ||
              (if($pages[$pos + 1] > $p + 1) then ' … ' else ())
            return (
              if ($page = $p) then $p || $suffix else (
                html:link(string($p), '', ($params, map { 'page': $p, 'sort': $sort })), $suffix
              )
            )
          )
        },
    
        (: list of results :)
        let $shown-entries := if($count) then (
          $sorted-entries
        ) else (
          $sorted-entries[position() >= $start][position() <= $max + 1]
        )
        return if(empty($shown-entries)) then () else (
          element table {
            element tr {
              for $header at $pos in $headers
              let $name := $header?key
              let $label := upper-case($header?label)
              return element th {
                attribute align {
                  if($header?type = $html:NUMBER) then 'right' else 'left'
                },
    
                if($pos = 1 and $buttons) then (
                  <input type='checkbox' onclick='toggle(this)'/>, ' '
                ) else (),
    
                if($header?type = 'id') then (
                  (: id columns: empty header column :)
                ) else if(empty($sort) or $name = $sort) then (
                  (: sorted column, xml column: only display label :)
                  $label
                ) else (
                  (: generate sort link :)
                  html:link($label, '', ($params, map { 'sort': $name }))
                )
              }
            },
    
            let $link := $options?link
            for $entry in $shown-entries[position() <= $max]
            return element tr {
              $entry?id ! attribute id { . },
              for $header at $pos in $headers
              let $name := $header?key
              let $type := $header?type
    
              (: format value :)
              let $v := $entry($name)
              let $value := try {
                if($type = 'bytes') then (
                  prof:human(if(exists($v)) then xs:integer($v) else 0)
                ) else if($type = 'decimal') then (
                  format-number(if(exists($v)) then number($v) else 0, '0.00')
                ) else if($type = 'dateTime') then (
                  html:date(xs:dateTime($v))
                ) else if($v instance of function(*)) then (
                  $v()
                ) else (
                  string($v)
                )
              } catch * {
                $err:description
              }
              return element td {
                attribute align { if($type = $html:NUMBER) then 'right' else 'left' },
                if($pos = 1 and $buttons) then (
                  <input type='checkbox' name='{ $name }' value='{ data($value) }'
                    onclick='buttons(this)'/>,
                  ' '
                ) else (),
                if($pos = 1 and exists($link)) then (
                  html:link($value, $link, ($params, map { $name: $value }))
                ) else if($type = 'id') then () else (
                  $value
                )
              }
            }
          }
        )
      )
    };
    
    (:~
     : Focuses the specified field via Javascript.
     : @param  $element  element to be focused
     : @return script element
     :)
    declare function html:focus(
      $element  as xs:string
    ) as element(script) {
      html:js('var u = document.getElementById("' || replace($element, '"', '') || '"); ' ||
        'u.focus(); u.select();')
    };
    
    (:~
     : Creates a link to the specified target.
     : @param  $text  link text
     : @param  $href  link reference
     : @return link
     :)
    declare function html:link(
      $text  as xs:string,
      $href  as xs:string
    ) as element(a) {
      <a href='{ $href }'>{ $text }</a>
    };
    
    (:~
     : Creates a link to the specified target.
     : @param  $text    link text
     : @param  $href    link reference
     : @param  $params  query parameters
     : @return link
     :)
    declare function html:link(
      $text    as xs:string,
      $href    as xs:string,
      $params  as map(*)*
    ) as element(a) {
      html:link($text, web:create-url($href, map:merge($params)))
    };
    
    (:~
     : Formats a date.
     : @param  $date  date
     : @return string
     :)
    declare function html:date(
      $date  as xs:dateTime
    ) as xs:string {
      let $zone := timezone-from-dateTime(current-dateTime())
      let $dt := fn:adjust-dateTime-to-timezone(xs:dateTime($date), $zone)
      return format-dateTime($dt, '[Y0000]-[M00]-[D00], [H00]:[m00]:[s00]')
    };
    
    (:~
     : Formats a duration.
     : @param  $seconds  seconds
     : @return string
     :)
    declare function html:duration(
      $seconds  as xs:decimal
    ) as xs:string {
      let $min := $seconds idiv 60
      let $sec := $seconds - $min * 60
      return (format-number($min, '00') || ':' || format-number($sec, '00'))
    };
    
    (:~
     : Creates an embedded JavaScript snippet.
     : @param  $js  JavaScript string
     : @return script element
     :)
    declare function html:js(
      $js  as xs:string
    ) as element(script) {
      <script type='text/javascript'>{
        '(function() { ' || $js || ' })();'
      }</script>
    };
    
    (:~
     : Creates a new map with the current query parameters.
     : @return map with query parameters
     :)
    declare function html:parameters() as map(*) {
      map:merge(
        for $param in request:parameter-names()[not(starts-with(., '_'))]
        return map { $param: request:parameter($param) }
      )
    };
    
    (:~
     : Creates a new map with query parameters. The returned map contains all
     : current query parameters, : and the given ones, prefixed with an underscore.
     : @param  $map  predefined parameters
     : @return map with query parameters
     :)
    declare function html:parameters(
      $map  as map(*)?
    ) as map(*) {
      map:merge((
        html:parameters(),
        map:for-each($map, function($name, $value) {
          map:entry('_' || $name, $value)
        })
      ))
    };