@digital-blueprint/checkin-app
Version:
[GitHub Repository](https://github.com/digital-blueprint/checkin-app) | [npmjs package](https://www.npmjs.com/package/@digital-blueprint/checkin-app) | [Unpkg CDN](https://unpkg.com/browse/@digital-blueprint/checkin-app/) | [Checkin Bundle](https://github
34 lines (33 loc) • 16.6 kB
JavaScript
/*!
* License: LGPL-2.1-or-later
* Dependencies:
*
* @webcomponents/scoped-custom-element-registry: 0.0.9 (BSD-3-Clause)
* @dbp-toolkit/app-shell: 0.3.4 (LGPL-2.1-or-later)
* @dbp-toolkit/language-select: 0.3.2 (LGPL-2.1-or-later)
* @dbp-toolkit/common: 0.3.5 (LGPL-2.1-or-later)
* @dbp-toolkit/auth: 0.3.2 (LGPL-2.1-or-later)
* event-target-shim: 6.0.2 (MIT)
* @dbp-toolkit/notification: 0.3.2 (LGPL-2.1-or-later)
* @dbp-toolkit/theme-switcher: 0.0.6 (LGPL-2.1-or-later)
* path-to-regexp: 6.2.0 (MIT)
* universal-router: 9.1.0 (MIT)
* generateUrls: 9.1.0 (MIT)
* @dbp-toolkit/matomo: 0.2.7 (LGPL-2.1-or-later)
* @dbp-toolkit/qr-code-scanner: 0.3.3 (LGPL-2.1-or-later)
* async-mutex: 0.4.0 (MIT)
* select2: 4.0.13 (MIT)
* @lit/reactive-element: 1.6.1 (BSD-3-Clause)
* lit-element: 3.3.1 (BSD-3-Clause)
* i18next: 23.7.13 (MIT)
* lit-html: 2.8.0 (BSD-3-Clause)
* @open-wc/dedupe-mixin: 1.4.0 (MIT)
* @open-wc/scoped-elements: 2.2.4 (MIT)
* base64-js: 1.5.1 (MIT)
* js-sha256: 0.9.0 (MIT)
* keycloak-js: 21.0.2 (Apache-2.0)
* jquery: 3.6.0 (MIT)
* qr-scanner: 1.4.1 (MIT)
*/
class e{constructor(t,a,i,s,n){this._legacyCanvasSize=e.DEFAULT_CANVAS_SIZE,this._preferredCamera="environment",this._maxScansPerSecond=25,this._lastScanTimestamp=-1,this._destroyed=this._flashOn=this._paused=this._active=!1,this.$video=t,this.$canvas=document.createElement("canvas"),i&&"object"==typeof i?this._onDecode=a:(i||s||n?console.warn("You're using a deprecated version of the QrScanner constructor which will be removed in the future"):console.warn("Note that the type of the scan result passed to onDecode will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true."),this._legacyOnDecode=a),a="object"==typeof i?i:{},this._onDecodeError=a.onDecodeError||("function"==typeof i?i:this._onDecodeError),this._calculateScanRegion=a.calculateScanRegion||("function"==typeof s?s:this._calculateScanRegion),this._preferredCamera=a.preferredCamera||n||this._preferredCamera,this._legacyCanvasSize="number"==typeof i?i:"number"==typeof s?s:this._legacyCanvasSize,this._maxScansPerSecond=a.maxScansPerSecond||this._maxScansPerSecond,this._onPlay=this._onPlay.bind(this),this._onLoadedMetaData=this._onLoadedMetaData.bind(this),this._onVisibilityChange=this._onVisibilityChange.bind(this),this._updateOverlay=this._updateOverlay.bind(this),t.disablePictureInPicture=!0,t.playsInline=!0,t.muted=!0;let r=!1;if(t.hidden&&(t.hidden=!1,r=!0),document.body.contains(t)||(document.body.appendChild(t),r=!0),i=t.parentElement,a.highlightScanRegion||a.highlightCodeOutline){if(s=!!a.overlay,this.$overlay=a.overlay||document.createElement("div"),(n=this.$overlay.style).position="absolute",n.display="none",n.pointerEvents="none",this.$overlay.classList.add("scan-region-highlight"),!s&&a.highlightScanRegion){this.$overlay.innerHTML='<svg class="scan-region-highlight-svg" viewBox="0 0 238 238" preserveAspectRatio="none" style="position:absolute;width:100%;height:100%;left:0;top:0;fill:none;stroke:#e9b213;stroke-width:4;stroke-linecap:round;stroke-linejoin:round"><path d="M31 2H10a8 8 0 0 0-8 8v21M207 2h21a8 8 0 0 1 8 8v21m0 176v21a8 8 0 0 1-8 8h-21m-176 0H10a8 8 0 0 1-8-8v-21"/></svg>';try{this.$overlay.firstElementChild.animate({transform:["scale(.98)","scale(1.01)"]},{duration:400,iterations:1/0,direction:"alternate",easing:"ease-in-out"})}catch(e){}i.insertBefore(this.$overlay,this.$video.nextSibling)}a.highlightCodeOutline&&(this.$overlay.insertAdjacentHTML("beforeend",'<svg class="code-outline-highlight" preserveAspectRatio="none" style="display:none;width:100%;height:100%;fill:none;stroke:#e9b213;stroke-width:5;stroke-dasharray:25;stroke-linecap:round;stroke-linejoin:round"><polygon/></svg>'),this.$codeOutlineHighlight=this.$overlay.lastElementChild)}this._scanRegion=this._calculateScanRegion(t),requestAnimationFrame((()=>{let e=window.getComputedStyle(t);"none"===e.display&&(t.style.setProperty("display","block","important"),r=!0),"visible"!==e.visibility&&(t.style.setProperty("visibility","visible","important"),r=!0),r&&(console.warn("QrScanner has overwritten the video hiding style to avoid Safari stopping the playback."),t.style.opacity="0",t.style.width="0",t.style.height="0",this.$overlay&&this.$overlay.parentElement&&this.$overlay.parentElement.removeChild(this.$overlay),delete this.$overlay,delete this.$codeOutlineHighlight),this.$overlay&&this._updateOverlay()})),t.addEventListener("play",this._onPlay),t.addEventListener("loadedmetadata",this._onLoadedMetaData),document.addEventListener("visibilitychange",this._onVisibilityChange),window.addEventListener("resize",this._updateOverlay),this._qrEnginePromise=e.createQrEngine()}static set WORKER_PATH(e){console.warn("Setting QrScanner.WORKER_PATH is not required and not supported anymore. Have a look at the README for new setup instructions.")}static async hasCamera(){try{return!!(await e.listCameras(!1)).length}catch(e){return!1}}static async listCameras(t=!1){if(!navigator.mediaDevices)return[];let a,i=async function(){return(await navigator.mediaDevices.enumerateDevices()).filter((e=>"videoinput"===e.kind))};try{t&&(await i()).every((e=>!e.label))&&(a=await navigator.mediaDevices.getUserMedia({audio:!1,video:!0}))}catch(e){}try{return(await i()).map(((e,t)=>({id:e.deviceId,label:e.label||(0===t?"Default Camera":`Camera ${t+1}`)})))}finally{a&&(console.warn("Call listCameras after successfully starting a QR scanner to avoid creating a temporary video stream"),e._stopVideoStream(a))}}async hasFlash(){let t;try{if(this.$video.srcObject){if(!(this.$video.srcObject instanceof MediaStream))return!1;t=this.$video.srcObject}else t=(await this._getCameraStream()).stream;return"torch"in t.getVideoTracks()[0].getSettings()}catch(e){return!1}finally{t&&t!==this.$video.srcObject&&(console.warn("Call hasFlash after successfully starting the scanner to avoid creating a temporary video stream"),e._stopVideoStream(t))}}isFlashOn(){return this._flashOn}async toggleFlash(){this._flashOn?await this.turnFlashOff():await this.turnFlashOn()}async turnFlashOn(){if(!this._flashOn&&!this._destroyed&&(this._flashOn=!0,this._active&&!this._paused))try{if(!await this.hasFlash())throw"No flash available";await this.$video.srcObject.getVideoTracks()[0].applyConstraints({advanced:[{torch:!0}]})}catch(e){throw this._flashOn=!1,e}}async turnFlashOff(){this._flashOn&&(this._flashOn=!1,await this._restartVideoStream())}destroy(){this.$video.removeEventListener("loadedmetadata",this._onLoadedMetaData),this.$video.removeEventListener("play",this._onPlay),document.removeEventListener("visibilitychange",this._onVisibilityChange),window.removeEventListener("resize",this._updateOverlay),this._destroyed=!0,this._flashOn=!1,this.stop(),e._postWorkerMessage(this._qrEnginePromise,"close")}async start(){if(this._destroyed)throw Error("The QR scanner can not be started as it had been destroyed.");if((!this._active||this._paused)&&("https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https."),this._active=!0,!document.hidden))if(this._paused=!1,this.$video.srcObject)await this.$video.play();else try{let{stream:t,facingMode:a}=await this._getCameraStream();!this._active||this._paused?e._stopVideoStream(t):(this._setVideoMirror(a),this.$video.srcObject=t,await this.$video.play(),this._flashOn&&(this._flashOn=!1,this.turnFlashOn().catch((()=>{}))))}catch(e){if(!this._paused)throw this._active=!1,e}}stop(){this.pause(),this._active=!1}async pause(t=!1){if(this._paused=!0,!this._active)return!0;this.$video.pause(),this.$overlay&&(this.$overlay.style.display="none");let a=()=>{this.$video.srcObject instanceof MediaStream&&(e._stopVideoStream(this.$video.srcObject),this.$video.srcObject=null)};return t?(a(),!0):(await new Promise((e=>setTimeout(e,300))),!!this._paused&&(a(),!0))}async setCamera(e){e!==this._preferredCamera&&(this._preferredCamera=e,await this._restartVideoStream())}static async scanImage(t,a,i,s,n=!1,r=!1){let o,d=!1;a&&("scanRegion"in a||"qrEngine"in a||"canvas"in a||"disallowCanvasResizing"in a||"alsoTryWithoutScanRegion"in a||"returnDetailedScanResult"in a)?(o=a.scanRegion,i=a.qrEngine,s=a.canvas,n=a.disallowCanvasResizing||!1,r=a.alsoTryWithoutScanRegion||!1,d=!0):a||i||s||n||r?console.warn("You're using a deprecated api for scanImage which will be removed in the future."):console.warn("Note that the return type of scanImage will change in the future. To already switch to the new api today, you can pass returnDetailedScanResult: true."),a=!!i;try{let c,h,l;if([i,c]=await Promise.all([i||e.createQrEngine(),e._loadImage(t)]),[s,h]=e._drawToCanvas(c,o,s,n),i instanceof Worker){let t=i;a||e._postWorkerMessageSync(t,"inversionMode","both"),l=await new Promise(((a,i)=>{let n,r,d,c=-1;r=s=>{s.data.id===c&&(t.removeEventListener("message",r),t.removeEventListener("error",d),clearTimeout(n),null!==s.data.data?a({data:s.data.data,cornerPoints:e._convertPoints(s.data.cornerPoints,o)}):i(e.NO_QR_CODE_FOUND))},d=e=>{t.removeEventListener("message",r),t.removeEventListener("error",d),clearTimeout(n),i("Scanner error: "+(e?e.message||e:"Unknown Error"))},t.addEventListener("message",r),t.addEventListener("error",d),n=setTimeout((()=>d("timeout")),1e4);let l=h.getImageData(0,0,s.width,s.height);c=e._postWorkerMessageSync(t,"decode",l,[l.data.buffer])}))}else l=await Promise.race([new Promise(((e,t)=>window.setTimeout((()=>t("Scanner error: timeout")),1e4))),async function(){try{var[a]=await i.detect(s);if(!a)throw e.NO_QR_CODE_FOUND;return{data:a.rawValue,cornerPoints:e._convertPoints(a.cornerPoints,o)}}catch(i){if(a=i.message||i,/not implemented|service unavailable/.test(a))return e._disableBarcodeDetector=!0,e.scanImage(t,{scanRegion:o,canvas:s,disallowCanvasResizing:n,alsoTryWithoutScanRegion:r});throw`Scanner error: ${a}`}}()]);return d?l:l.data}catch(a){if(!o||!r)throw a;let c=await e.scanImage(t,{qrEngine:i,canvas:s,disallowCanvasResizing:n});return d?c:c.data}finally{a||e._postWorkerMessage(i,"close")}}setGrayscaleWeights(t,a,i,s=!0){e._postWorkerMessage(this._qrEnginePromise,"grayscaleWeights",{red:t,green:a,blue:i,useIntegerApproximation:s})}setInversionMode(t){e._postWorkerMessage(this._qrEnginePromise,"inversionMode",t)}static async createQrEngine(t){return t&&console.warn("Specifying a worker path is not required and not supported anymore."),!e._disableBarcodeDetector&&"BarcodeDetector"in window&&BarcodeDetector.getSupportedFormats&&(await BarcodeDetector.getSupportedFormats()).includes("qr_code")?new BarcodeDetector({formats:["qr_code"]}):import("./qr-scanner-worker.min.4uhhuwOH.es.js").then((e=>e.createWorker()))}_onPlay(){this._scanRegion=this._calculateScanRegion(this.$video),this._updateOverlay(),this.$overlay&&(this.$overlay.style.display=""),this._scanFrame()}_onLoadedMetaData(){this._scanRegion=this._calculateScanRegion(this.$video),this._updateOverlay()}_onVisibilityChange(){document.hidden?this.pause():this._active&&this.start()}_calculateScanRegion(e){let t=Math.round(2/3*Math.min(e.videoWidth,e.videoHeight));return{x:Math.round((e.videoWidth-t)/2),y:Math.round((e.videoHeight-t)/2),width:t,height:t,downScaledWidth:this._legacyCanvasSize,downScaledHeight:this._legacyCanvasSize}}_updateOverlay(){requestAnimationFrame((()=>{if(this.$overlay){var e=this.$video,t=e.videoWidth,a=e.videoHeight,i=e.offsetWidth,s=e.offsetHeight,n=e.offsetLeft,r=e.offsetTop,o=window.getComputedStyle(e),d=o.objectFit,c=t/a,h=i/s;switch(d){case"none":var l=t,g=a;break;case"fill":l=i,g=s;break;default:("cover"===d?c>h:c<h)?l=(g=s)*c:g=(l=i)/c,"scale-down"===d&&(l=Math.min(l,t),g=Math.min(g,a))}var[v,m]=o.objectPosition.split(" ").map(((e,t)=>{const a=parseFloat(e);return e.endsWith("%")?(t?s-g:i-l)*a/100:a}));o=this._scanRegion.width||t,h=this._scanRegion.height||a,d=this._scanRegion.x||0;var u=this._scanRegion.y||0;(c=this.$overlay.style).width=o/t*l+"px",c.height=h/a*g+"px",c.top=`${r+m+u/a*g}px`,a=/scaleX\(-1\)/.test(e.style.transform),c.left=`${n+(a?i-v-l:v)+(a?t-d-o:d)/t*l}px`,c.transform=e.style.transform}}))}static _convertPoints(e,t){if(!t)return e;let a=t.x||0,i=t.y||0,s=t.width&&t.downScaledWidth?t.width/t.downScaledWidth:1;t=t.height&&t.downScaledHeight?t.height/t.downScaledHeight:1;for(let n of e)n.x=n.x*s+a,n.y=n.y*t+i;return e}_scanFrame(){var t=this;!this._active||this.$video.paused||this.$video.ended||("requestVideoFrameCallback"in this.$video?this.$video.requestVideoFrameCallback.bind(this.$video):requestAnimationFrame)((async function(){if(!(1>=t.$video.readyState)){var a=Date.now()-t._lastScanTimestamp,i=1e3/t._maxScansPerSecond;a<i&&await new Promise((e=>setTimeout(e,i-a))),t._lastScanTimestamp=Date.now();try{var s=await e.scanImage(t.$video,{scanRegion:t._scanRegion,qrEngine:t._qrEnginePromise,canvas:t.$canvas})}catch(e){if(!t._active)return;t._onDecodeError(e)}!e._disableBarcodeDetector||await t._qrEnginePromise instanceof Worker||(t._qrEnginePromise=e.createQrEngine()),s?(t._onDecode?t._onDecode(s):t._legacyOnDecode&&t._legacyOnDecode(s.data),t.$codeOutlineHighlight&&(clearTimeout(t._codeOutlineHighlightRemovalTimeout),t._codeOutlineHighlightRemovalTimeout=void 0,t.$codeOutlineHighlight.setAttribute("viewBox",`${t._scanRegion.x||0} ${t._scanRegion.y||0} ${t._scanRegion.width||t.$video.videoWidth} ${t._scanRegion.height||t.$video.videoHeight}`),t.$codeOutlineHighlight.firstElementChild.setAttribute("points",s.cornerPoints.map((({x:e,y:t})=>`${e},${t}`)).join(" ")),t.$codeOutlineHighlight.style.display="")):t.$codeOutlineHighlight&&!t._codeOutlineHighlightRemovalTimeout&&(t._codeOutlineHighlightRemovalTimeout=setTimeout((()=>t.$codeOutlineHighlight.style.display="none"),100))}t._scanFrame()}))}_onDecodeError(t){t!==e.NO_QR_CODE_FOUND&&console.log(t)}async _getCameraStream(){if(!navigator.mediaDevices)throw"Camera not found.";let e=/^(environment|user)$/.test(this._preferredCamera)?"facingMode":"deviceId",t=[{width:{min:1024}},{width:{min:768}},{}],a=t.map((t=>Object.assign({},t,{[e]:{exact:this._preferredCamera}})));for(let e of[...a,...t])try{let t=await navigator.mediaDevices.getUserMedia({video:e,audio:!1});return{stream:t,facingMode:this._getFacingMode(t)||(e.facingMode?this._preferredCamera:"environment"===this._preferredCamera?"user":"environment")}}catch(e){}throw"Camera not found."}async _restartVideoStream(){let e=this._paused;await this.pause(!0)&&!e&&this._active&&await this.start()}static _stopVideoStream(e){for(let t of e.getTracks())t.stop(),e.removeTrack(t)}_setVideoMirror(e){this.$video.style.transform="scaleX("+("user"===e?-1:1)+")"}_getFacingMode(e){return(e=e.getVideoTracks()[0])?/rear|back|environment/i.test(e.label)?"environment":/front|user|face/i.test(e.label)?"user":null:null}static _drawToCanvas(e,t,a,i=!1){a=a||document.createElement("canvas");let s=t&&t.x?t.x:0,n=t&&t.y?t.y:0,r=t&&t.width?t.width:e.videoWidth||e.width,o=t&&t.height?t.height:e.videoHeight||e.height;return i||(i=t&&t.downScaledWidth?t.downScaledWidth:r,t=t&&t.downScaledHeight?t.downScaledHeight:o,a.width!==i&&(a.width=i),a.height!==t&&(a.height=t)),(t=a.getContext("2d",{alpha:!1})).imageSmoothingEnabled=!1,t.drawImage(e,s,n,r,o,0,0,a.width,a.height),[a,t]}static async _loadImage(t){if(t instanceof Image)return await e._awaitImageLoad(t),t;if(t instanceof HTMLVideoElement||t instanceof HTMLCanvasElement||t instanceof SVGImageElement||"OffscreenCanvas"in window&&t instanceof OffscreenCanvas||"ImageBitmap"in window&&t instanceof ImageBitmap)return t;if(!(t instanceof File||t instanceof Blob||t instanceof URL||"string"==typeof t))throw"Unsupported image type.";{let a=new Image;a.src=t instanceof File||t instanceof Blob?URL.createObjectURL(t):t.toString();try{return await e._awaitImageLoad(a),a}finally{(t instanceof File||t instanceof Blob)&&URL.revokeObjectURL(a.src)}}}static async _awaitImageLoad(e){e.complete&&0!==e.naturalWidth||await new Promise(((t,a)=>{let i=s=>{e.removeEventListener("load",i),e.removeEventListener("error",i),s instanceof ErrorEvent?a("Image load error"):t()};e.addEventListener("load",i),e.addEventListener("error",i)}))}static async _postWorkerMessage(t,a,i,s){return e._postWorkerMessageSync(await t,a,i,s)}static _postWorkerMessageSync(t,a,i,s){if(!(t instanceof Worker))return-1;let n=e._workerMessageId++;return t.postMessage({id:n,type:a,data:i},s),n}}e.DEFAULT_CANVAS_SIZE=400,e.NO_QR_CODE_FOUND="No QR code found",e._disableBarcodeDetector=!1,e._workerMessageId=0;export{e as default};
//# sourceMappingURL=qr-scanner.min.GO0xfeSl.es.js.map