dba/html library module
Summary
HTML components.
- Tags
Author: Christian Grün, BaseX Team 2005-21, BSD License
__source : lib/html.xqm
Imports
This module is imported by 21 modules. It imports 3 modules.
dba/queries 2 3 4 5
imports
→this
imports
→Variables
Functions
4.1 html:button
Arities: html:button#2html:button#3html:button#4
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)
- value
as
xs:string
button value - label
as
xs:string
label
element(button)
button
Invoked by 17 functions from 17 modules
Source ( 0 lines)
4.2 html:checkbox
Arities: html:checkbox#2html:checkbox#4
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() +
- label
as
xs:string
label of checkbox - map
as
map(*)
additional attributes
node() +
checkbox
Invoked by 2 functions from 2 modules
Source ( 0 lines)
4.3 html:date
Arities: html:date#1
html:date
(
$date
as
xs:dateTime
)
as
xs:string
- date
as
xs:dateTime
date
xs:string
string
Invoked by 0 functions from 0 modules
Source ( 0 lines)
4.4 html:duration
Arities: html:duration#1
html:duration
(
$seconds
as
xs:decimal
)
as
xs:string
- seconds
as
xs:decimal
seconds
xs:string
string
Invoked by 1 functions from 1 modules
Source ( 0 lines)
4.5 html:focus
Arities: html:focus#1
html:focus
(
$element
as
xs:string
)
as
element(script)
- element
as
xs:string
element to be focused
element(script)
script element
Invoked by 13 functions from 13 modules
Source ( 0 lines)
4.6 html:js
Arities: html:js#1
html:js
(
$js
as
xs:string
)
as
element(script)
- js
as
xs:string
JavaScript string
element(script)
script element
Invoked by 5 functions from 5 modules
Source ( 0 lines)
4.7 html:link
Arities: html:link#2html:link#3
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)
- text
as
xs:string
link text - href
as
xs:string
link reference
element(a)
link
Invoked by 13 functions from 12 modules
Source ( 0 lines)
4.8 html:option
Arities: html:option#3
html:option
(
$value
as
xs:string
, $label
as
xs:string
, $opts
as
xs:string*
)
as
node() +
- value
as
xs:string
value - label
as
xs:string
label - opts
as
xs:string*
checked options
node() +
checkbox
Invoked by 3 functions from 3 modules
Source ( 0 lines)
4.9 html:parameters
Arities: html:parameters#0html:parameters#1
html:parameters
(
)
as
map(*)
html:parameters
(
$map
as
map(*)?
)
as
map(*)
map(*)
map with query parameters
Invoked by 1 functions from 1 modules
Source ( 0 lines)
4.10 html:properties
Arities: html:properties#1
html:properties
(
$props
as
element()
)
as
element(table)
- props
as
element()
properties
element(table)
table
Invoked by 2 functions from 2 modules
Source ( 0 lines)
4.11 html:table
Arities: html:table#5
html:table
(
$headers
as
map(*)*
, $entries
as
map(*)*
, $buttons
as
element(button)*
, $params
as
map(*)
, $options
as
map(*)
)
as
element() +
- 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
element() +
table
Invoked by 8 functions from 7 modules
Source ( 0 lines)
4.12 html:wrap
Arities: html:wrap#1html:wrap#2
html:wrap
(
$rows
as
element(tr)+
)
as
element(html)
html:wrap
(
$options
as
map(*)
, $rows
as
element(tr)+
)
as
element(html)
- rows
as
element(tr)+
tr elements
element(html)
HTML page
Invoked by 18 functions from 18 modules
Source ( 0 lines)
Namespaces
The following namespaces are defined:
Prefix | Uri |
---|---|
config | dba/config |
html | dba/html |
options | dba/options |
util | dba/util |
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) ! ' '
)
) 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)
})
))
};