summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortheia2023-02-09 13:31:50 -0500
committertheia2023-02-09 13:31:50 -0500
commit7413cb9d937986fd11936730d6773f1a270eba48 (patch)
treef4cf8042e736dda7b3e5202de1b9614ec3c7c185
parent5b951766757d89a4ab91457e8dbeabc50164ccdc (diff)
more robust object editing
-rw-r--r--demo/index.html1
-rw-r--r--graffiti.js92
2 files changed, 45 insertions, 48 deletions
diff --git a/demo/index.html b/demo/index.html
index 1f05b25..d1b5991 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -11,7 +11,6 @@
"vue": "https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.45/vue.esm-browser.prod.min.js",
"graffiti-vue": "../plugins/vue/plugin.js"
}}</script>
- <!--"graffiti-vue": "https://graffiti.garden/graffiti-js/plugins/vue/plugin.js"-->
<script type="module">
import { createApp } from 'vue'
import { Name, SetMyName } from './components/name.js'
diff --git a/graffiti.js b/graffiti.js
index 59e71eb..65c6ece 100644
--- a/graffiti.js
+++ b/graffiti.js
@@ -93,10 +93,10 @@ export default class {
const data = await dataPromise
delete data.messageID
- if (data.type == 'error') {
+ if ('error' in data) {
throw data
} else {
- return data['reply']
+ return data.reply
}
}
@@ -137,41 +137,36 @@ export default class {
if (!subscribed) return
- // Store the original object in case
- // there is an error with the update
- const originalObject = uuid in this.objectMap?
- Object.assign({},this.objectMap[uuid]) : null
+ // Define object specific properties
+ if (!('_id' in object)) {
+ // Assign the object UUID
+ Object.defineProperty(object, '_id', { value: uuid })
- // Assign the object UUID
- Object.defineProperty(object, '_id', { value: uuid })
-
- // Add proxy functions so object modifications
- // sync with the server
- const handler = {
- get: (target, prop, receiver)=>
- this.#getObjectProperty(handler, target, prop, receiver),
- set: (target, prop, val, receiver)=>
- this.#setObjectProperty(object, target, prop, val, receiver),
- deleteProperty: (target, prop)=>
- this.#deleteObjectProperty(object, target, prop)
+ // Add proxy functions so object modifications
+ // sync with the server
+ object = new Proxy(object, this.#objectHandler(object, true))
}
- this.objectMap[uuid] = new Proxy(object, handler)
- // Return the original in case of failure
- return originalObject
+ this.objectMap[uuid] = object
}
#removeCallback(object) {
const uuid = this.#objectUUID(object)
- // Remove the UUID from the tag map
- for (const tag of object._tags) {
- if (!(tag in this.tagMap)) continue
- this.tagMap[tag].uuids.delete(uuid)
+ // Remove the UUID from all relevant tag maps
+ let supported = false
+ for (const tag in this.tagMap) {
+ if (this.tagMap[tag].uuids.has(uuid)) {
+ if (object._tags.includes(tag)) {
+ this.tagMap[tag].uuids.delete(uuid)
+ } else {
+ supported = true
+ }
+ }
}
- // And the object map
- if (uuid in this.objectMap) {
+ // If all tags have been removed, delete entirely
+ if (!supported && uuid in this.objectMap) {
delete this.objectMap[uuid]
}
}
@@ -181,37 +176,46 @@ export default class {
if (!object._key) object._key = crypto.randomUUID()
// Immediately replace the object
- const originalObject = this.#updateCallback(object)
+ this.#updateCallback(object)
// Send it to the server
try {
await this.#request({ update: object })
} catch(e) {
- if (originalObject) {
- // Restore the original object
- this.#updateCallback(originalObject)
- } else {
- // Delete the temp object
- this.#removeCallback(object)
- }
+ // Delete the temp object
+ this.#removeCallback(object)
throw e
}
}
- #getObjectProperty(handler, target, prop, receiver) {
+ #objectHandler(object, root) {
+ return {
+ get: (target, prop, receiver)=>
+ this.#getObjectProperty(object, target, prop, receiver),
+ set: (target, prop, val, receiver)=>
+ this.#setObjectProperty(object, root, target, prop, val, receiver),
+ deleteProperty: (target, prop)=>
+ this.#deleteObjectProperty(object, root, target, prop)
+ }
+ }
+
+ #getObjectProperty(object, target, prop, receiver) {
if (typeof target[prop] === 'object' && target[prop] !== null) {
- return new Proxy(Reflect.get(target, prop, receiver), handler)
+ return new Proxy(Reflect.get(target, prop, receiver), this.#objectHandler(object, false))
} else {
return Reflect.get(target, prop, receiver)
}
}
- #setObjectProperty(object, target, prop, val, receiver) {
+ #setObjectProperty(object, root, target, prop, val, receiver) {
// Store the original, perform the update,
// sync with server and restore original if error
const originalObject = Object.assign({}, object)
if (Reflect.set(target, prop, val, receiver)) {
+ this.#removeCallback(originalObject)
+ this.#updateCallback(object)
this.#request({ update: object }).catch(e=> {
+ this.#removeCallback(object)
this.#updateCallback(originalObject)
throw e
})
@@ -219,17 +223,11 @@ export default class {
} else { return false }
}
- #deleteObjectProperty(object, target, prop) {
+ #deleteObjectProperty(object, root, target, prop) {
const originalObject = Object.assign({}, object)
- if (object==target && ['_key', '_by', '_tags'].includes(prop)) {
+ if (root && ['_key', '_by', '_tags'].includes(prop)) {
// This is a deletion of the whole object
- const uuid = this.#objectUUID(object)
- for (const tag of object._tags) {
- if (!(tag in this.tagMap)) continue
- this.tagMap[tag].uuids.delete(uuid)
- }
- if (!(uuid in this.objectMap)) return false
- delete this.objectMap[uuid]
+ this.#removeCallback(object)
this.#request({ remove: object._key }).catch(e=> {
this.#updateCallback(originalObject)
throw e