mas01mj@640: /* mas01mj@640: * jOWL_UI, User Interface Elements for jOWL, semantic javascript library mas01mj@640: * Creator - David Decraene mas01mj@640: * Version 1.0 mas01mj@640: * Website: http://Ontologyonline.org mas01mj@640: * Licensed under the MIT license mas01mj@640: * Verified with JSLint http://www.jslint.com/ mas01mj@640: */ mas01mj@640: (function($){ mas01mj@640: mas01mj@640: jOWL.UI = { mas01mj@640: broadcaster : function(){ mas01mj@640: var listeners = []; mas01mj@640: this.addListener = function(obj){ mas01mj@640: function add(obj){if(obj.propertyChange) { listeners.push(obj); } } mas01mj@640: if(obj.constructor == Array){for(var i=0;i").addClass(options.contentClass).appendTo(this); } mas01mj@640: this.parents = $('
').appendTo(this.content); mas01mj@640: this.focus = $('
').addClass(options.focusClass).appendTo(this.content); mas01mj@640: this.children = $('
').appendTo(this.content); mas01mj@640: var listnode = $('').click(function(){ mas01mj@640: var node = $(this); mas01mj@640: var res = jOWL(node.attr('title')); mas01mj@640: if(options.onSelect.call(node, res) === false) { return; } mas01mj@640: if(res && res.isClass) { self.propertyChange.call(res, res); self.broadcast(res); } mas01mj@640: }); mas01mj@640: mas01mj@640: jOWL.UI.asBroadcaster(this); mas01mj@640: mas01mj@640: this.propertyChange = function(item){ mas01mj@640: if(options.onPropertyChange.call(this, item) === false) { return; } mas01mj@640: if(item.isClass){ mas01mj@640: item.bind(self.focus); mas01mj@640: if(jOWL.options.reason) { item.hierarchy();} mas01mj@640: self.parents.empty().append(item.parents().bind(listnode)); mas01mj@640: self.children.empty().append(item.children().bind(listnode)); mas01mj@640: } mas01mj@640: }; mas01mj@640: return this; mas01mj@640: }, mas01mj@640: /** mas01mj@640: autocomplete field. mas01mj@640: */ mas01mj@640: owl_autocomplete : function(options){ mas01mj@640: options = $.extend({ mas01mj@640: time:500, //responsetime to check for new keystrokes, default 500 mas01mj@640: chars:3, //number of characters needed before autocomplete starts searching mas01mj@640: focus:false, //put cursor on the input field when loading mas01mj@640: limit:10, //limit size of result list to given amount mas01mj@640: contentClass : "ui-widget-content", mas01mj@640: focusClass : jOWL.UI.defaults.focusClass, mas01mj@640: hintClass : "ui-autocomplete-hint", mas01mj@640: hint: false, //Message (if any) to show when unfocused. mas01mj@640: onSelect : function(item){}, //function that can be overridden mas01mj@640: formatListItem : function(listitem, type, identifier, termarray){ //formatting of results, can be overridden mas01mj@640: if(type){ listitem.append($('
').text(type)); } mas01mj@640: listitem.append($('
').text(identifier)); mas01mj@640: if(termarray.length) { listitem.append($('
').text(termarray.join(', ')) mas01mj@640: .prepend($('').addClass('termlabel').text("Terms: "))); mas01mj@640: } mas01mj@640: }}, options); mas01mj@640: jOWL.UI.asBroadcaster(this); mas01mj@640: mas01mj@640: this.showHint = function(){ mas01mj@640: this.hinted = true; mas01mj@640: if(options.hint){ mas01mj@640: this.addClass(options.hintClass).val(options.hint); mas01mj@640: } mas01mj@640: else {this.val(''); } mas01mj@640: }; mas01mj@640: this.showHint(); mas01mj@640: mas01mj@640: var self = this; var old = ''; var open = false; self.val(''); mas01mj@640: var results = $('
    ').addClass(options.contentClass).addClass("jowl_autocomplete_results"); mas01mj@640: var div = $("
    ").addClass(options.wrapperClass).append(results); this.after(div); mas01mj@640: results.cache = {}; mas01mj@640: results.isEmpty = function(){ for(x in results.cache) { return false; } return true; }; mas01mj@640: results.close = function(){this.hide();}; mas01mj@640: results.open = function(q, cache){ mas01mj@640: this.show(); mas01mj@640: if(q){ mas01mj@640: if(!cache || results.isEmpty()) { results.cache = jOWL.query(q, options); } mas01mj@640: else { mas01mj@640: var newcache = {}; mas01mj@640: for(x in results.cache){ mas01mj@640: var entry = results.cache[x]; mas01mj@640: var found = false; mas01mj@640: var newentries = []; mas01mj@640: if(x.searchMatch(q) > -1) { found = true; } mas01mj@640: for(var i = 0;i -1) { found = true; newentries.push(entry[i]); } mas01mj@640: } mas01mj@640: if(found) { newcache[x] = newentries; } mas01mj@640: } mas01mj@640: results.cache = newcache; mas01mj@640: } mas01mj@640: this.populate(results.cache); mas01mj@640: } mas01mj@640: }; mas01mj@640: mas01mj@640: results.populate = function(data){ mas01mj@640: var res = this; this.empty(); var count =0; mas01mj@640: var clickFunction = function(){ mas01mj@640: var node = $(this), res = jOWL(node.data("jowltype")); mas01mj@640: if(options.onSelect.call(node, res) === false) { return; } mas01mj@640: self.broadcast(res); mas01mj@640: }; mas01mj@640: mas01mj@640: var onHover = function(){ $(this).addClass(options.focusClass); }; mas01mj@640: var offHover = function(){$(this).removeClass(options.focusClass);}; mas01mj@640: mas01mj@640: for(x in data){ mas01mj@640: if(count < options.limit){ mas01mj@640: var item = data[x]; mas01mj@640: var v = jOWL.isExternal(x); mas01mj@640: v = v ? v[1] : x; mas01mj@640: var list = $('
  • ').data("jowltype", x) mas01mj@640: .click(clickFunction).hover(onHover, offHover) mas01mj@640: .appendTo(res); mas01mj@640: var terms = []; mas01mj@640: for(var l = 0;l old.length && newvalue.indexOf(old) === 0; mas01mj@640: if(!old) { cache = false; } mas01mj@640: old = newvalue; mas01mj@640: if(newvalue.length < options.chars && open){ results.close();open = false;} mas01mj@640: else if(newvalue.length >=options.chars && newvalue.length > 0){ mas01mj@640: if(cache) { cache = longervalue && newvalue.length > options.chars; } mas01mj@640: results.open(newvalue, cache); mas01mj@640: open = true; mas01mj@640: } mas01mj@640: mas01mj@640: } mas01mj@640: }, options.time); mas01mj@640: mas01mj@640: self.bind('keyup', function(){ if(!this.value.length){ results.close(); open = false; } }); mas01mj@640: self.bind('blur', function(){ mas01mj@640: if(open){setTimeout(function(){results.close();}, 200);open = false;} mas01mj@640: if(!self.val().length){self.showHint();} mas01mj@640: }); mas01mj@640: //timeout for registering clicks on results. mas01mj@640: self.bind('focus', function(){ mas01mj@640: if(self.hinted){ mas01mj@640: self.hinted = false; mas01mj@640: $(this).removeClass(options.hintClass).val(''); mas01mj@640: } mas01mj@640: if(self.val().length && !open){results.open('', open);open = true;}}); mas01mj@640: //reopen, but do not get results mas01mj@640: return this; mas01mj@640: }, mas01mj@640: /** mas01mj@640: Tree View mas01mj@640: */ mas01mj@640: owl_treeview : function(options){ mas01mj@640: options = $.extend({ mas01mj@640: contentClass : jOWL.UI.defaults.contentClass, mas01mj@640: focusClass: "focus", mas01mj@640: nameClass: "name", mas01mj@640: treeClass: "jowl-treeview", mas01mj@640: rootClass: "root", mas01mj@640: onSelect : function(item){}, //function that can be overwritten to specfy behavior when something is selected mas01mj@640: rootThing : false, //if true then topnode is (owl) 'Thing' mas01mj@640: isStatic : false, // if static then selections will refresh the entire tree mas01mj@640: addChildren : false //add a given objects children to the treeview as well mas01mj@640: }, options); mas01mj@640: mas01mj@640: /** construct the hierarchy & make a tree of it */ mas01mj@640: function TreeModel(owlobject){ mas01mj@640: mas01mj@640: function clear(el){ //reset invParents, for later use. mas01mj@640: if(el.parents) { el.parents().each(function(){ mas01mj@640: this.invParents = null; clear(this); mas01mj@640: }); } mas01mj@640: } mas01mj@640: mas01mj@640: function leaf(node){ mas01mj@640: node.jnode.addClass(options.focusClass); mas01mj@640: if(options.addChildren){ mas01mj@640: var entry = jOWL(node.$name.attr('title')); mas01mj@640: if(entry && entry.children){ entry.children().each(function(){ node.add(this); }); } } mas01mj@640: } mas01mj@640: mas01mj@640: function traverse(itemarray, appendto){ mas01mj@640: if(!itemarray) { return; } mas01mj@640: itemarray.each(function(){ mas01mj@640: var node = appendto.add(this); mas01mj@640: if(this.invParents){ traverse(this.invParents, node); } mas01mj@640: else { leaf(node); } mas01mj@640: }); mas01mj@640: mas01mj@640: } mas01mj@640: mas01mj@640: var h = owlobject.hierarchy(true); mas01mj@640: if(options.rootThing) { traverse(h, tree.root(jOWL("Thing"))); } mas01mj@640: else { mas01mj@640: var root = tree.root(h); mas01mj@640: for(var i=0;i').addClass(options.treeClass).appendTo(node); mas01mj@640: var tree = this; mas01mj@640: /**item can be text, a jOWL object, or a jOWL array */ mas01mj@640: this.root = function(item){ mas01mj@640: var rt = null; //root mas01mj@640: rack.empty(); mas01mj@640: if(item && item.each) { mas01mj@640: rt = []; mas01mj@640: item.each(function(it){ mas01mj@640: var x = new fn.node(it, true); mas01mj@640: x.wrapper.addClass("tv"); mas01mj@640: x.jnode.appendTo(rack); mas01mj@640: x.invParents = it.invParents; it.invParents = null; //reset for later use mas01mj@640: rt.push(x); mas01mj@640: }); mas01mj@640: return rt; mas01mj@640: } mas01mj@640: rt = new fn.node(item, true); mas01mj@640: rt.wrapper.addClass("tv"); mas01mj@640: rt.jnode.appendTo(rack); mas01mj@640: return rt; mas01mj@640: }; mas01mj@640: mas01mj@640: var fn = {}; mas01mj@640: fn.node = function(text, isRoot){ //creates a new node mas01mj@640: this.jnode = isRoot ? $('
  • ').addClass(options.rootClass) : $('
  • '); mas01mj@640: this.$name = null; mas01mj@640: if(text){ mas01mj@640: this.$name = $('').addClass(options.nameClass); mas01mj@640: if(typeof text == "string") { this.$name.html(text); } mas01mj@640: else if(text.bind) { text.bind(this.$name); } mas01mj@640: var n = this.$name; mas01mj@640: this.$name.appendTo(this.jnode).click(function(){ mas01mj@640: var entry = jOWL(n.attr('title')); mas01mj@640: if(entry && options.onSelect.call(n, entry) === false) { return; } mas01mj@640: tree.broadcast(entry); mas01mj@640: if(options.isStatic) { tree.propertyChange(entry); } mas01mj@640: return false;}); mas01mj@640: } mas01mj@640: mas01mj@640: this.wrapper = $('
      ').appendTo(this.jnode); mas01mj@640: var self = this; mas01mj@640: self.jnode.click(function(){toggle(); return false;}); mas01mj@640: mas01mj@640: this.add = function(text){ mas01mj@640: var nn = new fn.node(text); mas01mj@640: if(!self.wrapper.children().length) { toNode(); } mas01mj@640: else { mas01mj@640: var lastchild = self.wrapper.children(':last'); mas01mj@640: lastchild.swapClass("tvilc", "tvic"); mas01mj@640: lastchild.swapClass("tvile", "tvie"); mas01mj@640: lastchild.swapClass("tvil", "tvi"); mas01mj@640: mas01mj@640: }//children - change end of list mas01mj@640: self.wrapper.append(nn.jnode.swapClass('tvi', 'tvil')); mas01mj@640: return nn; mas01mj@640: }; mas01mj@640: mas01mj@640: function toggle(){ mas01mj@640: var t = self.jnode.hasClass("tvic") || self.jnode.hasClass("tvie") || self.jnode.hasClass("tvilc") || self.jnode.hasClass("tvile"); mas01mj@640: if(!t) { return; } mas01mj@640: self.jnode.swapClass('tvic', 'tvie'); self.jnode.swapClass('tvilc', 'tvile'); mas01mj@640: self.wrapper.slideToggle(); mas01mj@640: } mas01mj@640: mas01mj@640: function toNode(){ mas01mj@640: self.jnode.swapClass('tvil', 'tvilc'); mas01mj@640: self.jnode.swapClass('tvi', 'tvic'); mas01mj@640: } mas01mj@640: }; mas01mj@640: return this; mas01mj@640: }// end Tree mas01mj@640: mas01mj@640: this.addClass("jowl-tree"); mas01mj@640: this.content = $("."+options.contentClass, this).empty(); mas01mj@640: if(!this.content.length){ this.content = $('
      ').addClass(options.contentClass).appendTo(this); } mas01mj@640: var tree = new Tree(this.content, null, options); mas01mj@640: jOWL.UI.asBroadcaster(tree); mas01mj@640: tree.propertyChange = function(item){ if(item.isClass) { var m = new TreeModel(item); } }; mas01mj@640: return tree; mas01mj@640: }, mas01mj@640: /** Uses templating mas01mj@640: options: mas01mj@640: onChange: owl:Class, owl:Thing, etc..., tell the widget what to do with the different kinds of Ontology Objects. mas01mj@640: "data-jowl" : {split: ", ", "somevariable" : function_triggered_for_each_result } mas01mj@640: example: "rdfs:label" : {split: ", ", "rdfs:label" : function(){ //'this' keyword refers to HTML element}} ) mas01mj@640: example: "sparql-dl:PropertyValue(owl:Class, ?p, ?x)" : {"?p": function(){ //'this' keyword refers to HTML element }} mas01mj@640: //prefil: for sparql-dl queries mas01mj@640: //onComplete: function to trigger when the specific propertybox query is completed, this refers to the HTML element for propertybox mas01mj@640: //sort: sort results on specified parameter, for sparql-dl results. mas01mj@640: onUpdate: called when the widget updates itself mas01mj@640: */ mas01mj@640: owl_propertyLens : function(options){ mas01mj@640: var self = this; mas01mj@640: self.options = $.extend({ mas01mj@640: backlinkClass : "backlink", mas01mj@640: split: {}, mas01mj@640: disable : {}, mas01mj@640: click : {}}, mas01mj@640: options); mas01mj@640: self.resourcetype = this.attr('data-jowl') || "owl:Class"; mas01mj@640: var propertyboxes = []; mas01mj@640: $('.propertybox', this).each(function(){ mas01mj@640: var node = new jOWL.UI.PropertyBox($(this), self); mas01mj@640: propertyboxes.push(node); mas01mj@640: node.el.hide(); mas01mj@640: }); mas01mj@640: var backlink = $('.backlink', this).hide(); mas01mj@640: if(!backlink.length) { backlink = $('