mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-23 22:46:49 +01:00
* Swap bootstrap asset files * Update themes and color definitions * Move general bootstrap customizations * Theme updates Theme updates * Remove BuildBundlerMinifier This lead to an error, because BuildBundlerMinifier and BundlerMinifier.Core seem to conflict here. Details: https://stackoverflow.com/a/61119586 * Rewplace btn-block class with w-100 * Update badge classes * Remove old font family head variable * Update margin classes * Cleanups * Update float classes * Update text classes * Update padding classes * Update border classes * UPdate dropdown classes * Update select classes * Update neutral custom props * Update bootstrap and customizations * Update ChromeDriver; disable smooth scroll https://github.com/SeleniumHQ/selenium/issues/8295 * Improve alert messages * Improve bootstrap customizations * Disable reduced motion See also 7358282f * Update Bootstrap data attributes * Update file inputs * Update input groups * Replace deprecated jumbotron class * Update variables; re-add negative margin util classes * Update cards * Update form labels * Debug alerts * Fix aria-labelledby associations * Dropdown-related test fixes * Fix CanUseWebhooks test * Test fixes * Nav updates * Fix nav usage in wallet send and payouts * Update alert and modal close buttons * Re-add backdrop properties * Upgrade Bootstrap to v5 final * Update screen reader classes * Update font-weight classes * Update monospace font classes * Update accordians * Update close icon usage * Cleanup * Update scripts and style integrations * Update input group texts * Update LN node setup page * Update more form control classes * Update inline forms * Add js specific test * Upgrade Vue.js * Remove unused JS * Upgrade Bootstrap to v5.0.1 * Try container related test updates * Separate jQuery bundle * Remove jQuery from LND seed backup page * Remove unused code * Refactor email autofill js * Refactor camera scanner JS * Re-add tests * Re-add BuildBundlerMinifier * Do not minify bundles containing Bootstrap Details https://github.com/madskristensen/BundlerMinifier/issues/558 * Update bundles * Cleanup JS test * Cleanup tests involving dropdowns * Cleanup tests involving collapses * Cleanup locale additions in ConfigureCore * Cleanup bundles * Remove duplicate status message * Cleanup formatting * Fix missing validation scripts * Remove unused unminified Bootstrap js files * Fix classic theme * Fix Casa theme * Fix PoS validation
185 lines
5.6 KiB
Text
185 lines
5.6 KiB
Text
<template id="camera-qr-scanner-wrap">
|
|
<div v-if="modalId" :id="modalId" class="modal fade" data-bs-backdrop="static">
|
|
<div class="modal-dialog" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">
|
|
{{title}}
|
|
<span v-if="workload.length > 0">Animated QR detected: {{workload.length}} / {{workload[0].total}} scanned</span>
|
|
</h5>
|
|
<button type="button" class="btn-close" aria-label="Close" v-on:click="close">
|
|
<vc:icon symbol="close"/>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<slot/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-else>
|
|
<slot></slot>
|
|
<div v-if="workload.length > 0">Animated QR detected: {{workload.length}} / {{workload[0].total}} scanned</div>
|
|
</div>
|
|
</template>
|
|
|
|
<div id="camera-qr-scanner-modal-app" v-cloak class="only-for-js">
|
|
<scanner-wrap v-bind="$data" v-on:close="close">
|
|
<div v-if="isLoaded && requestInput" class="d-flex justify-content-center align-items-center" :class="{'border border-secondary': !isModal}">
|
|
<div class="spinner-border text-secondary position-absolute" role="status"></div>
|
|
<qrcode-drop-zone v-on:decode="onDecode" v-on:init="logErrors">
|
|
<qrcode-stream v-on:decode="onDecode" v-on:init="onInit" :camera="camera" :track="paint"/>
|
|
</qrcode-drop-zone>
|
|
<qrcode-capture v-if="noStreamApiSupport" v-on:decode="onDecode" :camera="camera"/>
|
|
</div>
|
|
<div v-else-if="qrData || errorMessage">
|
|
<div v-if="errorMessage" class="alert alert-danger" role="alert">
|
|
{{errorMessage}}
|
|
</div>
|
|
<div class="text-break font-monospace">
|
|
{{qrData}}
|
|
</div>
|
|
<div class="mt-4">
|
|
<button type="button" class="btn btn-primary me-1" v-if="qrData" v-on:click="submitData">Submit</button>
|
|
<button type="button" class="btn btn-secondary me-1" v-on:click="retry">Retry</button>
|
|
<button type="button" class="btn btn-outline-secondary" v-if="isModal" v-on:click="close">Cancel</button>
|
|
</div>
|
|
</div>
|
|
</scanner-wrap>
|
|
</div>
|
|
|
|
<script>
|
|
function initCameraScanningApp(title, onDataSubmit, modalId) {
|
|
const isModal = !!modalId;
|
|
|
|
Vue.component('scanner-wrap', {
|
|
props: ["modalId", "title", "workload"],
|
|
template: "#camera-qr-scanner-wrap",
|
|
methods: {
|
|
close() {
|
|
this.$emit('close');
|
|
}
|
|
}
|
|
});
|
|
|
|
new Vue({
|
|
el: '#camera-qr-scanner-modal-app',
|
|
data() {
|
|
return {
|
|
isModal,
|
|
isLoaded: !isModal,
|
|
title: title,
|
|
modalId: modalId,
|
|
noStreamApiSupport: false,
|
|
qrData: null,
|
|
errorMessage: null,
|
|
workload: [],
|
|
camera: "auto"
|
|
}
|
|
},
|
|
mounted() {
|
|
if (this.isModal) {
|
|
const modal = document.getElementById(this.modalId);
|
|
modal.addEventListener('shown.bs.modal', () => { this.isLoaded = true; });
|
|
modal.addEventListener('hide.bs.modal', () => { this.isLoaded = false; });
|
|
} else {
|
|
this.isLoaded = true;
|
|
}
|
|
},
|
|
computed: {
|
|
requestInput() {
|
|
return this.camera === 'auto' && this.errorMessage === null;
|
|
}
|
|
},
|
|
methods: {
|
|
setQrData (qrData) {
|
|
this.qrData = qrData;
|
|
this.camera = qrData ? "off" : "auto";
|
|
},
|
|
retry() {
|
|
this.camera = "off";
|
|
this.$nextTick(this.reset);
|
|
},
|
|
reset() {
|
|
this.setQrData(null);
|
|
this.errorMessage = null;
|
|
this.workload = [];
|
|
},
|
|
close() {
|
|
if (this.modalId) {
|
|
const modal = bootstrap.Modal.getInstance(document.getElementById(this.modalId));
|
|
modal.hide();
|
|
}
|
|
this.reset();
|
|
},
|
|
onDecode(content) {
|
|
if (this.qrData) return;
|
|
|
|
if (!content.toLowerCase().startsWith("ur:")) {
|
|
this.setQrData(content);
|
|
this.workload = [];
|
|
} else {
|
|
const [index, total] = window.bcur.extractSingleWorkload(content);
|
|
if (this.workload.length > 0) {
|
|
const currentTotal = this.workload[0].total;
|
|
if (total !== currentTotal) {
|
|
this.workload = [];
|
|
}
|
|
}
|
|
if (!this.workload.find(i => i.index === index)) {
|
|
this.workload.push({
|
|
index,
|
|
total,
|
|
data: content,
|
|
});
|
|
if (this.workload.length === total) {
|
|
const decoded = window.bcur.decodeUR(this.workload.map(i => i.data));
|
|
this.setQrData(decoded);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
submitData() {
|
|
if (onDataSubmit) {
|
|
onDataSubmit(this.qrData);
|
|
}
|
|
this.close();
|
|
},
|
|
logErrors(promise) {
|
|
promise.catch(console.error)
|
|
},
|
|
paint(location, ctx) {
|
|
ctx.fillStyle = '#137547';
|
|
[
|
|
location.topLeftFinderPattern,
|
|
location.topRightFinderPattern,
|
|
location.bottomLeftFinderPattern
|
|
].forEach(({ x, y }) => {
|
|
ctx.fillRect(x - 5, y - 5, 10, 10);
|
|
})
|
|
},
|
|
onInit(promise) {
|
|
promise.then(() => {
|
|
this.errorMessage = null;
|
|
}).catch(error => {
|
|
if (error.name === 'StreamApiNotSupportedError') {
|
|
this.noStreamApiSupport = true;
|
|
} else if (error.name === 'NotAllowedError') {
|
|
this.errorMessage = 'A permission to the camera is needed to scan the QR code. Please grant the browser access and then retry.'
|
|
} else if (error.name === 'NotFoundError') {
|
|
this.errorMessage = 'A camera was not detected on your device.'
|
|
} else if (error.name === 'NotSupportedError') {
|
|
this.errorMessage = 'This page is served in non-secure context (HTTPS, localhost or file://)'
|
|
} else if (error.name === 'NotReadableError') {
|
|
this.errorMessage = 'Couldn\'t access your camera. Is it already in use?'
|
|
} else if (error.name === 'OverconstrainedError') {
|
|
this.errorMessage = 'Constraints don\'t match any installed camera.'
|
|
} else {
|
|
this.errorMessage = 'UNKNOWN ERROR: ' + error.message
|
|
}
|
|
})
|
|
}
|
|
}
|
|
});
|
|
}
|
|
</script>
|