base_ui/components/forms/TextareaComponent.vue

295 lines
7.8 KiB
Vue
Raw Permalink Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div class="row form-group mt-3" :key="$attrs.key">
<template v-if="enableSuggestion">
<label
:for="localFormElement.key"
:class="$attrs.labelClass ?? 'col-md-2'"
>{{ localFormElement.label }}:</label
>
<vue-tribute
:class="[$attrs.inputClass ?? ' col-md-10']"
:options="tributeOptions"
>
<textarea
@tribute-no-match="noMatchFound"
@tribute-replaced="textReplaced"
:ref="localFormElement.key"
class="form-control"
@focus="clearErrors"
@blur="validate"
@change="validate"
:placeholder="localFormElement.placeholder"
:id="localFormElement.key"
:name="localFormElement.key"
v-model="textValue"
cols="30"
:rows="getRows()"
>
</textarea>
</vue-tribute>
<context-menu
style="position: static; display: inline-flex"
v-if="contextMenu.length"
:id="'context-menu-' + localFormElement.key"
:contextMenu="contextMenu"
@other="methodName($event)"
>
</context-menu>
</template>
<template v-else>
<label
:for="localFormElement.key"
:class="$attrs.labelClass ?? 'col-md-3'"
>{{ localFormElement.label }}:</label
>
<div class="mt-2" :class="[$attrs.inputClass ?? ' col-md-9']">
<textarea
@tribute-no-match="noMatchFound"
@tribute-replaced="textReplaced"
:ref="localFormElement.key"
class="form-control"
@focus="clearErrors"
@blur="validate"
@change="validate"
:placeholder="localFormElement.placeholder"
:id="localFormElement.key"
:name="localFormElement.key"
v-model="textValue"
cols="30"
:rows="getRows()"
>
</textarea>
</div>
</template>
</div>
</template>
<script>
import formBuilderMixin from "@mixins/formBuilderMixin";
import HttpService from "@services/httpService";
import VueTribute from "vue-tribute";
import apis from "@apis/borhanApi.js";
export default {
props: {
enableSuggestion: {
default: false,
},
contextMenu: {
default() {
return [];
},
},
},
mixins: [formBuilderMixin],
data() {
return {
tributeOptions: {
// symbol or string that starts the lookup
trigger: "",
// element to target for @mentions
iframe: null,
// class added in the flyout menu for active item
selectClass: "highlight",
// class added to the menu container
containerClass: "tribute-container",
// class added to each list item
itemClass: "my-tribute-class",
// function called on select that returns the content to insert
selectTemplate: function (item) {
return item.original.value;
// return "@" + item.original.value;
},
// template for displaying item in menu
menuItemTemplate: function (item) {
return item.string;
},
// template for when no match is found (optional),
// If no template is provided, menu is hidden.
noMatchTemplate:
'<span class="no-result">مورد مشابهی ثبت نشده است.</span>',
// specify an alternative parent container for the menu
// container must be a positioned element for the menu to appear correctly ie. `position: relative;`
// default container is the body
menuContainer: document.body,
// column to search against in the object (accepts function or string)
lookup: "key",
// column that contains the content to insert by default
fillAttr: "value",
// REQUIRED: array of objects to match or a function that returns data (see 'Loading remote data' for an example)
values: [
{
key: "سلام",
value: "سلام",
},
{
key: "باسلام",
value: "باسلام",
},
{
key: "علیک سلام",
value: "علیک سلام",
},
{
key: "بی سلام",
value: "بی سلام",
},
{
key: "صدتا سلام",
value: "صدتا سلام",
},
],
// values: ["سلام", "باسلام", "علیک سلام", "بی سلام", "صدتا سلام"],
// values: (text, cb) => {
// this.remoteSearch(text, (items) => cb(items));
// },
// When your values function is async, an optional loading template to show
loadingItemTemplate: null,
// specify whether a space is required before the trigger string
requireLeadingSpace: true,
// specify whether a space is allowed in the middle of mentions
allowSpaces: true,
// optionally specify a custom suffix for the replace text
// (defaults to empty space if undefined)
// replaceTextSuffix: "",
// specify whether the menu should be positioned. Set to false and use in conjuction with menuContainer to create an inline menu
// (defaults to true)
positionMenu: true,
// when the spacebar is hit, select the current match
spaceSelectsMatch: false,
// turn tribute into an autocomplete
autocompleteMode: true,
// Customize the elements used to wrap matched strings within the results list
// defaults to <span></span> if undefined
searchOpts: {
pre: "<span>",
post: "</span>",
skip: false, // true will skip local search, useful if doing server-side search
},
// Limits the number of items in the menu
menuItemLimit: 25,
// specify the minimum number of characters that must be typed before menu appears
menuShowMinLength: 0,
},
httpService: undefined,
};
},
mounted() {
this.httpService = new HttpService();
},
methods: {
getRows() {
if (this.localFormElement?.rows) return this.localFormElement?.rows;
return "3";
},
noMatchFound(args) {
console.info(args);
},
textReplaced(args) {
console.info(args);
},
methodName(action, index = 0) {
try {
this[action](index);
} catch (err) {
this.$emit(action, index);
}
},
remoteSearch(input, callback) {
console.info(input);
return this.httpService
.getRequest(apis.concept.annotations.read + "?ontology_id=" + input)
.then((res) => {
callback(res.data);
})
.catch((e) => {
callback([]);
})
.finally(() => {
this.fetchingData = false;
});
},
},
components: {
VueTribute: () => import("vue-tribute"),
},
};
</script>
<style scoped>
.form-control {
height: auto !important;
}
</style>
<style>
.tribute-container {
position: absolute;
top: 0;
left: 0;
height: auto;
overflow: auto;
max-height: 25em;
overflow: auto;
display: block;
z-index: 999999;
transform: translate(-80px, 7px);
box-shadow: 0 9px 8px -3px rgba(64, 60, 67, 0.24),
8px 0 8px -7px rgba(64, 60, 67, 0.24),
-8px 0 8px -7px rgba(64, 60, 67, 0.24);
box-shadow: 0px 0px 14px 0px #eee;
border-radius: 0.3em;
background: #ededed;
}
.tribute-container ul {
margin: 0;
margin-top: 2px;
padding: 0;
list-style: none;
/* background: #efefef; */
}
.tribute-container li {
padding: 0.5em 1em;
cursor: pointer;
}
.tribute-container li.highlight {
/* background: #ddd; */
}
.tribute-container li span {
font-weight: bold;
}
.tribute-container li.no-match {
cursor: default;
}
.tribute-container .menu-highlighted {
font-weight: bold;
}
</style>