test
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

so tired

12Me21 7258e218 a2c39bb1

+214 -12
+5 -5
editor.js
··· 21 21 return 22 22 } 23 23 lock = true 24 - this.update() 24 + this.oninput() 25 25 setTimeout(()=>{ 26 26 lock = false 27 27 if (missed) 28 - this.update() 28 + this.oninput() 29 29 }) 30 30 }, {passive: true}) 31 + this.oninput = null 31 32 } 32 - update() { 33 - let text = this.textarea.value 34 - this.overlay.textContent = text 33 + set_overlay(spans) { 34 + this.overlay.replaceChildren(...spans) 35 35 } 36 36 reset_textarea(text="") { 37 37 this.textarea.value = text
+2 -6
facet.js
··· 1 - import {index_to_byteindex, byteindex_to_index} from './byteindex.js' 1 + import {index_to_byteindex} from './byteindex.js' 2 2 3 3 // stages: 4 4 // 1: list of "spans" {start:Number, end:Number, strip:[Number,Number], feature:Feature} - can overlap etc. ··· 33 33 for (let [index,span] of edges) { 34 34 if (index > last && open.size) 35 35 this.windows.push({start: last, end: index, spans: [...open]}) 36 - open.delete(span) || open.add(span) // toggle 36 + if (!open.delete(span)) open.add(span) // toggle 37 37 last = index 38 38 } 39 39 // propagate strips ··· 119 119 return {text, facets} 120 120 } 121 121 } 122 - 123 - function facets_to_segments() { 124 - 125 - }
+184
markup2.js
··· 1 + let r = String.raw 2 + let whitespace = r`\s\u00AD\u2060\u200A\u200B\u200C\u200D\u20e2` 3 + let url = r`[-\w/%&=#+~@$*'!?,.;:]*` 4 + let url_final = r`[-\w/%&=#+~@$*']` 5 + const STYLE_START 6 + = /^[\s,][^\s,]|^['"}{(>|\[][^\s,'"]/ 7 + const STYLE_END 8 + = /^[^\s,][-\s.,:;!?'"}{)<\\|\]]/ 9 + const ITALIC_START 10 + = /^[\s,][^\s,/]|^['"}{(|\[][^\s,'"/<]/ 11 + const ITALIC_END 12 + = /^[^\s,/>][-\s.,:;!?'"}{)\\|\]]/ 13 + let big_regex = RegExp([ 14 + r`\b(?<link>https?://${url}${url_final}([(]${url}[)](${url}${url_final})?)?)(?<link_open>\[)?`, 15 + r`(?<=^|\s)[##](?<hashtag>(?!\uFE0F)[^${whitespace}]*[^\p{P}${whitespace}])`, // note: must filter out #123 16 + r`(?<=^|\s|[(])@(?<mention>[-a-zA-Z0-9]+([.][-a-zA-Z0-9]+)+)\b`, 17 + r`(?<style>[*][*]|[_][_]|[~][~]|[/])`, 18 + r`(?<close>\])`, 19 + r`(?<open>\[)`, 20 + r`(?<hidden>[|][|])`, 21 + ].join("|"), 'gu') 22 + 23 + export class Markup { 24 + constructor() { 25 + this.text = "" 26 + } 27 + update_text(text) { 28 + this.text = text 29 + } 30 + make_overlay() { 31 + let highlights = [] 32 + let spans = [] 33 + let open_styles = new Map() //ugh but we have to go back and remove any highlights when these arent closed.. idk this is all such a mess 34 + let open_brackets = [] 35 + let last = 0 36 + let push = (start, end, style)=>{ 37 + if (start>last) { 38 + let node = document.createElement('span') 39 + node.textContent = this.text.slice(last, start) 40 + node.className = [...open_styles].map(([type])=>type).join(" ") 41 + highlights.push(node) 42 + } 43 + if (end>start) { 44 + let node = document.createElement('span') 45 + node.textContent = this.text.slice(start, end) 46 + node.className = style+" "+[...open_styles].map(([type])=>type).join(" ") 47 + highlights.push(node) 48 + } 49 + last = end 50 + } 51 + for (let match of String(this.text).matchAll(big_regex)) { 52 + let start = match.index 53 + let end = start+match[0].length 54 + let g = match.groups 55 + if (g.mention!=null) { 56 + push(start, end, 'mention') 57 + spans.push({ 58 + start, end, strip: [0, 0], 59 + feature: { 60 + $type: 'app.bsky.richtext.facet#mention', 61 + did: g.mention, // hack, DID must be resolved afterwards 62 + }, 63 + }) 64 + } 65 + if (g.link!=null) { 66 + if (g.link_open!=null) { 67 + push(start, end, 'link') 68 + open_brackets.push({ 69 + start, end:null, strip: [g.link.length+1, 0], 70 + feature: { 71 + $type: 'app.bsky.richtext.facet#link', 72 + uri: g.link, 73 + }, 74 + }) 75 + } else { 76 + push(start, end, 'link') 77 + spans.push({ 78 + start, end, strip: [0, 0], 79 + feature: { 80 + $type: 'app.bsky.richtext.facet#link', 81 + uri: g.link, 82 + }, 83 + }) 84 + } 85 + } 86 + if (g.hashtag!=null && !/^#\d+$/.test(g.hashtag)) { 87 + push(start, end, 'hashtag') 88 + spans.push({ 89 + start, end, strip: [0,0], 90 + feature: { 91 + $type: 'app.bsky.richtext.facet#tag', 92 + tag: g.hashtag, 93 + }, 94 + }) 95 + } 96 + if (g.style!=null) { 97 + let type = {__proto__:null, '**':'bold', '__':'underline', '~~':'strikethrough', '/':'italic'}[g.style] 98 + let current = open_styles.get(type) 99 + let before = this.text.charAt(start-1)||"\n" 100 + let after = this.text.charAt(end)||"\n" 101 + if (current) { 102 + // try close 103 + if ((type=='italic' ? ITALIC_END : STYLE_END).test(before+after)) { 104 + current.end = end 105 + current.strip[1] = g.style.length 106 + spans.push(current) 107 + push(start, end, 'style-close') 108 + open_styles.delete(type) 109 + } 110 + } else { 111 + // try open 112 + if ((type=='italic' ? ITALIC_START : STYLE_START).test(before+after)) { 113 + open_styles.set(type, { 114 + start, end:null, strip:[g.style.length,0], 115 + feature: { 116 + $type: 'com.example.richtext.facet#markup', 117 + style: type, 118 + }, 119 + }) 120 + push(start, end, 'style-open') 121 + } 122 + } 123 + 124 + } 125 + if (g.open!=null) { 126 + open_brackets.push(null) 127 + } 128 + if (g.close!=null && open_brackets.length) { 129 + let top = open_brackets.pop() 130 + if (top && top.feature) { 131 + top.strip[1] = g.close.length 132 + top.end = end 133 + spans.push(top) 134 + } 135 + } 136 + } 137 + push(this.text.length, this.text.length, "") 138 + // 139 + let edges = [] 140 + for (let span of spans) { 141 + edges.push([span.start, span]) 142 + edges.push([span.end, span]) 143 + } 144 + edges.sort(([a],[b])=>a-b) 145 + let open = new Set() 146 + let windows = [] 147 + { 148 + let last = 0 149 + for (let [index,span] of edges) { 150 + if (index > last && open.size) 151 + windows.push({start: last, end: index, spans: [...open]}) 152 + if (!open.delete(span)) open.add(span) // toggle 153 + last = index 154 + } 155 + } 156 + // propagate strips 157 + for (let win of windows) { 158 + win.spans = win.spans.map(span=>{ 159 + let length = win.end-win.start 160 + function clamp(x) { 161 + if (x<0) 162 + return 0 163 + if (x>length) 164 + return length 165 + return x 166 + } 167 + let inset_left = win.start - span.start 168 + let inset_right = span.end - win.end 169 + let strip_left = clamp(span.strip[0] - inset_left) 170 + let strip_right = clamp(span.strip[1] - inset_right) 171 + let span2 = { 172 + feature: span.feature, 173 + strip: [strip_left, strip_right], 174 + } 175 + return span2 176 + }) 177 + } 178 + this.windows = windows 179 + return highlights 180 + } 181 + make_facets() { 182 + 183 + } 184 + }
+2 -1
test3.html
··· 17 17 import {MarkedText} from './facet.js' 18 18 import {index_to_byteindex, byteindex_to_index} from './byteindex.js' 19 19 import {markup_main} from './markup.js' 20 + import {markup_bbcode} from './markup-bbcode.js' 20 21 import {HTML} from './template.js' 21 22 22 23 function *post_to_segments(post) { ··· 121 122 122 123 let text = new MarkedText(inputtext) 123 124 text.spans = [ 124 - ...markup_main(text.text), 125 + ...markup_bbcode(text.text), 125 126 ] 126 127 127 128 text.make_windows()
+21
test4.html
··· 1 1 <!doctype html> 2 2 3 3 <link rel=stylesheet href=editor.css> 4 + <style> 5 + .italic { 6 + background: skyblue; 7 + } 8 + .style-open, .style-close { 9 + color: white; 10 + background: gray; 11 + } 12 + </style> 4 13 <script type=module> 5 14 import {Editor} from './editor.js' 6 15 7 16 window.e = new Editor() 8 17 $edit.append(e.root) 18 + 19 + import {Markup} from './markup2.js' 20 + 21 + window.Markup = Markup 22 + 23 + let m = new Markup() 24 + e.oninput = ()=>{ 25 + m.text = e.textarea.value 26 + let spans = m.make_overlay() 27 + console.log(spans) 28 + e.set_overlay(spans) 29 + } 9 30 </script> 10 31 11 32 <div id=$edit>