summaryrefslogtreecommitdiff
path: root/framework/Web/Javascripts/extra
diff options
context:
space:
mode:
authorxue <>2005-12-05 01:00:16 +0000
committerxue <>2005-12-05 01:00:16 +0000
commitccf76e430b7703db028966a845a966f50956f490 (patch)
tree9762b746f8b7d432dbe5e5cb8f38f90007e0e1b5 /framework/Web/Javascripts/extra
parent418baf36d477bcbdd6fb4eaf4037ea6a2d93f21c (diff)
Diffstat (limited to 'framework/Web/Javascripts/extra')
-rw-r--r--framework/Web/Javascripts/extra/behaviour.js83
-rw-r--r--framework/Web/Javascripts/extra/getElementsBySelector.js176
-rw-r--r--framework/Web/Javascripts/extra/logger.js659
-rw-r--r--framework/Web/Javascripts/extra/tp_template.js315
4 files changed, 1233 insertions, 0 deletions
diff --git a/framework/Web/Javascripts/extra/behaviour.js b/framework/Web/Javascripts/extra/behaviour.js
new file mode 100644
index 00000000..0004c5db
--- /dev/null
+++ b/framework/Web/Javascripts/extra/behaviour.js
@@ -0,0 +1,83 @@
+/*
+ Behaviour v1.1 by Ben Nolan, June 2005. Based largely on the work
+ of Simon Willison (see comments by Simon below).
+
+ Description:
+
+ Uses css selectors to apply javascript behaviours to enable
+ unobtrusive javascript in html documents.
+
+ Usage:
+
+ var myrules = {
+ 'b.someclass' : function(element){
+ element.onclick = function(){
+ alert(this.innerHTML);
+ }
+ },
+ '#someid u' : function(element){
+ element.onmouseover = function(){
+ this.innerHTML = "BLAH!";
+ }
+ }
+ };
+
+ Behaviour.register(myrules);
+
+ // Call Behaviour.apply() to re-apply the rules (if you
+ // update the dom, etc).
+
+ License:
+
+ This file is entirely BSD licensed.
+
+ More information:
+
+ http://ripcord.co.nz/behaviour/
+
+*/
+
+var Behaviour = {
+ list : new Array,
+
+ register : function(sheet){
+ Behaviour.list.push(sheet);
+ },
+
+ start : function(){
+ Behaviour.addLoadEvent(function(){
+ Behaviour.apply();
+ });
+ },
+
+ apply : function(){
+ for (h=0;sheet=Behaviour.list[h];h++){
+ for (selector in sheet){
+ list = document.getElementsBySelector(selector);
+
+ if (!list){
+ continue;
+ }
+
+ for (i=0;element=list[i];i++){
+ sheet[selector](element);
+ }
+ }
+ }
+ },
+
+ addLoadEvent : function(func){
+ var oldonload = window.onload;
+
+ if (typeof window.onload != 'function') {
+ window.onload = func;
+ } else {
+ window.onload = function() {
+ oldonload();
+ func();
+ }
+ }
+ }
+}
+
+Behaviour.start(); \ No newline at end of file
diff --git a/framework/Web/Javascripts/extra/getElementsBySelector.js b/framework/Web/Javascripts/extra/getElementsBySelector.js
new file mode 100644
index 00000000..d6675cd5
--- /dev/null
+++ b/framework/Web/Javascripts/extra/getElementsBySelector.js
@@ -0,0 +1,176 @@
+/** document.getElementsBySelector(selector)
+ - returns an array of element objects from the current document
+ matching the CSS selector. Selectors can contain element names,
+ class names and ids and can be nested. For example:
+
+ elements = document.getElementsBySelect('div#main p a.external')
+
+ Will return an array of all 'a' elements with 'external' in their
+ class attribute that are contained inside 'p' elements that are
+ contained inside the 'div' element which has id="main"
+
+ New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
+ See http://www.w3.org/TR/css3-selectors/#attribute-selectors
+
+ Version 0.4 - Simon Willison, March 25th 2003
+ -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
+ -- Opera 7 fails
+*/
+
+/**
+ * Returns all children of element. Workaround required for IE5/Windo
+ */
+function getAllChildren(e) {
+ // Returns all children of element. Workaround required for IE5/Windows. Ugh.
+ return e.all ? e.all : e.getElementsByTagName('*');
+}
+
+/**
+ * returns an array of element objects from the current document
+ matching the CSS selector. Selectors can contain element names,
+ class names and ids and can be nested. For example:
+
+ <pre><tt>elements = document.getElementsBySelect('div#main p a.external')</tt></pre>
+
+ Will return an array of all 'a' elements with 'external' in their
+ class attribute that are contained inside 'p' elements that are
+ contained inside the 'div' element which has id="main"
+ */
+document.getElementsBySelector = function(selector) {
+ // Attempt to fail gracefully in lesser browsers
+ if (!document.getElementsByTagName) {
+ return new Array();
+ }
+ // Split selector in to tokens
+ var tokens = selector.split(' ');
+ var currentContext = new Array(document);
+ for (var i = 0; i < tokens.length; i++) {
+ token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
+ if (token.indexOf('#') > -1) {
+ // Token is an ID selector
+ var bits = token.split('#');
+ var tagName = bits[0];
+ var id = bits[1];
+ var element = document.getElementById(id);
+ if (tagName && element.nodeName.toLowerCase() != tagName) {
+ // tag with that ID not found, return false
+ return new Array();
+ }
+ // Set currentContext to contain just this element
+ currentContext = new Array(element);
+ continue; // Skip to next token
+ }
+ if (token.indexOf('.') > -1) {
+ // Token contains a class selector
+ var bits = token.split('.');
+ var tagName = bits[0];
+ var className = bits[1];
+ if (!tagName) {
+ tagName = '*';
+ }
+ // Get elements matching tag, filter them for class selector
+ var found = new Array;
+ var foundCount = 0;
+ for (var h = 0; h < currentContext.length; h++) {
+ var elements;
+ if (tagName == '*') {
+ elements = getAllChildren(currentContext[h]);
+ } else {
+ elements = currentContext[h].getElementsByTagName(tagName);
+ }
+ for (var j = 0; j < elements.length; j++) {
+ found[foundCount++] = elements[j];
+ }
+ }
+ currentContext = new Array;
+ var currentContextIndex = 0;
+ for (var k = 0; k < found.length; k++) {
+ if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
+ currentContext[currentContextIndex++] = found[k];
+ }
+ }
+ continue; // Skip to next token
+ }
+ // Code to deal with attribute selectors
+ if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
+ var tagName = RegExp.$1;
+ var attrName = RegExp.$2;
+ var attrOperator = RegExp.$3;
+ var attrValue = RegExp.$4;
+ if (!tagName) {
+ tagName = '*';
+ }
+ // Grab all of the tagName elements within current context
+ var found = new Array;
+ var foundCount = 0;
+ for (var h = 0; h < currentContext.length; h++) {
+ var elements;
+ if (tagName == '*') {
+ elements = getAllChildren(currentContext[h]);
+ } else {
+ elements = currentContext[h].getElementsByTagName(tagName);
+ }
+ for (var j = 0; j < elements.length; j++) {
+ found[foundCount++] = elements[j];
+ }
+ }
+ currentContext = new Array;
+ var currentContextIndex = 0;
+ var checkFunction; // This function will be used to filter the elements
+ switch (attrOperator) {
+ case '=': // Equality
+ checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
+ break;
+ case '~': // Match one of space seperated words
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
+ break;
+ case '|': // Match start with value followed by optional hyphen
+ checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
+ break;
+ case '^': // Match starts with value
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
+ break;
+ case '$': // Match ends with value - fails with "Warning" in Opera 7
+ checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
+ break;
+ case '*': // Match ends with value
+ checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
+ break;
+ default :
+ // Just test for existence of attribute
+ checkFunction = function(e) { return e.getAttribute(attrName); };
+ }
+ currentContext = new Array;
+ var currentContextIndex = 0;
+ for (var k = 0; k < found.length; k++) {
+ if (checkFunction(found[k])) {
+ currentContext[currentContextIndex++] = found[k];
+ }
+ }
+ // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
+ continue; // Skip to next token
+ }
+ // If we get here, token is JUST an element (not a class or ID selector)
+ tagName = token;
+ var found = new Array;
+ var foundCount = 0;
+ for (var h = 0; h < currentContext.length; h++) {
+ var elements = currentContext[h].getElementsByTagName(tagName);
+ for (var j = 0; j < elements.length; j++) {
+ found[foundCount++] = elements[j];
+ }
+ }
+ currentContext = found;
+ }
+ return currentContext;
+}
+
+/* That revolting regular expression explained
+/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
+ \---/ \---/\-------------/ \-------/
+ | | | |
+ | | | The value
+ | | ~,|,^,$,* or =
+ | Attribute
+ Tag
+*/
diff --git a/framework/Web/Javascripts/extra/logger.js b/framework/Web/Javascripts/extra/logger.js
new file mode 100644
index 00000000..438772e9
--- /dev/null
+++ b/framework/Web/Javascripts/extra/logger.js
@@ -0,0 +1,659 @@
+/*
+
+Created By: Corey Johnson
+E-mail: probablyCorey@gmail.com
+
+Requires: Prototype Javascript library (http://prototype.conio.net/)
+
+Use it all you want. Just remember to give me some credit :)
+
+*/
+
+// ------------
+// Custom Event
+// ------------
+
+CustomEvent = Class.create()
+CustomEvent.prototype = {
+ initialize : function() {
+ this.listeners = []
+ },
+
+ addListener : function(method) {
+ this.listeners.push(method)
+ },
+
+ removeListener : function(method) {
+ var foundIndexes = this._findListenerIndexes(method)
+
+ for(var i = 0; i < foundIndexes.length; i++) {
+ this.listeners.splice(foundIndexes[i], 1)
+ }
+ },
+
+ dispatch : function(handler) {
+ for(var i = 0; i < this.listeners.length; i++) {
+ try {
+ this.listeners[i](handler)
+ }
+ catch (e) {
+ alert("Could not run the listener " + this.listeners[i] + ". " + e)
+ }
+ }
+ },
+
+ // Private Methods
+ // ---------------
+ _findListenerIndexes : function(method) {
+ var indexes = []
+ for(var i = 0; i < this.listeners.length; i++) {
+ if (this.listeners[i] == method) {
+ indexes.push(i)
+ }
+ }
+
+ return indexes
+ }
+}
+
+// ------
+// Cookie
+// ------
+
+var Cookie = {
+ set : function(name, value, expirationInDays, path) {
+ var cookie = escape(name) + "=" + escape(value)
+
+ if (expirationInDays) {
+ var date = new Date()
+ date.setDate(date.getDate() + expirationInDays)
+ cookie += "; expires=" + date.toGMTString()
+ }
+
+ if (path) {
+ cookie += ";path=" + path
+ }
+
+ document.cookie = cookie
+
+ if (value && (expirationInDays == undefined || expirationInDays > 0) && !this.get(name)) {
+ Logger.error("Cookie (" + name + ") was not set correctly... The value was " + value.toString().length + " charachters long (This may be over the cookie limit)");
+ }
+ },
+
+ get : function(name) {
+ var pattern = "(^|;)\\s*" + escape(name) + "=([^;]+)"
+
+ var m = document.cookie.match(pattern)
+ if (m && m[2]) {
+ return unescape(m[2])
+ }
+ else return null
+ },
+
+ getAll : function() {
+ var cookies = document.cookie.split(';')
+ var cookieArray = []
+
+ for (var i = 0; i < cookies.length; i++) {
+ try {
+ var name = unescape(cookies[i].match(/^\s*([^=]+)/m)[1])
+ var value = unescape(cookies[i].match(/=(.*$)/m)[1])
+ }
+ catch (e) {
+ continue
+ }
+
+ cookieArray.push({name : name, value : value})
+
+ if (cookieArray[name] != undefined) {
+ Logger.waring("Trying to retrieve cookie named(" + name + "). There appears to be another property with this name though.");
+ }
+
+ cookieArray[name] = value
+ }
+
+ return cookieArray
+ },
+
+ clear : function(name) {
+ this.set(name, "", -1)
+ },
+
+ clearAll : function() {
+ var cookies = this.getAll()
+
+ for(var i = 0; i < cookies.length; i++) {
+ this.clear(cookies[i].name)
+ }
+
+ }
+}
+
+// ------
+// Logger
+// -----
+
+Logger = {
+ logEntries : [],
+
+ onupdate : new CustomEvent(),
+ onclear : new CustomEvent(),
+
+
+ // Logger output
+ log : function(message, tag) {
+ var logEntry = new LogEntry(message, tag || "info")
+ this.logEntries.push(logEntry)
+ this.onupdate.dispatch(logEntry)
+ },
+
+ info : function(message) {
+ this.log(message, 'info')
+ },
+
+ debug : function(message) {
+ this.log(message, 'debug')
+ },
+
+ warn : function(message) {
+ this.log(message, 'warning')
+ },
+
+ error : function(message, error) {
+ this.log(message + ": \n" + error, 'error')
+ },
+
+ clear : function () {
+ this.logEntries = []
+ this.onclear.dispatch()
+ }
+}
+
+LogEntry = Class.create()
+LogEntry.prototype = {
+ initialize : function(message, tag) {
+ this.message = message
+ this.tag = tag
+ }
+}
+
+LogConsole = Class.create()
+LogConsole.prototype = {
+
+ // Properties
+ // ----------
+ commandHistory : [],
+ commandIndex : 0,
+
+ // Methods
+ // -------
+
+ initialize : function() {
+ this.outputCount = 0
+ this.tagPattern = Cookie.get('tagPattern') || ".*"
+
+ // I hate writing javascript in HTML... but what's a better alternative
+ this.logElement = document.createElement('div')
+ document.body.appendChild(this.logElement)
+ Element.hide(this.logElement)
+
+ this.logElement.style.position = "absolute"
+ this.logElement.style.left = '0px'
+ this.logElement.style.width = '100%'
+
+ this.logElement.style.textAlign = "left"
+ this.logElement.style.fontFamily = "lucida console"
+ this.logElement.style.fontSize = "100%"
+ this.logElement.style.backgroundColor = 'darkgray'
+ this.logElement.style.opacity = 0.9
+ this.logElement.style.zIndex = 2000
+
+ // Add toolbarElement
+ this.toolbarElement = document.createElement('div')
+ this.logElement.appendChild(this.toolbarElement)
+ this.toolbarElement.style.padding = "0 0 0 2px"
+
+ // Add buttons
+ this.buttonsContainerElement = document.createElement('span')
+ this.toolbarElement.appendChild(this.buttonsContainerElement)
+
+ this.buttonsContainerElement.innerHTML += '<button onclick="logConsole.toggle()" style="float:right;color:black">close</button>'
+ this.buttonsContainerElement.innerHTML += '<button onclick="Logger.clear()" style="float:right;color:black">clear</button>'
+ if(!Prado.Inspector.disabled)
+ this.buttonsContainerElement.innerHTML += '<button onclick="Prado.Inspector.inspect()" style="float:right;color:black; margin-right:15px;">Object Tree</button>'
+
+
+ //Add Tag Filter
+ this.tagFilterContainerElement = document.createElement('span')
+ this.toolbarElement.appendChild(this.tagFilterContainerElement)
+ this.tagFilterContainerElement.style.cssFloat = 'left'
+ this.tagFilterContainerElement.appendChild(document.createTextNode("Log Filter"))
+
+ this.tagFilterElement = document.createElement('input')
+ this.tagFilterContainerElement.appendChild(this.tagFilterElement)
+ this.tagFilterElement.style.width = '200px'
+ this.tagFilterElement.value = this.tagPattern
+ this.tagFilterElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out
+
+ Event.observe(this.tagFilterElement, 'keyup', this.updateTags.bind(this))
+ Event.observe(this.tagFilterElement, 'click', function() {this.tagFilterElement.select()}.bind(this))
+
+ // Add outputElement
+ this.outputElement = document.createElement('div')
+ this.logElement.appendChild(this.outputElement)
+ this.outputElement.style.overflow = "auto"
+ this.outputElement.style.clear = "both"
+ this.outputElement.style.height = "200px"
+ this.outputElement.style.backgroundColor = 'black'
+
+ this.inputContainerElement = document.createElement('div')
+ this.inputContainerElement.style.width = "100%"
+ this.logElement.appendChild(this.inputContainerElement)
+
+ this.inputElement = document.createElement('input')
+ this.inputContainerElement.appendChild(this.inputElement)
+ this.inputElement.style.width = '100%'
+ this.inputElement.style.borderWidth = '0px' // Inputs with 100% width always seem to be too large (I HATE THEM) they only work if the border, margin and padding are 0
+ this.inputElement.style.margin = '0px'
+ this.inputElement.style.padding = '0px'
+ this.inputElement.value = 'Type command here'
+ this.inputElement.setAttribute('autocomplete', 'off') // So Firefox doesn't flip out
+
+ Event.observe(this.inputElement, 'keyup', this.handleInput.bind(this))
+ Event.observe(this.inputElement, 'click', function() {this.inputElement.select()}.bind(this))
+
+ window.setInterval(this.repositionWindow.bind(this), 500)
+ this.repositionWindow()
+
+ // Listen to the logger....
+ Logger.onupdate.addListener(this.logUpdate.bind(this))
+ Logger.onclear.addListener(this.clear.bind(this))
+
+ // Preload log element with the log entries that have been entered
+ for (var i = 0; i < Logger.logEntries.length; i++) {
+ this.logUpdate(Logger.logEntries[i])
+ }
+
+ // Feed all errors into the logger (For some unknown reason I can only get this to work
+ // with an inline event declaration)
+ Event.observe(window, 'error', function(msg, url, lineNumber) {Logger.error("Error in (" + (url || location) + ") on line "+lineNumber+"", msg)})
+
+ // Allow acess key link
+ var accessElement = document.createElement('span')
+ accessElement.innerHTML = '<button style="position:absolute;top:-100px" onclick="javascript:logConsole.toggle()" accesskey="d"></button>'
+ document.body.appendChild(accessElement)
+
+ if (Cookie.get('ConsoleVisible') == 'true') {
+ this.toggle()
+ }
+ },
+
+ toggle : function() {
+ if (this.logElement.style.display == 'none') {
+ this.show()
+ }
+ else {
+ this.hide()
+ }
+ },
+
+ show : function() {
+ Element.show(this.logElement)
+ this.outputElement.scrollTop = this.outputElement.scrollHeight // Scroll to bottom when toggled
+ Cookie.set('ConsoleVisible', 'true')
+ this.inputElement.select()
+ },
+
+ hide : function() {
+ Element.hide(this.logElement)
+ Cookie.set('ConsoleVisible', 'false')
+ },
+
+ output : function(message, style) {
+ // If we are at the bottom of the window, then keep scrolling with the output
+ var shouldScroll = (this.outputElement.scrollTop + (2 * this.outputElement.clientHeight)) >= this.outputElement.scrollHeight
+
+ this.outputCount++
+ style = (style ? style += ';' : '')
+ style += 'padding:1px;margin:0 0 5px 0'
+
+ if (this.outputCount % 2 == 0) style += ";background-color:#101010"
+
+ message = message || "undefined"
+ message = message.toString().escapeHTML()
+
+ this.outputElement.innerHTML += "<pre style='" + style + "'>" + message + "</pre>"
+
+ if (shouldScroll) {
+ this.outputElement.scrollTop = this.outputElement.scrollHeight
+ }
+ },
+
+ updateTags : function() {
+ var pattern = this.tagFilterElement.value
+
+ if (this.tagPattern == pattern) return
+
+ try {
+ new RegExp(pattern)
+ }
+ catch (e) {
+ return
+ }
+
+ this.tagPattern = pattern
+ Cookie.set('tagPattern', this.tagPattern)
+
+ this.outputElement.innerHTML = ""
+
+ // Go through each log entry again
+ this.outputCount = 0;
+ for (var i = 0; i < Logger.logEntries.length; i++) {
+ this.logUpdate(Logger.logEntries[i])
+ }
+ },
+
+ repositionWindow : function() {
+ var offset = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop
+ var pageHeight = self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
+ this.logElement.style.top = (offset + pageHeight - Element.getHeight(this.logElement)) + "px"
+ },
+
+ // Event Handlers
+ // --------------
+
+ logUpdate : function(logEntry) {
+ if (logEntry.tag.search(new RegExp(this.tagPattern, 'igm')) == -1) return
+ var style = ''
+ if (logEntry.tag.search(/error/) != -1) style += 'color:red'
+ else if (logEntry.tag.search(/warning/) != -1) style += 'color:orange'
+ else if (logEntry.tag.search(/debug/) != -1) style += 'color:green'
+ else if (logEntry.tag.search(/info/) != -1) style += 'color:white'
+ else style += 'color:yellow'
+
+ this.output(logEntry.message, style)
+ },
+
+ clear : function(e) {
+ this.outputElement.innerHTML = ""
+ },
+
+ handleInput : function(e) {
+ if (e.keyCode == Event.KEY_RETURN ) {
+ var command = this.inputElement.value
+
+ switch(command) {
+ case "clear":
+ Logger.clear()
+ break
+
+ default:
+ var consoleOutput = ""
+
+ try {
+ consoleOutput = eval(this.inputElement.value)
+ }
+ catch (e) {
+ Logger.error("Problem parsing input <" + command + ">", e)
+ break
+ }
+
+ Logger.log(consoleOutput)
+ break
+ }
+
+ if (this.inputElement.value != "" && this.inputElement.value != this.commandHistory[0]) {
+ this.commandHistory.unshift(this.inputElement.value)
+ }
+
+ this.commandIndex = 0
+ this.inputElement.value = ""
+ }
+ else if (e.keyCode == Event.KEY_UP && this.commandHistory.length > 0) {
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+
+ if (this.commandIndex < this.commandHistory.length - 1) {
+ this.commandIndex += 1
+ }
+ }
+ else if (e.keyCode == Event.KEY_DOWN && this.commandHistory.length > 0) {
+ if (this.commandIndex > 0) {
+ this.commandIndex -= 1
+ }
+
+ this.inputElement.value = this.commandHistory[this.commandIndex]
+ }
+ else {
+ this.commandIndex = 0
+ }
+ }
+}
+
+// Load the Console when the window loads
+Event.observe(window, "load", function() {logConsole = new LogConsole()})
+
+// -------------------------
+// Helper Functions And Junk
+// -------------------------
+function inspect(element, hideProperties, showMethods) {
+ var properties = []
+ var methods = []
+
+
+ for(var internal in element) {
+ if(internal == '______array') continue;
+ try {
+ if (element[internal] instanceof Function) {
+ if (showMethods)
+ methods.push(internal + ":\t" + element[internal] )
+ }
+ else if(element[internal] instanceof Object)
+ {
+ methods.push(internal + ":\t" + inspect(element[internal], hideProperties, showMethods));
+ }
+ else {
+ if (!hideProperties)
+ properties.push(internal + ":\t" + element[internal] )
+ }
+ }
+ catch (e) {
+ Logger.error("Excetion thrown while inspecting object.", e)
+ }
+ }
+
+ properties.sort()
+ methods.sort()
+
+ var internals = properties.concat(methods)
+ var output = ""
+ for (var i = 0; i < internals.length; i++) {
+ output += (internals[i] + "\n")
+ }
+
+ return output
+}
+
+Array.prototype.contains = function(object) {
+ for(var i = 0; i < this.length; i++) {
+ if (object == this[i]) return true
+ }
+
+ return false
+}
+
+// Helper Alias for simple logging
+var puts = function() {return Logger.log(arguments[0], arguments[1])}
+
+/*************************************
+
+ Javascript Object Tree
+ version 1.0
+ last revision:04.11.2004
+ steve@slayeroffice.com
+ http://slayeroffice.com
+
+ (c)2004 S.G. Chipman
+
+ Please notify me of any modifications
+ you make to this code so that I can
+ update the version hosted on slayeroffice.com
+
+
+************************************/
+if(typeof Prado == "undefined")
+ var Prado = {};
+Prado.Inspector =
+{
+ d : document,
+ types : new Array(),
+ objs : new Array(),
+ hidden : new Array(),
+ opera : window.opera,
+ displaying : '',
+
+ format : function(str) {
+ str=str.replace(/</g,"&lt;");
+ str=str.replace(/>/g,"&gt;");
+ return str;
+ },
+
+ parseJS : function(obj) {
+ var name;
+ if(typeof obj == "string") { name = obj; obj = eval(obj); }
+ win= typeof obj == 'undefined' ? window : obj;
+ this.displaying = name ? name : win.toString();
+ for(js in win) {
+ try {
+ if(win[js] && js.toString().indexOf("Inspector")==-1 && win[js].toString().indexOf("[native code]")==-1) {
+ t=typeof(win[js]);
+ if(!this.objs[t.toString()]) {
+ this.types[this.types.length]=t;;
+ this.objs[t]=new Array();
+ }
+ index=this.objs[t].length
+ this.objs[t][index]=new Array();
+ this.objs[t][index][0]=js;
+ this.objs[t][index][1]=this.format(win[js].toString());
+ }
+ } catch(err) { }
+ }
+
+ },
+
+ show : function(objID) {
+ this.d.getElementById(objID).style.display=this.hidden[objID]?"none":"block";
+ this.hidden[objID]=this.hidden[objID]?0:1;
+ },
+
+ changeSpan : function(spanID) {
+ if(this.d.getElementById(spanID).innerHTML.indexOf("+")>-1){
+ this.d.getElementById(spanID).innerHTML="[-]";
+ } else {
+ this.d.getElementById(spanID).innerHTML="[+]";
+ }
+ },
+
+ buildInspectionLevel : function()
+ {
+ var display = this.displaying;
+ var list = display.split(".");
+ var links = ["<a href=\"javascript:var_dump()\">[object Window]</a>"];
+ var name = '';
+ if(display.indexOf("[object ") >= 0) return links.join(".");
+ for(var i = 0; i < list.length; i++)
+ {
+ name += (name.length ? "." : "") + list[i];
+ links[i+1] = "<a href=\"javascript:var_dump('"+name+"')\">"+list[i]+"</a>";
+ }
+ return links.join(".");
+ },
+
+ buildTree : function() {
+ mHTML = "<div>Inspecting "+this.buildInspectionLevel()+"</div>";
+ mHTML +="<ul class=\"topLevel\">";
+ this.types.sort();
+ var so_objIndex=0;
+ for(i=0;i<this.types.length;i++) {
+ mHTML+="<li style=\"cursor:pointer;\" onclick=\"Prado.Inspector.show('ul"+i+"');Prado.Inspector.changeSpan('sp" + i + "')\"><span id=\"sp" + i + "\">[+]</span><b>" + this.types[i] + "</b> (" + this.objs[this.types[i]].length + ")</li><ul style=\"display:none;\" id=\"ul"+i+"\">";
+ this.hidden["ul"+i]=0;
+ for(e=0;e<this.objs[this.types[i]].length;e++) {
+ var more = "";
+ if(this.objs[this.types[i]][e][1].indexOf("[object ") >= 0 && /^[a-zA-Z_]/.test(this.objs[this.types[i]][e][0][0]))
+ {
+ if(this.displaying.indexOf("[object ") < 0)
+ more = " <a href=\"javascript:var_dump('"+this.displaying+"."+this.objs[this.types[i]][e][0]+"')\"><b>more</b></a>";
+ else if(this.displaying.indexOf("[object Window]") >= 0)
+ more = " <a href=\"javascript:var_dump('"+this.objs[this.types[i]][e][0]+"')\"><b>more</b></a>";
+ }
+ mHTML+="<li style=\"cursor:pointer;\" onclick=\"Prado.Inspector.show('mul" + so_objIndex + "');Prado.Inspector.changeSpan('sk" + so_objIndex + "')\"><span id=\"sk" + so_objIndex + "\">[+]</span>" + this.objs[this.types[i]][e][0] + "</li><ul id=\"mul" + so_objIndex + "\" style=\"display:none;\"><li style=\"list-style-type:none;\"><pre>" + this.objs[this.types[i]][e][1] + more + "</pre></li></ul>";
+ this.hidden["mul"+so_objIndex]=0;
+ so_objIndex++;
+ }
+ mHTML+="</ul>";
+ }
+ mHTML+="</ul>";
+ this.d.getElementById("so_mContainer").innerHTML =mHTML;
+ },
+
+ handleKeyEvent : function(e) {
+ keyCode=document.all?window.event.keyCode:e.keyCode;
+ if(keyCode==27) {
+ this.cleanUp();
+ }
+ },
+
+ cleanUp : function()
+ {
+ if(this.d.getElementById("so_mContainer"))
+ {
+ this.d.body.removeChild(this.d.getElementById("so_mContainer"));
+ this.d.body.removeChild(this.d.getElementById("so_mStyle"));
+ if(typeof Event != "undefined")
+ Event.stopObserving(this.d, "keydown", this.handleKeyEvent.bind(this));
+ this.types = new Array();
+ this.objs = new Array();
+ this.hidden = new Array();
+ }
+ },
+
+ disabled : document.all && !this.opera,
+
+ inspect : function(obj)
+ {
+ if(this.disabled)return alert("Sorry, this only works in Mozilla and Firefox currently.");
+ this.cleanUp();
+ mObj=this.d.body.appendChild(this.d.createElement("div"));
+ mObj.id="so_mContainer";
+ sObj=this.d.body.appendChild(this.d.createElement("style"));
+ sObj.id="so_mStyle";
+ sObj.type="text/css";
+ sObj.innerHTML = this.style;
+ if(typeof Event != "undefined")
+ Event.observe(this.d, "keydown", this.handleKeyEvent.bind(this));
+
+ this.parseJS(obj);
+ this.buildTree();
+
+ cObj=mObj.appendChild(this.d.createElement("div"));
+ cObj.className="credits";
+ cObj.innerHTML = "<b>[esc] to <a href=\"javascript:Prado.Inspector.cleanUp();\">close</a></b><br />Javascript Object Tree V2.0, <a target=\"_blank\" href=\"http://slayeroffice.com/?c=/content/tools/js_tree.html\">more info</a>.";
+
+ window.scrollTo(0,0);
+ },
+
+ style : "#so_mContainer { position:absolute; top:5px; left:5px; background-color:#E3EBED; text-align:left; font:9pt verdana; width:85%; border:2px solid #000; padding:5px; z-index:1000; color:#000; } " +
+ "#so_mContainer ul { padding-left:20px; } " +
+ "#so_mContainer ul li { display:block; list-style-type:none; list-style-image:url(); line-height:2em; -moz-border-radius:.75em; font:10px verdana; padding:0; margin:2px; color:#000; } " +
+ "#so_mContainer li:hover { background-color:#E3EBED; } " +
+ "#so_mContainer ul li span { position:relative; width:15px; height:15px; margin-right:4px; } " +
+ "#so_mContainer pre { background-color:#F9FAFB; border:1px solid #638DA1; height:auto; padding:5px; font:9px verdana; color:#000; } " +
+ "#so_mContainer .topLevel { margin:0; padding:0; } " +
+ "#so_mContainer .credits { float:left; width:200px; font:6.5pt verdana; color:#000; padding:2px; margin-left:5px; text-align:left; border-top:1px solid #000; margin-top:15px; width:75%; } " +
+ "#so_mContainer .credits a { font:9px verdana; font-weight:bold; color:#004465; text-decoration:none; background-color:transparent; }"
+}
+
+function var_dump(obj)
+{
+ Prado.Inspector.inspect(obj);
+} \ No newline at end of file
diff --git a/framework/Web/Javascripts/extra/tp_template.js b/framework/Web/Javascripts/extra/tp_template.js
new file mode 100644
index 00000000..6015034c
--- /dev/null
+++ b/framework/Web/Javascripts/extra/tp_template.js
@@ -0,0 +1,315 @@
+/**
+ * TrimPath Template. Release 1.0.16.
+ * Copyright (C) 2004, 2005 Metaha.
+ *
+ * TrimPath Template is licensed under the GNU General Public License
+ * and the Apache License, Version 2.0, as follows:
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Licensed 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.
+ */
+var TrimPath;
+
+// TODO: Debugging mode vs stop-on-error mode - runtime flag.
+// TODO: Handle || (or) characters and backslashes.
+// TODO: Add more modifiers.
+
+(function() { // Using a closure to keep global namespace clean.
+ var theEval = eval; // Security, to ensure eval cleanliness.
+ if (TrimPath == null)
+ TrimPath = new Object();
+ if (TrimPath.evalEx == null)
+ TrimPath.evalEx = function(src) { return theEval(src); };
+
+ TrimPath.parseTemplate = function(tmplContent, optTmplName, optEtc) {
+ if (optEtc == null)
+ optEtc = TrimPath.parseTemplate_etc;
+ var funcSrc = parse(tmplContent, optTmplName, optEtc);
+ var func = TrimPath.evalEx(funcSrc, optTmplName, 1);
+ if (func != null)
+ return new optEtc.Template(optTmplName, tmplContent, funcSrc, func, optEtc);
+ return null;
+ }
+
+ try {
+ String.prototype.process = function(context, optFlags) {
+ var template = TrimPath.parseTemplate(this, null);
+ if (template != null)
+ return template.process(context, optFlags);
+ return this;
+ }
+ } catch (e) { // Swallow exception, such as when String.prototype is sealed.
+ }
+
+ TrimPath.parseTemplate_etc = {}; // Exposed for extensibility.
+ TrimPath.parseTemplate_etc.statementTag = "forelse|for|if|elseif|else|var|macro";
+ TrimPath.parseTemplate_etc.statementDef = { // Lookup table for statement tags.
+ "if" : { delta: 1, prefix: "if (", suffix: ") {", paramMin: 1 },
+ "else" : { delta: 0, prefix: "} else {" },
+ "elseif" : { delta: 0, prefix: "} else { if (", suffix: ") {", paramDefault: "true" },
+ "/if" : { delta: -1, prefix: "}" },
+ "for" : { delta: 1, paramMin: 3,
+ prefixFunc : function(stmtParts, state, tmplName, etc) {
+ if (stmtParts[2] != "in")
+ throw new etc.ParseError(tmplName, state.line, "bad for loop statement: " + stmtParts.join(' '));
+ var iterVar = stmtParts[1];
+ var listVar = "__LIST__" + iterVar;
+ return [ "var ", listVar, " = ", stmtParts[3], ";",
+ "if ((", listVar, ") != null && (", listVar, ").length > 0) { for (var ",
+ iterVar, "_index in ", listVar, ") { var ",
+ iterVar, " = ", listVar, "[", iterVar, "_index];" ].join("");
+ } },
+ "forelse" : { delta: 0, prefix: "} } else { if (", suffix: ") {", paramDefault: "true" },
+ "/for" : { delta: -1, prefix: "} }" },
+ "var" : { delta: 0, prefix: "var ", suffix: ";" },
+ "macro" : { delta: 1, prefix: "function ", suffix: "{ var _OUT_arr = []; var _OUT = { write: function(m) { if (m) _OUT_arr.push(m); }, }; " },
+ "/macro" : { delta: -1, prefix: " return _OUT_arr.join(''); }" }
+ }
+ TrimPath.parseTemplate_etc.modifierDef = {
+ "eat" : function(v) { return ""; },
+ "escape" : function(s) { return String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"); },
+ "capitalize" : function(s) { return String(s).toUpperCase(); },
+ "default" : function(s, d) { return s != null ? s : d; }
+ }
+ TrimPath.parseTemplate_etc.modifierDef.h = TrimPath.parseTemplate_etc.modifierDef.escape;
+
+ TrimPath.parseTemplate_etc.Template = function(tmplName, tmplContent, funcSrc, func, etc) {
+ this.process = function(context, flags) {
+ if (context == null)
+ context = {};
+ if (context._MODIFIERS == null)
+ context._MODIFIERS = {};
+ for (var k in etc.modifierDef) {
+ if (context._MODIFIERS[k] == null)
+ context._MODIFIERS[k] = etc.modifierDef[k];
+ }
+ if (flags == null)
+ flags = {};
+ var resultArr = [];
+ var resultOut = { write: function(m) { if (m) resultArr.push(m); } };
+ try {
+ func(resultOut, context, flags);
+ } catch (e) {
+ if (flags.throwExceptions == true)
+ throw e;
+ var result = new String(resultArr.join("") + "[ERROR: " + e.toString() + "]");
+ result["exception"] = e;
+ return result;
+ }
+ return resultArr.join("");
+ }
+ this.name = tmplName;
+ this.source = tmplContent;
+ this.sourceFunc = funcSrc;
+ this.toString = function() { return "TrimPath.Template [" + tmplName + "]"; }
+ }
+ TrimPath.parseTemplate_etc.ParseError = function(name, line, message) {
+ this.name = name;
+ this.line = line;
+ this.message = message;
+ }
+ TrimPath.parseTemplate_etc.ParseError.prototype.toString = function() {
+ return ("TrimPath template ParseError in " + this.name + ": line " + this.line + ", " + this.msg);
+ }
+
+ var parse = function(body, tmplName, etc) {
+ body = cleanWhiteSpace(body);
+ var funcText = [ "var TrimPath_Template_TEMP = function(_OUT, _CONTEXT, _FLAGS) { with (_CONTEXT) {" ];
+ var state = { stack: [], line: 1 }; // TODO: Fix line number counting.
+ var endStmtPrev = -1;
+ while (endStmtPrev + 1 < body.length) {
+ var begStmt = endStmtPrev;
+ // Scan until we find some statement markup.
+ begStmt = body.indexOf("{", begStmt + 1);
+ while (begStmt >= 0) {
+ if (body.charAt(begStmt - 1) != '$' && // Not an expression or backslashed,
+ body.charAt(begStmt - 1) != '\\') { // so we assume it must be a statement tag.
+ var offset = (body.charAt(begStmt + 1) == '/' ? 2 : 1); // Close tags offset of 2 skips '/'.
+ // 10 is larger than maximum statement tag length.
+ if (body.substring(begStmt + offset, begStmt + 10 + offset).search(TrimPath.parseTemplate_etc.statementTag) == 0)
+ break; // Found a match.
+ }
+ begStmt = body.indexOf("{", begStmt + 1);
+ }
+ if (begStmt < 0) // In "a{for}c", begStmt will be 1.
+ break;
+ var endStmt = body.indexOf("}", begStmt + 1); // In "a{for}c", endStmt will be 5.
+ if (endStmt < 0)
+ break;
+ emitSectionText(body.substring(endStmtPrev + 1, begStmt), funcText);
+ emitStatement(body.substring(begStmt, endStmt +1), state, funcText, tmplName, etc);
+ endStmtPrev = endStmt;
+ }
+ emitSectionText(body.substring(endStmtPrev + 1), funcText);
+ if (state.stack.length != 0)
+ throw new etc.ParseError(tmplName, state.line, "unclosed, unmatched statement(s): " + state.stack.join(","));
+ funcText.push("}}; TrimPath_Template_TEMP");
+ return funcText.join("");
+ }
+
+ var emitStatement = function(stmtStr, state, funcText, tmplName, etc) {
+ var parts = stmtStr.slice(1, -1).split(' ');
+ var stmt = etc.statementDef[parts[0]]; // Here, parts[0] == for/if/else/...
+ if (stmt == null) { // Not a real statement.
+ emitSectionText(stmtStr, funcText);
+ return;
+ }
+ if (stmt.delta < 0) {
+ if (state.stack.length <= 0)
+ throw new etc.ParseError(tmplName, state.line, "close tag does not match any previous statement: " + stmtStr);
+ state.stack.pop();
+ }
+ if (stmt.delta > 0)
+ state.stack.push(stmtStr);
+
+ if (stmt.paramMin != null &&
+ stmt.paramMin >= parts.length)
+ throw new etc.ParseError(tmplName, state.line, "statement needs more parameters: " + stmtStr);
+ if (stmt.prefixFunc != null)
+ funcText.push(stmt.prefixFunc(parts, state, tmplName, etc));
+ else
+ funcText.push(stmt.prefix);
+ if (stmt.suffix != null) {
+ if (parts.length <= 1) {
+ if (stmt.paramDefault != null)
+ funcText.push(stmt.paramDefault);
+ } else {
+ for (var i = 1; i < parts.length; i++) {
+ if (i > 1)
+ funcText.push(' ');
+ funcText.push(parts[i]);
+ }
+ }
+ funcText.push(stmt.suffix);
+ }
+ }
+
+ var emitSectionText = function(text, funcText) {
+ if (text.length <= 0)
+ return;
+ var nlPrefix = 0; // Index to first non-newline in prefix.
+ var nlSuffix = text.length - 1; // Index to first non-space/tab in suffix.
+ while (nlPrefix < text.length && (text.charAt(nlPrefix) == '\n'))
+ nlPrefix++;
+ while (nlSuffix >= 0 && (text.charAt(nlSuffix) == ' ' || text.charAt(nlSuffix) == '\t'))
+ nlSuffix--;
+ if (nlSuffix < nlPrefix)
+ nlSuffix = nlPrefix;
+ if (nlPrefix > 0) {
+ funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("');
+ funcText.push(text.substring(0, nlPrefix).replace('\n', '\\n'));
+ funcText.push('");');
+ }
+ var lines = text.substring(nlPrefix, nlSuffix + 1).split('\n');
+ for (var i = 0; i < lines.length; i++) {
+ emitSectionTextLine(lines[i], funcText);
+ if (i < lines.length - 1)
+ funcText.push('_OUT.write("\\n");\n');
+ }
+ if (nlSuffix + 1 < text.length) {
+ funcText.push('if (_FLAGS.keepWhitespace == true) _OUT.write("');
+ funcText.push(text.substring(nlSuffix + 1).replace('\n', '\\n'));
+ funcText.push('");');
+ }
+ }
+
+ var emitSectionTextLine = function(line, funcText) {
+ var endExprPrev = -1;
+ while (endExprPrev + 1 < line.length) {
+ var begExpr = line.indexOf("${", endExprPrev + 1); // In "a${b}c", begExpr == 1
+ if (begExpr < 0)
+ break;
+ var endExpr = line.indexOf("}", begExpr + 2); // In "a${b}c", endExpr == 4; 2 == "${".length
+ if (endExpr < 0)
+ break;
+ emitText(line.substring(endExprPrev + 1, begExpr), funcText);
+ // Example: exprs == 'firstName|default:"John Doe"|capitalize'.split('|')
+ var exprArr = line.substring(begExpr + 2, endExpr).replace(/\|\|/g, "#@@#").split('|');
+ for (var k in exprArr)
+ exprArr[k] = exprArr[k].replace(/#@@#/g, '||');
+ funcText.push('_OUT.write(');
+ emitExpression(exprArr, exprArr.length - 1, funcText);
+ funcText.push(');');
+ endExprPrev = endExpr;
+ }
+ emitText(line.substring(endExprPrev + 1), funcText);
+ }
+
+ var emitText = function(text, funcText) {
+ if (text == null ||
+ text.length <= 0)
+ return;
+ text = text.replace(/\\/g, '\\\\');
+ text = text.replace(/"/g, '\\"');
+ funcText.push('_OUT.write("');
+ funcText.push(text);
+ funcText.push('");');
+ }
+
+ var emitExpression = function(exprArr, index, funcText) {
+ // Ex: foo|a:x|b:y1,y2|c:z1,z2 is emitted as c(b(a(foo,x),y1,y2),z1,z2)
+ var expr = exprArr[index]; // Ex: exprArr == [firstName,capitalize,default:"John Doe"]
+ if (index <= 0) { // Ex: expr == 'default:"John Doe"'
+ funcText.push(expr);
+ return;
+ }
+ var parts = expr.split(':');
+ funcText.push('_MODIFIERS["');
+ funcText.push(parts[0]); // The parts[0] is a modifier function name, like capitalize.
+ funcText.push('"](');
+ emitExpression(exprArr, index - 1, funcText);
+ if (parts.length > 1) {
+ funcText.push(',');
+ funcText.push(parts[1]);
+ }
+ funcText.push(')');
+ }
+
+ var cleanWhiteSpace = function(result) {
+ result = result.replace(/\t/g, " ");
+ result = result.replace(/\r\n/g, "\n");
+ result = result.replace(/\r/g, "\n");
+ result = result.replace(/^(.*\S)[ \t]+$/gm, "$1"); // Right trim.
+ return result;
+ }
+
+ // The DOM helper functions depend on DOM/DHTML, so they only work in a browser.
+ // However, these are not considered core to the engine.
+ //
+ TrimPath.parseDOMTemplate = function(elementId, optDocument, optEtc) {
+ if (optDocument == null)
+ optDocument = document;
+ var element = optDocument.getElementById(elementId);
+ var content = element.value; // Like textarea.value.
+ if (content == null)
+ content = element.innerHTML; // Like textarea.innerHTML.
+ content = content.replace(/&lt;/g, "<").replace(/&gt;/g, ">");
+ return TrimPath.parseTemplate(content, elementId, optEtc);
+ }
+
+ TrimPath.processDOMTemplate = function(elementId, context, optFlags, optDocument, optEtc) {
+ return TrimPath.parseDOMTemplate(elementId, optDocument, optEtc).process(context, optFlags);
+ }
+}) ();