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:
7
node_modules/html5-qrcode/src/camera/core-impl.d.ts
generated
vendored
Normal file
7
node_modules/html5-qrcode/src/camera/core-impl.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Camera, CameraRenderingOptions, RenderedCamera, RenderingCallbacks } from "./core";
|
||||
export declare class CameraImpl implements Camera {
|
||||
private readonly mediaStream;
|
||||
private constructor();
|
||||
render(parentElement: HTMLElement, options: CameraRenderingOptions, callbacks: RenderingCallbacks): Promise<RenderedCamera>;
|
||||
static create(videoConstraints: MediaTrackConstraints): Promise<Camera>;
|
||||
}
|
||||
340
node_modules/html5-qrcode/src/camera/core-impl.ts
generated
vendored
Normal file
340
node_modules/html5-qrcode/src/camera/core-impl.ts
generated
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Core camera library implementations.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
import {
|
||||
Camera,
|
||||
CameraCapabilities,
|
||||
CameraCapability,
|
||||
RangeCameraCapability,
|
||||
CameraRenderingOptions,
|
||||
RenderedCamera,
|
||||
RenderingCallbacks,
|
||||
BooleanCameraCapability
|
||||
} from "./core";
|
||||
|
||||
/** Interface for a range value. */
|
||||
interface RangeValue {
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
}
|
||||
|
||||
/** Abstract camera capability class. */
|
||||
abstract class AbstractCameraCapability<T> implements CameraCapability<T> {
|
||||
protected readonly name: string;
|
||||
protected readonly track: MediaStreamTrack;
|
||||
|
||||
constructor(name: string, track: MediaStreamTrack) {
|
||||
this.name = name;
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
public isSupported(): boolean {
|
||||
// TODO(minhazav): Figure out fallback for getCapabilities()
|
||||
// in firefox.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Media_Capture_and_Streams_API/Constraints
|
||||
if (!this.track.getCapabilities) {
|
||||
return false;
|
||||
}
|
||||
return this.name in this.track.getCapabilities();
|
||||
}
|
||||
|
||||
public apply(value: T): Promise<void> {
|
||||
let constraint: any = {};
|
||||
constraint[this.name] = value;
|
||||
let constraints = { advanced: [ constraint ] };
|
||||
return this.track.applyConstraints(constraints);
|
||||
}
|
||||
|
||||
public value(): T | null {
|
||||
let settings: any = this.track.getSettings();
|
||||
if (this.name in settings) {
|
||||
let settingValue = settings[this.name];
|
||||
return settingValue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractRangeCameraCapability extends AbstractCameraCapability<number> {
|
||||
constructor(name: string, track: MediaStreamTrack) {
|
||||
super(name, track);
|
||||
}
|
||||
|
||||
public min(): number {
|
||||
return this.getCapabilities().min;
|
||||
}
|
||||
|
||||
public max(): number {
|
||||
return this.getCapabilities().max;
|
||||
}
|
||||
|
||||
public step(): number {
|
||||
return this.getCapabilities().step;
|
||||
}
|
||||
|
||||
public apply(value: number): Promise<void> {
|
||||
let constraint: any = {};
|
||||
constraint[this.name] = value;
|
||||
let constraints = {advanced: [ constraint ]};
|
||||
return this.track.applyConstraints(constraints);
|
||||
}
|
||||
|
||||
private getCapabilities(): RangeValue {
|
||||
this.failIfNotSupported();
|
||||
let capabilities: any = this.track.getCapabilities();
|
||||
let capability: any = capabilities[this.name];
|
||||
return {
|
||||
min: capability.min,
|
||||
max: capability.max,
|
||||
step: capability.step,
|
||||
};
|
||||
}
|
||||
|
||||
private failIfNotSupported() {
|
||||
if (!this.isSupported()) {
|
||||
throw new Error(`${this.name} capability not supported`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Zoom feature. */
|
||||
class ZoomFeatureImpl extends AbstractRangeCameraCapability {
|
||||
constructor(track: MediaStreamTrack) {
|
||||
super("zoom", track);
|
||||
}
|
||||
}
|
||||
|
||||
/** Torch feature. */
|
||||
class TorchFeatureImpl extends AbstractCameraCapability<boolean> {
|
||||
constructor(track: MediaStreamTrack) {
|
||||
super("torch", track);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link CameraCapabilities}. */
|
||||
class CameraCapabilitiesImpl implements CameraCapabilities {
|
||||
private readonly track: MediaStreamTrack;
|
||||
|
||||
constructor(track: MediaStreamTrack) {
|
||||
this.track = track;
|
||||
}
|
||||
|
||||
zoomFeature(): RangeCameraCapability {
|
||||
return new ZoomFeatureImpl(this.track);
|
||||
}
|
||||
|
||||
torchFeature(): BooleanCameraCapability {
|
||||
return new TorchFeatureImpl(this.track);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of {@link RenderedCamera}. */
|
||||
class RenderedCameraImpl implements RenderedCamera {
|
||||
|
||||
private readonly parentElement: HTMLElement;
|
||||
private readonly mediaStream: MediaStream;
|
||||
private readonly surface: HTMLVideoElement;
|
||||
private readonly callbacks: RenderingCallbacks;
|
||||
|
||||
private isClosed: boolean = false;
|
||||
|
||||
private constructor(
|
||||
parentElement: HTMLElement,
|
||||
mediaStream: MediaStream,
|
||||
callbacks: RenderingCallbacks) {
|
||||
this.parentElement = parentElement;
|
||||
this.mediaStream = mediaStream;
|
||||
this.callbacks = callbacks;
|
||||
|
||||
this.surface = this.createVideoElement(this.parentElement.clientWidth);
|
||||
|
||||
// Setup
|
||||
parentElement.append(this.surface);
|
||||
}
|
||||
|
||||
private createVideoElement(width: number): HTMLVideoElement {
|
||||
const videoElement = document.createElement("video");
|
||||
videoElement.style.width = `${width}px`;
|
||||
videoElement.style.display = "block";
|
||||
videoElement.muted = true;
|
||||
videoElement.setAttribute("muted", "true");
|
||||
(<any>videoElement).playsInline = true;
|
||||
return videoElement;
|
||||
}
|
||||
|
||||
private setupSurface() {
|
||||
this.surface.onabort = () => {
|
||||
throw "RenderedCameraImpl video surface onabort() called";
|
||||
};
|
||||
|
||||
this.surface.onerror = () => {
|
||||
throw "RenderedCameraImpl video surface onerror() called";
|
||||
};
|
||||
|
||||
let onVideoStart = () => {
|
||||
const videoWidth = this.surface.clientWidth;
|
||||
const videoHeight = this.surface.clientHeight;
|
||||
this.callbacks.onRenderSurfaceReady(videoWidth, videoHeight);
|
||||
this.surface.removeEventListener("playing", onVideoStart);
|
||||
};
|
||||
|
||||
this.surface.addEventListener("playing", onVideoStart);
|
||||
this.surface.srcObject = this.mediaStream;
|
||||
this.surface.play();
|
||||
}
|
||||
|
||||
static async create(
|
||||
parentElement: HTMLElement,
|
||||
mediaStream: MediaStream,
|
||||
options: CameraRenderingOptions,
|
||||
callbacks: RenderingCallbacks)
|
||||
: Promise<RenderedCamera> {
|
||||
let renderedCamera = new RenderedCameraImpl(
|
||||
parentElement, mediaStream, callbacks);
|
||||
if (options.aspectRatio) {
|
||||
let aspectRatioConstraint = {
|
||||
aspectRatio: options.aspectRatio!
|
||||
};
|
||||
await renderedCamera.getFirstTrackOrFail().applyConstraints(
|
||||
aspectRatioConstraint);
|
||||
}
|
||||
|
||||
renderedCamera.setupSurface();
|
||||
return renderedCamera;
|
||||
}
|
||||
|
||||
private failIfClosed() {
|
||||
if (this.isClosed) {
|
||||
throw "The RenderedCamera has already been closed.";
|
||||
}
|
||||
}
|
||||
|
||||
private getFirstTrackOrFail(): MediaStreamTrack {
|
||||
this.failIfClosed();
|
||||
|
||||
if (this.mediaStream.getVideoTracks().length === 0) {
|
||||
throw "No video tracks found";
|
||||
}
|
||||
|
||||
return this.mediaStream.getVideoTracks()[0];
|
||||
}
|
||||
|
||||
//#region Public APIs.
|
||||
public pause(): void {
|
||||
this.failIfClosed();
|
||||
this.surface.pause();
|
||||
}
|
||||
|
||||
public resume(onResumeCallback: () => void): void {
|
||||
this.failIfClosed();
|
||||
let $this = this;
|
||||
|
||||
const onVideoResume = () => {
|
||||
// Transition after 200ms to avoid the previous canvas frame being
|
||||
// re-scanned.
|
||||
setTimeout(onResumeCallback, 200);
|
||||
$this.surface.removeEventListener("playing", onVideoResume);
|
||||
};
|
||||
|
||||
this.surface.addEventListener("playing", onVideoResume);
|
||||
this.surface.play();
|
||||
}
|
||||
|
||||
public isPaused(): boolean {
|
||||
this.failIfClosed();
|
||||
return this.surface.paused;
|
||||
}
|
||||
|
||||
public getSurface(): HTMLVideoElement {
|
||||
this.failIfClosed();
|
||||
return this.surface;
|
||||
}
|
||||
|
||||
public getRunningTrackCapabilities(): MediaTrackCapabilities {
|
||||
return this.getFirstTrackOrFail().getCapabilities();
|
||||
}
|
||||
|
||||
public getRunningTrackSettings(): MediaTrackSettings {
|
||||
return this.getFirstTrackOrFail().getSettings();
|
||||
}
|
||||
|
||||
public async applyVideoConstraints(constraints: MediaTrackConstraints)
|
||||
: Promise<void> {
|
||||
if ("aspectRatio" in constraints) {
|
||||
throw "Changing 'aspectRatio' in run-time is not yet supported.";
|
||||
}
|
||||
|
||||
return this.getFirstTrackOrFail().applyConstraints(constraints);
|
||||
}
|
||||
|
||||
public close(): Promise<void> {
|
||||
if (this.isClosed) {
|
||||
// Already closed.
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
let $this = this;
|
||||
return new Promise((resolve, _) => {
|
||||
let tracks = $this.mediaStream.getVideoTracks();
|
||||
const tracksToClose = tracks.length;
|
||||
var tracksClosed = 0;
|
||||
$this.mediaStream.getVideoTracks().forEach((videoTrack) => {
|
||||
$this.mediaStream.removeTrack(videoTrack);
|
||||
videoTrack.stop();
|
||||
++tracksClosed;
|
||||
|
||||
if (tracksClosed >= tracksToClose) {
|
||||
$this.isClosed = true;
|
||||
$this.parentElement.removeChild($this.surface);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
getCapabilities(): CameraCapabilities {
|
||||
return new CameraCapabilitiesImpl(this.getFirstTrackOrFail());
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
/** Default implementation of {@link Camera} interface. */
|
||||
export class CameraImpl implements Camera {
|
||||
private readonly mediaStream: MediaStream;
|
||||
|
||||
private constructor(mediaStream: MediaStream) {
|
||||
this.mediaStream = mediaStream;
|
||||
}
|
||||
|
||||
async render(
|
||||
parentElement: HTMLElement,
|
||||
options: CameraRenderingOptions,
|
||||
callbacks: RenderingCallbacks)
|
||||
: Promise<RenderedCamera> {
|
||||
return RenderedCameraImpl.create(
|
||||
parentElement, this.mediaStream, options, callbacks);
|
||||
}
|
||||
|
||||
static async create(videoConstraints: MediaTrackConstraints)
|
||||
: Promise<Camera> {
|
||||
if (!navigator.mediaDevices) {
|
||||
throw "navigator.mediaDevices not supported";
|
||||
}
|
||||
let constraints: MediaStreamConstraints = {
|
||||
audio: false,
|
||||
video: videoConstraints
|
||||
};
|
||||
|
||||
let mediaStream = await navigator.mediaDevices.getUserMedia(
|
||||
constraints);
|
||||
return new CameraImpl(mediaStream);
|
||||
}
|
||||
}
|
||||
41
node_modules/html5-qrcode/src/camera/core.d.ts
generated
vendored
Normal file
41
node_modules/html5-qrcode/src/camera/core.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
export interface CameraDevice {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
export interface CameraCapability<T> {
|
||||
isSupported(): boolean;
|
||||
apply(value: T): Promise<void>;
|
||||
value(): T | null;
|
||||
}
|
||||
export interface RangeCameraCapability extends CameraCapability<number> {
|
||||
min(): number;
|
||||
max(): number;
|
||||
step(): number;
|
||||
}
|
||||
export interface BooleanCameraCapability extends CameraCapability<boolean> {
|
||||
}
|
||||
export interface CameraCapabilities {
|
||||
zoomFeature(): RangeCameraCapability;
|
||||
torchFeature(): BooleanCameraCapability;
|
||||
}
|
||||
export type OnRenderSurfaceReady = (viewfinderWidth: number, viewfinderHeight: number) => void;
|
||||
export interface RenderingCallbacks {
|
||||
onRenderSurfaceReady: OnRenderSurfaceReady;
|
||||
}
|
||||
export interface RenderedCamera {
|
||||
getSurface(): HTMLVideoElement;
|
||||
pause(): void;
|
||||
resume(onResumeCallback: () => void): void;
|
||||
isPaused(): boolean;
|
||||
close(): Promise<void>;
|
||||
getRunningTrackCapabilities(): MediaTrackCapabilities;
|
||||
getRunningTrackSettings(): MediaTrackSettings;
|
||||
applyVideoConstraints(constraints: MediaTrackConstraints): Promise<void>;
|
||||
getCapabilities(): CameraCapabilities;
|
||||
}
|
||||
export interface CameraRenderingOptions {
|
||||
aspectRatio?: number;
|
||||
}
|
||||
export interface Camera {
|
||||
render(parentElement: HTMLElement, options: CameraRenderingOptions, callbacks: RenderingCallbacks): Promise<RenderedCamera>;
|
||||
}
|
||||
180
node_modules/html5-qrcode/src/camera/core.ts
generated
vendored
Normal file
180
node_modules/html5-qrcode/src/camera/core.ts
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @module
|
||||
* Core Camera interfaces.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
/** Camera device interface. */
|
||||
export interface CameraDevice {
|
||||
id: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
//#region Features
|
||||
/** Generic capability of camera. */
|
||||
export interface CameraCapability<T> {
|
||||
/** Returns {@code true} if the capability is supported by the camera. */
|
||||
isSupported(): boolean;
|
||||
|
||||
/** Apply the {@code value} to camera for this capability. */
|
||||
apply(value: T): Promise<void>;
|
||||
|
||||
/** Returns current value of this capability. */
|
||||
value(): T | null;
|
||||
}
|
||||
|
||||
/** Capability of the camera that has range. */
|
||||
export interface RangeCameraCapability extends CameraCapability<number> {
|
||||
/** Min value allowed for this capability. */
|
||||
min(): number;
|
||||
|
||||
/** Max value allowed for this capability. */
|
||||
max(): number;
|
||||
|
||||
/** Steps allowed for this capability. */
|
||||
step(): number;
|
||||
}
|
||||
|
||||
/** Capability of camera that is boolean in nature. */
|
||||
export interface BooleanCameraCapability extends CameraCapability<boolean> {}
|
||||
|
||||
/** Class exposing different capabilities of camera. */
|
||||
export interface CameraCapabilities {
|
||||
|
||||
/** Zoom capability of the camera. */
|
||||
zoomFeature(): RangeCameraCapability;
|
||||
|
||||
/** Torch capability of the camera. */
|
||||
torchFeature(): BooleanCameraCapability;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
/** Type for callback called when camera surface is ready. */
|
||||
export type OnRenderSurfaceReady
|
||||
= (viewfinderWidth: number, viewfinderHeight: number) => void;
|
||||
|
||||
/** Callbacks around camera rendering. */
|
||||
export interface RenderingCallbacks {
|
||||
onRenderSurfaceReady: OnRenderSurfaceReady;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for a rendered camera that is actively showing feed on a surface.
|
||||
*/
|
||||
export interface RenderedCamera {
|
||||
/**
|
||||
* Returns the video surface.
|
||||
*
|
||||
* @throws error if method is called when scanner is not in scanning state.
|
||||
*/
|
||||
getSurface(): HTMLVideoElement;
|
||||
|
||||
/**
|
||||
* Pauses the camera feed.
|
||||
*
|
||||
* @throws error if method is called when scanner is not in scanning state.
|
||||
*/
|
||||
pause(): void;
|
||||
|
||||
/**
|
||||
* Resumes the camera feed, if it's in paused state.
|
||||
*
|
||||
* @param onResumeCallback callback that is called when camera resumes.
|
||||
*
|
||||
* @throws error if {@link RenderedCamera} instance is already closed.
|
||||
*/
|
||||
resume(onResumeCallback: () => void): void;
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the instance is paused.
|
||||
*
|
||||
* @throws error if {@link RenderedCamera} instance is already closed.
|
||||
*/
|
||||
isPaused(): boolean;
|
||||
|
||||
/**
|
||||
* Closes the instance.
|
||||
*
|
||||
* <p> The instance cannot be used after closing.
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Direct Camera Access APIs.
|
||||
//
|
||||
// The APIs below are in flavour similar to what Javascript exposes.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the capabilities of the running camera stream.
|
||||
*
|
||||
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/getConstraints
|
||||
*
|
||||
* @returns the capabilities of a running video track.
|
||||
* @throws error if {@link RenderedCamera} instance is already closed.
|
||||
*/
|
||||
getRunningTrackCapabilities(): MediaTrackCapabilities;
|
||||
|
||||
/**
|
||||
* Returns the object containing the current values of each constrainable
|
||||
* property of the running video track.
|
||||
*
|
||||
* Read more: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/getSettings
|
||||
*
|
||||
* @returns the supported settings of the running video track.
|
||||
* @throws error if {@link RenderedCamera} instance is already closed.
|
||||
*/
|
||||
getRunningTrackSettings(): MediaTrackSettings;
|
||||
|
||||
/**
|
||||
* Apply a video constraints on running video track from camera.
|
||||
*
|
||||
* Important: Changing aspectRatio while scanner is running is not supported
|
||||
* with this API.
|
||||
*
|
||||
* @param {MediaTrackConstraints} specifies a variety of video or camera
|
||||
* controls as defined in
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints
|
||||
* @returns a Promise which succeeds if the passed constraints are applied,
|
||||
* fails otherwise.
|
||||
* @throws error if {@link RenderedCamera} instance is already closed.
|
||||
*/
|
||||
applyVideoConstraints(constraints: MediaTrackConstraints): Promise<void>;
|
||||
|
||||
/**
|
||||
* Returns all capabilities of the camera.
|
||||
*/
|
||||
getCapabilities(): CameraCapabilities;
|
||||
}
|
||||
|
||||
/** Options for rendering camera feed. */
|
||||
export interface CameraRenderingOptions {
|
||||
/**
|
||||
* Aspect ratio to setup the surface with.
|
||||
*
|
||||
* <p> Setting this value doesn't guarantee the exact value to be applied.
|
||||
*/
|
||||
aspectRatio?: number;
|
||||
}
|
||||
|
||||
/** Interface for the camera. */
|
||||
export interface Camera {
|
||||
|
||||
/**
|
||||
* Renders camera to {@link HTMLVideoElement} as a child of
|
||||
* {@code parentElement}.
|
||||
*
|
||||
* @params parentElement Parent HtmlElement to render camera feed into
|
||||
* @params options rendering options
|
||||
* @params callbacks callbacks associated with rendering
|
||||
*
|
||||
* @returns the {@link RenderedCamera} instance.
|
||||
*/
|
||||
render(
|
||||
parentElement: HTMLElement,
|
||||
options: CameraRenderingOptions,
|
||||
callbacks: RenderingCallbacks)
|
||||
: Promise<RenderedCamera>;
|
||||
}
|
||||
6
node_modules/html5-qrcode/src/camera/factories.d.ts
generated
vendored
Normal file
6
node_modules/html5-qrcode/src/camera/factories.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Camera } from "./core";
|
||||
export declare class CameraFactory {
|
||||
static failIfNotSupported(): Promise<CameraFactory>;
|
||||
private constructor();
|
||||
create(videoConstraints: MediaTrackConstraints): Promise<Camera>;
|
||||
}
|
||||
33
node_modules/html5-qrcode/src/camera/factories.ts
generated
vendored
Normal file
33
node_modules/html5-qrcode/src/camera/factories.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Set of factory implementations around Camera.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
import { Camera } from "./core";
|
||||
import { CameraImpl } from "./core-impl";
|
||||
|
||||
/** Factory class for creating Camera. */
|
||||
export class CameraFactory {
|
||||
|
||||
/**
|
||||
* Returns {@link CameraFactory} if {@link navigator.mediaDevices} is
|
||||
* supported else fails.
|
||||
*/
|
||||
public static async failIfNotSupported(): Promise<CameraFactory> {
|
||||
if (!navigator.mediaDevices) {
|
||||
throw "navigator.mediaDevices not supported";
|
||||
}
|
||||
|
||||
return new CameraFactory();
|
||||
}
|
||||
|
||||
private constructor() { /* No Op. */ }
|
||||
|
||||
/** Creates camera instance based on constraints. */
|
||||
public async create(videoConstraints: MediaTrackConstraints)
|
||||
: Promise<Camera> {
|
||||
return CameraImpl.create(videoConstraints);
|
||||
}
|
||||
}
|
||||
3
node_modules/html5-qrcode/src/camera/permissions.d.ts
generated
vendored
Normal file
3
node_modules/html5-qrcode/src/camera/permissions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export declare class CameraPermissions {
|
||||
static hasPermissions(): Promise<boolean>;
|
||||
}
|
||||
34
node_modules/html5-qrcode/src/camera/permissions.ts
generated
vendored
Normal file
34
node_modules/html5-qrcode/src/camera/permissions.ts
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Libraries associated with Camera Permissions.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Permission management around Camera in javascript.
|
||||
*
|
||||
* TODO(mebjas): Migrate camera specific code / logic to this class / library.
|
||||
*/
|
||||
export class CameraPermissions {
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the web page already has access to user camera
|
||||
* permissions.
|
||||
*/
|
||||
public static async hasPermissions(): Promise<boolean> {
|
||||
// TODO(mebjas): Use Permissions Query API, once support is widespread.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
|
||||
|
||||
let devices = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const device of devices) {
|
||||
// Hacky way to check if camera permissions are granted. Device
|
||||
// labels are only set in case user has granted permissions.
|
||||
if(device.kind === "videoinput" && device.label) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
8
node_modules/html5-qrcode/src/camera/retriever.d.ts
generated
vendored
Normal file
8
node_modules/html5-qrcode/src/camera/retriever.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { CameraDevice } from "./core";
|
||||
export declare class CameraRetriever {
|
||||
static retrieve(): Promise<Array<CameraDevice>>;
|
||||
private static rejectWithError;
|
||||
private static isHttpsOrLocalhost;
|
||||
private static getCamerasFromMediaDevices;
|
||||
private static getCamerasFromMediaStreamTrack;
|
||||
}
|
||||
93
node_modules/html5-qrcode/src/camera/retriever.ts
generated
vendored
Normal file
93
node_modules/html5-qrcode/src/camera/retriever.ts
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Libraries associated with retrieving cameras.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
import { CameraDevice } from "./core";
|
||||
import { Html5QrcodeStrings } from "../strings";
|
||||
|
||||
/** Class for retrieving cameras on the device. */
|
||||
export class CameraRetriever {
|
||||
|
||||
/** Returns list of {@link CameraDevice} supported by the device. */
|
||||
public static retrieve(): Promise<Array<CameraDevice>> {
|
||||
if (navigator.mediaDevices) {
|
||||
return CameraRetriever.getCamerasFromMediaDevices();
|
||||
}
|
||||
|
||||
// Using deprecated api to support really old browsers.
|
||||
var mst = <any>MediaStreamTrack;
|
||||
if (MediaStreamTrack && mst.getSources) {
|
||||
return CameraRetriever.getCamerasFromMediaStreamTrack();
|
||||
}
|
||||
|
||||
return CameraRetriever.rejectWithError();
|
||||
}
|
||||
|
||||
private static rejectWithError(): Promise<Array<CameraDevice>> {
|
||||
// This can potentially happen if the page is loaded without SSL.
|
||||
let errorMessage = Html5QrcodeStrings.unableToQuerySupportedDevices();
|
||||
if (!CameraRetriever.isHttpsOrLocalhost()) {
|
||||
errorMessage = Html5QrcodeStrings.insecureContextCameraQueryError();
|
||||
}
|
||||
return Promise.reject(errorMessage);
|
||||
}
|
||||
|
||||
private static isHttpsOrLocalhost(): boolean {
|
||||
if (location.protocol === "https:") {
|
||||
return true;
|
||||
}
|
||||
const host = location.host.split(":")[0];
|
||||
return host === "127.0.0.1" || host === "localhost";
|
||||
}
|
||||
|
||||
private static async getCamerasFromMediaDevices(): Promise<Array<CameraDevice>> {
|
||||
// Hacky approach to close any active stream if they are active.
|
||||
const closeActiveStreams = (stream: MediaStream) => {
|
||||
const tracks = stream.getVideoTracks();
|
||||
for (const track of tracks) {
|
||||
track.enabled = false;
|
||||
track.stop();
|
||||
stream.removeTrack(track);
|
||||
}
|
||||
};
|
||||
// This should trigger the permission flow if required.
|
||||
let mediaStream = await navigator.mediaDevices.getUserMedia(
|
||||
{ audio: false, video: true });
|
||||
let devices = await navigator.mediaDevices.enumerateDevices();
|
||||
let results: Array<CameraDevice> = [];
|
||||
for (const device of devices) {
|
||||
if (device.kind === "videoinput") {
|
||||
results.push({
|
||||
id: device.deviceId,
|
||||
label: device.label
|
||||
});
|
||||
}
|
||||
}
|
||||
closeActiveStreams(mediaStream);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static getCamerasFromMediaStreamTrack()
|
||||
: Promise<Array<CameraDevice>> {
|
||||
return new Promise((resolve, _) => {
|
||||
const callback = (sourceInfos: Array<any>) => {
|
||||
const results: Array<CameraDevice> = [];
|
||||
for (const sourceInfo of sourceInfos) {
|
||||
if (sourceInfo.kind === "video") {
|
||||
results.push({
|
||||
id: sourceInfo.id,
|
||||
label: sourceInfo.label
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(results);
|
||||
}
|
||||
|
||||
var mst = <any>MediaStreamTrack;
|
||||
mst.getSources(callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
16
node_modules/html5-qrcode/src/code-decoder.d.ts
generated
vendored
Normal file
16
node_modules/html5-qrcode/src/code-decoder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { QrcodeResult, Html5QrcodeSupportedFormats, Logger, RobustQrcodeDecoderAsync } from "./core";
|
||||
export declare class Html5QrcodeShim implements RobustQrcodeDecoderAsync {
|
||||
private verbose;
|
||||
private primaryDecoder;
|
||||
private secondaryDecoder;
|
||||
private readonly EXECUTIONS_TO_REPORT_PERFORMANCE;
|
||||
private executions;
|
||||
private executionResults;
|
||||
private wasPrimaryDecoderUsedInLastDecode;
|
||||
constructor(requestedFormats: Array<Html5QrcodeSupportedFormats>, useBarCodeDetectorIfSupported: boolean, verbose: boolean, logger: Logger);
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
decodeRobustlyAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
private getDecoder;
|
||||
private possiblyLogPerformance;
|
||||
possiblyFlushPerformanceReport(): void;
|
||||
}
|
||||
127
node_modules/html5-qrcode/src/code-decoder.ts
generated
vendored
Normal file
127
node_modules/html5-qrcode/src/code-decoder.ts
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Shim layer for providing the decoding library.
|
||||
*
|
||||
* @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 {
|
||||
QrcodeResult,
|
||||
Html5QrcodeSupportedFormats,
|
||||
Logger,
|
||||
QrcodeDecoderAsync,
|
||||
RobustQrcodeDecoderAsync,
|
||||
} from "./core";
|
||||
|
||||
import { ZXingHtml5QrcodeDecoder } from "./zxing-html5-qrcode-decoder";
|
||||
import { BarcodeDetectorDelegate } from "./native-bar-code-detector";
|
||||
|
||||
/**
|
||||
* Shim layer for {@interface QrcodeDecoder}.
|
||||
*
|
||||
* Currently uses {@class ZXingHtml5QrcodeDecoder}, can be replace with another library.
|
||||
*/
|
||||
export class Html5QrcodeShim implements RobustQrcodeDecoderAsync {
|
||||
|
||||
private verbose: boolean;
|
||||
private primaryDecoder: QrcodeDecoderAsync;
|
||||
private secondaryDecoder: QrcodeDecoderAsync | undefined;
|
||||
|
||||
private readonly EXECUTIONS_TO_REPORT_PERFORMANCE = 100;
|
||||
private executions: number = 0;
|
||||
private executionResults: Array<number> = [];
|
||||
private wasPrimaryDecoderUsedInLastDecode = false;
|
||||
|
||||
public constructor(
|
||||
requestedFormats: Array<Html5QrcodeSupportedFormats>,
|
||||
useBarCodeDetectorIfSupported: boolean,
|
||||
verbose: boolean,
|
||||
logger: Logger) {
|
||||
this.verbose = verbose;
|
||||
|
||||
// Use BarcodeDetector library if enabled by config and is supported.
|
||||
if (useBarCodeDetectorIfSupported
|
||||
&& BarcodeDetectorDelegate.isSupported()) {
|
||||
this.primaryDecoder = new BarcodeDetectorDelegate(
|
||||
requestedFormats, verbose, logger);
|
||||
// If 'BarcodeDetector' is supported, the library will alternate
|
||||
// between 'BarcodeDetector' and 'zxing-js' to compensate for
|
||||
// quality gaps between the two.
|
||||
this.secondaryDecoder = new ZXingHtml5QrcodeDecoder(
|
||||
requestedFormats, verbose, logger);
|
||||
} else {
|
||||
this.primaryDecoder = new ZXingHtml5QrcodeDecoder(
|
||||
requestedFormats, verbose, logger);
|
||||
}
|
||||
}
|
||||
|
||||
async decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult> {
|
||||
let startTime = performance.now();
|
||||
try {
|
||||
return await this.getDecoder().decodeAsync(canvas);
|
||||
} finally {
|
||||
this.possiblyLogPerformance(startTime);
|
||||
}
|
||||
}
|
||||
|
||||
async decodeRobustlyAsync(canvas: HTMLCanvasElement)
|
||||
: Promise<QrcodeResult> {
|
||||
let startTime = performance.now();
|
||||
try {
|
||||
return await this.primaryDecoder.decodeAsync(canvas);
|
||||
} catch(error) {
|
||||
if (this.secondaryDecoder) {
|
||||
// Try fallback.
|
||||
return this.secondaryDecoder.decodeAsync(canvas);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
this.possiblyLogPerformance(startTime);
|
||||
}
|
||||
}
|
||||
|
||||
private getDecoder(): QrcodeDecoderAsync {
|
||||
if (!this.secondaryDecoder) {
|
||||
return this.primaryDecoder;
|
||||
}
|
||||
|
||||
if (this.wasPrimaryDecoderUsedInLastDecode === false) {
|
||||
this.wasPrimaryDecoderUsedInLastDecode = true;
|
||||
return this.primaryDecoder;
|
||||
}
|
||||
this.wasPrimaryDecoderUsedInLastDecode = false;
|
||||
return this.secondaryDecoder;
|
||||
}
|
||||
|
||||
private possiblyLogPerformance(startTime: number) {
|
||||
if (!this.verbose) {
|
||||
return;
|
||||
}
|
||||
let executionTime = performance.now() - startTime;
|
||||
this.executionResults.push(executionTime);
|
||||
this.executions++;
|
||||
this.possiblyFlushPerformanceReport();
|
||||
}
|
||||
|
||||
// Dumps mean decoding latency to console for last
|
||||
// EXECUTIONS_TO_REPORT_PERFORMANCE runs.
|
||||
// TODO(mebjas): Can we automate instrumentation runs?
|
||||
possiblyFlushPerformanceReport() {
|
||||
if (this.executions < this.EXECUTIONS_TO_REPORT_PERFORMANCE) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sum:number = 0;
|
||||
for (let executionTime of this.executionResults) {
|
||||
sum += executionTime;
|
||||
}
|
||||
let mean = sum / this.executionResults.length;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`${mean} ms for ${this.executionResults.length} last runs.`);
|
||||
this.executions = 0;
|
||||
this.executionResults = [];
|
||||
}
|
||||
}
|
||||
105
node_modules/html5-qrcode/src/core.d.ts
generated
vendored
Normal file
105
node_modules/html5-qrcode/src/core.d.ts
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
export declare enum Html5QrcodeSupportedFormats {
|
||||
QR_CODE = 0,
|
||||
AZTEC = 1,
|
||||
CODABAR = 2,
|
||||
CODE_39 = 3,
|
||||
CODE_93 = 4,
|
||||
CODE_128 = 5,
|
||||
DATA_MATRIX = 6,
|
||||
MAXICODE = 7,
|
||||
ITF = 8,
|
||||
EAN_13 = 9,
|
||||
EAN_8 = 10,
|
||||
PDF_417 = 11,
|
||||
RSS_14 = 12,
|
||||
RSS_EXPANDED = 13,
|
||||
UPC_A = 14,
|
||||
UPC_E = 15,
|
||||
UPC_EAN_EXTENSION = 16
|
||||
}
|
||||
export declare enum DecodedTextType {
|
||||
UNKNOWN = 0,
|
||||
URL = 1
|
||||
}
|
||||
export declare function isValidHtml5QrcodeSupportedFormats(format: any): boolean;
|
||||
export declare enum Html5QrcodeScanType {
|
||||
SCAN_TYPE_CAMERA = 0,
|
||||
SCAN_TYPE_FILE = 1
|
||||
}
|
||||
export declare class Html5QrcodeConstants {
|
||||
static GITHUB_PROJECT_URL: string;
|
||||
static SCAN_DEFAULT_FPS: number;
|
||||
static DEFAULT_DISABLE_FLIP: boolean;
|
||||
static DEFAULT_REMEMBER_LAST_CAMERA_USED: boolean;
|
||||
static DEFAULT_SUPPORTED_SCAN_TYPE: Html5QrcodeScanType[];
|
||||
}
|
||||
export interface QrDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
export type QrDimensionFunction = (viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
|
||||
export interface QrBounds extends QrDimensions {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
export declare class QrcodeResultFormat {
|
||||
readonly format: Html5QrcodeSupportedFormats;
|
||||
readonly formatName: string;
|
||||
private constructor();
|
||||
toString(): string;
|
||||
static create(format: Html5QrcodeSupportedFormats): QrcodeResultFormat;
|
||||
}
|
||||
export interface QrcodeResultDebugData {
|
||||
decoderName?: string;
|
||||
}
|
||||
export interface QrcodeResult {
|
||||
text: string;
|
||||
format?: QrcodeResultFormat;
|
||||
bounds?: QrBounds;
|
||||
decodedTextType?: DecodedTextType;
|
||||
debugData?: QrcodeResultDebugData;
|
||||
}
|
||||
export interface Html5QrcodeResult {
|
||||
decodedText: string;
|
||||
result: QrcodeResult;
|
||||
}
|
||||
export declare class Html5QrcodeResultFactory {
|
||||
static createFromText(decodedText: string): Html5QrcodeResult;
|
||||
static createFromQrcodeResult(qrcodeResult: QrcodeResult): Html5QrcodeResult;
|
||||
}
|
||||
export declare enum Html5QrcodeErrorTypes {
|
||||
UNKWOWN_ERROR = 0,
|
||||
IMPLEMENTATION_ERROR = 1,
|
||||
NO_CODE_FOUND_ERROR = 2
|
||||
}
|
||||
export interface Html5QrcodeError {
|
||||
errorMessage: string;
|
||||
type: Html5QrcodeErrorTypes;
|
||||
}
|
||||
export declare class Html5QrcodeErrorFactory {
|
||||
static createFrom(error: any): Html5QrcodeError;
|
||||
}
|
||||
export type QrcodeSuccessCallback = (decodedText: string, result: Html5QrcodeResult) => void;
|
||||
export type QrcodeErrorCallback = (errorMessage: string, error: Html5QrcodeError) => void;
|
||||
export interface QrcodeDecoderAsync {
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
}
|
||||
export interface RobustQrcodeDecoderAsync extends QrcodeDecoderAsync {
|
||||
decodeRobustlyAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
}
|
||||
export interface Logger {
|
||||
log(message: string): void;
|
||||
warn(message: string): void;
|
||||
logError(message: string, isExperimental?: boolean): void;
|
||||
logErrors(errors: Array<any>): void;
|
||||
}
|
||||
export declare class BaseLoggger implements Logger {
|
||||
private verbose;
|
||||
constructor(verbose: boolean);
|
||||
log(message: string): void;
|
||||
warn(message: string): void;
|
||||
logError(message: string, isExperimental?: boolean): void;
|
||||
logErrors(errors: Array<any>): void;
|
||||
}
|
||||
export declare function isNullOrUndefined(obj?: any): boolean;
|
||||
export declare function clip(value: number, minValue: number, maxValue: number): number;
|
||||
353
node_modules/html5-qrcode/src/core.ts
generated
vendored
Normal file
353
node_modules/html5-qrcode/src/core.ts
generated
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Core libraries, interfaces, enums shared across {@class Html5Qrcode} & {@class Html5QrcodeScanner}
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Code formats supported by this library.
|
||||
*/
|
||||
export enum Html5QrcodeSupportedFormats {
|
||||
QR_CODE = 0,
|
||||
AZTEC,
|
||||
CODABAR,
|
||||
CODE_39,
|
||||
CODE_93,
|
||||
CODE_128,
|
||||
DATA_MATRIX,
|
||||
MAXICODE,
|
||||
ITF,
|
||||
EAN_13,
|
||||
EAN_8,
|
||||
PDF_417,
|
||||
RSS_14,
|
||||
RSS_EXPANDED,
|
||||
UPC_A,
|
||||
UPC_E,
|
||||
UPC_EAN_EXTENSION,
|
||||
}
|
||||
|
||||
/** {@code Html5QrcodeSupportedFormats} to friendly name map. */
|
||||
const html5QrcodeSupportedFormatsTextMap
|
||||
: Map<Html5QrcodeSupportedFormats, string> = new Map(
|
||||
[
|
||||
[ Html5QrcodeSupportedFormats.QR_CODE, "QR_CODE" ],
|
||||
[ Html5QrcodeSupportedFormats.AZTEC, "AZTEC" ],
|
||||
[ Html5QrcodeSupportedFormats.CODABAR, "CODABAR" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_39, "CODE_39" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_93, "CODE_93" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_128, "CODE_128" ],
|
||||
[ Html5QrcodeSupportedFormats.DATA_MATRIX, "DATA_MATRIX" ],
|
||||
[ Html5QrcodeSupportedFormats.MAXICODE, "MAXICODE" ],
|
||||
[ Html5QrcodeSupportedFormats.ITF, "ITF" ],
|
||||
[ Html5QrcodeSupportedFormats.EAN_13, "EAN_13" ],
|
||||
[ Html5QrcodeSupportedFormats.EAN_8, "EAN_8" ],
|
||||
[ Html5QrcodeSupportedFormats.PDF_417, "PDF_417" ],
|
||||
[ Html5QrcodeSupportedFormats.RSS_14, "RSS_14" ],
|
||||
[ Html5QrcodeSupportedFormats.RSS_EXPANDED, "RSS_EXPANDED" ],
|
||||
[ Html5QrcodeSupportedFormats.UPC_A, "UPC_A" ],
|
||||
[ Html5QrcodeSupportedFormats.UPC_E, "UPC_E" ],
|
||||
[ Html5QrcodeSupportedFormats.UPC_EAN_EXTENSION, "UPC_EAN_EXTENSION" ]
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Indicates the type of decoded text.
|
||||
*
|
||||
* Note: this is very experimental in nature at the moment.
|
||||
*/
|
||||
export enum DecodedTextType {
|
||||
UNKNOWN = 0,
|
||||
URL,
|
||||
}
|
||||
|
||||
/** Returns true if the passed object instance is a valid format. */
|
||||
export function isValidHtml5QrcodeSupportedFormats(format: any): boolean {
|
||||
return Object.values(Html5QrcodeSupportedFormats).includes(format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Types of scans supported by the library
|
||||
*/
|
||||
export enum Html5QrcodeScanType {
|
||||
SCAN_TYPE_CAMERA = 0, // Camera based scanner.
|
||||
SCAN_TYPE_FILE = 1 // File based scanner.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants used in QR code library.
|
||||
*/
|
||||
export class Html5QrcodeConstants {
|
||||
static GITHUB_PROJECT_URL: string
|
||||
= "https://github.com/mebjas/html5-qrcode";
|
||||
static SCAN_DEFAULT_FPS = 2;
|
||||
static DEFAULT_DISABLE_FLIP = false;
|
||||
static DEFAULT_REMEMBER_LAST_CAMERA_USED = true;
|
||||
static DEFAULT_SUPPORTED_SCAN_TYPE = [
|
||||
Html5QrcodeScanType.SCAN_TYPE_CAMERA,
|
||||
Html5QrcodeScanType.SCAN_TYPE_FILE];
|
||||
}
|
||||
|
||||
/** Defines dimension for QR Code Scanner. */
|
||||
export interface QrDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that takes in the width and height of the video stream
|
||||
* and returns QrDimensions.
|
||||
*
|
||||
* Viewfinder refers to the video showing camera stream.
|
||||
*/
|
||||
export type QrDimensionFunction =
|
||||
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
|
||||
|
||||
/**
|
||||
* Defines bounds of detected QR code w.r.t the scan region.
|
||||
*/
|
||||
export interface QrBounds extends QrDimensions {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/** Format of detected code. */
|
||||
export class QrcodeResultFormat {
|
||||
public readonly format: Html5QrcodeSupportedFormats;
|
||||
public readonly formatName: string;
|
||||
|
||||
private constructor(
|
||||
format: Html5QrcodeSupportedFormats,
|
||||
formatName: string) {
|
||||
this.format = format;
|
||||
this.formatName = formatName;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return this.formatName;
|
||||
}
|
||||
|
||||
public static create(format: Html5QrcodeSupportedFormats) {
|
||||
if (!html5QrcodeSupportedFormatsTextMap.has(format)) {
|
||||
throw `${format} not in html5QrcodeSupportedFormatsTextMap`;
|
||||
}
|
||||
return new QrcodeResultFormat(
|
||||
format, html5QrcodeSupportedFormatsTextMap.get(format)!);
|
||||
}
|
||||
}
|
||||
|
||||
/** Data class for QR code result used for debugging. */
|
||||
export interface QrcodeResultDebugData {
|
||||
|
||||
/** Name of the decoder that was used for decoding. */
|
||||
decoderName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed scan result.
|
||||
*/
|
||||
export interface QrcodeResult {
|
||||
/** Decoded text. */
|
||||
text: string;
|
||||
|
||||
/** Format that was successfully scanned. */
|
||||
format?: QrcodeResultFormat,
|
||||
|
||||
/**
|
||||
* The bounds of the decoded QR code or bar code in the whole stream of
|
||||
* image.
|
||||
*
|
||||
* Note: this is experimental, and not fully supported.
|
||||
*/
|
||||
bounds?: QrBounds;
|
||||
|
||||
/**
|
||||
* If the decoded text from the QR code or bar code is of a known type like
|
||||
* url or upi id or email id.
|
||||
*
|
||||
* Note: this is experimental, and not fully supported.
|
||||
*/
|
||||
decodedTextType?: DecodedTextType;
|
||||
|
||||
/** Data class for QR code result used for debugging. */
|
||||
debugData?: QrcodeResultDebugData;
|
||||
}
|
||||
|
||||
/**
|
||||
* QrCode result object.
|
||||
*/
|
||||
export interface Html5QrcodeResult {
|
||||
decodedText: string;
|
||||
result: QrcodeResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory for creating {@interface Html5QrcodeResult} instance.
|
||||
*/
|
||||
export class Html5QrcodeResultFactory {
|
||||
static createFromText(decodedText: string): Html5QrcodeResult {
|
||||
let qrcodeResult = {
|
||||
text: decodedText
|
||||
};
|
||||
|
||||
return {
|
||||
decodedText: decodedText,
|
||||
result: qrcodeResult
|
||||
};
|
||||
}
|
||||
|
||||
static createFromQrcodeResult(qrcodeResult: QrcodeResult)
|
||||
: Html5QrcodeResult {
|
||||
return {
|
||||
decodedText: qrcodeResult.text,
|
||||
result: qrcodeResult
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Different kind of errors that can lead to scanning error.
|
||||
*/
|
||||
export enum Html5QrcodeErrorTypes {
|
||||
UNKWOWN_ERROR = 0,
|
||||
IMPLEMENTATION_ERROR = 1,
|
||||
NO_CODE_FOUND_ERROR = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for scan error response.
|
||||
*/
|
||||
export interface Html5QrcodeError {
|
||||
errorMessage: string;
|
||||
type: Html5QrcodeErrorTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static factory for creating {@interface Html5QrcodeError} instance.
|
||||
*/
|
||||
export class Html5QrcodeErrorFactory {
|
||||
static createFrom(error: any): Html5QrcodeError {
|
||||
return {
|
||||
errorMessage: error,
|
||||
type: Html5QrcodeErrorTypes.UNKWOWN_ERROR
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type for a callback for a successful code scan.
|
||||
*/
|
||||
export type QrcodeSuccessCallback
|
||||
= (decodedText: string, result: Html5QrcodeResult) => void;
|
||||
|
||||
/**
|
||||
* Type for a callback for failure during code scan.
|
||||
*/
|
||||
export type QrcodeErrorCallback
|
||||
= (errorMessage: string, error: Html5QrcodeError) => void;
|
||||
|
||||
/** Code decoder interface. */
|
||||
export interface QrcodeDecoderAsync {
|
||||
/**
|
||||
* Decodes content of the canvas to find a valid QR code or bar code.
|
||||
*
|
||||
* @param canvas a valid html5 canvas element.
|
||||
*/
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Code robust decoder interface.
|
||||
*
|
||||
* <p> A robust decoder may sacrifice latency of scanning for scanning quality.
|
||||
* Ideal for file scan kind of operation.
|
||||
*/
|
||||
export interface RobustQrcodeDecoderAsync extends QrcodeDecoderAsync {
|
||||
/**
|
||||
* Decodes content of the canvas to find a valid QR code or bar code.
|
||||
*
|
||||
* <p>The method implementation will run the decoder more robustly at the
|
||||
* expense of latency.
|
||||
*
|
||||
* @param canvas a valid html5 canvas element.
|
||||
*/
|
||||
decodeRobustlyAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
}
|
||||
|
||||
/** Interface for logger. */
|
||||
export interface Logger {
|
||||
log(message: string): void;
|
||||
warn(message: string): void;
|
||||
logError(message: string, isExperimental?: boolean): void;
|
||||
logErrors(errors: Array<any>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base logger implementation based on browser console.
|
||||
*
|
||||
* This can be replaced by a custom implementation of logger.
|
||||
*
|
||||
*/
|
||||
export class BaseLoggger implements Logger {
|
||||
|
||||
private verbose: boolean;
|
||||
|
||||
public constructor(verbose: boolean) {
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
public log(message: string): void {
|
||||
if (this.verbose) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(message);
|
||||
}
|
||||
}
|
||||
|
||||
public warn(message: string): void {
|
||||
if (this.verbose) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
|
||||
public logError(message: string, isExperimental?: boolean)
|
||||
: void {
|
||||
if (this.verbose || isExperimental === true) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
public logErrors(errors: Array<any>): void {
|
||||
if (errors.length === 0) {
|
||||
throw "Logger#logError called without arguments";
|
||||
}
|
||||
if (this.verbose) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#region global functions
|
||||
/** Returns true if the {@param obj} is null or undefined. */
|
||||
export function isNullOrUndefined(obj?: any) {
|
||||
return (typeof obj === "undefined") || obj === null;
|
||||
}
|
||||
|
||||
/** Clips the {@code value} between {@code minValue} and {@code maxValue}. */
|
||||
export function clip(value: number, minValue: number, maxValue: number) {
|
||||
if (value > maxValue) {
|
||||
return maxValue;
|
||||
}
|
||||
if (value < minValue) {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
//#endregion
|
||||
3
node_modules/html5-qrcode/src/experimental-features.d.ts
generated
vendored
Normal file
3
node_modules/html5-qrcode/src/experimental-features.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface ExperimentalFeaturesConfig {
|
||||
useBarCodeDetectorIfSupported?: boolean | undefined;
|
||||
}
|
||||
44
node_modules/html5-qrcode/src/experimental-features.ts
generated
vendored
Normal file
44
node_modules/html5-qrcode/src/experimental-features.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Core library for experimental features.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* Experimental features are those which have limited browser compatibility and
|
||||
* hidden from official documentations. These features are not recommended by
|
||||
* the author to be used in production unless explictly tested.
|
||||
*
|
||||
* Subset of the features are expected to upgrade to official feature list from
|
||||
* time to time.
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Configuration for enabling or disabling experimental features in the library.
|
||||
*
|
||||
* These features will eventually upgrade as fully supported features in the
|
||||
* library.
|
||||
*/
|
||||
export interface ExperimentalFeaturesConfig {
|
||||
/**
|
||||
* {@class BarcodeDetector} is being implemented by browsers at the moment.
|
||||
* It has very limited browser support but as it gets available it could
|
||||
* enable faster native code scanning experience.
|
||||
*
|
||||
* Set this flag to true, to enable using {@class BarcodeDetector} if
|
||||
* supported. This is false by default.
|
||||
*
|
||||
* @deprecated This configuration has graduated to
|
||||
* {@code Html5QrcodeCameraScanConfig} you can set it there directly. All
|
||||
* documentation and future improvements shall be added to that one. This
|
||||
* config will still work for backwards compatibility.
|
||||
*
|
||||
* Documentations:
|
||||
* - https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector
|
||||
* - https://web.dev/shape-detection/#barcodedetector
|
||||
*/
|
||||
useBarCodeDetectorIfSupported?: boolean | undefined;
|
||||
}
|
||||
67
node_modules/html5-qrcode/src/html5-qrcode-scanner.d.ts
generated
vendored
Normal file
67
node_modules/html5-qrcode/src/html5-qrcode-scanner.d.ts
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
import { Html5QrcodeScanType, QrcodeSuccessCallback, QrcodeErrorCallback } from "./core";
|
||||
import { Html5QrcodeConfigs, Html5QrcodeCameraScanConfig } from "./html5-qrcode";
|
||||
import { Html5QrcodeScannerState } from "./state-manager";
|
||||
export interface Html5QrcodeScannerConfig extends Html5QrcodeCameraScanConfig, Html5QrcodeConfigs {
|
||||
rememberLastUsedCamera?: boolean | undefined;
|
||||
supportedScanTypes?: Array<Html5QrcodeScanType> | [];
|
||||
showTorchButtonIfSupported?: boolean | undefined;
|
||||
showZoomSliderIfSupported?: boolean | undefined;
|
||||
defaultZoomValueIfSupported?: number | undefined;
|
||||
}
|
||||
export declare class Html5QrcodeScanner {
|
||||
private elementId;
|
||||
private config;
|
||||
private verbose;
|
||||
private currentScanType;
|
||||
private sectionSwapAllowed;
|
||||
private persistedDataManager;
|
||||
private scanTypeSelector;
|
||||
private logger;
|
||||
private html5Qrcode;
|
||||
private qrCodeSuccessCallback;
|
||||
private qrCodeErrorCallback;
|
||||
private lastMatchFound;
|
||||
private cameraScanImage;
|
||||
private fileScanImage;
|
||||
private fileSelectionUi;
|
||||
constructor(elementId: string, config: Html5QrcodeScannerConfig | undefined, verbose: boolean | undefined);
|
||||
render(qrCodeSuccessCallback: QrcodeSuccessCallback, qrCodeErrorCallback: QrcodeErrorCallback | undefined): void;
|
||||
pause(shouldPauseVideo?: boolean): void;
|
||||
resume(): void;
|
||||
getState(): Html5QrcodeScannerState;
|
||||
clear(): Promise<void>;
|
||||
getRunningTrackCapabilities(): MediaTrackCapabilities;
|
||||
getRunningTrackSettings(): MediaTrackSettings;
|
||||
applyVideoConstraints(videoConstaints: MediaTrackConstraints): Promise<void>;
|
||||
private getHtml5QrcodeOrFail;
|
||||
private createConfig;
|
||||
private createBasicLayout;
|
||||
private resetBasicLayout;
|
||||
private setupInitialDashboard;
|
||||
private createHeader;
|
||||
private createSection;
|
||||
private createCameraListUi;
|
||||
private createPermissionButton;
|
||||
private createPermissionsUi;
|
||||
private createSectionControlPanel;
|
||||
private renderFileScanUi;
|
||||
private renderCameraSelection;
|
||||
private createSectionSwap;
|
||||
private startCameraScanIfPermissionExistsOnSwap;
|
||||
private resetHeaderMessage;
|
||||
private setHeaderMessage;
|
||||
private showHideScanTypeSwapLink;
|
||||
private insertCameraScanImageToScanRegion;
|
||||
private insertFileScanImageToScanRegion;
|
||||
private clearScanRegion;
|
||||
private getDashboardSectionId;
|
||||
private getDashboardSectionCameraScanRegionId;
|
||||
private getDashboardSectionSwapLinkId;
|
||||
private getScanRegionId;
|
||||
private getDashboardId;
|
||||
private getHeaderMessageContainerId;
|
||||
private getCameraPermissionButtonId;
|
||||
private getCameraScanRegion;
|
||||
private getDashboardSectionSwapLink;
|
||||
private getHeaderMessageDiv;
|
||||
}
|
||||
1137
node_modules/html5-qrcode/src/html5-qrcode-scanner.ts
generated
vendored
Normal file
1137
node_modules/html5-qrcode/src/html5-qrcode-scanner.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
75
node_modules/html5-qrcode/src/html5-qrcode.d.ts
generated
vendored
Normal file
75
node_modules/html5-qrcode/src/html5-qrcode.d.ts
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
import { QrcodeErrorCallback, QrcodeSuccessCallback, Html5QrcodeSupportedFormats, Html5QrcodeResult, QrDimensions, QrDimensionFunction } from "./core";
|
||||
import { CameraDevice, CameraCapabilities } from "./camera/core";
|
||||
import { ExperimentalFeaturesConfig } from "./experimental-features";
|
||||
import { Html5QrcodeScannerState } from "./state-manager";
|
||||
export interface Html5QrcodeConfigs {
|
||||
formatsToSupport?: Array<Html5QrcodeSupportedFormats> | undefined;
|
||||
useBarCodeDetectorIfSupported?: boolean | undefined;
|
||||
experimentalFeatures?: ExperimentalFeaturesConfig | undefined;
|
||||
}
|
||||
export interface Html5QrcodeFullConfig extends Html5QrcodeConfigs {
|
||||
verbose: boolean | undefined;
|
||||
}
|
||||
export interface Html5QrcodeCameraScanConfig {
|
||||
fps: number | undefined;
|
||||
qrbox?: number | QrDimensions | QrDimensionFunction | undefined;
|
||||
aspectRatio?: number | undefined;
|
||||
disableFlip?: boolean | undefined;
|
||||
videoConstraints?: MediaTrackConstraints | undefined;
|
||||
}
|
||||
export declare class Html5Qrcode {
|
||||
private readonly logger;
|
||||
private readonly elementId;
|
||||
private readonly verbose;
|
||||
private readonly qrcode;
|
||||
private shouldScan;
|
||||
private element;
|
||||
private canvasElement;
|
||||
private scannerPausedUiElement;
|
||||
private hasBorderShaders;
|
||||
private borderShaders;
|
||||
private qrMatch;
|
||||
private renderedCamera;
|
||||
private foreverScanTimeout;
|
||||
private qrRegion;
|
||||
private context;
|
||||
private lastScanImageFile;
|
||||
private stateManagerProxy;
|
||||
isScanning: boolean;
|
||||
constructor(elementId: string, configOrVerbosityFlag?: boolean | Html5QrcodeFullConfig | undefined);
|
||||
start(cameraIdOrConfig: string | MediaTrackConstraints, configuration: Html5QrcodeCameraScanConfig | undefined, qrCodeSuccessCallback: QrcodeSuccessCallback | undefined, qrCodeErrorCallback: QrcodeErrorCallback | undefined): Promise<null>;
|
||||
pause(shouldPauseVideo?: boolean): void;
|
||||
resume(): void;
|
||||
getState(): Html5QrcodeScannerState;
|
||||
stop(): Promise<void>;
|
||||
scanFile(imageFile: File, showImage?: boolean): Promise<string>;
|
||||
scanFileV2(imageFile: File, showImage?: boolean): Promise<Html5QrcodeResult>;
|
||||
clear(): void;
|
||||
static getCameras(): Promise<Array<CameraDevice>>;
|
||||
getRunningTrackCapabilities(): MediaTrackCapabilities;
|
||||
getRunningTrackSettings(): MediaTrackSettings;
|
||||
getRunningTrackCameraCapabilities(): CameraCapabilities;
|
||||
applyVideoConstraints(videoConstaints: MediaTrackConstraints): Promise<void>;
|
||||
private getRenderedCameraOrFail;
|
||||
private getSupportedFormats;
|
||||
private getUseBarCodeDetectorIfSupported;
|
||||
private validateQrboxSize;
|
||||
private validateQrboxConfig;
|
||||
private toQrdimensions;
|
||||
private setupUi;
|
||||
private createScannerPausedUiElement;
|
||||
private scanContext;
|
||||
private foreverScan;
|
||||
private createVideoConstraints;
|
||||
private computeCanvasDrawConfig;
|
||||
private clearElement;
|
||||
private possiblyUpdateShaders;
|
||||
private possiblyCloseLastScanImageFile;
|
||||
private createCanvasElement;
|
||||
private getShadedRegionBounds;
|
||||
private possiblyInsertShadingElement;
|
||||
private insertShaderBorders;
|
||||
private showPausedState;
|
||||
private hidePausedState;
|
||||
private getTimeoutFps;
|
||||
}
|
||||
1595
node_modules/html5-qrcode/src/html5-qrcode.ts
generated
vendored
Normal file
1595
node_modules/html5-qrcode/src/html5-qrcode.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
node_modules/html5-qrcode/src/image-assets.d.ts
generated
vendored
Normal file
4
node_modules/html5-qrcode/src/image-assets.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
export declare const ASSET_CAMERA_SCAN: string;
|
||||
export declare const ASSET_FILE_SCAN: string;
|
||||
export declare const ASSET_INFO_ICON_16PX: string;
|
||||
export declare const ASSET_CLOSE_ICON_16PX: string;
|
||||
18
node_modules/html5-qrcode/src/image-assets.ts
generated
vendored
Normal file
18
node_modules/html5-qrcode/src/image-assets.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @fileoverview - Exports base64 assets for gif images.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
const SVG_XML_PREFIX = "data:image/svg+xml;base64,";
|
||||
|
||||
export const ASSET_CAMERA_SCAN: string = SVG_XML_PREFIX + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNzEuNjQzIDM3MS42NDMiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDM3MS42NDMgMzcxLjY0MyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHBhdGggZD0iTTEwNS4wODQgMzguMjcxaDE2My43Njh2MjBIMTA1LjA4NHoiLz48cGF0aCBkPSJNMzExLjU5NiAxOTAuMTg5Yy03LjQ0MS05LjM0Ny0xOC40MDMtMTYuMjA2LTMyLjc0My0yMC41MjJWMzBjMC0xNi41NDItMTMuNDU4LTMwLTMwLTMwSDEyNS4wODRjLTE2LjU0MiAwLTMwIDEzLjQ1OC0zMCAzMHYxMjAuMTQzaC04LjI5NmMtMTYuNTQyIDAtMzAgMTMuNDU4LTMwIDMwdjEuMzMzYTI5LjgwNCAyOS44MDQgMCAwIDAgNC42MDMgMTUuOTM5Yy03LjM0IDUuNDc0LTEyLjEwMyAxNC4yMjEtMTIuMTAzIDI0LjA2MXYxLjMzM2MwIDkuODQgNC43NjMgMTguNTg3IDEyLjEwMyAyNC4wNjJhMjkuODEgMjkuODEgMCAwIDAtNC42MDMgMTUuOTM4djEuMzMzYzAgMTYuNTQyIDEzLjQ1OCAzMCAzMCAzMGg4LjMyNGMuNDI3IDExLjYzMSA3LjUwMyAyMS41ODcgMTcuNTM0IDI2LjE3Ny45MzEgMTAuNTAzIDQuMDg0IDMwLjE4NyAxNC43NjggNDUuNTM3YTkuOTg4IDkuOTg4IDAgMCAwIDguMjE2IDQuMjg4IDkuOTU4IDkuOTU4IDAgMCAwIDUuNzA0LTEuNzkzYzQuNTMzLTMuMTU1IDUuNjUtOS4zODggMi40OTUtMTMuOTIxLTYuNzk4LTkuNzY3LTkuNjAyLTIyLjYwOC0xMC43Ni0zMS40aDgyLjY4NWMuMjcyLjQxNC41NDUuODE4LjgxNSAxLjIxIDMuMTQyIDQuNTQxIDkuMzcyIDUuNjc5IDEzLjkxMyAyLjUzNCA0LjU0Mi0zLjE0MiA1LjY3Ny05LjM3MSAyLjUzNS0xMy45MTMtMTEuOTE5LTE3LjIyOS04Ljc4Ny0zNS44ODQgOS41ODEtNTcuMDEyIDMuMDY3LTIuNjUyIDEyLjMwNy0xMS43MzIgMTEuMjE3LTI0LjAzMy0uODI4LTkuMzQzLTcuMTA5LTE3LjE5NC0xOC42NjktMjMuMzM3YTkuODU3IDkuODU3IDAgMCAwLTEuMDYxLS40ODZjLS40NjYtLjE4Mi0xMS40MDMtNC41NzktOS43NDEtMTUuNzA2IDEuMDA3LTYuNzM3IDE0Ljc2OC04LjI3MyAyMy43NjYtNy42NjYgMjMuMTU2IDEuNTY5IDM5LjY5OCA3LjgwMyA0Ny44MzYgMTguMDI2IDUuNzUyIDcuMjI1IDcuNjA3IDE2LjYyMyA1LjY3MyAyOC43MzMtLjQxMyAyLjU4NS0uODI0IDUuMjQxLTEuMjQ1IDcuOTU5LTUuNzU2IDM3LjE5NC0xMi45MTkgODMuNDgzLTQ5Ljg3IDExNC42NjEtNC4yMjEgMy41NjEtNC43NTYgOS44Ny0xLjE5NCAxNC4wOTJhOS45OCA5Ljk4IDAgMCAwIDcuNjQ4IDMuNTUxIDkuOTU1IDkuOTU1IDAgMCAwIDYuNDQ0LTIuMzU4YzQyLjY3Mi0zNi4wMDUgNTAuODAyLTg4LjUzMyA1Ni43MzctMTI2Ljg4OC40MTUtMi42ODQuODIxLTUuMzA5IDEuMjI5LTcuODYzIDIuODM0LTE3LjcyMS0uNDU1LTMyLjY0MS05Ljc3Mi00NC4zNDV6bS0yMzIuMzA4IDQyLjYyYy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi0xLjMzM2MwLTUuNTE0IDQuNDg2LTEwIDEwLTEwaDE1djIxLjMzM2gtMTV6bS0yLjUtNTIuNjY2YzAtNS41MTQgNC40ODYtMTAgMTAtMTBoNy41djIxLjMzM2gtNy41Yy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi0xLjMzM3ptMTcuNSA5My45OTloLTcuNWMtNS41MTQgMC0xMC00LjQ4Ni0xMC0xMHYtMS4zMzNjMC01LjUxNCA0LjQ4Ni0xMCAxMC0xMGg3LjV2MjEuMzMzem0zMC43OTYgMjguODg3Yy01LjUxNCAwLTEwLTQuNDg2LTEwLTEwdi04LjI3MWg5MS40NTdjLS44NTEgNi42NjgtLjQzNyAxMi43ODcuNzMxIDE4LjI3MWgtODIuMTg4em03OS40ODItMTEzLjY5OGMtMy4xMjQgMjAuOTA2IDEyLjQyNyAzMy4xODQgMjEuNjI1IDM3LjA0IDUuNDQxIDIuOTY4IDcuNTUxIDUuNjQ3IDcuNzAxIDcuMTg4LjIxIDIuMTUtMi41NTMgNS42ODQtNC40NzcgNy4yNTEtLjQ4Mi4zNzgtLjkyOS44LTEuMzM1IDEuMjYxLTYuOTg3IDcuOTM2LTExLjk4MiAxNS41Mi0xNS40MzIgMjIuNjg4aC05Ny41NjRWMzBjMC01LjUxNCA0LjQ4Ni0xMCAxMC0xMGgxMjMuNzY5YzUuNTE0IDAgMTAgNC40ODYgMTAgMTB2MTM1LjU3OWMtMy4wMzItLjM4MS02LjE1LS42OTQtOS4zODktLjkxNC0yNS4xNTktMS42OTQtNDIuMzcgNy43NDgtNDQuODk4IDI0LjY2NnoiLz48cGF0aCBkPSJNMTc5LjEyOSA4My4xNjdoLTI0LjA2YTUgNSAwIDAgMC01IDV2MjQuMDYxYTUgNSAwIDAgMCA1IDVoMjQuMDZhNSA1IDAgMCAwIDUtNVY4OC4xNjdhNSA1IDAgMCAwLTUtNXpNMTcyLjYyOSAxNDIuODZoLTEyLjU2VjEzMC44YTUgNSAwIDEgMC0xMCAwdjE3LjA2MWE1IDUgMCAwIDAgNSA1aDE3LjU2YTUgNSAwIDEgMCAwLTEwLjAwMXpNMjE2LjU2OCA4My4xNjdoLTI0LjA2YTUgNSAwIDAgMC01IDV2MjQuMDYxYTUgNSAwIDAgMCA1IDVoMjQuMDZhNSA1IDAgMCAwIDUtNVY4OC4xNjdhNSA1IDAgMCAwLTUtNXptLTUgMjQuMDYxaC0xNC4wNlY5My4xNjdoMTQuMDZ2MTQuMDYxek0yMTEuNjY5IDEyNS45MzZIMTk3LjQxYTUgNSAwIDAgMC01IDV2MTQuMjU3YTUgNSAwIDAgMCA1IDVoMTQuMjU5YTUgNSAwIDAgMCA1LTV2LTE0LjI1N2E1IDUgMCAwIDAtNS01eiIvPjwvc3ZnPg==";
|
||||
|
||||
export const ASSET_FILE_SCAN: string = SVG_XML_PREFIX + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1OS4wMTggNTkuMDE4IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1OS4wMTggNTkuMDE4IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBkPSJtNTguNzQxIDU0LjgwOS01Ljk2OS02LjI0NGExMC43NCAxMC43NCAwIDAgMCAyLjgyLTcuMjVjMC01Ljk1My00Ljg0My0xMC43OTYtMTAuNzk2LTEwLjc5NlMzNCAzNS4zNjEgMzQgNDEuMzE0IDM4Ljg0MyA1Mi4xMSA0NC43OTYgNTIuMTFjMi40NDEgMCA0LjY4OC0uODI0IDYuNDk5LTIuMTk2bDYuMDAxIDYuMjc3YS45OTguOTk4IDAgMCAwIDEuNDE0LjAzMiAxIDEgMCAwIDAgLjAzMS0xLjQxNHpNMzYgNDEuMzE0YzAtNC44NSAzLjk0Ni04Ljc5NiA4Ljc5Ni04Ljc5NnM4Ljc5NiAzLjk0NiA4Ljc5NiA4Ljc5Ni0zLjk0NiA4Ljc5Ni04Ljc5NiA4Ljc5NlMzNiA0Ni4xNjQgMzYgNDEuMzE0ek0xMC40MzEgMTYuMDg4YzAgMy4wNyAyLjQ5OCA1LjU2OCA1LjU2OSA1LjU2OHM1LjU2OS0yLjQ5OCA1LjU2OS01LjU2OGMwLTMuMDcxLTIuNDk4LTUuNTY5LTUuNTY5LTUuNTY5cy01LjU2OSAyLjQ5OC01LjU2OSA1LjU2OXptOS4xMzggMGMwIDEuOTY4LTEuNjAyIDMuNTY4LTMuNTY5IDMuNTY4cy0zLjU2OS0xLjYwMS0zLjU2OS0zLjU2OCAxLjYwMi0zLjU2OSAzLjU2OS0zLjU2OSAzLjU2OSAxLjYwMSAzLjU2OSAzLjU2OXoiLz48cGF0aCBkPSJtMzAuODgyIDI4Ljk4NyA5LjE4LTEwLjA1NCAxMS4yNjIgMTAuMzIzYTEgMSAwIDAgMCAxLjM1MS0xLjQ3NWwtMTItMTFhMSAxIDAgMCAwLTEuNDE0LjA2M2wtOS43OTQgMTAuNzI3LTQuNzQzLTQuNzQzYTEuMDAzIDEuMDAzIDAgMCAwLTEuMzY4LS4wNDRMNi4zMzkgMzcuNzY4YTEgMSAwIDEgMCAxLjMyMiAxLjUwMWwxNi4zMTMtMTQuMzYyIDcuMzE5IDcuMzE4YS45OTkuOTk5IDAgMSAwIDEuNDE0LTEuNDE0bC0xLjgyNS0xLjgyNHoiLz48cGF0aCBkPSJNMzAgNDYuNTE4SDJ2LTQyaDU0djI4YTEgMSAwIDEgMCAyIDB2LTI5YTEgMSAwIDAgMC0xLTFIMWExIDEgMCAwIDAtMSAxdjQ0YTEgMSAwIDAgMCAxIDFoMjlhMSAxIDAgMSAwIDAtMnoiLz48L3N2Zz4=";
|
||||
|
||||
export const ASSET_INFO_ICON_16PX : string = SVG_XML_PREFIX + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NjAgNDYwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA0NjAgNDYwIiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBkPSJNMjMwIDBDMTAyLjk3NSAwIDAgMTAyLjk3NSAwIDIzMHMxMDIuOTc1IDIzMCAyMzAgMjMwIDIzMC0xMDIuOTc0IDIzMC0yMzBTMzU3LjAyNSAwIDIzMCAwem0zOC4zMzMgMzc3LjM2YzAgOC42NzYtNy4wMzQgMTUuNzEtMTUuNzEgMTUuNzFoLTQzLjEwMWMtOC42NzYgMC0xNS43MS03LjAzNC0xNS43MS0xNS43MVYyMDIuNDc3YzAtOC42NzYgNy4wMzMtMTUuNzEgMTUuNzEtMTUuNzFoNDMuMTAxYzguNjc2IDAgMTUuNzEgNy4wMzMgMTUuNzEgMTUuNzFWMzc3LjM2ek0yMzAgMTU3Yy0yMS41MzkgMC0zOS0xNy40NjEtMzktMzlzMTcuNDYxLTM5IDM5LTM5IDM5IDE3LjQ2MSAzOSAzOS0xNy40NjEgMzktMzkgMzl6Ii8+PC9zdmc+";
|
||||
|
||||
export const ASSET_CLOSE_ICON_16PX : string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAQgAAAEIBarqQRAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAE1SURBVDiNfdI7S0NBEAXgLya1otFgpbYSbISAgpXYi6CmiH9KCAiChaVga6OiWPgfRDQ+0itaGVNosXtluWwcuMzePfM4M3sq8lbHBubwg1dc4m1E/J/N4ghDPOIsfk/4xiEao5KX0McFljN4C9d4QTPXuY99jP3DsIoDPGM6BY5i5yI5R7O4q+ImFkJY2DCh3cAH2klyB+9J1xUMMAG7eCh1a+Mr+k48b5diXrFVwwLuS+BJ9MfR7+G0FHOHhTHhnXNWS87VDF4pcnfQK4Ep7XScNLmPTZgURNKKYENYWDpzW1BhscS1WHS8CDgURFJQrWcoF3c13KKbgg1BYQfy8xZWEzTTw1QZbAoKu8FqJnktdu5hcVSHmchiILzzuaDQvjBzV2m8yohCE1jHfPx/xhU+y4G/D75ELlRJsSYAAAAASUVORK5CYII=";
|
||||
6
node_modules/html5-qrcode/src/index.d.ts
generated
vendored
Normal file
6
node_modules/html5-qrcode/src/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export { Html5Qrcode, Html5QrcodeFullConfig, Html5QrcodeCameraScanConfig } from "./html5-qrcode";
|
||||
export { Html5QrcodeScanner } from "./html5-qrcode-scanner";
|
||||
export { Html5QrcodeSupportedFormats, Html5QrcodeResult, QrcodeSuccessCallback, QrcodeErrorCallback } from "./core";
|
||||
export { Html5QrcodeScannerState } from "./state-manager";
|
||||
export { Html5QrcodeScanType } from "./core";
|
||||
export { CameraCapabilities, CameraDevice } from "./camera/core";
|
||||
32
node_modules/html5-qrcode/src/index.ts
generated
vendored
Normal file
32
node_modules/html5-qrcode/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @fileoverview - Global export file.
|
||||
* HTML5 QR code & barcode scanning library.
|
||||
* - Decode QR Code.
|
||||
* - Decode different kinds of barcodes.
|
||||
* - Decode using web cam, smart phone camera or using images on local file
|
||||
* system.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
export {
|
||||
Html5Qrcode,
|
||||
Html5QrcodeFullConfig,
|
||||
Html5QrcodeCameraScanConfig
|
||||
} from "./html5-qrcode";
|
||||
export { Html5QrcodeScanner } from "./html5-qrcode-scanner";
|
||||
export {
|
||||
Html5QrcodeSupportedFormats,
|
||||
Html5QrcodeResult,
|
||||
QrcodeSuccessCallback,
|
||||
QrcodeErrorCallback
|
||||
} from "./core";
|
||||
export { Html5QrcodeScannerState } from "./state-manager";
|
||||
export { Html5QrcodeScanType } from "./core";
|
||||
export {
|
||||
CameraCapabilities,
|
||||
CameraDevice
|
||||
} from "./camera/core";
|
||||
16
node_modules/html5-qrcode/src/native-bar-code-detector.d.ts
generated
vendored
Normal file
16
node_modules/html5-qrcode/src/native-bar-code-detector.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { QrcodeResult, Html5QrcodeSupportedFormats, QrcodeDecoderAsync, Logger } from "./core";
|
||||
export declare class BarcodeDetectorDelegate implements QrcodeDecoderAsync {
|
||||
private readonly formatMap;
|
||||
private readonly reverseFormatMap;
|
||||
private verbose;
|
||||
private logger;
|
||||
private detector;
|
||||
static isSupported(): boolean;
|
||||
constructor(requestedFormats: Array<Html5QrcodeSupportedFormats>, verbose: boolean, logger: Logger);
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
private selectLargestBarcode;
|
||||
private createBarcodeDetectorFormats;
|
||||
private toHtml5QrcodeSupportedFormats;
|
||||
private createReverseFormatMap;
|
||||
private createDebugData;
|
||||
}
|
||||
204
node_modules/html5-qrcode/src/native-bar-code-detector.ts
generated
vendored
Normal file
204
node_modules/html5-qrcode/src/native-bar-code-detector.ts
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* {@interface QrcodeDecoder} wrapper around experimental BarcodeDetector API.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* Read more about the experimental feature here:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import {
|
||||
QrcodeResult,
|
||||
QrcodeResultDebugData,
|
||||
QrcodeResultFormat,
|
||||
Html5QrcodeSupportedFormats,
|
||||
QrcodeDecoderAsync,
|
||||
Logger
|
||||
} from "./core";
|
||||
|
||||
declare const BarcodeDetector: any;
|
||||
|
||||
/** Config for BarcodeDetector API. */
|
||||
interface BarcodeDetectorConfig {
|
||||
formats: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for BarcodeDetector result.
|
||||
*
|
||||
* Forked from
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/BarcodeDetector#methods
|
||||
*/
|
||||
interface BarcodeDetectorResult {
|
||||
/**
|
||||
* A DOMRectReadOnly, which returns the dimensions of a rectangle
|
||||
* representing the extent of a detected barcode, aligned with the image.
|
||||
*/
|
||||
boundingBox: DOMRectReadOnly;
|
||||
|
||||
/**
|
||||
* The x and y co-ordinates of the four corner points of the detected
|
||||
* barcode relative to the image, starting with the top left and working
|
||||
* clockwise. This may not be square due to perspective distortions within
|
||||
* the image.
|
||||
*/
|
||||
cornerPoints: any;
|
||||
|
||||
/**
|
||||
* The detected barcode format.
|
||||
*/
|
||||
format: string;
|
||||
|
||||
/**
|
||||
* A String decoded from the barcode data.
|
||||
*/
|
||||
rawValue: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ZXing based Code decoder.
|
||||
*/
|
||||
export class BarcodeDetectorDelegate implements QrcodeDecoderAsync {
|
||||
|
||||
// All formats defined here
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Barcode_Detection_API#supported_barcode_formats
|
||||
private readonly formatMap: Map<Html5QrcodeSupportedFormats, string>
|
||||
= new Map([
|
||||
[ Html5QrcodeSupportedFormats.QR_CODE, "qr_code" ],
|
||||
[ Html5QrcodeSupportedFormats.AZTEC, "aztec" ],
|
||||
[ Html5QrcodeSupportedFormats.CODABAR, "codabar" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_39, "code_39" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_93, "code_93" ],
|
||||
[ Html5QrcodeSupportedFormats.CODE_128, "code_128" ],
|
||||
[ Html5QrcodeSupportedFormats.DATA_MATRIX, "data_matrix" ],
|
||||
[ Html5QrcodeSupportedFormats.ITF, "itf" ],
|
||||
[ Html5QrcodeSupportedFormats.EAN_13, "ean_13" ],
|
||||
[ Html5QrcodeSupportedFormats.EAN_8, "ean_8" ],
|
||||
[ Html5QrcodeSupportedFormats.PDF_417, "pdf417" ],
|
||||
[ Html5QrcodeSupportedFormats.UPC_A, "upc_a" ],
|
||||
[ Html5QrcodeSupportedFormats.UPC_E, "upc_e" ]
|
||||
]);
|
||||
private readonly reverseFormatMap: Map<string, Html5QrcodeSupportedFormats>
|
||||
= this.createReverseFormatMap();
|
||||
|
||||
private verbose: boolean;
|
||||
private logger: Logger;
|
||||
private detector: any;
|
||||
|
||||
/**
|
||||
* Returns true if this API is supported by the browser.
|
||||
*
|
||||
* TODO(mebjas): Add checks like this
|
||||
* https://web.dev/shape-detection/#featuredetection
|
||||
* TODO(mebjas): Check for format supported by the BarcodeDetector using
|
||||
* getSupportedFormats() API.
|
||||
* @returns
|
||||
*/
|
||||
public static isSupported(): boolean {
|
||||
if (!("BarcodeDetector" in window)) {
|
||||
return false;
|
||||
}
|
||||
const dummyDetector = new BarcodeDetector({formats: [ "qr_code" ]});
|
||||
return typeof dummyDetector !== "undefined";
|
||||
}
|
||||
|
||||
public constructor(
|
||||
requestedFormats: Array<Html5QrcodeSupportedFormats>,
|
||||
verbose: boolean,
|
||||
logger: Logger) {
|
||||
if (!BarcodeDetectorDelegate.isSupported()) {
|
||||
throw "Use html5qrcode.min.js without edit, Use "
|
||||
+ "BarcodeDetectorDelegate only if it isSupported();";
|
||||
}
|
||||
this.verbose = verbose;
|
||||
this.logger = logger;
|
||||
|
||||
// create new detector
|
||||
const formats = this.createBarcodeDetectorFormats(requestedFormats);
|
||||
this.detector = new BarcodeDetector(formats);
|
||||
|
||||
// check compatibility
|
||||
if (!this.detector) {
|
||||
throw "BarcodeDetector detector not supported";
|
||||
}
|
||||
}
|
||||
|
||||
async decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult> {
|
||||
const barcodes: Array<BarcodeDetectorResult>
|
||||
= await this.detector.detect(canvas);
|
||||
if (!barcodes || barcodes.length === 0) {
|
||||
throw "No barcode or QR code detected.";
|
||||
}
|
||||
|
||||
// TODO(mebjas): Today BarcodeDetector library seems to be returning
|
||||
// mutliple barcodes if supported. But the documentation around it is
|
||||
// not the best. As of now, we are returning just the largest code
|
||||
// found. In future it'd be desriable to return mutli codes if supported
|
||||
// and found.
|
||||
let largestBarcode = this.selectLargestBarcode(barcodes);
|
||||
return {
|
||||
text: largestBarcode.rawValue,
|
||||
format: QrcodeResultFormat.create(
|
||||
this.toHtml5QrcodeSupportedFormats(largestBarcode.format)),
|
||||
debugData: this.createDebugData()
|
||||
};
|
||||
}
|
||||
|
||||
private selectLargestBarcode(barcodes: Array<BarcodeDetectorResult>)
|
||||
: BarcodeDetectorResult {
|
||||
let largestBarcode: BarcodeDetectorResult | null = null;
|
||||
let maxArea = 0;
|
||||
for (let barcode of barcodes) {
|
||||
let area = barcode.boundingBox.width * barcode.boundingBox.height;
|
||||
if (area > maxArea) {
|
||||
maxArea = area;
|
||||
largestBarcode = barcode;
|
||||
}
|
||||
}
|
||||
if (!largestBarcode) {
|
||||
throw "No largest barcode found";
|
||||
}
|
||||
return largestBarcode!;
|
||||
}
|
||||
|
||||
private createBarcodeDetectorFormats(
|
||||
requestedFormats: Array<Html5QrcodeSupportedFormats>):
|
||||
BarcodeDetectorConfig {
|
||||
let formats: Array<string> = [];
|
||||
for (const requestedFormat of requestedFormats) {
|
||||
if (this.formatMap.has(requestedFormat)) {
|
||||
formats.push(
|
||||
this.formatMap.get(requestedFormat)!);
|
||||
} else {
|
||||
this.logger.warn(`${requestedFormat} is not supported by`
|
||||
+ "BarcodeDetectorDelegate");
|
||||
}
|
||||
}
|
||||
return { formats: formats };
|
||||
}
|
||||
|
||||
private toHtml5QrcodeSupportedFormats(barcodeDetectorFormat: string)
|
||||
: Html5QrcodeSupportedFormats {
|
||||
if (!this.reverseFormatMap.has(barcodeDetectorFormat)) {
|
||||
throw `reverseFormatMap doesn't have ${barcodeDetectorFormat}`;
|
||||
}
|
||||
return this.reverseFormatMap.get(barcodeDetectorFormat)!;
|
||||
}
|
||||
|
||||
private createReverseFormatMap(): Map<string, Html5QrcodeSupportedFormats> {
|
||||
let result = new Map();
|
||||
this.formatMap.forEach(
|
||||
(value: string, key: Html5QrcodeSupportedFormats, _) => {
|
||||
result.set(value, key);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private createDebugData(): QrcodeResultDebugData {
|
||||
return { decoderName: "BarcodeDetector" };
|
||||
}
|
||||
}
|
||||
29
node_modules/html5-qrcode/src/state-manager.d.ts
generated
vendored
Normal file
29
node_modules/html5-qrcode/src/state-manager.d.ts
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
export declare enum Html5QrcodeScannerState {
|
||||
UNKNOWN = 0,
|
||||
NOT_STARTED = 1,
|
||||
SCANNING = 2,
|
||||
PAUSED = 3
|
||||
}
|
||||
export interface StateManagerTransaction {
|
||||
execute(): void;
|
||||
cancel(): void;
|
||||
}
|
||||
export interface StateManager {
|
||||
startTransition(newState: Html5QrcodeScannerState): StateManagerTransaction;
|
||||
directTransition(newState: Html5QrcodeScannerState): void;
|
||||
getState(): Html5QrcodeScannerState;
|
||||
}
|
||||
export declare class StateManagerProxy {
|
||||
private stateManager;
|
||||
constructor(stateManager: StateManager);
|
||||
startTransition(newState: Html5QrcodeScannerState): StateManagerTransaction;
|
||||
directTransition(newState: Html5QrcodeScannerState): void;
|
||||
getState(): Html5QrcodeScannerState;
|
||||
canScanFile(): boolean;
|
||||
isScanning(): boolean;
|
||||
isStrictlyScanning(): boolean;
|
||||
isPaused(): boolean;
|
||||
}
|
||||
export declare class StateManagerFactory {
|
||||
static create(): StateManagerProxy;
|
||||
}
|
||||
193
node_modules/html5-qrcode/src/state-manager.ts
generated
vendored
Normal file
193
node_modules/html5-qrcode/src/state-manager.ts
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* State handler.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
/** Different states of scanner */
|
||||
export enum Html5QrcodeScannerState {
|
||||
// Invalid internal state, do not set to this state.
|
||||
UNKNOWN = 0,
|
||||
// Indicates the scanning is not running or user is using file based
|
||||
// scanning.
|
||||
NOT_STARTED = 1,
|
||||
// Camera scan is running.
|
||||
SCANNING,
|
||||
// Camera scan is paused but camera is running.
|
||||
PAUSED,
|
||||
}
|
||||
|
||||
/** Transaction for state transition. */
|
||||
export interface StateManagerTransaction {
|
||||
/**
|
||||
* Executes the current transaction.
|
||||
*/
|
||||
execute(): void;
|
||||
|
||||
/**
|
||||
* Cancels the current transaction.
|
||||
*/
|
||||
cancel(): void;
|
||||
}
|
||||
|
||||
/** Manager class for states. */
|
||||
export interface StateManager {
|
||||
/**
|
||||
* Start a transition to a new state. No other transitions will be allowed
|
||||
* till this one is executed.
|
||||
*
|
||||
* @param newState new state to transition to.
|
||||
*
|
||||
* @returns transaction of type {@interface StateManagerTransaction}.
|
||||
*
|
||||
* @throws error if the new state is not a valid transition from current
|
||||
* state.
|
||||
*/
|
||||
startTransition(newState: Html5QrcodeScannerState): StateManagerTransaction;
|
||||
|
||||
/**
|
||||
* Directly execute a transition.
|
||||
*
|
||||
* @param newState new state to transition to.
|
||||
*
|
||||
* @throws error if the new state is not a valid transition from current
|
||||
* state.
|
||||
*/
|
||||
directTransition(newState: Html5QrcodeScannerState): void;
|
||||
|
||||
/**
|
||||
* Get current state.
|
||||
*/
|
||||
getState(): Html5QrcodeScannerState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@interface StateManager} and
|
||||
* {@interface StateManagerTransaction}.
|
||||
*/
|
||||
class StateManagerImpl implements StateManager, StateManagerTransaction {
|
||||
|
||||
private state: Html5QrcodeScannerState = Html5QrcodeScannerState.NOT_STARTED;
|
||||
|
||||
private onGoingTransactionNewState: Html5QrcodeScannerState
|
||||
= Html5QrcodeScannerState.UNKNOWN;
|
||||
|
||||
public directTransition(newState: Html5QrcodeScannerState) {
|
||||
this.failIfTransitionOngoing();
|
||||
this.validateTransition(newState);
|
||||
this.state = newState;
|
||||
}
|
||||
|
||||
public startTransition(newState: Html5QrcodeScannerState): StateManagerTransaction {
|
||||
this.failIfTransitionOngoing();
|
||||
this.validateTransition(newState);
|
||||
|
||||
this.onGoingTransactionNewState = newState;
|
||||
return this;
|
||||
}
|
||||
|
||||
public execute() {
|
||||
if (this.onGoingTransactionNewState
|
||||
=== Html5QrcodeScannerState.UNKNOWN) {
|
||||
throw "Transaction is already cancelled, cannot execute().";
|
||||
}
|
||||
|
||||
const tempNewState = this.onGoingTransactionNewState;
|
||||
this.onGoingTransactionNewState = Html5QrcodeScannerState.UNKNOWN;
|
||||
this.directTransition(tempNewState);
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
if (this.onGoingTransactionNewState
|
||||
=== Html5QrcodeScannerState.UNKNOWN) {
|
||||
throw "Transaction is already cancelled, cannot cancel().";
|
||||
}
|
||||
|
||||
this.onGoingTransactionNewState = Html5QrcodeScannerState.UNKNOWN;
|
||||
}
|
||||
|
||||
public getState(): Html5QrcodeScannerState {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
//#region private methods
|
||||
private failIfTransitionOngoing() {
|
||||
if (this.onGoingTransactionNewState
|
||||
!== Html5QrcodeScannerState.UNKNOWN) {
|
||||
throw "Cannot transition to a new state, already under transition";
|
||||
}
|
||||
}
|
||||
|
||||
private validateTransition(newState: Html5QrcodeScannerState) {
|
||||
switch(this.state) {
|
||||
case Html5QrcodeScannerState.UNKNOWN:
|
||||
throw "Transition from unknown is not allowed";
|
||||
case Html5QrcodeScannerState.NOT_STARTED:
|
||||
this.failIfNewStateIs(newState, [Html5QrcodeScannerState.PAUSED]);
|
||||
break;
|
||||
case Html5QrcodeScannerState.SCANNING:
|
||||
// Both state transitions legal from here.
|
||||
break;
|
||||
case Html5QrcodeScannerState.PAUSED:
|
||||
// Both state transitions legal from here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private failIfNewStateIs(
|
||||
newState: Html5QrcodeScannerState,
|
||||
disallowedStatesToTransition: Array<Html5QrcodeScannerState>) {
|
||||
for (const disallowedState of disallowedStatesToTransition) {
|
||||
if (newState === disallowedState) {
|
||||
throw `Cannot transition from ${this.state} to ${newState}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
export class StateManagerProxy {
|
||||
private stateManager: StateManager;
|
||||
|
||||
constructor(stateManager: StateManager) {
|
||||
this.stateManager = stateManager;
|
||||
}
|
||||
|
||||
startTransition(newState: Html5QrcodeScannerState): StateManagerTransaction {
|
||||
return this.stateManager.startTransition(newState);
|
||||
}
|
||||
|
||||
directTransition(newState: Html5QrcodeScannerState) {
|
||||
this.stateManager.directTransition(newState);
|
||||
}
|
||||
|
||||
getState(): Html5QrcodeScannerState {
|
||||
return this.stateManager.getState();
|
||||
}
|
||||
|
||||
canScanFile(): boolean {
|
||||
return this.stateManager.getState() === Html5QrcodeScannerState.NOT_STARTED;
|
||||
}
|
||||
|
||||
isScanning(): boolean {
|
||||
return this.stateManager.getState() !== Html5QrcodeScannerState.NOT_STARTED;
|
||||
}
|
||||
|
||||
isStrictlyScanning(): boolean {
|
||||
return this.stateManager.getState() === Html5QrcodeScannerState.SCANNING;
|
||||
}
|
||||
|
||||
isPaused(): boolean {
|
||||
return this.stateManager.getState() === Html5QrcodeScannerState.PAUSED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for creating instance of {@class StateManagerProxy}.
|
||||
*/
|
||||
export class StateManagerFactory {
|
||||
public static create(): StateManagerProxy {
|
||||
return new StateManagerProxy(new StateManagerImpl());
|
||||
}
|
||||
}
|
||||
12
node_modules/html5-qrcode/src/storage.d.ts
generated
vendored
Normal file
12
node_modules/html5-qrcode/src/storage.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export declare class PersistedDataManager {
|
||||
private data;
|
||||
private static LOCAL_STORAGE_KEY;
|
||||
constructor();
|
||||
hasCameraPermissions(): boolean;
|
||||
getLastUsedCameraId(): string | null;
|
||||
setHasPermission(hasPermission: boolean): void;
|
||||
setLastUsedCameraId(lastUsedCameraId: string): void;
|
||||
resetLastUsedCameraId(): void;
|
||||
reset(): void;
|
||||
private flush;
|
||||
}
|
||||
72
node_modules/html5-qrcode/src/storage.ts
generated
vendored
Normal file
72
node_modules/html5-qrcode/src/storage.ts
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Core storage related APIs.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
interface PersistedData {
|
||||
hasPermission: boolean;
|
||||
lastUsedCameraId: string | null;
|
||||
}
|
||||
|
||||
class PersistedDataFactory {
|
||||
static createDefault(): PersistedData {
|
||||
return {
|
||||
hasPermission: false,
|
||||
lastUsedCameraId: null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class PersistedDataManager {
|
||||
|
||||
private data: PersistedData = PersistedDataFactory.createDefault();
|
||||
private static LOCAL_STORAGE_KEY: string = "HTML5_QRCODE_DATA";
|
||||
|
||||
constructor() {
|
||||
let data = localStorage.getItem(PersistedDataManager.LOCAL_STORAGE_KEY);
|
||||
if (!data) {
|
||||
this.reset();
|
||||
} else {
|
||||
this.data = JSON.parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
public hasCameraPermissions(): boolean {
|
||||
return this.data.hasPermission;
|
||||
}
|
||||
|
||||
public getLastUsedCameraId(): string | null {
|
||||
return this.data.lastUsedCameraId;
|
||||
}
|
||||
|
||||
public setHasPermission(hasPermission: boolean) {
|
||||
this.data.hasPermission = hasPermission;
|
||||
this.flush();
|
||||
}
|
||||
|
||||
public setLastUsedCameraId(lastUsedCameraId: string) {
|
||||
this.data.lastUsedCameraId = lastUsedCameraId;
|
||||
this.flush();
|
||||
}
|
||||
|
||||
public resetLastUsedCameraId() {
|
||||
this.data.lastUsedCameraId = null;
|
||||
this.flush();
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.data = PersistedDataFactory.createDefault();
|
||||
this.flush();
|
||||
}
|
||||
|
||||
private flush(): void {
|
||||
localStorage.setItem(
|
||||
PersistedDataManager.LOCAL_STORAGE_KEY,
|
||||
JSON.stringify(this.data));
|
||||
}
|
||||
}
|
||||
45
node_modules/html5-qrcode/src/strings.d.ts
generated
vendored
Normal file
45
node_modules/html5-qrcode/src/strings.d.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
export declare class Html5QrcodeStrings {
|
||||
static codeParseError(exception: any): string;
|
||||
static errorGettingUserMedia(error: any): string;
|
||||
static onlyDeviceSupportedError(): string;
|
||||
static cameraStreamingNotSupported(): string;
|
||||
static unableToQuerySupportedDevices(): string;
|
||||
static insecureContextCameraQueryError(): string;
|
||||
static scannerPaused(): string;
|
||||
}
|
||||
export declare class Html5QrcodeScannerStrings {
|
||||
static scanningStatus(): string;
|
||||
static idleStatus(): string;
|
||||
static errorStatus(): string;
|
||||
static permissionStatus(): string;
|
||||
static noCameraFoundErrorStatus(): string;
|
||||
static lastMatch(decodedText: string): string;
|
||||
static codeScannerTitle(): string;
|
||||
static cameraPermissionTitle(): string;
|
||||
static cameraPermissionRequesting(): string;
|
||||
static noCameraFound(): string;
|
||||
static scanButtonStopScanningText(): string;
|
||||
static scanButtonStartScanningText(): string;
|
||||
static torchOnButton(): string;
|
||||
static torchOffButton(): string;
|
||||
static torchOnFailedMessage(): string;
|
||||
static torchOffFailedMessage(): string;
|
||||
static scanButtonScanningStarting(): string;
|
||||
static textIfCameraScanSelected(): string;
|
||||
static textIfFileScanSelected(): string;
|
||||
static selectCamera(): string;
|
||||
static fileSelectionChooseImage(): string;
|
||||
static fileSelectionChooseAnother(): string;
|
||||
static fileSelectionNoImageSelected(): string;
|
||||
static anonymousCameraPrefix(): string;
|
||||
static dragAndDropMessage(): string;
|
||||
static dragAndDropMessageOnlyImages(): string;
|
||||
static zoom(): string;
|
||||
static loadingImage(): string;
|
||||
static cameraScanAltText(): string;
|
||||
static fileScanAltText(): string;
|
||||
}
|
||||
export declare class LibraryInfoStrings {
|
||||
static poweredBy(): string;
|
||||
static reportIssues(): string;
|
||||
}
|
||||
200
node_modules/html5-qrcode/src/strings.ts
generated
vendored
Normal file
200
node_modules/html5-qrcode/src/strings.ts
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Strings used by {@class Html5Qrcode} & {@class Html5QrcodeScanner}
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
|
||||
/**
|
||||
* Strings used in {@class Html5Qrcode}.
|
||||
*
|
||||
* TODO(mebjas): Support internalization.
|
||||
*/
|
||||
export class Html5QrcodeStrings {
|
||||
|
||||
public static codeParseError(exception: any): string {
|
||||
return `QR code parse error, error = ${exception}`;
|
||||
}
|
||||
|
||||
public static errorGettingUserMedia(error: any): string {
|
||||
return `Error getting userMedia, error = ${error}`;
|
||||
}
|
||||
|
||||
public static onlyDeviceSupportedError(): string {
|
||||
return "The device doesn't support navigator.mediaDevices , only "
|
||||
+ "supported cameraIdOrConfig in this case is deviceId parameter "
|
||||
+ "(string).";
|
||||
}
|
||||
|
||||
public static cameraStreamingNotSupported(): string {
|
||||
return "Camera streaming not supported by the browser.";
|
||||
}
|
||||
|
||||
public static unableToQuerySupportedDevices(): string {
|
||||
return "Unable to query supported devices, unknown error.";
|
||||
}
|
||||
|
||||
public static insecureContextCameraQueryError(): string {
|
||||
return "Camera access is only supported in secure context like https "
|
||||
+ "or localhost.";
|
||||
}
|
||||
|
||||
public static scannerPaused(): string {
|
||||
return "Scanner paused";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strings used in {@class Html5QrcodeScanner}.
|
||||
*
|
||||
* TODO(mebjas): Support internalization.
|
||||
*/
|
||||
export class Html5QrcodeScannerStrings {
|
||||
|
||||
public static scanningStatus(): string {
|
||||
return "Scanning";
|
||||
}
|
||||
|
||||
public static idleStatus(): string {
|
||||
return "Idle";
|
||||
}
|
||||
|
||||
public static errorStatus(): string {
|
||||
return "Error";
|
||||
}
|
||||
|
||||
public static permissionStatus(): string {
|
||||
return "Permission";
|
||||
}
|
||||
|
||||
public static noCameraFoundErrorStatus(): string {
|
||||
return "No Cameras";
|
||||
}
|
||||
|
||||
public static lastMatch(decodedText: string): string {
|
||||
return `Last Match: ${decodedText}`;
|
||||
}
|
||||
|
||||
public static codeScannerTitle(): string {
|
||||
return "Code Scanner";
|
||||
}
|
||||
|
||||
public static cameraPermissionTitle(): string {
|
||||
return "Request Camera Permissions";
|
||||
}
|
||||
|
||||
public static cameraPermissionRequesting(): string {
|
||||
return "Requesting camera permissions...";
|
||||
}
|
||||
|
||||
public static noCameraFound(): string {
|
||||
return "No camera found";
|
||||
}
|
||||
|
||||
public static scanButtonStopScanningText(): string {
|
||||
return "Stop Scanning";
|
||||
}
|
||||
|
||||
public static scanButtonStartScanningText(): string {
|
||||
return "Start Scanning";
|
||||
}
|
||||
|
||||
public static torchOnButton(): string {
|
||||
return "Switch On Torch";
|
||||
}
|
||||
|
||||
public static torchOffButton(): string {
|
||||
return "Switch Off Torch";
|
||||
}
|
||||
|
||||
public static torchOnFailedMessage(): string {
|
||||
return "Failed to turn on torch";
|
||||
}
|
||||
|
||||
public static torchOffFailedMessage(): string {
|
||||
return "Failed to turn off torch";
|
||||
}
|
||||
|
||||
public static scanButtonScanningStarting(): string {
|
||||
return "Launching Camera...";
|
||||
}
|
||||
|
||||
/**
|
||||
* Text to show when camera scan is selected.
|
||||
*
|
||||
* This will be used to switch to file based scanning.
|
||||
*/
|
||||
public static textIfCameraScanSelected(): string {
|
||||
return "Scan an Image File";
|
||||
}
|
||||
|
||||
/**
|
||||
* Text to show when file based scan is selected.
|
||||
*
|
||||
* This will be used to switch to camera based scanning.
|
||||
*/
|
||||
public static textIfFileScanSelected(): string {
|
||||
return "Scan using camera directly";
|
||||
}
|
||||
|
||||
public static selectCamera(): string {
|
||||
return "Select Camera";
|
||||
}
|
||||
|
||||
public static fileSelectionChooseImage(): string {
|
||||
return "Choose Image";
|
||||
}
|
||||
|
||||
public static fileSelectionChooseAnother(): string {
|
||||
return "Choose Another";
|
||||
}
|
||||
|
||||
public static fileSelectionNoImageSelected(): string {
|
||||
return "No image choosen";
|
||||
}
|
||||
|
||||
/** Prefix to be given to anonymous cameras. */
|
||||
public static anonymousCameraPrefix(): string {
|
||||
return "Anonymous Camera";
|
||||
}
|
||||
|
||||
public static dragAndDropMessage(): string {
|
||||
return "Or drop an image to scan";
|
||||
}
|
||||
|
||||
public static dragAndDropMessageOnlyImages(): string {
|
||||
return "Or drop an image to scan (other files not supported)";
|
||||
}
|
||||
|
||||
/** Value for zoom. */
|
||||
public static zoom(): string {
|
||||
return "zoom";
|
||||
}
|
||||
|
||||
public static loadingImage(): string {
|
||||
return "Loading image...";
|
||||
}
|
||||
|
||||
public static cameraScanAltText(): string {
|
||||
return "Camera based scan";
|
||||
}
|
||||
|
||||
public static fileScanAltText(): string {
|
||||
return "Fule based scan";
|
||||
}
|
||||
}
|
||||
|
||||
/** Strings used in {@class LibraryInfoDiv} */
|
||||
export class LibraryInfoStrings {
|
||||
|
||||
public static poweredBy(): string {
|
||||
return "Powered by ";
|
||||
}
|
||||
|
||||
public static reportIssues(): string {
|
||||
return "Report issues";
|
||||
}
|
||||
}
|
||||
6
node_modules/html5-qrcode/src/ui.d.ts
generated
vendored
Normal file
6
node_modules/html5-qrcode/src/ui.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
export declare class LibraryInfoContainer {
|
||||
private infoDiv;
|
||||
private infoIcon;
|
||||
constructor();
|
||||
renderInto(parent: HTMLElement): void;
|
||||
}
|
||||
152
node_modules/html5-qrcode/src/ui.ts
generated
vendored
Normal file
152
node_modules/html5-qrcode/src/ui.ts
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* All structured UI classes.
|
||||
*
|
||||
* TODO(mebjas): Migrate all UI components to modular UI classes so they are
|
||||
* easy to improve.
|
||||
* TODO(mebjas): Add tests for all UI components.
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*/
|
||||
|
||||
import { ASSET_CLOSE_ICON_16PX, ASSET_INFO_ICON_16PX } from "./image-assets";
|
||||
|
||||
import { LibraryInfoStrings } from "./strings";
|
||||
|
||||
type OnClickListener0 = () => void;
|
||||
|
||||
//#region Info Icon + Div
|
||||
|
||||
class LibraryInfoDiv {
|
||||
private infoDiv: HTMLDivElement;
|
||||
|
||||
constructor() {
|
||||
this.infoDiv = document.createElement("div");
|
||||
}
|
||||
|
||||
public renderInto(parent: HTMLElement) {
|
||||
this.infoDiv.style.position = "absolute";
|
||||
this.infoDiv.style.top = "10px";
|
||||
this.infoDiv.style.right = "10px";
|
||||
this.infoDiv.style.zIndex = "2";
|
||||
this.infoDiv.style.display = "none";
|
||||
this.infoDiv.style.padding = "5pt";
|
||||
this.infoDiv.style.border = "1px solid #171717";
|
||||
this.infoDiv.style.fontSize = "10pt";
|
||||
this.infoDiv.style.background = "rgb(0 0 0 / 69%)";
|
||||
this.infoDiv.style.borderRadius = "5px";
|
||||
this.infoDiv.style.textAlign = "center";
|
||||
this.infoDiv.style.fontWeight = "400";
|
||||
this.infoDiv.style.color = "white";
|
||||
|
||||
this.infoDiv.innerText = LibraryInfoStrings.poweredBy();
|
||||
const projectLink = document.createElement("a");
|
||||
projectLink.innerText = "ScanApp";
|
||||
projectLink.href = "https://scanapp.org";
|
||||
projectLink.target = "new";
|
||||
projectLink.style.color = "white";
|
||||
this.infoDiv.appendChild(projectLink);
|
||||
|
||||
const breakElemFirst = document.createElement("br");
|
||||
const breakElemSecond = document.createElement("br");
|
||||
this.infoDiv.appendChild(breakElemFirst);
|
||||
this.infoDiv.appendChild(breakElemSecond);
|
||||
|
||||
const reportIssueLink = document.createElement("a");
|
||||
reportIssueLink.innerText = LibraryInfoStrings.reportIssues();
|
||||
reportIssueLink.href = "https://github.com/mebjas/html5-qrcode/issues";
|
||||
reportIssueLink.target = "new";
|
||||
reportIssueLink.style.color = "white";
|
||||
this.infoDiv.appendChild(reportIssueLink);
|
||||
|
||||
parent.appendChild(this.infoDiv);
|
||||
}
|
||||
|
||||
public show() {
|
||||
this.infoDiv.style.display = "block";
|
||||
}
|
||||
|
||||
public hide() {
|
||||
this.infoDiv.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
class LibraryInfoIcon {
|
||||
|
||||
private infoIcon: HTMLImageElement;
|
||||
private onTapIn: OnClickListener0;
|
||||
private onTapOut: OnClickListener0;
|
||||
private isShowingInfoIcon: boolean = true;
|
||||
|
||||
constructor(onTapIn: OnClickListener0, onTapOut: OnClickListener0) {
|
||||
this.onTapIn = onTapIn;
|
||||
this.onTapOut = onTapOut;
|
||||
|
||||
this.infoIcon = document.createElement("img");
|
||||
}
|
||||
|
||||
public renderInto(parent: HTMLElement) {
|
||||
this.infoIcon.alt = "Info icon";
|
||||
this.infoIcon.src = ASSET_INFO_ICON_16PX;
|
||||
this.infoIcon.style.position = "absolute";
|
||||
this.infoIcon.style.top = "4px";
|
||||
this.infoIcon.style.right = "4px";
|
||||
this.infoIcon.style.opacity = "0.6";
|
||||
this.infoIcon.style.cursor = "pointer";
|
||||
this.infoIcon.style.zIndex = "2";
|
||||
this.infoIcon.style.width = "16px";
|
||||
this.infoIcon.style.height = "16px";
|
||||
|
||||
this.infoIcon.onmouseover = (_) => this.onHoverIn();
|
||||
this.infoIcon.onmouseout = (_) => this.onHoverOut();
|
||||
this.infoIcon.onclick = (_) => this.onClick();
|
||||
|
||||
parent.appendChild(this.infoIcon);
|
||||
}
|
||||
|
||||
private onHoverIn() {
|
||||
if (this.isShowingInfoIcon) {
|
||||
this.infoIcon.style.opacity = "1";
|
||||
}
|
||||
}
|
||||
|
||||
private onHoverOut() {
|
||||
if (this.isShowingInfoIcon) {
|
||||
this.infoIcon.style.opacity = "0.6";
|
||||
}
|
||||
}
|
||||
|
||||
private onClick() {
|
||||
if (this.isShowingInfoIcon) {
|
||||
this.isShowingInfoIcon = false;
|
||||
this.onTapIn();
|
||||
this.infoIcon.src = ASSET_CLOSE_ICON_16PX;
|
||||
this.infoIcon.style.opacity = "1";
|
||||
} else {
|
||||
this.isShowingInfoIcon = true;
|
||||
this.onTapOut();
|
||||
this.infoIcon.src = ASSET_INFO_ICON_16PX;
|
||||
this.infoIcon.style.opacity = "0.6";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class LibraryInfoContainer {
|
||||
|
||||
private infoDiv: LibraryInfoDiv;
|
||||
private infoIcon: LibraryInfoIcon;
|
||||
|
||||
constructor() {
|
||||
this.infoDiv = new LibraryInfoDiv();
|
||||
this.infoIcon = new LibraryInfoIcon(() => {
|
||||
this.infoDiv.show();
|
||||
}, () => {
|
||||
this.infoDiv.hide();
|
||||
});
|
||||
}
|
||||
|
||||
public renderInto(parent: HTMLElement) {
|
||||
this.infoDiv.renderInto(parent);
|
||||
this.infoIcon.renderInto(parent);
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
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;
|
||||
}
|
||||
}
|
||||
4
node_modules/html5-qrcode/src/utils.d.ts
generated
vendored
Normal file
4
node_modules/html5-qrcode/src/utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Logger } from "./core";
|
||||
export declare class VideoConstraintsUtil {
|
||||
static isMediaStreamConstraintsValid(videoConstraints: MediaTrackConstraints, logger: Logger): boolean;
|
||||
}
|
||||
53
node_modules/html5-qrcode/src/utils.ts
generated
vendored
Normal file
53
node_modules/html5-qrcode/src/utils.ts
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* Utils used by {@class Html5Qrcode} & {@class Html5QrcodeScanner}
|
||||
*
|
||||
* @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 { Logger } from "./core";
|
||||
|
||||
/**
|
||||
* Utils around {@interface MediaTrackConstraints} for video.
|
||||
*/
|
||||
export class VideoConstraintsUtil {
|
||||
public static isMediaStreamConstraintsValid(
|
||||
videoConstraints: MediaTrackConstraints,
|
||||
logger: Logger): boolean {
|
||||
if (typeof videoConstraints !== "object") {
|
||||
const typeofVideoConstraints = typeof videoConstraints;
|
||||
logger.logError(
|
||||
"videoConstraints should be of type object, the "
|
||||
+ `object passed is of type ${typeofVideoConstraints}.`,
|
||||
/* experimental= */ true);
|
||||
return false;
|
||||
}
|
||||
// TODO(mebjas): Make this validity check more sophisticuated
|
||||
// Following keys are audio controls, audio controls are not supported.
|
||||
const bannedKeys = [
|
||||
"autoGainControl",
|
||||
"channelCount",
|
||||
"echoCancellation",
|
||||
"latency",
|
||||
"noiseSuppression",
|
||||
"sampleRate",
|
||||
"sampleSize",
|
||||
"volume"
|
||||
];
|
||||
const bannedkeysSet = new Set(bannedKeys);
|
||||
const keysInVideoConstraints = Object.keys(videoConstraints);
|
||||
for (const key of keysInVideoConstraints) {
|
||||
if (bannedkeysSet.has(key)) {
|
||||
logger.logError(
|
||||
`${key} is not supported videoConstaints.`,
|
||||
/* experimental= */ true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
15
node_modules/html5-qrcode/src/zxing-html5-qrcode-decoder.d.ts
generated
vendored
Normal file
15
node_modules/html5-qrcode/src/zxing-html5-qrcode-decoder.d.ts
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { QrcodeResult, Html5QrcodeSupportedFormats, Logger, QrcodeDecoderAsync } from "./core";
|
||||
export declare class ZXingHtml5QrcodeDecoder implements QrcodeDecoderAsync {
|
||||
private readonly formatMap;
|
||||
private readonly reverseFormatMap;
|
||||
private hints;
|
||||
private verbose;
|
||||
private logger;
|
||||
constructor(requestedFormats: Array<Html5QrcodeSupportedFormats>, verbose: boolean, logger: Logger);
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult>;
|
||||
private decode;
|
||||
private createReverseFormatMap;
|
||||
private toHtml5QrcodeSupportedFormats;
|
||||
private createZXingFormats;
|
||||
private createDebugData;
|
||||
}
|
||||
155
node_modules/html5-qrcode/src/zxing-html5-qrcode-decoder.ts
generated
vendored
Normal file
155
node_modules/html5-qrcode/src/zxing-html5-qrcode-decoder.ts
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @fileoverview
|
||||
* {@interface QrcodeDecoder} wrapper around ZXing library.
|
||||
*
|
||||
* @author mebjas <minhazav@gmail.com>
|
||||
*
|
||||
* ZXing library forked from https://github.com/zxing-js/library.
|
||||
*
|
||||
* The word "QR Code" is registered trademark of DENSO WAVE INCORPORATED
|
||||
* http://www.denso-wave.com/qrcode/faqpatent-e.html
|
||||
*/
|
||||
|
||||
import * as ZXing from "../third_party/zxing-js.umd";
|
||||
|
||||
import {
|
||||
QrcodeResult,
|
||||
QrcodeResultDebugData,
|
||||
QrcodeResultFormat,
|
||||
Html5QrcodeSupportedFormats,
|
||||
Logger,
|
||||
QrcodeDecoderAsync
|
||||
} from "./core";
|
||||
|
||||
/**
|
||||
* ZXing based Code decoder.
|
||||
*/
|
||||
export class ZXingHtml5QrcodeDecoder implements QrcodeDecoderAsync {
|
||||
|
||||
private readonly formatMap: Map<Html5QrcodeSupportedFormats, any>
|
||||
= new Map([
|
||||
[Html5QrcodeSupportedFormats.QR_CODE, ZXing.BarcodeFormat.QR_CODE ],
|
||||
[Html5QrcodeSupportedFormats.AZTEC, ZXing.BarcodeFormat.AZTEC ],
|
||||
[Html5QrcodeSupportedFormats.CODABAR, ZXing.BarcodeFormat.CODABAR ],
|
||||
[Html5QrcodeSupportedFormats.CODE_39, ZXing.BarcodeFormat.CODE_39 ],
|
||||
[Html5QrcodeSupportedFormats.CODE_93, ZXing.BarcodeFormat.CODE_93 ],
|
||||
[
|
||||
Html5QrcodeSupportedFormats.CODE_128,
|
||||
ZXing.BarcodeFormat.CODE_128 ],
|
||||
[
|
||||
Html5QrcodeSupportedFormats.DATA_MATRIX,
|
||||
ZXing.BarcodeFormat.DATA_MATRIX ],
|
||||
[
|
||||
Html5QrcodeSupportedFormats.MAXICODE,
|
||||
ZXing.BarcodeFormat.MAXICODE ],
|
||||
[Html5QrcodeSupportedFormats.ITF, ZXing.BarcodeFormat.ITF ],
|
||||
[Html5QrcodeSupportedFormats.EAN_13, ZXing.BarcodeFormat.EAN_13 ],
|
||||
[Html5QrcodeSupportedFormats.EAN_8, ZXing.BarcodeFormat.EAN_8 ],
|
||||
[Html5QrcodeSupportedFormats.PDF_417, ZXing.BarcodeFormat.PDF_417 ],
|
||||
[Html5QrcodeSupportedFormats.RSS_14, ZXing.BarcodeFormat.RSS_14 ],
|
||||
[
|
||||
Html5QrcodeSupportedFormats.RSS_EXPANDED,
|
||||
ZXing.BarcodeFormat.RSS_EXPANDED ],
|
||||
[Html5QrcodeSupportedFormats.UPC_A, ZXing.BarcodeFormat.UPC_A ],
|
||||
[Html5QrcodeSupportedFormats.UPC_E, ZXing.BarcodeFormat.UPC_E ],
|
||||
[
|
||||
Html5QrcodeSupportedFormats.UPC_EAN_EXTENSION,
|
||||
ZXing.BarcodeFormat.UPC_EAN_EXTENSION ]
|
||||
]);
|
||||
private readonly reverseFormatMap: Map<any, Html5QrcodeSupportedFormats>
|
||||
= this.createReverseFormatMap();
|
||||
|
||||
private hints: Map<any, any>;
|
||||
private verbose: boolean;
|
||||
private logger: Logger;
|
||||
|
||||
public constructor(
|
||||
requestedFormats: Array<Html5QrcodeSupportedFormats>,
|
||||
verbose: boolean,
|
||||
logger: Logger) {
|
||||
if (!ZXing) {
|
||||
throw "Use html5qrcode.min.js without edit, ZXing not found.";
|
||||
}
|
||||
this.verbose = verbose;
|
||||
this.logger = logger;
|
||||
|
||||
const formats = this.createZXingFormats(requestedFormats);
|
||||
const hints = new Map();
|
||||
hints.set(ZXing.DecodeHintType.POSSIBLE_FORMATS, formats);
|
||||
// TODO(minhazav): Make this configurable by developers.
|
||||
hints.set(ZXing.DecodeHintType.TRY_HARDER, false);
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
|
||||
decodeAsync(canvas: HTMLCanvasElement): Promise<QrcodeResult> {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
resolve(this.decode(canvas));
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private decode(canvas: HTMLCanvasElement): QrcodeResult {
|
||||
// Note: Earlier we used to instantiate the zxingDecoder once as state
|
||||
// of this class and use it for each scans. There seems to be some
|
||||
// stateful bug in ZXing library around RSS_14 likely due to
|
||||
// https://github.com/zxing-js/library/issues/211.
|
||||
// Recreating a new instance per scan doesn't lead to performance issues
|
||||
// and temporarily mitigates this issue.
|
||||
// TODO(mebjas): Properly fix this issue in ZXing library.
|
||||
const zxingDecoder = new ZXing.MultiFormatReader(
|
||||
this.verbose, this.hints);
|
||||
const luminanceSource
|
||||
= new ZXing.HTMLCanvasElementLuminanceSource(canvas);
|
||||
const binaryBitmap
|
||||
= new ZXing.BinaryBitmap(
|
||||
new ZXing.HybridBinarizer(luminanceSource));
|
||||
let result = zxingDecoder.decode(binaryBitmap);
|
||||
return {
|
||||
text: result.text,
|
||||
format: QrcodeResultFormat.create(
|
||||
this.toHtml5QrcodeSupportedFormats(result.format)),
|
||||
debugData: this.createDebugData()
|
||||
};
|
||||
}
|
||||
|
||||
private createReverseFormatMap(): Map<any, Html5QrcodeSupportedFormats> {
|
||||
let result = new Map();
|
||||
this.formatMap.forEach(
|
||||
(value: any, key: Html5QrcodeSupportedFormats, _) => {
|
||||
result.set(value, key);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private toHtml5QrcodeSupportedFormats(zxingFormat: any)
|
||||
: Html5QrcodeSupportedFormats {
|
||||
if (!this.reverseFormatMap.has(zxingFormat)) {
|
||||
throw `reverseFormatMap doesn't have ${zxingFormat}`;
|
||||
}
|
||||
return this.reverseFormatMap.get(zxingFormat)!;
|
||||
}
|
||||
|
||||
private createZXingFormats(
|
||||
requestedFormats: Array<Html5QrcodeSupportedFormats>):
|
||||
Array<any> {
|
||||
let zxingFormats = [];
|
||||
for (const requestedFormat of requestedFormats) {
|
||||
if (this.formatMap.has(requestedFormat)) {
|
||||
zxingFormats.push(
|
||||
this.formatMap.get(requestedFormat));
|
||||
} else {
|
||||
this.logger.logError(`${requestedFormat} is not supported by`
|
||||
+ "ZXingHtml5QrcodeShim");
|
||||
}
|
||||
}
|
||||
return zxingFormats;
|
||||
}
|
||||
|
||||
private createDebugData(): QrcodeResultDebugData {
|
||||
return { decoderName: "zxing-js" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user