aboutsummaryrefslogtreecommitdiff
path: root/resources/vue/components/Quicksearch.vue
blob: 0f37ae0d6ab796febe203deeb1186d7d691e91b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<template>
    <span :class="'quicksearch_container' + (containerclass ? ' ' + containerclass : '')">
        <input type="hidden"
               :name="name"
               :value="returnValue"
               v-if="!autocomplete && name">
        <input type="text"
               :name="autocomplete ? name : null"
               v-model="inputValue"
               autocomplete="off"
               @blur="reset()"
               @keydown.up="selectUp"
               @keydown.down="selectDown"
               @keydown.enter.prevent="selectByKey"
               v-bind="$attrs">
        <div class="dropdownmenu">
            <ul class="autocomplete__results" v-if="isVisible">
                <li class="autocomplete__result"
                    v-for="(result, index) in results"
                    :key="index"
                    :class="index === selected ? 'autocomplete__result--selected' : ''"
                    @click="select(result)"
                    v-html="result.item_name">
                </li>
                <li v-if="errorMessage !== null">{{errorMessage}}</li>
            </ul>
        </div>
    </span>
</template>

<script>
export default {
    name: 'quicksearch',
    props: {
        searchtype: {
            type: String,
            required: true
        },
        name: {
            type: String,
            required: false
        },
        value: {
            type: String,
            required: false,
            default: ''
        },
        needle: {
            type: String,
            required: false,
            default: ''
        },
        autocomplete: {
            type: Boolean,
            required: false,
            default: false
        },
        containerclass: {
            type: String,
            required: false,
            default: ''
        }
    },
    inheritAttrs: false,
    data () {
        return {
            searching: false,
            debounceTimeout: null,
            selected: null,
            results: [],
            errorMessage: null,
            inputValue: null,
            returnValue: null,
            initialValue: null
        };
    },
    methods: {
        initialize (value, displayname) {
            this.initialValue = value;
            this.inputValue = displayname ?? value;
            this.returnValue = value;
        },
        search (needle) {
            clearTimeout(this.debounceTimeout);
            this.debounceTimeout = setTimeout(() => {
                let data = []
                if ($(this.$el).closest("form").length > 0) {
                    data = $(this.$el).closest("form").serializeArray();
                }
                data.push({
                    name: "request",
                    value: needle
                });

                $.post(
                    STUDIP.URLHelper.getURL("dispatch.php/quicksearch/response/" + this.searchtype),
                    data
                ).done(response => {
                    this.selected = null;
                    this.results = response;
                    this.errorMessage = null;
                }).fail(response => {
                    this.errorMessage = response.responseText;
                }).always(() => {
                    this.searching = false;
                });

                this.searching = true;
            }, 500);
        },
        select (result) {
            this.inputValue = result.item_search_name;
            this.initialValue = this.inputValue;
            if (this.autocomplete) {
                this.returnValue = result.item_search_name;
            } else {
                this.returnValue = result.item_id;
            }
            this.results = [];

            this.$emit('input', this.returnValue, this.inputValue);
            this.inputValue = '';
        },
        selectUp () {
            if (this.selected > 0) {
                this.selected -= 1;
            } else if (this.selected === null) {
                this.selected = this.results.length - 1;
            } else {
                this.selected = null;
            }
        },
        selectDown () {
            if (this.selected === null) {
                this.selected = 0;
            } else if (this.selected < this.results.length - 1) {
                this.selected += 1;
            } else {
                this.selected = null;
            }
        },
        selectByKey () {
            if (this.selected !== null) {
                this.select(this.results[this.selected]);
            }
            return false;
        },
        reset (clear = false) {
            setTimeout(() => {
                this.results = [];
                this.selected = null;

                if (clear) {
                    this.returnValue = this.initialValue;
                    this.inputValue = this.initialValue;
                }
            }, clear ? 0 : 200);
        }
    },
    created () {
        this.initialize(
            this.value,
            this.autocomplete ? this.value : this.needle
        );
    },
    computed: {
        isVisible() {
            return this.results.length > 0 || this.errorMessage !== null;
        }
    },
    watch: {
        value (val) {
            this.reset(true);
            this.initialize(val);
        },
        inputValue (needle, oldneedle) {
            if (oldneedle !== null && (oldneedle !== needle) && needle.length > 2) {
                this.search(needle);
            }
        }
    }
}
</script>