| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- ;(function( $, window, document, undefined ) {
- "use strict";
- // cross browser request animation frame
- if ( !window.requestAnimationFrame ) {
- window.requestAnimationFrame = ( function() {
- return window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element ) {
- window.setTimeout( callback, 1000 / 60 );
- };
- } )();
- }
- var qrr, // our qrcode reader singletone instance
- QRCodeReader = function() {};
- $.qrCodeReader = {
- jsQRpath: "../libs/qrcode-reader/js/jsQR/jsQR.min.js",
- beepPath: "../libs/qrcode-reader/audio/beep.mp3",
- instance: null,
- defaults: {
- // single read or multiple readings/
- multiple: false,
- // only triggers for QRCodes matching the regexp
- qrcodeRegexp: /./,
- // play "Beep!" sound when reading qrcode successfully
- audioFeedback: true,
- // in case of multiple readings, after a successful reading,
- // wait for repeatTimeout milliseconds before trying for the next lookup.
- // Set to 0 to disable automatic re-tries: in such case user will have to
- // click on the webcam canvas to trigger a new reading tentative
- repeatTimeout: 1500,
- // target input element to fill in with the readings in case of successful reading
- // (newline separated in case of multiple readings).
- // Such element can be specified as jQuery object or as string identifier, e.g. "#target-input"
- target: null,
- // in case of multiple readings, skip duplicate readings
- skipDuplicates: true,
- // color of the lines highlighting the QRCode in the image when found
- lineColor: "#FF3B58",
- // In case of multiple readings, function to call when pressing the OK button (or Enter),
- // in such case read QRCodes are passed as an array.
- // In case of single reading, call immediately after the successful reading
- // (in the latter case the QRCode is passed as a single string value)
- callback: function(code) {}
- }
- };
- QRCodeReader.prototype = {
- constructor: QRCodeReader,
- init: function () {
- // build the HTML
- qrr.buildHTML();
- qrr.scriptLoaded = false;
- qrr.isOpen = false;
- // load the script performing the actual QRCode reading
- $.getScript( $.qrCodeReader.jsQRpath, function( data, textStatus, jqxhr ) {
- if ( jqxhr.status == 200) {
- qrr.scriptLoaded = true;
- } else {
- console.error("Error loading QRCode parser script");
- };
- });
- },
- // build the HTML interface of the widget
- buildHTML: function() {
- qrr.bgOverlay = $('<div id="qrr-overlay"></div>');
- qrr.container = $('<div id="qrr-container"></div>');
-
- qrr.closeBtn = $('<button type="button" class="fadeIn third" id="qrr-close">ANNULER</button>')
- qrr.closeBtn.appendTo(qrr.container);
- qrr.okBtn = $('<a id="qrr-ok">OK</a>');
-
- qrr.loadingMessage = $('<div id="qrr-loading-message">🎥 Unable to access video stream (please make sure you have a webcam enabled)</div>');
- qrr.canvas = $('<canvas id="qrr-canvas" class="hidden"></canvas>');
- qrr.audio = $('<audio hidden id="qrr-beep" src="' + $.qrCodeReader.beepPath + '" type="audio/mp3"></audio>');
-
- qrr.outputDiv = $('<div id="qrr-output"></div>');
- qrr.outputNoData = $('<div id="qrr-nodata">Aucun QRCode détecté</div>');
- qrr.outputData = $('<div id="qrr-output-data"></div>');
-
- qrr.outputNoData.appendTo(qrr.outputDiv);
- qrr.outputData.appendTo(qrr.outputDiv);
-
- qrr.loadingMessage.appendTo(qrr.container);
- qrr.canvas.appendTo(qrr.container);
- qrr.outputDiv.appendTo(qrr.container);
- qrr.audio.appendTo(qrr.container);
- qrr.okBtn.appendTo(qrr.container);
-
- qrr.bgOverlay.appendTo(document.body);
- qrr.bgOverlay.on("click", qrr.close);
- qrr.closeBtn.on("click", qrr.close);
-
- qrr.container.appendTo(document.body);
- qrr.video = document.createElement("video");
- },
- // draw a line
- drawLine: function(begin, end, color) {
- var canvas = qrr.canvas[0].getContext("2d");
- canvas.beginPath();
- canvas.moveTo(begin.x, begin.y);
- canvas.lineTo(end.x, end.y);
- canvas.lineWidth = 4;
- canvas.strokeStyle = color;
- canvas.stroke();
- },
- // draw a rectangle around a matched QRCode image
- drawBox: function(location, color) {
- qrr.drawLine(location.topLeftCorner, location.topRightCorner, color);
- qrr.drawLine(location.topRightCorner, location.bottomRightCorner, color);
- qrr.drawLine(location.bottomRightCorner, location.bottomLeftCorner, color);
- qrr.drawLine(location.bottomLeftCorner, location.topLeftCorner, color);
- },
- // merge the options with the element data attributes and then save them
- setOptions: function (element, options) {
- // data-attributes options
- var dataOptions = {
- multiple: $(element).data("qrr-multiple"),
- qrcodeRegexp: new RegExp($(element).data("qrr-qrcode-regexp")),
- audioFeedback: $(element).data("qrr-audio-feedback"),
- repeatTimeout: $(element).data("qrr-repeat-timeout"),
- target: $(element).data("qrr-target"),
- skipDuplicates: $(element).data("qrr-skip-duplicates"),
- lineColor: $(element).data("qrr-line-color"),
- callback: $(element).data("qrr-callback")
- }
- // argument options override data-attributes options
- options = $.extend( {}, dataOptions, options);
-
- // extend defaults with options
- var settings = $.extend( {}, $.qrCodeReader.defaults, options);
- // save options in the data attributes
- $(element).data("qrr", settings);
- },
- // get the options from the element the reader is attached
- getOptions: function (element) {
- qrr.settings = $(element).data("qrr");
- },
- // open the QRCode reader interface
- open: function () {
- // prevent multiple opening
- if (qrr.isOpen) return;
-
- // get options for the current called element
- qrr.getOptions(this);
- // show the widget
- qrr.bgOverlay.show();
- qrr.container.slideDown();
- // initialize codes container
- qrr.codes = [];
- // initialize interface
- qrr.outputNoData.show();
- qrr.outputData.empty();
- qrr.outputData.hide();
- if (qrr.settings.multiple) {
- qrr.okBtn.show();
- qrr.okBtn.off("click").on("click", qrr.doneReading);
- } else {
- qrr.okBtn.hide();
- }
- // close on ESC, doneReading on Enter if multiple
- $(document).on('keyup.qrCodeReader', function(e) {
- if(e.keyCode === 27) {
- qrr.close();
- }
- if (qrr.settings.multiple && e.keyCode === 13) {
- qrr.doneReading();
- }
- });
- qrr.isOpen = true;
- if (qrr.scriptLoaded) {
- // start the business
- qrr.start();
- }
- },
- // get the camera, show video, start searching qrcode in the stream
- start: function() {
- // Use {facingMode: environment} to attempt to get the front camera on phones
- navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function(stream) {
- qrr.video.srcObject = stream;
- qrr.video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
- qrr.video.play();
- qrr.startReading();
- });
- },
- // start continuously searching qrcode in the video stream
- startReading: function() {
- qrr.requestID = window.requestAnimationFrame(qrr.read);
- },
- // done with reading QRcode
- doneReading: function() {
- var value = qrr.codes[0];
- // fill in the target element
- if (qrr.settings.target) {
- if (qrr.settings.multiple) {
- var value = qrr.codes.join("\n");
- }
- $(qrr.settings.target).val(value);
- }
- // call a callback
- if (qrr.settings.callback) {
- try {
- if (qrr.settings.multiple) {
- qrr.settings.callback(qrr.codes);
- } else {
- qrr.settings.callback(value);
- }
- } catch(err) {
- console.error(err);
- }
- }
- // close the widget
- qrr.close();
- },
- // search for a QRCode
- read: function() {
- var codeRead = false;
- var canvas = qrr.canvas[0].getContext("2d");
-
- qrr.loadingMessage.text("⌛ Loading video...");
- qrr.canvas.off("click.qrCodeReader", qrr.startReading);
- if (qrr.video.readyState === qrr.video.HAVE_ENOUGH_DATA) {
- qrr.loadingMessage.hide();
- qrr.canvas.removeClass("hidden");
- qrr.canvas[0].height = qrr.video.videoHeight;
- qrr.canvas[0].width = qrr.video.videoWidth;
- canvas.drawImage(qrr.video, 0, 0, qrr.canvas[0].width, qrr.canvas[0].height);
-
- var imageData = canvas.getImageData(0, 0, qrr.canvas[0].width, qrr.canvas[0].height);
-
- // this performs the actual QRCode reading
- var code = jsQR(imageData.data, imageData.width, imageData.height, {
- inversionAttempts: "dontInvert",
- });
- // a QRCode has been found
- if (code && qrr.settings.qrcodeRegexp.test(code.data)) {
- // draw lines around the matched QRCode
- qrr.drawBox(code.location, qrr.settings.lineColor);
- codeRead = true;
- qrr.codes.push(code.data);
- qrr.outputNoData.hide();
- qrr.outputData.show();
- // play audio if requested
- if (qrr.settings.audioFeedback) {
- qrr.audio[0].play();
- }
- // read multiple codes
- if (qrr.settings.multiple) {
- // avoid duplicates
- if(qrr.settings.skipDuplicates) {
- qrr.codes = $.unique(qrr.codes);
- }
- // show our reading
- $('<div class="qrr-input"></div>').text(code.data).appendTo(qrr.outputData);
- qrr.outputDiv[0].scrollTop = qrr.outputDiv[0].scrollHeight;
-
- // read again by clicking on the canvas
- qrr.canvas.on("click.qrCodeReader", qrr.startReading);
- // repeat reading after a timeout
- if (qrr.settings.repeatTimeout > 0) {
- setTimeout(qrr.startReading, qrr.settings.repeatTimeout);
- } else {
- qrr.loadingMessage.text("Click on the image to read the next QRCode");
- qrr.loadingMessage.show();
- }
- // single reading
- } else {
- qrr.doneReading();
- }
- }
- }
- if (!codeRead) {
- qrr.startReading();
- }
- },
- close: function() {
- // cancel the refresh function
- if (qrr.requestID) {
- window.cancelAnimationFrame(qrr.requestID);
- }
- // unbind keyboard
- $(document).off('keyup.qrCodeReader');
- // stop the video
- if (qrr.video.srcObject) {
- qrr.video.srcObject.getTracks()[0].stop();
- }
-
- // hide the GUI
- qrr.canvas.addClass("hidden");
- qrr.loadingMessage.show();
- qrr.bgOverlay.hide();
- qrr.container.hide();
- qrr.isOpen = false;
- }
- };
- $.fn.qrCodeReader = function ( options ) {
- // Instantiate the plugin only once (singletone) in the page:
- // when called again (or on a different element), we simply re-set the options
- // and display the QrCode reader interface with the right options.
- // Options are saved in the data attribute of the bound element.
-
- if(!$.qrCodeReader.instance) {
- qrr = new QRCodeReader();
- qrr.init();
- $.qrCodeReader.instance = qrr;
- }
- return this.each(function () {
- qrr.setOptions(this, options);
- $(this).off("click.qrCodeReader").on("click.qrCodeReader", qrr.open);
- });
-
- };
- }( jQuery, window, document ));
|