From 5b6af381171f4500c7cfc5c9ce179edef9e0fd78 Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Mon, 6 Dec 2010 07:19:24 +0000 Subject: Create a js module for client side javascripts. Move client component script to that module and add a few utility scripts. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1042535 13f79535-47bb-0310-9956-ffa450edef68 --- sca-cpp/trunk/modules/Makefile.am | 2 +- sca-cpp/trunk/modules/js/Makefile.am | 21 + sca-cpp/trunk/modules/js/htdocs/component.js | 578 +++++++++++++++++++++++++ sca-cpp/trunk/modules/js/htdocs/scdl.js | 24 + sca-cpp/trunk/modules/js/htdocs/ui.js | 232 ++++++++++ sca-cpp/trunk/modules/js/htdocs/util.js | 85 ++++ sca-cpp/trunk/modules/oauth/htdocs/index.html | 2 +- sca-cpp/trunk/modules/openid/htdocs/index.html | 2 +- sca-cpp/trunk/modules/server/Makefile.am | 4 +- sca-cpp/trunk/modules/server/server-conf | 9 +- 10 files changed, 951 insertions(+), 8 deletions(-) create mode 100644 sca-cpp/trunk/modules/js/Makefile.am create mode 100644 sca-cpp/trunk/modules/js/htdocs/component.js create mode 100644 sca-cpp/trunk/modules/js/htdocs/scdl.js create mode 100644 sca-cpp/trunk/modules/js/htdocs/ui.js create mode 100644 sca-cpp/trunk/modules/js/htdocs/util.js (limited to 'sca-cpp/trunk/modules') diff --git a/sca-cpp/trunk/modules/Makefile.am b/sca-cpp/trunk/modules/Makefile.am index fa07c599ca..a0fa000791 100644 --- a/sca-cpp/trunk/modules/Makefile.am +++ b/sca-cpp/trunk/modules/Makefile.am @@ -15,5 +15,5 @@ # specific language governing permissions and limitations # under the License. -SUBDIRS = scheme atom rss json scdl http server python java openid oauth wsgi +SUBDIRS = scheme atom rss js json scdl http server python java openid oauth wsgi diff --git a/sca-cpp/trunk/modules/js/Makefile.am b/sca-cpp/trunk/modules/js/Makefile.am new file mode 100644 index 0000000000..3c38f6c93b --- /dev/null +++ b/sca-cpp/trunk/modules/js/Makefile.am @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +moddir = $(prefix)/modules/js +nobase_dist_mod_DATA = htdocs/*.js +EXTRA_DIST = htdocs/*.js + diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js new file mode 100644 index 0000000000..cceb494e2d --- /dev/null +++ b/sca-cpp/trunk/modules/js/htdocs/component.js @@ -0,0 +1,578 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * The JSON-RPC client code is based on Jan-Klaas' JavaScript + * o lait library (jsolait). + * + * $Id: jsonrpc.js,v 1.36.2.3 2006/03/08 15:09:37 mclark Exp $ + * + * Copyright (c) 2003-2004 Jan-Klaas Kollhof + * Copyright (c) 2005 Michael Clark, Metaparadigm Pte Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"). + */ + +/** + * Client component wiring API, supporting JSON and ATOM bindings. + */ + +/** + * Escape a character. + */ +var JSONClient = new Object(); + +JSONClient.escapeJSONChar = function(c) { + if(c == "\"" || c == "\\") return "\\" + c; + else if (c == "\b") return "\\b"; + else if (c == "\f") return "\\f"; + else if (c == "\n") return "\\n"; + else if (c == "\r") return "\\r"; + else if (c == "\t") return "\\t"; + var hex = c.charCodeAt(0).toString(16); + if(hex.length == 1) return "\\u000" + hex; + else if(hex.length == 2) return "\\u00" + hex; + else if(hex.length == 3) return "\\u0" + hex; + else return "\\u" + hex; +}; + +/** + * Encode a string into JSON format. + */ +JSONClient.escapeJSONString = function(s) { + /* The following should suffice but Safari's regex is broken + (doesn't support callback substitutions) + return "\"" + s.replace(/([^\u0020-\u007f]|[\\\"])/g, + JSONClient.escapeJSONChar) + "\""; + */ + + /* Rather inefficient way to do it */ + var parts = s.split(""); + for(var i = 0; i < parts.length; i++) { + var c = parts[i]; + if(c == '"' || + c == '\\' || + c.charCodeAt(0) < 32 || + c.charCodeAt(0) >= 128) + parts[i] = JSONClient.escapeJSONChar(parts[i]); + } + return "\"" + parts.join("") + "\""; +}; + +/** + * Marshall objects to JSON format. + */ +JSONClient.toJSON = function(o) { + if(o == null) { + return "null"; + } else if(o.constructor == String) { + return JSONClient.escapeJSONString(o); + } else if(o.constructor == Number) { + return o.toString(); + } else if(o.constructor == Boolean) { + return o.toString(); + } else if(o.constructor == Date) { + return '{javaClass: "java.util.Date", time: ' + o.valueOf() +'}'; + } else if(o.constructor == Array) { + var v = []; + for(var i = 0; i < o.length; i++) v.push(JSONClient.toJSON(o[i])); + return "[" + v.join(", ") + "]"; + } else { + var v = []; + for(attr in o) { + if(o[attr] == null) v.push("\"" + attr + "\": null"); + else if(typeof o[attr] == "function"); /* skip */ + else v.push(JSONClient.escapeJSONString(attr) + ": " + JSONClient.toJSON(o[attr])); + } + return "{" + v.join(", ") + "}"; + } +}; + +/** + * HTTPBindingClient.Exception. + */ +HTTPBindingClient.Exception = function(code, message, javaStack) { + this.code = code; + var name; + if(javaStack) { + this.javaStack = javaStack; + var m = javaStack.match(/^([^:]*)/); + if(m) name = m[0]; + } + if(name) this.name = name; + else this.name = "HTTPBindingClientException"; + this.message = message; +}; + +HTTPBindingClient.Exception.CODE_REMOTE_EXCEPTION = 490; +HTTPBindingClient.Exception.CODE_ERR_CLIENT = 550; +HTTPBindingClient.Exception.CODE_ERR_PARSE = 590; +HTTPBindingClient.Exception.CODE_ERR_NOMETHOD = 591; +HTTPBindingClient.Exception.CODE_ERR_UNMARSHALL = 592; +HTTPBindingClient.Exception.CODE_ERR_MARSHALL = 593; + +HTTPBindingClient.Exception.prototype = new Error(); +HTTPBindingClient.Exception.prototype.toString = function(code, msg) { + return this.name + ": " + this.message; +}; + +/** + * Default top level exception handler. + */ +HTTPBindingClient.default_ex_handler = function(e) { + alert(e); +}; + +/** + * Client settable variables + */ +HTTPBindingClient.toplevel_ex_handler = HTTPBindingClient.default_ex_handler; +HTTPBindingClient.profile_async = false; +HTTPBindingClient.max_req_active = 1; +HTTPBindingClient.requestId = 1; + +/** + * HTTPBindingClient implementation + */ +HTTPBindingClient.prototype._createApplyMethod = function() { + var fn = function() { + var args = []; + var callback = null; + var methodName = arguments[0]; + for(var i = 1; i < arguments.length; i++) args.push(arguments[i]); + + if(typeof args[args.length - 1] == "function") callback = args.pop(); + + var req = fn.client._makeRequest.call(fn.client, methodName, args, callback); + if(callback == null) { + return fn.client._sendRequest.call(fn.client, req); + } else { + HTTPBindingClient.async_requests.push(req); + HTTPBindingClient.kick_async(); + return req.requestId; + } + }; + fn.client = this; + return fn; +}; + +HTTPBindingClient._getCharsetFromHeaders = function(http) { + try { + var contentType = http.getResponseHeader("Content-type"); + var parts = contentType.split(/\s*;\s*/); + for(var i = 0; i < parts.length; i++) { + if(parts[i].substring(0, 8) == "charset=") + return parts[i].substring(8, parts[i].length); + } + } catch (e) {} + return "UTF-8"; +}; + +/** + * Async queue globals + */ +HTTPBindingClient.async_requests = []; +HTTPBindingClient.async_inflight = {}; +HTTPBindingClient.async_responses = []; +HTTPBindingClient.async_timeout = null; +HTTPBindingClient.num_req_active = 0; + +HTTPBindingClient._async_handler = function() { + HTTPBindingClient.async_timeout = null; + + while(HTTPBindingClient.async_responses.length > 0) { + var res = HTTPBindingClient.async_responses.shift(); + if(res.canceled) continue; + if(res.profile) res.profile.dispatch = new Date(); + try { + res.cb(res.result, res.ex, res.profile); + } catch(e) { + HTTPBindingClient.toplevel_ex_handler(e); + } + } + + while(HTTPBindingClient.async_requests.length > 0 && HTTPBindingClient.num_req_active < HTTPBindingClient.max_req_active) { + var req = HTTPBindingClient.async_requests.shift(); + if(req.canceled) continue; + req.client._sendRequest.call(req.client, req); + } +}; + +HTTPBindingClient.kick_async = function() { + if(HTTPBindingClient.async_timeout == null) + HTTPBindingClient.async_timeout = setTimeout(HTTPBindingClient._async_handler, 0); +}; + +HTTPBindingClient.cancelRequest = function(requestId) { + /* If it is in flight then mark it as canceled in the inflight map + and the XMLHttpRequest callback will discard the reply. */ + if(HTTPBindingClient.async_inflight[requestId]) { + HTTPBindingClient.async_inflight[requestId].canceled = true; + return true; + } + + /* If its not in flight yet then we can just mark it as canceled in + the the request queue and it will get discarded before being sent. */ + for(var i in HTTPBindingClient.async_requests) { + if(HTTPBindingClient.async_requests[i].requestId == requestId) { + HTTPBindingClient.async_requests[i].canceled = true; + return true; + } + } + + /* It may have returned from the network and be waiting for its callback + to be dispatched, so mark it as canceled in the response queue + and the response will get discarded before calling the callback. */ + for(var i in HTTPBindingClient.async_responses) { + if(HTTPBindingClient.async_responses[i].requestId == requestId) { + HTTPBindingClient.async_responses[i].canceled = true; + return true; + } + } + + return false; +}; + +HTTPBindingClient.prototype._makeRequest = function(methodName, args, cb) { + var req = {}; + req.client = this; + req.requestId = HTTPBindingClient.requestId++; + + var obj = {}; + obj.id = req.requestId; + if (this.objectID) + obj.method = ".obj#" + this.objectID + "." + methodName; + else + obj.method = methodName; + obj.params = args; + + if (cb) req.cb = cb; + if (HTTPBindingClient.profile_async) + req.profile = { "submit": new Date() }; + req.data = JSONClient.toJSON(obj); + + return req; +}; + +HTTPBindingClient.prototype._sendRequest = function(req) { + if(req.profile) req.profile.start = new Date(); + + /* Get free http object from the pool */ + var http = HTTPBindingClient.poolGetHTTPRequest(); + HTTPBindingClient.num_req_active++; + + /* Send the request */ + http.open("POST", this.uri, (req.cb != null)); + + /* setRequestHeader is missing in Opera 8 Beta */ + try { + http.setRequestHeader("Content-type", "text/plain"); + } catch(e) {} + + /* Construct call back if we have one */ + if(req.cb) { + var self = this; + http.onreadystatechange = function() { + if(http.readyState == 4) { + http.onreadystatechange = function () {}; + var res = { "cb": req.cb, "result": null, "ex": null}; + if (req.profile) { + res.profile = req.profile; + res.profile.end = new Date(); + } + try { res.result = self._handleResponse(http); } + catch(e) { res.ex = e; } + if(!HTTPBindingClient.async_inflight[req.requestId].canceled) + HTTPBindingClient.async_responses.push(res); + delete HTTPBindingClient.async_inflight[req.requestId]; + HTTPBindingClient.kick_async(); + } + }; + } else { + http.onreadystatechange = function() {}; + } + + HTTPBindingClient.async_inflight[req.requestId] = req; + + try { + http.send(req.data); + } catch(e) { + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + if(!req.cb) return this._handleResponse(http); +}; + +HTTPBindingClient.prototype._handleResponse = function(http) { + /* Get the charset */ + if(!this.charset) { + this.charset = HTTPBindingClient._getCharsetFromHeaders(http); + } + + /* Get request results */ + var status, statusText, data; + try { + status = http.status; + statusText = http.statusText; + data = http.responseText; + } catch(e) { + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + HTTPBindingClient.kick_async(); + throw new HTTPBindingClient.Exception(HTTPBindingClient.Exception.CODE_ERR_CLIENT, "Connection failed"); + } + + /* Return http object to the pool; */ + HTTPBindingClient.poolReturnHTTPRequest(http); + HTTPBindingClient.num_req_active--; + + /* Unmarshall the response */ + if(status != 200) { + throw new HTTPBindingClient.Exception(status, statusText); + } + var obj; + try { + eval("obj = " + data); + } catch(e) { + throw new HTTPBindingClient.Exception(550, "error parsing result"); + } + if(obj.error) + throw new HTTPBindingClient.Exception(obj.error.code, obj.error.msg, obj.error.trace); + var res = obj.result; + + /* Handle CallableProxy */ + if(res && res.objectID && res.JSONRPCType == "CallableReference") + return new HTTPBindingClient(this.uri, res.objectID); + + return res; +}; + + +/** + * XMLHttpRequest wrapper code + */ +HTTPBindingClient.http_spare = []; +HTTPBindingClient.http_max_spare = 8; + +HTTPBindingClient.poolGetHTTPRequest = function() { + if(HTTPBindingClient.http_spare.length > 0) { + return HTTPBindingClient.http_spare.pop(); + } + return HTTPBindingClient.getHTTPRequest(); +}; + +HTTPBindingClient.poolReturnHTTPRequest = function(http) { + if(HTTPBindingClient.http_spare.length >= HTTPBindingClient.http_max_spare) + delete http; + else + HTTPBindingClient.http_spare.push(http); +}; + +HTTPBindingClient.msxmlNames = [ "MSXML2.XMLHTTP.5.0", + "MSXML2.XMLHTTP.4.0", + "MSXML2.XMLHTTP.3.0", + "MSXML2.XMLHTTP", + "Microsoft.XMLHTTP" ]; + +HTTPBindingClient.getHTTPRequest = function() { + /* Mozilla XMLHttpRequest */ + try { + HTTPBindingClient.httpObjectName = "XMLHttpRequest"; + return new XMLHttpRequest(); + } catch(e) {} + + /* Microsoft MSXML ActiveX */ + for (var i=0; i < HTTPBindingClient.msxmlNames.length; i++) { + try { + HTTPBindingClient.httpObjectName = HTTPBindingClient.msxmlNames[i]; + return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); + } catch (e) {} + } + + /* None found */ + HTTPBindingClient.httpObjectName = null; + throw new HTTPBindingClient.Exception(0, "Can't create XMLHttpRequest object"); +}; + + +HTTPBindingClient.prototype.get = function(id, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("get - Error getting data from the server"); + } + } + } + xhr.open("GET", this.uri + '/' + id, true); + xhr.send(null); +}; + +HTTPBindingClient.prototype.post = function (entry, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 201) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("post - Error getting data from the server"); + } + } + } + xhr.open("POST", this.uri, true); + xhr.setRequestHeader("Content-Type", "application/atom+xml"); + xhr.send(entry); +}; + +HTTPBindingClient.prototype.put = function (id, entry, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + var strDocument = xhr.responseText; + var xmlDocument = xhr.responseXML; + if(!xmlDocument || xmlDocument.childNodes.length==0){ + xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml"); + } + if (responseFunction != null) responseFunction(xmlDocument); + } else { + alert("put - Error getting data from the server"); + } + } + } + xhr.open("PUT", this.uri + '/' + id, true); + xhr.setRequestHeader("Content-Type", "application/atom+xml"); + xhr.send(entry); +}; + +HTTPBindingClient.prototype.del = function (id, responseFunction) { + var xhr = this.createXMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + if (responseFunction != null) responseFunction(); + } else { + alert("delete - Error getting data from the server"); + } + } + } + xhr.open("DELETE", this.uri + '/' + id, true); + xhr.send(null); +}; + +HTTPBindingClient.prototype.createXMLHttpRequest = function () { + /* Mozilla XMLHttpRequest */ + try { return new XMLHttpRequest(); } catch(e) {} + + /* Microsoft MSXML ActiveX */ + for (var i = 0; i < HTTPBindingClient.msxmlNames.length; i++) { + try { return new ActiveXObject(HTTPBindingClient.msxmlNames[i]); } catch (e) {} + } + alert("XML http request not supported"); + return null; +} + +/** + * Construct an HTTPBindingClient. + */ +function HTTPBindingClient(cname, uri, objectID) { + this.uri = "/references/" + cname + "/" + uri; + this.objectID = objectID; + this.apply = this._createApplyMethod(); + + if (typeof DOMParser == "undefined") { + DOMParser = function () {} + + DOMParser.prototype.parseFromString = function (str, contentType) { + if (typeof ActiveXObject != "undefined") { + var d = new ActiveXObject("MSXML.DomDocument"); + d.loadXML(str); + return d; + } else if (typeof XMLHttpRequest != "undefined") { + var req = new XMLHttpRequest; + req.open("GET", "data:" + (contentType || "application/xml") + + ";charset=utf-8," + encodeURIComponent(str), false); + if (req.overrideMimeType) { + req.overrideMimeType(contentType); + } + req.send(null); + return req.responseXML; + } + } + } +}; + +/** + * Construct a component. + */ +function ClientComponent(name) { + this.name = name; +} + +/** + * Public API. + */ + +/** + * Return a component. + */ +function component(name) { + return new ClientComponent(name); +} + +/** + * Return a reference proxy. + */ +function reference(comp, name) { + return new HTTPBindingClient(comp.name, name); +}; + +/** + * Add proxy functions to a reference proxy. + */ +function defun(ref) { + function defapply(name) { + return function() { + var args = new Array(); + args[0] = name; + for (i = 0, n = arguments.length; i < n; i++) + args[i + 1] = arguments[i]; + return this.apply.apply(this, args); + }; + } + + for (f = 1; f < arguments.length; f++) { + var fn = arguments[f]; + ref[fn]= defapply(fn); + } + return ref; +}; + diff --git a/sca-cpp/trunk/modules/js/htdocs/scdl.js b/sca-cpp/trunk/modules/js/htdocs/scdl.js new file mode 100644 index 0000000000..a98056d790 --- /dev/null +++ b/sca-cpp/trunk/modules/js/htdocs/scdl.js @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * SCDL parsing functions. + */ + + diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.js b/sca-cpp/trunk/modules/js/htdocs/ui.js new file mode 100644 index 0000000000..72c6c6b870 --- /dev/null +++ b/sca-cpp/trunk/modules/js/htdocs/ui.js @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * UI utility functions. + */ + +/** + * Build a menu bar. + */ +function menu(name, href) { + function Menu(n, h) { + this.name = n; + this.href = h; + + this.content = function() { + function complete(uri) { + if (uri.match('.*\.html$')) + return uri; + if (uri.match('.*/$')) + return uri + 'index.html'; + return uri + '/index.html'; + } + + if (complete(this.href) != complete(window.top.location.pathname)) + return '' + this.name + ''; + return '' + this.name + ''; + }; + } + return new Menu(name, href); +} + +function menubar(left, right) { + var bar = '' + + '' + + '
'; + for (i in left) + bar = bar + '' + + bar = bar + '
' + left[i].content() + '
'; + for (i in right) + bar = bar + '' + + bar = bar + '
' + right[i].content() + '
'; + return bar; +} + + +/** + * Autocomplete / suggest support for input fields + * To use it declare a 'suggest' function as follows: + * function suggestItems() { + * return new Array('abc', 'def', 'ghi'); + * } + * then hook it to an input field as follows: + * suggest(document.yourForm.yourInputField, suggestItems); + */ +function selectSuggestion(node, value) { + for (;;) { + node = node.parentNode; + if (node.tagName.toLowerCase() == 'div') + break; + } + node.selectSuggestion(value); +} + +function hilightSuggestion(node, over) { + if (over) + node.className = 'suggestHilighted'; + node.className = 'suggestItem'; +} + +function suggest(input, suggestFunction) { + input.suggest = suggestFunction; + + input.selectSuggestion = function(value) { + this.hideSuggestDiv(); + this.value = value; + } + + input.hideSuggestDiv = function() { + if (this.suggestDiv != null) { + this.suggestDiv.style.visibility = 'hidden'; + } + } + + input.showSuggestDiv = function() { + if (this.suggestDiv == null) { + this.suggestDiv = document.createElement('div'); + this.suggestDiv.input = this; + this.suggestDiv.className = 'suggest'; + input.parentNode.insertBefore(this.suggestDiv, input); + this.suggestDiv.style.visibility = 'hidden'; + this.suggestDiv.style.zIndex = '99'; + + this.suggestDiv.selectSuggestion = function(value) { + this.input.selectSuggestion(value); + } + } + + var values = this.suggest(); + var items = ''; + for (var i = 0; i < values.length; i++) { + if (values[i].indexOf(this.value) == -1) + continue; + if (items.length == 0) + items += ''; + items += ''; + } + if (items.length != 0) + items += '
' + values[i] + '
'; + this.suggestDiv.innerHTML = items; + + if (items.length != 0) { + var node = input; + var left = 0; + var top = 0; + for (;;) { + left += node.offsetLeft; + top += node.offsetTop; + node = node.offsetParent; + if (node.tagName.toLowerCase() == 'body') + break; + } + this.suggestDiv.style.left = left; + this.suggestDiv.style.top = top + input.offsetHeight; + this.suggestDiv.style.visibility = 'visible'; + } else + this.suggestDiv.style.visibility = 'hidden'; + } + + input.onkeydown = function(event) { + this.showSuggestDiv(); + }; + + input.onkeyup = function(event) { + this.showSuggestDiv(); + }; + + input.onmousedown = function(event) { + this.showSuggestDiv(); + }; + + input.onblur = function(event) { + setTimeout(function() { input.hideSuggestDiv(); }, 50); + }; +} + +/** + * Return the content document of a window. + */ +function content(win) { + if (!isNil(win.document)) + return win.document; + if (!isNil(win.contentDocument)) + return win.contentDocument; + return null; +} + +/** + * Return a child element of a node with the given id. + */ +function elementByID(node, id) { + for (var i in node.childNodes) { + var child = node.childNodes[i]; + if (child.id == id) + return child; + var gchild = elementByID(child, id); + if (gchild != null) + return gchild; + } + return null; +} + +/** + * Return the current document, or a child element with the given id. + */ +function $(id) { + if (id == document) { + if (!isNil(document.widget)) + return widget; + return document; + } + return elementByID($(document), id); +} + +/** + * Initialize a widget. + */ +function onloadwidget() { + if (isNil(window.parent) || isNil(window.parent.widgets)) + return true; + var pdoc = content(window.parent); + for (w in window.parent.widgets) { + var ww = elementByID(pdoc, w).contentWindow; + if (ww == window) { + document.widget = elementByID(pdoc, window.parent.widgets[w]); + document.widget.innerHTML = document.body.innerHTML; + return true; + } + } + return true; +} + +/** + * Load a widget into an element. + */ +var widgets = new Array(); + +function bindwidget(f, el) { + window.widgets[f] = el; + return f; +} + diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js new file mode 100644 index 0000000000..96a84af6d6 --- /dev/null +++ b/sca-cpp/trunk/modules/js/htdocs/util.js @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Utility functions. + */ + +/** + * Simple scheme-like lists. + */ +function cons(car, cdr) { + return new Array(car).concat(cdr); +} + +function car(l) { + return l[0]; +} + +function cdr(l) { + return l.slice(1); +} + +function mklist() { + var a = new Array(); + for (i = 0; i < arguments.length; i++) + a[i] = arguments[i]; + return a; +} + +function isList(v) { + return toString.call(v) === '[object Array]'; +} + +function isNil(v) { + return v == 'undefined' || v == null; +} + +function isEmpty(l) { + return l.length == 0; +} + +/** + * convert an array or object to a non-sparse array. + */ +function array(obj) { + if (isNil(obj.length)) { + var a = new Array(); + a[0] = obj; + return a; + } else { + var a = new Array(); + var n = 0; + for (var i in obj) + a[n++] = obj[i]; + return a; + } +} + +/** + * Dump an object to the console. + */ +function dump(o) { + for (f in o) { + try { + console.log(f + '=' + o[f]); + } catch (e) {} + } +} + diff --git a/sca-cpp/trunk/modules/oauth/htdocs/index.html b/sca-cpp/trunk/modules/oauth/htdocs/index.html index fc8ce922f1..9a9d833898 100644 --- a/sca-cpp/trunk/modules/oauth/htdocs/index.html +++ b/sca-cpp/trunk/modules/oauth/htdocs/index.html @@ -19,7 +19,7 @@ - + +