broke the dammn thing
This commit is contained in:
@@ -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,7 +435,10 @@ module.exports = ()->
|
||||
# Return the content that this operation holds.
|
||||
#
|
||||
val: ()->
|
||||
@content
|
||||
if @content? and @content.getCustomType?
|
||||
@content.getCustomType()
|
||||
else
|
||||
@content
|
||||
|
||||
applyDelete: ()->
|
||||
res = super
|
||||
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user