*Project* Anubis
*Title* Making interactive Web sites.
*Copyright* Copyright (c) Alain Prouté 2004-2005.
Copyright (c) Calexium 2007-2017.
Copyright (c) David René 2007-2019.
*Authors* Alain Prouté
David René
Jérémy Larrieu
Julien Verneuil
*Revised* May 2015
*Overview*
In this file we propose simple tools for making well structured interactive and secured
web sites.
----------------------------------- Table of Contents ---------------------------------
* (1) Structure of a web site.
** (1.1) Three sorts of data.
** (1.2) How requests are handled.
** (1.3) What web pages are made of.
** (1.4) Actions.
** (1.5) States.
* (2) Carrying on.
** (2.1) Describing your web sites.
** (2.2) Directories on the server's disk.
** (2.3) Starting your web sites.
* (3) The HTML interface.
** (3.1) Types used by the HTML interface.
** (3.2) ``in form'' versus ``off form''.
** (3.3) Defining your own style.
** (3.4) Actioners and forms.
** (3.5) Local popup.
---------------------------------------------------------------------------------------
transmit tools/basis.anubis
read tools/printable_tree.anubis
read tools/base64.anubis
read tools/random.anubis
read tools/dictionaries.anubis
read system/lists.anubis
read system/string.anubis
read system/logger.anubis
transmit CXM_common.anubis
transmit CXM_multihost_http_server.anubis
read web/mime.anubis
read calexium_lib/web/plugin/plugin.anubis
read CXM_cookies.anubis
read CXM_json.anubis
transmit CXM_web_dump.anubis
transmit CXM_web_arg_utils.anubis
transmit CXM_web_session.anubis
transmit CXM_web_action.anubis
transmit calexium_lib/web/types/web_action_name.anubis
transmit calexium_lib/web/types/making_a_web_site.anubis
//TODO move anywhere
define List(Word8)
/** Test for HTML entity which must be encoded
* and return the encoded entity if needed
*/
get_entity
(
Word8 _char,
List(Word8) tail
)=
//test for the ampersand
if _char = '&' then
//test if it's already an encoded string like & < etc. In that case we do nothing
if insensitive_equal(['&','a','m','p',';'], tail, 0) then [_char]
else if insensitive_equal(['&','l','t',';'], tail, 0) then [_char]
else if insensitive_equal(['&','g','t',';'], tail, 0) then [_char]
else if insensitive_equal(['&','q','u','o','t',';'], tail, 0) then [_char]
else
[';','p','m','a','&']
//test for '<' etc.
else if _char = '<' then [';','t','l','&']
else if _char = '>' then [';','t','g','&']
else if _char = '\"' then [';','t','o','u','q','&']
else [_char]
.
define String
_HTML_encode_entities
(
List(Word8) source,
List(Word8) current
)=
if source is
{
[] then implode(reverse(current)),
[c . t] then
_HTML_encode_entities(t, get_entity(c, t) + current)
}
.
public define String
encode_HTML_entities
(
String source
)=
_HTML_encode_entities(explode(source), [])
.
//public define String
// encode_HTML_entities
// (
// String source
// )=
//.
//read CXM_html_tooltip.anubis
* (1) Structure of a web site.
First of all we need to explain what a web site should be made of. Ideally, the
visitor (also called the 'client') should see the web site working as any other
interactive computer software. So, it should be clear that a 'session' (i.e. a visit
to the web site, including the consultation of several pages) is some kind of
conversation between the visitor and the web site, and that the web site should
maintain a 'current state' of this conversation. At each new request (click) from the
visitor, this state must be updated. This whole conversation is called a 'session' and
should not be confused with a single request.
** (1.1) Three sorts of data.
All the data needed for putting a web site at work may be dispatched into three
categories:
1. Constant data (data that never change). These data may be hard coded into the
Anubis source files of the web site.
2. Permanent data (data which always exist independantly of the users connected to
the web site). These data are normally recorded into data bases.
3. Session data (data which depend on a particular visitor and which exist only
during the time he visits the web site). These data are stored into so-called
'states'.
It is important to determine which data belongs to which category. This is part of your
design decisions.
** (1.2) How requests are handled.
We want to separate the following two functionalities (which are used at each request
(click) during a single session):
- computing the new state from the previous state and from the client request, and
updating the data base,
- computing the page to be sent to the client from the new current state and from
the informations in the data base.
The next picture shows the structure we have in mind:
request +---------+ HTML page (with state name in cookie)
.-------------------| client |<--------------.
| .-----------------| | |
| | session +---------+ |
| | in cookie |
| | | client side
............................................................................
| | | server side
| | |
| | .-------------------. |
| | | previous session | |
V V V | |
+---------------+ +---------------+ +--------------+
| compute state | | server's disk | | compute page |
+---------------+ +---------------+ +--------------+
^ | | ^ ^ ^ ^ ^
| | | | | | | |
| | `--------------------+--------------------' | |
| | new state | | |
read | `------------------------+--------------------' |
write | new state name |
update V |
+-----------+ |
| data base |--------------------------------------------'
+-----------+ read only
When the client begins a session, there is no previous state. In this case, a default
'initial state' is used instead.
The data base may be updated by 'compute state' box, but should not be update by the
'compute page' box. The 'compute page' box should be allowed only to read the data
base.
In this file, all the above stuff is defined, except the 'compute state' and 'compute
page' boxes. You just have to provide the function for computing a new state (compute
state) and the function for computing the page (compute page) from the new state. You
don't have to worry about state names, saving and retrieving states and the like.
** (1.3) What web pages are made of.
What the client can see in his browser's window may be called a 'page'. Within a page,
we have several sorts of components:
- 'local' components, i.e. all components which do not open a connection, like
texts, images, etc... possibly using JavaScript programmation,
- 'actioners', which, when clicked upon, open a connection with our web site; they
may appear as links or buttons, etc...
- 'foreign links', which when clicked upon, open a connection with another web site
(or ours eventually).
Of course, what an actioner does is just ask our web site to perform an action. To that
end, the actioner essentially sends the name of the action to be performed. However, it
may be necessary to provide additional informations which may be seen as 'operands' of
the action. In order to attach operands to an action, HTML provides the notion of
'form'. Indeed, a form contains essentially a set of input fields into which the client
may put values for the required operands of the action, and a submit button, which is
the actioner itself. Notice that a single form may contain several submit buttons,
which simply means that there are several distincts actions taking the same set of
operands.
Restrictions must be put on the use of all theses gadgets. Indeed, for example,
putting a form within another form is officially meaningless in HTML, and the client's
browser may be seriously disturbed by this. In this file, we propose an interface to
the HTML language, which forbids such meaningless things, simply by imposing a strict
typing of HTML concepts.
Each web site may be accessible through two communication channels:
- a non secured channel (HTTP),
- a secured channel (HTTPS).
Nevertheless, the whole thing should be considered as a single web site. For example,
you may have a secured page, obtained through HTTPS, containing public images obtained
through HTTP. An actioner in a non secured page may open a secured connection, and
conversely.
Summarizing, a web page is made of local elements, foreign links and actioners.
Actioners receive operands from forms, and they also choose to communicate through the
non secured or through the secured channel.
+-------------------+
| page |
| | +---------------+
| +--------------+ | | next page |
| | form | | | (non secured) |
| | +----------+ | | HTTP | |
| | | actioner |---------------------------->| |
| | +----------+ | | +---------------+
| | | |
| | +----------+ | | +---------------+
| | | actioner |---------------------------->| next page |
| | +----------+ | | HTTPS | (secured) |
| | | | | |
| +--------------+ | | |
| | +---------------+
| |
+-------------------+
Notice that actioners need no be necessarily put into forms. In that case, they work as
ordinary links, but they still may receive operands as we shall see.
** (1.4) Actions.
The client opens a new connection with our web site whenever he clicks on an
actioner. The result is that a request is sent, essentially made of a list of 'web
arguments'. Each web argument is a pair (name,value). One of these web arguments, the
'action' web argument (whose name is "a"), determines the action to be performed. The
other web arguments (not including "s", used to identify the state) are the operands
for this action.
Hence, the 'compute state' box in the picture above, splits naturally into as many
sub-boxes as there are actions. For this reason, we define the following type for
representing actions (where '$State' is the type representing session informations):
'http_action's are executed only under HTTP, and 'https_action's are executed only
under HTTPS. 'http_https_action's may be executed under both types of connections.
Each action has a name, which is used to identify the action. Each action also has a
function 'allow' whose job is to verify that the action is allowed in the current
state, and a function 'do_it' for performing the action. The function 'do_it' receives
a lot of informations:
- 'HTTP informations':
- the IP address of the client,
- the URI requested by the client (after redirection),
- the list of HTTP headers generated by the client's browser,
- the list of web arguments sent by the client (except "s" and "a"),
- the previous state (or the 'initial' or 'ticket expired' state if no previous
state can be found).
In most cases, HTTP informations are not used. This is the reason why they are gathered
for simplicity into a unique datum of type 'HTTP_Info'.
When you define your web site, you must provide the list of all the actions of the
site. When a new state has been computed, a graphical representation of this state
must be sent to the client. To that end, you must provide a function (named below
'compute_page') of type:
$State -> HTTP_Answer
where the type 'HTTP_Answer' (defined below in this file) abstractly represents HTML
pages.
//public type HTTP_Answer:...
It should be clear that states and pages are deeply linked together. Indeed, we really
understand the page shown to the client as a representation of the current state of the
conversation between the client and the web site, but also containing informations
taken from the data bases.
//public type HTML_Partial_Content:...
public define WEB_Controller_Result
ajax
(
HTTP_Answer http_answer
)=
ajax(failure, http_answer)
.
public define WEB_Controller_Result
ajax
(
WEB_Session session, //modified session
HTTP_Answer http_answer
)=
ajax(success(session), http_answer)
.
public define WEB_Controller_Result
ajax
(
HTML_Partial_Content content
)=
ajax(failure, content, "").
public define WEB_Controller_Result
ajax
(
HTML_Partial_Content content,
String additional_script
)=
ajax(failure, content, additional_script).
public define WEB_Controller_Result
ajax
(
WEB_Session session, //modified session
HTML_Partial_Content content
)=
ajax(success(session), content, "").
public define WEB_Controller_Result
ajax
(
WEB_Session session, //modified session
HTML_Partial_Content content,
String additional_script
)=
ajax(success(session), content, additional_script).
public define WEB_Controller_Result
ajax
(
Printable_tree content
)=
ajax(failure, content, "").
public define WEB_Controller_Result
ajax
(
Printable_tree content,
String additional_script
)=
ajax(failure, content, additional_script).
public define WEB_Controller_Result
ajax
(
WEB_Session session, //modified session
Printable_tree content
)=
ajax(success(session), content, "").
public define WEB_Controller_Result
ajax
(
WEB_Session session, //modified session
Printable_tree content,
String additional_script
)=
ajax(success(session), content, additional_script).
public define WEB_Controller_Result
renderer_content(
HTML_Partial_Content content,
)=
renderer_content(failure, content)
.
public define WEB_Controller_Result
renderer_content(
WEB_Session session, //modified session if success else failure
HTML_Partial_Content content,
)=
renderer_content(success(session), content)
.
public define WEB_Controller_Result
redraw(
HTML_Partial_Content content,
)=
redraw(failure, content)
.
define List(HTTP_header)
make_session_cookie_headers
(
String website_name,
String session_name
)
=
//println("Set-Cookie state_"+website_name+"="+state_name);
[
http_header("Set-Cookie", "session_"+website_name+"="+session_name)
]
.
define WEB_Session -> String // the function constructed returns the name of the state
make_save_session_function
(
Int timeout,
String state_directory,
(LogLevel, String) -> One logger
) =
(WEB_Session s_var) |->
//Set the new timeout
with time_stamp = now+timeout,
s = to_WEB_Session_No_Var(s_var),
to_be_saved = (time_stamp,s),
//generate new session name
//session_name = to_ascii(sha1(s)),
session_name = s_var.session_id,
//println("make_save_state_function " + state_directory+"/s"+state_name);
if save(to_be_saved,state_directory+"/"+session_name) is ok then
logger(logInfo, "----- session ["+session_name+"] saved"+dump_WEB_Session_Fields(*s_var.fields));
session_name
else
logger(logError, ("Cannot create session file in '"+state_directory+"'.\n"));
""
.
When a request arrives, we need to retrieve the previous state from the server's
disk. We receive the name of that state. If the state is out of date, the state file is
kept 3 days, and then deleted.
type Previous_Session:
not_found, // cannot retrieve the previous state
out_of_date(WEB_Session p_session), // the previous state is out of date
still_valid(WEB_Session p_session). // the previous state is still valid
define Previous_Session
retrieve_session
(
HTTP_Info http_info,
String session_directory,
String website_name
) =
if find_cookie("session_"+website_name, server_get_cookies(http_headers(http_info))) is
{
failure then not_found
success(cookie) then
//println("find_cookie(\"state_"+website_name+"\" success");
with session_name = value(cookie),
with file_path = session_directory+"/"+session_name,
//unserialize the stored session and his timeout value
//println("retrieve session ["+session_name+"]");
if (RetrieveResult((Int, WEB_Session_No_Var)))retrieve(file_path) is ok(d) then
(
//println("retrieve session OK ["+session_name+"]");
since d is (time_stamp, s_no_var),
with s = to_WEB_Session(s_no_var),
if time_stamp < now then
(
forget(remove(file_path));
out_of_date(s)
)
else
still_valid(s) // state has been successfully retrieved
)
else
not_found
}
.
define (List(String) file_names) -> One
make_delete_out_of_date_sessions_function
(
String state_directory,
(LogLevel, String) -> One logger
) =
(List(String) file_names) |-df->
if file_names is
{
[ ] then unique,
[h . t] then
if h = "." | h = ".." then
df(t)
else
with file_path = state_directory+"/"+h,
if (RetrieveResult((Int, WEB_Session_No_Var)))retrieve(file_path) is ok(d) then
(
if d is (time_stamp, data) then
if time_stamp < now then
//println("session "+h+" out date will be deleted timestamp ["+time_stamp+"] now ["+now+"]");
(forget(remove(file_path));
df(t))
else
//println("Session "+h+" still valid ["+time_stamp+"] now ["+now+"]");
df(t)
)
else
logger(logError, "Can't retreive session "+h+", hence will be deleted");
(forget(remove(file_path)); df(t))
}.
define One
delete_out_of_date_sessions // for all web sites
(
List((String, List(String) -> One)) directories_and_functions
)=
if directories_and_functions is
{
[ ] then unique,
[h . t] then
since h is (state_directory, function),
function(directory_list(state_directory,"*"));
delete_out_of_date_sessions(t)
}
.
** (1.5) States.
Now, we explain how you can define the type (say 'State') to be used as an instance of
the type parameter '$State'. The following is just a suggestion.
Each state determines a page (since 'compute_page' computes a page from a
state). However, some components of the state may be independant of the page. It may be
the case for example for the indication of the natural language used by the
client. Hence, a state should be made of (at least) two parts:
- informations which are the same for all pages,
- informations which are particular to each page.
For example, you could define:
type Page: // one alternative per page, with particular informations
login(...), // in the components
main_page(...),
...etc...
Now, the type 'State' could be defined as follows:
type State:
state(Language, // informations valid for all pages
...,
Page). // informations particular to a page
However, if you are making a secured web site within which clients should be identified
(by id and password), it may be a good idea to have two sorts of states, one for non
identified clients and one for identified clients. In this case, define the type
'State' as follows (this is just a suggestion):
type State:
non_identified(Language),
identified(String id,
Language,
Page).
When a request arrives, check if the previous state is 'identified(...)' or
'non_identified(...)', and don't provide access to certain pages to non identified
clients. This is required for security.
Some more words on security. If your site needs to identify clients, define the
initial state as 'non_identified(...)'. Construct a 'login' page, and check the id and
password of the client. If the id and password are correct, then change the state of
the client to 'identified(...)'. No other action should be able to do that. Now, be
confident that clients cannot forge states. The only information they have is the name
of a state, not the state itself which is never sent over the network, but only stored
on the server's disk. The name of the state is constructed using strong cryptographical
methods (sha1). If everything (since the 'login' page) is performed under HTTPS, even
state names cannot be seen by a third party. So, if the system retrieves a previous
state of the form 'identified(...)', you can be confident that your client is well
identified, and you can send him confidential informations.
States have a limited life time. It may happen that a client clicks on a button at a
time its state is out of date. In this case, this system considers that the new state
is a special state named 'ticket expired'. You must provide a function producing this
state when you describe your web site. The page corresponding to this state must just
inform the client that he/she waited a too long time before clicking on a button, and
has to restart (a new conversation) from the begining.
* (2) Carrying on.
** (2.1) Describing your web sites.
Before you may start your web site, you must describe it, i.e. produce a datum of the
opaque type 'Web_Site'.
public type Web_Site:...
Producing such a datum may be performed by:
public define Web_Site
make_web_site_description
(
List(String) common_names, // for example: ["www.our-business.com",
// "192.168.0.1"]
// the second one is just for testing
String site_directory, // where 'public' and other directories are
// located (should NOT end with '/')
String state_directory,
One -> One init,
(HTTP_Info,
List(Web_arg),
Bool is_https) -> $State initial_state,
($State expired,
Maybe(String),
HTTP_Info,
List(Web_arg),
Bool is_https) -> $State ticket_expired_state,
(Maybe(String),
HTTP_Info,
List(Web_arg),
Bool is_https) -> $State ticket_lost_state,
List(Web_Action($State)) actions,
$State -> HTTP_Answer compute_page,
$State -> List(HTTP_header) additional_headers,
List(HTTP_header) constant_additional_headers,
Int timeout, // seconds (todo: minutes)
Redirections redirections,
String charset,
List(String) journal_extensions,
List(String) journal_headers,
String authorization_secret,
List(MIME) known_mime_types,
(String action_name,
List(Web_arg) args)-> One before_send_file
).
Explanations:
'common_names' is the list of names of the site (the name the browser must send as the
value of the 'Host' HTTP header in order to access the site must be in that list). Such
a name generally looks like this:
www.somewhere.com
If you are using HTTPS, you also have an 'X.509 SSL server certificate'. The name of
the site must be exactly the same as the name on the certificate (which is precisely
called the 'common name' in the X.509 jargon). If the two names do not match, the site
will still work, but the transaction will not be transparent to the client. His browser
will complain that the name of the certificate does not match the name of the site, and
he will have to accept the certificate manually.
'site_directory' is the absolute path to the directory where the files needed by the
site are located. Usually this directory looks like:
my_anubis/web_sites/www.somewhere.com
However, this information is not computed from 'common_name', so that you can change
the common name (for example temporarily, for networking reasons) without loosing
access to the files.
'ticket_expired_state(expired_state,http_info,lwa,is_https)' must produce the state
whose graphical representation is a page explaining to the user that its 'ticket' (or
'session information') has expired, and that he/she must close all popup windows and
start a new session. The arguments of the function contain the previous (expired)
state and all current informations concerning the user. This arguments may be useful
for example for producing the expiration message in the language chosen by the user.
You can also (and this may be much smarter) send a 'ticket prolongation page'
(including a new login for example), and resume the same conversation, since you have
all the pertinent informations at hand. In the case the ticket is definitely lost, the
second fonction 'ticket_lost_state' is used.
Notice that despite the fact that the parameter $State is involved in the arguments of
the above function, the type 'Web_Site' does not depend on this parameter. This allows
to produce lists of web site descriptions, where each description may be constructed
with a different instance of $State. This is required because distinct sites must have
distinct types of session informations. This is made possible by the fact that the
type is obscure, and the constructor replaced by a function which assembles
'ticket_expired_state', ticket_lost_state', 'actions' and 'compute_page' into a single
entity not depending on $State. You should have a look to the private part of this file
if you want more precisions about this programming technique.
'charset' is a string which will determine the character encoding to be used by the
browser. Typically, this string is one of: "UTF-8", "ISO-8859-1", "Windows-1252",
etc...
'before_send_file' is a function which is executed just before the HTTP server sends a
file. It gets an action name and the web arguments received with the request for that
file. Notice that this action name and these web arguments may be put into a
'private_download' element, and will come back to the server at the time of the
download.
** (2.2) Directories on the server's disk.
The description of your site contains the name of the directory within which the
required files are located. This may be for example:
my_anubis/web_sites/www.our-business.com/
This is called the 'site directory' (for the given site). Within the site directory,
the following directories are created by this program:
states
public
journal
private_download
upload_temporary
The directory 'states' is used for storing states (session informations). Out of date
states are automatically removed after some time.
The tree rooted at 'public' contains files that the server is allowed to send to the
clients. For security reasons, the server never sends a file which is not within the
tree whose root is this 'public' directory (except for the 'private download' mecanism;
see 'web/multihost_http_server.anubis'). Also, the MIME type (see 'web/mime.anubis')
must have been recognized before the file may be sent.
The directory 'journal' contains the jounal files. The roles of the remaining
directories 'private_download' and 'upload_temporary' is explained in
'multihost_http_server.anubis', where you will also find further informations on
'public' and 'journal'.
** (2.3) Web servers parameters.
The web servers have several parameters useful for administration. They are described
as follows:
public type WebServersParameters:
wsparms(Var(Bool) shutdown_required,
** (2.4) Starting your web sites.
When you have described all your web sites (you may want to have several web sites, and
they are distinguished by their 'common name'), you may start them all together using
'start_web_sites' below. This function returns a result of the following type:
public type Start_Web_Sites_Result:
cannot_bind_to_port(Word32),
cannot_bind_to_port(Word32,Word32),
ok(Server http_server,
Server https_server).
Indeed, it may happen that the system cannot bind (begin to listen) to one of the two
ports (or to both). The main reason is that another server is already listening on that
port. Another reason may be that 'anbexec' has not been correctly installed, i.e. that
the 's' bit has not been set for 'user' and 'group' (there is not such problem under
Windows). Also notice that the Linux kernel may need a rather long time (up to several
minutes) before liberating a listening port. Now, if the system can bind to the two
ports, the pair of the two servers is returned. Two tools are useful for manipulating
servers:
shutdown of type Server -> One
is_down of type Server -> Bool
They are defined in 'predefined.anubis' (together with the type 'Server').
public define Start_Web_Sites_Result
start_web_sites
(
Word32 ip_address, // the IP address shared by the web sites
Word32 http_port, // usually: 80
Word32 https_port, // usually: 443
String ssl_certificate_common_name,
List(Web_Site) web_sites, // web sites to be started
(One) -> Bool shutdown_required
).
'ip_address' is the IP address on which the two servers listen. If you put 0, the
servers listen on all the IP addresses of the machine. This may be useful if the
machine has several network interfaces.
'ssl_certificate_common_name' is the common name of the SSL certificate that 'anbexec'
loads when it starts. One instance of 'anbexec' cannot handle more than one SSL server
certificate. This is due to a problem of conception of SSL itself. See the book 'SSL
and TLS' by Eric Rescorla (at Addison Wesley) for more explanations.
Notice that the number of servers is always 2, regardless of the number of web sites
you are starting.
The dynamic variable 'shutdown_required' may be used to control the shutdown of the two
servers from within the web site (typically the administration part). The servers will
shutdown as soon as this variable contains 'true'. So you must provide a variable
containing 'false' otherwise your servers will not run. You may also use the primitive
'must_restart' (see 'predefined.anubis') to control the restarting of your servers.
* (3) The HTML interface.
We propose an interface to dynamic HTML. Dynamic HTML includes HTML, and a combination
of CSS (Cascading Style Sheet) and JavaScript techniques for making HTML elements more
reactive and attractive on the client side.
** (3.1) Types used by the HTML interface.
For easy reference, we gather below the definitions of all the types used by the HTML
interface, and we comment them immediately.
//public type HTML_Off_Form:...
public define Printable_tree [HTML_Id x . Printable_tree y] = str_pt(x.id, y).
public define Printable_tree [HtmlClass x . Printable_tree y] = str_pt(x.class, y).
public define Printable_tree [WebArgName x . Printable_tree y] = str_pt(x.name, y).
public define Printable_tree [WebArgValue x . Printable_tree y] = str_pt(x.value, y).
public define Printable_tree [InitialValue x . Printable_tree y] = str_pt(x.value, y).
public define CoreAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
public define InputAttrs attr(String name, Bool value) = attr(name, if value then "true" else "false").
public define Text_Option
tooltip(String s) = title(s).
A list of 'Text_Option' must be given with each text you want to put in your page.
public define CoreAttrs
tooltip(String s) = title(s).
public define InputAttrs
tooltip(String s) = title(s).
public type I18n:
lang (String),
dir (Reading_Way).
A list of 'DIV_Option' must be given with each DIV you want to put in your page.
public define String
event_name
(
HtmlEvents e
) =
if e is
{
onafterprint then "onafterprint", //HTML5 Script to be run after the document is printed
onbeforeprint then "onbeforeprint", //HTML5 Script to be run before the document is printed
onbeforeunload then "onbeforeunload", //HTML5 Script to be run when the document is about to be unloaded
onerror then "onerror", //HTML5 Script to be run when an error occurs
onhashchange then "onhashchange", //HTML5 Script to be run when there has been changes to the anchor part of the a URL
onload then "onload", // Fires after the page is finished loading
onmessage then "onmessage", //HTML5 Script to be run when the message is triggered
onoffline then "onoffline", //HTML5 Script to be run when the browser starts to work offline
ononline then "ononline", //HTML5 Script to be run when the browser starts to work online
onpagehide then "onpagehide", //HTML5 Script to be run when a user navigates away from a page
onpageshow then "onpageshow", //HTML5 Script to be run when a user navigates to a page
onpopstate then "onpopstate", //HTML5 Script to be run when the window's history changes
onresize then "onresize", //HTML5 Fires when the browser window is resized
onstorage then "onstorage", //HTML5 Script to be run when a Web Storage area is updated
onunload then "onunload", // Fires once a page has unloaded (or the browser window has been closed)
// Form element events
onblur then "onblur", // Fires the moment that the element loses focus
onchange then "onchange", // Fires the moment when the value of the element is changed
oncontextmenu then "oncontextmenu", //HTML5 Script to be run when a context menu is triggered
onfocus then "onfocus", // Fires the moment when the element gets focus
oninput then "oninput", //HTML5 Script to be run when an element gets user input
oninvalid then "oninvalid", //HTML5 Script to be run when an element is invalid
onreset then "onreset", // Fires when the Reset button in a form is clicked
onsearch then "onsearch", // Fires when the user writes something in a search field (for )
onselect then "onselect", // Fires after some text has been selected in an element
onsubmit then "onsubmit", // Fires when a form is submitted
// Keyboard events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
onkeydown then "onkeydown", // Fires when a user is pressing a key
onkeypress then "onkeypress", // Fires when a user presses a key
onkeyup then "onkeyup", // Fires when a user releases a key
// Mouse events (Not valid in base, bdo, br, frame, frameset, head, html, iframe, meta, param, script, style, and title elements.)
onclick then "onclick", // Fires on a mouse click on the element
ondblclick then "ondblclick", // Fires on a mouse double-click on the element
onmousedown then "onmousedown", // Fires when a mouse button is pressed down on an element
onmousemove then "onmousemove", // Fires when the mouse pointer is moving while it is over an element
onmouseout then "onmouseout", // Fires when the mouse pointer moves out of an element
onmouseover then "onmouseover", // Fires when the mouse pointer moves over an element
onmouseup then "onmouseup", // Fires when a mouse button is released over an element
onwheel then "onwheel", //HTML5 Fires when the mouse wheel rolls up or down over an element
//Drag Events
ondrag then "ondrag", //HMTL5 Script to be run when an element is dragged
ondragend then "ondragend", //HTML5 Script to be run at the end of a drag operation
ondragenter then "ondragenter", //HTML5 Script to be run when an element has been dragged to a valid drop target
ondragleave then "ondragleave", //HTML5 Script to be run when an element leaves a valid drop target
ondragover then "ondragover", //HTML5 Script to be run when an element is being dragged over a valid drop target
ondragstart then "ondragstart", //HTML5 Script to be run at the start of a drag operation
ondrop then "ondrop", //HTML5 Script to be run when dragged element is being dropped
onscroll then "onscroll", //HTML5 Script to be run when an element's scrollbar is being scrolled
//Clipboard Events
oncopy then "oncopy", //HTML5 Fires when the user copies the content of an element
oncut then "oncut", //HTML5 Fires when the user cuts the content of an element
onpaste then "onpaste", //HTML5 Fires when the user pastes some content in an element
//Media Events
onabort then "onabort", //HTML5 Script to be run on abort
oncanplay then "oncanplay", //HTML5 Script to be run when a file is ready to start playing (when it has buffered enough to begin)
oncanplaythrough then "oncanplaythrough", //HTML5 Script to be run when a file can be played all the way to the end without pausing for buffering
oncuechange then "oncuechange", //HTML5 Script to be run when the cue changes in a