Get checked and undetermined nodes - javascript

I have been selected a node in jstree. I can get a json value of the selected nodes. But the problem is, I want the parent nodes of the child node , upto root

You can do this with the code as below. Check demo - Fiddle.
function getParentNode(node) {
return $('#tree').jstree().get_parent(node);
}
var nodes = $('#tree').jstree().get_selected('full'), parentNodes = [], parentTexts = [];
nodes.forEach( function(node) {
var parentNode = getParentNode(node);
while (parentNode && parentNode !=='#') {
if (parentNodes.indexOf(parentNode) === -1 ) {
parentNodes.push( parentNode );
parentTexts.push( $('#tree').jstree().get_node(parentNode).text );
}
parentNode = getParentNode(parentNode);
}
})
UPDATE
The code you use could look like:
var checked_ids = [], checked_ids1 = [];
$("#temporary1").find(".jstree-undetermined").each(
function(i, element) {
var nodeId = $(element).closest('.jstree-node').attr("id");
// alert( nodeId );
checked_ids.push( nodeId );
checked_ids1.push( $('#temporary1').jstree().get_node( nodeId ).text );
}
);

Try using jstree's get_path. The way I have it below will return to the console an array of the parents of the selected node.
* get the path to a node, either consisting of node texts, or of node IDs, optionally glued together (otherwise an array)
$('#jstree').jstree().on('changed.jstree', function(e, data) {
console.log(data.instance.get_path(data.node, undefined, true));
});

Related

Looping through XML and finding the text node - Jquery

I have got the below XML.
var xml = '<parent1><person><child><name>Name1</name><details><data1>123</data1><data2>34567</data2></details></child></person><person><child><name>Name2</name><details><data1>123</data1><data2>34567</data2></details></child></person></parent1>';
I need to loop through all the children. I only care about the XML tags that has values. Below is the code I am using to loop the same.
addChildren($f);
function addChildren( $parent ) {
$parent.children().each( function( i, child ) {
console.log(child)
if(child.childNodes[i] && child.childNodes[i].nodeType === 3){
//I am not getting all the text nodes here even with nodtype 3 check.
obj.push(
{}
//Push the dynamic key and value)
addChildren( $(child) );
});
Expected output is
{name : Name1, data1 :123, data2:34567}, {name : Name2, data1 :123, data2:34567}.
Could someone please guide me how would I get the key (Tag) and value (text node)
var xml = '<parent1><person><child><name>Name1</name><details><data1>123</data1><data2>34567</data2></details></child></person><person><child><name>Name2</name><details><data1>123</data1><data2>34567</data2></details></child></person></parent1>';
var results = $(xml).find("child").map(function () {
var item = {
name: $(this).children("name").text()
};
$(this).children("details").children().each(function () {
item[this.localName] = $(this).text();
});
return item;
}).toArray();
console.log(results);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

How to change all texts in DOM without breaking existing HTML?

I want to replace specific texts on a page with javascript. For simplicty lets say I want to replace all letters A with the letter X. Important is that it's not going to break inline HTML.
Is there a simple way to iterate over all DOM elements and only change actual texts?
<span>hello world abcd..</span>
should become
<span>hello world xbcd..</span>
and not
<spxn>hello world <x href="/">xbcd</x>..</spxn>
Iterate over all text nodes, and change their nodeValue if they contain an a:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
getAllTextNodes().forEach((node) => {
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
abcd
You can also create a whitelist or blacklist of parents whose text nodes are changeable, if you want:
function getAllTextNodes() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node);
}
return textNodes;
}
const tagNamesToKeepUnchanged = ['SCRIPT'];
getAllTextNodes().forEach((node) => {
if (tagNamesToKeepUnchanged.includes(node.parentNode.tagName)) {
return;
}
const { nodeValue } = node;
const newValue = nodeValue.replace(/a/g, 'x');
if (newValue !== nodeValue) {
node.nodeValue = newValue;
}
});
const obj = JSON.parse(
document.querySelector('script[type="application/json"]').textContent
);
console.log(obj.key);
abcd
<p>foo bar</p>
<script type="application/json">{"key":"value"}</script>
This will preserve tag names, event listeners, and pretty much everything except the content of certain text nodes.
I usually use this:
/**
* Executes operation over all text nodes in a document
* #param {HTMLElement} element
* #param {function(Text):void} callback
*/
function processTextNodes(element, callback) {
// For text node, execute callback
if (element.nodeType == Node.TEXT_NODE)
callback(element);
// Otherwise, loop over child nodes
else if (element.childNodes.length > 0) {
for (const childNode of element.childNodes) {
if (childNode.nodeType == Node.TEXT_NODE)
callback(childNode);
// Recursion to child nodes
else {
processTextNodes(childNode, callback);
}
}
}
}
For example try this:
processTextNodes(document.body, (el)=>{el.data = el.data.toUpperCase()})
I used this in several userscripts that replace words in news articles to make them more fun.
The crawler by #CertainPerformance made JSfiddle.net crash for me.
I also need to replace the text node with an html element, so I had to move away from text nodes and I settled for more modest solution with an extensive regex lookaround to ensure html tags, properties and values are (mostly) not edited.
var list = ["crabe", "eau", "voir", "nom", "de", "des", "le", "les"];
var colorThoseWords = function(arr) {
words = arr.join('|');
// Regex lookareound: https://regular-expressions.info/lookaround.html
// Regex `negative lookbehind` and `negative lookahead`
// Run it: https://regex101.com/r/NZ5LQZ/1
var s = `(?<![<=#"'\`:;,./({[-])\\b(${words})\\b(?![>=#"'\`:)\]}-])`,
r = new RegExp(s, 'gi');
console.log({r});
$("p,li,h2,h3,a").each(function() {
var text = $(this).html();
$(this).html(text.replace(r, "<i class='signit-colored'>$1</i>"));
});
};
var uncolorWords = function() {
$(".signit-colored").each(function() {
var $text = $(this).text();
$(this).replaceWith($text);
});
};
colorThoseWords(list);
// uncolorWords();
See https://jsfiddle.net/x7f24qnv/13/
I suspect #Tomáš_Zato_-_Reinstate_Monica's transverse solution may be best if we edit the TEXT_NODE's parent.

Adding a node just after one node (jstree)

I'm creating a tree using jstree javascript library https://www.jstree.com/ .I need to create a new node just after current node as a sibling.
Elem 1
Elem 2
Elem 3
My point is when i click on Elem 2 a new node say Elem 2.5 is added in between Elem 2 and Elem 3
so result:--
Elem 1
Elem 2
Elem 2.5
Elem 3
My current code:
$(".appendTree").jstree('create_node', CurrentNode, html, 'last');
by this new ,nodes are always added at the end.is there any api or workaround to handle this??
You will have to figure out the current index for the selected node in the current folder, then pass the index to create_node method instead of your last. See code below. Check demo - Fiddle Demo.
$('.appendTree')
.jstree({
core : {
check_callback : true,
data : coredata
}
})
.on("select_node.jstree", function (e, data) {
var $parent = $('#'+data.node.id).parent();
var index = $parent.children().index( $('#'+data.node.id) ) +1;
if(data.node.parent === '#') {
$parent = '#';
}
$(".appendTree").jstree('create_node', $parent, 'new node', index);
});

How to find & retrieve a node position without relying on id, class or content in javascript

Context:
I need to keep the node selection of an user & be able to retrieve it later.
If there is an id on the html node I will use it.
But the problem arrive when there is no ID. I need to be able to mark this node & be able to find it back even after a page refresh.
I tried a couple of things with childnodes but I failed so far.
You can use the nodes position relative to its siblings to locate it within the dom. When dealing with nested elements, you simply prefix the nodes location with its parents location relative to its siblings. So you end up with a node identifier looking something like this: 2/0/4/1 Where each / corresponds to an additional level of depth. Here is a working example:
function getNodePosition(node){
var node = $(node);
var result;
var parent = node.parent();
var siblings = parent.children();
var pos = siblings.index(node);
result = '/' + pos;
if(parent.length && !parent.is('body')){
result = getNodePosition(parent) + result;
}
return result;
}
function getNodeByPosition(position){
var node = $('body');
var layers = position.substring(1).split('/');
$.each(layers, function(index, val){
val = parseInt(++val);
node = node.find(':nth-child(' + val +')')
});
return node[0];
}
Jsfiddle

storing html-nodes as key in array

I want to store elements as the keys in my array and object as values,for example -
var arr = [];
arr[ document.getElementById('something') ] = { data: 'something' , fn : function(){ } };
But the problem is: If I will add another element with the key of : document.getElementById('otherthing').
And later will try to get the value of : arr[ document.getElementById('something') ].data , I will get the value of arr[ document.getElementById('otherthing') ].For Example :
var arr = [];
arr[ document.getElementById('something') ] = { data: 'something' , fn : function(){ } };
arr[ document.getElementById('otherthing') ] = { data: 'otherthing' , fn : function(){ alert('k'); } };
alert( arr[ document.getElementById('otherthing') ].data ); // alerts "otherthing"
alert( arr[ document.getElementById('something') ].data ); // alerts "otherthing" but suppose to alert "something"
How I can fix this problem,I can`t save by id,because I want to support other nodes with no-id
Thanks,Yosy.
EDIT:My answer to this,If you have better answer please write it :) (Inspired by casablanca`s answer)
array for id: key-integer the node id, value the node it self
and the array with data and fn with key of my id,It will look like this :
var idArray = [],nodeArray = [];
idArray[0] = document.getElementById('hello_ducks');
nodeArray[0] = { data: 'hello ducks!!' , fn : function(){ alert('k'); } };
idArray[1] = document.getElementById('hello');
nodeArray[1] = { data: 'hello' , fn : function(){ } };
var testNode = document.getElementById('hello_ducks'), foundId = -1 /*found id*/;
// Do we have testNode in our array?
for(var i = 0 ; i < idArray.length; i++ ){
if( idArray[i] === testNode ){
foundId = i;
}
}
// Do we found our element?
if(foundId >= 0) {
alert( nodeArray[foundId].data ); // "hello ducks!!"
}
I can`t save by id,because I want to support other nodes with no-id
You should keep in mind that in order to get back a node from the array, you have to somehow identify it. If a node doesn't have any such unique identifier, then how do you retrieve it later from the array, or even store it in the first place?
In lower-level languages like C++, every object implicitly has a unique address, but there is no such thing you can use in JavaScript, so you need to manually provide some way of identifying an object, and the DOM ID is the most convenient way of doing this.
If some of your nodes don't initially have an ID, the best way to proceed is to simply assign your own unique ID.
Update: The solution you posted will work, but it's not very efficient because you need to search the entire array every time you need to find a node. Why not simply assign your own ID to those elements which don't have one? For example:
var nextID = 0;
function getID(elem) {
if (elem.hasAttribute('id') == false || elem.id == '')
elem.id = 'dummy-' + (++nodeID);
return elem.id;
}
This way you can always use the ID as a key:
var nodeArray = [];
var e = document.getElementById('hello');
nodeArray[getID(e)] = { ... };
var e = /* element obtained from somewhere, doesn't have an ID */
nodeArray[getID(e)] = { ... }; // still works
I would suggest that instead of using an array for this purpose, you take advantage of the DOM-elements being objects:
document.getElementById('something').info = {data: 'something', fn: function () { } };
but you may end up with some issues with memory leaks in certain older browsers (read: ie6). That is fixed if you use jQuery's data storage instead:
$("#something").data("info", {data: 'something', fn: function () { } });

Categories

Resources