broke the dammn thing
This commit is contained in:
		
							parent
							
								
									792440a71d
								
							
						
					
					
						commit
						860934de06
					
				
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -164,6 +164,17 @@ module.exports = function() {
 | 
			
		||||
      return success;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Operation.prototype.getCustomType = function() {
 | 
			
		||||
      if (this.custom_type == null) {
 | 
			
		||||
        throw new Error("This operation was not initialized with a custom type");
 | 
			
		||||
      }
 | 
			
		||||
      if (this.custom_type.constructor === String) {
 | 
			
		||||
        this.custom_type = new this.custom_types[this.custom_type]();
 | 
			
		||||
        this.custom_type._setModel(this);
 | 
			
		||||
      }
 | 
			
		||||
      return this.custom_type;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return Operation;
 | 
			
		||||
 | 
			
		||||
  })();
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,11 @@ module.exports = function() {
 | 
			
		||||
  ops.MapManager = (function(_super) {
 | 
			
		||||
    __extends(MapManager, _super);
 | 
			
		||||
 | 
			
		||||
    function MapManager(uid) {
 | 
			
		||||
      this.map = {};
 | 
			
		||||
    function MapManager(custom_type, uid) {
 | 
			
		||||
      if (custom_type != null) {
 | 
			
		||||
        this.custom_type = custom_type;
 | 
			
		||||
      }
 | 
			
		||||
      this._map = {};
 | 
			
		||||
      MapManager.__super__.constructor.call(this, uid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -20,7 +23,7 @@ module.exports = function() {
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype.applyDelete = function() {
 | 
			
		||||
      var name, p, _ref;
 | 
			
		||||
      _ref = this.map;
 | 
			
		||||
      _ref = this._map;
 | 
			
		||||
      for (name in _ref) {
 | 
			
		||||
        p = _ref[name];
 | 
			
		||||
        p.applyDelete();
 | 
			
		||||
@ -32,25 +35,50 @@ module.exports = function() {
 | 
			
		||||
      return MapManager.__super__.cleanup.call(this);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype.map = function(f) {
 | 
			
		||||
      var n, v, _ref;
 | 
			
		||||
      _ref = this._map;
 | 
			
		||||
      for (n in _ref) {
 | 
			
		||||
        v = _ref[n];
 | 
			
		||||
        f(n, v);
 | 
			
		||||
      }
 | 
			
		||||
      return void 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype.val = function(name, content) {
 | 
			
		||||
      var o, prop, result, _ref;
 | 
			
		||||
      var o, prop, rep, res, result, _ref;
 | 
			
		||||
      if (arguments.length > 1) {
 | 
			
		||||
        this.retrieveSub(name).replace(content);
 | 
			
		||||
        if ((content != null) && (content._model != null) && content._model instanceof ops.Operation) {
 | 
			
		||||
          rep = content._model;
 | 
			
		||||
        } else {
 | 
			
		||||
          rep = content;
 | 
			
		||||
        }
 | 
			
		||||
        this.retrieveSub(name).replace(rep);
 | 
			
		||||
        return this;
 | 
			
		||||
      } else if (name != null) {
 | 
			
		||||
        prop = this.map[name];
 | 
			
		||||
        prop = this._map[name];
 | 
			
		||||
        if ((prop != null) && !prop.isContentDeleted()) {
 | 
			
		||||
          return prop.val();
 | 
			
		||||
          res = prop.val();
 | 
			
		||||
          if (res instanceof ops.Operation) {
 | 
			
		||||
            return res.getCustomType();
 | 
			
		||||
          } else {
 | 
			
		||||
            return res;
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          return void 0;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        result = {};
 | 
			
		||||
        _ref = this.map;
 | 
			
		||||
        _ref = this._map;
 | 
			
		||||
        for (name in _ref) {
 | 
			
		||||
          o = _ref[name];
 | 
			
		||||
          if (!o.isContentDeleted()) {
 | 
			
		||||
            result[name] = o.val();
 | 
			
		||||
            res = prop.val();
 | 
			
		||||
            if (res instanceof ops.Operation) {
 | 
			
		||||
              result[name] = res.getCustomType();
 | 
			
		||||
            } else {
 | 
			
		||||
              result[name] = res;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
@ -59,7 +87,7 @@ module.exports = function() {
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype["delete"] = function(name) {
 | 
			
		||||
      var _ref;
 | 
			
		||||
      if ((_ref = this.map[name]) != null) {
 | 
			
		||||
      if ((_ref = this._map[name]) != null) {
 | 
			
		||||
        _ref.deleteContent();
 | 
			
		||||
      }
 | 
			
		||||
      return this;
 | 
			
		||||
@ -67,7 +95,7 @@ module.exports = function() {
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype.retrieveSub = function(property_name) {
 | 
			
		||||
      var event_properties, event_this, rm, rm_uid;
 | 
			
		||||
      if (this.map[property_name] == null) {
 | 
			
		||||
      if (this._map[property_name] == null) {
 | 
			
		||||
        event_properties = {
 | 
			
		||||
          name: property_name
 | 
			
		||||
        };
 | 
			
		||||
@ -78,16 +106,35 @@ module.exports = function() {
 | 
			
		||||
          alt: this
 | 
			
		||||
        };
 | 
			
		||||
        rm = new ops.ReplaceManager(event_properties, event_this, rm_uid);
 | 
			
		||||
        this.map[property_name] = rm;
 | 
			
		||||
        this._map[property_name] = rm;
 | 
			
		||||
        rm.setParent(this, property_name);
 | 
			
		||||
        rm.execute();
 | 
			
		||||
      }
 | 
			
		||||
      return this.map[property_name];
 | 
			
		||||
      return this._map[property_name];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    MapManager.prototype._encode = function() {
 | 
			
		||||
      var json;
 | 
			
		||||
      json = {
 | 
			
		||||
        'type': this.type,
 | 
			
		||||
        'uid': this.getUid()
 | 
			
		||||
      };
 | 
			
		||||
      if (this.custom_type.constructor === String) {
 | 
			
		||||
        json.custom_type = this.custom_type;
 | 
			
		||||
      } else {
 | 
			
		||||
        json.custom_type = this.custom_type._name;
 | 
			
		||||
      }
 | 
			
		||||
      return json;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return MapManager;
 | 
			
		||||
 | 
			
		||||
  })(ops.Operation);
 | 
			
		||||
  ops.MapManager.parse = function(json) {
 | 
			
		||||
    var custom_type, uid;
 | 
			
		||||
    uid = json['uid'], custom_type = json['custom_type'];
 | 
			
		||||
    return new this(custom_type, uid);
 | 
			
		||||
  };
 | 
			
		||||
  ops.ListManager = (function(_super) {
 | 
			
		||||
    __extends(ListManager, _super);
 | 
			
		||||
 | 
			
		||||
@ -413,7 +460,11 @@ module.exports = function() {
 | 
			
		||||
    Replaceable.prototype.type = "Replaceable";
 | 
			
		||||
 | 
			
		||||
    Replaceable.prototype.val = function() {
 | 
			
		||||
      if ((this.content != null) && (this.content.getCustomType != null)) {
 | 
			
		||||
        return this.content.getCustomType();
 | 
			
		||||
      } else {
 | 
			
		||||
        return this.content;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Replaceable.prototype.applyDelete = function() {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										80
									
								
								build/node/Types/Object.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								build/node/Types/Object.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
			
		||||
var YObject;
 | 
			
		||||
 | 
			
		||||
YObject = (function() {
 | 
			
		||||
  function YObject(_at__object) {
 | 
			
		||||
    var name, val, _ref;
 | 
			
		||||
    this._object = _at__object != null ? _at__object : {};
 | 
			
		||||
    if (this._object.constructor === Object) {
 | 
			
		||||
      _ref = this._object;
 | 
			
		||||
      for (name in _ref) {
 | 
			
		||||
        val = _ref[name];
 | 
			
		||||
        if (val.constructor === Object) {
 | 
			
		||||
          this._object[name] = new YObject(val);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      throw new Error("Y.Object accepts Json Objects only");
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  YObject.prototype._name = "Object";
 | 
			
		||||
 | 
			
		||||
  YObject.prototype._getModel = function(types, ops) {
 | 
			
		||||
    var n, o, _ref;
 | 
			
		||||
    if (this._model == null) {
 | 
			
		||||
      this._model = new ops.MapManager(this).execute();
 | 
			
		||||
      _ref = this._object;
 | 
			
		||||
      for (n in _ref) {
 | 
			
		||||
        o = _ref[n];
 | 
			
		||||
        this._model.val(n, o);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    delete this._object;
 | 
			
		||||
    return this._model;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YObject.prototype._setModel = function(_at__model) {
 | 
			
		||||
    this._model = _at__model;
 | 
			
		||||
    return delete this._object;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YObject.prototype.observe = function(f) {
 | 
			
		||||
    return this._model.observe(f);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  YObject.prototype.val = function(name, content) {
 | 
			
		||||
    var n, res, v, _ref;
 | 
			
		||||
    if (this._model != null) {
 | 
			
		||||
      return this._model.val.apply(this._model, arguments);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (content != null) {
 | 
			
		||||
        return this._object[name] = content;
 | 
			
		||||
      } else if (name != null) {
 | 
			
		||||
        return this._object[name];
 | 
			
		||||
      } else {
 | 
			
		||||
        res = {};
 | 
			
		||||
        _ref = this._object;
 | 
			
		||||
        for (n in _ref) {
 | 
			
		||||
          v = _ref[n];
 | 
			
		||||
          res[n] = v;
 | 
			
		||||
        }
 | 
			
		||||
        return res;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return YObject;
 | 
			
		||||
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  if (window.Y != null) {
 | 
			
		||||
    window.Y.Object = YObject;
 | 
			
		||||
  } else {
 | 
			
		||||
    throw new Error("You must first import Y!");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (typeof module !== "undefined" && module !== null) {
 | 
			
		||||
  module.exports = YObject;
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
var Engine, HistoryBuffer, adaptConnector, createY, json_ops_uninitialized;
 | 
			
		||||
var Engine, HistoryBuffer, adaptConnector, createY, text_ops_uninitialized;
 | 
			
		||||
 | 
			
		||||
json_ops_uninitialized = require("./Operations/Json");
 | 
			
		||||
text_ops_uninitialized = require("./Operations/Text");
 | 
			
		||||
 | 
			
		||||
HistoryBuffer = require("./HistoryBuffer");
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ Engine = require("./Engine");
 | 
			
		||||
adaptConnector = require("./ConnectorAdapter");
 | 
			
		||||
 | 
			
		||||
createY = function(connector) {
 | 
			
		||||
  var HB, engine, ops, ops_manager, user_id;
 | 
			
		||||
  var HB, ct, engine, model, ops, ops_manager, user_id;
 | 
			
		||||
  user_id = null;
 | 
			
		||||
  if (connector.user_id != null) {
 | 
			
		||||
    user_id = connector.user_id;
 | 
			
		||||
@ -21,7 +21,7 @@ createY = function(connector) {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
  HB = new HistoryBuffer(user_id);
 | 
			
		||||
  ops_manager = json_ops_uninitialized(HB, this.constructor);
 | 
			
		||||
  ops_manager = text_ops_uninitialized(HB, this.constructor);
 | 
			
		||||
  ops = ops_manager.operations;
 | 
			
		||||
  engine = new Engine(HB, ops);
 | 
			
		||||
  adaptConnector(connector, engine, HB, ops_manager.execution_listener);
 | 
			
		||||
@ -30,11 +30,16 @@ createY = function(connector) {
 | 
			
		||||
  ops.Operation.prototype.engine = engine;
 | 
			
		||||
  ops.Operation.prototype.connector = connector;
 | 
			
		||||
  ops.Operation.prototype.custom_ops = this.constructor;
 | 
			
		||||
  return new ops.Object(HB.getReservedUniqueIdentifier()).execute();
 | 
			
		||||
  ct = new createY.Object();
 | 
			
		||||
  model = new ops.MapManager(ct, HB.getReservedUniqueIdentifier()).execute();
 | 
			
		||||
  ct._setModel(model);
 | 
			
		||||
  return ct;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = createY;
 | 
			
		||||
 | 
			
		||||
if ((typeof window !== "undefined" && window !== null) && (window.Y == null)) {
 | 
			
		||||
if (typeof window !== "undefined" && window !== null) {
 | 
			
		||||
  window.Y = createY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
createY.Object = require("./Types/Object");
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -201,6 +201,16 @@ module.exports = ()->
 | 
			
		||||
        @unchecked = uninstantiated
 | 
			
		||||
      success
 | 
			
		||||
 | 
			
		||||
    getCustomType: ()->
 | 
			
		||||
      if not @custom_type?
 | 
			
		||||
        throw new Error "This operation was not initialized with a custom type"
 | 
			
		||||
      if @custom_type.constructor is String
 | 
			
		||||
        # has not been initialized yet (only the name is specified)
 | 
			
		||||
        @custom_type = new @custom_types[@custom_type]()
 | 
			
		||||
        @custom_type._setModel @
 | 
			
		||||
      @custom_type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # @nodoc
 | 
			
		||||
  # A simple Delete-type operation that deletes an operation.
 | 
			
		||||
 | 
			
		||||
@ -1,147 +0,0 @@
 | 
			
		||||
text_ops_uninitialized = require "./Text"
 | 
			
		||||
 | 
			
		||||
module.exports = ()->
 | 
			
		||||
  text_ops = text_ops_uninitialized()
 | 
			
		||||
  ops = text_ops.operations
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Manages Object-like values.
 | 
			
		||||
  #
 | 
			
		||||
  class ops.Object extends ops.MapManager
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # Identifies this class.
 | 
			
		||||
    # Use it to check whether this is a json-type or something else.
 | 
			
		||||
    #
 | 
			
		||||
    # @example
 | 
			
		||||
    #   var x = y.val('unknown')
 | 
			
		||||
    #   if (x.type === "Object") {
 | 
			
		||||
    #     console.log JSON.stringify(x.toJson())
 | 
			
		||||
    #   }
 | 
			
		||||
    #
 | 
			
		||||
    type: "Object"
 | 
			
		||||
 | 
			
		||||
    applyDelete: ()->
 | 
			
		||||
      super()
 | 
			
		||||
 | 
			
		||||
    cleanup: ()->
 | 
			
		||||
      super()
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # Transform this to a Json. If your browser supports Object.observe it will be transformed automatically when a change arrives.
 | 
			
		||||
    # Otherwise you will loose all the sharing-abilities (the new object will be a deep clone)!
 | 
			
		||||
    # @return {Json}
 | 
			
		||||
    #
 | 
			
		||||
    # TODO: at the moment you don't consider changing of properties.
 | 
			
		||||
    # E.g.: let x = {a:[]}. Then x.a.push 1 wouldn't change anything
 | 
			
		||||
    #
 | 
			
		||||
    toJson: (transform_to_value = false)->
 | 
			
		||||
      if not @bound_json? or not Object.observe? or true # TODO: currently, you are not watching mutable strings for changes, and, therefore, the @bound_json is not updated. TODO TODO  wuawuawua easy
 | 
			
		||||
        val = @val()
 | 
			
		||||
        json = {}
 | 
			
		||||
        for name, o of val
 | 
			
		||||
          if o instanceof ops.Object
 | 
			
		||||
            json[name] = o.toJson(transform_to_value)
 | 
			
		||||
          else if o instanceof ops.ListManager
 | 
			
		||||
            json[name] = o.toJson(transform_to_value)
 | 
			
		||||
          else if transform_to_value and o instanceof ops.Operation
 | 
			
		||||
            json[name] = o.val()
 | 
			
		||||
          else
 | 
			
		||||
            json[name] = o
 | 
			
		||||
        @bound_json = json
 | 
			
		||||
        if Object.observe?
 | 
			
		||||
          that = @
 | 
			
		||||
          Object.observe @bound_json, (events)->
 | 
			
		||||
            for event in events
 | 
			
		||||
              if not event.changedBy? and (event.type is "add" or event.type = "update")
 | 
			
		||||
                # this event is not created by Y.
 | 
			
		||||
                that.val(event.name, event.object[event.name])
 | 
			
		||||
          @observe (events)->
 | 
			
		||||
            for event in events
 | 
			
		||||
              if event.created_ isnt @HB.getUserId()
 | 
			
		||||
                notifier = Object.getNotifier(that.bound_json)
 | 
			
		||||
                oldVal = that.bound_json[event.name]
 | 
			
		||||
                if oldVal?
 | 
			
		||||
                  notifier.performChange 'update', ()->
 | 
			
		||||
                      that.bound_json[event.name] = that.val(event.name)
 | 
			
		||||
                    , that.bound_json
 | 
			
		||||
                  notifier.notify
 | 
			
		||||
                    object: that.bound_json
 | 
			
		||||
                    type: 'update'
 | 
			
		||||
                    name: event.name
 | 
			
		||||
                    oldValue: oldVal
 | 
			
		||||
                    changedBy: event.changedBy
 | 
			
		||||
                else
 | 
			
		||||
                  notifier.performChange 'add', ()->
 | 
			
		||||
                      that.bound_json[event.name] = that.val(event.name)
 | 
			
		||||
                    , that.bound_json
 | 
			
		||||
                  notifier.notify
 | 
			
		||||
                    object: that.bound_json
 | 
			
		||||
                    type: 'add'
 | 
			
		||||
                    name: event.name
 | 
			
		||||
                    oldValue: oldVal
 | 
			
		||||
                    changedBy:event.changedBy
 | 
			
		||||
      @bound_json
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # @overload val()
 | 
			
		||||
    #   Get this as a Json object.
 | 
			
		||||
    #   @return [Json]
 | 
			
		||||
    #
 | 
			
		||||
    # @overload val(name)
 | 
			
		||||
    #   Get value of a property.
 | 
			
		||||
    #   @param {String} name Name of the object property.
 | 
			
		||||
    #   @return [Object Type||String|Object] Depending on the value of the property. If mutable it will return a Operation-type object, if immutable it will return String/Object.
 | 
			
		||||
    #
 | 
			
		||||
    # @overload val(name, content)
 | 
			
		||||
    #   Set a new property.
 | 
			
		||||
    #   @param {String} name Name of the object property.
 | 
			
		||||
    #   @param {Object|String} content Content of the object property.
 | 
			
		||||
    #   @return [Object Type] This object. (supports chaining)
 | 
			
		||||
    #
 | 
			
		||||
    val: (name, content)->
 | 
			
		||||
      if name? and arguments.length > 1
 | 
			
		||||
        if content? and content.constructor?
 | 
			
		||||
          type = ops[content.constructor.name]
 | 
			
		||||
          if type? and type.create?
 | 
			
		||||
            args = []
 | 
			
		||||
            for i in [1...arguments.length]
 | 
			
		||||
              args.push arguments[i]
 | 
			
		||||
            o = type.create.apply null, args
 | 
			
		||||
            super name, o
 | 
			
		||||
          else
 | 
			
		||||
            throw new Error "The #{content.constructor.name}-type is not (yet) supported in Y."
 | 
			
		||||
        else
 | 
			
		||||
          super name, content
 | 
			
		||||
      else # is this even necessary ? I have to define every type anyway.. (see Number type below)
 | 
			
		||||
        super name
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # @private
 | 
			
		||||
    #
 | 
			
		||||
    _encode: ()->
 | 
			
		||||
      {
 | 
			
		||||
        'type' : @type
 | 
			
		||||
        'uid' : @getUid()
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
  ops.Object.parse = (json)->
 | 
			
		||||
    {
 | 
			
		||||
      'uid' : uid
 | 
			
		||||
    } = json
 | 
			
		||||
    new this(uid)
 | 
			
		||||
 | 
			
		||||
  ops.Object.create = (content, mutable)->
 | 
			
		||||
    json = new ops.Object().execute()
 | 
			
		||||
    for n,o of content
 | 
			
		||||
      json.val n, o, mutable
 | 
			
		||||
    json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  ops.Number = {}
 | 
			
		||||
  ops.Number.create = (content)->
 | 
			
		||||
    content
 | 
			
		||||
 | 
			
		||||
  text_ops
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -13,46 +13,65 @@ module.exports = ()->
 | 
			
		||||
    #
 | 
			
		||||
    # @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
 | 
			
		||||
    #
 | 
			
		||||
    constructor: (uid)->
 | 
			
		||||
      @map = {}
 | 
			
		||||
    constructor: (custom_type, uid)->
 | 
			
		||||
      if custom_type?
 | 
			
		||||
        @custom_type = custom_type
 | 
			
		||||
      @_map = {}
 | 
			
		||||
      super uid
 | 
			
		||||
 | 
			
		||||
    type: "MapManager"
 | 
			
		||||
 | 
			
		||||
    applyDelete: ()->
 | 
			
		||||
      for name,p of @map
 | 
			
		||||
      for name,p of @_map
 | 
			
		||||
        p.applyDelete()
 | 
			
		||||
      super()
 | 
			
		||||
 | 
			
		||||
    cleanup: ()->
 | 
			
		||||
      super()
 | 
			
		||||
 | 
			
		||||
    map: (f)->
 | 
			
		||||
      for n,v of @_map
 | 
			
		||||
        f(n,v)
 | 
			
		||||
      undefined
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # @see JsonOperations.val
 | 
			
		||||
    #
 | 
			
		||||
    val: (name, content)->
 | 
			
		||||
      if arguments.length > 1
 | 
			
		||||
        @retrieveSub(name).replace content
 | 
			
		||||
        if content? and content._model? and content._model instanceof ops.Operation
 | 
			
		||||
          rep = content._model
 | 
			
		||||
        else
 | 
			
		||||
          rep = content
 | 
			
		||||
        @retrieveSub(name).replace rep
 | 
			
		||||
        @
 | 
			
		||||
      else if name?
 | 
			
		||||
        prop = @map[name]
 | 
			
		||||
        prop = @_map[name]
 | 
			
		||||
        if prop? and not prop.isContentDeleted()
 | 
			
		||||
          prop.val()
 | 
			
		||||
          res = prop.val()
 | 
			
		||||
          if res instanceof ops.Operation
 | 
			
		||||
            res.getCustomType()
 | 
			
		||||
          else
 | 
			
		||||
            res
 | 
			
		||||
        else
 | 
			
		||||
          undefined
 | 
			
		||||
      else
 | 
			
		||||
        result = {}
 | 
			
		||||
        for name,o of @map
 | 
			
		||||
        for name,o of @_map
 | 
			
		||||
          if not o.isContentDeleted()
 | 
			
		||||
            result[name] = o.val()
 | 
			
		||||
            res = prop.val()
 | 
			
		||||
            if res instanceof ops.Operation
 | 
			
		||||
              result[name] = res.getCustomType()
 | 
			
		||||
            else
 | 
			
		||||
              result[name] = res
 | 
			
		||||
        result
 | 
			
		||||
 | 
			
		||||
    delete: (name)->
 | 
			
		||||
      @map[name]?.deleteContent()
 | 
			
		||||
      @_map[name]?.deleteContent()
 | 
			
		||||
      @
 | 
			
		||||
 | 
			
		||||
    retrieveSub: (property_name)->
 | 
			
		||||
      if not @map[property_name]?
 | 
			
		||||
      if not @_map[property_name]?
 | 
			
		||||
        event_properties =
 | 
			
		||||
          name: property_name
 | 
			
		||||
        event_this = @
 | 
			
		||||
@ -61,10 +80,33 @@ module.exports = ()->
 | 
			
		||||
          sub: property_name
 | 
			
		||||
          alt: @
 | 
			
		||||
        rm = new ops.ReplaceManager event_properties, event_this, rm_uid # this operation shall not be saved in the HB
 | 
			
		||||
        @map[property_name] = rm
 | 
			
		||||
        @_map[property_name] = rm
 | 
			
		||||
        rm.setParent @, property_name
 | 
			
		||||
        rm.execute()
 | 
			
		||||
      @map[property_name]
 | 
			
		||||
      @_map[property_name]
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # @private
 | 
			
		||||
    #
 | 
			
		||||
    _encode: ()->
 | 
			
		||||
      json = {
 | 
			
		||||
        'type' : @type
 | 
			
		||||
        'uid' : @getUid()
 | 
			
		||||
      }
 | 
			
		||||
      if @custom_type.constructor is String
 | 
			
		||||
        json.custom_type = @custom_type
 | 
			
		||||
      else
 | 
			
		||||
        json.custom_type = @custom_type._name
 | 
			
		||||
      json
 | 
			
		||||
 | 
			
		||||
  ops.MapManager.parse = (json)->
 | 
			
		||||
    {
 | 
			
		||||
      'uid' : uid
 | 
			
		||||
      'custom_type' : custom_type
 | 
			
		||||
    } = json
 | 
			
		||||
    new this(custom_type, uid)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # @nodoc
 | 
			
		||||
@ -393,6 +435,9 @@ module.exports = ()->
 | 
			
		||||
    # Return the content that this operation holds.
 | 
			
		||||
    #
 | 
			
		||||
    val: ()->
 | 
			
		||||
      if @content? and @content.getCustomType?
 | 
			
		||||
        @content.getCustomType()
 | 
			
		||||
      else
 | 
			
		||||
        @content
 | 
			
		||||
 | 
			
		||||
    applyDelete: ()->
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										73
									
								
								lib/Types/Object.coffee
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								lib/Types/Object.coffee
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
 | 
			
		||||
class YObject
 | 
			
		||||
 | 
			
		||||
  constructor: (@_object = {})->
 | 
			
		||||
    if @_object.constructor is Object
 | 
			
		||||
      for name, val of @_object
 | 
			
		||||
        if val.constructor is Object
 | 
			
		||||
          @_object[name] = new YObject(val)
 | 
			
		||||
    else
 | 
			
		||||
      throw new Error "Y.Object accepts Json Objects only"
 | 
			
		||||
 | 
			
		||||
  _name: "Object"
 | 
			
		||||
 | 
			
		||||
  _getModel: (types, ops)->
 | 
			
		||||
    if not @_model?
 | 
			
		||||
      @_model = new ops.MapManager(@).execute()
 | 
			
		||||
      for n,o of @_object
 | 
			
		||||
        @_model.val n, o
 | 
			
		||||
    delete @_object
 | 
			
		||||
    @_model
 | 
			
		||||
 | 
			
		||||
  _setModel: (@_model)->
 | 
			
		||||
    delete @_object
 | 
			
		||||
 | 
			
		||||
  observe: (f)->
 | 
			
		||||
    @_model.observe f
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # @overload val()
 | 
			
		||||
  #   Get this as a Json object.
 | 
			
		||||
  #   @return [Json]
 | 
			
		||||
  #
 | 
			
		||||
  # @overload val(name)
 | 
			
		||||
  #   Get value of a property.
 | 
			
		||||
  #   @param {String} name Name of the object property.
 | 
			
		||||
  #   @return [Object Type||String|Object] Depending on the value of the property. If mutable it will return a Operation-type object, if immutable it will return String/Object.
 | 
			
		||||
  #
 | 
			
		||||
  # @overload val(name, content)
 | 
			
		||||
  #   Set a new property.
 | 
			
		||||
  #   @param {String} name Name of the object property.
 | 
			
		||||
  #   @param {Object|String} content Content of the object property.
 | 
			
		||||
  #   @return [Object Type] This object. (supports chaining)
 | 
			
		||||
  #
 | 
			
		||||
  val: (name, content)->
 | 
			
		||||
    if @_model?
 | 
			
		||||
      @_model.val.apply @_model, arguments
 | 
			
		||||
    else
 | 
			
		||||
      if content?
 | 
			
		||||
        @_object[name] = content
 | 
			
		||||
      else if name?
 | 
			
		||||
        @_object[name]
 | 
			
		||||
      else
 | 
			
		||||
        res = {}
 | 
			
		||||
        for n,v of @_object
 | 
			
		||||
          res[n] = v
 | 
			
		||||
        res
 | 
			
		||||
 | 
			
		||||
if window?
 | 
			
		||||
  if window.Y?
 | 
			
		||||
    window.Y.Object = YObject
 | 
			
		||||
  else
 | 
			
		||||
    throw new Error "You must first import Y!"
 | 
			
		||||
 | 
			
		||||
if module?
 | 
			
		||||
  module.exports = YObject
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								lib/y.coffee
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								lib/y.coffee
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
 | 
			
		||||
json_ops_uninitialized = require "./Operations/Json"
 | 
			
		||||
text_ops_uninitialized = require "./Operations/Text"
 | 
			
		||||
 | 
			
		||||
HistoryBuffer = require "./HistoryBuffer"
 | 
			
		||||
Engine = require "./Engine"
 | 
			
		||||
@ -15,7 +15,7 @@ createY = (connector)->
 | 
			
		||||
      user_id = id
 | 
			
		||||
      HB.resetUserId id
 | 
			
		||||
  HB = new HistoryBuffer user_id
 | 
			
		||||
  ops_manager = json_ops_uninitialized HB, this.constructor
 | 
			
		||||
  ops_manager = text_ops_uninitialized HB, this.constructor
 | 
			
		||||
  ops = ops_manager.operations
 | 
			
		||||
 | 
			
		||||
  engine = new Engine HB, ops
 | 
			
		||||
@ -27,8 +27,13 @@ createY = (connector)->
 | 
			
		||||
  ops.Operation.prototype.connector = connector
 | 
			
		||||
  ops.Operation.prototype.custom_ops = this.constructor
 | 
			
		||||
 | 
			
		||||
  return new ops.Object(HB.getReservedUniqueIdentifier()).execute()
 | 
			
		||||
  ct = new createY.Object()
 | 
			
		||||
  model = new ops.MapManager(ct, HB.getReservedUniqueIdentifier()).execute()
 | 
			
		||||
  ct._setModel model
 | 
			
		||||
  ct
 | 
			
		||||
 | 
			
		||||
module.exports = createY
 | 
			
		||||
if window? and not window.Y?
 | 
			
		||||
if window?
 | 
			
		||||
  window.Y = createY
 | 
			
		||||
 | 
			
		||||
createY.Object = require "./Types/Object"
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,18 @@ chai.use(sinonChai)
 | 
			
		||||
Connector = require "../../y-test/lib/y-test.coffee"
 | 
			
		||||
Y = require "../lib/y.coffee"
 | 
			
		||||
 | 
			
		||||
compare = (o1, o2)->
 | 
			
		||||
  if o1.type? and o1.type isnt o2.type
 | 
			
		||||
    throw new Error "different types"
 | 
			
		||||
  else if o1.type is "Object"
 | 
			
		||||
    for name, val of o1.val()
 | 
			
		||||
      compare(val, o2.val(name))
 | 
			
		||||
  else if o1.type?
 | 
			
		||||
    compare(o1.val(), o2.val())
 | 
			
		||||
  else if o1 isnt o2
 | 
			
		||||
    throw new Error "different values"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Test = require "./TestSuite"
 | 
			
		||||
 | 
			
		||||
class JsonTest extends Test
 | 
			
		||||
@ -43,12 +55,8 @@ class JsonTest extends Test
 | 
			
		||||
        p = elems[_.random(0, elems.length-1)]
 | 
			
		||||
        @getRandomRoot user_num, p
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  getContent: (user_num)->
 | 
			
		||||
    @users[user_num].toJson(true)
 | 
			
		||||
 | 
			
		||||
  getGeneratingFunctions: (user_num)->
 | 
			
		||||
    types = @users[user_num].operations
 | 
			
		||||
    types = @users[user_num]._model.operations
 | 
			
		||||
    super(user_num).concat [
 | 
			
		||||
        f : (y)=> # SET PROPERTY
 | 
			
		||||
          l = y.val().length
 | 
			
		||||
@ -113,18 +121,8 @@ describe "JsonFramework", ->
 | 
			
		||||
    ops2 = u2.HB._encode()
 | 
			
		||||
    u1.engine.applyOp ops2, true
 | 
			
		||||
    u2.engine.applyOp ops1, true
 | 
			
		||||
    compare = (o1, o2)->
 | 
			
		||||
      if o1.type? and o1.type isnt o2.type
 | 
			
		||||
        throw new Error "different types"
 | 
			
		||||
      else if o1.type is "Object"
 | 
			
		||||
        for name, val of o1.val()
 | 
			
		||||
          compare(val, o2.val(name))
 | 
			
		||||
      else if o1.type?
 | 
			
		||||
        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))
 | 
			
		||||
 | 
			
		||||
    expect(compare(u1, u2)).to.not.be.undefined
 | 
			
		||||
 | 
			
		||||
  it "can handle creaton of complex json (1)", ->
 | 
			
		||||
    @yTest.users[0].val('a', 'q', "mutable")
 | 
			
		||||
@ -136,16 +134,16 @@ describe "JsonFramework", ->
 | 
			
		||||
    expect(@yTest.getSomeUser().val("a").val()).to.equal("At")
 | 
			
		||||
 | 
			
		||||
  it "can handle creaton of complex json (2)", ->
 | 
			
		||||
    @yTest.getSomeUser().val('x', {'a':'b'})
 | 
			
		||||
    @yTest.getSomeUser().val('a', {'a':{q:"dtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt"}}, "mutable")
 | 
			
		||||
    @yTest.getSomeUser().val('b', {'a':{}})
 | 
			
		||||
    @yTest.getSomeUser().val('c', {'a':'c'})
 | 
			
		||||
    @yTest.getSomeUser().val('c', {'a':'b'})
 | 
			
		||||
    @yTest.getSomeUser().val('x', new Y.Object({'a':'b'}))
 | 
			
		||||
    @yTest.getSomeUser().val('a', new Y.Object({'a':{q:"dtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt"}}))
 | 
			
		||||
    @yTest.getSomeUser().val('b', new Y.Object({'a':{}}))
 | 
			
		||||
    @yTest.getSomeUser().val('c', new Y.Object({'a':'c'}))
 | 
			
		||||
    @yTest.getSomeUser().val('c', new Y.Object({'a':'b'}))
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
    q = @yTest.getSomeUser().val("a").val("a").val("q")
 | 
			
		||||
    q.insert(0,'A')
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
    expect(@yTest.getSomeUser().val("a").val("a").val("q").val()).to.equal("Adtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt")
 | 
			
		||||
    expect(@yTest.getSomeUser().val("a").val("a").val("q")).to.equal("Adtrndtrtdrntdrnrtdnrtdnrtdnrtdnrdnrdt")
 | 
			
		||||
 | 
			
		||||
  it "can handle creaton of complex json (3)", ->
 | 
			
		||||
    @yTest.users[0].val('l', [1,2,3], "mutable")
 | 
			
		||||
@ -171,7 +169,7 @@ describe "JsonFramework", ->
 | 
			
		||||
  it "handles immutables and primitive data types (2)", ->
 | 
			
		||||
    @yTest.users[0].val('string', "text", "immutable")
 | 
			
		||||
    @yTest.users[1].val('number', 4, "immutable")
 | 
			
		||||
    @yTest.users[2].val('object', {q:"rr"}, "immutable")
 | 
			
		||||
    @yTest.users[2].val('object', {q:"rr"})
 | 
			
		||||
    @yTest.users[0].val('null', null)
 | 
			
		||||
    @yTest.compareAll()
 | 
			
		||||
    expect(@yTest.getSomeUser().val('string')).to.equal "text"
 | 
			
		||||
 | 
			
		||||
@ -28,14 +28,14 @@ module.exports = class Test
 | 
			
		||||
    for i in [0...@number_of_engines]
 | 
			
		||||
      u = @makeNewUser (i+@name_suffix)
 | 
			
		||||
      for user in @users
 | 
			
		||||
        u.connector.join(user.connector) # TODO: change the test-connector to make this more convenient
 | 
			
		||||
        u._model.connector.join(user._model.connector) # TODO: change the test-connector to make this more convenient
 | 
			
		||||
      @users.push u
 | 
			
		||||
    @initUsers?(@users[0])
 | 
			
		||||
    @flushAll()
 | 
			
		||||
 | 
			
		||||
  # is called by implementing class
 | 
			
		||||
  makeNewUser: (user)->
 | 
			
		||||
    user.HB.stopGarbageCollection()
 | 
			
		||||
    user._model.HB.stopGarbageCollection()
 | 
			
		||||
    user
 | 
			
		||||
 | 
			
		||||
  getSomeUser: ()->
 | 
			
		||||
@ -69,7 +69,7 @@ module.exports = class Test
 | 
			
		||||
    @getRandomText [1,2,'x','y'], 1 # only 4 keys
 | 
			
		||||
 | 
			
		||||
  getGeneratingFunctions: (user_num)=>
 | 
			
		||||
    types = @users[user_num].operations
 | 
			
		||||
    types = @users[user_num]._model.operations
 | 
			
		||||
    [
 | 
			
		||||
        f : (y)=> # INSERT TEXT
 | 
			
		||||
          y
 | 
			
		||||
@ -106,7 +106,7 @@ module.exports = class Test
 | 
			
		||||
 | 
			
		||||
  applyRandomOp: (user_num)=>
 | 
			
		||||
    user = @users[user_num]
 | 
			
		||||
    user.connector.flushOneRandom()
 | 
			
		||||
    user._model.connector.flushOneRandom()
 | 
			
		||||
 | 
			
		||||
  doSomething: ()->
 | 
			
		||||
    user_num = _.random (@number_of_engines-1)
 | 
			
		||||
@ -119,15 +119,14 @@ module.exports = class Test
 | 
			
		||||
    final = false
 | 
			
		||||
    if @users.length <= 1 or not final
 | 
			
		||||
      for user,user_number in @users
 | 
			
		||||
        user.connector.flushAll()
 | 
			
		||||
        user._model.connector.flushAll()
 | 
			
		||||
    else
 | 
			
		||||
      for user,user_number in @users[1..]
 | 
			
		||||
        user.connector.flushAll()
 | 
			
		||||
        user._model.connector.flushAll()
 | 
			
		||||
      ops = @users[1].getHistoryBuffer()._encode @users[0].HB.getOperationCounter()
 | 
			
		||||
      @users[0].engine.applyOpsCheckDouble ops
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  compareAll: (test_number)->
 | 
			
		||||
    @flushAll(true)
 | 
			
		||||
 | 
			
		||||
@ -135,7 +134,7 @@ module.exports = class Test
 | 
			
		||||
 | 
			
		||||
    number_of_created_operations = 0
 | 
			
		||||
    for i in [0...(@users.length)]
 | 
			
		||||
      number_of_created_operations += @users[i].connector.getOpsInExecutionOrder().length
 | 
			
		||||
      number_of_created_operations += @users[i]._model.connector.getOpsInExecutionOrder().length
 | 
			
		||||
    @ops += number_of_created_operations*@users.length
 | 
			
		||||
 | 
			
		||||
    ops_per_msek = Math.floor(@ops/@time)
 | 
			
		||||
@ -146,7 +145,7 @@ module.exports = class Test
 | 
			
		||||
      if @debug
 | 
			
		||||
        if not _.isEqual @getContent(i), @getContent(i+1)
 | 
			
		||||
          printOpsInExecutionOrder = (otnumber, otherotnumber)=>
 | 
			
		||||
            ops = _.filter @users[otnumber].connector.getOpsInExecutionOrder(), (o)->
 | 
			
		||||
            ops = _.filter @users[otnumber]._model.connector.getOpsInExecutionOrder(), (o)->
 | 
			
		||||
              typeof o.uid.op_name isnt 'string' and o.uid.creator isnt '_'
 | 
			
		||||
            for s,j in ops
 | 
			
		||||
              console.log "op#{j} = " + (JSON.stringify s)
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user