/*
* jQuery Taconite plugin - A port of the Taconite framework by Ryan Asleson and
* Nathaniel T. Schutta: http://taconite.sourceforge.net/
*
* Examples and documentation at: http://malsup.com/jquery/taconite/
* Copyright (c) 2007 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
* Thanks to Kenton Simpson for contributing some good ideas!
*
* @author: M. Alsup
* @version: 2.0.9 (3/14/2007)
* @requires jQuery v1.0.4 or later
*/
(function($) {
// add 'replace' and 'replaceContent' plugins (conditionally)
if (typeof $.fn.replace == 'undefined')
$.fn.replace = function(a) { return this.after(a).remove(); };
if (typeof $.fn.replaceContent == 'undefined')
$.fn.replaceContent = function(a) { return this.empty().append(a); };
/**
* Processes a Taconite XML command document.
* @name taconite
* @param Document|String command document
*/
$.taconite = $.xmlExec = function(xml) { $.taconite.impl.process(xml); }
$.taconite.version = [2,0,9]; // major,minor,point revision nums
$.taconite.debug = 0; // set to true to enable debug logging to Firebug
$.taconite.lastTime = 0; // processing time for most recent document
$.taconite._httpData = $.httpData; // original jQuery httpData function
// auto-detection method (replaces jQuery's httpData method when auto-detection is enabled)
$.httpData = $.taconite.detect = function(xhr, type) {
var ct = xhr.getResponseHeader('content-type');
$.taconite.log('[AJAX response] content-type: ', ct, '; status: ', xhr.status, ' ', xhr.statusText, '; has responseXML: ', xhr.responseXML != null);
var data = $.taconite._httpData(xhr, type); // call original method
if (data && data.documentElement) {
var root = data.documentElement.tagName;
$.taconite.log('XML document root: ', root);
if (root == 'taconite') {
$.taconite.log('taconite command document detected');
$.taconite(data);
}
}
else $.taconite.log('httpData: response is not XML (or not "valid" XML)');
return data;
};
// allow auto-detection to be enabled/disabled on-demand
$.taconite.enableAutoDetection = function(b) {
// reset jQuery's httpData method
$.httpData = b ? $.taconite.detect : $.taconite._httpData;
};
$.taconite.log = function() {
if (!$.taconite.debug || !window.console || !window.console.log) return;
if (!$.taconite.log.count++)
$.taconite.log('Plugin Version: ' + $.taconite.version.join('.'));
window.console.log('[taconite] ' + [].join.call(arguments,''));
};
$.taconite.log.count = 0;
$.taconite.impl = {
trimHash: {wrap:1},
// convert string to xml document
convert: function(s) {
var doc;
$.taconite.log('attempting string to document conversion');
try {
if (window.ActiveXObject) {
doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = 'false';
doc.loadXML(s);
}
else {
var parser = new DOMParser();
doc = parser.parseFromString(s, 'text/xml');
}
}
catch(e) {
if (window.console && window.console.error)
window.console.error('[taconite] ERROR parsing XML string for conversion: ' + e);
throw e;
}
var ok = doc && doc.documentElement && doc.documentElement.tagName != 'parsererror';
$.taconite.log('conversion ', ok ? 'successful!' : 'FAILED');
return doc;
},
process: function(xml) {
if (typeof xml == 'string')
xml = this.convert(xml);
if (!xml || !xml.documentElement) {
$.taconite.log('$.taconite invoked without valid document; nothing to process');
return;
}
try {
var t = new Date().getTime();
// process the document
$.taconite.impl.process1(xml.documentElement.childNodes);
$.taconite.lastTime = (new Date().getTime()) - t;
$.taconite.log('time to process response: ' + $.taconite.lastTime + 'ms');
} catch(e) {
if (window.console && window.console.error)
window.console.error('[taconite] ERROR processing document: ' + e);
throw e;
}
},
process1: function(commands) {
for(var i=0; i < commands.length; i++) {
if (commands[i].nodeType != 1)
continue; // commands are elements
var cmdNode = commands[i], cmd = cmdNode.tagName;
if (cmd == 'eval') {
var js = (cmdNode.firstChild ? cmdNode.firstChild.nodeValue : null);
$.taconite.log('invoking "eval" command: ', js);
if (js) $.globalEval(js);
continue;
}
var q = cmdNode.getAttribute('select');
var jq = $(q);
if (!jq[0]) {
$.taconite.log('No matching targets for selector: ', q);
continue;
}
var a = [];
if (cmdNode.childNodes.length > 0) {
for (var j=0,els=[]; j < cmdNode.childNodes.length; j++)
els[j] = this.createNode(cmdNode.childNodes[j]);
a.push(this.trimHash[cmd] ? this.cleanse(els) : els);
}
else {
// remain backward compat with pre 2.0.9 versions
var n = cmdNode.getAttribute('name');
var v = cmdNode.getAttribute('value');
if (n !== null) a.push(n);
if (v !== null) a.push(v);
// @since: 2.0.9: support arg1, arg2, arg3...
for (var j=1; true; j++) {
v = cmdNode.getAttribute('arg'+j);
if (v === null)
break;
a.push(v);
}
}
if ($.taconite.debug) {
var arg = els ? '...' : a.join(',');
$.taconite.log("invoking command: $('", q, "').", cmd, '('+ arg +')');
}
jq[cmd].apply(jq,a);
}
},
cleanse: function(els) {
for (var i=0, a=[]; i < els.length; i++)
if (els[i].nodeType == 1) a.push(els[i]);
return a;
},
createNode: function (node) {
var type = node.nodeType;
if (type == 1) return this.createElement(node);
if (type == 3) return this.fixTextNode(node.nodeValue);
if (type == 4) return document.createTextNode(node.nodeValue);
return null;
},
fixTextNode: function(s) {
if ($.browser.msie) s = s.replace(/\n/g, '\r');
return document.createTextNode(s);
},
createElement: function (node) {
var e, tag = node.tagName.toLowerCase();
if ($.browser.msie && (tag == 'input' || tag == 'button')) {
var type = node.getAttribute('type');
if (type == 'radio' || type == 'checkbox')
return document.createElement('<input ' + this.copyAttrs(null, node, true) + '>');
else if (tag == 'button')
e = document.createElement('<button ' + this.copyAttrs(null, node, true) + '>');
}
if (!e) {
e = document.createElement(tag);
this.copyAttrs(e, node);
}
// IE fix; script tag not allowed to have children
if($.browser.msie && !e.canHaveChildren) {
if(node.childNodes.length > 0)
e.text = node.text;
}
else {
for(var i=0, max=node.childNodes.length; i < max; i++) {
var child = this.createNode (node.childNodes[i]);
if(child) e.appendChild(child);
}
}
return e;
},
copyAttrs: function (dest, src, inline) {
for (var i=0, attr=''; i < src.attributes.length; i++) {
var a = src.attributes[i], n = $.trim(a.name), v = $.trim(a.value);
if (inline) attr += (n + '="' + v + '" ');
else if (n == 'style') { // IE workaround
dest.style.cssText = v;
dest.setAttribute(n, v);
}
else $.attr(dest, n, v);
}
return attr;
}
};
})(jQuery);