Skip to content

pawjy/html-page-components

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HTML page components
~~~~~~~~~~~~~~~~~~~~

* Files

The |src/page-components.js| file implements most elements described
in this document.

The |src/maps.js| and |src/qr-code.js| files implement some elements
described in this document.

The |css/default.css| file describes the default style for these
elements.  Though the file itself is not required to be loaded itself,
some of style rules in the file are effectively required for these
elements rendered as intended.  It only has minumum rules to render
the elements implemented by the scripts.  Additional
application-specific style rules are expected to be added to the
application's style sheet such that the elements are rendered
prettily.

  <link rel=stylesheet href=css/default.css>
  <script src=src/page-components.js async></script>

* Elements

Following elements and API are available once the script has been
loaded:

  <enum-value>
  <button is=command-button>
  <button is=mode-button>
  <button is=copy-text-content>
  <a is=copy-url>
  <can-copy>
  <popup-menu>
  <tab-set>
  <sub-window>
  <toast-group>
  <toast-box>
  <list-container>
  <form is=save-data>
  <before-unload-check>
  <input-datetime>
  <input-tzoffset>
  <sandboxed-viewer>
  <image-editor>
  <table-mapper>
  <template-set>

The following elements are defined in another script files:

  <map-area>
  <qr-code>

** <enum-value>

An |enum-value| element represents one of possible values.

The element may have a |value| content attribute, whose value
represents the element's *value*.  If there is no element specified,
the element's value is |null|.

The element's |hidden| content attribute is set when the element's
value is |null|.  Otherwise the attribute is not set.

When the element's value is not |null|, the element's |textContent|
property value is set to the element's label text.  The element's
label text is the element's |label-/value/| content attribute value,
where /value/ is the element's value.  If there is no such attribute,
the element's label text is the element's value.

** <button is=command-button>

A |button| element whose |is| attribute value is |command-button|
represents a command button.  (Be aware that this implementation does
not support mutation of |is| attribute; it must be set to a value
before the element's insertion into the document.)

The element must have a |data-selector| attribute, whose value is a
selector.

The element must have a |data-command| attribute whose value is the
name of the command.

When the element is clicked, the command specified by the
|data-command| attribute value of the element selected by the
|data-selector| attribute value is invoked.

A command whose name is /name/ for element /element/ can be defined by
setting these two values:

  element.cbCommands[name]   An object.  It can have any property.
  element[name]  A function.  This is the method implementing the command.

** <button is=mode-button>

A |button| element whose |is| attribute value is |mode-button|
represents one of buttons used to select modes of another element.
(Be aware that this implementation does not support mutation of |is|
attribute; it must be set to a value before the element's insertion
into the document.)

The element must have a |data-selector| attribute, whose value is a
selector.

The element must have a |name| attribute.  Its value is the name of
the mode (i.e. one of the property names for the element selected by
the |data-selector| attribute value).

The element must have a |value| attribute.  Its value is the value of
the mode (i.e. the property value for the property identified by the
|name| attribute value).

The |selected| class is added to the element when the mode is set to
the value equals to the |value| attribute value, and is removed when
the mode is set to another value.

The element selected by the |data-selector| attribute is expected to
be fired a bubbling |pcModeChange| event whose |mode| property is set
to the value equal to the |name| attribute value when a new mode value
is set.

** <button is=copy-text-content>

A |<button is=copy-text-content>| element represents a copy button.

When the button is clicked, a text is copied to the clipboard.

The element must have a |data-selector| attribute, whose value is a
selector.  The copied text is the |textContent| property value of the
selected element.

Once copied, a toast whose message is the CSS '--paco-copied-message'
property value, which is a CSS string, is shown.  The toast is a
|toast-box| element with a class |paco-copied|.

** <a is=copy-url>

An |<a is=copy-url>| element represnts a button used to copy a URL.

When the link is clicked, the linked URL is copied to the clipboard.

Once copied, a toast whose message is the CSS '--paco-copied-message'
property value, which is a CSS string, is shown.  The toast is a
|toast-box| element with a class |paco-copied|.

** <can-copy>

A |can-copy| element represents a data that can be copied to the
clipboard.

A |can-copy| element is expected to have a *copied data element*,
which is a |code|, |data|, |time|, or |output| element.  The data
contained by that element is to be copied.

When initialized, a copy button is appended to the |can-copy| element.
The copy button's text content is set to the CSS
'--paco-copy-button-label' property value, which is a CSS string.

The copied text is chosen by the CSS '--paco-copy-format' property
value of the copied data element:

  'auto' (The initial value)

    The copied text is the |textContent| property value of the copied
    data element.

  'unix-tz-json'

    The copied data element must be a |time| element.  The copied text
    is the JSON serialization of the Unix time and time zone offset
    (if specified) of the element in the |unix-tz-json| format
    <https://wiki.suikawiki.org/n/JSON%20Timestamps>.

Once copied, a toast whose message is the CSS '--paco-copied-message'
property value, which is a CSS string, is shown.  The toast is a
|toast-box| element with a class |paco-copied|.

** <popup-menu>

A |popup-menu| element represents a button with popup-menu.  Its
content must be a |button| element followed by a |menu-main| element.

The |button| element child, if any, represents the button which is
associated with a popup menu.  Its |type| attribute should be in the
Button state (i.e. |<button type=button>|).

The |menu-main| element child, if any, represents the popuped menu.
Its content model is phrasing content if any |popup-menu| parent is a
phrasing content, flow content otherwise.

The |open| content attribute of the |popup-menu| element is a boolean
attribute.  It represents whether the popup menu is shown or not.  If
specified, the popup menu, if any, is shown.

A |popup-menu| element has the following method:

  toggle

    If no argument is specified, change whether the element has an
    |open| attribute or not.

    If the argument is true, set the |open| attribute of the element,
    if not yet.

    If the argument is false, remove the |open| attribute of the
    element, if any.

Clicking the |button| element child is equivalent to invoking the
|popup-menu| element's |toggle| method.

While the popup menu is open, clicking outside of the |popup-menu|
element is equivalent to invoking the |toggle| method with argument
false.

Clicking a |button| or |a| element descendant of the |menu-main|
element is equivalent to invoking the |toggle| method with argument
false (unless the |click| event's propagation has been stopped).

When the popup menu is open, or is closed, a bubbling |toggle| event
is fired at the |popup-menu| element.

** <tab-set>

A |tab-set| element represents a set of sections where one of them are
expected to be shown at once and can be switched by user's direction.
Its content model is an optional |tab-menu| element followed by one or
more |section| elements.

A |tab-menu| element represents the menu the user can select the
section to show.  The element content is set to the list of the
anchors corresponding to the sections in the set.  It can be either:

  - A |tab-menu| element child of the |tab-set| element,

  - A |tab-menu| element in the document, pointed by the |<tab-set
    menu-selector="">| attribute, or

  - A |tab-menu| element descendant of the element pointed by the
    |<tab-set menu-selector="">| attribute,

... where |menu-selector=""| attribute value is a selector.

A |tab-menu| element may also contain zero or more |tab-menu-extras|
element children, which can be used to insert additional content to
tab menu.  Any "real" tab menu item is always inserted before the
"extra" elements.

There can be a |tab-menu-active| element.  Whenever a tab section is
shown, its text content is updated to the section's label.  If
|<tab-set menu-selector="">| attribute points a non-|tab-menu|
element, the |tab-menu-active| element can be its descendant.
Otherwise, the |menu-active| element can be a descendant of the
|tab-menu| element.

The |section| child elements represent the sections of the set.  A
|section| element should have a |h1| element descendant, which labels
the section.  The content of that element is used as the label of the
anchor corresponding to the section in the menu.

If there is one or more sections in a set, one of them is selected at
a time.  The selected section has the class |active|.  The anchor in
the menu corresponding to the selected section also has the class
|active|.  No other section or anchor in the menu has the class
|active|.

By default the first section is selected.

Whenever a section is selected, a bubbling |show| event is fired at
the selected section.

If a section has a |data-tab-button-class| attribute, its value is
copied to the |class| attribute of the corresponding anchor in the
menu when the anchor is created.

If a section has a |data-pjax| attribute, its value, resolved relative
to the document URL at the time of the initialization of the element,
represents the URL of the state the section is shown.  The document
URL is changed to that URL when a section is selected (using
|history.replaceState|).  When the element is initialized, when the
|hashchange| event is fired, and when the |pcLocationChange| event is
fired, the document URL is compared with sections' URLs.  If there is
a section with the same URL, that section is selected by default.  If
a section has no |data-pjax| attribute but has a |id| attribute, a |#|
character followed by the |id| attribute value is considered as the
relative URL instead.

Likewise, if a section has a |data-pjax-selecting| attribute, it is
interpreted as a list of space-separated list of URLs resolved
relative to the document URL at the time of the initialization of the
element.  If one of them is equal to the document URL or one of them
is a URL and fragment identifier whose non-fragment parts are equal to
the document URL's and the fragment part is the prefix of the document
URL's prefix, the section is selected by default.  However, unlike
|data-pjax|, the document URL is unchanged.

** <sub-window>

A |sub-window| element represents a window shown within the viewport.
The element has *mode*, which is either |default| or |minimized|,
initialized to |default|.

The element can contain any flow content, optionally preceded by a
|sub-window-minimized| element child, which is the element's
*minimized element*.  If there is no minimized element child, an empty
element is created.

When the mode is set to |default| (including when the element is
initialized), the element is shown and the element's minimized element
is not shown.

When the mode is set to |minimized|, the element is hidden and the
element's minimized element is set to the document's minimized content
element.  If the document has a |sub-window-minimized-container|
element, its the document's minimized content element.  Otherwise, an
empty element is created.

There is following property:

  mode

    On getting, it returns the element's mode.

    On setting, it sets the element's mode to the new value.

    If the element has |pcSetDimension| method, it is invoked whenever
    the mode is set to new value (including when the element is
    initialized) and is expected to modify the element's style
    properties as appropriate.

There can be HTML |button| elements with |data-sub-window-action|
attribute set to one of following values, within the element's
content:

  minimize

    Set the element's mode to |minimized|.

  unminimize

    Set the element's mode to |default|.

** <toast-group> and <toast-box>

A |toast-box| element represents a toast, i.e. a small notification
dialog.

A |toast-group| element can be used to group zero or more |toast-box|
elements such that toasts shown at the same time are rendered in an
appropriate fashion (as controlled by normal CSS rules).  In the
simplest case there is only a |toast-group| element within a document
and any |toast-box| element for that document is appended as a child
of it.

A toast can be closed, i.e. hidden from the viewport, in several ways:

  By default, the toast is closed after 5s has elapsed.  This timeout
  value can be controlled by CSS '--paco-toast-auto-close' property,
  whose value is <time> (such as '10s' or '1500ms').

  A |toast-box| element has a |pcClose| method.  When invoked, the
  toast is closed.

  A |toast-box| element is closed when a |pcDone| event is fired at
  the element (or its descendant and the event bubbles).

  If there is a |button| element whose |is| attribute is
  |toast-close-button| in the |toast-box| element and the button is
  clicked, the toast is closed.

There is the |$paco.showToast| method, which can be used to insert a
|toast-box| element.

** <list-container>

A |list-container| element represents a dynamic list of items.  Its
content model is transparent.

A |list-container| element has a *list*, which is a list of JavaScript
objects.  The list is constructed by the following steps:

  1. Loader.  The loader whose name is equal to the |loader| attribute
     value, whose default is |src|, is invoked for the element with
     the argument of a load options.  A *loader* is a definition of
     type |loader|.

     A loader is expected to prepare the list data (e.g. by fetching
     from the server).  Note that a loader may change its behaviours
     based on the content attributes of the |list-container| element
     (e.g. the built-in |src| loader depends on the |src| and |key|
     content attributes of the list).

     A *load options* is a dictionary of the following values:

       signal : AbortSignal

         The signal that is notified when the current loading
         operation should be cancelled (e.g. when a new loading
         operation is invoked).  The loader may ignore this signal,
         but its result will be discarded.

     While a loader is running, the action status stage is set to
     |loader|.

  2. Filter.  The filter whose name is equal to the |filter| attribute
     value, whose default is |default|, is invoked for the element
     with the arguments of the result of the loader and a filter
     options.  A *filter* is a definition of type |filter|.

     A filter is expected to mutate the loaded data to the structure
     interpretable as list data.

     A *filter options* is a dictionary of the following values:

       signal : AbortSignal

         The signal that is notified when the current loading
         operation should be cancelled (e.g. when a new loading
         operation is invoked).  The filter may ignore this signal,
         but its result will be discarded.

     While a filter is running, the action status stage is set to
     |filter|.

  3. The result of the filter is expected to be a *list description
     object*, which is a JavaScript object with following name/value
     pairs:

       data

         The list, as a JavaScript array.  This value is required.  If
         there is no object, an empty array should be specified.

       reverse

         Whether the |data| is in the reverse order or not.  The
         canonical order is the order the list should show items when
         no option is specified.  The reverse order is the other
         order.

       next, prev

         An object on the next or previous "page", with following
         name/value pairs:

           ref

             An opaque string to identify the page.

           has

             Whether there is the page or not.

           append, prepend

             Whether the page should be appended or prepended to the
             current list or not.  At most one of them can be set to
             true.  If none is set to true, the current list is
             cleared and then the new list items are inserted.

  4. If the |list-container| element has the |reverse| attribute
     specified, the list description object's |data| are to be
     rendered in reverse order.  Otherwise, they are to be rendered in
     their original order.


A |list-container| element has at most one *list item insertion
point*.  When the |list-container| element is *rendered*, any child of
the list item insertion point except for fixed content is discarded
and the list item elements created from the items of the list of the
element using the selected template of the |list-container| element
are inserted into the list item insertion point.  The |list-container|
elements support templates.  List item insertion point, fixed content,
and list item element depend on the |type| attribute value of the
|list-container| element:

  type=table

    List item insertion point: The first |tbody| element descendant of
    the |list-container| element.

    Fixed content: None.

    List item element: A |tr| element.

  type=ul

    List item insertion point: The first |ul| element descendant of
    the |list-container| element.

    Fixed content: None.

    List item element: An |li| element.

  type=ol

    List item insertion point: The first |ol| element descendant of
    the |list-container| element.

    Fixed content: None.

    List item element: An |li| element.

  type=option

    List item insertion point: The first |select| element descendant
    of the |list-container| element.

    Fixed content: None.

    List item element: An |option| element.

  type=datalist

    List item insertion point: The first |datalist| element descendant
    of the |list-container| element.

    Fixed content: None.

    List item element: An |option| element.

  type=tab-set

    List item insertion point: The first |tab-set| element descendant
    of the |list-container| element.

    Fixed content: Any |tab-menu| element child.

    List item element: A |section| element.

  Otherwise

    List item insertion point: The first |list-main| element
    descendant of the |list-container| element.

    Fixed content: None.

    List item element: A |list-item| element.

A |list-container| element is rendered when the element is inserted
and has list item insertion point and selected template, or when a
list item insertion point, selected template, or pager button
descendant is inserted.

After a |list-container| element is rendered, a |pcRendered| event,
which bubbles, is fired at the |list-container| element.

When a |button| element which has a |list-reload| class, the list is
reloaded, which is equivalent to invoking the |load| method with no
explicit option.

There are features that control the element, or its ancestor or
descendants, depending on the number of items rendered by the
|list-container| element:

  A *pager button* is a next page button or a previous page button.  A
  *next page button* is an |a| or |button| element which has a
  |list-next| class.  A *previous page button* is an |a| or |button|
  element which has a |list-prev| class.  A page button's |hidden|
  attribute is set or removed appropriately, according to whether
  there is the next or previous page or not.  When a page button is
  clicked, the list is updated to inculude the previous or next page
  appropriately and the |list-container| element is rendered.  A pager
  button may have |data-list-scroll| attribute, whose value is set to
  the |scroll| dictionary option in the equivalent |load| method call.

  A |list-container| element can have a |hascontainer| attribute
  specified.  If specified, whenever the |list-container| element is
  rendered, the nearest |section| element ancestor's |hidden|
  attribute is updated such that it is hidden if the |list-container|
  element's list has no item.

  A |list-container| element can contain |list-is-empty| element
  descendants.  The content model of a |list-is-empty| element is
  transparent.  Whenever the |list-container| element is rendered, the
  |list-is-empty| element descendants' |hidden| attributes are updated
  such that they are hidden if the |list-container| element's list has
  one or more list items.

A |list-container| element has following members:

  load ({})

    Load and render the list data.  This method is implicitly invoked
    when the element is initialized.  It can also be invoked when the
    list should be reloaded.

    The argument is a dictionary.  If the |scroll| value is set to
    |preserve| in the dictionary, the rendering after the load
    preserves the original human-perceived scroll position where
    possible.

  loadNext ({})

    Load and render the next page.  This is equivalent to clicking a
    next page button.  The |scroll| option can be specified as a
    dictionary argument to the method.

  loadPrev ({})

    Load and render the previous page.  This is equivalent to clicking
    a previous page button.  The |scroll| option can be specified as a
    dictionary argument to the method.

  loaded : Promise

    When the |load| method is invoked, this property value is set to a
    new promise.  The promise is fulfilled when the load is completed.

The |list-container| element supports action statuses.

If a |list-container| element has the |autoreload| attribute
specified, the loader is repeatedly invoked with some intervals.

** <form is=save-data>

A |<form is=save-data>| element represents a form used to submit data
using HTTP |POST| method and |multipart/form-data| MIME type.

As usual, the data is submitted to the |form| element's |action|
attribute's URL.  It must be same origin as the current document,
otherwise no credentials and referrer and origin headers are sent.
Any of |method|, |enctype|, and |target| attribute is ignored, but the
|method| attribute should be set to |POST| and the |enctype|
attribute, if specified, should be set to |multipart/form-data| to
provide better fallback story for environments where scripting is
disabled.  Note that these behaviors can be overriden by specifying a
saver using the |data-saver| attribute.

If the element has a |data-confirm| attribute specified, a confirm
dialog box whose text is the attribute value is shown and the user can
cancel the submission.

If the element has a |data-validator| attribute specified, custom form
validators specified by the attribute are invoked before the
submission.  A *custom form validator* is a definition of type
|formvalidator|.  The custom form validator for an element can be
specified in the |data-validator| attribute as a space-separated list
of custom form validator names.  If multiple custom form validators
are specified for an element, they are invoked in order.  A custom
form validator is invoked with a dictionary argument with following
member:

  formData : FormData

    A |FormData| that is to be submitted.  This object can be examined
    by the custom form validator.

While a validator is running, the action status stage is set to
|formvalidator|.

Once the response to the submission is received, instead of navigation
to the response as in usual forms, any formsaved handler for the
element is invoked.  A *formsaved handler* is a definition of type
|formsaved|.  The formsaved actions for an element can be specified in
the |data-next| attribute as a space-separated list of formsaved
handler names (with optional arguments).  If multiple formsaved
handlers are specified for an element, they are invoked in order.  A
formsaved handler is invoked with a dictionary argument with following
members:

  args : Array

    An |Array| of the formsaved handler name and optional arguments.
    The handler name and arguments can be specified in the |data-next|
    attribute as a |:|-separated string.  The first component (before
    first |:| character) is considered as the handler name and any
    other component is considered as arguments.  All of them are
    provided in this array, in order.

  response : Response

    The |Response| for the form submission's response.

  json : Function<Promise<Object>>

    When invoked, return the result of the |response|'s |json| method.
    Unlike the direct invocation of the |response.json| method, the
    result is cached in this method such that multiple invocations
    would not reject.

While formsaved handlers are running, the action status stage is set
to |formsaved|.

During the form submission (since just before the start of the custom
validations and fetch, until the completion of any formsaved
handlers), any form control is disabled.

In addition to HTML's standard form control elements, autonomous
custom elements can be defined as form controls for the purpose of
this element's form submission by setting the |formcontrol| content
attribute.  Such custom form controls must have |pcModifyFormData|
method at the time of form submission.  The method is invoked with a
|FormData| object.  The method is expected to append name/value
pair(s) to the object before the method is returned (or the promise
returned by the method is fulfilled).  The method can throw (or return
a promise which is rejected) when the custom form control is
considered as invalid.  The custom form control element is expected to
be disabled by setting the |disabled| content attribute.  While custom
form control form data are collected, the action status stage is set
to |formdata|.

The |form| content attribute of form controls are not supported.

The saver for the element can be specified by setting the saver's name
to the |data-saver| attribute of the element.  A *saver* is a
definition of type |saver|.  The saver is invoked with the |FormData|
object representing the form data that should be submitted.  It is
expected to return a |Response| object (or an object whose API is
compatible with |Response|), or a promise which is fulfilled with such
an object.  If it cannot be saved the data, it is expected to throw
(or return a promise which is rejected).  While a saver is running,
the action status stage is set to |saver|.

The |<form is=save-data>| supports action statuses.

The |<form is=save-data>| element can be combined with the
|before-unload-check| element.  When the |form| element (or its
descendant) is dispatched a |change| event, the |data-pc-modified|
attribute is set to the element.  The |data-pc-modified| attribute, if
any, is removed when the element's saver has concluded successfully.

A |<form is=save-data>| element has the following method:

  /element/.pcSendFocus (/e/)

    Focus the element /e/.  During the form submission, form controls
    are disabled such that they cannot be focused.  If this method is
    invoked during the form submission, the focus is sent after the
    submission is done.

    If the method is invoked multiple times during a single form
    submission, earlier focus requests are discarded.  If the form
    submission fails, any focus requests during the form submission is
    discarded.

** <before-unload-check>

A |before-unload-check| element, once inserted into a document,
defines a |beforeunload| event listener.  The event listener sets the
|returnValue| attribute of the event object to a non-empty value
(i.e. asks the browser to show a dialog box to the user) if the
document has a |form| element with a |data-pc-modified| attribute.

** <input-datetime>

An |input-datetime| element represents a date and time input control,
implying a time-zone offset.

An |input-datetime| element has a |value| property, whose value is a
JavaScript number, representing the so-called Unix time seconds.

If the |input-datetime| element has a |value| content attribute, the
attribute value is interpreted as the initial value of the |value|
property of the element.  Otherwise, the initial value is the
00:00:00.000 (i.e. the first instance) of "today".

If the |input-datetime| element has a |tzoffset| content attribute
whose value is a number, it is interpreted from the time-zone offset
from UTC in seconds, where positive numbers mean Asian date while
negative numbers mean American date.  Otherwise, the time-zone offset
is set to the platform's time-zone offset.

The content of an |input-datetime| element is application dependent,
but it must contain a date component element and a time component
element.

A *date component element* is an HTML |input| element whose |type|
attribute is |date|.  When the user changes the value of the element,
the |input-datetime| element's |value| is changed.

A *time component element* is an HTML |input| element whose |type|
attribute is |time|.  It may have a |step| attribute.  When the user
changes the value of the element, the |input-datetime| element's
|value| is changed.

An |input-datetime| element may contain zero or more HTML |button|
elements with |data-dt-type| attribute set to one of following values:

  set

    Set the |input-datetime| element's |value| to the button's
    |value|.  Example:

      <button type=button data-dt-type=set value=12345>Button</button>

  set-now

    Set the |input-datetime| element's |value| to the current time.
    Example:

      <button type=button data-dt-type=set-now>Button</button>

  set-today

    Set the |input-datetime| element's |value| to the 00:00:00 of the
    day.  Example:

      <button type=button data-dt-type=set-today>Button</button>

An |input-datetime| element may contain zero or more HTML |time|
elements.  When the |input-datetime| element is initialized and
whenever the element's |value| property is updated, the |datetime|
attribute value of these |time| elements are set to the value.  This
is compatible with time.js <https://github.com/wakaba/timejs>.

A |change| event and an |input| event can be listened at an
|input-datetime| element when the element's |value| is edited by the
user.

An |input-datetime| element may have a |name| content attribute and
can be used as a custom form element for the purpose of <form
is=save-data>.  The element's |name| content attribute value and the
element's |value| property value are added to the form data set.

** <input-tzoffset>

An |input-tzoffset| element represents a time-zone offset input
control.

An |input-tzoffset| element has a |value| property, whose value is a
JavaScript number, representing the time-zone offset from UTC in
seconds, where positive numbers mean Asian date while negative numbers
mean American date.

If the |input-tzoffset| element has a |value| content attribute, the
attribute value is interpreted as the initial value of the |value|
property of the element.  Otherwise, if the |input-tzoffset| element
has a |platformvalue| content attribute specified, the initial value
of the |value| property of the element is set to the platform's
time-zone offset.  Otherwise, the initial value is 0, i.e. same as
UTC.

The content of an |input-tzoffset| element is application dependent,
but it must contain a time-zone offset sign component element and a
time-zone offset time component element.

A *time-zone offset sign component element* is an HTML |select|
element, which must contain two |option| elements whose |value|s are
|+1| and |-1|.  When the user changes the value of the element, the
|input-tzoffset| element's |value| is changed.

A *time-zone offset time component element* is an HTML |input| element
whose |type| attribute is |time|.  It may have a |step| attribute.
When the user changes the value of the element, the |input-tzoffset|
element's |value| is changed.

An |input-tzoffset| element may contain zero or more HTML |time|
elements.  When the |input-tzoffset| element is initialized and
whenever the element's |value| property is updated, the
|data-tzoffset| attribute value of these |time| elements are set to
the value.  This is compatible with time.js
<https://github.com/wakaba/timejs>'s time-zone offset support.

An |input-tzoffset| element may contain zero or more <enum-value
data-tzoffset-type=sign> elements and <unit-number type=duration
data-tzoffset-type=time> elements.  When the |input-tzoffset| element
is initialized and whenever the element's |value| property is updated,
the |value| attributes of these elements are set to the sign (either
|plus| or |minus|) and the absolute value of the time-zone offset of
the element's |value| property.  This is compatible with
unit-number.js <https://github.com/wakaba/html-unit-number>.

An |input-tzoffset| element may contain zero or more <enum-value
data-tzoffset-type=platformdelta-sign> elements and <unit-number
type=duration data-tzoffset-type=platformdelta-time> elements.  When
the |input-tzoffset| element is initialized and whenever the element's
|value| property is updated, the |value| attributes of these elements
are set to the sign (either |plus| or |minus|) and the absolute value
of the time-zone offset of the element's |value| property, relative to
the platform's time-zone offset.  This is compatible with
unit-number.js <https://github.com/wakaba/html-unit-number>.

A |change| event and an |input| event can be listened at an
|input-tzoffset| element when the element's |value| is edited by the
user.

An |input-tzoffset| element may have a |name| content attribute and
can be used as a custom form element for the purpose of <form
is=save-data>.  The element's |name| content attribute value and the
element's |value| property value are added to the form data set.

** <sandboxed-viewer>

A |sandboxed-viewer| element represents a sandboxed |iframe| viewer.
It can be used as a basis of implementing viewer showing HTML
fragments that might not be secure enough.

If a |sandboxed-viewer| element has a |seamlessheight| attribute, the
element is resized to the height of the content of the sandboxed
|iframe|.

If a |sandboxed-viewer| element has an |allow| attribute, its value is
set to the |iframe|'s |allow| attribute.

If a |sandboxed-viewer| element has an |allowsandbox| attribute, its
value is set to the |iframe|'s |sandbox| attribute, as well as default
values.

A |sandboxed-viewer| element has following member:

  ready

    A promise, which is resolved when the element is ready.

A |sandboxed-viewer| element has following methods:

  pcInvoke (methodName, methodArgs)

    Invoke a method in the sandbox.  Two arguments must be specified:
    the first argument is the method name.  The second argument is a
    dictionary of named arguments.  The dictionary can only contain
    transferrable objects.

    The method returns a promise, which is to be resolved with the
    method's return value, or is to be rejected with the method's
    exception.

    When a sandbox is initialized, these method is available:

      "pcEval", {code: String}

        Evaluate the "code" value of the dictionary argument as a
        JavaScript code in the sandbox.  The JavaScript code is
        interpreted as if it were in the "async function" body.  The
        value returned by the JavaScript code is returned (or thrown).
        Note that the value the |pcInvoke| method's returned promise
        resolved with (or rejected with) is a copy of the value
        returned (or thrown) by the code evaluated within the sandbox.
        It must be transferrable.

    Within a sandbox, the following global function is available:

      pcRegisterMethod (methodName, methodCode)

        Register a method in sandbox.  Two arguments must be
        specified: the first argument is the method name.  The second
        argument is a Function that is the implementation of the
        method.  The function will be invoked with (a copy of) the
        dictionary argument sent from the outside of the sandbox.  The
        value returned by the function (if it is a promise, the value
        the promise is resolved with) must be transferrable.

      pcInvoke (methodName, methodArgs)

        Invoke a method of the element (outside of the sandbox).  Two
        arguments must be specified: the first argument is the method
        name.  The second argument is a dictionary of named arguments.
        The dictionary can only contain transferrable objects.

        The method returns a promise, which is to be resolved with the
        method's return value, or is to be rejected with the method's
        exception.

  pcRegisterMethod (methodName, methodCode)

    Register a method to the element (outside of the sandbox), which
    can be invoked from within the sandbox.  Two arguments must be
    specified: the first argument is the method name.  The second
    argument is a Function that is the implementation of the method.
    The function will be invoked with (a copy of) the dictionary
    argument sent from the inside of the sandbox.  The value returned
    by the function (if it is a promise, the value the promise is
    resolved with) must be transferrable.

** <image-editor>

An |image-editor| element represents an editable image.  Its content
can be one or more |image-layer| elements, representing layers in the
image.  The order of child elements (in tree order) is the layers'
compound order, where an earlier element has smaller z-index.

A *layer* can be an image or a placeholder (which is a transparent
image for the purpose of composition).  A layer has *natural width*,
*natural height*, and *scale factor*.  A |canvas| element is inserted
into a |image-layer| element.  A layer's *computed width* and
*computed height* are natural width and natural height multiplied by
scale factor, respectively.  Layeres are rendered within the image
using computed width and computed height.

Initially, a layer is a placeholder.  The |placeholder| class is set
to the element while it is a placeholder.  If a placeholder layer has
a |useplaceholderui| attribute specified, the user can click the
element to open a user interface to set a image (i.e. manually
invoking the |selectImageFromFile| method).  In addition, the user can
drop an image file to the element to set the image.  When the user is
dragging an image file over the element, the |drop-target| class is
set to the element.  When the user-selected file cannot be loaded as a
valid image, a bubbling |error| event is dispatched at the layer whose
|exception| property is set to the exception representing the
image-loading error.

When a layer is *set* to an image, its natural width and natural
height are set to the image's width and height, respectively, and its
scale factor is set to 1.

A layer has *left* and *top*, which are offsets from the left and top
edges of the parent |image-editor| element, respectively.  They are
both initially set to zero.  If a |movable| attribute is specified to
an |image-layer| element, the layer is *movable*.  If a layer is
movable, its left and top can be modified by dragging the layer, or
using keyboard arrow keys.

A layer has an *anchor point*.  Initially, the anchor point of a layer
is the top left corner of the layer.  If an |anchorpoint| attribute is
set to |center|, the anchor point of a layer is the center of the
layer both horizontally and vertically.  When a layer is set to an
image, the layer's left and top are modified appropriately such that
the anchor point of the layer in the parent |image-editor| element is
preserved.

An |image-editor| element has *width* and *height*.  An |image-editor|
element can have |width| and |height| content attributes, whose values
must be valid floating-point numbers representing width and height in
pixels, respectively.  If specified, they set width and height of the
element and they are not affected by layers' dimension.  Otherwise,
the width is set to the offset of the rightmost layer's right edge
from the left edge of the element and the height is set to the offset
of the bottommost layer's bottom edge from the top edge of the
element.

An |image-editor| element has these object properties:

  height (read-only)

    The element's height, in pixels.

  width (read-only)

    The element's width, in pixels.

An |image-editor| element has these methods:

  getPNGBlob () : Promise

    Serializes the element as a PNG file.  It returns a promise which
    is fulfilled with a Blob of that file.

  getJPEGBlob () : Promise

    Serializes the element as a JPEG file.  It returns a promise which
    is fulfilled with a Blob of that file.

An |image-layer| element has these object properties:

  left (read-only)

    The layer's left, in pixels.

  top (read-only)

    The layer's top, in pixels.

  height (read-only)

    The layer's computed height, in pixels.

  width (read-only)

    The layer's computed width, in pixels.

An |image-layer| element has these methods:

  selectImageByURL (url : String) : Promise

    Set the layer to an image specified by the URL /url/.  It returns
    a promise which is fulfilled once the image has been loaded.  It
    is rejected if the image cannot be loaded.

  selectImageFromFile () : Promise

    Set the layer to an image for the element by showing a user
    interface to choose a file.  It returns a promise which is
    fulfilled once the image has been loaded.  It is rejected if the
    image cannot be loaded.  This is a |command-button| command.

  selectImageFromGooglePhotos () : Promise

    Obsolete.  This method was used to open an image selection dialog
    using the Google Picker API, listing image data from Google
    Photos.  As Google terminates the support for the feature, this
    method now just returns a rejected promise.

    Attributes |data-paco-image-proxy|, |data-google-picker-key|, and
    |data-google-picker-client-id| of the document root |html| element
    were referenced by this method.  They are now obsolete.

  startCaptureMode ()

    Starts the element's *camera capture mode*, if not yet and if
    possible.  While the element is in the camera capture mode, a
    |video| element with class |capture| is inserted in the element.
    This is a |command-button| command.

  endCaptureMode ()

    Ends the element's camera capture mode, if the element is in that
    mode.  This is a |command-button| command.

  selectImageFromCaptureModeAndEndCaptureMode () : Promise

    Set the layer to the current snapshot of the camera image.  It
    returns a promise which is fulfilled once the image has been
    loaded.  It is rejected if the image cannot be loaded.  It
    implicitly invokes |endCaptureMode|.  This is a |command-button|
    command.

  rotateClockwise ()

    Set the layer to the result of rotation of the layer π/2 radian
    clockwise.  This is a |command-button| command.

  rotateCounterclockwise ()

    Set the layer to the result of rotation of the layer 3π/2 radian
    clockwise.  This is a |command-button| command.

  setScale (number)

    Set the scale factor of the layer to the argument and set the
    layer to the scaled variant of the layer.

The |resize| event is fired at an |image-editor| or |image-layer|
element when it is initialized and whenever the its width or height
has been changed.

The |pcImageSelect| event is fired at an |image-layer| element when an
image is set for the element.  The event object has the |element|
property, whose value is an element which contains the image, if any.
It can be an |HTMLImageElement| or |HTMLVideoElement|.  Future version
of this script might also use another kinds of elements.  This is a
hook that can be used for e.g. extracting Exif metadata from the image
data.

The |change| event is fired at an |image-layer| element when the
element is initialized and whenever the layer is set to a new image or
placeholder.

** <table-mapper>

A |table-mapper| element represents a possibly user-configurable
tabular-data mapping tool.  It can be used as a data mapping proxy
converting a tabular data extracted from a CSV file or similar data
source to an application-specific data structure.

It has following methods:

  setRawData (inputData, {
    header: boolean,
  })

    Set the input tabular data.

    The first argument must be an Array whose items are Array values.
    The inner Array values represents rows, which contains cells.  In
    other words, |inputData[/row/][/column/]| is the value in the cell
    (/row/, /column/), if any.

    The second argument is a dictionary of options.  If the |header|
    option is set to |true|, the first row (|inputData[0]|) is
    interpreted as the header row.

  setExpectedStructure (structureData)

    Set the expected structure data.

    The first argument must be an Object of name/value pairs, where
    names are keys of mapped field and whose values are their
    descriptions.  The key is used to determine column to field
    mapping.  The key must not be the empty string.

    For example:

      tm = document.createElement ('table-mapper');
      tm.setData ([
        ["name", "keyword"],
        ["A", "a"],
        ["B", "b"],
      ], {header: true});
      tm.setExpectedStructure ({
        "name": {},
        "keyword": {},
      });

    ... will generate:

      [
        {name: "A", keyword: "a"},
        {name: "B", keyword: "b"},
      ]

    Values can have following properties:

      allowOtherValues : Boolean

        If true and |valueMapping| is also specified, any other value
        than those in the |valueMapping| is marked as in error and the
        field value is not set.

      headerValues : Array?

        An Array of zero or more header values used to determine
        column to field mapping.

        Column to field mapping is determined by these rules:

          1. If the column's header value is equal to a key, the
             column is mapped to that field.

          2. If the column's header value is one of values in the
             |headerValues| array, the column is mapped to that field.

      label : String?

        The human readable name of the field.  If missing, the key of
        the field is used.

      validator : (any, state) => Promise<any>

        A custom validator.

        The value must be a function.  It can directly return a value
        or throw an exception, or can return a promise which is
        resolved with a value or rejected with an error.

        The function is invoked with the cell's value and a state
        object.  If the value is valid, it is expected to return the
        value that should be set to the field.  If the value is
        invalid, it is expected to throw an error object.

        The function can use the state object in any way.  The same
        object is used for the all invocations for one evaluation of
        an input data set.  For example, it can be used to check
        whether there is any duplicate value.

      valueMapping : Object?

        An object describing value mapping as name/value pairs.  If
        the cell's value is found in the object as a name, the field's
        value is set to the name's value instead.

    evaluate () : Promise

      Return a promise, which is resolved when |getComputedData|
      method is ready to return a new data.  The promise is resolved
      after any input data given before the |evaluate| method is
      reflected to |getComputedData|'s result.  Input data given after
      the |evaluate| method, if any, may or may not be reflected.

    getComputedData () : Array

      Get the mapped objects.  It returns an Array containing objects
      generated from the data rows.  An object has |raw| property,
      whose value is the original row Array, and |data| property,
      whose value is the mapped object.

    getComputedInError () : Boolean

      Return whether the mapped object computation is in error or not.

A |table-mapper| element can contain |list-container| element
descendants whose |loader| is |tableMapperLoader|, representing
mapping data:

  If the |loader-type| attribute value is set to |data|, the list is
  expanded with the |getComputedData|'s array items.

  If the |loader-type| attribute value is set to |mapping|, the list
  is expanded with the objects with following properties:

    index : Number

      The index (0-origin) of the column.

    headerValue : String

      The value of the header cell of the column, if any.

    mappedKey : String

      The key of the field the column is mapped to, if any.

    errorCount : Number

      The number of the cells in the column whose values are in error.

    errors : Array

      The array of the errors of the values of the cells in the
      column.

If the |loader-limit| attribute is set to a non-negative integer, the
maximum number of the list items are set to that value.

A |table-mapper| element can contain |select| element descendants
whose |is| attribute values is |table-mapper-header|.  It allows the
user to manually override column to field mapping.  Its content is
expanded with the list of available fields (taken from the expected
structure data).  It can also contain an |option| element whose
|value| is the empty string, representing the column is not mapped to
any field.  The |data-index| attribute specifies the column's index.
The |data-mappedkey| attribute specifies the initial value of the
mapped field's key.  This is the idiomatic example of a column mapping
editor, which can be used in the |loader-type=mapping| list template
as is:

  <select is=table-mapper-header
      data-data-index-field=index
      data-data-mappedkey-field=mappedKey
      data-filled="data-index data-mappedkey">
    <option value>None
  </select>

If a cell's value is in error, the mapped object's |pcError| property
is set to an object and the object's property whose name is the
field's key is set to the error object for the cell's value.
(Therefore the field's key cannot be |pcError|.)

** <template-set>

A |template-set| element is a set of template.  The element itself
represents nothing.  Its content model is one or more |template|
elements.

A |template-set| element must have a |name| attribute, whose name
identifies the set.  The |name| attribute value must be unique within
the tree.

A *template set* can be defined explicitly by a |template-set|
element, or implicitly by an element which *supports templates*.  If
an element that supports template has the |template| attribute, the
template set of the element is the |template-set| element whose name
is the |template| attribute value.  Otherwise, if the element has no
|template| attribute, the element itself is the template set.

The *template map* of a template set is a map whose values are the
|template| element children of the template set.  Their names are the
|data-name| attribute value of the value's |template| element, if
specified, or the empty string.  The |data-name| attribute value (or
the empty string, if not specified) must be unique in the template
set.

The *selected template* for an element is a |template| element chosen
by the template selector specified by the |templateselector| attribute
of the template set (whose default is |default|).  A *template
selector* is a definition of type |templateselector|.  A template
selector is expected to choose a template from the template map.

  For example, in the fragment:

    <list-container>
      <template></template>
    </list-container>

  ... the |list-container| element's tempalte set is the element
  itself and the |template| element child is the selected template.

  In the fragment:

    <list-container template=set1>
    </list-container>
    <template-set name=set1>
      <template></template>
    </template-set>

  ... the |list-container| element's tempalte set is the
  |template-set| element and the |template| element child of the
  |template-set| is the selected template.

When a /name/ element is created from an /object/ using /template/,

  - Its |data-requires| attribute value is interpreted as a
    space-separated list of the definition type-name pair separated by
    |:| required to process the template.

  - Its |class|, |title|, and |id| attribute values are set by
    attributes of /template/, in the same way as the |$fill| function
    (e.g. |data-title-template| attributes are applicable).  The set
    of attributes can be extended by the |data-filled| attribute.

  - Its content is set to a deep clone of the template content of
    /template/.

  - The |$fill| function is invoked with it and /object/.

For example, a template:

  <template data-requires=filltype:unit-number>
    <unit-number type=distance data-field=from-station></unit-number>
  </template>

... will be processed after the |filltype| definition for name
|unit-number| is loaded.

** <map-area>

The |map-area| element represents a map.

To enable this element, the |maps.js| script must be loaded in
addition to the main script:

  <script src=src/page-components.js async></script>
  <script src=js/maps.js async></script>

The following content attributes are available:

  <map-engine controls="">

    How builtin map controls are shown.

    If a |controls| attribute is specified with the empty value,
    default builtin map control is shown.  It is equivalent to
    |controls="scale zoom fullscreen streetview currentposition type"|
    (but might be changed in future).

    If a |controls| attribute is specified to a space-separated list
    of keywords, the respective controls are shown, as follows:

      |currentposition|  "Pan to the current position" button
      |fullscreen|       "Fullscreen mode" button
      |scale|            Scale
      |streetview|       "Open Street View" button
      |togglelegend|     A legend toggle-button control
      |type|             Map type menu (or buttons, if the map's
                         |engine| is |googlemaps|)
      |typebuttons|      Map type buttons, if |type| is also specified
      |zoom|             "Zoom in" and "Zoom out" buttons

    If there is no |controls| attribute, no builtin map control is
    shown.

    For backward compatibility, when the map's |engine| is
    |googlemaps|, the map's |engine|'s default is applied when there
    is no |controls| attribute and no builtin control is shown when
    the |controls| attribute value is the empty string.

    This attribute is ignored when the map's |engine| is
    |googlemapsembed|.

    When the "Pan to the current position" button is clicked but the
    user or the browser does not allow to return the device's
    location, a toast whose message is the CSS
    '--paco-currentposition-failed-message' property value, which is a
    CSS string, is shown.

    A legend toggle-button control is available when the map's
    |engine| is |leaflet|.  When clicked, the button toggles whether
    map legend controls are shown or not.  For the purpose of the
    button, the followings are legends:

      - A scale (|controls=scale|).

      - The timestamp label of a JMA map (<map-area jma>).

      - A |map-controls| element with a |legend| attribute specified.

  <map-area engine="">

    The engine used to render the map.

    If this content attribute is not explicitly specified, one of
    available engines is chosen.  Applications should not rely on the
    default.

    The following value is available:

      engine="leaflet"

        Leaflet <https://leafletjs.com/>.  Note that the script is
        automatically loaded such that the application does not have
        to load it by itself.

    For backward compatibility, the following values are also
    supported.  These values should not be used for new applications.

      engine="googlemaps" [deprecated]

        Google Maps, using the Google Maps JavaScript API.  If this
        engine is used, the API key for the API must be specified to
        the |data-google-maps-key| attribute value of the root element
        (the |html| element).  If there is the
        |data-google-maps-libraries| attribute for the root element,
        its value is used as the |libraries| parameter to the Google
        Maps API.

      engine="googlemapsembed" [deprecated]

        Google Maps, using the Google Maps Embed API.  If this engine
        is used, the API key for the API must be specified to the
        |data-google-maps-key| attribute value of the root element
        (the |html| element).

  <map-area formcontrol=""> : boolean

    Whether the map should act as a position selection form control or
    not.

    If specified, a marker is shown at the "value" point coordinate of
    the map, which can be accessed via the |valueAsLatLon| property
    and through the form submission (see |latname=""| and |lonname=""|
    content attributes).  The marker is draggable unless |readonly=""|
    content attribute is also specified.

    When the marker is dragged by the user, an |input| event, followed
    by a |change| event, is fired at the element.

  <map-area gsi=""> : boolean

    Whether GSI map types are enabled by default or not.

    The GSI map types show the 地理院タイル (GSI Tile)
    <https://maps.gsi.go.jp/development/ichiran.html> map data
    provided by 国土地理院 (Geospatial Information Authority of Japan)
    <https://www.gsi.go.jp/> of the Japanese Government.

    If specified, the attribute value has to be the empty string.

    If the attribute is specified, the |gsi-lang| map type is selected
    by default.

    If the attribute is specified, GSI map types are added to the map
    type menu (see |<map-area controls=type>|).

    For backward compatibility, when the map's |engine| is
    |googlemaps|:

      If the attribute is specified, the GSI standard map is added to
      the list of map type buttons available for the selection.  If
      the attribute value is not the empty string, it is used as the
      label of the button.  If the attribute value is the empty
      string, the default label is used instead.

      When the map type GSI is selected, a |map-credit| element whose
      content is a link to the GSI Web site is displayed as the credit
      of the GSI Tile, as required by GSI.  This element and its
      content can be styled using CSS.

    This attribute is ignored when the map's |engine| is
    |googlemapsembed|.

  <map-area gsititle=""> : string [deprecated]

    The short description of the GSI map type, used as the tooltip of
    the button to switch to the GSI map type.  If not specified, the
    default text is used.  This content attribute is ignored unless
    the map's |engine| is |googlemaps| and the |gsi| content attribute
    is specified.

  <map-area jma=""> : boolean

    Whether the JMA map are enabled or not.

    The JMA map shows the tile images provided by 気象庁 (Japan
    Meteorological Agency) <https://www.jma.go.jp/> of the Japanese
    Government.

    If specified, the attribute value has to be the empty string.

    If the attribute is specified, the JMA map option is added to the
    map type menu (see |<map-area controls=type>|).

    This attribute is ignored when the map's |engine| is |googlemaps|
    or |googlemapsembed|.

  lat="" : Float
  lon="" : Float

    The initial latitude and longitude of the center point of the map.
    The default is zero.

    Any mutation to these attributes result in the map being moved, if
    necessary.

  <map-area latname=""> : string
  <map-area lonname=""> : string

    The form field name for the latitude and longitude of the "value"
    point coordinate of the map.

    The |formcontrol=""| content attribute must also be specified.
    Otherwise, these content attributes have no effect.

    When the containing |form[is=save-data]| element is submitted, two
    form data entries are inserted from the map: (/latname/, /lat/)
    and (/lonname/, /lon/) where /latname/ and /lonname/ are
    |latname=""| and |lonname=""| content attribute values and /lat/
    and /lon/ are |valueAsLatLon| property value's |lat| and |lon|
    values.

  <map-area maptype=""> : string

    Set the map type.  This is a declarative equivalent to the
    |setMapType| method.

  <map-area noimgsrc=""> : URL

    The (absolute or relative) URL of the image that is used when no
    image data is available.  If not specified, the default image is
    used.  This is applied to GSI maps.

  <map-area readonly=""> : boolean

    If specified, the marker for the "value" point coordinate of the
    map is not draggable.

  <map-area tzoffset=""> : number

    The time-zone offset from UTC, represented as a floating-point
    number in seconds, where a positive number mean a time faster than
    UTC.  If not specified, defaulted to the platform's time-zone
    offset.

    This value is used when a timestamp is shown.  See also
    |toggleJMANowc|.

  <map-area zoom=""> : integer

    The zoom-level of the map.  Default is 8.

The following properties are available:

  ready : Promise

    The promise which is fulfilled after the initialization of the
    element.

    Note that the initial drawing of the element might not be finished
    yet.

  explicitTime : integer?

    The timestamp for the map, in Unix time (in seconds).  If no
    explicit timestamp is specified, the |null| value.

    The timestamp is used for the JMA map tile images.

  getMapCenter ()

    Returns the center of the map of the element at the time of the
    invocation.  The returned value is an object whose |lat| is the
    latitude as a number and |lon| is the longitude as a number.

    This method must be invoked after the initialization; otherwise
    the method returns |null|.

  getMapBounds ()

    Returns the bounds of the map of the element at the time of the
    invocation.  The returned value is an object whose |north| is the
    latitude of the northmost edge of the map, |east| is the longitude
    of the eastmost edge of the map, |south| is the latitude of the
    southmost edge of the map, and |west| is the longitude of the
    westmost edge of the map.

    This method must be invoked after the initialization; otherwise
    the method throws an exception.

    This method throws an exception if the |engine| is
    |googlemapsembed|.

  googleMap [deprecated]

    The Google Maps API's |google.maps.Map| object of the map of the
    element.  If the element's map is not a Google Maps API's map, an
    exception is thrown.

    This property getter must be invoked after the initialization;
    otherwise the property getter returns |null|.
    
    This property returns |undefined| unless the |engine| is
    |googlemaps|.

  maGoogleMapTypeGSI : String [deprecated]

    The identifier of the GSI map type, that can be used in Google
    Maps API when the |gsi| content attribute is specified.

  noMapDraggable : boolean

    Whether the map is not scrolled by dragging or not.  Defaulted to
    false.

  pcScroll ({...})

    Change the area shown in the map and the position of the map
    element.

    The argument must be an object with one or more of following
    name/value pairs:

      bounds : {north: float, south: float, east: float, west: float}

        Change the range of the map identified by the latitudes and
        longitudes of the four edges.

      center : {lat: float, lon: float}

        Change the center of the map to the location identified by the
        latitude and longitude.

      ifNeeded : boolean

        If true and |intoView| option is also specified, the map
        element is scrolled into the view, if necessary.

        If true and |center| option is also specified, the center of
        the map is not changed when the location identified by the
        |center|'s latitude and longitude is shown in the current view
        of the map.

      includes : [{lat: float, lon: float}, ...]

        Change the range of the map such that the locations identified
        by the latitudes and longitudes are shown.

      intoView : boolean

        If true, the map element is scrolled into the view.

      setValue : boolean

        If true, the "value" point coordinate of the map is set to the
        |center| coordinate.  The |center| option must also be
        specified.

  setMapType (/mapType/)

    Set the map type.

    The argument must be an identifier of map type, i.e. one of
    followings:

      gsi-english

        GSI's English map
        <https://maps.gsi.go.jp/development/ichiran.html#english>.

      gsi-english-standard

        GSI's English map, if available for the zoom level, or
        fallbacked to GSI's standard map
        <https://maps.gsi.go.jp/development/ichiran.html#std>.

      gsi-hillshade

        GSI's hillshade map
        <https://maps.gsi.go.jp/development/ichiran.html#hillshademap>.

      gsi-hillshade-standard

        GSI's standard map, rendered on the GSI's hillshade map.

      gsi-lang

        Language-dependent.  If the map's language (as specified by
        the |lang=""| attribute) is |en|, same as
        |gsi-english-standard|.  Otherwise, same as |gsi-standard|.

      gsi-photo

        GSI's photo
        <https://maps.gsi.go.jp/development/ichiran.html#seamlessphoto>.

      gsi-photo-standard

        GSI's standard map, rendered on the GSI's photo.

      gsi-standard

        GSI's standard map.

      gsi-standard-hillshade

        GSI's standard map, overlayed on the GSI's hillshade map.

      none

        No map.

    This method is ignored unless the map's |engine| is |leaflet|.

  setMouseHandler ({...})

    Set a set of mouse event handlers.  The argument must be a
    dictionary (object), where there can be these name/value pairs:

      mousedown: Function
      mousemove: Function
      mouseup: Function

    When the method is invoked for multiple times, earlier handlers
    are removed.

    The handlers are invoked with an argument, which is an object with
    following name/value pairs:

      getMouseButton () : string

        Returns the button of the mouse (or equivalent).  Either
        |left|, |right|, or |other|.

      getPoint () : {lat, lon}

        Returns the latitude and longitude of the point on the map
        pointed by the mouse (or equivalent).

  toggleJMANowc (flag, type)

    Set whether the JMA map tile images should be shown over the map
    or not.

    The first argument, /flag/, is a boolean value.  If true, it's
    shown.

    The second argument, /type/, identifies the map image type.

    The following /type/ values are available:

      hrpns

        The 速報版解析雨量タイル画像, which is generated every 10
        minutes.  See:
        <https://www.data.jma.go.jp/add/suishin/cgi-bin/catalogue/make_product_page.cgi?id=KaisekiU>,
        <https://www.jma.go.jp/jma/kishou/know/kurashi/kaiseki.html>,
        <https://www.jma.go.jp/jma/kishou/know/kurashi/kotan_nowcast.html>.

      rain (Default)

        Same as |hrpns|, except that the 降水短時間・15時間予報タイル
        画像 and the 速報版降水短時間予報タイル画像 are used for
        future timestamps. See:
        <https://www.data.jma.go.jp/add/suishin/cgi-bin/catalogue/make_product_page.cgi?id=KosuiTan>.

      thns

        The 雷ナウキャスト画像.  See:
        <https://www.data.jma.go.jp/add/suishin/cgi-bin/catalogue/make_product_page.cgi?id=Nowcast>.

      trns

        The 竜巻発生確度ナウキャスト画像.  See:
        <https://www.data.jma.go.jp/add/suishin/cgi-bin/catalogue/make_product_page.cgi?id=Nowcast>.

    See also: <https://www.jma.go.jp/bosai/nowc/>,
    <https://www.jma.go.jp/jma/kishou/info/coment.html>.

    The tile images are reloaded whenever the new image data is
    available, unless the |explicitTime| property is set.

    When the JMA map is shown, a map control that contains the
    timestamp of the map is shown.  Its formatting should be handled
    by time.js <https://github.com/wakaba/timejs>.  (A demo file
    |demo/map-leaflet.html| has an example.)

  valueAsLatLon : {lat: Float, lon: Float}

    The "value" point coordinate of the map.

    On getting, it returns a new {lat, lon} object.

    On setting, the new value must be a {lat, lon} object.
    
    The "value" point is set by the following operations:

      - Setting the |lat| content attribute.
      - Setting the |lon| content attribute.
      - Setting the |valueAsLatLon| property to a {lat, lon} value.
      - User moving the "value" point marker by dragging.
      - User clicking a point on the map.

Events.

  A |pcRedraw| event, which bubbles, is fired at the element when the
  map's visible area has been changed; e.g., when the map is
  initialized, the map's center has been moved (when |engine| is not
  |googlemapsembed|), the zoom level has been changed (when |engine|
  is not |googlemapsembed|), the map's dimension has been changed
  (when |engine| is not |googlemapsembed|), and so on.  This event can
  be used as the oppotunity to relocate map overlay objects or to
  recalculate any associated data outside of the map.

Element content.  A |map-area| element can contain zero or more
|map-controls| child elements.

  A |map-controls| element represents a set of custom control
  elements, which are placed over the map.

  A |map-controls| element can have a |position| content attribute,
  which indicates the desired placement of the element within the box
  of the map.

  The value must be one of: |left-top|, |left-bottom|, |right-top|,
  and |right-bottom|.

  For backward compatibility, following values are also supported (but
  deprecated): |top-left|, |top-right|, |bottom-left|, and
  |bottom-right|.  If the map's |engine| does not support these values
  (i.e. the map's |engine| is not |googlemaps|), these are interpreted
  as if their counterpart, e.g. |right-bottom| for |bottom-right|.

  For backward compatibility, following values are also supported (but
  deprecated): |left-center|, |right-center|, |top-center|, and
  |bottom-center|.  If the map's |engine| does not support these
  values (i.e. the map's |engine| is not |googlemaps|), these are
  interpreted as if |center| in the values were replaced by |top| or
  |left|.

  If a |map-controls| element does not have any |position| content
  attribute, it is placed as if the value |bottom-right| were
  specified.

  A |map-controls| element can have a |legend| attribute.  If
  specified, the element is a legend for the purpose of legend
  toggle-button controls.

  Note that |map-controls| elements might be reparented whenever
  necessary.

  Any |map-controls| element is ignored when the map's |engine| is
  |googlemapsembed|.

** <qr-code>

The |qr-code| element represents a QR code.  Its content model is
empty.

To enable this element, the |qr-code.js| script must be loaded in
addition to the main script:

  <script src=js/qrcode.js async></script>

The following content attribute is available:

  data = text

    The string encoded by the QR code.  Required.

* Exportable functions

By setting the |data-export| attribute of the |script| element loading
the |page-components.js| to a space-separated list of the function
namespace names, the function namespaces can be exported to the global
scope.  The following functions are available:

  |$fill| namespace

    $fill (root, object)

      Edit any descendant of /root/ with the following conditions:

        An element with |data-field| attribute

          Replace the value of the element by the field value
          specified by the |data-field| attribute.

          For the purpose of this function, the *value* of an element
          /element/ depsnds on the definition of type |filltype| for
          /element/'s local name:

            |contentattribute|

              The value of /element/ is the |value| content attribute
              value of /element/, if specified, or |null|.

              HTML page components' |enum-value| elements are set to
              this mode.

            |idlattribute|

              The value of /element/ is the |value| IDL attribute
              value of /element/.

              HTML |select|, |textarea|, and |output| elements are set
              to this mode.

            |datetime|

              The value of /element/ is the |datetime| attribute value
              and is set to the result of the |new Date (/field value/
              * 1000).toISOString ()|.  If it throws, the |datetime|
              attribute is removed and the |textContent| property
              value is set to the exception.

              In other words, the field value is expected to be a Unix
              time number and the |datetime| attribute is set to its
              global date and time string equivalent.

              In addition, if /element/ has the |data-tzoffset-field|
              attribute, the |data-tzoffset| attribute is set the
              field value for the |data-tzoffset-field| attribute
              value.  If the field value is |null| or |undefined|, any
              |data-tzoffset| attribute is removed instead.

              Note that the |textContent| property value of /element/
              is *not* updated when the |datetime| attribute value is
              changed.  It should be handled by another JavaScript
              codes, such as time.js
              <https://github.com/wakaba/timejs>.

              HTML |time| element is set to this mode.

            |input|
            
              The value of /element/ is the |value| IDL attribute
              value of /element/.  If /element/'s |type| content
              attribute value is |date|, |month|, |week|, or
              |datetime-local|, the value is the result of the |new
              Date (/field value/ * 1000).toISOString ()|, or the
              empty string if /field value/ is not defined.

              HTML |input| elements are set to this mode.

            Any other value

              The |textContent| property value of /element/.

              When the |textContent| property value of /element/ is
              updated, if the new value is the empty string, |null|,
              or |undefined| and there is the |data-empty| attribute
              for /element/, the |textContent| property value is set
              to the |data-empty| attribute value.

          If the element has a |data-filling| attribute, it is
          removed.  This can be used to style the element in an
          indeterminate state.

        An element with |data-/*/-field| attribute

          ... where /*/ is the *target attribute name* and is one of:
          |href|, |src|, |id|, |title|, |value|, |action|, or |class|,
          or is one of names listed in |data-filled| attribute value
          (that is a space-separated list of attribute names).

          The attribute whose name is the target attribute name is set
          to the field value for the |data-/*/-field| attribute value.
          If the field value is |null| or |undefined|, the attribute
          whose name is the target attribute name is removed instead.

          For example,

            <a data-href-field=link data-field=title></a>

          ... with /object/:

            {
              link: "https://example.com/",
              title: "Example Web Page",
            }

          ... is expanded as:

            <a data-href-field=link data-field=title
                href="https://example.com/">Example Web Page</a>

        An element with |data-/*/-template| attribute

          ... where /*/ is the target attribute name (as for the
          |data-/*/-field| attribute).

          The attribute whose name is the target attribute name is set
          to the result of processing the |data-/*/-template|
          attribute value as a value template.

          For example,

            <a data-href-template=https://example.com/{user_id}/{object_id}>

          ... with /object/:

            {
              user_id: 535555,
              object_id: 72534151,
            }

          ... is expanded as:

            <a data-href-template=https://example.com/{user_id}/{object_id}
                href="https://example.com/535555/72534151">

        An element with |data-enable-by-fill| attribute

          The |disabled| attribute, if specified, is removed.  This
          feature can be used to enable the submit button and other
          controls only after other fields are filled in.

        An element with |data-filledprops| attribute

          The attribute value is interpreted as a space-separated list
          of field names.  For each field, the element's property
          whose name is equal to the field name is set to the field
          value, if specified, or null.

          For example, when an element |element| has its
          |data-filledprops| attribute set to |a b c| and the object
          {a: [1, 2], b: "xyz"} is given, |element|'s properties are
          set as following:

            element.a = [1, 2]
            element.b = "xyz"
            element.c = null

    resultString = $fill.string (templateString, object)

      Return the result of processing the *value template*
      /templateString/ with /object/, i.e. a copy of /templateString/
      where any substring |{/field-name/}| is replaced by the field
      value for /field-name/ of /object/ and any substring
      |{url:/field-name/}| is replaced by the percent-encoded (or
      URL-encoded) field value for /field-name/ of /object/.

    The *field value* for /field/ of /object/ is the /field/ property
    value of /object/.  If /field/ contains a |.| character, the
    substring before the character is the property value and the
    remaining substring is interpreted as the field value recursively
    applied to that property value (If the property value is |null| or
    |undefined|, the result is |null|).  For example, field value for
    |abc.def.xyz| is the value of |object.abc.def.xyz|.

  |$getTemplateSet| namespace

    ts = await $getTemplateSet (name)

      Get the |template-set| element whose |name| is /name/.  The
      function returns a promise which is resolved once the template
      set has been inserted into the document.

  |$paco| namespace

    as = $paco.actionStatus (element)

      Create a new action status object with the specified element.

    $paco.download ({...})
    $paco.ondownload = function ({...}) { ... }

      Let download a file.  The argument for the |$paco.download|
      method is a dictionary of following options:

        blob : Blob?

          A |Blob| or |File| to be downloaded.

        fileName : String?

          The file name of the file.

        json : Value?

          A JavaScript value to be serialized into JSON and then
          downloaded.

        mime : String?

          The MIME type of the file.

        string : String?

          A string content of the file to be downloaded.

        url : String?

          An absolute or relative URL of the file to be downloaded.

      Exactly one of |blob|, |json|, |string|, and |url| is required.

      The |$paco.ondownload| is a function that is invoked with a
      dictionary with |url|, which is an absolute URL string, and
      |fileName|, which is a file name string.  By default it lets the
      specified URL to be downloaded as a file.  It can be replaced to
      another function for, e.g., development purposes.

    $paco.showToast ({...})

      Show a toast, i.e. inserting a |toast-box| element into the
      first |toast-group| element in the document.  If there is no
      |toast-group| element in the document, a new |toast-group|
      element is inserted first.

      The arguemnt is a dictionary of following options:

        className : String?

          A string that is used as the |class| attribute value of the
          |toast-box| element.

        fragment : DocumentFragment?

          A |DocumentFragment| node whose content is used as the
          content of the |toast-box| element.

          Note that any |text| option is ignored and no close button
          is inserted by the method.

        text : String?

          A string that is shown as the message of the |toast-box|
          element.

          When specified, the |toast-box| element will have two
          elements: |toast-box-header| and |toast-box-main|.  The
          former has a |<button is=toast-close-button>| element and
          the latter has the text specified by the |text| option.

          The close button's text content is set to the CSS
          '--paco-close-button-label' property value, which is a CSS
          string.

          Note that this option is ignored when the |fragment| option
          is specified.

      Either |text| or |fragment| option is required.

    promise = $paco.upgrade (element)

      Upgrade an element, using any available element definition.

  |$promised| namespace

    promise = $promised.forEach ((item) => { return promise }, list)

      Iterate for each array item in /list/, in order, one after
      another.  The first argument to the |forEach| method is a
      |Function|, which is invoked with each item.  It can return a
      |Promise|, in such case the iteration is not over until the
      promise is fulfilled.  If the function throws, or if the
      function returns a promise which is rejected, the entire
      iteration fails and any remaining item is ignored.  The function
      returns a promise, which is fulfilled when the entire iteration
      is over, or rejected with the exception of the failed iteration.

    promise = $promised.map ((item) => { return promise }, list)
    
      Iterate for each array item in /list/, in order, one after
      another, in a similar way to the |forEach| method.  Unlike the
      |forEach| method, the function is expected to return a value
      (either a non-|Promise| value directly, or by returning a
      |Promise| and resolving it with a value).  The function returns
      a promise, which is fulfillwed with an |Array| of returned
      values of the iterations, in order.

* Definitions

The *definition* is an integration point with another script libraries
and the application.

A definition is represented by an element whose namespace URL is
<data:,pc>.  The definition's *type* is its local name.  The
definition can be registered by inserting the element into the head
element of the document.  There is no way to remove a definition.

The definition's *name* is its |name| attribute value.  A definition
must have a |name| attribute.  The name must be unique for its type.
Predefined names cannot be used as a name.

There are following definition types:

  filltype (string)

    A map entry for |$fill| handling.

  loader (handler)

    A handler for |list-container| element's loader.  It is expected
    to return an object (or a promise fulfulled with an object).

    The |this| value used when the handler is invoked is the
    |list-container| element.  The handler is invoked with the
    argument of the load options.

  filter (handler)

    A handler for |list-container| element's filter.  It is expected
    to return an object (or a promise fulfilled with an object).

    The |this| value used when the handler is invoked is the
    |list-container| element.  The handler is invoked with the
    argument of the result of the previous step.

  formsaved (handler)

    A formsaved handler for |form| element whose |is| is |save-data|.
    It can return a promise.

    The |this| value used when the handler is invoked is the |form|
    element.  The handler is invoked with the dictionary, as described
    in the |form[is=save-data]|'s documentation.

  formvalidator (handler)

    A custom form validator for |form| element whose |is| is
    |save-data|.  It can return a promise.

    The |this| value used when the handler is the |form| element.  The
    handler is invoked with the dictionary, as described in the
    |form[is=save-data]|'s documentation.

    If the result is valid (i.e. the form is ready to be submitted),
    the handler must return (or return a promise that is fulfilled).

    Otherwise, if the result is invalid, the handler must throw (or
    return a promise that is rejected).

  saver (handler)

    A form submission handler for |form| element whose |is| is
    |save-data|.  It is expected to return a |Response| object or
    equivalent, as described in the |form[is=save-data]|'s
    documentation.

    The |this| value used when the handler is the |form| element.

  templateselector (handler)

    A handler for template set's template selector.  It is expected to
    return a |template| element chosen from the argument.  (It cannot
    return a promise and cannot throw any exception.)

    The |this| value used when the handler is invoked is the template
    set.  The handler is invoked with two arguments: the candidate
    template map and the object for which a template should be chosen.
    Note that the template map (which is a JavaScript object used to
    represent name/value pairs) might be empty.

If a definition type is /handler/, it must have a handler.  The
*handler* of a definition is the |pcHandler| JavaScript property
value, which must be a JavaScript function.

If a definition type is /string/, it must have a content.  The
*content* of a definition is the |content| content attribute value.

There is a predefined loader: |src|.  It fetches the JSON file whose
URL is the |src| attribute value and returns the value for name
specified by the |key| attribute.  For example,

  <list-container src=data.json key=users>
    <template><p data-field=name></template>
    <list-main></list-main>
  </list-container>

  data.json:
  {
    "users": [
      ["name": "Hanako"}
    ]
  }

... will result in:

  <list-container src=data.json key=users>
    <template><p data-field=name></template>
    <list-main><list-item><p data-field=name>Hanako</p></list-item></list-main>
  </list-container>

There is a predefined filter: |default|.  It replaces the input's
|data| to the result of |Object.values (/input/.data)| if the input's
|data| is not a JavaScript |Array|.

There are predefined formsaved handlers:

  fill:{selector}

    Run the |$fill| function for the first descendant element
    identified by the selector specified as the first argument, with
    the response returned by the form's saver (i.e. the server's
    response in case of the default saver) interpreted as a JSON data.

  focus:{selector}

    Focus the first descendant element identified by the selector
    specified as the first argument, using the |pcSendFocus| method.

  go:{templateOfURL}

    Navigate to the URL specified as the first argument
    /templateOfURL/, processed as value template with form response
    interpreted as a JSON data.  Please note that /templateOfURL/
    cannot contain the |:| character (i.e. it cannot be an absolute
    URL) as it is the argument separator.

  reset

    Reset the form.

* Action statuses

Several elements support action statuses, i.e. they can contain zero
or more |action-status| elements as its descendants.  Such elements
are used to show the progress of actions.

The |hidden| content attribute is set to an action status element,
depending on whether a status should be shown to the user.

The |status| content attribute is set to |ok| if an action has
successfully completed, set to |ng| if an action has errorneously
completed, or left unset otherwise.

If an |action-status| element is empty when an action is started, its
content is filled by |action-status-message| and |progress| elements.

Any |progress| element descendants are used to show progress bars.  If
there is no ongoing action, the |hidden| content attribute is set.

Any |action-status-message| element descendants are used to show the
current status message.  If there is no useful message, the |hidden|
content attribute is set.

If an action has successfully completed, the |ok| content attribute
value of the element is set to the current status message, if any.

If an action has failed with an exception, the stringification of the
exception is set to the current status message.  In addition, a
non-bubbling |error| event whose |pcError| property is set to the
exception is fired at the |action-status| element.

If an action has entered in a stage, the |status-/stage/| content
attribute value, where /stage/ is the stage's name, is set to the
current status message, if any.

* Application-specific elements

An element's implementation can be defined by inserting an |element|
element in the <data:,pc> namespace whose property |pcDef|'s value is
the definition of the element into the |head| element.

  For example, the |my-element| element can be defined by the
  following code:

    var e = document.createElementNS ('data:,pc', 'element');
    e.pcDef = {
      name: 'my-element',
      props: {
        pcInit: function () {
          var myattr = this.getAttribute ('myattr');
          ...
        },
        myMethod: function () {
          ...
        },
      },
    };
    document.head.appendChild (e);

For an autonomous custom element (i.e. a custom element with its own
name), the definition's |name| must be specified to the element name.
For a customized built-in element (i.e. a standard HTML element with
the |is| attribute), the definition's |name| must be specified to the
element name and the definition's |is| must be specified to the |is|
attribute value.  Any element inserted into the document before or
after the definition is initialized as specified by the definition.

The definition has following name/value pairs:

  name (string, required)

    The element name.

  is (string)

    The |is| attribute value.  This field must be specified if |name|
    does not have |-| in its value.  This value must have |-| in its
    value.

  props (dictionary)

    The additional properties for the element.  The properties
    specified here are copied into the element when the element is
    initialized.

    If there is a |pcInit| property, the |pcInit| method of the
    element is invoked upon initialization.

  templateSet (boolean)

    If the value is true, the element is initialized as a template set
    just before any |pcInit| method is invoked.  The element's content
    attributes |template| and |templateselector|, as well as its
    |template| element children, are interpreted as part of the
    template set for the element.  (Note that |template| and
    |templateselector| attributes must be set before this function is
    invoked.)  This option is only available to autonomous custom
    elements (i.e. when |name| is specified but |is| is not
    specified).

    A |pctemplatesetupdated| event is fired at the element whenever
    its template set's definition is updated such that any content
    created using the template might need to be updated.  The event is
    fired with an event object whose |pcTemplateSet| property is the
    template set for the element.  (Note that the |pcTemplateSet|
    value might not be the same object as the element when the
    |template| attribute is specified.)

    A template set object has the |createFromTemplate| element, which
    returns an element created from the selected template.  The method
    requires two arguments: the name of the element to be created and
    the object used to select and to fill (by |$fill|) the template.

* Development

To run a Web server for development and testing:

  $ ./lserver

... and then open the URL shown in the browser.

* Author

Wakaba <wakaba@suikawiki.org>.

* History

The Git repository was at
<https://github.com/wakaba/html-page-components> until 22 November
2023.

* License

Copyright 2017-2023 Wakaba <wakaba@suikawiki.org>.

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Affero General Public License for more details.

You does not have received a copy of the GNU Affero General Public
License along with this program, see <https://www.gnu.org/licenses/>.

Note that some files in this repository might be licensed under
different terms.  See the license statements contained in those files
and "LICENSE" files in relevant directories.