Related
new_line=function()
{
var conteiner=document.createElement('div');
conteiner.classList.add('conteiner');
conteiner.addEventListener('click', function (event){on_click(event, conteiner);}, false);//this is an anonymous function so it is always new
document.body.appendChild(conteiner);
create_el(conteiner);
};
I have this function and in it addEventListener. I know that when I'm giving: function (event){on_click(event, conteiner);} I can't remove this EventListener, but I need give on_click function second parameter.
delete_conteiner=function(which)
{
which.removeEventListener("click", function (event){on_click(event, conteiner);}, false);//this isn't working
document.body.removeChild(which);
};
Is it posible to add EventListener, which execute on_click, and than remove it in oder EventListener? Here full code:
(function()
{
var create_ul, user_names, menage_ul, open, look_for, save_as, user_name, real_name, on_click, set_up, create_el, show_hide_btn_click, delete_el, on_load, get_object_to_save, change_all, save, delete_conteiner, change_see_able, restart, new_line, new_cubes, scroll_with_ctrl;
create_el=function(where, options)
{
var configs=options || {
class_names:'textbox',
value:''
};
var block=document.createElement('textarea');
block.className=configs.class_names;
block.value=configs.value;
where.appendChild(block);
};
delete_el=function(where, which)
{
where.removeChild(which);
};
delete_conteiner=function(which)
{
which.removeEventListener("click", function(event){on_click(event, conteiner);}, false);//I know that won't work
document.body.removeChild(which);
};
change_see_able=function(where)
{
var is_see_able=true;
where.classList.forEach(function(str){
if(str=='none_see_able')
{
is_see_able=false;
}
});
if(is_see_able)
{
where.classList.add('none_see_able');
}
else
{
where.classList.remove('none_see_able');
}
};
on_click=function(ev, conteiner)
{
var is_box_cliked=false;
ev.target.classList.forEach(function(className){
if(className=='textbox')
{
is_box_cliked=true;
}
});
if(is_box_cliked)
{
if(ev.shiftKey)
{
if(!ev.ctrlKey)
{
if(!ev.altKey)
{
create_el(conteiner);
}
}
}
else if(ev.ctrlKey)
{
if(!ev.altKey)
{
delete_el(conteiner, ev.target);
}
}
else if(ev.altKey)
{
change_see_able(ev.target);
}
else
{}
}
else
{
if(ev.ctrlKey)
{
delete_conteiner(conteiner);
}
else
{
if((conteiner.querySelector('.textbox')==null) || ev.shiftKey)
{
create_el(conteiner);
}
}
}
};
get_object_to_save=function()
{
var conteiners=document.body.querySelectorAll('.conteiner'), conteiners_to_save=Array();
conteiners.forEach(function(textboxes){
var textboxes=textboxes.querySelectorAll('.textbox'), textboxes_to_save=Array();
textboxes.forEach(function(textbox){
var textbox_to_save={
class_names:textbox.className,
value:textbox.value
};
textboxes_to_save.push(textbox_to_save);
});
conteiners_to_save.push(textboxes_to_save);
});
return [user_name, JSON.stringify(conteiners_to_save)];
};
new_line=function()
{
var conteiner=document.createElement('div');
conteiner.classList.add('conteiner');
create_el(conteiner);
conteiner.addEventListener('click', function(event){on_click(event, conteiner);}, false);
document.body.appendChild(conteiner);
};
load=function(conteiners)
{
if(conteiners.length===0)
{
new_line();
}
else
{
conteiners.forEach(function(textboxes){
var conteiner=document.createElement('div');
conteiner.classList.add('conteiner');
conteiner.addEventListener('click', function(event){
on_click(event, conteiner);
}, false);
document.body.appendChild(conteiner);
textboxes.forEach(function(options_for_textbox){
create_el(conteiner, options_for_textbox);
});
});
}
}
save=function()
{
localStorage.setItem(real_name, JSON.stringify(get_object_to_save()));
};
look_for=function()
{
for(i=localStorage.length-1; i>=0; i--)
{
if(localStorage.key(i)!='name_last')
{
if(user_name===JSON.parse(localStorage.getItem(localStorage.key(i)))[0])
{
return [true, localStorage.key(i)];
}
}
}
user_names.push(user_name);
localStorage.setItem('names', JSON.stringify(user_names));
return [false, 'c_'+new Date().getTime()];
};
open=function()
{
if(document.querySelector('.buttons > .open > input').value!='')
{
var conteiners=document.querySelectorAll('.conteiner');
conteiners.forEach(function(conteiner)
{
delete_conteiner(conteiner);
});
user_name=document.querySelector('.buttons > .open > input').value;
document.querySelector('.buttons > .open > input').value='';
var is=look_for();
real_name=is[1];
localStorage.setItem('name_last', real_name);
if(!is[0])
{
localStorage.setItem(real_name, JSON.stringify([user_name, JSON.stringify(new Array())]));
}
conteiners=JSON.parse(JSON.parse(localStorage.getItem(real_name))[1]);
load(conteiners);
}
};
save_as=function()
{
if(document.querySelector('.buttons > .save_as > input').value!='')
{
user_name=document.querySelector('.buttons > .save_as > input').value;
document.querySelector('.buttons > .save_as > input').value='';
real_name=look_for();
localStorage.setItem('name_last', real_name);
localStorage.setItem(real_name, JSON.stringify(get_object_to_save()));
}
};
on_load=function()
{
var name=localStorage.getItem('name_last');
if(localStorage.length===0)
{
user_names=new Array();
localStorage.setItem('names', JSON.stringify(new Array()));
user_name='first';
real_name=look_for()[1];
localStorage.setItem('name_last', real_name);
localStorage.setItem(real_name, JSON.stringify([user_name, JSON.stringify(new Array())]));
}
else
{
real_name=name;
user_name=JSON.parse(localStorage.getItem(real_name))[0];
user_names=JSON.parse(localStorage.getItem('names'));
}
var conteiners=JSON.parse(JSON.parse(localStorage.getItem(real_name))[1]);
load(conteiners);
};
new_cubes=function()
{
var conteiners=document.querySelectorAll('.conteiner');
conteiners.forEach(function(conteiner){
create_el(conteiner);
});
};
restart=function()
{
var conteiners=document.querySelectorAll('.conteiner');
conteiners.forEach(function(conteiner){
delete_conteiner(conteiner);
});
new_line();
};
change_all=function()
{
var value=document.querySelector('.buttons > .to_all > textarea').value;
document.querySelector('.buttons > .to_all > textarea').value='';
var textboxes=document.querySelectorAll('.textbox');
textboxes.forEach(function(textbox){
textbox.value=value;
});
};
set_size=function()
{
//textareas in menu prepare for calculations
var textareas=document.querySelectorAll('label textarea');
textareas.forEach(function(textarea){
textarea.style.height='0px';
});
//inputs in menu prepare for calculations
var inputs=document.querySelectorAll('label input');
inputs.forEach(function(input){
input.style.height='0px';
});
//show_hide_btn prepare for calculations
var show_hide_btn=document.querySelector('.button.show_hide_menu');
show_hide_btn.style.height='0px';
//get height for textareas and inputs
var width=textareas[0].offsetWidth+'px';
var height=document.querySelector('.to_all .to_all').offsetHeight+'px';
var uls=document.querySelectorAll('label ul');
uls.forEach(function(ul){
ul.style.bottom=height;
});
//textareas set height
textareas.forEach(function(textarea){
textarea.style.height=height;
});
//inputs set height
inputs.forEach(function(input){
input.style.height=height;
input.style.width=width;
});
//show_hide_btn set height
show_hide_btn.style.height=document.querySelector('.buttons_place').offsetHeight+'px';
};
show_hide_btn_click=function(btn)
{
if(btn.style.transform==='')
{
document.querySelector('.buttons_place').style.transform='translateX('+document.querySelector('.buttons').offsetWidth+'px)'
btn.style.transform='rotateY(180deg)';
setTimeout(function()
{
btn.style.borderTopLeftRadius='0';
btn.style.borderBottomLeftRadius='0';
btn.style.borderTopRightRadius='10px';
btn.style.borderBottomRightRadius='10px';
}, 750);
}
else
{
document.querySelector('.buttons_place').style.transform='';
btn.style.transform='';
setTimeout(function()
{
btn.style.borderTopLeftRadius='';
btn.style.borderBottomLeftRadius='';
btn.style.borderTopRightRadius='';
btn.style.borderBottomRightRadius='';
}, 750);
}
};
ul_click=function(where, value)
{
where.querySelector('input').value=value;
};
create_ul=function(where, names_to_show)
{
var ul=where.querySelectorAll('ul');
if(ul!=null)
{
ul.forEach(function(ul_one_object)
{
where.removeChild(ul_one_object);
});
}
if(names_to_show.length!=0)
{
ul=document.createElement('ul');
names_to_show.forEach(function(name)
{
var li=document.createElement('li');
li.textContent=name;
ul.appendChild(li);
});
ul.addEventListener('click', function(ev){ul_click(where, ev.target.textContent);}, false);
ul.style.bottom=document.querySelector('.to_all .to_all').offsetHeight+'px';
where.appendChild(ul);
}
};
menage_ul=function(label, value)
{
var names_to_show=user_names.filter(function(name){
return name.indexOf(value)==0;
});
create_ul(label, names_to_show)
};
set_up=function()
{
var show_hide_btn=document.querySelector('.button.show_hide_menu');
show_hide_btn.addEventListener('click', function(event){show_hide_btn_click(show_hide_btn);}, false);
var width=document.body.offsetWidth;
setInterval(function()
{
if(width!=document.body.offsetWidth)
{
width=document.body.offsetWidth;
set_size();
}
}, 500);
set_size();
var add_new_line_btn=document.querySelector('.new_line');
add_new_line_btn.addEventListener('click', new_line, false);
var add_new_cubes_btn=document.querySelector('.new_cubes');
add_new_cubes_btn.addEventListener('click', new_cubes, false);
var restart_btn=document.querySelector('.restart');
restart_btn.addEventListener('click', restart, false);
var save_structure_btn=document.querySelector('.save');
save_structure_btn.addEventListener('click', save, false);
var to_all_btn=document.querySelector('.to_all .to_all');
to_all_btn.addEventListener('click', change_all, false);
var save_as_btn=document.querySelector('.save_as .save_as');
save_as_btn.addEventListener('click', save_as, false);
var open_btn=document.querySelector('.open .open');
open_btn.addEventListener('click', open, false);
var labels=document.querySelectorAll('label');
labels.forEach(function(label)
{
var input=label.querySelector('input');
if(input!=null)
{
input.addEventListener('keyup', function(ev){menage_ul(label, input.value);}, false);
}
});
on_load();
};
set_up();
})();
The removeEventListener() method removes an event handler that has been attached with the addEventListener() method.
Note: To remove event handlers, the function specified with the addEventListener() method must be an external function, like in the example below (click_event_func).
Anonymous functions, like "function (event){on_click(event, conteiner);}" will not work.
click_event_func = function(event) {
on_click(event, conteiner);
};
new_line = function() {
var conteiner = document.createElement('div');
conteiner.classList.add('conteiner');
conteiner.addEventListener('click', click_event_func, false);
document.body.appendChild(conteiner);
create_el(conteiner);
};
delete_conteiner = function(which) {
which.removeEventListener("click", click_event_func, false);
document.body.removeChild(which);
};
If you want to pass another param to an event listener you have to bind it to the function, as eventlistener will only pass the event itself (click event in your example). If you pass the exact same params and the same function when you remove it will remove it successfuly according to MDN.
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
I think your problem is you don't use named functions.
Try to do like this:
function NameHere(event) { on_click(event, conteiner); }
new_line=function() {
var conteiner=document.createElement('div');
conteiner.classList.add('conteiner');
conteiner.addEventListener('click', NameHere, false);
document.body.appendChild(conteiner);
create_el(conteiner);
};
delete_conteiner=function(which) {
which.removeEventListener("click", NameHere, false);//this isn't working
document.body.removeChild(which);
};
The problem is when you try to remove the listener without using names, you will remove a different function from the one you added before.
By example:
which.removeEventListener("click", function (event){on_click(event, conteiner);}, false);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// This here creates a new function. It's not related to
// the function you created with addEventListener earlier.
// Trying to remove it from eventlisteners on "which" is silly
// because it doesn't exist there.
Instead:
var eventHandler = function(event){on_click(event, conteiner);}; // Store for later
conteiner.addEventListener('click', eventHandler); // Add.
conteiner.removeEventListener('click', eventHandler); // Remove.
You can remove eventListeners as long as you referencing the same function.
I am using 'jquery.ui.autocomplete.js'. What issue I am facing is that during TAB Press default Naviagtion get stuck
when it reached in Autocomplete Text Box. The issue is reflecting only in Mozilla Firefox. What I want is that on TAB key press
it shold move to next elemnt. Can anyone please assist me to fix this issue?
I have tried Googled solutions but not able to fix. I am posting some link hope it will help you to understand isue.
1. http://bugs.jqueryui.com/ticket/6661
I think issue is somewhere in these lines:
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.menu.element.is(":visible")) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;
case keyCode.ESCAPE:
self.element.val(self.term);
self.close(event);
break;
default:
// keypress is triggered before the input value is changed
clearTimeout(self.searching);
self.searching = setTimeout(function () {
// only search if the value has changed
if (self.term != self.element.val()) {
self.selectedItem = null;
self.search(null, event);
}
}, self.options.delay);
break;
}
})
My jquery code is here:
(function ($, undefined) {
$.widget("ui.autocomplete", {
options: {
appendTo: "body",
delay: 300,
minLength: 1,
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
source: null
},
_create: function () {
var self = this,
doc = this.element[0].ownerDocument;
this.element
.addClass("ui-autocomplete-input")
.attr("autocomplete", "off")
// TODO verify these actually work as intended
.attr({
role: "textbox",
"aria-autocomplete": "list",
"aria-haspopup": "true"
})
.bind("keydown.autocomplete", function (event) {
if (self.options.disabled || self.element.attr("readonly")) {
return;
}
var keyCode = $.ui.keyCode;
switch (event.keyCode) {
case keyCode.PAGE_UP:
self._move("previousPage", event);
break;
case keyCode.PAGE_DOWN:
self._move("nextPage", event);
break;
case keyCode.UP:
self._move("previous", event);
// prevent moving cursor to beginning of text field in some browsers
event.preventDefault();
break;
case keyCode.DOWN:
self._move("next", event);
// prevent moving cursor to end of text field in some browsers
event.preventDefault();
break;
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.menu.element.is(":visible")) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;
case keyCode.ESCAPE:
self.element.val(self.term);
self.close(event);
break;
default:
// keypress is triggered before the input value is changed
clearTimeout(self.searching);
self.searching = setTimeout(function () {
// only search if the value has changed
if (self.term != self.element.val()) {
self.selectedItem = null;
self.search(null, event);
}
}, self.options.delay);
break;
}
})
.bind("focus.autocomplete", function () {
if (self.options.disabled) {
return;
}
self.selectedItem = null;
self.previous = self.element.val();
})
.bind("blur.autocomplete", function (event) {
if (self.options.disabled) {
return;
}
clearTimeout(self.searching);
// clicks on the menu (or a button to trigger a search) will cause a blur event
self.closing = setTimeout(function () {
self.close(event);
self._change(event);
}, 150);
});
this._initSource();
this.response = function () {
return self._response.apply(self, arguments);
};
this.menu = $("<ul></ul>")
.addClass("ui-autocomplete")
.appendTo($(this.options.appendTo || "body", doc)[0])
// prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
.mousedown(function (event) {
// clicking on the scrollbar causes focus to shift to the body
// but we can't detect a mouseup or a click immediately afterward
// so we have to track the next mousedown and close the menu if
// the user clicks somewhere outside of the autocomplete
var menuElement = self.menu.element[0];
if (event.target === menuElement) {
setTimeout(function () {
$(document).one('mousedown', function (event) {
if (event.target !== self.element[0] &&
event.target !== menuElement &&
!$.ui.contains(menuElement, event.target)) {
self.close();
}
});
}, 1);
}
// use another timeout to make sure the blur-event-handler on the input was already triggered
setTimeout(function () {
clearTimeout(self.closing);
}, 13);
})
.menu({
focus: function (event, ui) {
var item = ui.item.data("item.autocomplete");
if (false !== self._trigger("focus", null, { item: item })) {
// use value to match what will end up in the input, if it was a key event
if (/^key/.test(event.originalEvent.type)) {
self.element.val(item.value);
}
}
},
selected: function (event, ui) {
var item = ui.item.data("item.autocomplete"),
previous = self.previous;
// only trigger when focus was lost (click on menu)
if (self.element[0] !== doc.activeElement) {
self.element.focus();
self.previous = previous;
}
if (false !== self._trigger("select", event, { item: item })) {
self.element.val(item.value);
}
self.close(event);
self.selectedItem = item;
},
blur: function (event, ui) {
// don't set the value of the text field if it's already correct
// this prevents moving the cursor unnecessarily
if (self.menu.element.is(":visible") &&
(self.element.val() !== self.term)) {
self.element.val(self.term);
}
}
})
.zIndex(this.element.zIndex() + 1)
// workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
.css({ top: 0, left: 0 })
.hide()
.data("menu");
if ($.fn.bgiframe) {
this.menu.element.bgiframe();
}
},
destroy: function () {
this.element
.removeClass("ui-autocomplete-input")
.removeAttr("autocomplete")
.removeAttr("role")
.removeAttr("aria-autocomplete")
.removeAttr("aria-haspopup");
this.menu.element.remove();
$.Widget.prototype.destroy.call(this);
},
_setOption: function (key, value) {
$.Widget.prototype._setOption.apply(this, arguments);
if (key === "source") {
this._initSource();
}
if (key === "appendTo") {
this.menu.element.appendTo($(value || "body", this.element[0].ownerDocument)[0])
}
},
_initSource: function () {
var array,
url;
if ($.isArray(this.options.source)) {
array = this.options.source;
this.source = function (request, response) {
response($.ui.autocomplete.filter(array, request.term));
};
} else if (typeof this.options.source === "string") {
url = this.options.source;
this.source = function (request, response) {
$.getJSON(url, request, response);
};
} else {
this.source = this.options.source;
}
},
search: function (value, event) {
value = value != null ? value : this.element.val();
if (value.length < this.options.minLength) {
return this.close(event);
}
clearTimeout(this.closing);
if (this._trigger("search") === false) {
return;
}
return this._search(value);
},
_search: function (value) {
this.term = this.element
.addClass("ui-autocomplete-loading")
// always save the actual value, not the one passed as an argument
.val();
this.source({ term: value }, this.response);
},
_response: function (content) {
if (content.length) {
content = this._normalize(content);
this._suggest(content);
this._trigger("open");
} else {
this.close();
}
this.element.removeClass("ui-autocomplete-loading");
},
close: function (event) {
clearTimeout(this.closing);
if (this.menu.element.is(":visible")) {
this._trigger("close", event);
this.menu.element.hide();
this.menu.deactivate();
}
},
_change: function (event) {
if (this.previous !== this.element.val()) {
this._trigger("change", event, { item: this.selectedItem });
}
},
_normalize: function (items) {
// assume all items have the right format when the first item is complete
if (items.length && items[0].label && items[0].value) {
return items;
}
return $.map(items, function (item) {
if (typeof item === "string") {
return {
label: item,
value: item
};
}
return $.extend({
label: item.label || item.value,
value: item.value || item.label
}, item);
});
},
_suggest: function (items) {
var ul = this.menu.element
.empty()
.zIndex(this.element.zIndex() + 1),
menuWidth,
textWidth;
this._renderMenu(ul, items);
// TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
this.menu.deactivate();
this.menu.refresh();
this.menu.element.show().position($.extend({
of: this.element
}, this.options.position));
menuWidth = ul.width("").outerWidth();
textWidth = this.element.outerWidth();
ul.outerWidth(Math.max(menuWidth, textWidth));
},
_renderMenu: function (ul, items) {
var self = this;
$.each(items, function (index, item) {
self._renderItem(ul, item);
});
},
_renderItem: function (ul, item) {
return $("<li></li>")
.data("item.autocomplete", item)
.append($("<a></a>").text(item.label))
.appendTo(ul);
},
_move: function (direction, event) {
if (!this.menu.element.is(":visible")) {
this.search(null, event);
return;
}
if (this.menu.first() && /^previous/.test(direction) ||
this.menu.last() && /^next/.test(direction)) {
this.element.val(this.term);
this.menu.deactivate();
return;
}
this.menu[direction](event);
},
widget: function () {
return this.menu.element;
}
});
$.extend($.ui.autocomplete, {
escapeRegex: function (value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
},
filter: function (array, term) {
var matcher = new RegExp($.ui.autocomplete.escapeRegex(term), "i");
return $.grep(array, function (value) {
return matcher.test(value.label || value.value || value);
});
}
});
} (jQuery));
Yes, that bug ticket you linked to shows the changeset you need to follow.
Notice how instead of saying $('selector').autocomplete(...) you're expected to do:
$('selector').bind('keydown', function (event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).data('autocomplete').menu.active ) {
event.preventDefault();
}
}).autocomplete(...)
Notice that you're intercepting TAB keydowns if the menu is "active" and preventing the event from doing the default behavior, which in a browser is focusing the next statically laid out element.
At the moment we are using the below script to create a lightweight lightbox for a wordpress site, which works perfectly on desktop, but the overlay is being triggered when just scrolling on a touch device if you scroll with your finger on one of the images, is there anyway to stop this happening?
<script>
var WHLightbox = {
settings: {
overlay: $('.portfolio-tile--overlay'),
imageCell: $('.cell-image, .portfolio-tile--image')
},
data: {
images: []
},
init: function() {
this.events();
this.buildImageData();
},
events: function() {
var self = this;
this.settings.imageCell.on('click touchend', function(e) {
e.preventDefault();
e.stopPropagation();
// set up the overlay
self._positionOverlay();
self._openOverlay();
self._preventScrolling();
// create the image slide
self._createImageSlide($(this));
});
this.settings.overlay.on('click touchend', function(e) {
e.preventDefault();
e.stopPropagation();
self._closeOverlay();
});
$('.portfolio-tile--overlay--controls--prev, .portfolio-tile--overlay--controls--next').on('click touchend', function(e) {
e.preventDefault();
e.stopPropagation();
});
$('.portfolio-tile--overlay--controls--prev').on('click touchend', function(e) {
e.preventDefault();
e.stopPropagation();
self.showPrev();
});
$('.portfolio-tile--overlay--controls--next').on('click touchend', function(e) {
e.preventDefault();
e.stopPropagation();
self.showNext();
});
},
// public functions
showPrev: function() {
var index = this.currentImageIndex();
if(index === 0) {
index = this.data.images.length;
}
this._createImageSlide(false, index-1);
},
showNext: function() {
var index = this.currentImageIndex();
if(index === this.data.images.length-1) {
// set to -1 because it adds 1 in the _createImageSlide call
index = -1;
}
this._createImageSlide(false, index+1);
},
currentImageIndex: function() {
if(this.settings.overlay.hasClass('open')) {
var imageUrl = $('.portfolio-tile--main-image').attr('src');
for(var i=0; i<this.data.images.length; i++) {
if(this.data.images[i].imageUrl === imageUrl) {
return i;
}
}
} else {
return false;
}
},
// image data
buildImageData: function() {
var self = this,
i = 0;
this.settings.imageCell.each(function() {
self.data.images[i] = {
imageUrl: self._getImagePath($(this))
}
i++;
});
},
// slide
_createImageSlide: function($el, index) {
var imagePath;
if(!$el) {
imagePath = this.data.images[index].imageUrl;
} else {
imagePath = this._getImagePath($el);
}
this.settings.overlay.find('.portfolio-tile--main-image').attr('src', imagePath);
},
_getImagePath: function($el) {
var imagePath,
spanEl = $el.find('span.js-cell-image-background'),
imgEl = $el.find('img.cell-image__image');
if(spanEl.length) {
imagePath = spanEl.css('backgroundImage');
imagePath = imagePath.replace('url(', '').replace(')', '');
} else if(imgEl.length) {
imagePath = imgEl.attr('src');
}
return imagePath;
},
// overlay
_positionOverlay: function() {
this.settings.overlay.css({
// position the overlay to current scroll position
top: $(window).scrollTop()
});
},
_openOverlay: function() {
this.settings.overlay.addClass('open');
},
_preventScrolling: function() {
$('html, body').addClass('no-scroll');
},
_reInitScrolling: function() {
$('html, body').removeClass('no-scroll');
},
_closeOverlay: function() {
this.settings.overlay.removeClass('open');
this._reInitScrolling();
}
};
WHLightbox.init();
</script>
You could use a library such as Modernizr to detect touch take a look at the answer to this question on detecting touch What's the best way to detect a 'touch screen' device using JavaScript?
With Modernizr only:
if (Modernizr.touch) {
alert('Touch Screen');
} else {
alert('No Touch Screen');
}
or with the use of jQuery & Modernizr you can do something like:
if($('html').hasClass('touch') === false) {
//run your code here
}
Thank you for your reply aharen, I managed to get it working by just changing touchend to tap and it seems to be working as intended now.
on my website I have a div .toggle-search that if you click on it it expands to .search-expand where a search form is. This is the code in jQuery
/* Toggle header search
/* ------------------------------------ */
$('.toggle-search').click(function(){
$('.toggle-search').toggleClass('active');
$('.search-expand').fadeToggle(250);
setTimeout(function(){
$('.search-expand input').focus();
}, 300);
});
Now the only way to close the .search-expand is to click once again on the .toggle-search. But I want to change that it closes if you click anywhere else on the site. For an easier example I have the Hueman theme, and I'm talking about the top right corner search option. http://demo.alxmedia.se/hueman/
Thanks!
Add the event on all elements except the search area.
$('body *:not(".search-expand")').click(function(){
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
});
or another way,
$('body').click(function(e){
if(e.target.className.indexOf('search-expand') < 0){
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
}
});
var isSearchFieldOpen = false;
var $toggleSearch = $('.toggle-search');
var $searchExpand = $('.search-expand');
function toggleSearch() {
// Reverse state
isSearchFieldOpen = !isSearchFieldOpen;
$toggleSearch.toggleClass('active');
// You can use callback function instead of using setTimeout
$searchExpand.fadeToggle(250, function() {
if (isSearchFieldOpen) {
$searchExpand.find('input').focus();
}
});
}
$toggleSearch.on('click', function(e) {
e.stopPropagation();
toggleSearch();
});
$(document.body).on('click', function(e) {
if (isSearchFieldOpen) {
var target = e.target;
// Checking if user clicks outside .search-expand
if (!$searchExpand.is(target) && !$searchExpand.has(target).length) {
toggleSearch();
}
}
});
I have a second search on the site with the same code as before only
with div .toggle-serach2 and .expand-search2, how can i make your code
so it wont overlap. just changing the name to $('toggle-search2')
doesn't cut it
in that case, I would suggest you convert your code into a plugin:
(function($, document) {
var bodyHandlerAttached = false;
var openedForms = [];
var instances = {};
var defaults = {
activeClass: 'active'
};
function ToggleSearch(elem, options) {
this.options = $.extend({}, defaults, options);
this.$elem = $(elem);
this.$btn = $(options.toggleBtn);
this.isOpen = false;
this.id = generateId();
this.bindEvents();
instances[this.id] = this;
if (!bodyHandlerAttached) {
handleOutsideClick();
bodyHandlerAttached = true;
}
}
ToggleSearch.prototype = {
bindEvents: function() {
this.$btn.on('click', $.proxy(toggleHandler, this));
},
open: function() {
if (this.isOpen) { return; }
var _this = this;
this.$btn.addClass(this.options.activeClass);
this.$elem.fadeIn(250, function() {
_this.$elem.find('input').focus();
});
openedForms.push(this.id);
this.isOpen = true;
},
close: function(instantly) {
if (!this.isOpen) { return; }
this.$btn.removeClass(this.options.activeClass);
if (instantly) {
this.$elem.hide();
} else {
this.$elem.fadeOut(250);
}
openedForms.splice(openedForms.indexOf(this.id), 1);
this.isOpen = false;
},
toggle: function() {
if (this.isOpen) {
this.close();
} else {
this.open();
}
}
};
var toggleHandler = function(ev) {
ev.stopPropagation();
this.toggle();
};
var handleOutsideClick = function(e) {
$(document.body).on('click', function(e) {
if (openedForms.length) {
var target = e.target;
var instance;
for (var id in instances) {
instance = instances[id];
if (!instance.$elem.is(target) && !instance.$elem.has(target).length) {
instance.close(true);
}
}
}
});
};
function generateId() {
return Math.random().toString(36).substr(2, 8);
}
$.fn.toggleSearch = function(options) {
return this.each(function() {
if (!$.data(this, 'toggleSearch')) {
$.data(this, 'toggleSearch', new ToggleSearch(this, options));
}
});
};
})(window.jQuery, document);
And then use it like this:
$('.search-expand').toggleSearch({
toggleBtn: '.toggle-search'
});
$('.search-expand2').toggleSearch({
toggleBtn: '.toggle-search2'
});
JSFiddle example
You could add a click handler to the main window that removes the active class:
$(window).click(function(){
$('.toggle-search').removeClass('active');
}
and then prevent the class removal when you click inside of your toggle-search elem
$('.toggle-search').click(function(e){
e.stopPropagation();
// remainder of click code here
)};
Try to add body click listener
$('body').click(function(e){
if ($(e.target).is('.toggle-search')) return;
$('.toggle-search').removeClass('active');
$('.search-expand').fadeOut(250);
});
Im trying to use hover with .on(), but all bits of code and answers i find do not work.
I need to use .on because its Ajax content.
A few ive tried:
$(document).on('mouseenter', '[rel=popup]', function() {
mouseMove = true;
width = 415;
$('#tool-tip').show();
var type = $(this).attr('data-type'),
id = $(this).attr('data-skillid');
console.log("TT-open");
ttAjax(type, id);
}).on('mouseleave', '[rel=popup]', function() {
mouseMove = false;
console.log("TT-close");
$('#tool-tip').hide();
$('#tt-cont').html("");
$('#tt-ajax').show();
});
$('[rel=popup]').on('hover',function(e) {
if(e.type == "mouseenter") {
mouseMove = true;
width = 415;
$('#tool-tip').show();
var type = $(this).attr('data-type'),
id = $(this).attr('data-skillid');
console.log("TT-open");
ttAjax(type, id);
}
else if (e.type == "mouseleave") {
mouseMove = false;
console.log("TT-close");
$('#tool-tip').hide();
$('#tt-cont').html("");
$('#tt-ajax').show();
}
});
$('[rel=popup]').on("hover", function(e) {
if (e.type === "mouseenter") { console.log("enter"); }
else if (e.type === "mouseleave") { console.log("leave"); }
});
$(document).on({
mouseenter: function () {
console.log("on");
},
mouseleave: function () {
console.log("off");
}
}, "[rel=popup]"); //pass the element as an argument to .on
The original non .on:
$('[rel=popup]').hover(function(){
mouseMove = true;
width = 415;
$('#tool-tip').show();
var type = $(this).attr('data-type'),
id = $(this).attr('data-skillid');
console.log("TT-open");
ttAjax(type, id);
},function () {
mouseMove = false;
console.log("TT-close");
$('#tool-tip').hide();
$('#tt-cont').html("");
$('#tt-ajax').show();
})
All the .on return "TypeError: $(...).on is not a function". I am using version 1.9.1.
The events you're looking for may be
$("#id").mouseover(function(){});
or
$("#id").mouseout(function(){});
There was an answer with:
$(document).on({
mouseenter: function () {
console.log("on");
},
mouseleave: function () {
console.log("off");
}
},"[rel=popup]");
This worked, and for some reason I have JQ 1.4 in a 1.9.1 named file that was causing the problem.