Page Middle Click Listener - javascript

I need to pop-up alert when I use Middle Click and it must don't pop-up if I click it on a link but on any other element of page (or just on empty space).
var test = {
pageMiddleClickListener : function(e) {
if(e.which === 2) {
//if (!gContextMenu.onLink) {
alert('ok');
//}
}
}
window.addEventListener("click",test.pageMiddleClickListener,false);
Alert show-ups when I use Middle Click on a link, but I need to prevent this behavior to links
I need something like "!gContextMenu.onLink" but not for context menu (without)

There are multiple ways that you can test for the target of the click being a link. One way would be to check to see if the Element.tagName is A, another would be to test for the href property. As it turns out is is also necessary to test to see if any of the target's parentNodes are links.
var test = {
pageMiddleClickListener : function(e) {
if(e.button === 1) {
if (!test.isLinkOrAParentIsLink(e.target)) {
e.view.alert('ok');
}
}
},
isLinkOrAParentIsLink : function(el) {
if (el.tagName === "A") {
return true;
} //else
let parent= el.parentNode;
while (parent !== null && typeof parent.tagName !== "undefined") {
if (parent.tagName === "A") {
return true;
} //else
parent= parent.parentNode;
}
return false;
}
}
window.addEventListener("click",test.pageMiddleClickListener,false);
or
isLinkOrAParentIsLink : function(el) {
if (el.hasAttribute("href")) {
return true;
} //else
let parent= el.parentNode;
while (parent !== null && typeof parent.tagName !== "undefined") {
if (parent.hasAttribute("href")) {
return true;
} //else
parent= parent.parentNode;
}
return false;
}
Note: I changed e.which to e.button as that is what is in the specification for click events and MouseEvent.which is non-standard. Note this also required testing for e.button === 1 instead of 2.

You can check if you have clicked an <a> with the prop method.
$(this).prop("tagName") == "A"
In your event listener:
var test = {
pageMiddleClickListener : function(e) {
if(e.which === 2) {
// not an <a> ?
if ($(this).prop("tagName") !== "A") {
alert('ok');
}
}
}
window.addEventListener("click",test.pageMiddleClickListener,false);

Related

Selection.focusNode doesn't work on a <br> element [duplicate]

I am trying to develop a wysiwyg editör.
In the editör, i am trying to find the position of "br" when onkeydown function fire.
<p><b>1234</b><br><br>678</p>
When i locate cursor near 6 getting 678 with "oSelection.anchorNode.nodeValue".
When i locate cursot near "br" getting nothing.
i want to find before and after tag near cursor?
Update 2: After talking to ismail the question could be changed to: how to find out, whether the element before/after the cursor is a <br> tag. This can be achieved like this:
var selection = window.getSelection(),
isBRBeforeCursor = IsBRBeforeCursor(selection),
isBRAfterCursor = IsBRAfterCursor(selection);
function GetPreviousSibling(node) {
if (node.previousSibling != null) {
return node.previousSibling;
} else if (node.parentNode != null) {
return GetPreviousSibling(node.parentNode);
} else {
return null;
}
}
function GetNextSibling(node) {
if (node.nextSibling != null) {
return node.nextSibling;
} else if (node.parentNode != null) {
return GetNextSibling(node.parentNode);
} else {
return null;
}
}
function IsBRBeforeCursor(selection) {
if(selection.anchorNode.nodeName === '#text') {
if(selection.anchorOffset > 0) {
// There is text before the cursor
return false;
} else {
var previousSibling = GetPreviousSibling(selection.anchorNode);
return previousSibling !== null && previousSibling.nodeName === 'BR';
}
} else {
if(selection.anchorOffset > 0) {
return selection.anchorNode.childNodes[selection.anchorOffset - 1].nodeName === 'BR';
} else {
var previousSibling = GetPreviousSibling(selection.anchorNode);
return previousSibling !== null && previousSibling.nodeName === 'BR';
}
}
}
function IsBRAfterCursor(selection) {
if(selection.anchorNode.nodeName === '#text') {
if(selection.anchorOffset < selection.anchorNode.nodeValue.length) {
// There is text after the cursor
return false;
} else {
var nextSibling = GetNextSibling(selection.anchorNode);
return nextSibling !== null && nextSibling.nodeName === 'BR';
}
} else {
if(selection.anchorNode.childNodes.length > selection.anchorOffset) {
return selection.anchorNode.childNodes[selection.anchorOffset].nodeName === 'BR';
} else {
var nextSibling = GetNextSibling(selection.anchorNode);
return nextSibling !== null && nextSibling.nodeName === 'BR';
}
}
}
Update: I think it is a bit tricky to always find the correct previous/next element, because the text is a node itself. So to get the previous/next element, you need to go a level up sometimes before looking left and right. Have a look at the following example:
<p><b>123</b><br><u><i><br>456</i></u><br></p>
Cursor is between 1 and 2.
The next element is <br>, which is one level up and then to the right.
Cursor is between 4 and 5.
The previous element is <br>, which is just one to the left.
The next element is <br>, which is two levels up and then to the right.
If this is the case, you can find the previous/next element like this:
function getElementBeforeSelection() {
var anchor = window.getSelection().anchorNode;
while(anchor.previousSibling === null && anchor.nodeName != 'BODY') {
anchor = anchor.parentNode;
}
return anchor.previousSibling;
}
Original answer: You can get to the surrounding elements with parentNode, previousSibling and nextSibling. So the tags before and after the cursor are:
var anchorNode = window.getSelection().anchorNode,
before = anchorNode.previousSibling,
after = anchorNode.nextSibling;

How could I add the ability to navigate onclick to the code?

I am trying to add links eg <a> to the code from here, it is a treeview using JS and JSON.
It fully works and the children are already <a></a> with href="#", I have replaced the following code, to grab a href : "example.com" attribute from the JSON and set it to the href, which works. I have also made a change to the onclick, but that only does something if you click twice :/
I would like for it to instantly href, and not when you click twice on the child.
class SimpleTree extends Emitter {
constructor(parent, properties = {}) {
super();
// do not toggle with click
parent.addEventListener('click', e => {
// e.clientX to prevent stopping Enter key
// e.detail to prevent dbl-click
// e.offsetX to allow plus and minus clicking
if (e && e.clientX && e.detail === 1 && e.offsetX >= 0) {
if (parent.href != null) {
window.location.href = parent.href;
}
return e.preventDefault();
}
const active = this.active();
if (active && active.dataset.type === SimpleTree.FILE) {
e.preventDefault();
this.emit('action', active);
if (properties['no-focus-on-action'] === true) {
window.clearTimeout(this.id);
}
}
});
[...]
class SelectTree extends AsyncTree {
constructor(parent, options = {}) {
super(parent, options);
/* multiple clicks outside of elements */
parent.addEventListener('click', e => {
if (e.target.href !== '#' || e.target.href !== 'javascript:void(0)' || e.target.href !== undefined || e.target.href !== '' || e.target.href !== null) {
window.open(href, '_blank');
}
if (e.detail > 1) {
const active = this.active();
if (active && active !== e.target) {
if (e.target.tagName === 'A' || e.target.tagName === 'SUMMARY') {
return this.select(e.target, 'click');
}
}
if (active) {
this.focus(active);
}
}
});
The simplest answer to this, add an eventlistener for the <a> element and navigate if it's not empty, null, etc.
Solution below is using Jquery.
$("a").click(function(e) {
e.preventDefault();
var href = $(this).attr("href");
if (href !== '#' || href !== 'javascript:void(0)' || href !== undefined || href !== '' || href !== null) {
window.open(href, '_blank');
}
});

In FabricJS, how can I identify through a set of objects that overlap at the coordinates where the mouse is clicked?

I need to be able to iterate through a set of objects that overlap each other at the coordinates where the mouse if clicked. As a follow-on, I would use bringToFront and then display a nice menu based on that object but I'm unsure of how to even identify and iterate on the set of objects.
My specific need was to iterate over a set of overlapping objects by pressing the tab key to set the active object/group. Below is what I did:
var stackArray = new Array();
canvas.on('mouse:down', function(e){
var subobj = canvas.getObjects();
stackArray = [];
for (var i=0;i<subobj.length;i++) {
if (subobj[i].id != '' && typeof(subobj[i].id) != 'undefined' && subobj[i].id != 'navpanel' && subobj[i].id != 'header') {
if (e.target!=null && typeof(e.target.id) != 'undefined') {
if (subobj[i].intersectsWithObject(canvas.getActiveObject()) && subobj[i].id != e.target.id) {
stackArray.push(subobj[i]);
} else if (subobj[i].id == e.target.id) {
stackArray.push(subobj[i]);
}
}
}
}
});
...
e.preventDefault();
switch(e.keyCode){
case 9: // tab
if (stackArray.length > 1) {
fillObj(canvas.getActiveObject(),'inactive');
canvas.getActiveObject().sendToBack();
canvas.setActiveObject(stackArray[stackArray.length-1]);
fillObj(canvas.getActiveObject(),'active');
stackArray.splice(0, 0, stackArray.splice(stackArray.length-1,1)[0]);
}
break;
}
function fillObj(obj,mode) {
if (obj.type == 'group') {
obj = obj.item(0);
}
if (mode == 'active') {
obj.set('fill', 'red');
obj.set('strokeWidth', 1);
obj.set('shadow','rgba(0,0,0,0.5) 5px 5px 15px');
} else if (mode == 'inactive') {
obj.set('fill', '#333');
obj.set('strokeWidth', 0);
obj.set('shadow','');
}
}

Is the image visible or not

Test if the image I am about to grab using code is visible to the user or not
Limitations:
Plain javascript - please do not suggest jQuery or other framework
I am only interested in display:none and visibility:hidden but opacity and such is of course welcome
Code: below (taken from here) does not work in my DEMO
Question: Can you help making either work or suggest a better script?
Version A
function isVisible(obj){
if (obj == document) return true;
if (!obj) return false;
if (!obj.parentNode) return false;
if (obj.style) {
if (obj.style.display == 'none' || obj.style.visibility == 'hidden') return false;
}
else if (window.getComputedStyle) { // MY BAD - I PUT THE INCORRECT ELSE HERE
var style = window.getComputedStyle(obj, "");
if (style.display == 'none' || style.visibility == 'hidden') return false;
}
else if (obj.currentStyle) {
var style = obj.currentStyle;
if (style['display'] == 'none' || style['visibility'] == 'hidden') return false;
}
return isVisible(obj.parentNode);
}
Version B
function isVisible1(obj) {
var cnode = obj;
try {
while(cnode) {
if (cnode.nodeName) {
if (cnode.nodeName.toLowerCase()=="body") {
return true;
}
}
if (cnode.style.display=="none" || cnode.style.visibility=="hidden") {
return false;
}
cnode = cnode.parentNode;
}
return true;
}
catch(ex) {return false;}
}
Try taking the computed style conditionals outside the else of the style check. We want to check both the inline styles and the computed styles (from stylesheets.)
Changing:
else if (window.getComputedStyle) {
To:
if (window.getComputedStyle) {
Forked fiddle: http://jsfiddle.net/MXgbh/1/

modify click event script to be more specific

I have to the following function that I would like to modify so that it only binds the click event to all href's that = /ShoppingCart.asp?ProductCode="whatever" (whatever = whatever is in there") but not if it is specifically /ShoppingCart.asp?ProductCode="GFT". It must also check or convert a gft or Gft to upper case to check for those as well. So basically it has to check for any variation of the case of GFT.
If it finds a "GFT" do not bind the click event.
function sacsoftaddtocart() {
if (location.pathname == "/SearchResults.asp" || location.pathname == "/Articles.asp" || location.pathname.indexOf("-s/") != -1 || location.pathname.indexOf("_s/") != -1) {
$("a[href^='/ShoppingCart.asp?ProductCode']").click(function () {
var href = $(this).attr('href');
addToCart3(href);
return false;
});
}
}
You can do it using .toUpperCase() and .filter(), like this:
function sacsoftaddtocart (){
if (location.pathname == "/SearchResults.asp" || location.pathname == "/Articles.asp" || location.pathname.indexOf("-s/") != -1 || location.pathname.indexOf("_s/") != -1) {
$("a[href^='/ShoppingCart.asp?ProductCode']").filter(function() {
return this.href.length - this.href.toUpperCase().indexOf('PRODUCTCODE=GFT') != 15;
}).click(function () {
var href = $(this).attr('href');
addToCart3(href);
return false;
});
}
}
You cant test it in a demo here. The this.href.length - matchPosition == 15 is checking that the ProductCode=GFT is both matched and there's nothing after the "GFT", so a product code like "GFT5" won't match.
using the filter in this post link text
function sacsoftaddtocart() {
if (location.pathname == "/SearchResults.asp" || location.pathname == "/Articles.asp" || location.pathname.indexOf("-s/") != -1 || location.pathname.indexOf("_s/") != -1) {
$("a:regex('href','*/ShoppingCart.asp\?ProductCode=(!?=GFT)*)").click(function () {
var href = $(this).attr('href');
addToCart3(href);
return false;
});
}
}
or if you don't want to use an exrat plugin:
function sacsoftaddtocart() {
if (location.pathname == "/SearchResults.asp" || location.pathname == "/Articles.asp" || location.pathname.indexOf("-s/") != -1 || location.pathname.indexOf("_s/") != -1) {
$("a['href^='/ShoppingCart.asp?ProductCode']")
.filter(function(){ return !/ProductCode=GTF/.test($(this).attr('href')) };
.click(function () {
var href = $(this).attr('href');
addToCart3(href);
return false;
});
}
}
Try them and see what happens ;)

Categories