|
78 | 78 | </cdx-button> |
79 | 79 | </div> |
80 | 80 | <form id="items-form" @submit.prevent="send"> |
81 | | - <text-area |
82 | | - :label="$i18n('item-form-id-input-label')" |
83 | | - :placeholder="$i18n('item-form-id-input-placeholder')" |
84 | | - :rows="8" |
| 81 | + <item-id-search-textarea |
85 | 82 | :loading="loading" |
86 | | - :error="validationError" |
87 | | - v-model="form.itemsInput" |
| 83 | + ref="textarea" |
88 | 84 | /> |
89 | 85 | <div class="form-buttons"> |
90 | 86 | <cdx-button |
|
106 | 102 | import { Head as InertiaHead } from '@inertiajs/inertia-vue3'; |
107 | 103 | import { mapState } from 'pinia'; |
108 | 104 | import { useStore } from '../store'; |
109 | | - import { TextArea } from '@wmde/wikit-vue-components'; |
110 | 105 | import { CdxDialog, CdxButton, CdxIcon, CdxMessage } from "@wikimedia/codex"; |
| 106 | + import ItemIdSearchTextarea from '../Components/ItemIdSearchTextarea.vue'; |
111 | 107 | import { cdxIconDie, cdxIconInfo } from '@wikimedia/codex-icons'; |
112 | | - import { defineComponent } from 'vue'; |
| 108 | + import { defineComponent, ref } from 'vue'; |
| 109 | + import ValidationError from '../types/ValidationError'; |
113 | 110 |
|
114 | 111 | interface HomeState { |
115 | | - form: { |
116 | | - itemsInput: string |
117 | | - }, |
118 | | - validationError: null|{ |
119 | | - type: string, |
120 | | - message: string |
121 | | - }, |
122 | | - faqDialog: boolean |
| 112 | + validationError: null|ValidationError, |
| 113 | + faqDialog: boolean |
123 | 114 | } |
124 | 115 |
|
125 | 116 | interface ErrorMessages { |
|
130 | 121 | errors : { [ key : string ] : string } |
131 | 122 | } |
132 | 123 |
|
133 | | - export const MAX_NUM_IDS = 600; |
134 | | -
|
135 | 124 | export default defineComponent({ |
136 | 125 | components: { |
137 | 126 | CdxDialog, |
138 | 127 | CdxButton, |
139 | 128 | CdxIcon, |
140 | 129 | CdxMessage, |
141 | | - InertiaHead, |
142 | | - TextArea, |
| 130 | + ItemIdSearchTextarea, |
| 131 | + InertiaHead |
143 | 132 | }, |
144 | 133 | setup() { |
| 134 | + const store = useStore(); |
| 135 | + const textareaInputValue = ref(store.lastSearchedIds); |
| 136 | + |
145 | 137 | return { |
146 | 138 | cdxIconDie, |
147 | | - cdxIconInfo |
| 139 | + cdxIconInfo, |
| 140 | + textareaInputValue |
148 | 141 | }; |
149 | 142 | }, |
150 | 143 | methods: { |
151 | | - splitInput: function(): Array<string> { |
152 | | - return this.form.itemsInput.split( '\n' ); |
153 | | - }, |
154 | | - sanitizeArray: function(): Array<string> { |
155 | | - // this filter function removes all falsy values |
156 | | - // see: https://stackoverflow.com/a/281335/1619792 |
157 | | - return this.splitInput().filter(x => x); |
158 | | - }, |
159 | | - serializeInput: function(): string { |
160 | | - return this.sanitizeArray().join('|'); |
161 | | - }, |
162 | | - validate(): void { |
163 | | - this.validationError = null; |
164 | | -
|
165 | | - const rules = [{ |
166 | | - check: (ids: Array<string>) => ids.length < 1, |
167 | | - type: 'warning', |
168 | | - message: this.$i18n('item-form-error-message-empty') |
169 | | - }, |
170 | | - { |
171 | | - check: (ids: Array<string>) => ids.length > MAX_NUM_IDS, |
172 | | - type: 'error', |
173 | | - message: this.$i18n('item-form-error-message-max', MAX_NUM_IDS) |
174 | | - }, |
175 | | - { |
176 | | - check: (ids: Array<string>) => !ids.every(value => /^[Qq]\d+$/.test( value.trim() )), |
177 | | - type: 'error', |
178 | | - message: this.$i18n('item-form-error-message-invalid') |
179 | | - }]; |
180 | | -
|
181 | | - const sanitized = this.sanitizeArray(); |
182 | | -
|
183 | | - for(const {check, type, message} of rules){ |
184 | | - if(check(sanitized)){ |
185 | | - this.validationError = { type, message }; |
186 | | - return; |
187 | | - } |
188 | | - } |
189 | | - }, |
190 | 144 | send(): void { |
191 | | - this.validate(); |
| 145 | + (this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).validate(); |
192 | 146 |
|
193 | | - if(this.validationError) { |
| 147 | + if((this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).validationError) { |
194 | 148 | return; |
195 | 149 | } |
196 | 150 | const store = useStore(); |
197 | | - store.saveSearchedIds( this.form.itemsInput ); |
198 | | - this.$inertia.get( '/results', { ids: this.serializeInput() } ); |
| 151 | + store.saveSearchedIds( this.textareaInputValue ); |
| 152 | + this.$inertia.get( '/results', |
| 153 | + { ids: (this.$refs.textarea as InstanceType<typeof ItemIdSearchTextarea>).serializeInput() } |
| 154 | + ); |
199 | 155 | }, |
200 | 156 | showRandom(): void { |
201 | 157 | this.$inertia.get( '/random' ); |
|
216 | 172 | ...mapState(useStore, ['loading']), |
217 | 173 | }, |
218 | 174 | data(): HomeState { |
219 | | - const store = useStore(); |
220 | 175 | return { |
221 | | - form: { |
222 | | - itemsInput: store.lastSearchedIds |
223 | | - }, |
224 | 176 | validationError: null, |
225 | 177 | faqDialog: false |
226 | 178 | } |
|
272 | 224 | .form-buttons { |
273 | 225 | text-align: end; |
274 | 226 | } |
| 227 | +
|
| 228 | + .cdx-field__control { |
| 229 | + position: relative; |
| 230 | + width: 100%; |
| 231 | +
|
| 232 | + .progress-bar-wrapper { |
| 233 | + position: absolute; |
| 234 | + top: 50%; |
| 235 | + width: 100%; |
| 236 | +
|
| 237 | + .cdx-progress-bar { |
| 238 | + width: 50%; |
| 239 | + margin: auto; |
| 240 | + } |
| 241 | + } |
| 242 | + } |
275 | 243 | } |
276 | 244 | </style> |
0 commit comments