diff --git a/Makefile b/Makefile
index ab2a20c..f6166ea 100644
--- a/Makefile
+++ b/Makefile
@@ -699,14 +699,15 @@ install:
install -m 644 $(TARGET) $(ILIBDIR)/
install -m 644 $(SHARED) $(ILIBDIR)/
install -m 644 $(CONFDIR)/*.conf.sample $(IETCDIR)/
- install -m 644 $(SHRDIR)/dmpack.css $(ISHRDIR)/
- install -m 644 $(SHRDIR)/dmpack.min.css $(ISHRDIR)/
- install -m 644 $(SHRDIR)/dmreport.css $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/dmpack.css $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/dmpack.min.css $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/dmreport.css $(ISHRDIR)/
install -m 644 $(SHRDIR)/dmreport.min.css $(ISHRDIR)/
- install -m 644 $(SHRDIR)/dmlua.lua $(ISHRDIR)/
- install -m 644 $(SHRDIR)/feed.xsl $(ISHRDIR)/
- install -m 755 $(SHRDIR)/diskfree.sh $(ISHRDIR)/
- install -m 755 $(SHRDIR)/mkreport.sh $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/dmpack.js $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/dmlua.lua $(ISHRDIR)/
+ install -m 644 $(SHRDIR)/feed.xsl $(ISHRDIR)/
+ install -m 755 $(SHRDIR)/diskfree.sh $(ISHRDIR)/
+ install -m 755 $(SHRDIR)/mkreport.sh $(ISHRDIR)/
$(GZIP) -9 < $(MANDIR)/dmapi.1 > $(IMANDIR)/dmapi.1.gz
$(GZIP) -9 < $(MANDIR)/dmbackup.1 > $(IMANDIR)/dmbackup.1.gz
$(GZIP) -9 < $(MANDIR)/dmbeat.1 > $(IMANDIR)/dmbeat.1.gz
diff --git a/app/dmweb.f90 b/app/dmweb.f90
index f72df98..7159ce3 100644
--- a/app/dmweb.f90
+++ b/app/dmweb.f90
@@ -23,9 +23,9 @@ program dmweb
!! The databases have to exist at start-up. Add the variables to the
!! configuration file of your web server.
!!
- !! Copy the CSS file `share/dmpack.min.css` to the document root path
- !! (`/var/www/`), or create a symlink. Any other classless CSS may work
- !! as well.
+ !! Copy the CSS file `share/dmpack.min.css` and the JavaScript file
+ !! `share/dmpack.js` to the document root path (`/var/www/`), or create a
+ !! symlink. Other classless style sheets may work as well.
use :: dmpack
implicit none (type, external)
@@ -37,6 +37,7 @@ program dmweb
! Program parameters.
character(len=*), parameter :: APP_BASE_PATH = '/dmpack' !! URI base path.
character(len=*), parameter :: APP_CSS_PATH = '/dmpack.min.css' !! Path to CSS file.
+ character(len=*), parameter :: APP_JS_PATH = '/dmpack.js' !! Path to JavaScript file.
character(len=*), parameter :: APP_TITLE = 'DMPACK' !! HTML title and heading.
integer, parameter :: APP_DB_TIMEOUT = DB_TIMEOUT_DEFAULT !! SQLite 3 busy timeout in mseconds.
logical, parameter :: APP_READ_ONLY = .false. !! Read-only mode.
@@ -2198,7 +2199,11 @@ subroutine html_footer()
' | Status' // &
H_SMALL_END // H_P_END
- call dm_cgi_out(dm_html_footer(CONTENT))
+ if (len_trim(APP_JS_PATH) > 0) then
+ call dm_cgi_out(dm_html_footer(CONTENT, APP_JS_PATH))
+ else
+ call dm_cgi_out(dm_html_footer(CONTENT))
+ end if
end subroutine html_footer
subroutine html_header(title)
diff --git a/share/dmpack.js b/share/dmpack.js
new file mode 100644
index 0000000..5d456b7
--- /dev/null
+++ b/share/dmpack.js
@@ -0,0 +1,18 @@
+/*
+ * Additional formatting of ISO 8601 time stamps in the DMPACK web interface.
+ */
+function formatTimeElements()
+{
+ var times = document.getElementsByTagName('time');
+
+ for (var i = 0; i < times.length; i++)
+ {
+ var attr = times[i].getAttribute('datetime');
+ var date = attr.substring(0, 10);
+ var time = attr.substring(11, 19);
+ var zone = attr.substring(19);
+ times[i].innerHTML = `${date} ${time} ${zone}`;
+ }
+}
+
+formatTimeElements();
diff --git a/src/dm_html.f90 b/src/dm_html.f90
index 9dad8d7..9097fc5 100644
--- a/src/dm_html.f90
+++ b/src/dm_html.f90
@@ -136,7 +136,8 @@ module dm_html
character(len=*), parameter, public :: H_UL_END = '' // NL
type, public :: anchor_type
- !! HTML anchor type.
+ !! HTML anchor type. The length of link text and URL are limited to 256
+ !! characters.
character(len=256) :: link = ' ' !! URL.
character(len=256) :: text = ' ' !! Link text.
end type anchor_type
@@ -180,6 +181,7 @@ module dm_html
public :: dm_html_pre
public :: dm_html_request
public :: dm_html_responses
+ public :: dm_html_script
public :: dm_html_select
public :: dm_html_select_create
public :: dm_html_select_destroy
@@ -194,13 +196,23 @@ module dm_html
public :: dm_html_th
public :: dm_html_time
contains
- pure function dm_html_anchor(anchor) result(html)
- !! Returns HTML anchor tag.
- type(anchor_type), intent(in) :: anchor !! Anchor type.
- character(len=:), allocatable :: html !! Generated HTML.
+ pure function dm_html_anchor(anchor, encode) result(html)
+ !! Returns HTML anchor tag. Address and inner HTML of the anchor
+ !! element are encoded by default.
+ type(anchor_type), intent(in) :: anchor !! Anchor type.
+ logical, intent(in), optional :: encode !! Encode address and inner HTML of anchor element.
+ character(len=:), allocatable :: html !! Generated HTML.
+
+ logical :: encode_
- html = '' // &
- dm_html_encode(anchor%text) // ''
+ encode_ = .true.
+ if (present(encode)) encode_ = encode
+
+ if (encode_) then
+ html = '' // dm_html_encode(anchor%text) // ''
+ else
+ html = '' // trim(anchor%text) // ''
+ end if
end function dm_html_anchor
function dm_html_beat(beat, delta, prefix) result(html)
@@ -325,7 +337,7 @@ function dm_html_beats(beats, deltas, prefix) result(html)
html = html // &
H_TD // H_CODE // dm_html_encode(beats(i)%address) // H_CODE_END // H_TD_END // &
- H_TD // dm_html_encode(beats(i)%time_recv) // H_TD_END // &
+ H_TD // dm_html_time(beats(i)%time_recv) // H_TD_END // &
H_TD // dm_itoa(beats(i)%error) // H_TD_END // &
H_TD // dm_itoa(beats(i)%interval) // ' secs' // H_TD_END // &
H_TD // dm_time_delta_to_string(time_delta, hours=.false., minutes=.false., seconds=.false.) // H_TD_END // &
@@ -551,18 +563,22 @@ pure function dm_html_figure(content, caption) result(html)
html = html // H_FIGURE_END
end function dm_html_figure
- pure function dm_html_footer(content) result(html)
- !! Returns HTML footer. The content will not be HTML encoded.
+ pure function dm_html_footer(content, script) result(html)
+ !! Returns HTML footer. The content and the script URL will not be HTML
+ !! encoded. The script element will be placed before the `