I have a web application that, after clicking any node in the HTML, needs to retrieve the index of that node in its parent's childNodes array. However, I am having trouble getting the currently selected node through an onclick event. The returned target of the event is the containing element rather than the specific node inside the element. This difference is important when text nodes exist, such as:
<div>This is Node 1<span>node 2</span>, node 3, and <span>node 4</span></div>
If you click on the spans for Node 2 or Node 4, it's straightforward to know where you are. However, if you click on the text for Node 1 and Node 3, I can't seem to find where the event would help you figure out which part of the actual content was clicked on.
This happens to be important because a later operation needs to check for certain properties either forward or backward through the document until the first match. So, if both Node 2 and Node 4 are a match for the search, I need to know if I am in Node 1 or Node 3 in order to know which one to return. For example, if searching rightwards, starting in Node 1 means that Node 2 should be returned, and starting in Node 3 means that Node 4 should be returned. Obviously, this is a simplification, but it demonstrates the issue. Does anyone know the canonical solution for this? If I can get the node object or the index, that should be sufficient. jquery is fine, but not necessary.
Maybe somthing like this demo could help you out a bit:
document.getElementsByTagName('div')[0].addEventListener('click', function () {
var fullStr = this.innerHTML.replace(/<[^>]*>/g, ''),
sel = window.getSelection(),
str = sel.anchorNode.data,
clickPos = sel.focusOffset,
wordPosLeft = str.slice(0, clickPos + 1).search(/\S+$/),
wordPosRight = str.slice(clickPos).search(/\s/),
wordClicked,
nextWordRegex,
nextWordPosLeft,
nextWord;
if(wordPosRight < 0) {
wordClicked = str.slice(wordPosLeft);
} else {
wordClicked = str.slice(wordPosLeft, wordPosRight + clickPos);
}
nextWordRegex = new RegExp(wordClicked);
nextWordPosLeft = fullStr.search(nextWordRegex) + wordClicked.length;
nextWord = fullStr.slice(nextWordPosLeft).match(/^\s*(\S*)\s*.*$/)[1];
console.log('wordClicked: ' + wordClicked);
console.log('nextWord: ' + nextWord);
});
See this fiddle.
You need to get Your nodes in some containers. If You would click on "Node 1" text, function will return You a <div> element. But, if You would change Your code on this:
<div>
<span>This is Node 1</span>
<span>node 2</span>
<span>, node 3, and </span>
<span>node 4</span>
</div>
it would work and return <span> container. Not possible in other way, I think.
You can eventually make some JavaScript split() or regex operations.
If you're just trying to work out the text of the element you clicked, minus child nodes text, I have a solution:
$('body').on('click', function(e) {
alert('Node Text: '+$(e.target).clone().children().remove().end().text());
});
http://jsfiddle.net/xoegujqu/1/
Essentially, delegate the click event to the highest-level element you want this to run for (in this example it just used body, but you'll probably want to be more specific). use $(e.target) to get the element that was actually clicked, .clone() to clone it so you can modify it without affecting the actual page content, .children().remove() to remove all it's descendant elements, .end() to go back to the previous jQuery selector object, then finally .text() to get the remaining text content.
check out even bubbling / propagation
Also: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
useCapture section
It is not possible to do this as far as I know. You cannot:
Detect events on text nodes.
Detect the position of the text node relative to window or page.
This answer gives an idea with some good insight, but does not do what you want (return the index of the node).
I believe you are out of luck, unless you can find a way to use the solution above to determine index.
Related
I'm trying to use bootstraptoggle in one of my pages. The initial state is off / disabled.
The page loads several boolean values and stores them as hidden text. Then I have a script which looks them up via their IDs. Upon that hidden text it should toggle the slider.
I was able to get the hidden text and make the conditional check but I'm not able to toggle the slider for some reason.
Here is my code:
$(document).ready(function () {
var flags = [];
var userID = '',
toggleSlider = '';
flags = document.querySelectorAll('*[id^="activeFlag_"]');
flags.forEach(function (flag) {
userID = flag.id.split('_')[1];
// This is where i search for the hidden text
if (flag.firstChild.data == 'True') {
// Nothing works here.
$('#activeToggle_' + userID).bootstrapToggle('toggle');
}
});
});
And this is the html code that I need to work with:
<p id="activeFlag_#user1">#item.activeFlag</p>
<div class="checkbox">
<label>
<input id="activeToggle_user1" type="checkbox" data-toggle="toggle" data-on="Enabled" data-off="Disabled">
</label>
</div>
Your code is too opaque without any data example.
However one thing could be a cause of its problem:
if (flag.firstChild.data == 'True') {
Try to replace it with:
if (flag.firstElementChild.data == 'True') {
Here you could find explanation:
The firstChild property returns the first child node of the specified node, as a Node object.
The difference between this property and firstElementChild, is that firstChild returns the first child node as an element node, a text node or a comment node (depending on which one's first), while firstElementChild returns the first child node as an element node (ignores text and comment nodes).
Note: Whitespace inside elements is considered as text, and text is considered as nodes (See "More Examples").
Update after example code was added
For the example code you provided, you should change the split argument:
userID = flag.id.split('_')[1];
to:
userID = flag.id.split('_#')[1];
Thanks to twain for initial jsfiddle. I have updated it accordingly: jsfiddle
I guess the problem is, that the following part does not use the correct id for the toggle $('#activeToggle_' + userID).bootstrapToggle('toggle');
Your html ID is activeToggle_user1, but the js part above will probably resolve to #activeToggle_1. So the text user is missing here.
I created a working fiddle here: https://jsfiddle.net/pbcrh5d2/
Ok, for some reason asp.net and javascript have a problem with coping together. I used asp.net to provide javascript to build the strings.
So I switched to the raw id that is used in the table.
I have customized the wp_get_archive added a class="tlyear" to its tag.
and using jquery to get each of the years
var y = jQuery('.tlyear');
var m = jQuery('.tlyear').text();
jQuery('.tlyear').click(function() {
alert(m);
});
when I click on one of the it supposes to return the alert text as 1955 but instead, it returns me a whole string of years as "19481955". How do I get the years only from the I click on? since all the has the same class.
You want to get the text of the just the clicked item, so make use of this, which refers to that item:
jQuery('.tlyear').click(function() {
alert(jQuery(this).text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="tlyear">1948</div>
<div class="tlyear">1955</div>
<div class="tlyear">1963</div>
(Or it may make sense to use jQuery(this).find('a').text(), because you're binding the click handlers to the containing divs, not to the anchor elements that have the text you want, though it doesn't really matter if there are no other elements within those divs.)
In your code, this line:
var m = jQuery('.tlyear').text();
...gets the text of all of the matching elements with no relation to which one(s) might later be clicked on.
In mozilla, I can select a text and print the selected text using contentWindow.getSelection(). But I am trying to get the underlying html code block for this selected text. Is there any way I can retrieve it?
I need to extract urls and other informations like src, etc. underneath any clickable text that a user selects. I need the code block of its parent node.
Thanks.
Retrieving the HTML should be relatively easy, but it depends on what you are wanting. window.getSelection() returns a selection object. You can use:
window.getSelection().anchorNode to obtain the Node in which the selection begins and
window.getSelection().focusNode to get the Node in which the selection ends.
For instance:
let selection = contentWindow.getSelection();
let firstElement = selection.anchorNode;
let lastElement = selection.focusNode;
What you do once you have the nodes/elements will depend on what it is that you are actually wanting to find. You have not specified that, so manipulating it past finding those nodes would just be a guess as to what you are wanting. For instance, you just might want to find the parent of the anchorNode, verify that it contains the focusNode (firstElement.parentNode.contains(lastElement)) (if not then continue finding the next parent until it does) and use the parent's innerHTML. Alternately, maybe you want to find the first parent element of the anchorNode which contains the focusNode and then use a TreeWalker to walk the DOM tree until you find the anchorNode and start accumulating the HTML until you encounter the focusNode.
Do you have a mouse event listener or something before you do contentWindow.getSelection?
If you do you can get the selected node by doing:
function onMouseUp(event) {
var aWindow = event.target.ownerDocument.defaultView;
// should test if aWindow is chrome area or actually content area
var contentWindow = aWindow.document instanceof Ci.nsIHTMLDocument ? aWindow : null; // i guessed here but testing if its content window is done in some similar way
if (!contentWindow) { return }
// do contentWindow.getSelection im not familiar with the code, if selection exists // check if more then one range selected then get node for each, however im going to assume only one range is selected
var nodeOfFirstRange = event.explicitOriginalTarget
var elementOfNode = nodeOfFirstRange.parentNode;
var htmlOfElement = elementOfNode.innerHTML;
}
Services.wm.getMostRecentWindow('navigator:browser').gBrowser.addEventListener('mouseup');
issue with this code is if user mouses down in content window and then highlights and mouseup while mouse its outside of content window, like on chrome window or even outside the browser (like if the browser window was not in maximum or if user mousedup in taskbar of os etc) so just use this code as a guide
Okay so, I want to make an OnClick function in JavaScript that makes it so when a user clicks on it, it will change the word. Is there a replaceword() function or something that which will let me do so? I know this is not real code, but for example:
<p>Quickly <span onclick="replaceword('Surf');">Search</span> The Web!</p>
If there is, then can someone tell me also how to reverse the code maybe? So when they click on it the second time, it will change back to "Search"?
If you want to jump between multiple words, you'll need to store them someplace. You could have two words in the sentence, and toggle the visibility of one or the other (which doesn't scale well), or you could even store them as values on an attribute placed on the element itself.
<p>Hello, <span data-values="World,People,Stack Overflow">World</span>.</p>
I have placed all possible values within the data-values attribute. Each distinct value is separated from the other values by a comma. We'll use this for creating an array of values next:
// Leverage event-delegation via bubbling
document.addEventListener( "click", function toggleWords ( event ) {
// A few variables to help us track important values/references
var target = event.target, values = [], placed;
// If the clicked element has multiple values
if ( target.hasAttribute( "data-values" ) ) {
// Split those values out into an array
values = target.getAttribute( "data-values" ).split( "," );
// Find the location of its current value in the array
// IE9+ (Older versions supported by polyfill: http://goo.gl/uZslmo)
placed = values.indexOf( target.textContent );
// Set its text to be the next value in the array
target.textContent = values[ ++placed % values.length ];
}
});
The results:
The above listens for clicks on the document. There are numerous reasons why this is a good option:
You don't need to wait for the document to finish loading to run this code
This code will work for any elements added asynchronously later in the page life
Rather than setting up one handler for each element, we have one handler for all.
There are some caveats; you may run into a case where the click is prevented from propagating up past a particular parent element. In that case, you would want to add the eventListener closer to your target region, so the likeliness that bubbling will be prevented is less.
There are other benefits to this code as well:
Logic is separated from markup
Scale to any number of values without adjusting your JavaScript
A demo is available for your review online: http://jsfiddle.net/7N5K5/2/
No, there isn't any native function, but you can create on your own.
function replaceword(that, word, oword) {
that.textContent = that.textContent == oword ? word : oword;
}
You can call it like this:
<p>Quickly<span onclick="replaceword(this,'Surf','Search');">Search</span>The Web!</p>
Live Demo: http://jsfiddle.net/t6bvA/6
<p id="abc">Hello</p>
<input type="submit" name="Change" onclick="change()">
function change(){
var ab=document.getElementById('abc').value;
ab.innerHTML="Hi, Bye";
}
I think so this should help you, you should go to site such as w3schools.com, its basic and it will answer your doubt
You can try something like this if you wanna use jQuery
http://jsfiddle.net/R3Ume/2/
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<body>
<p>Hello <a id='name'>John<a></p>
<input id="clickMe" type="button" value="replace" onclick="onClick();" />
<script>
function onClick() {
$('#name').text('world');
}
</script>
I'm not sure how to ask this question correct since my understanding of the DOM is lacking.
What I'm trying to do is to catch any click event on any given DOM element. I then want to save the element type as well as the complete reference to element in a Database. But I'm not sure this is at all possible?
What i want to achieve is to save a hole interaction with a web app, in a way so you can later replay every action performed on the site, in a given session.
I have tried different approaches like getting the X and Y position of the clicked element, and later on trigger a click on those x-y coordinates, but theres several problems with this approach. I've also tried to traverse the Dom backwards until i reach the body tag, to build a unike selecter, but this also have it's shortcomings.. The best solution i can think of would be to save what ever $(this) contains.
If click events are the only thing you want to track, you probably want to add click event handlers to every clickable element on the page.
This would require starting at the <body> and walking the DOM, adding handlers as you go.
At the same time, I'd add a new data-xpath attribute to each element containing an XPath selector so you can use it in your handler to note the element being clicked, and so replay the user's interaction.
See http://www.w3schools.com/xpath/xpath_intro.asp for an introduction to XPath.
Faling a sleep yesterday i got an idea and ended up with this code today. - It works as intended but I'm guessing that Xpath would perform better!?
$(document).click(function(event) {
var target = $(event.target);
var parents = target.parents();
var myParents = '';
$($(parents).get().reverse()).each(function(key, value){
var parentIndex = $(this).index()+1;
myParents += $(this).prop("tagName")+':NTH-CHILD('+parentIndex+') > ';
});
var childIndex = target.index()+1;
var childTag = target.get(0).tagName;
myParents += childTag+':NTH-CHILD('+childIndex+')';
alert(myParents);
});
The above code will return a unique selector-string likes this:
HTML:NTH-CHILD(1) > BODY:NTH-CHILD(2) > SECTION:NTH-CHILD(1) > UL:NTH-CHILD(1) > LI:NTH-CHILD(3) > A:NTH-CHILD(1)