Popover not hiding when leaving the textbox in Opera 12 - javascript

I'm using the following script to display popovers on focus with HTML support in Bootstrap 3:
$(document).ready(function () {
$(".focus-popover").each(function (index) {
var showPopover = function () {
$(this).popover('show');
};
var hidePopover = function () {
$(this).popover('hide');
};
$(this).popover({
html: true,
placement: $(this).attr('data-placement'),
trigger: 'manual'
})
.focus(showPopover)
.blur(hidePopover);
})
});
However this input ...
<input type="date" ID="test2" class="form-control focus-popover" data-original-title="This is my title" data-placement="top" data-container="body" data-content="Click away and see how this will be dismissed.<br />However, on Opera 12 it will remain."></input>
... is somehow bugged in Opera 12. Due the fact the input type is "date" and not "text" it will not hide the popover when leaving the textbox.
Please look at this Example in Opera 12 as well as any other browser.
What can I do to make it work properly?

Apparently the date-picker prevents the browser from triggering the blur event once it lost focus by clicking away.
It does triggers the blur event only if you keep tabbing to lost focus or by changing the values by picking a date.
So, basically a workaround could be emulating the blur event by using the click/focus of another element.
Workaround
$(document).ready(function () {
$(".focus-popover").each(function (index) {
var showPopover = function () {
$(this).popover('show');
};
var hidePopover = function () {
$(this).popover('hide');
};
$(this).popover({
html: true,
placement: $(this).attr('data-placement'),
trigger: 'manual'
})
.focus(showPopover)
.blur(hidePopover);
})
// The nasty Opera < 12 "workaround"
if ( window.opera && +window.opera.version() <= 13 ) {
var $buggyInput = $("#test2"), // Caching is important!
buggyInputFocus = false,
buggyFocus = function(event) {
event.stopPropagation();
if(!buggyInputFocus) {
$(this).popover('show');
buggyInputFocus = true;
}
},
buggyBlur = function(event) {
$(this).popover('hide');
buggyInputFocus = false;
}
;
// The focus also stop triggering if it was blurred then clicked back, so we added a click. It doesn't run buggyFocus twice since it only execute itself if it hasn't been focused first
$buggyInput.on({
"focus": buggyFocus,
"click": buggyFocus,
"blur":buggyBlur,
"change":buggyBlur // On change is also important, you don't want to leave it open when it changes
})
// Since it doesn't the blur event, we fake it by capturing focus or click on the html tag
$("html").on({
click: function() {
if ( buggyInputFocus ) $buggyInput.trigger("blur");
},
focus: function() {
if ( buggyInputFocus ) $buggyInput.trigger("blur");
}
})
}
});
Fiddle: http://jsfiddle.net/5wsq38u3/4/
EDIT: For more than 1 date input
$(document).ready(function () {
$(".focus-popover").each(function (index) {
var showPopover = function () {
$(this).popover('show');
};
var hidePopover = function () {
$(this).popover('hide');
};
$(this).popover({
html: true,
placement: $(this).attr('data-placement'),
trigger: 'manual'
})
.focus(showPopover)
.blur(hidePopover);
})
// The nasty Opera < 12 "workaround"
if (window.opera && +window.opera.version() < 13) {
var $buggyInputs = $(".operaFix"), // Caching is important!
buggyInputFocus = false,
buggyInput = {}, // We store an instance of the focused element
buggyFocus = function(event) {
event.stopPropagation();
if(!buggyInputFocus) {
$(buggyInput).popover('hide');
$(this).popover('show');
buggyInputFocus = true;
buggyInput = $(this);
}
else if ($(buggyInput).attr("id") !== $(this).attr("id")){
$(buggyInput).trigger("blur")
}
},
buggyBlur = function(event) {
$(this).popover('hide');
buggyInputFocus = false;
buggyInput = {}
}
;
// The focus also stop triggering if it was blurred then clicked back, so we added a click. It doesn't run buggyFocus twice since it only execute itself if it hasn't been focused first
$buggyInputs.on({
"focus": buggyFocus,
"click": buggyFocus,
"blur": buggyBlur,
"change": buggyBlur // On change is also important, you don't want to leave it open when it changes
})
// Since it doesn't the blur event, we fake it by capturing focus or click on the html tag
$("html").on({
click: function() {
if (buggyInputFocus) $(buggyInput).trigger("blur");
},
focus: function() {
if (buggyInputFocus) $(buggyInput).trigger("blur");
}
})
}
});
JSBin: http://jsbin.com/xucagomutera/1/edit

Related

Call a onkeyup function when click on other button jQuery

I have function which has keyup event on input field which is working fine.
I want to trigger this function also upon click on other button.
Here is my function
function validateChild(el) {
var validated = {};
console.log('Remove button clicked');
var dateOfBirthField = $(el).find('.date_of_birth');
$(dateOfBirthField).on("keyup", function () {
var dateOfBirthValue = $(el).find('.date_of_birth').val();
console.log('Check DoB');
if(validateDateOfBirth(dateOfBirthValue, dateOfBirthField)){
console.log('True');
validated.dateOfBirth = true;
} else {
validated.dateOfBirth = false;
}
validateButton(validated);
});
}
I'm calling this function on document load
function validateForms() {
$(document).find(".child-form").each(function () {
validateChild(this);
});
}
Here i have click event
.on('click', '.removeButton', function (event) {
validateForms();
});
When i click on this remove button it trigger but stop working after this
console.log('Remove button clicked');
How can i trigger keyup event also on this remove button, or there is better way to do this in javascript.
Can anyone help me with this?
Thanks
I have reviewed your three code blocks. Please try following three code blocks respectively.
Your function
function validateChild(dateOfBirthField) {
var validated = {};
var dateOfBirthValue = $(dateOfBirthField).val();
console.log('Check DoB');
if(validateDateOfBirth(dateOfBirthValue, dateOfBirthField)){
console.log('True');
validated.dateOfBirth = true;
} else {
validated.dateOfBirth = false;
}
validateButton(validated);
}
Call this function on document load
function validateForms() {
$('.child-form').on('keyup', '.date_of_birth', function() {
validateChild(this);
});
}
Click event
.on('click', '.removeButton', function() {
console.log('Remove button clicked');
$('.child-form .date_of_birth').each(function() {
validateChild(this);
});
});

Script doesn't work if misplaced in jQuery

i will create website with validate in input field, i used Mottie Keyboard in every input field, and i use validation on it. i will create disable button when validation is not correct. And I get a script for it, directly from github page mottie keyboard. I want is if the validation was not correct then the button in a virtual keyboard can not be pressed. Here's the script:
var toggleKeysIfEmpty = function( kb ) {
var toggle = kb.$preview.val() === '';
console.log( toggle, kb.$preview.val() );
kb.$keyboard
.find('.ui-keyboard-bksp')
.toggleClass('disabled', toggle)
.prop('disabled', toggle);
};
And this my script before adding script above:
$(function() {
// change default navigation keys
$('#jkeyboard2, #jkeyboard').keyboard({
layout: 'num',
// setting alwaysOpen does odd things with input focus on initialization
// best to leave it false and focus on the desired input
// alwaysOpen: true,
autoAccept: true,
usePreview: false,
position: {
of: $(window),
// null (attach to input/textarea) or a jQuery object (attach elsewhere)
my: 'center bottom',
at: 'center bottom',
at2: 'center bottom'
},
maxLength: 4,
layout: 'custom',
customLayout: {
'normal': ['1 2 3', '4 5 6', '7 8 9', '0 . {b}'],
},
visible : function(e, keyboard) {
toggleKeysIfEmpty( keyboard );
},
tabNavigation: true,
initialFocus: false,
initialized: function() {
setTimeout(function(){
$('#jkeyboard').focus();
}, 200);
},
change: function(e, keyboard, el) {
if (keyboard.$el.val().length >= 4) {
// switchInput( goToNext, isAccepted );
keyboard.switchInput(true, true);
} else if (keyboard.$el.val() === "" && keyboard.last.key === "bksp") {
// go to previous if user hits backspace on an empty input
keyboard.switchInput(false, true);
}
}
})
});
$(document).ready(function() {
$('#jkeyboard').bind('keyboardChange', function (e, keyboard, el) {
if (validatePhone('jkeyboard')) {
$('#spnPhoneStatus').html('');
$('#spnPhoneStatus').css('color', 'green');
} else {
$('#spnPhoneStatus').html('<b>Wrong Number</b>');
$('#spnPhoneStatus').css('color', 'red');
}
});
});
function validatePhone(jkeyboard) {
var a = document.getElementById(jkeyboard).value;
var filter = /^0(?:8(?:(?:1(?:[789][0-9]{0,9})?|3(?:[1238][0-9]{0,9})?|5(?:9[0-9]{0,9})?|7(?:[78][0-9]{0,9})?)?)?)?$/;
//var filter = /^0([8]([1357]([123789]([0-9]{0,8}))?)?)?$/;
if (filter.test(a)) {
return true;
} else {
return false;
}
}
I want disable backspace button if validation was not correct, so i added the script. And become like this:
$(function() {
// change default navigation keys
$('#jkeyboard2, #jkeyboard').keyboard({
layout: 'num',
// setting alwaysOpen does odd things with input focus on initialization
// best to leave it false and focus on the desired input
// alwaysOpen: true,
autoAccept: true,
usePreview: false,
position: {
of: $(window),
// null (attach to input/textarea) or a jQuery object (attach elsewhere)
my: 'center bottom',
at: 'center bottom',
at2: 'center bottom'
},
maxLength: 4,
layout: 'custom',
customLayout: {
'normal': ['1 2 3', '4 5 6', '7 8 9', '0 . {b}'],
},
visible : function(e, keyboard) {
toggleKeysIfEmpty( keyboard );
},
tabNavigation: true,
initialFocus: false,
initialized: function() {
setTimeout(function(){
$('#jkeyboard').focus();
}, 200);
},
change: function(e, keyboard, el) {
if (keyboard.$el.val().length >= 4) {
// switchInput( goToNext, isAccepted );
keyboard.switchInput(true, true);
} else if (keyboard.$el.val() === "" && keyboard.last.key === "bksp") {
// go to previous if user hits backspace on an empty input
keyboard.switchInput(false, true);
}
}
})
});
$(document).ready(function() {
$('#jkeyboard').bind('keyboardChange', function (e, keyboard, el) {
if (validatePhone('jkeyboard')) {
$('#spnPhoneStatus').html('');
$('#spnPhoneStatus').css('color', 'green');
} else {
$('#spnPhoneStatus').html('<b>Wrong Number</b>');
$('#spnPhoneStatus').css('color', 'red');
var toggleKeysIfEmpty = function( kb ) {
var toggle = kb.$preview.val() === '';
console.log( toggle, kb.$preview.val() );
kb.$keyboard
.find('.ui-keyboard-bksp')
.toggleClass('disabled', toggle)
.prop('disabled', toggle);
};
}
});
});
function validatePhone(jkeyboard) {
var a = document.getElementById(jkeyboard).value;
var filter = /^0(?:8(?:(?:1(?:[789][0-9]{0,9})?|3(?:[1238][0-9]{0,9})?|5(?:9[0-9]{0,9})?|7(?:[78][0-9]{0,9})?)?)?)?$/;
//var filter = /^0([8]([1357]([123789]([0-9]{0,8}))?)?)?$/;
if (filter.test(a)) {
return true;
} else {
return false;
}
}
it's doesn't work, and i try put the code i get at the top of my code. it's work but backspace button can not be pressed from the start. Anyone can fix it?
Here's my fiddle: DEMO
I have changed your code to update the fiddle here : you wanted to
disable backspace button if validation was not correct
so here's what I did:
I renamed toggleKeysIfEmpty to toggleBackspaceKey and changed its implementation to add the CSS classes to render the button correctly depending on the desired state:
var toggleBackspaceKey = function( kb, toggle ) {
console.log( toggle, kb.$preview.val() );
var $bkSpaceBtn = kb.$keyboard.find('.ui-keyboard-bksp');
if (toggle) {
$bkSpaceBtn
.attr({
'disabled': 'disabled',
'aria-disabled': 'true'
})
.removeClass(kb.options.css.buttonHover)
.addClass(kb.options.css.buttonDisabled);
} else {
$bkSpaceBtn
.removeAttr('disabled')
.attr({
'aria-disabled': 'false'
})
.addClass(kb.options.css.buttonDefault)
.removeClass(kb.options.css.buttonDisabled);
}
};
I changed the implementation of the bksp keyaction handler to ensure that if it's invoked when the button is disabled, no action is executed. The handler for the backspace will be invoked if you press the corresponding key or if you double click on the backspace button in the keyboard even when it's disabled (this might be a bug). Here is the handler code: if the backspace button is enabled it simply invokes the default backspace processing handler. Also, this function is invoked once from the visible callback:
var processBkSpcKey = function(kb) {
var originalBkSpaceHandler = $.keyboard.keyaction.bksp;
$.keyboard.keyaction.bksp = function(base) {
// If the backspace button is disabled, do not process it.
var $bkSpaceBtn = kb.$keyboard.find('.ui-keyboard-bksp');
if($bkSpaceBtn.hasClass(kb.options.css.buttonDisabled)) {
return false;
}
return originalBkSpaceHandler.apply(kb, arguments);
}
};
With these changes in place, the backspace button is disabled if the input is empty or if the validation fails, in this case though, how would the user clear the contents of the input?

Need to simulate keypress jquery

I have a function that uses the value of a textbox (prodinput) to hide/show links in a dropdown list. It works when a user types in a string manually but when I want to auto-populate the value by passing a url parameter I'll need to trigger a keyup or keydown to get it to call the function.
Here is the function that does the search (located in the core.js):
prodinput.on('keyup, keydown',function() {
var search = $(this).val().toLowerCase();
$('.support-product .browse-products a').each(function() {
if($(this).text().toLowerCase().search(search) > -1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
});
Here is the function I'm using to trigger the function above (located on the page I'm trying to run it on.
$(function(){
$target = $('.browse-products .display');
$target.val($trimmed);
$('.browse-products').addClass('active');
$target.focus();
var e = jQuery.Event( "keydown" );
$target.trigger(e);
});
I've tried using:
$target.keyup();
and as shown above:
var e = jQuery.Event( "keydown" );
$target.trigger(e);
I'm wondering if it's a problem with the order in which things load on the page.
I'd put your keyup code in a named function.
$(function () {
myFunction();
prodinput.on('keyup, keydown', function () {
myFunction();
})
};
var myFunction = function () {
var search = $('#prodinput').val().toLowerCase();
$('.support-product .browse-products a').each(function () {
if ($(this).text().toLowerCase().search(search) > -1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
};
Assuming you don't need to support ancient browsers you can just listen for the input event which covers keypress and change events. Then after attaching the listener simply trigger the event:
$(function() {
$("#prodinput").on('input', function() {//alternatively you could use change and keyup
var search = $(this).val().toLowerCase();
$('.support-product .browse-products a').each(function() {
if ($(this).text().toLowerCase().search(search) > -1) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
}).trigger("input");//trigger the event now
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="search" id="prodinput" value="peanuts" />
<div class="support-product">
<ul class="browse-products">
<li>jam</li>
<li>elephants</li>
<li>peanuts</li>
</ul>
</div>

How can I disable mouse hover effect when user is using keyboard?

I'm trying to implement a search as you type feature on my site. I'm working on the front-end side right now and using mockjax to pull in fake data.
My problem: When the drop down menu pops up you have the option to go over your choices (which highlight in yellow). I realized today though that if your using the arrow keys to scroll through your choices and move your mouse over the menu then it will cause two options to be highlighted! I don't want to confuse my users so I only want it to highlight one at a time. If they are using their keyboard and hover over with the mouse than the keyboard selection would jump to where the mouse is.
(In case I'm not being clear and you need an example, go to amazon and use their search with your arrow keys and then hover the mouse over an option, it changes. I want it like that!)
Most of the html, css and mockjax can't be included in this fiddle so it looks funky- but just case someone needs to see my code.
http://jsfiddle.net/2JGHu/
(function (Backbone, _, context) {
"use strict";
var SuggestiveSearch = Backbone.View.extend({
tracking: function (action, label) {
_gaq.push(['_trackEvent', 'SearchAsYouType2.0', action, label]);
},
fetchTemplate: function (name) {
var callback = _.bind(function (template) {
this.template = tmpl(template);
}, this);
$.get("/js/templates/" + name + ".html", callback);
},
close: function () {
this.$suggestionList.addClass("hide");
this.tracking('Close', 'Clicked-Off');
// Reset our list selection index
this.model.set("currentIndex", null);
},
open: function () {
this.$suggestionList.removeClass("hide");
this.tracking('Open', 'Clicked-On');
},
preventCloseHandler: function (e) {
e.stopPropagation();
},
directionSelectionHandler: function (keyCode) {
var currentIndex = this.model.get("currentIndex"),
incr = keyCode === 40 ? 1 : -1,
newIndex = currentIndex + incr,
choicesLen = this.$choices.length - 1,
isOutOfRange = newIndex > choicesLen || newIndex < 0;
// If index is out of range set it either to the first or last choice
if (isOutOfRange) {
newIndex = newIndex < 0 ? choicesLen : 0;
}
// Remove previous selected
// class on li's
this.$choices
.removeClass("is-selected");
this.$choices
.eq(newIndex)
.addClass("is-selected");
// Store our index
this.model.set("currentIndex", newIndex);
},
enterHandler: function (e) {
var currentIndex = this.model.get("currentIndex");
if (currentIndex !== 0) {
this.tracking('Enter', 'Selected-Choice');
window.location = this.$choices.eq(currentIndex).find("a").attr('href');
}
},
keyDownHandler: function (e) {
var keyCode = e.which,
isArrowKeys = keyCode === 40 || keyCode === 38;
if (!isArrowKeys) {
return;
}
e.preventDefault();
},
keyUpHandler: function (e) {
var $input = $(e.currentTarget),
query = $input.val(),
keyCode = e.which;
switch (keyCode) {
case 40:
case 38:
this.directionSelectionHandler(keyCode);
this.tracking('Keyboard navigate', 'Selected-Choice');
e.preventDefault();
break;
case 13:
this.enterHandler(e);
break;
default:
this.model.set("query", query);
}
},
choiceClickHandler: function (e) {
this.tracking('Click', 'Selected-Choice');
e.stopPropagation();
},
render: function () {
this.$suggestionList
.html(this.template(_.pick(this.model.attributes, "ProductSuggestions", "FilterSuggestions")));
// Store our list of choices but also add our already cached input to that collection
this.$choices = this.$suggestionList.find(".autocomplete__choice", this.$el).add(this.$input);
this.open();
},
events: {
"keyup input": "keyUpHandler",
"keydown input": "keyDownHandler",
"click .autocomplete__choice": "choiceClickHandler",
"click": "preventCloseHandler"
},
bindings: function () {
this.listenTo(this.model, "sync", this.render);
$(document).on('click', _.bind(this.close, this));
},
initialize: function () {
this.fetchTemplate("suggestions");
this.$suggestionList = this.$el.find(".autocomplete");
this.$input = this.$el.find("input");
this.bindings();
}
});
context.Views = context.Views || {};
context.Views.SuggestiveSearch = SuggestiveSearch;
}(Backbone, _, =|| {}));
Let me know if I need to include anymore information. Thank you in advance!
Since your JSFiddle doesn't produce the behavior, it's not easy for me to write code that solves your problem, but I can give you advice that might help you do it yourself.
The way I recommend solving this issue is by removing the .hover highlighting in your CSS and implementing a function that adds the class is-selected to an object when it is being hovered over and removing the class from all other elements. That way it will be compatible with your current directionSelectionHandler:

disable text selection except input

I've got this snippet of code to disable all text selection. How would I go about disabling all text except for input? I tried $('* :not(input)').disableTextSelect(); but it disabled selection for everything (input included)
$.extend($.fn.disableTextSelect = function () {
return this.each(function () {
if ($.browser.mozilla) {//Firefox
$(this).css('MozUserSelect', 'none');
} else if ($.browser.msie) {//IE
$(this).bind('selectstart', function () { return false; });
} else {//Opera, etc.
$(this).mousedown(function () { return false; });
}
});
});
$('* :not(input)').disableTextSelect();
$(document).bind('mousedown selectstart', function(e) {
return $(e.target).is('input, textarea, select, option, html');
});
Thanks to #user2873592, who mentioned that adding html here would fix the chrome scroll bar can't be dragged issue.
This works in IE and FF:
jQuery(document).ready(function () {
//Disable default text selection behavior
toggleEnableSelectStart(false);
//for inputs it must be possible to select text
jQuery("input[type=text]").focusin(function () { toggleEnableSelectStart(true); });
jQuery("input[type=text]").mouseover(function () { toggleEnableSelectStart(true); });
jQuery("input[type=text]").focusout(function () { toggleEnableSelectStart(false); });
jQuery("input[type=text]").mouseout(function () { toggleEnableSelectStart(false); });
});
function toggleEnableSelectStart(enable) {
document.onmousedown = function (e) { return enable; };
document.onselectstart = function (e) { return enable; }; ;
}
The problem seems to be that this disabling is inherited. So, even though you aren't selected them in the $() they still get disabled. But this can also be in our favor.
After disabling, you can enable the inputs.
$('body').css('MozUserSelect', '-moz-none');
$('input').css('MozUserSelect', 'text');
NOTE: the value must be '-moz-none'. If 'none', it can't be changed.
I can't test IE nor do I have a solution for Opera. But maybe this will help part way.

Categories

Resources