Use requirejs for clientside scripting
diff --git a/dev/js/src/vc.js b/dev/js/src/vc.js
index 2c8ad01..48c5694 100644
--- a/dev/js/src/vc.js
+++ b/dev/js/src/vc.js
@@ -6,9 +6,6 @@
 /*
  * Replaces a previous version written by Mengfei Zhou
  */
-var KorAP = KorAP || {};
-
-// Requires menu.js
 
 /*
   TODO: Implement a working localization solution!
@@ -33,131 +30,60 @@
   815: "Rewrite expects source"
 */
 
-(function (KorAP) {
+define([
+  'vc/unspecified',
+  'vc/doc',
+  'vc/docgroup',
+  'util'
+], function (unspecDocClass, docClass, docGroupClass) {
   "use strict";
 
-  // Default log message
-  KorAP.log = KorAP.log || function (type, msg) {
-    console.log(type + ": " + msg);
-  };
-
   KorAP._validStringMatchRE = new RegExp("^(?:eq|ne|contains|excludes)$");
-  KorAP._validRegexMatchRE  = new RegExp("^(?:eq|ne)$");
+  // KorAP._validRegexMatchRE  = new RegExp("^(?:eq|ne)$");
   KorAP._validDateMatchRE   = new RegExp("^[lg]?eq$");
   KorAP._validDateRE        = new RegExp("^(?:\\d{4})(?:-\\d\\d(?:-\\d\\d)?)?$");
-  KorAP._validGroupOpRE     = new RegExp("^(?:and|or)$");
-  KorAP._validRewriteOpRE   = new RegExp("^(?:injec|modifica)tion$");
-  KorAP._quote              = new RegExp("([\"\\\\])", 'g');
+  // KorAP._validGroupOpRE     = new RegExp("^(?:and|or)$");
+  // KorAP._quote              = new RegExp("([\"\\\\])", 'g');
 
   // Localization values
   var loc   = (KorAP.Locale = KorAP.Locale || {} );
-  loc.AND   = loc.AND   || 'and';
-  loc.OR    = loc.OR    || 'or';
-  loc.DEL   = loc.DEL   || '×';
-  loc.EMPTY = loc.EMPTY || '⋯'
-
-  // Utility for analysing boolean values
-  function _bool (bool) {
-    return (bool === undefined || bool === null || bool === false) ? false : true;
-  };
-
-
-  // Utility for removing all children of a node
-  function _removeChildren (node) {
-    // Remove everything underneath
-    while (node.firstChild)
-      node.removeChild(node.firstChild);
-  };
-
-
-  // Add new unspecified document
-  KorAP._add = function (obj, type) {
-    var ref = obj.parentNode.refTo;
-    var parent = ref.parent();
-
-    if (ref.ldType() === 'docGroup') {
-
-      // Check that the action differs from the type
-      if (ref.operation() === type)
-	return;
-
-      if (parent.ldType() !== null) {
-	return parent.newAfter(ref);
-      }
-      else {
-	// The group is on root - wrap
-	return ref.wrapOnRoot();
-      };
-    }
-    else if (ref.ldType() === 'doc') {
-
-      if (parent.ldType() === null) {
-	return ref.wrapOnRoot(type);
-      }
-      else if (parent.operation() === type) {
-	return parent.newAfter(ref);
-      }
-      else {
-	return ref.wrap(type);
-      };
-    };
-  };
-
-
-  // Add doc with 'and' relation
-  KorAP._and = function () {
-    return KorAP._add(this, 'and');
-  };
-
-
-  // Add doc with 'or' relation
-  KorAP._or = function () {
-    return KorAP._add(this, 'or');
-  };
-
-
-  // Remove doc or docGroup
-  KorAP._delete = function () {
-    var ref = this.parentNode.refTo;
-    if (ref.parent().ldType() !== null) {
-      return ref.parent().delOperand(ref).update();
-    }
-    else {
-      ref.parent().clean();
-    };
-  };
-
+  /*
+    loc.AND   = loc.AND   || 'and';
+    loc.OR    = loc.OR    || 'or';
+    loc.DEL   = loc.DEL   || '×';
+    loc.EMPTY = loc.EMPTY || '⋯'
+  */
 
   /**
    * Virtual Collection
    */
-  KorAP.VirtualCollection = {
+  return {
     ldType : function () {
       return null;
     },
 
     create : function () {
-      return Object.create(KorAP.VirtualCollection);
+      return Object.create(this);
     },
 
     clean : function () {
       if (this._root.ldType() !== "non") {
 	this._root.destroy();
-	this.root(KorAP.UnspecifiedDoc.create(this));
+	this.root(unspecDocClass.create(this));
       };
       return this;
     },
 
     render : function (json) {
-      var obj = Object.create(KorAP.VirtualCollection);
+      var obj = Object.create(this);
 
       if (json !== undefined) {
 	// Root object
 	if (json['@type'] == 'koral:doc') {
-	  obj._root = KorAP.Doc.create(obj, json);
+	  obj._root = docClass.create(obj, json);
 	}
 	else if (json['@type'] == 'koral:docGroup') {
-	  obj._root = KorAP.DocGroup.create(obj, json);
+	  obj._root = docGroupClass.create(obj, json);
 	}
 	else {
 	  KorAP.log(813, "Collection type is not supported");
@@ -225,1174 +151,4 @@
       return this._root.toQuery();
     }
   };
-
-
-  /**
-   * Operators for criteria
-   */
-  KorAP.Operators = {
-    create : function (and, or, del) {
-      var op = Object.create(KorAP.Operators);
-      op.and(and);
-      op.or(or);
-      op.del(del);
-      return op;
-    },
-
-    update : function () {
-      // Init the element
-      if (this._element === undefined)
-	return this.element();
-
-      var op = this._element;
-
-      op.refTo = this.parent();
-
-      // Remove everything underneath
-      _removeChildren(op);
-
-      // Add and button
-      if (this._and === true) {
-	var andE = document.createElement('span');
-	andE.setAttribute('class', 'and');
-	andE.addEventListener('click', KorAP._and, false);
-	andE.appendChild(
-	  document.createTextNode(KorAP.Locale.AND)
-	);
-	op.appendChild(andE);
-      };
-
-      // Add or button
-      if (this._or === true) {
-	var orE = document.createElement('span');
-	orE.setAttribute('class', 'or');
-	orE.addEventListener('click', KorAP._or, false);
-	orE.appendChild(document.createTextNode(KorAP.Locale.OR));
-	op.appendChild(orE);
-      };
-
-      // Add delete button
-      if (this._del === true) {
-	var delE = document.createElement('span');
-	delE.setAttribute('class', 'delete');
-	delE.appendChild(document.createTextNode(KorAP.Locale.DEL));
-	delE.addEventListener('click', KorAP._delete, false);
-	op.appendChild(delE);
-      };
-
-      return op;
-    },
-
-    // Be aware! This may be cyclic
-    parent : function (obj) {
-      if (arguments.length === 1)
-	this._parent = obj;
-      return this._parent;
-    },
-
-    element : function () {
-
-      // Return existing element
-      if (this._element !== undefined)
-	return this._element;
-
-      this._element = document.createElement('div');
-      this._element.setAttribute('class', 'operators');
-
-      // Init elements
-      this.update();
-      return this._element;
-    },
-
-    and : function (bool) {
-      if (arguments.length === 1)
-	this._and = _bool(bool);
-      return this._and;
-    },
-
-    or : function (bool) {
-      if (arguments.length === 1)
-	this._or = _bool(bool);
-      return this._or;
-    },
-
-    del : function (bool) {
-      if (arguments.length === 1)
-	this._del = _bool(bool);
-      return this._del;
-    }
-  };
-
-
-  /**
-   * Unspecified criterion
-   */
-  KorAP.UnspecifiedDoc = {
-    _ldType : "non",
-    create : function (parent) {
-      var obj = Object.create(KorAP.JsonLD).
-	upgradeTo(KorAP.UnspecifiedDoc);
-
-      if (parent !== undefined)
-	obj._parent = parent;
-
-      return obj;
-    },
-
-    // Set key - replace
-    key : function (v) {
-
-      // Not replaceable
-      if (this._parent === undefined)
-	return null;
-
-      // Set JSON-LD type
-      var newDoc = KorAP.Doc.create(this._parent, {
-	"@type" : "koral:doc",
-	"value" : "",
-	"key"   : v
-      });
-
-      // Unspecified document on root
-      if (this._parent.ldType() === null) {
-	this._parent.root(newDoc);
-	this.destroy();
-      }
-
-      // Unspecified document in group
-      else {
-	this._parent.replaceOperand(this, newDoc);
-      };
-      this._parent.update();
-      return newDoc;
-    },
-
-    update : function () {
-
-      if (this._element === undefined)
-	return this.element();
-
-      // Remove element content
-      _removeChildren(this._element);
-
-      var ellipsis = document.createElement('span');
-      ellipsis.appendChild(document.createTextNode(loc.EMPTY));
-      this._element.appendChild(ellipsis);
-
-      // Set ref - TODO: Cleanup!
-      this._element.refTo = this;
-
-      // Set operators
-      if (this._parent !== undefined && this.parent().ldType() !== null) {
-	var op = this.operators(
-	  false,
-	  false,
-	  true
-	);
-
-	this._element.appendChild(
-	  op.element()
-	);
-      };
-
-      return this.element();
-    },
-
-    element : function () {
-      if (this._element !== undefined)
-	return this._element;
-      this._element = document.createElement('div');
-      this._element.setAttribute('class', 'doc unspecified');
-      this.update();
-      return this._element;
-    },
-
-    
-  };
-
-
-  /**
-   * Document criterion
-   */
-  KorAP.Doc = {
-    _ldType : "doc",
-    _obj : function () { return KorAP.Doc },
-
-    create : function (parent, json) {
-      var obj = Object(KorAP.JsonLD).
-	create().
-	upgradeTo(KorAP.Doc).
-	fromJson(json);
-
-      if (parent !== undefined)
-	obj._parent = parent;
-
-      obj.__changed = true;
-      return obj;
-    },
-
-    update : function () {
-      if (this._element === undefined)
-	return this.element();
-
-      // Get element
-      var e = this._element;
-
-      // Set ref - TODO: Cleanup!
-      e.refTo = this;
-
-      // Check if there is a change
-      if (this.__changed) {
-
-	// Was rewritten
-	if (this.rewrites() !== undefined) {
-	  e.classList.add("rewritten");
-	};
-
-	// Added key
-	var key = document.createElement('span');
-	key.setAttribute('class', 'key');
-
-	// Change key
-	key.addEventListener('click', KorAP._changeKey, false);
-
-	if (this.key())
-	  key.appendChild(document.createTextNode(this.key()));
-
-	// Added match operator
-	var matchop = document.createElement('span');
-	matchop.setAttribute('data-type', this.type());
-	matchop.setAttribute('class', 'match');
-	matchop.appendChild(
-	  document.createTextNode(this.matchop())
-	);
-
-	// Added match operator
-	var value = document.createElement('span');
-	value.setAttribute('data-type', this.type());
-	value.setAttribute('class', 'value');
-	if (this.value())
-	  value.appendChild(
-	    document.createTextNode(this.value())
-	  );
-
-	// Remove all element children
-	_removeChildren(e);
-
-	// Add spans
-	e.appendChild(key);
-	e.appendChild(matchop);
-	e.appendChild(value);
-
-	this.__changed = false;
-      };
-
-      if (this._rewrites !== undefined) {
-	e.appendChild(this._rewrites.element());
-      };
-
-      if (this._parent !== undefined) {
-	// Set operators
-	var op = this.operators(
-	  true,
-	  true,
-	  true
-	);
-
-	// Append new operators
-	e.appendChild(op.element());
-      };
-
-      return e;
-    },
-
-    element : function () {
-      if (this._element !== undefined)
-	return this._element;
-
-      this._element = document.createElement('div');
-      this._element.setAttribute('class', 'doc');
-
-      this.update();
-      return this._element;
-    },
-
-    // Wrap a new operation around the doc element
-    wrap : function (op) {
-      var parent = this.parent();
-      var group = KorAP.DocGroup.create(parent);
-      group.operation(op);
-      group.append(this);
-      group.append();
-      return parent.replaceOperand(this, group).update();
-    },
-
-    // Deserialize from json
-    fromJson : function (json) {
-      if (json === undefined)
-	return this;
-
-      if (json["@type"] === undefined) {
-	KorAP.log(701, "JSON-LD group has no @type attribute");
-	return;
-      };
-
-      if (json["value"] === undefined ||
-	  typeof json["value"] != 'string') {
-	KorAP.log(805, "Value is invalid");
-	return;
-      };
-
-      // There is a defined key
-      if (json["key"] !== undefined &&
-	  typeof json["key"] === 'string') {
-
-	// Set key
-	this.key(json["key"]);
-
-	// Set match operation
-	if (json["match"] !== undefined) {
-	  if (typeof json["match"] === 'string') {
-	    this.matchop(json["match"]);
-	  }
-	  else {
-	    KorAP.log(802, "Match type is not supported by value type");
-	    return;
-	  };
-	};
-
-	// Key is a string
-	if (json["type"] === undefined ||
-	    json["type"] == "type:string") {
-	  this.type("string");
-
-	  // Check match type
-	  if (!KorAP._validStringMatchRE.test(this.matchop())) {
-	    KorAP.log(802, "Match type is not supported by value type");
-	    return;
-	  };
-
-	  // Set string value
-	  this.value(json["value"]);
-	}
-
-	// Key is a date
-	else if (json["type"] === "type:date") {
-	  this.type("date");
-
-	  if (json["value"] !== undefined &&
-	      KorAP._validDateRE.test(json["value"])) {
-
-	    if (!KorAP._validDateMatchRE.test(this.matchop())) {
-	      KorAP.log(802, "Match type is not supported by value type");
-	      return;
-	    };
-
-	    // Set value
-	    this.value(json["value"]);
-	  }
-	  else {
-	    KorAP.log(806, "Value is not a valid date string");
-	    return;
-	  };
-	}
-
-	// Key is a regular expression
-	else if (json["type"] === "type:regex") {
-	  this.type("regex");
-
-	  try {
-
-	    // Try to create a regular expression
-	    var check = new RegExp(json["value"]);
-
-	    if (!KorAP._validRegexMatchRE.test(this.matchop())) {
-	      KorAP.log(802, "Match type is not supported by value type");
-	      return;
-	    };
-
-	    this.value(json["value"]);
-	  }
-
-	  catch (e) {
-	    KorAP.log(807, "Value is not a valid regular expression");
-	    return;
-	  };
-	  this.type("regex");
-	}
-
-	else {
-	  KorAP.log(804, "Unknown value type");
-	  return;
-	};
-
-      };
-
-      if (json["rewrites"] !== undefined) {
-	this._rewrites = KorAP.RewriteList.create(json["rewrites"]);
-      };
-	
-      return this;
-    },
-
-    key : function (value) {
-      if (arguments.length === 1) {
-	this._key = value;
-	this._changed();
-	return this;
-      };
-      return this._key;
-    },
-
-    matchop : function (match) {
-      if (arguments.length === 1) {
-	this._matchop = match.replace(/^match:/, '');
-	this._changed();
-	return this;
-      };
-      return this._matchop || "eq";
-    },
-
-    type : function (type) {
-      if (arguments.length === 1) {
-	this._type = type;
-	this._changed();
-	return this;
-      };
-      return this._type || "string";
-    },
-
-    value : function (value) {
-      if (arguments.length === 1) {
-	this._value = value;
-	this._changed();
-	return this;
-      };
-      return this._value;
-    },
-
-    rewrites : function () {
-      return this._rewrites;
-    },
-
-    _changed : function () {
-      this.__changed = true;
-
-      if (this._rewrites === undefined)
-	return;
-      delete this["_rewrites"];
-      if (this._element === undefined)
-	return;
-      this._element.classList.remove("rewritten");
-    },
-
-    toJson : function () {
-      if (!this.matchop() || !this.key())
-	return {};
-      
-      return {
-	"@type" : "koral:" + this.ldType(),
-	"key"   : this.key(),
-	"match" : "match:" + this.matchop(),
-	"value" : this.value() || '',
-	"type"  : "type:" + this.type()
-      };
-    },
-
-    toQuery : function () {
-      if (!this.matchop() || !this.key())
-	return "";
-
-      // Build doc string based on key
-      var string = this.key() + ' ';
-
-      // Add match operator
-      switch (this.matchop()) {
-      case "ne":
-	string += '!=';
-	break;
-      case "contains":
-	string += '~';
-	break;
-      case "excludes":
-	string += '!~';
-	break;
-      case "geq":
-	string += 'since';
-	break;
-      case "leq":
-	string += 'until';
-	break;
-      default:
-	string += (this.type() == 'date') ? 'in' : '=';
-	break;
-      };
-
-      string += ' ';
-
-      // Add value
-      switch (this.type()) {
-      case "date":
-	return string + this.value();
-	break;
-      case "regex":
-	return string + '/' + this.value() + '/';
-	break;
-      case "string":
-	return string + '"' + this.value().replace(KorAP._quote, '\\$1') + '"';
-	break;
-      };
-
-      return "";
-    }
-  };
-
-
-  /**
-   * Document group criterion
-   */
-  KorAP.DocGroup = {
-    _ldType : "docGroup",
-
-    create : function (parent, json) {
-      var obj = Object.create(KorAP.JsonLD).upgradeTo(KorAP.DocGroup);
-      obj._operands = [];
-      obj.fromJson(json);
-      if (parent !== undefined)
-	obj._parent = parent;
-      return obj;
-    },
-
-    newAfter : function (obj) {
-      for (var i = 0; i < this._operands.length; i++) {
-	if (this._operands[i] === obj) {
-	  var operand = KorAP.UnspecifiedDoc.create(this);
-	  this._operands.splice(i + 1, 0, operand);
-	  return this.update();
-	};
-      };
-    },
-
-    // The doc is already set in the group
-    _duplicate : function (operand) {
-      if (operand.ldType() !== 'doc')
-	return null;
-
-      for (var i = 0; i < this._operands.length; i++) {
-	var op = this.getOperand(i);
-	if (op.ldType() === 'doc'
-	    && operand.key() === op.key()
-	    && operand.matchop() === op.matchop()
-	    && operand.value() === op.value()) {
-	  return op;
-	};
-      };
-      return null;
-    },
-
-    append : function (operand) {
-
-      // Append unspecified object
-      if (operand === undefined) {
-
-	// Be aware of cyclic structures!
-	operand = KorAP.UnspecifiedDoc.create(this);
-	this._operands.push(operand);
-	return operand;
-      };
-
-      switch (operand["@type"]) {
-
-      case undefined:
-	// No @type defined
-	if (operand["ldType"] !== undefined) {
-	  if (operand.ldType() !== 'doc' &&
-	      operand.ldType() !== 'docGroup') {
-	    KorAP.log(812, "Operand not supported in document group");
-	    return;
-	  };
-	  // Be aware of cyclic structures!
-	  operand.parent(this);
-
-	  var dupl = this._duplicate(operand);
-	  if (dupl === null) {
-	    this._operands.push(operand);
-	    return operand;
-	  };
-	  return dupl;
-	};
-
-	KorAP.log(701, "JSON-LD group has no @type attribute");
-	return;
-
-      case "koral:doc":
-	// Be aware of cyclic structures!
-	var doc = KorAP.Doc.create(this, operand);
-	if (doc === undefined)
-	  return;
-	var dupl = this._duplicate(doc);
-	if (dupl === null) {
-	  this._operands.push(doc);
-	  return doc;
-	};
-	return dupl;
-
-      case "koral:docGroup":
-	// Be aware of cyclic structures!
-	var docGroup = KorAP.DocGroup.create(this, operand);
-	if (docGroup === undefined)
-	  return;
-
-	// Flatten group
-	if (docGroup.operation() === this.operation()) {
-	  for (var op in docGroup.operands()) {
-	    op = docGroup.getOperand(op);
-	    var dupl = this._duplicate(op);
-	    if (dupl === null) {
-	      this._operands.push(op);
-	      op.parent(this);
-	    };
-	  };
-	  docGroup._operands = [];
-	  docGroup.destroy();
-	  return this;
-	};
-	this._operands.push(docGroup);
-	return docGroup;
-
-      default:
-	KorAP.log(812, "Operand not supported in document group");
-	return;
-      };
-    },
-
-    update : function () {
-      // There is only one operand in group
-
-      if (this._operands.length === 1) {
-
-	var parent = this.parent();
-	var op = this.getOperand(0);
-
-	// This will prevent destruction of
-	// the operand
-	this._operands = [];
-
-	// Parent is a group
-	if (parent.ldType() !== null)
-	  return parent.replaceOperand(this, op).update();
-
-	// Parent is vc
-	else {
-	  this.destroy();
-	  // Cyclic madness
-	  parent.root(op);
-	  op.parent(parent);
-	  return parent.root();
-	};
-      };
-
-      if (this._element === undefined)
-	return this;
-
-      var group = this._element;
-      group.setAttribute('data-operation', this.operation());
-
-      _removeChildren(group);
-
-      // Append operands
-      for (var i = 0; i < this._operands.length; i++) {
-	group.appendChild(
-	  this.getOperand(i).element()
-	);
-      };
-
-      // Set operators
-      var op = this.operators(
-	this.operation() == 'and' ? false : true,
-	this.operation() == 'or'  ? false : true,
-	true
-      );
-
-      group.appendChild(
-	op.element()
-      );
-
-      return this;
-    },
-
-    element : function () {
-      if (this._element !== undefined)
-	return this._element;
-
-      this._element = document.createElement('div');
-      this._element.setAttribute('class', 'docGroup');
-
-      // Update the object - including optimization
-      this.update();
-
-      return this._element;
-    },
-
-    operation : function (op) {
-      if (arguments.length === 1) {
-	if (KorAP._validGroupOpRE.test(op)) {
-	  this._op = op;
-	}
-	else {
-	  KorAP.log(810, "Unknown operation type");
-	  return;
-	};
-      };
-      return this._op || 'and';
-    },
-
-    operands : function () {
-      return this._operands;
-    },
-
-    getOperand : function (index) {
-      return this._operands[index];
-    },
-
-    // Replace operand
-    replaceOperand : function (oldOp, newOp) {
-
-      for (var i = 0; i < this._operands.length; i++) {
-	if (this._operands[i] === oldOp) {
-
-	  // Just insert a doc or ...
-	  if (newOp.ldType() === "doc" ||
-	      newOp.ldType() === "non" ||
-	      // ... insert a group of a different operation
-	      // (i.e. "and" in "or"/"or" in "and")
-	      newOp.operation() != this.operation()) {
-	    this._operands[i] = newOp;
-	    newOp.parent(this);
-	  }
-
-	  // Flatten group
-	  else {
-	    // Remove old group
-	    this._operands.splice(i, 1);
-
-	    // Inject new operands
-	    for (var op in newOp.operands().reverse()) {
-	      op = newOp.getOperand(op);
-	      this._operands.splice(i, 0, op);
-	      op.parent(this);
-	    };
-	    // Prevent destruction of operands
-	    newOp._operands = [];
-	    newOp.destroy();
-	  };
-	  oldOp.destroy();
-	  return this;
-	}
-      };
-      return false;
-    },
-
-    // Delete operand from group
-    delOperand : function (obj) {
-      for (var i = 0; i < this._operands.length; i++) {
-	if (this._operands[i] === obj) {
-
-	  // Delete identified operand
-	  this._operands.splice(i,1);
-
-	  // Destroy object for cyclic references
-	  obj.destroy();
-
-	  return this;
-	};
-      };
-
-      // Operand not found
-      return undefined;
-    },
-
-    // Deserialize from json
-    fromJson : function (json) {
-      if (json === undefined)
-	return this;
-
-      if (json["@type"] === undefined) {
-	KorAP.log(701, "JSON-LD group has no @type attribute");
-	return;
-      };
-
-      if (json["operation"] === undefined ||
-	  typeof json["operation"] !== 'string') {
-	KorAP.log(811, "Document group expects operation");
-	return;
-      };
-
-      var operation = json["operation"];
-
-      this.operation(operation.replace(/^operation:/,''));
-
-      if (json["operands"] === undefined ||
-	  !(json["operands"] instanceof Array)) {
-	KorAP.log(704, "Operation needs operand list")
-	return;
-      };
-
-      // Add all documents
-      for (var i in json["operands"]) {
-	var operand = json["operands"][i];
-	this.append(operand);
-      };
-    
-      return this;
-    },
-
-    toJson : function () {
-      var opArray = new Array();
-      for (var i = 0; i < this._operands.length; i++) {
-	if (this._operands[i].ldType() !== 'non')
-	  opArray.push(this._operands[i].toJson());
-      };
-      return {
-	"@type"     : "koral:" + this.ldType(),
-	"operation" : "operation:" + this.operation(),
-	"operands"  : opArray
-      };
-    },
-
-    toQuery : function (brackets) {
-      var list = this._operands
-	.filter(function (op) {
-	  return op.ldType() !== 'non';
-	})
-	.map(function (op) {
-	  return (op.ldType() === 'docGroup') ?
-	    op.toQuery(true) :
-	    op.toQuery();
-	});
-
-      if (list.length === 1)
-	return list.join('');
-      else {
-	var str = list.join(this.operation() === 'or' ? ' | ' : ' & ');
-	return brackets ? '(' + str + ')' : str;
-      };
-    }
-  };
-
-
-  KorAP.RewriteList = {
-    // Construction method
-    create : function (json) {
-      var obj = Object(KorAP.JsonLD).
-	create().
-	upgradeTo(KorAP.RewriteList).
-	fromJson(json);
-      return obj;
-    },
-    fromJson : function (json) {
-      this._list = new Array();
-      for (var i = 0; i < json.length; i++) {
-	this._list.push(
-	  KorAP.Rewrite.create(json[i])
-	);
-      };
-      return this;
-    },
-    element : function () {
-      if (this._element !== undefined)
-	return this._element;
-
-      this._element = document.createElement('div');
-      this._element.setAttribute('class', 'rewrite');
-      for (var x in this._list) {
-	var rewrite = this._list[x];
-	var span = document.createElement('span');
-
-	// Set class attribute
-	span.setAttribute('class', rewrite.operation());
-
-	// Append source information
-	span.appendChild(document.createTextNode(rewrite.src()));
-
-	// Append scope information
-	if (rewrite.scope() !== undefined) {
-	  span.appendChild(
-	    document.createTextNode(
-	      ': ' + rewrite.scope()
-	    )
-	  );
-	};
-	this._element.appendChild(span);
-      };
-      return this._element;
-    }
-  };
-
-
-  /**
-   * Implementation of rewrite objects.
-   */
-  KorAP.Rewrite = {
-
-    // Construction method
-    create : function (json) {
-      var obj = Object(KorAP.JsonLD).
-	create().
-	upgradeTo(KorAP.Rewrite).
-	fromJson(json);
-      return obj;
-    },
-
-    // Get or set source
-    src : function (string) {
-      if (arguments.length === 1)
-	this._src = string;
-      return this._src;
-    },
-    
-    // Get or set operation
-    operation : function (op) {
-      if (arguments.length === 1) {
-	if (KorAP._validRewriteOpRE.test(op)) {
-	  this._op = op;
-	}
-	else {
-	  KorAP.log(814, "Unknown rewrite operation");
-	  return;
-	};
-      };
-      return this._op || 'injection';
-    },
-
-    // Get or set scope
-    scope : function (attr) {
-      if (arguments.length === 1)
-	this._scope = attr;
-      return this._scope;
-    },
-
-    // Serialize from Json
-    fromJson : function (json) {
-      if (json === undefined)
-	return this;
-
-      // Missing @type
-      if (json["@type"] === undefined) {
-	KorAP.log(701, "JSON-LD group has no @type attribute");
-	return;
-      };
-
-      // Missing source
-      if (json["src"] === undefined ||
-	 typeof json["src"] !== 'string') {
-	KorAP.log(815, "Rewrite expects source");
-	return;
-      };
-
-      // Set source
-      this.src(json["src"]);
-
-      // Set operation
-      if (json["operation"] !== undefined) {
-	var operation = json["operation"];
-	this.operation(operation.replace(/^operation:/,''));
-      };
-
-      // Set scope
-      if (json["scope"] !== undefined &&
-	  typeof json["scope"] === 'string')
-	this.scope(json["scope"]);
-
-      return this;
-    },
-
-    toString : function () {
-      var str = '';
-      var op = this.operation();
-      str += op.charAt(0).toUpperCase() + op.slice(1);
-      str += ' of ' + (
-	this._scope === null ?
-	  'object' :
-	  '"' +
-	  this.scope().replace(KorAP._quote, '\\$1') +
-	  '"'
-      );
-      str += ' by ' +
-	'"' +
-	this.src().replace(KorAP._quote, '\\$1') +
-	'"';
-      return str;
-    }
-  };
-
-
-  /**
-   * Abstract JsonLD criterion object
-   */
-  KorAP.JsonLD = {
-    __changed : false,
-
-    create : function () {
-      return Object.create(KorAP.JsonLD);
-    },
-
-    /**
-     * Upgrade this object to another object
-     * while private data stays intact
-     */
-    upgradeTo : function (props) {
-      for (var prop in props) {
-	this[prop] = props[prop];
-      };
-      return this;
-    },
-
-    ldType : function (type) {
-      if (arguments.length === 1)
-	this._ldType = type;
-      return this._ldType;
-    },
-
-    parent : function (obj) {
-      if (arguments.length === 1) {
-	this._parent = obj;
-	this.__changed = true;
-      };
-      return this._parent;
-    },
-
-    // Destroy object - especially for
-    // acyclic structures!
-    // I'm paranoid!
-    destroy : function () {
-      if (this._ops != undefined) {
-	this._ops._parent = undefined;
-	if (this._ops._element !== undefined)
-	  this._ops._element.refTo = undefined;
-	this._ops = undefined;
-      };
-      if (this._element !== undefined)
-	this._element = undefined;
-
-      // In case of a group, destroy all operands
-      if (this._operands !== undefined) {
-      for (var i = 0; i < this._operands.length; i++)
-	  this.getOperand(i).destroy();
-	this._operands = [];
-      };
-    },
-
-    // Wrap a new operation around the root group element 
-    wrapOnRoot : function (op) {
-      var parent = this.parent();
-
-      var group = KorAP.DocGroup.create(parent);
-      if (arguments.length === 1)
-	group.operation(op);
-      else
-	group.operation(
-	  this.operation() === 'and' ? 'or' : 'and'
-	);
-      group.append(this);
-      this.parent(group);
-      group.append();
-      group.element(); // Init (seems to be necessary)
-      parent.root(group);
-      return this.parent();
-    },
-
-    // Be aware! This may be cyclic
-    operators : function (and, or, del) {
-      if (arguments === 0)
-	return this._ops;
-      this._ops = KorAP.Operators.create(
-	and, or, del
-      );
-      this._ops.parent(this);
-      return this._ops;
-    },
-
-    toJson : function () {
-      return {
-	// Unspecified object
-	"@type" : "koral:" + this.ldType()
-      };
-    },
-
-    toQuery : function () {
-      return '';
-    }
-  };
-
-
-  /**
-   * Criterion in a KorAP.Doc
-   */
-  KorAP._changeKey = function () {
-    var doc = this.parentNode.refTo;
-    var key = doc.element().firstChild;
-    key.appendChild(KorAP.FieldChooser.element());
-    KorAP.FieldChooser.show();
-    KorAP.FieldChooser.focus();
-    // key, matchop, type, value
-  };
-  
-  // Field menu
-  KorAP.FieldMenu = {
-    create : function (params) {
-      return Object.create(KorAP.Menu)
-	.upgradeTo(KorAP.FieldMenu)
-	._init(KorAP.FieldMenuItem, undefined, params)
-    }
-  };
-
-
-  // Field menu item
-  KorAP.FieldMenuItem = {
-    create : function (params) {
-      return Object.create(KorAP.MenuItem)
-	.upgradeTo(KorAP.FieldMenuItem)
-	._init(params);
-    },
-    _init : function (params) {
-      if (params[0] === undefined)
-	throw new Error("Missing parameters");
-
-      this._name  = params[0];
-      this._value = params[1];
-      this._type  = params[2];
-
-      this._lcField = ' ' + this._name.toLowerCase();
-
-      return this;
-    },
-    name : function () {
-      return this._name;
-    },
-    type : function () {
-      return this._type;
-    },
-    element : function () {
-      // already defined
-      if (this._element !== undefined)
-	return this._element;
-
-      // Create list item
-      var li = document.createElement("li");
-      li.setAttribute("data-type", this._type);
-      li.setAttribute("data-value", this._value);
-      li.appendChild(document.createTextNode(this._name));
-      return this._element = li;
-    }
-  };
-
-  KorAP.FieldChooser = KorAP.FieldMenu.create([
-    ['Titel', 'title', 'string'],
-    ['Untertitel', 'subTitle', 'string'],
-    ['Veröffentlichungsdatum', 'pubDate', 'date'],
-    ['Autor', 'author', 'string']
-  ]);
-  KorAP.FieldChooser.limit(5);
- 
-}(this.KorAP));
+});