trying to understand some js codes from a site - javascript

Ev.DOMit = function (e) {
e = e ? e : window.event; // e IS passed when using attachEvent though ...
if (!e.target) {
e.target = e.srcElement;
}
if (!e.preventDefault) {
e.preventDefault = function () {
e.returnValue = false;
return false;
};
}
return e;
};
Ev.getTarget = function (e) {
e = Ev.DOMit(e);
var tgt = e.target;
if (tgt.nodeType !== 1) {
tgt = tgt.parentNode;
}
return tgt;
};
I saw above code from one js file
Questions:
1.
e.returnValue = false;
return false;
since we already have this line: e.returnValue = false;,why we need to have this line here: return false;?
2 .
if (tgt.nodeType !== 1) {
tgt = tgt.parentNode;
}
what is this line for?

The e.returnValue = false; sets the property returnValue of the function argument. The return false; method returns the function with the value of 'false'.
My guess is per this - http://www.w3schools.com/dom/dom_nodetype.asp - the function sets the tgt (return value) to the parentNode for any node except for ELEMENT_NODE

I am not sure about question 1 but I have some view on question 2.
"nodeType" represent the "integer" value of a node, element like "p, div"
will have node type 1 "this is text" will have node type of "3".
code:
if ( tgt.nodeType !== 1 ) {
tgt = tgt.parentNode;
}
I guess coder wants to handle the event on "element" like "p, div" tag.
Example:
Let say we have following html code
<p>Text in p</p>
So if some event occur on the text "Text in p" inside "p" then also coder want to get target element for the event as "p" not the text inside it "Text in p".
Now think an event of text node "DOMCharacterDataModified", when this event fire the target
element should be "Text in p" but our coder want the target element as "p" tag.
Again this is a view of mine may concrete answer to the question
One useful Links you may like to read
https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
Thanks

Not necessary at all.
Make sure tgt is always an ElementNode, even if the event fires on a contained text node.

Related

Bind hover (mouseenter / mouseleave) event to dynamic content with Javascript (without Jquery)

I wrote an event delegation function in javascript:
function matches(el, selector) {
var test = (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector);
if (test)
return test.call(el, selector);
return false;
}
function delegation(node, child, evt, fn, limit) {
node.addEventListener(evt, function (e) {
//maximum number of ancestors i'm going to check
limit = limit ? limit : 2;
e = e || event;
var target = e.target || e.srcElement, i = 0, fire = false;
while (target) {
if (matches(target, child)) {
//break out of the loop if i find the matching DOM element, then fire the event
fire = true;
break;
}
if (i > limit) {
break;
}
i++;
//If event.target doesn't has id/class/tag "child", check its ancestors.
target = target.parentNode;
}
if (fire) {
fn(target, e);
}
}, false);
}
Usage: delegation(document, 'class-or-id-or-tagName', 'event-name', function, query-limit);
It works relatively well until I stumbled upon mouse enter and mouse leave events. The problem is that the events are only triggered when my mouse leave or enter document window, not DOM element, I do understand the problem why but I can't seem to fix it. Is there any way to replicate
$(document).on('mouseenter, DOM , function).on('mouseleave', DOM, function);
in pure Javascript.
Edit: Thanks for all the comments, I found out that there's nothing wrong with my code. I just need to use the correct event name when calling the delegation function, mouseenter should be mouseover, mouseleave should be mouseout.
Changing from
delegation(document, '.some-class-name', 'mouseenter', function(){});
to
delegation(document, '.some-class-name', 'mouseover', function(){});
works wonder.

JavaScript track click on div exclude inner id?

I've got the following JavaScript code to track clicks on a div:
var anchor = document.getElementById('clickMe');
if (anchor.addEventListener) {
anchor.addEventListener('click', clickHandlerOpen, false);
} else if (anchor.attachEvent) {
anchor.attachEvent('onclick', function () {
return clickHandlerOpen.apply(anchor, [window.event])
});
}
My html looks like this:
<div id="clickMe">
<div id="someContent"><p>hello</p></div>
<div id="closeMe">X</div>
</div>
How can i exclude the id closeMe from the above click handler? I want the closeMe to have its own.
Please note that i do not want to use jQuery.
Check the target.id of the clicked element inside your function:
clickHandlerOpen(event) {
//Satisfy IE8
event = event || window.event; // get window.event if argument is falsy (in IE)
// get srcElement if target is falsy (IE)
var targetElement = event.target || event.srcElement;
if (targetElement.id == 'closeMe') return false;
//your code here
}

select multiple rows using control and shift key

Demo
<table id="tableStudent" border="1">
<thead>
<tr><th>ID</th><th>Name</th> <th>Class</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>John</td><td>4th</td></tr>
<tr><td>2</td><td>Jack</td><td>5th</td></tr>
<tr><td>3</td><td>Michel</td><td>6th</td></tr>
<tr><td>4</td><td>Mike</td><td>7th</td></tr>
<tr><td>5</td><td>Yke</td><td>8th</td></tr>
<tr><td>6</td><td>4ke</td><td>9th</td></tr>
<tr><td>7</td><td>7ke</td><td>10th</td></tr>
</tbody>
</table>
$('tr').on('click',function(e)
{
var objTR=$(this);
});
I have to select multiple rows using control key.
And then store Student ID in array.
How should i do using jquery Click event.
If you only want the cells to light up when the control key is pressed, this code does the trick:
var studendIds = [];
$(window).on('keydown',(function()
{
var target = $('tr'),
root = $(window),
clickCb = function(e)
{
if (!$(this).hasClass('ui-selected'))
{
$(this).addClass('ui-selected');
//add id to array
studentIds.push(+(this.cells[0].innerHTML))
}
else
{
$(this).removeClass('ui-selected');
for(var i=0;i<studentIds.length;i++)
{
if (studentIds[i] === +(this.cells[0].innerHTML))
{//remove id from array
delete studentIds[i];
break;
}
}
}
},
upCb = function(e)
{
target.off('click',clickCb);
root.on('keydown',downCb);
root.off('keyup',upCb);
},
downCb = function(e)
{
if (e.which === 17 || e.which === 16)
{//17 is ctrl, 16 is shift
root.off('keydown',downCb);
root.on('keyup',upCb);
target.on('click',clickCb);
}
};
return downCb;
}()));
Fiddle demo.
What this code does, essentially, is listen for a keydown event. If that key is the ctrl key (code 17), a click listener is attached, that will set/unset the ui-selected class if a particular row is clicked. The handler also detaches the keydown listener itself and attaches a keyup listener that sets up the event listeners back to their original states once the ctrl key is released.
Meanwhile, another listener is attached, that picks up on the keyup event. If the key (ctrl) is released, the click listener is removed, and the keydown event listener is restored.
As I said in the comments, though the code above does keep track of which ids are selected, I'd personally not do that.
Whenever you need those ids (probably on form submission, or to perform an ajax request), seeing as you have those rows marked usign a class, I'd just do this:
function assumingAjaxFunction()
{
var data = {some: 'boring', stuff: 'you might send', ids: []};
$('.ui-selected > td:first').each(function()
{
data.ids.push($(this).text());
});
console.log(data.ids);//array of ids
}
VanillaJS fiddle with shift-select support
and the code to go with it:
window.addEventListener('load',function load()
{
'use strict';
var tbl = document.getElementById('tableStudent');
window.addEventListener('keydown',(function()
{
var expr = /\bui\-selected\b/i,
key, prev,
clickCb = function(e)
{
e = e || window.event;
var i, target = (function(elem)
{//get the row element, in case user clicked on cell
if (elem.tagName.toLowerCase() === 'th')
{//head shouldn't be clickable
return elem;
}
while(elem !== tbl)
{//if elem is tbl, we can't determine which row was clicked anyway
if (elem.tagName.toLowerCase() === 'tr')
{//row found, break
break;
}
elem = elem.parentNode;//if td clicked, goto parent (ie tr)
}
return elem;
}(e.target || e.srcElement));
if (target.tagName.toLowerCase() !== 'tr')
{//either head, table or something else was clicked
return e;//stop handler
}
if (expr.test(target.className))
{//if row WAS selected, unselect it
target.className = target.className.replace(expr, '');
}
else
{//target was not selected
target.className += ' ui-selected';//set class
}
if (key === 17)
{//ctrl-key was pressed, so end handler here
return e;
}
//key === 16 here, handle shift event
if (prev === undefined)
{//first click, set previous and return
prev = target;
return e;
}
for(i=1;i<tbl.rows.length;i++)
{//start at 1, because head is ignored
if (tbl.rows[i] === target)
{//select from bottom to top
break;
}
if (tbl.rows[i] === prev)
{//top to bottom
prev = target;//prev is bottom row to select
break;
}
}
for(i;i<tbl.rows.length;i++)
{
if (!expr.test(tbl.rows[i].className))
{//if cel is not selected yet, select it
tbl.rows[i].className += 'ui-selected';
}
if (tbl.rows[i] === prev)
{//we've reached the previous cell, we're done
break;
}
}
},
upCb = function(e)
{
prev = undefined;//clear prev reference, if set
window.addEventListener('keydown',downCb,false);//restore keydown listener
tbl.removeEventListener('click',clickCb, false);//remove click
window.removeEventListener('keyup',upCb,false);//and keyup listeners
},
downCb = function(e)
{//this is the actual event handler
e= e || window.event;
key = e.which || e.keyCode;//which key was pressed
if (key === 16 || key === 17)
{//ctrl or shift:
window.removeEventListener('keydown',downCb,false);//ignore other keydown events
tbl.addEventListener('click',clickCb,false);//listen for clicks
window.addEventListener('keyup', upCb, false);//register when key is released
}
};
return downCb;//return handled
}()), false);
window.removeEventListener('load',load,false);
}, false);
This code is close to copy-paste ready, so please, at least give it a chance. Check the fiddle, it works fine for me. It passes JSlint in with fairly strict settings, too (/*jslint browser: true, white: true */), so it's safe to say this code isn't that bad. Yes it may look somewhat complicated. But a quick read-up about how event delegation works will soon turn out that delegating an event is easier than you think
This code also heavily uses closures, a powerful concept which, in essence isn't really that hard to understand either, this linked answer uses images that came from this article: JavaScript closures explained. It's a fairly easy read, but it does a great job. After you've read this, you'll see closures as essential, easy, powerful and undervalued constructs, promise
First of all, define some classes which will indicate that you have selected a table row:
tr.selected, tr.selected td {
background: #ffc; /* light-red variant */
}
Then write this jQuery event handler:
$('table#tableStudent').on('click', 'tr', function() {
if($(this).hasClass('selected')) {
// this accours during the second click - unselecting the row
$(this).removeClass('selected');
} else {
// here you are selecting a row, adding a new class "selected" into <tr> element.
// you can reverse the IF condition to get this one up above, and the unselecting case down.
$(this).addClass('selected');
}
});
In this way you have the expirence that you have selected a row. If you have a column which contains a checkbox, or something similar, you might want to do that logic inside the event listener I provided you above.
This might help DEMO:
function bindMultipleSelect(element){
var self = this;
var isCtrlDown = false;
element.on('click', 'tr', function(){
var tr = $(this);
if(!isCtrlDown)
return;
tr.toggleClass('ui-selected')
})
$(document).on('keydown', function(e){
isCtrlDown = (e.which === 17)
});
$(document).on('keyup', function(e){
isCtrlDown = !(e.which === 17)
});
self.getSelectedRows = function(){
var arr = [];
element.find('.ui-selected').each(function(){
arr.push($(this).find('td').eq(0).text())
})
return arr;
}
return self;
}
window.myElement = bindMultipleSelect($('#tableStudent'))

Listen for events on certain element at window level - Javascript, no library

I want to listen for events on <p> elements at window or document level as there are too many such elements to attach an onclick event hander for each.
This is what I've got:
window.onload=function()
{
window.addEventListener('click',onClick,false);
}
function onClick(event)
{
alert(event.target.nodeName.toString());
}
I need advice on the code above, is it good?
And also, how can I check if the clicked element is a <p> element other than checking nodeName?
For example, if the <p> element contains a <b> element and that is clicked, the nodeType will be b not p.
Thank you.
I think it is good, and you can perform checking this way
var e = event.target
while (e.tagName != 'P')
if (!(e = e.parentNode))
return
alert(e)
If I was you I'd register for the "load" event in the same way that you are for "click". It's a more modern way of event handling, but might not be supported by some older browsers.
Checking the nodeName is the best way to interrogate the node:
function onClick(event) {
var el = event.target;
while (el && "P" != el.nodeName) {
el = el.parentNode;
}
if (el) {
console.log("found a P!");
}
}
Consider this:
(function () {
// returns true if the given node or any of its ancestor nodes
// is of the given type
function isAncestor( node, type ) {
while ( node ) {
if ( node.nodeName.toLowerCase() === type ) {
return true;
}
node = node.parentNode;
}
return false;
}
// page initialization; runs on page load
function init() {
// global click handler
window.addEventListener( 'click', function (e) {
if ( isAncestor( e.target, 'p' ) ) {
// a P element was clicked; do your thing
}
}, false );
}
window.onload = init;
})();
Live demo: http://jsfiddle.net/xWybT/

How to implement jQuery's .not()?

I have code like:
document.onmousedown = function(){
alert('test');
}
Now, except the element with ID "box", clicking should call this function, i.e. the equivalent of jQuery's .not() selector.
The jQuery code would be:
$(document).not('#box').mousedown(function(){
alert('test');
});
How can I achieve the same thing without using jQuery?
Edit: I don't want jQuery code, but i want an action similar to the .not() selector of jQuery in Javascript.
Edit: I am making an addthis-like widget. It is a 10kb file which will show a popup when a text is selected. It will not use jQuery.
In my case, when a text is selected, a popup is shown. When the document is clicked somewhere other than the widget, the widget should disappear.
To do this properly, you need to check whether e.target || e.srcElement or any of its parents has id === 'box'.
For example: (with jQuery)
$(document).mousedown(function(e) {
if ($(e.target).closest('#box').length)
return;
//Do things
});
Without jQuery:
function isBox(elem) {
return elem != null && (elem.id === 'box' || isBox(elem.parentNode));
}
document.onmousedown = function(e) {
e = e || window.event;
if (isBox(e.target || e.srcElement))
return;
//Do things
};
Alternatively, you could handle the mousedown event for the box element and cancel bubbling.
Here's one way that should work:
document.onmousedown = function(e){
var event = e || window.event;
var element = event.target || event.srcElement;
if (target.id !== "box") { alert("hi"); }
}
or if you would like it to be reusable with different ids:
function myNot(id, callback) {
return function (e) {
var event = e || window.event;
var element = event.target || event.srcElement;
if (target.id !== id) { callback(); }
}
}
and to use it:
document.onmousedown = myNot("box", function () {
alert("hi");
});
The cleanest way I can come up with for what you're trying to do is to set a document.onmousedown event and then halt event propagation on the box.onmousedown event. This avoids creating a large number of onmousedown events all over the document, and avoids having to recurse through the entire parent hierarchy of a node every time an event is triggered.
document.onmousedown = function() {
alert("Foo!");
};
document.getElementById("box").onmousedown = function(e) {
alert("Bar!");
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
};

Categories