Remove items from an HTML collection based on another HTML collection - javascript

I'm trying to crete 3 HTML collections containing all my links on a page, so I can attach 3 separate function to each categories of links.
My first HTML collection is "header links", the second is "footer links" and the third is "all other links". I need to attach link tracking functions and other elements as well.
Creating the first two collections is fairly easy as I can do document.getElementById('header'); and document.getElementById('footer'); and then this.getElementsByTagName('a');
However, getting the third collection of "all other links" is a bit more tricky. There isn't a clean div that contains just the "middle" of the page, and there are links outside the header and footer that are also difficult to single out.
I wish I could do something like allLinks = document.linnks, and then filter out of that all the links already present in the first and second HTML collections.
Any way to do that ? Ideally I would like to avoid loading more libraries and pure JS would be welcome
Thanks !

You can turn the node lists into arrays, then use filter() to pull out links that are already in one of the other lists:
var hdr = document.getElementById('header');
var hlinks = arrayOf(hdr.getElementsByTagName('a'));
var ftr = document.getElementById('footer');
var flinks = arrayOf(ftr.getElementsByTagName('a'));
var others = arrayOf(document.getElementsByTagName('a')).
filter(
function(element) {
return (hlinks.indexOf(element) < 0) && (flinks.indexOf(element) < 0);
}
);
function arrayOf(nodelist)
{
var result = [];
for ( var i = 0; i < nodelist.length; ++i )
result.push(nodelist.item(i));
return result;
}
Example: http://codepen.io/paulroub/pen/ikebh
If you need to support older browsers that lack Array.prototype.filter(), include the code from this MDN page to implement it when needed.

Related

Get Unsorted list list items that are added dynamically in the Controller

I am working on a project (MVC) with Razor views.
I am trying to populate a list dynamically (trying with ul/li but the select/option would also be fine) with a click on a button. The user is filling in a field, clicks a "add" button and this adds it to a ul/li structure.
When I am looking at the inspect element, I can see my values being added, my issue is to store them into Session["..."] ... Or in a hidden field so that I can iterate on them in the Controller action.
I tried several JS/Jquery answers from the net but none of them seemed to work in my case.
Here is how I populate the ul/li structure:
function addPrice() {
var priceValue = $("#PriceValue").val() // this is the input that users fill in
var ul = document.getElementById("priceListBox");
var li = document.createElement("li");
li.setAttribute('class', "list-group-item list-group-item-action"); // set the class for design
li.setAttribute('id', priceValue); // set the id to be able to remove
li.appendChild(document.createTextNode(priceValue));
ul.appendChild(li);
}
Above correctly populates a ul with list items holding the value of the user input.
This is my hidden field attempt:
<input type="hidden" name="PriceValues" value="" runat="server"/>
This is my predefined ul:
<ul class="list-group col-md-3" id="priceListBox" name="priceListBox" runat="server"> </ul>
This is the latest attempt I tried to build up my array and access these values in the controller action:
function SetItemsToArray() {
//const listItems = document.querySelectorAll('li');
//for (let i = 0; i < listItems.length; i++) {
// alert(listItems[i].textContent);
//}
var listItems = document.getElementById('priceListBox').getElementsByTagName('li'), myArray = map(listItems, getText);
function map(arraylike, fn) {
var ret = [], i = -1, len = arraylike.length;
while (++i < len) ret[i] = fn(arraylike[i]);
return ret;
}
function gettext(node) {
if (node.nodetype === 3) return node.data;
var txt = '';
if (node = node.firstchild) do {
txt += gettext(node);
} while (node = node.nextsibling);
$('#PriceValues').val(txt); // Jquery attempt
document.getelementbyid("PriceValues").value = txt; // js attempt
}
}
I would like to know:
What is the best way of achieving this?
What is the quickest way of achieving this?
Why is the current attempt not working?
Thank you all for any response, if any question ask and I will do my best to reply correctly to it.
Kind regards.
Perhaps, I'm wrong but, your input hidden, has a "name" attribute, instead of id? So shouldn't you assign an id instead of a name?
So with everyones input and several attempts i have succeeded to get the values in my controller.
#joseatchang, you are totally right, good point! Thank you for pointing that out. #Andreas, you are correct as well, with alerts i can see that it stops running at the "var listItems ..." and then it doesn't run any further. I am not able to make it work neither, i changed the getElementById syntax as well but i can't get the function to work properly but i still want to know what is wrong so if you want to elaborate on that i would appreciate it greatly.
#Scott Rickman, i tried several approaches with .textContent and others but the following worked like a charm (thanks for the splitting tip as well ;)):
This worked by putting it where i add the list items dynamically:
document.getElementById("PriceValues").value += priceValue + ";";
and in my controller:
var a = Request.Form["PriceValues"];
Thank you all for helping me, i really appreciate it!
Have a good week, kind regards!

Append HTML to a DIV in a forum

This is yet another question about appending HTML (I have seen another questions already answered but I can't make it work on my own).
I need to add a couple of HTML lines inside a DIV in the form of a DL. To put it context, it's a (spanish) forum where I want to add extra info under every user in a thread.
Take this page as an example: http://www.antronio.cl/threads/comunidad-steam-antronio.1127070/page-222, each user has its avatar, a nick name, a secondary nick name and under all that a box with extra info. This is the box I want to modify.
The box is a DIV called "extraUserInfo" and every line on that box is a DL called "pairsJustified". I want to add a DL at the begining with text on it like the ones already there, but I can't make it work.
This is my manifest.json
{
"manifest_version": 2,
"content_scripts": [{
"js": ["js\/medallas.js"],
"matches": ["http://www.antronio.cl/threads/*/*/"]
}],
"description": "medallas para usuarios",
"name": "medallas",
"version": "1",
"permissions": ["tabs","http://www.antronio.cl/threads/*/*/"]
}
and my "medallas.js"
var dl = document.createElement("dl");
dl.setAttribute("class","pairsJustified");
dl.innerHTML = "<dt>Status:</dt><dd>OK</dd>";
document.getElementById("extraUserInfo").appendChild(dl);
I'm new to this and actually trying to learn with this extension. Maybe even my folder structure is wrong
/medallas/
manifest.json
/js/
medallas.js
Any help would be appreciated.
The main issue is there is no element with id extraUserInfo. They are using a class. You'll want to use getElementsByClassName and iterate over the NodeList. Something similar to this should get you started.
var extraUserInfos = document.getElementsByClassName("extraUserInfo");
for (var i = 0; i < extraUserInfos.length; ++i) {
var item = extraUserInfos[i];
var dl = document.createElement("dl");
dl.setAttribute("class","pairsJustified");
dl.innerHTML = "<dt>Status:</dt><dd>OK</dd>";
item.appendChild(dl);
}
From the source on the site you mentioned the "extraUserInfo" is a class not an id.
You would want to use
document.getElementsByClassName("extraUserInfo")
however this will return an array of all elements that match this. To handle this you will need to loop through the array one at a time.
var items = document.getElementsByClassName("extraUserInfo");
for( var i = 0; i < items.length; i++) {
// place your logic here for each item.
var dl = document.createElement("dl");
dl.setAttribute("class","pairsJustified");
dl.innerHTML = "<dt>Status:</dt><dd>OK</dd>";
items[i].appendChild(dl);
}
fyi: getElementById will only return the first matched element, (id attributes are supposed to be unique)
hope this helps
more info: getElementsByClassName
edit:
since the page utilizes jQuery you can place the code inside the jQuery doc ready event and you can even use jquery to append the elements
$(document).ready(function(){
$('.extraUserInfo').each(function(){
$('<dl class="pairsJustified"><dt>Status:</dt><dd>OK</dd></dl>').appendTo(this)
})
});

Displaying all icons in a glyph

I'm writing a widget UI where the user can manipulate widgets and text. One of the UI functions needed is to select an icon from the list of icons in a glyph and as I'm using twitter bootstrap it should be possible to select the "icon-" classes in the CSS in JavaScript then display them in a DIV. However I'm still relatively new to web development so unsure how I can loop through all the CSS classes selecting all the "icon-" classes. I can see how to do that with a selector to search the HTML body, for example with $.find("[class^='icon-']"); but I'm not sure how to do similar to search the CSS file itself and extract a list of CSS icon classes.
Thanks for any pointers.
Something like this should work if your browser implements the CSSStyleSheet interface:
var icons = [];
var cssRules = document.styleSheets[0].cssRules; // your bootstrap.css
for (var i=0; i<cssRules.length; i++) {
var selectorText = cssRules[i].selectorText;
if (selectorText && selectorText.match(/^\.icon-[a-z_-]+$/)) {
icons.push(selectorText);
}
}
http://jsfiddle.net/V2wjX/
The best approach I can think of is creating an array of the possible values, then looping through them. Here, I made it for you: (from this page)
var icons = ["glass","music","search","envelope","heart","star","star-empty","user","film","th-large","th","th-list","ok","remove","zoom-in","zoom-out","off","signal","cog","trash","home","file","time","road","download-alt","download","upload","inbox","play-circle","repeat","refresh","list-alt","lock","flag","headphones","volume-off","volume-down","volume-up","qrcode","barcode","tag","tags","book","bookmark","print","camera","font","bold","italic","text-height","text-width","align-left","align-center","align-right","align-justify","list","indent-left","indent-right","facetime-video","picture","pencil","map-marker","adjust","tint","edit","share","check","move","step-backward","fast-backward","backward","play","pause","stop","forward","fast-forward","step-forward","eject","chevron-left","chevron-right","plus-sign","minus-sign","remove-sign","ok-sign","question-sign","info-sign","screenshot","remove-circle","ok-circle","ban-circle","arrow-left","arrow-right","arrow-up","arrow-down","share-alt","resize-full","resize-small","plus","minus","asterisk","exclamation-sign","gift","leaf","fire","eye-open","eye-close","warning-sign","plane","calendar","random","comment","magnet","chevron-up","chevron-down","retweet","shopping-cart","folder-close","folder-open","resize-vertical","resize-horizontal","hdd","bullhorn","bell","certificate","thumbs-up","thumbs-down","hand-right","hand-left","hand-up","hand-down","circle-arrow-right","circle-arrow-left","circle-arrow-up","circle-arrow-down","globe","wrench","tasks","filter","briefcase","fullscreen"]
Now you can loop through this array, and create the elements as needed.
for (var i=0,l=icons.length; i<l; i++){
var el = document.createElement('i');
el.className = 'icon-'+icons[i];
document.getElementById("iconContainer").appendChild(el);
}
JSFIDDLE
As for searching the CSS, I can suggest you to write a function like this:
You somehow get the contents of a CSS file into a string, using AJAX (jqXHR) possibly.
Then, write a very basic parsing script, which accepts the CSS string as the parameter.
function getIcons(cssStr){
var matches = cssStr.match(/\.icon\-\w*.*\{/g), icons = [];
for (var i=0,l=matches.length; i<l; i++) icons.push(matches[i].replace(/\.icon\-/g,'').replace(/\W/g,''));
return icons;
}
This will give you the array shown before.
JSFIDDLE

Need performance improvement

I am trying out CasperJS. I am trying to create a web scraper . I need to scrape all pages of site(s) and get data in less than 5 seconds(each page).
For this I will have to crawl through all similar pages. Go to appropriate content div and get data from there.
So If the site has say 1000 pages. I need to complete whole operation as quickly as possible. I can not control N/w latency, page size etc parameter. All I can control is parsing mechanism. So I want it to be as fast as possible. If there is even small improvement, then it will extrapolate as the number of URLs
I am trying to parse child elements and creating CSS paths.
I need to make sure parsing does not take long time.
I hear standard java-script is more efficient in terms of performance than JQuery.
Hence, I need inputs.
What will be the standard JS equivalent of following JQuery code, which performance efficient in terms of parsing.
function() {
var TAG_CSS_PATH = 'div#buttons ul li.tab';
var selectOptions = $(TAG_CSS_PATH);
var results = [],i=0;
selectOptions.each(function(index,value) {
index=index+1;
results.push(TAG_CSS_PATH+':nth-of-type('+index+')');
});
return results
}
If anybody can provide any other suggestions, I will appreciate it.
This should do it:
function() {
var TAG_CSS_PATH = 'div#buttons ul li.tab',
selectOptions = document.querySelectorAll(TAG_CSS_PATH),
results = [],
l = selectOptions.length + 1;
for(var i = 1; i < l; i++){
results.push(TAG_CSS_PATH+':nth-of-type('+i+')');
}
return results;
}
The jQuery part is the $selector, and the $each. These can be replaced as follows.
function() {
var TAG_CSS_PATH = '#buttons ul li.tab',
selectOptions = document.querySelectorAll(TAG_CSS_PATH),
results = [];
for( var i = 1, ln = selectOptions.length + 1; i < ln; i++ ) {
results.push(TAG_CSS_PATH+':nth-of-type('+ i +')');
}
return results;
}
Since you are storing selectors, it seems still really inefficient to me (usage of nth-of-type are expensive selectors). Selectors are read from right to left.
CSS/selector optimisation
Note,
the div#buttons seems redundant. If you use CSS properly, you will have only exactly one element that matches id='buttons'. Thus, with proper use of IDs, you should be able to remove the div in the selector.
Further, if all your .tabs are li, then you can remove the li, too. If all your li.tabs are inside ul, you can remove the ul too.

Adding element to page every X number of divs

I need to run this function every X number of posts and the page uses AJAX to load in new posts as you scroll down the page. I was hoping to use the function below using a for loop with the modulus operator but it doesn't seem to accomplish what i'm looking for. Any idea how to do this?
$(document).ready(function($) {
function adTileLoop(){
var adTile = "<div class='new-box' id='article-tile'></div>";
var adLoc = 11;
var p = $('#article-tile');
var tile = $('#article-tile:nth-child('+adLoc+')');
for(var i = 0; i <= p.length; i++){
if(i % adLoc == 0){
$(tile).after(adTile);
}
}
}
$('#content').live(adTileLoop);
}
First of all, you need to be careful to keep IDs unique. The fact that you have $("#article-tile") and you are trying to select more than one is a mistake. ID's must be unique.
Here's a better way to run over a bunch of divs with jQuery:
$("div").each(function() {
console.log($(this));
});
You can then improve the selector to select only nth-children as you do in your question:
$("div:nth-child(2)") for example will get every other div on the page.
To retrieve the information about your posts specifically, use a selector specific to each post, something like: $(".post:nth-child(2)").
As Ashirvad suggested in the comments, you can run this after a successful ajax call and you will be able to retrieve the updated information about your page.

Categories

Resources