Files
aws/web_elements/javascripts/aws_kernel.tjs
Emmanuel Briot 30e53aaf68 Implement Draft76 protocol for websockets.
Improve the websockets demo so that the websocket is not started on page load.
 This makes it easier to look at packets that are exchanged, without reloading
 the full javascript each time. Also change javascript so that new status do
 not replace the message on the page, but add to it (so that we can see "open"
 and "close", not just "close" for instance)
L629-010
2012-08-23 15:23:30 +02:00

826 lines
22 KiB
Plaintext

@@----------------------------------------------------------------------------
@@-- Ada Web Server
@@--
@@-- Copyright (C) 2007-2012, AdaCore
@@--
@@-- This library is free software; you can redistribute it and/or modify
@@-- it under terms of the GNU General Public License as published by the
@@-- Free Software Foundation; either version 3, or (at your option) any
@@-- later version. This library 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.
@@--
@@-- As a special exception under Section 7 of GPL version 3, you are
@@-- granted additional permissions described in the GCC Runtime Library
@@-- Exception, version 3.1, as published by the Free Software Foundation.
@@--
@@-- You should have received a copy of the GNU General Public License and
@@-- a copy of the GCC Runtime Library Exception along with this program;
@@-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
@@-- <http://www.gnu.org/licenses/>.
@@--
@@----------------------------------------------------------------------------
@@SET@@ CTX_WB = "CTX_WB"
@@-- The context parameter name
@@SET@@ TIMEZONE_COOKIE = ""
@@-- Set to empty string for no timezone support
@@---------------------------------------------------------------- AWS
var AWS = {
Context : null,
Ajax : null,
WebSocket : null,
Tools : null
}
@@---------------------------------------------------------------- TOOLS
AWS.Tools = new function() {
@@-----------
@@-- PUBLIC
@@-----------
@@-- --------------------------------
@@-- onload event to update CTX_WB
this.addLoadEvent = function (func)
{
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() { oldonload(); func(); }
}
}
@@-- --------------------------------
@@-- Used to report javascript errors
this.report_error = function (request)
{
alert ('There was! an error on this Ajax request.');
}
@@-- Clear select content
this.clearSelect = function (select_id)
{
while ($(select_id).length > 0) {
$(select_id).remove(0);
}
}
@@-- Delete a given option from the select
this.delSelectOption = function (select_id, option)
{
var idx = 0;
while (idx < $(select_id).length) {
if ($(select_id).options[idx].value == option) {
$(select_id).remove(idx);
return;
}
idx = idx + 1;
}
}
@@-- Add option_value/option_content into the given select
this.addToSelect =
function (select_id, option_value, option_content, option_class)
{
// Create a new option
var new_option = document.createElement("option");
new_option.value = option_value;
new_option.className = option_class;
var content = document.createTextNode(option_content);
new_option.appendChild(content);
// And add it to select
$(select_id).appendChild(new_option);
return new_option;
}
@@-- Select the given option from the select
this.selectChangeSelected =
function (select_id, option, hook_func, hook_param)
{
var idx = 0;
while (idx < $(select_id).length) {
if ($(select_id).options[idx].value == option) {
$(select_id).selectedIndex = idx;
if (hook_func != null && hook_func != "") {
hook_func($(select_id).options[idx], hook_param);
}
return;
}
idx = idx + 1;
}
}
@@IF@@ @_TIMEZONE_COOKIE_@ /= ""
@@-- Use cookie to record that the timezone has been sent
@@INCLUDE@@ cookies.js
@@-- Handle Web Browser local timezone
this.TZ_offset = new Date().getTimezoneOffset();
this.setTimezone =
function ()
{
if (readCookie ("@_TIMEZONE_COOKIE_@") == null) {
createCookie ("@_TIMEZONE_COOKIE_@", this.TZ_offset, 1);
}
}
@@END_IF@@
}
@@---------------------------------------------------------------- CONTEXT
AWS.Context = new function() {
@@-----------
@@-- PUBLIC
@@-----------
@@-- --------------------------------
@@-- Returns the context id
this.get = function ()
{
var context = document.getElementById('@_CTX_WB_@');
if (context == null)
return "";
else
return $(context).innerHTML;
}
this.set = function (value)
{
var context = document.getElementById('@_CTX_WB_@');
if (context == null)
return;
else
$(context).innerHTML = value;
this.update();
}
@@-- --------------------------------
@@-- Update the context tag in anchors and forms
this.update = function ()
{
var k = 0;
@@-- anchors
var anchors = document.getElementsBySelector('a');
for (k=0; k<anchors.length; k++) {
var href = anchors[k].getAttribute('href');
if (href != null) {
@@-- IE insists on returning the derived absolute URL,
@@-- make sure that the ref is on the current page if the
@@-- prefix is HTTP.
if ((href.indexOf("http:",0) != 0
|| href.indexOf(window.location.hostname) == 7)
&& href.indexOf("mailto:",0) != 0
&& href.indexOf("#",0) != 0) {
anchors[k].setAttribute('href',
AWS.Context.href_add_anchor(href));
}
}
}
@@-- forms
var forms = document.getElementsBySelector('form');
for (k=0; k<forms.length; k++) {
var action = forms[k].getAttribute('action');
if (action != null) {
if (action != ""
&& action.indexOf("http:",0) != 0
&& action.indexOf("#", 0) != 0
&& forms[k].getAttribute('onsubmit') == null) {
add_context_to_form (forms[k]);
}
}
}
}
@@-- --------------------------------
@@-- Add Context parameter CTX_WB for Ajax
this.add_ajax = function (pars)
{
if (pars == "")
pars = pars + "?";
else
pars = pars + "&";
pars = pars + "@_CTX_WB_@=" + this.get();
return pars;
}
@@-- --------------------------------
@@-- Add context parameter CTX_WB for anchors
this.add_anchor = function (a)
{
a.href = this.href_add_anchor(a.href);
}
this.href_add_anchor = function (href)
{
var href_last = ""; // Contains fragment
if (href.indexOf('#', 0) != -1) {
var splitted_href = href.split('#');
href = splitted_href[0];
href_last = splitted_href[1];
}
// Remove CTX_WB if exists
if (href.indexOf("@_CTX_WB_@", 0) != -1) {
href = href.split("@_CTX_WB_@")[0];
href = href.substr(0, href.length - 1); // Remove & or ?
}
if (href.indexOf('?',0) == -1) {
href = href + '?';
} else {
href = href + '&';
}
href = href + "@_CTX_WB_@=" + this.get();
if (href_last != "") {
href = href + "#" + href_last;
}
return (href);
}
@@------------
@@-- PRIVATE
@@------------
@@-- --------------------------------
@@-- Append or update context into form
function add_context_to_form (form)
{
var k = 0;
var items = form.elements;
var found_context = false;
for (k=0; k<items.length; k++) {
if (items[k].tagName == "INPUT"
&& items[k].getAttribute('NAME') == '@_CTX_WB_@') {
// Update context if needed
if (items[k].getAttribute('VALUE') != AWS.Context.get()) {
items[k].setAttribute ('VALUE', AWS.Context.get());
}
found_context = true;
}
}
// Insert new context field
if (!found_context) {
hi = document.createElement('input');
hi.setAttribute('type', 'hidden');
hi.setAttribute('name', '@_CTX_WB_@');
hi.setAttribute('value', AWS.Context.get());
form.appendChild(hi);
}
}
}
@@---------------------------------------------------------------- AJAX
AWS.Ajax = new function() {
@@-----------
@@-- PUBLIC
@@-----------
this.XML = null;
@@-- --------------------------------
@@-- Update the behavior rules, needed when loading new section
@@-- containing JavaScript code. Also update the CTX_WB.
this.update_framework = function()
{
Behaviour.apply ();
AWS.Context.update();
}
@@-- --------------------------------
@@-- Call url?pars and put result into placeholder
this.replace = function (url, pars, placeholder, oncomplete)
{
var rplaceholder = $(placeholder);
if (rplaceholder.tagName == "TEXTAREA" ||
rplaceholder.tagName == "INPUT")
var O_ajax = new Ajax.Request
(url,
{method: 'get',
parameters: AWS.Context.add_ajax(pars),
onFailure: AWS.Tools.report_error,
onComplete: function(req)
{rplaceholder.value = req.responseText;
if (oncomplete != "") oncomplete();}});
else
var O_ajax = new Ajax.Updater
({success: placeholder},
url,
{method: 'get',
parameters: AWS.Context.add_ajax(pars),
onFailure: AWS.Tools.report_error,
onComplete: function(req)
{AWS.Ajax.update_framework();
if (oncomplete != "") oncomplete();}});
}
@@-- --------------------------------
@@-- Serialize a tag or all fields in a form
this.serialize = function(elm, name) {
var param = "";
if ($(elm) == null) return "";
if ($(elm).tagName == "FORM") {
param = Form.serialize (elm);
} else if ($(elm).tagName == "UL") {
param = Sortable.serialize(elm);
} else if (name == "" || name == null) {
param = elm + "=" + $F(elm);
} else {
param = name + "=" + $F(elm);
}
return (param);
}
}
AWS.Ajax.XML = new function() {
@@-- --------------------------------
@@-- Call url?pars and execute aws_xml_handler methods then the
@@-- oncomplete method (to chain commands) if defined
this.request = function (url, pars, oncomplete)
{
var myAjax = new Ajax.Request
(url,
{method: 'get',
parameters: AWS.Context.add_ajax(pars),
onFailure : AWS.Tools.report_error,
onComplete : function(req)
{AWS.Ajax.XML.handler(req.responseXML);
AWS.Ajax.update_framework();
if (oncomplete != "") oncomplete();}});
}
@@-- Handle XML responses
this.fromString = function (str)
{
var parser = new DOMParser();
var doc = parser.parseFromString(str, "application/xml");
AWS.Ajax.XML.handler(doc);
}
@@-- Handle XML responses
this.handler = function (xml_actions)
{
var response = xml_actions.getElementsByTagName('response');
var i = 0;
for (i = 0; i < response[0].childNodes.length; i++) {
var node = response[0].childNodes[i];
if (node.nodeName == 'replace') {
handler_replace (node);
} else if (node.nodeName == 'clear') {
handler_clear (node);
} else if (node.nodeName == 'select') {
handler_select (node);
} else if (node.nodeName == 'radio') {
handler_radio (node);
} else if (node.nodeName == 'check') {
handler_check (node);
} else if (node.nodeName == 'get') {
handler_get (node);
} else if (node.nodeName == 'location') {
handler_location (node);
} else if (node.nodeName == 'refresh') {
window.location.reload (true);
} else if (node.nodeName == 'create_sortable') {
handler_create_sortable (node);
} else if (node.nodeName == 'destroy_sortable') {
handler_destroy_sortable (node);
} else if (node.nodeName == 'apply_style') {
handler_apply_style (node);
} else if (node.nodeName == 'insert_after') {
handler_insert_after (node);
} else if (node.nodeName == 'ctx') {
handler_ctx (node);
} else if (node.nodeName == 'read_only') {
handler_read_only (node);
} else if (node.nodeName == 'disabled') {
handler_disabled (node);
} else if (node.nodeName == 'reset') {
handler_reset (node);
}
}
}
@@-- Internal handler, replace current context in Web page
function handler_ctx (node)
{
var cid = node.getAttribute("id");
AWS.Context.set (cid);
AWS.Ajax.update_framework();
}
@@-- Replace a node content by an HTML String
function handler_replace (node)
{
var placeholder_id = node.getAttribute("id");
var placeholder_content;
if ($(placeholder_id) == null) return;
if (node.childNodes.length > 1) {
placeholder_content = node.childNodes[1].nodeValue;
} else {
placeholder_content = node.firstChild.nodeValue;
}
if ($(placeholder_id).tagName == "TEXTAREA" ||
$(placeholder_id).tagName == "INPUT") {
$(placeholder_id).value = placeholder_content;
} else {
$(placeholder_id).innerHTML = placeholder_content;
}
AWS.Ajax.update_framework();
}
@@-- Clear a node
function handler_clear (node)
{
var placeholder_id = node.getAttribute("id");
if ($(placeholder_id).tagName == "TEXTAREA" ||
$(placeholder_id).tagName == "INPUT") {
$(placeholder_id).value = "";
} else if ( $(placeholder_id).tagName == "IFRAME") {
window.frames[placeholder_id].document.body.innerHTML="";
} else {
$(placeholder_id).innerHTML = "";
}
}
@@-- Action on select : add, delete or select an option, or clear a select
function handler_select (node)
{
var select_action = node.getAttribute("action");
var select_id = node.getAttribute("id");
if (select_action == "add") {
var option_value = node.getAttribute("option_value");
var option_content = node.getAttribute("option_content");
AWS.Tools.addToSelect (select_id, option_value, option_content);
} else if (select_action == "clear") {
AWS.Tools.clearSelect (select_id);
} else if (select_action == "delete") {
var option_value = node.getAttribute("option_value");
AWS.Tools.delSelectOption (select_id, option_value);
} else if (select_action == "select") {
var option_value = node.getAttribute("option_value");
AWS.Tools.selectChangeSelected (select_id, option_value);
}
}
@@-- Action on list : add an element
function handler_insert_after (node)
{
var id = node.getAttribute('id');
var placeholder_content;
if (node.childNodes.length > 1) {
placeholder_content = node.childNodes[1].nodeValue;
} else {
placeholder_content = node.firstChild.nodeValue;
}
new Insertion.After (id, placeholder_content);
AWS.Ajax.update_framework();
}
@@-- Action on radio
function handler_radio (node)
{
var action = node.getAttribute('action');
var id = node.getAttribute('id');
if (action == 'select') {
$(id).checked = 1;
}
}
@@-- Action on check
function handler_check (node)
{
var action = node.getAttribute('action');
var id = node.getAttribute('id');
if (action == 'select') {
$(id).checked = 1;
} else if (action == 'clear') {
$(id).checked = 0;
}
}
@@-- Action on get
function handler_get (node)
{
var url = node.getAttribute('url');
var pars = '';
var i = 0;
for (i = 0; i < node.childNodes.length; i++) {
var current_node = node.childNodes[i];
if (current_node.nodeName == 'parameters') {
if (pars != '') {
pars = pars + '&';
}
pars = pars + current_node.getAttribute('value');
} else if (current_node.nodeName == 'field') {
if (pars != '') {
pars = pars + '&';
}
var id = current_node.getAttribute('id');
pars = pars + AWS.Ajax.serialize (id);
}
}
AWS.Ajax.update_framework(); /* Update behaviour before request url */
AWS.Ajax.XML.request (url, pars, '');
}
@@-- Action on location
function handler_location (node)
{
var url = node.getAttribute('url');
if (url.indexOf('http',0) == -1
&& url.indexOf('@_CTX_WB_@') == -1
&& url[0] != '#')
{
@@-- pointing inside server and no context
if (url.indexOf("?",0) == -1)
url = url + '?';
else
url = url + '&';
url = url + "@_CTX_WB_@=" + AWS.Context.get();
}
/* Redirect to url */
document.location.href = url;
}
@@-- Action on create_sortable
function handler_create_sortable (node)
{
var lists = []; /* Get all list for containment */
var i = 0;
for (i = 0; i < node.childNodes.length; i++) {
var current_node = node.childNodes[i];
if (current_node.nodeName == 'list') {
lists.push (current_node.getAttribute('id'));
}
}
/* Call Sortable.create for each element */
for (i = 0; i < node.childNodes.length; i++) {
var current_node = node.childNodes[i];
if (current_node.nodeName == 'list') {
var id = current_node.getAttribute('id');
/* Add cursor style */
var elm = document.getElementById (id);
elm.style.cursor = 'move';
/* Create sortable */
Sortable.create
(id, { containment:lists, constraint:false, dropOnEmpty:true });
}
}
}
@@-- Action on destroy_sortable
function handler_destroy_sortable (node)
{
var i = 0;
/* Call Sortable.destroy for each element */
for (i = 0; i < node.childNodes.length; i++) {
var current_node = node.childNodes[i];
if (current_node.nodeName == 'list') {
var list_id = current_node.getAttribute('id');
/* Revert cursor style */
var elm = document.getElementById (list_id);
elm.style.cursor = 'default';
/* Destroy sortable */
Sortable.destroy (list_id);
}
}
}
@@-- Action on apply_style
function handler_apply_style (node)
{
var elm_id = node.getAttribute('id');
if ($(elm_id) == null) return;
var i = 0;
for (i = 0; i < node.childNodes.length; i++) {
var current_node = node.childNodes[i];
if (current_node.nodeName == 'attribute') {
var id = current_node.getAttribute('id');
var value = current_node.getAttribute('value');
$(elm_id).style[id] = value;
}
}
}
@@-- Action on read_only
function handler_read_only (node)
{
var id = node.getAttribute('id');
var value = node.getAttribute('value');
if (value == 'true') {
$(id).readOnly = true;
} else if (value == 'false') {
$(id).readOnly = false;
}
}
@@-- Action on disabled
function handler_disabled (node)
{
var id = node.getAttribute('id');
var value = node.getAttribute('value');
if (value == 'true') {
$(id).disabled = true;
} else if (value == 'false') {
$(id).disabled = false;
}
}
@@-- Action on reset
function handler_reset (node)
{
var id = node.getAttribute('id');
$(id).reset();
}
}
@@---------------------------------------------------------------- TOOLS
AWS.WebSocket = new function() {
@@-----------
@@-- PUBLIC
@@-----------
@@-- --------------------------------
@@-- getTransport
this.getTransport = function (url)
{
return Try.these(
function() {return new WebSocket(url)},
function() {return new MozWebSocket(url)}
) || false;
}
this.open = function(url, message_id, status_id)
{
ws = AWS.WebSocket.getTransport(url);
if (ws == false) {
if (status_id != null) {
var a = document.getElementById(status_id);
a.innerHTML = a.innerHTML + '<br>Your browser does NOT support webSocket.';
}
return;
}
ws.onmessage = default_onmessage;
ws.onerror = default_onerror;
ws.onclose = default_onclose;
ws.onopen = default_onopen;
if (message_id != null)
ws.aws_message_id=message_id;
if (status_id != null)
ws.aws_status_id=status_id;
return ws;
}
function default_onmessage(e)
{
var data=e.data;
// if the first characters are an <response, let's pretends this is
// an AWS XML response. Parse using the AWS XML Ajax framework.
if (data.substring(0,5) == '<?xml')
AWS.Ajax.XML.fromString(data);
else if (this.aws_message_id != null) {
var a = document.getElementById(this.aws_message_id);
a.innerHTML = a.innerHTML + "<br>" + data;
}
}
function default_onopen(e)
{
if (this.aws_status_id != null) {
var a = document.getElementById(this.aws_status_id);
a.innerHTML = a.innerHTML + '<br>WebSocket now opened';
}
}
function default_onclose(e)
{
if (this.aws_status_id != null) {
var a = document.getElementById(this.aws_status_id);
a.innerHTML = a.innerHTML + '<br>WebSocket now closed';
}
}
function default_onerror(e)
{
if (this.aws_status_id != null) {
var a = document.getElementById(this.aws_status_id);
a.innerHTML = a.innerHTML + "<br>Error: " + e.data;
}
}
}
@@-- INIT
AWS.Tools.addLoadEvent (AWS.Context.update);
@@IF@@ @_TIMEZONE_COOKIE_@ /= ""
AWS.Tools.setTimezone();
@@END_IF@@