<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>