README.md | 8 +-
css/edit.css | 143 +-
edit.module | 174 +-
generate-core-patch.sh | 9 +-
grunt.js | 41 +-
images/attention.png | Bin 1687 -> 409 bytes
images/close.png | Bin 3276 -> 333 bytes
images/icon-edit-active.png | Bin 0 -> 358 bytes
images/icon-edit.png | Bin 0 -> 498 bytes
images/throbber.gif | Bin 13395 -> 1032 bytes
includes/form.inc | 68 +-
includes/missing-api.inc | 43 -
js/app.js | 20 +-
js/backbone.drupalform.js | 9 +-
js/createjs/editable.js | 4 +-
js/createjs/editingWidgets/drupalalohawidget.js | 20 +-
.../editingWidgets/drupalcontenteditablewidget.js | 7 +-
js/createjs/editingWidgets/formwidget.js | 10 +-
js/edit.js | 4 +-
js/lib/create.js | 1643 ------
js/lib/vie.js | 3682 -------------
js/theme.js | 4 +-
js/viejs/EditService.js | 201 +
js/viejs/SparkEditService.js | 208 -
js/views/fielddecorator-view.js | 324 --
js/views/overlay-view.js | 2 -
js/views/propertyeditordecoration-view.js | 322 ++
js/views/toolbar-view.js | 13 +-
vie-and-create.patch | 5401 ++++++++++++++++++++
29 files changed, 6141 insertions(+), 6219 deletions(-)
diff --git a/README.md b/README.md
index 391048c..628e59f 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,16 @@
# Requirements
+- Please apply the included core patch "vie-and-create.patch".
- Please also apply the included core patch "text.patch". Without it, you wont' be able to use direct editing, with or without WYSIWYG.
- Optionally, if you also want WYSIWYG editing, install the latest version of Aloha Editor for Drupal 8: http://drupal.org/project/aloha
# D8 port notes
-* D8 has no Entity Access API yet, so I implemented a node-only stub in includes/missing-api.inc.
+* D8 has no Entity Access API yet, so I implemented a node-only stub.
* Node title/author/date are not yet proper Entity Properties, and thus they are not yet editable.
-# TODO
-
-Search the code base for "@todo"
-
-
# Want to see it?
Go to a node page (e.g. node/1), at the top of the page you should see the "editbar", with a "View/Quick edit" toggle. Click that and now you should be able to see outlines around every field, if you click any of those, you should get an in-place form for that field.
diff --git a/css/edit.css b/css/edit.css
index 9109d62..3480a2b 100644
--- a/css/edit.css
+++ b/css/edit.css
@@ -2,13 +2,13 @@
* Animations.
*/
.edit-animate-invisible {
- opacity: 0 !important;
+ opacity: 0;
}
.edit-animate-fast {
-webkit-transition: all .2s ease;
-moz-transition: all .2s ease;
- -ie-transition: all .2s ease;
+ -ms-transition: all .2s ease;
-o-transition: all .2s ease;
transition: all .2s ease;
}
@@ -16,7 +16,7 @@
.edit-animate-default {
-webkit-transition: all .4s ease;
-moz-transition: all .4s ease;
- -ie-transition: all .4s ease;
+ -ms-transition: all .4s ease;
-o-transition: all .4s ease;
transition: all .4s ease;
}
@@ -24,105 +24,58 @@
.edit-animate-slow {
-webkit-transition: all .6s ease;
-moz-transition: all .6s ease;
- -ie-transition: all .6s ease;
+ -ms-transition: all .6s ease;
-o-transition: all .6s ease;
transition: all .6s ease;
}
.edit-animate-delay-veryfast {
-webkit-transition-delay: .05s;
+ -moz-transition-delay: .05s;
+ -ms-transition-delay: .05s;
+ -o-transition-delay: .05s;
+ transition-delay: .05s;
}
.edit-animate-delay-fast {
-webkit-transition-delay: .2s;
-}
-
-.edit-animate-delay-default {
- -webkit-transition-delay: .4s;
-}
-
-.edit-animate-delay-slow {
- -webkit-transition-delay: .6s;
+ -moz-transition-delay: .2s;
+ -ms-transition-delay: .2s;
+ -o-transition-delay: .2s;
+ transition-delay: .2s;
}
.edit-animate-disable-width {
-webkit-transition: width 0s;
+ -moz-transition: width 0s;
+ -ms-transition: width 0s;
+ -o-transition: width 0s;
+ transition: width 0s;
}
.edit-animate-only-visibility {
-webkit-transition: opacity .2s ease;
-moz-transition: opacity .2s ease;
- -ie-transition: opacity .2s ease;
+ -ms-transition: opacity .2s ease;
-o-transition: opacity .2s ease;
transition: opacity .2s ease;
- -webkit-transition-delay: 0s;
}
/**
- * Edit's bar — inspired by core's toolbar.module & shortcut.module.
+ * Toolbar.
*/
-#editbar,
-#editbar * {
- border: 0;
- font-size: 100%;
- line-height: inherit;
- list-style: none;
- margin: 0;
- outline: 0;
- padding: 0;
- text-align: left; /* LTR */
- vertical-align: baseline;
+.icon-edit:before {
+ background-image: url("../images/icon-edit.png");
}
-#editbar {
- position: relative;
- background: #666;
- color: #ccc;
- font: normal small "Lucida Grande", Verdana, sans-serif;
- margin: 0 -20px;
- padding: 0 20px;
- -moz-box-shadow: 0 3px 20px #000;
- -webkit-box-shadow: 0 3px 20px #000;
- box-shadow: 0 3px 20px #000;
- z-index: 500;
-}
-#editbar ul {
- padding: 5px 0 2px 0;
- height: 28px;
- line-height: 24px;
- margin-left:5px; /* LTR */
-}
-#editbar ul li,
-#editbar ul li a {
- float: left; /* LTR */
- padding: 0 5px 0 5px;
- margin-right: 5px; /* LTR */
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- border-radius: 5px;
+.icon-edit:active:before,
+.active .icon-edit:before {
+ background-image: url("../images/icon-edit-active.png");
}
-#editbar a {
- padding: 5px 10px 5px 5px;
- line-height: 24px;
- color: #fefefe;
- font-size: .846em;
- text-decoration: none;
-}
-#editbar a:focus,
-#editbar a:hover,
-#editbar a.active {
- color: #fff;
-}
-#editbar ul li a:focus,
-#editbar ul li a:hover,
-#editbar ul li a.active:focus {
- background: #555;
-}
-#editbar ul li a.active:hover,
-#editbar ul li a.active {
- background: #000;
+.toolbar .tray.edit.active {
+ z-index: 340;
}
@@ -140,9 +93,10 @@
z-index: 250;
width: 100%;
height: 100%;
+ background-color: #fff;
background-color: rgba(255,255,255,.5);
- top: 0px; /* offset for navbar, modified later */
- left: 0px;
+ top: 0;
+ left: 0;
}
/* Editable. */
@@ -155,22 +109,22 @@
}
.edit-field.edit-editable,
.edit-field.edit-type-direct .edit-editable {
- box-shadow: 0px 0px 1px 1px #4D9DE9;
+ box-shadow: 0 0 1px 1px #4D9DE9;
}
/* Highlighted (hovered) editable. */
.edit-editable.edit-highlighted {
- min-width: 200px; /* TODO: we even need them to be at least fairly wide! */
+ min-width: 200px;
}
.edit-field.edit-editable.edit-highlighted,
.edit-form.edit-editable.edit-highlighted,
.edit-field.edit-type-direct .edit-editable.edit-highlighted {
- box-shadow: 0px 0px 1px 1px #0199FF, 0px 0px 3px 3px rgba(153, 153, 153, .5);
+ box-shadow: 0 0 1px 1px #0199FF, 0 0 3px 3px rgba(153, 153, 153, .5);
}
.edit-field.edit-editable.edit-highlighted.edit-validation-error,
.edit-form.edit-editable.edit-highlighted.edit-validation-error,
.edit-field.edit-type-direct .edit-editable.edit-highlighted.edit-validation-error {
- box-shadow: 0px 0px 1px 1px red, 0px 0px 3px 3px rgba(153, 153, 153, .5);
+ box-shadow: 0 0 1px 1px red, 0 0 3px 3px rgba(153, 153, 153, .5);
}
.edit-form.edit-editable .form-item .error {
border: 1px solid #eea0a0;
@@ -181,7 +135,9 @@
.edit-form.edit-editable.edit-editing,
.edit-field.edit-type-direct .edit-editable.edit-editing {
/* In the latest design, there's no special styling when editing as opposed to
- just hovering. */
+ * just hovering.
+ * This will be necessary again for http://drupal.org/node/1844220.
+ */
}
@@ -242,7 +198,7 @@
left: -5px;
margin: 0;
border: none;
- box-shadow: 0px 0px 1px 1px red, 0px 0px 3px 3px rgba(153, 153, 153, .5);
+ box-shadow: 0 0 1px 1px red, 0 0 3px 3px rgba(153, 153, 153, .5);
background-color: white;
}
@@ -305,7 +261,7 @@
height: auto;
position: absolute;
bottom: 1px;
- box-shadow: 0px 0px 1px 1px #0199FF, 0px 0px 3px 3px rgba(153, 153, 153, .5);
+ box-shadow: 0 0 1px 1px #0199FF, 0 0 3px 3px rgba(153, 153, 153, .5);
background: #FFF;
}
@@ -355,7 +311,7 @@
.edit-toolgroup.wysiwyg {
clear: left;
width: 100%;
- padding-left: none;
+ padding-left: 0;
}
@@ -402,14 +358,9 @@
float: left;
}
.edit-toolbar a span.close {
- background: url('../images/close.png') no-repeat 2px 2px;
+ background: url('../images/close.png') no-repeat 3px 2px;
}
-.edit-toolbar a span.close:hover {
- /* TODO: use a different "close" image */
-}
-
-
.edit-toolbar a.blank-button {
color: black;
}
@@ -418,6 +369,7 @@
.edit-toolbar a.blue-button {
color: white;
background-image: -webkit-linear-gradient(top, #6fc2f2 0%, #4e97c0 100%);
+ background-image: -moz-linear-gradient(top, #6fc2f2 0%, #4e97c0 100%);
background-image: linear-gradient(top, #6fc2f2 0%, #4e97c0 100%);
border-radius: 5px;
}
@@ -426,26 +378,17 @@
.edit-toolbar a.gray-button {
color: #666;
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #ccc 100%);
+ background-image: -moz-linear-gradient(top, #f5f5f5 0%, #ccc 100%);
background-image: linear-gradient(top, #f5f5f5 0%, #ccc 100%);
border-radius: 5px;
}
-#edit_modal a img.gray-button.close img, .gray-button.save img, .blue-button.save img,
-.edit-toolbar a img.gray-button.close img, .gray-button.save img, .blue-button.save img {
- padding: 0;
-}
-
-.gray-button img, .blue-button img,
-.gray-button img, .blue-button img {
- padding-right: 5px;
-}
-
#edit_modal a.blue-button:hover,
.edit-toolbar a.blue-button:hover,
#edit_modal a.blue-button:active,
.edit-toolbar a.blue-button:active {
border: 1px solid #55a5d3;
- box-shadow: 0px 2px 1px rgba(0,0,0,0.2);
+ box-shadow: 0 2px 1px rgba(0,0,0,0.2);
}
#edit_modal a.gray-button:hover,
@@ -453,5 +396,5 @@
#edit_modal a.gray-button:active,
.edit-toolbar a.gray-button:active {
border: 1px solid #cdcdcd;
- box-shadow: 0px 2px 1px rgba(0,0,0,0.1);
+ box-shadow: 0 2px 1px rgba(0,0,0,0.1);
}
diff --git a/edit.module b/edit.module
index 0e11895..5df4a07 100644
--- a/edit.module
+++ b/edit.module
@@ -14,8 +14,19 @@
use Drupal\Core\Template\Attribute;
use Drupal\field\FieldInstance;
-// @todo Get rid of missing-api.inc by improving Entity API.
-module_load_include('inc', 'edit', 'includes/missing-api');
+// @todo: POSTPONED_ON(Drupal core, http://drupal.org/node/1839516)
+// Remove this when Entity Access API is ready.
+// Edit needs the Entity Access API. Sadly, http://drupal.org/node/1696660 is
+// just the framework, it still needs to be used; currently it will simply
+// always return FALSE (i.e. "no access").
+function edit_entity_access($op, $entity_type, $entity = NULL, $account = NULL) {
+ if ($entity_type == 'node') {
+ return node_access($op, $entity, $account);
+ }
+
+ // Currently, only editing of nodes is supported. See the above issue.
+ return FALSE;
+}
/**
* Implements hook_menu()
@@ -49,46 +60,68 @@ function edit_menu() {
}
/**
- * Implements hook_page_alter().
+ * Implements hook_toolbar().
*/
-function edit_page_alter(&$page) {
+function edit_toolbar() {
if (path_is_admin(current_path())) {
return;
}
- $page['page_top']['edit'] = array(
- 'view_edit_toggle' => array(
- '#prefix' => '
' . t('In-place edit operations') . '
',
- '#suffix' => '
',
- 'content' => array(
- array(
- '#theme' => 'menu_local_task',
- '#link' => array('title' => t('View'), 'href' => current_path(), 'localized_options' => array('fragment' => 'view', 'attributes' => array('class' => array('edit_view-edit-toggle', 'edit-view')))),
- '#active' => TRUE,
+ $tab['edit'] = array(
+ 'tab' => array(
+ 'title' => t('Edit'),
+ 'href' => '',
+ 'html' => FALSE,
+ 'attributes' => array(
+ 'class' => array('icon', 'icon-edit'),
+ ),
+ // @todo: BLOCKED_ON(Drupal core, http://drupal.org/node/1847198)
+ // This #post_render callback does not yet get called, which means that
+ // even if zero fields on the current page are editable for the current
+ // user, the "Edit" tab will still show up.
+ '#post_render' => array(
+ 'edit_toolbar_post_render',
+ ),
+ ),
+ 'tray' => array(
+ 'view_edit_toggle' => array(
+ '#prefix' => '
' . t('In-place edit operations') . '
',
+ '#suffix' => '
',
+ 'content' => array(
+ array(
+ '#theme' => 'menu_local_task',
+ '#link' => array('title' => t('View'), 'href' => current_path(), 'localized_options' => array('fragment' => 'view', 'attributes' => array('class' => array('edit_view-edit-toggle', 'edit-view')))),
+ '#active' => TRUE,
+ ),
+ array(
+ '#theme' => 'menu_local_task',
+ '#link' => array('title' => t('Quick edit'), 'href' => current_path(), 'localized_options' => array('fragment' => 'quick-edit', 'attributes' => array('class' => array('edit_view-edit-toggle', 'edit-edit')))),
+ ),
),
- array(
- '#theme' => 'menu_local_task',
- '#link' => array('title' => t('Quick edit'), 'href' => current_path(), 'localized_options' => array('fragment' => 'quick-edit', 'attributes' => array('class' => array('edit_view-edit-toggle', 'edit-edit')))),
+ '#attached' => array(
+ 'library' => array(
+ array('edit', 'edit'),
+ ),
),
),
- '#attached' => array(
- 'library' => array(
- array('edit', 'edit'),
- ),
+ '#post_render' => array(
+ 'edit_toolbar_post_render',
),
),
- '#post_render' => array(
- 'edit_editbar_post_render',
- ),
);
+
+ return $tab;
}
/**
- * Post-render function to remove the editbar if nothing editable is present.
+ * Post-render function to only show the Edit tab in the toolbar if relevant.
+ *
+ * When the user cannot edit any of the fields on the page, he should not be
+ * given the possibility to toggle edit mode.
*/
-function edit_editbar_post_render($html) {
- global $editbar;
- return ($editbar !== TRUE) ? '' : $html;
+function edit_toolbar_post_render($html) {
+ global $edit_toolbar;
+ return ($edit_toolbar !== TRUE) ? '' : $html;
}
/**
@@ -101,15 +134,32 @@ function edit_library_info() {
'website' => 'http://drupal.org/project/edit',
'version' => VERSION,
'js' => array(
- $path . '/js/edit.js' => array(
- 'defer' => TRUE,
- ),
- $path . '/js/util.js' => array(
- 'defer' => TRUE,
- ),
- $path . '/js/theme.js' => array(
- 'defer' => TRUE,
- ),
+ // Core.
+ $path . '/js/edit.js' => array('defer' => TRUE),
+ $path . '/js/app.js' => array('defer' => TRUE),
+ // Routers.
+ $path . '/js/routers/edit-router.js' => array('defer' => TRUE),
+ // Models.
+ $path . '/js/models/edit-app-model.js' => array('defer' => TRUE),
+ // Views.
+ $path . '/js/views/propertyeditordecoration-view.js' => array('defer' => TRUE),
+ $path . '/js/views/menu-view.js' => array('defer' => TRUE),
+ $path . '/js/views/modal-view.js' => array('defer' => TRUE),
+ $path . '/js/views/overlay-view.js' => array('defer' => TRUE),
+ $path . '/js/views/toolbar-view.js' => array('defer' => TRUE),
+ // Backbone.sync implementation on top of Drupal forms.
+ $path . '/js/backbone.drupalform.js' => array('defer' => TRUE),
+ // VIE service.
+ $path . '/js/viejs/EditService.js' => array('defer' => TRUE),
+ // Create.js subclasses.
+ $path . '/js/createjs/editable.js' => array('defer' => TRUE),
+ $path . '/js/createjs/storage.js' => array('defer' => TRUE),
+ $path . '/js/createjs/editingWidgets/formwidget.js' => array('defer' => TRUE),
+ $path . '/js/createjs/editingWidgets/drupalcontenteditablewidget.js' => array('defer' => TRUE),
+ $path . '/js/createjs/editingWidgets/drupalalohawidget.js' => array('defer' => TRUE),
+ // Other.
+ $path . '/js/util.js' => array('defer' => TRUE),
+ $path . '/js/theme.js' => array('defer' => TRUE),
// Basic settings.
array(
'data' => array('edit' => array(
@@ -124,52 +174,14 @@ function edit_library_info() {
$path . '/css/edit.css',
),
'dependencies' => array(
+ array('system', 'jquery'),
+ array('system', 'underscore'),
+ array('system', 'backbone'),
+ array('system', 'vie.core'),
+ array('system', 'create.editonly'),
array('system', 'jquery.form'),
array('system', 'drupal.form'),
array('system', 'drupal.ajax'),
- array('system', 'backbone'),
- array('edit', 'edit.createjs'),
- ),
- );
-
- $libraries['edit.createjs'] = array(
- 'title' => 'CreateJS and deps',
- 'website' => 'http://createjs.org',
- 'version' => NULL,
- 'js' => array(
- $path . '/js/lib/create.js' => array('defer' => TRUE),
- $path . '/js/viejs/SparkEditService.js' => array('defer' => TRUE),
- $path . '/js/createjs/editable.js' => array('defer' => TRUE),
- $path . '/js/createjs/storage.js' => array('defer' => TRUE),
- $path . '/js/createjs/editingWidgets/formwidget.js' => array('defer' => TRUE),
- $path . '/js/createjs/editingWidgets/drupalcontenteditablewidget.js' => array('defer' => TRUE),
- $path . '/js/createjs/editingWidgets/drupalalohawidget.js' => array('defer' => TRUE),
- $path . '/js/views/menu-view.js' => array('defer' => TRUE),
- $path . '/js/views/overlay-view.js' => array('defer' => TRUE),
- $path . '/js/views/toolbar-view.js' => array('defer' => TRUE),
- $path . '/js/views/fielddecorator-view.js' => array('defer' => TRUE),
- $path . '/js/views/modal-view.js' => array('defer' => TRUE),
- $path . '/js/routers/edit-router.js' => array('defer' => TRUE),
- $path . '/js/models/edit-app-model.js' => array('defer' => TRUE),
- $path . '/js/backbone.drupalform.js' => array('defer' => TRUE),
- $path . '/js/app.js' => array('defer' => TRUE),
- ),
- 'dependencies' => array(
- array('system', 'jquery.ui.widget'),
- array('system', 'backbone'),
- array('edit', 'edit.vie'),
- ),
- );
-
- $libraries['edit.vie'] = array(
- 'title' => 'Vienna IKS Editables',
- 'website' => 'http://wiki.iks-project.eu/index.php/VIE',
- 'version' => '2.0',
- 'js' => array(
- $path . '/js/lib/vie.js' => array('defer' => TRUE),
- ),
- 'dependencies' => array(
- array('system', 'backbone'),
),
);
@@ -215,8 +227,8 @@ function edit_preprocess_field(&$variables) {
$field_access = field_access('edit', $field_name, $entity->entityType(), $entity);
$editability = _edit_analyze_field_editability($items, $instance, $formatter_type);
if ($entity_access && $field_access && $editability != 'disabled') {
- global $editbar;
- $editbar = TRUE;
+ global $edit_toolbar;
+ $edit_toolbar = TRUE;
// Mark this field as editable and provide metadata through data- attributes.
$variables['attributes']['data-edit-field-label'] = $instance->definition['label'];
diff --git a/generate-core-patch.sh b/generate-core-patch.sh
index 67a64ea..8dd4d13 100644
--- a/generate-core-patch.sh
+++ b/generate-core-patch.sh
@@ -19,12 +19,19 @@ mkdir $DRUPAL_DIR/core/modules/edit
# Generate the patch for the Edit module.
cp -R edit.info edit.module css images includes js $DRUPAL_DIR/core/modules/edit/
-rm $DRUPAL_DIR/core/modules/edit/includes/text.inc
+rm -rf $DRUPAL_DIR/core/modules/edit/js/build
cp text.patch $DRUPAL_DIR/
+cp vie-and-create.patch $DRUPAL_DIR/
cd $DRUPAL_DIR
git apply text.patch
+rm text.patch
+git apply vie-and-create.patch
+rm vie-and-create.patch
git add core/modules/edit
git add core/modules/field/modules/text/lib/Drupal/text/Plugin/field/formatter
+git add core/modules/system
+git add core/misc/create
+git add core/misc/vie
git diff --staged --binary --patch-with-stat > $EDIT_DIR/$FILENAME-$COMMENTNR.patch
git commit -m "edit module"
cd $EDIT_DIR
diff --git a/grunt.js b/grunt.js
index 1c94414..f160df9 100644
--- a/grunt.js
+++ b/grunt.js
@@ -1,5 +1,4 @@
module.exports = function(grunt) {
- // Project configuration.
grunt.initConfig({
lint: {
all: [
@@ -13,7 +12,6 @@ module.exports = function(grunt) {
},
concat: {
dist: {
- // @todo: do we want to concat VIE and createjs, too?
src: [
'js/createjs/*.js',
'js/viejs/*.js',
@@ -22,20 +20,7 @@ module.exports = function(grunt) {
'js/routers/*.js',
'js/*.js'
],
- // @todo: shouldn't we keep source and build/ more separate?
dest: 'js/build/edit.js'
- },
- 'dist-all': {
- src: [
- 'js/lib/*',
- 'js/createjs/*.js',
- 'js/viejs/*.js',
- 'js/models/*.js',
- 'js/views/*.js',
- 'js/routers/*.js',
- 'js/*.js'
- ],
- dest: 'js/build/edit-all.js'
}
},
watch: {
@@ -46,11 +31,7 @@ module.exports = function(grunt) {
dist: {
src: ['js/build/edit.js'],
dest: 'js/build/edit.min.js'
- },
- 'dist-all':{
- src: ['js/build/edit-all.js'],
- dest: 'js/build/edit-all.min.js'
- },
+ }
},
jshint: {
options: {
@@ -67,13 +48,21 @@ module.exports = function(grunt) {
VIE: true,
_: true
}
+ },
+ csslint: {
+ all: {
+ src: 'css/edit.css',
+ rules: {
+ 'adjoining-classes': false,
+ 'ids': false,
+ 'outline-none': false,
+ 'box-model': false,
+ 'overqualified-elements': false
+ }
+ }
}
});
- // Load local tasks; we should add local tasks later.
- // grunt.loadTasks("tasks");
-
- // Set default
- grunt.registerTask('default', 'lint concat min');
-
+ grunt.loadNpmTasks('grunt-css');
+ grunt.registerTask('default', 'lint concat min csslint');
};
diff --git a/images/attention.png b/images/attention.png
index 3c833c9..6a35d1d 100644
Binary files a/images/attention.png and b/images/attention.png differ
diff --git a/images/close.png b/images/close.png
index 2f5d665..e3f98b8 100644
Binary files a/images/close.png and b/images/close.png differ
diff --git a/images/icon-edit-active.png b/images/icon-edit-active.png
new file mode 100644
index 0000000..ad84761
Binary files /dev/null and b/images/icon-edit-active.png differ
diff --git a/images/icon-edit.png b/images/icon-edit.png
new file mode 100644
index 0000000..4f0dcc2
Binary files /dev/null and b/images/icon-edit.png differ
diff --git a/images/throbber.gif b/images/throbber.gif
index 58f4a42..f2603e8 100644
Binary files a/images/throbber.gif and b/images/throbber.gif differ
diff --git a/includes/form.inc b/includes/form.inc
index 6936a2f..cdf9935 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -2,15 +2,16 @@
/**
* @file
- * Form callbacks for the Edit module.
+ * Form handlers for the Edit module.
*/
/**
- * Field editing form. (For editing a field instance.)
+ * Form constructor for the field editing form.
*
- * Proudly found elsewhere: FAPE module's fape_field_edit_form() and friends.
+ * @see edit_field_form_validate()
+ * @ingroup forms
*/
-function edit_field_form($form, &$form_state) {
+function edit_field_form(array $form, array &$form_state) {
$entity = $form_state['entity'];
$langcode = $form_state['langcode'];
@@ -19,40 +20,6 @@ function edit_field_form($form, &$form_state) {
field_attach_form($entity->entityType(), $entity, $form, $form_state, $langcode, $options);
$form['#validate'][] = 'edit_field_form_validate';
- // @todo Verify that this is indeed not necessary anymore, see edit_field_form_validate().
- // $form['#submit'][] = '';
-
- // Add revisions form items if necessary.
- // @todo We may be able to get rid of this when http://drupal.org/node/1678002 is solved.
- list($use_revisions, $control_revisions) = edit_entity_allows_revisions($entity->entityType(), $entity->bundle(), $entity);
- if ($use_revisions) {
- $form_state['use revisions'] = TRUE;
- $form['revision_information'] = array(
- '#weight' => 11,
- );
-
- $form['revision_information']['revision'] = array(
- '#type' => 'checkbox',
- '#title' => t('Create new revision'),
- '#default_value' => $entity->revision,
- '#id' => 'edit-revision',
- '#access' => $control_revisions,
- );
-
- if ($control_revisions || $entity->revision) {
- $form['revision_information']['log'] = array(
- '#type' => 'textarea',
- '#title' => t('Log message'),
- '#description' => t('Provide an explanation of the changes you are making. This will help other authors understand your motivations.'),
- '#default_value' => $entity->log,
- );
-
- if ($control_revisions) {
- $form['revision_information']['log']['#dependency'] = array('edit-revision' => array(1));
- }
- }
- $form['#submit'][] = 'edit_field_form_revision_submit';
- }
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array(
@@ -67,9 +34,12 @@ function edit_field_form($form, &$form_state) {
}
/**
- * Helper function to simplify the field edit form for in-place editing.
+ * Simplifies the field edit form for in-place editing.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
*/
-function _simplify_edit_field_edit_form(&$form) {
+function _simplify_edit_field_edit_form(array &$form) {
$elements = element_children($form);
// Required internal form properties.
@@ -116,9 +86,12 @@ function _simplify_edit_field_edit_form(&$form) {
/**
* Validate field editing form.
*
- * @todo: clean up once http://drupal.org/node/1846648 is solved.
+ * @see edit_field_form()
+ *
+ * @todo: BLOCKED_ON(Drupal core, http://drupal.org/node/1846648)
+ * Clean up once that issue is solved.
*/
-function edit_field_form_validate($form, &$form_state) {
+function edit_field_form_validate(array $form, array &$form_state) {
$entity = $form_state['entity'];
$options = array('field_name' => $form_state['field_name']);
@@ -130,14 +103,3 @@ function edit_field_form_validate($form, &$form_state) {
// Validation.
field_attach_form_validate($entity->entityType(), $entity, $form, $form_state, $options);
}
-
-/**
- * Submit callback that handles entity revisioning.
- */
-function edit_field_form_revision_submit($form, &$form_state) {
- $entity = $form_state['entity'];
- if (!empty($form_state['use revisions'])) {
- $entity->revision = $form_state['values']['revision'];
- $entity->log = $form_state['values']['log'];
- }
-}
diff --git a/includes/missing-api.inc b/includes/missing-api.inc
deleted file mode 100644
index 1b2f08a..0000000
--- a/includes/missing-api.inc
+++ /dev/null
@@ -1,43 +0,0 @@
-revision = $retval[0];
- $entity->log = '';
- return $retval;
-}
-
-/**
- * @} End of "ingroup Missing in Entity API.".
- */
diff --git a/js/app.js b/js/app.js
index b18675c..82d390f 100644
--- a/js/app.js
+++ b/js/app.js
@@ -28,7 +28,7 @@
// VIE instance for Edit.
this.vie = new VIE();
// Use our custom DOM parsing service until RDFa is available.
- this.vie.use(new this.vie.SparkEditService());
+ this.vie.use(new this.vie.EditService());
this.domService = this.vie.service('edit');
// Instantiate configuration for state handling.
@@ -83,9 +83,10 @@
* Should be called whenever EditAppModel's "isViewing" changes.
*/
appStateChange: function() {
- // @todo: we're currently setting the state on EditableEntity widgets
- // instead of PropertyEditor widgets, because of
- // https://github.com/bergie/create/issues/140
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133, https://github.com/bergie/create/issues/140)
+ // We're currently setting the state on EditableEntity widgets instead of
+ // PropertyEditor widgets, because of
+ // https://github.com/bergie/create/issues/133.
var newState = (this.model.get('isViewing')) ? 'inactive' : 'candidate';
this.$entityElements.each(function() {
$(this).createEditable('setState', newState);
@@ -248,7 +249,8 @@
* The PropertyEditor widget object.
*/
editorStateChange: function(from, to, editor) {
- // @todo get rid of this once https://github.com/bergie/create/issues/133 is solved.
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
+ // Get rid of this once that issue is solved.
if (!editor) {
return;
}
@@ -273,7 +275,8 @@
}
// Propagate the state change to the decoration and toolbar views.
- // @todo enable this once https://github.com/bergie/create/issues/133 is solved.
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
+ // Uncomment this once that issue is solved.
// editor.decorationView.stateChange(from, to);
// editor.toolbarView.stateChange(from, to);
},
@@ -297,13 +300,14 @@
});
// Decorate the editor's DOM element depending on its state.
- editor.decorationView = new Drupal.edit.views.FieldDecorationView({
+ editor.decorationView = new Drupal.edit.views.PropertyEditorDecorationView({
el: editor.element,
editor: editor,
toolbarId: editor.toolbarView.getId()
});
- // @todo get rid of this once https://github.com/bergie/create/issues/133 is solved.
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
+ // Get rid of this once that issue is solved.
editor.options.widget.element.bind('createeditablestatechange', function(event, data) {
editor.decorationView.stateChange(data.previous, data.current);
editor.toolbarView.stateChange(data.previous, data.current);
diff --git a/js/backbone.drupalform.js b/js/backbone.drupalform.js
index 3285af7..aee82c1 100644
--- a/js/backbone.drupalform.js
+++ b/js/backbone.drupalform.js
@@ -27,8 +27,6 @@ Backbone.sync = function(method, model, options) {
* form when there are validation errors and ensure no Drupal.ajax memory leaks.
*
* @see Drupal.edit.util.form
- *
- * @todo: HTTP status handling.
*/
Backbone.syncDrupalFormWidget = function(method, model, options) {
if (method === 'update') {
@@ -44,7 +42,10 @@ Backbone.syncDrupalFormWidget = function(method, model, options) {
// Call Backbone.sync's success callback with the rerendered field.
var changedAttributes = {};
- changedAttributes[predicate] = '@todo: JSON-LD representation N/A yet.';
+ // @todo: POSTPONED_ON(Drupal core, http://drupal.org/node/1784216)
+ // Once full JSON-LD support in Drupal core lands, we can ensure that the
+ // models that VIE maintains are properly updated.
+ changedAttributes[predicate] = 'JSON-LD representation N/A yet.';
changedAttributes[predicate + '/rendered'] = response.data;
options.success(changedAttributes);
};
@@ -84,8 +85,6 @@ Backbone.syncDrupalFormWidget = function(method, model, options) {
*
* @see Backbone.syncDrupalFormWidget()
* @see Drupal.edit.util.form
- *
- * @todo: HTTP status handling.
*/
Backbone.syncDirect = function(method, model, options) {
if (method === 'update') {
diff --git a/js/createjs/editable.js b/js/createjs/editable.js
index cc34498..beabc2c 100644
--- a/js/createjs/editable.js
+++ b/js/createjs/editable.js
@@ -30,8 +30,8 @@
},
_propertyEditorName: function (data) {
- if (Drupal.settings.edit.wysiwyg && jQuery(this.element).hasClass('edit-type-direct')) {
- if (jQuery(this.element).hasClass('edit-type-direct-with-wysiwyg')) {
+ if (jQuery(this.element).hasClass('edit-type-direct')) {
+ if (Drupal.settings.edit.wysiwyg && jQuery(this.element).hasClass('edit-type-direct-with-wysiwyg')) {
return 'direct-with-wysiwyg';
}
return 'direct';
diff --git a/js/createjs/editingWidgets/drupalalohawidget.js b/js/createjs/editingWidgets/drupalalohawidget.js
index c972911..6ef3a93 100644
--- a/js/createjs/editingWidgets/drupalalohawidget.js
+++ b/js/createjs/editingWidgets/drupalalohawidget.js
@@ -10,15 +10,16 @@
jQuery.widget('Drupal.drupalAlohaWidget', jQuery.Create.alohaWidget, {
- // @todo: actually use this when restoring original content, but for that we
+ // @todo BLOCKED_ON(Create.js/VIE.js, how to restore original content when canceling editing)
+ // Actually use this when restoring original content, but for that we
// first need to know how to restore content in a Create.js context
originalTransformedContent: null,
/**
* Implements jQuery UI widget factory's _init() method.
*
- * @todo: get rid of this once https://github.com/bergie/create/issues/142
- * is solved.
+ * @todo: POSTPONED_ON(Create.js, https://github.com/bergie/create/issues/142)
+ * Get rid of this once that issue is solved.
*/
_init: function() {},
@@ -37,8 +38,9 @@
/**
* Binds to events.
*
- * @todo: get rid of this helper function and move it into _initialize()
- * once https://github.com/alohaeditor/Aloha-Editor/issues/693 is solved.
+ * @todo: POSTPONED_ON(Aloha Editor, https://github.com/alohaeditor/Aloha-Editor/issues/693)
+ * Get rid of this helper function and move it into _initialize() once that
+ * issue is solved. Also see http://drupal.org/node/1725032.
*/
_bindEvents: function() {
var that = this;
@@ -62,9 +64,6 @@
/**
* Makes this PropertyEditor widget react to state changes.
- *
- * @todo revisit this once https://github.com/bergie/create/issues/133 is
- * solved.
*/
stateChange: function(from, to) {
switch (to) {
@@ -75,11 +74,6 @@
Drupal.aloha.detach(this.element);
this._removeValidationErrors();
this._cleanUp();
-
- // TRICKY: work-around for major AE bug. See:
- // - http://drupal.org/node/1725032
- // - https://github.com/alohaeditor/Aloha-Editor/issues/693.
- // @todo: get rid of this once https://github.com/alohaeditor/Aloha-Editor/issues/693 is solved.
this._bindEvents();
}
break;
diff --git a/js/createjs/editingWidgets/drupalcontenteditablewidget.js b/js/createjs/editingWidgets/drupalcontenteditablewidget.js
index a9c9c46..65f5116 100644
--- a/js/createjs/editingWidgets/drupalcontenteditablewidget.js
+++ b/js/createjs/editingWidgets/drupalcontenteditablewidget.js
@@ -11,8 +11,8 @@
/**
* Implements jQuery UI widget factory's _init() method.
*
- * @todo: get rid of this once https://github.com/bergie/create/issues/142
- * is solved.
+ * @todo: POSTPONED_ON(Create.js, https://github.com/bergie/create/issues/142)
+ * Get rid of this once that issue is solved.
*/
_init: function() {},
@@ -45,9 +45,6 @@
/**
* Makes this PropertyEditor widget react to state changes.
- *
- * @todo revisit this once https://github.com/bergie/create/issues/133 is
- * solved.
*/
stateChange: function(from, to) {
switch (to) {
diff --git a/js/createjs/editingWidgets/formwidget.js b/js/createjs/editingWidgets/formwidget.js
index 94ad3f5..889ee87 100644
--- a/js/createjs/editingWidgets/formwidget.js
+++ b/js/createjs/editingWidgets/formwidget.js
@@ -14,8 +14,8 @@
/**
* Implements jQuery UI widget factory's _init() method.
*
- * @todo: get rid of this once https://github.com/bergie/create/issues/142
- * is solved.
+ * @todo: POSTPONED_ON(Create.js, https://github.com/bergie/create/issues/142)
+ * Get rid of this once that issue is solved.
*/
_init: function() {},
@@ -34,9 +34,6 @@
/**
* Makes this PropertyEditor widget react to state changes.
- *
- * @todo revisit this once https://github.com/bergie/create/issues/133 is
- * solved.
*/
stateChange: function(from, to) {
switch (to) {
@@ -87,7 +84,8 @@
// Insert form container in DOM.
if ($editorElement.css('display') === 'inline') {
- // @todo: this is untested in Drupal 8, because in Drupal 8 we don't yet
+ // @todo: POSTPONED_ON(Drupal core, title/author/date as Entity Properties)
+ // This is untested in Drupal 8, because in Drupal 8 we don't yet
// have the ability to edit the node title/author/date, because they
// haven't been converted into Entity Properties yet, and they're the
// only examples in core of "display: inline" properties.
diff --git a/js/edit.js b/js/edit.js
index 22c976c..0c813fb 100644
--- a/js/edit.js
+++ b/js/edit.js
@@ -10,7 +10,9 @@ Drupal.edit = Drupal.edit || {};
Drupal.behaviors.editDiscoverEditables = {
attach: function(context) {
- // @todo: we need to separate the discovery of editables if we want updated
+ // @todo BLOCKED_ON(VIE.js, how to let VIE know that some content was removed and how to scan new content for VIE entities, to make them editable?)
+ // Also see ToolbarView.save().
+ // We need to separate the discovery of editables if we want updated
// or new content (added by code other than Edit) to be detected
// automatically. Once we implement this, we'll be able to get rid of all
// calls to Drupal.edit.domService.findSubjectElements() :)
diff --git a/js/lib/create.js b/js/lib/create.js
deleted file mode 100644
index 1d76bff..0000000
--- a/js/lib/create.js
+++ /dev/null
@@ -1,1643 +0,0 @@
-// Create.js - On-site web editing interface
-// (c) 2011-2012 Henri Bergius, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false window:false console:false */
- 'use strict';
-
- // # Widget for adding items to a collection
- jQuery.widget('Midgard.midgardCollectionAdd', {
- options: {
- editingWidgets: null,
- collection: null,
- model: null,
- definition: null,
- view: null,
- disabled: false,
- vie: null,
- editableOptions: null,
- templates: {
- button: ''
- }
- },
-
- _create: function () {
- this.addButtons = [];
- var widget = this;
- if (!widget.options.collection.localStorage) {
- try {
- widget.options.collection.url = widget.options.model.url();
- } catch (e) {
- if (window.console) {
- console.log(e);
- }
- }
- }
-
- widget.options.collection.bind('add', function (model) {
- model.primaryCollection = widget.options.collection;
- widget.options.vie.entities.add(model);
- model.collection = widget.options.collection;
- });
-
- // Re-check collection constraints
- widget.options.collection.bind('add remove reset', widget.checkCollectionConstraints, widget);
-
- widget._bindCollectionView(widget.options.view);
- },
-
- _bindCollectionView: function (view) {
- var widget = this;
- view.bind('add', function (itemView) {
- itemView.$el.effect('slide', function () {
- widget._makeEditable(itemView);
- });
- });
- },
-
- _makeEditable: function (itemView) {
- this.options.editableOptions.disabled = this.options.disabled;
- this.options.editableOptions.model = itemView.model;
- itemView.$el.midgardEditable(this.options.editableOptions);
- },
-
- _init: function () {
- if (this.options.disabled) {
- this.disable();
- return;
- }
- this.enable();
- },
-
- hideButtons: function () {
- _.each(this.addButtons, function (button) {
- button.hide();
- });
- },
-
- showButtons: function () {
- _.each(this.addButtons, function (button) {
- button.show();
- });
- },
-
- checkCollectionConstraints: function () {
- if (this.options.disabled) {
- return;
- }
-
- if (!this.options.view.canAdd()) {
- this.hideButtons();
- return;
- }
-
- if (!this.options.definition) {
- // We have now information on the constraints applying to this collection
- this.showButtons();
- return;
- }
-
- if (!this.options.definition.max || this.options.definition.max === -1) {
- // No maximum constraint
- this.showButtons();
- return;
- }
-
- if (this.options.collection.length < this.options.definition.max) {
- this.showButtons();
- return;
- }
- // Collection is already full by its definition
- this.hideButtons();
- },
-
- enable: function () {
- var widget = this;
-
- var addButton = jQuery(_.template(this.options.templates.button, {
- icon: 'plus',
- label: this.options.editableOptions.localize('Add', this.options.editableOptions.language)
- })).button();
- addButton.addClass('midgard-create-add');
- addButton.click(function () {
- widget.addItem(addButton);
- });
- jQuery(widget.options.view.el).after(addButton);
-
- widget.addButtons.push(addButton);
- widget.checkCollectionConstraints();
- },
-
- disable: function () {
- _.each(this.addButtons, function (button) {
- button.remove();
- });
- this.addButtons = [];
- },
-
- _getTypeActions: function (options) {
- var widget = this;
- var actions = [];
- _.each(this.options.definition.range, function (type) {
- var nsType = widget.options.collection.vie.namespaces.uri(type);
- if (!widget.options.view.canAdd(nsType)) {
- return;
- }
- actions.push({
- name: type,
- label: type,
- cb: function () {
- widget.options.collection.add({
- '@type': type
- }, options);
- },
- className: 'create-ui-btn'
- });
- });
- return actions;
- },
-
- addItem: function (button, options) {
- if (options === undefined) {
- options = {};
- }
- var addOptions = _.extend({}, options, { validate: false });
-
- var itemData = {};
- if (this.options.definition && this.options.definition.range) {
- if (this.options.definition.range.length === 1) {
- // Items can be of single type, add that
- itemData['@type'] = this.options.definition.range[0];
- } else {
- // Ask user which type to add
- jQuery('body').midgardNotifications('create', {
- bindTo: button,
- gravity: 'L',
- body: this.options.editableOptions.localize('Choose type to add', this.options.editableOptions.language),
- timeout: 0,
- actions: this._getTypeActions(addOptions)
- });
- return;
- }
- } else {
- // Check the view templates for possible non-Thing type to use
- var keys = _.keys(this.options.view.templates);
- if (keys.length == 2) {
- itemData['@type'] = keys[0];
- }
- }
- this.options.collection.add(itemData, addOptions);
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2011-2012 Henri Bergius, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false window:false console:false */
- 'use strict';
-
- // # Widget for adding items anywhere inside a collection
- jQuery.widget('Midgard.midgardCollectionAddBetween', jQuery.Midgard.midgardCollectionAdd, {
- _bindCollectionView: function (view) {
- var widget = this;
- view.bind('add', function (itemView) {
- //itemView.el.effect('slide');
- widget._makeEditable(itemView);
- widget._refreshButtons();
- });
- view.bind('remove', function () {
- widget._refreshButtons();
- });
- },
-
- _refreshButtons: function () {
- var widget = this;
- window.setTimeout(function () {
- widget.disable();
- widget.enable();
- }, 1);
- },
-
- prepareButton: function (index) {
- var widget = this;
- var addButton = jQuery(_.template(this.options.templates.button, {
- icon: 'plus',
- label: ''
- })).button();
- addButton.addClass('midgard-create-add');
- addButton.click(function () {
- widget.addItem(addButton, {
- at: index
- });
- });
- return addButton;
- },
-
- enable: function () {
- var widget = this;
-
- var firstAddButton = widget.prepareButton(0);
- jQuery(widget.options.view.el).prepend(firstAddButton);
- widget.addButtons.push(firstAddButton);
- jQuery.each(widget.options.view.entityViews, function (cid, view) {
- var index = widget.options.collection.indexOf(view.model);
- var addButton = widget.prepareButton(index + 1);
- jQuery(view.el).append(addButton);
- widget.addButtons.push(addButton);
- });
-
- this.checkCollectionConstraints();
- },
-
- disable: function () {
- var widget = this;
- jQuery.each(widget.addButtons, function (idx, button) {
- button.remove();
- });
- widget.addButtons = [];
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2011-2012 Henri Bergius, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false window:false VIE:false */
- 'use strict';
-
- // Define Create's EditableEntity widget.
- jQuery.widget('Midgard.midgardEditable', {
- options: {
- propertyEditors: {},
- collections: [],
- model: null,
- // the configuration (mapping and options) of property editor widgets
- propertyEditorWidgetsConfiguration: {
- hallo: {
- widget: 'halloWidget',
- options: {}
- }
- },
- // the available property editor widgets by data type
- propertyEditorWidgets: {
- 'default': 'hallo'
- },
- collectionWidgets: {
- 'default': 'midgardCollectionAdd'
- },
- toolbarState: 'full',
- vie: null,
- domService: 'rdfa',
- predicateSelector: '[property]',
- disabled: false,
- localize: function (id, language) {
- return window.midgardCreate.localize(id, language);
- },
- language: null,
- // Current state of the Editable
- state: null,
- // Callback function for validating changes between states. Receives the previous state, new state, possibly property, and a callback
- acceptStateChange: true,
- // Callback function for listening (and reacting) to state changes.
- stateChange: null,
- // Callback function for decorating the full editable. Will be called on instantiation
- decorateEditableEntity: null,
- // Callback function for decorating a single property editor widget. Will
- // be called on editing widget instantiation.
- decoratePropertyEditor: null,
-
- // Deprecated.
- editables: [], // Now `propertyEditors`.
- editors: {}, // Now `propertyEditorWidgetsConfiguration`.
- widgets: {} // Now `propertyEditorW
- },
-
- // Aids in consistently passing parameters to events and callbacks.
- _params: function(predicate, extended) {
- var entityParams = {
- entity: this.options.model,
- editableEntity: this,
- entityElement: this.element,
-
- // Deprecated.
- editable: this,
- element: this.element,
- instance: this.options.model
- };
-
- var propertyParams = (predicate) ? {
- predicate: predicate,
- propertyEditor: this.options.propertyEditors[predicate],
- propertyElement: this.options.propertyEditors[predicate].element,
-
- // Deprecated.
- property: predicate,
- element: this.options.propertyEditors[predicate].element
- } : {};
-
- return _.extend(entityParams, propertyParams, extended);
- },
-
- _create: function () {
- // Backwards compatibility:
- // - this.options.propertyEditorWidgets used to be this.options.widgets
- // - this.options.propertyEditorWidgetsConfiguration used to be
- // this.options.editors
- if (this.options.widgets) {
- this.options.propertyEditorWidgets = _.extend(this.options.propertyEditorWidgets, this.options.widgets);
- }
- if (this.options.editors) {
- this.options.propertyEditorWidgetsConfiguration = _.extend(this.options.propertyEditorWidgetsConfiguration, this.options.editors);
- }
-
- this.vie = this.options.vie;
- this.domService = this.vie.service(this.options.domService);
- if (!this.options.model) {
- var widget = this;
- this.vie.load({
- element: this.element
- }).from(this.options.domService).execute().done(function (entities) {
- widget.options.model = entities[0];
- });
- }
- if (_.isFunction(this.options.decorateEditableEntity)) {
- this.options.decorateEditableEntity(this._params());
- }
- },
-
- _init: function () {
- // Backwards compatibility:
- // - this.options.propertyEditorWidgets used to be this.options.widgets
- // - this.options.propertyEditorWidgetsConfiguration used to be
- // this.options.editors
- if (this.options.widgets) {
- this.options.propertyEditorWidgets = _.extend(this.options.propertyEditorWidgets, this.options.widgets);
- }
- if (this.options.editors) {
- this.options.propertyEditorWidgetsConfiguration = _.extend(this.options.propertyEditorWidgetsConfiguration, this.options.editors);
- }
-
- // Old way of setting the widget inactive
- if (this.options.disabled === true) {
- this.setState('inactive');
- return;
- }
-
- if (this.options.disabled === false && this.options.state === 'inactive') {
- this.setState('candidate');
- return;
- }
- this.options.disabled = false;
-
- if (this.options.state) {
- this.setState(this.options.state);
- return;
- }
- this.setState('candidate');
- },
-
- // Method used for cycling between the different states of the Editable widget:
- //
- // * Inactive: editable is loaded but disabled
- // * Candidate: editable is enabled but not activated
- // * Highlight: user is hovering over the editable (not set by Editable widget directly)
- // * Activating: an editor widget is being activated for user to edit with it (skipped for editors that activate instantly)
- // * Active: user is actually editing something inside the editable
- // * Changed: user has made changes to the editable
- // * Invalid: the contents of the editable have validation errors
- //
- // In situations where state changes are triggered for a particular property editor, the `predicate`
- // argument will provide the name of that property.
- //
- // State changes may carry optional context information in a JavaScript object. The payload of these context objects is not
- // standardized, and is meant to be set and used by the application controller
- //
- // The callback parameter is optional and will be invoked after a state change has been accepted (after the 'statechange'
- // event) or rejected.
- setState: function (state, predicate, context, callback) {
- var previous = this.options.state;
- var current = state;
- if (current === previous) {
- return;
- }
-
- if (this.options.acceptStateChange === undefined || !_.isFunction(this.options.acceptStateChange)) {
- // Skip state transition validation
- this._doSetState(previous, current, predicate, context);
- if (_.isFunction(callback)) {
- callback(true);
- }
- return;
- }
-
- var widget = this;
- this.options.acceptStateChange(previous, current, predicate, context, function (accepted) {
- if (accepted) {
- widget._doSetState(previous, current, predicate, context);
- }
- if (_.isFunction(callback)) {
- callback(accepted);
- }
- return;
- });
- },
-
- getState: function () {
- return this.options.state;
- },
-
- _doSetState: function (previous, current, predicate, context) {
- this.options.state = current;
- if (current === 'inactive') {
- this.disable();
- } else if ((previous === null || previous === 'inactive') && current !== 'inactive') {
- this.enable();
- }
-
- this._trigger('statechange', null, this._params(predicate, {
- previous: previous,
- current: current,
- context: context
- }));
- },
-
- findEditablePredicateElements: function (callback) {
- this.domService.findPredicateElements(this.options.model.id, jQuery(this.options.predicateSelector, this.element), false).each(callback);
- },
-
- getElementPredicate: function (element) {
- return this.domService.getElementPredicate(element);
- },
-
- enable: function () {
- var editableEntity = this;
- if (!this.options.model) {
- return;
- }
-
- this.findEditablePredicateElements(function () {
- editableEntity._enablePropertyEditor(jQuery(this));
- });
-
- this._trigger('enable', null, this._params());
-
- _.each(this.domService.views, function (view) {
- if (view instanceof this.vie.view.Collection && this.options.model === view.owner) {
- var predicate = view.collection.predicate;
- var editableOptions = _.clone(this.options);
- editableOptions.state = null;
- var collection = this.enableCollection({
- model: this.options.model,
- collection: view.collection,
- property: predicate,
- definition: this.getAttributeDefinition(predicate),
- view: view,
- element: view.el,
- vie: editableEntity.vie,
- editableOptions: editableOptions
- });
- editableEntity.options.collections.push(collection);
- }
- }, this);
- },
-
- disable: function () {
- _.each(this.options.propertyEditors, function (editable) {
- this.disableEditor({
- widget: this,
- editable: editable,
- entity: this.options.model,
- element: jQuery(editable)
- });
- }, this);
- this.options.propertyEditors = {};
-
- // Deprecated.
- this.options.editables = [];
-
- _.each(this.options.collections, function (collectionWidget) {
- var editableOptions = _.clone(this.options);
- editableOptions.state = 'inactive';
- this.disableCollection({
- widget: this,
- model: this.options.model,
- element: collectionWidget,
- vie: this.vie,
- editableOptions: editableOptions
- });
- }, this);
- this.options.collections = [];
-
- this._trigger('disable', null, this._params());
- },
-
- _enablePropertyEditor: function (element) {
- var widget = this;
- var predicate = this.getElementPredicate(element);
- if (!predicate) {
- return true;
- }
- if (this.options.model.get(predicate) instanceof Array) {
- // For now we don't deal with multivalued properties in the editable
- return true;
- }
-
- var propertyElement = this.enablePropertyEditor({
- widget: this,
- element: element,
- entity: this.options.model,
- property: predicate,
- vie: this.vie,
- decorate: this.options.decoratePropertyEditor,
- decorateParams: _.bind(this._params, this),
- changed: function (content) {
- widget.setState('changed', predicate);
-
- var changedProperties = {};
- changedProperties[predicate] = content;
- widget.options.model.set(changedProperties, {
- silent: true
- });
-
- widget._trigger('changed', null, widget._params(predicate));
- },
- activating: function () {
- widget.setState('activating', predicate);
- },
- activated: function () {
- widget.setState('active', predicate);
- widget._trigger('activated', null, widget._params(predicate));
- },
- deactivated: function () {
- widget.setState('candidate', predicate);
- widget._trigger('deactivated', null, widget._params(predicate));
- }
- });
-
- if (!propertyElement) {
- return;
- }
- var widgetType = propertyElement.data('createWidgetName');
- this.options.propertyEditors[predicate] = propertyElement.data(widgetType);
-
- // Deprecated.
- this.options.editables.push(propertyElement);
-
- this._trigger('enableproperty', null, this._params(predicate));
- },
-
- // returns the name of the property editor widget to use for the given property
- _propertyEditorName: function (data) {
- if (this.options.propertyEditorWidgets[data.property] !== undefined) {
- // Property editor widget configuration set for specific RDF predicate
- return this.options.propertyEditorWidgets[data.property];
- }
-
- // Load the property editor widget configuration for the data type
- var propertyType = 'default';
- var attributeDefinition = this.getAttributeDefinition(data.property);
- if (attributeDefinition) {
- propertyType = attributeDefinition.range[0];
- }
- if (this.options.propertyEditorWidgets[propertyType] !== undefined) {
- return this.options.propertyEditorWidgets[propertyType];
- }
- return this.options.propertyEditorWidgets['default'];
- },
-
- _propertyEditorWidget: function (editor) {
- return this.options.propertyEditorWidgetsConfiguration[editor].widget;
- },
-
- _propertyEditorOptions: function (editor) {
- return this.options.propertyEditorWidgetsConfiguration[editor].options;
- },
-
- getAttributeDefinition: function (property) {
- var type = this.options.model.get('@type');
- if (!type) {
- return;
- }
- if (!type.attributes) {
- return;
- }
- return type.attributes.get(property);
- },
-
- // Deprecated.
- enableEditor: function (data) {
- return this.enablePropertyEditor(data);
- },
-
- enablePropertyEditor: function (data) {
- var editorName = this._propertyEditorName(data);
- if (editorName === null) {
- return;
- }
-
- var editorWidget = this._propertyEditorWidget(editorName);
-
- data.editorOptions = this._propertyEditorOptions(editorName);
- data.toolbarState = this.options.toolbarState;
- data.disabled = false;
- // Pass metadata that could be useful for some implementations.
- data.editorName = editorName;
- data.editorWidget = editorWidget;
-
- if (typeof jQuery(data.element)[editorWidget] !== 'function') {
- throw new Error(editorWidget + ' widget is not available');
- }
-
- jQuery(data.element)[editorWidget](data);
- jQuery(data.element).data('createWidgetName', editorWidget);
- return jQuery(data.element);
- },
-
- // Deprecated.
- disableEditor: function (data) {
- return this.disablePropertyEditor(data);
- },
-
- disablePropertyEditor: function (data) {
- var widgetName = jQuery(data.element).data('createWidgetName');
-
- data.disabled = true;
-
- if (widgetName) {
- // only if there has been an editing widget registered
- jQuery(data.element)[widgetName](data);
- jQuery(data.element).removeClass('ui-state-disabled');
-
- if (data.element.is(':focus')) {
- data.element.blur();
- }
- }
- },
-
- collectionWidgetName: function (data) {
- if (this.options.collectionWidgets[data.property] !== undefined) {
- // Widget configuration set for specific RDF predicate
- return this.options.collectionWidgets[data.property];
- }
-
- var propertyType = 'default';
- var attributeDefinition = this.getAttributeDefinition(data.property);
- if (attributeDefinition) {
- propertyType = attributeDefinition.range[0];
- }
- if (this.options.collectionWidgets[propertyType] !== undefined) {
- return this.options.collectionWidgets[propertyType];
- }
- return this.options.collectionWidgets['default'];
- },
-
- enableCollection: function (data) {
- var widgetName = this.collectionWidgetName(data);
- if (widgetName === null) {
- return;
- }
- data.disabled = false;
- if (typeof jQuery(data.element)[widgetName] !== 'function') {
- throw new Error(widgetName + ' widget is not available');
- }
- jQuery(data.element)[widgetName](data);
- jQuery(data.element).data('createCollectionWidgetName', widgetName);
- return jQuery(data.element);
- },
-
- disableCollection: function (data) {
- var widgetName = jQuery(data.element).data('createCollectionWidgetName');
- if (widgetName === null) {
- return;
- }
- data.disabled = true;
- if (widgetName) {
- // only if there has been an editing widget registered
- jQuery(data.element)[widgetName](data);
- jQuery(data.element).removeClass('ui-state-disabled');
- }
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2012 Tobias Herrmann, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false document:false */
- 'use strict';
-
- // # Base property editor widget
- //
- // This property editor widget provides a very simplistic `contentEditable`
- // property editor that can be used as standalone, but should more usually be
- // used as the base class for other property editor widgets.
- // This property editor widget is only useful for textual properties!
- //
- // Subclassing this base property editor widget is easy:
- //
- // jQuery.widget('Namespace.MyWidget', jQuery.Create.editWidget, {
- // // override any properties
- // });
- jQuery.widget('Create.editWidget', {
- options: {
- disabled: false,
- vie: null
- },
- // override to enable the widget
- enable: function () {
- this.element.attr('contenteditable', 'true');
- },
- // override to disable the widget
- disable: function (disable) {
- this.element.attr('contenteditable', 'false');
- },
- // called by the jQuery UI plugin factory when creating the property editor
- // widget instance
- _create: function () {
- this._registerWidget();
- this._initialize();
-
- if (_.isFunction(this.options.decorate) && _.isFunction(this.options.decorateParams)) {
- // TRICKY: we can't use this.options.decorateParams()'s 'propertyName'
- // parameter just yet, because it will only be available after this
- // object has been created, but we're currently in the constructor!
- // Hence we have to duplicate part of its logic here.
- this.options.decorate(this.options.decorateParams(null, {
- propertyName: this.options.property,
- propertyEditor: this,
- propertyElement: this.element,
- // Deprecated.
- editor: this,
- predicate: this.options.property,
- element: this.element
- }));
- }
- },
- // called every time the property editor widget is called
- _init: function () {
- if (this.options.disabled) {
- this.disable();
- return;
- }
- this.enable();
- },
- // override this function to initialize the property editor widget functions
- _initialize: function () {
- var self = this;
- this.element.bind('focus', function () {
- if (self.options.disabled) {
- return;
- }
- self.options.activated();
- });
- this.element.bind('blur', function () {
- if (self.options.disabled) {
- return;
- }
- self.options.deactivated();
- });
- var before = this.element.html();
- this.element.bind('keyup paste', function (event) {
- if (self.options.disabled) {
- return;
- }
- var current = jQuery(this).html();
- if (before !== current) {
- before = current;
- self.options.changed(current);
- }
- });
- },
- // used to register the property editor widget name with the DOM element
- _registerWidget: function () {
- this.element.data("createWidgetName", this.widgetName);
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2012 Tobias Herrmann, IKS Consortium
-// (c) 2011 Rene Kapusta, Evo42
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false document:false Aloha:false */
- 'use strict';
-
- // # Aloha editing widget
- //
- // This widget allows editing textual contents using the
- // [Aloha](http://aloha-editor.org) rich text editor.
- //
- // Due to licensing incompatibilities, Aloha Editor needs to be installed
- // and configured separately.
- jQuery.widget('Create.alohaWidget', jQuery.Create.editWidget, {
- _initialize: function () {},
- enable: function () {
- var options = this.options;
- var editable;
- var currentElement = Aloha.jQuery(options.element.get(0)).aloha();
- _.each(Aloha.editables, function (aloha) {
- // Find the actual editable instance so we can hook to the events
- // correctly
- if (aloha.obj.get(0) === currentElement.get(0)) {
- editable = aloha;
- }
- });
- if (!editable) {
- return;
- }
- editable.vieEntity = options.entity;
-
- // Subscribe to activation and deactivation events
- Aloha.bind('aloha-editable-activated', function (event, data) {
- if (data.editable !== editable) {
- return;
- }
- options.activated();
- });
- Aloha.bind('aloha-editable-deactivated', function (event, data) {
- if (data.editable !== editable) {
- return;
- }
- options.deactivated();
- });
-
- Aloha.bind('aloha-smart-content-changed', function (event, data) {
- if (data.editable !== editable) {
- return;
- }
- if (!data.editable.isModified()) {
- return true;
- }
- options.changed(data.editable.getContents());
- data.editable.setUnmodified();
- });
- this.options.disabled = false;
- },
- disable: function () {
- Aloha.jQuery(this.options.element.get(0)).mahalo();
- this.options.disabled = true;
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2012 Tobias Herrmann, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false document:false CKEDITOR:false */
- 'use strict';
-
- // # CKEditor editing widget
- //
- // This widget allows editing textual content areas with the
- // [CKEditor](http://ckeditor.com/) rich text editor.
- jQuery.widget('Create.ckeditorWidget', jQuery.Create.editWidget, {
- enable: function () {
- this.element.attr('contentEditable', 'true');
- this.editor = CKEDITOR.inline(this.element.get(0));
- this.options.disabled = false;
-
- var widget = this;
- this.editor.on('focus', function () {
- widget.options.activated();
- });
- this.editor.on('blur', function () {
- widget.options.activated();
- });
- this.editor.on('key', function () {
- widget.options.changed(widget.editor.getData());
- });
- this.editor.on('paste', function () {
- widget.options.changed(widget.editor.getData());
- });
- this.editor.on('afterCommandExec', function () {
- widget.options.changed(widget.editor.getData());
- });
- },
-
- disable: function () {
- if (!this.editor) {
- return;
- }
- this.element.attr('contentEditable', 'false');
- this.editor.destroy();
- this.editor = null;
- },
-
- _initialize: function () {
- CKEDITOR.disableAutoInline = true;
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2012 Tobias Herrmann, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false document:false */
- 'use strict';
-
- // # Hallo editing widget
- //
- // This widget allows editing textual content areas with the
- // [Hallo](http://hallojs.org) rich text editor.
- jQuery.widget('Create.halloWidget', jQuery.Create.editWidget, {
- options: {
- editorOptions: {},
- disabled: true,
- toolbarState: 'full',
- vie: null,
- entity: null
- },
- enable: function () {
- jQuery(this.element).hallo({
- editable: true
- });
- this.options.disabled = false;
- },
-
- disable: function () {
- jQuery(this.element).hallo({
- editable: false
- });
- this.options.disabled = true;
- },
-
- _initialize: function () {
- jQuery(this.element).hallo(this.getHalloOptions());
- var self = this;
- jQuery(this.element).bind('halloactivated', function (event, data) {
- self.options.activated();
- });
- jQuery(this.element).bind('hallodeactivated', function (event, data) {
- self.options.deactivated();
- });
- jQuery(this.element).bind('hallomodified', function (event, data) {
- self.options.changed(data.content);
- data.editable.setUnmodified();
- });
-
- jQuery(document).bind('midgardtoolbarstatechange', function(event, data) {
- // Switch between Hallo configurations when toolbar state changes
- if (data.display === self.options.toolbarState) {
- return;
- }
- self.options.toolbarState = data.display;
- var newOptions = self.getHalloOptions();
- self.element.hallo('changeToolbar', newOptions.parentElement, newOptions.toolbar, true);
- });
- },
-
- getHalloOptions: function() {
- var defaults = {
- plugins: {
- halloformat: {},
- halloblock: {},
- hallolists: {},
- hallolink: {},
- halloimage: {
- entity: this.options.entity
- }
- },
- buttonCssClass: 'create-ui-btn-small',
- placeholder: '[' + this.options.property + ']'
- };
-
- if (typeof this.element.annotate === 'function' && this.options.vie.services.stanbol) {
- // Enable Hallo Annotate plugin by default if user has annotate.js
- // loaded and VIE has Stanbol enabled
- defaults.plugins.halloannotate = {
- vie: this.options.vie
- };
- }
-
- if (this.options.toolbarState === 'full') {
- // Use fixed toolbar in the Create tools area
- defaults.parentElement = jQuery('.create-ui-toolbar-dynamictoolarea .create-ui-tool-freearea');
- defaults.toolbar = 'halloToolbarFixed';
- } else {
- // Tools area minimized, use floating toolbar
- defaults.parentElement = 'body';
- defaults.toolbar = 'halloToolbarContextual';
- }
- return _.extend(defaults, this.options.editorOptions);
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2012 Henri Bergius, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false document:false */
- 'use strict';
-
- // # Redactor editing widget
- //
- // This widget allows editing textual content areas with the
- // [Redactor](http://redactorjs.com/) rich text editor.
- jQuery.widget('Create.redactorWidget', jQuery.Create.editWidget, {
- editor: null,
-
- options: {
- editorOptions: {},
- disabled: true
- },
-
- enable: function () {
- jQuery(this.element).redactor(this.getRedactorOptions());
- this.options.disabled = false;
- },
-
- disable: function () {
- jQuery(this.element).destroyEditor();
- this.options.disabled = true;
- },
-
- _initialize: function () {
- var self = this;
- jQuery(this.element).bind('focus', function (event) {
- self.options.activated();
- });
- /*
- jQuery(this.element).bind('blur', function (event) {
- self.options.deactivated();
- });
- */
- },
-
- getRedactorOptions: function () {
- var self = this;
- var overrides = {
- keyupCallback: function (obj, event) {
- self.options.changed(jQuery(self.element).getCode());
- },
- execCommandCallback: function (obj, command) {
- self.options.changed(jQuery(self.element).getCode());
- }
- };
-
- return _.extend(self.options.editorOptions, overrides);
- }
- });
-})(jQuery);
-// Create.js - On-site web editing interface
-// (c) 2011-2012 Henri Bergius, IKS Consortium
-// Create may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://createjs.org/
-(function (jQuery, undefined) {
- // Run JavaScript in strict mode
- /*global jQuery:false _:false window:false */
- 'use strict';
-
- jQuery.widget('Midgard.midgardStorage', {
- saveEnabled: true,
- options: {
- // Whether to use localstorage
- localStorage: false,
- removeLocalstorageOnIgnore: true,
- // VIE instance to use for storage handling
- vie: null,
- // URL callback for Backbone.sync
- url: '',
- // Whether to enable automatic saving
- autoSave: false,
- // How often to autosave in milliseconds
- autoSaveInterval: 5000,
- // Whether to save entities that are referenced by entities
- // we're saving to the server.
- saveReferencedNew: false,
- saveReferencedChanged: false,
- // Namespace used for events from midgardEditable-derived widget
- editableNs: 'midgardeditable',
- // CSS selector for the Edit button, leave to null to not bind
- // notifications to any element
- editSelector: '#midgardcreate-edit a',
- localize: function (id, language) {
- return window.midgardCreate.localize(id, language);
- },
- language: null
- },
-
- _create: function () {
- var widget = this;
- this.changedModels = [];
-
- if (window.localStorage) {
- this.options.localStorage = true;
- }
-
- this.vie = this.options.vie;
-
- this.vie.entities.bind('add', function (model) {
- // Add the back-end URL used by Backbone.sync
- model.url = widget.options.url;
- model.toJSON = model.toJSONLD;
- });
-
- widget._bindEditables();
- if (widget.options.autoSave) {
- widget._autoSave();
- }
- },
-
- _autoSave: function () {
- var widget = this;
- widget.saveEnabled = true;
-
- var doAutoSave = function () {
- if (!widget.saveEnabled) {
- return;
- }
-
- if (widget.changedModels.length === 0) {
- return;
- }
-
- widget.saveRemoteAll({
- // We make autosaves silent so that potential changes from server
- // don't disrupt user while writing.
- silent: true
- });
- };
-
- var timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval);
-
- this.element.bind('startPreventSave', function () {
- if (timeout) {
- window.clearInterval(timeout);
- timeout = null;
- }
- widget.disableAutoSave();
- });
- this.element.bind('stopPreventSave', function () {
- if (!timeout) {
- timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval);
- }
- widget.enableAutoSave();
- });
-
- },
-
- enableAutoSave: function () {
- this.saveEnabled = true;
- },
-
- disableAutoSave: function () {
- this.saveEnabled = false;
- },
-
- _bindEditables: function () {
- var widget = this;
- this.restorables = [];
- var restorer;
-
- widget.element.bind(widget.options.editableNs + 'changed', function (event, options) {
- if (_.indexOf(widget.changedModels, options.instance) === -1) {
- widget.changedModels.push(options.instance);
- }
- widget._saveLocal(options.instance);
- });
-
- widget.element.bind(widget.options.editableNs + 'disable', function (event, options) {
- widget._restoreLocal(options.instance);
- });
-
- widget.element.bind(widget.options.editableNs + 'enable', function (event, options) {
- if (!options.instance._originalAttributes) {
- options.instance._originalAttributes = _.clone(options.instance.attributes);
- }
-
- if (!options.instance.isNew() && widget._checkLocal(options.instance)) {
- // We have locally-stored modifications, user needs to be asked
- widget.restorables.push(options.instance);
- }
-
- /*_.each(options.instance.attributes, function (attributeValue, property) {
- if (attributeValue instanceof widget.vie.Collection) {
- widget._readLocalReferences(options.instance, property, attributeValue);
- }
- });*/
- });
-
- widget.element.bind('midgardcreatestatechange', function (event, options) {
- if (options.state === 'browse' || widget.restorables.length === 0) {
- widget.restorables = [];
- if (restorer) {
- restorer.close();
- }
- return;
- }
- restorer = widget.checkRestore();
- });
-
- widget.element.bind('midgardstorageloaded', function (event, options) {
- if (_.indexOf(widget.changedModels, options.instance) === -1) {
- widget.changedModels.push(options.instance);
- }
- });
- },
-
- checkRestore: function () {
- var widget = this;
- if (widget.restorables.length === 0) {
- return;
- }
-
- var message;
- var restorer;
- if (widget.restorables.length === 1) {
- message = _.template(widget.options.localize('localModification', widget.options.language), {
- label: widget.restorables[0].getSubjectUri()
- });
- } else {
- message = _.template(widget.options.localize('localModifications', widget.options.language), {
- number: widget.restorables.length
- });
- }
-
- var doRestore = function (event, notification) {
- widget.restoreLocal();
- restorer.close();
- };
-
- var doIgnore = function (event, notification) {
- widget.ignoreLocal();
- restorer.close();
- };
-
- restorer = jQuery('body').midgardNotifications('create', {
- bindTo: widget.options.editSelector,
- gravity: 'TR',
- body: message,
- timeout: 0,
- actions: [
- {
- name: 'restore',
- label: widget.options.localize('Restore', widget.options.language),
- cb: doRestore,
- className: 'create-ui-btn'
- },
- {
- name: 'ignore',
- label: widget.options.localize('Ignore', widget.options.language),
- cb: doIgnore,
- className: 'create-ui-btn'
- }
- ],
- callbacks: {
- beforeShow: function () {
- if (!window.Mousetrap) {
- return;
- }
- window.Mousetrap.bind(['command+shift+r', 'ctrl+shift+r'], function (event) {
- event.preventDefault();
- doRestore();
- });
- window.Mousetrap.bind(['command+shift+i', 'ctrl+shift+i'], function (event) {
- event.preventDefault();
- doIgnore();
- });
- },
- afterClose: function () {
- if (!window.Mousetrap) {
- return;
- }
- window.Mousetrap.unbind(['command+shift+r', 'ctrl+shift+r']);
- window.Mousetrap.unbind(['command+shift+i', 'ctrl+shift+i']);
- }
- }
- });
- return restorer;
- },
-
- restoreLocal: function () {
- _.each(this.restorables, function (instance) {
- this.readLocal(instance);
- }, this);
- this.restorables = [];
- },
-
- ignoreLocal: function () {
- if (this.options.removeLocalstorageOnIgnore) {
- _.each(this.restorables, function (instance) {
- this._removeLocal(instance);
- }, this);
- }
- this.restorables = [];
- },
-
- saveReferences: function (model) {
- _.each(model.attributes, function (value, property) {
- if (!value || !value.isCollection) {
- return;
- }
-
- value.each(function (referencedModel) {
- if (this.changedModels.indexOf(referencedModel) !== -1) {
- // The referenced model is already in the save queue
- return;
- }
-
- if (referencedModel.isNew() && this.options.saveReferencedNew) {
- return referencedModel.save();
- }
-
- if (referencedModel.hasChanged() && this.options.saveReferencedChanged) {
- return referencedModel.save();
- }
- }, this);
- }, this);
- },
-
- saveRemote: function (model, options) {
- // Optionally handle entities referenced in this model first
- this.saveReferences(model);
-
- this._trigger('saveentity', null, {
- entity: model,
- options: options
- });
-
- var widget = this;
- model.save(null, _.extend({}, options, {
- success: function (m, response) {
- // From now on we're going with the values we have on server
- model._originalAttributes = _.clone(model.attributes);
- widget._removeLocal(model);
- window.setTimeout(function () {
- // Remove the model from the list of changed models after saving
- widget.changedModels.splice(widget.changedModels.indexOf(model), 1);
- }, 0);
- if (_.isFunction(options.success)) {
- options.success(m, response);
- }
- widget._trigger('savedentity', null, {
- entity: model,
- options: options
- });
- },
- error: function (m, response) {
- if (_.isFunction(options.error)) {
- options.error(m, response);
- }
- }
- }));
- },
-
- saveRemoteAll: function (options) {
- var widget = this;
- if (widget.changedModels.length === 0) {
- return;
- }
-
- widget._trigger('save', null, {
- entities: widget.changedModels,
- options: options,
- // Deprecated
- models: widget.changedModels
- });
-
- var notification_msg;
- var needed = widget.changedModels.length;
- if (needed > 1) {
- notification_msg = _.template(widget.options.localize('saveSuccessMultiple', widget.options.language), {
- number: needed
- });
- } else {
- notification_msg = _.template(widget.options.localize('saveSuccess', widget.options.language), {
- label: widget.changedModels[0].getSubjectUri()
- });
- }
-
- widget.disableAutoSave();
- _.each(widget.changedModels, function (model) {
- this.saveRemote(model, {
- success: function (m, response) {
- needed--;
- if (needed <= 0) {
- // All models were happily saved
- widget._trigger('saved', null, {
- options: options
- });
- if (options && _.isFunction(options.success)) {
- options.success(m, response);
- }
- jQuery('body').midgardNotifications('create', {
- body: notification_msg
- });
- widget.enableAutoSave();
- }
- },
- error: function (m, err) {
- if (options && _.isFunction(options.error)) {
- options.error(m, err);
- }
- jQuery('body').midgardNotifications('create', {
- body: _.template(widget.options.localize('saveError', widget.options.language), {
- error: err.responseText || ''
- }),
- timeout: 0
- });
-
- widget._trigger('error', null, {
- instance: model
- });
- }
- });
- }, this);
- },
-
- _saveLocal: function (model) {
- if (!this.options.localStorage) {
- return;
- }
-
- if (model.isNew()) {
- // Anonymous object, save as refs instead
- if (!model.primaryCollection) {
- return;
- }
- return this._saveLocalReferences(model.primaryCollection.subject, model.primaryCollection.predicate, model);
- }
- window.localStorage.setItem(model.getSubjectUri(), JSON.stringify(model.toJSONLD()));
- },
-
- _getReferenceId: function (model, property) {
- return model.id + ':' + property;
- },
-
- _saveLocalReferences: function (subject, predicate, model) {
- if (!this.options.localStorage) {
- return;
- }
-
- if (!subject || !predicate) {
- return;
- }
-
- var widget = this;
- var identifier = subject + ':' + predicate;
- var json = model.toJSONLD();
- if (window.localStorage.getItem(identifier)) {
- var referenceList = JSON.parse(window.localStorage.getItem(identifier));
- var index = _.pluck(referenceList, '@').indexOf(json['@']);
- if (index !== -1) {
- referenceList[index] = json;
- } else {
- referenceList.push(json);
- }
- window.localStorage.setItem(identifier, JSON.stringify(referenceList));
- return;
- }
- window.localStorage.setItem(identifier, JSON.stringify([json]));
- },
-
- _checkLocal: function (model) {
- if (!this.options.localStorage) {
- return false;
- }
-
- var local = window.localStorage.getItem(model.getSubjectUri());
- if (!local) {
- return false;
- }
-
- return true;
- },
-
- hasLocal: function (model) {
- if (!this.options.localStorage) {
- return false;
- }
-
- if (!window.localStorage.getItem(model.getSubjectUri())) {
- return false;
- }
- return true;
- },
-
- readLocal: function (model) {
- if (!this.options.localStorage) {
- return;
- }
-
- var local = window.localStorage.getItem(model.getSubjectUri());
- if (!local) {
- return;
- }
- if (!model._originalAttributes) {
- model._originalAttributes = _.clone(model.attributes);
- }
- var parsed = JSON.parse(local);
- var entity = this.vie.entities.addOrUpdate(parsed, {
- overrideAttributes: true
- });
-
- this._trigger('loaded', null, {
- instance: entity
- });
- },
-
- _readLocalReferences: function (model, property, collection) {
- if (!this.options.localStorage) {
- return;
- }
-
- var identifier = this._getReferenceId(model, property);
- var local = window.localStorage.getItem(identifier);
- if (!local) {
- return;
- }
- collection.add(JSON.parse(local));
- },
-
- _restoreLocal: function (model) {
- var widget = this;
-
- // Remove unsaved collection members
- if (!model) { return; }
- _.each(model.attributes, function (attributeValue, property) {
- if (attributeValue instanceof widget.vie.Collection) {
- var removables = [];
- attributeValue.forEach(function (model) {
- if (model.isNew()) {
- removables.push(model);
- }
- });
- attributeValue.remove(removables);
- }
- });
-
- // Restore original object properties
- if (!model.changedAttributes()) {
- if (model._originalAttributes) {
- model.set(model._originalAttributes);
- }
- return;
- }
-
- model.set(model.previousAttributes());
- },
-
- _removeLocal: function (model) {
- if (!this.options.localStorage) {
- return;
- }
-
- window.localStorage.removeItem(model.getSubjectUri());
- }
- });
-})(jQuery);
-if (window.midgardCreate === undefined) {
- window.midgardCreate = {};
-}
-if (window.midgardCreate.locale === undefined) {
- window.midgardCreate.locale = {};
-}
-
-window.midgardCreate.locale.en = {
- // Session-state buttons for the main toolbar
- 'Save': 'Save',
- 'Saving': 'Saving',
- 'Cancel': 'Cancel',
- 'Edit': 'Edit',
- // Storage status messages
- 'localModification': 'Item "<%= label %>" has local modifications',
- 'localModifications': '<%= number %> items on this page have local modifications',
- 'Restore': 'Restore',
- 'Ignore': 'Ignore',
- 'saveSuccess': 'Item "<%= label %>" saved successfully',
- 'saveSuccessMultiple': '<%= number %> items saved successfully',
- 'saveError': 'Error occurred while saving <%= error %>',
- // Tagging
- 'Item tags': 'Item tags',
- 'Suggested tags': 'Suggested tags',
- 'Tags': 'Tags',
- 'add a tag': 'add a tag',
- // Collection widgets
- 'Add': 'Add',
- 'Choose type to add': 'Choose type to add'
-};
diff --git a/js/lib/vie.js b/js/lib/vie.js
deleted file mode 100644
index ca5c079..0000000
--- a/js/lib/vie.js
+++ /dev/null
@@ -1,3682 +0,0 @@
-/*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('')` 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
-// Namespaces documentation.
- 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
-// Types documentation.
- 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 = "";
-// 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 = "";
-// 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);
-// -->
-// VIE.Util.toUri(scurie, ns);
-// -->
- 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 = "";
-// 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 schema.org 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("");
-
- 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]));
- 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 VIE.Type.
-// * `@context` stores namespace definitions used in the entity. Read more about
-// Namespaces in VIE Namespaces.
-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);
- return Backbone.Model.prototype.set.call(this, attrs, options);
- },
-
- // **`.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);
-// // --> ""
- 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 VIE.Attributes)
-// **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 constructor of VIE.Entity
-// *{object}* **opts** see constructor of VIE.Entity
-// **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);
-// // -->
- 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 = "";
-// 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 = "";
-// 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);
-// -->
-// ns.uri(scurie);
-// -->
-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 = "";
-// var curie = "test:Person";
-// namespaces.isUri(uri); // --> true
-// namespaces.isUri(curie); // --> false
-VIE.prototype.Namespaces.prototype.isUri = VIE.Util.isUri;
-})();
\ No newline at end of file
diff --git a/js/theme.js b/js/theme.js
index 4853246..f92c308 100644
--- a/js/theme.js
+++ b/js/theme.js
@@ -2,7 +2,7 @@
* @file
* Provides overridable theme functions for all of Edit's client-side HTML.
*/
-(function($) {
+(function($, Drupal) {
"use strict";
@@ -153,4 +153,4 @@ Drupal.theme.editFormContainer = function(settings) {
return html;
};
-})(jQuery);
+})(jQuery, Drupal);
diff --git a/js/viejs/EditService.js b/js/viejs/EditService.js
new file mode 100644
index 0000000..cde0e2e
--- /dev/null
+++ b/js/viejs/EditService.js
@@ -0,0 +1,201 @@
+/**
+ * @file
+ * VIE DOM parsing service for Edit.
+ */
+(function(jQuery, _, Drupal, VIE) {
+
+"use strict";
+
+ VIE.prototype.EditService = function (options) {
+ var defaults = {
+ name: 'edit',
+ subjectSelector: '.edit-field.edit-allowed'
+ };
+ this.options = _.extend({}, defaults, options);
+
+ this.views = [];
+ this.vie = null;
+ this.name = this.options.name;
+ };
+
+ VIE.prototype.EditService.prototype = {
+ load: function (loadable) {
+ var correct = loadable instanceof this.vie.Loadable;
+ if (!correct) {
+ throw new Error('Invalid Loadable passed');
+ }
+
+ var element;
+ if (!loadable.options.element) {
+ if (typeof document === 'undefined') {
+ return loadable.resolve([]);
+ } else {
+ element = Drupal.settings.edit.context;
+ }
+ } else {
+ element = loadable.options.element;
+ }
+
+ var entities = this.readEntities(element);
+ loadable.resolve(entities);
+ },
+
+ // The edit-id data attribute contains the full identifier of
+ // each entity element in the format
+ // `::::`.
+ _getID: function (element) {
+ var id = jQuery(element).attr('data-edit-id');
+ if (!id) {
+ id = jQuery(element).closest('[data-edit-id]').attr('data-edit-id');
+ }
+ return id;
+ },
+
+ // Returns the "URI" of an entity of an element in format
+ // `/`.
+ getElementSubject: function (element) {
+ return this._getID(element).split(':').slice(0, 2).join('/');
+ },
+
+ // Returns the field name for an element in format
+ // `//`.
+ // (Slashes instead of colons because the field name is no namespace.)
+ getElementPredicate: function (element) {
+ if (!this._getID(element)) {
+ throw new Error('Could not find predicate for element');
+ }
+ return this._getID(element).split(':').slice(2, 5).join('/');
+ },
+
+ getElementType: function (element) {
+ return this._getID(element).split(':').slice(0, 1)[0];
+ },
+
+ // Reads all editable entities (currently each Drupal field is considered an
+ // entity, in the future Drupal entities should be mapped to VIE entities)
+ // from DOM and returns the VIE enties it found.
+ readEntities: function (element) {
+ var service = this;
+ var entities = [];
+ var entityElements = jQuery(this.options.subjectSelector, element);
+ entityElements = entityElements.add(jQuery(element).filter(this.options.subjectSelector));
+ entityElements.each(function () {
+ var entity = service._readEntity(jQuery(this));
+ if (entity) {
+ entities.push(entity);
+ }
+ });
+ return entities;
+ },
+
+ // Returns a filled VIE Entity instance for a DOM element. The Entity
+ // is also registered in the VIE entities collection.
+ _readEntity: function (element) {
+ var subject = this.getElementSubject(element);
+ var type = this.getElementType(element);
+ var entity = this._readEntityPredicates(subject, element, false);
+ if (jQuery.isEmptyObject(entity)) {
+ return null;
+ }
+ entity['@subject'] = subject;
+ if (type) {
+ entity['@type'] = this._registerType(type, element);
+ }
+
+ // Register with VIE
+ return this._registerEntity(entity);
+ },
+
+ _registerEntity: function (entityData) {
+ var entityInstance = new this.vie.Entity(entityData);
+ return this.vie.entities.addOrUpdate(entityInstance, {
+ updateOptions: {
+ silent: true
+ }
+ });
+ },
+
+ _registerType: function (typeId, element) {
+ typeId = '';
+ var type = this.vie.types.get(typeId);
+ if (!type) {
+ this.vie.types.add(typeId, []);
+ type = this.vie.types.get(typeId);
+ }
+
+ var predicate = this.getElementPredicate(element);
+ if (type.attributes.get(predicate)) {
+ return type;
+ }
+
+ var label = element.data('edit-field-label');
+ var range = 'Form';
+ if (element.hasClass('edit-type-direct')) {
+ range = 'Direct';
+ }
+ if (element.hasClass('edit-type-direct-with-wysiwyg')) {
+ range = 'Wysiwyg';
+ }
+ type.attributes.add(predicate, [range], 0, 1, {
+ label: element.data('edit-field-label')
+ });
+
+ return type;
+ },
+
+ _readEntityPredicates: function (subject, element, emptyValues) {
+ var entityPredicates = {};
+ var service = this;
+ this.findPredicateElements(subject, element, true).each(function () {
+ var predicateElement = jQuery(this);
+ var predicate = service.getElementPredicate(predicateElement);
+ if (!predicate) {
+ return;
+ }
+ var value = service._readElementValue(predicateElement);
+ if (value === null && !emptyValues) {
+ return;
+ }
+
+ entityPredicates[predicate] = value;
+ });
+ return entityPredicates;
+ },
+
+ _readElementValue: function (element) {
+ return jQuery.trim(element.html());
+ },
+
+ // Subject elements are the DOM elements containing a single or multiple
+ // editable fields.
+ findSubjectElements: function (element) {
+ if (!element) {
+ element = Drupal.settings.edit.context;
+ }
+ return jQuery(this.options.subjectSelector, element);
+ },
+
+ // Predicate Elements are the actual DOM elements that users will be able
+ // to edit.
+ findPredicateElements: function (subject, element, allowNestedPredicates, stop) {
+ var predicates = jQuery();
+
+ // Form-type predicates
+ predicates = predicates.add(element.filter('.edit-type-form'));
+
+ // Direct-type predicates
+ var direct = element.filter('.edit-type-direct');
+ predicates = predicates.add(direct.find('.field-item'));
+
+ if (!predicates.length && !stop) {
+ var parentElement = element.parent(this.options.subjectSelector);
+ if (parentElement.length) {
+ return this.findPredicateElements(subject, parentElement, allowNestedPredicates, true);
+ }
+ }
+
+ return predicates;
+ }
+ };
+
+})(jQuery, _, Drupal, VIE);
diff --git a/js/viejs/SparkEditService.js b/js/viejs/SparkEditService.js
deleted file mode 100644
index ff95266..0000000
--- a/js/viejs/SparkEditService.js
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * @file
- * VIE DOM parsing service for Edit.
- */
-(function(jQuery, _, Drupal, VIE) {
-
-"use strict";
-
- VIE.prototype.SparkEditService = function (options) {
- var defaults = {
- name: 'edit',
- subjectSelector: '.edit-field.edit-allowed'
- };
- this.options = _.extend({}, defaults, options);
-
- this.views = [];
- this.vie = null;
- this.name = this.options.name;
- };
-
- VIE.prototype.SparkEditService.prototype = {
- load: function (loadable) {
- var correct = loadable instanceof this.vie.Loadable;
- if (!correct) {
- throw new Error('Invalid Loadable passed');
- }
-
- var element;
- if (!loadable.options.element) {
- if (typeof document === 'undefined') {
- return loadable.resolve([]);
- } else {
- element = Drupal.settings.edit.context;
- }
- } else {
- element = loadable.options.element;
- }
-
- var entities = this.readEntities(element);
- loadable.resolve(entities);
- },
-
- // The edit-id data attribute contains the full identifier of
- // each entity element in the format
- // `::::`.
- _getID: function (element) {
- var id = jQuery(element).attr('data-edit-id');
- if (!id) {
- id = jQuery(element).closest('[data-edit-id]').attr('data-edit-id');
- }
- return id;
- },
-
- // Returns the "URI" of an entity of an element in format
- // `/`.
- getElementSubject: function (element) {
- return this._getID(element).split(':').slice(0, 2).join('/');
- },
-
- // Returns the field name for an element in format
- // `//`.
- // (Slashes instead of colons because the field name is no namespace.)
- getElementPredicate: function (element) {
- if (!this._getID(element)) {
- throw new Error('Could not find predicate for element');
- }
- return this._getID(element).split(':').slice(2, 5).join('/');
- },
-
- getElementType: function (element) {
- return this._getID(element).split(':').slice(0, 1)[0];
- },
-
- // Reads all editable entities (currently each Drupal field is considered an
- // entity, in the future Drupal entities should be mapped to VIE entities)
- // from DOM and returns the VIE enties it found.
- // @todo: check the above.
- readEntities: function (element) {
- var service = this;
- var entities = [];
- var entityElements = jQuery(this.options.subjectSelector, element);
- entityElements = entityElements.add(jQuery(element).filter(this.options.subjectSelector));
- entityElements.each(function () {
- var entity = service._readEntity(jQuery(this));
- if (entity) {
- entities.push(entity);
- }
- });
- return entities;
- },
-
- // Returns a filled VIE Entity instance for a DOM element. The Entity
- // is also registered in the VIE entities collection.
- _readEntity: function (element) {
- var subject = this.getElementSubject(element);
- var type = this.getElementType(element);
- var entity = this._readEntityPredicates(subject, element, false);
- if (jQuery.isEmptyObject(entity)) {
- return null;
- }
- entity['@subject'] = subject;
- if (type) {
- entity['@type'] = this._registerType(type, element);
- }
-
- // Register with VIE
- return this._registerEntity(entity);
- },
-
- _registerEntity: function (entityData) {
- var entityInstance = new this.vie.Entity(entityData);
- return this.vie.entities.addOrUpdate(entityInstance, {
- updateOptions: {
- silent: true
- }
- });
- },
-
- _registerType: function (typeId, element) {
- typeId = '';
- var type = this.vie.types.get(typeId);
- if (!type) {
- this.vie.types.add(typeId, []);
- type = this.vie.types.get(typeId);
- }
-
- var predicate = this.getElementPredicate(element);
- if (type.attributes.get(predicate)) {
- return type;
- }
-
- var label = element.data('edit-field-label');
- var range = 'Form';
- if (element.hasClass('edit-type-direct')) {
- range = 'Direct';
- }
- if (element.hasClass('edit-type-direct-with-wysiwyg')) {
- range = 'Wysiwyg';
- }
- type.attributes.add(predicate, [range], 0, 1, {
- label: element.data('edit-field-label')
- });
-
- return type;
- },
-
- _readEntityPredicates: function (subject, element, emptyValues) {
- var entityPredicates = {};
- var service = this;
- this.findPredicateElements(subject, element, true).each(function () {
- var predicateElement = jQuery(this);
- var predicate = service.getElementPredicate(predicateElement);
- if (!predicate) {
- return;
- }
- var value = service._readElementValue(predicateElement);
- if (value === null && !emptyValues) {
- return;
- }
-
- entityPredicates[predicate] = value;
- });
- return entityPredicates;
- },
-
- _readElementValue: function (element) {
- return jQuery.trim(element.html());
- },
-
- // Subject elements are the DOM elements containing a single or multiple
- // editable fields. In Spark Edit these elements are called _Fields_,
- // and the actual DOM elements which are edited are called _Editables_.
- findSubjectElements: function (element) {
- if (!element) {
- element = Drupal.settings.edit.context;
- }
- return jQuery(this.options.subjectSelector, element);
- },
-
- // Predicate Elements are the actual DOM elements that users will be able
- // to edit. In regular Spark Edit they are called _Editables_.
- //
- // They are contained within Entity elements, which in Spark Edit are called
- // _Fields_.
- // @todo: clarify and document what the Best Way to do this is? Should VIE's
- // entities map to Drupal's entities etc? Also see higher comments.
- findPredicateElements: function (subject, element, allowNestedPredicates, stop) {
- var predicates = jQuery();
-
- // Form-type predicates
- predicates = predicates.add(element.filter('.edit-type-form'));
-
- // Direct-type predicates
- var direct = element.filter('.edit-type-direct');
- predicates = predicates.add(direct.find('.field-item'));
-
- if (!predicates.length && !stop) {
- var parentElement = element.parent(this.options.subjectSelector);
- if (parentElement.length) {
- return this.findPredicateElements(subject, parentElement, allowNestedPredicates, true);
- }
- }
-
- return predicates;
- }
- };
-
-})(jQuery, _, Drupal, VIE);
diff --git a/js/views/fielddecorator-view.js b/js/views/fielddecorator-view.js
deleted file mode 100644
index 01a4e83..0000000
--- a/js/views/fielddecorator-view.js
+++ /dev/null
@@ -1,324 +0,0 @@
-/**
- * @file
- * A Backbone View that decorates properties.
- *
- * It listens to state changes of the property editor.
- *
- * @todo rename to propertydecorator-view.js + PropertyDecorationView.
- */
-(function($, Backbone, Drupal) {
-
-"use strict";
-
-Drupal.edit = Drupal.edit || {};
-Drupal.edit.views = Drupal.edit.views || {};
-Drupal.edit.views.FieldDecorationView = Backbone.View.extend({
-
- editor: null,
- entity: null,
- predicate : null,
- editorName: null,
- toolbarId: null,
-
- _widthAttributeIsEmpty: null,
-
- events: {
- 'mouseenter.edit' : 'onMouseEnter',
- 'mouseleave.edit' : 'onMouseLeave'
- },
-
- /**
- * Implements Backbone Views' initialize() function.
- *
- * @param options
- * An object with the following keys:
- * - editor: the editor object with an 'options' object that has these keys:
- * * entity: the VIE entity for the property.
- * * property: the predicate of the property.
- * * editorName: the editor name: 'form', 'direct' or
- * 'direct-with-wysiwyg'.
- * * widget: the parent EditableeEntity widget.
- * - toolbarId: the ID attribute of the toolbar as rendered in the DOM.
- */
- initialize: function(options) {
- this.editor = options.editor;
- this.toolbarId = options.toolbarId;
-
- this.entity = this.editor.options.entity;
- this.predicate = this.editor.options.property;
- this.editorName = this.editor.options.editorName;
-
- this.$el.css('background-color', this._getBgColor(this.$el));
- },
-
- /**
- * Listens to editor state changes.
- */
- stateChange: function(from, to) {
- switch (to) {
- case 'inactive':
- if (from !== null) {
- this.undecorate();
- }
- break;
- case 'candidate':
- this.decorate();
- if (from !== 'inactive') {
- this.stopHighlight();
- if (from !== 'highlighted') {
- this.stopEdit(this.editorName);
- }
- }
- break;
- case 'highlighted':
- this.startHighlight();
- break;
- case 'activating':
- // NOTE: this step only exists for the 'form' editor! It is skipped by
- // the 'direct' and 'direct-with-wysiwyg' editors, because no loading is
- // necessary.
- this.prepareEdit(this.editorName);
- break;
- case 'active':
- if (this.editorName !== 'form') {
- this.prepareEdit(this.editorName);
- }
- this.startEdit(this.editorName);
- break;
- case 'changed':
- break;
- case 'saving':
- break;
- case 'saved':
- break;
- case 'invalid':
- break;
- }
- },
-
- /**
- * Starts hover: transition to 'highlight' state.
- *
- * @param event
- */
- onMouseEnter: function(event) {
- var that = this;
- this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
- var editableEntity = that.editor.options.widget;
- editableEntity.setState('highlighted', that.predicate);
- event.stopPropagation();
- });
- },
-
- /**
- * Stops hover: back to 'candidate' state.
- *
- * @param event
- */
- onMouseLeave: function(event) {
- var that = this;
- this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
- var editableEntity = that.editor.options.widget;
- editableEntity.setState('candidate', that.predicate, { reason: 'mouseleave' });
- event.stopPropagation();
- });
- },
-
- decorate: function () {
- this.$el.addClass('edit-animate-fast edit-candidate edit-editable');
- },
-
- undecorate: function () {
- this.$el
- .removeClass('edit-candidate edit-editable edit-highlighted edit-editing edit-belowoverlay');
- },
-
- startHighlight: function () {
- // Animations.
- var that = this;
- setTimeout(function() {
- that.$el.addClass('edit-highlighted');
- }, 0);
- },
-
- stopHighlight: function() {
- this.$el
- .removeClass('edit-highlighted');
- },
-
- prepareEdit: function(editorName) {
- this.$el.addClass('edit-editing');
-
- // While editing, don't show *any* other editors.
- // @todo: revisit this once https://github.com/bergie/create/issues/133 is solved.
- $('.edit-candidate').not('.edit-editing').removeClass('edit-editable');
-
- if (editorName === 'form') {
- this.$el.addClass('edit-belowoverlay');
- }
- },
-
- startEdit: function(editorName) {
- if (editorName !== 'form') {
- this._pad();
- }
- },
-
- stopEdit: function(editorName) {
- this.$el.removeClass('edit-highlighted edit-editing');
-
- // Make the other editors show up again.
- // @todo: revisit this once https://github.com/bergie/create/issues/133 is solved.
- $('.edit-candidate').addClass('edit-editable');
-
- if (editorName === 'form') {
- this.$el.removeClass('edit-belowoverlay');
- }
- else {
- this._unpad();
- }
- },
-
- _pad: function () {
- var self = this;
-
- // Add 5px padding for readability. This means we'll freeze the current
- // width and *then* add 5px padding, hence ensuring the padding is added "on
- // the outside".
- // 1) Freeze the width (if it's not already set); don't use animations.
- if (this.$el[0].style.width === "") {
- this._widthAttributeIsEmpty = true;
- this.$el
- .addClass('edit-animate-disable-width')
- .css('width', this.$el.width());
- }
-
- // 2) Add padding; use animations.
- var posProp = this._getPositionProperties(this.$el);
- setTimeout(function() {
- // Re-enable width animations (padding changes affect width too!).
- self.$el.removeClass('edit-animate-disable-width');
-
- // Pad the editable.
- self.$el
- .css({
- 'position': 'relative',
- 'top': posProp.top - 5 + 'px',
- 'left': posProp.left - 5 + 'px',
- 'padding-top' : posProp['padding-top'] + 5 + 'px',
- 'padding-left' : posProp['padding-left'] + 5 + 'px',
- 'padding-right' : posProp['padding-right'] + 5 + 'px',
- 'padding-bottom': posProp['padding-bottom'] + 5 + 'px',
- 'margin-bottom': posProp['margin-bottom'] - 10 + 'px'
- });
- }, 0);
- },
-
- _unpad: function () {
- var self = this;
-
- // 1) Set the empty width again.
- if (this._widthAttributeIsEmpty) {
- this.$el
- .addClass('edit-animate-disable-width')
- .css('width', '');
- }
-
- // 2) Remove padding; use animations (these will run simultaneously with)
- // the fading out of the toolbar as its gets removed).
- var posProp = this._getPositionProperties(this.$el);
- setTimeout(function() {
- // Re-enable width animations (padding changes affect width too!).
- self.$el.removeClass('edit-animate-disable-width');
-
- // Unpad the editable.
- self.$el
- .css({
- 'position': 'relative',
- 'top': posProp.top + 5 + 'px',
- 'left': posProp.left + 5 + 'px',
- 'padding-top' : posProp['padding-top'] - 5 + 'px',
- 'padding-left' : posProp['padding-left'] - 5 + 'px',
- 'padding-right' : posProp['padding-right'] - 5 + 'px',
- 'padding-bottom': posProp['padding-bottom'] - 5 + 'px',
- 'margin-bottom': posProp['margin-bottom'] + 10 + 'px'
- });
- }, 0);
- },
-
- /**
- * Gets the background color of an element (or the inherited one).
- *
- * @param $e
- * A DOM element.
- */
- _getBgColor: function($e) {
- var c;
-
- if ($e === null || $e[0].nodeName === 'HTML') {
- // Fallback to white.
- return 'rgb(255, 255, 255)';
- }
- c = $e.css('background-color');
- // TRICKY: edge case for Firefox' "transparent" here; this is a
- // browser bug: https://bugzilla.mozilla.org/show_bug.cgi?id=635724
- if (c === 'rgba(0, 0, 0, 0)' || c === 'transparent') {
- return this._getBgColor($e.parent());
- }
- return c;
- },
-
- /**
- * Gets the top and left properties of an element and convert extraneous
- * values and information into numbers ready for subtraction.
- *
- * @param $e
- * A DOM element.
- */
- _getPositionProperties: function($e) {
- var p,
- r = {},
- props = [
- 'top', 'left', 'bottom', 'right',
- 'padding-top', 'padding-left', 'padding-right', 'padding-bottom',
- 'margin-bottom'
- ];
-
- var propCount = props.length;
- for (var i = 0; i < propCount; i++) {
- p = props[i];
- r[p] = parseInt(this._replaceBlankPosition($e.css(p)), 10);
- }
- return r;
- },
-
- /**
- * Replaces blank or 'auto' CSS "position: " values with "0px".
- *
- * @param pos
- * The value for a CSS position declaration.
- */
- _replaceBlankPosition: function(pos) {
- // @todo: this was pos == NaN (which always returns false, keeping this
- // comment in case we find a regression.
- if (pos === 'auto' || !pos) {
- pos = '0px';
- }
- return pos;
- },
-
- /**
- * Ignores hovering to/from the given closest element, but as soon as a hover
- * occurs to/from *another* element, then call the given callback.
- */
- _ignoreHoveringVia: function(event, closest, callback) {
- if ($(event.relatedTarget).closest(closest).length > 0) {
- event.stopPropagation();
- }
- else {
- callback();
- }
- }
-});
-
-})(jQuery, Backbone, Drupal);
diff --git a/js/views/overlay-view.js b/js/views/overlay-view.js
index d41f091..e545087 100644
--- a/js/views/overlay-view.js
+++ b/js/views/overlay-view.js
@@ -75,8 +75,6 @@ Drupal.edit.views.OverlayView = Backbone.View.extend({
.addClass('edit-animate-invisible')
.bind(Drupal.edit.util.constants.transitionEnd, function (event) {
that.$el.remove();
- // @todo - should the overlay really do this?
- $('.edit-form-container, .edit-toolbar-container, #edit_modal, .edit-curtain, .edit-validation-errors').remove();
});
}
});
diff --git a/js/views/propertyeditordecoration-view.js b/js/views/propertyeditordecoration-view.js
new file mode 100644
index 0000000..7d8a27c
--- /dev/null
+++ b/js/views/propertyeditordecoration-view.js
@@ -0,0 +1,322 @@
+/**
+ * @file
+ * A Backbone View that decorates a Property Editor widget.
+ *
+ * It listens to state changes of the property editor.
+ */
+(function($, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+Drupal.edit.views = Drupal.edit.views || {};
+Drupal.edit.views.PropertyEditorDecorationView = Backbone.View.extend({
+
+ editor: null,
+ entity: null,
+ predicate : null,
+ editorName: null,
+ toolbarId: null,
+
+ _widthAttributeIsEmpty: null,
+
+ events: {
+ 'mouseenter.edit' : 'onMouseEnter',
+ 'mouseleave.edit' : 'onMouseLeave'
+ },
+
+ /**
+ * Implements Backbone Views' initialize() function.
+ *
+ * @param options
+ * An object with the following keys:
+ * - editor: the editor object with an 'options' object that has these keys:
+ * * entity: the VIE entity for the property.
+ * * property: the predicate of the property.
+ * * editorName: the editor name: 'form', 'direct' or
+ * 'direct-with-wysiwyg'.
+ * * widget: the parent EditableeEntity widget.
+ * - toolbarId: the ID attribute of the toolbar as rendered in the DOM.
+ */
+ initialize: function(options) {
+ this.editor = options.editor;
+ this.toolbarId = options.toolbarId;
+
+ this.entity = this.editor.options.entity;
+ this.predicate = this.editor.options.property;
+ this.editorName = this.editor.options.editorName;
+
+ this.$el.css('background-color', this._getBgColor(this.$el));
+ },
+
+ /**
+ * Listens to editor state changes.
+ */
+ stateChange: function(from, to) {
+ switch (to) {
+ case 'inactive':
+ if (from !== null) {
+ this.undecorate();
+ }
+ break;
+ case 'candidate':
+ this.decorate();
+ if (from !== 'inactive') {
+ this.stopHighlight();
+ if (from !== 'highlighted') {
+ this.stopEdit(this.editorName);
+ }
+ }
+ break;
+ case 'highlighted':
+ this.startHighlight();
+ break;
+ case 'activating':
+ // NOTE: this step only exists for the 'form' editor! It is skipped by
+ // the 'direct' and 'direct-with-wysiwyg' editors, because no loading is
+ // necessary.
+ this.prepareEdit(this.editorName);
+ break;
+ case 'active':
+ if (this.editorName !== 'form') {
+ this.prepareEdit(this.editorName);
+ }
+ this.startEdit(this.editorName);
+ break;
+ case 'changed':
+ break;
+ case 'saving':
+ break;
+ case 'saved':
+ break;
+ case 'invalid':
+ break;
+ }
+ },
+
+ /**
+ * Starts hover: transition to 'highlight' state.
+ *
+ * @param event
+ */
+ onMouseEnter: function(event) {
+ var that = this;
+ this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
+ var editableEntity = that.editor.options.widget;
+ editableEntity.setState('highlighted', that.predicate);
+ event.stopPropagation();
+ });
+ },
+
+ /**
+ * Stops hover: back to 'candidate' state.
+ *
+ * @param event
+ */
+ onMouseLeave: function(event) {
+ var that = this;
+ this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
+ var editableEntity = that.editor.options.widget;
+ editableEntity.setState('candidate', that.predicate, { reason: 'mouseleave' });
+ event.stopPropagation();
+ });
+ },
+
+ decorate: function () {
+ this.$el.addClass('edit-animate-fast edit-candidate edit-editable');
+ },
+
+ undecorate: function () {
+ this.$el
+ .removeClass('edit-candidate edit-editable edit-highlighted edit-editing edit-belowoverlay');
+ },
+
+ startHighlight: function () {
+ // Animations.
+ var that = this;
+ setTimeout(function() {
+ that.$el.addClass('edit-highlighted');
+ }, 0);
+ },
+
+ stopHighlight: function() {
+ this.$el
+ .removeClass('edit-highlighted');
+ },
+
+ prepareEdit: function(editorName) {
+ this.$el.addClass('edit-editing');
+
+ // While editing, don't show *any* other editors.
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
+ // Revisit this.
+ $('.edit-candidate').not('.edit-editing').removeClass('edit-editable');
+
+ if (editorName === 'form') {
+ this.$el.addClass('edit-belowoverlay');
+ }
+ },
+
+ startEdit: function(editorName) {
+ if (editorName !== 'form') {
+ this._pad();
+ }
+ },
+
+ stopEdit: function(editorName) {
+ this.$el.removeClass('edit-highlighted edit-editing');
+
+ // Make the other editors show up again.
+ // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
+ // Revisit this.
+ $('.edit-candidate').addClass('edit-editable');
+
+ if (editorName === 'form') {
+ this.$el.removeClass('edit-belowoverlay');
+ }
+ else {
+ this._unpad();
+ }
+ },
+
+ _pad: function () {
+ var self = this;
+
+ // Add 5px padding for readability. This means we'll freeze the current
+ // width and *then* add 5px padding, hence ensuring the padding is added "on
+ // the outside".
+ // 1) Freeze the width (if it's not already set); don't use animations.
+ if (this.$el[0].style.width === "") {
+ this._widthAttributeIsEmpty = true;
+ this.$el
+ .addClass('edit-animate-disable-width')
+ .css('width', this.$el.width());
+ }
+
+ // 2) Add padding; use animations.
+ var posProp = this._getPositionProperties(this.$el);
+ setTimeout(function() {
+ // Re-enable width animations (padding changes affect width too!).
+ self.$el.removeClass('edit-animate-disable-width');
+
+ // Pad the editable.
+ self.$el
+ .css({
+ 'position': 'relative',
+ 'top': posProp.top - 5 + 'px',
+ 'left': posProp.left - 5 + 'px',
+ 'padding-top' : posProp['padding-top'] + 5 + 'px',
+ 'padding-left' : posProp['padding-left'] + 5 + 'px',
+ 'padding-right' : posProp['padding-right'] + 5 + 'px',
+ 'padding-bottom': posProp['padding-bottom'] + 5 + 'px',
+ 'margin-bottom': posProp['margin-bottom'] - 10 + 'px'
+ });
+ }, 0);
+ },
+
+ _unpad: function () {
+ var self = this;
+
+ // 1) Set the empty width again.
+ if (this._widthAttributeIsEmpty) {
+ this.$el
+ .addClass('edit-animate-disable-width')
+ .css('width', '');
+ }
+
+ // 2) Remove padding; use animations (these will run simultaneously with)
+ // the fading out of the toolbar as its gets removed).
+ var posProp = this._getPositionProperties(this.$el);
+ setTimeout(function() {
+ // Re-enable width animations (padding changes affect width too!).
+ self.$el.removeClass('edit-animate-disable-width');
+
+ // Unpad the editable.
+ self.$el
+ .css({
+ 'position': 'relative',
+ 'top': posProp.top + 5 + 'px',
+ 'left': posProp.left + 5 + 'px',
+ 'padding-top' : posProp['padding-top'] - 5 + 'px',
+ 'padding-left' : posProp['padding-left'] - 5 + 'px',
+ 'padding-right' : posProp['padding-right'] - 5 + 'px',
+ 'padding-bottom': posProp['padding-bottom'] - 5 + 'px',
+ 'margin-bottom': posProp['margin-bottom'] + 10 + 'px'
+ });
+ }, 0);
+ },
+
+ /**
+ * Gets the background color of an element (or the inherited one).
+ *
+ * @param $e
+ * A DOM element.
+ */
+ _getBgColor: function($e) {
+ var c;
+
+ if ($e === null || $e[0].nodeName === 'HTML') {
+ // Fallback to white.
+ return 'rgb(255, 255, 255)';
+ }
+ c = $e.css('background-color');
+ // TRICKY: edge case for Firefox' "transparent" here; this is a
+ // browser bug: https://bugzilla.mozilla.org/show_bug.cgi?id=635724
+ if (c === 'rgba(0, 0, 0, 0)' || c === 'transparent') {
+ return this._getBgColor($e.parent());
+ }
+ return c;
+ },
+
+ /**
+ * Gets the top and left properties of an element and convert extraneous
+ * values and information into numbers ready for subtraction.
+ *
+ * @param $e
+ * A DOM element.
+ */
+ _getPositionProperties: function($e) {
+ var p,
+ r = {},
+ props = [
+ 'top', 'left', 'bottom', 'right',
+ 'padding-top', 'padding-left', 'padding-right', 'padding-bottom',
+ 'margin-bottom'
+ ];
+
+ var propCount = props.length;
+ for (var i = 0; i < propCount; i++) {
+ p = props[i];
+ r[p] = parseInt(this._replaceBlankPosition($e.css(p)), 10);
+ }
+ return r;
+ },
+
+ /**
+ * Replaces blank or 'auto' CSS "position: " values with "0px".
+ *
+ * @param pos
+ * The value for a CSS position declaration.
+ */
+ _replaceBlankPosition: function(pos) {
+ if (pos === 'auto' || !pos) {
+ pos = '0px';
+ }
+ return pos;
+ },
+
+ /**
+ * Ignores hovering to/from the given closest element, but as soon as a hover
+ * occurs to/from *another* element, then call the given callback.
+ */
+ _ignoreHoveringVia: function(event, closest, callback) {
+ if ($(event.relatedTarget).closest(closest).length > 0) {
+ event.stopPropagation();
+ }
+ else {
+ callback();
+ }
+ }
+});
+
+})(jQuery, Backbone, Drupal);
diff --git a/js/views/toolbar-view.js b/js/views/toolbar-view.js
index 55b5da3..c31791a 100644
--- a/js/views/toolbar-view.js
+++ b/js/views/toolbar-view.js
@@ -140,7 +140,9 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
var $inner = $(updatedField).html();
editor.element.html($inner);
- // @todo: VIE doesn't seem to like this? :) It seems that if I delete/
+ // @todo BLOCKED_ON(VIE.js, how to let VIE know that some content was removed and how to scan new content for VIE entities, to make them editable?)
+ // Also see Drupal.behaviors.editDiscoverEditables.
+ // VIE doesn't seem to like this? :) It seems that if I delete/
// overwrite an existing field, that VIE refuses to find the same
// predicate again for the same entity?
// self.$el.replaceWith(updatedField);
@@ -285,7 +287,7 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
/**
* Adjusts the toolbar to accomodate padding on the PropertyEditor widget.
*
- * @see FieldDecorationView._pad().
+ * @see PropertyEditorDecorationView._pad().
*/
_pad: function(editorName) {
// The whole toolbar must move to the top when the property's DOM element
@@ -307,7 +309,7 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
/**
* Undoes the changes made by _pad().
*
- * @see FieldDecorationView._unpad().
+ * @see PropertyEditorDecorationView._unpad().
*/
_unpad: function(editorName) {
// Move the toolbar back to its original position.
@@ -385,11 +387,6 @@ Drupal.edit.views.ToolbarView = Backbone.View.extend({
.bind(Drupal.edit.util.constants.transitionEnd, function (e) {
$el.remove();
});
- // @todo: verify/confirm that this really necessary. Messing with this.$el
- // is not recommended - maybe temporarily unbind/undelegate events?
- // Immediately set to null, so that if the user hovers over the property
- // before the removal been completed, a new toolbar can be created.
- // this.$el = null;
},
/**
diff --git a/vie-and-create.patch b/vie-and-create.patch
new file mode 100644
index 0000000..a050e04
--- /dev/null
+++ b/vie-and-create.patch
@@ -0,0 +1,5401 @@
+ core/misc/create/create-editonly.js | 1643 ++++++++++++++++
+ core/misc/vie/vie-core.js | 3682 +++++++++++++++++++++++++++++++++++
+ core/modules/system/system.module | 33 +-
+ 3 files changed, 5356 insertions(+), 2 deletions(-)
+
+diff --git a/core/misc/create/create-editonly.js b/core/misc/create/create-editonly.js
+new file mode 100644
+index 0000000..1d76bff
+--- /dev/null
++++ b/core/misc/create/create-editonly.js
+@@ -0,0 +1,1643 @@
++// Create.js - On-site web editing interface
++// (c) 2011-2012 Henri Bergius, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false window:false console:false */
++ 'use strict';
++
++ // # Widget for adding items to a collection
++ jQuery.widget('Midgard.midgardCollectionAdd', {
++ options: {
++ editingWidgets: null,
++ collection: null,
++ model: null,
++ definition: null,
++ view: null,
++ disabled: false,
++ vie: null,
++ editableOptions: null,
++ templates: {
++ button: ''
++ }
++ },
++
++ _create: function () {
++ this.addButtons = [];
++ var widget = this;
++ if (!widget.options.collection.localStorage) {
++ try {
++ widget.options.collection.url = widget.options.model.url();
++ } catch (e) {
++ if (window.console) {
++ console.log(e);
++ }
++ }
++ }
++
++ widget.options.collection.bind('add', function (model) {
++ model.primaryCollection = widget.options.collection;
++ widget.options.vie.entities.add(model);
++ model.collection = widget.options.collection;
++ });
++
++ // Re-check collection constraints
++ widget.options.collection.bind('add remove reset', widget.checkCollectionConstraints, widget);
++
++ widget._bindCollectionView(widget.options.view);
++ },
++
++ _bindCollectionView: function (view) {
++ var widget = this;
++ view.bind('add', function (itemView) {
++ itemView.$el.effect('slide', function () {
++ widget._makeEditable(itemView);
++ });
++ });
++ },
++
++ _makeEditable: function (itemView) {
++ this.options.editableOptions.disabled = this.options.disabled;
++ this.options.editableOptions.model = itemView.model;
++ itemView.$el.midgardEditable(this.options.editableOptions);
++ },
++
++ _init: function () {
++ if (this.options.disabled) {
++ this.disable();
++ return;
++ }
++ this.enable();
++ },
++
++ hideButtons: function () {
++ _.each(this.addButtons, function (button) {
++ button.hide();
++ });
++ },
++
++ showButtons: function () {
++ _.each(this.addButtons, function (button) {
++ button.show();
++ });
++ },
++
++ checkCollectionConstraints: function () {
++ if (this.options.disabled) {
++ return;
++ }
++
++ if (!this.options.view.canAdd()) {
++ this.hideButtons();
++ return;
++ }
++
++ if (!this.options.definition) {
++ // We have now information on the constraints applying to this collection
++ this.showButtons();
++ return;
++ }
++
++ if (!this.options.definition.max || this.options.definition.max === -1) {
++ // No maximum constraint
++ this.showButtons();
++ return;
++ }
++
++ if (this.options.collection.length < this.options.definition.max) {
++ this.showButtons();
++ return;
++ }
++ // Collection is already full by its definition
++ this.hideButtons();
++ },
++
++ enable: function () {
++ var widget = this;
++
++ var addButton = jQuery(_.template(this.options.templates.button, {
++ icon: 'plus',
++ label: this.options.editableOptions.localize('Add', this.options.editableOptions.language)
++ })).button();
++ addButton.addClass('midgard-create-add');
++ addButton.click(function () {
++ widget.addItem(addButton);
++ });
++ jQuery(widget.options.view.el).after(addButton);
++
++ widget.addButtons.push(addButton);
++ widget.checkCollectionConstraints();
++ },
++
++ disable: function () {
++ _.each(this.addButtons, function (button) {
++ button.remove();
++ });
++ this.addButtons = [];
++ },
++
++ _getTypeActions: function (options) {
++ var widget = this;
++ var actions = [];
++ _.each(this.options.definition.range, function (type) {
++ var nsType = widget.options.collection.vie.namespaces.uri(type);
++ if (!widget.options.view.canAdd(nsType)) {
++ return;
++ }
++ actions.push({
++ name: type,
++ label: type,
++ cb: function () {
++ widget.options.collection.add({
++ '@type': type
++ }, options);
++ },
++ className: 'create-ui-btn'
++ });
++ });
++ return actions;
++ },
++
++ addItem: function (button, options) {
++ if (options === undefined) {
++ options = {};
++ }
++ var addOptions = _.extend({}, options, { validate: false });
++
++ var itemData = {};
++ if (this.options.definition && this.options.definition.range) {
++ if (this.options.definition.range.length === 1) {
++ // Items can be of single type, add that
++ itemData['@type'] = this.options.definition.range[0];
++ } else {
++ // Ask user which type to add
++ jQuery('body').midgardNotifications('create', {
++ bindTo: button,
++ gravity: 'L',
++ body: this.options.editableOptions.localize('Choose type to add', this.options.editableOptions.language),
++ timeout: 0,
++ actions: this._getTypeActions(addOptions)
++ });
++ return;
++ }
++ } else {
++ // Check the view templates for possible non-Thing type to use
++ var keys = _.keys(this.options.view.templates);
++ if (keys.length == 2) {
++ itemData['@type'] = keys[0];
++ }
++ }
++ this.options.collection.add(itemData, addOptions);
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2011-2012 Henri Bergius, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false window:false console:false */
++ 'use strict';
++
++ // # Widget for adding items anywhere inside a collection
++ jQuery.widget('Midgard.midgardCollectionAddBetween', jQuery.Midgard.midgardCollectionAdd, {
++ _bindCollectionView: function (view) {
++ var widget = this;
++ view.bind('add', function (itemView) {
++ //itemView.el.effect('slide');
++ widget._makeEditable(itemView);
++ widget._refreshButtons();
++ });
++ view.bind('remove', function () {
++ widget._refreshButtons();
++ });
++ },
++
++ _refreshButtons: function () {
++ var widget = this;
++ window.setTimeout(function () {
++ widget.disable();
++ widget.enable();
++ }, 1);
++ },
++
++ prepareButton: function (index) {
++ var widget = this;
++ var addButton = jQuery(_.template(this.options.templates.button, {
++ icon: 'plus',
++ label: ''
++ })).button();
++ addButton.addClass('midgard-create-add');
++ addButton.click(function () {
++ widget.addItem(addButton, {
++ at: index
++ });
++ });
++ return addButton;
++ },
++
++ enable: function () {
++ var widget = this;
++
++ var firstAddButton = widget.prepareButton(0);
++ jQuery(widget.options.view.el).prepend(firstAddButton);
++ widget.addButtons.push(firstAddButton);
++ jQuery.each(widget.options.view.entityViews, function (cid, view) {
++ var index = widget.options.collection.indexOf(view.model);
++ var addButton = widget.prepareButton(index + 1);
++ jQuery(view.el).append(addButton);
++ widget.addButtons.push(addButton);
++ });
++
++ this.checkCollectionConstraints();
++ },
++
++ disable: function () {
++ var widget = this;
++ jQuery.each(widget.addButtons, function (idx, button) {
++ button.remove();
++ });
++ widget.addButtons = [];
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2011-2012 Henri Bergius, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false window:false VIE:false */
++ 'use strict';
++
++ // Define Create's EditableEntity widget.
++ jQuery.widget('Midgard.midgardEditable', {
++ options: {
++ propertyEditors: {},
++ collections: [],
++ model: null,
++ // the configuration (mapping and options) of property editor widgets
++ propertyEditorWidgetsConfiguration: {
++ hallo: {
++ widget: 'halloWidget',
++ options: {}
++ }
++ },
++ // the available property editor widgets by data type
++ propertyEditorWidgets: {
++ 'default': 'hallo'
++ },
++ collectionWidgets: {
++ 'default': 'midgardCollectionAdd'
++ },
++ toolbarState: 'full',
++ vie: null,
++ domService: 'rdfa',
++ predicateSelector: '[property]',
++ disabled: false,
++ localize: function (id, language) {
++ return window.midgardCreate.localize(id, language);
++ },
++ language: null,
++ // Current state of the Editable
++ state: null,
++ // Callback function for validating changes between states. Receives the previous state, new state, possibly property, and a callback
++ acceptStateChange: true,
++ // Callback function for listening (and reacting) to state changes.
++ stateChange: null,
++ // Callback function for decorating the full editable. Will be called on instantiation
++ decorateEditableEntity: null,
++ // Callback function for decorating a single property editor widget. Will
++ // be called on editing widget instantiation.
++ decoratePropertyEditor: null,
++
++ // Deprecated.
++ editables: [], // Now `propertyEditors`.
++ editors: {}, // Now `propertyEditorWidgetsConfiguration`.
++ widgets: {} // Now `propertyEditorW
++ },
++
++ // Aids in consistently passing parameters to events and callbacks.
++ _params: function(predicate, extended) {
++ var entityParams = {
++ entity: this.options.model,
++ editableEntity: this,
++ entityElement: this.element,
++
++ // Deprecated.
++ editable: this,
++ element: this.element,
++ instance: this.options.model
++ };
++
++ var propertyParams = (predicate) ? {
++ predicate: predicate,
++ propertyEditor: this.options.propertyEditors[predicate],
++ propertyElement: this.options.propertyEditors[predicate].element,
++
++ // Deprecated.
++ property: predicate,
++ element: this.options.propertyEditors[predicate].element
++ } : {};
++
++ return _.extend(entityParams, propertyParams, extended);
++ },
++
++ _create: function () {
++ // Backwards compatibility:
++ // - this.options.propertyEditorWidgets used to be this.options.widgets
++ // - this.options.propertyEditorWidgetsConfiguration used to be
++ // this.options.editors
++ if (this.options.widgets) {
++ this.options.propertyEditorWidgets = _.extend(this.options.propertyEditorWidgets, this.options.widgets);
++ }
++ if (this.options.editors) {
++ this.options.propertyEditorWidgetsConfiguration = _.extend(this.options.propertyEditorWidgetsConfiguration, this.options.editors);
++ }
++
++ this.vie = this.options.vie;
++ this.domService = this.vie.service(this.options.domService);
++ if (!this.options.model) {
++ var widget = this;
++ this.vie.load({
++ element: this.element
++ }).from(this.options.domService).execute().done(function (entities) {
++ widget.options.model = entities[0];
++ });
++ }
++ if (_.isFunction(this.options.decorateEditableEntity)) {
++ this.options.decorateEditableEntity(this._params());
++ }
++ },
++
++ _init: function () {
++ // Backwards compatibility:
++ // - this.options.propertyEditorWidgets used to be this.options.widgets
++ // - this.options.propertyEditorWidgetsConfiguration used to be
++ // this.options.editors
++ if (this.options.widgets) {
++ this.options.propertyEditorWidgets = _.extend(this.options.propertyEditorWidgets, this.options.widgets);
++ }
++ if (this.options.editors) {
++ this.options.propertyEditorWidgetsConfiguration = _.extend(this.options.propertyEditorWidgetsConfiguration, this.options.editors);
++ }
++
++ // Old way of setting the widget inactive
++ if (this.options.disabled === true) {
++ this.setState('inactive');
++ return;
++ }
++
++ if (this.options.disabled === false && this.options.state === 'inactive') {
++ this.setState('candidate');
++ return;
++ }
++ this.options.disabled = false;
++
++ if (this.options.state) {
++ this.setState(this.options.state);
++ return;
++ }
++ this.setState('candidate');
++ },
++
++ // Method used for cycling between the different states of the Editable widget:
++ //
++ // * Inactive: editable is loaded but disabled
++ // * Candidate: editable is enabled but not activated
++ // * Highlight: user is hovering over the editable (not set by Editable widget directly)
++ // * Activating: an editor widget is being activated for user to edit with it (skipped for editors that activate instantly)
++ // * Active: user is actually editing something inside the editable
++ // * Changed: user has made changes to the editable
++ // * Invalid: the contents of the editable have validation errors
++ //
++ // In situations where state changes are triggered for a particular property editor, the `predicate`
++ // argument will provide the name of that property.
++ //
++ // State changes may carry optional context information in a JavaScript object. The payload of these context objects is not
++ // standardized, and is meant to be set and used by the application controller
++ //
++ // The callback parameter is optional and will be invoked after a state change has been accepted (after the 'statechange'
++ // event) or rejected.
++ setState: function (state, predicate, context, callback) {
++ var previous = this.options.state;
++ var current = state;
++ if (current === previous) {
++ return;
++ }
++
++ if (this.options.acceptStateChange === undefined || !_.isFunction(this.options.acceptStateChange)) {
++ // Skip state transition validation
++ this._doSetState(previous, current, predicate, context);
++ if (_.isFunction(callback)) {
++ callback(true);
++ }
++ return;
++ }
++
++ var widget = this;
++ this.options.acceptStateChange(previous, current, predicate, context, function (accepted) {
++ if (accepted) {
++ widget._doSetState(previous, current, predicate, context);
++ }
++ if (_.isFunction(callback)) {
++ callback(accepted);
++ }
++ return;
++ });
++ },
++
++ getState: function () {
++ return this.options.state;
++ },
++
++ _doSetState: function (previous, current, predicate, context) {
++ this.options.state = current;
++ if (current === 'inactive') {
++ this.disable();
++ } else if ((previous === null || previous === 'inactive') && current !== 'inactive') {
++ this.enable();
++ }
++
++ this._trigger('statechange', null, this._params(predicate, {
++ previous: previous,
++ current: current,
++ context: context
++ }));
++ },
++
++ findEditablePredicateElements: function (callback) {
++ this.domService.findPredicateElements(this.options.model.id, jQuery(this.options.predicateSelector, this.element), false).each(callback);
++ },
++
++ getElementPredicate: function (element) {
++ return this.domService.getElementPredicate(element);
++ },
++
++ enable: function () {
++ var editableEntity = this;
++ if (!this.options.model) {
++ return;
++ }
++
++ this.findEditablePredicateElements(function () {
++ editableEntity._enablePropertyEditor(jQuery(this));
++ });
++
++ this._trigger('enable', null, this._params());
++
++ _.each(this.domService.views, function (view) {
++ if (view instanceof this.vie.view.Collection && this.options.model === view.owner) {
++ var predicate = view.collection.predicate;
++ var editableOptions = _.clone(this.options);
++ editableOptions.state = null;
++ var collection = this.enableCollection({
++ model: this.options.model,
++ collection: view.collection,
++ property: predicate,
++ definition: this.getAttributeDefinition(predicate),
++ view: view,
++ element: view.el,
++ vie: editableEntity.vie,
++ editableOptions: editableOptions
++ });
++ editableEntity.options.collections.push(collection);
++ }
++ }, this);
++ },
++
++ disable: function () {
++ _.each(this.options.propertyEditors, function (editable) {
++ this.disableEditor({
++ widget: this,
++ editable: editable,
++ entity: this.options.model,
++ element: jQuery(editable)
++ });
++ }, this);
++ this.options.propertyEditors = {};
++
++ // Deprecated.
++ this.options.editables = [];
++
++ _.each(this.options.collections, function (collectionWidget) {
++ var editableOptions = _.clone(this.options);
++ editableOptions.state = 'inactive';
++ this.disableCollection({
++ widget: this,
++ model: this.options.model,
++ element: collectionWidget,
++ vie: this.vie,
++ editableOptions: editableOptions
++ });
++ }, this);
++ this.options.collections = [];
++
++ this._trigger('disable', null, this._params());
++ },
++
++ _enablePropertyEditor: function (element) {
++ var widget = this;
++ var predicate = this.getElementPredicate(element);
++ if (!predicate) {
++ return true;
++ }
++ if (this.options.model.get(predicate) instanceof Array) {
++ // For now we don't deal with multivalued properties in the editable
++ return true;
++ }
++
++ var propertyElement = this.enablePropertyEditor({
++ widget: this,
++ element: element,
++ entity: this.options.model,
++ property: predicate,
++ vie: this.vie,
++ decorate: this.options.decoratePropertyEditor,
++ decorateParams: _.bind(this._params, this),
++ changed: function (content) {
++ widget.setState('changed', predicate);
++
++ var changedProperties = {};
++ changedProperties[predicate] = content;
++ widget.options.model.set(changedProperties, {
++ silent: true
++ });
++
++ widget._trigger('changed', null, widget._params(predicate));
++ },
++ activating: function () {
++ widget.setState('activating', predicate);
++ },
++ activated: function () {
++ widget.setState('active', predicate);
++ widget._trigger('activated', null, widget._params(predicate));
++ },
++ deactivated: function () {
++ widget.setState('candidate', predicate);
++ widget._trigger('deactivated', null, widget._params(predicate));
++ }
++ });
++
++ if (!propertyElement) {
++ return;
++ }
++ var widgetType = propertyElement.data('createWidgetName');
++ this.options.propertyEditors[predicate] = propertyElement.data(widgetType);
++
++ // Deprecated.
++ this.options.editables.push(propertyElement);
++
++ this._trigger('enableproperty', null, this._params(predicate));
++ },
++
++ // returns the name of the property editor widget to use for the given property
++ _propertyEditorName: function (data) {
++ if (this.options.propertyEditorWidgets[data.property] !== undefined) {
++ // Property editor widget configuration set for specific RDF predicate
++ return this.options.propertyEditorWidgets[data.property];
++ }
++
++ // Load the property editor widget configuration for the data type
++ var propertyType = 'default';
++ var attributeDefinition = this.getAttributeDefinition(data.property);
++ if (attributeDefinition) {
++ propertyType = attributeDefinition.range[0];
++ }
++ if (this.options.propertyEditorWidgets[propertyType] !== undefined) {
++ return this.options.propertyEditorWidgets[propertyType];
++ }
++ return this.options.propertyEditorWidgets['default'];
++ },
++
++ _propertyEditorWidget: function (editor) {
++ return this.options.propertyEditorWidgetsConfiguration[editor].widget;
++ },
++
++ _propertyEditorOptions: function (editor) {
++ return this.options.propertyEditorWidgetsConfiguration[editor].options;
++ },
++
++ getAttributeDefinition: function (property) {
++ var type = this.options.model.get('@type');
++ if (!type) {
++ return;
++ }
++ if (!type.attributes) {
++ return;
++ }
++ return type.attributes.get(property);
++ },
++
++ // Deprecated.
++ enableEditor: function (data) {
++ return this.enablePropertyEditor(data);
++ },
++
++ enablePropertyEditor: function (data) {
++ var editorName = this._propertyEditorName(data);
++ if (editorName === null) {
++ return;
++ }
++
++ var editorWidget = this._propertyEditorWidget(editorName);
++
++ data.editorOptions = this._propertyEditorOptions(editorName);
++ data.toolbarState = this.options.toolbarState;
++ data.disabled = false;
++ // Pass metadata that could be useful for some implementations.
++ data.editorName = editorName;
++ data.editorWidget = editorWidget;
++
++ if (typeof jQuery(data.element)[editorWidget] !== 'function') {
++ throw new Error(editorWidget + ' widget is not available');
++ }
++
++ jQuery(data.element)[editorWidget](data);
++ jQuery(data.element).data('createWidgetName', editorWidget);
++ return jQuery(data.element);
++ },
++
++ // Deprecated.
++ disableEditor: function (data) {
++ return this.disablePropertyEditor(data);
++ },
++
++ disablePropertyEditor: function (data) {
++ var widgetName = jQuery(data.element).data('createWidgetName');
++
++ data.disabled = true;
++
++ if (widgetName) {
++ // only if there has been an editing widget registered
++ jQuery(data.element)[widgetName](data);
++ jQuery(data.element).removeClass('ui-state-disabled');
++
++ if (data.element.is(':focus')) {
++ data.element.blur();
++ }
++ }
++ },
++
++ collectionWidgetName: function (data) {
++ if (this.options.collectionWidgets[data.property] !== undefined) {
++ // Widget configuration set for specific RDF predicate
++ return this.options.collectionWidgets[data.property];
++ }
++
++ var propertyType = 'default';
++ var attributeDefinition = this.getAttributeDefinition(data.property);
++ if (attributeDefinition) {
++ propertyType = attributeDefinition.range[0];
++ }
++ if (this.options.collectionWidgets[propertyType] !== undefined) {
++ return this.options.collectionWidgets[propertyType];
++ }
++ return this.options.collectionWidgets['default'];
++ },
++
++ enableCollection: function (data) {
++ var widgetName = this.collectionWidgetName(data);
++ if (widgetName === null) {
++ return;
++ }
++ data.disabled = false;
++ if (typeof jQuery(data.element)[widgetName] !== 'function') {
++ throw new Error(widgetName + ' widget is not available');
++ }
++ jQuery(data.element)[widgetName](data);
++ jQuery(data.element).data('createCollectionWidgetName', widgetName);
++ return jQuery(data.element);
++ },
++
++ disableCollection: function (data) {
++ var widgetName = jQuery(data.element).data('createCollectionWidgetName');
++ if (widgetName === null) {
++ return;
++ }
++ data.disabled = true;
++ if (widgetName) {
++ // only if there has been an editing widget registered
++ jQuery(data.element)[widgetName](data);
++ jQuery(data.element).removeClass('ui-state-disabled');
++ }
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2012 Tobias Herrmann, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false document:false */
++ 'use strict';
++
++ // # Base property editor widget
++ //
++ // This property editor widget provides a very simplistic `contentEditable`
++ // property editor that can be used as standalone, but should more usually be
++ // used as the base class for other property editor widgets.
++ // This property editor widget is only useful for textual properties!
++ //
++ // Subclassing this base property editor widget is easy:
++ //
++ // jQuery.widget('Namespace.MyWidget', jQuery.Create.editWidget, {
++ // // override any properties
++ // });
++ jQuery.widget('Create.editWidget', {
++ options: {
++ disabled: false,
++ vie: null
++ },
++ // override to enable the widget
++ enable: function () {
++ this.element.attr('contenteditable', 'true');
++ },
++ // override to disable the widget
++ disable: function (disable) {
++ this.element.attr('contenteditable', 'false');
++ },
++ // called by the jQuery UI plugin factory when creating the property editor
++ // widget instance
++ _create: function () {
++ this._registerWidget();
++ this._initialize();
++
++ if (_.isFunction(this.options.decorate) && _.isFunction(this.options.decorateParams)) {
++ // TRICKY: we can't use this.options.decorateParams()'s 'propertyName'
++ // parameter just yet, because it will only be available after this
++ // object has been created, but we're currently in the constructor!
++ // Hence we have to duplicate part of its logic here.
++ this.options.decorate(this.options.decorateParams(null, {
++ propertyName: this.options.property,
++ propertyEditor: this,
++ propertyElement: this.element,
++ // Deprecated.
++ editor: this,
++ predicate: this.options.property,
++ element: this.element
++ }));
++ }
++ },
++ // called every time the property editor widget is called
++ _init: function () {
++ if (this.options.disabled) {
++ this.disable();
++ return;
++ }
++ this.enable();
++ },
++ // override this function to initialize the property editor widget functions
++ _initialize: function () {
++ var self = this;
++ this.element.bind('focus', function () {
++ if (self.options.disabled) {
++ return;
++ }
++ self.options.activated();
++ });
++ this.element.bind('blur', function () {
++ if (self.options.disabled) {
++ return;
++ }
++ self.options.deactivated();
++ });
++ var before = this.element.html();
++ this.element.bind('keyup paste', function (event) {
++ if (self.options.disabled) {
++ return;
++ }
++ var current = jQuery(this).html();
++ if (before !== current) {
++ before = current;
++ self.options.changed(current);
++ }
++ });
++ },
++ // used to register the property editor widget name with the DOM element
++ _registerWidget: function () {
++ this.element.data("createWidgetName", this.widgetName);
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2012 Tobias Herrmann, IKS Consortium
++// (c) 2011 Rene Kapusta, Evo42
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false document:false Aloha:false */
++ 'use strict';
++
++ // # Aloha editing widget
++ //
++ // This widget allows editing textual contents using the
++ // [Aloha](http://aloha-editor.org) rich text editor.
++ //
++ // Due to licensing incompatibilities, Aloha Editor needs to be installed
++ // and configured separately.
++ jQuery.widget('Create.alohaWidget', jQuery.Create.editWidget, {
++ _initialize: function () {},
++ enable: function () {
++ var options = this.options;
++ var editable;
++ var currentElement = Aloha.jQuery(options.element.get(0)).aloha();
++ _.each(Aloha.editables, function (aloha) {
++ // Find the actual editable instance so we can hook to the events
++ // correctly
++ if (aloha.obj.get(0) === currentElement.get(0)) {
++ editable = aloha;
++ }
++ });
++ if (!editable) {
++ return;
++ }
++ editable.vieEntity = options.entity;
++
++ // Subscribe to activation and deactivation events
++ Aloha.bind('aloha-editable-activated', function (event, data) {
++ if (data.editable !== editable) {
++ return;
++ }
++ options.activated();
++ });
++ Aloha.bind('aloha-editable-deactivated', function (event, data) {
++ if (data.editable !== editable) {
++ return;
++ }
++ options.deactivated();
++ });
++
++ Aloha.bind('aloha-smart-content-changed', function (event, data) {
++ if (data.editable !== editable) {
++ return;
++ }
++ if (!data.editable.isModified()) {
++ return true;
++ }
++ options.changed(data.editable.getContents());
++ data.editable.setUnmodified();
++ });
++ this.options.disabled = false;
++ },
++ disable: function () {
++ Aloha.jQuery(this.options.element.get(0)).mahalo();
++ this.options.disabled = true;
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2012 Tobias Herrmann, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false document:false CKEDITOR:false */
++ 'use strict';
++
++ // # CKEditor editing widget
++ //
++ // This widget allows editing textual content areas with the
++ // [CKEditor](http://ckeditor.com/) rich text editor.
++ jQuery.widget('Create.ckeditorWidget', jQuery.Create.editWidget, {
++ enable: function () {
++ this.element.attr('contentEditable', 'true');
++ this.editor = CKEDITOR.inline(this.element.get(0));
++ this.options.disabled = false;
++
++ var widget = this;
++ this.editor.on('focus', function () {
++ widget.options.activated();
++ });
++ this.editor.on('blur', function () {
++ widget.options.activated();
++ });
++ this.editor.on('key', function () {
++ widget.options.changed(widget.editor.getData());
++ });
++ this.editor.on('paste', function () {
++ widget.options.changed(widget.editor.getData());
++ });
++ this.editor.on('afterCommandExec', function () {
++ widget.options.changed(widget.editor.getData());
++ });
++ },
++
++ disable: function () {
++ if (!this.editor) {
++ return;
++ }
++ this.element.attr('contentEditable', 'false');
++ this.editor.destroy();
++ this.editor = null;
++ },
++
++ _initialize: function () {
++ CKEDITOR.disableAutoInline = true;
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2012 Tobias Herrmann, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false document:false */
++ 'use strict';
++
++ // # Hallo editing widget
++ //
++ // This widget allows editing textual content areas with the
++ // [Hallo](http://hallojs.org) rich text editor.
++ jQuery.widget('Create.halloWidget', jQuery.Create.editWidget, {
++ options: {
++ editorOptions: {},
++ disabled: true,
++ toolbarState: 'full',
++ vie: null,
++ entity: null
++ },
++ enable: function () {
++ jQuery(this.element).hallo({
++ editable: true
++ });
++ this.options.disabled = false;
++ },
++
++ disable: function () {
++ jQuery(this.element).hallo({
++ editable: false
++ });
++ this.options.disabled = true;
++ },
++
++ _initialize: function () {
++ jQuery(this.element).hallo(this.getHalloOptions());
++ var self = this;
++ jQuery(this.element).bind('halloactivated', function (event, data) {
++ self.options.activated();
++ });
++ jQuery(this.element).bind('hallodeactivated', function (event, data) {
++ self.options.deactivated();
++ });
++ jQuery(this.element).bind('hallomodified', function (event, data) {
++ self.options.changed(data.content);
++ data.editable.setUnmodified();
++ });
++
++ jQuery(document).bind('midgardtoolbarstatechange', function(event, data) {
++ // Switch between Hallo configurations when toolbar state changes
++ if (data.display === self.options.toolbarState) {
++ return;
++ }
++ self.options.toolbarState = data.display;
++ var newOptions = self.getHalloOptions();
++ self.element.hallo('changeToolbar', newOptions.parentElement, newOptions.toolbar, true);
++ });
++ },
++
++ getHalloOptions: function() {
++ var defaults = {
++ plugins: {
++ halloformat: {},
++ halloblock: {},
++ hallolists: {},
++ hallolink: {},
++ halloimage: {
++ entity: this.options.entity
++ }
++ },
++ buttonCssClass: 'create-ui-btn-small',
++ placeholder: '[' + this.options.property + ']'
++ };
++
++ if (typeof this.element.annotate === 'function' && this.options.vie.services.stanbol) {
++ // Enable Hallo Annotate plugin by default if user has annotate.js
++ // loaded and VIE has Stanbol enabled
++ defaults.plugins.halloannotate = {
++ vie: this.options.vie
++ };
++ }
++
++ if (this.options.toolbarState === 'full') {
++ // Use fixed toolbar in the Create tools area
++ defaults.parentElement = jQuery('.create-ui-toolbar-dynamictoolarea .create-ui-tool-freearea');
++ defaults.toolbar = 'halloToolbarFixed';
++ } else {
++ // Tools area minimized, use floating toolbar
++ defaults.parentElement = 'body';
++ defaults.toolbar = 'halloToolbarContextual';
++ }
++ return _.extend(defaults, this.options.editorOptions);
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2012 Henri Bergius, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false document:false */
++ 'use strict';
++
++ // # Redactor editing widget
++ //
++ // This widget allows editing textual content areas with the
++ // [Redactor](http://redactorjs.com/) rich text editor.
++ jQuery.widget('Create.redactorWidget', jQuery.Create.editWidget, {
++ editor: null,
++
++ options: {
++ editorOptions: {},
++ disabled: true
++ },
++
++ enable: function () {
++ jQuery(this.element).redactor(this.getRedactorOptions());
++ this.options.disabled = false;
++ },
++
++ disable: function () {
++ jQuery(this.element).destroyEditor();
++ this.options.disabled = true;
++ },
++
++ _initialize: function () {
++ var self = this;
++ jQuery(this.element).bind('focus', function (event) {
++ self.options.activated();
++ });
++ /*
++ jQuery(this.element).bind('blur', function (event) {
++ self.options.deactivated();
++ });
++ */
++ },
++
++ getRedactorOptions: function () {
++ var self = this;
++ var overrides = {
++ keyupCallback: function (obj, event) {
++ self.options.changed(jQuery(self.element).getCode());
++ },
++ execCommandCallback: function (obj, command) {
++ self.options.changed(jQuery(self.element).getCode());
++ }
++ };
++
++ return _.extend(self.options.editorOptions, overrides);
++ }
++ });
++})(jQuery);
++// Create.js - On-site web editing interface
++// (c) 2011-2012 Henri Bergius, IKS Consortium
++// Create may be freely distributed under the MIT license.
++// For all details and documentation:
++// http://createjs.org/
++(function (jQuery, undefined) {
++ // Run JavaScript in strict mode
++ /*global jQuery:false _:false window:false */
++ 'use strict';
++
++ jQuery.widget('Midgard.midgardStorage', {
++ saveEnabled: true,
++ options: {
++ // Whether to use localstorage
++ localStorage: false,
++ removeLocalstorageOnIgnore: true,
++ // VIE instance to use for storage handling
++ vie: null,
++ // URL callback for Backbone.sync
++ url: '',
++ // Whether to enable automatic saving
++ autoSave: false,
++ // How often to autosave in milliseconds
++ autoSaveInterval: 5000,
++ // Whether to save entities that are referenced by entities
++ // we're saving to the server.
++ saveReferencedNew: false,
++ saveReferencedChanged: false,
++ // Namespace used for events from midgardEditable-derived widget
++ editableNs: 'midgardeditable',
++ // CSS selector for the Edit button, leave to null to not bind
++ // notifications to any element
++ editSelector: '#midgardcreate-edit a',
++ localize: function (id, language) {
++ return window.midgardCreate.localize(id, language);
++ },
++ language: null
++ },
++
++ _create: function () {
++ var widget = this;
++ this.changedModels = [];
++
++ if (window.localStorage) {
++ this.options.localStorage = true;
++ }
++
++ this.vie = this.options.vie;
++
++ this.vie.entities.bind('add', function (model) {
++ // Add the back-end URL used by Backbone.sync
++ model.url = widget.options.url;
++ model.toJSON = model.toJSONLD;
++ });
++
++ widget._bindEditables();
++ if (widget.options.autoSave) {
++ widget._autoSave();
++ }
++ },
++
++ _autoSave: function () {
++ var widget = this;
++ widget.saveEnabled = true;
++
++ var doAutoSave = function () {
++ if (!widget.saveEnabled) {
++ return;
++ }
++
++ if (widget.changedModels.length === 0) {
++ return;
++ }
++
++ widget.saveRemoteAll({
++ // We make autosaves silent so that potential changes from server
++ // don't disrupt user while writing.
++ silent: true
++ });
++ };
++
++ var timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval);
++
++ this.element.bind('startPreventSave', function () {
++ if (timeout) {
++ window.clearInterval(timeout);
++ timeout = null;
++ }
++ widget.disableAutoSave();
++ });
++ this.element.bind('stopPreventSave', function () {
++ if (!timeout) {
++ timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval);
++ }
++ widget.enableAutoSave();
++ });
++
++ },
++
++ enableAutoSave: function () {
++ this.saveEnabled = true;
++ },
++
++ disableAutoSave: function () {
++ this.saveEnabled = false;
++ },
++
++ _bindEditables: function () {
++ var widget = this;
++ this.restorables = [];
++ var restorer;
++
++ widget.element.bind(widget.options.editableNs + 'changed', function (event, options) {
++ if (_.indexOf(widget.changedModels, options.instance) === -1) {
++ widget.changedModels.push(options.instance);
++ }
++ widget._saveLocal(options.instance);
++ });
++
++ widget.element.bind(widget.options.editableNs + 'disable', function (event, options) {
++ widget._restoreLocal(options.instance);
++ });
++
++ widget.element.bind(widget.options.editableNs + 'enable', function (event, options) {
++ if (!options.instance._originalAttributes) {
++ options.instance._originalAttributes = _.clone(options.instance.attributes);
++ }
++
++ if (!options.instance.isNew() && widget._checkLocal(options.instance)) {
++ // We have locally-stored modifications, user needs to be asked
++ widget.restorables.push(options.instance);
++ }
++
++ /*_.each(options.instance.attributes, function (attributeValue, property) {
++ if (attributeValue instanceof widget.vie.Collection) {
++ widget._readLocalReferences(options.instance, property, attributeValue);
++ }
++ });*/
++ });
++
++ widget.element.bind('midgardcreatestatechange', function (event, options) {
++ if (options.state === 'browse' || widget.restorables.length === 0) {
++ widget.restorables = [];
++ if (restorer) {
++ restorer.close();
++ }
++ return;
++ }
++ restorer = widget.checkRestore();
++ });
++
++ widget.element.bind('midgardstorageloaded', function (event, options) {
++ if (_.indexOf(widget.changedModels, options.instance) === -1) {
++ widget.changedModels.push(options.instance);
++ }
++ });
++ },
++
++ checkRestore: function () {
++ var widget = this;
++ if (widget.restorables.length === 0) {
++ return;
++ }
++
++ var message;
++ var restorer;
++ if (widget.restorables.length === 1) {
++ message = _.template(widget.options.localize('localModification', widget.options.language), {
++ label: widget.restorables[0].getSubjectUri()
++ });
++ } else {
++ message = _.template(widget.options.localize('localModifications', widget.options.language), {
++ number: widget.restorables.length
++ });
++ }
++
++ var doRestore = function (event, notification) {
++ widget.restoreLocal();
++ restorer.close();
++ };
++
++ var doIgnore = function (event, notification) {
++ widget.ignoreLocal();
++ restorer.close();
++ };
++
++ restorer = jQuery('body').midgardNotifications('create', {
++ bindTo: widget.options.editSelector,
++ gravity: 'TR',
++ body: message,
++ timeout: 0,
++ actions: [
++ {
++ name: 'restore',
++ label: widget.options.localize('Restore', widget.options.language),
++ cb: doRestore,
++ className: 'create-ui-btn'
++ },
++ {
++ name: 'ignore',
++ label: widget.options.localize('Ignore', widget.options.language),
++ cb: doIgnore,
++ className: 'create-ui-btn'
++ }
++ ],
++ callbacks: {
++ beforeShow: function () {
++ if (!window.Mousetrap) {
++ return;
++ }
++ window.Mousetrap.bind(['command+shift+r', 'ctrl+shift+r'], function (event) {
++ event.preventDefault();
++ doRestore();
++ });
++ window.Mousetrap.bind(['command+shift+i', 'ctrl+shift+i'], function (event) {
++ event.preventDefault();
++ doIgnore();
++ });
++ },
++ afterClose: function () {
++ if (!window.Mousetrap) {
++ return;
++ }
++ window.Mousetrap.unbind(['command+shift+r', 'ctrl+shift+r']);
++ window.Mousetrap.unbind(['command+shift+i', 'ctrl+shift+i']);
++ }
++ }
++ });
++ return restorer;
++ },
++
++ restoreLocal: function () {
++ _.each(this.restorables, function (instance) {
++ this.readLocal(instance);
++ }, this);
++ this.restorables = [];
++ },
++
++ ignoreLocal: function () {
++ if (this.options.removeLocalstorageOnIgnore) {
++ _.each(this.restorables, function (instance) {
++ this._removeLocal(instance);
++ }, this);
++ }
++ this.restorables = [];
++ },
++
++ saveReferences: function (model) {
++ _.each(model.attributes, function (value, property) {
++ if (!value || !value.isCollection) {
++ return;
++ }
++
++ value.each(function (referencedModel) {
++ if (this.changedModels.indexOf(referencedModel) !== -1) {
++ // The referenced model is already in the save queue
++ return;
++ }
++
++ if (referencedModel.isNew() && this.options.saveReferencedNew) {
++ return referencedModel.save();
++ }
++
++ if (referencedModel.hasChanged() && this.options.saveReferencedChanged) {
++ return referencedModel.save();
++ }
++ }, this);
++ }, this);
++ },
++
++ saveRemote: function (model, options) {
++ // Optionally handle entities referenced in this model first
++ this.saveReferences(model);
++
++ this._trigger('saveentity', null, {
++ entity: model,
++ options: options
++ });
++
++ var widget = this;
++ model.save(null, _.extend({}, options, {
++ success: function (m, response) {
++ // From now on we're going with the values we have on server
++ model._originalAttributes = _.clone(model.attributes);
++ widget._removeLocal(model);
++ window.setTimeout(function () {
++ // Remove the model from the list of changed models after saving
++ widget.changedModels.splice(widget.changedModels.indexOf(model), 1);
++ }, 0);
++ if (_.isFunction(options.success)) {
++ options.success(m, response);
++ }
++ widget._trigger('savedentity', null, {
++ entity: model,
++ options: options
++ });
++ },
++ error: function (m, response) {
++ if (_.isFunction(options.error)) {
++ options.error(m, response);
++ }
++ }
++ }));
++ },
++
++ saveRemoteAll: function (options) {
++ var widget = this;
++ if (widget.changedModels.length === 0) {
++ return;
++ }
++
++ widget._trigger('save', null, {
++ entities: widget.changedModels,
++ options: options,
++ // Deprecated
++ models: widget.changedModels
++ });
++
++ var notification_msg;
++ var needed = widget.changedModels.length;
++ if (needed > 1) {
++ notification_msg = _.template(widget.options.localize('saveSuccessMultiple', widget.options.language), {
++ number: needed
++ });
++ } else {
++ notification_msg = _.template(widget.options.localize('saveSuccess', widget.options.language), {
++ label: widget.changedModels[0].getSubjectUri()
++ });
++ }
++
++ widget.disableAutoSave();
++ _.each(widget.changedModels, function (model) {
++ this.saveRemote(model, {
++ success: function (m, response) {
++ needed--;
++ if (needed <= 0) {
++ // All models were happily saved
++ widget._trigger('saved', null, {
++ options: options
++ });
++ if (options && _.isFunction(options.success)) {
++ options.success(m, response);
++ }
++ jQuery('body').midgardNotifications('create', {
++ body: notification_msg
++ });
++ widget.enableAutoSave();
++ }
++ },
++ error: function (m, err) {
++ if (options && _.isFunction(options.error)) {
++ options.error(m, err);
++ }
++ jQuery('body').midgardNotifications('create', {
++ body: _.template(widget.options.localize('saveError', widget.options.language), {
++ error: err.responseText || ''
++ }),
++ timeout: 0
++ });
++
++ widget._trigger('error', null, {
++ instance: model
++ });
++ }
++ });
++ }, this);
++ },
++
++ _saveLocal: function (model) {
++ if (!this.options.localStorage) {
++ return;
++ }
++
++ if (model.isNew()) {
++ // Anonymous object, save as refs instead
++ if (!model.primaryCollection) {
++ return;
++ }
++ return this._saveLocalReferences(model.primaryCollection.subject, model.primaryCollection.predicate, model);
++ }
++ window.localStorage.setItem(model.getSubjectUri(), JSON.stringify(model.toJSONLD()));
++ },
++
++ _getReferenceId: function (model, property) {
++ return model.id + ':' + property;
++ },
++
++ _saveLocalReferences: function (subject, predicate, model) {
++ if (!this.options.localStorage) {
++ return;
++ }
++
++ if (!subject || !predicate) {
++ return;
++ }
++
++ var widget = this;
++ var identifier = subject + ':' + predicate;
++ var json = model.toJSONLD();
++ if (window.localStorage.getItem(identifier)) {
++ var referenceList = JSON.parse(window.localStorage.getItem(identifier));
++ var index = _.pluck(referenceList, '@').indexOf(json['@']);
++ if (index !== -1) {
++ referenceList[index] = json;
++ } else {
++ referenceList.push(json);
++ }
++ window.localStorage.setItem(identifier, JSON.stringify(referenceList));
++ return;
++ }
++ window.localStorage.setItem(identifier, JSON.stringify([json]));
++ },
++
++ _checkLocal: function (model) {
++ if (!this.options.localStorage) {
++ return false;
++ }
++
++ var local = window.localStorage.getItem(model.getSubjectUri());
++ if (!local) {
++ return false;
++ }
++
++ return true;
++ },
++
++ hasLocal: function (model) {
++ if (!this.options.localStorage) {
++ return false;
++ }
++
++ if (!window.localStorage.getItem(model.getSubjectUri())) {
++ return false;
++ }
++ return true;
++ },
++
++ readLocal: function (model) {
++ if (!this.options.localStorage) {
++ return;
++ }
++
++ var local = window.localStorage.getItem(model.getSubjectUri());
++ if (!local) {
++ return;
++ }
++ if (!model._originalAttributes) {
++ model._originalAttributes = _.clone(model.attributes);
++ }
++ var parsed = JSON.parse(local);
++ var entity = this.vie.entities.addOrUpdate(parsed, {
++ overrideAttributes: true
++ });
++
++ this._trigger('loaded', null, {
++ instance: entity
++ });
++ },
++
++ _readLocalReferences: function (model, property, collection) {
++ if (!this.options.localStorage) {
++ return;
++ }
++
++ var identifier = this._getReferenceId(model, property);
++ var local = window.localStorage.getItem(identifier);
++ if (!local) {
++ return;
++ }
++ collection.add(JSON.parse(local));
++ },
++
++ _restoreLocal: function (model) {
++ var widget = this;
++
++ // Remove unsaved collection members
++ if (!model) { return; }
++ _.each(model.attributes, function (attributeValue, property) {
++ if (attributeValue instanceof widget.vie.Collection) {
++ var removables = [];
++ attributeValue.forEach(function (model) {
++ if (model.isNew()) {
++ removables.push(model);
++ }
++ });
++ attributeValue.remove(removables);
++ }
++ });
++
++ // Restore original object properties
++ if (!model.changedAttributes()) {
++ if (model._originalAttributes) {
++ model.set(model._originalAttributes);
++ }
++ return;
++ }
++
++ model.set(model.previousAttributes());
++ },
++
++ _removeLocal: function (model) {
++ if (!this.options.localStorage) {
++ return;
++ }
++
++ window.localStorage.removeItem(model.getSubjectUri());
++ }
++ });
++})(jQuery);
++if (window.midgardCreate === undefined) {
++ window.midgardCreate = {};
++}
++if (window.midgardCreate.locale === undefined) {
++ window.midgardCreate.locale = {};
++}
++
++window.midgardCreate.locale.en = {
++ // Session-state buttons for the main toolbar
++ 'Save': 'Save',
++ 'Saving': 'Saving',
++ 'Cancel': 'Cancel',
++ 'Edit': 'Edit',
++ // Storage status messages
++ 'localModification': 'Item "<%= label %>" has local modifications',
++ 'localModifications': '<%= number %> items on this page have local modifications',
++ 'Restore': 'Restore',
++ 'Ignore': 'Ignore',
++ 'saveSuccess': 'Item "<%= label %>" saved successfully',
++ 'saveSuccessMultiple': '<%= number %> items saved successfully',
++ 'saveError': 'Error occurred while saving <%= error %>',
++ // Tagging
++ 'Item tags': 'Item tags',
++ 'Suggested tags': 'Suggested tags',
++ 'Tags': 'Tags',
++ 'add a tag': 'add a tag',
++ // Collection widgets
++ 'Add': 'Add',
++ 'Choose type to add': 'Choose type to add'
++};
+diff --git a/core/misc/vie/vie-core.js b/core/misc/vie/vie-core.js
+new file mode 100644
+index 0000000..ca5c079
+--- /dev/null
++++ b/core/misc/vie/vie-core.js
+@@ -0,0 +1,3682 @@
++/*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('')` 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
++// Namespaces documentation.
++ 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
++// Types documentation.
++ 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 = "";
++// 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 = "";
++// 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);
++// -->
++// VIE.Util.toUri(scurie, ns);
++// -->
++ 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 = "";
++// 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 schema.org 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("");
++
++ 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]));
++ 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 VIE.Type.
++// * `@context` stores namespace definitions used in the entity. Read more about
++// Namespaces in VIE Namespaces.
++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);
++ return Backbone.Model.prototype.set.call(this, attrs, options);
++ },
++
++ // **`.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);
++// // --> ""
++ 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 VIE.Attributes)
++// **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 constructor of VIE.Entity
++// *{object}* **opts** see constructor of VIE.Entity
++// **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);
++// // -->
++ 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 = "";
++// 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 = "";
++// 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);
++// -->
++// ns.uri(scurie);
++// -->
++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 = "";
++// var curie = "test:Person";
++// namespaces.isUri(uri); // --> true
++// namespaces.isUri(curie); // --> false
++VIE.prototype.Namespaces.prototype.isUri = VIE.Util.isUri;
++})();
+\ No newline at end of file
+diff --git a/core/modules/system/system.module b/core/modules/system/system.module
+index 3b2d131..f8c67e8 100644
+--- a/core/modules/system/system.module
++++ b/core/modules/system/system.module
+@@ -1839,7 +1839,7 @@ function system_library_info() {
+ ),
+ );
+
+- // Underscore
++ // Underscore.
+ $libraries['underscore'] = array(
+ 'title' => 'Underscore.js',
+ 'website' => 'http://underscorejs.org/',
+@@ -1849,7 +1849,7 @@ function system_library_info() {
+ ),
+ );
+
+- // Backbone
++ // Backbone.
+ $libraries['backbone'] = array(
+ 'title' => 'Backbone.js',
+ 'website' => 'http://backbonejs.org/',
+@@ -1862,6 +1862,35 @@ function system_library_info() {
+ ),
+ );
+
++ // VIE.
++ $libraries['vie.core'] = array(
++ 'title' => 'VIE.js core (excluding services, views and xdr)',
++ 'website' => 'http://viejs.org/',
++ 'version' => '2.0.0-dev',
++ 'js' => array(
++ 'core/misc/vie/vie-core.js' => array('group' => JS_LIBRARY),
++ ),
++ 'dependencies' => array(
++ array('system', 'jquery'),
++ array('system', 'underscore'),
++ array('system', 'backbone'),
++ ),
++ );
++
++ // Create.
++ $libraries['create.editonly'] = array(
++ 'title' => 'Create.js edit-only (editing features only)',
++ 'website' => 'http://backbonejs.org/',
++ 'version' => '1.0.0-dev',
++ 'js' => array(
++ 'core/misc/create/create-editonly.js' => array('group' => JS_LIBRARY),
++ ),
++ 'dependencies' => array(
++ array('system', 'vie.core'),
++ array('system', 'jquery.ui.widget'),
++ ),
++ );
++
+ // Cookie.
+ $libraries['jquery.cookie'] = array(
+ 'title' => 'Cookie',