implemented observePath, fixed some inconsistencies

This commit is contained in:
Kevin Jahns 2015-10-06 19:45:29 +02:00
parent c95dae3c33
commit 1ace3e3120
5 changed files with 101 additions and 28 deletions

View File

@ -14,16 +14,11 @@ Y({
window.yconfig = yconfig
var textarea = document.getElementById('textfield')
var contenteditable = document.getElementById('contenteditable')
yconfig.root.observe(function (events) {
for (var e in events) {
var event = events[e]
if (event.name === 'text' && (event.type === 'add' || event.type === 'update')) {
event.object.get(event.name).then(function (text) { // eslint-disable-line
yconfig.root.observePath(['text'], function (text) {
if (text != null) {
text.bind(textarea)
text.bind(contenteditable)
window.ytext = text
})
}
}
})
yconfig.root.set('text', Y.TextBind)

View File

@ -81,6 +81,7 @@ class AbstractTransaction {
/*
Get a type based on the id of its model.
If it does not exist yes, create it.
TODO: delete type from store.initializedTypes[id] when corresponding id was deleted!
*/
* getType (id) {
var sid = JSON.stringify(id)

View File

@ -1,8 +1,8 @@
/* global createUsers, wait, Y, compareAllUsers, getRandomNumber, applyRandomTransactions, async, garbageCollectAllUsers, describeManyTimes */
/* eslint-env browser,jasmine */
var numberOfYArrayTests = 1000
var repeatArrayTests = 5
var numberOfYArrayTests = 200
var repeatArrayTests = 1
describe('Array Type', function () {
var y1, y2, y3, yconfig1, yconfig2, yconfig3, flushAll

View File

@ -3,12 +3,12 @@
;(function () {
class YMap {
constructor (os, model) {
constructor (os, model, contents, opContents) {
this._model = model.id
this.os = os
this.map = Y.utils.copyObject(model.map)
this.contents = {}
this.opContents = {}
this.contents = contents
this.opContents = opContents
this.eventHandler = new Y.utils.EventHandler(ops => {
var userEvents = []
for (var i in ops) {
@ -84,12 +84,11 @@
// return property.
// if property does not exist, return null
// if property is a type, return a promise
if (this.opContents[key] == null) {
if (key == null) {
return Y.utils.copyObject(this.contents)
} else {
return this.contents[key]
throw new Error('You must specify key!')
}
if (this.opContents[key] == null) {
return this.contents[key]
} else {
return new Promise((resolve) => {
var oid = this.opContents[key]
@ -99,6 +98,19 @@
})
}
}
/*
If there is a primitive (not a custom type), then return it.
Returns all primitive values, if propertyName is specified!
Note: modifying the return value could result in inconsistencies!
-- so make sure to copy it first!
*/
getPrimitive (key) {
if (key == null) {
return Y.utils.copyObject(this.contents)
} else {
return this.contents[key]
}
}
delete (key) {
var right = this.map[key]
if (right != null) {
@ -161,10 +173,48 @@
unobserve (f) {
this.eventHandler.removeEventListener(f)
}
/*
Observe a path.
E.g.
```
o.set('textarea', Y.TextBind)
o.observePath(['textarea'], function(t){
// is called whenever textarea is replaced
t.bind(textarea)
})
returns a Promise that contains a function that removes the observer from the path.
*/
observePath (path, f) {
var self = this
if (path.length === 0) {
this.observe(f)
function observeProperty (events) {
// call f whenever path changes
for (var i = 0; i < events.length; i++) {
var event = events[i]
if (event.name === propertyName) {
// call this also for delete events!
var property = self.get(propertyName)
if (property instanceof Promise) {
property.then(f)
} else {
f(property)
}
}
}
}
if (path.length < 1) {
throw new Error('Path must contain at least one element!')
} else if (path.length === 1) {
var propertyName = path[0]
var property = self.get(propertyName)
if (property instanceof Promise) {
property.then(f)
} else {
f(property)
}
this.observe(observeProperty)
return Promise.resolve(function () {
self.unobserve(f)
})
@ -173,14 +223,15 @@
var resetObserverPath = function () {
var promise = self.get(path[0])
if (!promise instanceof Promise) {
// its either not defined or a premitive value
// its either not defined or a primitive value
promise = self.set(path[0], Y.Map)
}
return promise.then(function (map) {
return map.observePath(path.slice(1), f)
}).then(function (_deleteChildObservers) {
// update deleteChildObservers
deleteChildObservers = _deleteChildObservers
return Promise.resolve()
return Promise.resolve() // Promise does not return anything
})
}
var observer = function (events) {
@ -191,11 +242,14 @@
if (event.type === 'add' || event.type === 'update') {
resetObserverPath()
}
// TODO: what about the delete events?
}
}
}
self.observe(observer)
return resetObserverPath().then(
// this promise contains a function that deletes all the child observers
// and how to unobserve the observe from this object
Promise.resolve(function () {
deleteChildObservers()
self.unobserve(observer)
@ -223,8 +277,19 @@
yield* this.applyCreatedOperations([model])
return modelid
},
initType: function * YMapInitializer (os, model) { // eslint-disable-line
return new YMap(os, model)
initType: function * YMapInitializer (os, model) {
var contents = {}
var opContents = {}
var map = model.map
for (var name in map) {
var op = yield* this.getOperation(map[name])
if (op.opContent != null) {
opContents[name] = op.opContent
} else {
contents[name] = op.content
}
}
return new YMap(os, model, contents, opContents)
}
})
})()

View File

@ -2,7 +2,7 @@
/* eslint-env browser,jasmine */
var numberOfYMapTests = 100
var repeatMapTeasts = 10
var repeatMapTeasts = 1
describe('Map Type', function () {
var y1, y2, y3, y4, flushAll
@ -117,6 +117,18 @@ describe('Map Type', function () {
}
done()
}))
it('observePath properties', async(function * (done) {
y1.observePath(['map'], function (map) {
if (map != null) {
map.set('yay', 4)
}
})
yield y2.set('map', Y.Map)
yield flushAll()
var map = yield y3.get('map')
expect(map.get('yay')).toEqual(4)
done()
}))
it('throws add & update & delete events (with type and primitive content)', async(function * (done) {
var event
yield flushAll()
@ -170,7 +182,7 @@ describe('Map Type', function () {
function compareMapValues (maps) {
var firstMap
for (var map of maps) {
var val = map.get()
var val = map.getPrimitive()
if (firstMap == null) {
firstMap = val
} else {