source: main/trunk/model-interfaces-dev/atea/macron-restoration/src/components/DirectInput.vue@ 35772

Last change on this file since 35772 was 35772, checked in by cstephen, 2 years ago

Upgrade to support the new macroniser backend.
Fix chunk/asset resolution

File size: 6.2 KB
Line 
1<template>
2<div class="root">
3 <textarea class="text-input input-area" @input="onTextInput"
4 v-model="input" :placeholder="translations.get('DirectInput_InputPlaceholder')" />
5
6 <div class="text-container">
7 <span v-if="errorState" class="material-icons mdi-m error-text">error</span>
8 <span v-if="errorState" class="error-text">{{ translations.get('DirectInput_UnknownError') }}</span>
9
10 <span class="preserveWhitespace" v-html="formattedRestored" />
11 </div>
12
13 <div class="flex">
14 <input type="checkbox" id="i-preserve-existing-macrons" v-model="preserveExistingMacrons" @input="startMacronisationWait" />
15 <label for="i-preserve-existing-macrons">{{ translations.get('DirectInput_PreserveExistingMacrons') }}</label>
16 </div>
17
18 <div class="flex">
19 <input type="checkbox" id="i-show-macronised-words" v-model="showMacronisedWords" :disabled="restored.length === 0" />
20 <label for="i-show-macronised-words">{{ translations.get('DirectInput_ShowMacronisedWords') }}</label>
21 </div>
22
23 <div class="flex right-column">
24 <input type="checkbox" id="i-show-macronised-words" v-model="normaliseLinebreaks" :disabled="restored.length === 0" />
25 <label for="i-show-macronised-words">{{ translations.get('DirectInput_NormaliseLinebreaks') }}</label>
26 </div>
27
28 <button class="btn-primary right-column" :disabled="!canDownload" @click="copyToClipboard">
29 {{ translations.get('DirectInput_CopyToClipboard') }}
30 </button>
31
32 <button class="btn-primary right-column" :disabled="!canDownload" @click="downloadAsText">
33 {{ translations.get('DirectInput_Download') }}
34 </button>
35</div>
36</template>
37
38<style scoped lang="scss">
39.root {
40 display: grid;
41 grid-template-columns: 1fr 1fr;
42 gap: 1em;
43}
44
45.preserveWhitespace {
46 white-space: pre-line;
47}
48
49.input-area {
50 resize: vertical;
51 min-height: 4em;
52}
53
54.flex {
55 display: flex;
56 align-items: center;
57 gap: 0.5em;
58}
59
60.right-column {
61 grid-column: 2;
62}
63
64.highlight {
65 background-color: var(--highlighted-word-bg);
66}
67
68.error-text {
69 color: rgb(185, 3, 3);
70}
71</style>
72
73<script>
74import { mapState } from "vuex";
75import { saveAs } from "file-saver"
76import { log } from "../js/Util"
77import MacronRestorationModule from "../js/MacronRestorationModule"
78import { SnackController } from "./Snackbar.vue"
79
80const macroniser = new MacronRestorationModule();
81
82export default {
83 name: "DirectInput",
84 data() {
85 return {
86 preserveExistingMacrons: true,
87 showMacronisedWords: false,
88 macroniseWaitTimeout: null,
89 waitingToMacronise: false,
90 errorState: false,
91 normaliseLinebreaks: false
92 }
93 },
94 computed: {
95 canDownload() {
96 return this.restored.length > 0 && !this.waitingToMacronise;
97 },
98 input: {
99 get() {
100 return this.$store.state.directInput;
101 },
102 set(newValue) {
103 this.$store.commit("setDirectInput", newValue);
104 this.startMacronisationWait();
105 }
106 },
107 restored: {
108 get() {
109 return this.$store.state.directOutput;
110 },
111 set(newValue) {
112 this.$store.commit("setDirectOutput", newValue);
113 }
114 },
115 formattedRestored() {
116 let restored = "";
117
118 for (const word of this.restored) {
119 if (word.w) {
120 if (word[0] !== "-") {
121 restored += " ";
122 }
123
124 if (word.macronised && this.showMacronisedWords) {
125 restored += `<mark class="highlight">${word.w}</mark>`;
126 }
127 else {
128 restored += word.w;
129 }
130 }
131
132 if (word.linebreaks) {
133 restored += this.normaliseLinebreak(word.linebreaks);
134 }
135 }
136
137 return restored;
138 },
139 ...mapState({
140 translations: state => state.translations
141 })
142 },
143 methods: {
144 /**
145 * Handles input on an element, and grows its height so that the text is always visible.
146 * @param {InputEvent} event The input event.
147 */
148 onTextInput(event) {
149 event.target.height = "auto";
150 event.target.height = event.target.scrollHeight;
151 },
152 startMacronisationWait() {
153 if (this.input === null || this.input === "") {
154 return;
155 }
156
157 this.waitingToMacronise = true;
158
159 if (this.macroniseWaitTimeout !== null) {
160 clearTimeout(this.macroniseWaitTimeout);
161 }
162
163 this.macroniseWaitTimeout = setTimeout(this.updateMacronisedText, 1000);
164 },
165 async updateMacronisedText() {
166 this.errorState = false;
167
168 try {
169 this.restored = await macroniser.directMacronisation(this.input, this.preserveExistingMacrons);
170 this.waitingToMacronise = false;
171 }
172 catch (ex) {
173 this.errorState = true;
174 log(ex, "warn");
175 }
176 },
177
178 downloadAsText() {
179 const blob = new Blob([ this.formattedRestored ], { type: "text/plain;charset=utf-8" });
180 saveAs(blob, "restored.txt");
181 },
182 async copyToClipboard() {
183 await navigator.clipboard.writeText(this.formattedRestored);
184 SnackController.addSnack(this.translations.get("DirectInput_CopySuccess"));
185 },
186
187 /**
188 * Normalises a linebreak.
189 * @param {String} linebreakCount The linebreak sequence.
190 */
191 normaliseLinebreak(linebreakCount) {
192 if (!this.normaliseLinebreaks) {
193 return this.repeatString("\n", linebreakCount);
194 }
195
196 linebreakCount = Math.min(2, linebreakCount);
197 return this.repeatString("\n", linebreakCount);
198 },
199 repeatString(string, count) {
200 let result = "";
201
202 for (let i = 0; i < count; i++) {
203 result += string;
204 }
205
206 return result;
207 }
208 }
209}
210</script>
Note: See TracBrowser for help on using the repository browser.