diff options
-rw-r--r-- | README.md | 64 | ||||
-rw-r--r-- | graffiti.js | 20 | ||||
-rw-r--r-- | test.html | 97 |
3 files changed, 102 insertions, 79 deletions
@@ -3,66 +3,4 @@ This is the base Javascript library that interfaces with the [Graffiti server](https://github.com/graffiti-garden/server). We recommend not using this vanilla library itself but instead using framework plugins that are built on top of it like the [Graffiti plugin for Vue.JS](https://github.com/graffiti-garden/graffiti-x-vue). -Example usage: - -```javascript -import Graffiti from "https://graffiti-garden.github.io/graffiti-x-js/graffiti.js" - -// You can initialize a connection to the graffiti server -const graffiti = Graffiti() -await graffiti.initialize() - -// You can subscribe to queries -const queryID = await graffiti.subscribe({ - type: 'post', - content: { $type: 'string' } - } - // With an arbitrary update callback - (obj) => console.log(`An object has been created: {obj}`), - // and remove callback - (obj) => console.log(`An object with id {obj._id} by user {obj._by} has been removed.`) -) - -// And then unsubscribe to those queries -await graffiti.unsubscribe(queryID) - -// You can toggle logging in and out -graffiti.toggleLogIn() - -// When you are logged in you can reference your user ID -console.log(graffiti.myID) - -// And when you are logged in you can -// create objects, -const myCoolPost = { - type: 'post', - content: 'hello world' -} -// ("completing" an object annotates -// it with your user ID and a random -// object ID, required by the server) -graffiti.complete(myCoolPost) -await graffiti.update(myCoolPost, {}) - -// replace objects, -myCoolPost.content += '!!!' -await graffiti.update(myCoolPost, {}) - -// and remove objects. -await graffiti.remove(myCoolPost) - -// The second argument in the update -// function is a query. If the object you -// try to add does not match the query -// it will be rejected. This prevents -// you from accidentally creating data -// that gets "lost". -const query = { type: 'post' } -const myPost = { type: 'post' } -const myNotPost = { type: 'notpost' } -graffiti.complete(myNotPost) -// This works -await graffiti.update(myPost, query) -// But this won't work! -await graffiti.update(myNotPost, query) -``` +If you create a [local Graffiti instance](https://github.com/graffiti-garden/server#local-usage) and a local webserver in this directory (*e.g.* `python3 -m http.server`) and navigate to `test.html` (*e.g.* [http://localhost:8000/test.html](http://localhost:8000/test.html)) you should be able to log in and test each of the Graffiti primitives: `subscribe`, `unsubscribe`, `update`, `remove`. These primitives will be robust to spamming and network interruptions. diff --git a/graffiti.js b/graffiti.js index 5db4eff..0314b85 100644 --- a/graffiti.js +++ b/graffiti.js @@ -126,18 +126,12 @@ export default class { } async update(object, query) { - const data = await this.request({ - type: "update", - object, query - }) + const data = await this.request({ object, query }) return data.objectID } async remove(objectID) { - await this.request({ - type: "remove", - objectID - }) + await this.request({ objectID }) } async subscribe( @@ -152,10 +146,7 @@ export default class { if (!queryID) queryID = crypto.randomUUID() // Send the request - await this.request({ - type: "subscribe", - queryID, query, since, ...flags - }) + await this.request({ queryID, query, since, ...flags }) // Store the subscription in case of disconnections this.subscriptionData[queryID] = { @@ -171,10 +162,7 @@ export default class { delete this.subscriptionData[queryID] // And unsubscribe - const data = await this.request({ - type: "unsubscribe", - queryID - }) + const data = await this.request({ queryID }) } async onOpen() { diff --git a/test.html b/test.html new file mode 100644 index 0000000..3a0d853 --- /dev/null +++ b/test.html @@ -0,0 +1,97 @@ +<!DOCTYPE html> +<html> +<body> + <h1> Graffiti x JS </h1> + + <p id="ID"></p> + + <h2 id="status">Unsubscribed</h2> + + <button onclick="Subscribe()"> + Subscribe + </button> + + <button onclick="Unsubscribe()"> + Unsubscribe + </button> + + <button onclick="Update()"> + Update + </button> + + <button onclick="Remove()"> + Remove + </button> + + <button onclick="LogOut()"> + Log Out + </button> + +<script type="module"> + import Graffiti from "./graffiti.js" + + // Connect to a local Graffiti instance + // (see the server README for how to run locally) + const graffiti = new Graffiti("http://localhost:5001") + await graffiti.initialize() + + // Log in automatically if not already + // and supply a log out button + if (!graffiti.myID) graffiti.toggleLogIn() + window.LogOut = ()=> graffiti.toggleLogIn() + document.getElementById('ID').innerHTML = `Your Graffiti ID is: ${graffiti.myID}` + + // Create a display counter + let count = 0 + function displayCount() { + document.getElementById('status').innerHTML = `Subscribed: ${count} Objects` + } + + // From here to below we're going to + // define functions that can be activated + // with button presses, corresponding to + // each of the four Graffiti primitives. + + // Create an object containing a special string + const special = crypto.randomUUID() + const usedIDs = [] + window.Update = async function() { + usedIDs.unshift(crypto.randomUUID()) + await graffiti.update({ + _id: usedIDs[0], + _by: graffiti.myID, + special + }, {}) + } + + // Remove an existing object + window.Remove = async function() { + if ( usedIDs.length ) { + await graffiti.remove( usedIDs.pop() ) + } + } + + // Subscribe to objects containing the special string + let queryID = null + window.Subscribe = async function() { + if (queryID) return + count = 0 + queryID = await graffiti.subscribe( + { special }, + (obj)=> { count++; displayCount() }, + (obj)=> { count--; displayCount() } + ) + displayCount() + } + + // Unsubscribe to the existing query + window.Unsubscribe = async function() { + if (queryID) { + await graffiti.unsubscribe(queryID) + queryID = null + document.getElementById('status').innerHTML = "Unsubscribed" + } + } +</script> +</body> +</html> |