|
9 | 9 | <TextAnnotations |
10 | 10 | :extract-keys="extractTextKeys" |
11 | 11 | :link-prefix="linkPrefix" |
12 | | - :files="files" |
| 12 | + :files="store.files" |
13 | 13 | :selected="selectedFileIndex" |
| 14 | + @value-change="valueChange" |
14 | 15 | @select-file="selectFile" |
15 | 16 | /> |
16 | 17 | <VolumeAnnotations |
|
40 | 41 |
|
41 | 42 | <script setup> |
42 | 43 | import { forEach, get, set } from "lodash"; |
43 | | - import { initSyncedStore, waitForSync } from "../store/synced"; |
44 | 44 | import useVisualization from "../store/visualization"; |
45 | | - import { enableVueBindings } from "@syncedstore/core"; |
| 45 | + import { HocuspocusProvider } from "@hocuspocus/provider"; |
| 46 | + import { syncedStore, getYjsDoc, enableVueBindings } from "@syncedstore/core"; |
46 | 47 | import Tools from "./Tools.vue"; |
47 | 48 | import { |
48 | 49 | Editor, |
|
53 | 54 | } from "nwl-components"; |
54 | 55 | import * as Vue from "vue"; |
55 | 56 | |
56 | | - const { store, webrtcProvider, doc } = initSyncedStore(projectInfo.shortname); |
57 | | - const { baseURL } = Vue.inject('config'); |
58 | | - |
59 | 57 | // make SyncedStore use Vuejs internally |
60 | 58 | enableVueBindings(Vue); |
61 | | - |
| 59 | +
|
| 60 | + const store = syncedStore({ files: [], fragment: "xml" }); |
| 61 | + const doc = getYjsDoc(store); |
| 62 | +
|
| 63 | + const crdtProvider = new HocuspocusProvider({ |
| 64 | + url: "ws://0.0.0.0:8081", // FIXME |
| 65 | + name: projectInfo.shortname, |
| 66 | + document: doc |
| 67 | + }); |
| 68 | +
|
| 69 | + const { baseURL } = Vue.inject('config'); |
| 70 | + |
62 | 71 | const props = defineProps({ |
63 | 72 | project: { |
64 | 73 | type: Object, |
|
71 | 80 | }); |
72 | 81 | |
73 | 82 | const linkPrefix = `${baseURL}/project/${projectInfo.shortname}?source=` |
74 | | - const files = Vue.ref(projectInfo.files.list); |
75 | 83 | const selectedFileIndex = projectInfo.files.list.findIndex(file => file.source === props.selectedFile); |
76 | | - doc.getArray("files").observe(() => { |
77 | | - files.value.splice(0, files.value.length); |
78 | | - files.value.push(...store.files); |
79 | | - }); |
80 | 84 |
|
81 | 85 | const textAnnotations = projectInfo.annotations.list.filter(anno => anno.type !== 'vectorial'); |
82 | 86 | const volumeAnnotations = projectInfo.annotations.list.filter(anno => anno.type === 'vectorial'); |
|
102 | 106 | const keys = new Map(); |
103 | 107 | keys.set("Name", "name"); |
104 | 108 | keys.set("File", "source"); |
| 109 | + forEach(textAnnotations, (annotation) => { |
| 110 | + if (annotation.display) |
| 111 | + keys.set(annotation.name, `${annotation.name}`); |
| 112 | + }); |
105 | 113 | return keys; |
106 | 114 | }; |
107 | 115 | |
|
113 | 121 | return keys; |
114 | 122 | }; |
115 | 123 | |
116 | | - const syncMicrodraw = () => { |
117 | | - console.log('sync microdraw') |
118 | | - } |
119 | | - |
120 | 124 | const valueChange = (content, index, selector) => { |
121 | 125 | const sel = |
122 | 126 | typeof selector === "string" ? [index, selector] : [index, ...selector]; |
123 | | - set(store.files, sel, content); |
124 | | - syncMicrodraw(); |
| 127 | + set(store.files, sel, content); |
125 | 128 | }; |
126 | 129 |
|
127 | 130 | const selectFile = async (file) => { |
128 | | - window.location = `${linkPrefix}${file.source}` |
| 131 | + // No-op. We'd rather let user click on a link. |
129 | 132 | } |
130 | 133 | |
131 | 134 | const setupKeyDownListeners = () => { |
|
137 | 140 | return; |
138 | 141 | } |
139 | 142 | if (selectedTr.previousElementSibling) { |
140 | | - selectedTr.previousElementSibling.click(); |
| 143 | + selectedTr.previousElementSibling.querySelector('a[href]').click(); |
141 | 144 | } |
142 | 145 | break; |
143 | 146 | case "ArrowDown": |
144 | 147 | if (!selectedTr) { |
145 | 148 | return; |
146 | 149 | } |
147 | 150 | if (selectedTr.nextElementSibling) { |
148 | | - selectedTr.nextElementSibling.click(); |
| 151 | + selectedTr.nextElementSibling.querySelector('a[href]').click(); |
149 | 152 | } |
150 | 153 | break; |
151 | 154 | default: |
152 | 155 | break; |
153 | 156 | } |
154 | 157 | }); |
155 | 158 | }; |
156 | | - |
157 | | - const delay = (ms) => { |
158 | | - return new Promise((resolve) => setTimeout(resolve, ms)); |
159 | | - }; |
160 | | - |
| 159 | + |
161 | 160 | const handleLayoutChange = () => { |
162 | 161 | Microdraw.resizeAnnotationOverlay(); |
163 | 162 | }; |
|
187 | 186 | |
188 | 187 | Vue.onMounted(async () => { |
189 | 188 | setupKeyDownListeners(); |
190 | | - await waitForSync(webrtcProvider); |
| 189 | + crdtProvider.on('synced', () => { |
| 190 | + console.log('on synced'); |
| 191 | + if (store.files.length === 0) { |
| 192 | + store.files.push(...projectInfo.files.list); |
| 193 | + forEach(textAnnotations, (annotation) => { |
| 194 | + forEach(annotation.values, (value, source) => { |
| 195 | + const file = store.files.find(file => file.source === source); |
| 196 | + if (file) file[annotation.name] = value; |
| 197 | + }); |
| 198 | + }); |
| 199 | + } |
| 200 | + }); |
191 | 201 | await initVisualization(); |
192 | 202 | window.addEventListener('resize', handleResize); |
193 | 203 | }); |
|
0 commit comments