1 |
|
2 |
|
3 |
|
4 | ;(function (global, factory) {
|
5 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
6 | typeof define === 'function' && define.amd ? define(factory()) :
|
7 | global.onScan = factory()
|
8 | }(this, (function () {
|
9 | var onScan = {
|
10 |
|
11 | |
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | attachTo: function(oDomElement, oOptions) {
|
18 |
|
19 | if(oDomElement.scannerDetectionData !== undefined){
|
20 | throw new Error("onScan.js is already initialized for DOM element " + oDomElement);
|
21 | }
|
22 |
|
23 | var oDefaults = {
|
24 | onScan: function(sScanned, iQty){},
|
25 | onScanError: function(oDebug){},
|
26 | onKeyProcess: function(sChar, oEvent){},
|
27 | onKeyDetect: function(iKeyCode, oEvent){},
|
28 | onPaste: function(sPasted, oEvent){},
|
29 | keyCodeMapper: function(oEvent) {return onScan.decodeKeyEvent(oEvent)},
|
30 | onScanButtonLongPress: function(){},
|
31 | scanButtonKeyCode:false,
|
32 | scanButtonLongPressTime:500,
|
33 | timeBeforeScanTest:100,
|
34 | avgTimeByChar:30,
|
35 | minLength:6,
|
36 | suffixKeyCodes:[9,13],
|
37 | prefixKeyCodes:[],
|
38 | ignoreIfFocusOn:false,
|
39 | stopPropagation:false,
|
40 | preventDefault:false,
|
41 | captureEvents:false,
|
42 | reactToKeydown:true,
|
43 | reactToPaste:false,
|
44 | singleScanQty: 1,
|
45 | }
|
46 |
|
47 | oOptions = this._mergeOptions(oDefaults, oOptions);
|
48 |
|
49 |
|
50 | oDomElement.scannerDetectionData = {
|
51 | options: oOptions,
|
52 | vars:{
|
53 | firstCharTime: 0,
|
54 | lastCharTime: 0,
|
55 | accumulatedString: '',
|
56 | testTimer: false,
|
57 | longPressTimeStart: 0,
|
58 | longPressed: false
|
59 | }
|
60 |
|
61 | };
|
62 |
|
63 |
|
64 | if (oOptions.reactToPaste === true){
|
65 | oDomElement.addEventListener("paste", this._handlePaste, oOptions.captureEvents);
|
66 | }
|
67 | if (oOptions.scanButtonKeyCode !== false){
|
68 | oDomElement.addEventListener("keyup", this._handleKeyUp, oOptions.captureEvents);
|
69 | }
|
70 | if (oOptions.reactToKeydown === true || oOptions.scanButtonKeyCode !== false){
|
71 | oDomElement.addEventListener("keydown", this._handleKeyDown, oOptions.captureEvents);
|
72 | }
|
73 | return this;
|
74 | },
|
75 |
|
76 | |
77 |
|
78 |
|
79 |
|
80 |
|
81 | detachFrom: function(oDomElement) {
|
82 |
|
83 | if (oDomElement.scannerDetectionData.options.reactToPaste){
|
84 | oDomElement.removeEventListener("paste", this._handlePaste);
|
85 | }
|
86 | if (oDomElement.scannerDetectionData.options.scanButtonKeyCode !== false){
|
87 | oDomElement.removeEventListener("keyup", this._handleKeyUp);
|
88 | }
|
89 | oDomElement.removeEventListener("keydown", this._handleKeyDown);
|
90 |
|
91 |
|
92 | oDomElement.scannerDetectionData = undefined;
|
93 | return;
|
94 | },
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 | getOptions: function(oDomElement){
|
102 | return oDomElement.scannerDetectionData.options;
|
103 | },
|
104 |
|
105 | |
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | setOptions: function(oDomElement, oOptions){
|
112 |
|
113 | switch (oDomElement.scannerDetectionData.options.reactToPaste){
|
114 | case true:
|
115 | if (oOptions.reactToPaste === false){
|
116 | oDomElement.removeEventListener("paste", this._handlePaste);
|
117 | }
|
118 | break;
|
119 | case false:
|
120 | if (oOptions.reactToPaste === true){
|
121 | oDomElement.addEventListener("paste", this._handlePaste);
|
122 | }
|
123 | break;
|
124 | }
|
125 |
|
126 | switch (oDomElement.scannerDetectionData.options.scanButtonKeyCode){
|
127 | case false:
|
128 | if (oOptions.scanButtonKeyCode !== false){
|
129 | oDomElement.addEventListener("keyup", this._handleKeyUp);
|
130 | }
|
131 | break;
|
132 | default:
|
133 | if (oOptions.scanButtonKeyCode === false){
|
134 | oDomElement.removeEventListener("keyup", this._handleKeyUp);
|
135 | }
|
136 | break;
|
137 | }
|
138 |
|
139 |
|
140 | oDomElement.scannerDetectionData.options = this._mergeOptions(oDomElement.scannerDetectionData.options, oOptions);
|
141 |
|
142 |
|
143 | this._reinitialize(oDomElement);
|
144 | return this;
|
145 | },
|
146 |
|
147 | |
148 |
|
149 |
|
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | decodeKeyEvent : function (oEvent) {
|
166 | var iCode = this._getNormalizedKeyNum(oEvent);
|
167 | switch (true) {
|
168 | case iCode >= 48 && iCode <= 90:
|
169 | case iCode >= 106 && iCode <= 111:
|
170 | if (oEvent.key !== undefined && oEvent.key !== '') {
|
171 | return oEvent.key;
|
172 | }
|
173 |
|
174 | var sDecoded = String.fromCharCode(iCode);
|
175 | switch (oEvent.shiftKey) {
|
176 | case false: sDecoded = sDecoded.toLowerCase(); break;
|
177 | case true: sDecoded = sDecoded.toUpperCase(); break;
|
178 | }
|
179 | return sDecoded;
|
180 | case iCode >= 96 && iCode <= 105:
|
181 | return 0+(iCode-96);
|
182 | }
|
183 | return '';
|
184 | },
|
185 |
|
186 | |
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 | simulate: function(oDomElement, mStringOrArray){
|
203 | this._reinitialize(oDomElement);
|
204 | if (Array.isArray(mStringOrArray)){
|
205 | mStringOrArray.forEach(function(mKey){
|
206 | var oEventProps = {};
|
207 | if( (typeof mKey === "object" || typeof mKey === 'function') && (mKey !== null) ) {
|
208 | oEventProps = mKey;
|
209 | } else {
|
210 | oEventProps.keyCode = parseInt(mKey);
|
211 | }
|
212 | var oEvent = new KeyboardEvent('keydown', oEventProps);
|
213 | document.dispatchEvent(oEvent);
|
214 | })
|
215 | } else {
|
216 | this._validateScanCode(oDomElement, mStringOrArray);
|
217 | }
|
218 | return this;
|
219 | },
|
220 |
|
221 | |
222 |
|
223 |
|
224 |
|
225 |
|
226 | _reinitialize: function(oDomElement){
|
227 | var oVars = oDomElement.scannerDetectionData.vars;
|
228 | oVars.firstCharTime = 0;
|
229 | oVars.lastCharTime = 0;
|
230 | oVars.accumulatedString = '';
|
231 | return;
|
232 | },
|
233 |
|
234 | |
235 |
|
236 |
|
237 |
|
238 |
|
239 | _isFocusOnIgnoredElement: function(oDomElement){
|
240 |
|
241 | var ignoreSelectors = oDomElement.scannerDetectionData.options.ignoreIfFocusOn;
|
242 |
|
243 | if(!ignoreSelectors){
|
244 | return false;
|
245 | }
|
246 |
|
247 | var oFocused = document.activeElement;
|
248 |
|
249 |
|
250 | if (Array.isArray(ignoreSelectors)){
|
251 | for(var i=0; i<ignoreSelectors.length; i++){
|
252 | if(oFocused.matches(ignoreSelectors[i]) === true){
|
253 | return true;
|
254 | }
|
255 | }
|
256 |
|
257 | } else if (oFocused.matches(ignoreSelectors)){
|
258 | return true;
|
259 | }
|
260 |
|
261 |
|
262 | return false;
|
263 | },
|
264 |
|
265 | |
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 | _validateScanCode: function(oDomElement, sScanCode){
|
273 | var oScannerData = oDomElement.scannerDetectionData;
|
274 | var oOptions = oScannerData.options;
|
275 | var iSingleScanQty = oScannerData.options.singleScanQty;
|
276 | var iFirstCharTime = oScannerData.vars.firstCharTime;
|
277 | var iLastCharTime = oScannerData.vars.lastCharTime;
|
278 | var oScanError = {};
|
279 | var oEvent;
|
280 |
|
281 | switch(true){
|
282 |
|
283 |
|
284 | case (sScanCode.length < oOptions.minLength):
|
285 | oScanError = {
|
286 | message: "Receieved code is shorter then minimal length"
|
287 | };
|
288 | break;
|
289 |
|
290 |
|
291 | case ((iLastCharTime - iFirstCharTime) > (sScanCode.length * oOptions.avgTimeByChar)):
|
292 | oScanError = {
|
293 | message: "Receieved code was not entered in time"
|
294 | };
|
295 | break;
|
296 |
|
297 |
|
298 | default:
|
299 | oOptions.onScan.call(oDomElement, sScanCode, iSingleScanQty);
|
300 | oEvent = new CustomEvent(
|
301 | 'scan',
|
302 | {
|
303 | detail: {
|
304 | scanCode: sScanCode,
|
305 | qty: iSingleScanQty
|
306 | }
|
307 | }
|
308 | );
|
309 | oDomElement.dispatchEvent(oEvent);
|
310 | onScan._reinitialize(oDomElement);
|
311 | return true;
|
312 | }
|
313 |
|
314 |
|
315 | oScanError.scanCode = sScanCode;
|
316 | oScanError.scanDuration = iLastCharTime - iFirstCharTime;
|
317 | oScanError.avgTimeByChar = oOptions.avgTimeByChar;
|
318 | oScanError.minLength = oOptions.minLength;
|
319 |
|
320 | oOptions.onScanError.call(oDomElement, oScanError);
|
321 |
|
322 | oEvent = new CustomEvent(
|
323 | 'scanError',
|
324 | {detail: oScanError}
|
325 | );
|
326 | oDomElement.dispatchEvent(oEvent);
|
327 |
|
328 | onScan._reinitialize(oDomElement);
|
329 | return false;
|
330 | },
|
331 |
|
332 | |
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 | _mergeOptions: function(oDefaults, oOptions){
|
339 | var oExtended = {};
|
340 | var prop;
|
341 | for (prop in oDefaults){
|
342 | if (Object.prototype.hasOwnProperty.call(oDefaults, prop)){
|
343 | oExtended[prop] = oDefaults[prop];
|
344 | }
|
345 | }
|
346 | for (prop in oOptions){
|
347 | if (Object.prototype.hasOwnProperty.call(oOptions, prop)){
|
348 | oExtended[prop] = oOptions[prop];
|
349 | }
|
350 | }
|
351 | return oExtended;
|
352 | },
|
353 |
|
354 | |
355 |
|
356 |
|
357 |
|
358 |
|
359 |
|
360 | _getNormalizedKeyNum: function(e){
|
361 | return e.which || e.keyCode;
|
362 | },
|
363 |
|
364 |
|
365 | |
366 |
|
367 |
|
368 |
|
369 |
|
370 | _handleKeyDown: function(e){
|
371 | var iKeyCode = onScan._getNormalizedKeyNum(e);
|
372 | var oOptions = this.scannerDetectionData.options;
|
373 | var oVars = this.scannerDetectionData.vars;
|
374 | var bScanFinished = false;
|
375 |
|
376 | if (oOptions.onKeyDetect.call(this, iKeyCode, e) === false) {
|
377 | return;
|
378 | }
|
379 |
|
380 | if (onScan._isFocusOnIgnoredElement(this)){
|
381 | return;
|
382 | }
|
383 |
|
384 |
|
385 | if(oOptions.scanButtonKeyCode !== false && iKeyCode==oOptions.scanButtonKeyCode) {
|
386 |
|
387 |
|
388 | if (!oVars.longPressed){
|
389 | oVars.longPressTimer = setTimeout( oOptions.onScanButtonLongPress, oOptions.scanButtonLongPressTime, this);
|
390 | oVars.longPressed = true;
|
391 | }
|
392 |
|
393 | return;
|
394 | }
|
395 |
|
396 | switch(true){
|
397 |
|
398 | case (oVars.firstCharTime && oOptions.suffixKeyCodes.indexOf(iKeyCode)!==-1):
|
399 | e.preventDefault();
|
400 | e.stopImmediatePropagation();
|
401 | bScanFinished=true;
|
402 | break;
|
403 |
|
404 |
|
405 | case (!oVars.firstCharTime && oOptions.prefixKeyCodes.indexOf(iKeyCode)!==-1):
|
406 | e.preventDefault();
|
407 | e.stopImmediatePropagation();
|
408 | bScanFinished=false;
|
409 | break;
|
410 |
|
411 |
|
412 | default:
|
413 | var character = oOptions.keyCodeMapper.call(this, e);
|
414 | if (character === null){
|
415 | return;
|
416 | }
|
417 | oVars.accumulatedString += character;
|
418 |
|
419 | if (oOptions.preventDefault) {
|
420 | e.preventDefault();
|
421 | }
|
422 | if (oOptions.stopPropagation) {
|
423 | e.stopImmediatePropagation();
|
424 | }
|
425 |
|
426 | bScanFinished=false;
|
427 | break;
|
428 | }
|
429 |
|
430 | if(!oVars.firstCharTime){
|
431 | oVars.firstCharTime=Date.now();
|
432 | }
|
433 |
|
434 | oVars.lastCharTime=Date.now();
|
435 |
|
436 | if(oVars.testTimer){
|
437 | clearTimeout(oVars.testTimer);
|
438 | }
|
439 |
|
440 | if(bScanFinished){
|
441 | onScan._validateScanCode(this, oVars.accumulatedString);
|
442 | oVars.testTimer=false;
|
443 | } else {
|
444 | oVars.testTimer=setTimeout(onScan._validateScanCode, oOptions.timeBeforeScanTest, this, oVars.accumulatedString);
|
445 | }
|
446 |
|
447 | oOptions.onKeyProcess.call(this, character, e);
|
448 | return;
|
449 | },
|
450 |
|
451 | |
452 |
|
453 |
|
454 |
|
455 |
|
456 | _handlePaste: function(e){
|
457 |
|
458 | var oOptions = this.scannerDetectionData.options;
|
459 | var oVars = this.scannerDetectionData.vars;
|
460 | var sPasteString = (event.clipboardData || window.clipboardData).getData('text');
|
461 |
|
462 |
|
463 | if (onScan._isFocusOnIgnoredElement(this)){
|
464 | return;
|
465 | }
|
466 |
|
467 | e.preventDefault();
|
468 |
|
469 | if (oOptions.stopPropagation) {
|
470 | e.stopImmediatePropagation();
|
471 | }
|
472 |
|
473 | oOptions.onPaste.call(this, sPasteString, event);
|
474 |
|
475 | oVars.firstCharTime = 0;
|
476 | oVars.lastCharTime = 0;
|
477 |
|
478 |
|
479 | onScan._validateScanCode(this, sPasteString);
|
480 | return;
|
481 | },
|
482 |
|
483 | |
484 |
|
485 |
|
486 |
|
487 |
|
488 | _handleKeyUp: function(e){
|
489 |
|
490 | if (onScan._isFocusOnIgnoredElement(this)){
|
491 | return;
|
492 | }
|
493 |
|
494 | var iKeyCode = onScan._getNormalizedKeyNum(e);
|
495 |
|
496 |
|
497 | if (iKeyCode == this.scannerDetectionData.options.scanButtonKeyCode){
|
498 | clearTimeout(this.scannerDetectionData.vars.longPressTimer);
|
499 | this.scannerDetectionData.vars.longPressed = false;
|
500 | }
|
501 | return;
|
502 | },
|
503 |
|
504 | |
505 |
|
506 |
|
507 |
|
508 |
|
509 |
|
510 | isScanInProgressFor: function(oDomElement) {
|
511 | return oDomElement.scannerDetectionData.vars.firstCharTime > 0;
|
512 | },
|
513 |
|
514 | |
515 |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 | isAttachedTo: function(oDomElement) {
|
521 | return (oDomElement.scannerDetectionData !== undefined);
|
522 | }
|
523 | };
|
524 |
|
525 | return onScan;
|
526 | }))); |
\ | No newline at end of file |