+
+
+
+
diff -r 2eaea1afd6b3 -r 901803e1305f examples/browser/web/js/browser.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/browser/web/js/browser.js Thu Oct 08 11:19:11 2009 +0000
@@ -0,0 +1,130 @@
+var sparqler = new SPARQL.Service("http://harrison/sparql/");
+
+sparqler.setPrefix("mo", "http://purl.org/ontology/mo/");
+sparqler.setPrefix("foaf", "http://xmlns.com/foaf/0.1/");
+sparqler.setPrefix("dc", "http://purl.org/dc/elements/1.1/");
+
+sparqler.setRequestHeader("Accept", "application/json");
+
+var resultsTable;
+
+$(document).ready(function() {
+ $("#search").click(search)
+ $("#spinner").hide();
+ resultsTable = $('#results').dataTable({"bFilter":false,"bLengthChange":false,"bPaginate":true,
+ "fnRowCallback": function(nRow, aData, iDisplayIndex)
+ {
+ $(nRow).attr("typeof", "mo:Track");
+ return nRow;
+ },
+ "fnDrawCallback": function ()
+ {
+ $(".artist_name").click(function(event) { searchArtist($(this).attr("href")); return false; });
+ $(".album_name").click(function(event) { searchAlbum($(this).attr("href")); return false; });
+ }
+ });
+
+ $("#results tbody").click(function(event) {
+ $(resultsTable.fnSettings().aoData).each(function (){
+ $(this.nTr).removeClass('row_selected');
+ });
+ $(event.target.parentNode).addClass('row_selected');
+ });
+
+});
+
+function search(event) {
+
+ var trackSearchString = $("#tracksearch").val();
+ var artistSearchString = $("#artistsearch").val();
+
+ if(trackSearchString.length == 0 && artistSearchString.length == 0)
+ {
+ resultsTable.fnClearTable();
+ return;
+ }
+
+ var queryString = "SELECT ?maker ?album ?album_title ?tracknum ?artist_name ?track_title WHERE {";
+
+ queryString += " ?track a mo:Track; mo:track_number ?tracknum; foaf:maker ?maker. ?album mo:track ?track; dc:title ?album_title. ?maker foaf:name ?artist_name";
+
+ if(artistSearchString.length > 0)
+ {
+ queryString += ' FILTER regex(?artist_name, "'+artistSearchString+'", "i")';
+ }
+ else
+ {
+ queryString += ".";
+ }
+
+ queryString += " ?record mo:track ?track; mo:publication_of ?signal. ?signal dc:title ?track_title";
+
+ if(trackSearchString.length > 0)
+ {
+ queryString += ' FILTER regex(?track_title, "'+trackSearchString+'", "i")';
+ }
+ else
+ {
+ queryString += ".";
+ }
+
+ queryString += " }";
+
+ performSearch(queryString);
+}
+
+function searchArtist(id) {
+ var queryString = "SELECT ?maker ?album ?album_title ?tracknum ?artist_name ?track_title WHERE {";
+ queryString += " ?track a mo:Track; mo:track_number ?tracknum; foaf:maker ?maker. ?album mo:track ?track; dc:title ?album_title. ?maker foaf:name ?artist_name";
+ queryString += " ?record mo:track ?track; mo:publication_of ?signal. ?signal dc:title ?track_title.";
+ queryString += " FILTER(sameTerm(?maker, <"+id+">))";
+ queryString += " }";
+ performSearch(queryString);
+}
+
+function searchAlbum(id) {
+ var queryString = "SELECT ?maker ?album ?album_title ?tracknum ?artist_name ?track_title WHERE {";
+ queryString += " ?track a mo:Track; mo:track_number ?tracknum; foaf:maker ?maker. ?album mo:track ?track; dc:title ?album_title. ?maker foaf:name ?artist_name";
+ queryString += " ?record mo:track ?track; mo:publication_of ?signal. ?signal dc:title ?track_title.";
+ queryString += " FILTER(sameTerm(?album, <"+id+">))";
+ queryString += " }";
+ performSearch(queryString);
+}
+
+
+function performSearch(queryString) {
+ $("#spinner").show();
+ $("#query").text(queryString);
+ var query = sparqler.createQuery();
+ query.query(queryString, {failure: function(xhr) { alert("Bad response! "+xhr.responseText) }, success: displayResults});
+}
+
+function displayResults(json) {
+ resultsTable.fnClearTable();
+ if(json) {
+
+ var bindings = json.results.bindings;
+ for(var i=0; i');
+ var artistLink = $('');
+ artistEl.append(artistLink);
+ artistLink.attr("href", bindings[i].maker.value);
+ artistLink.attr("rel", "foaf:maker");
+ artistLink.addClass("artist_name");
+ artistLink.append(bindings[i].artist_name.value);
+
+ var albumEl = $('');
+ var albumLink = $('');
+ albumEl.append(albumLink);
+ albumLink.attr("href", bindings[i].album.value);
+ albumLink.attr("rel", "dc:title");
+ albumLink.addClass("album_name");
+ albumLink.append(bindings[i].album_title.value);
+
+ resultsTable.fnAddData([artistEl.html(), bindings[i].track_title.value, bindings[i].tracknum.value, albumEl.html()]);
+ }
+
+ }
+ $("#spinner").hide();
+}
diff -r 2eaea1afd6b3 -r 901803e1305f examples/browser/web/js/jOWL.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/browser/web/js/jOWL.js Thu Oct 08 11:19:11 2009 +0000
@@ -0,0 +1,2242 @@
+/**
+* jOWL - a jQuery plugin for traversing and visualizing OWL-DL documents.
+* Creator - David Decraene
+* Version 1.0
+* Website:
+* http://Ontologyonline.org
+* Licensed under the MIT license
+* http://www.opensource.org/licenses/mit-license.php
+* Verified with JSLint
+* http://www.jslint.com/
+*/
+
+jOWL = window.jOWL = function( resource, options ){ return jOWL.getResource( resource, options ); };
+jOWL.version = "1.0";
+
+/** for debugging compatibility */
+ try { console.log('...'); } catch(e) { console = window.console = { log: function() {} } }
+ if ($.browser.opera && opera.postError) { console = window.console = { log : function(){opera.postError(arguments); } }; }
+
+
+
+(function($){
+
+/**
+* if no param: @return string of main namespaces
+* if 1 param: assume a documentElement, parse namespaces
+* if prefix & URI: Bind prefix to namespace URI
+*/
+jOWL.NS = function(prefix, URI){
+ if(!arguments.length)
+ { return "xmlns:"+jOWL.NS.owl.prefix+"='"+jOWL.NS.owl()+"' xmlns:"+jOWL.NS.rdf.prefix+"='"+jOWL.NS.rdf()+"' xmlns:"+jOWL.NS.rdfs.prefix+"='"+jOWL.NS.rdfs()+"' xmlns:"+jOWL.NS.xsd.prefix+" ='"+jOWL.NS.xsd()+"'";}
+
+ if(arguments.length == 1){
+ var attr = prefix.get(0).attributes;
+ for(var i=0;i 0 ){ return xItems[0];} else { return null;}
+ };
+ Element.prototype.selectSingleNode = function(cXPathString){
+ if(this.ownerDocument.selectSingleNode) { return this.ownerDocument.selectSingleNode(cXPathString, this);}
+ else{throw "For XML Elements Only";}
+ };
+}
+
+/** @return A jQuery array of xml elements */
+jOWL.Xpath = function(selector, elem){
+ var node = null;
+ if(elem){ if(elem.each){ node = elem.get(0);} else { node = elem;} }
+ var arr = node ? node.selectNodes(selector) : jOWL.document.selectNodes(selector);
+ if($.browser.msie){ return $($.makeArray(arr));} return $(arr); //this is needed for IE, it returns a length of 1 on empty node array
+};
+
+/** @return a String array of class references */
+jOWL.Xpath.classes = function(jnode){
+ var cl = [];
+ jOWL.Xpath(__.rdfs("subClassOf"), jnode)
+ .each(function(){
+ var res = $(this).RDF_Resource();
+ if(res){ cl.push(res);}
+ });
+
+ jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Class"), jnode)
+ .each(function(){
+ var p = $(this).RDF_About(); if(p){ cl.push(p);}
+ });
+ return cl;
+};
+
+/** Functions stored in jOWL.priv are intended for local access only, to avoid a closure function */
+jOWL.priv = {
+ /** Arrray functions */
+ Array : {
+ isArray : function(array){
+ return Object.prototype.toString.call(array) === '[object Array]';
+ },
+ pushUnique : function(array, item){
+ if(jOWL.priv.Array.getIndex(array, item) === -1){ array.push(item); return true;}
+ return false;
+ },
+ getIndex : function(array, item){
+ for (var i=0; i 0){ targetMatch = true;}
+ }
+ }
+ else if(restriction.property.isDatatypeProperty){
+ targetMatch = restriction.property.assert(restriction.target, target);
+ }
+ else { targetMatch = (target == restriction.target);}
+ }
+ if(propertyMatch && targetMatch){ results.pushUnique(restriction);}
+
+ });
+ if(options.inherited){
+ var clRestrictions = this.owlClass().sourceof(property, target, options)
+ .each(function(){
+ //target can be a class, null, a duplicate individual...
+ var clRestr = this;
+ if(options.valuesOnly && clRestr.target === null){return;}
+ var clTarget = this.getTarget();
+ if(clTarget.isClass && options.ignoreClasses){ return;}
+
+ var containsProperty = false;
+ for(var i = 0;i 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"decimal", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"float", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"double", {base: __.xsd()+"integer" });
+jOWL.Ontology.Datatype(__.xsd()+"negativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x < 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"nonNegativeInteger", {base: __.xsd()+"integer", assert : function(x){ return x >= 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"nonPositiveInteger", {base: __.xsd()+"integer", assert : function(x){ return x <= 0;} });
+jOWL.Ontology.Datatype(__.xsd()+"string");
+
+var URIPattern = /^([a-z0-9+.\-]+):(?:\/\/(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?$/i;
+
+jOWL.Ontology.Datatype(__.xsd()+"anyURI", {base: __.xsd()+"string", pattern : URIPattern });
+jOWL.Ontology.Datatype(__.xsd()+"boolean", {sanitize : function(x){
+ if(typeof x == 'boolean'){ return x;}
+ if(x == 'true'){ return true;}
+ if(x == 'false'){ return false;}
+ }, assert : function(x){
+ return typeof x == 'boolean';
+ }, match: function(a, b){
+ if(a === "false"){ a = false;}
+ if(a === "true"){ a = true;}
+ return (a === b);
+}});
+
+/** 'superclass' for Properties */
+jOWL.Ontology.Property = function(jnode){
+ var r = this.parseProperty(jnode);
+ if(r){ return r;}
+};
+
+jOWL.Ontology.Property.prototype = $.extend({}, jOWL.Ontology.Thing.prototype,{
+ isProperty : true,
+ parseProperty : function(jnode){
+ if(!jnode || typeof jnode == 'string'){
+ this.domain = this.range = null;
+ this.parse(jnode);
+ return;
+ }
+ if(jOWL.options.cacheProperties && jOWL.indices.IDs){
+ var res = jnode.RDF_ID() || jnode.RDF_About();
+ var c = jOWL.index('property').get(res);
+ if(c){ return c;}
+ }
+ this.parse(jnode);
+ this.domain= $(this.jnode.get(0).selectSingleNode(__.rdfs('domain'))).RDF_Resource();
+ this.range = $(this.jnode.get(0).selectSingleNode(__.rdfs('range'))).RDF_Resource();
+ }
+});
+
+/** access to Datatype properties */
+jOWL.Ontology.DatatypeProperty = function(jnode){
+ var r = this.parseProperty(jnode);
+ if(r){ return r;}
+ if(this.type == __.owl("AnnotationProperty")){ this.range = __.xsd()+"string";}
+};
+
+jOWL.Ontology.DatatypeProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
+ isDatatypeProperty : true,
+ /** check datatype values against this */
+ assert : function(targetValue, value){
+ var self = this;
+ var dt = jOWL.Ontology.Datatype[this.range];
+ if(!dt){
+ console.log(this.range+" datatype reasoning not implemented");
+ return true;
+ }
+ if(value === undefined){ return dt.assert(targetValue);}
+ else {return dt.match(value, targetValue);}
+ }
+});
+
+/** access to Object properties */
+jOWL.Ontology.ObjectProperty = function(jnode){
+ var r = this.parseProperty(jnode);
+ if(r){ return r;}
+ var self = this;
+ jOWL.Xpath(__.rdf('type'), this.jnode).each(function(){
+ if($(this).RDF_Resource() == __.owl()+"TransitiveProperty"){ self.isTransitive = true;}
+ });
+ if(this.jnode.get(0).nodeName == __.owl("TransitiveProperty")){ self.isTransitive = true;}
+};
+
+jOWL.Ontology.ObjectProperty.prototype = $.extend({}, jOWL.Ontology.Thing.prototype, jOWL.Ontology.Property.prototype, {
+ isObjectProperty : true
+});
+
+/** access to an owl:Class */
+jOWL.Ontology.Class = function(jnode){
+ this.parse(jnode);
+};
+
+/** @return jOWL Array of Restrictions */
+jOWL.Xpath.restrictions = function(jnode){
+ var result = new jOWL.Ontology.Array();
+ jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
+ .add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode))
+ .each(function(){
+ result.push(new jOWL.Ontology.Restriction($(this)));
+ });
+ return result;
+};
+
+/** Internal Use */
+jOWL.Ontology.Intersection = function(jnode){
+ var self = this;
+ this.jnode = jnode;
+ this._arr = [];
+ this.URI = this.jnode.parent().RDF_ID();
+ this.matches = {};
+ jOWL.Xpath(__.owl("Restriction"), jnode).each(function(){
+ var restr = new jOWL.Ontology.Restriction($(this));
+ if(restr.isValueRestriction){self._arr.push(restr);}
+ });
+ jOWL.Xpath(__.owl('Class'), jnode).each(function(){
+ var uri = $(this).RDF_About();
+ if(uri){ self._arr.push(jOWL(uri));}
+ });
+};
+
+jOWL.Ontology.Intersection.prototype = {
+ isIntersection : true,
+ jOWL : jOWL.version,
+ match : function(id, cls, clRestr){
+ if(id == this.URI){ return false;}
+ if(this.matches[id] !== undefined){ return this.matches[id]; }//local cache
+
+ for(var i =0;i 1){ oParents.filter(function(){return this.name != ('Thing');});} //Remove Thing reference if other parents exist
+ jOWL.data(this.name, "parents", oParents);
+ return oParents;
+ },
+/** @return ancestors to the class in a jOWL.Ontology.Array */
+ ancestors : function(){
+ return this.hierarchy(false).flatindex;
+ },
+/**
+Constructs the entire (parent) hierarchy for a class
+@return a jOWL.Ontology.Array containing top nodes (classes directly subsumed by 'owl:Thing')
+@param addInverse add a variable invParents (jOWL.Ontology.Array of child references) to each node with exception of the leaves (original concept)
+*/
+ hierarchy : function(addInverse){
+ var endNodes = new jOWL.Ontology.Array();
+ var self = this;
+ endNodes.flatindex = new jOWL.Ontology.Array();
+
+ function URIARR(p_arr, obj){
+ var add = true;
+ if(!obj){ obj = {}; add = false;}
+ if(p_arr.each){
+ p_arr.each(function(){
+ if(obj[this.URI]){return;}
+ if(this.URI == __.owl()+'Thing'){ return;}
+ if(add){ obj[this.URI] = true;}
+ if(this.parents){ URIARR(this.parents(), obj);}
+ });
+ }
+ return obj;
+ }
+
+ function traverse(concept){
+ var parents = concept.parents();
+ if(parents.length == 1 && parents.contains(__.owl()+'Thing')){ endNodes.pushUnique(concept); return;}
+ else
+ {
+ var asso = jOWL.options.reason ? URIARR(parents) : {};
+ parents.filter(function(){ return (!asso[this.URI]);}); //throw out redundancies
+ parents.each(function(){
+ var item = endNodes.flatindex.pushUnique(this);
+ if(addInverse){
+ if(!item.invParents){ item.invParents = new jOWL.Ontology.Array();}
+ item.invParents.pushUnique(concept);
+ }
+ traverse(item);
+ });
+ concept.setParents(parents);
+ }
+ }
+
+ traverse(this);
+ return endNodes;
+
+ },
+ /**
+ @param level depth to fetch children, Default 5
+ @return jOWL array of classes that are descendant
+ */
+ descendants : function(level){
+ level = (typeof level == 'number') ? level : 5;
+ var oDescendants = jOWL.data(this.name, "descendants");
+ if(oDescendants && oDescendants.level >= level){ return oDescendants;}
+ oDescendants = new jOWL.Ontology.Array();
+ oDescendants.level = level;
+
+ function descend(concept, i){
+ if(i <= level){
+ i++;
+ var ch = concept.children();
+ oDescendants.concat(ch);
+ ch.each(function(item){ descend(item, i);});
+ }
+ }
+
+ descend(this, 1);
+ jOWL.data(this.name, "descendants", oDescendants);
+ return oDescendants;
+ },
+ /** @return jOWL.Array of Restrictions, target is an individual, not a class or undefined (unless includeAll is specified) - deprecated */
+ valueRestrictions : function(includeAll, array){
+ return this.sourceof(null, null, {ignoreClasses : !includeAll});
+ },
+ /**
+ get all restrictions that satisfy the arguments
+ @param property property or array of properties, or null
+ @param target class, individuals of array of them, or null
+ @return jOWL.Array of Restrictions
+ */
+ sourceof : function(property, target, options){
+ options = $.extend({
+ inherited : true, // add restrictions specified on parents as well
+ transitive : true, //expand on transitive relations too
+ ignoreGenerics : true, //if a parent has an identical property, with another target 'Thing', skip that restriction
+ ignoreClasses : false, //only individuals should return
+ valuesOnly : true //do not return valueless criteria
+ }, options);
+ var self = this;
+ var crit = jOWL.data(this.name, "sourceof");
+ var jnode = this.jnode;
+
+ if(!crit){
+ crit = new jOWL.Ontology.Array();
+ var arr = jOWL.Xpath(__.rdfs("subClassOf")+"/"+__.owl("Restriction"), jnode)
+ .add(jOWL.Xpath(__.owl("intersectionOf")+"/"+__.owl("Restriction"), jnode));
+ arr.each(function(index, entry){
+ var cr = new jOWL.Ontology.Restriction($(entry));
+ var dupe = false;
+ crit.each(function(item, i){
+ if(this.property.name == cr.property.name){ dupe = item;}
+ });
+ if(dupe){ if(!dupe.merge(cr)){ crit.push(cr);} }
+ else { crit.push(cr);}
+ });
+ jOWL.data(self.name, "sourceof", crit);
+ }
+ var results = new jOWL.Ontology.Array();
+
+ crit.each(function(){
+
+ var propertyMatch = property ? false : true;
+ var targetMatch = target ? false : true;
+
+ if(!propertyMatch){
+ if(property.isArray){ propertyMatch = property.contains(this.property);}
+ else { propertyMatch = (property.URI == this.property.URI);}
+ }
+
+ if(!target){
+ if(options.transitive && this.property.isTransitive){
+ var rTarget = this.getTarget();
+ var transitives = rTarget.sourceof(this.property, null, options);
+ results.concat(transitives);
+ }
+ }
+
+ if(!targetMatch && !this.target){
+ targetMatch = !options.valuesOnly;
+ }
+
+ if(!targetMatch){
+ var targ = this.getTarget();
+ if(targ.isClass && options.ignoreClasses){ return;}
+ targetMatch = jOWL.priv.testObjectTarget(target, this.target);
+ if(!targetMatch && options.transitive && propertyMatch && this.property.isTransitive){
+ if(targ.isThing){
+ if(targ.sourceof(property, target).length){ targetMatch = true;}
+ }
+ }
+ }
+
+ if(propertyMatch && targetMatch){ results.pushUnique(this);}
+ });
+
+ if(!options.inherited){ return results;}
+
+ this.parents().each(function(){
+ if(this.sourceof){
+ this.sourceof(property, target, options).each(function(parentsource){
+ var ptarget = this.getTarget();
+ var containsProperty = false;
+ var tempArray = new jOWL.Ontology.Array();
+ results.filter(function(){
+ var restr = this, keep = true;
+ if(restr.property.URI == parentsource.property.URI){
+ containsProperty = true;
+ if(!options.ignoreGenerics){
+ if(parentsource.target != restr.target){ tempArray.push(parentsource);}
+ } else {
+ if(ptarget.isThing){
+ keep = restr.getTarget().isThing && parentsource.target != restr.target;
+ tempArray.push(parentsource);
+ }
+ }
+ }
+ return keep;
+ });
+ if(!containsProperty){ results.push(parentsource);}
+ results.concat(tempArray);
+ });
+ }
+ });
+ return results;
+ }
+});
+
+/** Utility object */
+jOWL.Ontology.Array = function(arr, isXML){
+ var self = this;
+ this.items = [];
+ if(arr){
+ if(isXML){ $.each(arr, function(){
+ var entry = this.jOWL ? this : jOWL($(this));
+ self.items.push(entry);});
+ }
+ else { this.items = arr;}
+ }
+ this.length = this.items.length;
+};
+
+jOWL.Ontology.Array.prototype = {
+ jOWL : jOWL.version,
+ isArray : true,
+ bind : function(listitem, fn){
+ return this.map(function(){
+ var syntax = listitem ? listitem.clone(true) : $('');
+ var html = this.bind(syntax).append(document.createTextNode(' '));
+ if(fn){ fn.call(html, html, this);}
+ return html.get(0);
+ });
+ },
+ concat : function(arr, ignoreUnique){
+ var self = this;
+ if(arr.each){ arr.each(function(){
+ if(ignoreUnique){ self.push(this); }
+ else { self.pushUnique(this); }
+ });
+ }
+ else { self.items = self.items.concat(arr.items); this.length = self.items.length;}
+ return this;
+ },
+ contains : function(o){
+ return this.get(o) ? true: false;
+ },
+ each : function(fn, reverse){
+ var i, self = this;
+ var stop = false;
+ if(reverse){
+ for(i=this.items.length - 1; i>=0;i--){
+ if(stop){ break;}
+ (function(){
+ var item = self.eq(i);
+ if(fn.call(item, item, i) === false){ stop = true;}
+ })();
+ }
+ }
+ else {
+ for(i=0;i this.items.length -1){ return null;}
+ return this.items[index];
+ },
+ filter : function(fn){
+ var self = this;
+ this.each(function(item, i){
+ var q = fn.call(item, item, i);
+ if(!q){ self.items.splice(i, 1);}
+ }, true);
+ this.length = this.items.length;
+ return this;
+ },
+ getIndex : function(o){
+ var found = -1;
+ if(o.equals){
+ this.each(function(a, i){
+ if(this.equals && this.equals(o)){ found = i; return false;}
+ });
+ }
+ else {
+ if(typeof o == 'number'){ return o;}
+ var name = typeof o == "string" ? o : o.name;
+ var URI = o.URI || name;
+
+ this.each(function(a, i){
+ if(this.URI){ if(this.URI == URI){ found = i;}}
+ else if(this.name == name){ found = i;}
+ });
+ }
+ return found;
+ },
+ get : function(o){
+ return this.eq(this.getIndex(o));
+ },
+ map : function(fn){
+ var arr = [];
+ this.each(function(){ arr.push(fn.call(this, this));});
+ return arr;
+ },
+ push : function(o){
+ this.items.push(o);
+ this.length = this.items.length;
+ return this;
+ },
+ pushUnique : function(o){
+ return this.get(o) || this.push(o).get(o);
+ },
+ toString : function(){
+ return this.map(function(){return this.URI;}).join(', ');
+ },
+ /** Convert this array into an associative array with key = URI */
+ associative : function(){
+ var arr = {};
+ this.each(function(){
+ if(this.URI){ arr[this.URI] = this;}
+ });
+ return arr;
+ }
+};
+
+
+jOWL.options = {reason: true, locale:false, defaultlocale: 'en',
+ dictionary : { create: true, addID : true },
+ onParseError : function(msg){alert("jOWL parseError: "+msg);}, cacheProperties : true, niceClassLabels : true};
+jOWL.document = null;
+jOWL.namespace = null;
+jOWL.indices = { //internal indices
+ P : null, //jOWL array
+ data : {},
+ IDs : null,
+ I : null, //Intersection
+ T : null, //Thing
+ D : null, //dictionary
+ reset : function(){var i = jOWL.indices; i.data = {}; i.P = null; i.T = null; i.IDs = null; i.I = null;i.D = null;}
+};
+
+jOWL.index = function(type, wipe){
+ var i = jOWL.indices;
+ switch (type)
+ {
+ /**jOWL indexes all elements with rdf:ID, and first order ontology elements specified with rdf:about
+ @return Associative array with key = URI and value = jOWL object.
+ */
+ case "ID":
+ if(i.IDs === null || wipe){
+ if(wipe){ i.reset();}
+ i.IDs = {};
+ i.T = {};
+ var start = new Date();
+
+ var rID = jOWL.Xpath("//*[@"+__.rdf("ID")+"]").each(function(){
+ var jowl = jOWL.getResource($(this));
+ if(jowl){
+ i.IDs[jowl.URI] = jowl;
+ if(jowl.isThing){
+ if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
+ i.T[jowl.Class].push(jowl);
+ }
+ }
+ });
+
+ var rAbout = jOWL.Xpath("/"+__.rdf("RDF")+"/*[@"+__.rdf("about")+"]").each(function(){
+ var jnode = $(this);
+ var jowl = jOWL.getResource($(this));
+ if(!jowl){ return;}
+ if(jowl.isClass || jowl.isProperty || jowl.isThing){
+ if(i.IDs[jowl.URI]){ jnode.children().appendTo(i.IDs[jowl.URI].jnode); return;}
+ i.IDs[jowl.URI] = jowl;
+ if(jowl.isThing){
+ if(!i.T[jowl.Class]){ i.T[jowl.Class] = new jOWL.Ontology.Array();}
+ i.T[jowl.Class].push(jowl);
+ }
+ return;
+ }
+ });
+ console.log("Loaded in "+(new Date().getTime() - start.getTime())+"ms");
+ }
+ return i.IDs;
+ /** Generated together with ID index.
+ * @return Associative Array, key = class, value = jOWL Array of individuals.
+ */
+ case "Thing":
+ return i.T;
+ case "intersection":
+ if(i.I === null || wipe){
+ var temp = new jOWL.Ontology.Array();
+ i.I = {};
+ jOWL.Xpath("//"+__.owl("intersectionOf")).each(function(){
+ var isect = new jOWL.Ontology.Intersection($(this));
+ if(!isect.URI){return;}
+ var dupe = temp.get(isect);
+ if(dupe){
+ console.log("duplicate intersection found between : (Ignoring) "+isect.URI+" and "+dupe.URI);
+ } else {
+ if(!i.I[isect.URI]){i.I[isect.URI] = new jOWL.Ontology.Array();}
+ temp.push(isect);
+ i.I[isect.URI].push(isect);
+ }
+ });
+ }
+ return i.I;
+ case "property":
+ if(i.P === null || wipe)
+ {
+ jOWL.options.cacheProperties = false;
+ i.P = new jOWL.Ontology.Array();
+ for(x in i.IDs){
+ var jowl = i.IDs[x];
+ if(jowl.isProperty){ i.P.push(jowl);}
+ }
+ jOWL.options.cacheProperties = true;
+ }
+ return i.P;
+ case "dictionary":
+ /**Dictionary: Array of Arrays, where secondary array is of form: [0] = term, [1] = rdfID, [2] = locale */
+ if(i.D === null || wipe)
+ {
+ i.D = [];
+ for(x in i.IDs){
+ var entry = i.IDs[x];
+ i.D = i.D.concat(entry.terms());
+ }
+ }
+ return i.D;
+ }
+};
+
+/** Internal Function, storing data in associative array (JSON),
+jquery data function cannot be used as expando data does not work in IE for ActiveX XMLhttprequest*/
+jOWL.data = function(rdfID, dtype, data){
+ var d = jOWL.indices.data;
+ if(!d[rdfID]){ d[rdfID] = {};}
+ if(!data){ return d[rdfID][dtype];}
+ d[rdfID][dtype] = data;
+};
+
+/**
+* Initialize jOWL with an OWL-RDFS document.
+* @param path relative path to xml document
+* @param callback callback function to be called when loaded.
+* @options : optional settings:
+* onParseError : function(msg){} function to ba called when parsing fails
+* reason : true/false, turns on additional reasoning at the expense of performance
+* locale: set preferred language (if available), examples en, fr...
+*/
+jOWL.load = function(path, callback, options){
+ var that = this;
+ if($.browser.msie && location.toString().indexOf('file') === 0){ //IE won't load local xml files otherwise
+ var xml = document.createElement("xml");
+ xml.validateOnParse = false; //IE throws DTD errors (for 'rdf:') on perfectly defined OWL files otherwise
+ xml.src = path;
+ xml.onreadystatechange = function(){
+ if(xml.readyState == "interactive"){ var xmldoc = xml.XMLDocument; document.body.removeChild(xml);callback(that.parse(xmldoc, options));}
+ };
+ document.body.appendChild(xml);
+ }
+ else {
+ $.get(path, function(xml){callback(that.parse(xml, options));});
+ }
+};
+
+/**
+* initialize jOWL with some OWL-RDFS syntax
+* @param doc Either an xmlString or an xmlDocument
+* @param options optional, onParseError(msg) : function to execute when parse fails
+* @returns false on failure, or the jOWL object
+*/
+jOWL.parse = function(doc, options){
+ jOWL.document = null;
+ this.options = $.extend(jOWL.options, options);
+ if(typeof doc == 'string'){ doc = jOWL.fromString(doc);}
+ jOWL.document = doc;
+ if($.browser.msie){
+ if(doc.parseError.errorCode !== 0){ jOWL.options.onParseError(doc.parseError.reason); return false;}
+ }
+ else if(doc.documentElement.nodeName == 'parsererror'){jOWL.options.onParseError(doc.documentElement.firstChild.nodeValue); return false;}
+ var root = $(doc.documentElement);
+ jOWL.NS(root);
+ if($.browser.msie){
+ jOWL.document.setProperty("SelectionLanguage", "XPath");
+ jOWL.document.setProperty("SelectionNamespaces", __());
+ }
+ this.index('ID', true);
+ if(jOWL.options.cacheProperties){ this.index('property', true);}
+ if(jOWL.options.dictionary.create){ jOWL.index("dictionary");}
+ jOWL.Thing = new jOWL.Ontology.Thing($(jOWL.create(__.owl, "Class").attr(__.rdf, 'about', __.owl()+'Thing').node));
+ jOWL.Thing.type = false;
+ return this;
+};
+
+/**
+* A String representation of the OWL-RDFS document
+* @param xmlNode optional, node to generate a string from, when unspecified the entire document
+*/
+jOWL.toString = function(xmlNode){
+ if(!xmlNode){ return jOWL.toString(jOWL.document);}
+ if($.browser.msie){ return xmlNode.xml;}
+ return new XMLSerializer().serializeToString(xmlNode);// Gecko-based browsers, Safari, Opera.
+};
+
+/** create a document from string */
+jOWL.fromString = function(doc){
+ var owldoc;
+ if(document.implementation.createDocument){ owldoc = new DOMParser().parseFromString(doc, "text/xml");} // Mozilla and Netscape browsers
+ else if(window.ActiveXObject){ // MSIE
+ var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmldoc.async="false";
+ xmldoc.validateOnParse = false;
+ xmldoc.loadXML(doc);
+ owldoc = xmldoc;
+ }
+ return owldoc;
+};
+
+/** @return false if belongs to this namespace, or an array with length two, arr[0] == url, arr[1] == id */
+jOWL.isExternal = function(resource){
+ var r = jOWL.resolveURI(resource, true);
+ return r[0] != jOWL.namespace ? r : false;
+};
+
+/**
+if a URI belongs to the loaded namespace, then strips the prefix url of, else preserves URI
+also able to parse and reference html (or jquery) elements for their URI.
+*/
+jOWL.resolveURI = function(URI, array){
+ if(typeof URI != "string"){
+ var node = URI.jquery ? URI.get(0) : URI;
+ URI = node.localName || node.baseName;
+ if(node.namespaceURI){ URI = node.namespaceURI + URI;}
+ return jOWL.resolveURI(URI, array);
+ }
+ var rs = URI, ns = jOWL.namespace;
+ if(URI.indexOf('http') === 0){
+ var tr = URI.indexOf('#');
+ if(tr <= 0){ tr = URI.lastIndexOf('/');}
+ if(tr > 0)
+ {
+ ns = URI.substring(0, tr+1);
+ rs = URI.substring(tr+1);
+ }
+ } else if(URI.charAt(0) == '#'){ return URI.substring(1);}
+ if(array){ return [ns, rs];}
+ if(ns == jOWL.namespace){ return rs;}
+ return URI;
+};
+
+/**
+Main method to get an Ontology Object, access via jOWL(>String>, options);
+resource: rdfID/rdfResource or jQuery node.
+*/
+jOWL.getResource = function(resource, options){
+ if(!jOWL.document){ throw "You must successfully load an ontology before you can find anything";}
+ if(!resource){ throw "No resource specified";}
+ var node;
+ var opts = $.extend({}, options);
+ if(typeof resource == 'string'){
+ resource = jOWL.resolveURI(resource);
+ if(resource == 'Thing' || resource == __.owl()+'Thing'){ return jOWL.Thing;}
+ if(opts.type == 'property' && jOWL.options.cacheProperties){
+ var c = jOWL.index('property').get(resource);
+ if(c){ return c;}
+ if(jOWL.isExternal(resource)){ console.log("undeclared resource: "+resource); return new jOWL.Ontology.Property(resource);}
+ }
+ var match = jOWL.index("ID")[resource];
+ if(!match){ //try case insensitive
+ for(caseIns in jOWL.index("ID")){
+ if(caseIns.toLowerCase() == resource.replace(/ /g, "").toLowerCase()){ match = jOWL.index("ID")[caseIns]; break;}
+ }
+ }
+ if(!match){
+ if(jOWL.isExternal(resource)){
+ console.log("undeclared resource: "+resource);
+ return new jOWL.Ontology.Thing(resource);
+ }
+ console.log(resource+" not found");
+ return null;
+ }
+ return match;
+ }
+ node = resource.jquery ? resource : $(resource);
+ var jj = jOWL.type(node); if(!jj){ return null;}
+ return new (jj)(node);
+};
+
+/**
+* @param node jquery or html element.
+* @return the ontology type of the object.
+*/
+jOWL.type = function(node){
+ var xmlNode = node.jquery ? node.get(0) : node;
+ switch(xmlNode.nodeName){
+ case __.owl("Class") : return jOWL.Ontology.Class;
+ case __.rdfs("Class") : return jOWL.Ontology.Class; //test
+ case __.owl("Ontology") : return jOWL.Ontology;
+ case __.owl("ObjectProperty") : return jOWL.Ontology.ObjectProperty;
+ case __.owl("DatatypeProperty") : return jOWL.Ontology.DatatypeProperty;
+ case __.owl("FunctionalProperty") : return jOWL.Ontology.Property;
+ case __.rdf("Property") : return jOWL.Ontology.Property;
+ case __.owl("InverseFunctionalProperty") : return jOWL.Ontology.ObjectProperty;
+ case __.owl("TransitiveProperty") : return jOWL.Ontology.ObjectProperty;
+ case __.owl("SymmetricProperty") : return jOWL.Ontology.ObjectProperty;
+ //jOWL currently treats annotationproperties as string datatypeproperties.
+ case __.owl("AnnotationProperty") : return jOWL.Ontology.DatatypeProperty;
+ default :
+ switch(xmlNode.namespaceURI){
+ case __.owl(): if(xmlNode.nodeName == __.owl("Thing") ){ return jOWL.Ontology.Individual;} return false;
+ case __.rdf(): return false;
+ case __.rdfs(): return false;
+ default : return jOWL.Ontology.Individual;
+ }
+ }
+};
+
+/**
+@param rdfID or Array
+@return Array of DOM (xml) Nodes
+*/
+jOWL.getXML = function(rdfID){
+ var node = [];
+ function fetchFromIndex(rdfID){
+ var el = jOWL.index("ID")[rdfID];
+ return el ? el : null;
+ }
+
+ if(typeof rdfID == 'string'){ var q = fetchFromIndex(rdfID); if(q){ node.push(q);} }
+ else if(jOWL.priv.Array.isArray(rdfID)){ //assume an array of string rdfIDs
+ $.each(rdfID, function(){
+ var el = fetchFromIndex(this); if(el){ node.push(el);}
+ });
+ }
+ return node;
+};
+
+/** Create new ontology elements */
+jOWL.create = function(namespace, name, document){
+ var doc = document ? document : jOWL.document;
+
+ var el = {
+ attr : function(namespace, name, value){
+ if($.browser.msie){
+ var attribute = doc.createNode(2, namespace(name), namespace());
+ attribute.nodeValue = value;
+ this.node.setAttributeNode(attribute);
+ }
+ else { this.node.setAttributeNS(namespace(), namespace(name), value);}
+ return this;
+ },
+ appendTo : function(node){
+ var n = node.node ? node.node : node;
+ n.appendChild(this.node);
+ return this;
+ },
+ text : function(text, cdata){
+ var txt = cdata ? doc.createCDATASection(text) : doc.createTextNode(text);
+ this.node.appendChild(txt);
+ return this;
+ }
+ };
+
+ if($.browser.msie){ el.node = doc.createNode(1, namespace(name), namespace());}
+ else { el.node = doc.createElementNS(namespace(), namespace(name));}
+ return el;
+};
+
+/** Create a blank ontology document */
+jOWL.create.document = function(href){
+ var owl = [];
+ var base = href || window.location.href+"#";
+ owl.push('');
+ owl.push('<'+__.rdf('RDF')+' xml:base="'+base+'" xmlns="'+base+'" '+__()+'>');
+ owl.push(' <'+__.owl('Ontology')+' '+__.rdf('about')+'=""/>');
+ owl.push(''+__.rdf('RDF')+'>');
+ return jOWL.fromString(owl.join('\n'));
+};
+
+/** Extracts RDFa syntax from current page and feeds it to jOWL, simple implementation, only classes for the time being */
+jOWL.parseRDFa = function(fn, options){
+ var entries = options.node ? $("[typeof]", options.node) : $("[typeof]");
+ var doc = jOWL.create.document();
+
+ function property(p, node){
+ var arr = [];
+ $("[property="+p+"]", node).each(function(){ arr.push($(this).attr('content') || $(this).html());});
+ if(node.attr('property') === p){ arr.push(node.attr('content') || node.html());}
+ return arr;
+ }
+
+ function rel(p, node){
+ var arr = [];
+ $("[rel="+p+"]", node).each(function(){ arr.push($(this).attr('resource'));});
+ if(node.attr("rel") === p){ arr.push(node.attr('resource'));}
+ return arr;
+ }
+
+ function makeClass(node, ID){
+ var cl = jOWL.create(__.owl, "Class", doc).attr(__.rdf, 'about', ID).appendTo(doc.documentElement);
+
+ var parents = property(__.rdfs("subClassOf"), node).concat(rel(__.rdfs("subClassOf"), node));
+ for(var i = 0;i
+Used for term searches, intend to (partially) replace it by a sparql-dl query later on
+options:
+ filter: filter on a specific type, possible values: Class, Thing, ObjectProperty, DatatypeProperty
+ exclude: exclude specific types, not fully implemented
+*/
+jOWL.query = function(match, options){
+ options = $.extend({exclude : false}, options);
+ if(options.filter == 'Class'){ options.filter = __.owl("Class");}
+ var that = this;
+ //filter : [], exclude : false
+ var items = new jOWL.Ontology.Array();
+ var jsonobj = {};
+ var test = jOWL.index("dictionary");
+
+ function store(item){
+ var include = false, i = 0;
+ if(options.filter){
+ if(typeof options.filter == 'string'){ include = (options.filter == item[3]);}
+ else { for(i = 0;i -1){
+ if(options.locale){ if(options.locale == item[2]){ store(item);} }
+ else { store(item);}
+ }
+ }
+ return jsonobj;
+};
+
+/**
+allows asynchronous looping over arrays (prevent bowser freezing).
+arr the array to loop asynchonrously over.
+options.modify(item) things to do with each item of the array
+options.onUpdate array the size of chewsize or smaller, containing processed entries
+options.onComplete(array of results) function triggered when looping has completed
+*/
+jOWL.throttle =function(array, options){
+ options = $.extend({
+ modify : function(result){},
+ //onUpdate : function(arr){},
+ onComplete : function(arr){},
+ async : true,
+ chewsize : 5,
+ startIndex : 0,
+ timing : 5
+ }, options);
+ var temp = array.jOWL ? array.items : (array.jquery) ? $.makeArray(array) : array;
+ var items = options.startIndex ? temp.slice(startIndex) : temp.concat(); //clone the array
+ var results = [];
+
+ (function(){
+ var count = options.chewsize;
+ var a = [];
+ while (count > 0 && items.length > 0)
+ {
+ var item = items.shift(); count--;
+ var result = options.modify.call(item, item);
+ if(result){ results.push(result); a.push(result);}
+ }
+ if(options.onUpdate){ options.onUpdate(a);}
+
+ if(items.length> 0){
+ if(options.async){ setTimeout(arguments.callee, options.timing);}
+ else {arguments.callee();}
+ }
+ else{ options.onComplete(results);}
+ })();
+};
+
+/** Creates a new resultobj for the SPARQL-DL functionality */
+jOWL.SPARQL_DL_Result = function(){
+ this.assert = undefined;
+ this.head = {}; //associative array of query parameters, with value jOWL Array of results
+ this.results = []; //sparql-dl bindings
+ this.isBound = false;
+};
+
+jOWL.SPARQL_DL_Result.prototype = {
+ sort : function(param){
+ if(!param){ throw "parameter must be defined for sort function";}
+ function sortResults(a, b){
+ var o = a[param].name || a[param];
+ var p = b[param].name || b[param];
+ return (o < p) ? -1 : 1;
+ }
+ if(this.results){ this.results.sort(sortResults); }
+ },
+ jOWLArray : function(param){
+ if(!param){ throw "parameter must be defined for jOWLArray function";}
+ var arr = new jOWL.Ontology.Array();
+ for(var i=0;i=0;i--){
+ var valueX = this.results[i][x];
+ if(valueX){
+ if(!results.mappings[x].contains(valueX)){
+ this.results.splice(i, 1);
+ continue;
+ }
+ if(multimapping){
+ var keyArr= otherKeys[valueX.URI];
+ //ignoring the opposite for now (assuming original key x is unique (limits statements))
+ //TODO: improve these result merging methods/flexibility
+ for(var oK = 0; oK < keyArr.length;oK++){
+ var obj = (oK === 0) ? this.results[i] : {};
+ var valueY = keyArr[oK];
+ obj[x] = valueX;
+ for(yK in valueY){ obj[yK] = valueY[yK]; }
+ toAdd.push(obj);
+ }
+ this.results.splice(i, 1);
+ }
+ }
+ }
+ }
+ this.results = this.results.concat(toAdd);
+ }
+};
+/** Creates a new query for the SPARQL-DL functionality */
+jOWL.SPARQL_DL_Query = function(syntax, parameters){
+ this.parse(syntax);
+ this.fill(parameters);
+ this.entries = this.entries.sort(this.sort);
+};
+
+jOWL.SPARQL_DL_Query.prototype = {
+ parse : function(syntax){
+ var r2 = /(\w+)[(]([^)]+)[)]/;
+ var entries = syntax.match(/(\w+[(][^)]+[)])/g);
+ if(!entries){ this.error = "invalid abstract sparql-dl syntax"; return;}
+ entries = jOWL.priv.Array.unique(entries);
+ for(var i = 0;i=0;i--){
+ if(this.arr[i][keyX]){
+ if(!arr[this.arr[i][keyX].URI]){ arr[this.arr[i][keyX].URI] = []; }
+ arr[this.arr[i][keyX].URI].push(this.arr[i]);
+ }
+ }
+ return arr;
+ },
+ get : function(key)
+ {
+ return (this.mappings[key]) ? this.mappings[key] : new jOWL.Ontology.Array();
+ },
+ getArray : function(){
+ //check mappings for presence, discard arr entries based on that, return remainder.
+ for(var i = this.arr.length - 1;i>=0;i--){
+ var binding = this.arr[i], splice = false;
+ for(key in binding){
+ if(!splice){
+ splice = (!this.mappings[key] || !this.mappings[key].contains(binding[key]));
+ }
+ }
+ if(splice){
+ this.arr.splice(i, 1);
+ }
+ }
+ return this;
+ }
+};
+
+/**
+Support for abstract SPARQl-DL syntax
+options.onComplete: function triggered when all individuals have been looped over
+options.childDepth: depth to fetch children, default 5, impacts performance
+options.chewsize: arrays will be processed in smaller chunks (asynchronous), with size indicated by chewsize, default 10
+options.async: default true, query asynchronously
+parameters: prefill some sparql-dl parameters with jOWL objects
+execute: start query, results are passed through options.onComplete
+*/
+jOWL.SPARQL_DL = function(syntax, parameters, options){
+ if(!(this instanceof arguments.callee)){ return new jOWL.SPARQL_DL(syntax, parameters, options);}
+ var self = this;
+ this.parameters = $.extend({}, parameters);
+ this.query = new jOWL.SPARQL_DL_Query(syntax, this.parameters).entries;
+ this.result = new jOWL.SPARQL_DL_Result();
+ this.options = $.extend({onComplete: function(results){}}, options);
+};
+
+jOWL.SPARQL_DL.prototype = {
+ error: function(msg){ this.result.error = msg; return this.options.onComplete(this.result);},
+ /**
+ if(options.async == false) then this method returns the result of options.onComplete,
+ no matter what, result is always passed in options.onComplete
+ */
+ execute : function(options){
+ var self = this;
+ this.options = $.extend(this.options, options);
+ if(this.query.error){ return this.error(this.query.error);}
+
+ var resultobj = this.result;
+ var i = 0;
+ var loopoptions = $.extend({}, this.options);
+ loopoptions.onComplete = function(results){ i++; resultobj = results; loop(i);};
+
+ if(!this.query.length){
+ resultobj.error = "no query found or query did not parse properly";
+ return self.options.onComplete(resultobj);
+ }
+
+ function loop(i){
+ if(i < self.query.length){
+ self.process(self.query[i], resultobj, loopoptions );
+ }
+ else {
+ for(var j =0;j 0){ match = true;}
+ return;
+ }
+ if(!restrictions.length){ return;}
+ restrictions.each(function(){
+ var binding = new _Binding(results);
+ if(options.filterSource){
+ binding.bind(options.filterSource, source);
+ if(!options.filterProperty && !options.filterTarget){ results.add(binding); return false;}
+ }
+ if(options.filterProperty){
+ binding.bind(options.filterProperty, this.property);
+ }
+ if(options.filterTarget){
+ binding.bind(options.filterTarget, this.getTarget());
+ }
+ results.add(binding);
+ });
+ return true;
+ });
+ if(options.assert){
+ resultobj.assert = match;
+ return resultobj.assert;
+ }
+ if(options.filterSource){ resultobj.filter(options.filterSource, results.get(options.filterSource));}
+ if(options.filterProperty){ resultobj.filter(options.filterProperty, results.get(options.filterProperty));}
+ if(options.filterTarget) { resultobj.filter(options.filterTarget, results.get(options.filterTarget));}
+ resultobj.bind(results.getArray());
+ },
+ hasClassID: function(match, classID){
+ if(Object.prototype.toString.call(classID) === '[object Array]'){
+ for(var i =0;i -1){ return 1;} //contained within
+ var c = 0; var arr = matchstring.match(new RegExp("\\w+", "ig"));
+ for(var i = 0;i -1){ c++;} }
+ if(c == arr.length){ return 0;} //word shift
+ return -1; //nomatch
+};
+/**
+* @return Modified String.
+*/
+String.prototype.beautify = function(){
+ var e1 = new RegExp("([a-z0-9])([A-Z])", "g");
+ var e2 = new RegExp("([A-Z])([A-Z0-9])([a-z])", "g");
+ var e3 = new RegExp("_", "g");
+ return this.replace(e1, "$1 $2").replace(e2, "$1 $2$3").replace(e3, " ");
+};
diff -r 2eaea1afd6b3 -r 901803e1305f examples/browser/web/js/jOWL_UI.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/browser/web/js/jOWL_UI.js Thu Oct 08 11:19:11 2009 +0000
@@ -0,0 +1,698 @@
+/*
+ * jOWL_UI, User Interface Elements for jOWL, semantic javascript library
+ * Creator - David Decraene
+ * Version 1.0
+ * Website: http://Ontologyonline.org
+ * Licensed under the MIT license
+ * Verified with JSLint http://www.jslint.com/
+ */
+(function($){
+
+jOWL.UI = {
+ broadcaster : function(){
+ var listeners = [];
+ this.addListener = function(obj){
+ function add(obj){if(obj.propertyChange) { listeners.push(obj); } }
+ if(obj.constructor == Array){for(var i=0;i").addClass(options.contentClass).appendTo(this); }
+ this.parents = $('').appendTo(this.content);
+ this.focus = $('').addClass(options.focusClass).appendTo(this.content);
+ this.children = $('').appendTo(this.content);
+ var listnode = $('').click(function(){
+ var node = $(this);
+ var res = jOWL(node.attr('title'));
+ if(options.onSelect.call(node, res) === false) { return; }
+ if(res && res.isClass) { self.propertyChange.call(res, res); self.broadcast(res); }
+ });
+
+ jOWL.UI.asBroadcaster(this);
+
+ this.propertyChange = function(item){
+ if(options.onPropertyChange.call(this, item) === false) { return; }
+ if(item.isClass){
+ item.bind(self.focus);
+ if(jOWL.options.reason) { item.hierarchy();}
+ self.parents.empty().append(item.parents().bind(listnode));
+ self.children.empty().append(item.children().bind(listnode));
+ }
+ };
+ return this;
+ },
+/**
+autocomplete field.
+*/
+ owl_autocomplete : function(options){
+ options = $.extend({
+ time:500, //responsetime to check for new keystrokes, default 500
+ chars:3, //number of characters needed before autocomplete starts searching
+ focus:false, //put cursor on the input field when loading
+ limit:10, //limit size of result list to given amount
+ contentClass : "ui-widget-content",
+ focusClass : jOWL.UI.defaults.focusClass,
+ hintClass : "ui-autocomplete-hint",
+ hint: false, //Message (if any) to show when unfocused.
+ onSelect : function(item){}, //function that can be overridden
+ formatListItem : function(listitem, type, identifier, termarray){ //formatting of results, can be overridden
+ if(type){ listitem.append($('').text(type)); }
+ listitem.append($('').text(identifier));
+ if(termarray.length) { listitem.append($('').text(termarray.join(', '))
+ .prepend($('').addClass('termlabel').text("Terms: ")));
+ }
+ }}, options);
+ jOWL.UI.asBroadcaster(this);
+
+ this.showHint = function(){
+ this.hinted = true;
+ if(options.hint){
+ this.addClass(options.hintClass).val(options.hint);
+ }
+ else {this.val(''); }
+ };
+ this.showHint();
+
+ var self = this; var old = ''; var open = false; self.val('');
+ var results = $('
').addClass(options.contentClass).addClass("jowl_autocomplete_results");
+ var div = $("").addClass(options.wrapperClass).append(results); this.after(div);
+ results.cache = {};
+ results.isEmpty = function(){ for(x in results.cache) { return false; } return true; };
+ results.close = function(){this.hide();};
+ results.open = function(q, cache){
+ this.show();
+ if(q){
+ if(!cache || results.isEmpty()) { results.cache = jOWL.query(q, options); }
+ else {
+ var newcache = {};
+ for(x in results.cache){
+ var entry = results.cache[x];
+ var found = false;
+ var newentries = [];
+ if(x.searchMatch(q) > -1) { found = true; }
+ for(var i = 0;i -1) { found = true; newentries.push(entry[i]); }
+ }
+ if(found) { newcache[x] = newentries; }
+ }
+ results.cache = newcache;
+ }
+ this.populate(results.cache);
+ }
+ };
+
+ results.populate = function(data){
+ var res = this; this.empty(); var count =0;
+ var clickFunction = function(){
+ var node = $(this), res = jOWL(node.data("jowltype"));
+ if(options.onSelect.call(node, res) === false) { return; }
+ self.broadcast(res);
+ };
+
+ var onHover = function(){ $(this).addClass(options.focusClass); };
+ var offHover = function(){$(this).removeClass(options.focusClass);};
+
+ for(x in data){
+ if(count < options.limit){
+ var item = data[x];
+ var v = jOWL.isExternal(x);
+ v = v ? v[1] : x;
+ var list = $('').data("jowltype", x)
+ .click(clickFunction).hover(onHover, offHover)
+ .appendTo(res);
+ var terms = [];
+ for(var l = 0;l old.length && newvalue.indexOf(old) === 0;
+ if(!old) { cache = false; }
+ old = newvalue;
+ if(newvalue.length < options.chars && open){ results.close();open = false;}
+ else if(newvalue.length >=options.chars && newvalue.length > 0){
+ if(cache) { cache = longervalue && newvalue.length > options.chars; }
+ results.open(newvalue, cache);
+ open = true;
+ }
+
+ }
+ }, options.time);
+
+ self.bind('keyup', function(){ if(!this.value.length){ results.close(); open = false; } });
+ self.bind('blur', function(){
+ if(open){setTimeout(function(){results.close();}, 200);open = false;}
+ if(!self.val().length){self.showHint();}
+ });
+ //timeout for registering clicks on results.
+ self.bind('focus', function(){
+ if(self.hinted){
+ self.hinted = false;
+ $(this).removeClass(options.hintClass).val('');
+ }
+ if(self.val().length && !open){results.open('', open);open = true;}});
+ //reopen, but do not get results
+ return this;
+ },
+/**
+Tree View
+*/
+ owl_treeview : function(options){
+ options = $.extend({
+ contentClass : jOWL.UI.defaults.contentClass,
+ focusClass: "focus",
+ nameClass: "name",
+ treeClass: "jowl-treeview",
+ rootClass: "root",
+ onSelect : function(item){}, //function that can be overwritten to specfy behavior when something is selected
+ rootThing : false, //if true then topnode is (owl) 'Thing'
+ isStatic : false, // if static then selections will refresh the entire tree
+ addChildren : false //add a given objects children to the treeview as well
+ }, options);
+
+ /** construct the hierarchy & make a tree of it */
+ function TreeModel(owlobject){
+
+ function clear(el){ //reset invParents, for later use.
+ if(el.parents) { el.parents().each(function(){
+ this.invParents = null; clear(this);
+ }); }
+ }
+
+ function leaf(node){
+ node.jnode.addClass(options.focusClass);
+ if(options.addChildren){
+ var entry = jOWL(node.$name.attr('title'));
+ if(entry && entry.children){ entry.children().each(function(){ node.add(this); }); } }
+ }
+
+ function traverse(itemarray, appendto){
+ if(!itemarray) { return; }
+ itemarray.each(function(){
+ var node = appendto.add(this);
+ if(this.invParents){ traverse(this.invParents, node); }
+ else { leaf(node); }
+ });
+
+ }
+
+ var h = owlobject.hierarchy(true);
+ if(options.rootThing) { traverse(h, tree.root(jOWL("Thing"))); }
+ else {
+ var root = tree.root(h);
+ for(var i=0;i').addClass(options.treeClass).appendTo(node);
+ var tree = this;
+ /**item can be text, a jOWL object, or a jOWL array */
+ this.root = function(item){
+ var rt = null; //root
+ rack.empty();
+ if(item && item.each) {
+ rt = [];
+ item.each(function(it){
+ var x = new fn.node(it, true);
+ x.wrapper.addClass("tv");
+ x.jnode.appendTo(rack);
+ x.invParents = it.invParents; it.invParents = null; //reset for later use
+ rt.push(x);
+ });
+ return rt;
+ }
+ rt = new fn.node(item, true);
+ rt.wrapper.addClass("tv");
+ rt.jnode.appendTo(rack);
+ return rt;
+ };
+
+ var fn = {};
+ fn.node = function(text, isRoot){ //creates a new node
+ this.jnode = isRoot ? $('').addClass(options.rootClass) : $('');
+ this.$name = null;
+ if(text){
+ this.$name = $('').addClass(options.nameClass);
+ if(typeof text == "string") { this.$name.html(text); }
+ else if(text.bind) { text.bind(this.$name); }
+ var n = this.$name;
+ this.$name.appendTo(this.jnode).click(function(){
+ var entry = jOWL(n.attr('title'));
+ if(entry && options.onSelect.call(n, entry) === false) { return; }
+ tree.broadcast(entry);
+ if(options.isStatic) { tree.propertyChange(entry); }
+ return false;});
+ }
+
+ this.wrapper = $('
').appendTo(this.jnode);
+ var self = this;
+ self.jnode.click(function(){toggle(); return false;});
+
+ this.add = function(text){
+ var nn = new fn.node(text);
+ if(!self.wrapper.children().length) { toNode(); }
+ else {
+ var lastchild = self.wrapper.children(':last');
+ lastchild.swapClass("tvilc", "tvic");
+ lastchild.swapClass("tvile", "tvie");
+ lastchild.swapClass("tvil", "tvi");
+
+ }//children - change end of list
+ self.wrapper.append(nn.jnode.swapClass('tvi', 'tvil'));
+ return nn;
+ };
+
+ function toggle(){
+ var t = self.jnode.hasClass("tvic") || self.jnode.hasClass("tvie") || self.jnode.hasClass("tvilc") || self.jnode.hasClass("tvile");
+ if(!t) { return; }
+ self.jnode.swapClass('tvic', 'tvie'); self.jnode.swapClass('tvilc', 'tvile');
+ self.wrapper.slideToggle();
+ }
+
+ function toNode(){
+ self.jnode.swapClass('tvil', 'tvilc');
+ self.jnode.swapClass('tvi', 'tvic');
+ }
+ };
+ return this;
+ }// end Tree
+
+ this.addClass("jowl-tree");
+ this.content = $("."+options.contentClass, this).empty();
+ if(!this.content.length){ this.content = $('').addClass(options.contentClass).appendTo(this); }
+ var tree = new Tree(this.content, null, options);
+ jOWL.UI.asBroadcaster(tree);
+ tree.propertyChange = function(item){ if(item.isClass) { var m = new TreeModel(item); } };
+ return tree;
+ },
+/** Uses templating
+options:
+onChange: owl:Class, owl:Thing, etc..., tell the widget what to do with the different kinds of Ontology Objects.
+"data-jowl" : {split: ", ", "somevariable" : function_triggered_for_each_result }
+ example: "rdfs:label" : {split: ", ", "rdfs:label" : function(){ //'this' keyword refers to HTML element}} )
+ example: "sparql-dl:PropertyValue(owl:Class, ?p, ?x)" : {"?p": function(){ //'this' keyword refers to HTML element }}
+ //prefil: for sparql-dl queries
+ //onComplete: function to trigger when the specific propertybox query is completed, this refers to the HTML element for propertybox
+ //sort: sort results on specified parameter, for sparql-dl results.
+onUpdate: called when the widget updates itself
+*/
+ owl_propertyLens : function(options){
+ var self = this;
+ self.options = $.extend({
+ backlinkClass : "backlink",
+ split: {},
+ disable : {},
+ click : {}},
+ options);
+ self.resourcetype = this.attr('data-jowl') || "owl:Class";
+ var propertyboxes = [];
+ $('.propertybox', this).each(function(){
+ var node = new jOWL.UI.PropertyBox($(this), self);
+ propertyboxes.push(node);
+ node.el.hide();
+ });
+ var backlink = $('.backlink', this).hide();
+ if(!backlink.length) { backlink = $('').addClass(self.options.backlinkClass).text("Back").hide().appendTo(this); }
+ jOWL.UI.asBroadcaster(this);
+
+ /** fn: optional function to execute*/
+ this.link = function(source, target, htmlel, fn){
+ htmlel.addClass("jowl_link").click(function(){
+ if(fn) { fn(); }
+ self.broadcast(target);
+ self.propertyChange(target);
+ backlink.source = source.name;
+ backlink.show().unbind('click').click(function(){
+ self.broadcast(source); self.propertyChange(source); backlink.hide();
+ });
+
+ });
+
+ };
+
+ var action = {
+ "rdfs:label": function(item){ return [{"rdfs:label": item.label() }]; },
+ "rdf:ID" : function(item){ return [{"rdf:ID": [item.name, item] }]; },
+ "rdfs:comment" : function(item){
+ return $.map(item.description(), function(n){return {"rdfs:comment":n }; });
+ },
+ "rdf:type" : function(item){
+ if(item.owlClass) { return [{"rdf:type": item.owlClass() }]; }
+ return [{"rdf:type": item.type }];
+ },
+ "term" : function(item){
+ return $.map(item.terms(), function(n, i){ return { "term" : n[0] }; });
+ },
+ "rdfs:range": function(item){if(item.range) { return [{"rdfs:range": item.range }]; } },
+ "rdfs:domain": function(item){if(item.domain) { return [{"rdfs:domain": item.domain }]; } },
+ "permalink": function(item){
+ var href = jOWL.permalink(item);
+ return [{"permalink": "Permalink" }];
+ },
+ "owl:disjointWith": function(item){
+ if(!(item.isClass)) { return; }
+ return $.map(
+ jOWL.Xpath('*', item.jnode)
+ .filter(function(){return this.nodeName == "owl:disjointWith"; }),
+ function(n, i){ return {"owl:disjointWith": jOWL($(n).RDF_Resource())};
+ });
+ },
+ "default" : function(item){
+ var type = this.attr("data-jowl");
+ return $.map(
+ jOWL.Xpath('*', item.jnode).filter(function(){return this.nodeName == type; }),
+ function(n, i){ var x = {}; x[type] = $(n).text(); return x; }
+ );
+ }
+ };
+
+ this.propertyChange = function(item){
+ if(!item) { return; }
+ self.property = item;
+ if(backlink.source != item.name) { backlink.hide(); } else { backlink.source = false; }
+
+ if(item.type != self.resourcetype){
+ if(item.isDatatypeProperty && self.resourcetype == "rdf:Property") {}
+ else if(item.isObjectProperty && self.resourcetype == "rdf:Property"){}
+ else { return; }
+ }
+
+ for(var i = 0;i5 && <15' ";
+
+ this.addClass("owl_UI");
+ jOWL.UI.asBroadcaster(this);
+
+ this.property = null;
+
+ this.propertyChange = function(item){
+ if(item.isClass){
+ this.property = item;
+ for(x in pArray){//reset all properties
+ if(pArray[x].remove){ pArray[x].remove(); delete pArray[x]; }
+ }
+ }
+ };
+
+ /** Sets up a new field */
+ this.addField = function(property){
+ if(pArray[property.URI]){
+ //allow for multiple fields?
+ return;
+ }
+
+ var $content = $("");
+ pArray[property.URI] = $content;
+
+ var $title = property.bind($("")).addClass(options.labelClass).appendTo($content).click(function(){ $content.remove(); delete pArray[property.URI]; });
+
+ if(property.isObjectProperty){
+
+ var sp = new jOWL.SPARQL_DL("Type(?t, ?c),PropertyValue(concept, property, ?c)", {concept : self.property, property : property }).execute({
+ onComplete : function(obj){
+ if(!obj.results.length){ return; } //modify to deal with non value results
+ obj.sort("?t");
+
+ $select = $("").appendTo($content);
+
+ for(var i=0;i")).appendTo($select);
+ }
+
+ $content.appendTo(self);
+ }});
+
+ }
+ else if(property.isDatatypeProperty){
+ var msg ="";
+ if(self.messages[property.range]){ msg = self.messages[property.range]; }
+
+ var $input = $('').addClass(options.selectorClass).attr("title", property.range).append($(''));
+ var $message = $('').addClass(options.messageClass).text(msg).appendTo($input);
+
+ $content.append($input).appendTo(self);
+ $('input', $content).focus(function(){
+ $message.animate({opacity: 1.0}, 1500).fadeOut();
+ });
+
+
+ }
+
+ };
+
+ this.serialize = function(){
+ var q = { "Type": self.property, "PropertyValue" : [] };
+
+ $('.'+options.selectorClass, self).each(function(){
+ var $this = $(this);
+ var $prop = $this.siblings('.'+options.labelClass);
+ var prop = $prop.attr('title');
+ if( $this.is("select")){
+ var s = $this.get(0);
+ var thing = $(s[s.selectedIndex]).attr('title');
+ q.PropertyValue.push([prop, thing]);
+ }
+ else {
+ var $input = $this.find("input");
+ var datatype = $this.attr('title');
+ var entry = $input.get(0).value;
+ if(entry) { q.PropertyValue.push([prop, '"'+entry+'"']); }
+ }
+ });
+ return q;
+ };
+
+ return this;
+ }
+});
+
+/** Used by owl_PropertyLens */
+jOWL.UI.PropertyBox = function($el, resourcebox){
+ var v = $('[data-jowl]', $el);
+ if(v.length){ this.descendant = true;}
+
+ this.el = $el;
+ this.resourcebox = resourcebox;
+ this.valuebox = v.length ? v : $el;
+ this.actiontype = this.valuebox.attr('data-jowl');
+};
+
+jOWL.UI.PropertyBox.prototype = {
+ setResults : function(results, item){
+ var nodes = jOWL.UI.Template(results, this.valuebox, this.resourcebox.options[this.actiontype].split);
+ this.complete(nodes, item);
+ if(nodes && nodes.length && this.descendant) { this.el.show(); this.valuebox.hide(); }
+ if(this.resourcebox.options[this.actiontype].onComplete) { this.resourcebox.options[this.actiontype].onComplete.call(this.el.get(0)); }
+ },
+ complete : function(nodes, item){
+ var res = this.resourcebox;
+ if(!nodes || !nodes.length) { return; }
+ var v = $.data(nodes, "parameters");
+ for(x in v){
+ if(v[x].length && typeof res.options[this.actiontype][x] == "function") {
+ v[x].each(res.options[this.actiontype][x]);
+ }}
+ for(x in res.options.onChange){
+ var data = $('[typeof='+x+']', nodes).add(nodes.filter('[typeof='+x+']'));
+ if(x.charAt(0) == "." || x.charAt(0) == "#"){ data = data.add($(x, nodes));}
+ data.each(function(){
+ var node = $(this);
+ $.data(node, 'data-jowl', x);
+ var id = node.attr('title');
+ if(id != "anonymousOntologyObject") { res.options.onChange[$.data(node, 'data-jowl')].call(node, item, jOWL(id), res); }
+ });
+ }
+ },
+ clear : function(){
+ var prev = this.valuebox.prev('.jowl-template-result');
+ if(!prev.length){ prev = this.valuebox.prev('.jowl-template-splitter');}
+ if(prev.length) { prev.remove(); this.clear(this.valuebox); }
+ }
+};
+
+/**arr: associative array of variablrd, jqel: node for which variables need to be substituted, */
+jOWL.UI.Template = function(arr, jqel, splitter){
+ var options = {
+ resultClass : "jowl-template-result",
+ splitterClass : "jowl-template-splitter"
+ };
+ if(!arr) { return; }
+
+ function bindObject(value, jnode){
+ var bound = false;
+ if(!value) { return false; }
+ if(typeof value == 'string') { jnode.html(value); bound = true;}
+ else if(value.constructor == Array){
+ if(value.length == 2) { value[1].bind(jnode).text(value[0]); bound = true; }
+ }
+ else if(value.bind){ value.bind(jnode); bound = true; }
+ return bound;
+ }
+ var count = 0, a = [], b = {};
+ var remnantFn = function(){
+ var txt = $(this).text();
+ if(txt.indexOf('${') === 0 && txt.lastIndexOf('}') == txt.length-1 ) { $(this).hide(); }
+ };
+ for(var i=0;i").children();
+ /** copy style settings */
+ x.addClass(jqel.attr('class')).removeClass('propertybox');
+ /** accepted obj types= string, array["string", "jowlobject"], jowlobject*/
+ for(obj in arr[i]){
+ if(!b[obj]) { b[obj] = []; }
+ var occurrences = $(':contains(${'+obj+'})', x);
+ if(!occurrences.length){
+ if(x.text() == "${"+obj+"}") { if(bindObject(arr[i][obj], x)) {
+ count++; b[obj].push(x.get(0));
+ }}
+ }
+ else {
+ occurrences.each(function(){
+ if(this.innerHTML == "${"+obj+"}") { var node = $(this); if(bindObject(arr[i][obj], node)) { count++; b[obj].push(this); } }
+ });
+ }
+ }
+ var remnants = $(':contains(${)', x); //hide parameters that weren't substituted
+ remnants.each(remnantFn);
+ if(count){
+ x.insertBefore(jqel);
+ a.push(x.get(0));
+ if(count > 1 && splitter) {
+ $splitter = (splitter.indexOf('<') === 0) ? $(splitter) : $("").text(splitter);
+ $splitter.addClass(options.splitterClass).insertBefore(x);
+ }
+ }
+ }
+ for(x in b){ if(b[x].length) { b[x] = $(b[x]); } }
+ var nodes = $(a);
+ $.data(nodes, "parameters", b);
+ return nodes;
+};
+
+/**
+Supporting functionality
+*/
+
+$.fn.swapClass = function(c1,c2) {
+ return this.each(function() {
+ if ($(this).hasClass(c1)) { $(this).removeClass(c1); $(this).addClass(c2);}
+ else if ($(this).hasClass(c2)) {$(this).removeClass(c2);$(this).addClass(c1);}
+ });
+};
+
+})(jQuery);
\ No newline at end of file
diff -r 2eaea1afd6b3 -r 901803e1305f examples/browser/web/js/jquery.dataTables.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/browser/web/js/jquery.dataTables.js Thu Oct 08 11:19:11 2009 +0000
@@ -0,0 +1,4522 @@
+/*
+ * File: jquery.dataTables.js
+ * Version: 1.5.2
+ * CVS: $Id$
+ * Description: Paginate, search and sort HTML tables
+ * Author: Allan Jardine (www.sprymedia.co.uk)
+ * Created: 28/3/2008
+ * Modified: $Date$ by $Author$
+ * Language: Javascript
+ * License: GPL v2 or BSD 3 point style
+ * Project: Mtaala
+ * Contact: allan.jardine@sprymedia.co.uk
+ *
+ * Copyright 2008-2009 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, as supplied with this software.
+ *
+ * This source file 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. See the license files for details.
+ *
+ * For details pleease refer to: http://www.datatables.net
+ */
+
+/*
+ * When considering jsLint, we need to allow eval() as it it is used for reading cookies and
+ * building the dynamic multi-column sort functions.
+ */
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,_fnReadCookie,_fnProcessingDisplay,_fnDraw,_fnSort,_fnReDraw,_fnDetectType,_fnSortingClasses,_fnSettingsFromNode,_fnBuildSearchArray,_fnCalculateEnd,_fnFeatureHtmlProcessing,_fnFeatureHtmlPaginate,_fnFeatureHtmlInfo,_fnFeatureHtmlFilter,_fnFilter,_fnSaveState,_fnFilterColumn,_fnEscapeRegex,_fnFilterComplete,_fnFeatureHtmlLength,_fnGetDataMaster,_fnVisibleToColumnIndex,_fnDrawHead,_fnAddData,_fnGetTrNodes,_fnColumnIndexToVisible,_fnCreateCookie,_fnAddOptionsHtml,_fnMap,_fnClearTable,_fnDataToSearch,_fnReOrderIndex,_fnFilterCustom,_fnVisbleColumns,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnColumnOrdering,fnGetMaxLenString*/
+
+(function($) {
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables variables
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Variable: dataTableSettings
+ * Purpose: Store the settings for each dataTables instance
+ * Scope: jQuery.fn
+ */
+ $.fn.dataTableSettings = [];
+
+ /*
+ * Variable: dataTableExt
+ * Purpose: Container for customisable parts of DataTables
+ * Scope: jQuery.fn
+ */
+ $.fn.dataTableExt = {};
+ var _oExt = $.fn.dataTableExt; /* Short reference for fast internal lookup */
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables extensible objects
+ *
+ * The _oExt object is used to provide an area where user dfined plugins can be
+ * added to DataTables. The following properties of the object are used:
+ * oApi - Plug-in API functions
+ * aTypes - Auto-detection of types
+ * oSort - Sorting functions used by DataTables (based on the type)
+ * oPagination - Pagination functions for different input styles
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Variable: sVersion
+ * Purpose: Version string for plug-ins to check compatibility
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.sVersion = "1.5.2";
+
+ /*
+ * Variable: iApiIndex
+ * Purpose: Index for what 'this' index API functions should use
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.iApiIndex = 0;
+
+ /*
+ * Variable: oApi
+ * Purpose: Container for plugin API functions
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oApi = { };
+
+ /*
+ * Variable: aFiltering
+ * Purpose: Container for plugin filtering functions
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.afnFiltering = [ ];
+
+ /*
+ * Variable: aoFeatures
+ * Purpose: Container for plugin function functions
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: Array of objects with the following parameters:
+ * fnInit: Function for initialisation of Feature. Takes oSettings and returns node
+ * cFeature: Character that will be matched in sDom - case sensitive
+ * sFeature: Feature name - just for completeness :-)
+ */
+ _oExt.aoFeatures = [ ];
+
+ /*
+ * Variable: ofnSearch
+ * Purpose: Container for custom filtering functions
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: This is an object (the name should match the type) for custom filtering function,
+ * which can be used for live DOM checking or formatted text filtering
+ */
+ _oExt.ofnSearch = { };
+
+ /*
+ * Variable: oStdClasses
+ * Purpose: Storage for the various classes that DataTables uses
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oStdClasses = {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "paginate_enabled_previous",
+ "sPagePrevDisabled": "paginate_disabled_previous",
+ "sPageNextEnabled": "paginate_enabled_next",
+ "sPageNextDisabled": "paginate_disabled_next",
+ "sPageJUINext": "",
+ "sPageJUIPrev": "",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "paginate_button",
+ "sPageButtonActive": "paginate_active",
+ "sPageButtonStaticActive": "paginate_button",
+ "sPageFirst": "first",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last",
+
+ /* Stripping classes */
+ "sStripOdd": "odd",
+ "sStripEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "sorting_asc",
+ "sSortDesc": "sorting_desc",
+ "sSortable": "sorting",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "",
+ "sSortJUIDesc": "",
+ "sSortJUI": ""
+ };
+
+ /*
+ * Variable: oJUIClasses
+ * Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oJUIClasses = {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "fg-button ui-state-default ui-corner-left",
+ "sPagePrevDisabled": "fg-button ui-state-default ui-corner-left ui-state-disabled",
+ "sPageNextEnabled": "fg-button ui-state-default ui-corner-right",
+ "sPageNextDisabled": "fg-button ui-state-default ui-corner-right ui-state-disabled",
+ "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+ "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "fg-button ui-state-default",
+ "sPageButtonActive": "fg-button ui-state-default ui-state-disabled",
+ "sPageButtonStaticActive": "fg-button ui-state-default ui-state-disabled",
+ "sPageFirst": "first ui-corner-tl ui-corner-bl",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last ui-corner-tr ui-corner-br",
+
+ /* Stripping classes */
+ "sStripOdd": "odd",
+ "sStripEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate fg-buttonset fg-buttonset-multi paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "ui-state-default",
+ "sSortDesc": "ui-state-default",
+ "sSortable": "ui-state-default",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+ "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+ "sSortJUI": "css_right ui-icon ui-icon-triangle-2-n-s"
+ };
+
+ /*
+ * Variable: oPagination
+ * Purpose: Container for the various type of pagination that dataTables supports
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oPagination = {
+ /*
+ * Variable: two_button
+ * Purpose: Standard two button (forward/back) pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "two_button": {
+ /*
+ * Function: oPagination.two_button.fnInit
+ * Purpose: Initalise dom elements required for pagination with forward/back buttons only
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, fnCallbackDraw )
+ {
+ var nPaging = oSettings.anFeatures.p;
+
+ /* Store the next and previous elements in the oSettings object as they can be very
+ * usful for automation - particularly testing
+ */
+ if ( !oSettings.bJUI )
+ {
+ oSettings.nPrevious = document.createElement( 'div' );
+ oSettings.nNext = document.createElement( 'div' );
+ }
+ else
+ {
+ oSettings.nPrevious = document.createElement( 'a' );
+ oSettings.nNext = document.createElement( 'a' );
+
+ var nNextInner = document.createElement('span');
+ nNextInner.className = oSettings.oClasses.sPageJUINext;
+ oSettings.nNext.appendChild( nNextInner );
+
+ var nPreviousInner = document.createElement('span');
+ nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
+ oSettings.nPrevious.appendChild( nPreviousInner );
+ }
+
+ if ( oSettings.sTableId !== '' )
+ {
+ nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
+ oSettings.nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
+ oSettings.nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
+ }
+
+ oSettings.nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
+ oSettings.nNext.className = oSettings.oClasses.sPageNextDisabled;
+
+ oSettings.nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
+ oSettings.nNext.title = oSettings.oLanguage.oPaginate.sNext;
+
+ nPaging.appendChild( oSettings.nPrevious );
+ nPaging.appendChild( oSettings.nNext );
+ $(nPaging).insertAfter( oSettings.nTable );
+
+ $(oSettings.nPrevious).click( function() {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+
+ /* Correct for underrun */
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+
+ fnCallbackDraw( oSettings );
+ } );
+
+ $(oSettings.nNext).click( function() {
+ /* Make sure we are not over running the display array */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart += oSettings._iDisplayLength;
+ }
+
+ fnCallbackDraw( oSettings );
+ } );
+
+ /* Take the brutal approach to cancelling text selection */
+ $(oSettings.nPrevious).bind( 'selectstart', function () { return false; } );
+ $(oSettings.nNext).bind( 'selectstart', function () { return false; } );
+ },
+
+ /*
+ * Function: oPagination.two_button.fnUpdate
+ * Purpose: Update the two button pagination at the end of the draw
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.anFeatures.p )
+ {
+ return;
+ }
+
+ oSettings.nPrevious.className =
+ ( oSettings._iDisplayStart === 0 ) ?
+ oSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;
+
+ oSettings.nNext.className =
+ ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
+ oSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;
+ }
+ },
+
+
+ /*
+ * Variable: iFullNumbersShowPages
+ * Purpose: Change the number of pages which can be seen
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "iFullNumbersShowPages": 5,
+
+ /*
+ * Variable: full_numbers
+ * Purpose: Full numbers pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "full_numbers": {
+ /*
+ * Function: oPagination.full_numbers.fnInit
+ * Purpose: Initalise dom elements required for pagination with a list of the pages
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, fnCallbackDraw )
+ {
+ var nPaging = oSettings.anFeatures.p;
+ var nFirst = document.createElement( 'span' );
+ var nPrevious = document.createElement( 'span' );
+ var nList = document.createElement( 'span' );
+ var nNext = document.createElement( 'span' );
+ var nLast = document.createElement( 'span' );
+
+ nFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;
+ nPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;
+ nNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;
+ nLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;
+
+ var oClasses = oSettings.oClasses;
+ nFirst.className = oClasses.sPageButton+" "+oClasses.sPageFirst;
+ nPrevious.className = oClasses.sPageButton+" "+oClasses.sPagePrevious;
+ nNext.className= oClasses.sPageButton+" "+oClasses.sPageNext;
+ nLast.className = oClasses.sPageButton+" "+oClasses.sPageLast;
+
+ if ( oSettings.sTableId !== '' )
+ {
+ nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
+ nFirst.setAttribute( 'id', oSettings.sTableId+'_first' );
+ nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
+ nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
+ nLast.setAttribute( 'id', oSettings.sTableId+'_last' );
+ }
+
+ nPaging.appendChild( nFirst );
+ nPaging.appendChild( nPrevious );
+ nPaging.appendChild( nList );
+ nPaging.appendChild( nNext );
+ nPaging.appendChild( nLast );
+
+ $(nFirst).click( function () {
+ oSettings._iDisplayStart = 0;
+ fnCallbackDraw( oSettings );
+ } );
+
+ $(nPrevious).click( function() {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+
+ /* Correct for underrun */
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+
+ fnCallbackDraw( oSettings );
+ } );
+
+ $(nNext).click( function() {
+ /* Make sure we are not over running the display array */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart += oSettings._iDisplayLength;
+ }
+
+ fnCallbackDraw( oSettings );
+ } );
+
+ $(nLast).click( function() {
+ var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+ oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+
+ fnCallbackDraw( oSettings );
+ } );
+
+ /* Take the brutal approach to cancelling text selection */
+ $('span', nPaging).bind( 'mousedown', function () { return false; } );
+ $('span', nPaging).bind( 'selectstart', function () { return false; } );
+
+ oSettings.nPaginateList = nList;
+ },
+
+ /*
+ * Function: oPagination.full_numbers.fnUpdate
+ * Purpose: Update the list of page buttons shows
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.anFeatures.p )
+ {
+ return;
+ }
+
+ var iPageCount = jQuery.fn.dataTableExt.oPagination.iFullNumbersShowPages;
+ var iPageCountHalf = Math.floor(iPageCount / 2);
+ var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+ var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
+ var sList = "";
+ var iStartButton;
+ var iEndButton;
+ var oClasses = oSettings.oClasses;
+
+ if (iPages < iPageCount)
+ {
+ iStartButton = 1;
+ iEndButton = iPages;
+ }
+ else
+ {
+ if (iCurrentPage <= iPageCountHalf)
+ {
+ iStartButton = 1;
+ iEndButton = iPageCount;
+ }
+ else
+ {
+ if (iCurrentPage >= (iPages - iPageCountHalf))
+ {
+ iStartButton = iPages - iPageCount + 1;
+ iEndButton = iPages;
+ }
+ else
+ {
+ iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+ iEndButton = iStartButton + iPageCount - 1;
+ }
+ }
+ }
+
+ for ( var i=iStartButton ; i<=iEndButton ; i++ )
+ {
+ if ( iCurrentPage != i )
+ {
+ sList += ''+i+'';
+ }
+ else
+ {
+ sList += ''+i+'';
+ }
+ }
+
+ oSettings.nPaginateList.innerHTML = sList;
+
+ /* Take the brutal approach to cancelling text selection */
+ $('span', oSettings.nPaginateList).bind( 'mousedown', function () { return false; } );
+ $('span', oSettings.nPaginateList).bind( 'selectstart', function () { return false; } );
+
+ $('span', oSettings.nPaginateList).click( function() {
+ var iTarget = (this.innerHTML * 1) - 1;
+ oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
+
+ fnCallbackDraw( oSettings );
+ return false;
+ } );
+
+ /* Update the 'premanent botton's classes */
+ var nButtons = $('span', oSettings.anFeatures.p);
+ var nStatic = [ nButtons[0], nButtons[1], nButtons[nButtons.length-2], nButtons[nButtons.length-1] ];
+ $(nStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive );
+ if ( iCurrentPage == 1 )
+ {
+ nStatic[0].className += " "+oClasses.sPageButtonStaticActive;
+ nStatic[1].className += " "+oClasses.sPageButtonStaticActive;
+ }
+ else
+ {
+ nStatic[0].className += " "+oClasses.sPageButton;
+ nStatic[1].className += " "+oClasses.sPageButton;
+ }
+
+ if ( iCurrentPage == iPages )
+ {
+ nStatic[2].className += " "+oClasses.sPageButtonStaticActive;
+ nStatic[3].className += " "+oClasses.sPageButtonStaticActive;
+ }
+ else
+ {
+ nStatic[2].className += " "+oClasses.sPageButton;
+ nStatic[3].className += " "+oClasses.sPageButton;
+ }
+ }
+ }
+ };
+
+ /*
+ * Variable: oSort
+ * Purpose: Wrapper for the sorting functions that can be used in DataTables
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: The functions provided in this object are basically standard javascript sort
+ * functions - they expect two inputs which they then compare and then return a priority
+ * result. For each sort method added, two functions need to be defined, an ascending sort and
+ * a descending sort.
+ */
+ _oExt.oSort = {
+ /*
+ * text sorting
+ */
+ "string-asc": function ( a, b )
+ {
+ var x = a.toLowerCase();
+ var y = b.toLowerCase();
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "string-desc": function ( a, b )
+ {
+ var x = a.toLowerCase();
+ var y = b.toLowerCase();
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * html sorting (ignore html tags)
+ */
+ "html-asc": function ( a, b )
+ {
+ var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+ var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "html-desc": function ( a, b )
+ {
+ var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+ var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * date sorting
+ */
+ "date-asc": function ( a, b )
+ {
+ var x = Date.parse( a );
+ var y = Date.parse( b );
+
+ if ( isNaN( x ) )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ if ( isNaN( y ) )
+ {
+ y = Date.parse( "01/01/1970 00:00:00" );
+ }
+
+ return x - y;
+ },
+
+ "date-desc": function ( a, b )
+ {
+ var x = Date.parse( a );
+ var y = Date.parse( b );
+
+ if ( isNaN( x ) )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ if ( isNaN( y ) )
+ {
+ y = Date.parse( "01/01/1970 00:00:00" );
+ }
+
+ return y - x;
+ },
+
+
+ /*
+ * numerical sorting
+ */
+ "numeric-asc": function ( a, b )
+ {
+ var x = a == "-" ? 0 : a;
+ var y = b == "-" ? 0 : b;
+ return x - y;
+ },
+
+ "numeric-desc": function ( a, b )
+ {
+ var x = a == "-" ? 0 : a;
+ var y = b == "-" ? 0 : b;
+ return y - x;
+ }
+ };
+
+
+ /*
+ * Variable: aTypes
+ * Purpose: Container for the various type of type detection that dataTables supports
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: The functions in this array are expected to parse a string to see if it is a data
+ * type that it recognises. If so then the function should return the name of the type (a
+ * corresponding sort function should be defined!), if the type is not recognised then the
+ * function should return null such that the parser and move on to check the next type.
+ * Note that ordering is important in this array - the functions are processed linearly,
+ * starting at index 0.
+ */
+ _oExt.aTypes = [
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is numeric
+ * Returns: string:'numeric' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ /* Snaity check that we are dealing with a string or quick return for a number */
+ if ( typeof sData == 'number' )
+ {
+ return 'numeric';
+ }
+ else if ( typeof sData.charAt != 'function' )
+ {
+ return null;
+ }
+
+ var sValidFirstChars = "0123456789-";
+ var sValidChars = "0123456789.";
+ var Char;
+ var bDecimal = false;
+
+ /* Check for a valid first char (no period and allow negatives) */
+ Char = sData.charAt(0);
+ if (sValidFirstChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Check all the other characters are valid */
+ for ( var i=1 ; i' - div elements
+ * '<"class" and '>' - div with a class
+ * Examples: '<"wrapper"flipt>', 'ip>'
+ */
+ this.sDomPositioning = 'lfrtip';
+
+ /*
+ * Variable: sPaginationType
+ * Purpose: Note which type of sorting should be used
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sPaginationType = "two_button";
+
+ /*
+ * Variable: iCookieDuration
+ * Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.iCookieDuration = 60 * 60 * 2;
+
+ /*
+ * Variable: sAjaxSource
+ * Purpose: Source url for AJAX data for the table
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sAjaxSource = null;
+
+ /*
+ * Variable: bAjaxDataGet
+ * Purpose: Note if draw should be blocked while getting data
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.bAjaxDataGet = true;
+
+ /*
+ * Variable: fnServerData
+ * Purpose: Function to get the server-side data - can be overruled by the developer
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnServerData = $.getJSON;
+
+ /*
+ * Variable: iServerDraw
+ * Purpose: Counter and tracker for server-side processing draws
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.iServerDraw = 0;
+
+ /*
+ * Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd
+ * Purpose: Display length variables
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: These variable must NOT be used externally to get the data length. Rather, use
+ * the fnRecordsTotal() (etc) functions.
+ */
+ this._iDisplayLength = 10;
+ this._iDisplayStart = 0;
+ this._iDisplayEnd = 10;
+
+ /*
+ * Variable: _iRecordsTotal, _iRecordsDisplay
+ * Purpose: Display length variables used for server side processing
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: These variable must NOT be used externally to get the data length. Rather, use
+ * the fnRecordsTotal() (etc) functions.
+ */
+ this._iRecordsTotal = 0;
+ this._iRecordsDisplay = 0;
+
+ /*
+ * Variable: bJUI
+ * Purpose: Should we add the markup needed for jQuery UI theming?
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.bJUI = false;
+
+ /*
+ * Variable: bJUI
+ * Purpose: Should we add the markup needed for jQuery UI theming?
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oClasses = _oExt.oStdClasses;
+ }
+
+ /*
+ * Variable: oApi
+ * Purpose: Container for publicly exposed 'private' functions
+ * Scope: jQuery.dataTable
+ */
+ this.oApi = {};
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * API functions
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Function: fnDraw
+ * Purpose: Redraw the table
+ * Returns: -
+ * Inputs: -
+ */
+ this.fnDraw = function()
+ {
+ _fnReDraw( _fnSettingsFromNode( this[_oExt.iApiIndex] ) );
+ };
+
+ /*
+ * Function: fnFilter
+ * Purpose: Filter the input based on data
+ * Returns: -
+ * Inputs: string:sInput - string to filter the table on
+ * int:iColumn - optional - column to limit filtering to
+ * bool:bEscapeRegex - optional - escape regex characters or not - default true
+ */
+ this.fnFilter = function( sInput, iColumn, bEscapeRegex )
+ {
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ if ( typeof bEscapeRegex == 'undefined' )
+ {
+ bEscapeRegex = true;
+ }
+
+ if ( typeof iColumn == "undefined" || iColumn === null )
+ {
+ /* Global filter */
+ _fnFilterComplete( oSettings, {"sSearch":sInput, "bEscapeRegex": bEscapeRegex}, 1 );
+ }
+ else
+ {
+ /* Single column filter */
+ oSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;
+ oSettings.aoPreSearchCols[ iColumn ].bEscapeRegex = bEscapeRegex;
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+ }
+ };
+
+ /*
+ * Function: fnSettings
+ * Purpose: Get the settings for a particular table for extern. manipulation
+ * Returns: -
+ * Inputs: -
+ */
+ this.fnSettings = function( nNode )
+ {
+ return _fnSettingsFromNode( this[_oExt.iApiIndex] );
+ };
+
+ /*
+ * Function: fnSort
+ * Purpose: Sort the table by a particular row
+ * Returns: -
+ * Inputs: int:iCol - the data index to sort on. Note that this will
+ * not match the 'display index' if you have hidden data entries
+ */
+ this.fnSort = function( aaSort )
+ {
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+ oSettings.aaSorting = aaSort;
+ _fnSort( oSettings );
+ };
+
+ /*
+ * Function: fnAddData
+ * Purpose: Add new row(s) into the table
+ * Returns: array int: array of indexes (aoData) which have been added (zero length on error)
+ * Inputs: array:mData - the data to be added. The length must match
+ * the original data from the DOM
+ * or
+ * array array:mData - 2D array of data to be added
+ * bool:bRedraw - redraw the table or not - default true
+ * Notes: Warning - the refilter here will cause the table to redraw
+ * starting at zero
+ * Notes: Thanks to Yekimov Denis for contributing the basis for this function!
+ */
+ this.fnAddData = function( mData, bRedraw )
+ {
+ var aiReturn = [];
+ var iTest;
+ if ( typeof bRedraw == 'undefined' )
+ {
+ bRedraw = true;
+ }
+
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ /* Check if we want to add multiple rows or not */
+ if ( typeof mData[0] == "object" )
+ {
+ for ( var i=0 ; i= oSettings.aiDisplay.length )
+ {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+
+ /* Return the data array from this row */
+ var aData = oSettings.aoData[iAODataIndex]._aData.slice();
+
+ if ( typeof bNullRow != "undefined" && bNullRow === true )
+ {
+ oSettings.aoData[iAODataIndex] = null;
+ }
+
+ return aData;
+ };
+
+ /*
+ * Function: fnClearTable
+ * Purpose: Quickly and simply clear a table
+ * Returns: -
+ * Inputs: bool:bRedraw - redraw the table or not - default true
+ * Notes: Thanks to Yekimov Denis for contributing the basis for this function!
+ */
+ this.fnClearTable = function( bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+ _fnClearTable( oSettings );
+
+ if ( typeof bRedraw == 'undefined' || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+ /*
+ * Function: fnOpen
+ * Purpose: Open a display row (append a row after the row in question)
+ * Returns: -
+ * Inputs: node:nTr - the table row to 'open'
+ * string:sHtml - the HTML to put into the row
+ * string:sClass - class to give the new cell
+ */
+ this.fnOpen = function( nTr, sHtml, sClass )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ /* the old open one if there is one */
+ this.fnClose( nTr );
+
+
+ var nNewRow = document.createElement("tr");
+ var nNewCell = document.createElement("td");
+ nNewRow.appendChild( nNewCell );
+ nNewCell.className = sClass;
+ nNewCell.colSpan = _fnVisbleColumns( oSettings );
+ nNewCell.innerHTML = sHtml;
+
+ $(nNewRow).insertAfter(nTr);
+
+ /* No point in storing the row if using server-side processing since the nParent will be
+ * nuked on a re-draw anyway
+ */
+ if ( !oSettings.oFeatures.bServerSide )
+ {
+ oSettings.aoOpenRows.push( {
+ "nTr": nNewRow,
+ "nParent": nTr
+ } );
+ }
+ };
+
+ /*
+ * Function: fnClose
+ * Purpose: Close a display row
+ * Returns: int: 0 (success) or 1 (failed)
+ * Inputs: node:nTr - the table row to 'close'
+ */
+ this.fnClose = function( nTr )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ for ( var i=0 ; itd', oSettings.aoData[i].nTr)[j-iCorrector] == nNode )
+ if ( oSettings.aoData[i] !== null &&
+ oSettings.aoData[i].nTr.getElementsByTagName('td')[j-iCorrector] == nNode )
+ {
+ return [ i, j-iCorrector, j ];
+ }
+ }
+ else
+ {
+ iCorrector++;
+ }
+ }
+ }
+ }
+ return null;
+ };
+
+ /*
+ * Function: fnUpdate
+ * Purpose: Update a table cell or row
+ * Returns: int: 0 okay, 1 error
+ * Inputs: array string 'or' string:mData - data to update the cell/row with
+ * int:iRow - the row (from aoData) to update
+ * int:iColumn - the column to update
+ * bool:bRedraw - redraw the table or not - default true
+ */
+ this.fnUpdate = function( mData, iRow, iColumn, bRedraw )
+ {
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+ var iVisibleColumn;
+ var sDisplay;
+ if ( typeof bRedraw == 'undefined' )
+ {
+ bRedraw = true;
+ }
+
+ if ( typeof mData != 'object' )
+ {
+ sDisplay = mData;
+ oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
+
+ if ( oSettings.aoColumns[iColumn].fnRender !== null )
+ {
+ sDisplay = oSettings.aoColumns[iColumn].fnRender( {
+ "iDataRow": iRow,
+ "iDataColumn": iColumn,
+ "aData": oSettings.aoData[iRow]._aData
+ } );
+
+ if ( oSettings.aoColumns[iColumn].bUseRendered )
+ {
+ oSettings.aoData[iRow]._aData[iColumn] = sDisplay;
+ }
+ }
+
+ iVisibleColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+ if ( iVisibleColumn !== null )
+ {
+ oSettings.aoData[iRow].nTr.getElementsByTagName('td')[iVisibleColumn].innerHTML =
+ sDisplay;
+ }
+ }
+ else
+ {
+ if ( mData.length != oSettings.aoColumns.length )
+ {
+ alert( 'Warning: An array passed to fnUpdate must have the same number of columns as '+
+ 'the table in question - in this case '+oSettings.aoColumns.length );
+ return 1;
+ }
+
+ for ( var i=0 ; i= _fnVisbleColumns( oSettings ) )
+ {
+ nTrHead.appendChild( anTheadTh[iCol] );
+ if ( nTrFoot )
+ {
+ nTrFoot.appendChild( anTfootTh[iCol] );
+ }
+
+ for ( i=0, iLen=oSettings.aoData.length ; i=0 if successful (index of new aoData entry), -1 if failed
+ * Inputs: object:oSettings - dataTables settings object
+ * array:aData - data array to be added
+ */
+ function _fnAddData ( oSettings, aData )
+ {
+ /* Sanity check the length of the new array */
+ if ( aData.length != oSettings.aoColumns.length )
+ {
+ alert( "Warning - added data does not match known number of columns" );
+ return -1;
+ }
+
+ /* Create the object for storing information about this new row */
+ var iThisIndex = oSettings.aoData.length;
+ oSettings.aoData.push( {
+ "_iId": oSettings.iNextId++,
+ "_aData": aData.slice(),
+ "nTr": document.createElement('tr'),
+ "_anHidden": []
+ } );
+
+ /* Create the cells */
+ var nTd;
+ for ( var i=0 ; itr', oSettings.nTable).each( function() {
+ var iThisIndex = oSettings.aoData.length;
+ oSettings.aoData.push( {
+ "_iId": oSettings.iNextId++,
+ "_aData": [],
+ "nTr": this,
+ "_anHidden": []
+ } );
+
+ oSettings.aiDisplayMaster.push( iThisIndex );
+
+ /* Add the data for this column */
+ var aLocalData = oSettings.aoData[iThisIndex]._aData;
+ $('td', this).each( function( i ) {
+ aLocalData[i] = this.innerHTML;
+ } );
+ } );
+ }
+
+ /*
+ * Now process by column
+ */
+ var iCorrector = 0;
+ for ( i=0 ; itr' expression. This basically ensures that we
+ * only get tr elements of the tbody that the data table has been initialised on. If there
+ * are nested tables then we don't want to remove those elements.
+ */
+ var nTrs = $('tbody:eq(0)>tr', oSettings.nTable);
+ for ( i=0 ; i' )
+ {
+ /* End container div */
+ nInsertNode = nInsertNode.parentNode;
+ }
+ else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+ {
+ /* Length */
+ nTmp = _fnFeatureHtmlLength( oSettings );
+ oSettings.anFeatures[cOption] = nTmp;
+ nInsertNode.appendChild( nTmp );
+ }
+ else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+ {
+ /* Filter */
+ nTmp = _fnFeatureHtmlFilter( oSettings );
+ oSettings.anFeatures[cOption] = nTmp;
+ nInsertNode.appendChild( nTmp );
+ }
+ else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+ {
+ /* pRocessing */
+ nTmp = _fnFeatureHtmlProcessing( oSettings );
+ oSettings.anFeatures[cOption] = nTmp;
+ nInsertNode.appendChild( nTmp );
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ oSettings.anFeatures[cOption] = oSettings.nTable;
+ nInsertNode.appendChild( oSettings.nTable );
+ }
+ else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
+ {
+ /* Info */
+ nTmp = _fnFeatureHtmlInfo( oSettings );
+ oSettings.anFeatures[cOption] = nTmp;
+ nInsertNode.appendChild( nTmp );
+ }
+ else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+ {
+ /* Pagination */
+ nTmp = _fnFeatureHtmlPaginate( oSettings );
+ oSettings.anFeatures[cOption] = nTmp;
+ nInsertNode.appendChild( nTmp );
+ }
+ else if ( _oExt.aoFeatures.length !== 0 )
+ {
+ var aoFeatures = _oExt.aoFeatures;
+ for ( var k=0, kLen=aoFeatures.length ; k';
+
+ var jqFilter = $("input", nFilter);
+ jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','"') );
+ jqFilter.keyup( function(e) {
+ _fnFilterComplete( oSettings, {
+ "sSearch": this.value,
+ "bEscapeRegex": oSettings.oPreviousSearch.bEscapeRegex
+ } );
+
+ /* Prevent default */
+ return false;
+ } );
+
+ return nFilter;
+ }
+
+ /*
+ * Function: _fnFeatureHtmlInfo
+ * Purpose: Generate the node required for the info display
+ * Returns: node
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnFeatureHtmlInfo ( oSettings )
+ {
+ var nInfo = document.createElement( 'div' );
+ if ( oSettings.sTableId !== '' )
+ {
+ nInfo.setAttribute( 'id', oSettings.sTableId+'_info' );
+ }
+ nInfo.className = oSettings.oClasses.sInfo;
+ return nInfo;
+ }
+
+ /*
+ * Function: _fnFeatureHtmlPaginate
+ * Purpose: Generate the node required for default pagination
+ * Returns: node
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnFeatureHtmlPaginate ( oSettings )
+ {
+ var nPaginate = document.createElement( 'div' );
+ nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
+ oSettings.anFeatures.p = nPaginate; /* Need this stored in order to call paging plug-ins */
+
+ _oExt.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, function( oSettings ) {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ } );
+ return nPaginate;
+ }
+
+ /*
+ * Function: _fnFeatureHtmlLength
+ * Purpose: Generate the node required for user display length changing
+ * Returns: node
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnFeatureHtmlLength ( oSettings )
+ {
+ /* This can be overruled by not using the _MENU_ var/macro in the language variable */
+ var sName = (oSettings.sTableId === "") ? "" : 'name="'+oSettings.sTableId+'_length"';
+ var sStdMenu =
+ '';
+
+ var nLength = document.createElement( 'div' );
+ if ( oSettings.sTableId !== '' )
+ {
+ nLength.setAttribute( 'id', oSettings.sTableId+'_length' );
+ }
+ nLength.className = oSettings.oClasses.sLength;
+ nLength.innerHTML = oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu );
+
+ /*
+ * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+ * and Stefan Skopnik for fixing the fix!
+ */
+ $('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);
+
+ $('select', nLength).change( function(e) {
+ oSettings._iDisplayLength = parseInt($(this).val(), 10);
+
+ _fnCalculateEnd( oSettings );
+
+ /* If we have space to show extra rows (backing up from the end point - then do so */
+ if ( oSettings._iDisplayEnd == oSettings.aiDisplay.length )
+ {
+ oSettings._iDisplayStart = oSettings._iDisplayEnd - oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+
+ _fnDraw( oSettings );
+ } );
+
+ return nLength;
+ }
+
+ /*
+ * Function: _fnFeatureHtmlProcessing
+ * Purpose: Generate the node required for the processing node
+ * Returns: node
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnFeatureHtmlProcessing ( oSettings )
+ {
+ var nProcessing = document.createElement( 'div' );
+
+ if ( oSettings.sTableId !== '' )
+ {
+ nProcessing.setAttribute( 'id', oSettings.sTableId+'_processing' );
+ }
+ nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
+ nProcessing.className = oSettings.oClasses.sProcessing;
+ oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
+
+ return nProcessing;
+ }
+
+ /*
+ * Function: _fnProcessingDisplay
+ * Purpose: Display or hide the processing indicator
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * bool:
+ * true - show the processing indicator
+ * false - don't show
+ */
+ function _fnProcessingDisplay ( oSettings, bShow )
+ {
+ if ( oSettings.oFeatures.bProcessing )
+ {
+ oSettings.anFeatures.r.style.visibility = bShow ? "visible" : "hidden";
+ }
+ }
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Filtering
+ */
+
+ /*
+ * Function: _fnFilterComplete
+ * Purpose: Filter the table using both the global filter and column based filtering
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * object:oSearch: search information
+ * int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
+ */
+ function _fnFilterComplete ( oSettings, oInput, iForce )
+ {
+ /* Filter on everything */
+ _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bEscapeRegex );
+
+ /* Now do the individual column filter */
+ for ( var i=0 ; i=0 ; i-- )
+ {
+ var sData = _fnDataToSearch( oSettings.aoData[ oSettings.aiDisplay[i] ]._aData[iColumn],
+ oSettings.aoColumns[iColumn].sType );
+ if ( ! rpSearch.test( sData ) )
+ {
+ oSettings.aiDisplay.splice( i, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+
+ /*
+ * Function: _fnFilter
+ * Purpose: Filter the data table based on user input and draw the table
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * string:sInput - string to filter on
+ * int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
+ * bool:bEscapeRegex - escape regex or not
+ */
+ function _fnFilter( oSettings, sInput, iForce, bEscapeRegex )
+ {
+ var i;
+
+ /* Check if we are forcing or not - optional parameter */
+ if ( typeof iForce == 'undefined' || iForce === null )
+ {
+ iForce = 0;
+ }
+
+ /* Need to take account of custom filtering functions always */
+ if ( _oExt.afnFiltering.length !== 0 )
+ {
+ iForce = 1;
+ }
+
+ /* Generate the regular expression to use. Something along the lines of:
+ * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+ */
+ var asSearch = bEscapeRegex ?
+ _fnEscapeRegex( sInput ).split( ' ' ) :
+ sInput.split( ' ' );
+ var sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+ var rpSearch = new RegExp( sRegExpString, "i" ); /* case insensitive */
+
+ /*
+ * If the input is blank - we want the full data set
+ */
+ if ( sInput.length <= 0 )
+ {
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ }
+ else
+ {
+ /*
+ * We are starting a new search or the new search string is smaller
+ * then the old one (i.e. delete). Search from the master array
+ */
+ if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+ oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||
+ sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )
+ {
+ /* Nuke the old display array - we are going to rebuild it */
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+
+ /* Force a rebuild of the search array */
+ _fnBuildSearchArray( oSettings, 1 );
+
+ /* Search through all records to populate the search array
+ * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
+ * mapping
+ */
+ for ( i=0 ; i/g, "" );
+ }
+ else if ( typeof sData == "string" )
+ {
+ return sData.replace(/\n/g," ");
+ }
+ return sData;
+ }
+
+ /*
+ * Function: _fnCalculateEnd
+ * Purpose: Rcalculate the end point based on the start point
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnCalculateEnd( oSettings )
+ {
+ if ( oSettings.oFeatures.bPaginate === false )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ /* Set the end point of the display - based on how many elements there are
+ * still to display
+ */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
+ oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+ }
+ }
+ }
+
+ /*
+ * Function: _fnConvertToWidth
+ * Purpose: Convert a CSS unit width to pixels (e.g. 2em)
+ * Returns: int:iWidth - width in pixels
+ * Inputs: string:sWidth - width to be converted
+ * node:nParent - parent to get the with for (required for
+ * relative widths) - optional
+ */
+ function _fnConvertToWidth ( sWidth, nParent )
+ {
+ if ( !sWidth || sWidth === null || sWidth === '' )
+ {
+ return 0;
+ }
+
+ if ( typeof nParent == "undefined" )
+ {
+ nParent = document.getElementsByTagName('body')[0];
+ }
+
+ var iWidth;
+ var nTmp = document.createElement( "div" );
+ nTmp.style.width = sWidth;
+
+ nParent.appendChild( nTmp );
+ iWidth = nTmp.offsetWidth;
+ nParent.removeChild( nTmp );
+
+ return ( iWidth );
+ }
+
+ /*
+ * Function: _fnCalculateColumnWidths
+ * Purpose: Calculate the width of columns for the table
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnCalculateColumnWidths ( oSettings )
+ {
+ var iTableWidth = oSettings.nTable.offsetWidth;
+ var iTotalUserIpSize = 0;
+ var iTmpWidth;
+ var iVisibleColumns = 0;
+ var iColums = oSettings.aoColumns.length;
+ var i;
+ var oHeaders = $('thead th', oSettings.nTable);
+
+ /* Convert any user input sizes into pixel sizes */
+ for ( i=0 ; i';
+ var sCalcHead = "
";
+ var sCalcHtml = "
";
+
+ /* Construct a tempory table which we will inject (invisibly) into
+ * the dom - to let the browser do all the hard word
+ */
+ for ( i=0 ; i'+oSettings.aoColumns[i].sTitle+'';
+
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ var sWidth = '';
+ if ( oSettings.aoColumns[i].sWidth !== null )
+ {
+ sWidth = ' style="width:'+oSettings.aoColumns[i].sWidth+';"';
+ }
+
+ sCalcHtml += '
'+fnGetMaxLenString( oSettings, i)+'
';
+ }
+ else
+ {
+ sCalcHtml += '
'+fnGetMaxLenString( oSettings, i)+'
';
+ }
+ }
+ }
+
+ sCalcHead += "
";
+ sCalcHtml += "";
+
+ /* Create the tmp table node (thank you jQuery) */
+ nCalcTmp = $( sTableTmp + sCalcHead + sCalcHtml +'' )[0];
+ nCalcTmp.style.width = iTableWidth + "px";
+ nCalcTmp.style.visibility = "hidden";
+ nCalcTmp.style.position = "absolute"; /* Try to aviod scroll bar */
+
+ oSettings.nTable.parentNode.appendChild( nCalcTmp );
+
+ var oNodes = $("td", nCalcTmp);
+ var iIndex;
+
+ /* Gather in the browser calculated widths for the rows */
+ for ( i=0 ; i iMax )
+ {
+ iMax = oSettings.aoData[i]._aData[iCol].length;
+ iMaxIndex = i;
+ }
+ }
+
+ if ( iMaxIndex >= 0 )
+ {
+ return oSettings.aoData[iMaxIndex]._aData[iCol];
+ }
+ return '';
+ }
+
+ /*
+ * Function: _fnArrayCmp
+ * Purpose: Compare two arrays
+ * Returns: 0 if match, 1 if length is different, 2 if no match
+ * Inputs: array:aArray1 - first array
+ * array:aArray2 - second array
+ */
+ function _fnArrayCmp( aArray1, aArray2 )
+ {
+ if ( aArray1.length != aArray2.length )
+ {
+ return 1;
+ }
+
+ for ( var i=0 ; i'+
+ 't'+
+ '<"fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"ip>';
+ }
+ }
+
+ if ( typeof oInit.iDisplayStart != 'undefined' &&
+ typeof oSettings.iInitDisplayStart == 'undefined' ) {
+ /* Display start point, taking into account the save saving */
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
+ oSettings._iDisplayStart = oInit.iDisplayStart;
+ }
+
+ /* Must be done after everything which can be overridden by a cookie! */
+ if ( typeof oInit.bStateSave != 'undefined' )
+ {
+ oSettings.oFeatures.bStateSave = oInit.bStateSave;
+ _fnLoadState( oSettings, oInit );
+ }
+
+ if ( typeof oInit.aaData != 'undefined' ) {
+ bUsePassedData = true;
+ }
+
+ /* Backwards compatability */
+ /* aoColumns / aoData - remove at some point... */
+ if ( typeof oInit != 'undefined' && typeof oInit.aoData != 'undefined' )
+ {
+ oInit.aoColumns = oInit.aoData;
+ }
+
+ /* Language definitions */
+ if ( typeof oInit.oLanguage != 'undefined' )
+ {
+ if ( typeof oInit.oLanguage.sUrl != 'undefined' && oInit.oLanguage.sUrl !== "" )
+ {
+ /* Get the language definitions from a file */
+ oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
+ $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
+ _fnLanguageProcess( oSettings, json, true ); } );
+ bInitHandedOff = true;
+ }
+ else
+ {
+ _fnLanguageProcess( oSettings, oInit.oLanguage, false );
+ }
+ }
+ /* Warning: The _fnLanguageProcess function is async to the remainder of this function due
+ * to the XHR. We use _bInitialised in _fnLanguageProcess() to check this the processing
+ * below is complete. The reason for spliting it like this is optimisation - we can fire
+ * off the XHR (if needed) and then continue processing the data.
+ */
+ }
+
+ /* Add the strip classes now that we know which classes to apply - unless overruled */
+ if ( typeof oInit == 'undefined' || typeof oInit.asStripClasses == 'undefined' )
+ {
+ oSettings.asStripClasses.push( oSettings.oClasses.sStripOdd );
+ oSettings.asStripClasses.push( oSettings.oClasses.sStripEven );
+ }
+
+ /* See if we should load columns automatically or use defined ones - a bit messy this... */
+ var nThead = this.getElementsByTagName('thead');
+ var nThs = nThead.length===0 ? null : _fnGetUniqueThs( nThead[0] );
+ var bUseCols = typeof oInit != 'undefined' && typeof oInit.aoColumns != 'undefined';
+ for ( i=0, iLen=bUseCols ? oInit.aoColumns.length : nThs.length ; i 0) {
+ for (var i = 0; i < this._queued_queries.length; i++) {
+ if (this._queued_queries[i] != null && this._queued_queries[i][2] < p) {
+ this._queued_queries.splice(i, 0, [q, f, p]);
+ return;
+ }
+ }
+ }
+ this._queued_queries.push([q,f,p]);
+ };
+ this._markRunning = function(q) { this._active_queries++; };
+ this._markDone = function(q) {
+ this._active_queries--;
+ //document.getElementById('log').innerHTML+="query done. " + this._active_queries + " queries still active. ";
+ if (this._queued_queries[this._next_in_queue] != null && this._canRun()) {
+ var a = this._queued_queries[this._next_in_queue];
+ this._queued_queries[this._next_in_queue++] = null;
+ // a[0] is query object, a[1] is function to run query
+ //document.getElementById('log').innerHTML += "running query from Q ";
+ a[1]();
+ }
+ };
+
+ //---------------
+ // public methods
+
+ // use our varied transformations to create the various shortcut methods of actually
+ // issuing queries without explicitly creating a query object
+ for (var query_form in SPARQL._query_transformations) {
+ // need the extra function to properly scope query_form (qf)
+ this[query_form] = (function(qf) {
+ return function(queryString, callback) {
+ var q = this.createQuery();
+ q._doQuery(queryString, callback, SPARQL._query_transformations[qf]);
+ };
+ })(query_form);
+ }
+
+ //------------
+ // constructor
+
+ if (!_endpoint)
+ return null;
+
+ return this;
+}
+
+/**
+ * A SPARQL query object should be created using the createQuery method of a SPARQL
+ * service object. It allows prefixes and datasets to be defined specifically for
+ * a single query, and provides introspective methods to see the query string and the
+ * full (HTTP GET) URL of the query.
+ */
+SPARQL.Query = function(service, priority) {
+ //---------------
+ // private fields
+ var _conn = null;
+ var _service = service;
+ var _default_graphs = clone_obj(service.defaultGraphs()); // prevent future updates from affecting us
+ var _named_graphs = clone_obj(service.namedGraphs());
+ var _prefix_map = clone_obj(service.prefixes());
+ var _user_query = ''; // doesn't include auto-generated prefix declarations
+ var _method = service.method();
+ var _output = service.output();
+ var _priority = priority || 0;
+ var _request_headers = clone_obj(service.requestHeaders());
+
+ //------------------
+ // private functions
+ function _create_json(text) {
+ if (!text)
+ return null;
+ // make sure this is safe JSON
+ // see: http://www.ietf.org/internet-drafts/draft-crockford-jsonorg-json-03.txt
+
+ // (1) strip out quoted strings
+ var no_strings = text.replace(/"(\\.|[^"\\])*"/g, '');
+ // (2) make sure that all the characters are explicitly part of the JSON grammar
+ // (in particular, note as discussed in the IETF submission, there are no assignments
+ // or function invocations allowed by this reg. exp.)
+ var hasBadCharacter = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(no_strings);
+ // (3) evaluate the JSON string, returning its contents
+ if (!hasBadCharacter) {
+ try {
+ return eval('(' + text + ')');
+ } catch (e) {
+ return null;
+ }
+ }
+ return null;
+ }
+
+ function clone_obj(o) {
+ var o2 = o instanceof Array ? [] : {};
+ for(var x in o) {o2[x] = o[x];}
+ return o2;
+ }
+
+ //----------------
+ // private methods
+ this._doCallback = function(cb, which, arg) {
+ //document.getElementById('log').innerHTML += "_doCallback ... ";
+ var user_data = "argument" in cb ? cb.argument : null;
+ if (which in cb) {
+ if (cb.scope) {
+ cb[which].apply(cb.scope, [arg, user_data]);
+ } else {
+ cb[which](arg, user_data);
+ }
+ }
+ }
+
+ this._queryFailure = function(xhr, arg) {
+ SPARQL.statistics.failures++;
+ _service._markDone(this);
+ this._doCallback(arg.callback, 'failure', xhr /* just pass through the connection response object */);
+ };
+ this._querySuccess = function(xhr, arg) {
+ //alert(xhr.responseText);
+ SPARQL.statistics.successes++;
+ _service._markDone(this);
+ this._doCallback(arg.callback, 'success', arg.transformer(
+ _output == 'json' ? _create_json(xhr.responseText) : xhr.responseText
+ ));
+ };
+
+ function getXmlHttpRequest(url) {
+ // right now, this only does Firefox (Opera? Safari?)
+ return new XMLHttpRequest();
+ }
+
+ this._doQuery = function(queryString, callback, transformer) {
+ _user_query = queryString;
+ if (_service._canRun()) {
+ try {
+ if (_method != 'POST' && _method != 'GET')
+ throw("HTTP methods other than GET and POST are not supported.");
+
+ var url = _method == 'GET' ? this.queryUrl() : this.service().endpoint();
+ var xhr = getXmlHttpRequest(url);
+ var content = null;
+
+ try {
+ if (!document.domain || (url.match(/^https?:\/\//) && url.slice(7, document.domain.length + 7) != document.domain && window.netscape && netscape.security && netscape.security.PrivilegeManager)) {
+ netscape.security.PrivilegeManager.enablePrivilege( "UniversalBrowserRead");
+ netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect");
+ }
+ } catch(e) {
+ alert("Cross-site requests prohibited. You will only be able to SPARQL the origin site: " + e);
+ return;
+ }
+
+ xhr.open(_method, url, true /* async */);
+
+ // set the headers, including the content-type for POSTed queries
+ for (var header in this.requestHeaders())
+ if (typeof(this.requestHeaders()[header]) != "function")
+ xhr.setRequestHeader(header, this.requestHeaders()[header]);
+ if (_method == 'POST') {
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ content = this.queryParameters();
+ }
+
+ SPARQL.statistics.queries_sent++;
+ _service._markRunning(this);
+
+ var callbackData = {
+ scope:this,
+ success: this._querySuccess,
+ failure: this._queryFailure,
+ argument: {
+ transformer: transformer,
+ callback: callback
+ }
+ };
+
+ // I've seen some strange race-condition behavior (strange since normally
+ // JS is single-threaded, so synchronization conditions don't occur barring
+ // reentrancy) with onreadystatechange. Instead, we poll asynchronously to
+ // determine when the request is done.
+ var token = window.setInterval(
+ function () {
+ if (xhr.readyState == 4) { // ready!
+ // clear this handler
+ window.clearInterval(token);
+ // we check the status to know which callback to call
+ if (xhr.status >= 200 && xhr.status < 300)
+ callbackData.success.apply(callbackData.scope, [xhr, callbackData.argument]);
+ else
+ callbackData.failure.apply(callbackData.scope, [xhr, callbackData.argument]);
+ }
+ },
+ 200 /* maybe this should be customizable */
+ );
+
+ xhr.send(content);
+ } catch (e) {
+ alert("Error sending SPARQL query: " + e);
+ }
+ } else {
+ var self = this;
+ _service._queue(self, function() { self._doQuery(queryString, callback, transformer); }, _priority);
+ }
+ };
+
+
+ //----------
+ // accessors
+ this.request = function() { return _conn; };
+ this.service = function() { return _service; };
+ this.defaultGraphs = function() { return _default_graphs; };
+ this.namedGraphs = function() { return _named_graphs; };
+ this.prefixes = function() { return _prefix_map; };
+ this.method = function() { return _method; };
+ this.requestHeaders = function() { return _request_headers; };
+
+
+ /**
+ * Returns the SPARQL query represented by this object. The parameter, which can
+ * be omitted, determines whether or not auto-generated PREFIX clauses are included
+ * in the returned query string.
+ */
+ this.queryString = function(excludePrefixes) {
+ var preamble = '';
+ if (!excludePrefixes) {
+ for (var prefix in this.prefixes()) {
+ if(typeof(this.prefixes()[prefix]) != 'string') continue;
+ preamble += 'PREFIX ' + prefix + ': <' + this.prefixes()[prefix] + '> ';
+ }
+ }
+ return preamble + _user_query;
+ };
+
+ /**
+ * Returns the HTTP query parameters to invoke this query. This includes entries for
+ * all of the default graphs, the named graphs, the SPARQL query itself, and an
+ * output parameter to specify JSON (or other) output is desired.
+ */
+ this.queryParameters = function () {
+ var urlQueryString = '';
+ var i;
+
+ // add default and named graphs to the protocol invocation
+ for (i = 0; i < this.defaultGraphs().length; i++) urlQueryString += 'default-graph-uri=' + encodeURIComponent(this.defaultGraphs()[i]) + '&';
+ for (i = 0; i < this.namedGraphs().length; i++) urlQueryString += 'named-graph-uri=' + encodeURIComponent(this.namedGraphs()[i]) + '&';
+
+ // specify JSON output (currently output= supported by latest Joseki) (or other output)
+ urlQueryString += 'output=' + _output + '&soft-limit=-1&';
+ return urlQueryString + 'query=' + encodeURIComponent(this.queryString());
+ }
+
+ /**
+ * Returns the HTTP GET URL to invoke this query. (Note that this returns a full HTTP GET URL
+ * even if this query is set to actually use POST.)
+ */
+ this.queryUrl = function() {
+ var url = this.service().endpoint() + '?';
+ return url + this.queryParameters();
+ };
+
+ //---------
+ // mutators
+ function _add_graphs(toAdd, arr) {
+ if (toAdd instanceof Array)
+ for (var i = 0; i < toAdd.length; i++) arr.push(toAdd[i]);
+ else
+ arr.push(toAdd);
+ }
+ this.addDefaultGraph = function(g) { _add_graphs(g, this.defaultGraphs()); };
+ this.addNamedGraph = function(g) { _add_graphs(g, this.namedGraphs()); };
+ this.setPrefix = function(p, u) { this.prefixes()[p] = u; };
+ this.setMethod = function(m) {
+ if (m != 'GET' && m != 'POST') throw("HTTP methods other than GET and POST are not supported.");
+ _method = m;
+ };
+ this.setRequestHeader = function(h, v) { _request_headers[h] = v; };
+
+ //---------------
+ // public methods
+
+ // use our varied transformations to create the various methods of actually issuing
+ // queries
+ for (var query_form in SPARQL._query_transformations) {
+ // need the extra function to properly scope query_form (qf)
+ this[query_form] = (function(qf) {
+ return function(queryString, callback) {
+ this._doQuery(queryString, callback, SPARQL._query_transformations[qf]);
+ };
+ })(query_form);
+ }
+
+
+ //------------
+ // constructor
+
+ return this;
+}
+
+// Nothing to see here, yet.
+SPARQL.QueryUtilities = {
+};
+