feat(UI): html, xml, json, svg and yaml editor modes in long text fields edit

This commit is contained in:
Fabio Di Stasio 2021-02-21 19:22:03 +01:00
parent 110b0b414c
commit 9a1bf32128
6 changed files with 188 additions and 17 deletions

View File

@ -24,7 +24,7 @@
<slot name="body" /> <slot name="body" />
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer pt-0">
<button <button
class="btn btn-primary mr-2" class="btn btn-primary mr-2"
@click.stop="confirmModal" @click.stop="confirmModal"

View File

@ -0,0 +1,129 @@
<template>
<div class="editor-wrapper">
<div
:id="`editor-${id}`"
class="editor"
:class="editorClass"
:style="{height: `${height}px`}"
/>
</div>
</template>
<script>
import * as ace from 'ace-builds';
import 'ace-builds/webpack-resolver';
import { mapGetters } from 'vuex';
export default {
name: 'BaseTextEditor',
props: {
value: String,
mode: { type: String, default: 'text' },
editorClass: { type: String, default: '' },
autoFocus: { type: Boolean, default: false },
readOnly: { type: Boolean, default: false },
height: { type: Number, default: 200 }
},
data () {
return {
editor: null,
id: null
};
},
computed: {
...mapGetters({
editorTheme: 'settings/getEditorTheme',
autoComplete: 'settings/getAutoComplete',
lineWrap: 'settings/getLineWrap'
})
},
watch: {
mode () {
if (this.editor)
this.editor.session.setMode(`ace/mode/${this.mode}`);
},
editorTheme () {
if (this.editor)
this.editor.setTheme(`ace/theme/${this.editorTheme}`);
},
autoComplete () {
if (this.editor) {
this.editor.setOptions({
enableLiveAutocompletion: this.autoComplete
});
}
},
lineWrap () {
if (this.editor) {
this.editor.setOptions({
wrap: this.lineWrap
});
}
}
},
created () {
this.id = this._uid;
},
mounted () {
this.editor = ace.edit(`editor-${this.id}`, {
mode: `ace/mode/${this.mode}`,
theme: `ace/theme/${this.editorTheme}`,
value: this.value,
fontSize: '14px',
printMargin: false,
readOnly: this.readOnly
});
this.editor.setOptions({
enableBasicAutocompletion: false,
wrap: this.lineWrap,
enableSnippets: false,
enableLiveAutocompletion: false
});
this.editor.session.on('change', () => {
const content = this.editor.getValue();
this.$emit('update:value', content);
});
if (this.autoFocus) {
setTimeout(() => {
this.editor.focus();
this.editor.resize();
}, 20);
}
setTimeout(() => {
this.editor.resize();
}, 20);
}
};
</script>
<style lang="scss" scoped>
.editor-wrapper {
border-bottom: 1px solid #444;
.editor {
width: 100%;
}
}
.ace_.mdi {
display: inline-block;
width: 17px;
}
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {
background-color: #c9561a99;
}
.ace_dark.ace_editor.ace_autocomplete .ace_marker-layer .ace_line-hover {
background-color: #c9571a33;
border: none;
}
.ace_dark.ace_editor.ace_autocomplete .ace_completion-highlight {
color: #e0d00c;
}
</style>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="editor-wrapper"> <div class="editor-wrapper">
<div <div
ref="editor" :id="`editor-${id}`"
class="editor" class="editor"
:style="{height: `${height}px`}" :style="{height: `${height}px`}"
/> />
@ -29,7 +29,8 @@ export default {
return { return {
editor: null, editor: null,
fields: [], fields: [],
baseCompleter: [] baseCompleter: [],
id: null
}; };
}, },
computed: { computed: {
@ -165,8 +166,11 @@ export default {
} }
} }
}, },
created () {
this.id = this._uid;
},
mounted () { mounted () {
this.editor = ace.edit(this.$refs.editor, { this.editor = ace.edit(`editor-${this.id}`, {
mode: `ace/mode/${this.mode}`, mode: `ace/mode/${this.mode}`,
theme: `ace/theme/${this.editorTheme}`, theme: `ace/theme/${this.editorTheme}`,
value: this.value, value: this.value,

View File

@ -61,14 +61,48 @@
<div :slot="'body'"> <div :slot="'body'">
<div class="mb-2"> <div class="mb-2">
<div> <div>
<textarea <TextEditor
v-model="editingContent" :value.sync="editingContent"
class="form-input textarea-editor" editor-class="textarea-editor"
:mode="editorMode"
/> />
</div> </div>
<div class="editor-field-info"> <div class="editor-field-info p-vcentered">
<div><b>{{ $t('word.size') }}</b>: {{ editingContent ? editingContent.length : 0 }}</div> <div><b>{{ $t('word.size') }}</b>: {{ editingContent ? editingContent.length : 0 }}</div>
<div><b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}</div> <div class="d-flex">
<div class="d-flex p-vcentered mr-4">
<label for="editorMode" class="form-label mr-2">
<b>{{ $t('word.content') }}</b>:
</label>
<select
id="editorMode"
v-model="editorMode"
class="form-select select-sm"
>
<option value="text">
TEXT
</option>
<option value="html">
HTML
</option>
<option value="xml">
XML
</option>
<option value="json">
JSON
</option>
<option value="svg">
SVG
</option>
<option value="yaml">
YAML
</option>
</select>
</div>
<div class="p-vcentered">
<b>{{ $t('word.type') }}</b>: {{ editingType.toUpperCase() }}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -138,12 +172,14 @@ import hexToBinary from 'common/libs/hexToBinary';
import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes'; import { TEXT, LONG_TEXT, NUMBER, FLOAT, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
import { mask } from 'vue-the-mask'; import { mask } from 'vue-the-mask';
import ConfirmModal from '@/components/BaseConfirmModal'; import ConfirmModal from '@/components/BaseConfirmModal';
import TextEditor from '@/components/BaseTextEditor';
import ForeignKeySelect from '@/components/ForeignKeySelect'; import ForeignKeySelect from '@/components/ForeignKeySelect';
export default { export default {
name: 'WorkspaceQueryTableRow', name: 'WorkspaceQueryTableRow',
components: { components: {
ConfirmModal, ConfirmModal,
TextEditor,
ForeignKeySelect ForeignKeySelect
}, },
directives: { directives: {
@ -206,6 +242,7 @@ export default {
editingContent: null, editingContent: null,
editingType: null, editingType: null,
editingField: null, editingField: null,
editorMode: 'text',
contentInfo: { contentInfo: {
ext: '', ext: '',
mime: '', mime: '',
@ -473,7 +510,7 @@ export default {
} }
.editor-field-info { .editor-field-info {
margin-top: 0.6rem; margin-top: 0.4rem;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
white-space: normal; white-space: normal;

View File

@ -93,7 +93,8 @@ module.exports = {
ciphers: 'Ciphers', ciphers: 'Ciphers',
upload: 'Upload', upload: 'Upload',
browse: 'Browse', browse: 'Browse',
faker: 'Faker' faker: 'Faker',
content: 'Content'
}, },
message: { message: {
appWelcome: 'Welcome to Antares SQL Client!', appWelcome: 'Welcome to Antares SQL Client!',