1 /** 2 * @fileOverview Semantic Web Widget Library 3 * @author <a href="mailto:jambo@mit.edu">Jim Hollenbach</a> 4 * @license MIT License 5 * @license GPL v2 6 */ 7 8 /** 9 * @exports $ as jQuery 10 */ 11 12 /** 13 * @name jQuery 14 * @namespace The jQuery Javascript toolkit. 15 */ 16 17 /** 18 * @name jQuery.rdfwidgets 19 * @namespace Library functions for the widget library. 20 */ 21 jQuery.rdfwidgets = function($) { 22 23 var CONVERT_BASE = "http://feelings.xvm.mit.edu/" 24 25 var langs = { 26 "en": true, 27 "en-US":true 28 }; 29 30 var widgets = {}; 31 var matchers = []; 32 var loadFilters = []; 33 var pendingSources = []; 34 /** 35 * @description Define a new widget for use in the library. 36 * @param {String} name the namespaced name of the widget, eg. ui.mywidgetname 37 * @param {Object} prototype the prototype class of the new widget. 38 */ 39 $.rdfwidget = function( name, prototype ) { 40 var namespace = name.split( "." )[ 0 ], fullName; 41 var sname = name.split( "." )[ 1 ]; 42 fullName = namespace + "-" + sname; 43 widgets[fullName] = {s:(':'+fullName),n:sname}; 44 45 var w = $.extend({}, $.RdfWidget.prototype, prototype); 46 $.widget(name,w); 47 }; 48 49 /** 50 * @class 51 * @description The base class for all SW Widgets. 52 */ 53 $.RdfWidget = function(options, element) { 54 55 56 }; 57 58 59 $.RdfWidget.prototype = { 60 61 /** 62 * @description Get a valid term given a string input by the user, according to the options the user provided to the widget such as prefixes. 63 * @param {String | Object} term The string or Term object provided by the user. 64 * @returns {Object} A Literal or Symbol that matches the term supplied by the user. 65 */ 66 _resource: function( term ) { 67 return processResource( term, this.options ); 68 }, 69 70 /** 71 * @description A function that is called whenever new data is loaded into the local store. 72 * @param {Array} trips The new $rdf.Triples that were added to the store. 73 */ 74 insertData: function( trips ) { 75 if( !this.options.ignoreupdates ) { 76 this.refresh(); 77 } 78 }, 79 80 /** 81 * @description Redraw the widget. 82 */ 83 refresh: function() {}, 84 85 /** 86 * @description A function that is called whenever new data is removed from the local store. 87 * @param {Array} trips The new $rdf.Triples that were removed from the store. 88 */ 89 deleteData: function( trips ) { 90 if( !this.options.ignoreupdates ) { 91 this.refresh(); 92 } 93 }, 94 95 /** 96 * @description Get a Matcher for the provided element. 97 * @param {String | Object} [element=this.element] The element to draw into. Can be any valid argument to a jQuery constructor. 98 * @param {Boolean} [norefresh=false] If true, this matcher will not refresh when new data is loaded. 99 */ 100 _matcher: function( element, norefresh ) { 101 return Matcher( (element ? element : this.element) , this.options, norefresh ); 102 } 103 }; 104 105 /** 106 * @class 107 * @description a class for matching items. 108 */ 109 var Matcher = function( element, opts, norefresh ) { 110 var bindings = [{}]; // {"varname":somesymbol, "varname2":someliteral} 111 var elt = $(element); 112 var filters = processSourceFilter( opts.sources, opts ); 113 var history = []; 114 var cstring = ""; 115 var wstring = ""; 116 function processVar( s ) { 117 if( (typeof s) === "string" ) { 118 if( s.length > 0 && s.charAt(0) == "?" ) { 119 if( s.length > 1 ) { 120 return s.substring(1); 121 } 122 throw "invalid variable name: "+str; 123 } 124 } 125 return null; 126 } 127 var m = /** @lends jQuery.rdfwidgets-Matcher.prototype */{ 128 /** 129 * @description foobarbaz 130 */ 131 match: function( s,p,o,optional ) { 132 var s_v = processVar( s ); 133 var p_v = processVar( p ); 134 var o_v = processVar( o ); 135 136 var newBindings = []; 137 var matches; 138 for( var i=0; i < bindings.length; i++ ) { 139 var b = bindings[i] 140 matches = $.rdfwidgets.statementsMatching( s_v ? (b[s_v] ? b[s_v] : undefined) : processResource( s, opts ), 141 p_v ? (b[p_v] ? b[p_v] : undefined) : processResource( p, opts ), 142 o_v ? (b[o_v] ? b[o_v] : undefined) : processObject( o, opts ), 143 undefined, false, opts ); 144 if( opts.filterduplicates ) { 145 matches = filterDuplicates( matches ); 146 } 147 if( (!matches || (matches && matches.length === 0)) && optional ) { 148 var newvals = {}; 149 if( s_v && !b[s_v] ) { newvals[s_v] = null } 150 if( p_v && !b[p_v] ) { newvals[p_v] = null } 151 if( o_v && !b[o_v] ) { newvals[o_v] = null } 152 newBindings.push( $.extend( {}, b, newvals ) ); 153 } else { 154 for( var j=0; j < matches.length; j++ ) { 155 //use extend.. 156 var newvals = {}; 157 if( s_v && !b[s_v] ) { newvals[s_v] = matches[j].subject; } 158 if( p_v && !b[p_v] ) { newvals[p_v] = matches[j].predicate; } 159 if( o_v && !b[o_v] ) { newvals[o_v] = matches[j].object; } 160 newBindings.push( $.extend( {}, b, newvals ) ); 161 } 162 } 163 } 164 bindings = newBindings; 165 166 //build up query string.. 167 var pat = "" 168 if( optional ) { 169 pat += " optional { "; 170 } 171 if( s_v ) { 172 pat += " " + s + " "; 173 } else { pat += " " + processResource( s, opts ).toNT() + " "; 174 } 175 if( p_v ) { 176 pat += " " + p + " "; 177 } else { pat += " " + processResource( p, opts ).toNT() + " "; 178 } 179 if( o_v ) { 180 pat += " " + o + " . "; 181 } else { 182 pat += " " + processObject( o, opts ).toNT() + " . "; 183 } 184 if( optional ) { 185 pat += " } "; 186 } 187 if( !optional ) { 188 cstring += pat; 189 } 190 wstring += pat; 191 history.push({f:this.match, args:[s,p,o,optional]}); 192 return this; 193 }, 194 195 optional: function( s,p,o ) { 196 return this.match( s,p,o,true ); 197 }, 198 199 filter: function( f ) { 200 bindings = $.grep( bindings, f ); 201 history.push({f:this.filter, args:[f]}); 202 return this; 203 }, 204 205 draw: function( template, element, justOne ) { 206 var target = element ? $(element) : elt; 207 var output = ""; 208 var temp; 209 for( var i = 0; i < bindings.length && (!justOne || (justOne && i < 1 ) ); i++ ) { 210 temp = template; 211 for( x in bindings[i] ) { 212 temp = temp.replace( new RegExp("\\?"+x,"g"), (bindings[i][x] ? bindings[i][x].value : "None" )); 213 temp = temp.replace( new RegExp("\\@"+x,"g"), (bindings[i][x] ? doLabel( bindings[i][x] , opts ) : "None" )); 214 } 215 output += temp; 216 } 217 target.html( output ); 218 processHTMLWidgets( target ); 219 history.push({f:this.draw, args:[template, element, justOne]}); 220 return this; 221 }, 222 223 page: function( template, perPage, element ) { 224 //split bindings into ceil(bindings.length/perPage) pages. 225 if( !perPage ) { perPage = 10 } 226 //draw the first page, put listeners. 227 var target = element ? $(element) : elt; 228 var currentPage = 0; 229 var area = $('<div class="rdfpagearea"></div>'); 230 var page = $('<div class="rdfpage"></div>'); 231 var left = $('<div style="float:left"><a href="#">< Previous</a></div>'); 232 var center = $('<div style="clear:both"> </div>'); 233 var right = $('<div style="float:right"><a href="#">Next ></a></div>'); 234 235 left.click( function( e ) { 236 e.preventDefault(); 237 if( currentPage > 0 ) { 238 currentPage--; 239 drawPage( currentPage ); 240 } 241 }); 242 243 right.click( function( e ) { 244 e.preventDefault(); 245 if( (currentPage+1)*perPage < bindings.length ) { 246 currentPage++; 247 drawPage( currentPage ); 248 } 249 }); 250 251 area.append( page ); 252 area.append( left ); 253 area.append( right ); 254 area.append( center ); 255 var drawPage = function( pnumber ) { 256 257 if( pnumber === 0 ) { 258 left.hide(); 259 right.show(); 260 } else if ( (pnumber+1)*perPage >= bindings.length ) { 261 left.show(); 262 right.hide(); 263 } else { 264 left.show(); 265 right.show(); 266 } 267 268 var output = ""; 269 for( var i = pnumber * perPage; ( i < (pnumber+1)*perPage && (i < bindings.length) ); i++ ) { 270 temp = template; 271 for( x in bindings[i] ) { 272 temp = temp.replace( new RegExp("\\?"+x,"g"), (bindings[i][x] ? bindings[i][x].value : "None" )); 273 temp = temp.replace( new RegExp("\\@"+x,"g"), (bindings[i][x] ? doLabel( bindings[i][x] , opts ) : "None" )); 274 } 275 output += temp; 276 } 277 page.html( output ); 278 processHTMLWidgets( target ); 279 } 280 drawPage( currentPage ); 281 target.empty().append(area); 282 history.push({f:this.page, args:[template, perPage, element]}); 283 return this; 284 }, 285 286 replay: function() { 287 bindings = [{}]; 288 cstring = ""; 289 wstring = ""; 290 var len = history.length; 291 for( var i = 0; i < len; i++ ) { 292 history[i].f.apply( this, history[i].args ); 293 } 294 if( len > 0 ) { 295 history = history.slice( len ); 296 } 297 }, 298 299 reset: function() { 300 elt.empty(); 301 bindings = [{}]; 302 history = []; 303 cstring = ""; 304 wstring = ""; 305 return this; 306 }, 307 308 query: function( uri ) { 309 var q = "construct { " + cstring + " } where { "+ wstring +" }"; 310 q = escape( q ); 311 var u; 312 if( uri.indexOf( "?" ) !== -1 ) { 313 u = uri + "&query="+q; 314 } else { 315 u = uri + "?query="+q; 316 } 317 $.rdfwidgets.load( u ); 318 }, 319 320 bindings: function() { 321 return $.extend( true, [], bindings ); 322 } 323 }; 324 if( !norefresh ) { 325 matchers.push( m ); 326 } 327 return m; 328 }; 329 330 function allSubClasses( uri, o ) { 331 var s = processResource( uri, o ); 332 var c = {uri : s} 333 var q = [ s ]; 334 while( q.length > 0 ) { 335 var more = $.rdfwidgets.each( undefined, db.sym("http://www.w3.org/2000/01/rdf-schema#subClassOf"), q[0] ); 336 for( var i = 0; i < more.length; i++ ) { 337 if( !c[more[i].uri] ) { 338 c[more[i].uri] = more[i]; 339 q.push( more[i] ); 340 } 341 } 342 q = q.slice(1); 343 } 344 return c; 345 } 346 347 function allSubProperties( uri, o ) { 348 var s = processResource( uri, o ); 349 var c = {uri : s} 350 var q = [ s ]; 351 while( q.length > 0 ) { 352 var more = $.rdfwidgets.each( undefined, db.sym("http://www.w3.org/2000/01/rdf-schema#subPropertyOf"), q[0] ); 353 for( var i = 0; i < more.length; i++ ) { 354 if( !c[more[i].uri] ) { 355 c[more[i].uri] = more[i]; 356 q.push( more[i] ); 357 } 358 } 359 q = q.slice(1); 360 } 361 return c; 362 } 363 364 function filterDuplicates( trips ) { 365 var result = []; 366 var used = {}; 367 for( var i = 0; i < trips.length; i++ ) { 368 var hash = db.canon(trips[i].subject).toNT()+db.canon(trips[i].predicate).toNT()+(trips[i].object.termType==="literal" ? trips[i].object.value : db.canon(trips[i].object).toNT() ); 369 if( !used[hash] ) { 370 result.push( trips[i] ); 371 } 372 used[hash] = true; 373 } 374 return result; 375 } 376 377 function deleteData( trips ) { 378 labelCache = {}; 379 imageCache = {}; 380 var w; 381 for( x in widgets ) { 382 w = widgets[x]; 383 //w holds two fields: 384 //w.s, a jquery selector for the widget, eg ":ui-rdflabel" 385 //w.n, the name of the widget, eg "rdflabel" 386 $(w.s)[w.n]("deleteData", trips); 387 } 388 for( var i = 0; i < matchers.length; i++ ) { 389 matchers[i].replay(); 390 } 391 } 392 393 function insertData( trips ) { 394 labelCache = {}; 395 imageCache = {}; 396 var w; 397 for( x in widgets ) { 398 w = widgets[x]; 399 //the following line is explained in deleteData, above. 400 $(w.s)[w.n]("insertData", trips); 401 } 402 for( var i = 0; i < matchers.length; i++ ) { 403 matchers[i].replay(); 404 } 405 } 406 407 var uriRegex = /^(https?):\/\/((?:[a-z0-9.-]|%[0-9A-F]{2}){3,})(?::(\d+))?((?:\/(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})*)*)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*))?$/i; 408 //var uriRegex = /^(([a-z][\-a-z0-9+\.]*):)?(\/\/([^\/?#]+))?([^?#]*)?(\?([^#]*))?(#(.*))?$/i; 409 410 function validURI( str ) { 411 m = str.match(uriRegex); 412 if( m === null ) { 413 return false; 414 } 415 return true; 416 } 417 418 var docpart = $rdf.Util.uri.docpart 419 var join = $rdf.Util.uri.join 420 421 function randomID() { 422 return "rdfwidget"+Math.floor(Math.random()*100000000).toString(); 423 } 424 425 var SW_PREFIX = "http://dig.csail.mit.edu/2009/swjs#"; 426 427 var db = new $rdf.IndexedFormula(); 428 429 var requestedURIs = {}; 430 var endpoints = {}; 431 var selectedElement = null; 432 var labelCache = {}; 433 var defaultEndpoint = window.location; 434 var defaultUser = null; 435 var defaultFriend = null; 436 var sourceNames = {}; 437 var loadedSources = {}; 438 function finishLoads() { 439 $.each( db.statementsMatching( undefined, db.sym( SW_PREFIX+"data" ), undefined ), function() { 440 if( !requestedURIs[this.object.uri] ) { 441 loadDataSource( this.object.uri, undefined, finishLoads ); 442 } 443 }); 444 } 445 446 function doneLoading( uri ) { 447 pendingSources = $.grep(pendingSources, function( element ) { 448 return element !== uri; 449 }); 450 if( pendingSources.length === 0 ) { 451 $(document).trigger('rdfloaded'); 452 } 453 } 454 455 function loadDataSource( uri, t, callback, originalURI ) { 456 if( uri && !originalURI ) { 457 pendingSources.push(docpart( uri ) ); 458 } 459 var refresh = false; 460 var decrement = false; 461 if( (originalURI && requestedURIs[originalURI]) || (!originalURI && requestedURIs[docpart( uri )]) ) { 462 refresh = true; 463 } 464 465 if(originalURI && originalURI.indexOf('https') === 0 ) { 466 doneLoading( docpart( originalURI ) ); 467 return; 468 } 469 var format = (t === "application/json" ? "json" : 470 (t === "application/jsonp" ? "jsonp" : 471 (t === "application/rdf+xml" ? "xml" : 472 ((t === "text/n3" || t === "text/rdf+n3") ? "text" : 473 "text") ) ) ); 474 try { 475 requestedURIs[docpart( uri )] = true; 476 if( originalURI ) { requestedURIs[docpart( originalURI )] = true; } 477 $.ajax({ 478 url: uri, 479 beforeSend: function( xhr ) { 480 if( xhr.withCredentials !== undefined ) { 481 xhr.withCredentials = true; 482 } 483 }, 484 timeout:5000, 485 success: function( data, text, xhr ) { 486 var contenttype = t; 487 if( xhr ) { 488 contenttype = xhr.getResponseHeader("Content-Type").split(";")[0]; 489 if( !contenttype ) { 490 contenttype = t; 491 } 492 format = (contenttype === "application/json" ? "json" : 493 (contenttype === "application/jsonp" ? "jsonp" : 494 (contenttype === "application/rdf+xml" ? "xml" : 495 ((contenttype === "text/n3" || contenttype === "text/rdf+n3") ? "text" : 496 null) ) ) ); 497 } 498 if( xhr && xhr.status >= 400 || ( !xhr && format !== "jsonp" ) ) { 499 doneLoading( originalURI ? docpart( originalURI ) : docpart( uri ) ); 500 return; 501 } 502 if( (xhr && xhr.status === 0) || !format || ( !text && !originalURI ) || (!contenttype && !originalURI ) ) { 503 var converturi = CONVERT_BASE+"?data-uri[]="+escape(uri)+"&input=&output=jsonp"; 504 loadDataSource(converturi, "application/jsonp", callback, uri); 505 return; 506 } 507 var source = originalURI ? originalURI : uri; 508 if( refresh ) { 509 db.removeMany( undefined, undefined, undefined, db.sym( source ) ); 510 } 511 var triples = []; 512 if( format === "json" || format === "jsonp" ) { 513 var parser = $rdf.jsonParser; 514 triples = parser.parseJSON( data, source, db ); 515 if( originalURI ) { 516 loadedSources[originalURI] = originalURI; 517 } else { 518 loadedSources[uri] = uri; 519 } 520 if( !decrement ) { decrement = true; if( callback ) { callback(source, true); } } 521 } else if ( format === "xml" ) { 522 var p = new $rdf.RDFParser( db ); 523 triples = p.parse( xhr.responseXML, source, source ); 524 if( originalURI ) { 525 loadedSources[originalURI] = originalURI; 526 } else { 527 loadedSources[uri] = uri; 528 } 529 if( !decrement ) { decrement = true; if( callback ) { callback(source, true); } } 530 } else if ( format === "text" ) { 531 var u = originalURI ? originalURI : uri; 532 var p = new $rdf.N3Parser(db,db,u,u,null,null,"",null); 533 p.loadBuf( xhr.responseText ); 534 loadedSources[u] = u; 535 } 536 doneLoading( originalURI ? docpart( originalURI ) : docpart( uri ) ); 537 insertData( triples ); 538 }, 539 error: function(xhr) { 540 requestedURIs[docpart( uri )] = false; 541 if( !originalURI ) { 542 var converturi = CONVERT_BASE+"?data-uri[]="+escape(uri)+"&input=&output=jsonp"; 543 loadDataSource(converturi, "application/jsonp", callback, uri); 544 } else { 545 if( callback ) { callback( originalURI, false ); } 546 doneLoading( docpart( originalURI ) ); 547 } 548 }, 549 dataType: format 550 }); 551 } catch(e) { 552 /* if (jQuery.browser.msie && window.XDomainRequest && !originalURI && uri.indexOf('https://') === 0 && "xml" === format ) { 553 // Use Microsoft XDR 554 var xdr = new XDomainRequest(); 555 xdr.open("get", uri); 556 xdr.onload = function() { 557 var source = originalURI ? originalURI : uri; 558 var p = new $rdf.RDFParser( db ); 559 var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 560 xmlDoc.async="false"; 561 xmlDoc.loadXML(this.responseText); 562 triples = p.parse( xmlDoc, source, source ); 563 if( originalURI ) { 564 loadedSources[originalURI] = originalURI; 565 } else { 566 loadedSources[uri] = uri; 567 } 568 return; 569 }; 570 xdr.send(); 571 return; 572 } */ 573 if( !decrement ) { decrement = true; } 574 if( !originalURI ) { 575 requestedURIs[docpart( uri )] = false; 576 var converturi = CONVERT_BASE+"?data-uri[]="+escape(uri)+"&input=&output=jsonp"; 577 loadDataSource(converturi, "application/jsonp", callback, uri); 578 } else { 579 callback( originalURI, false ); 580 doneLoading( docpart( originalURI ) ); 581 } 582 } 583 } 584 585 function loadDataSources() { 586 $('link').each( function() { 587 if(this.href && "sw:data" === this.getAttribute("rel") ) { 588 var uri = docpart( this.href ); 589 var name = this.getAttribute("name"); 590 if( name ) { sourceNames[name] = uri; } 591 var endpoint = this.getAttribute("sw:endpoint"); 592 endpoints[uri] = endpoint; 593 loadDataSource( uri, this.getAttribute("type"), finishLoads ); 594 } else if( this.href && "sw:endpoint" === this.getAttribute("rel") ) { 595 var name = this.getAttribute("name"); 596 if( name ) { sourceNames[name] = uri; } 597 defaultEndpoint = docpart( this.href ); 598 } else if( this.href && "sw:user" === this.getAttribute("rel") ) { 599 defaultUser = this.href; 600 } 601 }); 602 return true; 603 } 604 605 //==================================== 606 // Widgets. 607 //==================================== 608 609 var namespaces = {'foaf':'http://xmlns.com/foaf/0.1/', 610 'sioc':'http://rdfs.org/sioc/ns#', 611 'dc' :'http://purl.org/dc/terms/', 612 'rdf' :'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 613 'rdfs':'http://www.w3.org/2000/01/rdf-schema#', 614 '' :window.location}; 615 616 function processResource( v, o ) { 617 if( v === null || v === undefined ) { return null; } 618 if( typeof( v ) === "object" && v.termType ) { 619 return v; 620 } 621 if( typeof( v ) === "string" && v.indexOf( '<' ) === 0 && v.lastIndexOf( '<' ) === 0 && v.indexOf( '>' ) === (v.length-1) ) { 622 return db.sym( v.substr( 1, v.length-2 ) ); 623 } 624 var index = v.indexOf( ':' ); 625 if( index !== -1 && v.indexOf( "://" ) !== index ) { 626 var pfx = v.substr( 0, index ); 627 var base = o.namespaces ? ( (o.namespaces[pfx] !== undefined) ? o.namespaces[pfx] : namespaces[pfx] ) : namespaces[pfx]; 628 if( base ) { 629 return db.sym( base + v.substr(index+1) ); 630 } 631 } 632 var sym = db.sym(v); 633 return sym; 634 } 635 636 function processSourceFilter( f, o ) { 637 if( !f ) { return null; } 638 var r = {}; 639 for( var i = 0; i < f.length; i++ ) { 640 var n = sourceNames[f[i]]; 641 r[ ( n ? n : processResource( f[i], o ).uri ) ] = true; 642 } 643 return r; 644 } 645 646 function processLiteral( v, o ) { 647 if( v === null || v === undefined ) { return null; } 648 if( typeof( v ) === "object" && "literal" === v.termType) { 649 return v; 650 } 651 var lit = db.literal( v ); 652 return lit; 653 } 654 655 function processObject( v, o ) { 656 if( v === null || v === undefined ) { return null; } 657 if( typeof( v ) === "object" && v.termType ) { 658 return v; 659 } 660 var object; 661 if( validURI ( v ) || (v.indexOf('"') !== 0 && v.indexOf(':') !== -1) ) { 662 object = processResource( v, o ); 663 } else { 664 object = processLiteral( v, o ); 665 } 666 return object; 667 } 668 669 function processEditTerm( o ) { 670 if( o.editTerm ) { 671 return o.editTerm; 672 } 673 if( o.subject && o.predicate && o.object ) { 674 o.editTerm = "object"; 675 return o.editTerm; 676 } else if ( o.object && o.predicate ) { 677 o.editTerm = "subject"; 678 return o.editTerm; 679 } else if ( o.subject && o.object ) { 680 o.editTerm = "predicate"; 681 return o.editTerm; 682 } else if ( o.subject && o.predicate ) { 683 o.editTerm = "object"; 684 return o.editTerm; 685 } 686 throw "Insufficient information provided to edit or view "+ o.editTerm +" term. S:"+o.subject+" P:"+o.predicate+" O:"+o.object; 687 } 688 689 function processGraph( o, subject ) { 690 return o.graph ? o.graph : ( (o.acl && o.acl.graph) ? o.acl.graph : (subject ? subject : null ) ); 691 } 692 693 function processACL( o, subject ) { 694 var a = o.acl; 695 var ACL_URI_BASE = "http://jambo.xvm.mit.edu/acl/"; 696 697 if( "string" === typeof(a) && validURI( a ) ) { 698 return a; 699 } 700 if( "object" === typeof(a) ) { 701 var graph = processGraph( o, subject ); 702 var user = a.user ? a.user : defaultUser; 703 var friend = a.friend ? a.friend : defaultFriend; 704 if( !graph ) { throw( "could not determine target graph for ACL." ); } 705 if( !a.type ) { 706 throw "no acl type provided:"+a; 707 } else if( a.type === "permanent" ) { 708 return ACL_URI_BASE+"permanent.n3?r="+escape(graph); 709 } else if( a.type === "private-readonly" ) { 710 if( !user ) { throw ("could not determine user for ACL"); } 711 if( !friend ) { throw ("could not determine friend or group to be given read access for ACL"); } 712 return ACL_URI_BASE+"private-readonly.n3?r="+escape(graph)+"&u="+escape(user)+"&f="+escape(friend); 713 } else if( a.type === "private-editable" ) { 714 if( !user ) { throw ("could not determine user for ACL"); } 715 if( !friend ) { throw ("could not determine friend or group to be given read-write access for ACL"); } 716 return ACL_URI_BASE+"private.n3?r="+escape(graph)+"&u="+escape(user)+"&f="+escape(friend); 717 } else if( a.type === "public-editable" ) { 718 return ACL_URI_BASE+"public.n3?r="+escape(graph); 719 } else if( a.type === "public-readonly" ) { 720 return ACL_URI_BASE+"public-readonly.n3?r="+escape(graph)+"&u="+escape(user); 721 } 722 } 723 throw "unrecognized acl format:"+a; 724 } 725 726 function getMenuPredicateOptions( o ) { 727 var props = $.rdfwidgets.each( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#Property"), undefined, o ); 728 var uriToValue = {}; 729 var valueToURI = {}; 730 var bindings = []; 731 for( x in props ) { 732 var binding = {}; 733 bindings.push( binding ); 734 var prop = props[x]; 735 var comment = $.rdfwidgets.any( prop, db.sym("http://www.w3.org/2000/01/rdf-schema#comment"), undefined, undefined, o ); 736 binding.uri = prop.uri; 737 binding.value = doLabel( prop, o ); 738 739 if( comment ) { 740 binding.comment = comment.value; 741 } else { 742 binding.comment = prop.value; 743 } 744 745 binding.label = "<span title='"+binding.comment+" "+binding.uri+"'>"+binding.value+"</span>"; 746 valueToURI[binding.value] = prop; 747 uriToValue[prop] = binding.value; 748 } 749 return {bindings:bindings, valueToURI:valueToURI, uriToValue:uriToValue}; 750 } 751 752 function getMenuNoOptions() { 753 return {bindings:[],valueToURI:{},uriToValue:{}}; 754 } 755 756 function getMenuUsedOptions( o ) { 757 var used = new Array(); 758 used = $.rdfwidgets.statementsMatching( undefined , db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), o.type ? processObject(o.type) : undefined, undefined, false, o); 759 760 used = filterDuplicates( used ); 761 762 var uriToValue = {}; 763 var valueToURI = {}; 764 var bindings = []; 765 766 for( x in used ) { 767 var st = used[x]; 768 var prop; 769 if( o.editTerm ) { 770 prop = st[o.editTerm]; 771 }else if( !o.subject ) { 772 prop = st.subject; 773 } else if( !o.object ) { 774 prop = st.object; 775 } else if( !o.predicate ) { 776 prop = st.predicate; 777 } 778 if( uriToValue[prop] || prop.termType === "bnode" ) { 779 continue; 780 } 781 var binding = {}; 782 bindings.push( binding ); 783 var comment = $.rdfwidgets.any( prop, db.sym("http://www.w3.org/2000/01/rdf-schema#comment"), undefined, undefined, o ); 784 binding.uri = prop.uri; 785 binding.value = doLabel( prop, o ); 786 787 if( comment ) { 788 binding.comment = comment.value; 789 } else { 790 binding.comment = prop.value; 791 } 792 793 binding.label = "<span title='"+binding.comment+" "+binding.uri+"'>"+binding.value+"</span>"; 794 valueToURI[binding.value] = prop; 795 uriToValue[prop] = binding.value; 796 } 797 798 return {bindings:bindings, valueToURI:valueToURI, uriToValue:uriToValue}; 799 } 800 801 function getMenuInstanceOptions( o ) { 802 var used = new Array(); 803 if( o.predicate ) { 804 if( $.rdfwidgets.whether(processResource( o.predicate, o ), db.sym("http://www.w3.org/2000/01/rdf-schema#range" ), db.sym("http://www.w3.org/2000/01/rdf-schema#Literal"), undefined, o ) ) { 805 return {bindings:[],valueToURI:{},uriToValue:{}}; 806 } 807 var p = allSubProperties( o.predicate, o ); 808 var used = []; 809 var ranges = []; 810 for( x in p ) { 811 used = used.concat( $.rdfwidgets.statementsMatching( undefined, p[x], undefined, undefined, false, o ) ); 812 if( o.editTerm === "subject" ) { 813 ranges = ranges.concat($.rdfwidgets.each( p[x], db.sym("http://www.w3.org/2000/01/rdf-schema#domain"), undefined, undefined, o )); 814 }else if( o.editTerm === "object" ) { 815 ranges = ranges.concat($.rdfwidgets.each( p[x], db.sym("http://www.w3.org/2000/01/rdf-schema#range"), undefined, undefined, o )); 816 } 817 } 818 } 819 820 var props = []; 821 if( ranges.length > 0 ) { 822 for( var i = 0; i < ranges.length; i++ ) { 823 var r = allSubClasses( ranges[i], o ); 824 for( x in r ) { 825 props = props.concat( $.rdfwidgets.statementsMatching( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), r[x], undefined, false, o) ); 826 } 827 } 828 } else { 829 props = $.rdfwidgets.statementsMatching( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), undefined, undefined, false, o ); 830 } 831 832 833 var uriToValue = {}; 834 var valueToURI = {}; 835 var bindings = []; 836 for( x in props ) { 837 var st = props[x]; 838 var prop = st.subject; 839 if( $.rdfwidgets.whether( st.subject, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#Property" ), undefined, o ) || uriToValue[st.subject] || st.subject.termType === "bnode") { 840 continue; 841 } 842 var binding = {}; 843 bindings.push( binding ); 844 var comment = $.rdfwidgets.any( prop, db.sym("http://www.w3.org/2000/01/rdf-schema#comment"), undefined, undefined, o ); 845 binding.uri = prop.uri; 846 binding.value = doLabel( prop, o ); 847 848 if( comment ) { 849 binding.comment = comment.value; 850 } else { 851 binding.comment = prop.value; 852 } 853 854 binding.label = "<span title='"+binding.comment+" "+binding.uri+"'>"+binding.value+"</span>"; 855 valueToURI[binding.value] = prop; 856 uriToValue[prop] = binding.value; 857 } 858 859 860 for( x in used ) { 861 var st = used[x]; 862 var prop; 863 if( o.editTerm === "subject" ) { 864 prop = st.subject; 865 } else { 866 prop = st.object; 867 } 868 if( uriToValue[prop] || prop.termType === "bnode" ) { 869 continue; 870 } 871 var binding = {}; 872 bindings.push( binding ); 873 var comment = $.rdfwidgets.any( prop, db.sym("http://www.w3.org/2000/01/rdf-schema#comment"), undefined, undefined, o ); 874 binding.uri = prop.uri; 875 binding.value = doLabel( prop, o ); 876 877 if( comment ) { 878 binding.comment = comment.value; 879 } else { 880 binding.comment = prop.value; 881 } 882 883 binding.label = "<span title='"+binding.comment+" "+binding.uri+"'>"+binding.value+"</span>"; 884 valueToURI[binding.value] = prop; 885 uriToValue[prop] = binding.value; 886 } 887 888 return {bindings:bindings, valueToURI:valueToURI, uriToValue:uriToValue}; 889 } 890 891 892 /* find the endpoint that you should write to for a given data source */ 893 function getEndpoint( why, o ) { 894 if( o.endpoint ) { 895 return o.endpoint; 896 } else if ( why && why.uri && endpoints[why] ) { 897 return endpoints[why]; 898 } else if ( defaultEndpoint ) { 899 return defaultEndpoint; 900 } else { 901 return window.location; 902 } 903 } 904 905 function doInsert( triples, callback, o ){ 906 if( !triples || triples.length == 0 ) { callback( true );return; } 907 var endpoint = getEndpoint( triples[0], o ); 908 var queryString = "INSERT "; 909 var postData = {}; 910 911 var graph; 912 if( o.acl ) { 913 postData['acl'] = processACL( o, triples[0].why.uri ); 914 graph = processGraph( o, triples[0].why.uri ); 915 } else { 916 graph = processGraph( o ); 917 } 918 if( graph ) { 919 queryString += "INTO <" + graph + "> "; 920 } 921 922 queryString += " { "; 923 for( x in triples ) { queryString += triples[x].toString(); } 924 queryString += " } "; 925 postData['query']=queryString; 926 $.ajax({ 927 type:"POST", 928 data:postData, 929 url :endpoint, 930 beforeSend: function( xhr ) { 931 if( xhr.withCredentials !== undefined ) { 932 xhr.withCredentials = true; 933 } 934 if( o.beforeSubmit ) { 935 o.beforeSubmit( triples, xhr ); 936 } 937 }, 938 success: function(data, stat, xhr) { 939 var sp, d; 940 for( var i = 0; i < data.childNodes.length; i++ ) { 941 var sp = data.childNodes[i]; 942 if( sp.nodeName === "sparql" ) { 943 for( var j = 0; j < sp.childNodes.length; j++ ) { 944 var d = sp.childNodes[j]; 945 if( d.nodeName === "inserted" ) { 946 var val =$(d).text(); 947 for( var t = 0; t < triples.length; t++ ) { 948 db.add( triples[t].subject, triples[t].predicate, triples[t].object, triples[t].why ); 949 } 950 callback( true, val ); 951 insertData( triples ); 952 if( o.afterSubmit ) { 953 o.afterSubmit( true, triples, xhr ); 954 } 955 return; 956 } 957 } 958 } 959 } 960 callback( false ); 961 if( o.afterSubmit ) { 962 o.afterSubmit( false, triples, xhr ); 963 } 964 }, 965 error: function(xhr, t, err) { 966 callback( false ); 967 if( o.afterSubmit ) { 968 o.afterSubmit( false, null, xhr ); 969 } 970 }, 971 dataType:"xml" 972 }); 973 } 974 975 function doDelete( triples, callback, o ){ 976 if( !triples || triples.length == 0 ) { callback( true );return; } 977 var endpoint = getEndpoint( triples[0], o ); 978 var queryString = "DELETE "; 979 var postData = {}; 980 var graph; 981 if( o.acl ) { 982 postData['acl'] = processACL( o, triples[0].why.uri ); 983 graph = processGraph( o, triples[0].why.uri ); 984 } else { 985 graph = processGraph( o ); 986 } 987 if( graph ) { 988 queryString += "FROM <" + graph + "> "; 989 } 990 991 queryString += " { "; 992 for( x in triples ) { queryString += triples[x].toString(); } 993 queryString += " } "; 994 postData['query']=queryString; 995 996 $.ajax({ 997 type:"POST", 998 data:postData, 999 url :endpoint, 1000 beforeSend: function( xhr ) { 1001 if( xhr.withCredentials !== undefined ) { 1002 xhr.withCredentials = true; 1003 } 1004 if( o.beforeSubmit ) { 1005 o.beforeSubmit( triples, xhr ); 1006 } 1007 }, 1008 success: function(data, stat, xhr) { 1009 var sp, d; 1010 for( var i = 0; i < data.childNodes.length; i++ ) { 1011 var sp = data.childNodes[i]; 1012 if( sp.nodeName === "sparql" ) { 1013 for( var j = 0; j < sp.childNodes.length; j++ ) { 1014 var d = sp.childNodes[j]; 1015 if( d.nodeName === "deleted" ) { 1016 var val =$(d).text(); 1017 for( var t = 0; t < triples.length; t++ ) { 1018 db.remove( triples[t] ); 1019 } 1020 callback( true, val ); 1021 deleteData( triples ); 1022 if( o.afterSubmit ) { 1023 o.afterSubmit( true, triples, xhr ); 1024 } 1025 return; 1026 } 1027 } 1028 } 1029 } 1030 callback( false ); 1031 if( o.afterSubmit ) { 1032 o.afterSubmit( false, triples, xhr ); 1033 } 1034 }, 1035 error: function(xhr, stat, err) { 1036 callback( false ); 1037 if( o.afterSubmit ) { 1038 o.afterSubmit( false, null, xhr ); 1039 } 1040 }, 1041 dataType:"xml" 1042 }); 1043 } 1044 1045 //when i feel confident that its being implemented, this will use the w3c spec which allows multiple update actions in one query 1046 function doUpdate( triples, callback, o ) { 1047 doDelete( triples['delete_triples'], function( success ) { 1048 if( success ) { 1049 doInsert( triples['insert_triples'], callback, o ); 1050 } else { 1051 callback( false ); 1052 } 1053 }, o ); 1054 } 1055 1056 function doLabel( term, o ) { 1057 if( labelCache[term] ) { 1058 return labelCache[term]; 1059 } 1060 if( term.termType === "literal" ) { 1061 return term.value; 1062 } 1063 var label = null; 1064 var t = term.value; 1065 if( !t ) { return ""; } 1066 var p = db.sym( "http://www.w3.org/2000/01/rdf-schema#label" ); 1067 //var pat = $.rdf.pattern( s,p,o ); 1068 var r = $.rdfwidgets.statementsMatching( term, p, undefined, undefined, false ); 1069 if( r.length > 0 ) { 1070 for( var i = 0; i < r.length; i++ ) { 1071 if( !r[i].lang || (r[i].lang && langs[r[i].lang]) ) { 1072 label = r[i].object.toString(); 1073 break; 1074 } 1075 } 1076 } 1077 if( !label ) { 1078 p = db.sym("http://purl.org/dc/terms/title"); 1079 r = $.rdfwidgets.statementsMatching( term, p, undefined, undefined, false ); 1080 if( r.length > 0 ) { 1081 for( var i = 0; i < r.length; i++ ) { 1082 if( !r[i].lang || (r[i].lang && langs[r[i].lang]) ) { 1083 label = r[i].object.toString(); 1084 break; 1085 } 1086 } 1087 } 1088 } 1089 if( !label ) { 1090 p = db.sym("http://xmlns.com/foaf/0.1/name"); 1091 r = $.rdfwidgets.statementsMatching( term, p, undefined, undefined, false ); 1092 if( r.length > 0 ) { 1093 for( var i = 0; i < r.length; i++ ) { 1094 if( !r[i].lang || (r[i].lang && langs[r[i].lang]) ) { 1095 label = r[i].object.toString(); 1096 break; 1097 } 1098 } 1099 } 1100 } 1101 if( !label ) { 1102 var li = t.lastIndexOf( "#" ); 1103 if( li !== -1 && li < t.length-2 ) { 1104 label = t.substr(li+1); 1105 } else { 1106 li = t.lastIndexOf( "/" ); 1107 if( (li > 0 && t[li-1] !== "/") && li < t.length-2 ) { 1108 label = t.substr(li+1); 1109 } else { 1110 label = t; 1111 } 1112 } 1113 } 1114 labelCache[term]=label; 1115 return label; 1116 } 1117 1118 var imageProperties = null; 1119 var imageCache = {}; 1120 1121 function findImageProperties() { 1122 q = [db.sym("http://xmlns.com/foaf/0.1/depiction"),db.sym("http://dbpedia.org/property/img")/*,db.sym("http://xmlns.com/foaf/0.1/img")*/]; 1123 imageProperties = {}; 1124 var current = null; 1125 var sp = db.sym( "http://www.w3.org/2000/01/rdf-schema#subPropertyOf" ); 1126 while( q.length > 0 ) { 1127 current = q[0]; 1128 q = q.slice(1); 1129 if( imageProperties[current.value] ) { 1130 continue; 1131 } else { 1132 var extras = $.rdfwidgets.each( undefined, sp, current ); 1133 for( var i = 0; i < extras.length; i++ ) { 1134 if( !imageProperties[extras[i].value] ) { 1135 q.push( extras[i] ); 1136 } 1137 } 1138 imageProperties[current.value] = 1; 1139 } 1140 } 1141 } 1142 1143 1144 1145 function doImage( term, o ) { 1146 if( !imageProperties ) { 1147 findImageProperties(); 1148 } 1149 1150 var sts = $.rdfwidgets.statementsMatching( term,undefined,undefined,undefined,false,o ); 1151 for( var i = 0; i < sts.length; i++ ) { 1152 if( imageProperties[sts[i].predicate.value] && sts[i].object.termType === "symbol" ) { 1153 imageCache[term.value] = sts[i].object; 1154 return sts[i].object; 1155 } 1156 } 1157 return null; 1158 } 1159 1160 function isImage( term, o ) { 1161 if( !imageProperties ) { 1162 findImageProperties(); 1163 } 1164 1165 if( $.rdfwidgets.anyStatementMatching( term, db.sym( "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" ), db.sym( "http://xmlns.com/foaf/0.1/Image" ), undefined, o ) ) { 1166 return term; 1167 } 1168 1169 var sts = $.rdfwidgets.statementsMatching( undefined, undefined, term, undefined, false, o ); 1170 for( var i = 0; i < sts.length; i++ ) { 1171 if( imageProperties[sts[i].predicate.value] ) { 1172 return sts[i].object; 1173 } 1174 } 1175 return null; 1176 } 1177 1178 function doAutocomplete( jq, o ) { 1179 var options; 1180 1181 if( o.menuOptions !== null && o.menuOptions !== undefined ) { 1182 options = o.menuOptions; 1183 } else if( o.editTerm === "object" && $.rdfwidgets.whether(processResource( o.predicate, o ), db.sym("http://www.w3.org/2000/01/rdf-schema#range" ), db.sym("http://www.w3.org/2000/01/rdf-schema#Literal"), undefined, o ) ) { 1184 jq.bind("blur", function() { jq.trigger("autocompletechoice") } ); 1185 return; 1186 } else if ( (o.editTerm === "object" || o.editTerm === "subject") ) { 1187 options = getMenuInstanceOptions( o ); 1188 } else if ( o.editTerm === "predicate" ) { 1189 options = getMenuPredicateOptions( o ); 1190 } else { 1191 options = {bindings:[],valueToURI:{},uriToValue:{}}; 1192 } 1193 var preds = options.bindings; 1194 var open = false; 1195 var passedUp = false; 1196 var selected = false; 1197 var lastSelect = null; 1198 1199 function getEvent( val ) { 1200 //perform label-> uri OR uri -> label. 1201 if( lastSelect && lastSelect.value === jq.val() ) { 1202 return { type: "autocompletechoice", uri:lastSelect.uri, input: jq.val(), label:lastSelect.value }; 1203 } else if ( validURI( jq.val() ) ) { 1204 return { type: "autocompletechoice", uri:jq.val(), input: jq.val(), label:( options.uriToValue[ jq.val() ] ? options.uriToValue[ jq.val() ] : jq.val() ) }; 1205 } else if ( options.valueToURI[jq.val()] ) { 1206 return { type: "autocompletechoice", uri: options.valueToURI[jq.val()],input: jq.val(), label:jq.val() }; 1207 } else if ( validURI( jq.val() ) ){ 1208 return { type: "autocompletechoice", uri: jq.val(),input: jq.val(), label:jq.val() }; 1209 } else { 1210 return { type: "autocompletechoice", uri: null,input: jq.val(), label:jq.val() }; 1211 } 1212 } 1213 1214 return jq.autocomplete("destroy").autocomplete({ 1215 source: preds, 1216 open: function() { 1217 open = true; 1218 passedUp = false; 1219 selected = false; 1220 }, 1221 close: function() { 1222 open = false; 1223 if( passedUp && !selected ) { 1224 var evt = getEvent( jq.val() ); 1225 if( evt.uri ) { 1226 jq.data( "uri", evt.uri ); 1227 jq.data( "val", evt.input ); 1228 } else { 1229 jq.data( "uri", null ); 1230 jq.data( "val", evt.input ); 1231 } 1232 $(this).trigger( evt ); 1233 } 1234 }, 1235 focus: function( e, ui ) { 1236 lastSelect = ui.item; 1237 }, 1238 select: function( e, ui ) { 1239 selected = true; 1240 lastSelect = ui.item; 1241 } 1242 }).blur( function() { 1243 if( !open ) { 1244 var evt = getEvent( jq.val() ); 1245 if( evt.uri ) { 1246 jq.data( "uri", evt.uri ); 1247 jq.data( "val", evt.input ); 1248 } else { 1249 jq.data( "uri", null ); 1250 jq.data( "val", evt.input ); 1251 } 1252 $(this).trigger( evt ); 1253 } else { 1254 passedUp = true; 1255 } 1256 }); 1257 } 1258 1259 function processTripleUpdate( term, original, o ) { 1260 var delete_triples = null; 1261 var insert_triples = null; 1262 if( o.editTerm === "subject" ) { 1263 var pred = processResource( o.predicate, o ); 1264 var obj = processObject( o.object, o ); 1265 if( original ) { delete_triples = $.rdfwidgets.statementsMatching( original, pred, obj,undefined,false,o ); } 1266 if( term ) { 1267 insert_triples = [ new $rdf.Statement( term, pred, obj ) ]; 1268 if( delete_triples && delete_triples[0] && delete_triples[0].why ) { insert_triples[0].why = delete_triples[0].why; } 1269 } 1270 } else if ( o.editTerm === "predicate" ) { 1271 var subj = processResource( o.subject, o ); 1272 var obj = processObject( o.object, o ); 1273 if( original ) { delete_triples = $.rdfwidgets.statementsMatching( subj, original, obj,undefined,false,o ); } 1274 if( term ) { 1275 insert_triples = [ new $rdf.Statement( subj, term, obj ) ]; 1276 if( delete_triples && delete_triples[0] && delete_triples[0].why ) { insert_triples[0].why = delete_triples[0].why; } 1277 } 1278 } else if ( o.editTerm === "object" ) { 1279 var subj = processResource( o.subject, o ); 1280 var pred = processResource( o.predicate, o ); 1281 if( original ) { delete_triples = $.rdfwidgets.statementsMatching( subj, pred, original,undefined,false,o ); } 1282 if( term ) { 1283 insert_triples = [ new $rdf.Statement( subj, pred, term ) ]; 1284 if( delete_triples && delete_triples[0] && delete_triples[0].why ) { insert_triples[0].why = delete_triples[0].why; } 1285 } 1286 } 1287 if( !delete_triples ) { delete_triples = new Array(); } 1288 if( !insert_triples ) { insert_triples = new Array(); } 1289 return { delete_triples: delete_triples, insert_triples:insert_triples } 1290 } 1291 1292 function setUnselected( element ) { 1293 if( element && element === selectedElement ) { 1294 selectedElement = null; 1295 element.removeClass( 'selected' ); 1296 } 1297 } 1298 1299 function setSelected( element, term ) { 1300 setUnselected( selectedElement ); 1301 if( element ) { 1302 selectedElement = element; 1303 element.addClass( 'selected' ); 1304 if( term ) { 1305 element.trigger( 'rdfselect', [term] ); 1306 } 1307 } 1308 } 1309 1310 function checkSelected( element ) { 1311 return element === selectedElement; 1312 } 1313 1314 1315 1316 function addDelayedClickEvent( element ) { 1317 var waiting = false; 1318 function firstClick( e ) { 1319 e.stopPropagation(); 1320 if( !waiting ) { 1321 waiting = true; 1322 setSelected( element, element.label('getRDFValue')); 1323 setTimeout( function() { 1324 waiting = false; 1325 element.unbind( "click", firstClick ); 1326 element.bind( "click", secondClick ); 1327 }, 1000); 1328 } 1329 } 1330 function secondClick( e ) { 1331 e.stopPropagation(); 1332 if( checkSelected( element ) ) { 1333 element.trigger( "delayedclick" ); 1334 } else { 1335 element.bind( "click", firstClick ); 1336 element.unbind( "click", secondClick ); 1337 firstClick( e ); 1338 } 1339 } 1340 element.bind( "click", firstClick ); 1341 } 1342 /* function addDelayedClickEvent( element ) { 1343 function firstClick( e ) { 1344 e.stopPropagation(); 1345 setSelected( element); 1346 element.trigger( "rdfselect",[element.rdflabel('getRDFValue')] ); 1347 setTimeout( function() { 1348 element.one( "click", secondClick ); 1349 }, 1000); 1350 } 1351 function secondClick( e ) { 1352 e.stopPropagation(); 1353 if( checkSelected( element ) ) { 1354 element.one( "click", firstClick ); 1355 element.trigger( "delayedclick" ); 1356 } else { 1357 firstClick( e ); 1358 } 1359 } 1360 element.one( "click", firstClick ); 1361 }*/ 1362 1363 1364 /** 1365 * @name jQuery.prototype.edit 1366 * @description Draw a label that, when clicked twice, transforms into an editable text box for modifying a value in a triple. 1367 * @function 1368 * @param {String | Object} [options.subject] The resource to display an edit for OR if predicate or object is defined, the subject of a statement to be matched. 1369 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 1370 * @param {String | Object} [options.object] The object of a statement to be matched. 1371 * @param {Boolean} [options.autocomplete=true] If false, no autocomplete menu will be displayed when the user is editing. 1372 * @param {Object} [options] @see CommonOptions 1373 */ 1374 $.rdfwidget("ui.edit", { 1375 options: { 1376 namespaces:namespaces, 1377 showlinks:false, 1378 autocomplete:true, 1379 usetextarea:false, 1380 editable:"delayedclick" 1381 }, 1382 _create: function() { 1383 this.originalSubject = this.options.subject; 1384 this.originalPredicate = this.options.predicate; 1385 this.originalObject = this.options.object; 1386 this.refresh(); 1387 }, 1388 reset: function() { 1389 this.element.edit('option','subject',this.originalSubject); 1390 this.element.edit('option','predicate',this.originalPredicate); 1391 this.element.edit('option','object',this.originalObject); 1392 refresh(); 1393 }, 1394 getTriple: function() { 1395 var o = this.options; 1396 var t = this.element.label( "getTriple" ); 1397 if( t ) { 1398 return t; 1399 } 1400 if( o.subject && o.predicate && o.object ) { 1401 var trip = $.rdfwidgets.anyStatementMatching( processResource(o.subject,o),processResource(o.predicate,o),processObject(o.object,o), undefined, o ); 1402 return trip ? trip : null; 1403 } 1404 return null; 1405 }, 1406 1407 refresh: function() { 1408 var acdone = false; 1409 var o = this.options; 1410 var element = this.element; 1411 processEditTerm( o ); 1412 element.label(o); 1413 addDelayedClickEvent( element ); 1414 if( false !== o.editable && "never" !== o.editable ) { 1415 var original = element.label("getRDFValue"); 1416 var inputbox; 1417 function insertAC( e ) { 1418 if( !inputbox ) { 1419 if( o.usetextarea ) { 1420 inputbox = $("<textarea class='rdfedit'></textarea>"); 1421 } else { 1422 inputbox = $("<input style='margin:0; padding:0; border: 1px solid black;' class='rdfedit' type='text'></input>"); 1423 } 1424 } 1425 if( !acdone ) { 1426 doAutocomplete( inputbox, o ); 1427 } 1428 inputbox.width( element.width()-2 ); 1429 // if( o.usetextarea ) { 1430 inputbox.height( element.height()-2 ); 1431 // } 1432 if( element.edit('option','disabled')) { 1433 element.one('delayedclick', insertAC ); 1434 return; 1435 } 1436 var oldText; 1437 if( original ) { 1438 inputbox.val(element.text()); 1439 oldText = element.text(); 1440 } else { 1441 oldText = ""; 1442 } 1443 element.empty().append( inputbox ); 1444 inputbox.select(); 1445 function insertLabel(e) { 1446 var i = inputbox.val(); 1447 var choice; 1448 var label; 1449 if( i === "" || i === oldText ) { 1450 element.empty().label(o).one('delayedclick', insertAC ); 1451 return; 1452 } 1453 if( !e.uri ) { 1454 if( !o.autocomplete ) { 1455 if( validURI( i ) ) { 1456 choice = processResource( i, o ); 1457 } else if ( o.editTerm === "object" ) { 1458 choice = processLiteral( i, o ); 1459 } 1460 } else if (o.editTerm === "object" ) { 1461 choice = processLiteral( i, o ); 1462 } 1463 label = i; 1464 } else { 1465 label = e.label; 1466 choice = processResource( e.uri, o ); 1467 } 1468 if( choice ) { 1469 var data = processTripleUpdate( choice, original, o ); 1470 doUpdate( data, function( success ) { 1471 if( success ) { 1472 element.edit("option",o.editTerm,choice.value); 1473 element.empty().label(o).one('delayedclick', insertAC ); 1474 original = choice; 1475 } else { 1476 alert( "Sorry, the server responded to your edit request with an error." ); 1477 element.empty().label(o).one('delayedclick', insertAC ); 1478 } 1479 }, o); 1480 } else { 1481 alert( "Sorry, the input you provided was not valid. Please choose a menu option or enter a valid URL."); 1482 inputbox.one("autocompletechoice", insertLabel ); 1483 inputbox.focus(); 1484 } 1485 } 1486 inputbox.one("autocompletechoice", insertLabel ); 1487 if( !o.autocomplete ) { 1488 o.menuOptions = []; 1489 } 1490 inputbox.focus(); 1491 } 1492 element.one('delayedclick', insertAC ); 1493 } 1494 } 1495 }); 1496 1497 $.ui.edit.getter = "getTriple"; 1498 1499 /** 1500 * @name jQuery.prototype.tripleedit 1501 * @description Draw a series of editable boxes for editing each term in a single triple. 1502 * @function 1503 * @param {String | Object} [options.subject] The subject of a statement to be matched. 1504 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 1505 * @param {String | Object} [options.object] The object of a statement to be matched. 1506 * @param {Boolean} [options.autocomplete=true] If false, no autocomplete menu will be displayed. 1507 * @param {Object} [options] @see CommonOptions 1508 */ 1509 $.rdfwidget("ui.tripleedit", { 1510 options: { 1511 namespaces:namespaces, 1512 showlinks:false, 1513 autocomplete:true 1514 }, 1515 _create: function() { 1516 this.refresh(); 1517 }, 1518 1519 disable: function() { 1520 var o = this.options; 1521 if( o.subjectElement ) { 1522 $(o.subjectElement).edit('disable'); 1523 } 1524 if( o.predicateElement ) { 1525 $(o.predicateElement).edit('disable'); 1526 } 1527 if( o.objectElement ) { 1528 $(o.objectElement).edit('disable'); 1529 } 1530 }, 1531 1532 enable: function() { 1533 var o = this.options; 1534 if( o.subjectElement ) { 1535 $(o.subjectElement).edit('enable'); 1536 } 1537 if( o.predicateElement ) { 1538 $(o.predicateElement).edit('enable'); 1539 } 1540 if( o.objectElement ) { 1541 $(o.objectElement).edit('enable'); 1542 } 1543 }, 1544 getTriple: function() { 1545 var o = this.options; 1546 if( o.subjectElement ) { 1547 return $(o.subjectElement).edit('getTriple'); 1548 } else if( o.predicateElement ) { 1549 return $(o.predicateElement).edit('getTriple'); 1550 } else if( o.objectElement) { 1551 return $(o.objectElement).edit('getTriple'); 1552 } 1553 return null; 1554 }, 1555 1556 refresh: function() { 1557 var o = this.options; 1558 var element = this.element; 1559 var that = this; 1560 if( ! (o.subjectElement || o.predicateElement || o.objectElement)) { 1561 element.empty(); 1562 } 1563 1564 var beforeSubmit = function(data, xhr) { 1565 that.disable(); 1566 if( o.beforeSubmit ) { 1567 o.beforeSubmit( data, xhr ); 1568 } 1569 } 1570 1571 var afterSubmit = function(success, data, xhr) { 1572 if( success && data.insert_triples && data.insert_triples[0] ) { 1573 element.tripleedit('option','subject',data.insert_triples[0].subject); 1574 element.tripleedit('option','predicate',data.insert_triples[0].predicate); 1575 element.tripleedit('option','object',data.insert_triples[0].object); 1576 } 1577 if( o.afterSubmit ) { 1578 o.afterSubmit( success, data, xhr ); 1579 } 1580 that.enable(); 1581 } 1582 1583 var subjectopts = {}; 1584 var newopts = {editTerm:'subject',beforeSubmit:beforeSubmit, afterSubmit:afterSubmit} 1585 $.extend( subjectopts, o, newopts ); 1586 if( o.subjectElement === undefined ) { 1587 element.tripleedit('option','subjectElement',$('<div class="rdftripleedit"></div>')); 1588 element.append( o.subjectElement ); 1589 } 1590 1591 var predopts = {}; 1592 newopts = {editTerm:'predicate',beforeSubmit:beforeSubmit, afterSubmit:afterSubmit} 1593 $.extend( predopts, o, newopts ); 1594 if( o.predicateElement === undefined ) { 1595 element.tripleedit('option','predicateElement',$('<div class="rdftripleedit"></div>')); 1596 element.append( o.predicateElement ); 1597 } 1598 var objectopts = {}; 1599 newopts = {editTerm:'object',beforeSubmit:beforeSubmit, afterSubmit:afterSubmit} 1600 $.extend( objectopts, o, newopts ); 1601 if( o.objectElement === undefined ) { 1602 element.tripleedit('option','objectElement',$('<div class="rdftripleedit"></div>')); 1603 element.append( o.objectElement ); 1604 } 1605 if( o.subjectElement ) { 1606 $(o.subjectElement).edit(subjectopts); 1607 } 1608 if( o.predicateElement ) { 1609 $(o.predicateElement).edit(predopts); 1610 } 1611 if( o.objectElement ) { 1612 $(o.objectElement).edit(objectopts); 1613 } 1614 1615 } 1616 1617 }); 1618 1619 $.ui.tripleedit.getter = "getTriple"; 1620 1621 /** 1622 * @name jQuery.prototype.selecttable 1623 * @description Perform a SPARQL SELECT query with a set of properties and display the results in a table. 1624 * @function 1625 * @param {String | Object} [options.type] If specified, the required rdf:type of each result in the list. 1626 * @param {Array} [options.properties] If specified, the set of properties to be SELECTed for. 1627 * @param {Array} [options.requireall=true] If false, matches that bind at least one item in options.properties will be displayed. 1628 * @param {Object} [options] @see CommonOptions 1629 */ 1630 $.rdfwidget("ui.selecttable", { 1631 options: { 1632 namespaces:namespaces, 1633 showlinks:false, 1634 editable:true, 1635 autocomplete:true, 1636 subject:window.location, 1637 requireall:true, 1638 properties:[] 1639 }, 1640 _create: function() { 1641 this.refresh(); 1642 }, 1643 1644 disable: function() { 1645 }, 1646 1647 enable: function() { 1648 }, 1649 1650 refresh: function() { 1651 var o = this.options; 1652 var element = this.element; 1653 var that = this; 1654 1655 var optsArray = {}; 1656 var properties = []; 1657 for( var i = 0; i < o.properties.length; i++ ) { 1658 properties.push( processResource( o.properties[i], o ) ); 1659 } 1660 1661 function doHeader( ) { 1662 var str = "<thead><tr class='rdfeditheader'><th></th>"; 1663 for( var i = 0; i < properties.length; i++ ) { 1664 var id = randomID(); 1665 var cell = "<div class='rdfeditheader' id='"+id+"'></div>"; 1666 var cellopts = {}; 1667 var tripopts = {subject: properties[i], predicate:null, object:null, selectable:false, editable:false}; 1668 $.extend( cellopts, o, tripopts ); 1669 optsArray[id]= cellopts; 1670 td+=cell; 1671 str += "<th class='rdfeditheader'>"+cell+"</th>"; 1672 } 1673 str += "</tr></thead>"; 1674 return str; 1675 } 1676 1677 var html = "<table class='rdfselecttable'><tbody>"; 1678 html += doHeader(); 1679 if( o.type ) { 1680 var t = processResource( o.type, o ); 1681 var subjects = $.rdfwidgets.each( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), t,undefined, o ); 1682 for( var i = 0; i < subjects.length; i++ ) { 1683 var row = "<tr>"; 1684 var subject = subjects[i]; 1685 //todo: row header. 1686 var id = randomID(); 1687 var td = "<td class='rdfeditheader'>"; 1688 var cell = "<div class='rdfeditheader' id='"+id+"'></div>"; 1689 var cellopts = {}; 1690 var tripopts = {subject: subject, predicate:null, object:null, selectable:false, editable:false}; 1691 $.extend( cellopts, o, tripopts ); 1692 optsArray[id]= cellopts; 1693 td += cell + "</td>"; 1694 row += td; 1695 var fail = false; 1696 for( var j = 0; j < properties.length; j++ ) { 1697 td = "<td>"; 1698 var objects = $.rdfwidgets.each( subject, properties[j],undefined,undefined,o ); 1699 if( (!objects || objects.length == 0)) { 1700 if( o.requireall ) { 1701 fail = true; 1702 break; 1703 } else { 1704 id = randomID(); 1705 cell = "<div id='"+id+"'></div>"; 1706 cellopts = {}; 1707 tripopts = {subject: subject, predicate:properties[j]}; 1708 $.extend( cellopts, o, tripopts ); 1709 optsArray[id] = cellopts; 1710 td += cell; 1711 } 1712 } 1713 for( var k = 0; k < objects.length; k++ ) { 1714 id = randomID(); 1715 cell = "<div id='"+id+"'></div>"; 1716 cellopts = {}; 1717 tripopts = {subject: subject, predicate:properties[j], object:objects[k]}; 1718 $.extend( cellopts, o, tripopts ); 1719 optsArray[id] = cellopts; 1720 td += cell; 1721 } 1722 td+="</td>"; 1723 row += td; 1724 } 1725 if( !o.requireall || !fail ) { 1726 row += "</tr>"; 1727 html += row; 1728 } 1729 } 1730 } else { 1731 var done = {}; 1732 var total = 0; 1733 for( var h = 0; ((h < properties.length && !o.requireall) || (o.requireall && h < 1)) ; h++ ) { 1734 var tempsubjects = $.rdfwidgets.statementsMatching( undefined, properties[h],undefined,undefined,false,o); 1735 var subjects = []; 1736 var count = total; 1737 for( var y= 0; y < tempsubjects.length; y++ ) { 1738 if( !done[tempsubjects[y].subject] ) { 1739 subjects.push(tempsubjects[y].subject); 1740 done[tempsubjects[y].subject]=true; 1741 total++; 1742 } 1743 } 1744 for( var i = 0; i < subjects.length; i++ ) { 1745 var fail = false; 1746 var row = "<tr>"; 1747 var subject = subjects[i]; 1748 //todo: row header. 1749 var id = randomID(); 1750 var td = "<td class='rdfeditheader'>"; 1751 var cell = "<div class='rdfeditheader' id='"+id+"'></div>"; 1752 var cellopts = {}; 1753 var tripopts = {subject: subject, predicate:null, object:null, selectable:false, editable:false}; 1754 $.extend( cellopts, o, tripopts ); 1755 optsArray[id]= cellopts; 1756 td += cell + "</td>"; 1757 row += td; 1758 for( var j = 0; j < h; j++ ) { 1759 row += "<td>"; 1760 id = randomID(); 1761 cell = "<div id='"+id+"'></div>"; 1762 cellopts = {}; 1763 tripopts = {subject: subject, predicate:properties[j]}; 1764 $.extend( cellopts, o, tripopts ); 1765 row+=cell+ "</td>"; 1766 optsArray[id] = cellopts; 1767 } 1768 for( var j = h; j < properties.length; j++ ) { 1769 td = "<td>"; 1770 var objects = $.rdfwidgets.each( subject, properties[j],undefined,undefined,o ); 1771 if( (!objects || objects.length == 0)) { 1772 if( o.requireall ) { 1773 fail = true; 1774 break; 1775 } else { 1776 id = randomID(); 1777 cell = "<div id='"+id+"'></div>"; 1778 cellopts = {}; 1779 tripopts = {subject: subject, predicate:properties[j]}; 1780 $.extend( cellopts, o, tripopts ); 1781 optsArray[id] = cellopts; 1782 td += cell; 1783 } 1784 } 1785 for( var k = 0; k < objects.length; k++ ) { 1786 id = randomID(); 1787 cell = "<div id='"+id+"'></div>"; 1788 cellopts = {}; 1789 tripopts = {subject: subject, predicate:properties[j], object:objects[k]}; 1790 $.extend( cellopts, o, tripopts ); 1791 optsArray[id] = cellopts; 1792 td += cell; 1793 } 1794 td+="</td>"; 1795 row += td; 1796 } 1797 if( !o.requireall || !fail ) { 1798 row += "</tr>"; 1799 html += row; 1800 } 1801 } 1802 } 1803 } 1804 html+= "</tbody></table>"; 1805 element.bind( "rdfdelete", function( e ) { 1806 var triple = $(e.target).edit("getTriple"); 1807 1808 if( triple ) { 1809 doDelete( [ triple ] , function( success ) { 1810 if( success ) { 1811 var parent = $(e.target).parent(); 1812 $(e.target).remove(); 1813 if( parent.children().size() == 0 ) { 1814 if( !o.requireall ) { 1815 id = randomID(); 1816 cell = "<div id='"+id+"'></div>"; 1817 cellopts = {}; 1818 tripopts = {subject: triple.subject, predicate:triple.predicate}; 1819 $.extend( cellopts, o, tripopts ); 1820 optsArray[id] = cellopts; 1821 $(parent).append(cell); 1822 $('#'+id).edit( cellopts ); 1823 } else { 1824 parent.parent().remove(); 1825 } 1826 } 1827 } else { 1828 alert( "Sorry, couldn't delete that." ); 1829 } 1830 }, o ); 1831 } else { 1832 alert( "Sorry, that triple can't be deleted yet for some reason." ); 1833 } 1834 }); 1835 element.html(html); 1836 1837 $(element).find('div').each( function() { 1838 var p = optsArray[this.id] 1839 if( p ) { 1840 if( p.editable ) { 1841 $(this).edit( optsArray[this.id] ); 1842 } else { 1843 $(this).label( optsArray[this.id] ); 1844 } 1845 } 1846 }); 1847 } 1848 }); 1849 1850 /** 1851 * @name jQuery.prototype.instancedropdown 1852 * @description Provide an autocomplete input that contains all instances of a given type. 1853 * @function 1854 * @param {Object} [options] @see CommonOptions 1855 * @param {String | Object} [options.type] If provided, only instances of the given type will be displayed in the dropdown. Otherwise, all instances in the local store are options. 1856 */ 1857 $.rdfwidget("ui.instancedropdown", { 1858 options: { 1859 namespaces:namespaces, 1860 showlinks:false, 1861 autocomplete:true 1862 }, 1863 _create: function() { 1864 this.refresh(); 1865 }, 1866 1867 disable: function() { 1868 }, 1869 1870 enable: function() { 1871 }, 1872 1873 refresh: function() { 1874 var o = this.options; 1875 var element = this.element; 1876 var that = this; 1877 var t = processResource( o.type, o ); 1878 this.triples = $.rdfwidgets.statementsMatching( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), t, undefined, false, o ); 1879 if( o.filterduplicates ) { 1880 this.triples = filterDuplicates( this.triples ); 1881 } 1882 var input = $("<input type='text'></input>"); 1883 doAutocomplete( input, {menuOptions: getMenuUsedOptions( { type: o.type, sources:o.sources } ) } ); 1884 input.bind( "autocompletechoice", function(e) { 1885 if( e.uri ) { 1886 element.trigger( "rdfselect", [db.sym(e.uri)] ); 1887 } else { 1888 alert( "Please enter a valid menu selection." ); 1889 } 1890 }); 1891 element.empty().append( input ); 1892 } 1893 }); 1894 1895 /** 1896 * @name jQuery.prototype.instancelist 1897 * @description Provide an list that contains all instances of a given type. 1898 * @function 1899 * @param {Object} [options] @see CommonOptions 1900 * @param {String | Object} [options.type] The rdf:type to filter instances by. 1901 */ 1902 $.rdfwidget("ui.instancelist", { 1903 options: { 1904 namespaces:namespaces, 1905 showlinks:false, 1906 autocomplete:true, 1907 subject:window.location 1908 }, 1909 _create: function() { 1910 this.refresh(); 1911 }, 1912 1913 disable: function() { 1914 }, 1915 1916 enable: function() { 1917 }, 1918 1919 refresh: function() { 1920 var o = this.options; 1921 var element = this.element; 1922 var that = this; 1923 var t = processResource( o.type, o ); 1924 this.triples = $.rdfwidgets.statementsMatching( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), t, undefined, false, o); 1925 if( o.filterduplicates ) { 1926 this.triples = filterDuplicates( this.triples ); 1927 } 1928 var html = "<table class='rdfinstancelist'><tbody>"; 1929 var ids = []; 1930 var id; 1931 for( var i = 0; i < this.triples.length; i++ ) { 1932 id = randomID(); 1933 ids.push( id ); 1934 html += "<tr><td id='"+id+"'></td></tr>"; 1935 } 1936 html += "</tbody></table>"; 1937 element.html(html); 1938 var opts,tripopts; 1939 for( var i = 0; i < ids.length; i++ ) { 1940 opts = {}; 1941 tripopts = {subject: that.triples[i].subject, selectable:true}; 1942 $.extend( opts, o, tripopts ); 1943 $('#'+ids[i]).label(opts); 1944 } 1945 } 1946 }); 1947 1948 /** 1949 * @name jQuery.prototype.checkbox 1950 * @description Let the user edit a triple by selecting which value(s) it takes on from a set of checkboxes. 1951 * @function 1952 * @param {Object} [options] @see CommonOptions 1953 * @param {Array} [options.choices] The set of Terms that are made available to choose from as checkboxes. 1954 * @param {String | Object} [options.subject] The subject of a statement to be matched. 1955 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 1956 * @param {String | Object} [options.object] The object of a statement to be matched. 1957 */ 1958 $.rdfwidget("ui.checkbox", { 1959 options: { 1960 namespaces:namespaces, 1961 showlinks:true, 1962 choices:[] 1963 }, 1964 _create: function() { 1965 this.groupname = randomID(); 1966 this.refresh(); 1967 }, 1968 1969 disable: function() { 1970 this.element.find('input').attr('disabled','disabled'); 1971 }, 1972 1973 enable: function() { 1974 this.element.find('input').attr('disabled',false); 1975 }, 1976 1977 _setOption: function( key ) { 1978 $.Widget.prototype._setOption.apply( this, arguments ); 1979 if ( key === "subject" || key === "predicate" || key === "object") { 1980 this.refresh(); 1981 } 1982 }, 1983 1984 refresh: function() { 1985 var o = this.options; 1986 var element = this.element; 1987 var that = this; 1988 processEditTerm( o ); 1989 var choices = []; 1990 var used = {}; 1991 var useda = []; 1992 var span = $('<span class="rdfcheckbox"></span>'); 1993 if( o.editTerm === "object" ) { 1994 for( var i = 0; i < o.choices.length; i++ ) { choices.push( processObject( o.choices[i], o ) ); } 1995 } else { 1996 for( var i = 0; i < o.choices.length; i++ ) { choices.push( processResource( o.choices[i], o ) ); } 1997 } 1998 var exist = $.rdfwidgets.each( (o.editTerm!=="subject" ? processResource(o.subject,o) : undefined ), (o.editTerm!=="predicate" ? processResource(o.predicate,o) : undefined ), (o.editTerm!=="object" ? processObject(o.object,o) : undefined ), undefined, o ); 1999 for( var i = 0; i < exist.length; i++ ) { 2000 choices.push( exist[i] ); 2001 } 2002 function handleCheck(e) { 2003 e.preventDefault(); 2004 var t = $(e.target); 2005 var selection = choices[Number($(this).val())]; 2006 t.attr("disabled","disabled"); 2007 var update = {insert_triples:[],delete_triples:[]}; 2008 if( !t.attr("checked") ) { 2009 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2010 o.predicate ? processResource( o.predicate,o ) : undefined, 2011 o.object ? processObject( o.object,o ) : undefined ); 2012 st[o.editTerm] = selection; 2013 var st2 = $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object,undefined,o ); 2014 st = st2 ? st2 : st; 2015 update.delete_triples.push( st ); 2016 } else { 2017 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2018 o.predicate ? processResource( o.predicate,o ) : undefined, 2019 o.object ? processObject( o.object,o ) : undefined ); 2020 st[o.editTerm] = selection; 2021 update.insert_triples.push( st ); 2022 } 2023 doUpdate( update, function( success ) { 2024 if( success ) { 2025 t.attr("checked",!t.attr("checked")); 2026 t.attr("disabled",false); 2027 } else { 2028 t.attr("disabled",false); 2029 alert( "Sorry, the server responded to your request with an error." ); 2030 } 2031 }, o); 2032 } 2033 2034 element.empty(); 2035 for( var i = 0; i < choices.length; i++ ) { 2036 if( !used[choices[i].value] ) { 2037 var id = randomID(); 2038 var div = $('<div class="rdfcheckbox" ></div>'); 2039 var cb = $('<input type="checkbox" name="'+this.groupname+'" id="'+id+'" value="'+useda.length+'"></input>'); 2040 var label = $('<label for="'+id+'">'+doLabel(choices[i],o)+'</label>'); 2041 span.append(div); 2042 div.append(cb); 2043 div.append(label); 2044 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2045 o.predicate ? processResource( o.predicate,o ) : undefined, 2046 o.object ? processObject( o.object,o ) : undefined ); 2047 st[o.editTerm] = choices[i]; 2048 if( $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object, undefined, o ) ) { 2049 cb.attr( "checked", "checked" ); 2050 } 2051 cb.bind("click", handleCheck); 2052 used[choices[i].value] = true; 2053 useda.push(choices[i].value); 2054 } 2055 } 2056 element.append(span); 2057 } 2058 2059 }); 2060 2061 /** 2062 * @name jQuery.prototype.radio 2063 * @description Let the user edit a triple by selecting which single value it takes on from a set of radio buttons. 2064 * @function 2065 * @param {Object} [options] @see CommonOptions 2066 * @param {Array} [options.choices] The set of choices the user may choose from as a set of radio buttons. 2067 * @param {String | Object} [options.subject] The subject of a statement to be matched. 2068 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 2069 * @param {String | Object} [options.object] The object of a statement to be matched. 2070 */ 2071 $.rdfwidget("ui.radio", { 2072 options: { 2073 namespaces:namespaces, 2074 2075 showlinks:true, 2076 choices:[] 2077 }, 2078 _create: function() { 2079 this.groupname = randomID(); 2080 this.refresh(); 2081 }, 2082 2083 disable: function() { 2084 this.element.find('input').attr('disabled','disabled'); 2085 }, 2086 2087 enable: function() { 2088 this.element.find('input').attr('disabled',false); 2089 }, 2090 2091 _setOption: function( key ) { 2092 $.Widget.prototype._setOption.apply( this, arguments ); 2093 if ( key === "subject" || key === "predicate" || key === "object") { 2094 this.refresh(); 2095 } 2096 }, 2097 2098 refresh: function() { 2099 var o = this.options; 2100 var element = this.element; 2101 var that = this; 2102 that.currentChoice = null; 2103 processEditTerm( o ); 2104 var initialValue; 2105 var choices = []; 2106 var used = {}; 2107 var useda = []; 2108 var span = $('<span class="rdfradio"></span>'); 2109 var temp = $.rdfwidgets.each( o.subject ? processResource( o.subject,o ) : undefined, 2110 o.predicate ? processResource( o.predicate,o ) : undefined, 2111 o.object ? processObject( o.object,o ) : undefined, undefined, o ); 2112 if( temp && temp.length > 1 ) { 2113 element.checkbox( o ); 2114 return; 2115 } 2116 if( o.editTerm === "object" ) { 2117 for( var i = 0; i < o.choices.length; i++ ) { choices.push( processObject( o.choices[i], o ) ); } 2118 } else { 2119 for( var i = 0; i < o.choices.length; i++ ) { choices.push( processResource( o.choices[i], o ) ); } 2120 } 2121 2122 if( temp && temp.length === 1 ) { 2123 initialValue = temp[0]; 2124 that.currentChoice = initialValue; 2125 choices.push( temp[0] ); 2126 } else { 2127 initialValue = null; 2128 } 2129 2130 function handleCheck(e) { 2131 e.preventDefault(); 2132 var selection = choices[Number($(this).val())]; 2133 if( that.currentChoice && selection.value === that.currentChoice.value ) { 2134 return; 2135 } 2136 element.find( "input" ).attr("disabled","disabled"); 2137 var update = {insert_triples:[],delete_triples:[]}; 2138 if( that.currentChoice ) { 2139 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2140 o.predicate ? processResource( o.predicate,o ) : undefined, 2141 o.object ? processObject( o.object,o ) : undefined ); 2142 st[o.editTerm] = that.currentChoice; 2143 var st2 = $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object, undefined, o ); 2144 st = st2 ? st2 : st; 2145 update.delete_triples.push( st ); 2146 } 2147 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2148 o.predicate ? processResource( o.predicate,o ) : undefined, 2149 o.object ? processObject( o.object,o ) : undefined ); 2150 st[o.editTerm] = selection; 2151 update.insert_triples.push( st ); 2152 doUpdate( update, function( success ) { 2153 if( success ) { 2154 $(e.target).attr("checked","checked"); 2155 that.currentChoice = selection; 2156 element.find( "input" ).attr("disabled",false); 2157 } else { 2158 element.find( "input" ).attr("disabled",false); 2159 alert( "Sorry, the server responded to your request with an error." ); 2160 } 2161 }, o); 2162 } 2163 2164 element.empty(); 2165 for( var i = 0; i < choices.length; i++ ) { 2166 if( !used[choices[i].value]) { 2167 var id = randomID(); 2168 var div = $('<div class="rdfradio"></div>'); 2169 var radio = $('<input class="rdfradio" type="radio" name="'+this.groupname+'" id="'+id+'" value="'+useda.length+'"></input>'); 2170 var label = $('<label for="'+id+'">'+doLabel(choices[i],o)+'</label>'); 2171 span.append(div); 2172 div.append(radio); 2173 div.append(label); 2174 if( initialValue && choices[i].value === initialValue.value ) { 2175 radio.attr("checked","checked"); 2176 } 2177 used[choices[i].value] = true; 2178 useda.push( choices[i].value ); 2179 radio.bind("click", handleCheck); 2180 } 2181 } 2182 element.append(span); 2183 }, 2184 getTriple: function() { 2185 var o = this.options; 2186 if( this.currentChoice ) { 2187 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2188 o.predicate ? processResource( o.predicate,o ) : undefined, 2189 o.object ? processObject( o.object,o ) : undefined ); 2190 st[o.editTerm] = this.currentChoice; 2191 return $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object, undefined, o ); 2192 } 2193 } 2194 2195 }); 2196 2197 $.ui.radio.getter = "getTriple"; 2198 2199 /** 2200 * @name jQuery.prototype.combobox 2201 * @description Let the user edit a triple by selecting which single value it takes on from a combobox. 2202 * @function 2203 * @param {Object} [options] @see CommonOptions 2204 * @param {Array} [options.choices] The set of choices the user may choose from as dropdown items in a combo box. 2205 * @param {String | Object} [options.subject] The subject of a statement to be matched. 2206 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 2207 * @param {String | Object} [options.object] The object of a statement to be matched. 2208 */ 2209 $.rdfwidget("ui.combobox", { 2210 options: { 2211 namespaces:namespaces, 2212 choices:[] 2213 }, 2214 _create: function() { 2215 this.refresh(); 2216 }, 2217 2218 disable: function() { 2219 this.combo.attr( "disabled", "disabled" ); 2220 }, 2221 2222 enable: function() { 2223 this.combo.attr( "disabled", false ); 2224 }, 2225 2226 getTriple: function() { 2227 var o = this.options; 2228 var term = this.ids[this.current.val()]; 2229 if( term && o.editTerm ) { 2230 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 2231 o.predicate ? processResource( o.predicate,o ) : undefined, 2232 o.object ? processObject( o.object,o ) : undefined ); 2233 st[o.editTerm] = term; 2234 return $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object, undefined, o ); 2235 } 2236 }, 2237 2238 _setOption: function( key ) { 2239 $.Widget.prototype._setOption.apply( this, arguments ); 2240 if ( key === "subject" || key === "predicate" || key === "object" || key === "editTerm" ) { 2241 this.refresh(); 2242 } 2243 }, 2244 2245 refresh: function() { 2246 var o = this.options; 2247 var element = this.element; 2248 var that = this; 2249 processEditTerm( o ); 2250 var ids = {}; 2251 var opt, term, id; 2252 var process = (o.editTerm === "object") ? processObject : processResource; 2253 var combo = $('<select class="rdfcombobox"></select>'); 2254 this.combo = combo; 2255 var initial = null; 2256 this.current = null; 2257 function addOption( str,hidden ) { 2258 term = process( str,o ); 2259 id = randomID(); 2260 if( !hidden ) { 2261 ids[id] = term; 2262 } 2263 opt = $('<option value="'+id+'" title="'+term.value.toString()+'"'+(hidden?' style="display:none"':'')+'>'+doLabel(term, o)+'</option>'); 2264 combo.append( opt ); 2265 return opt; 2266 } 2267 this.current = addOption( "", true ); 2268 var subject = ((o.editTerm === "subject") ? undefined : processResource(o.subject,o)); 2269 var predicate = ((o.editTerm === "predicate") ? undefined : processResource(o.predicate,o)); 2270 var object = ((o.editTerm === "object") ? undefined : processObject(o.object,o)); 2271 var existing = $.rdfwidgets.each( subject,predicate,object,undefined,o ); 2272 2273 var used = {}; 2274 var choices = []; 2275 for( var i = 0; i < o.choices.length; i++ ) { 2276 choices.push( process( o.choices[i], o ) ); 2277 } 2278 2279 if( existing ) { 2280 if( existing.length === 1 ) { 2281 initial = existing[0].value; 2282 choices.push( existing[0] ); 2283 } else if (existing.length > 1) { 2284 throw "Combobox functionality is only provided for patterns with a single value right now:"+existing; 2285 } 2286 } 2287 for( var i = 0; i < choices.length; i++ ) { 2288 if( !used[ choices[i].value ] ) { 2289 used[choices[i].value] = true; 2290 var opt = addOption( choices[i] ); 2291 if( choices[i].value === initial ) { 2292 opt.attr("selected","selected"); 2293 this.current = opt; 2294 } 2295 } 2296 } 2297 2298 element.empty().append(combo); 2299 combo.change( function( e ) { 2300 old = ids[that.current.val()]; 2301 var term = ids[e.target.value]; 2302 var d = processTripleUpdate( term, old, o ); 2303 combo.attr("disabled","disabled"); 2304 doUpdate( d, function( success ) { 2305 if( success ) { 2306 that.current = $(e.target).find(":selected"); 2307 } else { 2308 alert( "Sorry, the server responded to your request with an error." ); 2309 that.current.attr("selected","selected"); 2310 } 2311 combo.attr( "disabled", false ); 2312 }, o ); 2313 }); 2314 this.ids = ids; 2315 } 2316 }); 2317 2318 $.ui.combobox.getter = "getTriple"; 2319 2320 /** 2321 * @name jQuery.prototype.triplelist 2322 * @description Display the list of triples that match a given pattern. 2323 * @function 2324 * @param {Object} [options] @see CommonOptions 2325 * @param {String | Object} [options.subject] The subject of the statements to be matched. 2326 * @param {String | Object} [options.predicate] The predicate of the statements to be matched. 2327 * @param {String | Object} [options.object] The object of the statements to be matched. 2328 * @param {String | Object} [options.filterduplicates=false] Remove duplicate statements from multiple different data sources. 2329 */ 2330 $.rdfwidget("ui.triplelist", { 2331 options: { 2332 namespaces:namespaces, 2333 showlinks:false, 2334 autocomplete:true, 2335 filterduplicates:false 2336 }, 2337 _create: function() { 2338 this.refresh(); 2339 }, 2340 2341 _setOption: function( key ) { 2342 $.Widget.prototype._setOption.apply( this, arguments ); 2343 if ( key === "subject" || key === "predicate" || key === "object" ) { 2344 this.refresh(); 2345 } 2346 }, 2347 2348 refresh: function() { 2349 var o = this.options; 2350 var element = this.element; 2351 var that = this; 2352 var table = $('<table class="triplelist"></table>'); 2353 table.bind( "rdfdelete", function( e ) { 2354 var row = $(e.target).parent(); 2355 var triple = row.tripleedit( "getTriple" ); 2356 if( triple ) { 2357 doDelete( [ triple ] , function( success ) { 2358 if( success ) { 2359 row.remove(); 2360 } else { 2361 alert( "Sorry, the server responded to your edit request with an error." ); 2362 } 2363 }, o ); 2364 } else { 2365 alert( "Sorry, that triple can't be deleted yet for some reason." ); 2366 } 2367 }); 2368 element.empty().append(table); 2369 var subject = o.subject ? processResource( o.subject,o ) : undefined; 2370 var predicate = o.predicate ? processResource( o.predicate,o) : undefined; 2371 var object = o.object ? processObject( o.object, o) : undefined; 2372 this.triples = $.rdfwidgets.statementsMatching( subject,predicate,object, undefined, false, o ); 2373 if( o.filterduplicates ) { 2374 this.triples = filterDuplicates( this.triples ); 2375 } 2376 var rows = []; 2377 var html= "<tbody>"; 2378 for( var i = 0; i < this.triples.length; i++ ) { 2379 var t = this.triples[i]; 2380 var rid = randomID(), sid = null, pid = null, oid = null; 2381 html += "<tr id='"+rid+"'>"; 2382 if( !o.subject ) { 2383 sid = randomID(); 2384 html += "<td id='"+sid+"'></td>"; 2385 } 2386 if( !o.predicate ) { 2387 pid = randomID(); 2388 html += "<td id='"+pid+"'></td>"; 2389 } 2390 if( !o.object ) { 2391 oid = randomID(); 2392 html += "<td id='"+oid+"'></td>"; 2393 } 2394 html += "</tr>"; 2395 var opts = {}; 2396 var tripopts = {subject: t.subject, predicate: t.predicate, object: t.object, subjectElement: '#'+sid, predicateElement: '#'+pid, objectElement: '#'+oid}; 2397 $.extend( opts, o, tripopts ); 2398 rows.push({r:rid,o:opts}); 2399 } 2400 html += "</tbody>"; 2401 table.append( html ); 2402 2403 for( var i = 0; i < rows.length; i++ ) { 2404 $('#'+rows[i].r).tripleedit(rows[i].o); 2405 } 2406 } 2407 }); 2408 2409 /** 2410 * @name jQuery.prototype.toolbar 2411 * @description Display an image for each resource of a certain type in a toolbar layout. 2412 * @function 2413 * @param {Object} [options] @see CommonOptions 2414 * @param {String | Object} [options.type] The rdf:type that should be used to decide which resources will appear in the toolbar. 2415 */ 2416 $.rdfwidget("ui.toolbar", { 2417 options: { 2418 namespaces:namespaces, 2419 width:32, 2420 height:32 2421 }, 2422 _create: function() { 2423 this.refresh(); 2424 }, 2425 2426 disable: function() { 2427 element.find( "td" ).each( function() { 2428 $(this).image("disable"); 2429 }); 2430 }, 2431 2432 enable: function() { 2433 element.find( "td" ).each( function() { 2434 $(this).image("enable"); 2435 }); 2436 }, 2437 2438 refresh: function() { 2439 var o = this.options; 2440 var element = this.element; 2441 var that = this; 2442 var t = processResource( o.type, o ); 2443 2444 if( o.choices ) { 2445 this.choices = o.choices; 2446 } else { 2447 this.choices = $.rdfwidgets.each( undefined, db.sym("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), t, undefined, o ); 2448 } 2449 var html = "<table class='rdftoolbar'><tr>"; 2450 var actual = []; 2451 2452 for( var i = 0; i < this.choices.length; i++ ) { 2453 if( (o.mappings && o.mappings[this.choices[i]]) || doImage( processResource(this.choices[i],o),o) ) { 2454 actual.push( this.choices[i] ); 2455 html += "<td width="+o.width+" height="+o.height+" class='rdftoolbar' style='margin:1px'></td>"; 2456 } 2457 } 2458 html += "</tr></table>"; 2459 element.html(html); 2460 element.find( "td" ).each( function(i) { 2461 var opts = {}; 2462 var tripopts = {subject: actual[i], selectable:true}; 2463 $.extend( opts, o, tripopts ); 2464 $(this).image(opts); 2465 }); 2466 } 2467 }); 2468 2469 /** 2470 * @name jQuery.prototype.resource 2471 * @description Display a table containing all of the properties of a given resource. 2472 * @function 2473 * @param {Object} [options] @see CommonOptions 2474 * @param {String | Object} [options.subject] the URI of the resource to be described. 2475 */ 2476 $.rdfwidget("ui.resource", { 2477 options: { 2478 namespaces:namespaces, 2479 showlinks:false, 2480 autocomplete:true, 2481 subject:window.location 2482 }, 2483 _create: function() { 2484 this.refresh(); 2485 }, 2486 2487 disable: function() { 2488 }, 2489 2490 enable: function() { 2491 }, 2492 2493 _setOption: function( key ) { 2494 $.Widget.prototype._setOption.apply( this, arguments ); 2495 if ( key === "subject" ) { 2496 this.refresh(); 2497 } 2498 }, 2499 2500 refresh: function() { 2501 var o = this.options; 2502 var element = this.element; 2503 var that = this; 2504 var div = $('<div></div>'); 2505 var table = $('<table class="rdfresourceedit"></table>'); 2506 table.bind( "rdfdelete", function( e ) { 2507 var row = $(e.target).parent(); 2508 var triple = row.tripleedit( "getTriple" ); 2509 if( triple ) { 2510 doDelete( [ triple ] , function( success ) { 2511 if( success ) { 2512 row.remove(); 2513 } else { 2514 alert( "Sorry, couldn't delete that." ); 2515 } 2516 }, o ); 2517 } else { 2518 alert( "Sorry, that triple can't be deleted yet for some reason." ); 2519 } 2520 }); 2521 div.append(table); 2522 element.empty().append(div); 2523 var subject = processResource( o.subject,o ); 2524 this.triples = $.rdfwidgets.statementsMatching( subject,undefined,undefined,undefined,false,o ); 2525 var hid = randomID(); 2526 var thead = "<thead><tr class='rdfeditheader'><td id='"+hid+"' colspan=2></td></tr></thead>"; 2527 table.append(thead); 2528 $('#'+hid).label( {showlinks:o.showlinks,subject:o.subject, selectable:true } ); 2529 var tbody = "<tbody>"; 2530 var id, ids = [], opts, tripopts; 2531 var sopts = []; 2532 for( var i = 0; i < this.triples.length; i++ ) { 2533 id = { p:randomID(),r:randomID(),o:randomID() }; 2534 ids.push(id); 2535 var tr = '<tr id="'+id.r+'"><td id="'+id.p+'"></td><td id="'+id.o+'"></td></tr>'; 2536 var opts = {}; 2537 var tripopts = {subject: this.triples[i].subject, predicate: this.triples[i].predicate, object: this.triples[i].object, subjectElement: null, predicateElement: '#'+id.p, objectElement: '#'+id.o }; 2538 $.extend( opts, o, tripopts ); 2539 sopts.push( opts ); 2540 tbody+=tr; 2541 } 2542 tbody += "</tbody>"; 2543 table.append( tbody ); 2544 2545 for( var i = 0; i < this.triples.length; i++ ) { 2546 $('#'+ids[i].r).tripleedit( sopts[i] ); 2547 } 2548 var addButton = $('<input type="button" value="Add..."></input>'); 2549 div.append(addButton); 2550 addButton.click( function() { 2551 var addTable = $('<table class="rdfaddtriple"></table'); 2552 addTable.append('<tr><th colspan="2">Add Data</th></tr>'); 2553 var rowid1 = randomID(); 2554 var rowid2 = randomID(); 2555 var firstRow = $('<tr><td><label for="'+rowid1+'">Property: </label></td></tr>'); 2556 var secondRow = $('<tr><td><label for="'+rowid2+'">Value: </label></td></tr>'); 2557 var firstInput = $('<input name="'+rowid1+'" type="text"></input>'); 2558 var secondInput = $('<input name="'+rowid2+'" type="text"></input>'); 2559 2560 doAutocomplete( firstInput, { menuOptions:getMenuPredicateOptions( {} ) } ); 2561 doAutocomplete( secondInput, { menuOptions:getMenuInstanceOptions( {} ) } ); 2562 2563 var lastPred, lastPredInput, lastObj, lastObjInput; 2564 2565 firstInput.bind( "autocompletechoice", function(e) { 2566 lastPred = e.uri; 2567 lastPredInput = e.input; 2568 }); 2569 2570 secondInput.bind( "autocompletechoice", function(e) { 2571 lastObj = e.uri; 2572 lastObjInput = e.input; 2573 }); 2574 secondInput.focus( function() { 2575 doAutocomplete( secondInput, { menuOptions:getMenuInstanceOptions( {subject:o.subject, predicate:lastPred, editTerm:"object"} ) } ); 2576 }) 2577 firstRow.append(firstInput); 2578 secondRow.append(secondInput); 2579 addTable.append(firstRow).append(secondRow); 2580 var addPopup = $('<div style="position:absolute; display:none" class="rdfaddpropertypopup"></div>'); 2581 var closeButton = $('<a style="position:absolute" href="#">X</a>'); 2582 var submitButton = $('<input type="button" value="Submit"></input>'); 2583 submitButton.click( function() { 2584 if( !lastPred ) { 2585 alert( "You must enter a valid property."); 2586 return; 2587 }else if( !lastObjInput ) { 2588 alert( "You must enter a value." ); 2589 return; 2590 } else { 2591 var pred = processResource( lastPred, o ); 2592 var obj; 2593 if( lastObj ) { 2594 obj = processResource( lastObj, o ); 2595 } else { 2596 obj = processObject( lastObjInput, o ); 2597 } 2598 var triple = new $rdf.Statement( subject, pred, obj ); 2599 if( !$.rdfwidgets.anyStatementMatching( subject, pred, obj,undefined, o ) ) { 2600 doInsert( [ triple ], function( success ) { 2601 if( success ) { 2602 var predicateTD = $('<td class="'+((2%2===0) ? 'rdfediteven' : 'rdfeditodd')+'"></td>'); 2603 var objectTD = $('<td class="'+((2%2===0) ? 'rdfediteven' : 'rdfeditodd')+'"></td>'); 2604 var TR = $('<tr class="'+((2%2===0) ? 'rdfediteven' : 'rdfeditodd')+'"></tr>'); 2605 2606 table.append(TR); 2607 TR.append(predicateTD); 2608 TR.append(objectTD); 2609 var opts = {}; 2610 var tripopts = {subject: subject, predicate: pred, object: obj, subjectElement: null, predicateElement: predicateTD, objectElement: objectTD }; 2611 $.extend( opts, o, tripopts ); 2612 TR.tripleedit(opts); 2613 addPopup.hide("fast"); 2614 } else { 2615 alert( "Sorry, the triple could not be inserted at this time." ); 2616 } 2617 }, o ); 2618 } else { 2619 alert( "Good news: the triple you created already exists!" ); 2620 } 2621 } 2622 }); 2623 closeButton.click( function() { 2624 addPopup.hide("fast"); 2625 }); 2626 addPopup.append(closeButton); 2627 addPopup.append( addTable ); 2628 addPopup.append( submitButton ); 2629 var pos = addButton.offset(); 2630 var width = addButton.outerWidth(); 2631 var height = addButton.outerHeight(); 2632 div.append( addPopup ); 2633 closeButton.css( { "right": "2px", "top": "2px" } ); 2634 addPopup.css( {"left": (pos.left + width) + "px", "top":(pos.top+height) + "px" } ); 2635 2636 addPopup.show("fast"); 2637 }); 2638 } 2639 }); 2640 2641 /** 2642 * @name jQuery.prototype.createinstance 2643 * @description Create a form for creating new information about an as-yet undescribed object. 2644 * @function 2645 * @param {Object} [options] @see CommonOptions 2646 * @param {Object} [options.properties] An array of create instance options. Each object must at least have a property field, which defines which predicate the form input will obtain an object for. More coming soon. 2647 */ 2648 $.rdfwidget("ui.createinstance", { 2649 options: { 2650 namespaces:namespaces, 2651 showlinks:false, 2652 autocomplete:true 2653 }, 2654 _create: function() { 2655 this.refresh(); 2656 }, 2657 2658 disable: function() { 2659 element.find("input").attr("disabled","disabled"); 2660 element.find("textarea").attr("disabled","disabled"); 2661 }, 2662 2663 enable: function() { 2664 element.find("input").attr("disabled",false); 2665 element.find("textarea").attr("disabled",false); 2666 }, 2667 2668 refresh: function() { 2669 var o = this.options; 2670 var element = this.element; 2671 var that = this; 2672 var items = o.items; 2673 var itemIDs = []; 2674 var map = {}; 2675 var form = $('<form class="rdfcreateinstance"></form>'); 2676 var table = $('<table class="rdfcreateinstance"></table>'); 2677 var staticTriples = []; 2678 var why = db.sym(getEndpoint( null, o )); 2679 o.editTerm="object"; 2680 2681 if( o.items ) { 2682 for( var i=0; i < items.length; i++ ) { 2683 var item = items[i]; 2684 if ( item.type == "hidden" ) { 2685 if( item.predicate && item.object ) { 2686 staticTriples.push(item); 2687 } 2688 continue; 2689 } 2690 2691 var id = randomID(); 2692 if( !item.predicate ) { 2693 continue; 2694 } 2695 itemIDs.push( id ); 2696 map[id] = item; 2697 var row = $("<tr></tr>"); 2698 var p = processResource( item.predicate, o ); 2699 if( !item.type || item.type == "text" ) { 2700 var td = $("<td></td>"); 2701 var label = $("<td><label for='"+id+"'>"+doLabel( p, o )+"</label></td>"); 2702 var input = $("<input id='"+id+"' name='"+id+"' type='text'></input>"); 2703 td.append(input); 2704 row.append(label).append(td); 2705 var opts = {}; 2706 //todo: inputopts used to be {predicate:p} 2707 var inputopts = item; 2708 $.extend( opts, o, item, inputopts ); 2709 doAutocomplete( input, opts ); 2710 table.append(row); 2711 } else if ( item.type == "textarea" ) { 2712 var td = $("<td></td>"); 2713 var label = $("<td><label for='"+id+"'>"+doLabel( p, o )+"</label></td>"); 2714 var input = $("<textarea id='"+id+"' name='"+id+"' ></textarea>"); 2715 td.append(input); 2716 row.append(label).append(td); 2717 var opts = {}; 2718 var inputopts = {subject:(o.subject ? processResource(o.subject) : (o.baseURI ? db.sym(o.baseURI + '#' + randomID()) : db.sym( window.location + '#' + randomID() ) ) ), predicate: p }; 2719 $.extend( opts, o, item, inputopts ); 2720 doAutocomplete( input, opts ); 2721 table.append(row); 2722 } 2723 } 2724 } 2725 2726 form.append(table); 2727 var submit = $('<input type="submit" value="Submit"></input>'); 2728 form.append(submit); 2729 var disableAll = function() { 2730 for( var i=0; i<itemIDs.length; i++ ) { $('#'+itemIDs[i]).attr("disabled","disabled"); } 2731 submit.attr("disabled","disabled"); 2732 }; 2733 var enableAll = function() { 2734 for( var i=0; i<itemIDs.length; i++ ) { $('#'+itemIDs[i]).attr("disabled",false); } 2735 submit.attr("disabled",false); 2736 }; 2737 form.submit( function(e) { 2738 e.preventDefault(); 2739 disableAll(); 2740 var subject = o.subject ? processResource(o.subject) : (o.baseURI ? db.sym(docpart(o.baseURI) + '#' + randomID()) : db.sym( docpart(window.location.toString()) + '#' + randomID() ) ); 2741 var triples = []; 2742 for( var i=0; i<itemIDs.length; i++ ) { 2743 var id = itemIDs[i]; 2744 var item = map[id]; 2745 var elt = $('#'+id); 2746 var uri = elt.data("uri"); 2747 var lastAC = elt.data("val"); 2748 var val = elt.val(); 2749 if( val === lastAC ) { 2750 if( uri ) { 2751 triples.push( new $rdf.Statement( subject, processResource( item.predicate ), processResource( uri ), subject ) ); 2752 } else { 2753 triples.push( new $rdf.Statement( subject, processResource( item.predicate ), processLiteral( val ), subject ) ); 2754 } 2755 } else { 2756 triples.push( new $rdf.Statement( subject, processResource( item.predicate ), processLiteral( val ), subject ) ); 2757 } 2758 } 2759 for( var i = 0; i < staticTriples.length; i++ ) { 2760 triples.push( new $rdf.Statement( subject, processResource( staticTriples[i].predicate ), processObject( staticTriples[i].object ), subject ) ); 2761 } 2762 2763 doInsert( triples , function(success) { 2764 if( success ) { 2765 } else { 2766 alert( "Sorry, an error occurred during the submission of your information." ); 2767 } 2768 enableAll(); 2769 },o); 2770 return false; 2771 }); 2772 element.empty().append(form); 2773 } 2774 }); 2775 2776 2777 /** 2778 * @name jQuery.prototype.sourcelist 2779 * @description Display a list of all sources currently in use by the widget library. 2780 * @function 2781 */ 2782 $.rdfwidget("ui.sourcelist", { 2783 options: { 2784 }, 2785 _create: function() { 2786 this.refresh(); 2787 }, 2788 2789 disable: function() { 2790 }, 2791 2792 enable: function() { 2793 }, 2794 2795 refresh: function() { 2796 var o = this.options; 2797 var element = this.element; 2798 element.empty(); 2799 var span = $('<span class="rdfsourcelist"></span>'); 2800 2801 var html = "<div class='rdfsourcelisttitle'>Sources</div>"; 2802 for( var x in loadedSources ) { 2803 html += "<div class='rdfsourcelist'><a href='"+x+"' title='"+doLabel(db.sym(x),o)+"'>"+x+"</a></div>"; 2804 } 2805 span.html(html); 2806 element.append(span); 2807 }, 2808 2809 insertData: function(d) { 2810 this.refresh(); 2811 }, 2812 2813 deleteData: function(d) { 2814 this.refresh(); 2815 } 2816 }); 2817 2818 2819 getNodeSubject = function( node ) { 2820 var current = $(node); 2821 var subject; 2822 while( current.length > 0 ) { 2823 about = current.attr("about"); 2824 var nn = current.get(0).nodeName; 2825 if( nn && nn.toLowerCase() === "a" ) { 2826 subject = join( current.get(0).href, window.location.toString() ); 2827 break; 2828 } 2829 if( about ) { 2830 if( about.indexOf("[") === 0 ) { 2831 //TODO: support safe curies.. 2832 continue; 2833 } else { 2834 subject = join( about, window.location.toString() ); 2835 break; 2836 } 2837 } 2838 current = current.parent(); 2839 } 2840 if( !subject ) { 2841 subject = window.location.toString(); 2842 } 2843 return subject; 2844 } 2845 2846 /** 2847 * @name jQuery.prototype.annotator 2848 * @description Display an annotation box when any element inside of a certain element is shift+clicked. 2849 * @function 2850 * @param {Object} [options] @see CommonOptions 2851 * @param {String | Object} [options.displayElement] A valid jQuery constructor argument that determines where the annotations will be displayed when an item is selected. If not provided, the annotations will be displayed in a floating popup. 2852 */ 2853 $.rdfwidget("ui.annotator", { 2854 options: { 2855 }, 2856 2857 _findSubject: function( current ) { 2858 var subject; 2859 while( current.length > 0 ) { 2860 about = current.attr("about"); 2861 var nn = current.get(0).nodeName; 2862 if( nn && nn.toLowerCase() === "a" ) { 2863 subject = join( current.get(0).href, window.location.toString() ); 2864 break; 2865 } 2866 if( about ) { 2867 if( about.indexOf("[") === 0 ) { 2868 //TODO: support safe curies.. 2869 continue; 2870 } else { 2871 subject = join( about, window.location.toString() ); 2872 break; 2873 } 2874 } 2875 current = current.parent(); 2876 } 2877 if( !subject ) { 2878 subject = window.location.toString(); 2879 } 2880 return subject; 2881 }, 2882 2883 _create: function() { 2884 var annotator; 2885 var o = this.options; 2886 if( o.displayElement ) { 2887 annotator = $("<div class='rdfannotator'></div>"); 2888 } else { 2889 annotator = $("<div class='rdfannotator' style='display:none; position:absolute'></div>"); 2890 } 2891 var that=this; 2892 var filters = processSourceFilter( o.sources, o ); 2893 function doCommentBox( e ) { 2894 if( !e.target || !e.shiftKey ) { 2895 return; 2896 } 2897 if( e.stopPropagation ) { 2898 e.stopPropagation(); 2899 e.preventDefault(); 2900 } 2901 var current = $(e.target); 2902 that.current = current; 2903 var about; 2904 var subject = that._findSubject( current ); 2905 annotator.empty(); 2906 var listdiv = $("<div class='rdfannotatorlist'></div>"); 2907 that.listdiv = listdiv; 2908 that._matcher( listdiv ) 2909 .match( "?comment", "http://rdfs.org/sioc/ns#topic", processResource( subject ) ) 2910 .match( "?comment", "http://rdfs.org/sioc/ns#content", "?content" ) 2911 .match( "?comment", "http://rdfs.org/sioc/ns#has_creator", "?user" ) 2912 .page("<div class='rdfannotatorcomment'><div><a href='?user'>@user</a> wrote...</div><div><p>?content</p></div></div>", 4); 2913 2914 var user = $.rdfwidgets.getDefaultUser(); 2915 if( !user ) { user = SW_PREFIX + "Anonymous"; } 2916 annotator.append(listdiv); 2917 var lid = randomID(); 2918 annotator.append( "<div class='rdfannotatortitle'>Add a comment about <span id='"+lid+"' title='"+subject+"'>"+subject+"</span></div>" ); 2919 $('#'+lid).label({subject: db.sym(subject), selectable:false}) 2920 var formdiv = $("<div class='rdfannotatorform'></div>"); 2921 var opts = $.extend({},that.options,{afterSubmit:function(s) { if(s && !o.displayElement) { annotator.hide("fast"); } }, 2922 items:[{type:"textarea", 2923 predicate:"http://rdfs.org/sioc/ns#content", 2924 menuOptions:getMenuNoOptions()}, 2925 {type:"hidden", 2926 predicate:"http://rdfs.org/sioc/ns#has_creator", 2927 object:db.sym( user ) 2928 }, 2929 {type:"hidden", 2930 predicate:"http://rdfs.org/sioc/ns#topic", 2931 object:subject 2932 }, 2933 {type:"hidden", 2934 predicate:"http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 2935 object:"http://rdfs.org/sioc/types#Comment" 2936 }], 2937 acl:( o.acl ? o.acl : { 2938 type:"permanent" 2939 } )}); 2940 formdiv.createinstance(opts); 2941 annotator.append(formdiv); 2942 if( !o.displayElement ) { 2943 var closeButton = $('<a style="position:absolute" href="#">X</a>'); 2944 annotator.css({left:e.pageX+"px", top:e.pageY+"px"}); 2945 closeButton.click( function() { 2946 annotator.hide("fast"); 2947 }); 2948 closeButton.css( { "right": "2px", "top": "2px" } ); 2949 annotator.append( closeButton ); 2950 annotator.show("fast"); 2951 } 2952 } 2953 2954 this.element.bind( "click", doCommentBox ); 2955 if( o.displayElement ) { 2956 $(o.displayElement).append( annotator ); 2957 doCommentBox({target:this.element, shiftKey:true}); 2958 } else { 2959 $(document.body).append(annotator); 2960 } 2961 }, 2962 2963 disable: function() { 2964 }, 2965 2966 enable: function() { 2967 }, 2968 2969 refresh: function() { 2970 this._matcher( this.listdiv ) 2971 .match( "?comment", "http://rdfs.org/sioc/ns#topic", processResource( this._findSubject( this.current ) ) ) 2972 .match( "?comment", "http://rdfs.org/sioc/ns#content", "?content" ) 2973 .match( "?comment", "http://rdfs.org/sioc/ns#has_creator", "?user" ) 2974 .page("<div class='rdfannotatorcomment'><div><a href='?user'>@user</a> wrote...</div><div><p>?content</p></div></div>", 4); 2975 } 2976 }); 2977 2978 /** 2979 * @name jQuery.prototype.sourceview 2980 * @description Serialize the entire local store as N3 and display it in a text box. 2981 * @function 2982 */ 2983 $.rdfwidget("ui.sourceview", { 2984 options: { 2985 format:"n3" 2986 }, 2987 _create: function() { 2988 this.refresh(); 2989 }, 2990 2991 disable: function() { 2992 }, 2993 2994 enable: function() { 2995 }, 2996 2997 refresh: function() { 2998 var o = this.options; 2999 var element = this.element; 3000 element.empty(); 3001 var pre = $('<pre class="rdfsourceview"></pre>'); 3002 var s = $rdf.Serializer( data ); 3003 3004 var text; 3005 if( o.format === "xml" ) { 3006 text = s.statementsToXML( db.statements ); 3007 } else { 3008 text = s.toN3( db ); 3009 } 3010 3011 pre.text( text ); 3012 element.append(pre); 3013 } 3014 }); 3015 3016 /** 3017 * @name jQuery.prototype.image 3018 * @description Search for a valid image depicting a given resource and display it. Currently, bases this search off of the foaf:depiction property, dbpedia img property, and their subproperties. 3019 * @function 3020 * @param {Object} [options] @see CommonOptions 3021 * @param {String | Object} [options.subject] The resource to display an image of OR if predicate or object is defined, the subject of a statement to be matched. 3022 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 3023 * @param {String | Object} [options.object] The object of a statement to be matched. 3024 * @param {String | Number} [options.width] The width, in pixels, that the image should be displayed with (height will be scaled). 3025 * @param {String | Number} [options.height] The height, in pixels, that the image should be displayed with (width will be scaled). 3026 */ 3027 $.rdfwidget("ui.image", { 3028 options: { 3029 namespaces:namespaces, 3030 selectable:true 3031 }, 3032 _create: function() { 3033 this.originalEditTerm = this.options.editTerm; 3034 this.rdfvalue = null; 3035 this.refresh(); 3036 }, 3037 refresh: function() { 3038 var element = this.element; 3039 var o = this.options; 3040 var that = this; 3041 o.editTerm = this.originalEditTerm; 3042 3043 if( !( o.subject && !o.predicate && !o.object ) ) { 3044 processEditTerm( o ); 3045 } else { 3046 o.editTerm = "subject"; 3047 } 3048 3049 var subject, predicate, object; 3050 if( o.subject ) { subject = processResource(o.subject, o); } 3051 if( o.predicate ) { predicate = processResource(o.predicate, o); } 3052 if( o.object ) { object = processObject( o.object, o ); } 3053 3054 var temp; 3055 var output = null; 3056 var type; 3057 var filters = processSourceFilter( o.sources, o ); 3058 if( o.subject && !o.object && !o.predicate ) { 3059 output = subject; 3060 } else if( o.editTerm==="object" || !o.editTerm ) { 3061 if( object ) { output = object; } 3062 else { 3063 temp = $.rdfwidgets.any( (subject ? subject : undefined), (predicate ? predicate : undefined), undefined, undefined, o); 3064 if( temp ) { output = temp; } 3065 } 3066 } else if( o.editTerm==="predicate" ) { 3067 if( predicate ) { output = predicate; } 3068 else { 3069 temp = $.rdfwidgets.any( (subject ? subject : undefined), undefined,(object ? object : undefined), undefined, o ); 3070 if( temp ) { output = temp; } 3071 } 3072 } else if( o.editTerm==="subject" ) { 3073 o.editTerm="subject"; 3074 if( subject ) { output = subject; } 3075 else { 3076 temp = $.rdfwidgets.any( undefined, (predicate ? predicate : undefined),(object ? object : undefined), undefined, o ); 3077 if( temp ) { output = temp; } 3078 } 3079 } 3080 var stringLabel; 3081 if( !output ) { 3082 return; 3083 } else if( output.termType === "symbol" ) { 3084 stringLabel = doLabel(output, o); 3085 this.rdfvalue = output; 3086 } else { 3087 stringLabel = output.value; 3088 this.rdfvalue = output; 3089 } 3090 3091 if( o.selectable ) { 3092 element.click( function(e) { 3093 e.stopPropagation(); 3094 setSelected( element, that.rdfvalue ); 3095 } ); 3096 } 3097 var imageuri = null; 3098 if( o.mappings ) { 3099 imageuri = o.mappings[output.value]; 3100 } 3101 if( !imageuri && "symbol" === output.termType && o.editTerm !== "predicate" ) { 3102 var im = isImage( output, o ); 3103 if( im ) { 3104 imageuri = im.value; 3105 } 3106 } 3107 if( !imageuri && "symbol" === output.termType ) { 3108 var im = doImage( output, o ); 3109 if( im ) { 3110 imageuri = im.value; 3111 } 3112 } 3113 if( imageuri ) { 3114 output = "<span class='rdfimage'><img class='rdfimage' style='display:none' "+"src='"+imageuri+"' title='"+doLabel(output,o)+" "+output.value+"'></img></span>"; 3115 this.element.empty().html(output); 3116 $(element).find( "img" ).one( "load", function() { 3117 var im = $(this).show(0); 3118 var width = im.width(); // Current image width 3119 var height = im.height(); // Current image height 3120 3121 var maxWidth = o.width?o.width:width; // Max width for the image 3122 var maxHeight = o.height?o.height:height; // Max height for the image 3123 var ratio = 0; // Used for aspect ratio 3124 3125 // Check if the current width is larger than the max 3126 if(width > maxWidth){ 3127 ratio = maxWidth / width; // get ratio for scaling image 3128 height = height * ratio; // Reset height to match scaled image 3129 width = width * ratio; // Reset width to match scaled image 3130 } 3131 3132 // Check if current height is larger than max 3133 if(height > maxHeight){ 3134 ratio = maxHeight / height; // get ratio for scaling image 3135 width = width * ratio; // Reset width to match scaled image 3136 height = height * ratio; 3137 } 3138 im.css("width", width); // Set new width 3139 im.css("height", height); // Scale height based on ratio 3140 3141 }); 3142 } 3143 }, 3144 _setOption: function( key ) { 3145 $.Widget.prototype._setOption.apply( this, arguments ); 3146 if ( key === "subject" || key === "predicate" || key === "object" || key === "editTerm" ) { 3147 this.refresh(); 3148 } 3149 }, 3150 getRDFValue: function() { 3151 return this.rdfvalue; 3152 }, 3153 getTriple: function() { 3154 var o = this.options; 3155 if( this.rdfvalue && o.editTerm ) { 3156 var st = new $rdf.Statement( o.subject ? processResource( o.subject,o ) : undefined, 3157 o.predicate ? processResource( o.predicate,o ) : undefined, 3158 o.object ? processObject( o.object,o ) : undefined ); 3159 st[o.editTerm] = this.rdfvalue; 3160 return $.rdfwidgets.anyStatementMatching( st.subject, st.predicate, st.object, undefined, o ); 3161 } 3162 return null; 3163 } 3164 }); 3165 3166 $.ui.image.getter = "getRDFValue getTriple"; 3167 3168 /** 3169 * @name jQuery.prototype.label 3170 * @description Display a simple text label for a given resource or implied resource. 3171 * @param {String | Object} [options.subject] The resource to display a label for OR if predicate or object is defined, the subject of a statement to be matched. 3172 * @param {String | Object} [options.predicate] The predicate of a statement to be matched. 3173 * @param {String | Object} [options.object] The object of a statement to be matched. 3174 * @param {Boolean} [options.showlinks=true] If false, labels for Symbols will not contain hyperlinks. 3175 * @param {Boolean} [options.selectable=true] If false, the item will not be selectable and will not fire the rdfselect event. 3176 * @function 3177 * @param {Object} [options] @see CommonOptions 3178 */ 3179 $.rdfwidget("ui.label", { 3180 options: { 3181 namespaces:namespaces, 3182 selectable:false, 3183 showlinks:true 3184 }, 3185 _create: function() { 3186 this.originalEditTerm = this.options.editTerm; 3187 this.rdfvalue = null; 3188 this.refresh(); 3189 }, 3190 refresh: function() { 3191 var element = this.element; 3192 var o = this.options; 3193 var that = this; 3194 o.editTerm = this.originalEditTerm; 3195 3196 3197 if( !( o.subject && !o.predicate && !o.object ) ) { 3198 processEditTerm( o ); 3199 } else { 3200 o.editTerm = "subject"; 3201 } 3202 3203 3204 var subject, predicate, object; 3205 if( o.subject ) { subject = that._resource(o.subject); } 3206 if( o.predicate ) { predicate = that._resource(o.predicate); } 3207 if( o.object ) { object = processObject( o.object, o ); } 3208 var temp; 3209 var output = "<span class='rdflabel rdflabelempty'>None</span>"; 3210 var type; 3211 3212 if( o.subject && !o.object && !o.predicate ) { 3213 output = subject; 3214 } else if( o.editTerm==="object" ) { 3215 if( object ) { 3216 output = object; 3217 } 3218 else { 3219 temp = $.rdfwidgets.any( (subject ? subject : undefined), (predicate ? predicate : undefined), undefined, undefined, o); 3220 if( temp ) { o.object = temp; output = temp; } 3221 } 3222 3223 } else if( o.editTerm==="predicate" ) { 3224 if( predicate ) { 3225 output = predicate; 3226 } 3227 else { 3228 temp = $.rdfwidgets.any( (subject ? subject : undefined), undefined,(object ? object : undefined), undefined, o ); 3229 if( temp ) { o.predicate = temp; output = temp; } 3230 } 3231 } else if( o.editTerm==="subject" ) { 3232 if( subject ) { 3233 output = subject; 3234 } 3235 else { 3236 temp = $.rdfwidgets.any( undefined, (predicate ? predicate : undefined),(object ? object : undefined), undefined, o ); 3237 if( temp ) { o.subject = temp; output = temp; } 3238 } 3239 } 3240 3241 var stringLabel; 3242 if( typeof( output ) === "string" ) { 3243 stringLabel = output; 3244 } else if( o.label ) { 3245 stringLabel = o.label; 3246 this.rdfvalue = output; 3247 } else if( output.termType === "symbol" ) { 3248 stringLabel = doLabel(output, o); 3249 this.rdfvalue = output; 3250 } else { 3251 stringLabel = output.value; 3252 this.rdfvalue = output; 3253 } 3254 3255 if( o.selectable ) { 3256 element.click( function(e) { 3257 e.stopPropagation(); 3258 setSelected( element, that.rdfvalue ); 3259 } ); 3260 } 3261 3262 if( true === o.showlinks && output.termType === "symbol" ) { 3263 output = "<span class='rdflabel'><a href='"+output.value+"'>"+(o.linkText ? o.linkText : stringLabel)+"</a></span>"; 3264 } else if( typeof(output) !== "string" ){ 3265 output = "<span class='rdflabel' title='"+(output.value ? output.value : stringLabel)+"'>"+stringLabel+"</span>"; 3266 } 3267 this.element.html(output); 3268 }, 3269 _setOption: function( key ) { 3270 $.Widget.prototype._setOption.apply( this, arguments ); 3271 if ( key === "subject" || key === "predicate" || key === "object" || key === "editTerm" ) { 3272 this.refresh(); 3273 } 3274 }, 3275 getRDFValue: function() { 3276 return this.rdfvalue; 3277 }, 3278 getTriple: function() { 3279 var o = this.options; 3280 if( o.subject && o.predicate && o.object ) { 3281 var trip = $.rdfwidgets.anyStatementMatching( this._resource(o.subject),this._resource(o.predicate),processObject(o.object,o), undefined, o ); 3282 return trip ? trip : null; 3283 } 3284 return null; 3285 } 3286 }); 3287 3288 $.ui.label.getter = "getRDFValue getTriple"; 3289 3290 $(document).ready( function() { 3291 loadDataSources(); 3292 $(document).click( function(e) { 3293 setUnselected( selectedElement ); 3294 }); 3295 $(document).keyup( function( e ) { 3296 if( (!e.originalTarget || (e.originalTarget && e.originalTarget.nodeName.toLowerCase() !== "input" && e.originalTarget.nodeName.toLowerCase() !== "textarea") ) 3297 && e.which === 46 ) { 3298 if( selectedElement ) { 3299 selectedElement.trigger( "rdfdelete" ); 3300 } 3301 } 3302 }); 3303 processHTMLWidgets(); 3304 }); 3305 3306 function processHTMLWidgets ( element ) { 3307 element = element ? $(element).get(0) : document.body; 3308 $("[sw\\:widget]").closest( "*", element ).each( function( i, elt ) { 3309 var widget = null; 3310 var opts = {}; 3311 for( var i = 0; i < this.attributes.length; i++ ) { 3312 var a = this.attributes[i]; 3313 if( a.nodeName.indexOf("sw:") === 0 ) { 3314 if( a.nodeValue === "false" ) { 3315 opts[a.nodeName.substr(3)] = false; 3316 } else if( a.nodeValue.length>2 && 3317 ( ( a.nodeValue[0] === "[" && 3318 a.nodeValue[a.nodeValue.length-1] === "]") || 3319 ( a.nodeValue[0] === "{" && 3320 a.nodeValue[a.nodeValue.length-1] === "}") ) ) { 3321 opts[a.nodeName.substr(3)] = $.parseJSON( a.nodeValue ); 3322 } else { 3323 opts[a.nodeName.substr(3)] = a.nodeValue; 3324 } 3325 } 3326 if( a.nodeName === "sw:widget" ) { 3327 widget = a.nodeValue; 3328 } 3329 } 3330 $(this)[widget](opts); 3331 }); 3332 } 3333 3334 return { 3335 3336 /** 3337 * @description Set the default SPARUL endpoint to be used for user-generated content. 3338 * @memberOf jQuery.rdfwidgets 3339 * @param {String | $rdf.Symbol} uri The URI of the new default endpoint. 3340 */ 3341 setDefaultEndpoint: function( uri ) { 3342 if( typeof(uri) === "object" && "symbol" === object.termType ) { 3343 defaultEndpoint = uri.value; 3344 } else if( uri && uri.toString ) { 3345 defaultEndpoint = uri.toString(); 3346 } 3347 }, 3348 3349 /** 3350 * @description Get the default SPARUL endpoint to be used for user-generated content. 3351 * @memberOf jQuery.rdfwidgets 3352 * @returns {String} The current endpoint URI. 3353 */ 3354 getDefaultEndpoint: function() { 3355 return defaultEndpoint; 3356 }, 3357 3358 /** 3359 * @description Get the current default user used when generating ACL for new data. 3360 * @memberOf jQuery.rdfwidgets 3361 * @returns {String} The current default user URI. 3362 */ 3363 getDefaultUser: function() { 3364 return defaultUser; 3365 }, 3366 3367 /** 3368 * @description Get the Tabulator RDF Store backing the library. 3369 * @memberOf jQuery.rdfwidgets 3370 * @returns {$rdf.IndexedFormula} The data store. 3371 */ 3372 getStore: function() { 3373 return db; 3374 }, 3375 3376 /** 3377 * @description Load all of the RDF data from a given URI into the local store. 3378 * @memberOf jQuery.rdfwidgets 3379 * @param {String} uri The URI of the new default endpoint. 3380 * @param {Object} [o] 3381 * @param {String} [o.endpoint] The endpoint to be used when data from this source is edited. 3382 * @param {String} [o.name] The shorthand name of this data source. 3383 * @param {Function} [o.callback] A function to be called after the data source has loaded, of the form f(uri, success). 3384 */ 3385 load: function( uri, o ) { 3386 for( var i = 0; i < loadFilters.length; i++ ) { 3387 var t = loadFilters[i](uri); 3388 if( t && t !== uri ) { 3389 uri = t; 3390 break; 3391 } 3392 } 3393 if( !requestedURIs[ docpart( uri ) ] ) { 3394 var u = docpart( uri ); 3395 if( !o ) { o = {}; } 3396 if( o.name ) { 3397 sourceNames[u] = o.name; 3398 } 3399 if( o.endpoint ) { 3400 endpoints[u] = sourceNames[o.endpoint] ? sourceNames[o.endpoint] : processResource( o.endpoint ); 3401 } 3402 loadDataSource( u, o.format, o.callback ); 3403 } 3404 }, 3405 /** 3406 * @description Remove all data associated with a given URI from the local store. 3407 * @memberOf jQuery.rdfwidgets 3408 * @param {String} uri The data source for which to remove all data. 3409 */ 3410 remove: function( uri ) { 3411 var really = docpart( uri ); 3412 delete loadedSources[really]; 3413 db.removeMany( undefined, undefined, undefined, db.sym( really ) ); 3414 deleteData( null ); 3415 requestedURIs[ really ] = false; 3416 }, 3417 3418 match: function( o ) { 3419 if( !o ) { o = {}; } 3420 return $.rdfwidgets.statementsMatching(processResource( o.subject, o ), processResource( o.predicate, o ), processObject( o.object, o ), undefined, false, o ); 3421 }, 3422 3423 loadSameAs: function( uri, o ) { 3424 var uris = db.uris( processResource( uri, {} ) ); 3425 o = o ? o : {}; 3426 for( var i = 0; i < uris.length; i++ ) { 3427 if( !requestedURIs[ docpart( uris[i] ) ] ) { 3428 $.rdfwidgets.load( uris[i] , o ); 3429 } 3430 } 3431 }, 3432 3433 /** 3434 * @description Get a Matcher instance that draws into a given element. 3435 * @memberOf jQuery.rdfwidgets 3436 * @param {String | Object} element The element to be drawn into. Can be any valid jQuery constructor argument--a selector, a DOM element, or even another jQuery object. 3437 * @param {Object} [options] @see CommonOptions 3438 * @param {Boolean} [options.filterduplicates] Ignore identical matches that originate from different data sources. 3439 * @param {Boolean} [norefresh] If true, this matcher will not refresh itself automatically when new data is loaded. 3440 * @returns {Matcher} The new matcher instance 3441 */ 3442 matcher: function( element, options, norefresh ) { 3443 return Matcher( element, options ? options : {}, norefresh ); 3444 }, 3445 3446 /** 3447 * @description Process the DOM starting from a given element in search of HTML-encoded widgets. 3448 * @memberOf jQuery.rdfwidgets 3449 * @param {String | Object} [element="document.body"] The element to search in. Any valid jQuery constructor argument--only the first result of a selector will be searched. 3450 */ 3451 processHTML: function( element ) { 3452 processHTMLWidgets( element ); 3453 }, 3454 3455 /** 3456 * @description Ascend up the DOM looking for an RDFa "about" tag. 3457 * @memberOf jQuery.rdfwidgets 3458 * @param {String | Object} node The element to search in. Any valid jQuery constructor argument--only the first result of a selector will be searched. Currently does not support safe CURIEs. 3459 * @returns {String} the URI of the first "about" tag found, or the "href" of the first anchor tag found. 3460 */ 3461 getNodeSubject: function( node ) { 3462 return getNodeSubject( node ); 3463 }, 3464 3465 /** 3466 * @description Add a function that has a chance to override a source loading. If the function returns false, the provided URI will not be loaded. 3467 * @memberOf jQuery.rdfwidgets 3468 * @param {Function} f The filter function. If the function returns false, the data source will not be loaded. The function should have the signature f(uri). 3469 */ 3470 addLoadFilter: function( f ) { 3471 loadFilters.push( f ); 3472 }, 3473 3474 /** 3475 * @description Get the set of data sources pending. 3476 * @memberOf jQuery.rdfwidgets 3477 * @returns {Array} The list of URIs which are still loading. 3478 */ 3479 sourcesPending: function() { 3480 return $.extend( [], pendingSources ); 3481 }, 3482 3483 /** 3484 * @description See if a specific URI is in the process of loading. 3485 * @memberOf jQuery.rdfwidgets 3486 * @param {String} uri The URI to check. 3487 * @returns {Boolean} true if the data source is pending, false otherwise. 3488 */ 3489 sourcePending: function( uri ) { 3490 var u = docpart( uri ); 3491 for( var i = 0; i < pendingSources.length; i++ ) { 3492 if( pendingSources[i] === u ) { 3493 return true; 3494 } 3495 } 3496 return false; 3497 }, 3498 3499 /** 3500 * @description Remove a given load filter. 3501 * @memberOf jQuery.rdfwidgets 3502 * @param {Function} f a reference to the filter to be removed. 3503 */ 3504 removeLoadFilter: function( f ) { 3505 for( var i = 0; i < loadFilters.length; i++ ) { 3506 if( loadFilters[i] === f ) { 3507 loadFilters.splice(i,1); 3508 return; 3509 } 3510 } 3511 }, 3512 3513 /** 3514 * @description Get all statements matching a given triple pattern. 3515 * @memberOf jQuery.rdfwidgets 3516 * @param {String | Object} [s] Subject. A URI, prefixed name, or Symbol. 3517 * @param {String | Object} [p] Predicate. A URI, prefixed name, or Symbol. 3518 * @param {String | Object} [o] Object. A URI, prefixed name, Symbol, or Literal. 3519 * @param {String | Object} [w] Data Source. A URI, prefixed name, or Symbol. 3520 * @param {Boolean} [justOne] If true, only return the first result (still in an Array). 3521 * @param {Object} [opts] @see CommonOptions 3522 * @returns {Array} An Array of $rdf.Statement objects that match the provided pattern. 3523 */ 3524 statementsMatching: function( s, p, o, w, justOne, opts ) { 3525 var f = null; 3526 if( opts ) { 3527 f = processSourceFilter( opts.sources, opts ); 3528 } 3529 var sts = db.statementsMatching( s, p, o, w, justOne, f ); 3530 if( opts && opts.filter ) { 3531 sts = $.grep( sts, opts.filter ); 3532 } 3533 return sts; 3534 }, 3535 3536 /** 3537 * @description Get a single statement matching a given triple pattern. 3538 * @memberOf jQuery.rdfwidgets 3539 * @param {String | Object} [s] Subject. A URI, prefixed name, or Symbol. 3540 * @param {String | Object} [p] Predicate. A URI, prefixed name, or Symbol. 3541 * @param {String | Object} [o] Object. A URI, prefixed name, Symbol, or Literal. 3542 * @param {String | Object} [w] Data Source. A URI, prefixed name, or Symbol. 3543 * @param {Object} [opts] @see CommonOptions 3544 * @returns {Array} An Array of $rdf.Statement objects that match the provided pattern. 3545 */ 3546 anyStatementMatching: function( s, p, o, w, opts ) { 3547 var x = $.rdfwidgets.statementsMatching(s,p,o,w,true,opts); 3548 if (!x || x == []) return undefined; 3549 return x[0]; 3550 }, 3551 3552 /** 3553 * @description Given two of s, p, o, return any match for the missing term. 3554 * @memberOf jQuery.rdfwidgets 3555 * @param {String | Object} [s] Subject. A URI, prefixed name, or Symbol. 3556 * @param {String | Object} [p] Predicate. A URI, prefixed name, or Symbol. 3557 * @param {String | Object} [o] Object. A URI, prefixed name, Symbol, or Literal. 3558 * @param {String | Object} [w] Data Source. A URI, prefixed name, or Symbol. 3559 * @param {Object} [opts] @see CommonOptions 3560 * @returns {Object} A Symbol, Literal, or BlankNode representing a match for the missing term, or undefined if none was found. 3561 */ 3562 any: function( s, p, o, w, opts ) { 3563 var st = $.rdfwidgets.anyStatementMatching(s,p,o,w,opts); 3564 if (typeof st == 'undefined') return undefined; 3565 if (typeof s == 'undefined') return st.subject; 3566 if (typeof p == 'undefined') return st.predicate; 3567 if (typeof o == 'undefined') return st.object; 3568 return undefined; 3569 }, 3570 3571 /** 3572 * @description Given two of s, p, o, return all matches for the missing term. 3573 * @memberOf jQuery.rdfwidgets 3574 * @param {String | Object} [s] Subject. A URI, prefixed name, or Symbol. 3575 * @param {String | Object} [p] Predicate. A URI, prefixed name, or Symbol. 3576 * @param {String | Object} [o] Object. A URI, prefixed name, Symbol, or Literal. 3577 * @param {String | Object} [w] Data Source. A URI, prefixed name, or Symbol. 3578 * @param {Object} [opts] @see CommonOptions 3579 * @returns {Array} An Array of Symbols, Literals, and/or BlankNodes representing matches for the missing term. 3580 */ 3581 each: function( s, p, o, w, opts ) { 3582 var results = [] 3583 var st, sts = $.rdfwidgets.statementsMatching(s,p,o,w,false,opts) 3584 var i, n=sts.length 3585 if (typeof s == 'undefined') { 3586 for (i=0; i<n; i++) {st=sts[i]; results.push(st.subject);} 3587 } else if (typeof p == 'undefined') { 3588 for (i=0; i<n; i++) {st=sts[i]; results.push(st.predicate);} 3589 } else if (typeof o == 'undefined') { 3590 for (i=0; i<n; i++) {st=sts[i]; results.push(st.object);} 3591 } else if (typeof w == 'undefined') { 3592 for (i=0; i<n; i++) {st=sts[i]; results.push(st.why);} 3593 } 3594 return results; 3595 }, 3596 3597 /** 3598 * @description Given any of s, p, o, and w, see if any valid match exists. 3599 * @memberOf jQuery.rdfwidgets 3600 * @param {String | Object} [s] Subject. A URI, prefixed name, or Symbol. 3601 * @param {String | Object} [p] Predicate. A URI, prefixed name, or Symbol. 3602 * @param {String | Object} [o] Object. A URI, prefixed name, Symbol, or Literal. 3603 * @param {String | Object} [w] Data Source. A URI, prefixed name, or Symbol. 3604 * @param {Object} [opts] @see CommonOptions 3605 * @returns {Boolean} True if a match exists, false otherwise. 3606 */ 3607 whether: function( s, p, o, w, opts ) { 3608 return $.rdfwidgets.statementsMatching(s,p,o,w,false,opts).length; 3609 } 3610 3611 }; 3612 3613 /** 3614 * @name CommonOptions 3615 * @namespace Options commonly used by the widget library widgets. 3616 * @description Note that this isn't really a class, but is just meant as a reference to the options used by many widgets. 3617 */ 3618 3619 /** 3620 * @name sources 3621 * @type Array 3622 * @memberOf CommonOptions 3623 * @field 3624 * @description An array of URIs and shorthand names that define the set of sources that should be used when obtaining data for this widget. 3625 */ 3626 3627 /** 3628 * @name endpoint 3629 * @type String 3630 * @memberOf CommonOptions 3631 * @field 3632 * @description A URI indicating the SPARUL endpoint to which data created by this widget or edited at this data source should be written 3633 */ 3634 3635 3636 /** 3637 * @name filter 3638 * @type Function 3639 * @memberOf CommonOptions 3640 * @field 3641 * @description A function with the signature f($rdf.Triple) that, given a triple, will return true if that triple should be used in the output of the widget. 3642 */ 3643 3644 /** 3645 * @name acl 3646 * @type Object | String 3647 * @memberOf CommonOptions 3648 * @field 3649 * @description An anonymous object representing the ACL to be used with any new resource description created by this widget. Can use any of the pre-defined ACL strings, or an absolute URI pointing to a policy to be used. 3650 */ 3651 3652 /** 3653 * @name selectable 3654 * @type Boolean 3655 * @memberOf CommonOptions 3656 * @field 3657 * @description If true, this item will be selectable. When selected, the widget will fire an rdfselect event. 3658 */ 3659 3660 /** 3661 * @name editable 3662 * @type Boolean 3663 * @memberOf CommonOptions 3664 * @field 3665 * @description If true, this widget will be editable. 3666 */ 3667 3668 /** 3669 * @name beforeSubmit 3670 * @type Funtion 3671 * @memberOf CommonOptions 3672 * @field 3673 * @description A function with the signature f(data, xhr) to be called just prior to the submission of an update to a SPARUL server. 3674 */ 3675 3676 /** 3677 * @name afterSubmit 3678 * @type Function 3679 * @memberOf CommonOptions 3680 * @field 3681 * @description A function with the signature f(success, data, xhr) to be called following a SPARUL request's completion, regardless of success. 3682 */ 3683 3684 /** 3685 * @name namespaces 3686 * @type Object 3687 * @memberOf CommonOptions 3688 * @field 3689 * @description An anonymous object containing namespace->URI mappings, e.g. {"foaf":"http://xmlns.com/foaf/0.1/"}. 3690 */ 3691 3692 }(jQuery);