feat(core): update session, security system and QR exchange
- Removed session creation and Lightning payment logic - Refactored security system: * no more restrictions * all systems enabled on session creation - Improved QR code exchange for mobile devices
This commit is contained in:
16
node_modules/html5-qrcode/src/ui/scanner/base.d.ts
generated
vendored
Normal file
16
node_modules/html5-qrcode/src/ui/scanner/base.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export declare class PublicUiElementIdAndClasses {
|
||||
static ALL_ELEMENT_CLASS: string;
|
||||
static CAMERA_PERMISSION_BUTTON_ID: string;
|
||||
static CAMERA_START_BUTTON_ID: string;
|
||||
static CAMERA_STOP_BUTTON_ID: string;
|
||||
static TORCH_BUTTON_ID: string;
|
||||
static CAMERA_SELECTION_SELECT_ID: string;
|
||||
static FILE_SELECTION_BUTTON_ID: string;
|
||||
static ZOOM_SLIDER_ID: string;
|
||||
static SCAN_TYPE_CHANGE_ANCHOR_ID: string;
|
||||
static TORCH_BUTTON_CLASS_TORCH_ON: string;
|
||||
static TORCH_BUTTON_CLASS_TORCH_OFF: string;
|
||||
}
|
||||
export declare class BaseUiElementFactory {
|
||||
static createElement<Type extends HTMLElement>(elementType: string, elementId: string): Type;
|
||||
}
|
||||
81
node_modules/html5-qrcode/src/ui/scanner/base.ts
generated
vendored
Normal file
81
node_modules/html5-qrcode/src/ui/scanner/base.ts
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Contains base classes for different UI elements used in the scanner.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Id and classes of UI elements, for developers to configure the theme of
|
||||
* end to end scanner using css.
|
||||
*/
|
||||
export class PublicUiElementIdAndClasses {
|
||||
//#region Public list of element IDs for major UI elements.
|
||||
|
||||
/** Class name added to all major UI elements used in scanner. */
|
||||
static ALL_ELEMENT_CLASS = "html5-qrcode-element";
|
||||
|
||||
/** Id of the camera permission button. */
|
||||
static CAMERA_PERMISSION_BUTTON_ID = "html5-qrcode-button-camera-permission";
|
||||
|
||||
/** Id of the camera start button. */
|
||||
static CAMERA_START_BUTTON_ID = "html5-qrcode-button-camera-start";
|
||||
|
||||
/** Id of the camera stop button. */
|
||||
static CAMERA_STOP_BUTTON_ID = "html5-qrcode-button-camera-stop";
|
||||
|
||||
/** Id of the torch button. */
|
||||
static TORCH_BUTTON_ID = "html5-qrcode-button-torch";
|
||||
|
||||
/** Id of the select element used for camera selection. */
|
||||
static CAMERA_SELECTION_SELECT_ID = "html5-qrcode-select-camera";
|
||||
|
||||
/** Id of the button used for file selection. */
|
||||
static FILE_SELECTION_BUTTON_ID = "html5-qrcode-button-file-selection";
|
||||
|
||||
/** Id of the range input for zoom. */
|
||||
static ZOOM_SLIDER_ID = "html5-qrcode-input-range-zoom";
|
||||
|
||||
/**
|
||||
* Id of the anchor {@code <a>} element used for swapping between file scan
|
||||
* and camera scan.
|
||||
*/
|
||||
static SCAN_TYPE_CHANGE_ANCHOR_ID = "html5-qrcode-anchor-scan-type-change";
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region List of classes for specific use-cases.
|
||||
|
||||
/** Torch button class when torch is ON. */
|
||||
static TORCH_BUTTON_CLASS_TORCH_ON = "html5-qrcode-button-torch-on";
|
||||
|
||||
/** Torch button class when torch is OFF. */
|
||||
static TORCH_BUTTON_CLASS_TORCH_OFF = "html5-qrcode-button-torch-off";
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory class for creating different base UI elements used by the scanner.
|
||||
*/
|
||||
export class BaseUiElementFactory {
|
||||
/**
|
||||
* Creates {@link HTMLElement} of given {@param elementType}.
|
||||
*
|
||||
* @param elementType Type of element to create, example
|
||||
*/
|
||||
public static createElement<Type extends HTMLElement>(
|
||||
elementType: string, elementId: string): Type {
|
||||
|
||||
let element: Type = <Type>(document.createElement(elementType));
|
||||
element.id = elementId;
|
||||
element.classList.add(PublicUiElementIdAndClasses.ALL_ELEMENT_CLASS);
|
||||
if (elementType === "button") {
|
||||
element.setAttribute("type", "button");
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
17
node_modules/html5-qrcode/src/ui/scanner/camera-selection-ui.d.ts
generated
vendored
Normal file
17
node_modules/html5-qrcode/src/ui/scanner/camera-selection-ui.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { CameraDevice } from "../../camera/core";
|
||||
export declare class CameraSelectionUi {
|
||||
private readonly selectElement;
|
||||
private readonly options;
|
||||
private readonly cameras;
|
||||
private constructor();
|
||||
private render;
|
||||
disable(): void;
|
||||
isDisabled(): boolean;
|
||||
enable(): void;
|
||||
getValue(): string;
|
||||
hasValue(value: string): boolean;
|
||||
setValue(value: string): void;
|
||||
hasSingleItem(): boolean;
|
||||
numCameras(): number;
|
||||
static create(parentElement: HTMLElement, cameras: Array<CameraDevice>): CameraSelectionUi;
|
||||
}
|
||||
129
node_modules/html5-qrcode/src/ui/scanner/camera-selection-ui.ts
generated
vendored
Normal file
129
node_modules/html5-qrcode/src/ui/scanner/camera-selection-ui.ts
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* File for camera selection UI.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import { CameraDevice } from "../../camera/core";
|
||||
import {
|
||||
BaseUiElementFactory,
|
||||
PublicUiElementIdAndClasses
|
||||
} from "./base";
|
||||
import {
|
||||
Html5QrcodeScannerStrings
|
||||
} from "../../strings";
|
||||
|
||||
/** Class for rendering and handling camera selection UI. */
|
||||
export class CameraSelectionUi {
|
||||
|
||||
private readonly selectElement: HTMLSelectElement;
|
||||
private readonly options: Array<HTMLOptionElement>;
|
||||
private readonly cameras: Array<CameraDevice>;
|
||||
|
||||
private constructor(cameras: Array<CameraDevice>) {
|
||||
this.selectElement = BaseUiElementFactory
|
||||
.createElement<HTMLSelectElement>(
|
||||
"select",
|
||||
PublicUiElementIdAndClasses.CAMERA_SELECTION_SELECT_ID);
|
||||
this.cameras = cameras;
|
||||
this.options = [];
|
||||
}
|
||||
|
||||
/*eslint complexity: ["error", 10]*/
|
||||
private render(
|
||||
parentElement: HTMLElement) {
|
||||
const cameraSelectionContainer = document.createElement("span");
|
||||
cameraSelectionContainer.style.marginRight = "10px";
|
||||
const numCameras = this.cameras.length;
|
||||
if (numCameras === 0) {
|
||||
throw new Error("No cameras found");
|
||||
}
|
||||
if (numCameras === 1) {
|
||||
// If only one camera is found, don't show camera selection.
|
||||
cameraSelectionContainer.style.display = "none";
|
||||
} else {
|
||||
// Otherwise, show the number of cameras found as well.
|
||||
const selectCameraString = Html5QrcodeScannerStrings.selectCamera();
|
||||
cameraSelectionContainer.innerText
|
||||
= `${selectCameraString} (${this.cameras.length}) `;
|
||||
}
|
||||
|
||||
let anonymousCameraId = 1;
|
||||
|
||||
for (const camera of this.cameras) {
|
||||
const value = camera.id;
|
||||
let name = camera.label == null ? value : camera.label;
|
||||
// If no name is returned by the browser, replace it with custom
|
||||
// camera label with a count.
|
||||
if (!name || name === "") {
|
||||
name = [
|
||||
Html5QrcodeScannerStrings.anonymousCameraPrefix(),
|
||||
anonymousCameraId++
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
const option = document.createElement("option");
|
||||
option.value = value;
|
||||
option.innerText = name;
|
||||
this.options.push(option);
|
||||
this.selectElement.appendChild(option);
|
||||
}
|
||||
cameraSelectionContainer.appendChild(this.selectElement);
|
||||
parentElement.appendChild(cameraSelectionContainer);
|
||||
}
|
||||
|
||||
//#region Public APIs
|
||||
public disable() {
|
||||
this.selectElement.disabled = true;
|
||||
}
|
||||
|
||||
public isDisabled() {
|
||||
return this.selectElement.disabled === true;
|
||||
}
|
||||
|
||||
public enable() {
|
||||
this.selectElement.disabled = false;
|
||||
}
|
||||
|
||||
public getValue(): string {
|
||||
return this.selectElement.value;
|
||||
}
|
||||
|
||||
public hasValue(value: string): boolean {
|
||||
for (const option of this.options) {
|
||||
if (option.value === value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public setValue(value: string) {
|
||||
if (!this.hasValue(value)) {
|
||||
throw new Error(`${value} is not present in the camera list.`);
|
||||
}
|
||||
this.selectElement.value = value;
|
||||
}
|
||||
|
||||
public hasSingleItem() {
|
||||
return this.cameras.length === 1;
|
||||
}
|
||||
|
||||
public numCameras() {
|
||||
return this.cameras.length;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
/** Creates instance of {@link CameraSelectionUi} and renders it. */
|
||||
public static create(
|
||||
parentElement: HTMLElement,
|
||||
cameras: Array<CameraDevice>): CameraSelectionUi {
|
||||
let cameraSelectUi = new CameraSelectionUi(cameras);
|
||||
cameraSelectUi.render(parentElement);
|
||||
return cameraSelectUi;
|
||||
}
|
||||
}
|
||||
16
node_modules/html5-qrcode/src/ui/scanner/camera-zoom-ui.d.ts
generated
vendored
Normal file
16
node_modules/html5-qrcode/src/ui/scanner/camera-zoom-ui.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
export type OnCameraZoomValueChangeCallback = (zoomValue: number) => void;
|
||||
export declare class CameraZoomUi {
|
||||
private zoomElementContainer;
|
||||
private rangeInput;
|
||||
private rangeText;
|
||||
private onChangeCallback;
|
||||
private constructor();
|
||||
private render;
|
||||
private onValueChange;
|
||||
setValues(minValue: number, maxValue: number, defaultValue: number, step: number): void;
|
||||
show(): void;
|
||||
hide(): void;
|
||||
setOnCameraZoomValueChangeCallback(onChangeCallback: OnCameraZoomValueChangeCallback): void;
|
||||
removeOnCameraZoomValueChangeCallback(): void;
|
||||
static create(parentElement: HTMLElement, renderOnCreate: boolean): CameraZoomUi;
|
||||
}
|
||||
126
node_modules/html5-qrcode/src/ui/scanner/camera-zoom-ui.ts
generated
vendored
Normal file
126
node_modules/html5-qrcode/src/ui/scanner/camera-zoom-ui.ts
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* File for camera zooming UI.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import {
|
||||
BaseUiElementFactory,
|
||||
PublicUiElementIdAndClasses
|
||||
} from "./base";
|
||||
|
||||
import { Html5QrcodeScannerStrings } from "../../strings";
|
||||
|
||||
/** Callback when zoom value changes with the slider UI. */
|
||||
export type OnCameraZoomValueChangeCallback = (zoomValue: number) => void;
|
||||
|
||||
/** Class for creating and managing zoom slider UI. */
|
||||
export class CameraZoomUi {
|
||||
|
||||
private zoomElementContainer: HTMLDivElement;
|
||||
private rangeInput: HTMLInputElement;
|
||||
private rangeText: HTMLSpanElement;
|
||||
|
||||
private onChangeCallback: OnCameraZoomValueChangeCallback | null = null;
|
||||
|
||||
private constructor() {
|
||||
this.zoomElementContainer = document.createElement("div");
|
||||
this.rangeInput = BaseUiElementFactory.createElement<HTMLInputElement>(
|
||||
"input", PublicUiElementIdAndClasses.ZOOM_SLIDER_ID);
|
||||
this.rangeInput.type = "range";
|
||||
|
||||
this.rangeText = document.createElement("span");
|
||||
|
||||
// default values.
|
||||
this.rangeInput.min = "1";
|
||||
this.rangeInput.max = "5";
|
||||
this.rangeInput.value = "1";
|
||||
this.rangeInput.step = "0.1";
|
||||
}
|
||||
|
||||
private render(
|
||||
parentElement: HTMLElement,
|
||||
renderOnCreate: boolean) {
|
||||
// Style for the range slider.
|
||||
this.zoomElementContainer.style.display
|
||||
= renderOnCreate ? "block" : "none";
|
||||
this.zoomElementContainer.style.padding = "5px 10px";
|
||||
this.zoomElementContainer.style.textAlign = "center";
|
||||
parentElement.appendChild(this.zoomElementContainer);
|
||||
|
||||
this.rangeInput.style.display = "inline-block";
|
||||
this.rangeInput.style.width = "50%";
|
||||
this.rangeInput.style.height = "5px";
|
||||
this.rangeInput.style.background = "#d3d3d3";
|
||||
this.rangeInput.style.outline = "none";
|
||||
this.rangeInput.style.opacity = "0.7";
|
||||
|
||||
let zoomString = Html5QrcodeScannerStrings.zoom();
|
||||
this.rangeText.innerText = `${this.rangeInput.value}x ${zoomString}`;
|
||||
this.rangeText.style.marginRight = "10px";
|
||||
|
||||
// Bind values.
|
||||
let $this = this;
|
||||
this.rangeInput.addEventListener("input", () => $this.onValueChange());
|
||||
this.rangeInput.addEventListener("change", () => $this.onValueChange());
|
||||
|
||||
this.zoomElementContainer.appendChild(this.rangeInput);
|
||||
this.zoomElementContainer.appendChild(this.rangeText);
|
||||
}
|
||||
|
||||
private onValueChange() {
|
||||
let zoomString = Html5QrcodeScannerStrings.zoom();
|
||||
this.rangeText.innerText = `${this.rangeInput.value}x ${zoomString}`;
|
||||
if (this.onChangeCallback) {
|
||||
this.onChangeCallback(parseFloat(this.rangeInput.value));
|
||||
}
|
||||
}
|
||||
|
||||
//#region Public APIs
|
||||
public setValues(
|
||||
minValue: number,
|
||||
maxValue: number,
|
||||
defaultValue: number,
|
||||
step: number) {
|
||||
this.rangeInput.min = minValue.toString();
|
||||
this.rangeInput.max = maxValue.toString();
|
||||
this.rangeInput.step = step.toString();
|
||||
this.rangeInput.value = defaultValue.toString();
|
||||
|
||||
this.onValueChange();
|
||||
}
|
||||
|
||||
public show() {
|
||||
this.zoomElementContainer.style.display = "block";
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.zoomElementContainer.style.display = "none";
|
||||
}
|
||||
|
||||
public setOnCameraZoomValueChangeCallback(
|
||||
onChangeCallback: OnCameraZoomValueChangeCallback) {
|
||||
this.onChangeCallback = onChangeCallback;
|
||||
}
|
||||
|
||||
public removeOnCameraZoomValueChangeCallback() {
|
||||
this.onChangeCallback = null;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Creates and renders the zoom slider if {@code renderOnCreate} is
|
||||
* {@code true}.
|
||||
*/
|
||||
public static create(
|
||||
parentElement: HTMLElement,
|
||||
renderOnCreate: boolean): CameraZoomUi {
|
||||
let cameraZoomUi = new CameraZoomUi();
|
||||
cameraZoomUi.render(parentElement, renderOnCreate);
|
||||
return cameraZoomUi;
|
||||
}
|
||||
}
|
||||
19
node_modules/html5-qrcode/src/ui/scanner/file-selection-ui.d.ts
generated
vendored
Normal file
19
node_modules/html5-qrcode/src/ui/scanner/file-selection-ui.d.ts
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export type OnFileSelected = (file: File) => void;
|
||||
export declare class FileSelectionUi {
|
||||
private readonly fileBasedScanRegion;
|
||||
private readonly fileScanInput;
|
||||
private readonly fileSelectionButton;
|
||||
private constructor();
|
||||
hide(): void;
|
||||
show(): void;
|
||||
isShowing(): boolean;
|
||||
resetValue(): void;
|
||||
private createFileBasedScanRegion;
|
||||
private fileBasedScanRegionDefaultBorder;
|
||||
private fileBasedScanRegionActiveBorder;
|
||||
private createDragAndDropMessage;
|
||||
private setImageNameToButton;
|
||||
private setInitialValueToButton;
|
||||
private getFileScanInputId;
|
||||
static create(parentElement: HTMLDivElement, showOnRender: boolean, onFileSelected: OnFileSelected): FileSelectionUi;
|
||||
}
|
||||
263
node_modules/html5-qrcode/src/ui/scanner/file-selection-ui.ts
generated
vendored
Normal file
263
node_modules/html5-qrcode/src/ui/scanner/file-selection-ui.ts
generated
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* File for file selection UI handling.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import {Html5QrcodeScannerStrings} from "../../strings";
|
||||
import {
|
||||
BaseUiElementFactory,
|
||||
PublicUiElementIdAndClasses
|
||||
} from "./base";
|
||||
|
||||
/**
|
||||
* Interface for callback when a file is selected by user using the button.
|
||||
*/
|
||||
export type OnFileSelected = (file: File) => void;
|
||||
|
||||
/** UI class for file selection handling. */
|
||||
export class FileSelectionUi {
|
||||
|
||||
private readonly fileBasedScanRegion: HTMLDivElement;
|
||||
private readonly fileScanInput: HTMLInputElement;
|
||||
private readonly fileSelectionButton: HTMLButtonElement;
|
||||
|
||||
/** Creates object and renders. */
|
||||
private constructor(
|
||||
parentElement: HTMLDivElement,
|
||||
showOnRender: boolean,
|
||||
onFileSelected: OnFileSelected) {
|
||||
this.fileBasedScanRegion = this.createFileBasedScanRegion();
|
||||
this.fileBasedScanRegion.style.display
|
||||
= showOnRender ? "block" : "none";
|
||||
parentElement.appendChild(this.fileBasedScanRegion);
|
||||
|
||||
let fileScanLabel = document.createElement("label");
|
||||
fileScanLabel.setAttribute("for", this.getFileScanInputId());
|
||||
fileScanLabel.style.display = "inline-block";
|
||||
|
||||
this.fileBasedScanRegion.appendChild(fileScanLabel);
|
||||
|
||||
this.fileSelectionButton
|
||||
= BaseUiElementFactory.createElement<HTMLButtonElement>(
|
||||
"button",
|
||||
PublicUiElementIdAndClasses.FILE_SELECTION_BUTTON_ID);
|
||||
this.setInitialValueToButton();
|
||||
|
||||
// Bind click events with the label element.
|
||||
this.fileSelectionButton.addEventListener("click", (_) => {
|
||||
fileScanLabel.click();
|
||||
});
|
||||
fileScanLabel.append(this.fileSelectionButton);
|
||||
|
||||
this.fileScanInput
|
||||
= BaseUiElementFactory.createElement<HTMLInputElement>(
|
||||
"input", this.getFileScanInputId());
|
||||
this.fileScanInput.type = "file";
|
||||
this.fileScanInput.accept = "image/*";
|
||||
this.fileScanInput.style.display = "none";
|
||||
fileScanLabel.appendChild(this.fileScanInput);
|
||||
|
||||
let $this = this;
|
||||
/*eslint complexity: ["error", 5]*/
|
||||
this.fileScanInput.addEventListener("change", (e: Event) => {
|
||||
if (e == null || e.target == null) {
|
||||
return;
|
||||
}
|
||||
let target: HTMLInputElement = e.target as HTMLInputElement;
|
||||
if (target.files && target.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let fileList: FileList = target.files!;
|
||||
const file: File = fileList[0];
|
||||
let fileName = file.name;
|
||||
$this.setImageNameToButton(fileName);
|
||||
|
||||
onFileSelected(file);
|
||||
});
|
||||
|
||||
// Render drag and drop label
|
||||
let dragAndDropMessage = this.createDragAndDropMessage();
|
||||
this.fileBasedScanRegion.appendChild(dragAndDropMessage);
|
||||
|
||||
this.fileBasedScanRegion.addEventListener("dragenter", function(event) {
|
||||
$this.fileBasedScanRegion.style.border
|
||||
= $this.fileBasedScanRegionActiveBorder();
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
this.fileBasedScanRegion.addEventListener("dragleave", function(event) {
|
||||
$this.fileBasedScanRegion.style.border
|
||||
= $this.fileBasedScanRegionDefaultBorder();
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
this.fileBasedScanRegion.addEventListener("dragover", function(event) {
|
||||
$this.fileBasedScanRegion.style.border
|
||||
= $this.fileBasedScanRegionActiveBorder();
|
||||
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
/*eslint complexity: ["error", 10]*/
|
||||
this.fileBasedScanRegion.addEventListener("drop", function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
$this.fileBasedScanRegion.style.border
|
||||
= $this.fileBasedScanRegionDefaultBorder();
|
||||
|
||||
var dataTransfer = event.dataTransfer;
|
||||
if (dataTransfer) {
|
||||
let files = dataTransfer.files;
|
||||
if (!files || files.length === 0) {
|
||||
return;
|
||||
}
|
||||
let isAnyFileImage = false;
|
||||
for (let i = 0; i < files.length; ++i) {
|
||||
let file = files.item(i);
|
||||
if (!file) {
|
||||
continue;
|
||||
}
|
||||
let imageType = /image.*/;
|
||||
|
||||
// Only process images.
|
||||
if (!file.type.match(imageType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isAnyFileImage = true;
|
||||
let fileName = file.name;
|
||||
$this.setImageNameToButton(fileName);
|
||||
|
||||
onFileSelected(file);
|
||||
dragAndDropMessage.innerText
|
||||
= Html5QrcodeScannerStrings.dragAndDropMessage();
|
||||
break;
|
||||
}
|
||||
|
||||
// None of the files were images.
|
||||
if (!isAnyFileImage) {
|
||||
dragAndDropMessage.innerText
|
||||
= Html5QrcodeScannerStrings
|
||||
.dragAndDropMessageOnlyImages();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
//#region Public APIs.
|
||||
/** Hide the file selection UI. */
|
||||
public hide() {
|
||||
this.fileBasedScanRegion.style.display = "none";
|
||||
this.fileScanInput.disabled = true;
|
||||
}
|
||||
|
||||
/** Show the file selection UI. */
|
||||
public show() {
|
||||
this.fileBasedScanRegion.style.display = "block";
|
||||
this.fileScanInput.disabled = false;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if UI container is displayed. */
|
||||
public isShowing(): boolean {
|
||||
return this.fileBasedScanRegion.style.display === "block";
|
||||
}
|
||||
|
||||
/** Reset the file selection value */
|
||||
public resetValue() {
|
||||
this.fileScanInput.value = "";
|
||||
this.setInitialValueToButton();
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region private APIs
|
||||
private createFileBasedScanRegion(): HTMLDivElement {
|
||||
let fileBasedScanRegion = document.createElement("div");
|
||||
fileBasedScanRegion.style.textAlign = "center";
|
||||
fileBasedScanRegion.style.margin = "auto";
|
||||
fileBasedScanRegion.style.width = "80%";
|
||||
fileBasedScanRegion.style.maxWidth = "600px";
|
||||
fileBasedScanRegion.style.border
|
||||
= this.fileBasedScanRegionDefaultBorder();
|
||||
fileBasedScanRegion.style.padding = "10px";
|
||||
fileBasedScanRegion.style.marginBottom = "10px";
|
||||
return fileBasedScanRegion;
|
||||
}
|
||||
|
||||
private fileBasedScanRegionDefaultBorder() {
|
||||
return "6px dashed #ebebeb";
|
||||
}
|
||||
|
||||
/** Border when a file is being dragged over the file scan region. */
|
||||
private fileBasedScanRegionActiveBorder() {
|
||||
return "6px dashed rgb(153 151 151)";
|
||||
}
|
||||
|
||||
private createDragAndDropMessage(): HTMLDivElement {
|
||||
let dragAndDropMessage = document.createElement("div");
|
||||
dragAndDropMessage.innerText
|
||||
= Html5QrcodeScannerStrings.dragAndDropMessage();
|
||||
dragAndDropMessage.style.fontWeight = "400";
|
||||
return dragAndDropMessage;
|
||||
}
|
||||
|
||||
private setImageNameToButton(imageFileName: string) {
|
||||
const MAX_CHARS = 20;
|
||||
if (imageFileName.length > MAX_CHARS) {
|
||||
// Strip first 8
|
||||
// Strip last 8
|
||||
// Add 4 dots
|
||||
let start8Chars = imageFileName.substring(0, 8);
|
||||
let length = imageFileName.length;
|
||||
let last8Chars = imageFileName.substring(length - 8, length);
|
||||
imageFileName = `${start8Chars}....${last8Chars}`;
|
||||
}
|
||||
|
||||
let newText = Html5QrcodeScannerStrings.fileSelectionChooseAnother()
|
||||
+ " - "
|
||||
+ imageFileName;
|
||||
this.fileSelectionButton.innerText = newText;
|
||||
}
|
||||
|
||||
private setInitialValueToButton() {
|
||||
let initialText = Html5QrcodeScannerStrings.fileSelectionChooseImage()
|
||||
+ " - "
|
||||
+ Html5QrcodeScannerStrings.fileSelectionNoImageSelected();
|
||||
this.fileSelectionButton.innerText = initialText;
|
||||
}
|
||||
|
||||
private getFileScanInputId(): string {
|
||||
return "html5-qrcode-private-filescan-input";
|
||||
}
|
||||
//#endregion
|
||||
|
||||
/**
|
||||
* Creates a file selection UI and renders.
|
||||
*
|
||||
* @param parentElement parent div element to render the UI to.
|
||||
* @param showOnRender if {@code true}, the UI will be shown upon render
|
||||
* else hidden.
|
||||
* @param onFileSelected callback to be called when file selection changes.
|
||||
*
|
||||
* @returns Instance of {@code FileSelectionUi}.
|
||||
*/
|
||||
public static create(
|
||||
parentElement: HTMLDivElement,
|
||||
showOnRender: boolean,
|
||||
onFileSelected: OnFileSelected): FileSelectionUi {
|
||||
let button = new FileSelectionUi(
|
||||
parentElement, showOnRender, onFileSelected);
|
||||
return button;
|
||||
}
|
||||
}
|
||||
11
node_modules/html5-qrcode/src/ui/scanner/scan-type-selector.d.ts
generated
vendored
Normal file
11
node_modules/html5-qrcode/src/ui/scanner/scan-type-selector.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Html5QrcodeScanType } from "../../core";
|
||||
export declare class ScanTypeSelector {
|
||||
private supportedScanTypes;
|
||||
constructor(supportedScanTypes?: Array<Html5QrcodeScanType> | []);
|
||||
getDefaultScanType(): Html5QrcodeScanType;
|
||||
hasMoreThanOneScanType(): boolean;
|
||||
isCameraScanRequired(): boolean;
|
||||
static isCameraScanType(scanType: Html5QrcodeScanType): boolean;
|
||||
static isFileScanType(scanType: Html5QrcodeScanType): boolean;
|
||||
private validateAndReturnScanTypes;
|
||||
}
|
||||
94
node_modules/html5-qrcode/src/ui/scanner/scan-type-selector.ts
generated
vendored
Normal file
94
node_modules/html5-qrcode/src/ui/scanner/scan-type-selector.ts
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Util class to help with scan type selection in scanner class.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import {
|
||||
Html5QrcodeScanType,
|
||||
Html5QrcodeConstants
|
||||
} from "../../core";
|
||||
|
||||
/** Util class to help with scan type selection in scanner class. */
|
||||
export class ScanTypeSelector {
|
||||
private supportedScanTypes: Array<Html5QrcodeScanType>;
|
||||
|
||||
constructor(supportedScanTypes?: Array<Html5QrcodeScanType> | []) {
|
||||
this.supportedScanTypes = this.validateAndReturnScanTypes(
|
||||
supportedScanTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default {@link Html5QrcodeScanType} scanner UI should be
|
||||
* created with.
|
||||
*/
|
||||
public getDefaultScanType(): Html5QrcodeScanType {
|
||||
return this.supportedScanTypes[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if more than one {@link Html5QrcodeScanType} are
|
||||
* set.
|
||||
*/
|
||||
public hasMoreThanOneScanType(): boolean {
|
||||
return this.supportedScanTypes.length > 1;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if camera scan is required at all. */
|
||||
public isCameraScanRequired(): boolean {
|
||||
for (const scanType of this.supportedScanTypes) {
|
||||
if (ScanTypeSelector.isCameraScanType(scanType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns {@code true} is {@code scanType} is camera based. */
|
||||
public static isCameraScanType(scanType: Html5QrcodeScanType): boolean {
|
||||
return scanType === Html5QrcodeScanType.SCAN_TYPE_CAMERA;
|
||||
}
|
||||
|
||||
/** Returns {@code true} is {@code scanType} is file based. */
|
||||
public static isFileScanType(scanType: Html5QrcodeScanType): boolean {
|
||||
return scanType === Html5QrcodeScanType.SCAN_TYPE_FILE;
|
||||
}
|
||||
|
||||
//#region Private methods.
|
||||
/**
|
||||
* Validates the input {@code supportedScanTypes}.
|
||||
*
|
||||
* Fails early if the config values is incorrectly set.
|
||||
*/
|
||||
private validateAndReturnScanTypes(
|
||||
supportedScanTypes?:Array<Html5QrcodeScanType>):
|
||||
Array<Html5QrcodeScanType> {
|
||||
// If not set, use the default values and order.
|
||||
if (!supportedScanTypes || supportedScanTypes.length === 0) {
|
||||
return Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE;
|
||||
}
|
||||
|
||||
// Fail if more than expected number of values exist.
|
||||
let maxExpectedValues
|
||||
= Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE.length;
|
||||
if (supportedScanTypes.length > maxExpectedValues) {
|
||||
throw `Max ${maxExpectedValues} values expected for `
|
||||
+ "supportedScanTypes";
|
||||
}
|
||||
|
||||
// Fail if any of the scan types are not supported.
|
||||
for (const scanType of supportedScanTypes) {
|
||||
if (!Html5QrcodeConstants.DEFAULT_SUPPORTED_SCAN_TYPE
|
||||
.includes(scanType)) {
|
||||
throw `Unsupported scan type ${scanType}`;
|
||||
}
|
||||
}
|
||||
|
||||
return supportedScanTypes;
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
28
node_modules/html5-qrcode/src/ui/scanner/torch-button.d.ts
generated
vendored
Normal file
28
node_modules/html5-qrcode/src/ui/scanner/torch-button.d.ts
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import { BooleanCameraCapability } from "../../camera/core";
|
||||
export type OnTorchActionFailureCallback = (failureMessage: string) => void;
|
||||
interface TorchButtonController {
|
||||
disable(): void;
|
||||
enable(): void;
|
||||
setText(text: string): void;
|
||||
}
|
||||
export interface TorchButtonOptions {
|
||||
display: string;
|
||||
marginLeft: string;
|
||||
}
|
||||
export declare class TorchButton implements TorchButtonController {
|
||||
private readonly torchButton;
|
||||
private readonly onTorchActionFailureCallback;
|
||||
private torchController;
|
||||
private constructor();
|
||||
private render;
|
||||
updateTorchCapability(torchCapability: BooleanCameraCapability): void;
|
||||
getTorchButton(): HTMLButtonElement;
|
||||
hide(): void;
|
||||
show(): void;
|
||||
disable(): void;
|
||||
enable(): void;
|
||||
setText(text: string): void;
|
||||
reset(): void;
|
||||
static create(parentElement: HTMLElement, torchCapability: BooleanCameraCapability, torchButtonOptions: TorchButtonOptions, onTorchActionFailureCallback: OnTorchActionFailureCallback): TorchButton;
|
||||
}
|
||||
export {};
|
||||
227
node_modules/html5-qrcode/src/ui/scanner/torch-button.ts
generated
vendored
Normal file
227
node_modules/html5-qrcode/src/ui/scanner/torch-button.ts
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* File for torch related UI components and handling.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import { BooleanCameraCapability } from "../../camera/core";
|
||||
import { Html5QrcodeScannerStrings } from "../../strings";
|
||||
import {
|
||||
BaseUiElementFactory,
|
||||
PublicUiElementIdAndClasses
|
||||
} from "./base";
|
||||
|
||||
/**
|
||||
* Interface for callback that will be called in case of torch action failures.
|
||||
*/
|
||||
export type OnTorchActionFailureCallback = (failureMessage: string) => void;
|
||||
|
||||
/** Interface for controlling torch button. */
|
||||
interface TorchButtonController {
|
||||
disable(): void;
|
||||
enable(): void;
|
||||
setText(text: string): void;
|
||||
}
|
||||
|
||||
/** Controller class for handling torch / flash. */
|
||||
class TorchController {
|
||||
private readonly torchCapability: BooleanCameraCapability;
|
||||
private readonly buttonController: TorchButtonController;
|
||||
private readonly onTorchActionFailureCallback: OnTorchActionFailureCallback;
|
||||
|
||||
// Mutable states.
|
||||
private isTorchOn: boolean = false;
|
||||
|
||||
constructor(
|
||||
torchCapability: BooleanCameraCapability,
|
||||
buttonController: TorchButtonController,
|
||||
onTorchActionFailureCallback: OnTorchActionFailureCallback) {
|
||||
this.torchCapability = torchCapability;
|
||||
this.buttonController = buttonController;
|
||||
this.onTorchActionFailureCallback = onTorchActionFailureCallback;
|
||||
}
|
||||
|
||||
/** Returns {@code true} if torch is enabled. */
|
||||
public isTorchEnabled(): boolean {
|
||||
return this.isTorchOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flips the state of the torch.
|
||||
*
|
||||
* <p> Turns torch On if current state is Off and vice-versa.
|
||||
* <p> Modifies the UI state accordingly.
|
||||
*
|
||||
* @returns Promise that finishes when the async action is done.
|
||||
*/
|
||||
public async flipState(): Promise<void> {
|
||||
this.buttonController.disable();
|
||||
let isTorchOnExpected = !this.isTorchOn;
|
||||
try {
|
||||
await this.torchCapability.apply(isTorchOnExpected);
|
||||
this.updateUiBasedOnLatestSettings(
|
||||
this.torchCapability.value()!, isTorchOnExpected);
|
||||
} catch (error) {
|
||||
this.propagateFailure(isTorchOnExpected, error);
|
||||
this.buttonController.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private updateUiBasedOnLatestSettings(
|
||||
isTorchOn: boolean,
|
||||
isTorchOnExpected: boolean) {
|
||||
if (isTorchOn === isTorchOnExpected) {
|
||||
// Action succeeded, flip the state.
|
||||
this.buttonController.setText(isTorchOnExpected
|
||||
? Html5QrcodeScannerStrings.torchOffButton()
|
||||
: Html5QrcodeScannerStrings.torchOnButton());
|
||||
this.isTorchOn = isTorchOnExpected;
|
||||
} else {
|
||||
// Torch didn't get set as expected.
|
||||
// Show warning.
|
||||
this.propagateFailure(isTorchOnExpected);
|
||||
}
|
||||
this.buttonController.enable();
|
||||
}
|
||||
|
||||
private propagateFailure(
|
||||
isTorchOnExpected: boolean, error?: any) {
|
||||
let errorMessage = isTorchOnExpected
|
||||
? Html5QrcodeScannerStrings.torchOnFailedMessage()
|
||||
: Html5QrcodeScannerStrings.torchOffFailedMessage();
|
||||
if (error) {
|
||||
errorMessage += "; Error = " + error;
|
||||
}
|
||||
this.onTorchActionFailureCallback(errorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state.
|
||||
*
|
||||
* <p>Note: Doesn't turn off the torch implicitly.
|
||||
*/
|
||||
public reset() {
|
||||
this.isTorchOn = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Options for creating torch button. */
|
||||
export interface TorchButtonOptions {
|
||||
display: string;
|
||||
marginLeft: string;
|
||||
}
|
||||
|
||||
/** Helper class for creating Torch UI component. */
|
||||
export class TorchButton implements TorchButtonController {
|
||||
private readonly torchButton: HTMLButtonElement;
|
||||
private readonly onTorchActionFailureCallback: OnTorchActionFailureCallback;
|
||||
|
||||
private torchController: TorchController;
|
||||
|
||||
private constructor(
|
||||
torchCapability: BooleanCameraCapability,
|
||||
onTorchActionFailureCallback: OnTorchActionFailureCallback) {
|
||||
this.onTorchActionFailureCallback = onTorchActionFailureCallback;
|
||||
this.torchButton
|
||||
= BaseUiElementFactory.createElement<HTMLButtonElement>(
|
||||
"button", PublicUiElementIdAndClasses.TORCH_BUTTON_ID);
|
||||
|
||||
this.torchController = new TorchController(
|
||||
torchCapability,
|
||||
/* buttonController= */ this,
|
||||
onTorchActionFailureCallback);
|
||||
}
|
||||
|
||||
private render(
|
||||
parentElement: HTMLElement, torchButtonOptions: TorchButtonOptions) {
|
||||
this.torchButton.innerText
|
||||
= Html5QrcodeScannerStrings.torchOnButton();
|
||||
this.torchButton.style.display = torchButtonOptions.display;
|
||||
this.torchButton.style.marginLeft = torchButtonOptions.marginLeft;
|
||||
|
||||
let $this = this;
|
||||
this.torchButton.addEventListener("click", async (_) => {
|
||||
await $this.torchController.flipState();
|
||||
if ($this.torchController.isTorchEnabled()) {
|
||||
$this.torchButton.classList.remove(
|
||||
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_OFF);
|
||||
$this.torchButton.classList.add(
|
||||
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_ON);
|
||||
} else {
|
||||
$this.torchButton.classList.remove(
|
||||
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_ON);
|
||||
$this.torchButton.classList.add(
|
||||
PublicUiElementIdAndClasses.TORCH_BUTTON_CLASS_TORCH_OFF);
|
||||
}
|
||||
});
|
||||
|
||||
parentElement.appendChild(this.torchButton);
|
||||
}
|
||||
|
||||
public updateTorchCapability(torchCapability: BooleanCameraCapability) {
|
||||
this.torchController = new TorchController(
|
||||
torchCapability,
|
||||
/* buttonController= */ this,
|
||||
this.onTorchActionFailureCallback);
|
||||
}
|
||||
|
||||
/** Returns the torch button. */
|
||||
public getTorchButton(): HTMLButtonElement {
|
||||
return this.torchButton;
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.torchButton.style.display = "none";
|
||||
}
|
||||
|
||||
public show() {
|
||||
this.torchButton.style.display = "inline-block";
|
||||
}
|
||||
|
||||
disable(): void {
|
||||
this.torchButton.disabled = true;
|
||||
}
|
||||
|
||||
enable(): void {
|
||||
this.torchButton.disabled = false;
|
||||
}
|
||||
|
||||
setText(text: string): void {
|
||||
this.torchButton.innerText = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state.
|
||||
*
|
||||
* <p>Note: Doesn't turn off the torch implicitly.
|
||||
*/
|
||||
public reset() {
|
||||
this.torchButton.innerText = Html5QrcodeScannerStrings.torchOnButton();
|
||||
this.torchController.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating torch button.
|
||||
*
|
||||
* @param parentElement parent HTML element to render torch button into
|
||||
* @param torchCapability torch capability of the camera
|
||||
* @param torchButtonOptions options for creating torch
|
||||
* @param onTorchActionFailureCallback callback to be called in case of
|
||||
* torch action failure.
|
||||
*/
|
||||
public static create(
|
||||
parentElement: HTMLElement,
|
||||
torchCapability: BooleanCameraCapability,
|
||||
torchButtonOptions: TorchButtonOptions,
|
||||
onTorchActionFailureCallback: OnTorchActionFailureCallback)
|
||||
: TorchButton {
|
||||
let button = new TorchButton(
|
||||
torchCapability, onTorchActionFailureCallback);
|
||||
button.render(parentElement, torchButtonOptions);
|
||||
return button;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user