drupal/core/misc/vie/vie-core.js

3719 lines
131 KiB
JavaScript

/*Copyright (c) 2011 Henri Bergius, IKS Consortium
Copyright (c) 2011 Sebastian Germesin, IKS Consortium
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/(function(){// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
/*global console:false exports:false require:false */
var root = this,
jQuery = root.jQuery,
Backbone = root.Backbone,
_ = root._;
// ## VIE constructor
//
// The VIE constructor is the way to initialize VIE for your
// application. The instance of VIE handles all management of
// semantic interaction, including keeping track of entities,
// changes to them, the possible RDFa views on the page where
// the entities are displayed, and connections to external
// services like Stanbol and DBPedia.
//
// To get a VIE instance, simply run:
//
// var vie = new VIE();
//
// You can also pass configurations to the VIE instance through
// the constructor. For example, to set a different default
// namespace to be used for names that don't have a namespace
// specified, do:
//
// var vie = new VIE({
// baseNamespace: 'http://example.net'
// });
//
// ### Differences with VIE 1.x
//
// VIE 1.x used singletons for managing entities and views loaded
// from a page. This has been changed with VIE 2.x, and now all
// data managed by VIE is tied to the instance of VIE being used.
//
// This means that VIE needs to be instantiated before using. So,
// when previously you could get entities from page with:
//
// VIE.RDFaEntities.getInstances();
//
// Now you need to instantiate VIE first. This example uses the
// Classic API compatibility layer instead of the `load` method:
//
// var vie = new VIE();
// vie.RDFaEntities.getInstances();
//
// Currently the Classic API is enabled by default, but it is
// recommended to ensure it is enabled before using it. So:
//
// var vie = new VIE({classic: true});
// vie.RDFaEntities.getInstances();
var VIE = root.VIE = function(config) {
this.config = (config) ? config : {};
this.services = {};
this.jQuery = jQuery;
this.entities = new this.Collection([], {
vie: this
});
this.Entity.prototype.entities = this.entities;
this.Entity.prototype.entityCollection = this.Collection;
this.Entity.prototype.vie = this;
this.Namespaces.prototype.vie = this;
// ### Namespaces in VIE
// VIE supports different ontologies and an easy use of them.
// Namespace prefixes reduce the amount of code you have to
// write. In VIE, it does not matter if you access an entitie's
// property with
// `entity.get('<http://dbpedia.org/property/capitalOf>')` or
// `entity.get('dbprop:capitalOf')` or even
// `entity.get('capitalOf')` once the corresponding namespace
// is registered as *baseNamespace*.
// By default `"http://viejs.org/ns/"`is set as base namespace.
// For more information about how to set, get and list all
// registered namespaces, refer to the
// <a href="Namespace.html">Namespaces documentation</a>.
this.namespaces = new this.Namespaces(
(this.config.baseNamespace) ? this.config.baseNamespace : "http://viejs.org/ns/",
// By default, VIE is shipped with common namespace prefixes:
// + owl : "http://www.w3.org/2002/07/owl#"
// + rdfs : "http://www.w3.org/2000/01/rdf-schema#"
// + rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
// + schema : 'http://schema.org/'
// + foaf : 'http://xmlns.com/foaf/0.1/'
// + geo : 'http://www.w3.org/2003/01/geo/wgs84_pos#'
// + dbpedia: "http://dbpedia.org/ontology/"
// + dbprop : "http://dbpedia.org/property/"
// + skos : "http://www.w3.org/2004/02/skos/core#"
// + xsd : "http://www.w3.org/2001/XMLSchema#"
// + sioc : "http://rdfs.org/sioc/ns#"
// + dcterms: "http://purl.org/dc/terms/"
{
owl : "http://www.w3.org/2002/07/owl#",
rdfs : "http://www.w3.org/2000/01/rdf-schema#",
rdf : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
schema : 'http://schema.org/',
foaf : 'http://xmlns.com/foaf/0.1/',
geo : 'http://www.w3.org/2003/01/geo/wgs84_pos#',
dbpedia: "http://dbpedia.org/ontology/",
dbprop : "http://dbpedia.org/property/",
skos : "http://www.w3.org/2004/02/skos/core#",
xsd : "http://www.w3.org/2001/XMLSchema#",
sioc : "http://rdfs.org/sioc/ns#",
dcterms: "http://purl.org/dc/terms/"
}
);
this.Type.prototype.vie = this;
this.Types.prototype.vie = this;
this.Attribute.prototype.vie = this;
this.Attributes.prototype.vie = this;
// ### Type hierarchy in VIE
// VIE takes care about type hierarchy of entities
// (aka. *schema* or *ontology*).
// Once a type hierarchy is known to VIE, we can leverage
// this information, to easily ask, whether an entity
// is of type, e.g., *foaf:Person* or *schema:Place*.
// For more information about how to generate such a type
// hierarchy, refer to the
// <a href="Type.html">Types documentation</a>.
this.types = new this.Types();
// By default, there is a parent type in VIE, called
// *owl:Thing*. All types automatically inherit from this
// type and all registered entities, are of this type.
this.types.add("owl:Thing");
// As described above, the Classic API of VIE 1.x is loaded
// by default. As this might change in the future, it is
// recommended to ensure it is enabled before using it. So:
//
// var vie = new VIE({classic: true});
// vie.RDFaEntities.getInstances();
if (this.config.classic === true) {
/* Load Classic API as well */
this.RDFa = new this.ClassicRDFa(this);
this.RDFaEntities = new this.ClassicRDFaEntities(this);
this.EntityManager = new this.ClassicEntityManager(this);
this.cleanup = function() {
this.entities.reset();
};
}
};
// ### use(service, name)
// This method registers services within VIE.
// **Parameters**:
// *{string|object}* **service** The service to be registered.
// *{string}* **name** An optional name to register the service with. If this
// is not set, the default name that comes with the service is taken.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE}* : The current VIE instance.
// **Example usage**:
//
// var vie = new VIE();
// var conf1 = {...};
// var conf2 = {...};
// vie.use(new vie.StanbolService());
// vie.use(new vie.StanbolService(conf1), "stanbol_1");
// vie.use(new vie.StanbolService(conf2), "stanbol_2");
// // <-- this means that there are now 3 services registered!
VIE.prototype.use = function(service, name) {
if (!name && !service.name) {
throw new Error("Please provide a name for the service!");
}
service.vie = this;
service.name = (name)? name : service.name;
if (service.init) {
service.init();
}
this.services[service.name] = service;
return this;
};
// ### service(name)
// This method returns the service object that is
// registered under the given name.
// **Parameters**:
// *{string}* **name** ...
// **Throws**:
// *{Error}* if no service could be found.
// **Returns**:
// *{object}* : The service to be queried.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var service = vie.service("stanbol");
VIE.prototype.service = function(name) {
if (!this.hasService(name)) {
throw "Undefined service " + name;
}
return this.services[name];
};
// ### hasService(name)
// This method returns a boolean telling whether VIE has a particular
// service loaded.
// **Parameters**:
// *{string}* **name**
// **Returns**:
// *{boolean}* whether service is available
VIE.prototype.hasService = function(name) {
if (!this.services[name]) {
return false;
}
return true;
};
// ### getServicesArray()
// This method returns an array of all registered services.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{array}* : An array of service instances.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var services = vie.getServicesArray();
// services.length; // <-- 1
VIE.prototype.getServicesArray = function() {
return _.map(this.services, function (v) {return v;});
};
// ### load(options)
// This method instantiates a new VIE.Loadable in order to
// perform queries on the services.
// **Parameters**:
// *{object}* **options** Options to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Loadable}* : A new instance of VIE.Loadable.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var loader = vie.load({...});
VIE.prototype.load = function(options) {
if (!options) { options = {}; }
options.vie = this;
return new this.Loadable(options);
};
// ### save(options)
// This method instantiates a new VIE.Savable in order to
// perform queries on the services.
// **Parameters**:
// *{object}* **options** Options to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Savable}* : A new instance of VIE.Savable.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var saver = vie.save({...});
VIE.prototype.save = function(options) {
if (!options) { options = {}; }
options.vie = this;
return new this.Savable(options);
};
// ### remove(options)
// This method instantiates a new VIE.Removable in order to
// perform queries on the services.
// **Parameters**:
// *{object}* **options** Options to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Removable}* : A new instance of VIE.Removable.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var remover = vie.remove({...});
VIE.prototype.remove = function(options) {
if (!options) { options = {}; }
options.vie = this;
return new this.Removable(options);
};
// ### analyze(options)
// This method instantiates a new VIE.Analyzable in order to
// perform queries on the services.
// **Parameters**:
// *{object}* **options** Options to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Analyzable}* : A new instance of VIE.Analyzable.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var analyzer = vie.analyze({...});
VIE.prototype.analyze = function(options) {
if (!options) { options = {}; }
options.vie = this;
return new this.Analyzable(options);
};
// ### find(options)
// This method instantiates a new VIE.Findable in order to
// perform queries on the services.
// **Parameters**:
// *{object}* **options** Options to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Findable}* : A new instance of VIE.Findable.
// **Example usage**:
//
// var vie = new VIE();
// vie.use(new vie.StanbolService(), "stanbol");
// var finder = vie.find({...});
VIE.prototype.find = function(options) {
if (!options) { options = {}; }
options.vie = this;
return new this.Findable(options);
};
// ### loadSchema(url, options)
// VIE only knows the *owl:Thing* type by default.
// You can use this method to import another
// schema (ontology) from an external resource.
// (Currently, this supports only the JSON format!!)
// As this method works asynchronously, you might want
// to register `success` and `error` callbacks via the
// options.
// **Parameters**:
// *{string}* **url** The url, pointing to the schema to import.
// *{object}* **options** Options to be set.
// (Set ```success``` and ```error``` as callbacks.).
// **Throws**:
// *{Error}* if the url is not set.
// **Returns**:
// *{VIE}* : The VIE instance itself.
// **Example usage**:
//
// var vie = new VIE();
// vie.loadSchema("http://schema.rdfs.org/all.json",
// {
// baseNS : "http://schema.org/",
// success : function () {console.log("success");},
// error : function (msg) {console.warn(msg);}
// });
VIE.prototype.loadSchema = function(url, options) {
options = (!options)? {} : options;
if (!url) {
throw new Error("Please provide a proper URL");
}
else {
var vie = this;
jQuery.getJSON(url)
.success(function(data) {
try {
VIE.Util.loadSchemaOrg(vie, data, options.baseNS);
if (options.success) {
options.success.call(vie);
}
} catch (e) {
options.error.call(vie, e);
return;
}
})
.error(function(data, textStatus, jqXHR) {
if (options.error) {
console.warn(data, textStatus, jqXHR);
options.error.call(vie, "Could not load schema from URL (" + url + ")");
}
});
}
return this;
};
// ### getTypedEntityClass(type)
// This method generates a special type of `Entity` based on the given type.
// **Parameters**:
// *{string}* **type** The type.
// **Throws**:
// *{Error}* if the type is unknown to VIE.
// **Returns**:
// *{VIE.Entity}* : A subclass of `VIE.Entity`.
// **Example usage**:
//
// var vie = new VIE();
// vie.types.add("Person");
// var PersonClass = vie.getTypedEntityClass("Person");
// var Person = new PersonClass({"name", "Sebastian"});
VIE.prototype.getTypedEntityClass = function (type) {
var typeType = this.types.get(type);
if (!typeType) {
throw new Error("Unknown type " + type);
}
var TypedEntityClass = function (attrs, opts) {
if (!attrs) {
attrs = {};
}
attrs["@type"] = type;
this.set(attrs, opts);
};
TypedEntityClass.prototype = new this.Entity();
TypedEntityClass.prototype.schema = function () {
return VIE.Util.getFormSchemaForType(typeType);
};
return TypedEntityClass;
};
// ## Running VIE on Node.js
//
// When VIE is running under Node.js we can use the CommonJS
// require interface to load our dependencies automatically.
//
// This means Node.js users don't need to care about dependencies
// and can just run VIE with:
//
// var VIE = require('vie');
//
// In browser environments the dependencies have to be included
// before including VIE itself.
if (typeof exports === 'object') {
exports.VIE = VIE;
if (!jQuery) {
jQuery = require('jquery');
}
if (!Backbone) {
Backbone = require('backbone');
Backbone.setDomLibrary(jQuery);
}
if (!_) {
_ = require('underscore')._;
}
}
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
// ## VIE.Able
// VIE implements asynchronius service methods through
// [jQuery.Deferred](http://api.jquery.com/category/deferred-object/) objects.
// Loadable, Analysable, Savable, etc. are part of the VIE service API and
// are implemented with the generic VIE.Able class.
// Example:
//
// VIE.prototype.Loadable = function (options) {
// this.init(options,"load");
// };
// VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
//
// This defines
//
// someVIEService.load(options)
// .using(...)
// .execute()
// .success(...)
// .fail(...)
// which will run the asynchronius `load` function of the service with the created Loadable
// object.
// ### VIE.Able()
// This is the constructor of a VIE.Able. This should not be called
// globally but using the inherited classes below.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Able}* : A **new** VIE.Able object.
// Example:
//
// VIE.prototype.Loadable = function (options) {
// this.init(options,"load");
// };
// VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
VIE.prototype.Able = function(){
// ### init(options, methodName)
// Internal method, called during initialization.
// **Parameters**:
// *{object}* **options** the *able* options coming from the API call
// *{string}* **methodName** the service method called on `.execute`.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Able}* : The current instance.
// **Example usage**:
//
// VIE.prototype.Loadable = function (options) {
// this.init(options,"load");
// };
// VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
this.init = function(options, methodName) {
this.options = options;
this.services = options.from || options.using || options.to || [];
this.vie = options.vie;
this.methodName = methodName;
// Instantiate the deferred object
this.deferred = jQuery.Deferred();
// In order to get more information and documentation about the passed-through
// deferred methods and their synonyms, please see the documentation of
// the [jQuery.Deferred object](http://api.jquery.com/category/deferred-object/)
/* Public deferred-methods */
this.resolve = this.deferred.resolve;
this.resolveWith = this.deferred.resolveWith;
this.reject = this.deferred.reject;
this.rejectWith = this.deferred.rejectWith;
this.success = this.done = this.deferred.done;
this.fail = this.deferred.fail;
this.then = this.deferred.then;
this.always = this.deferred.always;
this.from = this.using;
this.to = this.using;
return this;
};
// ### using(services)
// This method registers services with the current able instance.
// **Parameters**:
// *{string|array}* **services** An id of a service or an array of strings.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Able}* : The current instance.
// **Example usage**:
//
// var loadable = vie.load({id: "http://example.com/entity/1234"});
// able.using("myService");
this.using = function(services) {
var self = this;
services = (_.isArray(services))? services : [ services ];
_.each (services, function (s) {
var obj = (typeof s === "string")? self.vie.service(s) : s;
self.services.push(obj);
});
return this;
};
// ### execute()
// This method runs the actual method on all registered services.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing* ...
// **Returns**:
// *{VIE.Able}* : The current instance.
// **Example usage**:
//
// var able = new vie.Able().init();
// able.using("stanbol")
// .done(function () {alert("finished");})
// .execute();
this.execute = function() {
/* call service[methodName] */
var able = this;
_(this.services).each(function(service){
service[able.methodName](able);
});
return this;
};
};
// ## VIE.Loadable
// A ```VIE.Loadable``` is a wrapper around the deferred object
// to **load** semantic data from a semantic web service.
VIE.prototype.Loadable = function (options) {
this.init(options,"load");
};
VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
// ## VIE.Savable
// A ```VIE.Savable``` is a wrapper around the deferred object
// to **save** entities by a VIE service. The RDFaService would write the data
// in the HTML as RDFa, the StanbolService stores the data in its Entityhub, etc.
VIE.prototype.Savable = function(options){
this.init(options, "save");
};
VIE.prototype.Savable.prototype = new VIE.prototype.Able();
// ## VIE.Removable
// A ```VIE.Removable``` is a wrapper around the deferred object
// to **remove** semantic data from a semantic web service.
VIE.prototype.Removable = function(options){
this.init(options, "remove");
};
VIE.prototype.Removable.prototype = new VIE.prototype.Able();
// ## VIE.Analyzable
// A ```VIE.Analyzable``` is a wrapper around the deferred object
// to **analyze** data and extract semantic information with the
// help of a semantic web service.
VIE.prototype.Analyzable = function (options) {
this.init(options, "analyze");
};
VIE.prototype.Analyzable.prototype = new VIE.prototype.Able();
// ## VIE.Findable
// A ```VIE.Findable``` is a wrapper around the deferred object
// to **find** semantic data on a semantic storage.
VIE.prototype.Findable = function (options) {
this.init(options, "find");
};
VIE.prototype.Findable.prototype = new VIE.prototype.Able();
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
// ## VIE Utils
//
// The here-listed methods are utility methods for the day-to-day
// VIE.js usage. All methods are within the static namespace ```VIE.Util```.
VIE.Util = {
// ### VIE.Util.toCurie(uri, safe, namespaces)
// This method converts a given
// URI into a CURIE (or SCURIE), based on the given ```VIE.Namespaces``` object.
// If the given uri is already a URI, it is left untouched and directly returned.
// If no prefix could be found, an ```Error``` is thrown.
// **Parameters**:
// *{string}* **uri** The URI to be transformed.
// *{boolean}* **safe** A flag whether to generate CURIEs or SCURIEs.
// *{VIE.Namespaces}* **namespaces** The namespaces to be used for the prefixes.
// **Throws**:
// *{Error}* If no prefix could be found in the passed namespaces.
// **Returns**:
// *{string}* The CURIE or SCURIE.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var uri = "<http://dbpedia.org/ontology/Person>";
// VIE.Util.toCurie(uri, false, ns); // --> dbp:Person
// VIE.Util.toCurie(uri, true, ns); // --> [dbp:Person]
toCurie : function (uri, safe, namespaces) {
if (VIE.Util.isCurie(uri, namespaces)) {
return uri;
}
var delim = ":";
for (var k in namespaces.toObj()) {
if (uri.indexOf(namespaces.get(k)) === 1) {
var pattern = new RegExp("^" + "<?" + namespaces.get(k));
if (k === '') {
delim = '';
}
return ((safe)? "[" : "") +
uri.replace(pattern, k + delim).replace(/>$/, '') +
((safe)? "]" : "");
}
}
throw new Error("No prefix found for URI '" + uri + "'!");
},
// ### VIE.Util.isCurie(curie, namespaces)
// This method checks, whether
// the given string is a CURIE and returns ```true``` if so and ```false```otherwise.
// **Parameters**:
// *{string}* **curie** The CURIE (or SCURIE) to be checked.
// *{VIE.Namespaces}* **namespaces** The namespaces to be used for the prefixes.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* ```true``` if the given curie is a CURIE or SCURIE and ```false``` otherwise.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var uri = "<http://dbpedia.org/ontology/Person>";
// var curie = "dbp:Person";
// var scurie = "[dbp:Person]";
// var text = "This is some text.";
// VIE.Util.isCurie(uri, ns); // --> false
// VIE.Util.isCurie(curie, ns); // --> true
// VIE.Util.isCurie(scurie, ns); // --> true
// VIE.Util.isCurie(text, ns); // --> false
isCurie : function (curie, namespaces) {
if (VIE.Util.isUri(curie)) {
return false;
} else {
try {
VIE.Util.toUri(curie, namespaces);
return true;
} catch (e) {
return false;
}
}
},
// ### VIE.Util.toUri(curie, namespaces)
// This method converts a
// given CURIE (or save CURIE) into a URI, based on the given ```VIE.Namespaces``` object.
// **Parameters**:
// *{string}* **curie** The CURIE to be transformed.
// *{VIE.Namespaces}* **namespaces** The namespaces object
// **Throws**:
// *{Error}* If no URI could be assembled.
// **Returns**:
// *{string}* : A string, representing the URI.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var curie = "dbp:Person";
// var scurie = "[dbp:Person]";
// VIE.Util.toUri(curie, ns);
// --> <http://dbpedia.org/ontology/Person>
// VIE.Util.toUri(scurie, ns);
// --> <http://dbpedia.org/ontology/Person>
toUri : function (curie, namespaces) {
if (VIE.Util.isUri(curie)) {
return curie;
}
var delim = ":";
for (var prefix in namespaces.toObj()) {
if (prefix !== "" && (curie.indexOf(prefix + ":") === 0 || curie.indexOf("[" + prefix + ":") === 0)) {
var pattern = new RegExp("^" + "\\[{0,1}" + prefix + delim);
return "<" + curie.replace(pattern, namespaces.get(prefix)).replace(/\]{0,1}$/, '') + ">";
}
}
/* check for the default namespace */
if (curie.indexOf(delim) === -1) {
return "<" + namespaces.base() + curie + ">";
}
throw new Error("No prefix found for CURIE '" + curie + "'!");
},
// ### VIE.Util.isUri(something)
// This method checks, whether the given string is a URI.
// **Parameters**:
// *{string}* **something** : The string to be checked.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* : ```true``` if the string is a URI, ```false``` otherwise.
// **Example usage**:
//
// var uri = "<http://dbpedia.org/ontology/Person>";
// var curie = "dbp:Person";
// VIE.Util.isUri(uri); // --> true
// VIE.Util.isUri(curie); // --> false
isUri : function (something) {
return (typeof something === "string" && something.search(/^<.+>$/) === 0);
},
// ### VIE.Util.mapAttributeNS(attr, ns)
// This method maps an attribute of an entity into namespaces if they have CURIEs.
// **Parameters**:
// *{string}* **attr** : The attribute to be transformed.
// *{VIE.Namespaces}* **ns** : The namespaces.
// **Throws**:
// *nothing*
// **Returns**:
// *{string}* : The transformed attribute's name.
// **Example usage**:
//
// var attr = "name";
// var ns = myVIE.namespaces;
// VIE.Util.mapAttributeNS(attr, ns); // '<' + ns.base() + attr + '>';
mapAttributeNS : function (attr, ns) {
var a = attr;
if (ns.isUri (attr) || attr.indexOf('@') === 0) {
//ignore
} else if (ns.isCurie(attr)) {
a = ns.uri(attr);
} else if (!ns.isUri(attr)) {
if (attr.indexOf(":") === -1) {
a = '<' + ns.base() + attr + '>';
} else {
a = '<' + attr + '>';
}
}
return a;
},
// ### VIE.Util.rdf2Entities(service, results)
// This method converts *rdf/json* data from an external service
// into VIE.Entities.
// **Parameters**:
// *{object}* **service** The service that retrieved the data.
// *{object}* **results** The data to be transformed.
// **Throws**:
// *nothing*
// **Returns**:
// *{[VIE.Entity]}* : An array, containing VIE.Entity instances which have been transformed from the given data.
rdf2Entities: function (service, results) {
if (typeof jQuery.rdf !== 'function') {
/* fallback if no rdfQuery has been loaded */
return VIE.Util._rdf2EntitiesNoRdfQuery(service, results);
}
try {
var rdf = (results instanceof jQuery.rdf)?
results.base(service.vie.namespaces.base()) :
jQuery.rdf().base(service.vie.namespaces.base()).load(results, {});
/* if the service contains rules to apply special transformation, they are executed here.*/
if (service.rules) {
var rules = jQuery.rdf.ruleset();
for (var prefix in service.vie.namespaces.toObj()) {
if (prefix !== "") {
rules.prefix(prefix, service.vie.namespaces.get(prefix));
}
}
for (var i = 0; i < service.rules.length; i++)if(service.rules.hasOwnProperty(i)) {
var rule = service.rules[i];
rules.add(rule.left, rule.right);
}
rdf = rdf.reason(rules, 10); /* execute the rules only 10 times to avoid looping */
}
var entities = {};
rdf.where('?subject ?property ?object').each(function() {
var subject = this.subject.toString();
if (!entities[subject]) {
entities[subject] = {
'@subject': subject,
'@context': service.vie.namespaces.toObj(true),
'@type': []
};
}
var propertyUri = this.property.toString();
var propertyCurie;
try {
propertyCurie = service.vie.namespaces.curie(propertyUri);
//jQuery.createCurie(propertyUri, {namespaces: service.vie.namespaces.toObj(true)});
} catch (e) {
propertyCurie = propertyUri;
// console.warn(propertyUri + " doesn't have a namespace definition in '", service.vie.namespaces.toObj());
}
entities[subject][propertyCurie] = entities[subject][propertyCurie] || [];
function getValue(rdfQueryLiteral){
if(typeof rdfQueryLiteral.value === "string"){
if (rdfQueryLiteral.lang){
var literal = {
toString: function(){
return this["@value"];
},
"@value": rdfQueryLiteral.value.replace(/^"|"$/g, ''),
"@language": rdfQueryLiteral.lang
};
return literal;
}
else
return rdfQueryLiteral.value;
return rdfQueryLiteral.value.toString();
} else if (rdfQueryLiteral.type === "uri"){
return rdfQueryLiteral.toString();
} else {
return rdfQueryLiteral.value;
}
}
entities[subject][propertyCurie].push(getValue(this.object));
});
_(entities).each(function(ent){
ent["@type"] = ent["@type"].concat(ent["rdf:type"]);
delete ent["rdf:type"];
_(ent).each(function(value, property){
if(value.length === 1){
ent[property] = value[0];
}
});
});
var vieEntities = [];
jQuery.each(entities, function() {
var entityInstance = new service.vie.Entity(this);
entityInstance = service.vie.entities.addOrUpdate(entityInstance);
vieEntities.push(entityInstance);
});
return vieEntities;
} catch (e) {
console.warn("Something went wrong while parsing the returned results!", e);
return [];
}
},
/*
VIE.Util.getPreferredLangForPreferredProperty(entity, preferredFields, preferredLanguages)
looks for specific ranking fields and languages. It calculates all possibilities and gives them
a score. It returns the value with the best score.
*/
getPreferredLangForPreferredProperty: function(entity, preferredFields, preferredLanguages) {
var l, labelArr, lang, p, property, resArr, valueArr, _len, _len2,
_this = this;
resArr = [];
/* Try to find a label in the preferred language
*/
_.each(preferredLanguages, function (lang) {
_.each(preferredFields, function (property) {
labelArr = null;
/* property can be a string e.g. "skos:prefLabel"
*/
if (typeof property === "string" && entity.get(property)) {
labelArr = _.flatten([entity.get(property)]);
_(labelArr).each(function(label) {
/*
The score is a natural number with 0 for the
best candidate with the first preferred language
and first preferred property
*/
var labelLang, score, value;
score = p;
labelLang = label["@language"];
/*
legacy code for compatibility with uotdated stanbol,
to be removed after may 2012
*/
if (typeof label === "string" && (label.indexOf("@") === label.length - 3 || label.indexOf("@") === label.length - 5)) {
labelLang = label.replace(/(^\"*|\"*@)..(..)?$/g, "");
}
/* end of legacy code
*/
if (labelLang) {
if (labelLang === lang) {
score += l;
} else {
score += 20;
}
} else {
score += 10;
}
value = label.toString();
/* legacy code for compatibility with uotdated stanbol, to be removed after may 2012
*/
value = value.replace(/(^\"*|\"*@..$)/g, "");
/* end of legacy code
*/
return resArr.push({
score: score,
value: value
});
});
/*
property can be an object like
{
property: "skos:broader",
makeLabel: function(propertyValueArr) { return "..."; }
}
*/
} else if (typeof property === "object" && entity.get(property.property)) {
valueArr = _.flatten([entity.get(property.property)]);
valueArr = _(valueArr).map(function(termUri) {
if (termUri.isEntity) {
return termUri.getSubject();
} else {
return termUri;
}
});
resArr.push({
score: p,
value: property.makeLabel(valueArr)
});
}
});
});
/*
take the result with the best score
*/
resArr = _(resArr).sortBy(function(a) {
return a.score;
});
if(resArr.length) {
return resArr[0].value;
} else {
return "n/a";
}
},
// ### VIE.Util._rdf2EntitiesNoRdfQuery(service, results)
// This is a **private** method which should
// only be accessed through ```VIE.Util._rdf2Entities()``` and is a helper method in case there is no
// rdfQuery loaded (*not recommended*).
// **Parameters**:
// *{object}* **service** The service that retrieved the data.
// *{object}* **results** The data to be transformed.
// **Throws**:
// *nothing*
// **Returns**:
// *{[VIE.Entity]}* : An array, containing VIE.Entity instances which have been transformed from the given data.
_rdf2EntitiesNoRdfQuery: function (service, results) {
var jsonLD = [];
_.forEach(results, function(value, key) {
var entity = {};
entity['@subject'] = '<' + key + '>';
_.forEach(value, function(triples, predicate) {
predicate = '<' + predicate + '>';
_.forEach(triples, function(triple) {
if (triple.type === 'uri') {
triple.value = '<' + triple.value + '>';
}
if (entity[predicate] && !_.isArray(entity[predicate])) {
entity[predicate] = [entity[predicate]];
}
if (_.isArray(entity[predicate])) {
entity[predicate].push(triple.value);
return;
}
entity[predicate] = triple.value;
});
});
jsonLD.push(entity);
});
return jsonLD;
},
// ### VIE.Util.loadSchemaOrg(vie, SchemaOrg, baseNS)
// This method is a wrapper around
// the <a href="http://schema.org/">schema.org</a> ontology. It adds all the
// given types and properties as ```VIE.Type``` instances to the given VIE instance.
// If the paramenter **baseNS** is set, the method automatically sets the namespace
// to the provided one. If it is not set, it will keep the base namespace of VIE untouched.
// **Parameters**:
// *{VIE}* **vie** The instance of ```VIE```.
// *{object}* **SchemaOrg** The data imported from schema.org.
// *{string|undefined}* **baseNS** If set, this will become the new baseNamespace within the given ```VIE``` instance.
// **Throws**:
// *{Error}* If the parameter was not given.
// **Returns**:
// *nothing*
loadSchemaOrg : function (vie, SchemaOrg, baseNS) {
if (!SchemaOrg) {
throw new Error("Please load the schema.json file.");
}
vie.types.remove("<http://schema.org/Thing>");
var baseNSBefore = (baseNS)? baseNS : vie.namespaces.base();
vie.namespaces.base(baseNS);
var datatypeMapping = {
'DataType': 'xsd:anyType',
'Boolean' : 'xsd:boolean',
'Date' : 'xsd:date',
'DateTime': 'xsd:dateTime',
'Time' : 'xsd:time',
'Float' : 'xsd:float',
'Integer' : 'xsd:integer',
'Number' : 'xsd:anySimpleType',
'Text' : 'xsd:string',
'URL' : 'xsd:anyURI'
};
var dataTypeHelper = function (ancestors, id) {
var type = vie.types.add(id, [{'id' : 'value', 'range' : datatypeMapping[id]}]);
for (var i = 0; i < ancestors.length; i++) {
var supertype = (vie.types.get(ancestors[i]))? vie.types.get(ancestors[i]) :
dataTypeHelper.call(vie, SchemaOrg.datatypes[ancestors[i]].supertypes, ancestors[i]);
type.inherit(supertype);
}
return type;
};
for (var dt in SchemaOrg.datatypes) {
if (!vie.types.get(dt)) {
var ancestors = SchemaOrg.datatypes[dt].supertypes;
dataTypeHelper.call(vie, ancestors, dt);
}
}
var metadataHelper = function (definition) {
var metadata = {};
if (definition.label) {
metadata.label = definition.label;
}
if (definition.url) {
metadata.url = definition.url;
}
if (definition.comment) {
metadata.comment = definition.comment;
}
if (definition.metadata) {
metadata = _.extend(metadata, definition.metadata);
}
return metadata;
};
var typeProps = function (id) {
var props = [];
_.each(SchemaOrg.types[id].specific_properties, function (pId) {
var property = SchemaOrg.properties[pId];
props.push({
'id' : property.id,
'range' : property.ranges,
'min' : property.min,
'max' : property.max,
'metadata': metadataHelper(property)
});
});
return props;
};
var typeHelper = function (ancestors, id, props, metadata) {
var type = vie.types.add(id, props, metadata);
for (var i = 0; i < ancestors.length; i++) {
var supertype = (vie.types.get(ancestors[i]))? vie.types.get(ancestors[i]) :
typeHelper.call(vie, SchemaOrg.types[ancestors[i]].supertypes, ancestors[i], typeProps.call(vie, ancestors[i]), metadataHelper(SchemaOrg.types[ancestors[i]]));
type.inherit(supertype);
}
if (id === "Thing" && !type.isof("owl:Thing")) {
type.inherit("owl:Thing");
}
return type;
};
_.each(SchemaOrg.types, function (typeDef) {
if (vie.types.get(typeDef.id)) {
return;
}
var ancestors = typeDef.supertypes;
var metadata = metadataHelper(typeDef);
typeHelper.call(vie, ancestors, typeDef.id, typeProps.call(vie, typeDef.id), metadata);
});
/* set the namespace to either the old value or the provided baseNS value */
vie.namespaces.base(baseNSBefore);
},
// ### VIE.Util.getEntityTypeUnion(entity)
// This generates a entity-specific VIE type that is a subtype of all the
// types of the entity. This makes it easier to deal with attribute definitions
// specific to an entity because they're merged to a single list. This custom
// type is transient, meaning that it won't be automatilly added to the entity
// or the VIE type registry.
getEntityTypeUnion : function(entity) {
var vie = entity.vie;
return new vie.Type('Union').inherit(entity.get('@type'));
},
// ### VIE.Util.getFormSchemaForType(type)
// This creates a [Backbone Forms](https://github.com/powmedia/backbone-forms)
// -compatible form schema for any VIE Type.
getFormSchemaForType : function(type, allowNested) {
var schema = {};
// Generate a schema
_.each(type.attributes.toArray(), function (attribute) {
var key = VIE.Util.toCurie(attribute.id, false, attribute.vie.namespaces);
schema[key] = VIE.Util.getFormSchemaForAttribute(attribute);
});
// Clean up unknown attribute types
_.each(schema, function (field, id) {
if (!field.type) {
delete schema[id];
}
if (field.type === 'URL') {
field.type = 'Text';
field.dataType = 'url';
}
if (field.type === 'List' && !field.listType) {
delete schema[id];
}
if (!allowNested) {
if (field.type === 'NestedModel' || field.listType === 'NestedModel') {
delete schema[id];
}
}
});
return schema;
},
/// ### VIE.Util.getFormSchemaForAttribute(attribute)
getFormSchemaForAttribute : function(attribute) {
var primaryType = attribute.range[0];
var schema = {};
var getWidgetForType = function (type) {
switch (type) {
case 'xsd:anySimpleType':
case 'xsd:float':
case 'xsd:integer':
return 'Number';
case 'xsd:string':
return 'Text';
case 'xsd:date':
return 'Date';
case 'xsd:dateTime':
return 'DateTime';
case 'xsd:boolean':
return 'Checkbox';
case 'xsd:anyURI':
return 'URL';
default:
var typeType = attribute.vie.types.get(type);
if (!typeType) {
return null;
}
if (typeType.attributes.get('value')) {
// Convert to proper xsd type
return getWidgetForType(typeType.attributes.get('value').range[0]);
}
return 'NestedModel';
}
};
// TODO: Generate a nicer label
schema.title = VIE.Util.toCurie(attribute.id, false, attribute.vie.namespaces);
// TODO: Handle attributes linking to other VIE entities
if (attribute.min > 0) {
schema.validators = ['required'];
}
if (attribute.max > 1) {
schema.type = 'List';
schema.listType = getWidgetForType(primaryType);
if (schema.listType === 'NestedModel') {
schema.nestedModelType = primaryType;
}
return schema;
}
schema.type = getWidgetForType(primaryType);
if (schema.type === 'NestedModel') {
schema.nestedModelType = primaryType;
}
return schema;
},
// ### VIE.Util.getFormSchema(entity)
// This creates a [Backbone Forms](https://github.com/powmedia/backbone-forms)
// -compatible form schema for any VIE Entity. The form schema creation
// utilizes type information attached to the entity.
// **Parameters**:
// *{```Entity```}* **entity** An instance of VIE ```Entity```.
// **Throws**:
// *nothing*..
// **Returns**:
// *{object}* a JavaScript object representation of the form schema
getFormSchema : function(entity) {
if (!entity || !entity.isEntity) {
return {};
}
var unionType = VIE.Util.getEntityTypeUnion(entity);
var schema = VIE.Util.getFormSchemaForType(unionType, true);
// Handle nested models
_.each(schema, function (property, id) {
if (property.type !== 'NestedModel' && property.listType !== 'NestedModel') {
return;
}
schema[id].model = entity.vie.getTypedEntityClass(property.nestedModelType);
});
return schema;
},
// ### VIE.Util.xsdDateTime(date)
// This transforms a ```Date``` instance into an xsd:DateTime format.
// **Parameters**:
// *{```Date```}* **date** An instance of a javascript ```Date```.
// **Throws**:
// *nothing*..
// **Returns**:
// *{string}* A string representation of the dateTime in the xsd:dateTime format.
xsdDateTime : function(date) {
function pad(n) {
var s = n.toString();
return s.length < 2 ? '0'+s : s;
}
var yyyy = date.getFullYear();
var mm1 = pad(date.getMonth()+1);
var dd = pad(date.getDate());
var hh = pad(date.getHours());
var mm2 = pad(date.getMinutes());
var ss = pad(date.getSeconds());
return yyyy +'-' +mm1 +'-' +dd +'T' +hh +':' +mm2 +':' +ss;
},
// ### VIE.Util.extractLanguageString(entity, attrs, langs)
// This method extracts a literal string from an entity, searching through the given attributes and languages.
// **Parameters**:
// *{```VIE.Entity```}* **entity** An instance of a VIE.Entity.
// *{```array|string```}* **attrs** Either a string or an array of possible attributes.
// *{```array|string```}* **langs** Either a string or an array of possible languages.
// **Throws**:
// *nothing*..
// **Returns**:
// *{string|undefined}* The string that was found at the attribute with the wanted language, undefined if nothing could be found.
// **Example usage**:
//
// var attrs = ["name", "rdfs:label"];
// var langs = ["en", "de"];
// VIE.Util.extractLanguageString(someEntity, attrs, langs); // "Barack Obama";
extractLanguageString : function(entity, attrs, langs) {
var p, attr, name, i, n;
if (entity && typeof entity !== "string") {
attrs = (_.isArray(attrs))? attrs : [ attrs ];
langs = (_.isArray(langs))? langs : [ langs ];
for (p = 0; p < attrs.length; p++) {
for (var l = 0; l < langs.length; l++) {
var lang = langs[l];
attr = attrs[p];
if (entity.has(attr)) {
name = entity.get(attr);
name = (_.isArray(name))? name : [ name ];
for (i = 0; i < name.length; i++) {
n = name[i];
if (n.isEntity) {
n = VIE.Util.extractLanguageString(n, attrs, lang);
} else if (typeof n === "string") {
n = n;
} else {
n = "";
}
if (n && n.indexOf('@' + lang) > -1) {
return n.replace(/"/g, "").replace(/@[a-z]+/, '').trim();
}
}
}
}
}
/* let's do this again in case we haven't found a name but are dealing with
broken data where no language is given */
for (p = 0; p < attrs.length; p++) {
attr = attrs[p];
if (entity.has(attr)) {
name = entity.get(attr);
name = (_.isArray(name))? name : [ name ];
for (i = 0; i < name.length; i++) {
n = name[i];
if (n.isEntity) {
n = VIE.Util.extractLanguageString(n, attrs, []);
}
if (n && (typeof n === "string") && n.indexOf('@') === -1) {
return n.replace(/"/g, "").replace(/@[a-z]+/, '').trim();
}
}
}
}
}
return undefined;
},
// ### VIE.Util.transformationRules(service)
// This returns a default set of rdfQuery rules that transform semantic data into the
// VIE entity types.
// **Parameters**:
// *{object}* **service** An instance of a vie.service.
// **Throws**:
// *nothing*..
// **Returns**:
// *{array}* An array of rules with 'left' and 'right' side.
transformationRules : function (service) {
var res = [
// rule(s) to transform a dbpedia:Person into a VIE:Person
{
'left' : [
'?subject a dbpedia:Person',
'?subject rdfs:label ?label'
],
'right': function(ns){
return function(){
return [
jQuery.rdf.triple(this.subject.toString(),
'a',
'<' + ns.base() + 'Person>', {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'name>',
this.label, {
namespaces: ns.toObj()
})
];
};
}(service.vie.namespaces)
},
// rule(s) to transform a foaf:Person into a VIE:Person
{
'left' : [
'?subject a foaf:Person',
'?subject rdfs:label ?label'
],
'right': function(ns){
return function(){
return [
jQuery.rdf.triple(this.subject.toString(),
'a',
'<' + ns.base() + 'Person>', {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'name>',
this.label, {
namespaces: ns.toObj()
})
];
};
}(service.vie.namespaces)
},
// rule(s) to transform a dbpedia:Place into a VIE:Place
{
'left' : [
'?subject a dbpedia:Place',
'?subject rdfs:label ?label'
],
'right': function(ns) {
return function() {
return [
jQuery.rdf.triple(this.subject.toString(),
'a',
'<' + ns.base() + 'Place>', {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'name>',
this.label.toString(), {
namespaces: ns.toObj()
})
];
};
}(service.vie.namespaces)
},
// rule(s) to transform a dbpedia:City into a VIE:City
{
'left' : [
'?subject a dbpedia:City',
'?subject rdfs:label ?label',
'?subject dbpedia:abstract ?abs',
'?subject dbpedia:country ?country'
],
'right': function(ns) {
return function() {
return [
jQuery.rdf.triple(this.subject.toString(),
'a',
'<' + ns.base() + 'City>', {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'name>',
this.label.toString(), {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'description>',
this.abs.toString(), {
namespaces: ns.toObj()
}),
jQuery.rdf.triple(this.subject.toString(),
'<' + ns.base() + 'containedIn>',
this.country.toString(), {
namespaces: ns.toObj()
})
];
};
}(service.vie.namespaces)
}
];
return res;
},
getAdditionalRules : function (service) {
var mapping = {
Work : "CreativeWork",
Film : "Movie",
TelevisionEpisode : "TVEpisode",
TelevisionShow : "TVSeries", // not listed as equivalent class on dbpedia.org
Website : "WebPage",
Painting : "Painting",
Sculpture : "Sculpture",
Event : "Event",
SportsEvent : "SportsEvent",
MusicFestival : "Festival",
FilmFestival : "Festival",
Place : "Place",
Continent : "Continent",
Country : "Country",
City : "City",
Airport : "Airport",
Station : "TrainStation", // not listed as equivalent class on dbpedia.org
Hospital : "GovernmentBuilding",
Mountain : "Mountain",
BodyOfWater : "BodyOfWater",
Company : "Organization",
Person : "Person"
};
var additionalRules = [];
_.each(mapping, function (map, key) {
var tripple = {
'left' : [ '?subject a dbpedia:' + key, '?subject rdfs:label ?label' ],
'right' : function(ns) {
return function() {
return [ jQuery.rdf.triple(this.subject.toString(), 'a', '<' + ns.base() + map + '>', {
namespaces : ns.toObj()
}), jQuery.rdf.triple(this.subject.toString(), '<' + ns.base() + 'name>', this.label.toString(), {
namespaces : ns.toObj()
}) ];
};
}(service.vie.namespaces)
};
additionalRules.push(tripple);
});
return additionalRules;
}
};
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
// ## VIE Entities
//
// In VIE there are two low-level model types for storing data.
// **Collections** and **Entities**. Considering `var v = new VIE();` a VIE instance,
// `v.entities` is a Collection with `VIE Entity` objects in it.
// VIE internally uses JSON-LD to store entities.
//
// Each Entity has a few special attributes starting with an `@`. VIE has an API
// for correctly using these attributes, so in order to stay compatible with later
// versions of the library, possibly using a later version of JSON-LD, use the API
// to interact with your entities.
//
// * `@subject` stands for the identifier of the entity. Use `e.getSubject()`
// * `@type` stores the explicit entity types. VIE internally handles Type hierarchy,
// which basically enables to define subtypes and supertypes. Every entity has
// the type 'owl:Thing'. Read more about Types in <a href="Type.html">VIE.Type</a>.
// * `@context` stores namespace definitions used in the entity. Read more about
// Namespaces in <a href="Namespace.html">VIE Namespaces</a>.
VIE.prototype.Entity = function(attrs, opts) {
attrs = (attrs)? attrs : {};
opts = (opts)? opts : {};
var self = this;
if (attrs['@type'] !== undefined) {
attrs['@type'] = (_.isArray(attrs['@type']))? attrs['@type'] : [ attrs['@type'] ];
attrs['@type'] = _.map(attrs['@type'], function(val){
if (!self.vie.types.get(val)) {
//if there is no such type -> add it and let it inherit from "owl:Thing"
self.vie.types.add(val).inherit("owl:Thing");
}
return self.vie.types.get(val).id;
});
attrs['@type'] = (attrs['@type'].length === 1)? attrs['@type'][0] : attrs['@type'];
} else {
// provide "owl:Thing" as the default type if none was given
attrs['@type'] = self.vie.types.get("owl:Thing").id;
}
//the following provides full seamless namespace support
//for attributes. It should not matter, if you
//query for `model.get('name')` or `model.get('foaf:name')`
//or even `model.get('http://xmlns.com/foaf/0.1/name');`
//However, if we just overwrite `set()` and `get()`, this
//raises a lot of side effects, so we need to expand
//the attributes before we create the model.
_.each (attrs, function (value, key) {
var newKey = VIE.Util.mapAttributeNS(key, this.namespaces);
if (key !== newKey) {
delete attrs[key];
attrs[newKey] = value;
}
}, self.vie);
var Model = Backbone.Model.extend({
idAttribute: '@subject',
initialize: function(attributes, options) {
if (attributes['@subject']) {
this.id = this['@subject'] = this.toReference(attributes['@subject']);
} else {
this.id = this['@subject'] = attributes['@subject'] = this.cid.replace('c', '_:bnode');
}
return this;
},
schema: function() {
return VIE.Util.getFormSchema(this);
},
// ### Getter, Has, Setter
// #### `.get(attr)`
// To be able to communicate to a VIE Entity you can use a simple get(property)
// command as in `entity.get('rdfs:label')` which will give you one or more literals.
// If the property points to a collection, its entities can be browsed further.
get: function (attr) {
attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
var value = Backbone.Model.prototype.get.call(this, attr);
value = (_.isArray(value))? value : [ value ];
value = _.map(value, function(v) {
if (v !== undefined && attr === '@type' && self.vie.types.get(v)) {
return self.vie.types.get(v);
} else if (v !== undefined && self.vie.entities.get(v)) {
return self.vie.entities.get(v);
} else {
return v;
}
}, this);
if(value.length === 0) {
return undefined;
}
// if there is only one element, just return that one
value = (value.length === 1)? value[0] : value;
return value;
},
// #### `.has(attr)`
// Sometimes you'd like to determine if a specific attribute is set
// in an entity. For this reason you can call for example `person.has('friend')`
// to determine if a person entity has friends.
has: function(attr) {
attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
return Backbone.Model.prototype.has.call(this, attr);
},
// #### `.set(attrName, value, opts)`,
// The `options` parameter always refers to a `Backbone.Model.set` `options` object.
//
// **`.set(attributes, options)`** is the most universal way of calling the
// `.set` method. In this case the `attributes` object is a map of all
// attributes to be changed.
set : function(attrs, options, opts) {
if (!attrs) {
return this;
}
if (attrs['@subject']) {
attrs['@subject'] = this.toReference(attrs['@subject']);
}
// Use **`.set(attrName, value, options)`** for setting or changing exactly one
// entity attribute.
if (typeof attrs === "string") {
var obj = {};
obj[attrs] = options;
return this.set(obj, opts);
}
// **`.set(entity)`**: In case you'd pass a VIE entity,
// the passed entities attributes are being set for the entity.
if (attrs.attributes) {
attrs = attrs.attributes;
}
var self = this;
var coll;
// resolve shortened URIs like rdfs:label..
_.each (attrs, function (value, key) {
var newKey = VIE.Util.mapAttributeNS(key, self.vie.namespaces);
if (key !== newKey) {
delete attrs[key];
attrs[newKey] = value;
}
}, this);
// Finally iterate through the *attributes* to be set and prepare
// them for the Backbone.Model.set method.
_.each (attrs, function (value, key) {
if (!value) { return; }
if (key.indexOf('@') === -1) {
if (value.isCollection) {
// ignore
value.each(function (child) {
self.vie.entities.addOrUpdate(child);
});
} else if (value.isEntity) {
self.vie.entities.addOrUpdate(value);
coll = new self.vie.Collection(value, {
vie: self.vie,
predicate: key
});
attrs[key] = coll;
} else if (_.isArray(value)) {
if (this.attributes[key] && this.attributes[key].isCollection) {
var newEntities = this.attributes[key].addOrUpdate(value);
attrs[key] = this.attributes[key];
attrs[key].reset(newEntities);
}
} else if (value["@value"]) {
// The value is a literal object, ignore
} else if (_.isObject(value) && !_.isDate(value)) {
// The value is another VIE Entity
var child = new self.vie.Entity(value, options);
// which is being stored in `v.entities`
self.vie.entities.addOrUpdate(child);
// and set as VIE Collection attribute on the original entity
coll = new self.vie.Collection(value, {
vie: self.vie,
predicate: key
});
attrs[key] = coll;
} else {
// ignore
}
}
}, this);
var ret = Backbone.Model.prototype.set.call(this, attrs, options);
if (options && options.ignoreChanges) {
this.changed = {};
this._previousAttributes = _.clone(this.attributes);
}
return ret;
},
// **`.unset(attr, opts)` ** removes an attribute from the entity.
unset: function (attr, opts) {
attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
return Backbone.Model.prototype.unset.call(this, attr, opts);
},
// Validation based on type rules.
//
// There are two ways to skip validation for entity operations:
//
// * `options.silent = true`
// * `options.validate = false`
validate: function (attrs, opts) {
if (opts && opts.validate === false) {
return;
}
var types = this.get('@type');
if (_.isArray(types)) {
var results = [];
_.each(types, function (type) {
var res = this.validateByType(type, attrs, opts);
if (res) {
results.push(res);
}
}, this);
if (_.isEmpty(results)) {
return;
}
return _.flatten(results);
}
return this.validateByType(types, attrs, opts);
},
validateByType: function (type, attrs, opts) {
var messages = {
max: '<%= property %> cannot contain more than <%= num %> items',
min: '<%= property %> must contain at least <%= num %> items',
required: '<%= property %> is required'
};
if (!type.attributes) {
return;
}
var toError = function (definition, constraint, messageValues) {
return {
property: definition.id,
constraint: constraint,
message: _.template(messages[constraint], _.extend({
property: definition.id
}, messageValues))
};
};
var checkMin = function (definition, attrs) {
if (!attrs[definition.id] || _.isEmpty(attrs[definition.id])) {
return toError(definition, 'required', {});
}
};
// Check the number of items in attr against max
var checkMax = function (definition, attrs) {
if (!attrs[definition.id]) {
return;
}
if (!attrs[definition.id].isCollection && !_.isArray(attrs[definition.id])) {
return;
}
if (attrs[definition.id].length > definition.max) {
return toError(definition, 'max', {
num: definition.max
});
}
};
var results = [];
_.each(type.attributes.list(), function (definition) {
var res;
if (definition.max && definition.max != -1) {
res = checkMax(definition, attrs);
if (res) {
results.push(res);
}
}
if (definition.min && definition.min > 0) {
res = checkMin(definition, attrs);
if (res) {
results.push(res);
}
}
});
if (_.isEmpty(results)) {
return;
}
return results;
},
isNew: function() {
if (this.getSubjectUri().substr(0, 7) === '_:bnode') {
return true;
}
return false;
},
hasChanged: function(attr) {
if (this.markedChanged) {
return true;
}
return Backbone.Model.prototype.hasChanged.call(this, attr);
},
// Force hasChanged to return true
forceChanged: function(changed) {
this.markedChanged = changed ? true : false;
},
// **`getSubject()`** is the getter for the entity identifier.
getSubject: function(){
if (typeof this.id === "undefined") {
this.id = this.attributes[this.idAttribute];
}
if (typeof this.id === 'string') {
if (this.id.substr(0, 7) === 'http://' || this.id.substr(0, 4) === 'urn:') {
return this.toReference(this.id);
}
return this.id;
}
return this.cid.replace('c', '_:bnode');
},
// TODO describe
getSubjectUri: function(){
return this.fromReference(this.getSubject());
},
isReference: function(uri){
var matcher = new RegExp("^\\<([^\\>]*)\\>$");
if (matcher.exec(uri)) {
return true;
}
return false;
},
toReference: function(uri){
if (_.isArray(uri)) {
var self = this;
return _.map(uri, function(part) {
return self.toReference(part);
});
}
var ns = this.vie.namespaces;
var ret = uri;
if (uri.substring(0, 2) === "_:") {
ret = uri;
}
else if (ns.isCurie(uri)) {
ret = ns.uri(uri);
if (ret === "<" + ns.base() + uri + ">") {
/* no base namespace extension with IDs */
ret = '<' + uri + '>';
}
} else if (!ns.isUri(uri)) {
ret = '<' + uri + '>';
}
return ret;
},
fromReference: function(uri){
var ns = this.vie.namespaces;
if (!ns.isUri(uri)) {
return uri;
}
return uri.substring(1, uri.length - 1);
},
as: function(encoding){
if (encoding === "JSON") {
return this.toJSON();
}
if (encoding === "JSONLD") {
return this.toJSONLD();
}
throw new Error("Unknown encoding " + encoding);
},
toJSONLD: function(){
var instanceLD = {};
var instance = this;
_.each(instance.attributes, function(value, name){
var entityValue = value; //instance.get(name);
if (value instanceof instance.vie.Collection) {
entityValue = value.map(function(instance) {
return instance.getSubject();
});
}
// TODO: Handle collections separately
instanceLD[name] = entityValue;
});
instanceLD['@subject'] = instance.getSubject();
return instanceLD;
},
// **`.setOrAdd(arg1, arg2)`** similar to `.set(..)`, `.setOrAdd(..)` can
// be used for setting one or more attributes of an entity, but in
// this case it's a collection of values, not just one. That means, if the
// entity already has the attribute set, make the value to a VIE Collection
// and use the collection as value. The collection can contain entities
// or literals, but not both at the same time.
setOrAdd: function (arg1, arg2, option) {
var entity = this;
if (typeof arg1 === "string" && arg2) {
// calling entity.setOrAdd("rdfs:type", "example:Musician")
entity._setOrAddOne(arg1, arg2, option);
}
else
if (typeof arg1 === "object") {
// calling entity.setOrAdd({"rdfs:type": "example:Musician", ...})
_(arg1).each(function(val, key){
entity._setOrAddOne(key, val, arg2);
});
}
return this;
},
/* attr is always of type string */
/* value can be of type: string,int,double,object,VIE.Entity,VIE.Collection */
/* val can be of type: undefined,string,int,double,array,VIE.Collection */
/* depending on the type of value and the type of val, different actions need to be made */
_setOrAddOne: function (attr, value, options) {
if (!attr || !value)
return;
options = (options)? options : {};
var v;
attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
if (_.isArray(value)) {
for (v = 0; v < value.length; v++) {
this._setOrAddOne(attr, value[v], options);
}
return;
}
if (attr === "@type" && value instanceof self.vie.Type) {
value = value.id;
}
var obj = {};
var existing = Backbone.Model.prototype.get.call(this, attr);
if (!existing) {
obj[attr] = value;
this.set(obj, options);
} else if (existing.isCollection) {
if (value.isCollection) {
value.each(function (model) {
existing.add(model);
});
} else if (value.isEntity) {
existing.add(value);
} else if (typeof value === "object") {
value = new this.vie.Entity(value);
existing.add(value);
} else {
throw new Error("you cannot add a literal to a collection of entities!");
}
this.trigger('change:' + attr, this, value, {});
this.change({});
} else if (_.isArray(existing)) {
if (value.isCollection) {
for (v = 0; v < value.size(); v++) {
this._setOrAddOne(attr, value.at(v).getSubject(), options);
}
} else if (value.isEntity) {
this._setOrAddOne(attr, value.getSubject(), options);
} else if (typeof value === "object") {
value = new this.vie.Entity(value);
this._setOrAddOne(attr, value, options);
} else {
/* yes, we (have to) allow multiple equal values */
existing.push(value);
obj[attr] = existing;
this.set(obj);
}
} else {
var arr = [ existing ];
arr.push(value);
obj[attr] = arr;
return this.set(obj, options);
}
},
// **`.hasType(type)`** determines if the entity has the explicit `type` set.
hasType: function(type){
type = self.vie.types.get(type);
return this.hasPropertyValue("@type", type);
},
// TODO describe
hasPropertyValue: function(property, value) {
var t = this.get(property);
if (!(value instanceof Object)) {
value = self.vie.entities.get(value);
}
if (t instanceof Array) {
return t.indexOf(value) !== -1;
}
else {
return t === value;
}
},
// **`.isof(type)`** determines if the entity is of `type` by explicit or implicit
// declaration. E.g. if Employee is a subtype of Person and e Entity has
// explicitly set type Employee, e.isof(Person) will evaluate to true.
isof: function (type) {
var types = this.get('@type');
if (types === undefined) {
return false;
}
types = (_.isArray(types))? types : [ types ];
type = (self.vie.types.get(type))? self.vie.types.get(type) : new self.vie.Type(type);
for (var t = 0; t < types.length; t++) {
if (self.vie.types.get(types[t])) {
if (self.vie.types.get(types[t]).isof(type)) {
return true;
}
} else {
var typeTmp = new self.vie.Type(types[t]);
if (typeTmp.id === type.id) {
return true;
}
}
}
return false;
},
// TODO describe
addTo : function (collection, update) {
var self = this;
if (collection instanceof self.vie.Collection) {
if (update) {
collection.addOrUpdate(self);
} else {
collection.add(self);
}
return this;
}
throw new Error("Please provide a proper collection of type VIE.Collection as argument!");
},
isEntity: true,
vie: self.vie
});
return new Model(attrs, opts);
};
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
VIE.prototype.Collection = Backbone.Collection.extend({
model: VIE.prototype.Entity,
initialize: function (models, options) {
if (!options || !options.vie) {
throw new Error('Each collection needs a VIE reference');
}
this.vie = options.vie;
this.predicate = options.predicate;
},
canAdd: function (type) {
return true;
},
get: function(id) {
if (id === null) {
return null;
}
id = (id.getSubject)? id.getSubject() : id;
if (typeof id === "string" && id.indexOf("_:") === 0) {
if (id.indexOf("bnode") === 2) {
//bnode!
id = id.replace("_:bnode", 'c');
return this._byCid[id];
} else {
return this._byId["<" + id + ">"];
}
} else {
id = this.toReference(id);
return this._byId[id];
}
},
addOrUpdate: function(model, options) {
options = options || {};
var collection = this;
var existing;
if (_.isArray(model)) {
var entities = [];
_.each(model, function(item) {
entities.push(collection.addOrUpdate(item, options));
});
return entities;
}
if (model === undefined) {
throw new Error("No model given");
}
if (_.isString(model)) {
model = {
'@subject': model,
id: model
};
}
if (!model.isEntity) {
model = new this.model(model);
}
if (model.id && this.get(model.id)) {
existing = this.get(model.id);
}
if (this.getByCid(model.cid)) {
existing = this.getByCid(model.cid);
}
if (existing) {
var newAttribs = {};
_.each(model.attributes, function(value, attribute) {
if (!existing.has(attribute)) {
newAttribs[attribute] = value;
return true;
}
if (attribute === '@subject') {
if (model.isNew() && !existing.isNew()) {
// Save order issue, skip
return true;
}
}
if (existing.get(attribute) === value) {
return true;
}
//merge existing attribute values with new ones!
//not just overwrite 'em!!
var oldVals = existing.attributes[attribute];
var newVals = value;
if (oldVals instanceof collection.vie.Collection) {
// TODO: Merge collections
return true;
}
if (options.overrideAttributes) {
newAttribs[attribute] = value;
return true;
}
if (attribute === '@context') {
newAttribs[attribute] = jQuery.extend(true, {}, oldVals, newVals);
} else {
oldVals = (jQuery.isArray(oldVals))? oldVals : [ oldVals ];
newVals = (jQuery.isArray(newVals))? newVals : [ newVals ];
newAttribs[attribute] = _.uniq(oldVals.concat(newVals));
newAttribs[attribute] = (newAttribs[attribute].length === 1)? newAttribs[attribute][0] : newAttribs[attribute];
}
});
if (!_.isEmpty(newAttribs)) {
existing.set(newAttribs, options.updateOptions);
}
return existing;
}
this.add(model, options.addOptions);
return model;
},
isReference: function(uri){
var matcher = new RegExp("^\\<([^\\>]*)\\>$");
if (matcher.exec(uri)) {
return true;
}
return false;
},
toReference: function(uri){
if (this.isReference(uri)) {
return uri;
}
return '<' + uri + '>';
},
fromReference: function(uri){
if (!this.isReference(uri)) {
return uri;
}
return uri.substring(1, uri.length - 1);
},
isCollection: true
});
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
//
// ## VIE.Types
// Within VIE, we provide special capabilities of handling types of entites. This helps
// for example to query easily for certain entities (e.g., you only need to query for *Person*s
// and not for all subtypes).
if (VIE.prototype.Type) {
throw new Error("ERROR: VIE.Type is already defined. Please check your installation!");
}
if (VIE.prototype.Types) {
throw new Error("ERROR: VIE.Types is already defined. Please check your installation!");
}
// ### VIE.Type(id, attrs, metadata)
// This is the constructor of a VIE.Type.
// **Parameters**:
// *{string}* **id** The id of the type.
// *{string|array|VIE.Attribute}* **attrs** A string, proper ```VIE.Attribute``` or an array of these which
// *{object}* **metadata** Possible metadata about the type
// are the possible attributes of the type
// **Throws**:
// *{Error}* if one of the given paramenters is missing.
// **Returns**:
// *{VIE.Type}* : A **new** VIE.Type object.
// **Example usage**:
//
// var person = new vie.Type("Person", ["name", "knows"]);
VIE.prototype.Type = function (id, attrs, metadata) {
if (id === undefined || typeof id !== 'string') {
throw "The type constructor needs an 'id' of type string! E.g., 'Person'";
}
// ### id
// This field stores the id of the type's instance.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{string}* : The id of the type as a URI.
// **Example usage**:
//
// console.log(person.id);
// // --> "<http://viejs.org/ns/Person>"
this.id = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
/* checks whether such a type is already defined. */
if (this.vie.types.get(this.id)) {
throw new Error("The type " + this.id + " is already defined!");
}
// ### supertypes
// This field stores all parent types of the type's instance. This
// is set if the current type inherits from another type.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{VIE.Types}* : The supertypes (parents) of the type.
// **Example usage**:
//
// console.log(person.supertypes);
this.supertypes = new this.vie.Types();
// ### subtypes
// This field stores all children types of the type's instance. This
// will be set if another type inherits from the current type.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{VIE.Types}* : The subtypes (parents) of the type.
// **Example usage**:
//
// console.log(person.subtypes);
this.subtypes = new this.vie.Types();
// ### attributes
// This field stores all attributes of the type's instance as
// a proper ```VIE.Attributes``` class. (see also <a href="Attribute.html">VIE.Attributes</a>)
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{VIE.Attributes}* : The attributes of the type.
// **Example usage**:
//
// console.log(person.attributes);
this.attributes = new this.vie.Attributes(this, (attrs)? attrs : []);
// ### metadata
// This field stores possible additional information about the type, like
// a human-readable label.
this.metadata = metadata ? metadata : {};
// ### isof(type)
// This method checks whether the current type is a child of the given type.
// **Parameters**:
// *{string|VIE.Type}* **type** The type (or the id of that type) to be checked.
// **Throws**:
// *{Error}* If the type is not valid.
// **Returns**:
// *{boolean}* : ```true``` if the current type inherits from the type, ```false``` otherwise.
// **Example usage**:
//
// console.log(person.isof("owl:Thing"));
// // <-- true
this.isof = function (type) {
type = this.vie.types.get(type);
if (type) {
return type.subsumes(this.id);
} else {
throw new Error("No valid type given");
}
};
// ### subsumes(type)
// This method checks whether the current type is a parent of the given type.
// **Parameters**:
// *{string|VIE.Type}* **type** The type (or the id of that type) to be checked.
// **Throws**:
// *{Error}* If the type is not valid.
// **Returns**:
// *{boolean}* : ```true``` if the current type is a parent of the type, ```false``` otherwise.
// **Example usage**:
//
// var x = new vie.Type(...);
// var y = new vie.Type(...).inherit(x);
// y.isof(x) === x.subsumes(y);
this.subsumes = function (type) {
type = this.vie.types.get(type);
if (type) {
if (this.id === type.id) {
return true;
}
var subtypes = this.subtypes.list();
for (var c = 0; c < subtypes.length; c++) {
var childObj = subtypes[c];
if (childObj) {
if (childObj.id === type.id || childObj.subsumes(type)) {
return true;
}
}
}
return false;
} else {
throw new Error("No valid type given");
}
};
// ### inherit(supertype)
// This method invokes inheritance throught the types. This adds the current type to the
// subtypes of the supertype and vice versa.
// **Parameters**:
// *{string|VIE.Type|array}* **supertype** The type to be inherited from. If this is an array
// the inherit method is called sequentially on all types.
// **Throws**:
// *{Error}* If the type is not valid.
// **Returns**:
// *{VIE.Type}* : The instance itself.
// **Example usage**:
//
// var x = new vie.Type(...);
// var y = new vie.Type(...).inherit(x);
// y.isof(x) // <-- true
this.inherit = function (supertype) {
if (typeof supertype === "string") {
this.inherit(this.vie.types.get(supertype));
}
else if (supertype instanceof this.vie.Type) {
supertype.subtypes.addOrOverwrite(this);
this.supertypes.addOrOverwrite(supertype);
try {
/* only for validation of attribute-inheritance!
if this throws an error (inheriting two attributes
that cannot be combined) we reverse all changes. */
this.attributes.list();
} catch (e) {
supertype.subtypes.remove(this);
this.supertypes.remove(supertype);
throw e;
}
} else if (jQuery.isArray(supertype)) {
for (var i = 0, slen = supertype.length; i < slen; i++) {
this.inherit(supertype[i]);
}
} else {
throw new Error("Wrong argument in VIE.Type.inherit()");
}
return this;
};
// ### hierarchy()
// This method serializes the hierarchy of child types into an object.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{object}* : The hierachy of child types as an object.
// **Example usage**:
//
// var x = new vie.Type(...);
// var y = new vie.Type(...).inherit(x);
// x.hierarchy();
this.hierarchy = function () {
var obj = {id : this.id, subtypes: []};
var list = this.subtypes.list();
for (var c = 0, llen = list.length; c < llen; c++) {
var childObj = this.vie.types.get(list[c]);
obj.subtypes.push(childObj.hierarchy());
}
return obj;
};
// ### instance()
// This method creates a ```VIE.Entity``` instance from this type.
// **Parameters**:
// *{object}* **attrs** see <a href="Entity.html">constructor of VIE.Entity</a>
// *{object}* **opts** see <a href="Entity.html">constructor of VIE.Entity</a>
// **Throws**:
// *{Error}* if the instance could not be built
// **Returns**:
// *{VIE.Entity}* : A **new** instance of a ```VIE.Entity``` with the current type.
// **Example usage**:
//
// var person = new vie.Type("person");
// var sebastian = person.instance(
// {"@subject" : "#me",
// "name" : "Sebastian"});
// console.log(sebastian.get("name")); // <-- "Sebastian"
this.instance = function (attrs, opts) {
attrs = (attrs)? attrs : {};
opts = (opts)? opts : {};
/* turn type/attribute checking on by default! */
if (opts.typeChecking !== false) {
for (var a in attrs) {
if (a.indexOf('@') !== 0 && !this.attributes.get(a)) {
throw new Error("Cannot create an instance of " + this.id + " as the type does not allow an attribute '" + a + "'!");
}
}
}
if (attrs['@type']) {
attrs['@type'].push(this.id);
} else {
attrs['@type'] = this.id;
}
return new this.vie.Entity(attrs, opts);
};
// ### toString()
// This method returns the id of the type.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{string}* : The id of the type.
// **Example usage**:
//
// var x = new vie.Type(...);
// x.toString() === x.id;
this.toString = function () {
return this.id;
};
};
// ### VIE.Types()
// This is the constructor of a VIE.Types. This is a convenience class
// to store ```VIE.Type``` instances properly.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Types}* : A **new** VIE.Types object.
// **Example usage**:
//
// var types = new vie.Types();
VIE.prototype.Types = function () {
this._types = {};
// ### add(id, attrs, metadata)
// This method adds a `VIE.Type` to the types.
// **Parameters**:
// *{string|VIE.Type}* **id** If this is a string, the type is created and directly added.
// *{string|object}* **attrs** Only used if ```id``` is a string.
// *{object}* **metadata** potential additional metadata about the type.
// **Throws**:
// *{Error}* if a type with the given id already exists a ```VIE.Entity``` instance from this type.
// **Returns**:
// *{VIE.Types}* : The instance itself.
// **Example usage**:
//
// var types = new vie.Types();
// types.add("Person", ["name", "knows"]);
this.add = function (id, attrs, metadata) {
if (_.isArray(id)) {
_.each(id, function (type) {
this.add(type);
}, this);
return this;
}
if (this.get(id)) {
throw new Error("Type '" + id + "' already registered.");
} else {
if (typeof id === "string") {
var t = new this.vie.Type(id, attrs, metadata);
this._types[t.id] = t;
return t;
} else if (id instanceof this.vie.Type) {
this._types[id.id] = id;
return id;
} else {
throw new Error("Wrong argument to VIE.Types.add()!");
}
}
return this;
};
// ### addOrOverwrite(id, attrs)
// This method adds or overwrites a `VIE.Type` to the types. This is the same as
// ``this.remove(id); this.add(id, attrs);``
// **Parameters**:
// *{string|VIE.Type}* **id** If this is a string, the type is created and directly added.
// *{string|object}* **attrs** Only used if ```id``` is a string.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Types}* : The instance itself.
// **Example usage**:
//
// var types = new vie.Types();
// types.addOrOverwrite("Person", ["name", "knows"]);
this.addOrOverwrite = function(id, attrs){
if (this.get(id)) {
this.remove(id);
}
return this.add(id, attrs);
};
// ### get(id)
// This method retrieves a `VIE.Type` from the types by it's id.
// **Parameters**:
// *{string|VIE.Type}* **id** The id or the type itself.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Type}* : The instance of the type or ```undefined```.
// **Example usage**:
//
// var types = new vie.Types();
// types.addOrOverwrite("Person", ["name", "knows"]);
// types.get("Person");
this.get = function (id) {
if (!id) {
return undefined;
}
if (typeof id === 'string') {
var lid = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
return this._types[lid];
} else if (id instanceof this.vie.Type) {
return this.get(id.id);
}
return undefined;
};
// ### remove(id)
// This method removes a type of given id from the type. This also
// removes all children if their only parent were this
// type. Furthermore, this removes the link from the
// super- and subtypes.
// **Parameters**:
// *{string|VIE.Type}* **id** The id or the type itself.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Type}* : The removed type.
// **Example usage**:
//
// var types = new vie.Types();
// types.addOrOverwrite("Person", ["name", "knows"]);
// types.remove("Person");
this.remove = function (id) {
var t = this.get(id);
/* test whether the type actually exists in VIE
* and prevents removing *owl:Thing*.
*/
if (!t) {
return this;
}
if (!t || t.subsumes("owl:Thing")) {
console.warn("You are not allowed to remove 'owl:Thing'.");
return this;
}
delete this._types[t.id];
var subtypes = t.subtypes.list();
for (var c = 0; c < subtypes.length; c++) {
var childObj = subtypes[c];
if (childObj.supertypes.list().length === 1) {
/* recursively remove all children
that inherit only from this type */
this.remove(childObj);
} else {
childObj.supertypes.remove(t.id);
}
}
return t;
};
// ### toArray() === list()
// This method returns an array of all types.
// **Parameters**:
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{array}* : An array of ```VIE.Type``` instances.
// **Example usage**:
//
// var types = new vie.Types();
// types.addOrOverwrite("Person", ["name", "knows"]);
// types.list();
this.toArray = this.list = function () {
var ret = [];
for (var i in this._types) {
ret.push(this._types[i]);
}
return ret;
};
// ### sort(types, desc)
// This method sorts an array of types in their order, given by the
// inheritance. This returns a copy and leaves the original array untouched.
// **Parameters**:
// *{array|VIE.Type}* **types** The array of ```VIE.Type``` instances or ids of types to be sorted.
// *{boolean}* **desc** If 'desc' is given and 'true', the array will be sorted
// in descendant order.
// *nothing*
// **Throws**:
// *nothing*
// **Returns**:
// *{array}* : A sorted copy of the array.
// **Example usage**:
//
// var types = new vie.Types();
// types.addOrOverwrite("Person", ["name", "knows"]);
// types.sort(types.list(), true);
this.sort = function (types, desc) {
var self = this;
types = (jQuery.isArray(types))? types : [ types ];
desc = (desc)? true : false;
if (types.length === 0) return [];
var copy = [ types[0] ];
var x, tlen;
for (x = 1, tlen = types.length; x < tlen; x++) {
var insert = types[x];
var insType = self.get(insert);
if (insType) {
for (var y = 0; y < copy.length; y++) {
if (insType.subsumes(copy[y])) {
copy.splice(y,0,insert);
break;
} else if (y === copy.length - 1) {
copy.push(insert);
}
}
}
}
//unduplicate
for (x = 0; x < copy.length; x++) {
if (copy.lastIndexOf(copy[x]) !== x) {
copy.splice(x, 1);
x--;
}
}
if (!desc) {
copy.reverse();
}
return copy;
};
};
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
//
// ## VIE.Attributes
// Within VIE, we provide special capabilities of handling attributes of types of entites. This
// helps first of all to list all attributes of an entity type, but furthermore fully supports
// inheritance of attributes from the type-class to inherit from.
if (VIE.prototype.Attribute) {
throw new Error("ERROR: VIE.Attribute is already defined. Please check your VIE installation!");
}
if (VIE.prototype.Attributes) {
throw new Error("ERROR: VIE.Attributes is already defined. Please check your VIE installation!");
}
// ### VIE.Attribute(id, range, domain, minCount, maxCount, metadata)
// This is the constructor of a VIE.Attribute.
// **Parameters**:
// *{string}* **id** The id of the attribute.
// *{string|array}* **range** A string or an array of strings of the target range of
// the attribute.
// *{string}* **domain** The domain of the attribute.
// *{number}* **minCount** The minimal number this attribute can occur. (needs to be >= 0)
// *{number}* **maxCount** The maximal number this attribute can occur. (needs to be >= minCount, use `-1` for unlimited)
// *{object}* **metadata** Possible metadata about the attribute
// **Throws**:
// *{Error}* if one of the given paramenters is missing.
// **Returns**:
// *{VIE.Attribute}* : A **new** VIE.Attribute object.
// **Example usage**:
//
// var knowsAttr = new vie.Attribute("knows", ["Person"], "Person", 0, 10);
// // Creates an attribute to describe a *knows*-relationship
// // between persons. Each person can only have
VIE.prototype.Attribute = function (id, range, domain, minCount, maxCount, metadata) {
if (id === undefined || typeof id !== 'string') {
throw new Error("The attribute constructor needs an 'id' of type string! E.g., 'Person'");
}
if (range === undefined) {
throw new Error("The attribute constructor of " + id + " needs 'range'.");
}
if (domain === undefined) {
throw new Error("The attribute constructor of " + id + " needs a 'domain'.");
}
this._domain = domain;
// ### id
// This field stores the id of the attribute's instance.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{string}* : A URI, representing the id of the attribute.
// **Example usage**:
//
// var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
// console.log(knowsAttr.id);
// // --> <http://viejs.org/ns/knows>
this.id = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
// ### range
// This field stores the ranges of the attribute's instance.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{array}* : An array of strings which represent the types.
// **Example usage**:
//
// var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
// console.log(knowsAttr.range);
// // --> ["Person"]
this.range = (_.isArray(range))? range : [ range ];
// ### min
// This field stores the minimal amount this attribute can occur in the type's instance. The number
// needs to be greater or equal to zero.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{int}* : The minimal amount this attribute can occur.
// **Example usage**:
//
// console.log(person.min);
// // --> 0
minCount = minCount ? minCount : 0;
this.min = (minCount > 0) ? minCount : 0;
// ### max
// This field stores the maximal amount this attribute can occur in the type's instance.
// This number cannot be smaller than min
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{int}* : The maximal amount this attribute can occur.
// **Example usage**:
//
// console.log(person.max);
// // --> 1.7976931348623157e+308
maxCount = maxCount ? maxCount : 1;
if (maxCount === -1) {
maxCount = Number.MAX_VALUE;
}
this.max = (maxCount >= this.min)? maxCount : this.min;
// ### metadata
// This field holds potential metadata about the attribute.
this.metadata = metadata ? metadata : {};
// ### applies(range)
// This method checks, whether the current attribute applies in the given range.
// If ```range``` is a string and cannot be transformed into a ```VIE.Type```,
// this performs only string comparison, if it is a VIE.Type
// or an ID of a VIE.Type, then inheritance is checked as well.
// **Parameters**:
// *{string|VIE.Type}* **range** The ```VIE.Type``` (or it's string representation) to be checked.
// **Throws**:
// nothing
// **Returns**:
// *{boolean}* : ```true``` if the given type applies to this attribute and ```false``` otherwise.
// **Example usage**:
//
// var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
// console.log(knowsAttr.applies("Person")); // --> true
// console.log(knowsAttr.applies("Place")); // --> false
this.applies = function (range) {
if (this.vie.types.get(range)) {
range = this.vie.types.get(range);
}
for (var r = 0, len = this.range.length; r < len; r++) {
var x = this.vie.types.get(this.range[r]);
if (x === undefined && typeof range === "string") {
if (range === this.range[r]) {
return true;
}
}
else {
if (range.isof(this.range[r])) {
return true;
}
}
}
return false;
};
};
// ## VIE.Attributes(domain, attrs)
// This is the constructor of a VIE.Attributes. Basically a convenience class
// that represents a list of ```VIE.Attribute```. As attributes are part of a
// certain ```VIE.Type```, it needs to be passed for inheritance checks.
// **Parameters**:
// *{string}* **domain** The domain of the attributes (the type they will be part of).
// *{string|VIE.Attribute|array}* **attrs** Either a string representation of an attribute,
// a proper instance of ```VIE.Attribute``` or an array of both.
// *{string}* **domain** The domain of the attribute.
// **Throws**:
// *{Error}* if one of the given paramenters is missing.
// **Returns**:
// *{VIE.Attribute}* : A **new** VIE.Attribute instance.
// **Example usage**:
//
// var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
// var personAttrs = new vie.Attributes("Person", knowsAttr);
VIE.prototype.Attributes = function (domain, attrs) {
this._local = {};
this._attributes = {};
// ### domain
// This field stores the domain of the attributes' instance.
// **Parameters**:
// nothing
// **Throws**:
// nothing
// **Returns**:
// *{string}* : The string representation of the domain.
// **Example usage**:
//
// console.log(personAttrs.domain);
// // --> ["Person"]
this.domain = domain;
// ### add(id, range, min, max, metadata)
// This method adds a ```VIE.Attribute``` to the attributes instance.
// **Parameters**:
// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
// instance of a ```VIE.Attribute```.
// *{string|array}* **range** An array representing the target range of the attribute.
// *{number}* **min** The minimal amount this attribute can appear.
// instance of a ```VIE.Attribute```.
// *{number}* **max** The maximal amount this attribute can appear.
// *{object}* **metadata** Additional metadata for the attribute.
// **Throws**:
// *{Error}* If an atribute with the given id is already registered.
// *{Error}* If the ```id``` parameter is not a string, nor a ```VIE.Type``` instance.
// **Returns**:
// *{VIE.Attribute}* : The generated or passed attribute.
// **Example usage**:
//
// personAttrs.add("name", "Text", 0, 1);
this.add = function (id, range, min, max, metadata) {
if (_.isArray(id)) {
_.each(id, function (attribute) {
this.add(attribute);
}, this);
return this;
}
if (this.get(id)) {
throw new Error("Attribute '" + id + "' already registered for domain " + this.domain.id + "!");
} else {
if (typeof id === "string") {
var a = new this.vie.Attribute(id, range, this.domain, min, max, metadata);
this._local[a.id] = a;
return a;
} else if (id instanceof this.vie.Attribute) {
id.domain = this.domain;
id.vie = this.vie;
this._local[id.id] = id;
return id;
} else {
throw new Error("Wrong argument to VIE.Types.add()!");
}
}
};
// ### remove(id)
// This method removes a ```VIE.Attribute``` from the attributes instance.
// **Parameters**:
// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
// instance of a ```VIE.Attribute```.
// **Throws**:
// *{Error}* When the attribute is inherited from a parent ```VIE.Type``` and thus cannot be removed.
// **Returns**:
// *{VIE.Attribute}* : The removed attribute.
// **Example usage**:
//
// personAttrs.remove("knows");
this.remove = function (id) {
var a = this.get(id);
if (a.id in this._local) {
delete this._local[a.id];
return a;
}
throw new Error("The attribute " + id + " is inherited and cannot be removed from the domain " + this.domain.id + "!");
};
// ### get(id)
// This method returns a ```VIE.Attribute``` from the attributes instance by it's id.
// **Parameters**:
// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
// instance of a ```VIE.Attribute```.
// **Throws**:
// *{Error}* When the method is called with an unknown datatype.
// **Returns**:
// *{VIE.Attribute}* : The attribute.
// **Example usage**:
//
// personAttrs.get("knows");
this.get = function (id) {
if (typeof id === 'string') {
var lid = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
return this._inherit()._attributes[lid];
} else if (id instanceof this.vie.Attribute) {
return this.get(id.id);
} else {
throw new Error("Wrong argument in VIE.Attributes.get()");
}
};
// ### _inherit()
// The private method ```_inherit``` creates a full list of all attributes. This includes
// local attributes as well as inherited attributes from the parents. The ranges of attributes
// with the same id will be merged. This method is called everytime an attribute is requested or
// the list of all attributes. Usually this method should not be invoked outside of the class.
// **Parameters**:
// *nothing*
// instance of a ```VIE.Attribute```.
// **Throws**:
// *nothing*
// **Returns**:
// *nothing*
// **Example usage**:
//
// personAttrs._inherit();
this._inherit = function () {
var a, x, id;
var attributes = jQuery.extend(true, {}, this._local);
var inherited = _.map(this.domain.supertypes.list(),
function (x) {
return x.attributes;
}
);
var add = {};
var merge = {};
var ilen, alen;
for (a = 0, ilen = inherited.length; a < ilen; a++) {
var attrs = inherited[a].list();
for (x = 0, alen = attrs.length; x < alen; x++) {
id = attrs[x].id;
if (!(id in attributes)) {
if (!(id in add) && !(id in merge)) {
add[id] = attrs[x];
}
else {
if (!merge[id]) {
merge[id] = {range : [], mins : [], maxs: [], metadatas: []};
}
if (id in add) {
merge[id].range = jQuery.merge(merge[id].range, add[id].range);
merge[id].mins = jQuery.merge(merge[id].mins, [ add[id].min ]);
merge[id].maxs = jQuery.merge(merge[id].maxs, [ add[id].max ]);
merge[id].metadatas = jQuery.merge(merge[id].metadatas, [ add[id].metadata ]);
delete add[id];
}
merge[id].range = jQuery.merge(merge[id].range, attrs[x].range);
merge[id].mins = jQuery.merge(merge[id].mins, [ attrs[x].min ]);
merge[id].maxs = jQuery.merge(merge[id].maxs, [ attrs[x].max ]);
merge[id].metadatas = jQuery.merge(merge[id].metadatas, [ attrs[x].metadata ]);
merge[id].range = _.uniq(merge[id].range);
merge[id].mins = _.uniq(merge[id].mins);
merge[id].maxs = _.uniq(merge[id].maxs);
merge[id].metadatas = _.uniq(merge[id].metadatas);
}
}
}
}
/* adds inherited attributes that do not need to be merged */
jQuery.extend(attributes, add);
/* merges inherited attributes */
for (id in merge) {
var mranges = merge[id].range;
var mins = merge[id].mins;
var maxs = merge[id].maxs;
var metadatas = merge[id].metadatas;
var ranges = [];
//merging ranges
for (var r = 0, mlen = mranges.length; r < mlen; r++) {
var p = this.vie.types.get(mranges[r]);
var isAncestorOf = false;
if (p) {
for (x = 0; x < mlen; x++) {
if (x === r) {
continue;
}
var c = this.vie.types.get(mranges[x]);
if (c && c.isof(p)) {
isAncestorOf = true;
break;
}
}
}
if (!isAncestorOf) {
ranges.push(mranges[r]);
}
}
var maxMin = _.max(mins);
var minMax = _.min(maxs);
if (maxMin <= minMax && minMax >= 0 && maxMin >= 0) {
attributes[id] = new this.vie.Attribute(id, ranges, this, maxMin, minMax, metadatas[0]);
} else {
throw new Error("This inheritance is not allowed because of an invalid minCount/maxCount pair!");
}
}
this._attributes = attributes;
return this;
};
// ### toArray() === list()
// This method return an array of ```VIE.Attribute```s from the attributes instance.
// **Parameters**:
// *nothing.
// **Throws**:
// *nothing*
// **Returns**:
// *{array}* : An array of ```VIE.Attribute```.
// **Example usage**:
//
// personAttrs.list();
this.toArray = this.list = function (range) {
var ret = [];
var attributes = this._inherit()._attributes;
for (var a in attributes) {
if (!range || attributes[a].applies(range)) {
ret.push(attributes[a]);
}
}
return ret;
};
attrs = _.isArray(attrs) ? attrs : [ attrs ];
_.each(attrs, function (attr) {
this.add(attr.id, attr.range, attr.min, attr.max, attr.metadata);
}, this);
};
// VIE - Vienna IKS Editables
// (c) 2011 Henri Bergius, IKS Consortium
// (c) 2011 Sebastian Germesin, IKS Consortium
// (c) 2011 Szaby Grünwald, IKS Consortium
// VIE may be freely distributed under the MIT license.
// For all details and documentation:
// http://viejs.org/
if (VIE.prototype.Namespaces) {
throw new Error("ERROR: VIE.Namespaces is already defined. " +
"Please check your VIE installation!");
}
// ## VIE Namespaces
//
// In general, a namespace is a container that provides context for the identifiers.
// Within VIE, namespaces are used to distinguish different ontolgies or vocabularies
// of identifiers, types and attributes. However, because of their verbosity, namespaces
// tend to make their usage pretty circuitous. The ``VIE.Namespaces(...)`` class provides VIE
// with methods to maintain abbreviations (akak **prefixes**) for namespaces in order to
// alleviate their usage. By default, every VIE instance is equipped with a main instance
// of the namespaces in ``myVIE.namespaces``. Furthermore, VIE uses a **base namespace**,
// which is used if no prefix is given (has an empty prefix).
// In the upcoming sections, we will explain the
// methods to add, access and remove prefixes.
// ## VIE.Namespaces(base, namespaces)
// This is the constructor of a VIE.Namespaces. The constructor initially
// needs a *base namespace* and can optionally be initialised with an
// associative array of prefixes and namespaces. The base namespace is used in a way
// that every non-prefixed, non-expanded attribute or type is assumed to be of that
// namespace. This helps, e.g., in an environment where only one namespace is given.
// **Parameters**:
// *{string}* **base** The base namespace.
// *{object}* **namespaces** Initial namespaces to bootstrap the namespaces. (optional)
// **Throws**:
// *{Error}* if the base namespace is missing.
// **Returns**:
// *{VIE.Attribute}* : A **new** VIE.Attribute object.
// **Example usage**:
//
// var ns = new myVIE.Namespaces("http://viejs.org/ns/",
// {
// "foaf": "http://xmlns.com/foaf/0.1/"
// });
VIE.prototype.Namespaces = function (base, namespaces) {
if (!base) {
throw new Error("Please provide a base namespace!");
}
this._base = base;
this._namespaces = (namespaces)? namespaces : {};
if (typeof this._namespaces !== "object" || _.isArray(this._namespaces)) {
throw new Error("If you want to initialise VIE namespace prefixes, " +
"please provide a proper object!");
}
};
// ### base(ns)
// This is a **getter** and **setter** for the base
// namespace. If called like ``base();`` it
// returns the actual base namespace as a string. If provided
// with a string, e.g., ``base("http://viejs.org/ns/");``
// it sets the current base namespace and retuns the namespace object
// for the purpose of chaining. If provided with anything except a string,
// it throws an Error.
// **Parameters**:
// *{string}* **ns** The namespace to be set. (optional)
// **Throws**:
// *{Error}* if the namespace is not of type string.
// **Returns**:
// *{string}* : The current base namespace.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// console.log(namespaces.base()); // <-- "http://base.ns/"
// namespaces.base("http://viejs.org/ns/");
// console.log(namespaces.base()); // <-- "http://viejs.org/ns/"
VIE.prototype.Namespaces.prototype.base = function (ns) {
if (!ns) {
return this._base;
}
else if (typeof ns === "string") {
/* remove another mapping */
this.removeNamespace(ns);
this._base = ns;
return this._base;
} else {
throw new Error("Please provide a valid namespace!");
}
};
// ### add(prefix, namespace)
// This method adds new prefix mappings to the
// current instance. If a prefix or a namespace is already
// present (in order to avoid ambiguities), an Error is thrown.
// ``prefix`` can also be an object in which case, the method
// is called sequentially on all elements.
// **Parameters**:
// *{string|object}* **prefix** The prefix to be set. If it is an object, the
// method will be applied to all key,value pairs sequentially.
// *{string}* **namespace** The namespace to be set.
// **Throws**:
// *{Error}* If a prefix or a namespace is already
// present (in order to avoid ambiguities).
// **Returns**:
// *{VIE.Namespaces}* : The current namespaces instance.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.add("", "http://...");
// // is always equal to
// namespaces.base("http://..."); // <-- setter of base namespace
VIE.prototype.Namespaces.prototype.add = function (prefix, namespace) {
if (typeof prefix === "object") {
for (var k1 in prefix) {
this.add(k1, prefix[k1]);
}
return this;
}
if (prefix === "") {
this.base(namespace);
return this;
}
/* checking if we overwrite existing mappings */
else if (this.contains(prefix) && namespace !== this._namespaces[prefix]) {
throw new Error("ERROR: Trying to register namespace prefix mapping (" + prefix + "," + namespace + ")!" +
"There is already a mapping existing: '(" + prefix + "," + this.get(prefix) + ")'!");
} else {
jQuery.each(this._namespaces, function (k1,v1) {
if (v1 === namespace && k1 !== prefix) {
throw new Error("ERROR: Trying to register namespace prefix mapping (" + prefix + "," + namespace + ")!" +
"There is already a mapping existing: '(" + k1 + "," + namespace + ")'!");
}
});
}
/* if not, just add them */
this._namespaces[prefix] = namespace;
return this;
};
// ### addOrReplace(prefix, namespace)
// This method adds new prefix mappings to the
// current instance. This will overwrite existing mappings.
// **Parameters**:
// *{string|object}* **prefix** The prefix to be set. If it is an object, the
// method will be applied to all key,value pairs sequentially.
// *{string}* **namespace** The namespace to be set.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Namespaces}* : The current namespaces instance.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("", "http://...");
// // is always equal to
// namespaces.base("http://..."); // <-- setter of base namespace
VIE.prototype.Namespaces.prototype.addOrReplace = function (prefix, namespace) {
if (typeof prefix === "object") {
for (var k1 in prefix) {
this.addOrReplace(k1, prefix[k1]);
}
return this;
}
this.remove(prefix);
this.removeNamespace(namespace);
return this.add(prefix, namespace);
};
// ### get(prefix)
// This method retrieves a namespaces, given a prefix. If the
// prefix is the empty string, the base namespace is returned.
// **Parameters**:
// *{string}* **prefix** The prefix to be retrieved.
// **Throws**:
// *nothing*
// **Returns**:
// *{string|undefined}* : The namespace or ```undefined``` if no namespace could be found.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("test", "http://test.ns");
// console.log(namespaces.get("test")); // <-- "http://test.ns"
VIE.prototype.Namespaces.prototype.get = function (prefix) {
if (prefix === "") {
return this.base();
}
return this._namespaces[prefix];
};
// ### getPrefix(namespace)
// This method retrieves a prefix, given a namespace.
// **Parameters**:
// *{string}* **namespace** The namespace to be retrieved.
// **Throws**:
// *nothing*
// **Returns**:
// *{string|undefined}* : The prefix or ```undefined``` if no prefix could be found.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("test", "http://test.ns");
// console.log(namespaces.getPrefix("http://test.ns")); // <-- "test"
VIE.prototype.Namespaces.prototype.getPrefix = function (namespace) {
var prefix;
if (namespace.indexOf('<') === 0) {
namespace = namespace.substring(1, namespace.length - 1);
}
jQuery.each(this._namespaces, function (k1,v1) {
if (namespace.indexOf(v1) === 0) {
prefix = k1;
}
if (namespace.indexOf(k1 + ':') === 0) {
prefix = k1;
}
});
return prefix;
};
// ### contains(prefix)
// This method checks, whether a prefix is stored in the instance.
// **Parameters**:
// *{string}* **prefix** The prefix to be checked.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* : ```true``` if the prefix could be found, ```false``` otherwise.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("test", "http://test.ns");
// console.log(namespaces.contains("test")); // <-- true
VIE.prototype.Namespaces.prototype.contains = function (prefix) {
return (prefix in this._namespaces);
};
// ### containsNamespace(namespace)
// This method checks, whether a namespace is stored in the instance.
// **Parameters**:
// *{string}* **namespace** The namespace to be checked.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* : ```true``` if the namespace could be found, ```false``` otherwise.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("test", "http://test.ns");
// console.log(namespaces.containsNamespace("http://test.ns")); // <-- true
VIE.prototype.Namespaces.prototype.containsNamespace = function (namespace) {
return this.getPrefix(namespace) !== undefined;
};
// ### update(prefix, namespace)
// This method overwrites the namespace that is stored under the
// prefix ``prefix`` with the new namespace ``namespace``.
// If a namespace is already bound to another prefix, an Error is thrown.
// **Parameters**:
// *{string}* **prefix** The prefix.
// *{string}* **namespace** The namespace.
// **Throws**:
// *{Error}* If a namespace is already bound to another prefix.
// **Returns**:
// *{VIE.Namespaces}* : The namespace instance.
// **Example usage**:
//
// ...
VIE.prototype.Namespaces.prototype.update = function (prefix, namespace) {
this.remove(prefix);
return this.add(prefix, namespace);
};
// ### updateNamespace(prefix, namespace)
// This method overwrites the prefix that is bound to the
// namespace ``namespace`` with the new prefix ``prefix``. If another namespace is
// already registered with the given ``prefix``, an Error is thrown.
// **Parameters**:
// *{string}* **prefix** The prefix.
// *{string}* **namespace** The namespace.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Namespaces}* : The namespace instance.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.add("test", "http://test.ns");
// namespaces.updateNamespace("test2", "http://test.ns");
// namespaces.get("test2"); // <-- "http://test.ns"
VIE.prototype.Namespaces.prototype.updateNamespace = function (prefix, namespace) {
this.removeNamespace(prefix);
return this.add(prefix, namespace);
};
// ### remove(prefix)
// This method removes the namespace that is stored under the prefix ``prefix``.
// **Parameters**:
// *{string}* **prefix** The prefix to be removed.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Namespaces}* : The namespace instance.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.add("test", "http://test.ns");
// namespaces.get("test"); // <-- "http://test.ns"
// namespaces.remove("test");
// namespaces.get("test"); // <-- undefined
VIE.prototype.Namespaces.prototype.remove = function (prefix) {
if (prefix) {
delete this._namespaces[prefix];
}
return this;
};
// ### removeNamespace(namespace)
// This method removes removes the namespace ``namespace`` from the instance.
// **Parameters**:
// *{string}* **namespace** The namespace to be removed.
// **Throws**:
// *nothing*
// **Returns**:
// *{VIE.Namespaces}* : The namespace instance.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.add("test", "http://test.ns");
// namespaces.get("test"); // <-- "http://test.ns"
// namespaces.removeNamespace("http://test.ns");
// namespaces.get("test"); // <-- undefined
VIE.prototype.Namespaces.prototype.removeNamespace = function (namespace) {
var prefix = this.getPrefix(namespace);
if (prefix) {
delete this._namespaces[prefix];
}
return this;
};
// ### toObj()
// This method serializes the namespace instance into an associative
// array representation. The base namespace is given an empty
// string as key.
// **Parameters**:
// *{boolean}* **omitBase** If set to ```true``` this omits the baseNamespace.
// **Throws**:
// *nothing*
// **Returns**:
// *{object}* : A serialization of the namespaces as an object.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.add("test", "http://test.ns");
// console.log(namespaces.toObj());
// // <-- {"" : "http://base.ns/",
// "test": "http://test.ns"}
// console.log(namespaces.toObj(true));
// // <-- {"test": "http://test.ns"}
VIE.prototype.Namespaces.prototype.toObj = function (omitBase) {
if (omitBase) {
return jQuery.extend({}, this._namespaces);
}
return jQuery.extend({'' : this._base}, this._namespaces);
};
// ### curie(uri, safe)
// This method converts a given
// URI into a CURIE (or SCURIE), based on the given ```VIE.Namespaces``` object.
// If the given uri is already a URI, it is left untouched and directly returned.
// If no prefix could be found, an ```Error``` is thrown.
// **Parameters**:
// *{string}* **uri** The URI to be transformed.
// *{boolean}* **safe** A flag whether to generate CURIEs or SCURIEs.
// **Throws**:
// *{Error}* If no prefix could be found in the passed namespaces.
// **Returns**:
// *{string}* The CURIE or SCURIE.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var uri = "<http://dbpedia.org/ontology/Person>";
// ns.curie(uri, false); // --> dbp:Person
// ns.curie(uri, true); // --> [dbp:Person]
VIE.prototype.Namespaces.prototype.curie = function(uri, safe){
return VIE.Util.toCurie(uri, safe, this);
};
// ### isCurie(curie)
// This method checks, whether
// the given string is a CURIE and returns ```true``` if so and ```false```otherwise.
// **Parameters**:
// *{string}* **curie** The CURIE (or SCURIE) to be checked.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* ```true``` if the given curie is a CURIE or SCURIE and ```false``` otherwise.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var uri = "<http://dbpedia.org/ontology/Person>";
// var curie = "dbp:Person";
// var scurie = "[dbp:Person]";
// var text = "This is some text.";
// ns.isCurie(uri); // --> false
// ns.isCurie(curie); // --> true
// ns.isCurie(scurie); // --> true
// ns.isCurie(text); // --> false
VIE.prototype.Namespaces.prototype.isCurie = function (something) {
return VIE.Util.isCurie(something, this);
};
// ### uri(curie)
// This method converts a
// given CURIE (or save CURIE) into a URI, based on the given ```VIE.Namespaces``` object.
// **Parameters**:
// *{string}* **curie** The CURIE to be transformed.
// **Throws**:
// *{Error}* If no URI could be assembled.
// **Returns**:
// *{string}* : A string, representing the URI.
// **Example usage**:
//
// var ns = new myVIE.Namespaces(
// "http://viejs.org/ns/",
// { "dbp": "http://dbpedia.org/ontology/" }
// );
// var curie = "dbp:Person";
// var scurie = "[dbp:Person]";
// ns.uri(curie);
// --> <http://dbpedia.org/ontology/Person>
// ns.uri(scurie);
// --> <http://dbpedia.org/ontology/Person>
VIE.prototype.Namespaces.prototype.uri = function (curie) {
return VIE.Util.toUri(curie, this);
};
// ### isUri(something)
// This method checks, whether the given string is a URI.
// **Parameters**:
// *{string}* **something** : The string to be checked.
// **Throws**:
// *nothing*
// **Returns**:
// *{boolean}* : ```true``` if the string is a URI, ```false``` otherwise.
// **Example usage**:
//
// var namespaces = new vie.Namespaces("http://base.ns/");
// namespaces.addOrReplace("test", "http://test.ns");
// var uri = "<http://test.ns/Person>";
// var curie = "test:Person";
// namespaces.isUri(uri); // --> true
// namespaces.isUri(curie); // --> false
VIE.prototype.Namespaces.prototype.isUri = VIE.Util.isUri;
/*global VIE:false Backbone:false _:false */
if (!VIE.prototype.view) {
VIE.prototype.view = {};
}
VIE.prototype.view.Entity = Backbone.View.extend({
initialize: function(options) {
this.service = options.service ? options.service : 'rdfa';
this.vie = options.vie;
// Ensure view gets updated when properties of the Entity change.
_.bindAll(this, 'render', 'renderAbout');
this.model.on('change', this.render);
this.model.on('change:@subject', this.renderAbout);
},
// Rendering a view means writing the properties of the Entity back to
// the element containing our RDFa annotations.
render: function() {
this.vie.save({
element: this.el,
entity: this.model
}).
to(this.service).
execute();
return this;
},
renderAbout: function () {
this.vie.service(this.service).setElementSubject(this.model.getSubjectUri(), this.el);
}
});
})();