source: main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/components/TranscriptionItem.vue@ 35731

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

Port updated material styles

File size: 7.7 KB
RevLine 
[35355]1<template>
[35406]2 <div class="card">
[35355]3 <!-- Header containing info and actions for the transcription -->
4 <div class="transcription__header">
[35451]5 <button class="btn-fab" v-on:click="toggleAudio" type="button" :title="translations.get('TranscriptionItem_PlayButtonTooltip')">
[35445]6 <span class="material-icons mdi-l play-button" v-if="!isPlaying">play_arrow</span>
7 <span class="material-icons mdi-l play-button" v-if="isPlaying">pause</span>
[35355]8 </button>
9
10 <span>{{ translations.get("TranscriptionItem_FileName") }}: {{ transcription.fileName }}</span>
11
[35404]12 <div style="position: relative;">
[35429]13 <button class="btn-primary" @mouseover="showDownloadOptions = true" @mouseout="showDownloadOptions = false" type="button">
[35399]14 <span class="material-icons">download</span>
15 <span>{{ translations.get("TranscriptionItem_Download") }}</span>
16 </button>
[35384]17
[35404]18 <div class="download-popup card" :class="{ 'download-popup-show': showDownloadOptions }"
19 @mouseover="showDownloadOptions = true" @mouseout="showDownloadOptions = false">
[35731]20 <button @click="downloadAsText" type="button" class="btn-primary theme-flat left-align">
[35399]21 <span class="material-icons">text_snippet</span>
22 <span>{{ translations.get("TranscriptionItem_DownloadAsText") }}</span>
23 </button>
24
[35731]25 <button @click="downloadAsJson" type="button" class="btn-primary theme-flat left-align">
[35399]26 <span class="material-icons">integration_instructions</span>
27 <span>{{ translations.get("TranscriptionItem_DownloadAsJson") }}</span>
28 </button>
29
[35731]30 <button @click="downloadAsWebvtt" type="button" class="btn-primary theme-flat left-align">
[35399]31 <span class="material-icons">subtitles</span>
32 <span>{{ translations.get("TranscriptionItem_DownloadAsWebvtt") }}</span>
33 </button>
34 </div>
35 </div>
36
[35429]37 <button class="btn-primary theme-error" @click="remove" type="button">
[35355]38 <span class="material-icons">delete</span>
39 <span>{{ translations.get("TranscriptionItem_Remove") }}</span>
40 </button>
41 </div>
42
[35631]43 <div class="editor-controls">
44 <audio-time-bar v-model.number="currentPlaybackTime" :audio-length="audioLength" :isDisabled="playbackState.id != transcription.id" />
45 </div>
46
[35355]47 <hr />
48
[35548]49 <div class="editor-controls">
[35631]50 <TranscriptionItemEditor ref="editor" :transcription="transcription" style="margin-bottom: 1em" :enableEditing="enableEditing" />
[35548]51 <toggle-button v-model="enableEditing" :title="translations.get('TranscriptionItemEditor_ToggleEditTooltip')">
52 <span class="material-icons">edit</span>
53 </toggle-button>
54 </div>
[35355]55 </div>
56</template>
57
58<style scoped lang="scss">
59.transcription__header {
60 display: grid;
61 gap: 0.5em 0.5em;
[35384]62 grid-template-columns: auto 1fr auto auto;
[35355]63 align-items: center;
64}
65
[35399]66.download-popup {
67 display: flex;
68 flex-direction: column;
[35404]69 align-items: stretch;
[35399]70
71 position: absolute;
[35404]72 top: 97%;
73 z-index: 2;
[35399]74
75 padding: 2px;
76 margin: 0;
[35404]77 width: 14em;
78
79 transition-duration: var(--transition-duration);
80 visibility: hidden;
81 opacity: 0;
[35399]82}
[35404]83
84.download-popup-show {
85 visibility: visible;
86 opacity: 1;
87}
[35429]88
[35548]89.editor-controls {
90 display: grid;
[35631]91 align-items: flex-start;
[35548]92 grid-template-columns: 1fr auto;
93 margin: 0.5em 0 0.3em 0;
94 gap: 1em;
[35429]95}
96
97.rotate-180 {
98 transform: rotate(180deg);
99}
[35731]100
101.left-align {
102 justify-content: flex-start;
103}
[35355]104</style>
105
106<script>
107import { mapState } from "vuex";
[35384]108import { saveAs } from "file-saver"
[35446]109import { TranscriptionViewModel } from "../main";
110import AudioPlayback from "../js/AudioPlaybackModule"
111import Util from "../js/Util"
[35548]112import AudioTimeBar from "./AudioTimeBar.vue"
[35439]113import TranscriptionItemEditor from "./TranscriptionItemEditor.vue"
[35355]114
115export default {
116 name: "TranscriptionItem",
117 components: {
[35548]118 AudioTimeBar,
[35355]119 TranscriptionItemEditor
120 },
121 props: {
122 transcription: TranscriptionViewModel
123 },
124 data() {
125 return {
[35548]126 enableEditing: false,
[35399]127 showDownloadOptions: false
[35355]128 }
129 },
[35548]130 computed: {
131 currentPlaybackTime: {
132 get() {
133 return this.$store.getters.transcriptionPlaybackTime(this.transcription.id);
134 },
135 set(value) {
136 this.$store.commit("playbackStateSetTime", { id: this.transcription.id, time: value });
137 }
138 },
139 audioLength() {
140 return this.$store.getters.transcriptionPlaybackLength(this.transcription.id);
141 },
142 isPlaying() {
143 return this.playbackState.isPlaying && this.playbackState.id === this.transcription.id;
144 },
145 ...mapState({
146 translations: state => state.translations,
147 playbackState: state => state.playbackState
148 })
149 },
[35355]150 methods: {
[35449]151 async toggleAudio() {
152 this.isPlaying ? AudioPlayback.pause() : await AudioPlayback.play(this.transcription.id, -1);
[35355]153 },
154 remove() {
[35439]155 this.$store.commit("rawTranscriptionRemove", this.transcription.id);
[35384]156 },
157 downloadAsText() {
[35400]158 const fileName = buildDownloadableFileName(this.transcription.fileName, "txt");
[35384]159
[35528]160 const blob = new Blob([ this.$refs.editor.words.map(w => w.word).join(" ") ], { type: "text/plain;charset=utf-8" });
[35384]161 saveAs(blob, fileName);
[35400]162 },
163 downloadAsJson() {
164 const fileName = buildDownloadableFileName(this.transcription.fileName, "json");
[35439]165 const toDownload = (({ fileName, transcription }) => ({ fileName, transcription }))(this.transcription);
166 toDownload.words = this.$refs.editor.words.map(w => (({ word, startTime, endTime }) => ({ word, startTime, endTime }))(w));
[35400]167
168 const blob = new Blob([ JSON.stringify(toDownload, null, 4) ], { type: "application/json;charset=utf-8" });
169 saveAs(blob, fileName);
[35403]170 },
171 downloadAsWebvtt() {
172 const fileName = buildDownloadableFileName(this.transcription.fileName, "vtt");
[35439]173 const toDownload = buildWebvttFileContents(this.transcription, this.$refs.editor);
[35403]174
175 const blob = new Blob([ toDownload ], { type: "text/vtt;charset=utf-8" });
176 saveAs(blob, fileName);
[35355]177 }
178 }
179}
[35400]180
181/**
182 * Builds a file name for a download.
183 * @param {String} transcriptionFileName The name of the transcription that will be downloaded.
184 * @param {String} extension The file extension of the download. Do not include a period.
185 * @returns {String} The file name.
186 */
187function buildDownloadableFileName(transcriptionFileName, extension) {
188 const extensionIndex = transcriptionFileName.lastIndexOf(".");
189 let fileName = transcriptionFileName.slice(0, extensionIndex);
190 fileName += "_transcription." + extension;
191
192 return fileName;
193}
[35403]194
195/**
196 * Builds a WebVTT file of the given transcription
197 * @param {TranscriptionViewModel} transcription The transcription.
198 * @returns {String} The WebVTT content.
199 */
[35439]200function buildWebvttFileContents(transcription, editor) {
[35403]201 let contents = "WEBVTT Transcription of " + transcription.fileName + "\n\n";
202
[35439]203 for (const word of editor.words) {
[35413]204 const startTime = Util.formatSecondsTimeString(word.startTime, true);
205 const endTime = Util.formatSecondsTimeString(word.endTime, true);
206
207 contents += startTime + " --> " + endTime + "\n";
[35403]208 contents += "- " + word.word + "\n\n";
209 }
210
211 return contents;
212}
[35355]213</script>
Note: See TracBrowser for help on using the repository browser.