|
1 | 1 | <template>
|
2 |
| - <!-- Normally this should be a <label> but IE borks out on it. Awaiting fix from MSFT --> |
3 |
| - <div :class="[custom?'custom-file':null, state?`is-${state}`:null]" |
| 2 | + <input v-if="plain" |
| 3 | + type="file" |
| 4 | + :id="safeId()" |
| 5 | + ref="input" |
| 6 | + :class="['form-control-file', sizeFormClass, stateClass]" |
| 7 | + :name="name" |
| 8 | + :disabled="disabled" |
| 9 | + :required="required" |
| 10 | + :capture="capture || null" |
| 11 | + :aria-required="required ? 'true' : null" |
| 12 | + :accept="accept || null" |
| 13 | + :multiple="multiple" |
| 14 | + :webkitdirectory="directory" |
| 15 | + @change="onFileChange"> |
| 16 | + <div v-else |
| 17 | + :class="['custom-file', 'w-100', stateClass]" |
4 | 18 | :id="safeId('_BV_file_outer_')"
|
5 |
| - @dragover.stop.prevent="dragover" |
6 |
| - > |
| 19 | + @dragover.stop.prevent="dragover"> |
| 20 | + <!-- Normally this div should be label, but IE borks out if label has a file input inside. Awaiting fix from MSFT --> |
7 | 21 |
|
8 |
| - <!-- Drop Here Target --> |
9 |
| - <span class="drop-here" |
10 |
| - v-if="dragging && custom" |
11 |
| - @dragover.stop.prevent="dragover" |
12 |
| - @drop.stop.prevent="drop" |
13 |
| - @dragleave.stop.prevent="dragging=false" |
14 |
| - :data-drop="dropLabel" |
15 |
| - ></span> |
| 22 | + <!-- Drop Here Target, set as label so it can be associated with input --> |
| 23 | + <label v-if="dragging" |
| 24 | + :for="safeId()" |
| 25 | + :data-drop="dropLabel" |
| 26 | + class="drop-here" |
| 27 | + @dragover.stop.prevent="dragover" |
| 28 | + @drop.stop.prevent="drop" |
| 29 | + @dragleave.stop.prevent="dragging=false" |
| 30 | + ></label> |
16 | 31 |
|
17 | 32 | <!-- Real Form input -->
|
18 | 33 | <input type="file"
|
19 | 34 | :id="safeId()"
|
20 | 35 | ref="input"
|
21 |
| - :class="[custom?'custom-file-input':'form-control-file', stateClass]" |
| 36 | + :class="['custom-file-input', 'w-100', stateClass, hasFocus?'focus':'']" |
22 | 37 | :name="name"
|
23 | 38 | :disabled="disabled"
|
24 | 39 | :required="required"
|
|
27 | 42 | :accept="accept || null"
|
28 | 43 | :multiple="multiple"
|
29 | 44 | :webkitdirectory="directory"
|
30 |
| - :aria-describedby="custom ? safeId('_BV_file_control_') : null" |
31 |
| - @change="onFileChange" |
32 |
| - > |
| 45 | + :aria-describedby="safeId('_BV_file_control_')" |
| 46 | + @focusin="focusHandler" |
| 47 | + @focusout="focusHandler" |
| 48 | + @change="onFileChange"> |
33 | 49 |
|
34 | 50 | <!-- Overlay Labels -->
|
35 |
| - <span :class="['custom-file-control',dragging?'dragging':null]" |
36 |
| - :id="safeId('_BV_file_control_')" |
37 |
| - :data-choose="computedChooseLabel" |
38 |
| - :data-selected="selectedLabel" |
39 |
| - v-if="custom" |
40 |
| - ></span> |
| 51 | + <!-- this is normally a <span> but we use <label> here so we can associate it with the input --> |
| 52 | + <label :id="safeId('_BV_file_control_')" |
| 53 | + :for="safeId()" |
| 54 | + :class="['custom-file-control', dragging?'dragging':null]" |
| 55 | + :data-choose="computedChooseLabel" |
| 56 | + :data-selected="selectedLabel" |
| 57 | + ></label> |
41 | 58 |
|
42 | 59 | </div>
|
43 | 60 | </template>
|
44 | 61 |
|
45 | 62 | <style scoped>
|
46 |
| - /* Are these classes needed??? bootstrap.css contains similar ones */ |
| 63 | + /* Custom-file focus styling */ |
| 64 | + /* regular focus styling */ |
| 65 | + .custom-file-input.focus ~ .custom-file-control, |
| 66 | + .custom-file-input:focus ~ .custom-file-control { |
| 67 | + color: #495057; |
| 68 | + background-color: #fff; |
| 69 | + border-color: #80bdff; |
| 70 | + outline: none; |
| 71 | + } |
| 72 | +
|
| 73 | + /* Invalid focus styling */ |
| 74 | + .custom-file-input.is-invalid.focus ~ .custom-file-control, |
| 75 | + .custom-file-input.is-invalid:focus ~ .custom-file-control, |
| 76 | + .was-validated .custom-file-input:invalid.focus ~ .custom-file-control, |
| 77 | + .was-validated .custom-file-input:invalid:focus ~ .custom-file-control { |
| 78 | + -webkit-box-shadow: 0 0 0 .2rem rgba(220,53,69,.25); |
| 79 | + box-shadow: 0 0 0 .2rem rgba(220,53,69,.25); |
| 80 | + border-color: #dc3545; |
| 81 | + } |
| 82 | +
|
| 83 | + /* valid focus styling */ |
| 84 | + .custom-file-input.is-valid.focus ~ .custom-file-control, |
| 85 | + .custom-file-input.is-valid:focus ~ .custom-file-control, |
| 86 | + .was-validated .custom-file-input:valid.focus ~ .custom-file-control, |
| 87 | + .was-validated .custom-file-input:valid:focus ~ .custom-file-control { |
| 88 | + -webkit-box-shadow: 0 0 0 .2rem rgba(40,167,69,.25); |
| 89 | + box-shadow: 0 0 0 .2rem rgba(40,167,69,.25); |
| 90 | + border-color: #28a745; |
| 91 | + } |
| 92 | +
|
| 93 | + /* Drag/Drop handling */ |
47 | 94 | .custom-file-control {
|
48 | 95 | overflow: hidden;
|
49 | 96 | }
|
|
95 | 142 | data() {
|
96 | 143 | return {
|
97 | 144 | selectedFile: null,
|
98 |
| - dragging: false |
| 145 | + dragging: false, |
| 146 | + hasFocus: false |
99 | 147 | };
|
100 | 148 | },
|
101 | 149 | props: {
|
|
177 | 225 | }
|
178 | 226 | },
|
179 | 227 | methods: {
|
| 228 | + handleFocus(evt) { |
| 229 | + // Boostrap v4.beta doesn't have focus styling for custom file input |
| 230 | + // Firefox has a borked '[type=file]:focus ~ sibling' selector, so we add |
| 231 | + // A 'focus' class to get around this bug |
| 232 | + if (this.plain || evt.type === 'focusout') { |
| 233 | + this.hasFocus = false; |
| 234 | + } else { |
| 235 | + // Add focus styling for custom file input |
| 236 | + this.hasFocus = true; |
| 237 | + } |
| 238 | + }, |
180 | 239 | reset() {
|
181 | 240 | try {
|
182 | 241 | // Wrapped in try in case IE < 11 craps out
|
|
0 commit comments