PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/public/js/jquery.fresnel.js

https://bitbucket.org/okfn/ordf
JavaScript | 891 lines | 736 code | 48 blank | 107 comment | 166 complexity | 6e9f1d8308c910c77bf557b604435a55 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*
  2. * jQuery / rdfquery Fresnel implementation.
  3. *
  4. * Copyright (c) 2010 Open Knowledge Foundation
  5. * Loosely based on fresnel.js from the Openlink Ajax Toolkit
  6. *
  7. * Fresnel docs:
  8. * http://www.w3.org/2005/04/fresnel-info/manual/
  9. *
  10. * Usage:
  11. * // 1. initialize the fresnel object
  12. * fresnel = $.rdf.fresnel();
  13. * // 2. load fresnel format instructions into fresnel.fresnel_data
  14. * fresnel.addFresnel({ uri: foo, callback: bar })
  15. * // 3. add some databank
  16. * fresnel.addData(databank);
  17. * // 4. format the data
  18. * fresnel.format().appendTo("#content");
  19. *
  20. */
  21. jQuery.rdf.fresnel = __fresnel = function(options) {
  22. this.options = options || {};
  23. this.listeners = [];
  24. this.flushData();
  25. this.flushFresnel();
  26. }
  27. __fresnel.prototype.flushFresnel = fresnel_flushFresnel;
  28. function fresnel_flushFresnel() {
  29. this.lenses = {};
  30. this.fresnel_data = $.rdf.databank([], {
  31. namespaces: {
  32. "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
  33. "fresnel": "http://www.w3.org/2004/09/fresnel#"
  34. }
  35. });
  36. }
  37. __fresnel.prototype.flushData = fresnel_flushData;
  38. function fresnel_flushData() {
  39. this.data = [];
  40. }
  41. __fresnel.prototype.selectData = fresnel_selectData;
  42. function fresnel_selectData(i, selected) {
  43. this.data[i].selected = selected;
  44. this.trigger("selectData");
  45. }
  46. __fresnel.prototype.addListener = fresnel_addListener;
  47. function fresnel_addListener(l) {
  48. this.listeners.push(l);
  49. }
  50. __fresnel.prototype.removeListener = fresnel_removeListener;
  51. function fresnel_removeListener(l) {
  52. var i = this.listeners.indexOf(l);
  53. if (i >= 0) {
  54. this.listeners = this.listeners.slice(0,i)
  55. .concat(this.listeners.slice(i+1, this.listeners.length));
  56. }
  57. }
  58. /**
  59. * needed because sometimes add/replace get race condition when
  60. * being called within event handler
  61. */
  62. __fresnel.prototype.replaceListener = fresnel_replaceListener;
  63. function fresnel_replaceListener(o, n) {
  64. var i = this.listeners.indexOf(o);
  65. if (i >= 0) {
  66. this.listeners[i] = n;
  67. } else {
  68. this.listeners.push(n);
  69. }
  70. }
  71. __fresnel.prototype.trigger = fresnel_trigger;
  72. function fresnel_trigger(event_type) {
  73. for (var i=0; i<this.listeners.length; i++) {
  74. this.listeners[i].trigger(event_type, this);
  75. }
  76. }
  77. __fresnel.prototype.addFresnel = fresnel_addFresnel;
  78. function fresnel_addFresnel(options) {
  79. if (options.uri == undefined)
  80. throw "addFresnel: requires uri in options";
  81. var self = this;
  82. var store = new jQuery.ordf();
  83. store.recv({
  84. uri: options.uri,
  85. callback: function (data) {
  86. self.lenses = {}; // invalidate cache
  87. self.fresnel_data = data;
  88. data.prefix("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
  89. data.prefix("fresnel", "http://www.w3.org/2004/09/fresnel#");
  90. self.trigger("addFresnel");
  91. if (options.callback)
  92. options.callback(data);
  93. }
  94. });
  95. }
  96. __fresnel.prototype.cloneFresnel = fresnel_cloneFresnel;
  97. function fresnel_cloneFresnel(other) {
  98. this.fresnel_data = other.fresnel_data;
  99. }
  100. __fresnel.prototype.addData = fresnel_addData;
  101. function fresnel_addData(databank) {
  102. this.data.push(databank);
  103. // some inferencing rules
  104. jQuery.rdf.ruleset()
  105. .prefix("bibo", "http://purl.org/ontology/bibo/")
  106. .prefix("owl", "http://www.w3.org/2002/07/owl#")
  107. .add("?book bibo:authorList ?authors",
  108. "?book a bibo:Book")
  109. // .add("?subject ?predicate ?object",
  110. // "?subject a owl:Thing")
  111. .run(databank);
  112. this.trigger("addData");
  113. }
  114. __fresnel.prototype.findSubjects = fresnel_findSubjects;
  115. function fresnel_findSubjects() {
  116. var subjects = {};
  117. for (var i=0; i<this.data.length; i++) {
  118. var store = this.data[i].tripleStore;
  119. for (var s in store) {
  120. var statement = store[s][0];
  121. subjects[statement.subject] = statement.subject;
  122. }
  123. }
  124. return subjects;
  125. }
  126. __fresnel.prototype.format = fresnel_format;
  127. function fresnel_format(options) {
  128. this.load_css();
  129. var container = $("<div></div>").addClass("fresnel_container");
  130. var subjects = this.findSubjects();
  131. for (var i in subjects) {
  132. var lens = this.findLens(subjects[i]);
  133. if (lens) {
  134. this.formatResource(options, lens, subjects[i]).appendTo(container);
  135. }
  136. }
  137. container.bind("addData", function (e, f) {
  138. f.redraw();
  139. });
  140. container.bind("addFresnel", function (e, f) {
  141. f.redraw();
  142. });
  143. container.bind("selectData", function (e, f) {
  144. f.redraw();
  145. });
  146. container.options = options;
  147. this.replaceListener(this.container, container);
  148. this.container = container;
  149. return container;
  150. }
  151. __fresnel.prototype.redraw = fresnel_redraw;
  152. function fresnel_redraw() {
  153. if (this.container == undefined)
  154. return;
  155. var old_container = this.container;
  156. var parent = old_container.parent();
  157. var new_container = this.format(old_container.options);
  158. old_container.remove();
  159. new_container.appendTo(parent);
  160. }
  161. __fresnel.prototype.save = fresnel_save;
  162. function fresnel_save(reason) {
  163. var store = new jQuery.ordf();
  164. for (var i=0; i<fresnel.data.length; i++) {
  165. store.send({ databank: this.data[i], reason: reason.toString() });
  166. }
  167. }
  168. __fresnel.prototype.rdf = fresnel_rdf;
  169. /*
  170. * utility function, returns the rdf contained in the formatting
  171. * databank
  172. */
  173. function fresnel_rdf() {
  174. return jQuery.rdf( { databank: this.fresnel_data } );
  175. }
  176. __fresnel.prototype.data_rdf = fresnel_data_rdf;
  177. /*
  178. * utility function, return the union of all databanks in this renderer
  179. */
  180. function fresnel_data_rdf() {
  181. var rdf = $.rdf();
  182. for (var i=0; i<this.data.length; i++) {
  183. if (this.data[i].selected == false)
  184. continue;
  185. rdf = rdf.add($.rdf({ databank: this.data[i] }));
  186. }
  187. return rdf;
  188. }
  189. __fresnel.prototype.load_css = fresnel_load_css;
  190. /*
  191. * Inform the browser of any stylesheets that we need to load
  192. */
  193. function fresnel_load_css() {
  194. this.rdf()
  195. .where("?group a fresnel:Group")
  196. .where("?group fresnel:stylesheetLink ?ss")
  197. .each(function () {
  198. var ss = this.ss.value.toString();
  199. var found = false;
  200. for (var i=0; i<document.styleSheets.length; i++) {
  201. if (document.styleSheets[i].href == ss) {
  202. found = true;
  203. break;
  204. }
  205. }
  206. if (!found) {
  207. $("<link></link>")
  208. .attr("rel", "stylesheet")
  209. .attr("type", "text/css")
  210. .attr("href", ss)
  211. .appendTo(document.head);
  212. }
  213. });
  214. }
  215. __fresnel.prototype.findLens = fresnel_findLens;
  216. /* find appropriate lens for resource */
  217. function fresnel_findLens(subject) {
  218. var lens = undefined;
  219. /* cache shortcut */
  220. lens = this.lenses[subject];
  221. if (lens != undefined)
  222. return lens;
  223. /* search for lens by instance first */
  224. this.rdf()
  225. .where("?lens a fresnel:Lens")
  226. .where("?lens fresnel:instanceLensDomain " + subject)
  227. .each(function () { lens = this.lens; });
  228. if (lens) {
  229. this.lenses[subject] = lens;
  230. return lens;
  231. }
  232. /* more expensive search */
  233. var types = this.findTypes(subject);
  234. /* cache shortcut */
  235. var undefined_type_found = false;
  236. for (var i=0; i<types.length; i++) {
  237. lens = this.lenses[types[i]];
  238. if (lens)
  239. return lens;
  240. if (lens == undefined)
  241. undefined_type_found = true;
  242. }
  243. /* this means all types were negatively cached */
  244. if (!undefined_type_found)
  245. return false;
  246. /* look for lenses for each type */
  247. for (var i=0; i<types.length; i++) {
  248. this.rdf()
  249. .where("?lens a fresnel:Lens")
  250. .where("?lens fresnel:classLensDomain " + types[i])
  251. .each(function () { lens = this.lens; });
  252. if (lens) {
  253. this.lenses[types[i]] = lens;
  254. return lens;
  255. } else {
  256. this.lenses[types[i]] = false; // negative caching
  257. }
  258. }
  259. /* at this point we know that we do not display the subject */
  260. this.lenses[subject] = false;
  261. return false;
  262. }
  263. __fresnel.prototype.styleElement = fresnel_styleElement;
  264. /*
  265. * apply the style to the element. style may be either
  266. * fresnel:stylingInstructions or fresnel:styleClass
  267. */
  268. function fresnel_styleElement(element, style) {
  269. var ns = this.fresnel_data.namespaces["fresnel"];
  270. if (style.datatype == ns + "stylingInstructions") {
  271. var styles = style.representation.split(";");
  272. var css = {}
  273. for (var i=0; i<styles.length; i++) {
  274. var j = styles[i].indexOf(":");
  275. if (j > 0) {
  276. css[styles[i].substr(0,j)] = styles[i].substr(j+1);
  277. }
  278. }
  279. return element = element.css(css);
  280. } else {
  281. element = element.addClass(style.representation);
  282. }
  283. return element;
  284. }
  285. __fresnel.prototype.lensProperties = fresnel_lensProperties;
  286. /*
  287. * Return the properties specified by the given lens.
  288. */
  289. function fresnel_lensProperties(subject, lens) {
  290. /* cache since we will look this up often */
  291. if (lens.properties == undefined) {
  292. var properties = [];
  293. var q = this.rdf().where(lens + " fresnel:showProperties ?first");
  294. if (q.length > 0)
  295. properties = jQuery.rdf.collection(this.rdf(), q[0].first);
  296. /* check for nested definitions of sublenses */
  297. for (var i=0; i<properties.length; i++) {
  298. if (jQuery.rdf.isBnode(properties[i])) { // bnode -> sublens
  299. q = this.rdf()
  300. .where(properties[i] + " fresnel:property ?property")
  301. .where(properties[i] + " fresnel:sublens ?sublens")
  302. .each(function () {
  303. properties[i] = this.property;
  304. properties[i].sublens = this.sublens;
  305. });
  306. }
  307. }
  308. if ( subject && (properties.length > 0) &&
  309. (properties[properties.length-1].toString() ==
  310. "<http://www.w3.org/2004/09/fresnel#allProperties>") ) {
  311. properties = properties.slice(0, properties.length-1);
  312. var all_properties = [];
  313. this.data_rdf()
  314. .where(subject + " ?p ?o")
  315. .each(function () {
  316. if ((properties.indexOf(this.p) < 0) && (all_properties.indexOf(this.p) < 0))
  317. all_properties.push(this.p);
  318. });
  319. properties = properties.concat(all_properties.sort());
  320. var q = this.rdf().where(lens + " fresnel:hideProperties ?first");
  321. if (q.length > 0) {
  322. var hidden = jQuery.rdf.collection(this.rdf(), q[0].first);
  323. for (var i=0; i<hidden.length; i++) {
  324. var hide = properties.indexOf(hidden[i]);
  325. if (hide >= 0) {
  326. properties =
  327. properties.slice(0,hide).concat(
  328. properties.slice(hide+1, properties.length));
  329. }
  330. }
  331. }
  332. // do not cache since property list is dynamic
  333. } else {
  334. lens.properties = properties;
  335. }
  336. } else { // lens.properties is defined
  337. properties = lens.properties;
  338. }
  339. return properties;
  340. }
  341. __fresnel.prototype.propertyStyle = fresnel_propertyStyle;
  342. /*
  343. * Return a Style attribute for the given format
  344. * property, label, value
  345. */
  346. function fresnel_propertyStyle(format) {
  347. if (format.propertyStyle == undefined) {
  348. format.propertyStyle = false;
  349. this.rdf()
  350. .where(format + " fresnel:propertyStyle ?style")
  351. .each(function () { format.propertyStyle = this.style; });
  352. }
  353. return format.propertyStyle;
  354. }
  355. __fresnel.prototype.labelStyle = fresnel_labelStyle;
  356. function fresnel_labelStyle(format) {
  357. if (format.labelStyle == undefined) {
  358. format.labelStyle = false;
  359. this.rdf()
  360. .where(format + " fresnel:labelStyle ?style")
  361. .each(function () { format.labelStyle = this.style; });
  362. }
  363. return format.labelStyle;
  364. }
  365. __fresnel.prototype.valueStyle = fresnel_valueStyle;
  366. function fresnel_valueStyle(format) {
  367. if (format.valueStyle == undefined) {
  368. format.valueStyle = false;
  369. this.rdf()
  370. .where(format + " fresnel:valueStyle ?style")
  371. .each(function () { format.valueStyle = this.style; });
  372. }
  373. return format.valueStyle;
  374. }
  375. __fresnel.prototype.propertyLabel = fresnel_propertyLabel;
  376. /*
  377. * Return an appropriate label (DOM Element or false) for the
  378. * given propety. Can return false if the label is the special
  379. * value fesnel:none
  380. */
  381. function fresnel_propertyLabel(options, format, property) {
  382. /* could probably benefit from caching */
  383. var label = true;
  384. if (format)
  385. this.rdf()
  386. .where(format + " fresnel:label ?label")
  387. .each(function () { label = this.label; });
  388. if (label == "<http://www.w3.org/2004/09/fresnel#none>")
  389. label = false;
  390. if (label == true) {
  391. /* naively infer the label from the property URI */
  392. var sp = property.value.toString().split("/");
  393. sp = sp[sp.length-1].split("#");
  394. label = { value: sp[sp.length-1] };
  395. }
  396. if (label) {
  397. var span = $("<span></span>").addClass("fresnel_label");
  398. span.text(label.value);
  399. label = span;
  400. if (format) {
  401. var style = this.labelStyle(format);
  402. if (style) label = this.styleElement(label, style);
  403. }
  404. if (options.controls)
  405. label.FresnelLabelControls(options, this);
  406. }
  407. return label;
  408. }
  409. function urlshorten(text) {
  410. if (text.length > 60) {
  411. return text.substr(0, 28) + "..." + text.substr(text.length-29, 29);
  412. }
  413. return text;
  414. }
  415. __fresnel.prototype.value = fresnel_value;
  416. function fresnel_value(options, lens, format, object) {
  417. var value = undefined;
  418. // filter on language. a bit spaghetti
  419. if (object.lang) {
  420. if (!this.languages)
  421. this.languages = {};
  422. this.languages[object.lang] = true;
  423. }
  424. if ((object.lang && this.lang) && (this.lang != object.lang)) {
  425. return undefined;
  426. }
  427. if (jQuery.rdf.isBnode(object)) {
  428. var new_lens = this.findLens(object);
  429. if (new_lens)
  430. value = this.formatResource(options, new_lens, object);
  431. // else
  432. // Probably not correct. This is here so we can support
  433. // such nonsense as
  434. // <foo> dc:subject [ rdfs:label "blah blah" ]
  435. // found e.g. in
  436. // http://purl.org/NET/book/isbn/9780061474095#book
  437. // Fresnel spec may not handle this case of how to display
  438. // a bnode with no type. Alternatively we might be better
  439. // adding an inferencing rule to assert rdfs:Resource as a
  440. // type in the absence of one explicitly stated. That may
  441. // be better than using whatever the current lens is.
  442. // But that inferencing rule is expensive (excessively
  443. // productive). Hmm.
  444. // value = this.formatResource(options, lens, object);
  445. } else if (format) {
  446. if (format.formatValue == undefined) {
  447. format.formatValue = false;
  448. this.rdf()
  449. .where(format + " fresnel:value ?value")
  450. .each(function () { format.formatValue = this.value });
  451. }
  452. if (format.formatValue == "<http://www.w3.org/2004/09/fresnel#externalLink>") {
  453. value = $("<a></a>")
  454. .attr("href", object.value.toString())
  455. .text(urlshorten(object.value.toString()));
  456. var label_link = function(labels) {
  457. if (this.lang && labels[this.lang]) {
  458. value.text(labels[this.lang]);
  459. } else if (labels["default"]) {
  460. value.text(labels["default"]);
  461. }
  462. }
  463. var ordf = new jQuery.ordf();
  464. ordf.get_label({ uri: object, callback: label_link });
  465. } else if (format.formatValue == "<http://www.w3.org/2004/09/fresnel#image>") {
  466. value = $("<img />")
  467. .attr("src", object.value.toString());
  468. }
  469. }
  470. if (value == undefined) {
  471. if (jQuery.rdf.isUri(object)) {
  472. value = $("<a></a>")
  473. .attr("href", object.value.toString())
  474. .text(urlshorten(object.value.toString()));
  475. var label_link = function(labels) {
  476. if (this.lang && labels[this.lang]) {
  477. value.text(labels[this.lang]);
  478. } else if (labels["default"]) {
  479. value.text(labels["default"]);
  480. }
  481. }
  482. var ordf = new jQuery.ordf();
  483. ordf.get_label({ uri: object, callback: label_link });
  484. } else if (jQuery.rdf.isLiteral) {
  485. value = $("<p></p>").text(object.value.toString());
  486. } else {
  487. value = $("<span></span>").text(object.value.toString());
  488. }
  489. }
  490. return value;
  491. }
  492. __fresnel.prototype.formatValue = fresnel_formatValue;
  493. /*
  494. * Render and return a formatted object part of a triple. This can
  495. * recurse through sublenses. It also sneakily stuffs a copy of the
  496. * original statement into the DOM Element with a "statement" attribute
  497. * to facilitate inline editing.
  498. */
  499. function fresnel_formatValue(options, lens, format, subject, property, object) {
  500. var div = $("<div></div>").addClass("fresnel_value");
  501. if (format) {
  502. var style = this.valueStyle(format);
  503. if (style) div = this.styleElement(div, style);
  504. }
  505. if (property.sublens) {
  506. this.formatResource(options, property.sublens, object).appendTo(div);
  507. } else {
  508. var value = this.value(options, lens, format, object);
  509. if (value) {
  510. if (!this.lang && object.lang) {
  511. $("<span></span>")
  512. .addClass("fresnel_object_language")
  513. .text("(" + object.lang + ")")
  514. .prependTo(value);
  515. }
  516. value.appendTo(div);
  517. }
  518. }
  519. // stuff the statement in the DOM for future use
  520. div[0].statement = this.findStatement(subject, property, object);
  521. if (options.controls)
  522. $(div).FresnelValueControls(options, this, lens, div[0].statement);
  523. return div;
  524. }
  525. __fresnel.prototype.formatProperty = fresnel_formatProperty;
  526. /*
  527. * Format labels on a given property, and then chain down to the
  528. * value/objects
  529. */
  530. function fresnel_formatProperty(options, lens, subject, property) {
  531. var div = $("<div></div>").addClass("fresnel_property");
  532. var format = false;
  533. this.rdf()
  534. .where(lens + " fresnel:group ?group")
  535. .where("?format fresnel:group ?group")
  536. .where("?format fresnel:propertyFormatDomain " + property)
  537. .each(function () { format = this.format; });
  538. if (format) {
  539. var style = this.propertyStyle(format);
  540. if (style) div = this.styleElement(div, style);
  541. }
  542. var label = this.propertyLabel(options, format, property);
  543. if (label) label.appendTo(div);
  544. var container = $("<div></div>").addClass("fresnel_container");
  545. var self = this;
  546. this.data_rdf()
  547. .where(subject + " " + property + " ?value")
  548. .each(function () {
  549. self.formatValue(options, lens, format, subject, property, this.value)
  550. .appendTo(container);
  551. })
  552. container.appendTo(div);
  553. if (container.children().length == 0)
  554. div = false;
  555. else if (options.controls)
  556. div.FresnelPropertyControls(options, this, lens, format, subject, property);
  557. return div;
  558. }
  559. __fresnel.prototype.findTypes = fresnel_findTypes;
  560. function fresnel_findTypes(subject) {
  561. if (subject.types == undefined) {
  562. var types = [];
  563. this.data_rdf()
  564. .where(subject + " a ?type")
  565. .each(function () { types.push(this.type); });
  566. subject.types = types;
  567. }
  568. return subject.types;
  569. }
  570. __fresnel.prototype.findFormats = fresnel_findFormats;
  571. function fresnel_findFormats(lens) {
  572. if (lens.formats == undefined) {
  573. var formats = [];
  574. this.rdf()
  575. .where(lens + " fresnel:group ?group")
  576. .where("?format fresnel:group ?group")
  577. .each(function () { formats.push(this.format); });
  578. lens.formats = formats;
  579. }
  580. return lens.formats;
  581. }
  582. __fresnel.prototype.formatResource = fresnel_formatResource;
  583. /*
  584. * Format a resource using the specified lens. This can also be called
  585. * for sublenses.
  586. */
  587. function fresnel_formatResource(options, lens, subject) {
  588. var resource = $("<div></div>").addClass("fresnel_resource");
  589. var format = false;
  590. var self = this;
  591. resource[0].fresnel = this;
  592. resource[0].subject = subject;
  593. resource[0].lens = lens;
  594. if (options.resource_header && jQuery.rdf.isUri(subject))
  595. $("<div></div>")
  596. .addClass("fresnel_resource_uri")
  597. .text("Resource: " + subject.toString())
  598. .appendTo(resource);
  599. // find formats to use, try instance first
  600. var formats = this.findFormats(lens);
  601. for (var i=0; i<formats.length; i++) {
  602. var q = this.rdf()
  603. .where(formats[i] + " fresnel:instanceFormatDomain " + subject);
  604. if (q.length > 0) {
  605. format = formats[i];
  606. break;
  607. }
  608. }
  609. // not found, try class
  610. if (!format) {
  611. var types = this.findTypes(subject);
  612. for (var i=0; i<types.length; i++) {
  613. for (var j=0; j<formats.length; j++) {
  614. var q = this.rdf()
  615. .where(formats[j] + " fresnel:classFormatDomain " + types[i]);
  616. if (q.length > 0) {
  617. format = formats[j];
  618. break;
  619. }
  620. }
  621. if (format)
  622. break;
  623. }
  624. }
  625. // if we have found a format apply its resource styles (and the group's)
  626. if (format) {
  627. this.rdf()
  628. .where(format + " fresnel:resourceStyle ?style")
  629. .each(function () { resource = self.styleElement(resource, this.style) })
  630. .end()
  631. .where(format + " fresnel:group ?group")
  632. .where("?group fresnel:resourceStyle ?style")
  633. .each(function () { resource = self.styleElement(resource, this.style) })
  634. .end();
  635. }
  636. var properties = self.lensProperties(subject, lens);
  637. for (var i=0; i<properties.length; i++) {
  638. var element = self.formatProperty(options, lens, subject, properties[i]);
  639. if (element) {
  640. element.appendTo(resource);
  641. }
  642. }
  643. if (options.controls)
  644. resource.FresnelResourceControls(options, this, lens, subject);
  645. return resource;
  646. }
  647. __fresnel.prototype.findStatement = fresnel_findStatement;
  648. function fresnel_findStatement(subject, property, object) {
  649. // a way to make this more efficient?
  650. for (var i=0; i<this.data.length; i++) {
  651. var statements = this.data[i].tripleStore[subject];
  652. if (statements == undefined)
  653. continue;
  654. for (var j=0; j<statements.length; j++) {
  655. if ( (statements[j].property.value == property.value) &&
  656. (statements[j].object.value == object.value) ) {
  657. return statements[j];
  658. }
  659. }
  660. }
  661. }
  662. __fresnel.prototype.removeStatement = fresnel_removeStatement;
  663. function fresnel_removeStatement(statement) {
  664. for (var i=0; i<this.data.length; i++) {
  665. this.data[i].remove(statement);
  666. }
  667. }
  668. __fresnel.prototype.addStatement = fresnel_addStatement;
  669. function fresnel_addStatement(statement) {
  670. // kludgy find the first graph with the subject
  671. // and add to that graph
  672. for (var i=0; i<this.data.length; i++) {
  673. var rdf = jQuery.rdf({ databank: this.data[i] });
  674. if (rdf.where(statement.subject + " ?p ?o").length > 0) {
  675. rdf.add(statement);
  676. return;
  677. }
  678. }
  679. // failing that, just add to the first graph
  680. jQuery.rdf({ databank: self.data[0] }).add(statement);
  681. }
  682. /* Widgets */
  683. jQuery.prototype.Fresnel = function(options) {
  684. var defaults = {
  685. editable: false,
  686. controls: true,
  687. resource_header: true
  688. }
  689. if (options.fresnel == undefined)
  690. throw "jQuery.fresnel.Fresnel: must pass a fresnel instance in options";
  691. var container = options.fresnel.format($.extend(defaults, options));
  692. container.appendTo(this);
  693. return this;
  694. }
  695. jQuery.prototype.GraphChooser = function(options) {
  696. if (options.fresnel == undefined)
  697. throw "jQuery.fresnel.GraphChooser: require fresnel to be in options";
  698. var chooser = $("<div></div>").addClass("fresnel_graph_chooser");
  699. $("<h3>Resource Selector</h3>").appendTo(chooser);
  700. var make_choices = function() {
  701. chooser.children("div").each(function () { $(this).remove(); });
  702. for (var i=0; i<options.fresnel.data.length; i++) {
  703. var graphdiv = $("<div></div>")
  704. .appendTo(chooser);
  705. var select_idx = i;
  706. $("<input></input>")
  707. .attr("type", "checkbox")
  708. .attr("checked", (options.fresnel.data[i].selected == true) ? "true" : "false")
  709. .click(function (e) {
  710. options.fresnel.selectData(select_idx, (this.value == "on" ? true : false));
  711. })
  712. .appendTo(graphdiv);
  713. $("<span></span>")
  714. .text("" + options.fresnel.data[i].baseURI)
  715. .appendTo(graphdiv);
  716. }
  717. }
  718. make_choices(); // initialise with whatever is in the fresnel now
  719. chooser.appendTo(this);
  720. fresnel.addListener(chooser);
  721. chooser.bind("addData", make_choices);
  722. return this;
  723. }
  724. jQuery.prototype.GraphSaver = function(options) {
  725. if (options.fresnel == undefined)
  726. throw "jQuery.fresnel.GraphSaver: require fresnel to be in options";
  727. var saver = $("<li></li>").addClass("fresnel_saver");
  728. $("<span></span>")
  729. .text("Log Message: ")
  730. .appendTo(saver);
  731. var reason = $("<input />")
  732. .attr("type", "text")
  733. .attr("size", "30")
  734. .appendTo(saver);
  735. $("<input />")
  736. .attr("type", "submit")
  737. .attr("value", "Save")
  738. .click(function () {
  739. options.fresnel.save(reason.val());
  740. })
  741. .appendTo(saver);
  742. saver.appendTo(this);
  743. return this;
  744. }
  745. jQuery.prototype.HistoryViewer = function(options) {
  746. if (options.fresnel == undefined)
  747. throw "jQuery.fresnel.GraphChooser: require fresnel to be in options";
  748. var viewer = $("<div></div>").addClass("fresnel_history_viewer");
  749. var show_history = function() {
  750. var query =
  751. "PREFIX cs: <http://purl.org/vocab/changeset/schema#>\n" +
  752. "PREFIX gr: <http://bibliographica.org/schema/graph#>\n" +
  753. "SELECT DISTINCT ?date ?name ?reason\n" +
  754. "WHERE {\n"
  755. "?cs a cs:ChangeSet .\n"
  756. for (var i=0; i<options.fresnel.data.length; i++) {
  757. var graph = options.fresnel.data[i].baseURI;
  758. query += "{ ?cs cs:addition [ gr:graph <" + graph + "> ] } UNION\n" +
  759. "{ ?cs cs:removal [ gr:graph <" + graph + "> ] } .\n";
  760. }
  761. query += "?cs cs:changeReason ?reason .\n" +
  762. "?cs cs:createdDate ?date .\n" +
  763. "?cs cs:creatorName ?name\n" +
  764. "} ORDER BY DESC(?date) LIMIT 10";
  765. var store = new jQuery.ordf();
  766. store.sparql({ query: query, callback: function(data) {
  767. viewer.children(".fresnel_short_history")
  768. .each(function () { $(this).remove(); });
  769. var history = $("<div></div>")
  770. .addClass("fresnel_short_history")
  771. .appendTo(viewer);
  772. var bindings = data.results.bindings;
  773. for (var i=0; i<bindings.length; i++) {
  774. var row = $("<div></div>")
  775. .css({ width: "100%", "border-top": "1px dotted black" })
  776. .appendTo(history);
  777. $("<span></span>")
  778. .text(bindings[i].name.value)
  779. .appendTo(row);
  780. $("<span></span>")
  781. .css({ float: "right" })
  782. .text(
  783. bindings[i].date.value.substr(0, 10) + " " +
  784. bindings[i].date.value.substr(11, 5)
  785. )
  786. .appendTo(row);
  787. $("<p></p>")
  788. .text(bindings[i].reason.value)
  789. .appendTo(row);
  790. }
  791. }});
  792. }
  793. $("<input />")
  794. .attr("type", "submit")
  795. .attr("value", "history")
  796. .click(show_history)
  797. .appendTo(viewer);
  798. viewer.appendTo(this);
  799. return this;
  800. }
  801. jQuery.typedValue.types["http://www.w3.org/2004/09/fresnel#styleClass"] = {
  802. strip: true,
  803. regex: /^.*$/,
  804. value: function(c) { return c; }
  805. };
  806. jQuery.typedValue.types["http://www.w3.org/2004/09/fresnel#stylingInstructions"] = {
  807. strip: false,
  808. regex: /^.*$/,
  809. value: function(c) { return c; }
  810. };
  811. /*
  812. * This function walks an rdf Collection and returns a list
  813. */
  814. jQuery.rdf.collection = function(rdf, first) {
  815. var l = [];
  816. var rest=first;
  817. for (var i=0; rest != "<http://www.w3.org/1999/02/22-rdf-syntax-ns#nil>"; i++) {
  818. var q = rdf
  819. .reset()
  820. .where(rest + " rdf:first ?value")
  821. .where(rest + " rdf:rest ?rest");
  822. if (q.length == 0)
  823. break;
  824. l[i] = q[0].value;
  825. rest = q[0].rest;
  826. }
  827. return l;
  828. }
  829. jQuery.rdf.isLiteral = function(o) {
  830. if (jQuery.rdf.isBnode(o) || jQuery.rdf.isUri(o))
  831. return false;
  832. return true;
  833. }
  834. jQuery.rdf.isBnode = function(o) {
  835. if (o.id != undefined)
  836. return true;
  837. return false;
  838. }
  839. jQuery.rdf.isUri = function(o) {
  840. if (typeof o.value == "object")
  841. return true;
  842. return false;
  843. }