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

Last change on this file since 35728 was 35728, checked in by cstephen, 13 months ago

Allow linebreak normalisation in direct input

File size: 5.7 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">Something went wrong! Please try modifying your input text.</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" />
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" />
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="downloadAsText">{{ translations.get('DirectInput_Download') }}</button>
29</div>
30</template>
31
32<style scoped lang="scss">
33.root {
34 display: grid;
35 grid-template-columns: 1fr 1fr;
36 gap: 1em;
37}
38
39.preserveWhitespace {
40 white-space: pre-line;
41}
42
43.input-area {
44 resize: vertical;
45 min-height: 4em;
46}
47
48.flex {
49 display: flex;
50 align-items: center;
51 gap: 0.5em;
52}
53
54.right-column {
55 grid-column: 2;
56}
57
58.highlight {
59 background-color: var(--highlighted-word-bg);
60}
61
62.error-text {
63 color: rgb(185, 3, 3);
64}
65</style>
66
67<script>
68import { mapState } from "vuex";
69import { saveAs } from "file-saver"
70import { log } from "../js/Util"
71import MacronRestorationModule from "../js/MacronRestorationModule"
72
73const macroniser = new MacronRestorationModule();
74
75export default {
76 name: "DirectInput",
77 data() {
78 return {
79 preserveExistingMacrons: true,
80 showMacronisedWords: false,
81 macroniseWaitTimeout: null,
82 waitingToMacronise: false,
83 errorState: false,
84 normaliseLinebreaks: false
85 }
86 },
87 computed: {
88 canDownload() {
89 return this.restored !== null && !this.waitingToMacronise;
90 },
91 input: {
92 get() {
93 return this.$store.state.directInput;
94 },
95 set(newValue) {
96 this.$store.commit("setDirectInput", newValue);
97 this.startMacronisationWait();
98 }
99 },
100 restored: {
101 get() {
102 return this.$store.state.directOutput;
103 },
104 set(newValue) {
105 this.$store.commit("setDirectOutput", newValue);
106 }
107 },
108 formattedRestored() {
109 let restored = "";
110
111 for (const word of this.restored) {
112 if (word.w) {
113 if (word[0] !== "-") {
114 restored += " ";
115 }
116
117 if (word.macronised && this.showMacronisedWords) {
118 restored += `<mark class="highlight">${word.w}</mark>`;
119 }
120 else {
121 restored += word.w;
122 }
123 }
124
125 if (word.linebreak) {
126 restored += this.normaliseLinebreak(word.linebreak);
127 }
128 }
129
130 return restored;
131 },
132 ...mapState({
133 translations: state => state.translations
134 })
135 },
136 methods: {
137 /**
138 * Handles input on an element, and grows its height so that the text is always visible.
139 * @param {InputEvent} event The input event.
140 */
141 onTextInput(event) {
142 event.target.height = "auto";
143 event.target.height = event.target.scrollHeight;
144 },
145 startMacronisationWait() {
146 if (this.input === null || this.input === "") {
147 return;
148 }
149
150 this.waitingToMacronise = true;
151
152 if (this.macroniseWaitTimeout !== null) {
153 clearTimeout(this.macroniseWaitTimeout);
154 }
155
156 this.macroniseWaitTimeout = setTimeout(this.updateMacronisedText, 1000);
157 },
158 async updateMacronisedText() {
159 this.errorState = false;
160
161 try {
162 this.restored = await macroniser.directMacronisation(this.input, this.preserveExistingMacrons);
163 this.waitingToMacronise = false;
164 }
165 catch (ex) {
166 this.errorState = true;
167 log(ex, "warn");
168 }
169 },
170 downloadAsText() {
171 const blob = new Blob([ this.restored ], { type: "text/plain;charset=utf-8" });
172 saveAs(blob, "restored.txt");
173 },
174 /**
175 * Normalises a linebreak.
176 * @param {String} linebreak The linebreak sequence.
177 */
178 normaliseLinebreak(linebreak) {
179 if (!this.normaliseLinebreaks) {
180 return linebreak;
181 }
182
183 const rCount = linebreak.split("\r").length - 1;
184 const nCount = linebreak.split("\n").length - 1;
185
186 if (rCount > 1) {
187 if (nCount > 0) {
188 return "\r\n\r\n";
189 }
190
191 return "\r\r";
192 }
193 else if (nCount > 1) {
194 return "\n\n";
195 }
196
197 return linebreak;
198 }
199 }
200}
201</script>
Note: See TracBrowser for help on using the repository browser.