Extjs Submenus disappear on Chrome 43 - javascript

How to fix submenus disappearing in Chrome 43?
Using Extjs 4.
This was working on previous versions of Chrome.

This overrides needs to be added in order to fix this.
https://www.sencha.com/forum/showthread.php?301116-Submenus-disappear-in-Chrome-43-beta
(Thanks to festr user on Sencha forum - thought this needed to be on SO too)
// fix hide submenu (in chrome 43)
Ext.override(Ext.menu.Menu, {
onMouseLeave: function(e) {
var me = this;
// BEGIN FIX
var visibleSubmenu = false;
me.items.each(function(item) {
if(item.menu && item.menu.isVisible()) {
visibleSubmenu = true;
}
})
if(visibleSubmenu) {
//console.log('apply fix hide submenu');
return;
}
// END FIX
me.deactivateActiveItem();
if (me.disabled) {
return;
}
me.fireEvent('mouseleave', me, e);
}
});

In regards to that same link, https://www.sencha.com/forum/showthread.php?301116-Submenus-disappear-in-Chrome-43-beta, here's a more general, non-specific fix thanks to post #27 by siq:
Ext.apply(Ext.EventManager,{
normalizeEvent: function(eventName, fn) {
//start fix
var EventManager = Ext.EventManager,
supports = Ext.supports;
if(Ext.chromeVersion >=43 && eventName == 'mouseover'){
var origFn = fn;
fn = function(){
var me = this,
args = arguments;
setTimeout(
function(){
origFn.apply(me || Ext.global, args);
},
0);
};
}
//end fix
if (EventManager.mouseEnterLeaveRe.test(eventName) && !supports.MouseEnterLeave) {
if (fn) {
fn = Ext.Function.createInterceptor(fn, EventManager.contains);
}
eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
} else if (eventName == 'mousewheel' && !supports.MouseWheel && !Ext.isOpera) {
eventName = 'DOMMouseScroll';
}
return {
eventName: eventName,
fn: fn
};
}
});
This has been tested on my end and I can verify that it works (v. 4.1.2).

Related

Browser Full screen feature

Hi I have the below page where you simply click the button Full screen and the page browser takes up the full screen, the navigation controls are also hidden to - which is what I like. However if you page refresh (or in my case my page refreshes every 5 minutes) the navigation controls return and it is no longer the view as previous. How can I solve this so that when it refreshed the navigation etc doesn't return and it remains full screen?
<html>
<head>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" />
<script src="screenfull.js"></script>
<script>
$(function () {
$('#supported').text('Supported/allowed: ' + !!screenfull.enabled);
if (!screenfull.enabled) {
return false;
}
$('#request').click(function () {
screenfull.request($('#container')[0]);
// does not require jQuery, can be used like this too:
// screenfull.request(document.getElementById('container'));
});
$('#exit').click(function () {
screenfull.exit();
});
function fullscreenchange() {
var elem = screenfull.element;
$('#status').text('Is fullscreen: ' + screenfull.isFullscreen);
if (elem) {
$('#element').text('Element: ' + elem.localName + (elem.id ? '#' + elem.id : ''));
}
if (!screenfull.isFullscreen) {
$('#external-iframe').remove();
document.body.style.overflow = 'hidden';
}
}
document.addEventListener(screenfull.raw.fullscreenchange, fullscreenchange);
// set the initial values
fullscreenchange();
});
</script>
<button id="request"><i class="fa fa-arrows-alt"></i> Request</button>
<button id="exit">Exit</button>
</body>
(function () {
'use strict';
var isCommonjs = typeof module !== 'undefined' && module.exports;
var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;
var fn = (function () {
var val;
var valLength;
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];
var i = 0;
var l = fnMap.length;
var ret = {};
for (; i < l; i++) {
val = fnMap[i];
if (val && val[1] in document) {
for (i = 0, valLength = val.length; i < valLength; i++) {
ret[fnMap[0][i]] = val[i];
}
return ret;
}
}
return false;
})();
var screenfull = {
request: function (elem) {
var request = fn.requestFullscreen;
elem = elem || document.documentElement;
// Work around Safari 5.1 bug: reports support for
// keyboard in fullscreen even though it doesn't.
// Browser sniffing, since the alternative with
// setTimeout is even worse.
if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
elem[request]();
} else {
elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
}
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
if (this.isFullscreen) {
this.exit();
} else {
this.request(elem);
}
},
raw: fn
};
if (!fn) {
if (isCommonjs) {
module.exports = false;
} else {
window.screenfull = false;
}
return;
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: function () {
return Boolean(document[fn.fullscreenElement]);
}
},
element: {
enumerable: true,
get: function () {
return document[fn.fullscreenElement];
}
},
enabled: {
enumerable: true,
get: function () {
// Coerce to boolean in case of old WebKit
return Boolean(document[fn.fullscreenEnabled]);
}
}
});
if (isCommonjs) {
module.exports = screenfull;
} else {
window.screenfull = screenfull;
}
})();
Online Demo : https://plnkr.co/edit/zx0rXwXpJbWdMvh3HQ25?p=preview
Make onepage website (ajax) (no refresh) Use history pushstate to save all your links so you can use history navigation and change your URL. (most of time I use this approach.)
Or you can use localstorage to save state.
Theoretically You can store an indication of what was the previews state (full-screen / normal) in the browser storage.
Then on page load, read the stored value and activate full-screen if necessary.
However, modern browsers require this to be an interactive user action (not automatically via script on load)
If you try to automate this, you'll get these type of warnings in the browser's console:
Alternatives
Avoid full refreshes
Workaround using custom browser extension to restore the fullscreen state

Error 0x8007000e (NS_ERROR_OUT_OF_MEMORY)

I'm working on an addon to a forum and I get this error:
Error: Component returned failure code: 0x8007000e (NS_ERROR_OUT_OF_MEMORY) [nsIXPCComponents_Utils.evalInSandbox]
I read that the error means that the script goes into infinite loop until it fills the sandbox.
apparently the js file that leads to this error is script-compiler.js
this is the script:
var ddplus_gmCompiler={
// getUrlContents adapted from Greasemonkey Compiler
// http://www.letitblog.com/code/python/greasemonkey.py.txt
// used under GPL permission
//
// most everything else below based heavily off of Greasemonkey
// http://greasemonkey.mozdev.org/
// used under GPL permission
getUrlContents: function(aUrl){
var ioService=Components.classes["#mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var scriptableStream=Components
.classes["#mozilla.org/scriptableinputstream;1"]
.getService(Components.interfaces.nsIScriptableInputStream);
var channel=ioService.newChannel(aUrl, null, null);
var input=channel.open();
scriptableStream.init(input);
var str=scriptableStream.read(input.available());
scriptableStream.close();
input.close();
return str;
},
isGreasemonkeyable: function(url) {
var scheme=Components.classes["#mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.extractScheme(url);
return (
(scheme == "http" || scheme == "https" || scheme == "file") &&
!/hiddenWindow\.html$/.test(url)
);
},
contentLoad: function(e) {
var unsafeWin=e.target.defaultView;
if (unsafeWin.wrappedJSObject) unsafeWin=unsafeWin.wrappedJSObject;
var unsafeLoc=new XPCNativeWrapper(unsafeWin, "location").location;
var href=new XPCNativeWrapper(unsafeLoc, "href").href;
if (
ddplus_gmCompiler.isGreasemonkeyable(href)
&& ( /http:\/\/ddunlimited\.net/.test(href) )
&& true
) {
var script=ddplus_gmCompiler.getUrlContents(
'chrome://ddplus/content/ddplus.js'
);
ddplus_gmCompiler.injectScript(script, href, unsafeWin);
}
},
injectScript: function(script, url, unsafeContentWin) {
var sandbox, script, logger, storage, xmlhttpRequester;
var safeWin=new XPCNativeWrapper(unsafeContentWin);
sandbox=new Components.utils.Sandbox(safeWin);
var storage=new ddplus_ScriptStorage();
xmlhttpRequester=new ddplus_xmlhttpRequester(
unsafeContentWin, window//appSvc.hiddenDOMWindow
);
sandbox.window=safeWin;
sandbox.document=sandbox.window.document;
sandbox.unsafeWindow=unsafeContentWin;
// patch missing properties on xpcnw
sandbox.XPathResult=Components.interfaces.nsIDOMXPathResult;
// add our own APIs
sandbox.GM_addStyle=function(css) { ddplus_gmCompiler.addStyle(sandbox.document, css) };
sandbox.GM_setValue=ddplus_gmCompiler.hitch(storage, "setValue");
sandbox.GM_getValue=ddplus_gmCompiler.hitch(storage, "getValue");
// kick : aggiunta la funzione
sandbox.GM_remove=ddplus_gmCompiler.hitch(storage, "remove");
sandbox.GM_openInTab=ddplus_gmCompiler.hitch(this, "openInTab", unsafeContentWin);
sandbox.GM_xmlhttpRequest=ddplus_gmCompiler.hitch(
xmlhttpRequester, "contentStartRequest"
);
//unsupported
sandbox.GM_registerMenuCommand=function(){};
sandbox.GM_log=function(){};
sandbox.GM_getResourceURL=function(){};
sandbox.GM_getResourceText=function(){};
sandbox.__proto__=sandbox.window;
try {
this.evalInSandbox(
"(function(){"+script+"})()",
url,
sandbox);
} catch (e) {
var e2=new Error(typeof e=="string" ? e : e.message);
e2.fileName=script.filename;
e2.lineNumber=0;
//GM_logError(e2);
alert(e2);
}
},
evalInSandbox: function(code, codebase, sandbox) {
if (Components.utils && Components.utils.Sandbox) {
// DP beta+
Components.utils.evalInSandbox(code, sandbox);
} else if (Components.utils && Components.utils.evalInSandbox) {
// DP alphas
Components.utils.evalInSandbox(code, codebase, sandbox);
} else if (Sandbox) {
// 1.0.x
evalInSandbox(code, sandbox, codebase);
} else {
throw new Error("Could not create sandbox.");
}
},
openInTab: function(unsafeContentWin, url) {
var tabBrowser = getBrowser(), browser, isMyWindow = false;
for (var i = 0; browser = tabBrowser.browsers[i]; i++)
if (browser.contentWindow == unsafeContentWin) {
isMyWindow = true;
break;
}
if (!isMyWindow) return;
var loadInBackground, sendReferrer, referrer = null;
loadInBackground = tabBrowser.mPrefs.getBoolPref("browser.tabs.loadInBackground");
sendReferrer = tabBrowser.mPrefs.getIntPref("network.http.sendRefererHeader");
if (sendReferrer) {
var ios = Components.classes["#mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
referrer = ios.newURI(content.document.location.href, null, null);
}
tabBrowser.loadOneTab(url, referrer, null, null, loadInBackground);
},
hitch: function(obj, meth) {
var unsafeTop = new XPCNativeWrapper(unsafeContentWin, "top").top;
for (var i = 0; i < this.browserWindows.length; i++) {
this.browserWindows[i].openInTab(unsafeTop, url);
}
},
apiLeakCheck: function(allowedCaller) {
var stack=Components.stack;
var leaked=false;
do {
if (2==stack.language) {
if ('chrome'!=stack.filename.substr(0, 6) &&
allowedCaller!=stack.filename
) {
leaked=true;
break;
}
}
stack=stack.caller;
} while (stack);
return leaked;
},
hitch: function(obj, meth) {
if (!obj[meth]) {
throw "method '" + meth + "' does not exist on object '" + obj + "'";
}
var hitchCaller=Components.stack.caller.filename;
var staticArgs = Array.prototype.splice.call(arguments, 2, arguments.length);
return function() {
if (ddplus_gmCompiler.apiLeakCheck(hitchCaller)) {
return;
}
// make a copy of staticArgs (don't modify it because it gets reused for
// every invocation).
var args = staticArgs.concat();
// add all the new arguments
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
// invoke the original function with the correct this obj and the combined
// list of static and dynamic arguments.
return obj[meth].apply(obj, args);
};
},
addStyle:function(doc, css) {
var head, style;
head = doc.getElementsByTagName('head')[0];
if (!head) { return; }
style = doc.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
},
onLoad: function() {
var appcontent=window.document.getElementById("appcontent");
if (appcontent && !appcontent.greased_ddplus_gmCompiler) {
appcontent.greased_ddplus_gmCompiler=true;
appcontent.addEventListener("DOMContentLoaded", ddplus_gmCompiler.contentLoad, false);
}
},
onUnLoad: function() {
//remove now unnecessary listeners
window.removeEventListener('load', ddplus_gmCompiler.onLoad, false);
window.removeEventListener('unload', ddplus_gmCompiler.onUnLoad, false);
window.document.getElementById("appcontent")
.removeEventListener("DOMContentLoaded", ddplus_gmCompiler.contentLoad, false);
},
}; //object ddplus_gmCompiler
function ddplus_ScriptStorage() {
this.prefMan=new ddplus_PrefManager();
}
ddplus_ScriptStorage.prototype.setValue = function(name, val) {
this.prefMan.setValue(name, val);
}
ddplus_ScriptStorage.prototype.getValue = function(name, defVal) {
return this.prefMan.getValue(name, defVal);
}
ddplus_ScriptStorage.prototype.remove = function(name) {
return this.prefMan.remove(name);
}
window.addEventListener('load', ddplus_gmCompiler.onLoad, false);
window.addEventListener('unload', ddplus_gmCompiler.onUnLoad, false);
The user script is massive and available in this gist.
To be able to see the error:
install the addon
go to the message board at http://ddunlimited.net/
open any thread and open click the reply link
The message will appear as soon as the reply page loads.
in practice is a tool created specifically for a forum ... with the functions targeted to simplify the daily actions of the moderator. Now the forum has changed domain and tried to make it compatible with the new forum. I'm editing the js file with a simple text editor. ettengo the error when I edit the script that I posted above. if you do not touch this script ... some functions disappear and are no longer present.
someone can help me? thank you very much: D
OK, reproducible after all. The error in this case has a bogus message, as this isn't actually an OOM condition, but evalInSandbox() receiving a notification from the JS engine that the script was aborted (due to it being unresponsive) and evalInSandbox() not being able to tell the difference.
The reason is an infinite loop in your code at line 425 (cont.):
var max = textArea.parentNode.parentNode.clientHeight;
while (max == textArea.parentNode.parentNode.clientHeight)
textArea.rows++;
This loop whill never abort as the condition will never get false.

Disable selection context menu in iOS safari

I want to disable the default context menu that appears after a certain text is selected in iOS Safari (web browser). Is that possible?
The only way i found was by removing the selection and select again with javascript.
Have a look at my code:
/* prevent ios edit-menu */
if (/(iPad|iPhone|iPod)/g.test(navigator.userAgent)) {
!function(){
var target = document.body; // the element where the edit menue should be disabled
var preventSelRecursion;
document.addEventListener('selectionchange', function(e){
var S = getSelection();
if (!S.rangeCount) return;
if (S.isCollapsed) return;
var r = S.getRangeAt(0);
if (!target.contains(r.commonAncestorContainer)) return;
if (preventSelRecursion) return;
iosSelMenuPrevent();
}, false);
var iosSelMenuPrevent = debounce(function(){
var S = getSelection();
var r = S.getRangeAt(0);
preventSelRecursion = true;
S = getSelection();
S.removeAllRanges();
setTimeout(function(){ // make remove-add-selection removes the menu
S.addRange(r);
setTimeout(function(){
preventSelRecursion = false;
});
},4);
},800); // if no selectionchange during 800ms : remove the menu
/* helper-function */
function debounce(fn, delay) {
var timer = null;
return function () {
var context = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
};
}
}();
}
It is possible, see this example. Basically, the important part is to set the right css atributes:
body { -webkit-touch-callout: none !important; }
a { -webkit-user-select: none !important; }
Also, here is a question which solves a similar issue
According to onclick blocks copy+paste on Mobile Safari?, if the text is in an element that has an onclick event, the context menu won't be displayed.
Inspired by Hans Gustavson's answer, I propose a simpler solution in TypeScript:
function disableIosSafariCallout(this: Window, event: any) {
const s = this.getSelection();
if ((s?.rangeCount || 0) > 0) {
const r = s?.getRangeAt(0);
s?.removeAllRanges();
setTimeout(() => {
s?.addRange(r!);
}, 50);
}
}
document.ontouchend = disableIosSafariCallout.bind(window);
This solution is actually a workaround. When you select a text, you might still see the text selection callout shows and then disappear immediately. I am not sure whether Hans Gustavson's answer has the same defect...

Detect when input box filled by keyboard and when by barcode scanner.

How I can programmatically detect when text input filled by typing on keyboard and when it filled automatically by bar-code scanner?
I wrote this answer, because my Barcode Scanner Motorola LS1203 generated keypress event, so I can't use Utkanos's solution.
My solution is:
var BarcodeScanerEvents = function() {
this.initialize.apply(this, arguments);
};
BarcodeScanerEvents.prototype = {
initialize: function() {
$(document).on({
keyup: $.proxy(this._keyup, this)
});
},
_timeoutHandler: 0,
_inputString: '',
_keyup: function (e) {
if (this._timeoutHandler) {
clearTimeout(this._timeoutHandler);
this._inputString += String.fromCharCode(e.which);
}
this._timeoutHandler = setTimeout($.proxy(function () {
if (this._inputString.length <= 3) {
this._inputString = '';
return;
}
$(document).trigger('onbarcodescaned', this._inputString);
this._inputString = '';
}, this), 20);
}
};
Adapted the super useful Vitall answer above to utilize an IIFE instead of prototyping, in case anyone just seeing this now is into that.
This also uses the 'keypress' event instead of keyup, which allowed me to reliably use KeyboardEvent.key, since KeyboardEvent.which is deprecated now. I found this to work for barcode scanning as well as magnetic-strip card swipes.
In my experience, handling card swipes with keyup caused me to do extra work handling 'Shift' keycodes e.g. a Shift code would be followed by the code representing '/', with the intended character being '?'. Using 'keypress' solved this as well.
(function($) {
var _timeoutHandler = 0,
_inputString = '',
_onKeypress = function(e) {
if (_timeoutHandler) {
clearTimeout(_timeoutHandler);
}
_inputString += e.key;
_timeoutHandler = setTimeout(function () {
if (_inputString.length <= 3) {
_inputString = '';
return;
}
$(e.target).trigger('altdeviceinput', _inputString);
_inputString = '';
}, 20);
};
$(document).on({
keypress: _onKeypress
});
})($);
Well a barcode won't fire any key events so you could do something like:
$('#my_field').on({
keypress: function() { typed_into = true; },
change: function() {
if (typed_into) {
alert('type');
typed_into = false; //reset type listener
} else {
alert('not type');
}
}
});
Depending on when you want to evaluate this, you may want to do this check not on change but on submit, or whatever.
you can try following example, using jQuery plugin https://plugins.jquery.com/scannerdetection/
Its highly configurable, time based scanner detector. It can be used as solution for prefix/postfix based, time based barcode scanner.
Tutorial for usage and best practices, as well discussed about various Barcode Scanner Models and how to deal with it. http://a.kabachnik.info/jquery-scannerdetection-tutorial.html
$(window).ready(function(){
//$("#bCode").scannerDetection();
console.log('all is well');
$(window).scannerDetection();
$(window).bind('scannerDetectionComplete',function(e,data){
console.log('complete '+data.string);
$("#bCode").val(data.string);
})
.bind('scannerDetectionError',function(e,data){
console.log('detection error '+data.string);
})
.bind('scannerDetectionReceive',function(e,data){
console.log('Recieve');
console.log(data.evt.which);
})
//$(window).scannerDetection('success');
<input id='bCode'type='text' value='barcode appears here'/>
For ES6 2019 version of Vitall answer.
const events = mitt()
class BarcodeScaner {
initialize = () => {
document.addEventListener('keypress', this.keyup)
if (this.timeoutHandler) {
clearTimeout(this.timeoutHandler)
}
this.timeoutHandler = setTimeout(() => {
this.inputString = ''
}, 10)
}
close = () => {
document.removeEventListener('keypress', this.keyup)
}
timeoutHandler = 0
inputString = ''
keyup = (e) => {
if (this.timeoutHandler) {
clearTimeout(this.timeoutHandler)
this.inputString += String.fromCharCode(e.keyCode)
}
this.timeoutHandler = setTimeout(() => {
if (this.inputString.length <= 3) {
this.inputString = ''
return
}
events.emit('onbarcodescaned', this.inputString)
this.inputString = ''
}, 10)
}
}
Can be used with react hooks like so:
const ScanComponent = (props) => {
const [scanned, setScanned] = useState('')
useEffect(() => {
const barcode = new BarcodeScaner()
barcode.initialize()
return () => {
barcode.close()
}
}, [])
useEffect(() => {
const scanHandler = code => {
console.log(code)
setScanned(code)
}
events.on('onbarcodescaned', scanHandler)
return () => {
events.off('onbarcodescaned', scanHandler)
}
}, [/* here put dependencies for your scanHandler ;) */])
return <div>{scanned}</div>
}
I use mitt from npm for events, but you can use whatever you prefer ;)
Tested on Zebra DS4208
The solution from Vitall only works fine if you already hit at least one key. If you don't the first character will be ignored (if(this._timeoutHandler) returns false and the char will not be appended).
If you want to begin scanning immediately you can use the following code:
var BarcodeScanerEvents = function() {
this.initialize.apply(this, arguments);
};
BarcodeScanerEvents.prototype = {
initialize : function() {
$(document).on({
keyup : $.proxy(this._keyup, this)
});
},
_timeoutHandler : 0,
_inputString : '',
_keyup : function(e) {
if (this._timeoutHandler) {
clearTimeout(this._timeoutHandler);
}
this._inputString += String.fromCharCode(e.which);
this._timeoutHandler = setTimeout($.proxy(function() {
if (this._inputString.length <= 3) {
this._inputString = '';
return;
}
$(document).trigger('onbarcodescaned', this._inputString);
this._inputString = '';
}, this), 20);
}
};
If you can set a prefix to your barcode scanner I suggests this (I changed a bit the Vitall code):
var BarcodeScanner = function(options) {
this.initialize.call(this, options);
};
BarcodeScanner.prototype = {
initialize: function(options) {
$.extend(this._options,options);
if(this._options.debug) console.log("BarcodeScanner: Initializing");
$(this._options.eventObj).on({
keydown: $.proxy(this._keydown, this),
});
},
destroy: function() {
$(this._options.eventObj).off("keyup",null,this._keyup);
$(this._options.eventObj).off("keydown",null,this._keydown);
},
fire: function(str){
if(this._options.debug) console.log("BarcodeScanner: Firing barcode event with string: "+str);
$(this._options.fireObj).trigger('barcode',[str]);
},
isReading: function(){
return this._isReading;
},
checkEvent: function(e){
return this._isReading || (this._options.isShiftPrefix?e.shiftKey:!e.shiftKey) && e.which==this._options.prefixCode;
},
_options: {timeout: 600, prefixCode: 36, suffixCode: 13, minCode: 32, maxCode: 126, isShiftPrefix: false, debug: false, eventObj: document, fireObj: document},
_isReading: false,
_timeoutHandler: false,
_inputString: '',
_keydown: function (e) {
if(this._input.call(this,e))
return false;
},
_input: function (e) {
if(this._isReading){
if(e.which==this._options.suffixCode){
//read end
if(this._options.debug) console.log("BarcodeScanner: Read END");
if (this._timeoutHandler)
clearTimeout(this._timeoutHandler);
this._isReading=false;
this.fire.call(this,this._inputString);
this._inputString='';
}else{
//char reading
if(this._options.debug) console.log("BarcodeScanner: Char reading "+(e.which));
if(e.which>=this._options.minCode && e.which<=this._options.maxCode)
this._inputString += String.fromCharCode(e.which);
}
return true;
}else{
if((this._options.isShiftPrefix?e.shiftKey:!e.shiftKey) && e.which==this._options.prefixCode){
//start reading
if(this._options.debug) console.log("BarcodeScanner: Start reading");
this._isReading=true;
this._timeoutHandler = setTimeout($.proxy(function () {
//read timeout
if(this._options.debug) console.log("BarcodeScanner: Read timeout");
this._inputString='';
this._isReading=false;
this._timeoutHandler=false;
}, this), this._options.timeout);
return true;
}
}
return false;
}
};
If you need you customize timeout, suffix, prefix, min/max ascii code readed:
new BarcodeScanner({timeout: 600, prefixKeyCode: 36, suffixKeyCode: 13, minKeyCode: 32, maxKeyCode: 126});
I also added the isShiftPrefix option to use for example the $ char as prefix with these options: new BarcodeScanner({prefixKeyCode: 52, isShiftPrefix: true});
This is a fiddle: https://jsfiddle.net/xmt76ca5/
You can use a "onkeyup" event on that input box. If the event has triggered then you can called it "Input from Keyboard".
$(window).ready(function(){
//$("#bCode").scannerDetection();
console.log('all is well');
$(window).scannerDetection();
$(window).bind('scannerDetectionComplete',function(e,data){
console.log('complete '+data.string);
$("#bCode").val(data.string);
})
.bind('scannerDetectionError',function(e,data){
console.log('detection error '+data.string);
})
.bind('scannerDetectionReceive',function(e,data){
console.log('Recieve');
console.log(data.evt.which);
})
//$(window).scannerDetection('success');
<input id='bCode'type='text' value='barcode appears here'/>
Hi I have and alternative solution for evaluate a result of the bar code scanner without use of jQuery, first you need and input text that have a focus the moment that the barcode scanner is works
<input id="input_resultado" type="text" />
The code in JavaScript is:
var elmInputScan = document.getElementById('input_resultado');
elmInputScan.addEventListener('keypress', function (e){
clearInterval( timer_response );
timer_response = setTimeout( "onInputChange()", 10);
});
When the barcode scanner input the text call serveral times to the keypress event, but only I interested to the final result, for this reason I use the timer. That's all, you can process the value into the onInputChange function.
function onInputChange() {
console.log( document.getElementById('input_resultado').value );
}
document.addEventListener("keypress", function (e) {
if (e.target.tagName !== "INPUT") {
// it's your scanner
}
});
None of the solutions worked for me because I don't want to focus on an input. I want the result page(item details page) to keep listening for the scanner to scan next item. My scanner fires the keypress event so this worked like a charm for me.
var inputTemp = '';
var inputTempInterval = setInterval(function() {
// change 5 as minimum length of the scan code
if (inputTemp.length >= 5) {
var detected = inputTemp;
inputTemp = '';
clearInterval(inputTempInterval); // stop listening if you don't need anymore
onScannerTrigger(detected);
} else {
inputTemp = '';
}
}, 100);
$(window).keypress(function(e){
inputTemp += String.fromCharCode(e.which);
});
function onScannerTrigger(scannedCode) {
console.log(scannedCode);
// do your stuff
}
I have published a lightweight JS package which doesn't rely on jQuery or input fields. It simple looks at the timing of the keyPress-events to determine wether it was a barcode scanner or regular input.
https://www.npmjs.com/package/#itexperts/barcode-scanner
import {BarcodeScanner} from "#itexperts/barcode-scanner";
let options = {
timeOut: 130,
characterCount: 13
}
let barcodeScanner = new BarcodeScanner(options);
barcodeScanner.addEventListener('scan', function(e){
let barcode = e.detail;
console.log(barcode);
});
I highly recommend this js plugin https://github.com/axenox/onscan.js
It's easy to use and has tones of options to meet your need.
<script src="path-to-onScan.js"></script>
<script>
// Initialize with options
onScan.attachTo(document, {
suffixKeyCodes: [13], // enter-key expected at the end of a scan
reactToPaste: true, // Compatibility to built-in scanners in paste-mode (as opposed to keyboard-mode)
onScan: function(sCode, iQty) { // Alternative to document.addEventListener('scan')
console.log('Scanned: ' + iQty + 'x ' + sCode);
},
onKeyDetect: function(iKeyCode){ // output all potentially relevant key events - great for debugging!
console.log('Pressed: ' + iKeyCode);
}
});
</script>

Long Press in JavaScript?

Is it possible to implement "long press" in JavaScript (or jQuery)? How?
(source: androinica.com)
HTML
Long press
JavaScript
$("a").mouseup(function(){
// Clear timeout
return false;
}).mousedown(function(){
// Set timeout
return false;
});
There is no 'jQuery' magic, just JavaScript timers.
var pressTimer;
$("a").mouseup(function(){
clearTimeout(pressTimer);
// Clear timeout
return false;
}).mousedown(function(){
// Set timeout
pressTimer = window.setTimeout(function() { ... Your Code ...},1000);
return false;
});
Based on Maycow Moura's answer, I wrote this. It also ensures that the user didn't do a right click, which would trigger a long press and works on mobile devices. DEMO
var node = document.getElementsByTagName("p")[0];
var longpress = false;
var presstimer = null;
var longtarget = null;
var cancel = function(e) {
if (presstimer !== null) {
clearTimeout(presstimer);
presstimer = null;
}
this.classList.remove("longpress");
};
var click = function(e) {
if (presstimer !== null) {
clearTimeout(presstimer);
presstimer = null;
}
this.classList.remove("longpress");
if (longpress) {
return false;
}
alert("press");
};
var start = function(e) {
console.log(e);
if (e.type === "click" && e.button !== 0) {
return;
}
longpress = false;
this.classList.add("longpress");
if (presstimer === null) {
presstimer = setTimeout(function() {
alert("long click");
longpress = true;
}, 1000);
}
return false;
};
node.addEventListener("mousedown", start);
node.addEventListener("touchstart", start);
node.addEventListener("click", click);
node.addEventListener("mouseout", cancel);
node.addEventListener("touchend", cancel);
node.addEventListener("touchleave", cancel);
node.addEventListener("touchcancel", cancel);
You should also include some indicator using CSS animations:
p {
background: red;
padding: 100px;
}
.longpress {
-webkit-animation: 1s longpress;
animation: 1s longpress;
}
#-webkit-keyframes longpress {
0%, 20% { background: red; }
100% { background: yellow; }
}
#keyframes longpress {
0%, 20% { background: red; }
100% { background: yellow; }
}
You can use taphold event of jQuery mobile API.
jQuery("a").on("taphold", function( event ) { ... } )
I created long-press-event (0.5k pure JS) to solve this, it adds a long-press event to the DOM.
Listen for a long-press on any element:
// the event bubbles, so you can listen at the root level
document.addEventListener('long-press', function(e) {
console.log(e.target);
});
Listen for a long-press on a specific element:
// get the element
var el = document.getElementById('idOfElement');
// add a long-press event listener
el.addEventListener('long-press', function(e) {
// stop the event from bubbling up
e.preventDefault()
console.log(e.target);
});
Works in IE9+, Chrome, Firefox, Safari & hybrid mobile apps (Cordova & Ionic on iOS/Android)
Demo
While it does look simple enough to implement on your own with a timeout and a couple of mouse event handlers, it gets a bit more complicated when you consider cases like click-drag-release, supporting both press and long-press on the same element, and working with touch devices like the iPad. I ended up using the longclick jQuery plugin (Github), which takes care of that stuff for me. If you only need to support touchscreen devices like mobile phones, you might also try the jQuery Mobile taphold event.
For modern, mobile browsers:
document.addEventListener('contextmenu', callback);
https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu
jQuery plugin. Just put $(expression).longClick(function() { <your code here> });. Second parameter is hold duration; default timeout is 500 ms.
(function($) {
$.fn.longClick = function(callback, timeout) {
var timer;
timeout = timeout || 500;
$(this).mousedown(function() {
timer = setTimeout(function() { callback(); }, timeout);
return false;
});
$(document).mouseup(function() {
clearTimeout(timer);
return false;
});
};
})(jQuery);
$(document).ready(function () {
var longpress = false;
$("button").on('click', function () {
(longpress) ? alert("Long Press") : alert("Short Press");
});
var startTime, endTime;
$("button").on('mousedown', function () {
startTime = new Date().getTime();
});
$("button").on('mouseup', function () {
endTime = new Date().getTime();
longpress = (endTime - startTime < 500) ? false : true;
});
});
DEMO
For cross platform developers (Note All answers given so far will not work on iOS):
Mouseup/down seemed to work okay on android - but not all devices ie (samsung tab4). Did not work at all on iOS.
Further research its seems that this is due to the element having selection and the native magnification interupts the listener.
This event listener enables a thumbnail image to be opened in a bootstrap modal, if the user holds the image for 500ms.
It uses a responsive image class therefore showing a larger version of the image.
This piece of code has been fully tested upon (iPad/Tab4/TabA/Galaxy4):
var pressTimer;
$(".thumbnail").on('touchend', function (e) {
clearTimeout(pressTimer);
}).on('touchstart', function (e) {
var target = $(e.currentTarget);
var imagePath = target.find('img').attr('src');
var title = target.find('.myCaption:visible').first().text();
$('#dds-modal-title').text(title);
$('#dds-modal-img').attr('src', imagePath);
// Set timeout
pressTimer = window.setTimeout(function () {
$('#dds-modal').modal('show');
}, 500)
});
The Diodeus's answer is awesome, but it prevent you to add a onClick function, it'll never run hold function if you put an onclick. And the Razzak's answer is almost perfect, but it run hold function only on mouseup, and generally, the function runs even if user keep holding.
So, I joined both, and made this:
$(element).on('click', function () {
if(longpress) { // if detect hold, stop onclick function
return false;
};
});
$(element).on('mousedown', function () {
longpress = false; //longpress is false initially
pressTimer = window.setTimeout(function(){
// your code here
longpress = true; //if run hold function, longpress is true
},1000)
});
$(element).on('mouseup', function () {
clearTimeout(pressTimer); //clear time on mouseup
});
You could set the timeout for that element on mouse down and clear it on mouse up:
$("a").mousedown(function() {
// set timeout for this element
var timeout = window.setTimeout(function() { /* … */ }, 1234);
$(this).mouseup(function() {
// clear timeout for this element
window.clearTimeout(timeout);
// reset mouse up event handler
$(this).unbind("mouseup");
return false;
});
return false;
});
With this each element gets its own timeout.
This worked for me:
const a = document.querySelector('a');
a.oncontextmenu = function() {
console.log('south north');
};
https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/oncontextmenu
You can use jquery-mobile's taphold. Include the jquery-mobile.js and the following code will work fine
$(document).on("pagecreate","#pagename",function(){
$("p").on("taphold",function(){
$(this).hide(); //your code
});
});
Most elegant and clean is a jQuery plugin:
https://github.com/untill/jquery.longclick/,
also available as packacke:
https://www.npmjs.com/package/jquery.longclick.
In short, you use it like so:
$( 'button').mayTriggerLongClicks().on( 'longClick', function() { your code here } );
The advantage of this plugin is that, in contrast to some of the other answers here, click events are still possible. Note also that a long click occurs, just like a long tap on a device, before mouseup. So, that's a feature.
I needed something for longpress keyboard events, so I wrote this.
var longpressKeys = [13];
var longpressTimeout = 1500;
var longpressActive = false;
var longpressFunc = null;
document.addEventListener('keydown', function(e) {
if (longpressFunc == null && longpressKeys.indexOf(e.keyCode) > -1) {
longpressFunc = setTimeout(function() {
console.log('longpress triggered');
longpressActive = true;
}, longpressTimeout);
// any key not defined as a longpress
} else if (longpressKeys.indexOf(e.keyCode) == -1) {
console.log('shortpress triggered');
}
});
document.addEventListener('keyup', function(e) {
clearTimeout(longpressFunc);
longpressFunc = null;
// longpress key triggered as a shortpress
if (!longpressActive && longpressKeys.indexOf(e.keyCode) > -1) {
console.log('shortpress triggered');
}
longpressActive = false;
});
In vanila JS if need to detect long-click after click released:
document.addEventListener("mousedown", longClickHandler, true);
document.addEventListener("mouseup", longClickHandler, true);
let startClick = 0;
function longClickHandler(e){
if(e.type == "mousedown"){
startClick = e.timeStamp;
}
else if(e.type == "mouseup" && startClick > 0){
if(e.timeStamp - startClick > 500){ // 0.5 secound
console.log("Long click !!!");
}
}
}
May need to use timer if need to check long-click while clicking. But for most case after release click is enought.
For me it's work with that code (with jQuery):
var int = null,
fired = false;
var longclickFilm = function($t) {
$body.css('background', 'red');
},
clickFilm = function($t) {
$t = $t.clone(false, false);
var $to = $('footer > div:first');
$to.find('.empty').remove();
$t.appendTo($to);
},
touchStartFilm = function(event) {
event.preventDefault();
fired = false;
int = setTimeout(function($t) {
longclickFilm($t);
fired = true;
}, 2000, $(this)); // 2 sec for long click ?
return false;
},
touchEndFilm = function(event) {
event.preventDefault();
clearTimeout(int);
if (fired) return false;
else clickFilm($(this));
return false;
};
$('ul#thelist .thumbBox')
.live('mousedown touchstart', touchStartFilm)
.live('mouseup touchend touchcancel', touchEndFilm);
You can check the time to identify Click or Long Press [jQuery]
function AddButtonEventListener() {
try {
var mousedowntime;
var presstime;
$("button[id$='" + buttonID + "']").mousedown(function() {
var d = new Date();
mousedowntime = d.getTime();
});
$("button[id$='" + buttonID + "']").mouseup(function() {
var d = new Date();
presstime = d.getTime() - mousedowntime;
if (presstime > 999/*You can decide the time*/) {
//Do_Action_Long_Press_Event();
}
else {
//Do_Action_Click_Event();
}
});
}
catch (err) {
alert(err.message);
}
}
You can use jquery Touch events. (see here)
let holdBtn = $('#holdBtn')
let holdDuration = 1000
let holdTimer
holdBtn.on('touchend', function () {
// finish hold
});
holdBtn.on('touchstart', function () {
// start hold
holdTimer = setTimeout(function() {
//action after certain time of hold
}, holdDuration );
});
like this?
target.addEeventListener("touchstart", function(){
// your code ...
}, false);

Categories

Resources