outsourced all types (except for object type)
This commit is contained in:
		
							parent
							
								
									c663230c1b
								
							
						
					
					
						commit
						96ed8b0f98
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -316,7 +316,7 @@ module.exports = function() {
 | 
			
		||||
        }
 | 
			
		||||
        this.prev_cl.next_cl = this.next_cl;
 | 
			
		||||
        this.next_cl.prev_cl = this.prev_cl;
 | 
			
		||||
        if (this.content instanceof ops.Operation && !deleted_earlyer) {
 | 
			
		||||
        if (this.content instanceof ops.Operation) {
 | 
			
		||||
          this.content.referenced_by--;
 | 
			
		||||
          if (this.content.referenced_by <= 0 && !this.content.is_deleted) {
 | 
			
		||||
            this.content.applyDelete();
 | 
			
		||||
 | 
			
		||||
@ -1,97 +0,0 @@
 | 
			
		||||
var json_types_uninitialized,
 | 
			
		||||
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
 | 
			
		||||
  __hasProp = {}.hasOwnProperty;
 | 
			
		||||
 | 
			
		||||
json_types_uninitialized = require("./JsonTypes");
 | 
			
		||||
 | 
			
		||||
module.exports = function(HB) {
 | 
			
		||||
  var XmlType, json_types, parser, types;
 | 
			
		||||
  json_types = json_types_uninitialized(HB);
 | 
			
		||||
  types = json_types.types;
 | 
			
		||||
  parser = json_types.parser;
 | 
			
		||||
  XmlType = (function(_super) {
 | 
			
		||||
    __extends(XmlType, _super);
 | 
			
		||||
 | 
			
		||||
    function XmlType(uid, _at_tagname, attributes, elements, _at_xml) {
 | 
			
		||||
      this.tagname = _at_tagname;
 | 
			
		||||
      this.xml = _at_xml;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    XmlType.prototype.setXmlProxy = function() {};
 | 
			
		||||
 | 
			
		||||
    XmlType.prototype.val = function(enforce) {
 | 
			
		||||
      var a, attr, attr_name, e, n, text_node, value;
 | 
			
		||||
      if (enforce == null) {
 | 
			
		||||
        enforce = false;
 | 
			
		||||
      }
 | 
			
		||||
      if (typeof document !== "undefined" && document !== null) {
 | 
			
		||||
        if ((this.xml == null) || enforce) {
 | 
			
		||||
          this.xml = document.createElement(this.tagname);
 | 
			
		||||
          attr = this.attributes.val();
 | 
			
		||||
          for (attr_name in attr) {
 | 
			
		||||
            value = attr[attr_name];
 | 
			
		||||
            if (value != null) {
 | 
			
		||||
              a = document.createAttribute(attr_name);
 | 
			
		||||
              a.value = value;
 | 
			
		||||
              this.xml.setAttributeNode(a);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          e = this.elements.beginning.next_cl;
 | 
			
		||||
          while (e.type !== "Delimiter") {
 | 
			
		||||
            n = e.content;
 | 
			
		||||
            if (!e.isDeleted() && (e.content != null)) {
 | 
			
		||||
              if (n.type === "XmlType") {
 | 
			
		||||
                this.xml.appendChild(n.val(enforce));
 | 
			
		||||
              } else if (n.type === "TextNodeType") {
 | 
			
		||||
                text_node = n.val();
 | 
			
		||||
                this.xml.appendChild(text_node);
 | 
			
		||||
              } else {
 | 
			
		||||
                throw new Error("Internal structure cannot be transformed to dom");
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            e = e.next_cl;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        this.setXmlProxy();
 | 
			
		||||
        return this.xml;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    XmlType.prototype.execute = function() {
 | 
			
		||||
      return XmlType.__super__.execute.call(this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
      if not @validateSavedOperations()
 | 
			
		||||
        return false
 | 
			
		||||
      else
 | 
			
		||||
    
 | 
			
		||||
        return true
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    XmlType.prototype.getParent = function() {
 | 
			
		||||
      return this.parent;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    XmlType.prototype._encode = function() {
 | 
			
		||||
      var json;
 | 
			
		||||
      json = {
 | 
			
		||||
        'type': this.type,
 | 
			
		||||
        'attributes': this.attributes.getUid(),
 | 
			
		||||
        'elements': this.elements.getUid(),
 | 
			
		||||
        'tagname': this.tagname,
 | 
			
		||||
        'uid': this.getUid()
 | 
			
		||||
      };
 | 
			
		||||
      return json;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return XmlType;
 | 
			
		||||
 | 
			
		||||
  })(types.Insert);
 | 
			
		||||
  return parser['XmlType'] = function(json) {
 | 
			
		||||
    var attributes, elements, tagname, uid;
 | 
			
		||||
    uid = json['uid'], attributes = json['attributes'], elements = json['elements'], tagname = json['tagname'];
 | 
			
		||||
    return new XmlType(uid, tagname, attributes, elements, void 0);
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
@ -1,84 +0,0 @@
 | 
			
		||||
var YList;
 | 
			
		||||
 | 
			
		||||
YList = (function() {
 | 
			
		||||
  function YList(list) {
 | 
			
		||||
    if (list == null) {
 | 
			
		||||
      this._list = [];
 | 
			
		||||
    } else if (list.constructor === Array) {
 | 
			
		||||
      this._list = list;
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("Y.List expects an Array as a parameter");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  YList.prototype._name = "List";
 | 
			
		||||
 | 
			
		||||
  YList.prototype._getModel = function(types, ops) {
 | 
			
		||||
    if (this._model == null) {
 | 
			
		||||
      this._model = new ops.ListManager(this).execute();
 | 
			
		||||
      this._model.insert(0, this._list);
 | 
			
		||||
    }
 | 
			
		||||
    delete this._list;
 | 
			
		||||
    return this._model;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype._setModel = function(_at__model) {
 | 
			
		||||
    this._model = _at__model;
 | 
			
		||||
    return delete this._list;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.val = function() {
 | 
			
		||||
    return this._model.val.apply(this._model, arguments);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.observe = function() {
 | 
			
		||||
    this._model.observe.apply(this._model, arguments);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.unobserve = function() {
 | 
			
		||||
    this._model.unobserve.apply(this._model, arguments);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.insert = function(position, content) {
 | 
			
		||||
    if (typeof position !== "number") {
 | 
			
		||||
      throw new Error("Y.List.insert expects a Number as the first parameter!");
 | 
			
		||||
    }
 | 
			
		||||
    this._model.insert(position, [content]);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.insertContents = function(position, contents) {
 | 
			
		||||
    if (typeof position !== "number") {
 | 
			
		||||
      throw new Error("Y.List.insert expects a Number as the first parameter!");
 | 
			
		||||
    }
 | 
			
		||||
    this._model.insert(position, contents);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype["delete"] = function(position, length) {
 | 
			
		||||
    this._model["delete"](position, length);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YList.prototype.push = function(content) {
 | 
			
		||||
    this._model.push(content);
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return YList;
 | 
			
		||||
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  if (window.Y != null) {
 | 
			
		||||
    window.Y.List = YList;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error("You must first import Y!");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (typeof module !== "undefined" && module !== null) {
 | 
			
		||||
  module.exports = YList;
 | 
			
		||||
}
 | 
			
		||||
@ -1,335 +0,0 @@
 | 
			
		||||
var YText;
 | 
			
		||||
 | 
			
		||||
YText = (function() {
 | 
			
		||||
  function YText(text) {
 | 
			
		||||
    this.textfields = [];
 | 
			
		||||
    if (text == null) {
 | 
			
		||||
      this._text = "";
 | 
			
		||||
    } else if (text.constructor === String) {
 | 
			
		||||
      this._text = text;
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("Y.Text expects a String as a constructor");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  YText.prototype._name = "Text";
 | 
			
		||||
 | 
			
		||||
  YText.prototype._getModel = function(types, ops) {
 | 
			
		||||
    if (this._model == null) {
 | 
			
		||||
      this._model = new ops.ListManager(this).execute();
 | 
			
		||||
      this.insert(0, this._text);
 | 
			
		||||
    }
 | 
			
		||||
    delete this._text;
 | 
			
		||||
    return this._model;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype._setModel = function(_at__model) {
 | 
			
		||||
    this._model = _at__model;
 | 
			
		||||
    return delete this._text;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.val = function() {
 | 
			
		||||
    return this._model.fold("", function(left, o) {
 | 
			
		||||
      return left + o.val();
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.observe = function() {
 | 
			
		||||
    return this._model.observe.apply(this._model, arguments);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.unobserve = function() {
 | 
			
		||||
    return this._model.unobserve.apply(this._model, arguments);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.toString = function() {
 | 
			
		||||
    return this.val();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.insert = function(position, content) {
 | 
			
		||||
    var ith;
 | 
			
		||||
    if (content.constructor !== String) {
 | 
			
		||||
      throw new Error("Y.String.insert expects a String as the second parameter!");
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof position !== "number") {
 | 
			
		||||
      throw new Error("Y.String.insert expects a Number as the first parameter!");
 | 
			
		||||
    }
 | 
			
		||||
    if (content.length > 0) {
 | 
			
		||||
      ith = this._model.getOperationByPosition(position);
 | 
			
		||||
      return this._model.insertAfter(ith, content);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype["delete"] = function(position, length) {
 | 
			
		||||
    return this._model["delete"](position, length);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YText.prototype.bind = function(textfield, dom_root) {
 | 
			
		||||
    var createRange, creator_token, t, word, writeContent, writeRange, _i, _len, _ref;
 | 
			
		||||
    if (dom_root == null) {
 | 
			
		||||
      dom_root = window;
 | 
			
		||||
    }
 | 
			
		||||
    if (dom_root.getSelection == null) {
 | 
			
		||||
      dom_root = window;
 | 
			
		||||
    }
 | 
			
		||||
    _ref = this.textfields;
 | 
			
		||||
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
 | 
			
		||||
      t = _ref[_i];
 | 
			
		||||
      if (t === textfield) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    creator_token = false;
 | 
			
		||||
    word = this;
 | 
			
		||||
    textfield.value = this.val();
 | 
			
		||||
    this.textfields.push(textfield);
 | 
			
		||||
    if ((textfield.selectionStart != null) && (textfield.setSelectionRange != null)) {
 | 
			
		||||
      createRange = function(fix) {
 | 
			
		||||
        var left, right;
 | 
			
		||||
        left = textfield.selectionStart;
 | 
			
		||||
        right = textfield.selectionEnd;
 | 
			
		||||
        if (fix != null) {
 | 
			
		||||
          left = fix(left);
 | 
			
		||||
          right = fix(right);
 | 
			
		||||
        }
 | 
			
		||||
        return {
 | 
			
		||||
          left: left,
 | 
			
		||||
          right: right
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
      writeRange = function(range) {
 | 
			
		||||
        writeContent(word.val());
 | 
			
		||||
        return textfield.setSelectionRange(range.left, range.right);
 | 
			
		||||
      };
 | 
			
		||||
      writeContent = function(content) {
 | 
			
		||||
        return textfield.value = content;
 | 
			
		||||
      };
 | 
			
		||||
    } else {
 | 
			
		||||
      createRange = function(fix) {
 | 
			
		||||
        var clength, edited_element, range, s;
 | 
			
		||||
        range = {};
 | 
			
		||||
        s = dom_root.getSelection();
 | 
			
		||||
        clength = textfield.textContent.length;
 | 
			
		||||
        range.left = Math.min(s.anchorOffset, clength);
 | 
			
		||||
        range.right = Math.min(s.focusOffset, clength);
 | 
			
		||||
        if (fix != null) {
 | 
			
		||||
          range.left = fix(range.left);
 | 
			
		||||
          range.right = fix(range.right);
 | 
			
		||||
        }
 | 
			
		||||
        edited_element = s.focusNode;
 | 
			
		||||
        if (edited_element === textfield || edited_element === textfield.childNodes[0]) {
 | 
			
		||||
          range.isReal = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          range.isReal = false;
 | 
			
		||||
        }
 | 
			
		||||
        return range;
 | 
			
		||||
      };
 | 
			
		||||
      writeRange = function(range) {
 | 
			
		||||
        var r, s, textnode;
 | 
			
		||||
        writeContent(word.val());
 | 
			
		||||
        textnode = textfield.childNodes[0];
 | 
			
		||||
        if (range.isReal && (textnode != null)) {
 | 
			
		||||
          if (range.left < 0) {
 | 
			
		||||
            range.left = 0;
 | 
			
		||||
          }
 | 
			
		||||
          range.right = Math.max(range.left, range.right);
 | 
			
		||||
          if (range.right > textnode.length) {
 | 
			
		||||
            range.right = textnode.length;
 | 
			
		||||
          }
 | 
			
		||||
          range.left = Math.min(range.left, range.right);
 | 
			
		||||
          r = document.createRange();
 | 
			
		||||
          r.setStart(textnode, range.left);
 | 
			
		||||
          r.setEnd(textnode, range.right);
 | 
			
		||||
          s = window.getSelection();
 | 
			
		||||
          s.removeAllRanges();
 | 
			
		||||
          return s.addRange(r);
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
      writeContent = function(content) {
 | 
			
		||||
        var c, content_array, i, _j, _len1, _results;
 | 
			
		||||
        content_array = content.replace(new RegExp("\n", 'g'), " ").split(" ");
 | 
			
		||||
        textfield.innerText = "";
 | 
			
		||||
        _results = [];
 | 
			
		||||
        for (i = _j = 0, _len1 = content_array.length; _j < _len1; i = ++_j) {
 | 
			
		||||
          c = content_array[i];
 | 
			
		||||
          textfield.innerText += c;
 | 
			
		||||
          if (i !== content_array.length - 1) {
 | 
			
		||||
            _results.push(textfield.innerHTML += ' ');
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return _results;
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    writeContent(this.val());
 | 
			
		||||
    this.observe(function(events) {
 | 
			
		||||
      var event, fix, o_pos, r, _j, _len1, _results;
 | 
			
		||||
      _results = [];
 | 
			
		||||
      for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
 | 
			
		||||
        event = events[_j];
 | 
			
		||||
        if (!creator_token) {
 | 
			
		||||
          if (event.type === "insert") {
 | 
			
		||||
            o_pos = event.position;
 | 
			
		||||
            fix = function(cursor) {
 | 
			
		||||
              if (cursor <= o_pos) {
 | 
			
		||||
                return cursor;
 | 
			
		||||
              } else {
 | 
			
		||||
                cursor += 1;
 | 
			
		||||
                return cursor;
 | 
			
		||||
              }
 | 
			
		||||
            };
 | 
			
		||||
            r = createRange(fix);
 | 
			
		||||
            _results.push(writeRange(r));
 | 
			
		||||
          } else if (event.type === "delete") {
 | 
			
		||||
            o_pos = event.position;
 | 
			
		||||
            fix = function(cursor) {
 | 
			
		||||
              if (cursor < o_pos) {
 | 
			
		||||
                return cursor;
 | 
			
		||||
              } else {
 | 
			
		||||
                cursor -= 1;
 | 
			
		||||
                return cursor;
 | 
			
		||||
              }
 | 
			
		||||
            };
 | 
			
		||||
            r = createRange(fix);
 | 
			
		||||
            _results.push(writeRange(r));
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          _results.push(void 0);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return _results;
 | 
			
		||||
    });
 | 
			
		||||
    textfield.onkeypress = function(event) {
 | 
			
		||||
      var char, diff, pos, r;
 | 
			
		||||
      if (word.is_deleted) {
 | 
			
		||||
        textfield.onkeypress = null;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      creator_token = true;
 | 
			
		||||
      char = null;
 | 
			
		||||
      if (event.keyCode === 13) {
 | 
			
		||||
        char = '\n';
 | 
			
		||||
      } else if (event.key != null) {
 | 
			
		||||
        if (event.charCode === 32) {
 | 
			
		||||
          char = " ";
 | 
			
		||||
        } else {
 | 
			
		||||
          char = event.key;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        char = window.String.fromCharCode(event.keyCode);
 | 
			
		||||
      }
 | 
			
		||||
      if (char.length > 1) {
 | 
			
		||||
        return true;
 | 
			
		||||
      } else if (char.length > 0) {
 | 
			
		||||
        r = createRange();
 | 
			
		||||
        pos = Math.min(r.left, r.right);
 | 
			
		||||
        diff = Math.abs(r.right - r.left);
 | 
			
		||||
        word["delete"](pos, diff);
 | 
			
		||||
        word.insert(pos, char);
 | 
			
		||||
        r.left = pos + char.length;
 | 
			
		||||
        r.right = r.left;
 | 
			
		||||
        writeRange(r);
 | 
			
		||||
      }
 | 
			
		||||
      event.preventDefault();
 | 
			
		||||
      creator_token = false;
 | 
			
		||||
      return false;
 | 
			
		||||
    };
 | 
			
		||||
    textfield.onpaste = function(event) {
 | 
			
		||||
      if (word.is_deleted) {
 | 
			
		||||
        textfield.onpaste = null;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      return event.preventDefault();
 | 
			
		||||
    };
 | 
			
		||||
    textfield.oncut = function(event) {
 | 
			
		||||
      if (word.is_deleted) {
 | 
			
		||||
        textfield.oncut = null;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      return event.preventDefault();
 | 
			
		||||
    };
 | 
			
		||||
    return textfield.onkeydown = function(event) {
 | 
			
		||||
      var del_length, diff, new_pos, pos, r, val;
 | 
			
		||||
      creator_token = true;
 | 
			
		||||
      if (word.is_deleted) {
 | 
			
		||||
        textfield.onkeydown = null;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
      r = createRange();
 | 
			
		||||
      pos = Math.min(r.left, r.right, word.val().length);
 | 
			
		||||
      diff = Math.abs(r.left - r.right);
 | 
			
		||||
      if ((event.keyCode != null) && event.keyCode === 8) {
 | 
			
		||||
        if (diff > 0) {
 | 
			
		||||
          word["delete"](pos, diff);
 | 
			
		||||
          r.left = pos;
 | 
			
		||||
          r.right = pos;
 | 
			
		||||
          writeRange(r);
 | 
			
		||||
        } else {
 | 
			
		||||
          if ((event.ctrlKey != null) && event.ctrlKey) {
 | 
			
		||||
            val = word.val();
 | 
			
		||||
            new_pos = pos;
 | 
			
		||||
            del_length = 0;
 | 
			
		||||
            if (pos > 0) {
 | 
			
		||||
              new_pos--;
 | 
			
		||||
              del_length++;
 | 
			
		||||
            }
 | 
			
		||||
            while (new_pos > 0 && val[new_pos] !== " " && val[new_pos] !== '\n') {
 | 
			
		||||
              new_pos--;
 | 
			
		||||
              del_length++;
 | 
			
		||||
            }
 | 
			
		||||
            word["delete"](new_pos, pos - new_pos);
 | 
			
		||||
            r.left = new_pos;
 | 
			
		||||
            r.right = new_pos;
 | 
			
		||||
            writeRange(r);
 | 
			
		||||
          } else {
 | 
			
		||||
            if (pos > 0) {
 | 
			
		||||
              word["delete"](pos - 1, 1);
 | 
			
		||||
              r.left = pos - 1;
 | 
			
		||||
              r.right = pos - 1;
 | 
			
		||||
              writeRange(r);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        creator_token = false;
 | 
			
		||||
        return false;
 | 
			
		||||
      } else if ((event.keyCode != null) && event.keyCode === 46) {
 | 
			
		||||
        if (diff > 0) {
 | 
			
		||||
          word["delete"](pos, diff);
 | 
			
		||||
          r.left = pos;
 | 
			
		||||
          r.right = pos;
 | 
			
		||||
          writeRange(r);
 | 
			
		||||
        } else {
 | 
			
		||||
          word["delete"](pos, 1);
 | 
			
		||||
          r.left = pos;
 | 
			
		||||
          r.right = pos;
 | 
			
		||||
          writeRange(r);
 | 
			
		||||
        }
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        creator_token = false;
 | 
			
		||||
        return false;
 | 
			
		||||
      } else {
 | 
			
		||||
        creator_token = false;
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return YText;
 | 
			
		||||
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  if (window.Y != null) {
 | 
			
		||||
    window.Y.Text = YText;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error("You must first import Y!");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (typeof module !== "undefined" && module !== null) {
 | 
			
		||||
  module.exports = YText;
 | 
			
		||||
}
 | 
			
		||||
@ -1,622 +0,0 @@
 | 
			
		||||
var YXml, dont_proxy, initialize_proxies, proxies_are_initialized, proxy_token;
 | 
			
		||||
 | 
			
		||||
YXml = (function() {
 | 
			
		||||
  function YXml(tag_or_dom, attributes) {
 | 
			
		||||
    var a, a_name, c, c_name, tagname, _classes, _i, _len, _ref;
 | 
			
		||||
    if (attributes == null) {
 | 
			
		||||
      attributes = {};
 | 
			
		||||
    }
 | 
			
		||||
    if (tag_or_dom == null) {
 | 
			
		||||
 | 
			
		||||
    } else if (tag_or_dom.constructor === String) {
 | 
			
		||||
      tagname = tag_or_dom;
 | 
			
		||||
      this._xml = {};
 | 
			
		||||
      this._xml.children = [];
 | 
			
		||||
      this._xml.tagname = tagname;
 | 
			
		||||
      if (attributes.constructor !== Object) {
 | 
			
		||||
        throw new Error("The attributes must be specified as a Object");
 | 
			
		||||
      }
 | 
			
		||||
      for (a_name in attributes) {
 | 
			
		||||
        a = attributes[a_name];
 | 
			
		||||
        if (a.constructor !== String) {
 | 
			
		||||
          throw new Error("The attributes must be of type String!");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this._xml.attributes = attributes;
 | 
			
		||||
      this._xml.classes = {};
 | 
			
		||||
      _classes = this._xml.attributes["class"];
 | 
			
		||||
      delete this._xml.attributes["class"];
 | 
			
		||||
      if (_classes != null) {
 | 
			
		||||
        _ref = _classes.split(" ");
 | 
			
		||||
        for (c = _i = 0, _len = _ref.length; _i < _len; c = ++_i) {
 | 
			
		||||
          c_name = _ref[c];
 | 
			
		||||
          if (c.length > 0) {
 | 
			
		||||
            this._xml.classes[c_name] = c;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      void 0;
 | 
			
		||||
    } else if (tag_or_dom instanceof Element) {
 | 
			
		||||
      this._dom = tag_or_dom;
 | 
			
		||||
      this._xml = {};
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  YXml.prototype._name = "Xml";
 | 
			
		||||
 | 
			
		||||
  YXml.prototype._getModel = function(Y, ops) {
 | 
			
		||||
    var attribute, c, child, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
 | 
			
		||||
    if (this._model == null) {
 | 
			
		||||
      if (this._dom != null) {
 | 
			
		||||
        this._xml.tagname = this._dom.tagName.toLowerCase();
 | 
			
		||||
        this._xml.attributes = {};
 | 
			
		||||
        this._xml.classes = {};
 | 
			
		||||
        _ref = this._dom.attributes;
 | 
			
		||||
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
 | 
			
		||||
          attribute = _ref[_i];
 | 
			
		||||
          if (attribute.name === "class") {
 | 
			
		||||
            _ref1 = attribute.value.split(" ");
 | 
			
		||||
            for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
 | 
			
		||||
              c = _ref1[_j];
 | 
			
		||||
              this._xml.classes[c] = true;
 | 
			
		||||
            }
 | 
			
		||||
          } else {
 | 
			
		||||
            this._xml.attributes[attribute.name] = attribute.value;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        this._xml.children = [];
 | 
			
		||||
        _ref2 = this._dom.childNodes;
 | 
			
		||||
        for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
 | 
			
		||||
          child = _ref2[_k];
 | 
			
		||||
          if (child.nodeType === child.TEXT_NODE) {
 | 
			
		||||
            this._xml.children.push(child.textContent);
 | 
			
		||||
          } else {
 | 
			
		||||
            this._xml.children.push(new YXml(child));
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      this._model = new ops.MapManager(this).execute();
 | 
			
		||||
      this._model.val("attributes", new Y.Object(this._xml.attributes));
 | 
			
		||||
      this._model.val("classes", new Y.Object(this._xml.classes));
 | 
			
		||||
      this._model.val("tagname", this._xml.tagname);
 | 
			
		||||
      this._model.val("children", new Y.List(this._xml.children));
 | 
			
		||||
      if (this._xml.parent != null) {
 | 
			
		||||
        this._model.val("parent", this._xml.parent);
 | 
			
		||||
      }
 | 
			
		||||
      if (this._dom != null) {
 | 
			
		||||
        this.getDom();
 | 
			
		||||
      }
 | 
			
		||||
      this._setModel(this._model);
 | 
			
		||||
    }
 | 
			
		||||
    return this._model;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype._setModel = function(_at__model) {
 | 
			
		||||
    this._model = _at__model;
 | 
			
		||||
    this._model.observe(function(events) {
 | 
			
		||||
      var c, children, event, i, parent, _i, _len, _ref, _results;
 | 
			
		||||
      _results = [];
 | 
			
		||||
      for (_i = 0, _len = events.length; _i < _len; _i++) {
 | 
			
		||||
        event = events[_i];
 | 
			
		||||
        if (event.name === "parent" && event.type !== "add") {
 | 
			
		||||
          parent = event.oldValue;
 | 
			
		||||
          children = (_ref = parent._model.val("children")) != null ? _ref.val() : void 0;
 | 
			
		||||
          if (children != null) {
 | 
			
		||||
            _results.push((function() {
 | 
			
		||||
              var _j, _len1, _results1;
 | 
			
		||||
              _results1 = [];
 | 
			
		||||
              for (i = _j = 0, _len1 = children.length; _j < _len1; i = ++_j) {
 | 
			
		||||
                c = children[i];
 | 
			
		||||
                if (c === this) {
 | 
			
		||||
                  parent._model.val("children")["delete"](i);
 | 
			
		||||
                  break;
 | 
			
		||||
                } else {
 | 
			
		||||
                  _results1.push(void 0);
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              return _results1;
 | 
			
		||||
            }).call(this));
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          _results.push(void 0);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return _results;
 | 
			
		||||
    });
 | 
			
		||||
    return delete this._xml;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype._setParent = function(parent) {
 | 
			
		||||
    if (parent instanceof YXml) {
 | 
			
		||||
      if (this._model != null) {
 | 
			
		||||
        this.remove();
 | 
			
		||||
        return this._model.val("parent", parent);
 | 
			
		||||
      } else {
 | 
			
		||||
        return this._xml.parent = parent;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("parent must be of type Y.Xml!");
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.toString = function() {
 | 
			
		||||
    var child, name, value, xml, _i, _len, _ref, _ref1;
 | 
			
		||||
    xml = "<" + this._model.val("tagname");
 | 
			
		||||
    _ref = this.attr();
 | 
			
		||||
    for (name in _ref) {
 | 
			
		||||
      value = _ref[name];
 | 
			
		||||
      xml += " " + name + '="' + value + '"';
 | 
			
		||||
    }
 | 
			
		||||
    xml += ">";
 | 
			
		||||
    _ref1 = this._model.val("children").val();
 | 
			
		||||
    for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
 | 
			
		||||
      child = _ref1[_i];
 | 
			
		||||
      xml += child.toString();
 | 
			
		||||
    }
 | 
			
		||||
    xml += '</' + this._model.val("tagname") + '>';
 | 
			
		||||
    return xml;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.attr = function(name, value) {
 | 
			
		||||
    var attrs, c, classes, cs, _i, _len;
 | 
			
		||||
    if (arguments.length > 1) {
 | 
			
		||||
      if (value.constructor !== String) {
 | 
			
		||||
        throw new Error("The attributes must be of type String!");
 | 
			
		||||
      }
 | 
			
		||||
      if (name === "class") {
 | 
			
		||||
        classes = value.split(" ");
 | 
			
		||||
        cs = {};
 | 
			
		||||
        for (_i = 0, _len = classes.length; _i < _len; _i++) {
 | 
			
		||||
          c = classes[_i];
 | 
			
		||||
          cs[c] = true;
 | 
			
		||||
        }
 | 
			
		||||
        this._model.val("classes", new this._model.custom_types.Object(cs));
 | 
			
		||||
      } else {
 | 
			
		||||
        this._model.val("attributes").val(name, value);
 | 
			
		||||
      }
 | 
			
		||||
      return this;
 | 
			
		||||
    } else if (arguments.length > 0) {
 | 
			
		||||
      if (name === "class") {
 | 
			
		||||
        return Object.keys(this._model.val("classes").val()).join(" ");
 | 
			
		||||
      } else {
 | 
			
		||||
        return this._model.val("attributes").val(name);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      attrs = this._model.val("attributes").val();
 | 
			
		||||
      classes = Object.keys(this._model.val("classes").val()).join(" ");
 | 
			
		||||
      if (classes.length > 0) {
 | 
			
		||||
        attrs["class"] = classes;
 | 
			
		||||
      }
 | 
			
		||||
      return attrs;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.addClass = function(names) {
 | 
			
		||||
    var name, _i, _len, _ref;
 | 
			
		||||
    _ref = names.split(" ");
 | 
			
		||||
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
 | 
			
		||||
      name = _ref[_i];
 | 
			
		||||
      this._model.val("classes").val(name, true);
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.after = function() {
 | 
			
		||||
    var c, content, contents, parent, position, _i, _j, _len, _len1, _ref;
 | 
			
		||||
    parent = this._model.val("parent");
 | 
			
		||||
    if (parent == null) {
 | 
			
		||||
      throw new Error("This Xml Element must not have siblings! (for it does not have a parent)");
 | 
			
		||||
    }
 | 
			
		||||
    _ref = parent.getChildren();
 | 
			
		||||
    for (position = _i = 0, _len = _ref.length; _i < _len; position = ++_i) {
 | 
			
		||||
      c = _ref[position];
 | 
			
		||||
      if (c === this) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    contents = [];
 | 
			
		||||
    for (_j = 0, _len1 = arguments.length; _j < _len1; _j++) {
 | 
			
		||||
      content = arguments[_j];
 | 
			
		||||
      if (content instanceof YXml) {
 | 
			
		||||
        content._setParent(this._model.val("parent"));
 | 
			
		||||
      } else if (content.constructor !== String) {
 | 
			
		||||
        throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
 | 
			
		||||
      }
 | 
			
		||||
      contents.push(content);
 | 
			
		||||
    }
 | 
			
		||||
    return parent._model.val("children").insertContents(position + 1, contents);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.append = function() {
 | 
			
		||||
    var content, _i, _len;
 | 
			
		||||
    for (_i = 0, _len = arguments.length; _i < _len; _i++) {
 | 
			
		||||
      content = arguments[_i];
 | 
			
		||||
      if (content instanceof YXml) {
 | 
			
		||||
        content._setParent(this);
 | 
			
		||||
      } else if (content.constructor !== String) {
 | 
			
		||||
        throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
 | 
			
		||||
      }
 | 
			
		||||
      this._model.val("children").push(content);
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.before = function() {
 | 
			
		||||
    var c, content, contents, parent, position, _i, _j, _len, _len1, _ref;
 | 
			
		||||
    parent = this._model.val("parent");
 | 
			
		||||
    if (parent == null) {
 | 
			
		||||
      throw new Error("This Xml Element must not have siblings! (for it does not have a parent)");
 | 
			
		||||
    }
 | 
			
		||||
    _ref = parent.getChildren();
 | 
			
		||||
    for (position = _i = 0, _len = _ref.length; _i < _len; position = ++_i) {
 | 
			
		||||
      c = _ref[position];
 | 
			
		||||
      if (c === this) {
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    contents = [];
 | 
			
		||||
    for (_j = 0, _len1 = arguments.length; _j < _len1; _j++) {
 | 
			
		||||
      content = arguments[_j];
 | 
			
		||||
      if (content instanceof YXml) {
 | 
			
		||||
        content._setParent(this._model.val("parent"));
 | 
			
		||||
      } else if (content.constructor !== String) {
 | 
			
		||||
        throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
 | 
			
		||||
      }
 | 
			
		||||
      contents.push(content);
 | 
			
		||||
    }
 | 
			
		||||
    return parent._model.val("children").insertContents(position, contents);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.empty = function() {
 | 
			
		||||
    var child, children, _i, _len, _ref, _results;
 | 
			
		||||
    children = this._model.val("children");
 | 
			
		||||
    _ref = children.val();
 | 
			
		||||
    _results = [];
 | 
			
		||||
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
 | 
			
		||||
      child = _ref[_i];
 | 
			
		||||
      if (child.constructor === String) {
 | 
			
		||||
        _results.push(children["delete"](0));
 | 
			
		||||
      } else {
 | 
			
		||||
        _results.push(child.remove());
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return _results;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.hasClass = function(className) {
 | 
			
		||||
    if (this._model.val("classes").val(className) != null) {
 | 
			
		||||
      return true;
 | 
			
		||||
    } else {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.prepend = function() {
 | 
			
		||||
    var content, _i, _len;
 | 
			
		||||
    for (_i = 0, _len = arguments.length; _i < _len; _i++) {
 | 
			
		||||
      content = arguments[_i];
 | 
			
		||||
      if (content instanceof YXml) {
 | 
			
		||||
        content._setParent(this);
 | 
			
		||||
      } else if (content.constructor !== String) {
 | 
			
		||||
        throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
 | 
			
		||||
      }
 | 
			
		||||
      this._model.val("children").insert(0, content);
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.remove = function() {
 | 
			
		||||
    var parent;
 | 
			
		||||
    parent = this._model["delete"]("parent");
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.removeAttr = function(attrName) {
 | 
			
		||||
    if (attrName === "class") {
 | 
			
		||||
      this._model.val("classes", new this._model.custom_types.Object());
 | 
			
		||||
    } else {
 | 
			
		||||
      this._model.val("attributes")["delete"](attrName);
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.removeClass = function() {
 | 
			
		||||
    var className, _i, _len;
 | 
			
		||||
    if (arguments.length === 0) {
 | 
			
		||||
      this._model.val("classes", new this._model.custom_types.Object());
 | 
			
		||||
    } else {
 | 
			
		||||
      for (_i = 0, _len = arguments.length; _i < _len; _i++) {
 | 
			
		||||
        className = arguments[_i];
 | 
			
		||||
        this._model.val("classes")["delete"](className);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.toggleClass = function() {
 | 
			
		||||
    var className, classes, _i, _len;
 | 
			
		||||
    for (_i = 0, _len = arguments.length; _i < _len; _i++) {
 | 
			
		||||
      className = arguments[_i];
 | 
			
		||||
      classes = this._model.val("classes");
 | 
			
		||||
      if (classes.val(className) != null) {
 | 
			
		||||
        classes["delete"](className);
 | 
			
		||||
      } else {
 | 
			
		||||
        classes.val(className, true);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return this;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.getParent = function() {
 | 
			
		||||
    return this._model.val("parent");
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.getChildren = function() {
 | 
			
		||||
    return this._model.val("children").val();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.getPosition = function() {
 | 
			
		||||
    var c, i, parent, _i, _len, _ref;
 | 
			
		||||
    parent = this._model.val("parent");
 | 
			
		||||
    if (parent != null) {
 | 
			
		||||
      _ref = parent._model.val("children").val();
 | 
			
		||||
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
 | 
			
		||||
        c = _ref[i];
 | 
			
		||||
        if (c === this) {
 | 
			
		||||
          return i;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      throw new Error("This is not a child of its parent (should not happen in Y.Xml!)");
 | 
			
		||||
    } else {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YXml.prototype.getDom = function() {
 | 
			
		||||
    var attr_name, attr_value, child, dom, i, setClasses, that, _i, _len, _ref, _ref1;
 | 
			
		||||
    if (this._dom == null) {
 | 
			
		||||
      this._dom = document.createElement(this._model.val("tagname"));
 | 
			
		||||
      _ref = this.attr();
 | 
			
		||||
      for (attr_name in _ref) {
 | 
			
		||||
        attr_value = _ref[attr_name];
 | 
			
		||||
        this._dom.setAttribute(attr_name, attr_value);
 | 
			
		||||
      }
 | 
			
		||||
      _ref1 = this.getChildren();
 | 
			
		||||
      for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
 | 
			
		||||
        child = _ref1[i];
 | 
			
		||||
        if (child.constructor === String) {
 | 
			
		||||
          dom = document.createTextNode(child);
 | 
			
		||||
        } else {
 | 
			
		||||
          dom = child.getDom();
 | 
			
		||||
        }
 | 
			
		||||
        this._dom.insertBefore(dom);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    that = this;
 | 
			
		||||
    if (this._dom._y_xml == null) {
 | 
			
		||||
      this._dom._y_xml = this;
 | 
			
		||||
      initialize_proxies.call(this);
 | 
			
		||||
      this._model.val("children").observe(function(events) {
 | 
			
		||||
        var children, deleted, event, newNode, rightNode, _j, _len1, _results;
 | 
			
		||||
        _results = [];
 | 
			
		||||
        for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
 | 
			
		||||
          event = events[_j];
 | 
			
		||||
          if (event.type === "insert") {
 | 
			
		||||
            if (event.value.constructor === String) {
 | 
			
		||||
              newNode = document.createTextNode(event.value);
 | 
			
		||||
            } else {
 | 
			
		||||
              newNode = event.value.getDom();
 | 
			
		||||
              event.value._setParent(that);
 | 
			
		||||
            }
 | 
			
		||||
            children = that._dom.childNodes;
 | 
			
		||||
            if (children.length === event.position) {
 | 
			
		||||
              rightNode = null;
 | 
			
		||||
            } else {
 | 
			
		||||
              rightNode = children[event.position];
 | 
			
		||||
            }
 | 
			
		||||
            _results.push(dont_proxy(function() {
 | 
			
		||||
              return that._dom.insertBefore(newNode, rightNode);
 | 
			
		||||
            }));
 | 
			
		||||
          } else if (event.type === "delete") {
 | 
			
		||||
            deleted = event.oldValue.getDom();
 | 
			
		||||
            _results.push(dont_proxy(function() {
 | 
			
		||||
              return that._dom.removeChild(deleted);
 | 
			
		||||
            }));
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return _results;
 | 
			
		||||
      });
 | 
			
		||||
      this._model.val("attributes").observe(function(events) {
 | 
			
		||||
        var event, newval, _j, _len1, _results;
 | 
			
		||||
        _results = [];
 | 
			
		||||
        for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
 | 
			
		||||
          event = events[_j];
 | 
			
		||||
          if (event.type === "add" || event.type === "update") {
 | 
			
		||||
            newval = event.object.val(event.name);
 | 
			
		||||
            _results.push(dont_proxy(function() {
 | 
			
		||||
              return that._dom.setAttribute(event.name, newval);
 | 
			
		||||
            }));
 | 
			
		||||
          } else if (event.type === "delete") {
 | 
			
		||||
            _results.push(dont_proxy(function() {
 | 
			
		||||
              return that._dom.removeAttribute(event.name);
 | 
			
		||||
            }));
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return _results;
 | 
			
		||||
      });
 | 
			
		||||
      setClasses = function() {
 | 
			
		||||
        return that._model.val("classes").observe(function(events) {
 | 
			
		||||
          var event, _j, _len1, _results;
 | 
			
		||||
          _results = [];
 | 
			
		||||
          for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
 | 
			
		||||
            event = events[_j];
 | 
			
		||||
            if (event.type === "add" || event.type === "update") {
 | 
			
		||||
              _results.push(dont_proxy(function() {
 | 
			
		||||
                return that._dom.classList.add(event.name);
 | 
			
		||||
              }));
 | 
			
		||||
            } else if (event.type === "delete") {
 | 
			
		||||
              _results.push(dont_proxy(function() {
 | 
			
		||||
                return that._dom.classList.remove(event.name);
 | 
			
		||||
              }));
 | 
			
		||||
            } else {
 | 
			
		||||
              _results.push(void 0);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          return _results;
 | 
			
		||||
        });
 | 
			
		||||
      };
 | 
			
		||||
      setClasses();
 | 
			
		||||
      this._model.observe(function(events) {
 | 
			
		||||
        var event, _j, _len1, _results;
 | 
			
		||||
        _results = [];
 | 
			
		||||
        for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
 | 
			
		||||
          event = events[_j];
 | 
			
		||||
          if (event.type === "add" || event.type === "update") {
 | 
			
		||||
            dont_proxy(function() {
 | 
			
		||||
              var classes;
 | 
			
		||||
              classes = that.attr("class");
 | 
			
		||||
              if ((classes == null) || classes === "") {
 | 
			
		||||
                return that._dom.removeAttribute("class");
 | 
			
		||||
              } else {
 | 
			
		||||
                return that._dom.setAttribute("class", that.attr("class"));
 | 
			
		||||
              }
 | 
			
		||||
            });
 | 
			
		||||
            _results.push(setClasses());
 | 
			
		||||
          } else {
 | 
			
		||||
            _results.push(void 0);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return _results;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    return this._dom;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return YXml;
 | 
			
		||||
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
proxies_are_initialized = false;
 | 
			
		||||
 | 
			
		||||
proxy_token = false;
 | 
			
		||||
 | 
			
		||||
dont_proxy = function(f) {
 | 
			
		||||
  var e;
 | 
			
		||||
  proxy_token = true;
 | 
			
		||||
  try {
 | 
			
		||||
    f();
 | 
			
		||||
  } catch (_error) {
 | 
			
		||||
    e = _error;
 | 
			
		||||
    proxy_token = false;
 | 
			
		||||
    throw new Error(e);
 | 
			
		||||
  }
 | 
			
		||||
  return proxy_token = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
initialize_proxies = function() {
 | 
			
		||||
  var f_add, f_remove, insertBefore, removeChild, replaceChild, that, _proxy;
 | 
			
		||||
  _proxy = function(f_name, f, source, y) {
 | 
			
		||||
    var old_f;
 | 
			
		||||
    if (source == null) {
 | 
			
		||||
      source = Element.prototype;
 | 
			
		||||
    }
 | 
			
		||||
    old_f = source[f_name];
 | 
			
		||||
    return source[f_name] = function() {
 | 
			
		||||
      if ((!((y != null) || (this._y_xml != null))) || proxy_token) {
 | 
			
		||||
        return old_f.apply(this, arguments);
 | 
			
		||||
      } else if (this._y_xml != null) {
 | 
			
		||||
        return f.apply(this._y_xml, arguments);
 | 
			
		||||
      } else {
 | 
			
		||||
        return f.apply(y, arguments);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  that = this;
 | 
			
		||||
  f_add = function(c) {
 | 
			
		||||
    return that.addClass(c);
 | 
			
		||||
  };
 | 
			
		||||
  _proxy("add", f_add, this._dom.classList, this);
 | 
			
		||||
  f_remove = function(c) {
 | 
			
		||||
    return that.removeClass(c);
 | 
			
		||||
  };
 | 
			
		||||
  _proxy("remove", f_remove, this._dom.classList, this);
 | 
			
		||||
  this._dom.__defineSetter__('className', function(val) {
 | 
			
		||||
    return that.attr('class', val);
 | 
			
		||||
  });
 | 
			
		||||
  this._dom.__defineGetter__('className', function() {
 | 
			
		||||
    return that.attr('class');
 | 
			
		||||
  });
 | 
			
		||||
  this._dom.__defineSetter__('textContent', function(val) {
 | 
			
		||||
    that.empty();
 | 
			
		||||
    if (val !== "") {
 | 
			
		||||
      return that.append(val);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  if (proxies_are_initialized) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  proxies_are_initialized = true;
 | 
			
		||||
  insertBefore = function(insertedNode_s, adjacentNode) {
 | 
			
		||||
    var child, new_childs, pos;
 | 
			
		||||
    if (adjacentNode != null) {
 | 
			
		||||
      pos = adjacentNode._y_xml.getPosition();
 | 
			
		||||
    } else {
 | 
			
		||||
      pos = this.getChildren().length;
 | 
			
		||||
    }
 | 
			
		||||
    new_childs = [];
 | 
			
		||||
    if (insertedNode_s.nodeType === insertedNode_s.DOCUMENT_FRAGMENT_NODE) {
 | 
			
		||||
      child = insertedNode_s.firstChild;
 | 
			
		||||
      while (child != null) {
 | 
			
		||||
        new_childs.push(child);
 | 
			
		||||
        child = child.nextSibling;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      new_childs.push(insertedNode_s);
 | 
			
		||||
    }
 | 
			
		||||
    new_childs = new_childs.map(function(child) {
 | 
			
		||||
      if (child._y_xml != null) {
 | 
			
		||||
        return child._y_xml;
 | 
			
		||||
      } else if (child.nodeType === child.TEXT_NODE) {
 | 
			
		||||
        return child.textContent;
 | 
			
		||||
      } else {
 | 
			
		||||
        return new YXml(child);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    return this._model.val("children").insertContents(pos, new_childs);
 | 
			
		||||
  };
 | 
			
		||||
  _proxy('insertBefore', insertBefore);
 | 
			
		||||
  _proxy('appendChild', insertBefore);
 | 
			
		||||
  _proxy('removeAttribute', function(name) {
 | 
			
		||||
    return this.removeAttr(name);
 | 
			
		||||
  });
 | 
			
		||||
  _proxy('setAttribute', function(name, value) {
 | 
			
		||||
    return this.attr(name, value);
 | 
			
		||||
  });
 | 
			
		||||
  removeChild = function(node) {
 | 
			
		||||
    return node._y_xml.remove();
 | 
			
		||||
  };
 | 
			
		||||
  _proxy('removeChild', removeChild);
 | 
			
		||||
  replaceChild = function(insertedNode, replacedNode) {
 | 
			
		||||
    insertBefore.call(this, insertedNode, replacedNode);
 | 
			
		||||
    return removeChild.call(this, replacedNode);
 | 
			
		||||
  };
 | 
			
		||||
  return _proxy('replaceChild', replaceChild);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  if (window.Y != null) {
 | 
			
		||||
    window.Y.Xml = YXml;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error("You must first import Y!");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (typeof module !== "undefined" && module !== null) {
 | 
			
		||||
  module.exports = YXml;
 | 
			
		||||
}
 | 
			
		||||
@ -42,4 +42,4 @@ if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  window.Y = createY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
createY.Object = require("./Types/Object");
 | 
			
		||||
createY.Object = require("./ObjectType");
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16915
									
								
								build/test/Json_test.js
									
									
									
									
									
								
							
							
						
						
									
										16915
									
								
								build/test/Json_test.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										16589
									
								
								build/test/Text_test.js
									
									
									
									
									
								
							
							
						
						
									
										16589
									
								
								build/test/Text_test.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										26877
									
								
								build/test/Xml_test.js
									
									
									
									
									
								
							
							
						
						
									
										26877
									
								
								build/test/Xml_test.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -6,17 +6,16 @@
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
  <div id="mocha"></div>
 | 
			
		||||
  <div id="test_dom" test_attribute="the test" class="stuffy" style="color: blue"><p id="replaceme">replace me</p><p id="removeme">remove me</p><p>This is a test object for <b>XmlFramework</b></p><span class="span_element"><p>span</p></span></div>
 | 
			
		||||
  <script src="../../node_modules/mocha/mocha.js" class="awesome"></script>
 | 
			
		||||
  <script>
 | 
			
		||||
    mocha.setup('bdd');
 | 
			
		||||
    mocha.ui('bdd');
 | 
			
		||||
    mocha.reporter('html');
 | 
			
		||||
  </script>
 | 
			
		||||
  <script src="Xml_test.js"></script>
 | 
			
		||||
  <!--script src="Text_test.js"></script>
 | 
			
		||||
  <script src="Json_test.js"></script-->
 | 
			
		||||
  <!--script src="Xml_test_browser.js"></script-->
 | 
			
		||||
  <script src="object-test.js"></script>
 | 
			
		||||
  <script src="xml-test.js"></script>
 | 
			
		||||
  <script src="list-test.js"></script>
 | 
			
		||||
  <script src="text-test.js"></script>
 | 
			
		||||
  <script>
 | 
			
		||||
    //mocha.checkLeaks();
 | 
			
		||||
    //mocha.run();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22357
									
								
								build/test/list-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22357
									
								
								build/test/list-test.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										16925
									
								
								build/test/object-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16925
									
								
								build/test/object-test.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										22375
									
								
								build/test/text-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22375
									
								
								build/test/text-test.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										32117
									
								
								build/test/xml-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32117
									
								
								build/test/xml-test.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -25,7 +25,7 @@ gulp.task 'default', ['build_browser']
 | 
			
		||||
files =
 | 
			
		||||
  lib : ['./lib/**/*.coffee']
 | 
			
		||||
  browser : ['./lib/y.coffee','./lib/y-object.coffee']
 | 
			
		||||
  test : ['./test/**/*_test.coffee']
 | 
			
		||||
  test : ['./test/**/*test.coffee', '../y-*/test/*test.coffee']
 | 
			
		||||
  #test : ['./test/Json_test.coffee', './test/Text_test.coffee']
 | 
			
		||||
  gulp : ['./gulpfile.coffee']
 | 
			
		||||
  examples : ['./examples/**/*.js']
 | 
			
		||||
@ -67,6 +67,7 @@ gulp.task 'build_browser', ->
 | 
			
		||||
      debug: true
 | 
			
		||||
    .pipe rename
 | 
			
		||||
      extname: ".js"
 | 
			
		||||
      dirname: "./"
 | 
			
		||||
    .pipe gulp.dest './build/test/'
 | 
			
		||||
 | 
			
		||||
gulp.task 'build_node', ->
 | 
			
		||||
 | 
			
		||||
@ -369,7 +369,7 @@ module.exports = ()->
 | 
			
		||||
        # (e.g. the following operation order must be invertible :
 | 
			
		||||
        #   Insert refers to content, then the content is deleted)
 | 
			
		||||
        # Therefore, we have to do this in the cleanup
 | 
			
		||||
        if @content instanceof ops.Operation and not deleted_earlyer
 | 
			
		||||
        if @content instanceof ops.Operation
 | 
			
		||||
          @content.referenced_by--
 | 
			
		||||
          if @content.referenced_by <= 0 and not @content.is_deleted
 | 
			
		||||
            @content.applyDelete()
 | 
			
		||||
 | 
			
		||||
@ -1,94 +0,0 @@
 | 
			
		||||
 | 
			
		||||
json_types_uninitialized = require "./JsonTypes"
 | 
			
		||||
 | 
			
		||||
module.exports = (HB)->
 | 
			
		||||
  json_types = json_types_uninitialized HB
 | 
			
		||||
  types = json_types.types
 | 
			
		||||
  parser = json_types.parser
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Manages XML types
 | 
			
		||||
  # Not supported:
 | 
			
		||||
  # * Attribute nodes
 | 
			
		||||
  # * Real replace of child elements (to much overhead). Currently, the new element is inserted after the 'replaced' element, and then it is deleted.
 | 
			
		||||
  # * Namespaces (*NS)
 | 
			
		||||
  # * Browser specific methods (webkit-* operations)
 | 
			
		||||
  class XmlType extends types.Insert
 | 
			
		||||
 | 
			
		||||
    constructor: (uid, @tagname, attributes, elements, @xml)->
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    setXmlProxy: ()->
 | 
			
		||||
 | 
			
		||||
    val: (enforce = false)->
 | 
			
		||||
      if document?
 | 
			
		||||
        if (not @xml?) or enforce
 | 
			
		||||
          @xml = document.createElement @tagname
 | 
			
		||||
 | 
			
		||||
          attr = @attributes.val()
 | 
			
		||||
          for attr_name, value of attr
 | 
			
		||||
            if value?
 | 
			
		||||
              a = document.createAttribute attr_name
 | 
			
		||||
              a.value = value
 | 
			
		||||
              @xml.setAttributeNode a
 | 
			
		||||
 | 
			
		||||
          e = @elements.beginning.next_cl
 | 
			
		||||
          while e.type isnt "Delimiter"
 | 
			
		||||
            n = e.content
 | 
			
		||||
            if not e.isDeleted() and e.content? # TODO: how can this happen?  Probably because listeners
 | 
			
		||||
              if n.type is "XmlType"
 | 
			
		||||
                @xml.appendChild n.val(enforce)
 | 
			
		||||
              else if n.type is "TextNodeType"
 | 
			
		||||
                text_node = n.val()
 | 
			
		||||
                @xml.appendChild text_node
 | 
			
		||||
              else
 | 
			
		||||
                throw new Error "Internal structure cannot be transformed to dom"
 | 
			
		||||
            e = e.next_cl
 | 
			
		||||
        @setXmlProxy()
 | 
			
		||||
        @xml
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    execute: ()->
 | 
			
		||||
      super()
 | 
			
		||||
    ###
 | 
			
		||||
      if not @validateSavedOperations()
 | 
			
		||||
        return false
 | 
			
		||||
      else
 | 
			
		||||
 | 
			
		||||
        return true
 | 
			
		||||
    ###
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # Get the parent of this JsonType.
 | 
			
		||||
    # @return {XmlType}
 | 
			
		||||
    #
 | 
			
		||||
    getParent: ()->
 | 
			
		||||
      @parent
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # @private
 | 
			
		||||
    #
 | 
			
		||||
    # Convert all relevant information of this operation to the json-format.
 | 
			
		||||
    # This result can be send to other clients.
 | 
			
		||||
    #
 | 
			
		||||
    _encode: ()->
 | 
			
		||||
      json =
 | 
			
		||||
        {
 | 
			
		||||
          'type' : @type
 | 
			
		||||
          'attributes' : @attributes.getUid()
 | 
			
		||||
          'elements' : @elements.getUid()
 | 
			
		||||
          'tagname' : @tagname
 | 
			
		||||
          'uid' : @getUid()
 | 
			
		||||
        }
 | 
			
		||||
      json
 | 
			
		||||
 | 
			
		||||
  parser['XmlType'] = (json)->
 | 
			
		||||
    {
 | 
			
		||||
      'uid' : uid
 | 
			
		||||
      'attributes' : attributes
 | 
			
		||||
      'elements' : elements
 | 
			
		||||
      'tagname' : tagname
 | 
			
		||||
    } = json
 | 
			
		||||
 | 
			
		||||
    new XmlType uid, tagname, attributes, elements, undefined
 | 
			
		||||
@ -1,80 +0,0 @@
 | 
			
		||||
class YList
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # @private
 | 
			
		||||
  # @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
 | 
			
		||||
  #
 | 
			
		||||
  constructor: (list)->
 | 
			
		||||
    if not list?
 | 
			
		||||
      @_list = []
 | 
			
		||||
    else if list.constructor is Array
 | 
			
		||||
      @_list = list
 | 
			
		||||
    else
 | 
			
		||||
      throw new Error "Y.List expects an Array as a parameter"
 | 
			
		||||
 | 
			
		||||
  _name: "List"
 | 
			
		||||
 | 
			
		||||
  _getModel: (types, ops)->
 | 
			
		||||
    if not @_model?
 | 
			
		||||
      @_model = new ops.ListManager(@).execute()
 | 
			
		||||
      @_model.insert 0, @_list
 | 
			
		||||
    delete @_list
 | 
			
		||||
    @_model
 | 
			
		||||
 | 
			
		||||
  _setModel: (@_model)->
 | 
			
		||||
    delete @_list
 | 
			
		||||
 | 
			
		||||
  val: ()->
 | 
			
		||||
    @_model.val.apply @_model, arguments
 | 
			
		||||
 | 
			
		||||
  observe: ()->
 | 
			
		||||
    @_model.observe.apply @_model, arguments
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  unobserve: ()->
 | 
			
		||||
    @_model.unobserve.apply @_model, arguments
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Inserts an Object into the list.
 | 
			
		||||
  #
 | 
			
		||||
  # @return {ListManager Type} This String object.
 | 
			
		||||
  #
 | 
			
		||||
  insert: (position, content)->
 | 
			
		||||
    if typeof position isnt "number"
 | 
			
		||||
      throw new Error "Y.List.insert expects a Number as the first parameter!"
 | 
			
		||||
    @_model.insert position, [content]
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  insertContents: (position, contents)->
 | 
			
		||||
    if typeof position isnt "number"
 | 
			
		||||
      throw new Error "Y.List.insert expects a Number as the first parameter!"
 | 
			
		||||
    @_model.insert position, contents
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  delete: (position, length)->
 | 
			
		||||
    @_model.delete position, length
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  push: (content)->
 | 
			
		||||
    @_model.push content
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
if window?
 | 
			
		||||
  if window.Y?
 | 
			
		||||
    window.Y.List = YList
 | 
			
		||||
  else
 | 
			
		||||
    throw new Error "You must first import Y!"
 | 
			
		||||
 | 
			
		||||
if module?
 | 
			
		||||
  module.exports = YList
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,305 +0,0 @@
 | 
			
		||||
#
 | 
			
		||||
# Handles a String-like data structures with support for insert/delete at a word-position.
 | 
			
		||||
#
 | 
			
		||||
class YText
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # @private
 | 
			
		||||
  # @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
 | 
			
		||||
  #
 | 
			
		||||
  constructor: (text)->
 | 
			
		||||
    @textfields = []
 | 
			
		||||
    if not text?
 | 
			
		||||
      @_text = ""
 | 
			
		||||
    else if text.constructor is String
 | 
			
		||||
      @_text = text
 | 
			
		||||
    else
 | 
			
		||||
      throw new Error "Y.Text expects a String as a constructor"
 | 
			
		||||
 | 
			
		||||
  _name: "Text"
 | 
			
		||||
 | 
			
		||||
  _getModel: (types, ops)->
 | 
			
		||||
    if not @_model?
 | 
			
		||||
      @_model = new ops.ListManager(@).execute()
 | 
			
		||||
      @insert 0, @_text
 | 
			
		||||
    delete @_text
 | 
			
		||||
    @_model
 | 
			
		||||
 | 
			
		||||
  _setModel: (@_model)->
 | 
			
		||||
    delete @_text
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Get the String-representation of this word.
 | 
			
		||||
  # @return {String} The String-representation of this object.
 | 
			
		||||
  #
 | 
			
		||||
  val: ()->
 | 
			
		||||
    @_model.fold "", (left, o)->
 | 
			
		||||
      left + o.val()
 | 
			
		||||
 | 
			
		||||
  observe: ()->
 | 
			
		||||
    @_model.observe.apply @_model, arguments
 | 
			
		||||
 | 
			
		||||
  unobserve: ()->
 | 
			
		||||
    @_model.unobserve.apply @_model, arguments
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Same as String.val
 | 
			
		||||
  # @see String.val
 | 
			
		||||
  #
 | 
			
		||||
  toString: ()->
 | 
			
		||||
    @val()
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Inserts a string into the word.
 | 
			
		||||
  #
 | 
			
		||||
  # @return {ListManager Type} This String object.
 | 
			
		||||
  #
 | 
			
		||||
  insert: (position, content)->
 | 
			
		||||
    if content.constructor isnt String
 | 
			
		||||
      throw new Error "Y.String.insert expects a String as the second parameter!"
 | 
			
		||||
    if typeof position isnt "number"
 | 
			
		||||
      throw new Error "Y.String.insert expects a Number as the first parameter!"
 | 
			
		||||
    if content.length > 0
 | 
			
		||||
      ith = @_model.getOperationByPosition position
 | 
			
		||||
      # the (i-1)th character. e.g. "abc" the 1th character is "a"
 | 
			
		||||
      # the 0th character is the left Delimiter
 | 
			
		||||
      @_model.insertAfter ith, content
 | 
			
		||||
 | 
			
		||||
  delete: (position, length)->
 | 
			
		||||
    @_model.delete position, length
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Bind this String to a textfield or input field.
 | 
			
		||||
  #
 | 
			
		||||
  # @example
 | 
			
		||||
  #   var textbox = document.getElementById("textfield");
 | 
			
		||||
  #   y.bind(textbox);
 | 
			
		||||
  #
 | 
			
		||||
  bind: (textfield, dom_root)->
 | 
			
		||||
    dom_root ?= window
 | 
			
		||||
    if (not dom_root.getSelection?)
 | 
			
		||||
      dom_root = window
 | 
			
		||||
 | 
			
		||||
    # don't duplicate!
 | 
			
		||||
    for t in @textfields
 | 
			
		||||
      if t is textfield
 | 
			
		||||
        return
 | 
			
		||||
    creator_token = false;
 | 
			
		||||
 | 
			
		||||
    word = @
 | 
			
		||||
    textfield.value = @val()
 | 
			
		||||
    @textfields.push textfield
 | 
			
		||||
 | 
			
		||||
    if textfield.selectionStart? and textfield.setSelectionRange?
 | 
			
		||||
      createRange = (fix)->
 | 
			
		||||
        left = textfield.selectionStart
 | 
			
		||||
        right = textfield.selectionEnd
 | 
			
		||||
        if fix?
 | 
			
		||||
          left = fix left
 | 
			
		||||
          right = fix right
 | 
			
		||||
        {
 | 
			
		||||
          left: left
 | 
			
		||||
          right: right
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      writeRange = (range)->
 | 
			
		||||
        writeContent word.val()
 | 
			
		||||
        textfield.setSelectionRange range.left, range.right
 | 
			
		||||
 | 
			
		||||
      writeContent = (content)->
 | 
			
		||||
        textfield.value = content
 | 
			
		||||
    else
 | 
			
		||||
      createRange = (fix)->
 | 
			
		||||
        range = {}
 | 
			
		||||
        s = dom_root.getSelection()
 | 
			
		||||
        clength = textfield.textContent.length
 | 
			
		||||
        range.left = Math.min s.anchorOffset, clength
 | 
			
		||||
        range.right = Math.min s.focusOffset, clength
 | 
			
		||||
        if fix?
 | 
			
		||||
          range.left = fix range.left
 | 
			
		||||
          range.right = fix range.right
 | 
			
		||||
 | 
			
		||||
        edited_element = s.focusNode
 | 
			
		||||
        if edited_element is textfield or edited_element is textfield.childNodes[0]
 | 
			
		||||
          range.isReal = true
 | 
			
		||||
        else
 | 
			
		||||
          range.isReal = false
 | 
			
		||||
        range
 | 
			
		||||
 | 
			
		||||
      writeRange = (range)->
 | 
			
		||||
        writeContent word.val()
 | 
			
		||||
        textnode = textfield.childNodes[0]
 | 
			
		||||
        if range.isReal and textnode?
 | 
			
		||||
          if range.left < 0
 | 
			
		||||
            range.left = 0
 | 
			
		||||
          range.right = Math.max range.left, range.right
 | 
			
		||||
          if range.right > textnode.length
 | 
			
		||||
            range.right = textnode.length
 | 
			
		||||
          range.left = Math.min range.left, range.right
 | 
			
		||||
          r = document.createRange()
 | 
			
		||||
          r.setStart(textnode, range.left)
 | 
			
		||||
          r.setEnd(textnode, range.right)
 | 
			
		||||
          s = window.getSelection()
 | 
			
		||||
          s.removeAllRanges()
 | 
			
		||||
          s.addRange(r)
 | 
			
		||||
      writeContent = (content)->
 | 
			
		||||
        content_array = content.replace(new RegExp("\n",'g')," ").split(" ")
 | 
			
		||||
        textfield.innerText = ""
 | 
			
		||||
        for c, i in content_array
 | 
			
		||||
          textfield.innerText += c
 | 
			
		||||
          if i isnt content_array.length-1
 | 
			
		||||
            textfield.innerHTML += ' '
 | 
			
		||||
 | 
			
		||||
    writeContent this.val()
 | 
			
		||||
 | 
			
		||||
    @observe (events)->
 | 
			
		||||
      for event in events
 | 
			
		||||
        if not creator_token
 | 
			
		||||
          if event.type is "insert"
 | 
			
		||||
            o_pos = event.position
 | 
			
		||||
            fix = (cursor)->
 | 
			
		||||
              if cursor <= o_pos
 | 
			
		||||
                cursor
 | 
			
		||||
              else
 | 
			
		||||
                cursor += 1
 | 
			
		||||
                cursor
 | 
			
		||||
            r = createRange fix
 | 
			
		||||
            writeRange r
 | 
			
		||||
 | 
			
		||||
          else if event.type is "delete"
 | 
			
		||||
            o_pos = event.position
 | 
			
		||||
            fix = (cursor)->
 | 
			
		||||
              if cursor < o_pos
 | 
			
		||||
                cursor
 | 
			
		||||
              else
 | 
			
		||||
                cursor -= 1
 | 
			
		||||
                cursor
 | 
			
		||||
            r = createRange fix
 | 
			
		||||
            writeRange r
 | 
			
		||||
 | 
			
		||||
    # consume all text-insert changes.
 | 
			
		||||
    textfield.onkeypress = (event)->
 | 
			
		||||
      if word.is_deleted
 | 
			
		||||
        # if word is deleted, do not do anything ever again
 | 
			
		||||
        textfield.onkeypress = null
 | 
			
		||||
        return true
 | 
			
		||||
      creator_token = true
 | 
			
		||||
      char = null
 | 
			
		||||
      if event.keyCode is 13
 | 
			
		||||
        char = '\n'
 | 
			
		||||
      else if event.key?
 | 
			
		||||
        if event.charCode is 32
 | 
			
		||||
          char = " "
 | 
			
		||||
        else
 | 
			
		||||
          char = event.key
 | 
			
		||||
      else
 | 
			
		||||
        char = window.String.fromCharCode event.keyCode
 | 
			
		||||
      if char.length > 1
 | 
			
		||||
        return true
 | 
			
		||||
      else if char.length > 0
 | 
			
		||||
        r = createRange()
 | 
			
		||||
        pos = Math.min r.left, r.right
 | 
			
		||||
        diff = Math.abs(r.right - r.left)
 | 
			
		||||
        word.delete pos, diff
 | 
			
		||||
        word.insert pos, char
 | 
			
		||||
        r.left = pos + char.length
 | 
			
		||||
        r.right = r.left
 | 
			
		||||
        writeRange r
 | 
			
		||||
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
      creator_token = false
 | 
			
		||||
      false
 | 
			
		||||
 | 
			
		||||
    textfield.onpaste = (event)->
 | 
			
		||||
      if word.is_deleted
 | 
			
		||||
        # if word is deleted, do not do anything ever again
 | 
			
		||||
        textfield.onpaste = null
 | 
			
		||||
        return true
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
    textfield.oncut = (event)->
 | 
			
		||||
      if word.is_deleted
 | 
			
		||||
        # if word is deleted, do not do anything ever again
 | 
			
		||||
        textfield.oncut = null
 | 
			
		||||
        return true
 | 
			
		||||
      event.preventDefault()
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # consume deletes. Note that
 | 
			
		||||
    #   chrome: won't consume deletions on keypress event.
 | 
			
		||||
    #   keyCode is deprecated. BUT: I don't see another way.
 | 
			
		||||
    #     since event.key is not implemented in the current version of chrome.
 | 
			
		||||
    #     Every browser supports keyCode. Let's stick with it for now..
 | 
			
		||||
    #
 | 
			
		||||
    textfield.onkeydown = (event)->
 | 
			
		||||
      creator_token = true
 | 
			
		||||
      if word.is_deleted
 | 
			
		||||
        # if word is deleted, do not do anything ever again
 | 
			
		||||
        textfield.onkeydown = null
 | 
			
		||||
        return true
 | 
			
		||||
      r = createRange()
 | 
			
		||||
      pos = Math.min(r.left, r.right, word.val().length)
 | 
			
		||||
      diff = Math.abs(r.left - r.right)
 | 
			
		||||
      if event.keyCode? and event.keyCode is 8 # Backspace
 | 
			
		||||
        if diff > 0
 | 
			
		||||
          word.delete pos, diff
 | 
			
		||||
          r.left = pos
 | 
			
		||||
          r.right = pos
 | 
			
		||||
          writeRange r
 | 
			
		||||
        else
 | 
			
		||||
          if event.ctrlKey? and event.ctrlKey
 | 
			
		||||
            val = word.val()
 | 
			
		||||
            new_pos = pos
 | 
			
		||||
            del_length = 0
 | 
			
		||||
            if pos > 0
 | 
			
		||||
              new_pos--
 | 
			
		||||
              del_length++
 | 
			
		||||
            while new_pos > 0 and val[new_pos] isnt " " and val[new_pos] isnt '\n'
 | 
			
		||||
              new_pos--
 | 
			
		||||
              del_length++
 | 
			
		||||
            word.delete new_pos, (pos-new_pos)
 | 
			
		||||
            r.left = new_pos
 | 
			
		||||
            r.right = new_pos
 | 
			
		||||
            writeRange r
 | 
			
		||||
          else
 | 
			
		||||
            if pos > 0
 | 
			
		||||
              word.delete (pos-1), 1
 | 
			
		||||
              r.left = pos-1
 | 
			
		||||
              r.right = pos-1
 | 
			
		||||
              writeRange r
 | 
			
		||||
        event.preventDefault()
 | 
			
		||||
        creator_token = false
 | 
			
		||||
        return false
 | 
			
		||||
      else if event.keyCode? and event.keyCode is 46 # Delete
 | 
			
		||||
        if diff > 0
 | 
			
		||||
          word.delete pos, diff
 | 
			
		||||
          r.left = pos
 | 
			
		||||
          r.right = pos
 | 
			
		||||
          writeRange r
 | 
			
		||||
        else
 | 
			
		||||
          word.delete pos, 1
 | 
			
		||||
          r.left = pos
 | 
			
		||||
          r.right = pos
 | 
			
		||||
          writeRange r
 | 
			
		||||
        event.preventDefault()
 | 
			
		||||
        creator_token = false
 | 
			
		||||
        return false
 | 
			
		||||
      else
 | 
			
		||||
        creator_token = false
 | 
			
		||||
        true
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if window?
 | 
			
		||||
  if window.Y?
 | 
			
		||||
    window.Y.Text = YText
 | 
			
		||||
  else
 | 
			
		||||
    throw new Error "You must first import Y!"
 | 
			
		||||
 | 
			
		||||
if module?
 | 
			
		||||
  module.exports = YText
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,492 +0,0 @@
 | 
			
		||||
class YXml
 | 
			
		||||
 | 
			
		||||
  constructor: (tag_or_dom, attributes = {})->
 | 
			
		||||
    if not tag_or_dom?
 | 
			
		||||
      # nop
 | 
			
		||||
    else if tag_or_dom.constructor is String
 | 
			
		||||
      tagname = tag_or_dom
 | 
			
		||||
      @_xml = {}
 | 
			
		||||
      @_xml.children = []
 | 
			
		||||
      #TODO: How to force the user to specify parameters?
 | 
			
		||||
      #if not tagname?
 | 
			
		||||
      #  throw new Error "You must specify a tagname"
 | 
			
		||||
      @_xml.tagname = tagname
 | 
			
		||||
      if attributes.constructor isnt Object
 | 
			
		||||
        throw new Error "The attributes must be specified as a Object"
 | 
			
		||||
      for a_name, a of attributes
 | 
			
		||||
        if a.constructor isnt String
 | 
			
		||||
          throw new Error "The attributes must be of type String!"
 | 
			
		||||
      @_xml.attributes = attributes
 | 
			
		||||
      @_xml.classes = {}
 | 
			
		||||
      _classes = @_xml.attributes.class
 | 
			
		||||
      delete @_xml.attributes.class
 | 
			
		||||
      if _classes?
 | 
			
		||||
        for c_name, c in _classes.split(" ")
 | 
			
		||||
          if c.length > 0
 | 
			
		||||
            @_xml.classes[c_name] = c
 | 
			
		||||
      undefined
 | 
			
		||||
    else if tag_or_dom instanceof Element
 | 
			
		||||
      @_dom = tag_or_dom
 | 
			
		||||
      @_xml = {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  _name: "Xml"
 | 
			
		||||
 | 
			
		||||
  _getModel: (Y, ops)->
 | 
			
		||||
    if not @_model?
 | 
			
		||||
      if @_dom?
 | 
			
		||||
        @_xml.tagname = @_dom.tagName.toLowerCase()
 | 
			
		||||
        @_xml.attributes = {}
 | 
			
		||||
        @_xml.classes = {}
 | 
			
		||||
        for attribute in @_dom.attributes
 | 
			
		||||
          if attribute.name is "class"
 | 
			
		||||
            for c in attribute.value.split(" ")
 | 
			
		||||
              @_xml.classes[c] = true
 | 
			
		||||
          else
 | 
			
		||||
            @_xml.attributes[attribute.name] = attribute.value
 | 
			
		||||
        @_xml.children = []
 | 
			
		||||
        for child in @_dom.childNodes
 | 
			
		||||
          if child.nodeType is child.TEXT_NODE
 | 
			
		||||
            @_xml.children.push child.textContent
 | 
			
		||||
          else
 | 
			
		||||
            @_xml.children.push(new YXml(child))
 | 
			
		||||
      @_model = new ops.MapManager(@).execute()
 | 
			
		||||
      @_model.val("attributes", new Y.Object(@_xml.attributes))
 | 
			
		||||
      @_model.val("classes", new Y.Object(@_xml.classes))
 | 
			
		||||
      @_model.val("tagname", @_xml.tagname)
 | 
			
		||||
      @_model.val("children", new Y.List(@_xml.children))
 | 
			
		||||
      if @_xml.parent?
 | 
			
		||||
        @_model.val("parent", @_xml.parent)
 | 
			
		||||
 | 
			
		||||
      if @_dom?
 | 
			
		||||
        @getDom() # two way bind dom to this xml type
 | 
			
		||||
 | 
			
		||||
      @_setModel @_model
 | 
			
		||||
 | 
			
		||||
    @_model
 | 
			
		||||
 | 
			
		||||
  _setModel: (@_model)->
 | 
			
		||||
    @_model.observe (events)->
 | 
			
		||||
      for event in events
 | 
			
		||||
        if event.name is "parent" and event.type isnt "add"
 | 
			
		||||
          parent = event.oldValue
 | 
			
		||||
          children = parent._model.val("children")?.val()
 | 
			
		||||
          if children?
 | 
			
		||||
            for c,i in children
 | 
			
		||||
              if c is @
 | 
			
		||||
                parent._model.val("children").delete i
 | 
			
		||||
                break
 | 
			
		||||
    delete @_xml
 | 
			
		||||
 | 
			
		||||
  _setParent: (parent)->
 | 
			
		||||
    if parent instanceof YXml
 | 
			
		||||
      if @_model?
 | 
			
		||||
        @remove()
 | 
			
		||||
        @_model.val("parent", parent)
 | 
			
		||||
      else
 | 
			
		||||
        @_xml.parent = parent
 | 
			
		||||
    else
 | 
			
		||||
      throw new Error "parent must be of type Y.Xml!"
 | 
			
		||||
 | 
			
		||||
  toString: ()->
 | 
			
		||||
    xml = "<"+@_model.val("tagname")
 | 
			
		||||
    for name, value of @attr()
 | 
			
		||||
      xml += " "+name+'="'+value+'"'
 | 
			
		||||
    xml += ">"
 | 
			
		||||
    for child in @_model.val("children").val()
 | 
			
		||||
      xml += child.toString()
 | 
			
		||||
    xml += '</'+@_model.val("tagname")+'>'
 | 
			
		||||
    xml
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Get/set the attribute(s) of this element.
 | 
			
		||||
  # .attr()
 | 
			
		||||
  # .attr(name)
 | 
			
		||||
  # .attr(name, value)
 | 
			
		||||
  #
 | 
			
		||||
  attr: (name, value)->
 | 
			
		||||
    if arguments.length > 1
 | 
			
		||||
      if value.constructor isnt String
 | 
			
		||||
        throw new Error "The attributes must be of type String!"
 | 
			
		||||
      if name is "class"
 | 
			
		||||
        classes = value.split(" ")
 | 
			
		||||
        cs = {}
 | 
			
		||||
        for c in classes
 | 
			
		||||
          cs[c] = true
 | 
			
		||||
 | 
			
		||||
        @_model.val("classes", new @_model.custom_types.Object(cs))
 | 
			
		||||
      else
 | 
			
		||||
        @_model.val("attributes").val(name, value)
 | 
			
		||||
      @
 | 
			
		||||
    else if arguments.length > 0
 | 
			
		||||
      if name is "class"
 | 
			
		||||
        Object.keys(@_model.val("classes").val()).join(" ")
 | 
			
		||||
      else
 | 
			
		||||
        @_model.val("attributes").val(name)
 | 
			
		||||
    else
 | 
			
		||||
      attrs = @_model.val("attributes").val()
 | 
			
		||||
      classes = Object.keys(@_model.val("classes").val()).join(" ")
 | 
			
		||||
      if classes.length > 0
 | 
			
		||||
        attrs["class"] = classes
 | 
			
		||||
      attrs
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Adds the specified class(es) to this element
 | 
			
		||||
  #
 | 
			
		||||
  addClass: (names)->
 | 
			
		||||
    for name in names.split(" ")
 | 
			
		||||
      @_model.val("classes").val(name, true)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Insert content, specified by the parameter, after this element
 | 
			
		||||
  # .after(content [, content])
 | 
			
		||||
  #
 | 
			
		||||
  after: ()->
 | 
			
		||||
    parent = @_model.val("parent")
 | 
			
		||||
    if not parent?
 | 
			
		||||
      throw new Error "This Xml Element must not have siblings! (for it does not have a parent)"
 | 
			
		||||
 | 
			
		||||
    # find the position of this element
 | 
			
		||||
    for c,position in parent.getChildren()
 | 
			
		||||
      if c is @
 | 
			
		||||
        break
 | 
			
		||||
 | 
			
		||||
    contents = []
 | 
			
		||||
    for content in arguments
 | 
			
		||||
      if content instanceof YXml
 | 
			
		||||
        content._setParent(@_model.val("parent"))
 | 
			
		||||
      else if content.constructor isnt String
 | 
			
		||||
        throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
 | 
			
		||||
      contents.push content
 | 
			
		||||
 | 
			
		||||
    parent._model.val("children").insertContents(position+1, contents)
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Insert content, specified by the parameter, to the end of this element
 | 
			
		||||
  # .append(content [, content])
 | 
			
		||||
  #
 | 
			
		||||
  append: ()->
 | 
			
		||||
    for content in arguments
 | 
			
		||||
      if content instanceof YXml
 | 
			
		||||
        content._setParent(@)
 | 
			
		||||
      else if content.constructor isnt String
 | 
			
		||||
        throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
 | 
			
		||||
      @_model.val("children").push(content)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Insert content, specified by the parameter, after this element
 | 
			
		||||
  # .after(content [, content])
 | 
			
		||||
  #
 | 
			
		||||
  before: ()->
 | 
			
		||||
    parent = @_model.val("parent")
 | 
			
		||||
    if not parent?
 | 
			
		||||
      throw new Error "This Xml Element must not have siblings! (for it does not have a parent)"
 | 
			
		||||
 | 
			
		||||
    # find the position of this element
 | 
			
		||||
    for c,position in parent.getChildren()
 | 
			
		||||
      if c is @
 | 
			
		||||
        break
 | 
			
		||||
 | 
			
		||||
    contents = []
 | 
			
		||||
    for content in arguments
 | 
			
		||||
      if content instanceof YXml
 | 
			
		||||
        content._setParent(@_model.val("parent"))
 | 
			
		||||
      else if content.constructor isnt String
 | 
			
		||||
        throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
 | 
			
		||||
      contents.push content
 | 
			
		||||
 | 
			
		||||
    parent._model.val("children").insertContents(position, contents)
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Remove all child nodes of the set of matched elements from the DOM.
 | 
			
		||||
  # .empty()
 | 
			
		||||
  #
 | 
			
		||||
  empty: ()->
 | 
			
		||||
    # TODO: do it like this : @_model.val("children", new Y.List())
 | 
			
		||||
    children = @_model.val("children")
 | 
			
		||||
    for child in children.val()
 | 
			
		||||
      if child.constructor is String
 | 
			
		||||
        children.delete(0)
 | 
			
		||||
      else
 | 
			
		||||
        child.remove()
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Determine whether any of the matched elements are assigned the given class.
 | 
			
		||||
  # .hasClass(className)
 | 
			
		||||
  #
 | 
			
		||||
  hasClass: (className)->
 | 
			
		||||
    if @_model.val("classes").val(className)?
 | 
			
		||||
      true
 | 
			
		||||
    else
 | 
			
		||||
      false
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Insert content, specified by the parameter, to the beginning of this element.
 | 
			
		||||
  # .prepend(content [, content])
 | 
			
		||||
  #
 | 
			
		||||
  prepend: ()->
 | 
			
		||||
    for content in arguments
 | 
			
		||||
      if content instanceof YXml
 | 
			
		||||
        content._setParent(@)
 | 
			
		||||
      else if content.constructor isnt String
 | 
			
		||||
        throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
 | 
			
		||||
      @_model.val("children").insert(0, content)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Remove this element from the DOM
 | 
			
		||||
  # .remove()
 | 
			
		||||
  #
 | 
			
		||||
  remove: ()->
 | 
			
		||||
    parent = @_model.delete("parent")
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Remove an attribute from this element
 | 
			
		||||
  # .removeAttr(attrName)
 | 
			
		||||
  #
 | 
			
		||||
  removeAttr: (attrName)->
 | 
			
		||||
    if attrName is "class"
 | 
			
		||||
      @_model.val("classes", new @_model.custom_types.Object())
 | 
			
		||||
    else
 | 
			
		||||
      @_model.val("attributes").delete(attrName)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Remove a single class, multiple classes, or all classes from this element
 | 
			
		||||
  # .removeClass([className])
 | 
			
		||||
  #
 | 
			
		||||
  removeClass: ()->
 | 
			
		||||
    if arguments.length is 0
 | 
			
		||||
      @_model.val("classes", new @_model.custom_types.Object())
 | 
			
		||||
    else
 | 
			
		||||
      for className in arguments
 | 
			
		||||
        @_model.val("classes").delete(className)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Add or remove one or more classes from this element,
 | 
			
		||||
  # depending on either the class’s presence or the value of the state argument.
 | 
			
		||||
  # .toggleClass([className])
 | 
			
		||||
  #
 | 
			
		||||
  toggleClass: ()->
 | 
			
		||||
    for className in arguments
 | 
			
		||||
      classes = @_model.val("classes")
 | 
			
		||||
      if classes.val(className)?
 | 
			
		||||
        classes.delete(className)
 | 
			
		||||
      else
 | 
			
		||||
        classes.val(className, true)
 | 
			
		||||
    @
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Get the parent of this Element
 | 
			
		||||
  # @Note: Every XML element can only have one parent
 | 
			
		||||
  # .getParent()
 | 
			
		||||
  #
 | 
			
		||||
  getParent: ()->
 | 
			
		||||
    @_model.val("parent")
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Get all the children of this XML Element as an Array
 | 
			
		||||
  # @Note: The children are either of type Y.Xml or String
 | 
			
		||||
  # .getChildren()
 | 
			
		||||
  #
 | 
			
		||||
  getChildren: ()->
 | 
			
		||||
    @_model.val("children").val()
 | 
			
		||||
 | 
			
		||||
  getPosition: ()->
 | 
			
		||||
    parent = @_model.val("parent")
 | 
			
		||||
    if parent?
 | 
			
		||||
      for c,i in parent._model.val("children").val()
 | 
			
		||||
        if c is @
 | 
			
		||||
          return i
 | 
			
		||||
      throw new Error "This is not a child of its parent (should not happen in Y.Xml!)"
 | 
			
		||||
    else
 | 
			
		||||
      null
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  getDom: ()->
 | 
			
		||||
    if not @_dom?
 | 
			
		||||
      @_dom = document.createElement(@_model.val("tagname"))
 | 
			
		||||
 | 
			
		||||
      # set the attributes _and_ the classes (@see .attr())
 | 
			
		||||
      for attr_name, attr_value of @attr()
 | 
			
		||||
        @_dom.setAttribute attr_name, attr_value
 | 
			
		||||
      for child,i in @getChildren()
 | 
			
		||||
        if child.constructor is String
 | 
			
		||||
          dom = document.createTextNode child
 | 
			
		||||
        else
 | 
			
		||||
          dom = child.getDom()
 | 
			
		||||
        @_dom.insertBefore dom
 | 
			
		||||
 | 
			
		||||
    that = @
 | 
			
		||||
 | 
			
		||||
    if (not @_dom._y_xml?)
 | 
			
		||||
      @_dom._y_xml = @
 | 
			
		||||
      initialize_proxies.call @
 | 
			
		||||
 | 
			
		||||
      @_model.val("children").observe (events)->
 | 
			
		||||
        for event in events
 | 
			
		||||
          if event.type is "insert"
 | 
			
		||||
            if event.value.constructor is String
 | 
			
		||||
              newNode = document.createTextNode(event.value)
 | 
			
		||||
            else
 | 
			
		||||
              newNode = event.value.getDom()
 | 
			
		||||
              event.value._setParent that
 | 
			
		||||
            children = that._dom.childNodes
 | 
			
		||||
            if children.length is event.position
 | 
			
		||||
              rightNode = null
 | 
			
		||||
            else
 | 
			
		||||
              rightNode = children[event.position]
 | 
			
		||||
 | 
			
		||||
            dont_proxy ()->
 | 
			
		||||
              that._dom.insertBefore newNode, rightNode
 | 
			
		||||
          else if event.type is "delete"
 | 
			
		||||
            deleted = event.oldValue.getDom()
 | 
			
		||||
            dont_proxy ()->
 | 
			
		||||
              that._dom.removeChild deleted
 | 
			
		||||
      @_model.val("attributes").observe (events)->
 | 
			
		||||
        for event in events
 | 
			
		||||
          if event.type is "add" or event.type is "update"
 | 
			
		||||
            newval = event.object.val(event.name)
 | 
			
		||||
            dont_proxy ()->
 | 
			
		||||
              that._dom.setAttribute event.name, newval
 | 
			
		||||
          else if event.type is "delete"
 | 
			
		||||
            dont_proxy ()->
 | 
			
		||||
              that._dom.removeAttribute event.name
 | 
			
		||||
      setClasses = ()->
 | 
			
		||||
        that._model.val("classes").observe (events)->
 | 
			
		||||
          for event in events
 | 
			
		||||
            if event.type is "add" or event.type is "update"
 | 
			
		||||
              dont_proxy ()->
 | 
			
		||||
                that._dom.classList.add event.name # classes are stored as the keys
 | 
			
		||||
            else if event.type is "delete"
 | 
			
		||||
              dont_proxy ()->
 | 
			
		||||
                that._dom.classList.remove event.name
 | 
			
		||||
      setClasses()
 | 
			
		||||
      @_model.observe (events)->
 | 
			
		||||
        for event in events
 | 
			
		||||
          if event.type is "add" or event.type is "update"
 | 
			
		||||
            dont_proxy ()->
 | 
			
		||||
              classes = that.attr("class")
 | 
			
		||||
              if (not classes?) or classes is ""
 | 
			
		||||
                that._dom.removeAttribute "class"
 | 
			
		||||
              else
 | 
			
		||||
                that._dom.setAttribute "class", that.attr("class")
 | 
			
		||||
            setClasses()
 | 
			
		||||
 | 
			
		||||
    @_dom
 | 
			
		||||
 | 
			
		||||
proxies_are_initialized = false
 | 
			
		||||
# some dom implementations may call another dom.method that simulates the behavior of another.
 | 
			
		||||
# For example xml.insertChild(dom) , wich inserts an element at the end, and xml.insertAfter(dom,null) wich does the same
 | 
			
		||||
# But Y's proxy may be called only once!
 | 
			
		||||
proxy_token = false
 | 
			
		||||
dont_proxy = (f)->
 | 
			
		||||
  proxy_token = true
 | 
			
		||||
  try
 | 
			
		||||
    f()
 | 
			
		||||
  catch e
 | 
			
		||||
    proxy_token = false
 | 
			
		||||
    throw new Error e
 | 
			
		||||
  proxy_token = false
 | 
			
		||||
 | 
			
		||||
initialize_proxies = ()->
 | 
			
		||||
 | 
			
		||||
  _proxy = (f_name, f, source = Element.prototype, y)->
 | 
			
		||||
    old_f = source[f_name]
 | 
			
		||||
    source[f_name] = ()->
 | 
			
		||||
      if (not (y? or @_y_xml?)) or proxy_token
 | 
			
		||||
        old_f.apply this, arguments
 | 
			
		||||
      else if @_y_xml?
 | 
			
		||||
        f.apply @_y_xml, arguments
 | 
			
		||||
      else
 | 
			
		||||
        f.apply y, arguments
 | 
			
		||||
 | 
			
		||||
  that = this
 | 
			
		||||
  f_add = (c)->
 | 
			
		||||
    that.addClass c
 | 
			
		||||
  _proxy "add", f_add, @_dom.classList, @
 | 
			
		||||
 | 
			
		||||
  f_remove = (c)->
 | 
			
		||||
    that.removeClass c
 | 
			
		||||
 | 
			
		||||
  _proxy "remove", f_remove, @_dom.classList, @
 | 
			
		||||
 | 
			
		||||
  @_dom.__defineSetter__ 'className', (val)->
 | 
			
		||||
    that.attr('class', val)
 | 
			
		||||
  @_dom.__defineGetter__ 'className', ()->
 | 
			
		||||
    that.attr('class')
 | 
			
		||||
  @_dom.__defineSetter__ 'textContent', (val)->
 | 
			
		||||
    # remove all nodes
 | 
			
		||||
    that.empty()
 | 
			
		||||
 | 
			
		||||
    # insert word content
 | 
			
		||||
    if val isnt ""
 | 
			
		||||
      that.append val
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  if proxies_are_initialized
 | 
			
		||||
    return
 | 
			
		||||
  proxies_are_initialized = true
 | 
			
		||||
 | 
			
		||||
  # the following methods are initialized on prototypes and therefore they need to be written only once!
 | 
			
		||||
 | 
			
		||||
  insertBefore = (insertedNode_s, adjacentNode)->
 | 
			
		||||
    if adjacentNode?
 | 
			
		||||
      pos = adjacentNode._y_xml.getPosition()
 | 
			
		||||
    else
 | 
			
		||||
      pos = @getChildren().length
 | 
			
		||||
 | 
			
		||||
    new_childs = []
 | 
			
		||||
    if insertedNode_s.nodeType is insertedNode_s.DOCUMENT_FRAGMENT_NODE
 | 
			
		||||
      child = insertedNode_s.firstChild
 | 
			
		||||
      while child?
 | 
			
		||||
        new_childs.push child
 | 
			
		||||
        child = child.nextSibling
 | 
			
		||||
    else
 | 
			
		||||
      new_childs.push insertedNode_s
 | 
			
		||||
    new_childs = new_childs.map (child)->
 | 
			
		||||
      if child._y_xml?
 | 
			
		||||
        child._y_xml
 | 
			
		||||
      else if child.nodeType == child.TEXT_NODE
 | 
			
		||||
        child.textContent
 | 
			
		||||
      else
 | 
			
		||||
        new YXml(child)
 | 
			
		||||
    @_model.val("children").insertContents pos, new_childs
 | 
			
		||||
 | 
			
		||||
  _proxy 'insertBefore', insertBefore
 | 
			
		||||
  _proxy 'appendChild', insertBefore
 | 
			
		||||
  _proxy 'removeAttribute', (name)->
 | 
			
		||||
    @removeAttr name
 | 
			
		||||
  _proxy 'setAttribute', (name, value)->
 | 
			
		||||
    @attr name, value
 | 
			
		||||
 | 
			
		||||
  removeChild = (node)->
 | 
			
		||||
    node._y_xml.remove()
 | 
			
		||||
  _proxy 'removeChild', removeChild
 | 
			
		||||
  replaceChild = (insertedNode, replacedNode)-> # TODO: handle replace with replace behavior...
 | 
			
		||||
    insertBefore.call this, insertedNode, replacedNode
 | 
			
		||||
    removeChild.call this, replacedNode
 | 
			
		||||
  _proxy 'replaceChild', replaceChild
 | 
			
		||||
 | 
			
		||||
if window?
 | 
			
		||||
  if window.Y?
 | 
			
		||||
    window.Y.Xml = YXml
 | 
			
		||||
  else
 | 
			
		||||
    throw new Error "You must first import Y!"
 | 
			
		||||
 | 
			
		||||
if module?
 | 
			
		||||
  module.exports = YXml
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -36,4 +36,4 @@ module.exports = createY
 | 
			
		||||
if window?
 | 
			
		||||
  window.Y = createY
 | 
			
		||||
 | 
			
		||||
createY.Object = require "./Types/Object"
 | 
			
		||||
createY.Object = require "./ObjectType"
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,6 @@
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "OT",
 | 
			
		||||
    "collaboration",
 | 
			
		||||
    "Yata",
 | 
			
		||||
    "synchronization",
 | 
			
		||||
    "ShareJS",
 | 
			
		||||
    "Coweb",
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ _         = require("underscore")
 | 
			
		||||
chai.use(sinonChai)
 | 
			
		||||
 | 
			
		||||
Connector = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
Y = null
 | 
			
		||||
Y = null # need global reference!
 | 
			
		||||
 | 
			
		||||
module.exports = class Test
 | 
			
		||||
  constructor: (@name_suffix = "", Yjs)->
 | 
			
		||||
@ -20,7 +20,7 @@ module.exports = class Test
 | 
			
		||||
    @time = 0 # denotes to the time when run was started
 | 
			
		||||
    @ops = 0 # number of operations (used with @time)
 | 
			
		||||
    @time_now = 0 # current time
 | 
			
		||||
    @max_depth = 4
 | 
			
		||||
    @max_depth = 3
 | 
			
		||||
 | 
			
		||||
    @debug = false
 | 
			
		||||
 | 
			
		||||
@ -79,22 +79,7 @@ module.exports = class Test
 | 
			
		||||
 | 
			
		||||
  getGeneratingFunctions: (user_num)=>
 | 
			
		||||
    types = @users[user_num]._model.operations
 | 
			
		||||
    [
 | 
			
		||||
        f : (y)=> # INSERT TEXT
 | 
			
		||||
          y
 | 
			
		||||
          pos = _.random 0, (y.val().length-1)
 | 
			
		||||
          y.insert pos, @getRandomText()
 | 
			
		||||
          null
 | 
			
		||||
        types: [Y.Text]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # DELETE TEXT
 | 
			
		||||
          if y.val().length > 0
 | 
			
		||||
            pos = _.random 0, (y.val().length-1) # TODO: put here also arbitrary number (test behaviour in error cases)
 | 
			
		||||
            length = _.random 0, (y.val().length - pos)
 | 
			
		||||
            ops1 = y.delete pos, length
 | 
			
		||||
          undefined
 | 
			
		||||
        types : [Y.Text]
 | 
			
		||||
    ]
 | 
			
		||||
    []
 | 
			
		||||
  getRandomRoot: (user_num)->
 | 
			
		||||
    throw new Error "implement me!"
 | 
			
		||||
 | 
			
		||||
@ -103,11 +88,14 @@ module.exports = class Test
 | 
			
		||||
      true
 | 
			
		||||
    else if o1._name? and o1._name isnt o2._name
 | 
			
		||||
      throw new Error "different types"
 | 
			
		||||
    else if o1._name is "Object" or o1.type is "MapManager"
 | 
			
		||||
    else if o1._model?
 | 
			
		||||
      @compare o1._model, o2._model, depth
 | 
			
		||||
    else if o1.type is "MapManager"
 | 
			
		||||
      for name, val of o1.val()
 | 
			
		||||
        @compare(val, o2.val(name), depth-1)
 | 
			
		||||
    else if o1._name?
 | 
			
		||||
      @compare(o1.val(), o2.val(), depth-1)
 | 
			
		||||
    else if o1.type is "ListManager"
 | 
			
		||||
      for val,i in o1.val()
 | 
			
		||||
        @compare(val, o2.val(i), depth-1)
 | 
			
		||||
    else if o1.constructor is Array and o2.constructor is Array
 | 
			
		||||
      if o1.length isnt o2.length
 | 
			
		||||
        throw new Error "The Arrays do not have the same size!"
 | 
			
		||||
 | 
			
		||||
@ -1,171 +0,0 @@
 | 
			
		||||
chai      = require('chai')
 | 
			
		||||
expect    = chai.expect
 | 
			
		||||
should    = chai.should()
 | 
			
		||||
sinon     = require('sinon')
 | 
			
		||||
sinonChai = require('sinon-chai')
 | 
			
		||||
_         = require("underscore")
 | 
			
		||||
 | 
			
		||||
chai.use(sinonChai)
 | 
			
		||||
 | 
			
		||||
Y = require "../lib/y"
 | 
			
		||||
Y.Text = require "../lib/Types/Text"
 | 
			
		||||
 | 
			
		||||
Connector = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
 | 
			
		||||
Test = require "./TestSuite"
 | 
			
		||||
class TextTest extends Test
 | 
			
		||||
 | 
			
		||||
  constructor: (suffix)->
 | 
			
		||||
    super suffix, Y
 | 
			
		||||
 | 
			
		||||
  type: "TextTest"
 | 
			
		||||
 | 
			
		||||
  makeNewUser: (userId)->
 | 
			
		||||
    conn = new Connector userId
 | 
			
		||||
    new Y conn
 | 
			
		||||
 | 
			
		||||
  initUsers: (u)->
 | 
			
		||||
    u.val("TextTest",new Y.Text())
 | 
			
		||||
 | 
			
		||||
  getRandomRoot: (user_num)->
 | 
			
		||||
    @users[user_num].val("TextTest")
 | 
			
		||||
 | 
			
		||||
  getContent: (user_num)->
 | 
			
		||||
    @users[user_num].val("TextTest").val()
 | 
			
		||||
 | 
			
		||||
describe "TextFramework", ->
 | 
			
		||||
  @timeout 500000
 | 
			
		||||
 | 
			
		||||
  beforeEach (done)->
 | 
			
		||||
    @yTest = new TextTest()
 | 
			
		||||
    done()
 | 
			
		||||
 | 
			
		||||
  it "simple multi-char insert", ->
 | 
			
		||||
    u = @yTest.users[0].val("TextTest")
 | 
			
		||||
    u.insert 0, "abc"
 | 
			
		||||
    u = @yTest.users[1].val("TextTest")
 | 
			
		||||
    u.insert 0, "xyz"
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
    u.delete 0, 1
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
    expect(u.val()).to.equal("bcxyz")
 | 
			
		||||
 | 
			
		||||
  it "Observers work on shared Text (insert type observers, local and foreign)", ->
 | 
			
		||||
    u = @yTest.users[0].val("TextTest",new Y.Text("my awesome Text")).val("TextTest")
 | 
			
		||||
    @yTest.flushAll()
 | 
			
		||||
    last_task = null
 | 
			
		||||
    observer1 = (changes)->
 | 
			
		||||
      expect(changes.length).to.equal(1)
 | 
			
		||||
      change = changes[0]
 | 
			
		||||
      expect(change.type).to.equal("insert")
 | 
			
		||||
      expect(change.object).to.equal(u)
 | 
			
		||||
      expect(change.value).to.equal("a")
 | 
			
		||||
      expect(change.position).to.equal(1)
 | 
			
		||||
      expect(change.changedBy).to.equal('0')
 | 
			
		||||
      last_task = "observer1"
 | 
			
		||||
    u.observe observer1
 | 
			
		||||
    u.insert 1, "a"
 | 
			
		||||
    expect(last_task).to.equal("observer1")
 | 
			
		||||
    u.unobserve observer1
 | 
			
		||||
 | 
			
		||||
    observer2 = (changes)->
 | 
			
		||||
      expect(changes.length).to.equal(1)
 | 
			
		||||
      change = changes[0]
 | 
			
		||||
      expect(change.type).to.equal("insert")
 | 
			
		||||
      expect(change.object).to.equal(u)
 | 
			
		||||
      expect(change.value).to.equal("x")
 | 
			
		||||
      expect(change.position).to.equal(0)
 | 
			
		||||
      expect(change.changedBy).to.equal('1')
 | 
			
		||||
      last_task = "observer2"
 | 
			
		||||
    u.observe observer2
 | 
			
		||||
    v = @yTest.users[1].val("TextTest")
 | 
			
		||||
    v.insert 0, "x"
 | 
			
		||||
    @yTest.flushAll()
 | 
			
		||||
    expect(last_task).to.equal("observer2")
 | 
			
		||||
    u.unobserve observer2
 | 
			
		||||
 | 
			
		||||
  it "Observers work on shared Text (delete type observers, local and foreign)", ->
 | 
			
		||||
    u = @yTest.users[0].val("TextTest",new Y.Text("my awesome Text")).val("TextTest")
 | 
			
		||||
    @yTest.flushAll()
 | 
			
		||||
    last_task = null
 | 
			
		||||
    observer1 = (changes)->
 | 
			
		||||
      expect(changes.length).to.equal(1)
 | 
			
		||||
      change = changes[0]
 | 
			
		||||
      expect(change.type).to.equal("delete")
 | 
			
		||||
      expect(change.object).to.equal(u)
 | 
			
		||||
      expect(change.position).to.equal(1)
 | 
			
		||||
      expect(change.length).to.equal(1)
 | 
			
		||||
      expect(change.changedBy).to.equal('0')
 | 
			
		||||
      last_task = "observer1"
 | 
			
		||||
    u.observe observer1
 | 
			
		||||
    u.delete 1, 1
 | 
			
		||||
    expect(last_task).to.equal("observer1")
 | 
			
		||||
    u.unobserve observer1
 | 
			
		||||
 | 
			
		||||
    observer2 = (changes)->
 | 
			
		||||
      expect(changes.length).to.equal(1)
 | 
			
		||||
      change = changes[0]
 | 
			
		||||
      expect(change.type).to.equal("delete")
 | 
			
		||||
      expect(change.object).to.equal(u)
 | 
			
		||||
      expect(change.position).to.equal(0)
 | 
			
		||||
      expect(change.length).to.equal(1)
 | 
			
		||||
      expect(change.changedBy).to.equal('1')
 | 
			
		||||
      last_task = "observer2"
 | 
			
		||||
    u.observe observer2
 | 
			
		||||
    v = @yTest.users[1].val("TextTest")
 | 
			
		||||
    v.delete 0, 1
 | 
			
		||||
    @yTest.flushAll()
 | 
			
		||||
    expect(last_task).to.equal("observer2")
 | 
			
		||||
    u.unobserve observer2
 | 
			
		||||
 | 
			
		||||
  it "can handle many engines, many operations, concurrently (random)", ->
 | 
			
		||||
    console.log("testiy deleted this TODO:dtrn")
 | 
			
		||||
    @yTest.run()
 | 
			
		||||
 | 
			
		||||
  it "handles double-late-join", ->
 | 
			
		||||
    test = new TextTest("double")
 | 
			
		||||
    test.run()
 | 
			
		||||
    @yTest.run()
 | 
			
		||||
    u1 = test.users[0]
 | 
			
		||||
    u2 = @yTest.users[1]
 | 
			
		||||
    ops1 = u1._model.HB._encode()
 | 
			
		||||
    ops2 = u2._model.HB._encode()
 | 
			
		||||
    u1._model.engine.applyOp ops2, true
 | 
			
		||||
    u2._model.engine.applyOp ops1, true
 | 
			
		||||
    compare = (o1, o2)->
 | 
			
		||||
      if o1._name? and o1._name isnt o2._name
 | 
			
		||||
        throw new Error "different types"
 | 
			
		||||
      else if o1._name is "Object"
 | 
			
		||||
        for name, val of o1.val()
 | 
			
		||||
          compare(val, o2.val(name))
 | 
			
		||||
      else if o1._name?
 | 
			
		||||
        compare(o1.val(), o2.val())
 | 
			
		||||
      else if o1 isnt o2
 | 
			
		||||
        throw new Error "different values"
 | 
			
		||||
    compare u1, u2
 | 
			
		||||
    expect(test.getContent(0)).to.deep.equal(@yTest.getContent(1))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,479 +0,0 @@
 | 
			
		||||
chai      = require('chai')
 | 
			
		||||
expect    = chai.expect
 | 
			
		||||
should    = chai.should()
 | 
			
		||||
sinon     = require('sinon')
 | 
			
		||||
sinonChai = require('sinon-chai')
 | 
			
		||||
_         = require("underscore")
 | 
			
		||||
$         = require('jquery')
 | 
			
		||||
 | 
			
		||||
chai.use(sinonChai)
 | 
			
		||||
 | 
			
		||||
Y = require "../lib/y.coffee"
 | 
			
		||||
Y.Test = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
 | 
			
		||||
Y.List = require "../lib/Types/List"
 | 
			
		||||
Y.Xml = require "../lib/Types/Xml"
 | 
			
		||||
Y.Text = require "../lib/Types/Text"
 | 
			
		||||
 | 
			
		||||
Test = require "./TestSuite"
 | 
			
		||||
 | 
			
		||||
class XmlTest extends Test
 | 
			
		||||
 | 
			
		||||
  constructor: (suffix)->
 | 
			
		||||
    super suffix, Y
 | 
			
		||||
    @doSomething_amount *= 20
 | 
			
		||||
 | 
			
		||||
  makeNewUser: (userId)->
 | 
			
		||||
    conn = new Y.Test userId
 | 
			
		||||
    super new Y conn
 | 
			
		||||
 | 
			
		||||
  initUsers: (u)->
 | 
			
		||||
    u.val("xml",new Y.Xml("div"))
 | 
			
		||||
 | 
			
		||||
  type: "XmlTest"
 | 
			
		||||
 | 
			
		||||
  compare: (o1, o2, depth)->
 | 
			
		||||
    if o1.constructor is Y.Xml
 | 
			
		||||
      super o1._model, o2._model, depth
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
 | 
			
		||||
  getRandomRoot: (user_num, root, depth = @max_depth)->
 | 
			
		||||
    root ?= @users[user_num].val("xml")
 | 
			
		||||
    if depth is 0 or _.random(0,1) is 1 # take root
 | 
			
		||||
      root
 | 
			
		||||
    else # take child
 | 
			
		||||
      elems = null
 | 
			
		||||
      if root._name is "Xml"
 | 
			
		||||
        elems = root.getChildren()
 | 
			
		||||
      else
 | 
			
		||||
        return root
 | 
			
		||||
 | 
			
		||||
      elems = elems.filter (elem)->
 | 
			
		||||
        elem._name is "Xml"
 | 
			
		||||
      if elems.length is 0
 | 
			
		||||
        root
 | 
			
		||||
      else
 | 
			
		||||
        p = elems[_.random(0, elems.length-1)]
 | 
			
		||||
        @getRandomRoot user_num, p, depth--
 | 
			
		||||
 | 
			
		||||
  getRandomXmlElement: ()->
 | 
			
		||||
    if _.random(0,1) is 0
 | 
			
		||||
      new Y.Xml(@getRandomKey())
 | 
			
		||||
    else
 | 
			
		||||
      @getRandomText()
 | 
			
		||||
 | 
			
		||||
  getGeneratingFunctions: (user_num)->
 | 
			
		||||
    that = @
 | 
			
		||||
    super(user_num).concat [
 | 
			
		||||
        f : (y)=> # set Attribute
 | 
			
		||||
          y.attr(that.getRandomKey(), that.getRandomText())
 | 
			
		||||
        types: [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # DELETE Attribute
 | 
			
		||||
          keys = Object.keys(y.attr())
 | 
			
		||||
          y.removeAttr(keys[_.random(0,keys.length-1)])
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # Add Class
 | 
			
		||||
          y.addClass(that.getRandomKey())
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # toggleClass
 | 
			
		||||
          y.toggleClass(that.getRandomKey())
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # Remove Class
 | 
			
		||||
          keys = y.attr("class").split(" ")
 | 
			
		||||
          y.removeClass(keys[_.random(0,keys.length-1)])
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # append XML
 | 
			
		||||
          child = that.getRandomXmlElement()
 | 
			
		||||
          y.append(child)
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # pepend XML
 | 
			
		||||
          child = that.getRandomXmlElement()
 | 
			
		||||
          y.prepend child
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # after XML
 | 
			
		||||
          if y.getParent()?
 | 
			
		||||
            child = that.getRandomXmlElement()
 | 
			
		||||
            y.after child
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # before XML
 | 
			
		||||
          if y.getParent()?
 | 
			
		||||
            child = that.getRandomXmlElement()
 | 
			
		||||
            y.before child
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # empty
 | 
			
		||||
          y.empty()
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # remove
 | 
			
		||||
          if y.getParent()?
 | 
			
		||||
            y.remove()
 | 
			
		||||
        types : [Y.Xml]
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
describe "Y-Xml", ->
 | 
			
		||||
  @timeout 500000
 | 
			
		||||
 | 
			
		||||
  beforeEach (done)->
 | 
			
		||||
    @yTest = new XmlTest()
 | 
			
		||||
    @users = @yTest.users
 | 
			
		||||
 | 
			
		||||
    @u1 = @users[1].val("xml")
 | 
			
		||||
    @u2 = @users[2].val("xml")
 | 
			
		||||
    @u3 = @users[3].val("xml")
 | 
			
		||||
    done()
 | 
			
		||||
 | 
			
		||||
  it "can handle many engines, many operations, concurrently (random)", ->
 | 
			
		||||
    console.log "" # TODO
 | 
			
		||||
    @yTest.run()
 | 
			
		||||
    console.log(@yTest.users[0].val("xml")+"")
 | 
			
		||||
 | 
			
		||||
  it "has a working test suite", ->
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
  it "handles double-late-join", ->
 | 
			
		||||
    test = new XmlTest("double")
 | 
			
		||||
    test.run()
 | 
			
		||||
    @yTest.run()
 | 
			
		||||
    u1 = test.users[0]
 | 
			
		||||
    u2 = @yTest.users[1]
 | 
			
		||||
    ops1 = u1._model.HB._encode()
 | 
			
		||||
    ops2 = u2._model.HB._encode()
 | 
			
		||||
    u1._model.engine.applyOp ops2, true
 | 
			
		||||
    u2._model.engine.applyOp ops1, true
 | 
			
		||||
 | 
			
		||||
  it "Create Xml Element", ->
 | 
			
		||||
    @u1.attr("stuff", "true")
 | 
			
		||||
    console.log(@u1.toString())
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
  describe "has method ", ->
 | 
			
		||||
    it "attr", ->
 | 
			
		||||
      @u1.attr("attr", "newAttr")
 | 
			
		||||
      @u1.attr("other_attr", "newAttr")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u2.attr("attr")).to.equal("newAttr")
 | 
			
		||||
      expect(@u2.attr().other_attr).to.equal("newAttr")
 | 
			
		||||
 | 
			
		||||
    it "addClass", ->
 | 
			
		||||
      @u1.addClass("newClass")
 | 
			
		||||
      @u2.addClass("otherClass")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u1.attr("class")).to.equal("newClass otherClass") # 1 < 2 and therefore this is the proper order
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    it "append", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      child2 = new Y.Xml("child2")
 | 
			
		||||
      @u1.append child
 | 
			
		||||
      @u1.append child2
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
    it "prepend", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      child2 = new Y.Xml("child2")
 | 
			
		||||
      @u1.prepend child2
 | 
			
		||||
      @u1.prepend child
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
    it "after", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      @u1.append child
 | 
			
		||||
      child.after new Y.Xml("right-child")
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><child></child><right-child></right-child></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
    it "before", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      @u1.append child
 | 
			
		||||
      child.before new Y.Xml("left-child")
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
    it "empty", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      @u1.append child
 | 
			
		||||
      child.before new Y.Xml("left-child")
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      @u1.empty()
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
    it "remove", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      child2 = new Y.Xml("child2")
 | 
			
		||||
      @u1.prepend child2
 | 
			
		||||
      @u1.prepend child
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      child2.remove()
 | 
			
		||||
      expect(@u1.toString()).to.equal("<div><child></child></div>")
 | 
			
		||||
 | 
			
		||||
    it "removeAttr", ->
 | 
			
		||||
      @u1.attr("dtrn", "stuff")
 | 
			
		||||
      @u1.attr("dutrianern", "stuff")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      @u2.removeAttr("dtrn")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u3.attr("dtrn")).to.be.undefined
 | 
			
		||||
 | 
			
		||||
    it "removeClass", ->
 | 
			
		||||
      @u1.addClass("dtrn")
 | 
			
		||||
      @u1.addClass("iExist")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      @u2.removeClass("dtrn")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u3.attr("class")).to.equal("iExist")
 | 
			
		||||
 | 
			
		||||
    it "toggleClass", ->
 | 
			
		||||
      @u1.addClass("dtrn")
 | 
			
		||||
      @u1.addClass("iExist")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      @u2.removeClass("dtrn")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u3.attr("class")).to.equal("iExist")
 | 
			
		||||
      @u3.toggleClass("iExist")
 | 
			
		||||
      @u3.toggleClass("wraa")
 | 
			
		||||
      @yTest.compareAll()
 | 
			
		||||
      expect(@u1.attr("class")).to.equal("wraa")
 | 
			
		||||
 | 
			
		||||
    it "getParent", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      @u1.prepend(child)
 | 
			
		||||
      expect(@u1).to.equal(child.getParent())
 | 
			
		||||
 | 
			
		||||
    it "getChildren", ->
 | 
			
		||||
      child = new Y.Xml("child")
 | 
			
		||||
      @u1.prepend(child)
 | 
			
		||||
      expect(@u1.getChildren()[0]).to.equal(child)
 | 
			
		||||
 | 
			
		||||
  if not window?
 | 
			
		||||
    describe "skip DOM tests (only in browser environment)", ->
 | 
			
		||||
      it "", ->
 | 
			
		||||
  else
 | 
			
		||||
    describe "DOM binding ", ->
 | 
			
		||||
      beforeEach (done)->
 | 
			
		||||
        @dom = @u1.getDom()
 | 
			
		||||
        @j = $(@dom)
 | 
			
		||||
        done()
 | 
			
		||||
 | 
			
		||||
      it "can transform to a new real Dom element", ->
 | 
			
		||||
        expect(@dom).to.not.be.undefined
 | 
			
		||||
 | 
			
		||||
      it "supports dom.insertBefore", ->
 | 
			
		||||
        newdom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        newdom2 = $("<p>dtrn2</p>")[0]
 | 
			
		||||
        @dom.insertBefore(newdom2, null)
 | 
			
		||||
        @dom.insertBefore(newdom, newdom2)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p><p>dtrn2</p></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>dtrn</p><p>dtrn2</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports dom.appendChild", ->
 | 
			
		||||
        newdom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        @dom.appendChild(newdom)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports dom.setAttribute", ->
 | 
			
		||||
        @dom.setAttribute("test_attribute", "newVal")
 | 
			
		||||
        expect(@u1.attr("test_attribute")).to.equal("newVal")
 | 
			
		||||
        expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
 | 
			
		||||
 | 
			
		||||
      it "supports dom.removeAttribute", ->
 | 
			
		||||
        @dom.setAttribute("test_attribute", "newVal")
 | 
			
		||||
        expect(@u1.attr("test_attribute")).to.equal("newVal")
 | 
			
		||||
        expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
 | 
			
		||||
        @dom.removeAttribute("test_attribute")
 | 
			
		||||
        expect(@u1.attr("test_attribute")).to.be.undefined
 | 
			
		||||
        attr = @dom.getAttribute("test_attribute")
 | 
			
		||||
        expect(attr?).to.be.false
 | 
			
		||||
 | 
			
		||||
      it "supports dom.removeChild", ->
 | 
			
		||||
        newdom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        @dom.appendChild(newdom)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
 | 
			
		||||
        @dom.removeChild(newdom)
 | 
			
		||||
        expect(@dom.childNodes.length).to.equal(0)
 | 
			
		||||
        expect(@u1.getChildren().length).to.equal(0)
 | 
			
		||||
 | 
			
		||||
      it "supports dom.replaceChild", ->
 | 
			
		||||
        dom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        @dom.appendChild(dom)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
 | 
			
		||||
        newdom = $("<p>replaced</p>")[0]
 | 
			
		||||
        @dom.replaceChild(newdom, dom)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>replaced</p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>replaced</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports dom.classList.add", ->
 | 
			
		||||
        @dom.classList.add "classy"
 | 
			
		||||
        @dom.classList.add "moreclassy"
 | 
			
		||||
        expect(@u1.attr("class")).to.equal("classy moreclassy")
 | 
			
		||||
        expect(@dom.getAttribute("class")).to.equal("classy moreclassy")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      it "supports dom.textContent", ->
 | 
			
		||||
        dom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        @dom.appendChild(dom)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
 | 
			
		||||
        @dom.textContent = ""
 | 
			
		||||
        expect(@u1+"").to.equal("<div></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div></div>")
 | 
			
		||||
 | 
			
		||||
      it "suppports dom.textContent (non empty string)", ->
 | 
			
		||||
        dom = $("<p>dtrn</p>")[0]
 | 
			
		||||
        @dom.appendChild(dom)
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
 | 
			
		||||
 | 
			
		||||
        @dom.textContent = "stuff"
 | 
			
		||||
        expect(@u1+"").to.equal("<div>stuff</div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div>stuff</div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.addClass", ->
 | 
			
		||||
        @j.addClass("testedy tested")
 | 
			
		||||
        expect(@dom.getAttribute("class")).to.equal("testedy tested")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.after", ->
 | 
			
		||||
        d = $("<span></span>")
 | 
			
		||||
        @dom.appendChild(d[0], null)
 | 
			
		||||
        d.after("<div>after</div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><span></span><div>after</div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><span></span><div>after</div></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.append", ->
 | 
			
		||||
        d = $("<span></span>")[0]
 | 
			
		||||
        @j.append(d)
 | 
			
		||||
        d = $("<div></div>")[0]
 | 
			
		||||
        @j.append(d)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><span></span><div></div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><span></span><div></div></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.appendTo", ->
 | 
			
		||||
        $("<b>appendedTo</b>").appendTo(@dom)
 | 
			
		||||
        $("<p>").appendTo(@dom)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><b>appendedTo</b><p></p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><b>appendedTo</b><p></p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.before", ->
 | 
			
		||||
        newdom = $("<p>")
 | 
			
		||||
        $(@dom).append(newdom)
 | 
			
		||||
        newdom.before("<div>before</div>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><div>before</div><p></p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><div>before</div><p></p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.detach", ->
 | 
			
		||||
        d = $("<p>")
 | 
			
		||||
        @j.append(d)
 | 
			
		||||
        d.detach()
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.empty", ->
 | 
			
		||||
        d = $("<p />")
 | 
			
		||||
        d.appendTo(@dom)
 | 
			
		||||
        d = $("<div />")
 | 
			
		||||
        d.appendTo(@dom)
 | 
			
		||||
        @j.empty()
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.insertAfter", ->
 | 
			
		||||
        d = $("<span>")
 | 
			
		||||
        d.appendTo(@dom)
 | 
			
		||||
        $("<p>after</p>").insertAfter(d)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><span></span><p>after</p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><span></span><p>after</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.insertBefore", ->
 | 
			
		||||
        d = $("<span>")
 | 
			
		||||
        d.appendTo(@j)
 | 
			
		||||
        $("<p>before</p>").insertBefore(d)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>before</p><span></span></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>before</p><span></span></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.prepend", ->
 | 
			
		||||
        @j.prepend("<p>prepended2</p>")
 | 
			
		||||
        @j.prepend("<p>prepended1</p>")
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.prependTo", ->
 | 
			
		||||
        $("<p>prepended2</p>").prependTo(@j)
 | 
			
		||||
        $("<p>prepended1</p>").prependTo(@j)
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.remove", ->
 | 
			
		||||
        d = $("<div />")
 | 
			
		||||
        d.prependTo(@j)
 | 
			
		||||
        d.remove()
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.removeAttr", ->
 | 
			
		||||
        @dom.setAttribute("test_attribute", "newVal")
 | 
			
		||||
        expect(@u1.attr("test_attribute")).to.equal("newVal")
 | 
			
		||||
        expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
 | 
			
		||||
 | 
			
		||||
        @j.removeAttr("test_attribute")
 | 
			
		||||
        expect(@u1.attr("test_attribute")).to.be.undefined
 | 
			
		||||
        expect(@j.attr("test_attribute")).to.be.undefined
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.removeClass", ->
 | 
			
		||||
        @j.addClass("testedy tested")
 | 
			
		||||
        expect(@dom.getAttribute("class")).to.equal("testedy tested")
 | 
			
		||||
 | 
			
		||||
        @j.removeClass("testedy")
 | 
			
		||||
        expect(@dom.getAttribute("class")).to.equal("tested")
 | 
			
		||||
        expect(@u1.hasClass("testedy")).to.be.false
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.attr", ->
 | 
			
		||||
        @j.attr("atone", "yeah")
 | 
			
		||||
        expect(@u1.attr("atone")).to.equal("yeah")
 | 
			
		||||
        expect(@j.attr("atone")).to.equal("yeah")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.replaceAll", ->
 | 
			
		||||
        d = $("<p />")
 | 
			
		||||
        d.appendTo(@dom)
 | 
			
		||||
        d = $("<p />")
 | 
			
		||||
        d.appendTo(@dom)
 | 
			
		||||
        $("<span>").replaceAll($(@dom).find("p"))
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><span></span><span></span></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><span></span><span></span></div>")
 | 
			
		||||
 | 
			
		||||
      it "supports jquery.replaceWith", ->
 | 
			
		||||
        d = $("<span>")
 | 
			
		||||
        @j.prepend(d)
 | 
			
		||||
        d = $("<span>")
 | 
			
		||||
        @j.prepend(d)
 | 
			
		||||
        d = $("<span>")
 | 
			
		||||
        @j.prepend(d)
 | 
			
		||||
        d = @j.find("span")
 | 
			
		||||
        d.replaceWith("<div></div>")
 | 
			
		||||
 | 
			
		||||
        expect(@dom.outerHTML).to.equal("<div><div></div><div></div><div></div></div>")
 | 
			
		||||
        expect(@u1+"").to.equal("<div><div></div><div></div><div></div></div>")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,196 +0,0 @@
 | 
			
		||||
chai      = require('chai')
 | 
			
		||||
expect    = chai.expect
 | 
			
		||||
should    = chai.should()
 | 
			
		||||
sinon     = require('sinon')
 | 
			
		||||
sinonChai = require('sinon-chai')
 | 
			
		||||
_         = require("underscore")
 | 
			
		||||
$         = require("jquery")
 | 
			
		||||
document?.$ = $ # for browser
 | 
			
		||||
require 'coffee-errors'
 | 
			
		||||
 | 
			
		||||
chai.use(sinonChai)
 | 
			
		||||
 | 
			
		||||
Y = require "../lib/index"
 | 
			
		||||
Connector = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
 | 
			
		||||
Test = require "./TestSuite"
 | 
			
		||||
class XmlTest extends Test
 | 
			
		||||
 | 
			
		||||
  type: "XmlTest"
 | 
			
		||||
 | 
			
		||||
  makeNewUser: (user, conn)->
 | 
			
		||||
    super new Y.XmlFramework user, conn
 | 
			
		||||
 | 
			
		||||
  getRandomRoot: (user_num)->
 | 
			
		||||
    @users[user_num].getSharedObject()
 | 
			
		||||
 | 
			
		||||
  getContent: (user_num)->
 | 
			
		||||
    @users[user_num].val()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
describe "XmlFramework", ->
 | 
			
		||||
  beforeEach (done)->
 | 
			
		||||
    @timeout 50000
 | 
			
		||||
    @yTest = new XmlTest()
 | 
			
		||||
    ###
 | 
			
		||||
 | 
			
		||||
    @users = @yTest.users
 | 
			
		||||
    ###
 | 
			
		||||
    test_users = []
 | 
			
		||||
    connector = (new Connector 0, test_users)
 | 
			
		||||
    @test_user = @yTest.makeNewUser 0, connector
 | 
			
		||||
    test_users.push @test_user
 | 
			
		||||
    # test_user_listen listens to the actions of test_user. He will update his dom when he receives from test_user.
 | 
			
		||||
    @test_user_listen = @yTest.makeNewUser 2, connector
 | 
			
		||||
    test_users.push @test_user_listen
 | 
			
		||||
    @test_user2 = @yTest.makeNewUser 1, (Connector_uninitialized [])
 | 
			
		||||
 | 
			
		||||
    $("#test_dom").replaceWith('<div id="test_dom" test_attribute="the test" class="stuffy" style="color: blue"><p id="replaceme">replace me</p><p id="removeme">remove me</p><p>This is a test object for <b>XmlFramework</b></p><span class="span_element"><p>span</p></span></div>')
 | 
			
		||||
    @$dom = $("#test_dom")
 | 
			
		||||
    @dom = @$dom[0]
 | 
			
		||||
    @test_user.val(@dom)
 | 
			
		||||
    @test_user_listen.getConnector().flushAll()
 | 
			
		||||
    @test_user_listen_dom = @test_user_listen.val()
 | 
			
		||||
 | 
			
		||||
    @check = ()=>
 | 
			
		||||
      dom_ = @dom.outerHTML
 | 
			
		||||
      # now test if other collaborators can parse the HB and result in the same content
 | 
			
		||||
      hb = @test_user.HB._encode()
 | 
			
		||||
      @test_user2.engine.applyOps(hb)
 | 
			
		||||
      dom2 = @test_user2.val()
 | 
			
		||||
      expect(dom_).to.equal(dom2.outerHTML)
 | 
			
		||||
      @test_user_listen.getConnector().flushAll()
 | 
			
		||||
      expect(dom_).to.equal(@test_user_listen_dom.outerHTML)
 | 
			
		||||
    done()
 | 
			
		||||
 | 
			
		||||
  it "can transform to a new real Dom element", ->
 | 
			
		||||
    dom_ = @test_user.val(true)
 | 
			
		||||
    expect(dom_ isnt @dom).to.be.true
 | 
			
		||||
 | 
			
		||||
  it "supports dom.insertBefore", ->
 | 
			
		||||
    newdom = $("<p>dtrn</p>")[0]
 | 
			
		||||
    newdom2 = $("<p>dtrn2</p>")[0]
 | 
			
		||||
    n = $("#removeme")[0]
 | 
			
		||||
    @dom.insertBefore(newdom, null)
 | 
			
		||||
    @dom.insertBefore(newdom2, n)
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.appendChild", ->
 | 
			
		||||
    newdom = $("<p>dtrn</p>")[0]
 | 
			
		||||
    @dom.appendChild(newdom)
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.setAttribute", ->
 | 
			
		||||
    @dom.setAttribute("test_attribute", "newVal")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.removeAttribute", ->
 | 
			
		||||
    @dom.removeAttribute("test_attribute")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.removeChild", ->
 | 
			
		||||
    @dom.removeChild($("#removeme")[0])
 | 
			
		||||
    expect($("#removeme").length).to.equal(0)
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.replaceChild", ->
 | 
			
		||||
    newdom = $("<p>replaced</p>")[0]
 | 
			
		||||
    replace = $("#replaceme")[0]
 | 
			
		||||
    @dom.replaceChild(newdom,replace)
 | 
			
		||||
    expect($("#replaceme").length).to.equal(0)
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports dom.classList.add", ->
 | 
			
		||||
    @dom.classList.add "classy"
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  it "supports dom.textcontent", -> #TODO!!!!
 | 
			
		||||
    @dom.classList.add "classy"
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.addClass", ->
 | 
			
		||||
    @$dom.addClass("testy")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.after", ->
 | 
			
		||||
    d = $("#test_dom p")
 | 
			
		||||
    d.after("<div class=\"inserted_after\">after</div>")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.append", ->
 | 
			
		||||
    d = $("#test_dom p")
 | 
			
		||||
    d.after("<b>appended</b>")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.appendTo", ->
 | 
			
		||||
    $("<b>appendedTo</b>").appendTo("#test_dom p")
 | 
			
		||||
    $("p").appendTo("#test_dom")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.before", ->
 | 
			
		||||
    d = $("#test_dom p")
 | 
			
		||||
    d.before("<div>before</div>")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.detach", ->
 | 
			
		||||
    d = $(".inserted_after")
 | 
			
		||||
    d.detach()
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.empty", ->
 | 
			
		||||
    d = $("#test_dom p")
 | 
			
		||||
    d.empty()
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.insertAfter", ->
 | 
			
		||||
    $("<p>after span</p>").insertAfter(".span_element")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.insertBefore", ->
 | 
			
		||||
    $("<p>before span</p>").insertBefore(".span_element")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.prepend", ->
 | 
			
		||||
    d = $("#test_dom div")
 | 
			
		||||
    d.prepend("<p>prepended</p>")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.prependTo", ->
 | 
			
		||||
    $("<p atone=false attwo=\"dtrn\" class=\"attr_node sudo su\">prepended to</p>").prependTo("#test_dom div")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.remove", ->
 | 
			
		||||
    d = $("#test_dom b")
 | 
			
		||||
    d.remove()
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.removeAttr", ->
 | 
			
		||||
    d = $(".attr_node")
 | 
			
		||||
    d.removeAttr("attwo")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.removeClass", ->
 | 
			
		||||
    d = $(".attr_node")
 | 
			
		||||
    d.removeClass("sudo")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.attr", ->
 | 
			
		||||
    d = $(".attr_node")
 | 
			
		||||
    d.attr("atone", true)
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.replaceAll", ->
 | 
			
		||||
    $("<span>New span content </span>").replaceAll("#test_dom div")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
  it "supports jquery.replaceWith", ->
 | 
			
		||||
    d = $("#test_dom span")
 | 
			
		||||
    d.replaceWith("<div>me is div again </div>")
 | 
			
		||||
    @check()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,12 +9,11 @@ chai.use(sinonChai)
 | 
			
		||||
 | 
			
		||||
Y = require "../lib/y.coffee"
 | 
			
		||||
Y.Test = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
Y.Text = require "../lib/Types/Text"
 | 
			
		||||
Y.List = require "../lib/Types/List"
 | 
			
		||||
Y.Text = require "../../y-text/lib/y-text"
 | 
			
		||||
Y.List = require "../../y-list/lib/y-list"
 | 
			
		||||
 | 
			
		||||
Test = require "./TestSuite"
 | 
			
		||||
 | 
			
		||||
class JsonTest extends Test
 | 
			
		||||
TestSuite = require "./TestSuite"
 | 
			
		||||
class ObjectTest extends TestSuite
 | 
			
		||||
 | 
			
		||||
  constructor: (suffix)->
 | 
			
		||||
    super suffix, Y
 | 
			
		||||
@ -23,7 +22,7 @@ class JsonTest extends Test
 | 
			
		||||
    conn = new Y.Test userId
 | 
			
		||||
    super new Y conn
 | 
			
		||||
 | 
			
		||||
  type: "JsonTest"
 | 
			
		||||
  type: "ObjectTest"
 | 
			
		||||
 | 
			
		||||
  getRandomRoot: (user_num, root, depth = @max_depth)->
 | 
			
		||||
    root ?= @users[user_num]
 | 
			
		||||
@ -67,11 +66,9 @@ class JsonTest extends Test
 | 
			
		||||
          y.val(@getRandomKey(), new Y.Text(@getRandomText()))
 | 
			
		||||
        types: [Y.Object]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # SET PROPERTY (primitive)
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.val(_.random(0, l-1), @getRandomText())
 | 
			
		||||
          null
 | 
			
		||||
        types : [Y.List]
 | 
			
		||||
        f : (y)=> # SET PROPERTY List
 | 
			
		||||
          y.val(@getRandomKey(), new Y.List(@getRandomText().split("")))
 | 
			
		||||
        types: [Y.Object]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # Delete Array Element
 | 
			
		||||
          list = y.val()
 | 
			
		||||
@ -82,17 +79,22 @@ class JsonTest extends Test
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # insert Object mutable
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.val(_.random(0, l-1), new Y.Object(@getRamdomObject()))
 | 
			
		||||
          y.insert(_.random(0, l-1), new Y.Object(@getRandomObject()))
 | 
			
		||||
        types: [Y.List]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # insert Text mutable
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.val(_.random(0, l-1), new Y.Text(@getRandomText()))
 | 
			
		||||
          y.insert(_.random(0, l-1), new Y.Text(@getRandomText()))
 | 
			
		||||
        types : [Y.List]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # insert List mutable
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.insert(_.random(0, l-1), new Y.List(@getRandomText().split("")))
 | 
			
		||||
        types : [Y.List]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # insert Number (primitive object)
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.val(_.random(0,l-1), _.random(0,42))
 | 
			
		||||
          y.insert(_.random(0,l-1), _.random(0,42))
 | 
			
		||||
        types : [Y.List]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # SET Object Property (circular)
 | 
			
		||||
@ -101,18 +103,32 @@ class JsonTest extends Test
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # insert Object mutable (circular)
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
          y.val(_.random(0, l-1), @getRandomRoot user_num)
 | 
			
		||||
          y.insert(_.random(0, l-1), @getRandomRoot user_num)
 | 
			
		||||
        types: [Y.List]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)=> # INSERT TEXT
 | 
			
		||||
          y
 | 
			
		||||
          pos = _.random 0, (y.val().length-1)
 | 
			
		||||
          y.insert pos, @getRandomText()
 | 
			
		||||
          null
 | 
			
		||||
        types: [Y.Text]
 | 
			
		||||
      ,
 | 
			
		||||
        f : (y)-> # DELETE TEXT
 | 
			
		||||
          if y.val().length > 0
 | 
			
		||||
            pos = _.random 0, (y.val().length-1) # TODO: put here also arbitrary number (test behaviour in error cases)
 | 
			
		||||
            length = _.random 0, (y.val().length - pos)
 | 
			
		||||
            ops1 = y.delete pos, length
 | 
			
		||||
          undefined
 | 
			
		||||
        types : [Y.Text]
 | 
			
		||||
      ]
 | 
			
		||||
###     
 | 
			
		||||
 | 
			
		||||
###
 | 
			
		||||
module.exports = ObjectTest
 | 
			
		||||
 | 
			
		||||
describe "JsonFramework", ->
 | 
			
		||||
describe "Object Test", ->
 | 
			
		||||
  @timeout 500000
 | 
			
		||||
 | 
			
		||||
  beforeEach (done)->
 | 
			
		||||
    @yTest = new JsonTest()
 | 
			
		||||
    @yTest = new ObjectTest()
 | 
			
		||||
    @users = @yTest.users
 | 
			
		||||
 | 
			
		||||
    @test_user = @yTest.makeNewUser "test_user"
 | 
			
		||||
@ -126,7 +142,7 @@ describe "JsonFramework", ->
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
 | 
			
		||||
  it "handles double-late-join", ->
 | 
			
		||||
    test = new JsonTest("double")
 | 
			
		||||
    test = new ObjectTest("double")
 | 
			
		||||
    test.run()
 | 
			
		||||
    @yTest.run()
 | 
			
		||||
    u1 = test.users[0]
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user