Problem with function reading all attributes of given node - javascript

// function to read all attributes
function get_attributes(source_node) { // source of attributes
var i, attribute, size, tab = [];
attribute = { name: "", value: "" } // new type
size = source_node.attributes.length; // reading size
for (i = 0; i < size; i++) {
attribute.name = source_node.attributes[i].name;
attribute.value = source_node.attributes[i].value;
tab[i] = attribute; //putting attribute into table
alert(tab[i].name + " - " + tab[i].value);
}
return tab; //returning filled table
}
Problem is, table (tab) consists only last red parameter :(
Anyone?

Source_node can be anything. ie "document.body"
it works if declared inside loop
...
for (i = 0; i < size; i++) {
VAR attribute =[];
attribute.name = source_node.attributes[i].name;
attribute.value = source_node.attributes[i].value;
tab[i] = attribute; //putting attribute into table
}
....

Related

Why I get Indefined when displaying Img’s on page?

I have been playing with this code for a while and I was wondering why when I try to add img’s to the array on the js code makes the images appear on DOM but also makes a bunch of Undefined elements appear, How can I just make the 15 images appear without the undefined? Thanks
enter link description here
var previous = document.getElementById('btnPrevious')
var next = document.getElementById('btnNext')
var gallery = document.getElementById('image-gallery')
var pageIndicator = document.getElementById('page')
var galleryDots = document.getElementById('gallery-dots');
var images = ["https://exoplanets.nasa.gov/internal_resources/1763/",
"https://cdn.britannica.com/56/234056-050-0AC049D7/first-image-from-James-Webb-Space-Telescope-deepest-and-sharpest-infrared-image-of-distant-universe-to-date-SMACS-0723.jpg",
"https://assets.newatlas.com/dims4/default/ac389ce/2147483647/strip/true/crop/1620x1080+150+0/resize/1200x800!/quality/90/?url=http%3A%2F%2Fnewatlas-brightspot.s3.amazonaws.com%2Farchive%2Funiverse-expanding-acceleration-1.jpg",
"https://media.newyorker.com/photos/590966ee1c7a8e33fb38d6cc/master/w_2560%2Cc_limit/Nissan-Universe-Shouts.jpg",
"https://www.thoughtco.com/thmb/NY5k_3slMRttvtS7mA0SXm2WW9Q=/1500x0/filters:no_upscale():max_bytes(150000):strip_icc()/smallerAndromeda-56a8ccf15f9b58b7d0f544fa.jpg",
"https://static.scientificamerican.com/sciam/cache/file/05B8482C-0C04-4E41-859DCCED721883D2_source.jpg?w=590&h=800&7ADE2895-F6E3-4DF4-A11F51B652E9FA88",
"https://qph.cf2.quoracdn.net/main-thumb-66277237-200-huqebnzwetdsnnwvysbxemlskpcxnygf.jpeg",
"http://www.pioneertv.com/media/1090/hero_shot_1080x720.jpg?anchor=center&mode=crop&width=600&height=400&rnd=133159257140000000",
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRSWFW1EpMNFM5-dbZEUUnzJkzT3KbUCeuhPHx_eseFCpPeX4Q_DIVPopjS0LeKVmKdQho&usqp=CAU",
"https://cdn.mos.cms.futurecdn.net/rwow8CCG3C3GrqHGiK8qcJ.jpg",
"https://static.wixstatic.com/media/917d103965314e2eacefed92edb6492c.jpg/v1/fill/w_640,h_356,al_c,q_80,usm_0.66_1.00_0.01,enc_auto/917d103965314e2eacefed92edb6492c.jpg",
"https://astronomy.com/~/media/A5B9B6CF36484AB9A6FFAE136C55B355.jpg",
"https://discovery.sndimg.com/content/dam/images/discovery/fullset/2022/9/alien%20planet%20GettyImages-913058614.jpg.rend.hgtvcom.616.411.suffix/1664497398007.jpeg",
"https://images.newscientist.com/wp-content/uploads/2017/06/21180000/planet-10-orange-blue-final-small.jpg?crop=16:9,smart&width=1200&height=675&upscale=true",
"https://images.hindustantimes.com/img/2022/07/20/1600x900/Viral_Instagram_Planet_Rainbow_Nasa_1658316556293_1658316573815_1658316573815.PNG"
]
for (var i = 0; i < 15; i++) {
images.push({
title: "Image " + (i + 1),
source: images[i]
});
}
var perPage = 8;
var page = 1;
var pages = Math.ceil(images.length / perPage)
// Gallery dots
for (var i = 0; i < pages; i++){
var dot = document.createElement('button')
var dotSpan = document.createElement('span')
var dotNumber = document.createTextNode(i + 1)
dot.classList.add('gallery-dot');
dot.setAttribute('data-index', i);
dotSpan.classList.add('sr-only');
dotSpan.appendChild(dotNumber);
dot.appendChild(dotSpan)
dot.addEventListener('click', function(e) {
var self = e.target
goToPage(self.getAttribute('data-index'))
})
galleryDots.appendChild(dot)
}
// Previous Button
previous.addEventListener('click', function() {
if (page === 1) {
page = 1;
} else {
page--;
showImages();
}
})
// Next Button
next.addEventListener('click', function() {
if (page < pages) {
page++;
showImages();
}
})
// Jump to page
function goToPage(index) {
index = parseInt(index);
page = index + 1;
showImages();
}
// Load images
function showImages() {
while(gallery.firstChild) gallery.removeChild(gallery.firstChild)
var offset = (page - 1) * perPage;
var dots = document.querySelectorAll('.gallery-dot');
for (var i = 0; i < dots.length; i++){
dots[i].classList.remove('active');
}
dots[page - 1].classList.add('active');
for (var i = offset; i < offset + perPage; i++) {
if ( images[i] ) {
var template = document.createElement('div');
var title = document.createElement('p');
var titleText = document.createTextNode(images[i].title);
var img = document.createElement('img');
template.classList.add('template')
img.setAttribute("src", images[i].source);
img.setAttribute('alt', images[i].title);
title.appendChild(titleText);
template.appendChild(img);
template.appendChild(title);
gallery.appendChild(template);
}
}
// Animate images
var galleryItems = document.querySelectorAll('.template')
for (var i = 0; i < galleryItems.length; i++) {
var onAnimateItemIn = animateItemIn(i);
setTimeout(onAnimateItemIn, i * 100);
}
function animateItemIn(i) {
var item = galleryItems[i];
return function() {
item.classList.add('animate');
}
}
// Update page indicator
pageIndicator.textContent = "Page " + page + " of " + pages;
}
showImages();
I checked your code and make it work with a small modification.
You are reusing the same array with the links of images and push inside the new object with the shape of { title, source }.
You just need to do this changes:
Change the name of your array of images. Something from images to arrayOfImages.
const arrayOfImages = ["https://exoplanets.nasa.gov/internal_resources/1763/", ...]
Declare an empty array before your first for loop. Make something like const images = []
On your for loop, instead of loop over the images variable, do it over the arrayOfImages variable.
const images = [];
for (var i = 0; i < 15; i++) {
images.push({
title: "Image " + (i + 1),
source: arrayOfImages[i]
});
}
With those changes, everything works for me.
Also, as a recommendation, try to avoid the var keyword. If you want more details about this, this answer is very helpful: https://stackoverflow.com/a/50335579/17101307
You can use Array#map to create a new array of objects from the array of URLS, then replace the original array.
images = images.map((x, i) => ({
title: "Image " + (i + 1),
source: x
}));

String to JSON Path (JavaScript)

I am trying to create a JavaScript function where I want to modify the object that I pass in and return that. I am able to create a string of the full path of the content that needs to be changed, but this is string. How can I change this so that it recognises that it is a JSON Path?
Currently, it fails my if check as it's checking as a string, when I need it to check as a JSON Path.
var modifiedObj = function (content) {
for (var i = 0; i < content.length; i++) {
var pathMaker = ["randonPath.one", "randonPath.two", "randonPath.three", "randonPath.four", "randonPath.five"];
for (var j = 0; j < pathMaker.length; j++) {
var pathValid = "content[" + i + "]." + pathMaker[j] + ".valid";
var pathNotValid = "content[" + i + "]." + pathMaker[j] + ".notValid";
if (pathValid !== undefined && pathNotValid == undefined) {
pathNotValid = content.referenceAnotherField;
};
};
};
return content;
};
Any advise?

Checking for a value within select box while looping

I'm looping over an Ajax result and populating the JSON in a select box, but not every JSON result is unique, some contain the same value.
I would like to check if there is already a value contained within the select box as the loop iterates, and if a value is the same, not to print it again, but for some reason my if check isn't working?
for (var i = 0; i < result.length; i++) {
var JsonResults = result[i];
var sourcename = JsonResults.Source.DataSourceName;
if ($('.SelectBox').find('option').text != sourcename) {
$('.SelectBox').append('<option>' + sourcename + '</option>');
}
}
The text() is a method, so it needs parentheses, and it returns text of all <option> concatenated. There are better ways to do this, but an approach similar to yours can be by using a variable to save all the added text, so we can check this variable instead of having to check in the <option> elements:
var result = ["first", "second", "first", "third", "second"];
var options = {};
for (var i = 0; i < result.length; i++) {
var JsonResults = result[i];
var sourcename = JsonResults; //JsonResults.Source.DataSourceName;
if (!options[sourcename]) {
$('.SelectBox').append('<option>' + sourcename + '</option>');
options[sourcename] = true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="SelectBox"></select>
Note: I only used var sourcename = JsonResults; for the demo. Use your original line instead.
.text is a function, so you have to call it to get back the text in the option
for (var i = 0; i < result.length; i++) {
var JsonResults = result[i];
var sourcename = JsonResults.Source.DataSourceName;
if ($('.SelectBox').find('option').text() != sourcename) {
$('.SelectBox').append('<option>' + sourcename + '</option>');
}
}
For one thing, the jQuery method is .text() - it's not a static property. For another, your .find will give you the combined text of every <option>, which isn't what you want.
Try deduping the object before populating the HTML:
const sourceNames = results.map(result => result.Source.DataSourceName);
const dedupedSourceNames = sourceNames.map((sourceName, i) => sourceNames.lastIndexOf(sourceName) === i);
dedupedSourceNames.forEach(sourceName => {
$('.SelectBox').append('<option>' + sourceName + '</option>');
});

How to remove, order up, down elements in Javascript

I'm using JavaScript to remove, order up, order down a text row, it runs normally in IE, but not in Chrome or Firefox.
When I run, I received a message from console bug:
Uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.
How to fix the error?
function dels(index) {
var frm = document.writeForm;
var opts = frm['ans' + index].value = ''; // eval("frm.ans_list" + index + ".options");
for (var i = 0; i < opts.length; i++) {
if (opts[i].selected) {
opts[i--].removeChild(true);
}
}
eval("frm.ans" + index + ".value = '' ");
setting_val(index);
}
function up_move(index) {
var frm = document.writeForm;
var opts = eval("frm.ans_list" + index + ".options"); // frm['ans' + index].value = '';
for (var i = 0; i < opts.length; i++) {
if (opts[i].selected && i > 0) {
tmp = opts[i].cloneNode(true);
opts[i].removeChild(true);
opts[i - 1].insertAdjacentElement("beforeBegin", tmp).selected = true;
}
}
setting_val(index);
}
**(UPDATED)**
function down_move(index)
{
var frm = document.writeForm;
var opts=frm["ans_list" + index].options // eval("frm.ans_list" + index + ".options"); // frm['ans' + index].value = '';
for (var i=opts.length-1; i>=0; i--) {
if (opts[i].selected && i<opts.length-1) {
tmp = opts[i].cloneNode(true);
opts[i].removeChild(true);
opts[i].insertAdjacentElement("afterEnd", tmp).selected = true;
}
}
setting_val(index);
}
<span class="bt_test_admin bg_type_01">Delete</span>
<span class="bt_test_admin bg_type_01">▲ Order</span>
<span class="bt_test_admin bg_type_01">▼ Order</span>
Wrong use of removeChild
if (opts[i].selected) {
opts[i--].removeChild(true);
}
The function is intended as:
ParentNode.removeChild(ChildNode);
// OR
ChildNode.parentNode.removeChild(ChildNode);
MDN Documentation on removeChild
Also, you can replace all your evals
eval("frm.ans" + index + ".value = '' ")
eval("frm.ans_list" + index + ".options")
It would be better written as
frm["ans" + index].value = ""
frm["ans_list" + index].options
Finally,
tmp = opts[i].cloneNode(true);
opts[i].removeChild(true);
opts[i].insertAdjacentElement("afterEnd", tmp).selected = true;
Cloning a node, appending the clone, and removing the original would be optimized as moving the original to its new location.
But, you try to remove the original, then insert the clone after the original. It's odd.
If I correctly understood what you try to do, this function could help you.
function reverse_options_order(select_element)
{
// we store the current value to restore it after reordering
const selected_value = select_element.value;
// document fragment will temporarily hold the children
const fragment = document.createDocumentFragment();
while (select_element.lastChild)
{
// last child become first child, effectively reversing the order
fragment.appendChild(select_element.lastChild);
}
// appending a fragment is equal to appending all its children
// the fragment will "merge" with the select_element seamlessly
select_element.appendChild(fragment);
select_element.value = selected_value;
}
You can use the same method to reverse any nodes order

passing page scraped data in the URL

In my Chrome extension, I'm trying to scrape information from the current tab (in content.js) and send it as parameter to the provided URL (background.js). It seems like I can scrape everything from the tab and append it to the URL except the values of input tags. Here's my code:
content.js:
var elements = new Array("form","h1","input","td","textarea","time","title","var");
//declare an array for found elements
var foundElements = new Array();
//declare an array for found ids
var foundIds = new Array();
//this counter is used to hold positions in the element array.
var elementCounter = 0;
//this counter is used to hold positions in the foundIds array
var idsCounter = 0;
//this counter is used to hold positions in the classCounter array.
var classCounter = 0;
//and we're going to output everything in a giantic string.
var output = "URL=" + document.URL;
//scrape the page for all elements
for (var i = 0; i < elements.length; i++)
{
var current = document.getElementsByTagName(elements[i]);
if(current.length>0)
{
for (var z=0; z<current.length; z++)
{
var inTxt = current[z].innerText;
output += "&" + elements[i] + "=" + inTxt;
}
elementCounter++;
//now that we have an array of a tag, check it for IDs and classes.
for (var y = 0; y<current.length; y++)
{
//check to see if the element has an id
if(current[y].id)
{
//these should be unique
var hit = false;
for (var x = 0; x<foundIds.length; x++)
{
if(foundIds[x]==current[y].id)
{
hit=true;
}
}
//if there was no hit...
if(!hit)
{
foundIds[idsCounter]=current[y].id;
idsCounter++;
var currVal = current[y].value;
output+="&" + current[y].id + "=" + currVal;
}
}
//now we pull the classes
var classes = current[y].classList;
if(classes.length>0)
{
for (var x = 0; x<classes.Length; x++)
{
var hit = false;
for (var z = 0; z<foundClasses.length; z++)
{
if(foundClasses[z]==classes[x])
{
hit=true;
}
}
//if there was not a hit
if(!hit)
{
foundClasses[classCounter]=classes[x];
classCounter++;
output+="&" + classes[x] + "=";
}
}
}
}
}
}
chrome.runtime.sendMessage({data: output});
background.js:
var output2;
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
output2 = "text_input1=";
output2 += request.data;
});
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.create({url: "http://www.google.com?" + output2}, function(tab) {
chrome.tabs.executeScript(tab.id, {file: "content.js"}, function() {
sendMessage();
});
});
});
Does anyone know why the input tags values are passed as blank?
Because you're trying to get the input text by using current[z].innerText.
However, you have to use current[z].value for inputs.

Categories