braid-text 0.2.48 → 0.2.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -69
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ Or try opening the URL in [Braid-Chrome](https://github.com/braid-org/braid-chro
|
|
|
37
37
|
|
|
38
38
|
Check out the `server-demo.js` file to see examples for how to add simple access control, where a user need only enter a password into a cookie in the javascript console like: `document.cookie = 'password'`; and a `/pages` endpoint to show all the edited pages.
|
|
39
39
|
|
|
40
|
-
## General Use
|
|
40
|
+
## General Use as Server
|
|
41
41
|
|
|
42
42
|
Install it in your project:
|
|
43
43
|
```shell
|
|
@@ -94,112 +94,138 @@ http_server.on("request", (req, res) => {
|
|
|
94
94
|
- `patches`: <small style="color:lightgrey">[optional]</small> Array of patches, each of the form `{unit: 'text', range: '[1:3]', content: 'hi'}`, which would replace the second and third unicode code-points in the text with `hi`. See Braid [Range-Patches](https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-range-patch-01.txt).
|
|
95
95
|
- `peer`: <small style="color:lightgrey">[optional]</small> Identifies this peer. This mutation will not be echoed back to `get` subscriptions that use this same `peer` header.
|
|
96
96
|
|
|
97
|
-
## General Use
|
|
97
|
+
## General Use as Client
|
|
98
|
+
|
|
99
|
+
Here's a basic running example to start:
|
|
98
100
|
|
|
99
101
|
```html
|
|
102
|
+
<!-- 1. Your textarea -->
|
|
103
|
+
<textarea id="my_textarea"></textarea>
|
|
104
|
+
|
|
105
|
+
<!-- 2. Include the libraries -->
|
|
106
|
+
<script src="https://unpkg.com/braid-http@~1.3/braid-http-client.js"></script>
|
|
100
107
|
<script src="https://unpkg.com/braid-text/simpleton-client.js"></script>
|
|
101
|
-
<script>
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// Example data:
|
|
110
|
-
// state: "Hello World" // The new text
|
|
111
|
-
// patches: [{ range: [5, 5], content: " World" }] // Patches that create the new text
|
|
112
|
-
//
|
|
113
|
-
// Then return the new state of textarea as a string:
|
|
114
|
-
return new_state
|
|
115
|
-
},
|
|
116
|
-
generate_local_diff_update: (prev_state) => {
|
|
117
|
-
|
|
118
|
-
// Compute diff between prev_state ^ and the current textarea string, such as:
|
|
119
|
-
//
|
|
120
|
-
// var patches = [{
|
|
121
|
-
// range: [5, 5], // The range from position 5 to position 5
|
|
122
|
-
// content: " World" // is replaced with the string " World"
|
|
123
|
-
// }]
|
|
124
|
-
//
|
|
125
|
-
// ...to insert something after a prev_state of "Hello".
|
|
126
|
-
|
|
127
|
-
// Then return the new state (as a string) and the diff (as `patches`)
|
|
128
|
-
return {new_state, patches}
|
|
129
|
-
},
|
|
109
|
+
<!-- 3. Wire it up -->
|
|
110
|
+
<script>
|
|
111
|
+
// Connect to server
|
|
112
|
+
var simpleton = simpleton_client('https://braid.org/simpleton_example', {
|
|
113
|
+
on_state: state => my_textarea.value = state, // incoming changes
|
|
114
|
+
get_state: () => my_textarea.value // outgoing changes
|
|
130
115
|
})
|
|
131
|
-
|
|
132
|
-
...
|
|
133
|
-
|
|
134
|
-
// When changes occur in client's textarea, let simpleton know,
|
|
135
|
-
// so that it can call generate_local_diff_update() to ask for them.
|
|
136
|
-
simpleton.changed()
|
|
137
116
|
|
|
117
|
+
// Tell simpleton when user types
|
|
118
|
+
my_textarea.oninput = () => simpleton.changed()
|
|
138
119
|
</script>
|
|
139
120
|
```
|
|
140
121
|
|
|
141
|
-
|
|
122
|
+
You should see something if you run this (though the server in this example will likely ignore your changes).
|
|
142
123
|
|
|
143
|
-
|
|
124
|
+
### How It Works
|
|
125
|
+
|
|
126
|
+
The client uses a **decoupled update mechanism** for efficiency:
|
|
127
|
+
|
|
128
|
+
1. When users type, you call `simpleton.changed()` to notify the client that something changed
|
|
129
|
+
2. The client decides *when* to actually fetch and send updates based on network conditions
|
|
130
|
+
3. When ready, it calls your `get_state` function to get the current text
|
|
131
|
+
|
|
132
|
+
This design prevents network congestion and handles disconnections gracefully. For example, if you edit offline for hours, the client will send just one efficient diff when reconnecting, rather than thousands of individual keystrokes.
|
|
133
|
+
|
|
134
|
+
### Advanced Integration
|
|
135
|
+
|
|
136
|
+
For better performance and control, you can work with patches instead of full text:
|
|
137
|
+
|
|
138
|
+
#### Receiving Patches
|
|
139
|
+
|
|
140
|
+
Instead of receiving complete text updates, you can process individual changes:
|
|
144
141
|
|
|
145
142
|
```javascript
|
|
146
|
-
simpleton = simpleton_client(url,
|
|
143
|
+
var simpleton = simpleton_client(url, {
|
|
144
|
+
on_patches: (patches) => {
|
|
145
|
+
// Apply each patch to your editor..
|
|
146
|
+
},
|
|
147
|
+
get_state: () => editor.getValue()
|
|
148
|
+
})
|
|
147
149
|
```
|
|
148
150
|
|
|
149
|
-
|
|
150
|
-
- `options`: An object containing the following properties:
|
|
151
|
+
This is more efficient for large documents and helps preserve cursor position.
|
|
151
152
|
|
|
152
|
-
|
|
153
|
+
#### Custom Patch Generation
|
|
153
154
|
|
|
154
|
-
|
|
155
|
+
You can provide your own diff algorithm or use patches from your editor's API:
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
157
|
+
```javascript
|
|
158
|
+
var simpleton = simpleton_client(url, {
|
|
159
|
+
on_state: state => editor.setValue(state),
|
|
160
|
+
get_state: () => editor.getValue(),
|
|
161
|
+
get_patches: (prev_state) => {
|
|
162
|
+
// Use your own diff algorithm or editor's change tracking
|
|
163
|
+
return compute_patches(prev_state, editor.getValue())
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
```
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
- `range`: An array of two numbers, `[start, end]`, specifying the start and end positions of the characters to be deleted.
|
|
162
|
-
- `content`: The text to be inserted in place of the deleted characters.
|
|
168
|
+
See [editor.html](https://github.com/braid-org/braid-text/blob/master/editor.html) for a complete example with CodeMirror integration.
|
|
163
169
|
|
|
164
|
-
|
|
170
|
+
## Client API
|
|
171
|
+
|
|
172
|
+
### Constructor
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
simpleton = simpleton_client(url, options)
|
|
176
|
+
```
|
|
165
177
|
|
|
166
|
-
|
|
178
|
+
Creates a new Simpleton client that synchronizes with a Braid-Text server.
|
|
167
179
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
180
|
+
**Parameters:**
|
|
181
|
+
- `url`: The URL of the resource to synchronize with
|
|
182
|
+
- `options`: Configuration object with the following properties:
|
|
171
183
|
|
|
172
|
-
|
|
184
|
+
#### Required Options
|
|
173
185
|
|
|
174
|
-
|
|
186
|
+
- `get_state`: **[required]** Function that returns the current text state
|
|
187
|
+
```javascript
|
|
188
|
+
() => current_text_string
|
|
189
|
+
```
|
|
175
190
|
|
|
176
|
-
|
|
191
|
+
#### Incoming Updates (choose one)
|
|
177
192
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
193
|
+
- `on_state`: <small style="color:lightgrey">[optional]</small> Callback for receiving complete state updates
|
|
194
|
+
```javascript
|
|
195
|
+
(state) => { /* update your UI with new text */ }
|
|
196
|
+
```
|
|
181
197
|
|
|
182
|
-
|
|
198
|
+
- `on_patches`: <small style="color:lightgrey">[optional]</small> Callback for receiving incremental changes
|
|
199
|
+
```javascript
|
|
200
|
+
(patches) => { /* apply patches to your editor */ }
|
|
201
|
+
```
|
|
202
|
+
Each patch has:
|
|
203
|
+
- `range`: `[start, end]` - positions to delete (in original text coordinates)
|
|
204
|
+
- `content`: Text to insert at that position
|
|
205
|
+
|
|
206
|
+
**Note:** All patches reference positions in the original text before any patches are applied.
|
|
183
207
|
|
|
184
|
-
|
|
185
|
-
(prev_state) => patches
|
|
186
|
-
```
|
|
208
|
+
#### Outgoing Updates
|
|
187
209
|
|
|
188
|
-
|
|
210
|
+
- `get_patches`: <small style="color:lightgrey">[optional]</small> Custom function to generate patches
|
|
211
|
+
```javascript
|
|
212
|
+
(previous_state) => array_of_patches
|
|
213
|
+
```
|
|
214
|
+
If not provided, uses a simple prefix/suffix diff algorithm.
|
|
189
215
|
|
|
190
|
-
|
|
216
|
+
#### Additional Options
|
|
191
217
|
|
|
192
|
-
|
|
218
|
+
- `content_type`: <small style="color:lightgrey">[optional]</small> MIME type for `Accept` and `Content-Type` headers
|
|
193
219
|
|
|
194
220
|
### Methods
|
|
195
221
|
|
|
196
|
-
- `simpleton.changed()`:
|
|
222
|
+
- `simpleton.changed()`: Notify the client that local changes have occurred. Call this in your editor's change event handler. The client will call `get_patches` and `get_state` when it's ready to send updates.
|
|
197
223
|
|
|
198
224
|
### Deprecated Options
|
|
199
225
|
|
|
200
226
|
The following options are deprecated and should be replaced with the new API:
|
|
201
227
|
|
|
202
|
-
- ~~`apply_remote_update`~~ → Use `on_patches`
|
|
228
|
+
- ~~`apply_remote_update`~~ → Use `on_patches` or `on_state` instead
|
|
203
229
|
- ~~`generate_local_diff_update`~~ → Use `get_patches` and `get_state` instead
|
|
204
230
|
|
|
205
231
|
## Testing
|