add QR/Barcode scan
This commit is contained in:
@@ -1201,6 +1201,12 @@ $(function() {
|
||||
$("#sxModal").attr('data-for', 'member');
|
||||
e.preventDefault();
|
||||
getCardNo();
|
||||
|
||||
onScan.attachTo(document, {
|
||||
onScan: function(sCode) {
|
||||
setCardNo(sCode)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#sxModal .btn_cancel").on('click',function(){
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
//= require jquery-fileupload/basic
|
||||
//= require induties/induties.js
|
||||
//= require select2
|
||||
//= require onscan.js
|
||||
|
||||
$(document).ready(function() {
|
||||
$('.count-to').countTo();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
//= require BSBMaterial/turbolink_admin.js
|
||||
//= require BSBMaterial/demo.js
|
||||
//= require custom.js
|
||||
//= require onscan.js
|
||||
|
||||
/* Constant Varaibles */
|
||||
_CREDIT_PAYMENTS_ = "/ CREDIT PAYMENTS";
|
||||
|
||||
373
app/assets/javascripts/onscan.js
Normal file
373
app/assets/javascripts/onscan.js
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* onScan.js - scan-events for hardware barcodes scanners in javascript
|
||||
*/
|
||||
var onScan = {
|
||||
attachTo: function(oDomElement, oOptions) {
|
||||
if (oDomElement.scannerDetectionData != undefined) {
|
||||
throw new Error(
|
||||
"onScan.js is already initialized for DOM element " + oDomElement
|
||||
);
|
||||
}
|
||||
|
||||
var oDefaults = {
|
||||
onScan: function(sScanned, iQty) {}, // Callback after detection of a successfull scanning: function(){sScancode, iCount)}()
|
||||
onScanError: function(oDebug) {}, // Callback after detection of a unsuccessfull scanning (scanned string in parameter)
|
||||
onKeyProcess: function(sChar, oEvent) {}, // Callback after receiving and processing a char (scanned char in parameter)
|
||||
onKeyDetect: function(iKeyCode, oEvent) {}, // Callback after detecting a keypress (key char in parameter) - in contrast to onKeyProcess, this fires for non-character keys like tab, arrows, etc. too!
|
||||
onPaste: function(sPasted, oEvent) {}, // Callback after receiving a value on paste, no matter if it is a valid code or not
|
||||
keyCodeMapper: function(oEvent) {
|
||||
return String.fromCharCode(oEvent.which);
|
||||
}, // Custom function to decode a keypress event into a character. Must return decoded character or NULL if the given event should not be processed.
|
||||
onScanButtonLongPress: function() {}, // Callback after detection of a successfull scan while the scan button was pressed and held down
|
||||
scanButtonKeyCode: false, // Key code of the scanner hardware button (if the scanner button a acts as a key itself)
|
||||
scanButtonLongPressTime: 500, // How long (ms) the hardware button should be pressed, until a callback gets executed
|
||||
timeBeforeScanTest: 100, // Wait duration (ms) after keypress event to check if scanning is finished
|
||||
avgTimeByChar: 30, // Average time (ms) between 2 chars. Used to do difference between keyboard typing and scanning
|
||||
minLength: 6, // Minimum length for a scanning
|
||||
suffixKeyCodes: [9, 13], // Chars to remove and means end of scanning
|
||||
prefixKeyCodes: [], // Chars to remove and means start of scanning
|
||||
ignoreIfFocusOn: false, // do not handle scans if the currently focused element matches this selector or object
|
||||
stopPropagation: false, // Stop immediate propagation on keypress event
|
||||
preventDefault: false, // Prevent default action on keypress event
|
||||
reactToKeypress: true, // look for scan input in keyboard events
|
||||
reactToPaste: false, // look for scan input in paste events
|
||||
singleScanQty: 1 // Quantity of Items put out to onScan in a single scan
|
||||
};
|
||||
|
||||
oOptions = this._mergeOptions(oDefaults, oOptions);
|
||||
|
||||
// initializing options and variables on DomElement
|
||||
oDomElement.scannerDetectionData = {
|
||||
options: oOptions,
|
||||
vars: {
|
||||
firstCharTime: 0,
|
||||
lastCharTime: 0,
|
||||
stringWriting: "",
|
||||
callIsScanner: false,
|
||||
testTimer: false,
|
||||
longPressTimeStart: 0,
|
||||
longPressed: false
|
||||
}
|
||||
};
|
||||
|
||||
// initializing handlers (based on settings)
|
||||
if (oOptions.reactToPaste === true) {
|
||||
oDomElement.addEventListener("paste", this._handlePaste);
|
||||
}
|
||||
if (oOptions.scanButtonKeyCode !== false) {
|
||||
oDomElement.addEventListener("keyup", this._handleKeyUp);
|
||||
}
|
||||
if (
|
||||
oOptions.reactToKeypress === true ||
|
||||
oOptions.scanButtonKeyCode !== false
|
||||
) {
|
||||
oDomElement.addEventListener("keypress", this._handleKeyPress);
|
||||
}
|
||||
},
|
||||
|
||||
detachFrom: function(oDomElement) {
|
||||
// detaching all used events
|
||||
if (oDomElement.scannerDetectionData.options.reactToPaste) {
|
||||
oDomElement.removeEventListener("paste", this._handlePaste);
|
||||
}
|
||||
if (oDomElement.scannerDetectionData.options.scanButtonKeyCode !== false) {
|
||||
oDomElement.removeEventListener("keyup", this._handleKeyUp);
|
||||
}
|
||||
oDomElement.removeEventListener("keypress", this._handleKeyPress);
|
||||
|
||||
// clearing data off DomElement
|
||||
oDomElement.scannerDetectionData = undefined;
|
||||
},
|
||||
|
||||
getOptions: function(oDomElement) {
|
||||
return oDomElement.scannerDetectionData.options;
|
||||
},
|
||||
|
||||
setOptions: function(oDomElement, oOptions) {
|
||||
// check if some handlers need to be changed based on possible option changes
|
||||
switch (oDomElement.scannerDetectionData.options.reactToPaste) {
|
||||
case true:
|
||||
if (oOptions.reactToPaste === false) {
|
||||
oDomElement.removeEventListener("paste", this._handlePaste);
|
||||
}
|
||||
break;
|
||||
case false:
|
||||
if (oOptions.reactToPaste === true) {
|
||||
oDomElement.addEventListener("paste", this._handlePaste);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (oDomElement.scannerDetectionData.options.scanButtonKeyCode) {
|
||||
case false:
|
||||
if (oOptions.scanButtonKeyCode !== false) {
|
||||
oDomElement.addEventListener("keyup", this._handleKeyUp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (oOptions.scanButtonKeyCode === false) {
|
||||
oDomElement.removeEventListener("keyup", this._handleKeyUp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// merge old and new options
|
||||
oDomElement.scannerDetectionData.options = this._mergeOptions(
|
||||
oDomElement.scannerDetectionData.options,
|
||||
oOptions
|
||||
);
|
||||
|
||||
// reinitiallize
|
||||
this._reinitialize(oDomElement);
|
||||
},
|
||||
|
||||
simulate: function(oDomElement, sTestString) {
|
||||
var oVars = oDomElement["scannerDetectionData"].vars;
|
||||
oVars.firstCharTime = 0;
|
||||
oVars.lastCharTime = 0;
|
||||
oVars.stringWriting = sTestString;
|
||||
this._validateScanCode(oDomElement);
|
||||
return this;
|
||||
},
|
||||
|
||||
_reinitialize: function(oDomElement) {
|
||||
var oVars = oDomElement["scannerDetectionData"].vars;
|
||||
oVars.firstCharTime = 0;
|
||||
oVars.stringWriting = "";
|
||||
},
|
||||
|
||||
_isFocusOnIgnoredElement: function(oDomElement) {
|
||||
ignoreSelectors =
|
||||
oDomElement["scannerDetectionData"].options.ignoreIfFocusOn;
|
||||
|
||||
if (!ignoreSelectors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var oFocused = document.activeElement;
|
||||
|
||||
// checks if ignored element is an array, and if so it checks if one of the elements of it is an active one
|
||||
if (Array.isArray(ignoreSelectors)) {
|
||||
for (var i = 0; i < ignoreSelectors.length; i++) {
|
||||
if (oFocused.matches(ignoreSelectors[i]) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// if the option consists of an single element, it only checks this one
|
||||
} else if (oFocused.matches(ignoreSelectors)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the active element is not listed in the ignoreIfFocusOn option, return false
|
||||
return false;
|
||||
},
|
||||
|
||||
_validateScanCode: function(oDomElement) {
|
||||
var oScannerData = oDomElement["scannerDetectionData"];
|
||||
var oOptions = oScannerData.options;
|
||||
var iSingleScanQty = oScannerData.options.singleScanQty;
|
||||
var sScanCode = oScannerData.vars.stringWriting;
|
||||
var iFirstCharTime = oScannerData.vars.firstCharTime;
|
||||
var iLastCharTime = oScannerData.vars.lastCharTime;
|
||||
|
||||
switch (true) {
|
||||
// detect codes that are too short
|
||||
case sScanCode.length < oOptions.minLength:
|
||||
var oScanError = {
|
||||
message: "Receieved code is shorter then minimal length"
|
||||
};
|
||||
break;
|
||||
|
||||
// detect codes that were entered too slow
|
||||
case iLastCharTime - iFirstCharTime >
|
||||
sScanCode.length * oOptions.avgTimeByChar:
|
||||
var oScanError = {
|
||||
message: "Receieved code was not entered in time"
|
||||
};
|
||||
break;
|
||||
|
||||
// if a code was not filtered out earlier it is valid
|
||||
default:
|
||||
oOptions.onScan.call(oDomElement, sScanCode, iSingleScanQty);
|
||||
var oEvent = new CustomEvent("scan", {
|
||||
detail: {
|
||||
scanCode: sScanCode,
|
||||
qty: iSingleScanQty
|
||||
}
|
||||
});
|
||||
oDomElement.dispatchEvent(oEvent);
|
||||
onScan._reinitialize(oDomElement);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If an error occurred (otherwise the method would return earlier) create an object for errordetection
|
||||
oScanError.scanCode = sScanCode;
|
||||
oScanError.scanDuration = iLastCharTime - iFirstCharTime;
|
||||
oScanError.avgTimeByChar = oOptions.avgTimeByChar;
|
||||
oScanError.minLength = oOptions.minLength;
|
||||
|
||||
oOptions.onScanError.call(oDomElement, oScanError);
|
||||
|
||||
var oEvent = new CustomEvent("scanError", oScanError);
|
||||
oDomElement.dispatchEvent(oEvent);
|
||||
|
||||
onScan._reinitialize(oDomElement);
|
||||
return false;
|
||||
},
|
||||
|
||||
_mergeOptions: function(oDefaults, oOptions) {
|
||||
var oExtended = {};
|
||||
var prop;
|
||||
for (prop in oDefaults) {
|
||||
if (Object.prototype.hasOwnProperty.call(oDefaults, prop)) {
|
||||
oExtended[prop] = oDefaults[prop];
|
||||
}
|
||||
}
|
||||
for (prop in oOptions) {
|
||||
if (Object.prototype.hasOwnProperty.call(oOptions, prop)) {
|
||||
oExtended[prop] = oOptions[prop];
|
||||
}
|
||||
}
|
||||
return oExtended;
|
||||
},
|
||||
|
||||
_getNormalizedKeyNum: function(e) {
|
||||
var iKeyCode;
|
||||
if (window.event) {
|
||||
// IE
|
||||
iKeyCode = e.keyCode;
|
||||
} else if (e.which) {
|
||||
// Netscape/Firefox/Opera
|
||||
iKeyCode = e.which;
|
||||
}
|
||||
return iKeyCode;
|
||||
},
|
||||
|
||||
_handleKeyPress: function(e) {
|
||||
// overwrite the which value of the event with keycode for cross platform compatibility
|
||||
e.which = onScan._getNormalizedKeyNum(e);
|
||||
var iKeyCode = e.which;
|
||||
var oOptions = this["scannerDetectionData"].options;
|
||||
var oVars = this["scannerDetectionData"].vars;
|
||||
|
||||
oOptions.onKeyDetect.call(this, e.which, e);
|
||||
|
||||
if (onScan._isFocusOnIgnoredElement(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's just the button of the scanner, ignore it and wait for the real input
|
||||
if (
|
||||
oOptions.scanButtonKeyCode !== false &&
|
||||
iKeyCode == oOptions.scanButtonKeyCode
|
||||
) {
|
||||
// if the button was first pressed, start a timeout for the callback, which gets interrupted if the scanbutton gets released
|
||||
if (!oVars.longPressed) {
|
||||
oVars.longPressTimer = setTimeout(
|
||||
oOptions.onScanButtonLongPress,
|
||||
oOptions.scanButtonLongPressTime,
|
||||
this
|
||||
);
|
||||
oVars.longPressed = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (oOptions.stopPropagation) {
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
|
||||
if (oOptions.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
// If it's not the first character and we encounter a terminating character, trigger scan process
|
||||
case oVars.firstCharTime &&
|
||||
oOptions.suffixKeyCodes.indexOf(iKeyCode) !== -1:
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
this["scannerDetectionData"].vars.callIsScanner = true;
|
||||
break;
|
||||
|
||||
// If it's the first character and we encountered one of the starting characters, don't process the scan
|
||||
case !oVars.firstCharTime &&
|
||||
oOptions.prefixKeyCodes.indexOf(iKeyCode) !== -1:
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
oVars.callIsScanner = false;
|
||||
break;
|
||||
|
||||
// Otherwise, just add the character to the scan string we're building
|
||||
default:
|
||||
var character = oOptions.keyCodeMapper.call(this, e);
|
||||
if (character === null) {
|
||||
return;
|
||||
}
|
||||
oVars.stringWriting += character;
|
||||
oVars.callIsScanner = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!oVars.firstCharTime) {
|
||||
oVars.firstCharTime = Date.now();
|
||||
}
|
||||
|
||||
oVars.lastCharTime = Date.now();
|
||||
|
||||
if (oVars.testTimer) {
|
||||
clearTimeout(oVars.testTimer);
|
||||
}
|
||||
|
||||
if (oVars.callIsScanner) {
|
||||
onScan._validateScanCode(this);
|
||||
oVars.testTimer = false;
|
||||
} else {
|
||||
oVars.testTimer = setTimeout(
|
||||
onScan._validateScanCode,
|
||||
oOptions.timeBeforeScanTest,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
oOptions.onKeyProcess.call(this, character, e);
|
||||
},
|
||||
|
||||
_handlePaste: function(e) {
|
||||
// if the focus is on an ignored element, abort
|
||||
if (onScan._isFocusOnIgnoredElement(this)) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
var sPasteString = (event.clipboardData || window.clipboardData).getData(
|
||||
"text"
|
||||
);
|
||||
this.scannerDetectionData.options.onPaste.call(this, sPasteString, event);
|
||||
|
||||
var oVars = this.scannerDetectionData.vars;
|
||||
oVars.firstCharTime = 0;
|
||||
oVars.lastCharTime = 0;
|
||||
oVars.stringWriting = sPasteString;
|
||||
|
||||
// validate the string
|
||||
onScan._validateScanCode(this);
|
||||
},
|
||||
|
||||
_handleKeyUp: function(e) {
|
||||
// if the focus is on an ignored element, abort
|
||||
if (onScan._isFocusOnIgnoredElement(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var iKeyCode = onScan._getNormalizedKeyNum(e);
|
||||
|
||||
// if hardware key is not being pressed anymore stop the timeout and reset
|
||||
if (iKeyCode == this.scannerDetectionData.options.scanButtonKeyCode) {
|
||||
clearTimeout(this.scannerDetectionData.vars.longPressTimer);
|
||||
this.scannerDetectionData.vars.longPressed = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user