From 85a9f215f2fc8931fed1ce59da2c79aed6a8e406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?"J.=20Rene=CC=81e=20Beach"?= <splendidnoise@gmail.com>
Date: Thu, 2 May 2013 23:19:37 -0400
Subject: [PATCH] Issue #1979784-10
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

commit 42a526c4bd205142bef7a8bed8a4b75e3341a492
Author: J. Renée Beach <splendidnoise@gmail.com>
Date:   Thu May 2 23:18:29 2013 -0400

    Issue #1979784-10

    Signed-off-by: J. Renée Beach <splendidnoise@gmail.com>

commit 2aa0087061d6ed774a8ddef2e58d517e018568d8
Author: J. Renée Beach <splendidnoise@gmail.com>
Date:   Thu May 2 14:27:23 2013 -0400

    Issue #1979784-9

    Signed-off-by: J. Renée Beach <splendidnoise@gmail.com>

Signed-off-by: J. Renée Beach <splendidnoise@gmail.com>
---
 core/misc/create/create-editonly.js                | 1651 ---------
 core/misc/vie/vie-core.js                          | 3719 --------------------
 core/modules/edit/css/edit.css                     |    3 -
 core/modules/edit/edit.module                      |   30 +-
 core/modules/edit/js/app.js                        |  391 --
 core/modules/edit/js/backbone.drupalform.js        |   33 +-
 core/modules/edit/js/createjs/editable.js          |   30 -
 .../editingWidgets/drupalcontenteditablewidget.js  |   83 -
 .../edit/js/createjs/editingWidgets/formwidget.js  |  152 -
 core/modules/edit/js/createjs/storage.js           |   11 -
 core/modules/edit/js/edit.js                       |  212 +-
 core/modules/edit/js/editors/directEditor.js       |   89 +
 core/modules/edit/js/editors/formEditor.js         |  190 +
 core/modules/edit/js/models/AppModel.js            |   23 +
 core/modules/edit/js/models/EntityModel.js         |   28 +
 core/modules/edit/js/models/FieldModel.js          |  131 +
 core/modules/edit/js/models/edit-app-model.js      |   21 -
 core/modules/edit/js/util.js                       |    2 +-
 core/modules/edit/js/viejs/EditService.js          |  289 --
 core/modules/edit/js/views/AppView.js              |  362 ++
 core/modules/edit/js/views/ContextualLinkView.js   |   75 +
 core/modules/edit/js/views/EditorDecorationView.js |  362 ++
 core/modules/edit/js/views/EditorView.js           |  213 ++
 core/modules/edit/js/views/FieldToolbarView.js     |  414 +++
 core/modules/edit/js/views/ModalView.js            |   80 +
 core/modules/edit/js/views/contextuallink-view.js  |  109 -
 core/modules/edit/js/views/modal-view.js           |   83 -
 .../edit/js/views/propertyeditordecoration-view.js |  363 --
 core/modules/edit/js/views/toolbar-view.js         |  490 ---
 core/modules/edit/lib/Drupal/edit/EditorBase.php   |    2 +-
 .../edit/lib/Drupal/edit/EditorSelector.php        |    6 +-
 .../edit/lib/Drupal/edit/MetadataGenerator.php     |    2 +-
 .../edit/lib/Drupal/edit/Plugin/EditorManager.php  |    2 +-
 .../edit/Plugin/edit/editor/DirectEditor.php       |    2 +-
 .../Drupal/edit/Plugin/edit/editor/FormEditor.php  |    2 +-
 .../lib/Drupal/edit/Tests/EditorSelectionTest.php  |    5 +-
 .../Drupal/edit/Tests/MetadataGeneratorTest.php    |    5 +-
 .../edit_test/Plugin/edit/editor/WysiwygEditor.php |    2 +-
 core/modules/editor/editor.module                  |    8 +-
 core/modules/editor/js/editor.createjs.js          |  157 -
 .../editor/js/editor.formattedTextEditor.js        |  179 +
 core/modules/editor/js/editor.js                   |    8 +-
 .../Drupal/editor/Plugin/edit/editor/Editor.php    |    6 +-
 .../Drupal/editor/Tests/EditIntegrationTest.php    |    4 +-
 core/modules/system/system.module                  |   14 -
 45 files changed, 2365 insertions(+), 7678 deletions(-)
 delete mode 100644 core/misc/create/create-editonly.js
 delete mode 100644 core/misc/vie/vie-core.js
 delete mode 100644 core/modules/edit/js/app.js
 delete mode 100644 core/modules/edit/js/createjs/editable.js
 delete mode 100644 core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
 delete mode 100644 core/modules/edit/js/createjs/editingWidgets/formwidget.js
 delete mode 100644 core/modules/edit/js/createjs/storage.js
 create mode 100644 core/modules/edit/js/editors/directEditor.js
 create mode 100644 core/modules/edit/js/editors/formEditor.js
 create mode 100644 core/modules/edit/js/models/AppModel.js
 create mode 100644 core/modules/edit/js/models/EntityModel.js
 create mode 100644 core/modules/edit/js/models/FieldModel.js
 delete mode 100644 core/modules/edit/js/models/edit-app-model.js
 delete mode 100644 core/modules/edit/js/viejs/EditService.js
 create mode 100644 core/modules/edit/js/views/AppView.js
 create mode 100644 core/modules/edit/js/views/ContextualLinkView.js
 create mode 100644 core/modules/edit/js/views/EditorDecorationView.js
 create mode 100644 core/modules/edit/js/views/EditorView.js
 create mode 100644 core/modules/edit/js/views/FieldToolbarView.js
 create mode 100644 core/modules/edit/js/views/ModalView.js
 delete mode 100644 core/modules/edit/js/views/contextuallink-view.js
 delete mode 100644 core/modules/edit/js/views/modal-view.js
 delete mode 100644 core/modules/edit/js/views/propertyeditordecoration-view.js
 delete mode 100644 core/modules/edit/js/views/toolbar-view.js
 delete mode 100644 core/modules/editor/js/editor.createjs.js
 create mode 100644 core/modules/editor/js/editor.formattedTextEditor.js

diff --git a/core/misc/create/create-editonly.js b/core/misc/create/create-editonly.js
deleted file mode 100644
index aed84a4..0000000
--- a/core/misc/create/create-editonly.js
+++ /dev/null
@@ -1,1651 +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: '<button class="btn"><i class="icon-<%= icon %>"></i> <%= label %></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.on('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.on('add remove reset', widget.checkCollectionConstraints, widget);
-
-      widget._bindCollectionView(widget.options.view);
-    },
-
-    _bindCollectionView: function (view) {
-      var widget = this;
-      view.on('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.on('add', function (itemView) {
-        //itemView.el.effect('slide');
-        widget._makeEditable(itemView);
-        widget._refreshButtons();
-      });
-      view.on('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());
-
-      if (!this.vie.view || !this.vie.view.Collection) {
-        return;
-      }
-
-      _.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.disablePropertyEditor({
-          widget: this,
-          editable: editable,
-          entity: this.options.model,
-          element: editable.element
-        });
-      }, 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('Midgard-' + 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) {
-      data.element[data.editable.widgetName]({
-        disabled: true
-      });
-      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('Midgard.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.on('focus', function () {
-        if (self.options.disabled) {
-          return;
-        }
-        self.options.activated();
-      });
-      this.element.on('blur', function () {
-        if (self.options.disabled) {
-          return;
-        }
-        self.options.deactivated();
-      });
-      var before = this.element.html();
-      this.element.on('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('Midgard.alohaWidget', jQuery.Midgard.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('Midgard.ckeditorWidget', jQuery.Midgard.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();
-        widget.options.changed(widget.editor.getData());
-      });
-      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());
-      });
-      this.editor.on('configLoaded', function() {
-        jQuery.each(widget.options.editorOptions, function(optionName, option) {
-          widget.editor.config[optionName] = option;
-        });
-      });
-    },
-
-    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('Midgard.halloWidget', jQuery.Midgard.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).on('halloactivated', function (event, data) {
-        self.options.activated();
-      });
-      jQuery(this.element).on('hallodeactivated', function (event, data) {
-        self.options.deactivated();
-      });
-      jQuery(this.element).on('hallomodified', function (event, data) {
-        self.options.changed(data.content);
-        data.editable.setUnmodified();
-      });
-
-      jQuery(document).on('midgardtoolbarstatechange', function(event, data) {
-        // Switch between Hallo configurations when toolbar state changes
-        if (data.display === self.options.toolbarState) {
-          return;
-        }
-        self.options.toolbarState = data.display;
-        if (!self.element.data('IKS-hallo')) {
-          // Hallo not yet instantiated
-          return;
-        }
-        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('Midgard.redactorWidget', jQuery.Midgard.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).on('focus', function (event) {
-        self.options.activated(); 
-      });
-      /*
-      jQuery(this.element).on('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.on('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.on('startPreventSave', function () {
-        if (timeout) {
-          window.clearInterval(timeout);
-          timeout = null;
-        }
-        widget.disableAutoSave();
-      });
-      this.element.on('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.on(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.on(widget.options.editableNs + 'disable', function (event, options) {
-        widget.revertChanges(options.instance);
-      });
-
-      widget.element.on(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.on('midgardcreatestatechange', function (event, options) {
-        if (options.state === 'browse' || widget.restorables.length === 0) {
-          widget.restorables = [];
-          if (restorer) {
-            restorer.close();
-          }
-          return;
-        }
-        restorer = widget.checkRestore();
-      });
-
-      widget.element.on('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.restoreLocalAll();
-        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;
-    },
-
-    restoreLocalAll: 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));
-    },
-
-    revertChanges: 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<br /><%= 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
deleted file mode 100644
index 4e1526e..0000000
--- a/core/misc/vie/vie-core.js
+++ /dev/null
@@ -1,3719 +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('<http://dbpedia.org/property/capitalOf>')` or
-// `entity.get('dbprop:capitalOf')` or even
-// `entity.get('capitalOf')` once the corresponding namespace
-// is registered as *baseNamespace*.
-// By default `"http://viejs.org/ns/"`is set as base namespace.
-// For more information about how to set, get and list all
-// registered namespaces, refer to the
-// <a href="Namespace.html">Namespaces documentation</a>.
-    this.namespaces = new this.Namespaces(
-        (this.config.baseNamespace) ? this.config.baseNamespace : "http://viejs.org/ns/",
-
-// By default, VIE is shipped with common namespace prefixes:
-
-// +    owl    : "http://www.w3.org/2002/07/owl#"
-// +    rdfs   : "http://www.w3.org/2000/01/rdf-schema#"
-// +    rdf    : "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-// +    schema : 'http://schema.org/'
-// +    foaf   : 'http://xmlns.com/foaf/0.1/'
-// +    geo    : 'http://www.w3.org/2003/01/geo/wgs84_pos#'
-// +    dbpedia: "http://dbpedia.org/ontology/"
-// +    dbprop : "http://dbpedia.org/property/"
-// +    skos   : "http://www.w3.org/2004/02/skos/core#"
-// +    xsd    : "http://www.w3.org/2001/XMLSchema#"
-// +    sioc   : "http://rdfs.org/sioc/ns#"
-// +    dcterms: "http://purl.org/dc/terms/"
-        {
-            owl    : "http://www.w3.org/2002/07/owl#",
-            rdfs   : "http://www.w3.org/2000/01/rdf-schema#",
-            rdf    : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
-            schema : 'http://schema.org/',
-            foaf   : 'http://xmlns.com/foaf/0.1/',
-            geo    : 'http://www.w3.org/2003/01/geo/wgs84_pos#',
-            dbpedia: "http://dbpedia.org/ontology/",
-            dbprop : "http://dbpedia.org/property/",
-            skos   : "http://www.w3.org/2004/02/skos/core#",
-            xsd    : "http://www.w3.org/2001/XMLSchema#",
-            sioc   : "http://rdfs.org/sioc/ns#",
-            dcterms: "http://purl.org/dc/terms/"
-        }
-    );
-
-
-    this.Type.prototype.vie = this;
-    this.Types.prototype.vie = this;
-    this.Attribute.prototype.vie = this;
-    this.Attributes.prototype.vie = this;
-// ### Type hierarchy in VIE
-// VIE takes care about type hierarchy of entities
-// (aka. *schema* or *ontology*).
-// Once a type hierarchy is known to VIE, we can leverage
-// this information, to easily ask, whether an entity
-// is of type, e.g., *foaf:Person* or *schema:Place*.
-// For more information about how to generate such a type
-// hierarchy, refer to the
-// <a href="Type.html">Types documentation</a>.
-    this.types = new this.Types();
-// By default, there is a parent type in VIE, called
-// *owl:Thing*. All types automatically inherit from this
-// type and all registered entities, are of this type.
-    this.types.add("owl:Thing");
-
-// As described above, the Classic API of VIE 1.x is loaded
-// by default. As this might change in the future, it is
-// recommended to ensure it is enabled before using it. So:
-//
-//     var vie = new VIE({classic: true});
-//     vie.RDFaEntities.getInstances();
-    if (this.config.classic === true) {
-        /* Load Classic API as well */
-        this.RDFa = new this.ClassicRDFa(this);
-        this.RDFaEntities = new this.ClassicRDFaEntities(this);
-        this.EntityManager = new this.ClassicEntityManager(this);
-
-        this.cleanup = function() {
-            this.entities.reset();
-        };
-    }
-};
-
-// ### use(service, name)
-// This method registers services within VIE.
-// **Parameters**:
-// *{string|object}* **service** The service to be registered.
-// *{string}* **name** An optional name to register the service with. If this
-// is not set, the default name that comes with the service is taken.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE}* : The current VIE instance.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     var conf1 = {...};
-//     var conf2 = {...};
-//     vie.use(new vie.StanbolService());
-//     vie.use(new vie.StanbolService(conf1), "stanbol_1");
-//     vie.use(new vie.StanbolService(conf2), "stanbol_2");
-//     // <-- this means that there are now 3 services registered!
-VIE.prototype.use = function(service, name) {
-  if (!name && !service.name) {
-    throw new Error("Please provide a name for the service!");
-  }
-  service.vie = this;
-  service.name = (name)? name : service.name;
-  if (service.init) {
-      service.init();
-  }
-  this.services[service.name] = service;
-
-  return this;
-};
-
-// ### service(name)
-// This method returns the service object that is
-// registered under the given name.
-// **Parameters**:
-// *{string}* **name** ...
-// **Throws**:
-// *{Error}* if no service could be found.
-// **Returns**:
-// *{object}* : The service to be queried.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var service = vie.service("stanbol");
-VIE.prototype.service = function(name) {
-  if (!this.hasService(name)) {
-    throw "Undefined service " + name;
-  }
-  return this.services[name];
-};
-
-// ### hasService(name)
-// This method returns a boolean telling whether VIE has a particular
-// service loaded.
-// **Parameters**:
-// *{string}* **name**
-// **Returns**:
-// *{boolean}* whether service is available
-VIE.prototype.hasService = function(name) {
-  if (!this.services[name]) {
-    return false;
-  }
-  return true;
-};
-
-// ### getServicesArray()
-// This method returns an array of all registered services.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{array}* : An array of service instances.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var services = vie.getServicesArray();
-//     services.length; // <-- 1
-VIE.prototype.getServicesArray = function() {
-  return _.map(this.services, function (v) {return v;});
-};
-
-// ### load(options)
-// This method instantiates a new VIE.Loadable in order to
-// perform queries on the services.
-// **Parameters**:
-// *{object}* **options** Options to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Loadable}* : A new instance of VIE.Loadable.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var loader = vie.load({...});
-VIE.prototype.load = function(options) {
-  if (!options) { options = {}; }
-  options.vie = this;
-  return new this.Loadable(options);
-};
-
-// ### save(options)
-// This method instantiates a new VIE.Savable in order to
-// perform queries on the services.
-// **Parameters**:
-// *{object}* **options** Options to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Savable}* : A new instance of VIE.Savable.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var saver = vie.save({...});
-VIE.prototype.save = function(options) {
-  if (!options) { options = {}; }
-  options.vie = this;
-  return new this.Savable(options);
-};
-
-// ### remove(options)
-// This method instantiates a new VIE.Removable in order to
-// perform queries on the services.
-// **Parameters**:
-// *{object}* **options** Options to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Removable}* : A new instance of VIE.Removable.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var remover = vie.remove({...});
-VIE.prototype.remove = function(options) {
-  if (!options) { options = {}; }
-  options.vie = this;
-  return new this.Removable(options);
-};
-
-// ### analyze(options)
-// This method instantiates a new VIE.Analyzable in order to
-// perform queries on the services.
-// **Parameters**:
-// *{object}* **options** Options to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Analyzable}* : A new instance of VIE.Analyzable.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var analyzer = vie.analyze({...});
-VIE.prototype.analyze = function(options) {
-  if (!options) { options = {}; }
-  options.vie = this;
-  return new this.Analyzable(options);
-};
-
-// ### find(options)
-// This method instantiates a new VIE.Findable in order to
-// perform queries on the services.
-// **Parameters**:
-// *{object}* **options** Options to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Findable}* : A new instance of VIE.Findable.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.use(new vie.StanbolService(), "stanbol");
-//     var finder = vie.find({...});
-VIE.prototype.find = function(options) {
-  if (!options) { options = {}; }
-  options.vie = this;
-  return new this.Findable(options);
-};
-
-// ### loadSchema(url, options)
-// VIE only knows the *owl:Thing* type by default.
-// You can use this method to import another
-// schema (ontology) from an external resource.
-// (Currently, this supports only the JSON format!!)
-// As this method works asynchronously, you might want
-// to register `success` and `error` callbacks via the
-// options.
-// **Parameters**:
-// *{string}* **url** The url, pointing to the schema to import.
-// *{object}* **options** Options to be set.
-// (Set ```success``` and ```error``` as callbacks.).
-// **Throws**:
-// *{Error}* if the url is not set.
-// **Returns**:
-// *{VIE}* : The VIE instance itself.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.loadSchema("http://schema.rdfs.org/all.json",
-//        {
-//          baseNS : "http://schema.org/",
-//          success : function () {console.log("success");},
-//          error  : function (msg) {console.warn(msg);}
-//        });
-VIE.prototype.loadSchema = function(url, options) {
-    options = (!options)? {} : options;
-
-    if (!url) {
-        throw new Error("Please provide a proper URL");
-    }
-    else {
-        var vie = this;
-        jQuery.getJSON(url)
-        .success(function(data) {
-            try {
-                VIE.Util.loadSchemaOrg(vie, data, options.baseNS);
-                if (options.success) {
-                    options.success.call(vie);
-                }
-            } catch (e) {
-                options.error.call(vie, e);
-                return;
-            }
-         })
-        .error(function(data, textStatus, jqXHR) {
-            if (options.error) {
-                console.warn(data, textStatus, jqXHR);
-                options.error.call(vie, "Could not load schema from URL (" + url + ")");
-            }
-         });
-    }
-
-    return this;
-};
-
-// ### getTypedEntityClass(type)
-// This method generates a special type of `Entity` based on the given type.
-// **Parameters**:
-// *{string}* **type** The type.
-// **Throws**:
-// *{Error}* if the type is unknown to VIE.
-// **Returns**:
-// *{VIE.Entity}* : A subclass of `VIE.Entity`.
-// **Example usage**:
-//
-//     var vie = new VIE();
-//     vie.types.add("Person");
-//     var PersonClass = vie.getTypedEntityClass("Person");
-//     var Person = new PersonClass({"name", "Sebastian"});
-VIE.prototype.getTypedEntityClass = function (type) {
-  var typeType = this.types.get(type);
-  if (!typeType) {
-    throw new Error("Unknown type " + type);
-  }
-  var TypedEntityClass = function (attrs, opts) {
-    if (!attrs) {
-      attrs = {};
-    }
-    attrs["@type"] = type;
-    this.set(attrs, opts);
-  };
-  TypedEntityClass.prototype = new this.Entity();
-  TypedEntityClass.prototype.schema = function () {
-    return VIE.Util.getFormSchemaForType(typeType);
-  };
-  return TypedEntityClass;
-};
-
-// ## Running VIE on Node.js
-//
-// When VIE is running under Node.js we can use the CommonJS
-// require interface to load our dependencies automatically.
-//
-// This means Node.js users don't need to care about dependencies
-// and can just run VIE with:
-//
-//     var VIE = require('vie');
-//
-// In browser environments the dependencies have to be included
-// before including VIE itself.
-if (typeof exports === 'object') {
-    exports.VIE = VIE;
-
-    if (!jQuery) {
-        jQuery = require('jquery');
-    }
-    if (!Backbone) {
-        Backbone = require('backbone');
-        Backbone.setDomLibrary(jQuery);
-    }
-    if (!_) {
-        _ = require('underscore')._;
-    }
-}
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-
-// ## VIE.Able
-// VIE implements asynchronius service methods through
-// [jQuery.Deferred](http://api.jquery.com/category/deferred-object/) objects.
-// Loadable, Analysable, Savable, etc. are part of the VIE service API and
-// are implemented with the generic VIE.Able class.
-// Example:
-//
-//      VIE.prototype.Loadable = function (options) {
-//          this.init(options,"load");
-//      };
-//      VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
-//
-// This defines
-//
-//     someVIEService.load(options)
-//     .using(...)
-//     .execute()
-//     .success(...)
-//     .fail(...)
-// which will run the asynchronius `load` function of the service with the created Loadable
-// object.
-
-// ### VIE.Able()
-// This is the constructor of a VIE.Able. This should not be called
-// globally but using the inherited classes below.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Able}* : A **new** VIE.Able object.
-// Example:
-//
-//      VIE.prototype.Loadable = function (options) {
-//          this.init(options,"load");
-//      };
-//      VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
-VIE.prototype.Able = function(){
-
-// ### init(options, methodName)
-// Internal method, called during initialization.
-// **Parameters**:
-// *{object}* **options** the *able* options coming from the API call
-// *{string}* **methodName** the service method called on `.execute`.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Able}* : The current instance.
-// **Example usage**:
-//
-//      VIE.prototype.Loadable = function (options) {
-//          this.init(options,"load");
-//      };
-//      VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
-    this.init = function(options, methodName) {
-        this.options = options;
-        this.services = options.from || options.using || options.to || [];
-        this.vie = options.vie;
-
-        this.methodName = methodName;
-
-        // Instantiate the deferred object
-        this.deferred = jQuery.Deferred();
-
-// In order to get more information and documentation about the passed-through
-// deferred methods and their synonyms, please see the documentation of
-// the [jQuery.Deferred object](http://api.jquery.com/category/deferred-object/)
-        /* Public deferred-methods */
-        this.resolve = this.deferred.resolve;
-        this.resolveWith = this.deferred.resolveWith;
-        this.reject = this.deferred.reject;
-        this.rejectWith = this.deferred.rejectWith;
-        this.success = this.done = this.deferred.done;
-        this.fail = this.deferred.fail;
-        this.then = this.deferred.then;
-        this.always = this.deferred.always;
-        this.from = this.using;
-        this.to = this.using;
-
-        return this;
-    };
-
-
-// ### using(services)
-// This method registers services with the current able instance.
-// **Parameters**:
-// *{string|array}* **services** An id of a service or an array of strings.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Able}* : The current instance.
-// **Example usage**:
-//
-//     var loadable = vie.load({id: "http://example.com/entity/1234"});
-//     able.using("myService");
-    this.using = function(services) {
-        var self = this;
-        services = (_.isArray(services))? services : [ services ];
-        _.each (services, function (s) {
-            var obj = (typeof s === "string")? self.vie.service(s) : s;
-            self.services.push(obj);
-        });
-        return this;
-    };
-
-// ### execute()
-// This method runs the actual method on all registered services.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing* ...
-// **Returns**:
-// *{VIE.Able}* : The current instance.
-// **Example usage**:
-//
-//     var able = new vie.Able().init();
-//     able.using("stanbol")
-//     .done(function () {alert("finished");})
-//     .execute();
-    this.execute = function() {
-        /* call service[methodName] */
-        var able = this;
-        _(this.services).each(function(service){
-            service[able.methodName](able);
-        });
-        return this;
-    };
-};
-
-// ## VIE.Loadable
-// A ```VIE.Loadable``` is a wrapper around the deferred object
-// to **load** semantic data from a semantic web service.
-VIE.prototype.Loadable = function (options) {
-    this.init(options,"load");
-};
-VIE.prototype.Loadable.prototype = new VIE.prototype.Able();
-
-// ## VIE.Savable
-// A ```VIE.Savable``` is a wrapper around the deferred object
-// to **save** entities by a VIE service. The RDFaService would write the data
-// in the HTML as RDFa, the StanbolService stores the data in its Entityhub, etc.
-VIE.prototype.Savable = function(options){
-    this.init(options, "save");
-};
-VIE.prototype.Savable.prototype = new VIE.prototype.Able();
-
-// ## VIE.Removable
-// A ```VIE.Removable``` is a wrapper around the deferred object
-// to **remove** semantic data from a semantic web service.
-VIE.prototype.Removable = function(options){
-    this.init(options, "remove");
-};
-VIE.prototype.Removable.prototype = new VIE.prototype.Able();
-
-// ## VIE.Analyzable
-// A ```VIE.Analyzable``` is a wrapper around the deferred object
-// to **analyze** data and extract semantic information with the
-// help of a semantic web service.
-VIE.prototype.Analyzable = function (options) {
-    this.init(options, "analyze");
-};
-VIE.prototype.Analyzable.prototype = new VIE.prototype.Able();
-
-// ## VIE.Findable
-// A ```VIE.Findable``` is a wrapper around the deferred object
-// to **find** semantic data on a semantic storage.
-VIE.prototype.Findable = function (options) {
-    this.init(options, "find");
-};
-VIE.prototype.Findable.prototype = new VIE.prototype.Able();
-
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-
-// ## VIE Utils
-//
-// The here-listed methods are utility methods for the day-to-day
-// VIE.js usage. All methods are within the static namespace ```VIE.Util```.
-VIE.Util = {
-
-// ### VIE.Util.toCurie(uri, safe, namespaces)
-// This method converts a given
-// URI into a CURIE (or SCURIE), based on the given ```VIE.Namespaces``` object.
-// If the given uri is already a URI, it is left untouched and directly returned.
-// If no prefix could be found, an ```Error``` is thrown.
-// **Parameters**:
-// *{string}* **uri** The URI to be transformed.
-// *{boolean}* **safe** A flag whether to generate CURIEs or SCURIEs.
-// *{VIE.Namespaces}* **namespaces** The namespaces to be used for the prefixes.
-// **Throws**:
-// *{Error}* If no prefix could be found in the passed namespaces.
-// **Returns**:
-// *{string}* The CURIE or SCURIE.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var uri = "<http://dbpedia.org/ontology/Person>";
-//     VIE.Util.toCurie(uri, false, ns); // --> dbp:Person
-//     VIE.Util.toCurie(uri, true, ns); // --> [dbp:Person]
-    toCurie : function (uri, safe, namespaces) {
-        if (VIE.Util.isCurie(uri, namespaces)) {
-            return uri;
-        }
-        var delim = ":";
-        for (var k in namespaces.toObj()) {
-            if (uri.indexOf(namespaces.get(k)) === 1) {
-                var pattern = new RegExp("^" + "<?" + namespaces.get(k));
-                if (k === '') {
-                    delim = '';
-                }
-                return ((safe)? "[" : "") +
-                        uri.replace(pattern, k + delim).replace(/>$/, '') +
-                        ((safe)? "]" : "");
-            }
-        }
-        throw new Error("No prefix found for URI '" + uri + "'!");
-    },
-
-// ### VIE.Util.isCurie(curie, namespaces)
-// This method checks, whether
-// the given string is a CURIE and returns ```true``` if so and ```false```otherwise.
-// **Parameters**:
-// *{string}* **curie** The CURIE (or SCURIE) to be checked.
-// *{VIE.Namespaces}* **namespaces** The namespaces to be used for the prefixes.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* ```true``` if the given curie is a CURIE or SCURIE and ```false``` otherwise.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var uri = "<http://dbpedia.org/ontology/Person>";
-//     var curie = "dbp:Person";
-//     var scurie = "[dbp:Person]";
-//     var text = "This is some text.";
-//     VIE.Util.isCurie(uri, ns);    // --> false
-//     VIE.Util.isCurie(curie, ns);  // --> true
-//     VIE.Util.isCurie(scurie, ns); // --> true
-//     VIE.Util.isCurie(text, ns);   // --> false
-    isCurie : function (curie, namespaces) {
-        if (VIE.Util.isUri(curie)) {
-            return false;
-        } else {
-            try {
-                VIE.Util.toUri(curie, namespaces);
-                return true;
-            } catch (e) {
-                return false;
-            }
-        }
-    },
-
-// ### VIE.Util.toUri(curie, namespaces)
-// This method converts a
-// given CURIE (or save CURIE) into a URI, based on the given ```VIE.Namespaces``` object.
-// **Parameters**:
-// *{string}* **curie** The CURIE to be transformed.
-// *{VIE.Namespaces}* **namespaces** The namespaces object
-// **Throws**:
-// *{Error}* If no URI could be assembled.
-// **Returns**:
-// *{string}* : A string, representing the URI.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var curie = "dbp:Person";
-//     var scurie = "[dbp:Person]";
-//     VIE.Util.toUri(curie, ns);
-//          --> <http://dbpedia.org/ontology/Person>
-//     VIE.Util.toUri(scurie, ns);
-//          --> <http://dbpedia.org/ontology/Person>
-    toUri : function (curie, namespaces) {
-        if (VIE.Util.isUri(curie)) {
-            return curie;
-        }
-        var delim = ":";
-        for (var prefix in namespaces.toObj()) {
-            if (prefix !== "" && (curie.indexOf(prefix + ":") === 0 || curie.indexOf("[" + prefix + ":") === 0)) {
-                var pattern = new RegExp("^" + "\\[{0,1}" + prefix + delim);
-                return "<" + curie.replace(pattern, namespaces.get(prefix)).replace(/\]{0,1}$/, '') + ">";
-            }
-        }
-        /* check for the default namespace */
-        if (curie.indexOf(delim) === -1) {
-            return "<" + namespaces.base() + curie + ">";
-        }
-        throw new Error("No prefix found for CURIE '" + curie + "'!");
-    },
-
-// ### VIE.Util.isUri(something)
-// This method checks, whether the given string is a URI.
-// **Parameters**:
-// *{string}* **something** : The string to be checked.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* : ```true``` if the string is a URI, ```false``` otherwise.
-// **Example usage**:
-//
-//     var uri = "<http://dbpedia.org/ontology/Person>";
-//     var curie = "dbp:Person";
-//     VIE.Util.isUri(uri);   // --> true
-//     VIE.Util.isUri(curie); // --> false
-    isUri : function (something) {
-        return (typeof something === "string" && something.search(/^<.+>$/) === 0);
-    },
-
-// ### VIE.Util.mapAttributeNS(attr, ns)
-// This method maps an attribute of an entity into namespaces if they have CURIEs.
-// **Parameters**:
-// *{string}* **attr** : The attribute to be transformed.
-// *{VIE.Namespaces}* **ns** : The namespaces.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{string}* : The transformed attribute's name.
-// **Example usage**:
-//
-//      var attr = "name";
-//      var ns = myVIE.namespaces;
-//      VIE.Util.mapAttributeNS(attr, ns); // '<' + ns.base() + attr + '>';
-    mapAttributeNS : function (attr, ns) {
-        var a = attr;
-        if (ns.isUri (attr) || attr.indexOf('@') === 0) {
-            //ignore
-        } else if (ns.isCurie(attr)) {
-            a = ns.uri(attr);
-        } else if (!ns.isUri(attr)) {
-            if (attr.indexOf(":") === -1) {
-                a = '<' + ns.base() + attr + '>';
-            } else {
-                a = '<' + attr + '>';
-            }
-        }
-        return a;
-    },
-
-// ### VIE.Util.rdf2Entities(service, results)
-// This method converts *rdf/json* data from an external service
-// into VIE.Entities.
-// **Parameters**:
-// *{object}* **service** The service that retrieved the data.
-// *{object}* **results** The data to be transformed.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{[VIE.Entity]}* : An array, containing VIE.Entity instances which have been transformed from the given data.
-    rdf2Entities: function (service, results) {
-        if (typeof jQuery.rdf !== 'function') {
-            /* fallback if no rdfQuery has been loaded */
-            return VIE.Util._rdf2EntitiesNoRdfQuery(service, results);
-        }
-        try {
-            var rdf = (results instanceof jQuery.rdf)?
-                    results.base(service.vie.namespaces.base()) :
-                        jQuery.rdf().base(service.vie.namespaces.base()).load(results, {});
-
-            /* if the service contains rules to apply special transformation, they are executed here.*/
-            if (service.rules) {
-                var rules = jQuery.rdf.ruleset();
-                for (var prefix in service.vie.namespaces.toObj()) {
-                    if (prefix !== "") {
-                        rules.prefix(prefix, service.vie.namespaces.get(prefix));
-                    }
-                }
-                for (var i = 0; i < service.rules.length; i++)if(service.rules.hasOwnProperty(i)) {
-                    var rule = service.rules[i];
-                    rules.add(rule.left, rule.right);
-                }
-                rdf = rdf.reason(rules, 10); /* execute the rules only 10 times to avoid looping */
-            }
-            var entities = {};
-            rdf.where('?subject ?property ?object').each(function() {
-                var subject = this.subject.toString();
-                if (!entities[subject]) {
-                    entities[subject] = {
-                        '@subject': subject,
-                        '@context': service.vie.namespaces.toObj(true),
-                        '@type': []
-                    };
-                }
-                var propertyUri = this.property.toString();
-                var propertyCurie;
-
-                try {
-                    propertyCurie = service.vie.namespaces.curie(propertyUri);
-                    //jQuery.createCurie(propertyUri, {namespaces: service.vie.namespaces.toObj(true)});
-                } catch (e) {
-                    propertyCurie = propertyUri;
-                    // console.warn(propertyUri + " doesn't have a namespace definition in '", service.vie.namespaces.toObj());
-                }
-                entities[subject][propertyCurie] = entities[subject][propertyCurie] || [];
-
-                function getValue(rdfQueryLiteral){
-                    if(typeof rdfQueryLiteral.value === "string"){
-                        if (rdfQueryLiteral.lang){
-                            var literal = {
-                                toString: function(){
-                                    return this["@value"];
-                                },
-                                "@value": rdfQueryLiteral.value.replace(/^"|"$/g, ''),
-                                "@language": rdfQueryLiteral.lang
-                            };
-                            return literal;
-                        }
-                        else
-                            return rdfQueryLiteral.value;
-                        return rdfQueryLiteral.value.toString();
-                    } else if (rdfQueryLiteral.type === "uri"){
-                        return rdfQueryLiteral.toString();
-                    } else {
-                        return rdfQueryLiteral.value;
-                    }
-                }
-                entities[subject][propertyCurie].push(getValue(this.object));
-            });
-
-            _(entities).each(function(ent){
-                ent["@type"] = ent["@type"].concat(ent["rdf:type"]);
-                delete ent["rdf:type"];
-                _(ent).each(function(value, property){
-                    if(value.length === 1){
-                        ent[property] = value[0];
-                    }
-                });
-            });
-
-            var vieEntities = [];
-            jQuery.each(entities, function() {
-                var entityInstance = new service.vie.Entity(this);
-                entityInstance = service.vie.entities.addOrUpdate(entityInstance);
-                vieEntities.push(entityInstance);
-            });
-            return vieEntities;
-        } catch (e) {
-            console.warn("Something went wrong while parsing the returned results!", e);
-            return [];
-        }
-    },
-
-    /*
-    VIE.Util.getPreferredLangForPreferredProperty(entity, preferredFields, preferredLanguages)
-    looks for specific ranking fields and languages. It calculates all possibilities and gives them
-    a score. It returns the value with the best score.
-    */
-    getPreferredLangForPreferredProperty: function(entity, preferredFields, preferredLanguages) {
-      var l, labelArr, lang, p, property, resArr, valueArr, _len, _len2,
-        _this = this;
-      resArr = [];
-      /* Try to find a label in the preferred language
-      */
-      _.each(preferredLanguages, function (lang) {
-        _.each(preferredFields, function (property) {
-          labelArr = null;
-          /* property can be a string e.g. "skos:prefLabel"
-          */
-          if (typeof property === "string" && entity.get(property)) {
-            labelArr = _.flatten([entity.get(property)]);
-            _(labelArr).each(function(label) {
-              /*
-              The score is a natural number with 0 for the
-              best candidate with the first preferred language
-              and first preferred property
-              */
-              var labelLang, score, value;
-              score = p;
-              labelLang = label["@language"];
-              /*
-                                      legacy code for compatibility with uotdated stanbol,
-                                      to be removed after may 2012
-              */
-              if (typeof label === "string" && (label.indexOf("@") === label.length - 3 || label.indexOf("@") === label.length - 5)) {
-                labelLang = label.replace(/(^\"*|\"*@)..(..)?$/g, "");
-              }
-              /* end of legacy code
-              */
-              if (labelLang) {
-                if (labelLang === lang) {
-                  score += l;
-                } else {
-                  score += 20;
-                }
-              } else {
-                score += 10;
-              }
-              value = label.toString();
-              /* legacy code for compatibility with uotdated stanbol, to be removed after may 2012
-              */
-              value = value.replace(/(^\"*|\"*@..$)/g, "");
-              /* end of legacy code
-              */
-              return resArr.push({
-                score: score,
-                value: value
-              });
-            });
-            /*
-            property can be an object like
-            {
-              property: "skos:broader",
-              makeLabel: function(propertyValueArr) { return "..."; }
-            }
-            */
-          } else if (typeof property === "object" && entity.get(property.property)) {
-            valueArr = _.flatten([entity.get(property.property)]);
-            valueArr = _(valueArr).map(function(termUri) {
-              if (termUri.isEntity) {
-                return termUri.getSubject();
-              } else {
-                return termUri;
-              }
-            });
-            resArr.push({
-              score: p,
-              value: property.makeLabel(valueArr)
-            });
-          }
-        });
-      });
-      /*
-              take the result with the best score
-      */
-      resArr = _(resArr).sortBy(function(a) {
-        return a.score;
-      });
-      if(resArr.length) {
-        return resArr[0].value;
-      } else {
-        return "n/a";
-      }
-    },
-
-
-// ### VIE.Util._rdf2EntitiesNoRdfQuery(service, results)
-// This is a **private** method which should
-// only be accessed through ```VIE.Util._rdf2Entities()``` and is a helper method in case there is no
-// rdfQuery loaded (*not recommended*).
-// **Parameters**:
-// *{object}* **service** The service that retrieved the data.
-// *{object}* **results** The data to be transformed.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{[VIE.Entity]}* : An array, containing VIE.Entity instances which have been transformed from the given data.
-    _rdf2EntitiesNoRdfQuery: function (service, results) {
-        var jsonLD = [];
-        _.forEach(results, function(value, key) {
-            var entity = {};
-            entity['@subject'] = '<' + key + '>';
-            _.forEach(value, function(triples, predicate) {
-                predicate = '<' + predicate + '>';
-                _.forEach(triples, function(triple) {
-                    if (triple.type === 'uri') {
-                        triple.value = '<' + triple.value + '>';
-                    }
-
-                    if (entity[predicate] && !_.isArray(entity[predicate])) {
-                        entity[predicate] = [entity[predicate]];
-                    }
-
-                    if (_.isArray(entity[predicate])) {
-                        entity[predicate].push(triple.value);
-                        return;
-                    }
-                    entity[predicate] = triple.value;
-                });
-            });
-            jsonLD.push(entity);
-        });
-        return jsonLD;
-    },
-
-// ### VIE.Util.loadSchemaOrg(vie, SchemaOrg, baseNS)
-// This method is a wrapper around
-// the <a href="http://schema.org/">schema.org</a> ontology. It adds all the
-// given types and properties as ```VIE.Type``` instances to the given VIE instance.
-// If the paramenter **baseNS** is set, the method automatically sets the namespace
-// to the provided one. If it is not set, it will keep the base namespace of VIE untouched.
-// **Parameters**:
-// *{VIE}* **vie** The instance of ```VIE```.
-// *{object}* **SchemaOrg** The data imported from schema.org.
-// *{string|undefined}* **baseNS** If set, this will become the new baseNamespace within the given ```VIE``` instance.
-// **Throws**:
-// *{Error}* If the parameter was not given.
-// **Returns**:
-// *nothing*
-    loadSchemaOrg : function (vie, SchemaOrg, baseNS) {
-
-        if (!SchemaOrg) {
-            throw new Error("Please load the schema.json file.");
-        }
-        vie.types.remove("<http://schema.org/Thing>");
-
-        var baseNSBefore = (baseNS)? baseNS : vie.namespaces.base();
-        vie.namespaces.base(baseNS);
-
-        var datatypeMapping = {
-            'DataType': 'xsd:anyType',
-            'Boolean' : 'xsd:boolean',
-            'Date'    : 'xsd:date',
-            'DateTime': 'xsd:dateTime',
-            'Time'    : 'xsd:time',
-            'Float'   : 'xsd:float',
-            'Integer' : 'xsd:integer',
-            'Number'  : 'xsd:anySimpleType',
-            'Text'    : 'xsd:string',
-            'URL'     : 'xsd:anyURI'
-        };
-
-        var dataTypeHelper = function (ancestors, id) {
-            var type = vie.types.add(id, [{'id' : 'value', 'range' : datatypeMapping[id]}]);
-
-            for (var i = 0; i < ancestors.length; i++) {
-                var supertype = (vie.types.get(ancestors[i]))? vie.types.get(ancestors[i]) :
-                    dataTypeHelper.call(vie, SchemaOrg.datatypes[ancestors[i]].supertypes, ancestors[i]);
-                type.inherit(supertype);
-            }
-            return type;
-        };
-
-        for (var dt in SchemaOrg.datatypes) {
-            if (!vie.types.get(dt)) {
-                var ancestors = SchemaOrg.datatypes[dt].supertypes;
-                dataTypeHelper.call(vie, ancestors, dt);
-            }
-        }
-
-        var metadataHelper = function (definition) {
-            var metadata = {};
-
-            if (definition.label) {
-              metadata.label = definition.label;
-            }
-
-            if (definition.url) {
-              metadata.url = definition.url;
-            }
-
-            if (definition.comment) {
-              metadata.comment = definition.comment;
-            }
-
-            if (definition.metadata) {
-              metadata = _.extend(metadata, definition.metadata);
-            }
-            return metadata;
-        };
-
-        var typeProps = function (id) {
-            var props = [];
-            _.each(SchemaOrg.types[id].specific_properties, function (pId) {
-                var property = SchemaOrg.properties[pId];
-                props.push({
-                    'id'    : property.id,
-                    'range' : property.ranges,
-                    'min'   : property.min,
-                    'max'   : property.max,
-                    'metadata': metadataHelper(property)
-                });
-            });
-            return props;
-        };
-
-        var typeHelper = function (ancestors, id, props, metadata) {
-            var type = vie.types.add(id, props, metadata);
-
-            for (var i = 0; i < ancestors.length; i++) {
-                var supertype = (vie.types.get(ancestors[i]))? vie.types.get(ancestors[i]) :
-                    typeHelper.call(vie, SchemaOrg.types[ancestors[i]].supertypes, ancestors[i], typeProps.call(vie, ancestors[i]), metadataHelper(SchemaOrg.types[ancestors[i]]));
-                type.inherit(supertype);
-            }
-            if (id === "Thing" && !type.isof("owl:Thing")) {
-                type.inherit("owl:Thing");
-            }
-            return type;
-        };
-
-        _.each(SchemaOrg.types, function (typeDef) {
-            if (vie.types.get(typeDef.id)) {
-                return;
-            }
-            var ancestors = typeDef.supertypes;
-            var metadata = metadataHelper(typeDef);
-            typeHelper.call(vie, ancestors, typeDef.id, typeProps.call(vie, typeDef.id), metadata);
-        });
-
-        /* set the namespace to either the old value or the provided baseNS value */
-        vie.namespaces.base(baseNSBefore);
-    },
-
-// ### VIE.Util.getEntityTypeUnion(entity)
-// This generates a entity-specific VIE type that is a subtype of all the
-// types of the entity. This makes it easier to deal with attribute definitions
-// specific to an entity because they're merged to a single list. This custom
-// type is transient, meaning that it won't be automatilly added to the entity
-// or the VIE type registry.
-    getEntityTypeUnion : function(entity) {
-      var vie = entity.vie;
-      return new vie.Type('Union').inherit(entity.get('@type'));
-    },
-
-// ### VIE.Util.getFormSchemaForType(type)
-// This creates a [Backbone Forms](https://github.com/powmedia/backbone-forms)
-// -compatible form schema for any VIE Type.
-    getFormSchemaForType : function(type, allowNested) {
-      var schema = {};
-
-      // Generate a schema
-      _.each(type.attributes.toArray(), function (attribute) {
-        var key = VIE.Util.toCurie(attribute.id, false, attribute.vie.namespaces);
-        schema[key] = VIE.Util.getFormSchemaForAttribute(attribute);
-      });
-
-      // Clean up unknown attribute types
-      _.each(schema, function (field, id) {
-        if (!field.type) {
-          delete schema[id];
-        }
-
-        if (field.type === 'URL') {
-          field.type = 'Text';
-          field.dataType = 'url';
-        }
-
-        if (field.type === 'List' && !field.listType) {
-          delete schema[id];
-        }
-
-        if (!allowNested) {
-          if (field.type === 'NestedModel' || field.listType === 'NestedModel') {
-            delete schema[id];
-          }
-        }
-      });
-
-      return schema;
-    },
-
-/// ### VIE.Util.getFormSchemaForAttribute(attribute)
-    getFormSchemaForAttribute : function(attribute) {
-      var primaryType = attribute.range[0];
-      var schema = {};
-
-      var getWidgetForType = function (type) {
-        switch (type) {
-          case 'xsd:anySimpleType':
-          case 'xsd:float':
-          case 'xsd:integer':
-            return 'Number';
-          case 'xsd:string':
-            return 'Text';
-          case 'xsd:date':
-            return 'Date';
-          case 'xsd:dateTime':
-            return 'DateTime';
-          case 'xsd:boolean':
-            return 'Checkbox';
-          case 'xsd:anyURI':
-            return 'URL';
-          default:
-            var typeType = attribute.vie.types.get(type);
-            if (!typeType) {
-              return null;
-            }
-            if (typeType.attributes.get('value')) {
-              // Convert to proper xsd type
-              return getWidgetForType(typeType.attributes.get('value').range[0]);
-            }
-            return 'NestedModel';
-        }
-      };
-
-      // TODO: Generate a nicer label
-      schema.title = VIE.Util.toCurie(attribute.id, false, attribute.vie.namespaces);
-
-      // TODO: Handle attributes linking to other VIE entities
-
-      if (attribute.min > 0) {
-        schema.validators = ['required'];
-      }
-
-      if (attribute.max > 1) {
-        schema.type = 'List';
-        schema.listType = getWidgetForType(primaryType);
-        if (schema.listType === 'NestedModel') {
-          schema.nestedModelType = primaryType;
-        }
-        return schema;
-      }
-
-      schema.type = getWidgetForType(primaryType);
-      if (schema.type === 'NestedModel') {
-        schema.nestedModelType = primaryType;
-      }
-      return schema;
-    },
-
-// ### VIE.Util.getFormSchema(entity)
-// This creates a [Backbone Forms](https://github.com/powmedia/backbone-forms)
-// -compatible form schema for any VIE Entity. The form schema creation
-// utilizes type information attached to the entity.
-// **Parameters**:
-// *{```Entity```}* **entity** An instance of VIE ```Entity```.
-// **Throws**:
-// *nothing*..
-// **Returns**:
-// *{object}* a JavaScript object representation of the form schema
-    getFormSchema : function(entity) {
-      if (!entity || !entity.isEntity) {
-        return {};
-      }
-
-      var unionType = VIE.Util.getEntityTypeUnion(entity);
-      var schema = VIE.Util.getFormSchemaForType(unionType, true);
-
-      // Handle nested models
-      _.each(schema, function (property, id) {
-        if (property.type !== 'NestedModel' && property.listType !== 'NestedModel') {
-          return;
-        }
-        schema[id].model = entity.vie.getTypedEntityClass(property.nestedModelType);
-      });
-
-      return schema;
-    },
-
-// ### VIE.Util.xsdDateTime(date)
-// This transforms a ```Date``` instance into an xsd:DateTime format.
-// **Parameters**:
-// *{```Date```}* **date** An instance of a javascript ```Date```.
-// **Throws**:
-// *nothing*..
-// **Returns**:
-// *{string}* A string representation of the dateTime in the xsd:dateTime format.
-    xsdDateTime : function(date) {
-        function pad(n) {
-            var s = n.toString();
-            return s.length < 2 ? '0'+s : s;
-        }
-
-        var yyyy = date.getFullYear();
-        var mm1  = pad(date.getMonth()+1);
-        var dd   = pad(date.getDate());
-        var hh   = pad(date.getHours());
-        var mm2  = pad(date.getMinutes());
-        var ss   = pad(date.getSeconds());
-
-        return yyyy +'-' +mm1 +'-' +dd +'T' +hh +':' +mm2 +':' +ss;
-    },
-
-// ### VIE.Util.extractLanguageString(entity, attrs, langs)
-// This method extracts a literal string from an entity, searching through the given attributes and languages.
-// **Parameters**:
-// *{```VIE.Entity```}* **entity** An instance of a VIE.Entity.
-// *{```array|string```}* **attrs** Either a string or an array of possible attributes.
-// *{```array|string```}* **langs** Either a string or an array of possible languages.
-// **Throws**:
-// *nothing*..
-// **Returns**:
-// *{string|undefined}* The string that was found at the attribute with the wanted language, undefined if nothing could be found.
-// **Example usage**:
-//
-//          var attrs = ["name", "rdfs:label"];
-//          var langs = ["en", "de"];
-//          VIE.Util.extractLanguageString(someEntity, attrs, langs); // "Barack Obama";
-    extractLanguageString : function(entity, attrs, langs) {
-        var p, attr, name, i, n;
-        if (entity && typeof entity !== "string") {
-            attrs = (_.isArray(attrs))? attrs : [ attrs ];
-            langs = (_.isArray(langs))? langs : [ langs ];
-            for (p = 0; p < attrs.length; p++) {
-                for (var l = 0; l < langs.length; l++) {
-                    var lang = langs[l];
-                    attr = attrs[p];
-                    if (entity.has(attr)) {
-                        name = entity.get(attr);
-                        name = (_.isArray(name))? name : [ name ];
-                        for (i = 0; i < name.length; i++) {
-                            n = name[i];
-                            if (n.isEntity) {
-                                n = VIE.Util.extractLanguageString(n, attrs, lang);
-                            } else if (typeof n === "string") {
-                                n = n;
-                            } else {
-                                n = "";
-                            }
-                            if (n && n.indexOf('@' + lang) > -1) {
-                                return n.replace(/"/g, "").replace(/@[a-z]+/, '').trim();
-                            }
-                        }
-                    }
-                }
-            }
-            /* let's do this again in case we haven't found a name but are dealing with
-            broken data where no language is given */
-            for (p = 0; p < attrs.length; p++) {
-                attr = attrs[p];
-                if (entity.has(attr)) {
-                    name = entity.get(attr);
-                    name = (_.isArray(name))? name : [ name ];
-                    for (i = 0; i < name.length; i++) {
-                        n = name[i];
-                        if (n.isEntity) {
-                            n = VIE.Util.extractLanguageString(n, attrs, []);
-                        }
-                        if (n && (typeof n === "string") && n.indexOf('@') === -1) {
-                            return n.replace(/"/g, "").replace(/@[a-z]+/, '').trim();
-                        }
-                    }
-                }
-            }
-        }
-        return undefined;
-    },
-
-// ### VIE.Util.transformationRules(service)
-// This returns a default set of rdfQuery rules that transform semantic data into the
-// VIE entity types.
-// **Parameters**:
-// *{object}* **service** An instance of a vie.service.
-// **Throws**:
-// *nothing*..
-// **Returns**:
-// *{array}* An array of rules with 'left' and 'right' side.
-    transformationRules : function (service) {
-        var res = [
-            // rule(s) to transform a dbpedia:Person into a VIE:Person
-             {
-                'left' : [
-                    '?subject a dbpedia:Person',
-                    '?subject rdfs:label ?label'
-                 ],
-                 'right': function(ns){
-                     return function(){
-                         return [
-                             jQuery.rdf.triple(this.subject.toString(),
-                                 'a',
-                                 '<' + ns.base() + 'Person>', {
-                                     namespaces: ns.toObj()
-                                 }),
-                             jQuery.rdf.triple(this.subject.toString(),
-                                 '<' + ns.base() + 'name>',
-                                 this.label, {
-                                     namespaces: ns.toObj()
-                                 })
-                             ];
-                     };
-                 }(service.vie.namespaces)
-             },
-             // rule(s) to transform a foaf:Person into a VIE:Person
-             {
-             'left' : [
-                     '?subject a foaf:Person',
-                     '?subject rdfs:label ?label'
-                  ],
-                  'right': function(ns){
-                      return function(){
-                          return [
-                              jQuery.rdf.triple(this.subject.toString(),
-                                  'a',
-                                  '<' + ns.base() + 'Person>', {
-                                      namespaces: ns.toObj()
-                                  }),
-                              jQuery.rdf.triple(this.subject.toString(),
-                                  '<' + ns.base() + 'name>',
-                                  this.label, {
-                                      namespaces: ns.toObj()
-                                  })
-                              ];
-                      };
-                  }(service.vie.namespaces)
-              },
-             // rule(s) to transform a dbpedia:Place into a VIE:Place
-             {
-                 'left' : [
-                     '?subject a dbpedia:Place',
-                     '?subject rdfs:label ?label'
-                  ],
-                  'right': function(ns) {
-                      return function() {
-                          return [
-                          jQuery.rdf.triple(this.subject.toString(),
-                              'a',
-                              '<' + ns.base() + 'Place>', {
-                                  namespaces: ns.toObj()
-                              }),
-                          jQuery.rdf.triple(this.subject.toString(),
-                                  '<' + ns.base() + 'name>',
-                              this.label.toString(), {
-                                  namespaces: ns.toObj()
-                              })
-                          ];
-                      };
-                  }(service.vie.namespaces)
-              },
-             // rule(s) to transform a dbpedia:City into a VIE:City
-              {
-                 'left' : [
-                     '?subject a dbpedia:City',
-                     '?subject rdfs:label ?label',
-                     '?subject dbpedia:abstract ?abs',
-                     '?subject dbpedia:country ?country'
-                  ],
-                  'right': function(ns) {
-                      return function() {
-                          return [
-                          jQuery.rdf.triple(this.subject.toString(),
-                              'a',
-                              '<' + ns.base() + 'City>', {
-                                  namespaces: ns.toObj()
-                              }),
-                          jQuery.rdf.triple(this.subject.toString(),
-                                  '<' + ns.base() + 'name>',
-                              this.label.toString(), {
-                                  namespaces: ns.toObj()
-                              }),
-                          jQuery.rdf.triple(this.subject.toString(),
-                                  '<' + ns.base() + 'description>',
-                              this.abs.toString(), {
-                                  namespaces: ns.toObj()
-                              }),
-                          jQuery.rdf.triple(this.subject.toString(),
-                                  '<' + ns.base() + 'containedIn>',
-                              this.country.toString(), {
-                                  namespaces: ns.toObj()
-                              })
-                          ];
-                      };
-                  }(service.vie.namespaces)
-              }
-        ];
-        return res;
-    },
-
-    getAdditionalRules : function (service) {
-
-        var mapping = {
-            Work : "CreativeWork",
-            Film : "Movie",
-            TelevisionEpisode : "TVEpisode",
-            TelevisionShow : "TVSeries", // not listed as equivalent class on dbpedia.org
-            Website : "WebPage",
-            Painting : "Painting",
-            Sculpture : "Sculpture",
-
-            Event : "Event",
-            SportsEvent : "SportsEvent",
-            MusicFestival : "Festival",
-            FilmFestival : "Festival",
-
-            Place : "Place",
-            Continent : "Continent",
-            Country : "Country",
-            City : "City",
-            Airport : "Airport",
-            Station : "TrainStation", // not listed as equivalent class on dbpedia.org
-            Hospital : "GovernmentBuilding",
-            Mountain : "Mountain",
-            BodyOfWater : "BodyOfWater",
-
-            Company : "Organization",
-            Person : "Person"
-        };
-
-        var additionalRules = [];
-        _.each(mapping, function (map, key) {
-            var tripple = {
-                'left' : [ '?subject a dbpedia:' + key, '?subject rdfs:label ?label' ],
-                'right' : function(ns) {
-                    return function() {
-                        return [ jQuery.rdf.triple(this.subject.toString(), 'a', '<' + ns.base() + map + '>', {
-                            namespaces : ns.toObj()
-                        }), jQuery.rdf.triple(this.subject.toString(), '<' + ns.base() + 'name>', this.label.toString(), {
-                            namespaces : ns.toObj()
-                        }) ];
-                    };
-                }(service.vie.namespaces)
-            };
-            additionalRules.push(tripple);
-        });
-        return additionalRules;
-    }
-};
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-
-// ## VIE Entities
-//
-// In VIE there are two low-level model types for storing data.
-// **Collections** and **Entities**. Considering `var v = new VIE();` a VIE instance,
-// `v.entities` is a Collection with `VIE Entity` objects in it.
-// VIE internally uses JSON-LD to store entities.
-//
-// Each Entity has a few special attributes starting with an `@`. VIE has an API
-// for correctly using these attributes, so in order to stay compatible with later
-// versions of the library, possibly using a later version of JSON-LD, use the API
-// to interact with your entities.
-//
-// * `@subject` stands for the identifier of the entity. Use `e.getSubject()`
-// * `@type` stores the explicit entity types. VIE internally handles Type hierarchy,
-// which basically enables to define subtypes and supertypes. Every entity has
-// the type 'owl:Thing'. Read more about Types in <a href="Type.html">VIE.Type</a>.
-// * `@context` stores namespace definitions used in the entity. Read more about
-// Namespaces in <a href="Namespace.html">VIE Namespaces</a>.
-VIE.prototype.Entity = function(attrs, opts) {
-
-    attrs = (attrs)? attrs : {};
-    opts = (opts)? opts : {};
-
-    var self = this;
-
-    if (attrs['@type'] !== undefined) {
-        attrs['@type'] = (_.isArray(attrs['@type']))? attrs['@type'] : [ attrs['@type'] ];
-        attrs['@type'] = _.map(attrs['@type'], function(val){
-            if (!self.vie.types.get(val)) {
-                //if there is no such type -> add it and let it inherit from "owl:Thing"
-                self.vie.types.add(val).inherit("owl:Thing");
-            }
-            return self.vie.types.get(val).id;
-        });
-        attrs['@type'] = (attrs['@type'].length === 1)? attrs['@type'][0] : attrs['@type'];
-    } else {
-        // provide "owl:Thing" as the default type if none was given
-        attrs['@type'] = self.vie.types.get("owl:Thing").id;
-    }
-
-    //the following provides full seamless namespace support
-    //for attributes. It should not matter, if you
-    //query for `model.get('name')` or `model.get('foaf:name')`
-    //or even `model.get('http://xmlns.com/foaf/0.1/name');`
-    //However, if we just overwrite `set()` and `get()`, this
-    //raises a lot of side effects, so we need to expand
-    //the attributes before we create the model.
-    _.each (attrs, function (value, key) {
-        var newKey = VIE.Util.mapAttributeNS(key, this.namespaces);
-        if (key !== newKey) {
-            delete attrs[key];
-            attrs[newKey] = value;
-        }
-    }, self.vie);
-
-    var Model = Backbone.Model.extend({
-        idAttribute: '@subject',
-
-        initialize: function(attributes, options) {
-            if (attributes['@subject']) {
-                this.id = this['@subject'] = this.toReference(attributes['@subject']);
-            } else {
-                this.id = this['@subject'] = attributes['@subject'] = this.cid.replace('c', '_:bnode');
-            }
-            return this;
-        },
-
-        schema: function() {
-          return VIE.Util.getFormSchema(this);
-        },
-
-        // ### Getter, Has, Setter
-        // #### `.get(attr)`
-        // To be able to communicate to a VIE Entity you can use a simple get(property)
-        // command as in `entity.get('rdfs:label')` which will give you one or more literals.
-        // If the property points to a collection, its entities can be browsed further.
-        get: function (attr) {
-            attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
-            var value = Backbone.Model.prototype.get.call(this, attr);
-            value = (_.isArray(value))? value : [ value ];
-
-            value = _.map(value, function(v) {
-                if (v !== undefined && attr === '@type' && self.vie.types.get(v)) {
-                    return self.vie.types.get(v);
-                } else if (v !== undefined && self.vie.entities.get(v)) {
-                    return self.vie.entities.get(v);
-                } else {
-                    return v;
-                }
-            }, this);
-            if(value.length === 0) {
-                return undefined;
-            }
-            // if there is only one element, just return that one
-            value = (value.length === 1)? value[0] : value;
-            return value;
-        },
-
-        // #### `.has(attr)`
-        // Sometimes you'd like to determine if a specific attribute is set
-        // in an entity. For this reason you can call for example `person.has('friend')`
-        // to determine if a person entity has friends.
-        has: function(attr) {
-            attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
-            return Backbone.Model.prototype.has.call(this, attr);
-        },
-
-        // #### `.set(attrName, value, opts)`,
-        // The `options` parameter always refers to a `Backbone.Model.set` `options` object.
-        //
-        // **`.set(attributes, options)`** is the most universal way of calling the
-        // `.set` method. In this case the `attributes` object is a map of all
-        // attributes to be changed.
-        set : function(attrs, options, opts) {
-            if (!attrs) {
-                return this;
-            }
-
-            if (attrs['@subject']) {
-                attrs['@subject'] = this.toReference(attrs['@subject']);
-            }
-
-            // Use **`.set(attrName, value, options)`** for setting or changing exactly one
-            // entity attribute.
-            if (typeof attrs === "string") {
-                var obj = {};
-                obj[attrs] = options;
-                return this.set(obj, opts);
-            }
-            // **`.set(entity)`**: In case you'd pass a VIE entity,
-            // the passed entities attributes are being set for the entity.
-            if (attrs.attributes) {
-                attrs = attrs.attributes;
-            }
-            var self = this;
-            var coll;
-            // resolve shortened URIs like rdfs:label..
-            _.each (attrs, function (value, key) {
-                var newKey = VIE.Util.mapAttributeNS(key, self.vie.namespaces);
-                if (key !== newKey) {
-                    delete attrs[key];
-                    attrs[newKey] = value;
-                }
-            }, this);
-            // Finally iterate through the *attributes* to be set and prepare
-            // them for the Backbone.Model.set method.
-            _.each (attrs, function (value, key) {
-               if (!value) { return; }
-               if (key.indexOf('@') === -1) {
-                   if (value.isCollection) {
-                       // ignore
-                       value.each(function (child) {
-                           self.vie.entities.addOrUpdate(child);
-                       });
-                   } else if (value.isEntity) {
-                       self.vie.entities.addOrUpdate(value);
-                       coll = new self.vie.Collection(value, {
-                         vie: self.vie,
-                         predicate: key
-                       });
-                       attrs[key] = coll;
-                   } else if (_.isArray(value)) {
-                       if (this.attributes[key] && this.attributes[key].isCollection) {
-                         var newEntities = this.attributes[key].addOrUpdate(value);
-                         attrs[key] = this.attributes[key];
-                         attrs[key].reset(newEntities);
-                       }
-                   } else if (value["@value"]) {
-                       // The value is a literal object, ignore
-                   } else if (_.isObject(value) && !_.isDate(value)) {
-                       // The value is another VIE Entity
-                       var child = new self.vie.Entity(value, options);
-                       // which is being stored in `v.entities`
-                       self.vie.entities.addOrUpdate(child);
-                       // and set as VIE Collection attribute on the original entity
-                       coll = new self.vie.Collection(value, {
-                         vie: self.vie,
-                         predicate: key
-                       });
-                       attrs[key] = coll;
-                   } else {
-                       // ignore
-                   }
-               }
-            }, this);
-            var ret = Backbone.Model.prototype.set.call(this, attrs, options);
-            if (options && options.ignoreChanges) {
-                this.changed = {};
-                this._previousAttributes = _.clone(this.attributes);
-            }
-            return ret;
-        },
-
-        // **`.unset(attr, opts)` ** removes an attribute from the entity.
-        unset: function (attr, opts) {
-            attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
-            return Backbone.Model.prototype.unset.call(this, attr, opts);
-        },
-
-        // Validation based on type rules.
-        //
-        // There are two ways to skip validation for entity operations:
-        //
-        // * `options.silent = true`
-        // * `options.validate = false`
-        validate: function (attrs, opts) {
-            if (opts && opts.validate === false) {
-                return;
-            }
-            var types = this.get('@type');
-            if (_.isArray(types)) {
-                var results = [];
-                _.each(types, function (type) {
-                    var res = this.validateByType(type, attrs, opts);
-                    if (res) {
-                        results.push(res);
-                    }
-                }, this);
-                if (_.isEmpty(results)) {
-                  return;
-                }
-                return _.flatten(results);
-            }
-
-            return this.validateByType(types, attrs, opts);
-        },
-
-        validateByType: function (type, attrs, opts) {
-            var messages = {
-              max: '<%= property %> cannot contain more than <%= num %> items',
-              min: '<%= property %> must contain at least <%= num %> items',
-              required: '<%= property %> is required'
-            };
-
-            if (!type.attributes) {
-                return;
-            }
-
-            var toError = function (definition, constraint, messageValues) {
-                return {
-                    property: definition.id,
-                    constraint: constraint,
-                    message: _.template(messages[constraint], _.extend({
-                        property: definition.id
-                    }, messageValues))
-                };
-            };
-
-            var checkMin = function (definition, attrs) {
-                if (!attrs[definition.id] || _.isEmpty(attrs[definition.id])) {
-                    return toError(definition, 'required', {});
-                }
-            };
-
-            // Check the number of items in attr against max
-            var checkMax = function (definition, attrs) {
-                if (!attrs[definition.id]) {
-                    return;
-                }
-
-                if (!attrs[definition.id].isCollection && !_.isArray(attrs[definition.id])) {
-                    return;
-                }
-
-                if (attrs[definition.id].length > definition.max) {
-                    return toError(definition, 'max', {
-                        num: definition.max
-                    });
-                }
-            };
-
-            var results = [];
-            _.each(type.attributes.list(), function (definition) {
-                var res;
-                if (definition.max && definition.max != -1) {
-                    res = checkMax(definition, attrs);
-                    if (res) {
-                        results.push(res);
-                    }
-                }
-
-                if (definition.min && definition.min > 0) {
-                    res = checkMin(definition, attrs);
-                    if (res) {
-                        results.push(res);
-                    }
-                }
-            });
-
-            if (_.isEmpty(results)) {
-              return;
-            }
-            return results;
-        },
-
-        isNew: function() {
-            if (this.getSubjectUri().substr(0, 7) === '_:bnode') {
-                return true;
-            }
-            return false;
-        },
-
-        hasChanged: function(attr) {
-            if (this.markedChanged) {
-                return true;
-            }
-
-            return Backbone.Model.prototype.hasChanged.call(this, attr);
-        },
-
-        // Force hasChanged to return true
-        forceChanged: function(changed) {
-            this.markedChanged = changed ? true : false;
-        },
-
-        // **`getSubject()`** is the getter for the entity identifier.
-        getSubject: function(){
-            if (typeof this.id === "undefined") {
-                this.id = this.attributes[this.idAttribute];
-            }
-            if (typeof this.id === 'string') {
-                if (this.id.substr(0, 7) === 'http://' || this.id.substr(0, 4) === 'urn:') {
-                    return this.toReference(this.id);
-                }
-                return this.id;
-            }
-            return this.cid.replace('c', '_:bnode');
-        },
-
-        // TODO describe
-        getSubjectUri: function(){
-            return this.fromReference(this.getSubject());
-        },
-
-        isReference: function(uri){
-            var matcher = new RegExp("^\\<([^\\>]*)\\>$");
-            if (matcher.exec(uri)) {
-                return true;
-            }
-            return false;
-        },
-
-        toReference: function(uri){
-            if (_.isArray(uri)) {
-              var self = this;
-              return _.map(uri, function(part) {
-                 return self.toReference(part);
-              });
-            }
-            var ns = this.vie.namespaces;
-            var ret = uri;
-            if (uri.substring(0, 2) === "_:") {
-                ret = uri;
-            }
-            else if (ns.isCurie(uri)) {
-                ret = ns.uri(uri);
-                if (ret === "<" + ns.base() + uri + ">") {
-                    /* no base namespace extension with IDs */
-                    ret = '<' + uri + '>';
-                }
-            } else if (!ns.isUri(uri)) {
-                ret = '<' + uri + '>';
-            }
-            return ret;
-        },
-
-        fromReference: function(uri){
-            var ns = this.vie.namespaces;
-            if (!ns.isUri(uri)) {
-                return uri;
-            }
-            return uri.substring(1, uri.length - 1);
-        },
-
-        as: function(encoding){
-            if (encoding === "JSON") {
-                return this.toJSON();
-            }
-            if (encoding === "JSONLD") {
-                return this.toJSONLD();
-            }
-            throw new Error("Unknown encoding " + encoding);
-        },
-
-        toJSONLD: function(){
-            var instanceLD = {};
-            var instance = this;
-            _.each(instance.attributes, function(value, name){
-                var entityValue = value; //instance.get(name);
-
-                if (value instanceof instance.vie.Collection) {
-                    entityValue = value.map(function(instance) {
-                        return instance.getSubject();
-                    });
-                }
-
-                // TODO: Handle collections separately
-                instanceLD[name] = entityValue;
-            });
-
-            instanceLD['@subject'] = instance.getSubject();
-
-            return instanceLD;
-        },
-
-        // **`.setOrAdd(arg1, arg2)`** similar to `.set(..)`, `.setOrAdd(..)` can
-        // be used for setting one or more attributes of an entity, but in
-        // this case it's a collection of values, not just one. That means, if the
-        // entity already has the attribute set, make the value to a VIE Collection
-        // and use the collection as value. The collection can contain entities
-        // or literals, but not both at the same time.
-        setOrAdd: function (arg1, arg2, option) {
-            var entity = this;
-            if (typeof arg1 === "string" && arg2) {
-                // calling entity.setOrAdd("rdfs:type", "example:Musician")
-                entity._setOrAddOne(arg1, arg2, option);
-            }
-            else
-                if (typeof arg1 === "object") {
-                    // calling entity.setOrAdd({"rdfs:type": "example:Musician", ...})
-                    _(arg1).each(function(val, key){
-                        entity._setOrAddOne(key, val, arg2);
-                    });
-                }
-            return this;
-        },
-
-
-        /* attr is always of type string */
-        /* value can be of type: string,int,double,object,VIE.Entity,VIE.Collection */
-       /*  val can be of type: undefined,string,int,double,array,VIE.Collection */
-
-        /* depending on the type of value and the type of val, different actions need to be made */
-        _setOrAddOne: function (attr, value, options) {
-            if (!attr || !value)
-                return;
-            options = (options)? options : {};
-            var v;
-
-            attr = VIE.Util.mapAttributeNS(attr, self.vie.namespaces);
-
-            if (_.isArray(value)) {
-                for (v = 0; v < value.length; v++) {
-                    this._setOrAddOne(attr, value[v], options);
-                }
-                return;
-            }
-
-            if (attr === "@type" && value instanceof self.vie.Type) {
-                value = value.id;
-            }
-
-            var obj = {};
-            var existing = Backbone.Model.prototype.get.call(this, attr);
-
-            if (!existing) {
-                obj[attr] = value;
-                this.set(obj, options);
-            } else if (existing.isCollection) {
-                if (value.isCollection) {
-                    value.each(function (model) {
-                        existing.add(model);
-                    });
-                } else if (value.isEntity) {
-                    existing.add(value);
-                } else if (typeof value === "object") {
-                    value = new this.vie.Entity(value);
-                    existing.add(value);
-                } else {
-                    throw new Error("you cannot add a literal to a collection of entities!");
-                }
-                this.trigger('change:' + attr, this, value, {});
-                this.change({});
-            } else if (_.isArray(existing)) {
-                if (value.isCollection) {
-                    for (v = 0; v < value.size(); v++) {
-                        this._setOrAddOne(attr, value.at(v).getSubject(), options);
-                    }
-                } else if (value.isEntity) {
-                    this._setOrAddOne(attr, value.getSubject(), options);
-                } else if (typeof value === "object") {
-                    value = new this.vie.Entity(value);
-                    this._setOrAddOne(attr, value, options);
-                } else {
-                    /* yes, we (have to) allow multiple equal values */
-                    existing.push(value);
-                    obj[attr] = existing;
-                    this.set(obj);
-                }
-            } else {
-                var arr = [ existing ];
-                arr.push(value);
-                obj[attr] = arr;
-                return this.set(obj, options);
-            }
-        },
-
-        // **`.hasType(type)`** determines if the entity has the explicit `type` set.
-        hasType: function(type){
-            type = self.vie.types.get(type);
-            return this.hasPropertyValue("@type", type);
-        },
-
-        // TODO describe
-        hasPropertyValue: function(property, value) {
-            var t = this.get(property);
-            if (!(value instanceof Object)) {
-                value = self.vie.entities.get(value);
-            }
-            if (t instanceof Array) {
-                return t.indexOf(value) !== -1;
-            }
-            else {
-                return t === value;
-            }
-        },
-
-        // **`.isof(type)`** determines if the entity is of `type` by explicit or implicit
-        // declaration. E.g. if Employee is a subtype of Person and e Entity has
-        // explicitly set type Employee, e.isof(Person) will evaluate to true.
-        isof: function (type) {
-            var types = this.get('@type');
-
-            if (types === undefined) {
-                return false;
-            }
-            types = (_.isArray(types))? types : [ types ];
-
-            type = (self.vie.types.get(type))? self.vie.types.get(type) : new self.vie.Type(type);
-            for (var t = 0; t < types.length; t++) {
-                if (self.vie.types.get(types[t])) {
-                    if (self.vie.types.get(types[t]).isof(type)) {
-                        return true;
-                    }
-                } else {
-                    var typeTmp = new self.vie.Type(types[t]);
-                    if (typeTmp.id === type.id) {
-                        return true;
-                    }
-                }
-            }
-            return false;
-        },
-        // TODO describe
-        addTo : function (collection, update) {
-            var self = this;
-            if (collection instanceof self.vie.Collection) {
-                if (update) {
-                    collection.addOrUpdate(self);
-                } else {
-                    collection.add(self);
-                }
-                return this;
-            }
-            throw new Error("Please provide a proper collection of type VIE.Collection as argument!");
-        },
-
-        isEntity: true,
-
-        vie: self.vie
-    });
-
-    return new Model(attrs, opts);
-};
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-VIE.prototype.Collection = Backbone.Collection.extend({
-    model: VIE.prototype.Entity,
-
-    initialize: function (models, options) {
-      if (!options || !options.vie) {
-        throw new Error('Each collection needs a VIE reference');
-      }
-      this.vie = options.vie;
-      this.predicate = options.predicate;
-    },
-
-    canAdd: function (type) {
-      return true;
-    },
-
-    get: function(id) {
-        if (id === null) {
-            return null;
-        }
-
-        id = (id.getSubject)? id.getSubject() : id;
-        if (typeof id === "string" && id.indexOf("_:") === 0) {
-            if (id.indexOf("bnode") === 2) {
-                //bnode!
-                id = id.replace("_:bnode", 'c');
-                return this._byCid[id];
-            } else {
-                return this._byId["<" + id + ">"];
-            }
-        } else {
-            id = this.toReference(id);
-            return this._byId[id];
-        }
-    },
-
-    addOrUpdate: function(model, options) {
-        options = options || {};
-
-        var collection = this;
-        var existing;
-        if (_.isArray(model)) {
-            var entities = [];
-            _.each(model, function(item) {
-                entities.push(collection.addOrUpdate(item, options));
-            });
-            return entities;
-        }
-
-        if (model === undefined) {
-            throw new Error("No model given");
-        }
-
-        if (_.isString(model)) {
-          model = {
-            '@subject': model,
-            id: model
-          };
-        }
-
-        if (!model.isEntity) {
-            model = new this.model(model);
-        }
-
-        if (model.id && this.get(model.id)) {
-            existing = this.get(model.id);
-        }
-        if (this.getByCid(model.cid)) {
-            existing = this.getByCid(model.cid);
-        }
-        if (existing) {
-            var newAttribs = {};
-            _.each(model.attributes, function(value, attribute) {
-                if (!existing.has(attribute)) {
-                    newAttribs[attribute] = value;
-                    return true;
-                }
-
-                if (attribute === '@subject') {
-                    if (model.isNew() && !existing.isNew()) {
-                        // Save order issue, skip
-                        return true;
-                    }
-                }
-
-                if (existing.get(attribute) === value) {
-                    return true;
-                }
-                //merge existing attribute values with new ones!
-                //not just overwrite 'em!!
-                var oldVals = existing.attributes[attribute];
-                var newVals = value;
-                if (oldVals instanceof collection.vie.Collection) {
-                    // TODO: Merge collections
-                    return true;
-                }
-                if (options.overrideAttributes) {
-                   newAttribs[attribute] = value;
-                   return true;
-                }
-                if (attribute === '@context') {
-                    newAttribs[attribute] = jQuery.extend(true, {}, oldVals, newVals);
-                } else {
-                    oldVals = (jQuery.isArray(oldVals))? oldVals : [ oldVals ];
-                    newVals = (jQuery.isArray(newVals))? newVals : [ newVals ];
-                    newAttribs[attribute] = _.uniq(oldVals.concat(newVals));
-                    newAttribs[attribute] = (newAttribs[attribute].length === 1)? newAttribs[attribute][0] : newAttribs[attribute];
-                }
-            });
-
-            if (!_.isEmpty(newAttribs)) {
-                existing.set(newAttribs, options.updateOptions);
-            }
-            return existing;
-        }
-        this.add(model, options.addOptions);
-        return model;
-    },
-
-    isReference: function(uri){
-        var matcher = new RegExp("^\\<([^\\>]*)\\>$");
-        if (matcher.exec(uri)) {
-            return true;
-        }
-        return false;
-    },
-
-    toReference: function(uri){
-        if (this.isReference(uri)) {
-            return uri;
-        }
-        return '<' + uri + '>';
-    },
-
-    fromReference: function(uri){
-        if (!this.isReference(uri)) {
-            return uri;
-        }
-        return uri.substring(1, uri.length - 1);
-    },
-
-    isCollection: true
-});
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-//
-
-// ## VIE.Types
-// Within VIE, we provide special capabilities of handling types of entites. This helps
-// for example to query easily for certain entities (e.g., you only need to query for *Person*s
-// and not for all subtypes).
-if (VIE.prototype.Type) {
-    throw new Error("ERROR: VIE.Type is already defined. Please check your installation!");
-}
-if (VIE.prototype.Types) {
-    throw new Error("ERROR: VIE.Types is already defined. Please check your installation!");
-}
-
-// ### VIE.Type(id, attrs, metadata)
-// This is the constructor of a VIE.Type.
-// **Parameters**:
-// *{string}* **id** The id of the type.
-// *{string|array|VIE.Attribute}* **attrs** A string, proper ```VIE.Attribute``` or an array of these which
-// *{object}* **metadata** Possible metadata about the type
-// are the possible attributes of the type
-// **Throws**:
-// *{Error}* if one of the given paramenters is missing.
-// **Returns**:
-// *{VIE.Type}* : A **new** VIE.Type object.
-// **Example usage**:
-//
-//     var person = new vie.Type("Person", ["name", "knows"]);
-VIE.prototype.Type = function (id, attrs, metadata) {
-    if (id === undefined || typeof id !== 'string') {
-        throw "The type constructor needs an 'id' of type string! E.g., 'Person'";
-    }
-
-// ### id
-// This field stores the id of the type's instance.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{string}* : The id of the type as a URI.
-// **Example usage**:
-//
-//     console.log(person.id);
-//      // --> "<http://viejs.org/ns/Person>"
-    this.id = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
-
-    /* checks whether such a type is already defined. */
-    if (this.vie.types.get(this.id)) {
-        throw new Error("The type " + this.id + " is already defined!");
-    }
-
-// ### supertypes
-// This field stores all parent types of the type's instance. This
-// is set if the current type inherits from another type.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{VIE.Types}* : The supertypes (parents) of the type.
-// **Example usage**:
-//
-//     console.log(person.supertypes);
-    this.supertypes = new this.vie.Types();
-
-// ### subtypes
-// This field stores all children types of the type's instance. This
-// will be set if another type inherits from the current type.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{VIE.Types}* : The subtypes (parents) of the type.
-// **Example usage**:
-//
-//     console.log(person.subtypes);
-    this.subtypes = new this.vie.Types();
-
-// ### attributes
-// This field stores all attributes of the type's instance as
-// a proper ```VIE.Attributes``` class. (see also <a href="Attribute.html">VIE.Attributes</a>)
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{VIE.Attributes}* : The attributes of the type.
-// **Example usage**:
-//
-//     console.log(person.attributes);
-    this.attributes = new this.vie.Attributes(this, (attrs)? attrs : []);
-
-// ### metadata
-// This field stores possible additional information about the type, like
-// a human-readable label.
-    this.metadata = metadata ? metadata : {};
-
-// ### isof(type)
-// This method checks whether the current type is a child of the given type.
-// **Parameters**:
-// *{string|VIE.Type}* **type** The type (or the id of that type) to be checked.
-// **Throws**:
-// *{Error}* If the type is not valid.
-// **Returns**:
-// *{boolean}* : ```true``` if the current type inherits from the type, ```false``` otherwise.
-// **Example usage**:
-//
-//     console.log(person.isof("owl:Thing"));
-//     // <-- true
-    this.isof = function (type) {
-        type = this.vie.types.get(type);
-        if (type) {
-            return type.subsumes(this.id);
-        } else {
-            throw new Error("No valid type given");
-        }
-    };
-
-// ### subsumes(type)
-// This method checks whether the current type is a parent of the given type.
-// **Parameters**:
-// *{string|VIE.Type}* **type** The type (or the id of that type) to be checked.
-// **Throws**:
-// *{Error}* If the type is not valid.
-// **Returns**:
-// *{boolean}* : ```true``` if the current type is a parent of the type, ```false``` otherwise.
-// **Example usage**:
-//
-//     var x = new vie.Type(...);
-//     var y = new vie.Type(...).inherit(x);
-//     y.isof(x) === x.subsumes(y);
-    this.subsumes = function (type) {
-        type = this.vie.types.get(type);
-        if (type) {
-            if (this.id === type.id) {
-                return true;
-            }
-            var subtypes = this.subtypes.list();
-            for (var c = 0; c < subtypes.length; c++) {
-                var childObj = subtypes[c];
-                if (childObj) {
-                     if (childObj.id === type.id || childObj.subsumes(type)) {
-                         return true;
-                     }
-                }
-            }
-            return false;
-        } else {
-            throw new Error("No valid type given");
-        }
-    };
-
-// ### inherit(supertype)
-// This method invokes inheritance throught the types. This adds the current type to the
-// subtypes of the supertype and vice versa.
-// **Parameters**:
-// *{string|VIE.Type|array}* **supertype** The type to be inherited from. If this is an array
-// the inherit method is called sequentially on all types.
-// **Throws**:
-// *{Error}* If the type is not valid.
-// **Returns**:
-// *{VIE.Type}* : The instance itself.
-// **Example usage**:
-//
-//     var x = new vie.Type(...);
-//     var y = new vie.Type(...).inherit(x);
-//     y.isof(x) // <-- true
-    this.inherit = function (supertype) {
-        if (typeof supertype === "string") {
-            this.inherit(this.vie.types.get(supertype));
-        }
-        else if (supertype instanceof this.vie.Type) {
-            supertype.subtypes.addOrOverwrite(this);
-            this.supertypes.addOrOverwrite(supertype);
-            try {
-                /* only for validation of attribute-inheritance!
-                   if this throws an error (inheriting two attributes
-                   that cannot be combined) we reverse all changes. */
-                this.attributes.list();
-            } catch (e) {
-                supertype.subtypes.remove(this);
-                this.supertypes.remove(supertype);
-                throw e;
-            }
-        } else if (jQuery.isArray(supertype)) {
-            for (var i = 0, slen = supertype.length; i < slen; i++) {
-                this.inherit(supertype[i]);
-            }
-        } else {
-            throw new Error("Wrong argument in VIE.Type.inherit()");
-        }
-        return this;
-    };
-
-// ### hierarchy()
-// This method serializes the hierarchy of child types into an object.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{object}* : The hierachy of child types as an object.
-// **Example usage**:
-//
-//     var x = new vie.Type(...);
-//     var y = new vie.Type(...).inherit(x);
-//     x.hierarchy();
-    this.hierarchy = function () {
-        var obj = {id : this.id, subtypes: []};
-        var list = this.subtypes.list();
-        for (var c = 0, llen = list.length; c < llen; c++) {
-            var childObj = this.vie.types.get(list[c]);
-            obj.subtypes.push(childObj.hierarchy());
-        }
-        return obj;
-    };
-
-// ### instance()
-// This method creates a ```VIE.Entity``` instance from this type.
-// **Parameters**:
-// *{object}* **attrs**  see <a href="Entity.html">constructor of VIE.Entity</a>
-// *{object}* **opts**  see <a href="Entity.html">constructor of VIE.Entity</a>
-// **Throws**:
-// *{Error}* if the instance could not be built
-// **Returns**:
-// *{VIE.Entity}* : A **new** instance of a ```VIE.Entity``` with the current type.
-// **Example usage**:
-//
-//     var person = new vie.Type("person");
-//     var sebastian = person.instance(
-//         {"@subject" : "#me",
-//          "name" : "Sebastian"});
-//     console.log(sebastian.get("name")); // <-- "Sebastian"
-    this.instance = function (attrs, opts) {
-        attrs = (attrs)? attrs : {};
-        opts = (opts)? opts : {};
-
-        /* turn type/attribute checking on by default! */
-        if (opts.typeChecking !== false) {
-            for (var a in attrs) {
-                if (a.indexOf('@') !== 0 && !this.attributes.get(a)) {
-                    throw new Error("Cannot create an instance of " + this.id + " as the type does not allow an attribute '" + a + "'!");
-                }
-            }
-        }
-
-        if (attrs['@type']) {
-            attrs['@type'].push(this.id);
-        } else {
-            attrs['@type'] = this.id;
-        }
-
-        return new this.vie.Entity(attrs, opts);
-    };
-
-// ### toString()
-// This method returns the id of the type.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{string}* : The id of the type.
-// **Example usage**:
-//
-//     var x = new vie.Type(...);
-//     x.toString() === x.id;
-    this.toString = function () {
-        return this.id;
-    };
-};
-
-// ### VIE.Types()
-// This is the constructor of a VIE.Types. This is a convenience class
-// to store ```VIE.Type``` instances properly.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Types}* : A **new** VIE.Types object.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-VIE.prototype.Types = function () {
-
-    this._types = {};
-
-// ### add(id, attrs, metadata)
-// This method adds a `VIE.Type` to the types.
-// **Parameters**:
-// *{string|VIE.Type}* **id** If this is a string, the type is created and directly added.
-// *{string|object}* **attrs** Only used if ```id``` is a string.
-// *{object}* **metadata** potential additional metadata about the type.
-// **Throws**:
-// *{Error}* if a type with the given id already exists a ```VIE.Entity``` instance from this type.
-// **Returns**:
-// *{VIE.Types}* : The instance itself.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.add("Person", ["name", "knows"]);
-    this.add = function (id, attrs, metadata) {
-        if (_.isArray(id)) {
-           _.each(id, function (type) {
-             this.add(type);
-           }, this);
-           return this;
-        }
-
-        if (this.get(id)) {
-            throw new Error("Type '" + id + "' already registered.");
-        }  else {
-            if (typeof id === "string") {
-                var t = new this.vie.Type(id, attrs, metadata);
-                this._types[t.id] = t;
-                return t;
-            } else if (id instanceof this.vie.Type) {
-                this._types[id.id] = id;
-                return id;
-            } else {
-                throw new Error("Wrong argument to VIE.Types.add()!");
-            }
-        }
-        return this;
-    };
-
-// ### addOrOverwrite(id, attrs)
-// This method adds or overwrites a `VIE.Type` to the types. This is the same as
-// ``this.remove(id); this.add(id, attrs);``
-// **Parameters**:
-// *{string|VIE.Type}* **id** If this is a string, the type is created and directly added.
-// *{string|object}* **attrs** Only used if ```id``` is a string.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Types}* : The instance itself.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.addOrOverwrite("Person", ["name", "knows"]);
-    this.addOrOverwrite = function(id, attrs){
-        if (this.get(id)) {
-            this.remove(id);
-        }
-        return this.add(id, attrs);
-    };
-
-// ### get(id)
-// This method retrieves a `VIE.Type` from the types by it's id.
-// **Parameters**:
-// *{string|VIE.Type}* **id** The id or the type itself.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Type}* : The instance of the type or ```undefined```.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.addOrOverwrite("Person", ["name", "knows"]);
-//     types.get("Person");
-    this.get = function (id) {
-        if (!id) {
-            return undefined;
-        }
-        if (typeof id === 'string') {
-            var lid = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
-            return this._types[lid];
-        } else if (id instanceof this.vie.Type) {
-            return this.get(id.id);
-        }
-        return undefined;
-    };
-
-// ### remove(id)
-// This method removes a type of given id from the type. This also
-// removes all children if their only parent were this
-// type. Furthermore, this removes the link from the
-// super- and subtypes.
-// **Parameters**:
-// *{string|VIE.Type}* **id** The id or the type itself.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Type}* : The removed type.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.addOrOverwrite("Person", ["name", "knows"]);
-//     types.remove("Person");
-    this.remove = function (id) {
-        var t = this.get(id);
-        /* test whether the type actually exists in VIE
-         * and prevents removing *owl:Thing*.
-         */
-        if (!t) {
-            return this;
-        }
-        if (!t || t.subsumes("owl:Thing")) {
-            console.warn("You are not allowed to remove 'owl:Thing'.");
-            return this;
-        }
-        delete this._types[t.id];
-
-        var subtypes = t.subtypes.list();
-        for (var c = 0; c < subtypes.length; c++) {
-            var childObj = subtypes[c];
-            if (childObj.supertypes.list().length === 1) {
-                /* recursively remove all children
-                   that inherit only from this type */
-                this.remove(childObj);
-            } else {
-                childObj.supertypes.remove(t.id);
-            }
-        }
-        return t;
-    };
-
-// ### toArray() === list()
-// This method returns an array of all types.
-// **Parameters**:
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{array}* : An array of ```VIE.Type``` instances.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.addOrOverwrite("Person", ["name", "knows"]);
-//     types.list();
-    this.toArray = this.list = function () {
-        var ret = [];
-        for (var i in this._types) {
-            ret.push(this._types[i]);
-        }
-        return ret;
-    };
-
-// ### sort(types, desc)
-// This method sorts an array of types in their order, given by the
-// inheritance. This returns a copy and leaves the original array untouched.
-// **Parameters**:
-// *{array|VIE.Type}* **types** The array of ```VIE.Type``` instances or ids of types to be sorted.
-// *{boolean}* **desc** If 'desc' is given and 'true', the array will be sorted
-// in descendant order.
-// *nothing*
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{array}* : A sorted copy of the array.
-// **Example usage**:
-//
-//     var types = new vie.Types();
-//     types.addOrOverwrite("Person", ["name", "knows"]);
-//     types.sort(types.list(), true);
-    this.sort = function (types, desc) {
-        var self = this;
-        types = (jQuery.isArray(types))? types : [ types ];
-        desc = (desc)? true : false;
-
-        if (types.length === 0) return [];
-        var copy = [ types[0] ];
-        var x, tlen;
-        for (x = 1, tlen = types.length; x < tlen; x++) {
-            var insert = types[x];
-            var insType = self.get(insert);
-            if (insType) {
-                for (var y = 0; y < copy.length; y++) {
-                    if (insType.subsumes(copy[y])) {
-                        copy.splice(y,0,insert);
-                        break;
-                    } else if (y === copy.length - 1) {
-                        copy.push(insert);
-                    }
-                }
-            }
-        }
-
-        //unduplicate
-        for (x = 0; x < copy.length; x++) {
-            if (copy.lastIndexOf(copy[x]) !== x) {
-                copy.splice(x, 1);
-                x--;
-            }
-        }
-
-        if (!desc) {
-            copy.reverse();
-        }
-        return copy;
-    };
-};
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-//
-
-// ## VIE.Attributes
-// Within VIE, we provide special capabilities of handling attributes of types of entites. This
-// helps first of all to list all attributes of an entity type, but furthermore fully supports
-// inheritance of attributes from the type-class to inherit from.
-if (VIE.prototype.Attribute) {
-	throw new Error("ERROR: VIE.Attribute is already defined. Please check your VIE installation!");
-}
-if (VIE.prototype.Attributes) {
-	throw new Error("ERROR: VIE.Attributes is already defined. Please check your VIE installation!");
-}
-
-// ### VIE.Attribute(id, range, domain, minCount, maxCount, metadata)
-// This is the constructor of a VIE.Attribute.
-// **Parameters**:
-// *{string}* **id** The id of the attribute.
-// *{string|array}* **range** A string or an array of strings of the target range of
-// the attribute.
-// *{string}* **domain** The domain of the attribute.
-// *{number}* **minCount** The minimal number this attribute can occur. (needs to be >= 0)
-// *{number}* **maxCount** The maximal number this attribute can occur. (needs to be >= minCount, use `-1` for unlimited)
-// *{object}* **metadata** Possible metadata about the attribute
-// **Throws**:
-// *{Error}* if one of the given paramenters is missing.
-// **Returns**:
-// *{VIE.Attribute}* : A **new** VIE.Attribute object.
-// **Example usage**:
-//
-//     var knowsAttr = new vie.Attribute("knows", ["Person"], "Person", 0, 10);
-//      // Creates an attribute to describe a *knows*-relationship
-//      // between persons. Each person can only have
-VIE.prototype.Attribute = function (id, range, domain, minCount, maxCount, metadata) {
-    if (id === undefined || typeof id !== 'string') {
-        throw new Error("The attribute constructor needs an 'id' of type string! E.g., 'Person'");
-    }
-    if (range === undefined) {
-        throw new Error("The attribute constructor of " + id + " needs 'range'.");
-    }
-    if (domain === undefined) {
-        throw new Error("The attribute constructor of " + id + " needs a 'domain'.");
-    }
-
-    this._domain = domain;
-
-// ### id
-// This field stores the id of the attribute's instance.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{string}* : A URI, representing the id of the attribute.
-// **Example usage**:
-//
-//     var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
-//     console.log(knowsAttr.id);
-//     // --> <http://viejs.org/ns/knows>
-    this.id = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
-
-// ### range
-// This field stores the ranges of the attribute's instance.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{array}* : An array of strings which represent the types.
-// **Example usage**:
-//
-//     var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
-//     console.log(knowsAttr.range);
-//      // --> ["Person"]
-    this.range = (_.isArray(range))? range : [ range ];
-
-// ### min
-// This field stores the minimal amount this attribute can occur in the type's instance. The number
-// needs to be greater or equal to zero.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{int}* : The minimal amount this attribute can occur.
-// **Example usage**:
-//
-//     console.log(person.min);
-//      // --> 0
-    minCount = minCount ? minCount : 0;
-    this.min = (minCount > 0) ? minCount : 0;
-
-// ### max
-// This field stores the maximal amount this attribute can occur in the type's instance.
-// This number cannot be smaller than min
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{int}* : The maximal amount this attribute can occur.
-// **Example usage**:
-//
-//     console.log(person.max);
-//      // --> 1.7976931348623157e+308
-    maxCount = maxCount ? maxCount : 1;
-    if (maxCount === -1) {
-      maxCount = Number.MAX_VALUE;
-    }
-    this.max = (maxCount >= this.min)? maxCount : this.min;
-
-// ### metadata
-// This field holds potential metadata about the attribute.
-    this.metadata = metadata ? metadata : {};
-
-// ### applies(range)
-// This method checks, whether the current attribute applies in the given range.
-// If ```range``` is a string and cannot be transformed into a ```VIE.Type```,
-// this performs only string comparison, if it is a VIE.Type
-// or an ID of a VIE.Type, then inheritance is checked as well.
-// **Parameters**:
-// *{string|VIE.Type}* **range** The ```VIE.Type``` (or it's string representation) to be checked.
-// **Throws**:
-// nothing
-// **Returns**:
-// *{boolean}* : ```true``` if the given type applies to this attribute and ```false``` otherwise.
-// **Example usage**:
-//
-//     var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
-//     console.log(knowsAttr.applies("Person")); // --> true
-//     console.log(knowsAttr.applies("Place")); // --> false
-    this.applies = function (range) {
-        if (this.vie.types.get(range)) {
-            range = this.vie.types.get(range);
-        }
-        for (var r = 0, len = this.range.length; r < len; r++) {
-            var x = this.vie.types.get(this.range[r]);
-            if (x === undefined && typeof range === "string") {
-                if (range === this.range[r]) {
-                    return true;
-                }
-            }
-            else {
-                if (range.isof(this.range[r])) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    };
-
-};
-
-// ## VIE.Attributes(domain, attrs)
-// This is the constructor of a VIE.Attributes. Basically a convenience class
-// that represents a list of ```VIE.Attribute```. As attributes are part of a
-// certain ```VIE.Type```, it needs to be passed for inheritance checks.
-// **Parameters**:
-// *{string}* **domain** The domain of the attributes (the type they will be part of).
-// *{string|VIE.Attribute|array}* **attrs** Either a string representation of an attribute,
-// a proper instance of ```VIE.Attribute``` or an array of both.
-// *{string}* **domain** The domain of the attribute.
-// **Throws**:
-// *{Error}* if one of the given paramenters is missing.
-// **Returns**:
-// *{VIE.Attribute}* : A **new** VIE.Attribute instance.
-// **Example usage**:
-//
-//     var knowsAttr = new vie.Attribute("knows", ["Person"], "Person");
-//     var personAttrs = new vie.Attributes("Person", knowsAttr);
-VIE.prototype.Attributes = function (domain, attrs) {
-
-    this._local = {};
-    this._attributes = {};
-
-// ### domain
-// This field stores the domain of the attributes' instance.
-// **Parameters**:
-// nothing
-// **Throws**:
-// nothing
-// **Returns**:
-// *{string}* : The string representation of the domain.
-// **Example usage**:
-//
-//     console.log(personAttrs.domain);
-//     // --> ["Person"]
-    this.domain = domain;
-
-// ### add(id, range, min, max, metadata)
-// This method adds a ```VIE.Attribute``` to the attributes instance.
-// **Parameters**:
-// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
-// instance of a ```VIE.Attribute```.
-// *{string|array}* **range** An array representing the target range of the attribute.
-// *{number}* **min** The minimal amount this attribute can appear.
-// instance of a ```VIE.Attribute```.
-// *{number}* **max** The maximal amount this attribute can appear.
-// *{object}* **metadata** Additional metadata for the attribute.
-// **Throws**:
-// *{Error}* If an atribute with the given id is already registered.
-// *{Error}* If the ```id``` parameter is not a string, nor a ```VIE.Type``` instance.
-// **Returns**:
-// *{VIE.Attribute}* : The generated or passed attribute.
-// **Example usage**:
-//
-//     personAttrs.add("name", "Text", 0, 1);
-    this.add = function (id, range, min, max, metadata) {
-        if (_.isArray(id)) {
-          _.each(id, function (attribute) {
-            this.add(attribute);
-          }, this);
-          return this;
-        }
-
-        if (this.get(id)) {
-            throw new Error("Attribute '" + id + "' already registered for domain " + this.domain.id + "!");
-        } else {
-            if (typeof id === "string") {
-                var a = new this.vie.Attribute(id, range, this.domain, min, max, metadata);
-                this._local[a.id] = a;
-                return a;
-            } else if (id instanceof this.vie.Attribute) {
-                id.domain = this.domain;
-                id.vie = this.vie;
-                this._local[id.id] = id;
-                return id;
-            } else {
-                throw new Error("Wrong argument to VIE.Types.add()!");
-            }
-        }
-    };
-
-// ### remove(id)
-// This method removes a ```VIE.Attribute``` from the attributes instance.
-// **Parameters**:
-// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
-// instance of a ```VIE.Attribute```.
-// **Throws**:
-// *{Error}* When the attribute is inherited from a parent ```VIE.Type``` and thus cannot be removed.
-// **Returns**:
-// *{VIE.Attribute}* : The removed attribute.
-// **Example usage**:
-//
-//     personAttrs.remove("knows");
-    this.remove = function (id) {
-        var a = this.get(id);
-        if (a.id in this._local) {
-            delete this._local[a.id];
-            return a;
-        }
-        throw new Error("The attribute " + id + " is inherited and cannot be removed from the domain " + this.domain.id + "!");
-    };
-
-// ### get(id)
-// This method returns a ```VIE.Attribute``` from the attributes instance by it's id.
-// **Parameters**:
-// *{string|VIE.Attribute}* **id** The string representation of an attribute, or a proper
-// instance of a ```VIE.Attribute```.
-// **Throws**:
-// *{Error}* When the method is called with an unknown datatype.
-// **Returns**:
-// *{VIE.Attribute}* : The attribute.
-// **Example usage**:
-//
-//     personAttrs.get("knows");
-    this.get = function (id) {
-        if (typeof id === 'string') {
-            var lid = this.vie.namespaces.isUri(id) ? id : this.vie.namespaces.uri(id);
-            return this._inherit()._attributes[lid];
-        } else if (id instanceof this.vie.Attribute) {
-            return this.get(id.id);
-        } else {
-            throw new Error("Wrong argument in VIE.Attributes.get()");
-        }
-    };
-
-// ### _inherit()
-// The private method ```_inherit``` creates a full list of all attributes. This includes
-// local attributes as well as inherited attributes from the parents. The ranges of attributes
-// with the same id will be merged. This method is called everytime an attribute is requested or
-// the list of all attributes. Usually this method should not be invoked outside of the class.
-// **Parameters**:
-// *nothing*
-// instance of a ```VIE.Attribute```.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *nothing*
-// **Example usage**:
-//
-//     personAttrs._inherit();
-    this._inherit = function () {
-        var a, x, id;
-        var attributes = jQuery.extend(true, {}, this._local);
-
-        var inherited = _.map(this.domain.supertypes.list(),
-            function (x) {
-               return x.attributes;
-            }
-        );
-
-        var add = {};
-        var merge = {};
-        var ilen, alen;
-        for (a = 0, ilen = inherited.length; a < ilen; a++) {
-            var attrs = inherited[a].list();
-            for (x = 0, alen = attrs.length; x < alen; x++) {
-                id = attrs[x].id;
-                if (!(id in attributes)) {
-                    if (!(id in add) && !(id in merge)) {
-                        add[id] = attrs[x];
-                    }
-                    else {
-                        if (!merge[id]) {
-                            merge[id] = {range : [], mins : [], maxs: [], metadatas: []};
-                        }
-                        if (id in add) {
-                            merge[id].range = jQuery.merge(merge[id].range, add[id].range);
-                            merge[id].mins = jQuery.merge(merge[id].mins, [ add[id].min ]);
-                            merge[id].maxs = jQuery.merge(merge[id].maxs, [ add[id].max ]);
-                            merge[id].metadatas = jQuery.merge(merge[id].metadatas, [ add[id].metadata ]);
-                            delete add[id];
-                        }
-                        merge[id].range = jQuery.merge(merge[id].range, attrs[x].range);
-                        merge[id].mins = jQuery.merge(merge[id].mins, [ attrs[x].min ]);
-                        merge[id].maxs = jQuery.merge(merge[id].maxs, [ attrs[x].max ]);
-                        merge[id].metadatas = jQuery.merge(merge[id].metadatas, [ attrs[x].metadata ]);
-                        merge[id].range = _.uniq(merge[id].range);
-                        merge[id].mins = _.uniq(merge[id].mins);
-                        merge[id].maxs = _.uniq(merge[id].maxs);
-                        merge[id].metadatas = _.uniq(merge[id].metadatas);
-                    }
-                }
-            }
-        }
-
-        /* adds inherited attributes that do not need to be merged */
-        jQuery.extend(attributes, add);
-
-        /* merges inherited attributes */
-        for (id in merge) {
-            var mranges = merge[id].range;
-            var mins = merge[id].mins;
-            var maxs = merge[id].maxs;
-            var metadatas = merge[id].metadatas;
-            var ranges = [];
-            //merging ranges
-            for (var r = 0, mlen = mranges.length; r < mlen; r++) {
-                var p = this.vie.types.get(mranges[r]);
-                var isAncestorOf = false;
-                if (p) {
-                    for (x = 0; x < mlen; x++) {
-                        if (x === r) {
-                            continue;
-                        }
-                        var c = this.vie.types.get(mranges[x]);
-                        if (c && c.isof(p)) {
-                            isAncestorOf = true;
-                            break;
-                        }
-                    }
-                }
-                if (!isAncestorOf) {
-                    ranges.push(mranges[r]);
-                }
-            }
-
-            var maxMin = _.max(mins);
-            var minMax = _.min(maxs);
-            if (maxMin <= minMax && minMax >= 0 && maxMin >= 0) {
-                attributes[id] = new this.vie.Attribute(id, ranges, this, maxMin, minMax, metadatas[0]);
-            } else {
-                throw new Error("This inheritance is not allowed because of an invalid minCount/maxCount pair!");
-            }
-        }
-
-        this._attributes = attributes;
-        return this;
-    };
-
-// ### toArray() === list()
-// This method return an array of ```VIE.Attribute```s from the attributes instance.
-// **Parameters**:
-// *nothing.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{array}* : An array of ```VIE.Attribute```.
-// **Example usage**:
-//
-//     personAttrs.list();
-    this.toArray = this.list = function (range) {
-        var ret = [];
-        var attributes = this._inherit()._attributes;
-        for (var a in attributes) {
-            if (!range || attributes[a].applies(range)) {
-                ret.push(attributes[a]);
-            }
-        }
-        return ret;
-    };
-
-    attrs = _.isArray(attrs) ? attrs : [ attrs ];
-    _.each(attrs, function (attr) {
-        this.add(attr.id, attr.range, attr.min, attr.max, attr.metadata);
-    }, this);
-};
-//     VIE - Vienna IKS Editables
-//     (c) 2011 Henri Bergius, IKS Consortium
-//     (c) 2011 Sebastian Germesin, IKS Consortium
-//     (c) 2011 Szaby Grünwald, IKS Consortium
-//     VIE may be freely distributed under the MIT license.
-//     For all details and documentation:
-//     http://viejs.org/
-if (VIE.prototype.Namespaces) {
-    throw new Error("ERROR: VIE.Namespaces is already defined. " +
-        "Please check your VIE installation!");
-}
-
-// ## VIE Namespaces
-//
-// In general, a namespace is a container that provides context for the identifiers.
-// Within VIE, namespaces are used to distinguish different ontolgies or vocabularies
-// of identifiers, types and attributes. However, because of their verbosity, namespaces
-// tend to make their usage pretty circuitous. The ``VIE.Namespaces(...)`` class provides VIE
-// with methods to maintain abbreviations (akak **prefixes**) for namespaces in order to
-// alleviate their usage. By default, every VIE instance is equipped with a main instance
-// of the namespaces in ``myVIE.namespaces``. Furthermore, VIE uses a **base namespace**,
-// which is used if no prefix is given (has an empty prefix).
-// In the upcoming sections, we will explain the
-// methods to add, access and remove prefixes.
-
-
-
-// ## VIE.Namespaces(base, namespaces)
-// This is the constructor of a VIE.Namespaces. The constructor initially
-// needs a *base namespace* and can optionally be initialised with an
-// associative array of prefixes and namespaces. The base namespace is used in a way
-// that every non-prefixed, non-expanded attribute or type is assumed to be of that
-// namespace. This helps, e.g., in an environment where only one namespace is given.
-// **Parameters**:
-// *{string}* **base** The base namespace.
-// *{object}* **namespaces** Initial namespaces to bootstrap the namespaces. (optional)
-// **Throws**:
-// *{Error}* if the base namespace is missing.
-// **Returns**:
-// *{VIE.Attribute}* : A **new** VIE.Attribute object.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces("http://viejs.org/ns/",
-//           {
-//            "foaf": "http://xmlns.com/foaf/0.1/"
-//           });
-VIE.prototype.Namespaces = function (base, namespaces) {
-
-    if (!base) {
-        throw new Error("Please provide a base namespace!");
-    }
-    this._base = base;
-
-    this._namespaces = (namespaces)? namespaces : {};
-    if (typeof this._namespaces !== "object" || _.isArray(this._namespaces)) {
-        throw new Error("If you want to initialise VIE namespace prefixes, " +
-            "please provide a proper object!");
-    }
-};
-
-
-// ### base(ns)
-// This is a **getter** and **setter** for the base
-// namespace. If called like ``base();`` it
-// returns the actual base namespace as a string. If provided
-// with a string, e.g., ``base("http://viejs.org/ns/");``
-// it sets the current base namespace and retuns the namespace object
-// for the purpose of chaining. If provided with anything except a string,
-// it throws an Error.
-// **Parameters**:
-// *{string}* **ns** The namespace to be set. (optional)
-// **Throws**:
-// *{Error}* if the namespace is not of type string.
-// **Returns**:
-// *{string}* : The current base namespace.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     console.log(namespaces.base()); // <-- "http://base.ns/"
-//     namespaces.base("http://viejs.org/ns/");
-//     console.log(namespaces.base()); // <-- "http://viejs.org/ns/"
-VIE.prototype.Namespaces.prototype.base = function (ns) {
-    if (!ns) {
-        return this._base;
-    }
-    else if (typeof ns === "string") {
-        /* remove another mapping */
-        this.removeNamespace(ns);
-        this._base = ns;
-        return this._base;
-    } else {
-        throw new Error("Please provide a valid namespace!");
-    }
-};
-
-// ### add(prefix, namespace)
-// This method adds new prefix mappings to the
-// current instance. If a prefix or a namespace is already
-// present (in order to avoid ambiguities), an Error is thrown.
-// ``prefix`` can also be an object in which case, the method
-// is called sequentially on all elements.
-// **Parameters**:
-// *{string|object}* **prefix** The prefix to be set. If it is an object, the
-// method will be applied to all key,value pairs sequentially.
-// *{string}* **namespace** The namespace to be set.
-// **Throws**:
-// *{Error}* If a prefix or a namespace is already
-// present (in order to avoid ambiguities).
-// **Returns**:
-// *{VIE.Namespaces}* : The current namespaces instance.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.add("", "http://...");
-//     // is always equal to
-//     namespaces.base("http://..."); // <-- setter of base namespace
-VIE.prototype.Namespaces.prototype.add = function (prefix, namespace) {
-    if (typeof prefix === "object") {
-        for (var k1 in prefix) {
-            this.add(k1, prefix[k1]);
-        }
-        return this;
-    }
-    if (prefix === "") {
-        this.base(namespace);
-        return this;
-    }
-    /* checking if we overwrite existing mappings */
-    else if (this.contains(prefix) && namespace !== this._namespaces[prefix]) {
-        throw new Error("ERROR: Trying to register namespace prefix mapping (" + prefix + "," + namespace + ")!" +
-              "There is already a mapping existing: '(" + prefix + "," + this.get(prefix) + ")'!");
-    } else {
-        jQuery.each(this._namespaces, function (k1,v1) {
-            if (v1 === namespace && k1 !== prefix) {
-                throw new Error("ERROR: Trying to register namespace prefix mapping (" + prefix + "," + namespace + ")!" +
-                      "There is already a mapping existing: '(" + k1 + "," + namespace + ")'!");
-            }
-        });
-    }
-    /* if not, just add them */
-    this._namespaces[prefix] = namespace;
-    return this;
-};
-
-// ### addOrReplace(prefix, namespace)
-// This method adds new prefix mappings to the
-// current instance. This will overwrite existing mappings.
-// **Parameters**:
-// *{string|object}* **prefix** The prefix to be set. If it is an object, the
-// method will be applied to all key,value pairs sequentially.
-// *{string}* **namespace** The namespace to be set.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Namespaces}* : The current namespaces instance.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("", "http://...");
-//     // is always equal to
-//     namespaces.base("http://..."); // <-- setter of base namespace
-VIE.prototype.Namespaces.prototype.addOrReplace = function (prefix, namespace) {
-    if (typeof prefix === "object") {
-        for (var k1 in prefix) {
-            this.addOrReplace(k1, prefix[k1]);
-        }
-        return this;
-    }
-    this.remove(prefix);
-    this.removeNamespace(namespace);
-    return this.add(prefix, namespace);
-};
-
-// ### get(prefix)
-// This method retrieves a namespaces, given a prefix. If the
-// prefix is the empty string, the base namespace is returned.
-// **Parameters**:
-// *{string}* **prefix** The prefix to be retrieved.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{string|undefined}* : The namespace or ```undefined``` if no namespace could be found.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("test", "http://test.ns");
-//     console.log(namespaces.get("test")); // <-- "http://test.ns"
-VIE.prototype.Namespaces.prototype.get = function (prefix) {
-    if (prefix === "") {
-        return this.base();
-    }
-    return this._namespaces[prefix];
-};
-
-// ### getPrefix(namespace)
-// This method retrieves a prefix, given a namespace.
-// **Parameters**:
-// *{string}* **namespace** The namespace to be retrieved.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{string|undefined}* : The prefix or ```undefined``` if no prefix could be found.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("test", "http://test.ns");
-//     console.log(namespaces.getPrefix("http://test.ns")); // <-- "test"
-VIE.prototype.Namespaces.prototype.getPrefix = function (namespace) {
-    var prefix;
-    if (namespace.indexOf('<') === 0) {
-        namespace = namespace.substring(1, namespace.length - 1);
-    }
-    jQuery.each(this._namespaces, function (k1,v1) {
-        if (namespace.indexOf(v1) === 0) {
-            prefix = k1;
-        }
-
-        if (namespace.indexOf(k1 + ':') === 0) {
-            prefix = k1;
-        }
-    });
-    return prefix;
-};
-
-// ### contains(prefix)
-// This method checks, whether a prefix is stored in the instance.
-// **Parameters**:
-// *{string}* **prefix** The prefix to be checked.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* : ```true``` if the prefix could be found, ```false``` otherwise.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("test", "http://test.ns");
-//     console.log(namespaces.contains("test")); // <-- true
-VIE.prototype.Namespaces.prototype.contains = function (prefix) {
-    return (prefix in this._namespaces);
-};
-
-// ### containsNamespace(namespace)
-// This method checks, whether a namespace is stored in the instance.
-// **Parameters**:
-// *{string}* **namespace** The namespace to be checked.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* : ```true``` if the namespace could be found, ```false``` otherwise.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("test", "http://test.ns");
-//     console.log(namespaces.containsNamespace("http://test.ns")); // <-- true
-VIE.prototype.Namespaces.prototype.containsNamespace = function (namespace) {
-    return this.getPrefix(namespace) !== undefined;
-};
-
-// ### update(prefix, namespace)
-// This method overwrites the namespace that is stored under the
-// prefix ``prefix`` with the new namespace ``namespace``.
-// If a namespace is already bound to another prefix, an Error is thrown.
-// **Parameters**:
-// *{string}* **prefix** The prefix.
-// *{string}* **namespace** The namespace.
-// **Throws**:
-// *{Error}* If a namespace is already bound to another prefix.
-// **Returns**:
-// *{VIE.Namespaces}* : The namespace instance.
-// **Example usage**:
-//
-//     ...
-VIE.prototype.Namespaces.prototype.update = function (prefix, namespace) {
-    this.remove(prefix);
-    return this.add(prefix, namespace);
-};
-
-// ### updateNamespace(prefix, namespace)
-// This method overwrites the prefix that is bound to the
-// namespace ``namespace`` with the new prefix ``prefix``. If another namespace is
-// already registered with the given ``prefix``, an Error is thrown.
-// **Parameters**:
-// *{string}* **prefix** The prefix.
-// *{string}* **namespace** The namespace.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Namespaces}* : The namespace instance.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.add("test", "http://test.ns");
-//     namespaces.updateNamespace("test2", "http://test.ns");
-//     namespaces.get("test2"); // <-- "http://test.ns"
-VIE.prototype.Namespaces.prototype.updateNamespace = function (prefix, namespace) {
-    this.removeNamespace(prefix);
-    return this.add(prefix, namespace);
-};
-
-// ### remove(prefix)
-// This method removes the namespace that is stored under the prefix ``prefix``.
-// **Parameters**:
-// *{string}* **prefix** The prefix to be removed.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Namespaces}* : The namespace instance.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.add("test", "http://test.ns");
-//     namespaces.get("test"); // <-- "http://test.ns"
-//     namespaces.remove("test");
-//     namespaces.get("test"); // <-- undefined
-VIE.prototype.Namespaces.prototype.remove = function (prefix) {
-    if (prefix) {
-        delete this._namespaces[prefix];
-    }
-    return this;
-};
-
-// ### removeNamespace(namespace)
-// This method removes removes the namespace ``namespace`` from the instance.
-// **Parameters**:
-// *{string}* **namespace** The namespace to be removed.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{VIE.Namespaces}* : The namespace instance.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.add("test", "http://test.ns");
-//     namespaces.get("test"); // <-- "http://test.ns"
-//     namespaces.removeNamespace("http://test.ns");
-//     namespaces.get("test"); // <-- undefined
-VIE.prototype.Namespaces.prototype.removeNamespace = function (namespace) {
-    var prefix = this.getPrefix(namespace);
-    if (prefix) {
-        delete this._namespaces[prefix];
-    }
-    return this;
-};
-
-// ### toObj()
-// This method serializes the namespace instance into an associative
-// array representation. The base namespace is given an empty
-// string as key.
-// **Parameters**:
-// *{boolean}* **omitBase** If set to ```true``` this omits the baseNamespace.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{object}* : A serialization of the namespaces as an object.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.add("test", "http://test.ns");
-//     console.log(namespaces.toObj());
-//     // <-- {""    : "http://base.ns/",
-//             "test": "http://test.ns"}
-//     console.log(namespaces.toObj(true));
-//     // <-- {"test": "http://test.ns"}
-VIE.prototype.Namespaces.prototype.toObj = function (omitBase) {
-    if (omitBase) {
-        return jQuery.extend({}, this._namespaces);
-    }
-    return jQuery.extend({'' : this._base}, this._namespaces);
-};
-
-// ### curie(uri, safe)
-// This method converts a given
-// URI into a CURIE (or SCURIE), based on the given ```VIE.Namespaces``` object.
-// If the given uri is already a URI, it is left untouched and directly returned.
-// If no prefix could be found, an ```Error``` is thrown.
-// **Parameters**:
-// *{string}* **uri** The URI to be transformed.
-// *{boolean}* **safe** A flag whether to generate CURIEs or SCURIEs.
-// **Throws**:
-// *{Error}* If no prefix could be found in the passed namespaces.
-// **Returns**:
-// *{string}* The CURIE or SCURIE.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var uri = "<http://dbpedia.org/ontology/Person>";
-//     ns.curie(uri, false); // --> dbp:Person
-//     ns.curie(uri, true); // --> [dbp:Person]
-VIE.prototype.Namespaces.prototype.curie = function(uri, safe){
-    return VIE.Util.toCurie(uri, safe, this);
-};
-
-// ### isCurie(curie)
-// This method checks, whether
-// the given string is a CURIE and returns ```true``` if so and ```false```otherwise.
-// **Parameters**:
-// *{string}* **curie** The CURIE (or SCURIE) to be checked.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* ```true``` if the given curie is a CURIE or SCURIE and ```false``` otherwise.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var uri = "<http://dbpedia.org/ontology/Person>";
-//     var curie = "dbp:Person";
-//     var scurie = "[dbp:Person]";
-//     var text = "This is some text.";
-//     ns.isCurie(uri);    // --> false
-//     ns.isCurie(curie);  // --> true
-//     ns.isCurie(scurie); // --> true
-//     ns.isCurie(text);   // --> false
-VIE.prototype.Namespaces.prototype.isCurie = function (something) {
-    return VIE.Util.isCurie(something, this);
-};
-
-// ### uri(curie)
-// This method converts a
-// given CURIE (or save CURIE) into a URI, based on the given ```VIE.Namespaces``` object.
-// **Parameters**:
-// *{string}* **curie** The CURIE to be transformed.
-// **Throws**:
-// *{Error}* If no URI could be assembled.
-// **Returns**:
-// *{string}* : A string, representing the URI.
-// **Example usage**:
-//
-//     var ns = new myVIE.Namespaces(
-//           "http://viejs.org/ns/",
-//           { "dbp": "http://dbpedia.org/ontology/" }
-//     );
-//     var curie = "dbp:Person";
-//     var scurie = "[dbp:Person]";
-//     ns.uri(curie);
-//          --> <http://dbpedia.org/ontology/Person>
-//     ns.uri(scurie);
-//          --> <http://dbpedia.org/ontology/Person>
-VIE.prototype.Namespaces.prototype.uri = function (curie) {
-    return VIE.Util.toUri(curie, this);
-};
-
-// ### isUri(something)
-// This method checks, whether the given string is a URI.
-// **Parameters**:
-// *{string}* **something** : The string to be checked.
-// **Throws**:
-// *nothing*
-// **Returns**:
-// *{boolean}* : ```true``` if the string is a URI, ```false``` otherwise.
-// **Example usage**:
-//
-//     var namespaces = new vie.Namespaces("http://base.ns/");
-//     namespaces.addOrReplace("test", "http://test.ns");
-//     var uri = "<http://test.ns/Person>";
-//     var curie = "test:Person";
-//     namespaces.isUri(uri);   // --> true
-//     namespaces.isUri(curie); // --> false
-VIE.prototype.Namespaces.prototype.isUri = VIE.Util.isUri;
-/*global VIE:false Backbone:false _:false */
-if (!VIE.prototype.view) {
-    VIE.prototype.view = {};
-}
-
-VIE.prototype.view.Entity = Backbone.View.extend({
-    initialize: function(options) {
-        this.service = options.service ? options.service : 'rdfa';
-        this.vie = options.vie;
-
-        // Ensure view gets updated when properties of the Entity change.
-        _.bindAll(this, 'render', 'renderAbout');
-        this.model.on('change', this.render);
-        this.model.on('change:@subject', this.renderAbout);
-    },
-
-    // Rendering a view means writing the properties of the Entity back to
-    // the element containing our RDFa annotations.
-    render: function() {
-        this.vie.save({
-                element: this.el,
-                entity: this.model
-            }).
-            to(this.service).
-            execute();
-        return this;
-    },
-
-    renderAbout: function () {
-        this.vie.service(this.service).setElementSubject(this.model.getSubjectUri(), this.el);
-    }
-});
-})();
\ No newline at end of file
diff --git a/core/modules/edit/css/edit.css b/core/modules/edit/css/edit.css
index 6a5ac83..37e7578 100644
--- a/core/modules/edit/css/edit.css
+++ b/core/modules/edit/css/edit.css
@@ -121,9 +121,6 @@
    */
 }
 
-
-
-
 /**
  * Edit mode: modal.
  */
diff --git a/core/modules/edit/edit.module b/core/modules/edit/edit.module
index e80b0d0..79b7f3d 100644
--- a/core/modules/edit/edit.module
+++ b/core/modules/edit/edit.module
@@ -114,21 +114,19 @@ function edit_library_info() {
     'js' => array(
       // Core.
       $path . '/js/edit.js' => $options,
-      $path . '/js/app.js' => $options,
       // Models.
-      $path . '/js/models/edit-app-model.js' => $options,
+      $path . '/js/models/AppModel.js' => $options,
+      $path . '/js/models/EntityModel.js' => $options,
+      $path . '/js/models/FieldModel.js' => $options,
       // Views.
-      $path . '/js/views/propertyeditordecoration-view.js' => $options,
-      $path . '/js/views/contextuallink-view.js' => $options,
-      $path . '/js/views/modal-view.js' => $options,
-      $path . '/js/views/toolbar-view.js' => $options,
+      $path . '/js/views/AppView.js' => $options,
+      $path . '/js/views/EditorDecorationView.js' => $options,
+      $path . '/js/views/ContextualLinkView.js' => $options,
+      $path . '/js/views/ModalView.js' => $options,
+      $path . '/js/views/FieldToolbarView.js' => $options,
+      $path . '/js/views/EditorView.js' => $options,
       // Backbone.sync implementation on top of Drupal forms.
       $path . '/js/backbone.drupalform.js' => $options,
-      // VIE service.
-      $path . '/js/viejs/EditService.js' => $options,
-      // Create.js subclasses.
-      $path . '/js/createjs/editable.js' => $options,
-      $path . '/js/createjs/storage.js' => $options,
       // Other.
       $path . '/js/util.js' => $options,
       $path . '/js/theme.js' => $options,
@@ -149,8 +147,6 @@ function edit_library_info() {
       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'),
@@ -158,20 +154,20 @@ function edit_library_info() {
     ),
   );
   $libraries['edit.editorWidget.form'] = array(
-    'title' => '"Form" Create.js PropertyEditor widget',
+    'title' => 'Form editor',
     'version' => VERSION,
     'js' => array(
-      $path . '/js/createjs/editingWidgets/formwidget.js' => $options,
+      $path . '/js/editors/formEditor.js' => $options,
     ),
     'dependencies' => array(
       array('edit', 'edit'),
     ),
   );
   $libraries['edit.editorWidget.direct'] = array(
-    'title' => '"Direct" Create.js PropertyEditor widget',
+    'title' => 'Direct editor',
     'version' => VERSION,
     'js' => array(
-      $path . '/js/createjs/editingWidgets/drupalcontenteditablewidget.js' => $options,
+      $path . '/js/editors/directEditor.js' => $options,
     ),
     'dependencies' => array(
       array('edit', 'edit'),
diff --git a/core/modules/edit/js/app.js b/core/modules/edit/js/app.js
deleted file mode 100644
index 14d76a0..0000000
--- a/core/modules/edit/js/app.js
+++ /dev/null
@@ -1,391 +0,0 @@
-/**
- * @file
- * A Backbone View that is the central app controller.
- */
-(function ($, _, Backbone, Drupal, VIE) {
-
-"use strict";
-
-  Drupal.edit = Drupal.edit || {};
-  Drupal.edit.EditAppView = Backbone.View.extend({
-    vie: null,
-    domService: null,
-
-    // Configuration for state handling.
-    states: [],
-    activeEditorStates: [],
-    singleEditorStates: [],
-
-    // State.
-    $entityElements: null,
-
-    /**
-     * Implements Backbone Views' initialize() function.
-     */
-    initialize: function() {
-      _.bindAll(this, 'appStateChange', 'acceptEditorStateChange', 'editorStateChange');
-
-      // VIE instance for Edit.
-      this.vie = new VIE();
-      // Use our custom DOM parsing service until RDFa is available.
-      this.vie.use(new this.vie.EditService());
-      this.domService = this.vie.service('edit');
-
-      // Instantiate configuration for state handling.
-      this.states = [
-        null, 'inactive', 'candidate', 'highlighted',
-        'activating', 'active', 'changed', 'saving', 'saved', 'invalid'
-      ];
-      this.activeEditorStates = ['activating', 'active'];
-      this.singleEditorStates = _.union(['highlighted'], this.activeEditorStates);
-
-      this.$entityElements = $([]);
-
-      // Use Create's Storage widget.
-      this.$el.createStorage({
-        vie: this.vie,
-        editableNs: 'createeditable'
-      });
-
-      // When view/edit mode is toggled in the menu, update the editor widgets.
-      this.model.on('change:activeEntity', this.appStateChange);
-    },
-
-    /**
-     * Finds editable properties within a given context.
-     *
-     * Finds editable properties, registers them with the app, updates their
-     * state to match the current app state.
-     *
-     * @param $context
-     *   A jQuery-wrapped context DOM element within which will be searched.
-     */
-    findEditableProperties: function($context) {
-      var that = this;
-      var activeEntity = this.model.get('activeEntity');
-
-      this.domService.findSubjectElements($context).each(function() {
-        var $element = $(this);
-
-        // Ignore editable properties for which we've already set up Create.js.
-        if (that.$entityElements.index($element) !== -1) {
-          return;
-        }
-
-        $element
-          // Instantiate an EditableEntity widget.
-          .createEditable({
-            vie: that.vie,
-            disabled: true,
-            state: 'inactive',
-            acceptStateChange: that.acceptEditorStateChange,
-            statechange: function(event, data) {
-              that.editorStateChange(data.previous, data.current, data.propertyEditor);
-            },
-            decoratePropertyEditor: function(data) {
-              that.decorateEditor(data.propertyEditor);
-            }
-          })
-          // This event is triggered just before Edit removes an EditableEntity
-          // widget, so that we can do proper clean-up.
-          .on('destroyedPropertyEditor.edit', function(event, editor) {
-            that.undecorateEditor(editor);
-            that.$entityElements = that.$entityElements.not($(this));
-          })
-          // Transition the new PropertyEditor into the default state.
-          .createEditable('setState', 'inactive');
-
-        // If the new PropertyEditor is for the entity that's currently being
-        // edited, then transition it to the 'candidate' state.
-        // (This happens when a field was modified and is re-rendered.)
-        var entityOfProperty = $element.createEditable('option', 'model');
-        if (entityOfProperty.getSubjectUri() === activeEntity) {
-          $element.createEditable('setState', 'candidate');
-        }
-
-        // Add this new EditableEntity widget element to the list.
-        that.$entityElements = that.$entityElements.add($element);
-      });
-    },
-
-    /**
-     * Sets the state of PropertyEditor widgets when edit mode begins or ends.
-     *
-     * Should be called whenever EditAppModel's "activeEntity" changes.
-     */
-    appStateChange: function() {
-      // @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 activeEntity = this.model.get('activeEntity');
-      var $editableFieldsForEntity = $('[data-edit-id^="' + activeEntity + '/"]');
-
-      // First, change the status of all PropertyEditor widgets to 'inactive'.
-      this.$entityElements.each(function() {
-        $(this).createEditable('setState', 'inactive', null, {reason: 'stop'});
-      });
-
-      // Then, change the status of PropertyEditor widgets of the currently
-      // active entity to 'candidate'.
-      $editableFieldsForEntity.each(function() {
-        $(this).createEditable('setState', 'candidate');
-      });
-
-      // Manage the page's tab indexes.
-    },
-
-    /**
-     * Accepts or reject editor (PropertyEditor) state changes.
-     *
-     * This is what ensures that the app is in control of what happens.
-     *
-     * @param from
-     *   The previous state.
-     * @param to
-     *   The new state.
-     * @param predicate
-     *   The predicate of the property for which the state change is happening.
-     * @param context
-     *   The context that is trying to trigger the state change.
-     * @param callback
-     *   The callback function that should receive the state acceptance result.
-     */
-    acceptEditorStateChange: function(from, to, predicate, context, callback) {
-      var accept = true;
-
-      // If the app is in view mode, then reject all state changes except for
-      // those to 'inactive'.
-      if (context && context.reason === 'stop') {
-        if (from === 'candidate' && to === 'inactive') {
-          accept = true;
-        }
-      }
-      // Handling of edit mode state changes is more granular.
-      else {
-        // In general, enforce the states sequence. Disallow going back from a
-        // "later" state to an "earlier" state, except in explicitly allowed
-        // cases.
-        if (_.indexOf(this.states, from) > _.indexOf(this.states, to)) {
-          accept = false;
-          // Allow: activating/active -> candidate.
-          // Necessary to stop editing a property.
-          if (_.indexOf(this.activeEditorStates, from) !== -1 && to === 'candidate') {
-            accept = true;
-          }
-          // Allow: changed/invalid -> candidate.
-          // Necessary to stop editing a property when it is changed or invalid.
-          else if ((from === 'changed' || from === 'invalid') && to === 'candidate') {
-            accept = true;
-          }
-          // Allow: highlighted -> candidate.
-          // Necessary to stop highlighting a property.
-          else if (from === 'highlighted' && to === 'candidate') {
-            accept = true;
-          }
-          // Allow: saved -> candidate.
-          // Necessary when successfully saved a property.
-          else if (from === 'saved' && to === 'candidate') {
-            accept = true;
-          }
-          // Allow: invalid -> saving.
-          // Necessary to be able to save a corrected, invalid property.
-          else if (from === 'invalid' && to === 'saving') {
-            accept = true;
-          }
-        }
-
-        // If it's not against the general principle, then here are more
-        // disallowed cases to check.
-        if (accept) {
-          // Ensure only one editor (field) at a time may be higlighted or active.
-          if (from === 'candidate' && _.indexOf(this.singleEditorStates, to) !== -1) {
-            if (this.model.get('highlightedEditor') || this.model.get('activeEditor')) {
-              accept = false;
-            }
-          }
-          // Reject going from activating/active to candidate because of a
-          // mouseleave.
-          else if (_.indexOf(this.activeEditorStates, from) !== -1 && to === 'candidate') {
-            if (context && context.reason === 'mouseleave') {
-              accept = false;
-            }
-          }
-          // When attempting to stop editing a changed/invalid property, ask for
-          // confirmation.
-          else if ((from === 'changed' || from === 'invalid') && to === 'candidate') {
-            if (context && context.reason === 'mouseleave') {
-              accept = false;
-            }
-            else {
-              // Check whether the transition has been confirmed?
-              if (context && context.confirmed) {
-                accept = true;
-              }
-              // Confirm this transition.
-              else {
-                // The callback will be called from the helper function.
-                this._confirmStopEditing(callback);
-                return;
-              }
-            }
-          }
-        }
-      }
-
-      callback(accept);
-    },
-
-    /**
-     * Asks the user to confirm whether he wants to stop editing via a modal.
-     *
-     * @param acceptCallback
-     *   The callback function as passed to acceptEditorStateChange(). This
-     *   callback function will be called with the user's choice.
-     *
-     * @see acceptEditorStateChange()
-     */
-    _confirmStopEditing: function(acceptCallback) {
-      // Only instantiate if there isn't a modal instance visible yet.
-      if (!this.model.get('activeModal')) {
-        var that = this;
-        var modal = new Drupal.edit.views.ModalView({
-          model: this.model,
-          message: Drupal.t('You have unsaved changes'),
-          buttons: [
-            { action: 'discard', classes: 'gray-button', label: Drupal.t('Discard changes') },
-            { action: 'save', type: 'submit', classes: 'blue-button', label: Drupal.t('Save') }
-          ],
-          callback: function(action) {
-            // The active modal has been removed.
-            that.model.set('activeModal', null);
-            if (action === 'discard') {
-              acceptCallback(true);
-            }
-            else {
-              acceptCallback(false);
-              var editor = that.model.get('activeEditor');
-              editor.options.widget.setState('saving', editor.options.property);
-            }
-          }
-        });
-        this.model.set('activeModal', modal);
-        // The modal will set the activeModal property on the model when rendering
-        // to prevent multiple modals from being instantiated.
-        modal.render();
-      }
-      else {
-        // Reject as there is still an open transition waiting for confirmation.
-        acceptCallback(false);
-      }
-    },
-
-    /**
-     * Reacts to editor (PropertyEditor) state changes; tracks global state.
-     *
-     * @param from
-     *   The previous state.
-     * @param to
-     *   The new state.
-     * @param editor
-     *   The PropertyEditor widget object.
-     */
-    editorStateChange: function(from, to, editor) {
-      // @todo: BLOCKED_ON(Create.js, https://github.com/bergie/create/issues/133)
-      // Get rid of this once that issue is solved.
-      if (!editor) {
-        return;
-      }
-      else {
-        editor.stateChange(from, to);
-      }
-
-      // Keep track of the highlighted editor in the global state.
-      if (_.indexOf(this.singleEditorStates, to) !== -1 && this.model.get('highlightedEditor') !== editor) {
-        this.model.set('highlightedEditor', editor);
-      }
-      else if (this.model.get('highlightedEditor') === editor && to === 'candidate') {
-        this.model.set('highlightedEditor', null);
-      }
-
-      // Keep track of the active editor in the global state.
-      if (_.indexOf(this.activeEditorStates, to) !== -1 && this.model.get('activeEditor') !== editor) {
-        this.model.set('activeEditor', editor);
-      }
-      else if (this.model.get('activeEditor') === editor && to === 'candidate') {
-        // Discarded if it transitions from a changed state to 'candidate'.
-        if (from === 'changed' || from === 'invalid') {
-          // Retrieve the storage widget from DOM.
-          var createStorageWidget = this.$el.data('DrupalCreateStorage');
-          // Revert changes in the model, this will trigger the direct editable
-          // content to be reset and redrawn.
-          createStorageWidget.revertChanges(editor.options.entity);
-        }
-        this.model.set('activeEditor', null);
-      }
-
-      // Propagate the state change to the decoration and toolbar views.
-      // @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);
-    },
-
-    /**
-     * Decorates an editor (PropertyEditor).
-     *
-     * Upon the page load, all appropriate editors are initialized and decorated
-     * (i.e. even before anything of the editing UI becomes visible; even before
-     * edit mode is enabled).
-     *
-     * @param editor
-     *   The PropertyEditor widget object.
-     */
-    decorateEditor: function(editor) {
-      // Toolbars are rendered "on-demand" (highlighting or activating).
-      // They are a sibling element before the editor's DOM element.
-      editor.toolbarView = new Drupal.edit.views.ToolbarView({
-        editor: editor,
-        $storageWidgetEl: this.$el
-      });
-
-      // Decorate the editor's DOM element depending on its state.
-      editor.decorationView = new Drupal.edit.views.PropertyEditorDecorationView({
-        el: editor.element,
-        editor: editor,
-        toolbarId: editor.toolbarView.getId()
-      });
-
-      // @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.on('createeditablestatechange', function(event, data) {
-        editor.decorationView.stateChange(data.previous, data.current);
-        editor.toolbarView.stateChange(data.previous, data.current);
-      });
-    },
-
-    /**
-     * Undecorates an editor (PropertyEditor).
-     *
-     * Whenever a property has been updated, the old HTML will be replaced by
-     * the new (re-rendered) HTML. The EditableEntity widget will be destroyed,
-     * as will be the PropertyEditor widget. This method ensures Edit's editor
-     * views also are removed properly.
-     *
-     * @param editor
-     *   The PropertyEditor widget object.
-     */
-    undecorateEditor: function(editor) {
-      editor.toolbarView.undelegateEvents();
-      editor.toolbarView.remove();
-      delete editor.toolbarView;
-      editor.decorationView.undelegateEvents();
-      // Don't call .remove() on the decoration view, because that would remove
-      // a potentially rerendered field.
-      delete editor.decorationView;
-    }
-
-  });
-
-})(jQuery, _, Backbone, Drupal, VIE);
diff --git a/core/modules/edit/js/backbone.drupalform.js b/core/modules/edit/js/backbone.drupalform.js
index 750d16f..48b6f71 100644
--- a/core/modules/edit/js/backbone.drupalform.js
+++ b/core/modules/edit/js/backbone.drupalform.js
@@ -7,8 +7,11 @@
 "use strict";
 
 Backbone.defaultSync = Backbone.sync;
+
+// @todo We should define a per-model sync method and assign it when creating
+// the fieldModel instance.
 Backbone.sync = function(method, model, options) {
-  if (options.editor.options.editorName === 'form') {
+  if (this.get('editorName') === 'form') {
     return Backbone.syncDrupalFormWidget(method, model, options);
   }
   else {
@@ -17,13 +20,12 @@ Backbone.sync = function(method, model, options) {
 };
 
 /**
- * Performs syncing for "form" PredicateEditor widgets.
+ * Performs syncing for "form" Editor widgets.
  *
  * Implemented on top of Form API and the AJAX commands framework. Sets up
- * scoped AJAX command closures specifically for a given PredicateEditor widget
+ * scoped AJAX command closures specifically for a given Editor
  * (which contains a pre-existing form). By submitting the form through
- * Drupal.ajax and leveraging Drupal.ajax' ability to have scoped (per-instance)
- * command implementations, we are able to update the VIE model, re-render the
+ * Drupal.ajax and leveraging Drupal.ajax' ability to re-render the
  * form when there are validation errors and ensure no Drupal.ajax memory leaks.
  *
  * @see Drupal.edit.util.form
@@ -43,8 +45,6 @@ Backbone.syncDrupalFormWidget = function(method, model, options) {
       // Call Backbone.sync's success callback with the rerendered field.
       var changedAttributes = {};
       // @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] = undefined;
       changedAttributes[predicate + '/rendered'] = response.data;
       options.success(changedAttributes);
@@ -97,15 +97,14 @@ Backbone.syncDirect = function(method, model, options) {
         // Submit the form.
       $form.find('.edit-form-submit').trigger('click.edit');
     };
-    var entity = options.editor.options.entity;
-    var predicate = options.editor.options.property;
-    var value = model.get(predicate);
+
+    var value = model.get('currentValue');
 
     // If form doesn't already exist, load it and then submit.
     if (jQuery('#edit_backstage form').length === 0) {
       var formOptions = {
-        propertyID: Drupal.edit.util.calcPropertyID(entity, predicate),
-        $editorElement: options.editor.element,
+        propertyID: model.id,
+        $editorElement: model.get('$el'),
         nocssjs: true
       };
       Drupal.edit.util.form.load(formOptions, function(form, ajax) {
@@ -130,10 +129,8 @@ Backbone.syncDirect = function(method, model, options) {
           // Call Backbone.sync's success callback with the rerendered field.
           var changedAttributes = {};
           // @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] = jQuery(response.data).find('.field-item').html();
-          changedAttributes[predicate + '/rendered'] = response.data;
+          changedAttributes[model.id] = jQuery(response.data).find('.field-item').html();
+          changedAttributes[model.id + '/rendered'] = response.data;
           options.success(changedAttributes);
         };
 
@@ -167,8 +164,8 @@ Backbone.syncDirect = function(method, model, options) {
  *
  * This is called automatically by Backbone.syncDirect when saving is successful
  * (i.e. when there are no validation errors). Only when editing is canceled
- * while a PropertyEditor widget is in the invalid state, this must be called
- * "manually" (in practice, ToolbarView does this). This is necessary because
+ * while an Editor widget is in the invalid state, this must be called
+ * "manually" (in practice, FieldToolbarView does this). This is necessary because
  * Backbone.syncDirect is not aware of the application state, it only does the
  * syncing.
  * An alternative could be to also remove the hidden form when validation errors
diff --git a/core/modules/edit/js/createjs/editable.js b/core/modules/edit/js/createjs/editable.js
deleted file mode 100644
index 1316023..0000000
--- a/core/modules/edit/js/createjs/editable.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @file
- * Determines which editor (Create.js PropertyEditor widget) to use.
- */
-(function (jQuery, Drupal, drupalSettings) {
-
-"use strict";
-
-  jQuery.widget('Drupal.createEditable', jQuery.Midgard.midgardEditable, {
-    _create: function() {
-      this.vie = this.options.vie;
-
-      this.options.domService = 'edit';
-      this.options.predicateSelector = '*'; //'.edit-field.edit-allowed';
-
-      // The Create.js PropertyEditor widget configuration is not hardcoded; it
-      // is generated by the server.
-      this.options.propertyEditorWidgetsConfiguration = drupalSettings.edit.editors;
-
-      jQuery.Midgard.midgardEditable.prototype._create.call(this);
-    },
-
-    _propertyEditorName: function(data) {
-      // Pick a PropertyEditor widget for a property depending on its metadata.
-      var propertyID = Drupal.edit.util.calcPropertyID(data.entity, data.property);
-      return Drupal.edit.metadataCache[propertyID].editor;
-    }
-  });
-
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js b/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
deleted file mode 100644
index cde6163..0000000
--- a/core/modules/edit/js/createjs/editingWidgets/drupalcontenteditablewidget.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * @file
- * Override of Create.js' default "base" (plain contentEditable) widget.
- */
-(function (jQuery, Drupal) {
-
-"use strict";
-
-  // @todo D8: use jQuery UI Widget bridging.
-  // @see http://drupal.org/node/1874934#comment-7124904
-  jQuery.widget('Midgard.direct', jQuery.Midgard.editWidget, {
-
-    /**
-     * Implements getEditUISettings() method.
-     */
-    getEditUISettings: function() {
-      return { padding: true, unifiedToolbar: false, fullWidthToolbar: false };
-    },
-
-    /**
-     * Implements jQuery UI widget factory's _init() method.
-     *
-     * @todo: POSTPONED_ON(Create.js, https://github.com/bergie/create/issues/142)
-     * Get rid of this once that issue is solved.
-     */
-    _init: function() {},
-
-    /**
-     * Implements Create's _initialize() method.
-     */
-    _initialize: function() {
-      var that = this;
-
-      // Sets the state to 'changed' whenever the content has changed.
-      var before = jQuery.trim(this.element.text());
-      this.element.on('keyup paste', function (event) {
-        if (that.options.disabled) {
-          return;
-        }
-        var current = jQuery.trim(that.element.text());
-        if (before !== current) {
-          before = current;
-          that.options.changed(current);
-        }
-      });
-    },
-
-    /**
-     * Makes this PropertyEditor widget react to state changes.
-     */
-    stateChange: function(from, to) {
-      switch (to) {
-        case 'inactive':
-          break;
-        case 'candidate':
-          if (from !== 'inactive') {
-            // Removes the "contenteditable" attribute.
-            this.disable();
-          }
-          break;
-        case 'highlighted':
-          break;
-        case 'activating':
-          this.options.activated();
-          break;
-        case 'active':
-          // Sets the "contenteditable" attribute to "true".
-          this.enable();
-          break;
-        case 'changed':
-          break;
-        case 'saving':
-          break;
-        case 'saved':
-          break;
-        case 'invalid':
-          break;
-      }
-    }
-
-  });
-
-})(jQuery, Drupal);
diff --git a/core/modules/edit/js/createjs/editingWidgets/formwidget.js b/core/modules/edit/js/createjs/editingWidgets/formwidget.js
deleted file mode 100644
index aa2dd0a..0000000
--- a/core/modules/edit/js/createjs/editingWidgets/formwidget.js
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * @file
- * Form-based Create.js widget for structured content in Drupal.
- */
-(function ($, Drupal) {
-
-"use strict";
-
-  // @todo D8: change the name to "form" + use jQuery UI Widget bridging.
-  // @see http://drupal.org/node/1874934#comment-7124904
-  $.widget('Midgard.formEditEditor', $.Midgard.editWidget, {
-
-    id: null,
-    $formContainer: null,
-
-    /**
-     * Implements getEditUISettings() method.
-     */
-    getEditUISettings: function() {
-      return { padding: false, unifiedToolbar: false, fullWidthToolbar: false };
-    },
-
-    /**
-     * Implements jQuery UI widget factory's _init() method.
-     *
-     * @todo: POSTPONED_ON(Create.js, https://github.com/bergie/create/issues/142)
-     * Get rid of this once that issue is solved.
-     */
-    _init: function() {},
-
-    /**
-     * Implements Create's _initialize() method.
-     */
-    _initialize: function() {},
-
-    /**
-     * Makes this PropertyEditor widget react to state changes.
-     */
-    stateChange: function(from, to) {
-      switch (to) {
-        case 'inactive':
-          break;
-        case 'candidate':
-          if (from !== 'inactive') {
-            this.disable();
-          }
-          break;
-        case 'highlighted':
-          break;
-        case 'activating':
-          this.enable();
-          break;
-        case 'active':
-          break;
-        case 'changed':
-          break;
-        case 'saving':
-          break;
-        case 'saved':
-          break;
-        case 'invalid':
-          break;
-      }
-    },
-
-    /**
-     * Enables the widget.
-     */
-    enable: function () {
-      var $editorElement = $(this.options.widget.element);
-      var propertyID = Drupal.edit.util.calcPropertyID(this.options.entity, this.options.property);
-
-      // Generate a DOM-compatible ID for the form container DOM element.
-      this.id = 'edit-form-for-' + propertyID.replace(/\//g, '_');
-
-      // Render form container.
-      this.$formContainer = $(Drupal.theme('editFormContainer', {
-        id: this.id,
-        loadingMsg: Drupal.t('Loading…')}
-      ));
-      this.$formContainer
-        .find('.edit-form')
-        .addClass('edit-editable edit-highlighted edit-editing')
-        .attr('role', 'dialog');
-
-      // Insert form container in DOM.
-      if ($editorElement.css('display') === 'inline') {
-        // @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.
-        this.$formContainer.prependTo($editorElement.offsetParent());
-
-        var pos = $editorElement.position();
-        this.$formContainer.css('left', pos.left).css('top', pos.top);
-      }
-      else {
-        this.$formContainer.insertBefore($editorElement);
-      }
-
-      // Load form, insert it into the form container and attach event handlers.
-      var widget = this;
-      var formOptions = {
-        propertyID: propertyID,
-        $editorElement: $editorElement,
-        nocssjs: false
-      };
-      Drupal.edit.util.form.load(formOptions, function(form, ajax) {
-        Drupal.ajax.prototype.commands.insert(ajax, {
-          data: form,
-          selector: '#' + widget.id + ' .placeholder'
-        });
-
-        var $submit = widget.$formContainer.find('.edit-form-submit');
-        Drupal.edit.util.form.ajaxifySaving(formOptions, $submit);
-        widget.$formContainer
-          .on('formUpdated.edit', ':input', function () {
-            // Sets the state to 'changed'.
-            widget.options.changed();
-          })
-          .on('keypress.edit', 'input', function (event) {
-            if (event.keyCode === 13) {
-              return false;
-            }
-          });
-
-        // Sets the state to 'activated'.
-        widget.options.activated();
-      });
-    },
-
-    /**
-     * Disables the widget.
-     */
-    disable: function () {
-      if (this.$formContainer === null) {
-        return;
-      }
-
-      Drupal.edit.util.form.unajaxifySaving(this.$formContainer.find('.edit-form-submit'));
-      // Allow form widgets to detach properly.
-      Drupal.detachBehaviors(this.$formContainer, null, 'unload');
-      this.$formContainer
-        .off('change.edit', ':input')
-        .off('keypress.edit', 'input')
-        .remove();
-      this.$formContainer = null;
-    }
-  });
-
-})(jQuery, Drupal);
diff --git a/core/modules/edit/js/createjs/storage.js b/core/modules/edit/js/createjs/storage.js
deleted file mode 100644
index 580ff82..0000000
--- a/core/modules/edit/js/createjs/storage.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * @file
- * Subclasses jQuery.Midgard.midgardStorage to have consistent namespaces.
- */
-(function(jQuery) {
-
-"use strict";
-
-  jQuery.widget('Drupal.createStorage', jQuery.Midgard.midgardStorage, {});
-
-})(jQuery);
diff --git a/core/modules/edit/js/edit.js b/core/modules/edit/js/edit.js
index bf181ed..9b032b3 100644
--- a/core/modules/edit/js/edit.js
+++ b/core/modules/edit/js/edit.js
@@ -13,29 +13,38 @@ Drupal.edit.metadataCache = Drupal.edit.metadataCache || {};
  * Attach toggling behavior and in-place editing.
  */
 Drupal.behaviors.edit = {
+
+  views: {
+    contextualLinks: {}
+  },
+
+  collections: {
+    entities: null,
+    fields: null
+  },
+
   attach: function(context) {
+    var that = this;
     var $context = $(context);
     var $fields = $context.find('[data-edit-id]');
+    var options = $.extend({}, this.defaults, (drupalSettings.edit || {}));
+    var Collection;
 
-    // Initialize the Edit app.
-    $('body').once('edit-init', Drupal.edit.init);
-
-    var annotateField = function(field) {
-      if (_.has(Drupal.edit.metadataCache, field.editID)) {
-        var meta = Drupal.edit.metadataCache[field.editID];
+    // A collection of all in-place editable entities on the page.
+    if (!this.collections.entities) {
+      Collection = Backbone.Collection.extend({
+        model: Drupal.edit.EntityModel
+      });
+      this.collections.entities = new Collection();
+    }
 
-        field.$el.addClass((meta.access) ? 'edit-allowed' : 'edit-disallowed');
-        if (meta.access) {
-          field.$el
-            .attr('data-edit-field-label', meta.label)
-            .attr('aria-label', meta.aria)
-            .addClass('edit-field edit-type-' + ((meta.editor === 'form') ? 'form' : 'direct'));
-        }
+    // A collection of all in-place editable fields on the page.
+    if (!this.collections.fields) {
+      this.collections.fields = new Drupal.edit.FieldCollection();
+    }
 
-        return true;
-      }
-      return false;
-    };
+    // Initialize the Edit app.
+    $('body').once('edit-init', $.proxy(this.init, this, options));
 
     // Find all fields in the context without metadata.
     var fieldsToAnnotate = _.map($fields.not('.edit-allowed, .edit-disallowed'), function(el) {
@@ -46,14 +55,15 @@ Drupal.behaviors.edit = {
     // Fields whose metadata is known (typically when they were just modified)
     // can be annotated immediately, those remaining must be requested.
     var remainingFieldsToAnnotate = _.reduce(fieldsToAnnotate, function(result, field) {
-      if (!annotateField(field)) {
+      var isAnnotated = $.proxy(that.annotateField, that, field)();
+      if (!isAnnotated) {
         result.push(field);
       }
       return result;
     }, []);
 
     // Make fields that could be annotated immediately available for editing.
-    Drupal.edit.app.findEditableProperties($context);
+    this.findEditableProperties($context, options);
 
     if (remainingFieldsToAnnotate.length) {
       $(window).ready(function() {
@@ -75,10 +85,10 @@ Drupal.behaviors.edit = {
           });
 
           // Annotate the remaining fields based on the updated access cache.
-          _.each(remainingFieldsToAnnotate, annotateField);
+          _.each(remainingFieldsToAnnotate, $.proxy(that.annotateField, that));
 
-          // Find editable fields, make them editable.
-          Drupal.edit.app.findEditableProperties($context);
+          // Make fields that could be annotated immediately available for editing.
+          that.findEditableProperties($context, options);
 
           // Delete the Drupal.ajax instance that called this very function.
           delete Drupal.ajax[id];
@@ -90,37 +100,139 @@ Drupal.behaviors.edit = {
         $el.trigger('edit-internal.edit');
       });
     }
-  }
-};
-
-Drupal.edit.init = function() {
-  // Instantiate EditAppView, which is the controller of it all. EditAppModel
-  // instance tracks global state (viewing/editing in-place).
-  var appModel = new Drupal.edit.models.EditAppModel();
-  var app = new Drupal.edit.EditAppView({
-    el: $('body'),
-    model: appModel
-  });
-
-  // Add "Quick edit" links to all contextual menus where editing the full
-  // node is possible.
-  // @todo Generalize this to work for all entities.
-  $('ul.contextual-links li.node-edit')
-  .before('<li class="quick-edit"></li>')
-  .each(function() {
-    // Instantiate ContextualLinkView.
-    var $editContextualLink = $(this).prev();
-    var editContextualLinkView = new Drupal.edit.views.ContextualLinkView({
-      el: $editContextualLink.get(0),
+  },
+
+  /**
+   *
+   */
+  init: function (options) {
+    var that = this;
+    // Instantiate AppModel (application state) and AppView, which is the
+    // controller of the whole in-place editing experience.
+    var appModel = new Drupal.edit.AppModel();
+    var app = new Drupal.edit.AppView({
+      el: $('body').get(0),
       model: appModel,
-      entity: $editContextualLink.parents('[data-edit-entity]').attr('data-edit-entity')
+      entitiesCollection: this.collections.entities,
+      fieldsCollection: this.collections.fields
     });
-  });
+    var entityModel;
+
+    // Create a model for the Entity just once.
+    $('[data-edit-entity]').once('editEntity', function (index) {
+      var $this = $(this);
+      var id = $this.data('edit-entity');
 
-  // For now, we work with a singleton app, because for Drupal.behaviors to be
-  // able to discover new editable properties that get AJAXed in, it must know
-  // with which app instance they should be associated.
-  Drupal.edit.app = app;
+      entityModel = new Drupal.edit.EntityModel({
+        id: id
+      });
+      that.collections.entities.add(entityModel);
+
+      // Create a view for the contextual links for this entity, if any.
+      $this.find('.contextual-links')
+        .each(function () {
+          // Instantiate ContextualLinkView.
+          that.views.contextualLinks[id] = new Drupal.edit.ContextualLinkView($.extend({
+            el: this,
+            model: entityModel,
+            appModel: appModel
+          }, options));
+        });
+    });
+
+    // For now, we work with a singleton app, because for Drupal.behaviors to be
+    // able to discover new editable properties that get AJAXed in, it must know
+    // with which app instance they should be associated.
+    Drupal.edit.app = app;
+  },
+
+  /**
+   * Finds editable properties within a given context.
+   *
+   * Finds editable properties, registers them with the app, updates their
+   * state to match the current app state.
+   *
+   * @param $context
+   *   A jQuery-wrapped context DOM element within which will be searched.
+   */
+  // @todo move to AppView
+  findEditableProperties: function($context) {
+    var that = this;
+    // Retrieve the active entity, of which there can only ever be one.
+    var activeEntity = this.collections.entities.where({ isActive: true })[0];
+
+    $context.find('[data-edit-id].edit-allowed').once('edit').each(function() {
+      var $element = $(this);
+      var editID = $element.attr('data-edit-id');
+      var entityId = $element.closest('[data-edit-entity]').data('edit-entity');
+
+      // Early-return when no surrounding [data-edit-entity] is found.
+      // @todo This breaks down in weird cases like full node views, where the
+      // node title is not rendered within the node DOM, but as the *page* title
+      if (entityId === null) {
+        return;
+      }
+
+      // @todo whether the "Quick Edit"
+      // link should appear depends on whether the user has access to edit any
+      // of the entity's fields. So, it is blocked on the metadata callback to
+      // the server. This is not yet implemented in the D8 HEAD Edit, but it is
+      // in http://drupal.org/node/1971108. We should take this into account if
+      // possible. If not, then we'll just have to refactor later.
+      // For now, this assumption is acceptable.
+      var entity = that.collections.entities.where({ id: entityId })[0];
+
+      // The FieldModel stores the state of an in-place editable entity field.
+      var field = new Drupal.edit.FieldModel({
+        entity: entity,
+        $el: $element,
+        // By setting the id attribute, Backbone assumes that this model is
+        // already saved on the server. Calls to Backbone.sync will
+        // trigger an "update" method rather than a "create" method.
+        id: editID || null,
+        editID: editID || null,
+        label: Drupal.edit.metadataCache[editID].label,
+        editor: Drupal.edit.metadataCache[editID].editor,
+        html: $element[0].outerHTML,
+        acceptStateChange: _.bind(Drupal.edit.app.acceptEditorStateChange, Drupal.edit.app)
+      });
+
+      // Track all fields on the page.
+      that.collections.fields.add(field);
+
+      // If the new in-place editable field is for the entity that's currently
+      // being edited, then transition it to the 'candidate' state.
+      // (This happens when a field was modified and is re-rendered.)
+      if (entity === activeEntity) {
+        Drupal.edit.app.decorate(field);
+        field.set('state', 'candidate');
+      }
+    });
+  },
+
+  annotateField: function (field) {
+    if (_.has(Drupal.edit.metadataCache, field.editID)) {
+      var meta = Drupal.edit.metadataCache[field.editID];
+
+      field.$el.addClass((meta.access) ? 'edit-allowed' : 'edit-disallowed');
+      if (meta.access) {
+        field.$el
+          .attr('data-edit-field-label', meta.label)
+          .attr('aria-label', meta.aria)
+          .addClass('edit-field edit-type-' + ((meta.editor === 'form') ? 'form' : 'direct'));
+      }
+
+      return true;
+    }
+    return false;
+  },
+
+  defaults: {
+    strings: {
+      quickEdit: Drupal.t('Quick edit'),
+      stopQuickEdit: Drupal.t('Stop quick edit')
+    }
+  }
 };
 
 })(jQuery, _, Backbone, Drupal, drupalSettings);
diff --git a/core/modules/edit/js/editors/directEditor.js b/core/modules/edit/js/editors/directEditor.js
new file mode 100644
index 0000000..12273ec
--- /dev/null
+++ b/core/modules/edit/js/editors/directEditor.js
@@ -0,0 +1,89 @@
+/**
+ * @file
+ * Defined a editor for direct editable fields.
+ */
+(function ($, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+Drupal.edit.editors = Drupal.edit.editors || {};
+
+Drupal.edit.editors.direct = Backbone.View.extend({
+
+  /**
+   * {@inheritdoc}
+   */
+  getEditUISettings: function () {
+    return { padding: true, unifiedToolbar: false, fullWidthToolbar: false };
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  initialize: function () {
+    var that = this;
+
+    // Sets the state to 'changed' whenever the content has changed.
+    var before = jQuery.trim(this.element.text());
+    this.element.on('keyup paste', function (event) {
+      var current = jQuery.trim(that.element.text());
+      if (before !== current) {
+        before = current;
+        that.model.set('state', 'changed');
+
+        // @todo we have yet to set this value originally (before the editing
+        // starts) AND we have to handle the reverting aspect when editing is
+        // canceled, see editorStateChange().
+        that.model.set('value', current);
+      }
+    });
+  },
+
+  /**
+   * Determines the actions to take given a change of state.
+   *
+   * @param Drupal.edit.FieldModel model
+   * @param String state
+   *   The state of the associated field. One of Drupal.edit.FieldModel.states.
+   */
+  stateChange: function (model, state) {
+    var from = model.previous('state');
+    var to = state;
+    switch (to) {
+      case 'inactive':
+        break;
+      case 'candidate':
+        if (from !== 'inactive') {
+          // Removes the "contenteditable" attribute.
+          this.disable();
+        }
+        break;
+      case 'highlighted':
+        break;
+      case 'activating':
+        // As soon as the current state change has propagated, apply this one.
+        // @see http://jsfiddle.net/5MVzp/2/ vs. http://jsfiddle.net/5MVzp/3/
+        var that = this;
+        _.defer(function() {
+          that.model.set('state', 'active');
+        });
+        break;
+      case 'active':
+        // Sets the "contenteditable" attribute to "true".
+        this.enable();
+        break;
+      case 'changed':
+        break;
+      case 'saving':
+        this.save();
+        break;
+      case 'saved':
+        break;
+      case 'invalid':
+        break;
+    }
+  }
+});
+
+})(jQuery, Drupal);
diff --git a/core/modules/edit/js/editors/formEditor.js b/core/modules/edit/js/editors/formEditor.js
new file mode 100644
index 0000000..b356135
--- /dev/null
+++ b/core/modules/edit/js/editors/formEditor.js
@@ -0,0 +1,190 @@
+/**
+ * @file
+ * Form-based in-place editor. Works for any field type.
+ */
+(function ($, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+Drupal.edit.editors = Drupal.edit.editors || {};
+
+Drupal.edit.editors.form = Drupal.edit.EditorView.extend({
+
+  $formContainer: null,
+
+  /**
+   * {@inheritdoc}
+   */
+  stateChange: function (model, state) {
+    var from = model.previous('state');
+    var to = state;
+    switch (to) {
+      case 'inactive':
+        break;
+      case 'candidate':
+        if (from !== 'inactive') {
+          this.disable();
+        }
+        if (from === 'invalid') {
+          // No need to call removeValidationErrors() for this in-place editor!
+        }
+        break;
+      case 'highlighted':
+        break;
+      case 'activating':
+        this.enable();
+        break;
+      case 'active':
+        break;
+      case 'changed':
+        break;
+      case 'saving':
+        this.save();
+        break;
+      case 'saved':
+        break;
+      case 'invalid':
+        this.showValidationErrors();
+        break;
+    }
+  },
+
+  /**
+   * Enables the widget.
+   */
+  enable: function () {
+    // Generate a DOM-compatible ID for the form container DOM element.
+    var id = 'edit-form-for-' + this.model.get('editID').replace(/\//g, '_');
+
+    // Render form container.
+    this.$formContainer = $(Drupal.theme('editFormContainer', {
+      id: id,
+      loadingMsg: Drupal.t('Loading…')}
+    ));
+    this.$formContainer
+      .find('.edit-form')
+      .addClass('edit-editable edit-highlighted edit-editing')
+      .attr('role', 'dialog');
+
+    // Insert form container in DOM.
+    if (this.$el.css('display') === 'inline') {
+      this.$formContainer.prependTo(this.$el.offsetParent());
+      // Position the form container to render on top of the field's element.
+      var pos = this.$el.position();
+      this.$formContainer.css('left', pos.left).css('top', pos.top);
+    }
+    else {
+      this.$formContainer.insertBefore(this.$el);
+    }
+
+    // Load form, insert it into the form container and attach event handlers.
+    var that = this;
+    var formOptions = {
+      propertyID: this.model.get('editID'),
+      $editorElement: this.$el,
+      nocssjs: false
+    };
+    Drupal.edit.util.form.load(formOptions, function(form, ajax) {
+      Drupal.ajax.prototype.commands.insert(ajax, {
+        data: form,
+        selector: '#' + id + ' .placeholder'
+      });
+
+      var $submit = that.$formContainer.find('.edit-form-submit');
+      Drupal.edit.util.form.ajaxifySaving(formOptions, $submit);
+      that.$formContainer
+        .on('formUpdated.edit', ':input', function () {
+          that.model.set('state', 'changed');
+        })
+        .on('keypress.edit', 'input', function (event) {
+          if (event.keyCode === 13) {
+            return false;
+          }
+        });
+
+      // The in-place editor has loaded; change state to 'active'.
+      that.model.set('state', 'active');
+    });
+  },
+
+  /**
+   * Disables the widget.
+   */
+  disable: function () {
+    if (this.$formContainer === null) {
+      return;
+    }
+
+    Drupal.edit.util.form.unajaxifySaving(this.$formContainer.find('.edit-form-submit'));
+    // Allow form widgets to detach properly.
+    Drupal.detachBehaviors(this.$formContainer, null, 'unload');
+    this.$formContainer
+      .off('change.edit', ':input')
+      .off('keypress.edit', 'input')
+      .remove();
+    this.$formContainer = null;
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  save: function () {
+    var $formContainer = this.model.attributes.editorView.$formContainer;
+    var $submit = $formContainer.find('.edit-form-submit');
+    var base = $submit.attr('id');
+    var that = this;
+
+    // Successfully saved.
+    Drupal.ajax[base].commands.editFieldFormSaved = function(ajax, response, status) {
+      Drupal.edit.util.form.unajaxifySaving(jQuery(ajax.element));
+
+      // First, transition the state to 'saved'.
+      that.model.set('state', 'saved');
+      // Then, set the 'html' attribute on the field model. This will cause the
+      // field to be rerendered.
+      that.model.set('html', response.data);
+     };
+
+    // Unsuccessfully saved; validation errors.
+    Drupal.ajax[base].commands.editFieldFormValidationErrors = function(ajax, response, status) {
+      that.model.set('validationErrors', response.data);
+      that.model.set('state', 'invalid');
+    };
+
+    // The edit_field_form AJAX command is only called upon loading the form for
+    // the first time, and when there are validation errors in the form; Form
+    // API then marks which form items have errors. Therefor, we have to replace
+    // the existing form, unbind the existing Drupal.ajax instance and create a
+    // new Drupal.ajax instance.
+    Drupal.ajax[base].commands.editFieldForm = function(ajax, response, status) {
+      Drupal.edit.util.form.unajaxifySaving(jQuery(ajax.element));
+
+      Drupal.ajax.prototype.commands.insert(ajax, {
+        data: response.data,
+        selector: '#' + $formContainer.attr('id') + ' form'
+      });
+
+      // Create a Drupal.ajax instance for the re-rendered ("new") form.
+      var $newSubmit = $formContainer.find('.edit-form-submit');
+      Drupal.edit.util.form.ajaxifySaving({ nocssjs: false }, $newSubmit);
+    };
+
+    // Click the form's submit button; the scoped AJAX commands above will
+    // handle the server's response.
+    $submit.trigger('click.edit');
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  showValidationErrors: function () {
+    this.$formContainer
+      .find('.edit-form')
+      .addClass('edit-validation-error')
+      .find('form')
+      .prepend(this.model.get('validationErrors'));
+  }
+});
+
+})(jQuery, Drupal);
diff --git a/core/modules/edit/js/models/AppModel.js b/core/modules/edit/js/models/AppModel.js
new file mode 100644
index 0000000..402d0f7
--- /dev/null
+++ b/core/modules/edit/js/models/AppModel.js
@@ -0,0 +1,23 @@
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+
+$.extend(Drupal.edit, {
+
+  /**
+   *
+   */
+  AppModel: Backbone.Model.extend({
+    defaults: {
+      activeEntity: null,
+      highlightedEditor: null,
+      activeEditor: null,
+      // Reference to a ModalView-instance if a state change requires confirmation.
+      activeModal: null
+    }
+  })
+});
+
+}(jQuery, _, Backbone, Drupal));
diff --git a/core/modules/edit/js/models/EntityModel.js b/core/modules/edit/js/models/EntityModel.js
new file mode 100644
index 0000000..047ffe7
--- /dev/null
+++ b/core/modules/edit/js/models/EntityModel.js
@@ -0,0 +1,28 @@
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+
+$.extend(Drupal.edit, {
+
+  /**
+   *
+   */
+  EntityModel: Backbone.Model.extend({
+    defaults: {
+      // An entity ID, of the form "<entity type>/<entity ID>", e.g. "node/1".
+      id: null,
+      // Indicates whether this instance of this entity is currently being
+      // edited.
+      isActive: false,
+      // A Drupal.edit.FieldCollection for all fields of this entity.
+      fields: null
+    },
+    initialize: function () {
+      this.set('fields', new Drupal.edit.FieldCollection());
+    }
+  })
+});
+
+}(jQuery, _, Backbone, Drupal));
diff --git a/core/modules/edit/js/models/FieldModel.js b/core/modules/edit/js/models/FieldModel.js
new file mode 100644
index 0000000..0181b9b
--- /dev/null
+++ b/core/modules/edit/js/models/FieldModel.js
@@ -0,0 +1,131 @@
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+
+$.extend(Drupal.edit, {
+
+  /**
+   *
+   */
+  FieldModel: Backbone.Model.extend({
+    defaults: {
+      // @todo Try to get rid of this, but it's hard; see appStateChange()
+      $el: null,
+
+      // Possible states: @see Drupal.edit.FieldModel.states.
+      state: 'inactive',
+      // A Drupal.edit.EntityModel. Its "fields" attribute, which is a
+      // FieldCollection, is automatically updated to include this FieldModel.
+      entity: null,
+
+
+      //
+      // Data set by the metadata callback.
+      //
+      // The ID of the in-place editor to use.
+      editor: null,
+      // The label to use.
+      label: null,
+
+      //
+      // Data derived from the information in the DOM.
+      //
+
+      // The edit ID, format: `<entity type>:<id>:<field name>:<language code>:<view mode>`.
+      editID: null,
+      // The full HTML representation of this field (with the element that has
+      // the data-edit-id as the outer element). Used to propagate changes from
+      // this field instance to other instances of the same field.
+      html: null,
+
+      // Not the full HTML representation of this field, but the "actual"
+      // original value of the field, stored by the used in-place editor, and
+      // in a representation that can be chosen by the in-place editor.
+      originalValue: null,
+      // Analogous to originalValue, but the current value.
+      currentValue: null,
+      // Optional, editor-specific custom value to store for this field.
+      editorSpecific: null,
+
+      validationErrors: null,
+
+      //
+      // Callbacks.
+      //
+
+      // Callback function for validating changes between states. Receives the
+      // previous state, new state, context, and a callback
+      acceptStateChange: null,
+
+
+      //
+      // Attached views.
+      //
+
+      editorView: null,
+      toolbarView: null,
+      decorationView: null
+
+    },
+    initialize: function () {
+      this.get('entity').get('fields').add(this);
+      this.on('change:state', function(model, state) {
+        console.log('%c [MOD] ' + this.previous('state') + ' → ' + state + '    ' + model.get('editID'), 'background-color: blue; color: white');
+      });
+      this.on('error', function(model, error) {
+          console.log('%c' + model.get("editID") + " " + error, 'color: orange');
+      });
+    },
+    destroy: function(options) {
+      if (this.get('state') !== 'inactive') {
+        throw new Error("FieldModel cannot be destroyed if it is not inactive state.");
+      }
+      Backbone.Model.prototype.destroy.apply(this, options);
+    },
+    validate: function (attrs, options) {
+      // We only care about validating the 'state' attribute.
+      if (!_.has(attrs, 'state')) {
+        return;
+      }
+
+      var current = this.get('state');
+      var next = attrs.state;
+      if (current !== next) {
+        // Ensure it's a valid state.
+        if (_.indexOf(this.constructor.states, next) === -1) {
+          return '"' + next + '" is an invalid state';
+        }
+        // Check if the acceptStateChange callback accepts it.
+        if (!this.get('acceptStateChange')(current, next, options)) {
+          return 'state change not accepted';
+        }
+      }
+    },
+    // Parses the `<entity type>/<id>` part from the edit ID.
+    getEntityID: function() {
+      return this.get('editID').split('/').slice(0, 2).join('/');
+    },
+    // Parses the `<field name>/<language code>/<view mode>` part from the edit ID.
+    getFieldID: function() {
+      return this.get('editID').split('/').slice(2, 5).join('/');
+    }
+  }, {
+    states: [
+        'inactive', 'candidate', 'highlighted',
+        'activating', 'active', 'changed', 'saving', 'saved', 'invalid'
+    ],
+    followsStateSequence: function (from, to) {
+      return _.indexOf(this.states, from) < _.indexOf(this.states, to);
+    }
+  }),
+
+  // A collection of FieldModels.
+  // @todo link back to the entity at the collection level (not the collection element level)?
+  FieldCollection: Backbone.Collection.extend({
+    model: Drupal.edit.FieldModel
+  })
+});
+
+}(jQuery, _, Backbone, Drupal));
diff --git a/core/modules/edit/js/models/edit-app-model.js b/core/modules/edit/js/models/edit-app-model.js
deleted file mode 100644
index 0c90fd0..0000000
--- a/core/modules/edit/js/models/edit-app-model.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @file
- * A Backbone Model that models the current Edit application state.
- */
-(function(Backbone, Drupal) {
-
-"use strict";
-
-Drupal.edit = Drupal.edit || {};
-Drupal.edit.models = Drupal.edit.models || {};
-Drupal.edit.models.EditAppModel = Backbone.Model.extend({
-  defaults: {
-    activeEntity: null,
-    highlightedEditor: null,
-    activeEditor: null,
-    // Reference to a ModalView-instance if a transition requires confirmation.
-    activeModal: null
-  }
-});
-
-})(Backbone, Drupal);
diff --git a/core/modules/edit/js/util.js b/core/modules/edit/js/util.js
index e0aa490..7e1bd57 100644
--- a/core/modules/edit/js/util.js
+++ b/core/modules/edit/js/util.js
@@ -24,7 +24,7 @@ Drupal.edit.util.calcPropertyID = function(entity, predicate) {
  * be used.
  *
  * @param editor
- *   A Create.js PropertyEditor widget instance.
+ *   A Drupal.edit.Editor instance.
  * @param setting
  *   Name of the Edit UI integration setting.
  *
diff --git a/core/modules/edit/js/viejs/EditService.js b/core/modules/edit/js/viejs/EditService.js
deleted file mode 100644
index 00cb04b..0000000
--- a/core/modules/edit/js/viejs/EditService.js
+++ /dev/null
@@ -1,289 +0,0 @@
-/**
- * @file
- * VIE DOM parsing service for Edit.
- */
-(function(jQuery, _, VIE, Drupal, drupalSettings) {
-
-"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 = drupalSettings.edit.context;
-        }
-      } else {
-        element = loadable.options.element;
-      }
-
-      var entities = this.readEntities(element);
-      loadable.resolve(entities);
-    },
-
-    _getViewForElement:function (element, collectionView) {
-      var viewInstance;
-
-      jQuery.each(this.views, function () {
-        if (jQuery(this.el).get(0) === element.get(0)) {
-          if (collectionView && !this.template) {
-            return true;
-          }
-          viewInstance = this;
-          return false;
-        }
-      });
-      return viewInstance;
-    },
-
-    _registerEntityView:function (entity, element, isNew) {
-      if (!element.length) {
-        return;
-      }
-
-      // Let's only have this overhead for direct types. Form-based editors are
-      // handled in backbone.drupalform.js and the PropertyEditor instance.
-      if (jQuery(element).hasClass('edit-type-form')) {
-        return;
-      }
-
-      var service = this;
-      var viewInstance = this._getViewForElement(element);
-      if (viewInstance) {
-        return viewInstance;
-      }
-
-      viewInstance = new this.vie.view.Entity({
-        model:entity,
-        el:element,
-        tagName:element.get(0).nodeName,
-        vie:this.vie,
-        service:this.name
-      });
-
-      this.views.push(viewInstance);
-
-      return viewInstance;
-    },
-
-    save: function(saveable) {
-      var correct = saveable instanceof this.vie.Savable;
-      if (!correct) {
-        throw "Invalid Savable passed";
-      }
-
-      if (!saveable.options.element) {
-        // FIXME: we could find element based on subject
-        throw "Unable to write entity to edit.module-markup, no element given";
-      }
-
-      if (!saveable.options.entity) {
-        throw "Unable to write to edit.module-markup, no entity given";
-      }
-
-      var $element = jQuery(saveable.options.element);
-      this._writeEntity(saveable.options.entity, saveable.options.element);
-      saveable.resolve();
-    },
-
-    _writeEntity:function (entity, element) {
-      var service = this;
-      this.findPredicateElements(this.getElementSubject(element), element, true).each(function () {
-        var predicateElement = jQuery(this);
-        var predicate = service.getElementPredicate(predicateElement);
-        if (!entity.has(predicate)) {
-          return true;
-        }
-
-        var value = entity.get(predicate);
-        if (value && value.isCollection) {
-          // Handled by CollectionViews separately
-          return true;
-        }
-        if (value === service.readElementValue(predicate, predicateElement)) {
-          return true;
-        }
-        // Unlike in the VIE's RdfaService no (re-)mapping needed here.
-        predicateElement.html(value);
-      });
-      return true;
-    },
-
-    // The edit-id data attribute contains the full identifier of
-    // each entity element in the format
-    // `<entity type>:<id>:<field name>:<language code>:<view mode>`.
-    _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
-    // `<entity type>/<id>`.
-    getElementSubject: function (element) {
-      return this._getID(element).split('/').slice(0, 2).join('/');
-    },
-
-    // Returns the field name for an element in format
-    // `<field name>/<language code>/<view mode>`.
-    // (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);
-      }
-
-      var entityInstance = new this.vie.Entity(entity);
-      entityInstance = this.vie.entities.addOrUpdate(entityInstance, {
-        updateOptions: {
-          silent: true,
-          ignoreChanges: true
-        }
-      });
-
-      this._registerEntityView(entityInstance, element);
-      return entityInstance;
-    },
-
-    _registerType: function (typeId, element) {
-      typeId = '<http://viejs.org/ns/' + 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 range = predicate.split('/')[0];
-      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(predicate, predicateElement);
-        if (value === null && !emptyValues) {
-          return;
-        }
-
-        entityPredicates[predicate] = value;
-        entityPredicates[predicate + '/rendered'] = predicateElement[0].outerHTML;
-      });
-      return entityPredicates;
-    },
-
-    readElementValue : function(predicate, element) {
-      // Unlike in RdfaService there is parsing needed here.
-      if (element.hasClass('edit-type-form')) {
-        return undefined;
-      }
-      else {
-        return jQuery.trim(element.html());
-      }
-    },
-
-    // Subject elements are the DOM elements containing a single or multiple
-    // editable fields.
-    findSubjectElements: function (element) {
-      if (!element) {
-        element = drupalSettings.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();
-      // Make sure that element is wrapped by jQuery.
-      var $element = jQuery(element);
-
-      // 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, _, VIE, Drupal, drupalSettings);
diff --git a/core/modules/edit/js/views/AppView.js b/core/modules/edit/js/views/AppView.js
new file mode 100644
index 0000000..742dcc5
--- /dev/null
+++ b/core/modules/edit/js/views/AppView.js
@@ -0,0 +1,362 @@
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+
+$.extend(Drupal.edit, {
+
+  /**
+   *
+   */
+  AppView: Backbone.View.extend({
+
+    // Configuration for state handling.
+    activeEditorStates: [],
+    singleEditorStates: [],
+
+    /**
+     * Implements Backbone Views' initialize() function.
+     */
+    initialize: function (options) {
+      this.entitiesCollection = options.entitiesCollection;
+      this.fieldsCollection = options.fieldsCollection;
+
+      _.bindAll(this, 'appStateChange', 'acceptEditorStateChange', 'editorStateChange');
+
+      // Instantiate configuration for state handling.
+      // @see Drupal.edit.FieldModel.states
+      this.activeEditorStates = ['activating', 'active'];
+      this.singleEditorStates = _.union(['highlighted'], this.activeEditorStates);
+
+      this.entitiesCollection
+        // Track app state.
+        .on('change:isActive', this.appStateChange, this)
+        .on('change:isActive', this.enforceSingleActiveEntity, this);
+
+      this.fieldsCollection
+        // Track app state.
+        .on('change:state', this.editorStateChange, this)
+        // Respond to field model HTML representation change events.
+        .on('change:html', this.propagateUpdatedField, this)
+        .on('change:html', this.renderUpdatedField, this)
+        // Respond to destruction
+        .on('destroy', this.undecorate, this);
+    },
+
+    /**
+     * Handles setup/teardown and state changes when the active entity changes.
+     */
+    appStateChange: function (entityModel, isActive) {
+      var app = this;
+      if (isActive) {
+        // Move all fields of this entity from the 'inactive' state to the
+        // 'candidate' state.
+        entityModel.get('fields').each(function (fieldModel) {
+          // First, set up decoration views.
+          app.decorate(fieldModel);
+          // Second, change the field's state.
+          fieldModel.set('state', 'candidate');
+        });
+      }
+      else {
+        // Move all fields of this entity from whatever state they are in to
+        // the 'inactive' state.
+        entityModel.get('fields').each(function (fieldModel) {
+          // First, change the field's state.
+          fieldModel.set('state', 'inactive', { reason: 'stop' });
+          // Second, tear down decoration views.
+          app.undecorate(fieldModel);
+        });
+      }
+    },
+
+    /**
+     * Accepts or reject editor (Editor) state changes.
+     *
+     * This is what ensures that the app is in control of what happens.
+     *
+     * @param String from
+     *   The previous state.
+     * @param String to
+     *   The new state.
+     * @param null|Object context
+     *   The context that is trying to trigger the state change.
+     * @param Function callback
+     *   The callback function that should receive the state acceptance result.
+     */
+    acceptEditorStateChange: function(from, to, context, callback) {
+      var accept = true;
+
+      console.log("accept? %s → %s (reason: %s)", from, to, (context && context.reason) ? context.reason : 'NONE');
+
+      // If the app is in view mode, then reject all state changes except for
+      // those to 'inactive'.
+      if (context && (context.reason === 'stop' || context.reason === 'rerender')) {
+        if (from === 'candidate' && to === 'inactive') {
+          accept = true;
+        }
+      }
+      // Handling of edit mode state changes is more granular.
+      else {
+        // In general, enforce the states sequence. Disallow going back from a
+        // "later" state to an "earlier" state, except in explicitly allowed
+        // cases.
+        if (!Drupal.edit.FieldModel.followsStateSequence(from, to)) {
+          accept = false;
+          // Allow: activating/active -> candidate.
+          // Necessary to stop editing a property.
+          if (_.indexOf(this.activeEditorStates, from) !== -1 && to === 'candidate') {
+            accept = true;
+          }
+          // Allow: changed/invalid -> candidate.
+          // Necessary to stop editing a property when it is changed or invalid.
+          else if ((from === 'changed' || from === 'invalid') && to === 'candidate') {
+            accept = true;
+          }
+          // Allow: highlighted -> candidate.
+          // Necessary to stop highlighting a property.
+          else if (from === 'highlighted' && to === 'candidate') {
+            accept = true;
+          }
+          // Allow: saved -> candidate.
+          // Necessary when successfully saved a property.
+          else if (from === 'saved' && to === 'candidate') {
+            accept = true;
+          }
+          // Allow: invalid -> saving.
+          // Necessary to be able to save a corrected, invalid property.
+          else if (from === 'invalid' && to === 'saving') {
+            accept = true;
+          }
+        }
+
+        // If it's not against the general principle, then here are more
+        // disallowed cases to check.
+        if (accept) {
+          // Ensure only one editor (field) at a time may be higlighted or active.
+          if (from === 'candidate' && _.indexOf(this.singleEditorStates, to) !== -1) {
+            if (this.model.get('highlightedEditor') || this.model.get('activeEditor')) {
+              accept = false;
+            }
+          }
+          // Reject going from activating/active to candidate because of a
+          // mouseleave.
+          else if (_.indexOf(this.activeEditorStates, from) !== -1 && to === 'candidate') {
+            if (context && context.reason === 'mouseleave') {
+              accept = false;
+            }
+          }
+          // When attempting to stop editing a changed/invalid property, ask for
+          // confirmation.
+          else if ((from === 'changed' || from === 'invalid') && to === 'candidate') {
+            if (context && context.reason === 'mouseleave') {
+              accept = false;
+            }
+            else {
+              // Check whether the transition has been confirmed?
+              if (context && context.confirmed) {
+                accept = true;
+              }
+              // Confirm this transition.
+              else {
+                // Do not accept this change right now, instead open a modal
+                // that will ask the user to confirm his choice.
+                accept = false;
+                // The callback will be called from the helper function.
+                this._confirmStopEditing(callback);
+              }
+            }
+          }
+        }
+      }
+
+      return accept;
+    },
+
+    // @todo rename to decorateField
+    decorate: function (fieldModel) {
+      var editID = fieldModel.get('editID');
+      var $el = fieldModel.get('$el');
+
+      // Create a new Editor.
+      var editorName = fieldModel.get('editor');
+      fieldModel.set('editorName', editorName);
+      var editorView = new Drupal.edit.editors[editorName]({
+        el: $el,
+        model: fieldModel
+      });
+
+      // Toolbars are rendered "on-demand" (highlighting or activating).
+      // They are a sibling element before the editor's DOM element.
+      var toolbarView = new Drupal.edit.FieldToolbarView({
+        model: fieldModel,
+        $field: $el,
+        editorView: editorView
+      });
+
+      // Decorate the editor's DOM element depending on its state.
+      var decorationView = new Drupal.edit.EditorDecorationView({
+        el: $el,
+        model: fieldModel,
+        editorView: editorView,
+        toolbarId: toolbarView.getId()
+      });
+
+      // Create references in the field model; necessary for undecorate() and
+      // necessary for some EditorView implementations.
+      fieldModel.set('editorView', editorView);
+      fieldModel.set('toolbarView', toolbarView);
+      fieldModel.set('decorationView', decorationView);
+    },
+
+    // @todo rename to undecorateField
+    undecorate: function (fieldModel) {
+      // Unbind event handlers; remove toolbar element; delete toolbar view.
+      var toolbarView = fieldModel.get('toolbarView');
+      toolbarView.undelegateEvents();
+      toolbarView.remove();
+      fieldModel.unset('toolbarView');
+
+      // Unbind event handlers; delete decoration view. Don't remove the element
+      // because that would remove the field itself.
+      var decorationView = fieldModel.get('decorationView');
+      decorationView.undelegateEvents();
+      fieldModel.unset('decorationView');
+
+      // Unbind event handlers; delete editor view. Don't remove the element
+      // because that would remove the field itself.
+      var editorView = fieldModel.get('editorView');
+      editorView.undelegateEvents();
+      fieldModel.unset('editorView');
+    },
+
+    /**
+     * Asks the user to confirm whether he wants to stop editing via a modal.
+     *
+     * @see acceptEditorStateChange()
+     */
+    _confirmStopEditing: function () {
+      // Only instantiate if there isn't a modal instance visible yet.
+      if (!this.model.get('activeModal')) {
+        var that = this;
+        var modal = new Drupal.edit.ModalView({
+          model: this.model,
+          message: Drupal.t('You have unsaved changes'),
+          buttons: [
+            { action: 'discard', classes: 'gray-button', label: Drupal.t('Discard changes') },
+            { action: 'save', type: 'submit', classes: 'blue-button', label: Drupal.t('Save') }
+          ],
+          callback: function(action) {
+            // The active modal has been removed.
+            that.model.set('activeModal', null);
+            // Set the state that matches the user's action.
+            var targetState = (action === 'discard') ? 'candidate' : 'saving';
+            that.model.get('activeEditor').set('state', 'candidate', { confirmed: true });
+          }
+        });
+        this.model.set('activeModal', modal);
+        // The modal will set the activeModal property on the model when rendering
+        // to prevent multiple modals from being instantiated.
+        modal.render();
+      }
+    },
+
+    /**
+     * Reacts to field state changes; tracks global state.
+     *
+     * @param Drupal.edit.FieldModel fieldModel
+     * @param String state
+     *   The state of the associated field. One of Drupal.edit.FieldModel.states.
+     */
+    editorStateChange: function(fieldModel, state) {
+      var from = fieldModel.previous('state');
+      var to = state;
+
+      console.log("%c [APP] %s → %s    %s", "background-color: black; color: white", from, to, fieldModel.get('editID'));
+
+      // Keep track of the highlighted editor in the global state.
+      if (_.indexOf(this.singleEditorStates, to) !== -1 && this.model.get('highlightedEditor') !== fieldModel) {
+        this.model.set('highlightedEditor', fieldModel);
+      }
+      else if (this.model.get('highlightedEditor') === fieldModel && to === 'candidate') {
+        this.model.set('highlightedEditor', null);
+      }
+
+      // Keep track of the active editor in the global state.
+      if (_.indexOf(this.activeEditorStates, to) !== -1 && this.model.get('activeEditor') !== fieldModel) {
+        this.model.set('activeEditor', fieldModel);
+      }
+      else if (this.model.get('activeEditor') === fieldModel && to === 'candidate') {
+        // Discarded if it transitions from a changed state to 'candidate'.
+        if (from === 'changed' || from === 'invalid') {
+          fieldModel.get('editorView').revert();
+        }
+        this.model.set('activeEditor', null);
+      }
+    },
+
+    // Updates all known instances of a specific entity field whenever the HTML
+    // representation of one of them has changed.
+    // @todo: this is currently prototype-level code, test this. The principle is
+    // sound, but the tricky thing is that an editID includes the view mode, but
+    // we actually want to update the same field in other view modes too, which
+    // means this method will have to check if there are any such instances, and
+    // if so, go to the server and re-render those too.
+    propagateUpdatedField: function (changedModel) {
+      // changedModel.collection.where({ editID: changedModel.get('editID') })
+        // .set('html', changedModel.get('html'));
+    },
+
+    renderUpdatedField: function (field) {
+      // Get data necessary to rerender property before it is unavailable.
+      var html = field.get('html');
+      var $fieldWrapper = field.get('$el').closest('[data-edit-id]');
+      var $context = $fieldWrapper.parent();
+
+      // First set the state to 'candidate', to allow all attached views to
+      // clean up all their "active state"-related changes.
+      // @todo: get rid of this, ensure all views do the proper clean-up when
+      // going directly to the 'inactive' state.
+      field.set('state', 'candidate');
+
+      // Set the field's state to 'inactive', to enable the updating of its DOM
+      // value.
+      field.set('state', 'inactive', { reason: 'rerender' });
+
+      // Destroy the field model; this will cause all attached views to be
+      // destroyed too, and removal from all collections in which it exists.
+      field.destroy();
+
+      // Replace the old content with the new content.
+      $fieldWrapper.replaceWith(html);
+
+      // Attach behaviors again to the modified piece of HTML; this will cause
+      // a new field model to be created.
+      Drupal.attachBehaviors($context);
+    },
+
+    /**
+     * EntityModel Collection change handler, called on change:isActive, enforces
+     * a single active entity.
+     */
+    enforceSingleActiveEntity: function (changedEntityModel) {
+      // When an entity is deactivated, we don't need to enforce anything.
+      if (changedEntityModel.get('isActive') === false) {
+        return;
+      }
+
+      // This entity was activated; deactivate all other entities.
+      changedEntityModel.collection.chain()
+        .filter(function (entityModel) {
+          return entityModel.get('isActive') === true && entityModel !== changedEntityModel;
+        })
+        .each(function (entityModel) {
+          entityModel.set('isActive', false);
+        });
+    }
+
+  })
+});
+
+}(jQuery, _, Backbone, Drupal));
diff --git a/core/modules/edit/js/views/ContextualLinkView.js b/core/modules/edit/js/views/ContextualLinkView.js
new file mode 100644
index 0000000..401e60a
--- /dev/null
+++ b/core/modules/edit/js/views/ContextualLinkView.js
@@ -0,0 +1,75 @@
+/**
+ * @file
+ * A Backbone View that a dynamic contextual link.
+ */
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+// Main model: Drupal.edit.EntityModel
+Drupal.edit.ContextualLinkView = Backbone.View.extend({
+
+  events: {
+    'click .quick-edit a': function (event) {
+      event.preventDefault();
+      this.model.set('isActive', !this.model.get('isActive'));
+    }
+  },
+
+  /**
+   * Implements Backbone.View.prototype.initialize().
+   *
+   * @param Object options
+   *   An object with the following keys:
+   *   - appModel: the application state model
+   *   - strings: the strings for the "Quick edit" link
+   */
+  initialize: function (options) {
+    this.appModel = options.appModel;
+    this.strings = options.strings;
+
+    // @todo Is this a good idea at all? I'm very unsure…
+    if (!this.model instanceof Drupal.edit.EntityModel) {
+      throw new Error('Drupal.edit.ContextualLinkView only accepts Drupal.edit.EntityModel models.');
+    }
+
+    // Build the DOM elements.
+    // @todo make this work in a generic way instead of applying this hack,
+    // being handled at http://drupal.org/node/1971108.
+    this.$el
+      .find('li.node-edit')
+      .before('<li class="quick-edit"><a href="#"></a></li>');
+
+    // Initial render.
+    this.render();
+
+    // Re-render whenever this entity's isActive attribute changes.
+    this.model.on('change:isActive', this.render, this);
+
+    // Hide the contextual links whenever an in-place editor is active.
+    this.appModel.on('change:activeEditor', this.toggleContextualLinksVisibility, this);
+  },
+
+  /**
+   * Implements Backbone.View.prototype.render().
+   */
+  render: function () {
+    var isActive = this.model.get('isActive');
+    this.$el.find('.quick-edit a').text((!isActive) ? this.strings.quickEdit : this.strings.stopQuickEdit);
+    return this;
+  },
+
+  /**
+   * Hides the contextual links if an in-place editor is active.
+   *
+   * @param Drupal.edit.AppModel model
+   * @param null|Drupal.edit.FieldModel activeEditor
+   *   The model of the field that is currently being edited, or, if none, null.
+   */
+  toggleContextualLinksVisibility: function (model, activeEditor) {
+    this.$el.parents('.contextual').toggle(activeEditor === null);
+  }
+
+});
+
+})(jQuery, _, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/EditorDecorationView.js b/core/modules/edit/js/views/EditorDecorationView.js
new file mode 100644
index 0000000..41647df
--- /dev/null
+++ b/core/modules/edit/js/views/EditorDecorationView.js
@@ -0,0 +1,362 @@
+/**
+ * @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.EditorDecorationView = Backbone.View.extend({
+  toolbarId: null,
+
+  _widthAttributeIsEmpty: null,
+
+  events: {
+    'mouseenter.edit' : 'onMouseEnter',
+    'mouseleave.edit' : 'onMouseLeave',
+    'click': 'onClick',
+    'tabIn.edit': 'onMouseEnter',
+    'tabOut.edit': 'onMouseLeave'
+  },
+
+  /**
+   * Implements Backbone.View.prototype.initialize().
+   *
+   * @param Object options
+   *   An object with the following keys:
+   *   - editorView: the editor object with an 'options' object that has these keys:
+   *      * property: the predicate of the property.
+   *      * editorName: the name of the Editor.
+   *   - toolbarId: the ID attribute of the toolbar as rendered in the DOM.
+   */
+  initialize: function (options) {
+    this.editorView = options.editorView;
+
+    this.toolbarId = options.toolbarId;
+
+    this.model.on('change:state', this.stateChange, this);
+  },
+
+  /**
+   * Determines the actions to take given a change of state.
+   *
+   * @param Drupal.edit.FieldModel model
+   * @param String state
+   *   The state of the associated field. One of Drupal.edit.FieldModel.states.
+   */
+  stateChange: function (model, state) {
+    var from = model.previous('state');
+    var to = state;
+    switch (to) {
+      case 'inactive':
+        this.undecorate();
+        break;
+      case 'candidate':
+        this.decorate();
+        if (from !== 'inactive') {
+          this.stopHighlight();
+          if (from !== 'highlighted') {
+            this.stopEdit();
+          }
+        }
+        break;
+      case 'highlighted':
+        this.startHighlight();
+        break;
+      case 'activating':
+        // NOTE: this state is not used by every editor! It's only used by those
+        // that need to interact with the server.
+        this.prepareEdit();
+        break;
+      case 'active':
+        if (from !== 'activating') {
+          this.prepareEdit();
+        }
+        this.startEdit();
+        break;
+      case 'changed':
+        break;
+      case 'saving':
+        break;
+      case 'saved':
+        break;
+      case 'invalid':
+        break;
+    }
+  },
+
+  /**
+   * Starts hover; transitions to 'highlight' state.
+   *
+   * @param jQuery event
+   */
+  onMouseEnter: function (event) {
+    var that = this;
+    this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
+      that.model.set('state', 'highlighted');
+      event.stopPropagation();
+    });
+  },
+
+  /**
+   * Stops hover; transitions to 'candidate' state.
+   *
+   * @param jQuery event
+   */
+  onMouseLeave: function (event) {
+    var that = this;
+    this._ignoreHoveringVia(event, '#' + this.toolbarId, function () {
+      that.model.set('state', 'candidate', { reason: 'mouseleave' });
+      event.stopPropagation();
+    });
+  },
+
+  /**
+   * Transition to 'activating' stage.
+   *
+   * @param jQuery event
+   */
+  onClick: function (event) {
+    this.model.set('state', 'activating');
+    event.preventDefault();
+    event.stopPropagation();
+  },
+
+  /**
+   * Adds classes used to indicate an elements editable state.
+   */
+  decorate: function () {
+    this.$el.addClass('edit-animate-fast edit-candidate edit-editable');
+  },
+
+  /**
+   * Removes classes used to indicate an elements editable state.
+   */
+  undecorate: function () {
+    this.$el.removeClass('edit-candidate edit-editable edit-highlighted edit-editing');
+  },
+
+  /**
+   * Adds that class that indicates that an element is highlighted.
+   */
+  startHighlight: function () {
+    // Animations.
+    var that = this;
+    // Use a timeout to grab the next available animation frame.
+    setTimeout(function () {
+      that.$el.addClass('edit-highlighted');
+    }, 0);
+  },
+
+  /**
+   * Removes the class that indicates that an element is highlighted.
+   */
+  stopHighlight: function () {
+    this.$el.removeClass('edit-highlighted');
+  },
+
+  /**
+   * Removes the class that indicates that an element as editable.
+   */
+  prepareEdit: function () {
+    this.$el.addClass('edit-editing');
+
+    // While editing, do not show any other editors.
+    $('.edit-candidate').not('.edit-editing').removeClass('edit-editable');
+  },
+
+  /**
+   * Updates the display of the editable element once editing has begun.
+   */
+  startEdit: function () {
+    if (this.getEditUISetting('padding')) {
+      this._pad();
+    }
+  },
+
+  /**
+   * Removes the class that indicates that an element is being edited.
+   *
+   * Reapplies the class that indicates that a candidate editable element is
+   * again available to be edited.
+   */
+  stopEdit: function () {
+    this.$el.removeClass('edit-highlighted edit-editing');
+
+    // Make the other editors show up again.
+    $('.edit-candidate').addClass('edit-editable');
+
+    if (this.getEditUISetting('padding')) {
+      this._unpad();
+    }
+  },
+
+  /**
+   * Retrieves a setting of the editor-specific Edit UI integration.
+   *
+   * @param String setting
+   *
+   * @see Drupal.edit.util.getEditUISetting().
+   */
+  getEditUISetting: function (setting) {
+    return Drupal.edit.util.getEditUISetting(this.editorView, setting);
+  },
+
+  /**
+   * Adds padding around the editable element in order to make it pop visually.
+   */
+  _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())
+        .css('background-color', this._getBgColor(this.$el));
+    }
+
+    // 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);
+  },
+
+  /**
+   * Removes the padding around the element being edited when editing ceases.
+   */
+  _unpad: function () {
+    var self = this;
+
+    // 1) Set the empty width again.
+    if (this._widthAttributeIsEmpty) {
+      this.$el
+        .addClass('edit-animate-disable-width')
+        .css('width', '')
+        .css('background-color', '');
+    }
+
+    // 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 DOM $e
+   */
+  _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.
+   *
+   * Convert extraneous values and information into numbers ready for
+   * subtraction.
+   *
+   * @param DOM $e
+   */
+  _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: <value>" values with "0px".
+   *
+   * @param String pos
+   *   (optional) 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.
+   *
+   * When a hover occurs to/from another element, invoke the callback.
+   *
+   * @param jQuery event
+   * @param jQuery closest
+   *   A jQuery-wrapped DOM element or compatibale jQuery input. The element
+   *   whose mouseenter and mouseleave events should be ignored.
+   * @param Function callback
+   */
+  _ignoreHoveringVia: function (event, closest, callback) {
+    if ($(event.relatedTarget).closest(closest).length > 0) {
+      event.stopPropagation();
+    }
+    else {
+      callback();
+    }
+  }
+});
+
+})(jQuery, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/EditorView.js b/core/modules/edit/js/views/EditorView.js
new file mode 100644
index 0000000..52a12a9
--- /dev/null
+++ b/core/modules/edit/js/views/EditorView.js
@@ -0,0 +1,213 @@
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit = Drupal.edit || {};
+
+$.extend(Drupal.edit, {
+
+  /**
+   * A base implementation that outlines the structure for in-place editors.
+   *
+   * Specific in-place editor implementations should subclass (extend) this View
+   * and override whichever method they deem necessary to override.
+   *
+   * Look at Drupal.edit.editors.form and Drupal.edit.editors.direct for
+   * examples.
+   */
+  EditorView: Backbone.View.extend({
+
+    /**
+     * Implements Backbone.View.prototype.initialize().
+     *
+     * If you override this method, you should call this method (the parent
+     * class' initialize()) first, like this:
+     *   Drupal.edit.EditorView.prototype.initialize.call(this, options);
+     *
+     * For an example, @see Drupal.edit.editors.direct.
+     */
+    initialize: function (options) {
+      this.model.on('change:state', this.stateChange, this);
+    },
+
+    /**
+     * Returns 3 Edit UI settings that depend on the in-place editor:
+     *  - padding: @todo
+     *  - unifiedToolbar: @todo
+     *  - fullWidthToolbar: @todo
+     */
+    getEditUISettings: function () {
+      return { padding: false, unifiedToolbar: false, fullWidthToolbar: false };
+    },
+
+    /**
+     * Determines the actions to take given a change of state.
+     *
+     * @param Drupal.edit.FieldModel model
+     * @param String state
+     *   The state of the associated field. One of Drupal.edit.FieldModel.states.
+     */
+    stateChange: function (model, state) {
+      var from = model.previous('state');
+      var to = state;
+      switch (to) {
+        case 'inactive':
+          // An in-place editor view will not yet exist in this state, hence
+          // this will never be reached. Listed for sake of completeness.
+          break;
+        case 'candidate':
+          // Nothing to do for the typical in-place editor: it should not be
+          // visible yet.
+
+          // Except when we come from the 'invalid' state, then we clean up.
+          if (from === 'invalid') {
+            this.removeValidationErrors();
+          }
+          break;
+        case 'highlighted':
+          // Nothing to do for the typical in-place editor: it should not be
+          // visible yet.
+          break;
+        case 'activating':
+          // The user has indicated he wants to do in-place editing: if
+          // something needs to be loaded (CSS/JavaScript/server data/…), then
+          // do so at this stage, and once the in-place editor is ready,
+          // set the 'active' state.
+          // A "loading" indicator will be shown in the UI for as long as the
+          // field remains in this state.
+          var that = this;
+          var loadDependencies = function (callback) {
+            // Do the loading here.
+            callback();
+          };
+          loadDependencies(function () {
+            that.model.set('state', 'active');
+          });
+          break;
+        case 'active':
+          // The user can now actually use the in-place editor.
+          break;
+        case 'changed':
+          // Nothing to do for the typical in-place editor. The UI will show an
+          // indicator that the field has changed.
+          break;
+        case 'saving':
+          // When the user has indicated he wants to save his changes to this
+          // field, this state will be entered.
+          // If the previous saving attempt resulted in validation errors, the
+          // previous state will be 'invalid'. Clean up those validation errors
+          // while the user is saving.
+          if (from === 'invalid') {
+            this.removeValidationErrors();
+          }
+          this.save();
+          break;
+        case 'saved':
+          // Nothing to do for the typical in-place editor. Immediately after
+          // being saved, a field will go to the 'candidate' state, where it
+          // should no longer be visible (after all, the field will then again
+          // just be a *candidate* to be in-place edited).
+          break;
+        case 'invalid':
+          // The modified field value was attempted to be saved, but there were
+          // validation errors.
+          this.showValidationErrors();
+          break;
+      }
+    },
+
+    /**
+     * Reverts the modified value back to the original value (before editing
+     * started).
+     */
+    revert: function () {
+      // @todo Should we implement a default here?
+    },
+
+    /**
+     * Saves the modified value in the in-place editor for this field.
+     */
+    save: function () {
+      // @todo implement here the "direct" case, i.e. the hidden form case
+      this.model.save(null, {
+        // Successfully saved without validation errors.
+        success: function (model, response, options) {
+          model.set('state', 'saved');
+
+          var entity = model.get('entity');
+          var id = model.get('id');
+
+          // Now that the changes to this property have been saved, the saved
+          // attributes are now the "original" attributes.
+          entity._originalAttributes = entity._previousAttributes = _.clone(entity.attributes);
+
+          // Get data necessary to rerender property before it is unavailable.
+          var updatedProperty = response[id + '/rendered'];
+          var $propertyWrapper = model.get('$el');
+          var $context = $propertyWrapper.parent();
+
+          model.set('state', 'candidate');
+
+          // @todo Do we need this trigger now that everything is driven from
+          // models?
+          // Trigger event to allow for proper clean-up of editor-specific views.
+          //editor.element.trigger('destroyedPropertyEditor.edit', editor);
+
+          // Replace the old content with the new content.
+          $propertyWrapper.replaceWith(updatedProperty);
+          Drupal.attachBehaviors($context);
+        },
+
+        // Save attempted but failed due to validation errors.
+        error: function (validationErrorMessages) {
+          editableEntity.setState('invalid', predicate);
+
+          if (that.editorName === 'form') {
+            editor.$formContainer
+              .find('.edit-form')
+              .addClass('edit-validation-error')
+              .find('form')
+              .prepend(validationErrorMessages);
+          }
+          else {
+            var $errors = $('<div class="edit-validation-errors"></div>')
+              .append(validationErrorMessages);
+            editor.element
+              .addClass('edit-validation-error')
+              .after($errors);
+          }
+        }
+      });
+    },
+
+    /**
+     * Shows validation error messages.
+     *
+     * Should be called when the state is changed to 'invalid'.
+     */
+    showValidationErrors: function () {
+      var $errors = $('<div class="edit-validation-errors"></div>')
+        .append(this.model.get('validationErrors'));
+      this.model.get('$el')
+        .addClass('edit-validation-error')
+        .after($errors);
+    },
+
+    /**
+     * Cleans up validation error messages.
+     *
+     * Should be called when the state is changed to 'candidate' or 'saving'. In
+     * the case of the latter: the user has modified the value in the in-place
+     * editor again to attempt to save again. In the case of the latter: the
+     * invalid value was discarded.
+     */
+    removeValidationErrors: function () {
+      this.model.get('$el')
+        .removeClass('edit-validation-error')
+        .next('.edit-validation-errors')
+        .remove();
+    }
+  })
+});
+
+}(jQuery, _, Backbone, Drupal));
diff --git a/core/modules/edit/js/views/FieldToolbarView.js b/core/modules/edit/js/views/FieldToolbarView.js
new file mode 100644
index 0000000..a854312
--- /dev/null
+++ b/core/modules/edit/js/views/FieldToolbarView.js
@@ -0,0 +1,414 @@
+/**
+ * @file
+ * A Backbone View that provides an interactive toolbar (1 per property editor).
+ *
+ * It listens to state changes of the property editor. It also triggers state
+ * changes in response to user interactions with the toolbar, including saving.
+ */
+(function ($, _, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit.FieldToolbarView = Backbone.View.extend({
+  $field: null,
+
+  _loader: null,
+  _loaderVisibleStart: 0,
+
+  _id: null,
+
+  events: {
+    'click.edit button.label': 'onClickInfoLabel',
+    'mouseleave.edit': 'onMouseLeave',
+    'click.edit button.field-save': 'onClickSave',
+    'click.edit button.field-close': 'onClickClose'
+  },
+
+  /**
+   * Implements Backbone.View.prototype.initialize().
+   */
+  initialize: function (options) {
+    this.$field = options.$field;
+    this.editorView = options.editorView;
+
+    this._loader = null;
+    this._loaderVisibleStart = 0;
+
+    // Generate a DOM-compatible ID for the form container DOM element.
+    this._id = 'edit-toolbar-for-' + this.model.get('editID').replace(/\//g, '_');
+
+    this.model.on('change:state', this.stateChange, this);
+  },
+
+  /**
+   * Implements Backbone.View.prototype.render().
+   *
+   * Depending on whether the display property of the $el for which a
+   * toolbar is being inserted into the DOM, it will be inserted differently.
+   */
+  render: function () {
+    // Render toolbar.
+    this.setElement($(Drupal.theme('editToolbarContainer', {
+      id: this._id
+    })));
+
+    // Insert in DOM.
+    if (this.$field.css('display') === 'inline') {
+      this.$el.prependTo(this.$field.offsetParent());
+      var pos = this.$field.position();
+      this.$el.css('left', pos.left).css('top', pos.top);
+    }
+    else {
+      this.$el.insertBefore(this.$field);
+    }
+
+    return this;
+  },
+
+  /**
+   * Determines the actions to take given a change of state.
+   *
+   * @param Drupal.edit.FieldModel model
+   * @param String state
+   *   The state of the associated field. One of Drupal.edit.FieldModel.states.
+   */
+  stateChange: function (model, state) {
+    var from = model.previous('state');
+    var to = state;
+    switch (to) {
+      case 'inactive':
+        if (from) {
+          this.remove();
+          if (this.model.get('editor') !== 'form') {
+            Backbone.syncDirectCleanUp();
+          }
+        }
+        break;
+      case 'candidate':
+        if (from === 'inactive') {
+          this.render();
+        }
+        else {
+          if (this.model.get('editor') !== 'form') {
+            Backbone.syncDirectCleanUp();
+          }
+          // Remove all toolgroups; they're no longer necessary.
+          this.$el
+            .removeClass('edit-highlighted edit-editing')
+            .find('.edit-toolbar .edit-toolgroup').remove();
+          if (from !== 'highlighted' && this.getEditUISetting('padding')) {
+            this._unpad();
+          }
+        }
+        break;
+      case 'highlighted':
+        // As soon as we highlight, make sure we have a toolbar in the DOM (with at least a title).
+        this.startHighlight();
+        break;
+      case 'activating':
+        this.setLoadingIndicator(true);
+        break;
+      case 'active':
+        this.startEdit();
+        this.setLoadingIndicator(false);
+        if (this.getEditUISetting('fullWidthToolbar')) {
+          this.$el.addClass('edit-toolbar-fullwidth');
+        }
+
+        if (this.getEditUISetting('padding')) {
+          this._pad();
+        }
+        if (this.getEditUISetting('unifiedToolbar')) {
+          this.insertWYSIWYGToolGroups();
+        }
+        break;
+      case 'changed':
+        this.$el
+          .find('button.save')
+          .addClass('blue-button')
+          .removeClass('gray-button');
+        break;
+      case 'saving':
+        this.setLoadingIndicator(true);
+        break;
+      case 'saved':
+        this.setLoadingIndicator(false);
+        break;
+      case 'invalid':
+        this.setLoadingIndicator(false);
+        break;
+    }
+  },
+
+  /**
+   * Redirects the click.edit-event to the editor DOM element.
+   *
+   * @param jQuery event
+   */
+  onClickInfoLabel: function (event) {
+    event.stopPropagation();
+    event.preventDefault();
+    // Redirects the event to the editor DOM element.
+    this.$field.trigger('click.edit');
+  },
+
+  /**
+   * Controls mouseleave events.
+   *
+   * A mouseleave to the editor doesn't matter; a mouseleave to something else
+   * counts as a mouseleave on the editor itself.
+   *
+   * @param jQuery event
+   */
+  onMouseLeave: function (event) {
+    if (event.relatedTarget !== this.$field[0] && !$.contains(this.$field, event.relatedTarget)) {
+      this.$field.trigger('mouseleave.edit');
+    }
+    event.stopPropagation();
+  },
+
+  /**
+   * Set the model state to 'saving' when the save button is clicked.
+   *
+   * @param jQuery event
+   */
+  onClickSave: function (event) {
+    event.stopPropagation();
+    event.preventDefault();
+    this.model.set('state', 'saving');
+  },
+
+  /**
+   * Sets the model state to candidate when the cancel button is clicked.
+   *
+   * @param jQuery event
+   */
+  onClickClose: function (event) {
+    event.stopPropagation();
+    event.preventDefault();
+    this.model.set('state', 'candidate', { reason: 'cancel' });
+  },
+
+  /**
+   * Indicates in the 'info' toolgroup that we're waiting for a server reponse.
+   *
+   * Prevents flickering loading indicator by only showing it after 0.6 seconds
+   * and if it is shown, only hiding it after another 0.6 seconds.
+   *
+   * @param Boolean enabled
+   *   Whether the loading indicator should be displayed or not.
+   */
+  setLoadingIndicator: function (enabled) {
+    var that = this;
+    if (enabled) {
+      this._loader = setTimeout(function() {
+        that.addClass('info', 'loading');
+        that._loaderVisibleStart = new Date().getTime();
+      }, 600);
+    }
+    else {
+      var currentTime = new Date().getTime();
+      clearTimeout(this._loader);
+      if (this._loaderVisibleStart) {
+        setTimeout(function() {
+          that.removeClass('info', 'loading');
+        }, this._loaderVisibleStart + 600 - currentTime);
+      }
+      this._loader = null;
+      this._loaderVisibleStart = 0;
+    }
+  },
+
+  /**
+   *
+   */
+  startHighlight: function () {
+    // Retrieve the lavel to show for this field.
+    var label = this.model.get('label');
+
+    this.$el
+      .addClass('edit-highlighted')
+      .find('.edit-toolbar')
+      // Append the "info" toolgroup into the toolbar.
+      .append(Drupal.theme('editToolgroup', {
+        classes: 'info edit-animate-only-background-and-padding',
+        buttons: [
+          { label: label, classes: 'blank-button label' }
+        ]
+      }));
+
+    // Animations.
+    var that = this;
+    setTimeout(function () {
+      that.show('info');
+    }, 0);
+  },
+
+  /**
+   *
+   */
+  startEdit: function () {
+    this.$el
+      .addClass('edit-editing')
+      .find('.edit-toolbar')
+      // Append the "ops" toolgroup into the toolbar.
+      .append(Drupal.theme('editToolgroup', {
+        classes: 'ops',
+        buttons: [
+          { label: Drupal.t('Save'), type: 'submit', classes: 'field-save save gray-button' },
+          { label: '<span class="close">' + Drupal.t('Close') + '</span>', classes: 'field-close close gray-button' }
+        ]
+      }));
+    this.show('ops');
+  },
+
+  /**
+   * Retrieves a setting of the editor-specific Edit UI integration.
+   *
+   * @param String setting
+   *
+   * @see Drupal.edit.util.getEditUISetting().
+   */
+  getEditUISetting: function (setting) {
+    return Drupal.edit.util.getEditUISetting(this.editorView, setting);
+  },
+
+  /**
+   * Adjusts the toolbar to accomodate padding on the editor.
+   *
+   * @see EditorDecorationView._pad().
+   */
+  _pad: function () {
+    // The whole toolbar must move to the top when the property's DOM element
+    // is displayed inline.
+    if (this.$field.css('display') === 'inline') {
+      this.$el.css('top', parseInt(this.$el.css('top'), 10) - 5 + 'px');
+    }
+
+    // The toolbar must move to the top and the left.
+    var $hf = this.$el.find('.edit-toolbar-heightfaker');
+    $hf.css({ bottom: '6px', left: '-5px' });
+
+    if (this.getEditUISetting('fullWidthToolbar')) {
+      $hf.css({ width: this.$field.width() + 10 });
+    }
+  },
+
+  /**
+   * Undoes the changes made by _pad().
+   *
+   * @see EditorDecorationView._unpad().
+   */
+  _unpad: function () {
+    // Move the toolbar back to its original position.
+    var $hf = this.$el.find('.edit-toolbar-heightfaker');
+    $hf.css({ bottom: '1px', left: '' });
+
+    if (this.getEditUISetting('fullWidthToolbar')) {
+      $hf.css({ width: '' });
+    }
+  },
+
+  /**
+   *
+   */
+  insertWYSIWYGToolGroups: function () {
+    this.$el
+      .find('.edit-toolbar')
+      .append(Drupal.theme('editToolgroup', {
+        id: this.getFloatedWysiwygToolgroupId(),
+        classes: 'wysiwyg-floated',
+        buttons: []
+      }))
+      .append(Drupal.theme('editToolgroup', {
+        id: this.getMainWysiwygToolgroupId(),
+        classes: 'wysiwyg-main',
+        buttons: []
+      }));
+
+    // Animate the toolgroups into visibility.
+    var that = this;
+    setTimeout(function () {
+      that.show('wysiwyg-floated');
+      that.show('wysiwyg-main');
+    }, 0);
+  },
+
+  /**
+   * Retrieves the ID for this toolbar's container.
+   *
+   * Only used to make sane hovering behavior possible.
+   *
+   * @return String
+   *   A string that can be used as the ID for this toolbar's container.
+   */
+  getId: function () {
+    return 'edit-toolbar-for-' + this._id;
+  },
+
+  /**
+   * Retrieves the ID for this toolbar's floating WYSIWYG toolgroup.
+   *
+   * Used to provide an abstraction for any WYSIWYG editor to plug in.
+   *
+   * @return String
+   *   A string that can be used as the ID.
+   */
+  getFloatedWysiwygToolgroupId: function () {
+    return 'edit-wysiwyg-floated-toolgroup-for-' + this._id;
+  },
+
+  /**
+   * Retrieves the ID for this toolbar's main WYSIWYG toolgroup.
+   *
+   * Used to provide an abstraction for any WYSIWYG editor to plug in.
+   *
+   * @return String
+   *   A string that can be used as the ID.
+   */
+  getMainWysiwygToolgroupId: function () {
+    return 'edit-wysiwyg-main-toolgroup-for-' + this._id;
+  },
+
+  /**
+   * Shows a toolgroup.
+   *
+   * @param String toolgroup
+   *   A toolgroup name.
+   */
+  show: function (toolgroup) {
+    this._find(toolgroup).removeClass('edit-animate-invisible');
+  },
+
+  /**
+   * Adds classes to a toolgroup.
+   *
+   * @param String toolgroup
+   *   A toolgroup name.
+   */
+  addClass: function (toolgroup, classes) {
+    this._find(toolgroup).addClass(classes);
+  },
+
+  /**
+   * Removes classes from a toolgroup.
+   *
+   * @param String toolgroup
+   *   A toolgroup name.
+   */
+  removeClass: function (toolgroup, classes) {
+    this._find(toolgroup).removeClass(classes);
+  },
+
+  /**
+   * Finds a toolgroup.
+   *
+   * @param String toolgroup
+   *   A toolgroup name.
+   */
+  _find: function (toolgroup) {
+    return this.$el.find('.edit-toolbar .edit-toolgroup.' + toolgroup);
+  }
+});
+
+})(jQuery, _, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/ModalView.js b/core/modules/edit/js/views/ModalView.js
new file mode 100644
index 0000000..15497cc
--- /dev/null
+++ b/core/modules/edit/js/views/ModalView.js
@@ -0,0 +1,80 @@
+/**
+ * @file
+ * A Backbone View that provides an interactive modal.
+ */
+(function ($, Backbone, Drupal) {
+
+"use strict";
+
+Drupal.edit.ModalView = Backbone.View.extend({
+
+  message: null,
+  buttons: null,
+  callback: null,
+  $elementsToHide: null,
+
+  events: {
+    'click button': 'onButtonClick'
+  },
+
+  /**
+   * Implements Backbone.View.prototype.initialize().
+   *
+   * @param Object options
+   *   An object with the following keys:
+   *   - message: a message to show in the modal.
+   *   - buttons: a set of buttons with 'action's defined, ready to be passed to
+   *     Drupal.theme.editButtons().
+   *   - callback: a callback that will receive the 'action' of the clicked
+   *     button.
+   *
+   * @see Drupal.theme.editModal()
+   * @see Drupal.theme.editButtons()
+   */
+  initialize: function (options) {
+    this.message = options.message;
+    this.buttons = options.buttons;
+    this.callback = options.callback;
+  },
+
+  /**
+   * Implements Backbone.View.prototype.render().
+   */
+  render: function () {
+    this.setElement(Drupal.theme('editModal', {}));
+    this.$el.appendTo('body');
+    // Template.
+    this.$('.main p').text(this.message);
+    var $actions = $(Drupal.theme('editButtons', { 'buttons' : this.buttons}));
+    this.$('.actions').append($actions);
+
+    // Show the modal with an animation.
+    var that = this;
+    setTimeout(function() {
+      that.$el.removeClass('edit-animate-invisible');
+    }, 0);
+  },
+
+  /**
+   * Passes the clicked button action to the callback; closes the modal.
+   *
+   * @param jQuery event
+   */
+  onButtonClick: function (event) {
+    event.stopPropagation();
+    event.preventDefault();
+
+    // Remove after animation.
+    var that = this;
+    this.$el
+      .addClass('edit-animate-invisible')
+      .on(Drupal.edit.util.constants.transitionEnd, function(e) {
+        that.remove();
+      });
+
+    var action = $(event.target).attr('data-edit-modal-action');
+    return this.callback(action);
+  }
+});
+
+})(jQuery, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/contextuallink-view.js b/core/modules/edit/js/views/contextuallink-view.js
deleted file mode 100644
index efe8ddd..0000000
--- a/core/modules/edit/js/views/contextuallink-view.js
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * @file
- * A Backbone View that a dynamic contextual link.
- */
-(function ($, _, Backbone, Drupal) {
-
-"use strict";
-
-Drupal.edit = Drupal.edit || {};
-Drupal.edit.views = Drupal.edit.views || {};
-Drupal.edit.views.ContextualLinkView = Backbone.View.extend({
-
-  entity: null,
-
-  events: {
-    'click': 'onClick'
-  },
-
-  /**
-   * Implements Backbone Views' initialize() function.
-   *
-   * @param options
-   *   An object with the following keys:
-   *   - entity: the entity ID (e.g. node/1) of the entity
-   */
-  initialize: function (options) {
-    this.entity = options.entity;
-
-    // Initial render.
-    this.render();
-
-    // Re-render whenever the app state's active entity changes.
-    this.model.on('change:activeEntity', this.render, this);
-
-    // Hide the contextual links whenever an in-place editor is active.
-    this.model.on('change:activeEditor', this.toggleContextualLinksVisibility, this);
-  },
-
-  /**
-   * Equates clicks anywhere on the overlay to clicking the active editor's (if
-   * any) "close" button.
-   *
-   * @param {Object} event
-   */
-  onClick: function (event) {
-    event.preventDefault();
-
-    var that = this;
-    var updateActiveEntity = function() {
-      // The active entity is the current entity, i.e. stop editing the current
-      // entity.
-      if (that.model.get('activeEntity') === that.entity) {
-        that.model.set('activeEntity', null);
-      }
-      // The active entity is different from the current entity, i.e. start
-      // editing this entity instead of the previous one.
-      else {
-        that.model.set('activeEntity', that.entity);
-      }
-    };
-
-    // If there's an active editor, attempt to set its state to 'candidate', and
-    // only then do what the user asked.
-    // (Only when all PropertyEditor widgets of an entity are in the 'candidate'
-    // state, it is possible to stop editing it.)
-    var activeEditor = this.model.get('activeEditor');
-    if (activeEditor) {
-      var editableEntity = activeEditor.options.widget;
-      var predicate = activeEditor.options.property;
-      editableEntity.setState('candidate', predicate, { reason: 'stop or switch' }, function(accepted) {
-        if (accepted) {
-          updateActiveEntity();
-        }
-        else {
-          // No change.
-        }
-      });
-    }
-    // Otherwise, we can immediately do what the user asked.
-    else {
-      updateActiveEntity();
-    }
-  },
-
-  /**
-   * Render the "Quick edit" contextual link.
-   */
-  render: function () {
-    var activeEntity = this.model.get('activeEntity');
-    var string = (activeEntity !== this.entity) ? Drupal.t('Quick edit') : Drupal.t('Stop quick edit');
-    this.$el.html('<a href="">' + string + '</a>');
-    return this;
-  },
-
-  /**
-   * Model change handler; hides the contextual links if an editor is active.
-   *
-   * @param Drupal.edit.models.EditAppModel model
-   *   An EditAppModel model.
-   * @param jQuery|null activeEditor
-   *   The active in-place editor (jQuery object) or, if none, null.
-   */
-  toggleContextualLinksVisibility: function (model, activeEditor) {
-    this.$el.parents('.contextual').toggle(activeEditor === null);
-  }
-
-});
-
-})(jQuery, _, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/modal-view.js b/core/modules/edit/js/views/modal-view.js
deleted file mode 100644
index b98c876..0000000
--- a/core/modules/edit/js/views/modal-view.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * @file
- * A Backbone View that provides an interactive modal.
- */
-(function($, Backbone, Drupal) {
-
-"use strict";
-
-Drupal.edit = Drupal.edit || {};
-Drupal.edit.views = Drupal.edit.views || {};
-Drupal.edit.views.ModalView = Backbone.View.extend({
-
-  message: null,
-  buttons: null,
-  callback: null,
-  $elementsToHide: null,
-
-  events: {
-    'click button': 'onButtonClick'
-  },
-
-  /**
-   * Implements Backbone Views' initialize() function.
-   *
-   * @param options
-   *   An object with the following keys:
-   *   - message: a message to show in the modal.
-   *   - buttons: a set of buttons with 'action's defined, ready to be passed to
-   *     Drupal.theme.editButtons().
-   *   - callback: a callback that will receive the 'action' of the clicked
-   *     button.
-   *
-   * @see Drupal.theme.editModal()
-   * @see Drupal.theme.editButtons()
-   */
-  initialize: function(options) {
-    this.message = options.message;
-    this.buttons = options.buttons;
-    this.callback = options.callback;
-  },
-
-  /**
-   * Implements Backbone Views' render() function.
-   */
-  render: function() {
-    this.setElement(Drupal.theme('editModal', {}));
-    this.$el.appendTo('body');
-    // Template.
-    this.$('.main p').text(this.message);
-    var $actions = $(Drupal.theme('editButtons', { 'buttons' : this.buttons}));
-    this.$('.actions').append($actions);
-
-    // Show the modal with an animation.
-    var that = this;
-    setTimeout(function() {
-      that.$el.removeClass('edit-animate-invisible');
-    }, 0);
-  },
-
-  /**
-   * When the user clicks on any of the buttons, the modal should be removed
-   * and the result should be passed to the callback.
-   *
-   * @param event
-   */
-  onButtonClick: function(event) {
-    event.stopPropagation();
-    event.preventDefault();
-
-    // Remove after animation.
-    var that = this;
-    this.$el
-      .addClass('edit-animate-invisible')
-      .on(Drupal.edit.util.constants.transitionEnd, function(e) {
-        that.remove();
-      });
-
-    var action = $(event.target).attr('data-edit-modal-action');
-    return this.callback(action);
-  }
-});
-
-})(jQuery, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/propertyeditordecoration-view.js b/core/modules/edit/js/views/propertyeditordecoration-view.js
deleted file mode 100644
index bee33d1..0000000
--- a/core/modules/edit/js/views/propertyeditordecoration-view.js
+++ /dev/null
@@ -1,363 +0,0 @@
-/**
- * @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({
-
-  toolbarId: null,
-
-  _widthAttributeIsEmpty: null,
-
-  events: {
-    'mouseenter.edit' : 'onMouseEnter',
-    'mouseleave.edit' : 'onMouseLeave',
-    'click': 'onClick',
-    'tabIn.edit': 'onMouseEnter',
-    'tabOut.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.
-   *      * widget: the parent EditableEntity widget.
-   *      * editorName: the name of the PropertyEditor 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.predicate = this.editor.options.property;
-    this.editorName = this.editor.options.editorName;
-
-    // Only start listening to events as soon as we're no longer in the 'inactive' state.
-    this.undelegateEvents();
-  },
-
-  /**
-   * Listens to editor state changes.
-   */
-  stateChange: function(from, to) {
-    switch (to) {
-      case 'inactive':
-        if (from !== null) {
-          this.undecorate();
-          if (from === 'invalid') {
-            this._removeValidationErrors();
-          }
-        }
-        break;
-      case 'candidate':
-        this.decorate();
-        if (from !== 'inactive') {
-          this.stopHighlight();
-          if (from !== 'highlighted') {
-            this.stopEdit();
-            if (from === 'invalid') {
-              this._removeValidationErrors();
-            }
-          }
-        }
-        break;
-      case 'highlighted':
-        this.startHighlight();
-        break;
-      case 'activating':
-        // NOTE: this state is not used by every editor! It's only used by those
-        // that need to interact with the server.
-        this.prepareEdit();
-        break;
-      case 'active':
-        if (from !== 'activating') {
-          this.prepareEdit();
-        }
-        this.startEdit();
-        break;
-      case 'changed':
-        break;
-      case 'saving':
-        if (from === 'invalid') {
-          this._removeValidationErrors();
-        }
-        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();
-    });
-  },
-
-  /**
-   * Clicks: transition to 'activating' stage.
-   *
-   * @param event
-   */
-  onClick: function(event) {
-    var editableEntity = this.editor.options.widget;
-    editableEntity.setState('activating', this.predicate);
-    event.preventDefault();
-    event.stopPropagation();
-  },
-
-  decorate: function () {
-    this.$el.addClass('edit-animate-fast edit-candidate edit-editable');
-    this.delegateEvents();
-  },
-
-  undecorate: function () {
-    this.$el
-      .removeClass('edit-candidate edit-editable edit-highlighted edit-editing');
-    this.undelegateEvents();
-  },
-
-  startHighlight: function () {
-    // Animations.
-    var that = this;
-    setTimeout(function() {
-      that.$el.addClass('edit-highlighted');
-    }, 0);
-  },
-
-  stopHighlight: function() {
-    this.$el
-      .removeClass('edit-highlighted');
-  },
-
-  prepareEdit: function() {
-    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');
-  },
-
-  startEdit: function() {
-    if (this.getEditUISetting('padding')) {
-      this._pad();
-    }
-  },
-
-  stopEdit: function() {
-    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 (this.getEditUISetting('padding')) {
-      this._unpad();
-    }
-  },
-
-  /**
-   * Retrieves a setting of the editor-specific Edit UI integration.
-   *
-   * @see Drupal.edit.util.getEditUISetting().
-   */
-  getEditUISetting: function(setting) {
-    return Drupal.edit.util.getEditUISetting(this.editor, setting);
-  },
-
-  _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())
-        .css('background-color', this._getBgColor(this.$el));
-    }
-
-    // 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', '')
-        .css('background-color', '');
-    }
-
-    // 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: <value>" 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();
-    }
-  },
-
-  /**
-   * Removes validation errors' markup changes, if any.
-   *
-   * Note: this only needs to happen for type=direct, because for type=direct,
-   * the property DOM element itself is modified; this is not the case for
-   * type=form.
-   */
-  _removeValidationErrors: function() {
-    if (this.editorName !== 'form') {
-      this.$el
-        .removeClass('edit-validation-error')
-        .next('.edit-validation-errors')
-        .remove();
-    }
-  }
-
-});
-
-})(jQuery, Backbone, Drupal);
diff --git a/core/modules/edit/js/views/toolbar-view.js b/core/modules/edit/js/views/toolbar-view.js
deleted file mode 100644
index f4b2123..0000000
--- a/core/modules/edit/js/views/toolbar-view.js
+++ /dev/null
@@ -1,490 +0,0 @@
-/**
- * @file
- * A Backbone View that provides an interactive toolbar (1 per property editor).
- *
- * It listens to state changes of the property editor. It also triggers state
- * changes in response to user interactions with the toolbar, including saving.
- */
-(function ($, _, Backbone, Drupal) {
-
-"use strict";
-
-Drupal.edit = Drupal.edit || {};
-Drupal.edit.views = Drupal.edit.views || {};
-Drupal.edit.views.ToolbarView = Backbone.View.extend({
-
-  editor: null,
-  $storageWidgetEl: null,
-
-  entity: null,
-  predicate : null,
-  editorName: null,
-
-  _loader: null,
-  _loaderVisibleStart: 0,
-
-  _id: null,
-
-  events: {
-    'click.edit button.label': 'onClickInfoLabel',
-    'mouseleave.edit': 'onMouseLeave',
-    'click.edit button.field-save': 'onClickSave',
-    'click.edit button.field-close': 'onClickClose'
-  },
-
-  /**
-   * 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.
-   *      * element: the jQuery-wrapped editor DOM element
-   *   - $storageWidgetEl: the DOM element on which the Create Storage widget is
-   *     initialized.
-   */
-  initialize: function(options) {
-    this.editor = options.editor;
-    this.$storageWidgetEl = options.$storageWidgetEl;
-
-    this.entity = this.editor.options.entity;
-    this.predicate = this.editor.options.property;
-    this.editorName = this.editor.options.editorName;
-
-    this._loader = null;
-    this._loaderVisibleStart = 0;
-
-    // Generate a DOM-compatible ID for the toolbar DOM element.
-    this._id = Drupal.edit.util.calcPropertyID(this.entity, this.predicate).replace(/\//g, '_');
-  },
-
-  /**
-   * Listens to editor state changes.
-   */
-  stateChange: function(from, to) {
-    switch (to) {
-      case 'inactive':
-        if (from) {
-          this.remove();
-          if (this.editorName !== 'form') {
-            Backbone.syncDirectCleanUp();
-          }
-        }
-        break;
-      case 'candidate':
-        if (from === 'inactive') {
-          this.render();
-        }
-        else {
-          if (this.editorName !== 'form') {
-            Backbone.syncDirectCleanUp();
-          }
-          // Remove all toolgroups; they're no longer necessary.
-          this.$el
-            .removeClass('edit-highlighted edit-editing')
-            .find('.edit-toolbar .edit-toolgroup').remove();
-          if (from !== 'highlighted' && this.getEditUISetting('padding')) {
-            this._unpad();
-          }
-        }
-        break;
-      case 'highlighted':
-        // As soon as we highlight, make sure we have a toolbar in the DOM (with at least a title).
-        this.startHighlight();
-        break;
-      case 'activating':
-        this.setLoadingIndicator(true);
-        break;
-      case 'active':
-        this.startEdit();
-        this.setLoadingIndicator(false);
-        if (this.getEditUISetting('fullWidthToolbar')) {
-          this.$el.addClass('edit-toolbar-fullwidth');
-        }
-
-        if (this.getEditUISetting('padding')) {
-          this._pad();
-        }
-        if (this.getEditUISetting('unifiedToolbar')) {
-          this.insertWYSIWYGToolGroups();
-        }
-        break;
-      case 'changed':
-        this.$el
-          .find('button.save')
-          .addClass('blue-button')
-          .removeClass('gray-button');
-        break;
-      case 'saving':
-        this.setLoadingIndicator(true);
-        this.save();
-        break;
-      case 'saved':
-        this.setLoadingIndicator(false);
-        break;
-      case 'invalid':
-        this.setLoadingIndicator(false);
-        break;
-    }
-  },
-
-  /**
-   * Saves a property.
-   *
-   * This method deals with the complexity of the editor-dependent ways of
-   * inserting updated content and showing validation error messages.
-   *
-   * One might argue that this does not belong in a view. However, there is no
-   * actual "save" logic here, that lives in Backbone.sync. This is just some
-   * glue code, along with the logic for inserting updated content as well as
-   * showing validation error messages, the latter of which is certainly okay.
-   */
-  save: function() {
-    var that = this;
-    var editor = this.editor;
-    var editableEntity = editor.options.widget;
-    var entity = editor.options.entity;
-    var predicate = editor.options.property;
-
-    // Use Create.js' Storage widget to handle saving. (Uses Backbone.sync.)
-    this.$storageWidgetEl.createStorage('saveRemote', entity, {
-      editor: editor,
-
-      // Successfully saved without validation errors.
-      success: function (model) {
-        editableEntity.setState('saved', predicate);
-
-        // Now that the changes to this property have been saved, the saved
-        // attributes are now the "original" attributes.
-        entity._originalAttributes = entity._previousAttributes = _.clone(entity.attributes);
-
-        // Get data necessary to rerender property before it is unavailable.
-        var updatedProperty = entity.get(predicate + '/rendered');
-        var $propertyWrapper = editor.element.closest('.edit-field');
-        var $context = $propertyWrapper.parent();
-
-        editableEntity.setState('candidate', predicate);
-        // Unset the property, because it will be parsed again from the DOM, iff
-        // its new value causes it to still be rendered.
-        entity.unset(predicate, { silent: true });
-        entity.unset(predicate + '/rendered', { silent: true });
-        // Trigger event to allow for proper clean-up of editor-specific views.
-        editor.element.trigger('destroyedPropertyEditor.edit', editor);
-
-        // Replace the old content with the new content.
-        $propertyWrapper.replaceWith(updatedProperty);
-        Drupal.attachBehaviors($context);
-      },
-
-      // Save attempted but failed due to validation errors.
-      error: function (validationErrorMessages) {
-        editableEntity.setState('invalid', predicate);
-
-        if (that.editorName === 'form') {
-          editor.$formContainer
-            .find('.edit-form')
-            .addClass('edit-validation-error')
-            .find('form')
-            .prepend(validationErrorMessages);
-        }
-        else {
-          var $errors = $('<div class="edit-validation-errors"></div>')
-            .append(validationErrorMessages);
-          editor.element
-            .addClass('edit-validation-error')
-            .after($errors);
-        }
-      }
-    });
-  },
-
-  /**
-   * When the user clicks the info label, nothing should happen.
-   * @note currently redirects the click.edit-event to the editor DOM element.
-   *
-   * @param event
-   */
-  onClickInfoLabel: function(event) {
-    event.stopPropagation();
-    event.preventDefault();
-    // Redirects the event to the editor DOM element.
-    this.editor.element.trigger('click.edit');
-  },
-
-  /**
-   * A mouseleave to the editor doesn't matter; a mouseleave to something else
-   * counts as a mouseleave on the editor itself.
-   *
-   * @param event
-   */
-  onMouseLeave: function(event) {
-    var el = this.editor.element[0];
-    if (event.relatedTarget != el && !$.contains(el, event.relatedTarget)) {
-      this.editor.element.trigger('mouseleave.edit');
-    }
-    event.stopPropagation();
-  },
-
-  /**
-   * Upon clicking "Save", trigger a custom event to save this property.
-   *
-   * @param event
-   */
-  onClickSave: function(event) {
-    event.stopPropagation();
-    event.preventDefault();
-    this.editor.options.widget.setState('saving', this.predicate);
-  },
-
-  /**
-   * Upon clicking "Close", trigger a custom event to stop editing.
-   *
-   * @param event
-   */
-  onClickClose: function(event) {
-    event.stopPropagation();
-    event.preventDefault();
-    this.editor.options.widget.setState('candidate', this.predicate, { reason: 'cancel' });
-  },
-
-  /**
-   * Indicates in the 'info' toolgroup that we're waiting for a server reponse.
-   *
-   * Prevents flickering loading indicator by only showing it after 0.6 seconds
-   * and if it is shown, only hiding it after another 0.6 seconds.
-   *
-   * @param bool enabled
-   *   Whether the loading indicator should be displayed or not.
-   */
-  setLoadingIndicator: function(enabled) {
-    var that = this;
-    if (enabled) {
-      this._loader = setTimeout(function() {
-        that.addClass('info', 'loading');
-        that._loaderVisibleStart = new Date().getTime();
-      }, 600);
-    }
-    else {
-      var currentTime = new Date().getTime();
-      clearTimeout(this._loader);
-      if (this._loaderVisibleStart) {
-        setTimeout(function() {
-          that.removeClass('info', 'loading');
-        }, this._loaderVisibleStart + 600 - currentTime);
-      }
-      this._loader = null;
-      this._loaderVisibleStart = 0;
-    }
-  },
-
-  startHighlight: function() {
-    // We get the label to show for this property from VIE's type system.
-    var label = this.predicate;
-    var attributeDef = this.entity.get('@type').attributes.get(this.predicate);
-    if (attributeDef && attributeDef.metadata) {
-      label = attributeDef.metadata.label;
-    }
-
-    this.$el
-      .addClass('edit-highlighted')
-      .find('.edit-toolbar')
-      // Append the "info" toolgroup into the toolbar.
-      .append(Drupal.theme('editToolgroup', {
-        classes: 'info edit-animate-only-background-and-padding',
-        buttons: [
-          { label: label, classes: 'blank-button label' }
-        ]
-      }));
-
-    // Animations.
-    var that = this;
-    setTimeout(function () {
-      that.show('info');
-    }, 0);
-  },
-
-  startEdit: function() {
-    this.$el
-      .addClass('edit-editing')
-      .find('.edit-toolbar')
-      // Append the "ops" toolgroup into the toolbar.
-      .append(Drupal.theme('editToolgroup', {
-        classes: 'ops',
-        buttons: [
-          { label: Drupal.t('Save'), type: 'submit', classes: 'field-save save gray-button' },
-          { label: '<span class="close">' + Drupal.t('Close') + '</span>', classes: 'field-close close gray-button' }
-        ]
-      }));
-    this.show('ops');
-  },
-
-  /**
-   * Retrieves a setting of the editor-specific Edit UI integration.
-   *
-   * @see Drupal.edit.util.getEditUISetting().
-   */
-  getEditUISetting: function(setting) {
-    return Drupal.edit.util.getEditUISetting(this.editor, setting);
-  },
-
-  /**
-   * Adjusts the toolbar to accomodate padding on the PropertyEditor widget.
-   *
-   * @see PropertyEditorDecorationView._pad().
-   */
-  _pad: function() {
-    // The whole toolbar must move to the top when the property's DOM element
-    // is displayed inline.
-    if (this.editor.element.css('display') === 'inline') {
-      this.$el.css('top', parseInt(this.$el.css('top'), 10) - 5 + 'px');
-    }
-
-    // The toolbar must move to the top and the left.
-    var $hf = this.$el.find('.edit-toolbar-heightfaker');
-    $hf.css({ bottom: '6px', left: '-5px' });
-
-    if (this.getEditUISetting('fullWidthToolbar')) {
-      $hf.css({ width: this.editor.element.width() + 10 });
-    }
-  },
-
-  /**
-   * Undoes the changes made by _pad().
-   *
-   * @see PropertyEditorDecorationView._unpad().
-   */
-  _unpad: function() {
-    // Move the toolbar back to its original position.
-    var $hf = this.$el.find('.edit-toolbar-heightfaker');
-    $hf.css({ bottom: '1px', left: '' });
-
-    if (this.getEditUISetting('fullWidthToolbar')) {
-      $hf.css({ width: '' });
-    }
-  },
-
-  insertWYSIWYGToolGroups: function() {
-    this.$el
-      .find('.edit-toolbar')
-      .append(Drupal.theme('editToolgroup', {
-        id: this.getFloatedWysiwygToolgroupId(),
-        classes: 'wysiwyg-floated',
-        buttons: []
-      }))
-      .append(Drupal.theme('editToolgroup', {
-        id: this.getMainWysiwygToolgroupId(),
-        classes: 'wysiwyg-main',
-        buttons: []
-      }));
-
-    // Animate the toolgroups into visibility.
-    var that = this;
-    setTimeout(function () {
-      that.show('wysiwyg-floated');
-      that.show('wysiwyg-main');
-    }, 0);
-  },
-
-  /**
-   * Renders the Toolbar's markup into the DOM.
-   *
-   * Note: depending on whether the 'display' property of the $el for which a
-   * toolbar is being inserted into the DOM, it will be inserted differently.
-   */
-  render: function () {
-    // Render toolbar.
-    this.setElement($(Drupal.theme('editToolbarContainer', {
-      id: this.getId()
-    })));
-
-    // Insert in DOM.
-    if (this.editor.element.css('display') === 'inline') {
-      this.$el.prependTo(this.editor.element.offsetParent());
-      var pos = this.editor.element.position();
-      this.$el.css('left', pos.left).css('top', pos.top);
-    }
-    else {
-      this.$el.insertBefore(this.editor.element);
-    }
-  },
-
-  /**
-   * Retrieves the ID for this toolbar's container.
-   *
-   * Only used to make sane hovering behavior possible.
-   *
-   * @return string
-   *   A string that can be used as the ID for this toolbar's container.
-   */
-  getId: function () {
-    return 'edit-toolbar-for-' + this._id;
-  },
-
-  /**
-   * Retrieves the ID for this toolbar's floating WYSIWYG toolgroup.
-   *
-   * Used to provide an abstraction for any WYSIWYG editor to plug in.
-   *
-   * @return string
-   *   A string that can be used as the ID.
-   */
-  getFloatedWysiwygToolgroupId: function () {
-    return 'edit-wysiwyg-floated-toolgroup-for-' + this._id;
-  },
-
-  /**
-   * Retrieves the ID for this toolbar's main WYSIWYG toolgroup.
-   *
-   * Used to provide an abstraction for any WYSIWYG editor to plug in.
-   *
-   * @return string
-   *   A string that can be used as the ID.
-   */
-  getMainWysiwygToolgroupId: function () {
-    return 'edit-wysiwyg-main-toolgroup-for-' + this._id;
-  },
-
-  /**
-   * Shows a toolgroup.
-   *
-   * @param string toolgroup
-   *   A toolgroup name.
-   */
-  show: function (toolgroup) {
-    this._find(toolgroup).removeClass('edit-animate-invisible');
-  },
-
-  /**
-   * Adds classes to a toolgroup.
-   *
-   * @param string toolgroup
-   *   A toolgroup name.
-   */
-  addClass: function (toolgroup, classes) {
-    this._find(toolgroup).addClass(classes);
-  },
-
-  /**
-   * Removes classes from a toolgroup.
-   *
-   * @param string toolgroup
-   *   A toolgroup name.
-   */
-  removeClass: function (toolgroup, classes) {
-    this._find(toolgroup).removeClass(classes);
-  },
-
-  /**
-   * Finds a toolgroup.
-   *
-   * @param string toolgroup
-   *   A toolgroup name.
-   */
-  _find: function (toolgroup) {
-    return this.$el.find('.edit-toolbar .edit-toolgroup.' + toolgroup);
-  }
-});
-
-})(jQuery, _, Backbone, Drupal);
diff --git a/core/modules/edit/lib/Drupal/edit/EditorBase.php b/core/modules/edit/lib/Drupal/edit/EditorBase.php
index 2bef9cf..39abaee 100644
--- a/core/modules/edit/lib/Drupal/edit/EditorBase.php
+++ b/core/modules/edit/lib/Drupal/edit/EditorBase.php
@@ -12,7 +12,7 @@
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
 
 /**
- * Defines a base editor (Create.js PropertyEditor widget) implementation.
+ * Defines a base editor implementation.
  */
 abstract class EditorBase extends PluginBase implements EditPluginInterface {
 
diff --git a/core/modules/edit/lib/Drupal/edit/EditorSelector.php b/core/modules/edit/lib/Drupal/edit/EditorSelector.php
index ce80def..0d823cf 100644
--- a/core/modules/edit/lib/Drupal/edit/EditorSelector.php
+++ b/core/modules/edit/lib/Drupal/edit/EditorSelector.php
@@ -17,7 +17,7 @@
 class EditorSelector implements EditorSelectorInterface {
 
   /**
-   * The manager for editor (Create.js PropertyEditor widget) plugins.
+   * The manager for editor plugins.
    *
    * @var \Drupal\Component\Plugin\PluginManagerInterface
    */
@@ -34,7 +34,7 @@ class EditorSelector implements EditorSelectorInterface {
    * Constructs a new EditorSelector.
    *
    * @param \Drupal\Component\Plugin\PluginManagerInterface
-   *   The manager for Create.js PropertyEditor widget plugins.
+   *   The manager for editor plugins.
    */
   public function __construct(PluginManagerInterface $editor_manager) {
     $this->editorManager = $editor_manager;
@@ -106,7 +106,7 @@ public function getEditorAttachments(array $editor_ids) {
     $definitions = $this->editorManager->getDefinitions();
     foreach ($definitions as $definition) {
       $attachments[] = array(
-        // This will be used in Create.js' propertyEditorWidgetsConfiguration.
+        // This will be used in Drupal.edit.metadataCache.
         'js' => array(
           array(
             'type' => 'setting',
diff --git a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
index b613442..cecc676 100644
--- a/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
+++ b/core/modules/edit/lib/Drupal/edit/MetadataGenerator.php
@@ -33,7 +33,7 @@ class MetadataGenerator implements MetadataGeneratorInterface {
   protected $editorSelector;
 
   /**
-   * The manager for editor (Create.js PropertyEditor widget) plugins.
+   * The manager for editor plugins.
    *
    * @var \Drupal\Component\Plugin\PluginManagerInterface
    */
diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/EditorManager.php b/core/modules/edit/lib/Drupal/edit/Plugin/EditorManager.php
index 8d0032f..fbcbda7 100644
--- a/core/modules/edit/lib/Drupal/edit/Plugin/EditorManager.php
+++ b/core/modules/edit/lib/Drupal/edit/Plugin/EditorManager.php
@@ -17,7 +17,7 @@
 /**
  * Editor manager.
  *
- * The "Form" Create.js PropertyEditor widget must always be available.
+ * The form editor must always be available.
  */
 class EditorManager extends PluginManagerBase {
 
diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/DirectEditor.php b/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/DirectEditor.php
index c3b9b55..c598604 100644
--- a/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/DirectEditor.php
+++ b/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/DirectEditor.php
@@ -12,7 +12,7 @@
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
 
 /**
- * Defines the "direct" Create.js PropertyEditor widget.
+ * Defines the direct editor.
  *
  * @Plugin(
  *   id = "direct",
diff --git a/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/FormEditor.php b/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/FormEditor.php
index c8d8bc8..c5f5fe3 100644
--- a/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/FormEditor.php
+++ b/core/modules/edit/lib/Drupal/edit/Plugin/edit/editor/FormEditor.php
@@ -12,7 +12,7 @@
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
 
 /**
- * Defines the "form" Create.js PropertyEditor widget.
+ * Defines the form editor.
  *
  * @Plugin(
  *   id = "form",
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
index 26ec6c0..767c570 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditorSelectionTest.php
@@ -16,7 +16,7 @@
 class EditorSelectionTest extends EditTestBase {
 
   /**
-   * The manager for editor (Create.js PropertyEditor widget) plugins.
+   * The manager for editor plugins.
    *
    * @var \Drupal\Component\Plugin\PluginManagerInterface
    */
@@ -106,8 +106,7 @@ function testText() {
    * processing, but with varying text format compatibility.
    */
   function testTextWysiwyg() {
-    // Enable edit_test module so that the 'wysiwyg' Create.js PropertyEditor
-    // widget becomes available.
+    // Enable edit_test module so that the 'wysiwyg' editor becomes available.
     $this->enableModules(array('edit_test'));
 
     $field_name = 'field_textarea';
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php b/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
index 6c4569f..1394285 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/MetadataGeneratorTest.php
@@ -18,7 +18,7 @@
 class MetadataGeneratorTest extends EditTestBase {
 
   /**
-   * The manager for editor (Create.js PropertyEditor widget) plugins.
+   * The manager for editor plugins.
    *
    * @var \Drupal\Component\Plugin\PluginManagerInterface
    */
@@ -128,8 +128,7 @@ function testEditorWithCustomMetadata() {
     $this->installSchema('system', 'url_alias');
     $this->enableModules(array('user', 'filter'));
 
-    // Enable edit_test module so that the WYSIWYG Create.js PropertyEditor
-    // widget becomes available.
+    // Enable edit_test module so that the WYSIWYG editor becomes available.
     $this->enableModules(array('edit_test'));
 
     // Create a rich text field.
diff --git a/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/edit/editor/WysiwygEditor.php b/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/edit/editor/WysiwygEditor.php
index e40e8b4..81ff964 100644
--- a/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/edit/editor/WysiwygEditor.php
+++ b/core/modules/edit/tests/modules/lib/Drupal/edit_test/Plugin/edit/editor/WysiwygEditor.php
@@ -12,7 +12,7 @@
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
 
 /**
- * Defines the "wysiwyg" Create.js PropertyEditor widget.
+ * Defines the wysiwyg editor.
  *
  * @Plugin(
  *   id = "wysiwyg",
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index 10f938b..0f317b9 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -78,12 +78,12 @@ function editor_library_info() {
       array('system', 'jquery.once'),
     ),
   );
-  // Create.js PropertyEditor widget library names begin with "edit.editor".
-  $libraries['edit.editorWidget.editor'] = array(
-    'title' => '"Editor" Create.js PropertyEditor widget',
+
+  $libraries['edit.formattedTextEditor.editor'] = array(
+    'title' => 'Formatted text editor',
     'version' => VERSION,
     'js' => array(
-      $path . '/js/editor.createjs.js' => array(
+      $path . '/js/editor.formattedTextEditor.js' => array(
         'scope' => 'footer',
         'attributes' => array('defer' => TRUE),
       ),
diff --git a/core/modules/editor/js/editor.createjs.js b/core/modules/editor/js/editor.createjs.js
deleted file mode 100644
index 693d9d9..0000000
--- a/core/modules/editor/js/editor.createjs.js
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * @file
- * Text editor-based Create.js widget for processed text content in Drupal.
- *
- * Depends on editor.module. Works with any (WYSIWYG) editor that implements the
- * editor.js API, including the optional attachInlineEditor() and onChange()
- * methods.
- * For example, assuming that a hypothetical editor's name was "Magical Editor"
- * and its editor.js API implementation lived at Drupal.editors.magical, this
- * JavaScript would use:
- *  - Drupal.editors.magical.attachInlineEditor()
- *  - Drupal.editors.magical.onChange()
- *  - Drupal.editors.magical.detach()
- */
-(function (jQuery, Drupal, drupalSettings) {
-
-"use strict";
-
-// @todo D8: use jQuery UI Widget bridging.
-// @see http://drupal.org/node/1874934#comment-7124904
-jQuery.widget('Midgard.editor', jQuery.Midgard.editWidget, {
-
-  textFormat: null,
-  textFormatHasTransformations: null,
-  textEditor: null,
-
-  /**
-   * Implements Create.editWidget.getEditUISettings.
-   */
-  getEditUISettings: function () {
-    return { padding: true, unifiedToolbar: true, fullWidthToolbar: true };
-  },
-
-  /**
-   * Implements jQuery.widget._init.
-   *
-   * @todo D8: Remove this.
-   * @see http://drupal.org/node/1874934
-   */
-  _init: function () {},
-
-  /**
-   * Implements Create.editWidget._initialize.
-   */
-  _initialize: function () {
-    var propertyID = Drupal.edit.util.calcPropertyID(this.options.entity, this.options.property);
-    var metadata = Drupal.edit.metadataCache[propertyID].custom;
-
-    this.textFormat = drupalSettings.editor.formats[metadata.format];
-    this.textFormatHasTransformations = metadata.formatHasTransformations;
-    this.textEditor = Drupal.editors[this.textFormat.editor];
-  },
-
-  /**
-   * Implements Create.editWidget.stateChange.
-   */
-  stateChange: function (from, to) {
-    var that = this;
-    switch (to) {
-      case 'inactive':
-        break;
-
-      case 'candidate':
-        // Detach the text editor when entering the 'candidate' state from one
-        // of the states where it could have been attached.
-        if (from !== 'inactive' && from !== 'highlighted') {
-            this.textEditor.detach(this.element.get(0), this.textFormat);
-        }
-        break;
-
-      case 'highlighted':
-        break;
-
-      case 'activating':
-        // When transformation filters have been been applied to the processed
-        // text of this field, then we'll need to load a re-processed version of
-        // it without the transformation filters.
-        if (this.textFormatHasTransformations) {
-          var propertyID = Drupal.edit.util.calcPropertyID(this.options.entity, this.options.property);
-          this._getUntransformedText(propertyID, this.element, function (untransformedText) {
-            that.element.html(untransformedText);
-            that.options.activated();
-          });
-        }
-        // When no transformation filters have been applied: start WYSIWYG
-        // editing immediately!
-        else {
-          this.options.activated();
-        }
-        break;
-
-      case 'active':
-        this.textEditor.attachInlineEditor(
-          this.element.get(0),
-          this.textFormat,
-          this.toolbarView.getMainWysiwygToolgroupId(),
-          this.toolbarView.getFloatedWysiwygToolgroupId()
-        );
-        // Set the state to 'changed' whenever the content has changed.
-        this.textEditor.onChange(this.element.get(0), function (html) {
-          that.options.changed(html);
-        });
-        break;
-
-      case 'changed':
-        break;
-
-      case 'saving':
-        break;
-
-      case 'saved':
-        break;
-
-      case 'invalid':
-        break;
-    }
-  },
-
-  /**
-   * Loads untransformed text for a given property.
-   *
-   * More accurately: it re-processes processed text to exclude transformation
-   * filters used by the text format.
-   *
-   * @param String propertyID
-   *   A property ID that uniquely identifies the given property.
-   * @param jQuery $editorElement
-   *   The property's PropertyEditor DOM element.
-   * @param Function callback
-   *   A callback function that will receive the untransformed text.
-   *
-   * @see \Drupal\editor\Ajax\GetUntransformedTextCommand
-   */
-  _getUntransformedText: function (propertyID, $editorElement, callback) {
-    // Create a Drupal.ajax instance to load the form.
-    Drupal.ajax[propertyID] = new Drupal.ajax(propertyID, $editorElement, {
-      url: Drupal.edit.util.buildUrl(propertyID, drupalSettings.editor.getUntransformedTextURL),
-      event: 'editor-internal.editor',
-      submit: { nocssjs : true },
-      progress: { type : null } // No progress indicator.
-    });
-    // Implement a scoped editorGetUntransformedText AJAX command: calls the
-    // callback.
-    Drupal.ajax[propertyID].commands.editorGetUntransformedText = function(ajax, response, status) {
-      callback(response.data);
-      // Delete the Drupal.ajax instance that called this very function.
-      delete Drupal.ajax[propertyID];
-      $editorElement.off('editor-internal.editor');
-    };
-    // This will ensure our scoped editorGetUntransformedText AJAX command
-    // gets called.
-    $editorElement.trigger('editor-internal.editor');
-  }
-
-});
-
-})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/editor/js/editor.formattedTextEditor.js b/core/modules/editor/js/editor.formattedTextEditor.js
new file mode 100644
index 0000000..2dcdf92
--- /dev/null
+++ b/core/modules/editor/js/editor.formattedTextEditor.js
@@ -0,0 +1,179 @@
+/**
+ * @file
+ * Text editor-based in-place editor for processed text content in Drupal.
+ *
+ * Depends on editor.module. Works with any (WYSIWYG) editor that implements the
+ * editor.js API, including the optional attachInlineEditor() and onChange()
+ * methods.
+ * For example, assuming that a hypothetical editor's name was "Magical Editor"
+ * and its editor.js API implementation lived at Drupal.editors.magical, this
+ * JavaScript would use:
+ *  - Drupal.editors.magical.attachInlineEditor()
+ */
+(function ($, Drupal, drupalSettings) {
+
+"use strict";
+
+Drupal.edit.editors = Drupal.edit.editors || {};
+
+Drupal.edit.editors.editor = Drupal.edit.EditorView.extend({
+
+  textFormat: null,
+  textFormatHasTransformations: null,
+  textEditor: null,
+  $textElement: null,
+
+  /**
+   * {@inheritdoc}
+   */
+  initialize: function (options) {
+    Drupal.edit.EditorView.prototype.initialize.call(this, options);
+
+    var editID = this.model.get('editID');
+    var metadata = Drupal.edit.metadataCache[editID].custom;
+    this.textFormat = drupalSettings.editor.formats[metadata.format];
+    this.textFormatHasTransformations = metadata.formatHasTransformations;
+    this.textEditor = Drupal.editors[this.textFormat.editor];
+
+    // Store the actual value of this field. We'll need this to restore the
+    // original value when the user discards his modifications.
+    // @todo: figure out a more nicely abstracted way to handle this.
+    this.$textElement = this.$el.find('.field-item:first');
+    this.model.set('originalValue', this.$textElement.html());
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  stateChange: function (model, state) {
+    var that = this;
+    var from = model.previous('state');
+    var to = state;
+    switch (to) {
+      case 'inactive':
+        break;
+
+      case 'candidate':
+        // Detach the text editor when entering the 'candidate' state from one
+        // of the states where it could have been attached.
+        if (from !== 'inactive' && from !== 'highlighted') {
+          this.textEditor.detach(this.$textElement.get(0), this.textFormat);
+        }
+        if (from === 'invalid') {
+            this.removeValidationErrors();
+        }
+        break;
+
+      case 'highlighted':
+        break;
+
+      case 'activating':
+        // When transformation filters have been been applied to the processed
+        // text of this field, then we'll need to load a re-processed version of
+        // it without the transformation filters.
+        if (this.textFormatHasTransformations) {
+          var editID = this.model.get('editID');
+          this._getUntransformedText(editID, this.$el, function (untransformedText) {
+            // @todo update this
+            debugger;
+            that.$textElement.set(untransformedText);
+            that.model.set('state', 'active');
+          });
+        }
+        // When no transformation filters have been applied: start WYSIWYG
+        // editing immediately!
+        else {
+          // As soon as the current state change has propagated, apply this one.
+          // @see http://jsfiddle.net/5MVzp/2/ vs. http://jsfiddle.net/5MVzp/3/
+          _.defer(function() {
+            that.model.set('state', 'active');
+          });
+        }
+        break;
+
+      case 'active':
+        this.textEditor.attachInlineEditor(
+          this.$textElement.get(0),
+          this.textFormat,
+          this.model.get('toolbarView').getMainWysiwygToolgroupId(),
+          this.model.get('toolbarView').getFloatedWysiwygToolgroupId()
+        );
+        // Set the state to 'changed' whenever the content has changed.
+        this.textEditor.onChange(this.$textElement.get(0), function (htmlText) {
+          that.model.set('currentValue', htmlText);
+          that.model.set('state', 'changed');
+        });
+        break;
+
+      case 'changed':
+        break;
+
+      case 'saving':
+        if (from === 'invalid') {
+          this.removeValidationErrors();
+        }
+        this.save();
+        break;
+
+      case 'saved':
+        break;
+
+      case 'invalid':
+        this.showValidationErrors();
+        break;
+    }
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  getEditUISettings: function () {
+    return { padding: true, unifiedToolbar: true, fullWidthToolbar: true };
+  },
+
+  /**
+   * {@inheritdoc}
+   */
+  revert: function () {
+    this.$textElement.html(this.model.get('originalValue'));
+  },
+
+  /**
+   * Loads untransformed text for a given field.
+   *
+   * More accurately: it re-processes processed text to exclude transformation
+   * filters used by the text format.
+   *
+   * @param String editID
+   *   A edit ID that uniquely identifies the given field.
+   * @param jQuery $editorElement
+   *   The property's PropertyEditor DOM element.
+   * @param Function callback
+   *   A callback function that will receive the untransformed text.
+   *
+   * @see \Drupal\editor\Ajax\GetUntransformedTextCommand
+   */
+  _getUntransformedText: function (editID, $editorElement, callback) {
+    // Create a Drupal.ajax instance to load the form.
+    Drupal.ajax[editID] = new Drupal.ajax(editID, $editorElement, {
+      url: Drupal.edit.util.buildUrl(editID, drupalSettings.editor.getUntransformedTextURL),
+      event: 'editor-internal.editor',
+      submit: { nocssjs : true },
+      progress: { type : null } // No progress indicator.
+    });
+    // Implement a scoped editorGetUntransformedText AJAX command: calls the
+    // callback.
+    Drupal.ajax[editID].commands.editorGetUntransformedText = function(ajax, response, status) {
+      callback(response.data);
+      // Delete the Drupal.ajax instance that called this very function.
+      delete Drupal.ajax[editID];
+      $editorElement.off('editor-internal.editor');
+    };
+    // This will ensure our scoped editorGetUntransformedText AJAX command
+    // gets called.
+    $editorElement.trigger('editor-internal.editor');
+  }
+
+});
+
+})(jQuery, Drupal, drupalSettings);
diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js
index 6483170..f07aa73 100644
--- a/core/modules/editor/js/editor.js
+++ b/core/modules/editor/js/editor.js
@@ -83,8 +83,12 @@ Drupal.behaviors.editor = {
       var $this = $(this);
       var activeFormatID = $this.val();
       var field = behavior.findFieldForFormatSelector($this);
-
-      Drupal.editorDetach(field, settings.editor.formats[activeFormatID], trigger);
+      if ('activeFormatID' in settings.editor.formats) {
+        Drupal.editorDetach(field, settings.editor.formats[activeFormatID], trigger);
+      }
+      else {
+        console.log('%c editor.js: The format ' + activeFormatID + ' does not have an editor.', 'background-color: red; color: white;');
+      }
     });
   },
 
diff --git a/core/modules/editor/lib/Drupal/editor/Plugin/edit/editor/Editor.php b/core/modules/editor/lib/Drupal/editor/Plugin/edit/editor/Editor.php
index 81c23d7..08cd210 100644
--- a/core/modules/editor/lib/Drupal/editor/Plugin/edit/editor/Editor.php
+++ b/core/modules/editor/lib/Drupal/editor/Plugin/edit/editor/Editor.php
@@ -14,7 +14,7 @@
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
 
 /**
- * Defines the "editor" Create.js PropertyEditor widget.
+ * Defines the formatted text editor.
  *
  * @Plugin(
  *   id = "editor",
@@ -90,8 +90,8 @@ public function getAttachments() {
     // Get the attachments for all text editors that the user might use.
     $attachments = $manager->getAttachments($formats);
 
-    // Also include editor.module's Create.js PropertyEditor widget.
-    $attachments['library'][] = array('editor', 'edit.editorWidget.editor');
+    // Also include editor.module's formatted text editor.
+    $attachments['library'][] = array('editor', 'edit.formattedTextEditor.editor');
 
     return $attachments;
   }
diff --git a/core/modules/editor/lib/Drupal/editor/Tests/EditIntegrationTest.php b/core/modules/editor/lib/Drupal/editor/Tests/EditIntegrationTest.php
index 1dcadc8..6e8e36f 100644
--- a/core/modules/editor/lib/Drupal/editor/Tests/EditIntegrationTest.php
+++ b/core/modules/editor/lib/Drupal/editor/Tests/EditIntegrationTest.php
@@ -21,7 +21,7 @@
 class EditIntegrationTest extends EditTestBase {
 
   /**
-   * The manager for editor (Create.js PropertyEditor widget) plug-ins.
+   * The manager for editor plug-ins.
    *
    * @var \Drupal\Component\Plugin\PluginManagerInterface
    */
@@ -143,7 +143,7 @@ function testEditorSelection() {
   }
 
   /**
-   * Tests (custom) metadata when the "Editor" Create.js editor is used.
+   * Tests (custom) metadata when the formatted text editor is used.
    */
   function testMetadata() {
     $this->editorManager = new EditorManager($this->container->get('container.namespaces'));
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 925709c..ad75b2f 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2109,20 +2109,6 @@ function system_library_info() {
     ),
   );
 
-  // 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',
-- 
1.7.10.4

