Skip to content

Commit 046b3d3

Browse files
committed
refactor: drag-and-drop in dedicated component
Outsource complexity from main component and prepare new component to be exposed as standalone public component.
1 parent a48312e commit 046b3d3

File tree

4 files changed

+97
-61
lines changed

4 files changed

+97
-61
lines changed

src/components/QrcodeDropZone.vue

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<template lang="html">
2+
<div
3+
@drop.prevent.stop="onDrop"
4+
@dragover.prevent.stop
5+
@dragenter.prevent.stop
6+
@dragleave.prevent.stop>
7+
<slot></slot>
8+
</div>
9+
</template>
10+
11+
<script>
12+
import { scan } from '../misc/scanner.js'
13+
import { imageDataFromFile, imageDataFromUrl } from '../misc/image-data.js'
14+
import CommonAPI from '../mixins/CommonAPI.vue'
15+
16+
export default {
17+
18+
mixins: [ CommonAPI ],
19+
20+
methods: {
21+
onDrop ({ dataTransfer }) {
22+
const droppedFiles = [...dataTransfer.files]
23+
const droppedUrl = dataTransfer.getData('text')
24+
25+
droppedFiles.forEach(file => {
26+
this.onDetect(this.processFile(file))
27+
})
28+
29+
if (droppedUrl !== '') {
30+
this.onDetect(this.processUrl(droppedUrl))
31+
}
32+
},
33+
34+
async processFile (file) {
35+
const imageData = await imageDataFromFile(file)
36+
const scanResult = await scan(imageData)
37+
38+
return { source: 'file', ...scanResult }
39+
},
40+
41+
async processUrl (url) {
42+
const imageData = await imageDataFromUrl(url)
43+
const scanResult = await scan(imageData)
44+
45+
return { source: 'url', ...scanResult }
46+
},
47+
48+
},
49+
50+
}
51+
</script>

src/components/QrcodeReader.vue

Lines changed: 20 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
<template lang="html">
22
<div class="qrcode-reader">
33
<div class="qrcode-reader__inner-wrapper">
4-
<div
5-
class="qrcode-reader__overlay"
6-
@drop.prevent.stop="onDrop"
7-
@dragover.prevent.stop
8-
@dragenter.prevent.stop
9-
@dragleave.prevent.stop
10-
>
4+
<QrcodeDropZone
5+
@detect="onDetect"
6+
class="qrcode-reader__overlay">
117
<slot></slot>
12-
</div>
8+
</QrcodeDropZone>
139

1410
<canvas
1511
ref="trackingLayer"
@@ -35,13 +31,18 @@
3531
</template>
3632

3733
<script>
38-
import * as Scanner from '../misc/scanner.js'
34+
import { keepScanning } from '../misc/scanner.js'
3935
import Camera from '../misc/camera.js'
40-
import { imageDataFromFile, imageDataFromUrl } from '../misc/image-data.js'
4136
import isBoolean from 'lodash/isBoolean'
37+
import QrcodeDropZone from './QrcodeDropZone.vue'
38+
import CommonAPI from '../mixins/CommonAPI.vue'
4239
4340
export default {
4441
42+
components: { QrcodeDropZone },
43+
44+
mixins: [ CommonAPI ],
45+
4546
props: {
4647
paused: {
4748
type: Boolean,
@@ -210,9 +211,16 @@ export default {
210211
},
211212
212213
startScanning () {
213-
Scanner.keepScanning(this.cameraInstance, {
214+
const detectHandler = promise => {
215+
this.onDetect(async () => {
216+
const result = await promise
217+
return { source: 'stream', ...result }
218+
})
219+
}
220+
221+
keepScanning(this.cameraInstance, {
222+
detectHandler,
214223
locateHandler: this.onLocate,
215-
detectHandler: scanResult => this.onDetect('stream', scanResult),
216224
shouldContinue: () => this.shouldScan,
217225
minDelay: this.scanInterval,
218226
})
@@ -235,54 +243,6 @@ export default {
235243
}
236244
},
237245
238-
async onDetect (source, promise) {
239-
this.$emit('detect', (async () => {
240-
const data = await promise
241-
242-
return { source, ...data }
243-
})())
244-
245-
try {
246-
const { content } = await promise
247-
248-
if (content !== null) {
249-
this.$emit('decode', content)
250-
}
251-
} catch (error) {
252-
// fail silently
253-
}
254-
},
255-
256-
onDrop ({ dataTransfer }) {
257-
const droppedFiles = [...dataTransfer.files]
258-
259-
droppedFiles.forEach(this.onDropFile)
260-
261-
const droppedUrl = dataTransfer.getData('text')
262-
263-
if (droppedUrl !== '') {
264-
this.onDropUrl(droppedUrl)
265-
}
266-
},
267-
268-
async onDropFile (file) {
269-
this.onDetect('file', (async () => {
270-
const imageData = await imageDataFromFile(file)
271-
const scanResult = await Scanner.scan(imageData)
272-
273-
return scanResult
274-
})())
275-
},
276-
277-
async onDropUrl (url) {
278-
this.onDetect('url', (async () => {
279-
const imageData = await imageDataFromUrl(url)
280-
const scanResult = await Scanner.scan(imageData)
281-
282-
return scanResult
283-
})())
284-
},
285-
286246
/**
287247
* The coordinates are based on the original camera resolution but the
288248
* video element is responsive and scales with space available. Therefore

src/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import QrcodeReader from './components/QrcodeReader.vue'
2+
// import QrcodeDropZone from './components/QrcodeDropZone.vue'
23

34
// Install the components
45
export function install (Vue) {
56
Vue.component('qrcode-reader', QrcodeReader)
67
}
78

89
// Expose the components
9-
export { QrcodeReader }
10+
export {
11+
QrcodeReader,
12+
// QrcodeDropZone,
13+
}
1014

1115
/* -- Plugin definition & Auto-install -- */
1216
/* You shouldn't have to modify the code below */

src/mixins/CommonAPI.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<script>
2+
export default {
3+
4+
methods: {
5+
async onDetect (resultPromise) {
6+
this.$emit('detect', resultPromise)
7+
8+
try {
9+
const { content } = await resultPromise
10+
11+
if (content !== null) {
12+
this.$emit('decode', content)
13+
}
14+
} catch (error) {
15+
// fail silently
16+
}
17+
},
18+
},
19+
20+
}
21+
</script>

0 commit comments

Comments
 (0)