···11+function string_to_bytes(string) {
22+ return unescape(encodeURIComponent(string))
33+}
44+function bytes_to_string(string) {
55+ return decodeURIComponent(escape(string))
66+}
77+// note: we always work with native strings in our code
88+export function index_to_byteindex(string, index) {
99+ return string_to_bytes(string.slice(0, index)).length
1010+}
1111+export function byteindex_to_index(string, byteindex) {
1212+ return bytes_to_string(string_to_bytes(string).slice(0, byteindex)).length
1313+}
+7-4
facet.js
···11+import {index_to_byteindex, byteindex_to_index} from './byteindex.js'
22+13// stages:
24// 1: list of "spans" {start:Number, end:Number, strip:[Number,Number], feature:Feature} - can overlap etc.
35// 2: list of "windows" {start:Number, end:Number, spans:Span[]} - do not overlap (like facets)
···8789 })
8890 }
8991 return spans
9090-}
9191-9292-function index_to_byteindex(string, index) {
9393- return unescape(encodeURIComponent(string.slice(0,index))).length
9492}
95939694function has_client_strip(feature) {
···186184 // now push the facet
187185 facets.push({
188186 index: {
187187+ // todo: make a class for this that has like, start, end, and a pointer to the string, which only calculates byteStart/byteEnd when converted to JSON.
189188 byteStart: index_to_byteindex(text, start),
190189 byteEnd: index_to_byteindex(text, end),
191190 },
···205204 return {text, facets}
206205 }
207206}
207207+208208+function facets_to_segments() {
209209+210210+}
+35
template.js
···11+export let HTML = ([html])=>{
22+ let temp = document.createElement('template')
33+ temp.innerHTML = html.replace(/\s*?\n\s*/g, "")
44+ let content = temp.content
55+ let root = content
66+ if (root.childNodes.length==1)
77+ root = root.firstChild
88+99+ let get_path = (root, node)=>{
1010+ let path = ""
1111+ while (node!==root) {
1212+ let parent = node.parentNode
1313+ let pos = [].indexOf.call(parent.childNodes, node)
1414+ path = ".firstChild"+".nextSibling".repeat(pos) + path
1515+ node = parent
1616+ }
1717+ return path
1818+ }
1919+2020+ let init = `const node=document.importNode(this, true)
2121+holder.$root=node`
2222+ for (let node of content.querySelectorAll("[\\$]")) {
2323+ let path = get_path(root, node)
2424+ let id = node.getAttribute('$')
2525+ node.removeAttribute('$')
2626+ id = id.replace(/,/g, " = holder.$")
2727+ init += `
2828+holder.$${id} = node${path}`
2929+ }
3030+ init += `
3131+return holder`
3232+ let c = new Function("holder={}", init).bind(root)
3333+ //c.prototype = {__proto__: null, template: root}
3434+ return c
3535+}
+51-1
test3.html
···11<!doctype html>
2233<script type=module>
44- import {MarkedText,markup_italic,markup1} from './facet.js'
44+ import {MarkedText, markup_italic, markup1} from './facet.js'
55+ import {index_to_byteindex, byteindex_to_index} from './byteindex.js'
66+ import {HTML} from './template.js'
5768 let text = new MarkedText("abc /123 #test/ http://example.com")
79 text.spans = [
···1214 text.make_windows()
1315 let f = text.create_facets()
1416 console.log(f)
1717+1818+ function *post_to_segments(post) {
1919+ let text = post.text
2020+ let last = 0
2121+ for (let x of post.facets) { // (assumes facets are sorted and valid)
2222+ let start = byteindex_to_index(text, x.index.byteStart)
2323+ let end = byteindex_to_index(text, x.index.byteEnd)
2424+ if (start>last)
2525+ yield {text:text.slice(last, start), features:[]}
2626+ if (end>start)
2727+ yield {text:text.slice(start, end), features:x.features}
2828+ last = end
2929+ }
3030+ if (text.length>last)
3131+ yield {text:text.slice(last, text.length), features:[]}
3232+ }
3333+3434+ let facetcont = HTML`<facet-display></facet-display>`
3535+ let facetspan = HTML`<div><div $=text></div><div $=data></div></div>`
3636+ function render(f) {
3737+ let elem = facetcont().$root
3838+ for (let seg of post_to_segments(f)) {
3939+ let span = facetspan()
4040+ span.$text.textContent = seg.text
4141+ span.$data.textContent = seg.features.length
4242+ elem.append(span.$root)
4343+ }
4444+ return elem
4545+ }
4646+ document.body.append(render(f))
1547</script>
4848+4949+<style>
5050+ facet-display {
5151+ display: flex;
5252+ }
5353+ facet-display > *{
5454+ display: flex;
5555+ flex-flow: column;
5656+ flex: 0;
5757+ margin: 1px;
5858+ border: 1px solid;
5959+ }
6060+ facet-display > * > :first-child {
6161+ white-space: pre;
6262+ font-family: monospace;
6363+ padding: 0 1px;
6464+ }
6565+</style>