braid-text 0.2.64 → 0.2.65

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/editor.html CHANGED
@@ -1,81 +1,23 @@
1
- <body style="background: auto; margin: 0px; padding: 0px">
2
- <textarea
3
- id="texty"
4
- style="width: 100%; height: 100%; box-sizing: border-box"
5
- ></textarea>
1
+ <body style="margin: 0px; padding: 0px; box-sizing: border-box">
2
+ <textarea id="the_editor" style="width: 100%; height: 100%;"></textarea>
6
3
  </body>
7
4
  <script src="https://braid.org/code/myers-diff1.js"></script>
8
5
  <script src="https://unpkg.com/braid-http@~1.3/braid-http-client.js"></script>
6
+ <script src="/web-utils.js"></script>
9
7
  <script src="/simpleton-client.js"></script>
10
8
  <script>
9
+
11
10
  let simpleton = simpleton_client(location.pathname, {
12
- on_patches: (patches) => apply_patches_and_update_selection(texty, patches),
13
- get_patches: (prev_state) => diff(prev_state, texty.value),
14
- get_state: () => texty.value,
15
- on_error: (e) => {
16
- texty.disabled = true
17
- texty.style.background = '#fee'
18
- texty.style.border = '4px solid red'
19
- },
20
- on_ack: () => texty.style.caretColor = ''
11
+ on_patches: (patches) => apply_patches_and_update_selection(the_editor, patches),
12
+ get_patches: (prev_state) => diff(prev_state, the_editor.value),
13
+ get_state: () => the_editor.value,
14
+ on_error: (e) => set_error_state(the_editor),
15
+ on_ack: () => set_acked_state(the_editor)
21
16
  });
22
17
 
23
- texty.value = "";
24
- texty.oninput = (e) => {
25
- texty.style.caretColor = 'red'
26
- simpleton.changed();
27
- }
28
-
29
- function diff(before, after) {
30
- let diff = diff_main(before, after);
31
- let patches = [];
32
- let offset = 0;
33
- for (let d of diff) {
34
- let p = null;
35
- if (d[0] == 1) p = { range: [offset, offset], content: d[1] };
36
- else if (d[0] == -1) {
37
- p = { range: [offset, offset + d[1].length], content: "" };
38
- offset += d[1].length;
39
- } else offset += d[1].length;
40
- if (p) {
41
- p.unit = "text";
42
- patches.push(p);
43
- }
44
- }
45
- return patches;
18
+ the_editor.oninput = (e) => {
19
+ set_acked_state(the_editor, false)
20
+ simpleton.changed()
46
21
  }
47
22
 
48
- function apply_patches_and_update_selection(textarea, patches) {
49
- let offset = 0;
50
- for (let p of patches) {
51
- p.range[0] += offset;
52
- p.range[1] += offset;
53
- offset -= p.range[1] - p.range[0];
54
- offset += p.content.length;
55
- }
56
-
57
- let original = textarea.value;
58
- let sel = [textarea.selectionStart, textarea.selectionEnd];
59
-
60
- for (var p of patches) {
61
- let range = p.range;
62
-
63
- for (let i = 0; i < sel.length; i++)
64
- if (sel[i] > range[0])
65
- if (sel[i] > range[1]) sel[i] -= range[1] - range[0];
66
- else sel[i] = range[0];
67
-
68
- for (let i = 0; i < sel.length; i++)
69
- if (sel[i] > range[0]) sel[i] += p.content.length;
70
-
71
- original =
72
- original.substring(0, range[0]) +
73
- p.content +
74
- original.substring(range[1]);
75
- }
76
-
77
- textarea.value = original;
78
- textarea.selectionStart = sel[0];
79
- textarea.selectionEnd = sel[1];
80
- }
81
23
  </script>
@@ -1,309 +1,98 @@
1
- <html lang="en">
2
- <script type="statebus">
3
- dom.BODY = -> DIV(WIKI())
4
- </script>
5
1
  <meta name="viewport" content="width=device-width,initial-scale=.62"/>
6
-
7
- <script src="https://stateb.us/client6.js" server="none"></script>
8
2
  <script src="https://invisible.college/js/marked.min.js"></script>
9
-
10
3
  <script src="https://braid.org/code/myers-diff1.js"></script>
11
- <script>
12
- window.statebus_fetch = window.fetch
13
- window.fetch = window.og_fetch
14
- </script>
15
4
  <script src="https://unpkg.com/braid-http@~1.3/braid-http-client.js"></script>
16
- <script>
17
- window.fetch = window.statebus_fetch
18
- </script>
5
+ <script src="/web-utils.js"></script>
19
6
  <script src="/simpleton-client.js"></script>
20
-
7
+ <body>
8
+ <div id="markdown_container" style="max-width: 750px; padding: 10px 60px"></div>
9
+ <div id="bottom_spacer" style="height: 50vh; display: none;"></div>
10
+ <textarea
11
+ id="the_editor"
12
+ style="
13
+ position: fixed;
14
+ bottom: 0;
15
+ right: 0;
16
+ width: 45vw;
17
+ height: 100%;
18
+ font-size: 15px;
19
+ font-family: helvetica, arial, avenir, lucida grande;
20
+ hyphens: none;
21
+ "></textarea>
22
+ <div
23
+ id="edit-button"
24
+ style="
25
+ position: fixed;
26
+ bottom: 0;
27
+ right: 0;
28
+ padding: 30px;
29
+ cursor: pointer;
30
+ text-decoration: none;
31
+ background-color: rgba(250, 250, 250, .5);
32
+ " onclick="toggle_editor()">edit</div>
33
+ </body>
21
34
  <script>
22
35
 
23
- var apply_patches_and_update_selection, diff, first_time, i, j, render_delay, scroll, t, timer, ting, toggle_editor, update_markdown, update_markdown_later;
24
-
25
- t = function() {
26
- return document.getElementById('the editor');
27
- };
36
+ var editing = false
37
+ var first_time = true
38
+ var render_timer = null
39
+ var render_delay = 100
28
40
 
29
41
  var simpleton = simpleton_client(location.pathname, {
30
42
  on_patches: (patches) => {
31
- apply_patches_and_update_selection(t(), patches);
32
- state.source = t().value;
33
- update_markdown_later();
34
- },
35
- get_patches: (prev_state) => diff(prev_state, t().value),
36
- get_state: () => t().value,
37
-
38
- on_error: (e) => {
39
- t().disabled = true
40
- t().style.background = '#fee'
41
- t().style.border = '4px solid red'
43
+ apply_patches_and_update_selection(the_editor, patches)
44
+ update_markdown_later()
42
45
  },
46
+ get_patches: (prev_state) => diff(prev_state, the_editor.value),
47
+ get_state: () => the_editor.value,
48
+ on_error: (e) => set_error_state(the_editor),
49
+ on_ack: () => set_acked_state(the_editor)
50
+ })
51
+
52
+ the_editor.oninput = (e) => {
53
+ set_acked_state(the_editor, false)
54
+ simpleton.changed()
55
+ update_markdown_later()
56
+ }
43
57
 
44
- on_ack: () => t().style.caretColor = ''
45
- });
46
-
47
- window.statebus_ready || (window.statebus_ready = []);
48
-
49
- window.statebus_ready.push(function() {
50
- state.vert = true;
51
- state.editing = false;
52
- state.source = '';
53
- // Toggle the editor with keyboard or edit button
54
- document.body.onkeydown = function(e) {
55
- if (e.keyCode === 27) { // Escape key
56
- e.stopPropagation();
57
- toggle_editor();
58
- }
59
- };
60
- // Switch to vertical layout when you resize
61
- window.onresize = function() {
62
- return state.vert = window.innerWidth < 1200;
63
- };
64
- return onresize();
65
- });
66
-
67
- // Diffing and Patching Utilities
68
- diff = function(before, after) {
69
- var d, diff2, j, len, offset, p, patches;
70
- diff2 = diff_main(before, after);
71
- // Now we just need to reformat the output from diff_main into some
72
- // nice json objects
73
- patches = [];
74
- offset = 0;
75
- for (j = 0, len = diff2.length; j < len; j++) {
76
- d = diff2[j];
77
- p = null;
78
- if (d[0] === 1) {
79
- p = {
80
- range: [offset, offset],
81
- content: d[1]
82
- };
83
- } else if (d[0] === -1) {
84
- p = {
85
- range: [offset, offset + d[1].length],
86
- content: ''
87
- };
88
- offset += d[1].length;
89
- } else {
90
- offset += d[1].length;
91
- }
92
- if (p) {
93
- patches.push(p);
94
- }
95
- }
96
- return patches;
97
- };
98
-
99
- apply_patches_and_update_selection = function(textarea, patches) {
100
- var i, j, k, l, len, len1, m, offset, original, p, range, ref, ref1, sel;
101
- // convert from absolute to relative coordinates
102
- offset = 0;
103
- for (j = 0, len = patches.length; j < len; j++) {
104
- p = patches[j];
105
- p.range[0] += offset;
106
- p.range[1] += offset;
107
- offset -= p.range[1] - p.range[0];
108
- offset += p.content.length;
109
- }
110
- original = textarea.value;
111
- sel = [
112
- textarea.selectionStart,
113
- textarea.selectionEnd // Current cursor & selection
114
- ];
115
- for (k = 0, len1 = patches.length; k < len1; k++) {
116
- p = patches[k];
117
- range = p.range;
118
- // Update the cursor locations
119
- for (i = l = 0, ref = sel.length; (0 <= ref ? l < ref : l > ref); i = 0 <= ref ? ++l : --l) {
120
- if (sel[i] > range[0]) {
121
- if (sel[i] > range[1]) {
122
- sel[i] -= range[1] - range[0];
123
- } else {
124
- sel[i] = range[0];
125
- }
126
- }
127
- }
128
- for (i = m = 0, ref1 = sel.length; (0 <= ref1 ? m < ref1 : m > ref1); i = 0 <= ref1 ? ++m : --m) {
129
- if (sel[i] > range[0]) {
130
- sel[i] += p.content.length;
131
- }
132
- }
133
- // Update the text with the new value
134
- original = original.substring(0, range[0]) + p.content + original.substring(range[1]);
135
- }
136
- textarea.value = original;
137
- textarea.selectionStart = sel[0];
138
- return textarea.selectionEnd = sel[1];
139
- };
140
-
141
- // Render everything
142
- dom.WIKI = function() {
143
- var o;
144
- // output
145
- return DIV({}, DIV({
146
- className: 'pad',
147
- maxWidth: 750,
148
- width: state.editing && !state.vert ? '55vw' : void 0
149
- }, (function() {
150
- var j, len, ref, results;
151
- ref = state.outputs || [];
152
- results = [];
153
- for (j = 0, len = ref.length; j < len; j++) {
154
- o = ref[j];
155
- results.push(DIV({
156
- dangerouslySetInnerHTML: {
157
- __html: o
158
- }
159
- }));
160
- }
161
- return results;
162
- // bottom pad
163
- })()), DIV({
164
- height: '50vh',
165
- display: !state.editing || !state.vert ? 'none' : void 0
166
- }), TEXTAREA({
167
- position: 'fixed',
168
- hyphens: 'none',
169
- bottom: 0,
170
- right: 0,
171
- width: state.vert ? '100%' : '45vw',
172
- height: state.vert ? '50vh' : '100%',
173
- display: !state.editing ? 'none' : void 0,
174
- fontSize: 15,
175
- fontFamily: 'helvetica, arial, avenir, lucida grande',
176
- id: 'the editor',
177
- onChange: function(e) {
178
- if (!e.target.value && e.target.value !== '') {
179
- return;
180
- }
181
- // Bail on edits that try to wipe us out
182
- state.source = e.target.value;
183
- e.target.style.caretColor = 'red'
184
- simpleton.changed();
185
- return update_markdown_later();
186
- },
187
- defaultValue: state.source
188
- }), DIV({
189
- position: 'fixed',
190
- bottom: 0,
191
- right: 0,
192
- padding: 30,
193
- cursor: 'pointer',
194
- textDecoration: 'none',
195
- backgroundColor: 'rgba(250, 250, 250, .5)',
196
- onClick: toggle_editor
197
- }, 'edit'));
198
- };
199
-
200
- // Render markdown after a delay
201
- timer = null;
202
-
203
- render_delay = 100;
204
-
205
- update_markdown_later = function() {
206
- if (timer) {
207
- clearTimeout(timer);
208
- }
209
- return timer = setTimeout(update_markdown, render_delay);
210
- };
211
-
212
- update_markdown = function() {
213
- var e, i, j, len, parse_markdown, ref, results, s, sources;
214
- parse_markdown = function() {
215
- var match, matches;
216
- matches = (function() {
217
- var results;
218
- results = [];
219
- while (match = /\n\|{3,}([^\n]*)\n/g.exec(state.source)) {
220
- results.push(match[1]);
221
- }
222
- return results;
223
- })();
224
- return matches;
225
- };
226
- try {
227
- if (!state.source) {
228
- return;
229
- }
230
- sources = state.source.split(/\n\|{3,}[^\n]*\n/g);
231
- timer = null;
232
- if (!state.sources || sources.length !== state.sources.length) {
233
- state.sources = sources.splice();
234
- state.outputs = (function() {
235
- var j, len, results;
236
- results = [];
237
- for (j = 0, len = sources.length; j < len; j++) {
238
- s = sources[j];
239
- results.push(marked(s, {
240
- sanitize: false
241
- }));
242
- }
243
- return results;
244
- })();
245
- return document.body.className = 'nopad';
246
- } else {
247
- ref = state.sources;
248
- // But most of the time we just redo one section
249
- results = [];
250
- for (i = j = 0, len = ref.length; j < len; i = ++j) {
251
- s = ref[i];
252
- if (s !== sources[i]) {
253
- state.sources[i] = sources[i];
254
- results.push(state.outputs[i] = marked(s, {
255
- sanitize: false
256
- }));
257
- } else {
258
- results.push(void 0);
259
- }
260
- }
261
- return results;
262
- }
263
- } catch (error) {
264
- e = error;
265
- return console.error('parse failure with', e);
58
+ document.body.onkeydown = (e) => {
59
+ if (e.keyCode === 27) { // Escape key
60
+ e.stopPropagation()
61
+ toggle_editor()
266
62
  }
267
- };
268
-
269
- update_markdown();
63
+ }
270
64
 
271
- first_time = true;
65
+ window.onresize = update_layout
272
66
 
273
- toggle_editor = function() {
274
- state.editing = !state.editing;
275
- if (state.editing) {
276
- t().focus();
277
- }
278
- if (state.editing && first_time) {
279
- first_time = false;
280
- t().setSelectionRange(0, 0);
281
- t().scrollTop = 0;
282
- }
283
- return update_markdown();
284
- };
67
+ update_layout()
285
68
 
286
- // Support #hashtag scrolling into view
287
- ting = null;
69
+ function update_layout() {
70
+ var vert = window.innerWidth < 1200
71
+ markdown_container.style.width = editing && !vert ? '55vw' : ''
72
+ bottom_spacer.style.display = !editing || !vert ? 'none' : ''
73
+ the_editor.style.width = vert ? '100%' : '45vw'
74
+ the_editor.style.height = vert ? '50vh' : '100%'
75
+ the_editor.style.display = !editing ? 'none' : ''
76
+ }
288
77
 
289
- scroll = function() {
290
- // We only scroll to the ting once -- if it's fresh
291
- if (ting || location.hash.length === 0) {
292
- return;
78
+ function toggle_editor() {
79
+ editing = !editing
80
+ update_layout()
81
+ if (editing) the_editor.focus()
82
+ if (editing && first_time) {
83
+ first_time = false
84
+ the_editor.setSelectionRange(0, 0)
85
+ the_editor.scrollTop = 0
293
86
  }
294
- ting = document.getElementById(location.hash.substr(1));
295
- return ting && ting.scrollIntoView();
296
- };
87
+ }
297
88
 
298
- for (i = j = 0; j <= 50; i = ++j) {
299
- setTimeout(scroll, i / 5.0 * 1000);
89
+ function update_markdown_later() {
90
+ if (render_timer) clearTimeout(render_timer)
91
+ render_timer = setTimeout(update_markdown, render_delay)
300
92
  }
301
93
 
302
- </script>
94
+ function update_markdown() {
95
+ markdown_container.innerHTML = marked(the_editor.value, { sanitize: false })
96
+ }
303
97
 
304
- <link rel="stylesheet" href="https://invisible.college/css/github-markdown.css">
305
- <style>
306
- body{-ms-hyphens: auto;-webkit-hyphens: auto;hyphens: auto;}
307
- h1,h2,h3,h4 {text-align: left; -ms-hyphens: none; -webkit-hyphens: none; hyphens: none;}
308
- note {position: absolute; left: 720px; width: 270px; background-color: #F8F3B7; padding: 10px; box-shadow: -2px 2px 2px #ccc; border-radius: 2px; text-align: left;}
309
- </style>
98
+ </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.2.64",
3
+ "version": "0.2.65",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-text",
package/server-demo.js CHANGED
@@ -13,21 +13,16 @@ var server = require("http").createServer(async (req, res) => {
13
13
  braid_text.free_cors(res)
14
14
  if (req.method === 'OPTIONS') return res.end()
15
15
 
16
- if (req.url.endsWith("?editor")) {
16
+ var q = req.url.split('?').slice(-1)[0]
17
+ if (q === 'editor' || q === 'markdown-editor') {
17
18
  res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-cache" })
18
- require("fs").createReadStream("./editor.html").pipe(res)
19
+ require("fs").createReadStream(`./${q}.html`).pipe(res)
19
20
  return
20
21
  }
21
22
 
22
- if (req.url.endsWith("?markdown-editor")) {
23
- res.writeHead(200, { "Content-Type": "text/html", "Cache-Control": "no-cache" })
24
- require("fs").createReadStream("./markdown-editor.html").pipe(res)
25
- return
26
- }
27
-
28
- if (req.url == '/simpleton-client.js') {
23
+ if (req.url === '/simpleton-client.js' || req.url === '/web-utils.js') {
29
24
  res.writeHead(200, { "Content-Type": "text/javascript", "Cache-Control": "no-cache" })
30
- require("fs").createReadStream("./simpleton-client.js").pipe(res)
25
+ require("fs").createReadStream("." + req.url).pipe(res)
31
26
  return
32
27
  }
33
28
 
package/web-utils.js ADDED
@@ -0,0 +1,75 @@
1
+
2
+ function set_acked_state(textarea, binary = true) {
3
+ if (!binary) {
4
+ textarea.old_caretColor = textarea.style.caretColor
5
+
6
+ textarea.style.caretColor = 'red'
7
+ } else {
8
+ textarea.style.caretColor = textarea.old_caretColor
9
+ }
10
+ }
11
+
12
+ function set_error_state(textarea, binary = true) {
13
+ if (binary) {
14
+ textarea.old_disabled = textarea.disabled
15
+ textarea.old_background = textarea.style.background
16
+ textarea.old_border = textarea.style.border
17
+
18
+ textarea.disabled = true
19
+ textarea.style.background = '#fee'
20
+ textarea.style.border = '4px solid red'
21
+ } else {
22
+ textarea.disabled = textarea.old_disabled
23
+ textarea.style.background = textarea.old_background
24
+ textarea.style.border = textarea.old_border
25
+ }
26
+ }
27
+
28
+ function diff(before, after) {
29
+ let diff = diff_main(before, after)
30
+ let patches = []
31
+ let offset = 0
32
+ for (let d of diff) {
33
+ let p = null
34
+ if (d[0] === 1) p = { range: [offset, offset], content: d[1] }
35
+ else if (d[0] === -1) {
36
+ p = { range: [offset, offset + d[1].length], content: "" }
37
+ offset += d[1].length
38
+ } else offset += d[1].length
39
+ if (p) {
40
+ p.unit = "text"
41
+ patches.push(p)
42
+ }
43
+ }
44
+ return patches
45
+ }
46
+
47
+ function apply_patches_and_update_selection(textarea, patches) {
48
+ let offset = 0
49
+ for (let p of patches) {
50
+ p.range[0] += offset
51
+ p.range[1] += offset
52
+ offset -= p.range[1] - p.range[0]
53
+ offset += p.content.length
54
+ }
55
+
56
+ let original = textarea.value
57
+ let sel = [textarea.selectionStart, textarea.selectionEnd]
58
+
59
+ for (var p of patches) {
60
+ let range = p.range
61
+
62
+ for (let i = 0; i < sel.length; i++)
63
+ if (sel[i] > range[0])
64
+ if (sel[i] > range[1]) sel[i] -= range[1] - range[0]
65
+ else sel[i] = range[0]
66
+
67
+ for (let i = 0; i < sel.length; i++) if (sel[i] > range[0]) sel[i] += p.content.length
68
+
69
+ original = original.substring(0, range[0]) + p.content + original.substring(range[1])
70
+ }
71
+
72
+ textarea.value = original
73
+ textarea.selectionStart = sel[0]
74
+ textarea.selectionEnd = sel[1]
75
+ }