Skip to content

Commit

Permalink
feat(QUploader): allow kdb interaction to pick files (ENTER/SPACE) qu…
Browse files Browse the repository at this point in the history
  • Loading branch information
pdanpdan committed Mar 11, 2021
1 parent e7bcda8 commit bfe9100
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/src/examples/QUploader/SlotHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<div class="q-uploader__title">Upload your files</div>
<div class="q-uploader__subtitle">{{ scope.uploadSizeLabel }} / {{ scope.uploadProgressLabel }}</div>
</div>
<q-btn v-if="scope.canAddFiles" type="a" icon="add_box" round dense flat>
<q-btn v-if="scope.canAddFiles" type="a" icon="add_box" @click="scope.pickFiles" round dense flat>
<q-uploader-add-trigger />
<q-tooltip>Pick Files</q-tooltip>
</q-btn>
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/vue-components/file-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ As a helper, you can use `clearable` prop so user can reset model to `null` thro
## Usage

::: warning
Under the covers, QFile uses a native input. Due to browser security policy, it is not allowed to programmatically fill such an input with a value. As a result, even if you set v-model from the beginning to a value, the component will show those file(s) but the input tag itself won't be filled in with that value. A user interaction (click/tap/<kbd>ENTER</kbd> key) is absolutely required in order for the native input to contain them. It's best to always have the initial value of model set to `null` or `undefined/void 0`.
Under the covers, QFile uses a native input. Due to browser security policy, it is not allowed to programmatically fill such an input with a value. As a result, even if you set v-model from the beginning to a value, the component will show those file(s) but the input tag itself won't be filled in with that value. A user interaction (click/tap/<kbd>ENTER</kbd> key/<kbd>SPACE</kbd> key) is absolutely required in order for the native input to contain them. It's best to always have the initial value of model set to `null` or `undefined/void 0`.
:::

### Basic
Expand Down
2 changes: 1 addition & 1 deletion ui/dev/src/pages/form/uploader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
{{ scope.uploadSizeLabel }} / {{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn v-if="scope.canAddFiles" type="a" icon="add_box" round dense flat>
<q-btn v-if="scope.canAddFiles" type="a" icon="add_box" @click="scope.pickFiles" round dense flat>
<q-uploader-add-trigger />
</q-btn>
<q-btn v-if="scope.canUpload" icon="cloud_upload" @click="scope.upload" round dense flat />
Expand Down
13 changes: 11 additions & 2 deletions ui/src/components/file/QFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import FileMixin, { FileValueMixin } from '../../mixins/file.js'
import { isSSR } from '../../plugins/Platform'
import { humanStorageSize } from '../../utils/format.js'
import cache from '../../utils/cache.js'
import { prevent } from '../../utils/event.js'

export default Vue.extend({
name: 'QFile',
Expand Down Expand Up @@ -115,9 +116,16 @@ export default Vue.extend({
this.$emit('input', this.multiple === true ? files : files[0])
},

__onKeydown (e) {
// prevent form submit if ENTER is pressed
e.keyCode === 13 && prevent(e)
},

__onKeyup (e) {
// only on ENTER
e.keyCode === 13 && this.pickFiles(e)
// only on ENTER and SPACE to match native input field
if (e.keyCode === 13 || e.keyCode === 32) {
this.pickFiles(e)
}
},

__getFileInput () {
Expand Down Expand Up @@ -146,6 +154,7 @@ export default Vue.extend({
if (this.editable === true) {
data.on = cache(this, 'native', {
dragover: this.__onDragOver,
keydown: this.__onKeydown,
keyup: this.__onKeyup
})
}
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/uploader/QUploaderBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ export default Vue.extend({
flat: true,
dense: true
},
on: icon === 'add' ? null : { click: fn }
on: { click: icon === 'add' ? this.pickFiles : fn }
}, icon === 'add' ? this.__getInputControl(h) : null)
}
},
Expand All @@ -307,6 +307,7 @@ export default Vue.extend({
},
on: cache(this, 'input', {
mousedown: stop, // need to stop refocus from QBtn
click: this.pickFiles,
change: this.__addFiles
})
})
Expand Down
20 changes: 15 additions & 5 deletions ui/src/mixins/file.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { stopAndPrevent } from '../utils/event.js'
import { stop, stopAndPrevent } from '../utils/event.js'
import cache from '../utils/cache.js'

function filterFiles (files, rejectedFiles, failedPropValidation, filterFn) {
Expand Down Expand Up @@ -58,10 +58,20 @@ export default {
},

methods: {
pickFiles (e) {
if (this.editable) {
const input = this.__getFileInput()
input && input.click(e)
pickFiles (ev) {
if (this.editable === true) {
if (ev !== Object(ev)) {
ev = { target: null }
}

if (ev.target !== null && ev.target.matches('input[type="file"]') === true) {
// stop propagation if it's not a real pointer event
ev.clientX === 0 && ev.clientY === 0 && stop(ev)
}
else {
const input = this.__getFileInput()
input && input !== ev.target && input.click(ev)
}
}
},

Expand Down

0 comments on commit bfe9100

Please sign in to comment.