Loop through array and remove stylesheets - javascript

I'm building a site in WordPress and the plugins come with a few unwanted css files.
I'm trying to remove these stylesheets via JS but encountering a Failed to execute 'querySelector' on 'Document': '0' is not a valid selector. error.
I'm trying to make it reusable so that I can add stylesheets to the array and remove easily, maybe even scripts too.
Unsure where I'm going wrong in my JS?
const assets = ["link[href*='/wp-content/plugins/js_composer/assets/css/js_composer.min.css']",
"link[href*='/wp-includes/css/dist/block-library/style.min.css']"
]
for (var i in assets) {
var cssElement = document.querySelector(i);
cssElement.disabled = true;
cssElement.remove();
console.log(cssElement);
}

First of all, the i in your for .. in loop holds the index of the item at the current iteration, so on the first iteration, i will be equal to 0. So to get the selector from you selector array, at each iteration, you'd need to pass assets[i] to the quesrySelector method.
Another thing, at every iteration, you should check if querySelector has found an element or not before trying to remove the expected element.
const assets = [
"link[href*='/wp-content/plugins/js_composer/assets/css/js_composer.min.css']",
"link[href*='/wp-includes/css/dist/block-library/style.min.css']"
];
let cssElement;
for (var i in assets) (cssElement = document.querySelector(assets[i])) && cssElement.remove();
/** the above line will only executed when "querySelector" has found an element on the page */
Another possible way to have the same effect is to use the forEach method:
const assets = [
"link[href*='/wp-content/plugins/js_composer/assets/css/js_composer.min.css']",
"link[href*='/wp-includes/css/dist/block-library/style.min.css']"
];
let cssElement;
assets.forEach(s => (cssElement = document.querySelector(s)) && cssElement.remove());
Learn more about the forEach method.

Use for of not for in. i in your case is the index but you want it to be the element in the array.
The error is saying that you passed 0 (which is the first index) to the querySelector which is not a valid DOM element

const assets = ["link[href*='/wp-content/plugins/js_composer/assets/css/js_composer.min.css']",
"link[href*='/wp-includes/css/dist/block-library/style.min.css']"
]
for (var i in assets) {
var cssElement = document.querySelector(assets[i]);
cssElement.disabled = true;
cssElement.remove();
console.log(cssElement);
}
<link href="/wp-content/plugins/js_composer/assets/css/js_composer.min.css" rel='stylesheet'/>
<link href="/wp-includes/css/dist/block-library/style.min.css" rel='stylesheet'/>

Related

Array.from returns empty array

I am trying to filter children of an div element.
I get direct access to the parent div via Angular ViewChild and if I print the children like this
console.log(this.myParentDiv.nativeElement.children);
I get the following output in Chrome:
I need to convert this to array to be able to filter the divs. However if I convert it like this
console.log(Array.from(this.myParentDiv.nativeElement.children));
It returns an empty array.
Any idea why it returns empty?
I think the problem in this case is that the Javascript code is being executed before the html document is ready.
Move your JS code or import to the bottom of the page and the problem should be fixed.
Not the fanciest solution but in order to achieve this I wrapped the logic into a timeout function:
setTimeout(() => {
const elementChildren = this.myParentDiv.nativeElement.children;
// regular for loop
for (let i = 0; i < elementChildren.length; i++) {
console.log(">>",elementChildren[i]);
}
}, 100);

InDesign Scripting: Deleting elements from the structure panel

I've imported some XML files inside InDesign (you can see the structure in the picture below) and I've also created a script to get some statistics concerning this hierarchy.
For example, to count the "free" elements:
var items = app.activeDocument.xmlElements.everyItem();
var items1 = items.xmlElements.itemByName("cars");
var cars = items1.xmlElements.everyItem();
var c_free = cars.xmlElements.itemByName("free");
var cars_free = c_free.xmlElements.count().length;
I also have apartments in my structure that's why I'm using itemByName.
The code above returns the correct number of free cars in my structure.
What I'm trying to do - without any luck so far - is to target those free items (inside cars) and either delete all of them or a specific number.
My last attempt was using:
var del1 = myInputGroup2.add ("button", undefined, "Delete All");
del1.onClick = function () {
cars.xmlElements.everyItem().remove();
}
inside a dialog I've created.
Any suggestions will be appreciated cause I'm really stuck here.
I would probably use XPath for this. You can use evaluateXPathExpression to create an array of the elements you want to target. Assuming your root element is cars and it contains elements called cars1, and you want to delete all free elements within a cars1 element, you could do something like:
var myDoc = app.activeDocument;
//xmlElements[0] is your root element, in this case "cars". The xPath expression is evaluated from cars.
//evaluateXPathExpression returns an array of all of the free elements that are children of cars.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("cars1/free");
for (var i = myFrees.length - 1; i>=0; i--){
myFrees[i].remove();
}
Tweaking this would require some knowledge of xPath, but it's not terribly hard to learn the basics and it does seem like the simplest approach.
I think your main problem was that XMLElements hasn't a itemByName method. You can only reference XMLElements through their indeces or ids.
Secondly you assume that you got xmlElements from XPath expression but it's likely that you got nothing as your xpath seems uncorrect.
var myFrees = myDoc.xmlElements[0].evaluateXPathExpression("./cars1/free");
var n = myFrees.length;
if ( !n ) {
alert("Aucun élément trouvé");
}
else {
while (n--) myFrees[n].remove();
}
You need to start your expression by setting the origin of your xpath. Here a dot "./" is used to tell you want to look for cars1/free xml elements at the "root" of the xmlelement. Using "//" on the contrary would have returned any cars/free items unregardingly of their locations.

Random item from Array - Can't find variable: getElementById

I realise this and similar questions / answers exist already. But I've looked at a lot now and just not sure what simple thing I'm doing wrong. I'm just getting to grips with this.
I have the error "Can't find variable: getElementById" I've try changing the order of the script and HTML.
I used this random method which works fine Get random item from JavaScript array Its just applying it to the src...
This video was also helpful https://www.youtube.com/watch?v=pqLS4oyJ8cA
Here is my code: http://jsfiddle.net/udkhpytm/
<div>
<script id="IntroAnimation" type="text/javascript" charset="utf-8" src=""></script>
</div>
<script type="text/javascript">
var my_array = ['FILE1', 'FILE2', 'FILE3'];
var ri = Math.floor(Math.random() * my_array.length); // Random Index position in the array
getElementById("IntroAnimation").src = ri;
</script>
I'm trying to get a random item from the array and place it in the src of my Script by the scripts ID.
getElementById is a method belonging to the document object. It isn't a standalone function. Change:
getElementById("IntroAnimation").src = my_array[ri];
To:
document.getElementById("IntroAnimation").src = my_array[ri];
Note that I've also changed ri to my_array[ri] as otherwise you're passing in the index position as the src rather than the contents of the array at that specific position.
You need to grab that item from the array, all you did was just get a random number based on the array length.
var my_array = ['FILE1', 'FILE2', 'FILE3'];
var ri = Math.floor(Math.random() * my_array.length);
var file = my_array[ri];
Then you need to add document before getElementById:
doucment.getElementById("IntroAnimation").src = file;

Trouble Replacing Multiple Links With iFrame Via Javascript

I'm trying to parse a page with javascript to replace links belonging to a specific class with an iframe to open a corresponding wikipedia page [so that rather than having a link you have an embedded result]. The function detects links properly but something about the replaceChild() action causes it to skip the next instance... as if it does the first replace and then thinks the next link is the one it just worked on, probably as a result of the loop.
For example, if there's 2 links on the page, the first will parse and the second will not even be seen but if there's 3, the first two will be parsed using the attributes from the first and third.
Can anyone suggest an alternative way of looping through the links that doesn't rely on a count function? Perhaps adding them to an array?
Sample Links
wiki it
Sample Javascript
(function(){
var lnks = document.getElementsByTagName("a");
for (var i = 0; i < lnks.length; i++) {
lnk = lnks[i]; if(lnk.className == "myspeciallinks"){
newif=document.createElement("iframe");
newif.setAttribute("src",'http://www.wikipedia.com');
newif.style.width="500px";
newif.style.height="100px";
newif.style.border="none";
newif.setAttribute("allowtransparency","true");
lnk.parentNode.replaceChild(newif,lnk);
}
}
})();
The problem here is that document.getElementsByTagName returns a NodeList and not an array. A NodeList is still connected to the actual DOM, you cannot safely iterate over its entries and at the same time remove the entries from the DOM (as you do when you replace the links).
You will need to convert the NodeList into an array and use the array for iteration:
(function(){
var lnksNodeList = document.getElementsByTagName("a");
// create an array from the above NodeList and use for iteration:
var lnks = Array.prototype.slice.call(lnksNodeList);
for (var i = 0; i < lnks.length; i++) {
var lnk = lnks[i];
if (lnk.className == "myspeciallinks") {
var newif = document.createElement("iframe");
newif.setAttribute("src", 'http://www.wikipedia.com');
newif.style.width = "500px";
newif.style.height = "100px";
newif.style.border = "none";
newif.setAttribute("allowtransparency", "true");
lnk.parentNode.replaceChild(newif, lnk);
}
}
})();
According to the MDN documentation:
Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments.
Therefore, the collection shrinks every time you replace an a. You could change your loop to decrement i whenever you do a replace.

Javascript & Split Arrays

What I want to accomplish is simple. I want a button's text to change depending on what page your on.
I start this by using the following:
var loc_array = document.location.href.split('/');
Now that I have the url and split it in an array I can grab certain directories depending on the position, like so:
if (loc_array[loc_array.length-1] == 'stations'){
var newT = document.createTextNode("Stations & Maps");
}
Now this works if the directory is /test/stations/, however if someone types /test/stations/index.html then it doesn't work. How can you test against this without throwing in another if statement or using a similar conditional.
Actually both your examples work the same. /stations/ and /stations/index.html both get split into two strings; /stations/ has an empty string at the end. So length-2 would have worked. Where it wouldn't work would be /stations, which is up a level. But that wouldn't normally be an issue because if stations is a static directory, the web server will redirect the browser to /stations/ with the slash.
That won't happen if you're doing the routing yourself. If you're doing routing, it's not a good idea to index from the end of the list of path parts, are there might be any old rubbish there being passed as path-parameters, eg. /stations/region1/stationname2. In this case you should be indexing from the start instead.
If the application can be mounted on a path other than a root you will need to tell JavaScript the path of that root, so it can work out how many slashes to skip. You'll probably also need to tell it for other purposes, for example if it creates any images on the fly it'll need to know the root to work out the directory to get images from.
var BASE= '/path-to/mysite';
var BASELEVEL= BASE.split('/').length;
...
var pagename= location.pathname.split('/')[BASELEVEL];
// '/path-to/mysite/stations/something' -> 'stations'
I'm using location.pathname to extract only the path part of the URL, rather than trying to pick apart href with string or regex methods, which would fail for query strings and fragment identifiers with / in them.
(See also protocol, host, port, search, hash for the other parts of the URL.)
I don't think string splitting is the best approach here. I would do it using RegEx.
var reStations = /\/stations(\/)?/i;
if (reStations.test(document.location.href))
//Do whatever
Not sure exactly what you're looking for, see if this fits:
var loc_array = document.location.href.split('/');
// this will loop through all parts
foreach (var i in loc_array) {
switch (loc_array[i]) {
case "stations":
// do something
break;
// other cases
}
}
// or if you want to check each specific element
switch (loc_array[0]) {
case "stations": // assuming /stations/[something/]
if (typeof loc_array[1] != 'undefined' && loc_array[1] == "something") {
// do things
}
break;
}
if( document.location.href.split( "station" ).length > 1 ){
//...
}
I think I see where you are going with this... As someone stated above using a RegExp (regular expression) could be helpful... but ONLY if you had more than a single type of page to filter out (html/js/php/...), but for what it looks like you want to do. Try something like this:
var loc_array = document.location.href.split('/');
var i = loc_array.length-1;
var button_label = "default";
while(i>1)
{
//checks to see if the current element at index [i] is html
if(loc_array[i].indexOf(".html")>-1)
{
if(i>0)
{
var button_label = loc_array[i-1];
break;
}
}
i--;
}
alert(button_label);
What it does is:
capture the current URL(URI)
split it into an array
starting from the END of the array and working BACKWARDS, look for the first element that contains the ".html" file identifier.
We now know that the element BEFORE our current element contains the label we want to add to our buttons...
You can then take the value and assign it wherever you need it.
If you run out of elements, it has a default value you can use.
Not sure if this helps.....
I have tested the above code and it worked.
if (loc_array[4]=='stations')
if the url was http://www.example.com/test/stations/index.html, the values in the array would be:
[0] = "http:"
[1] = ""
[2] = "www.example.com"
[3] = "test"
[4] = "stations"
[5] = "index.html"
For simplicity's sake, supposing that there is an array of keywords (such as "station") that identify the pages, use a map and try to match its keys with the href string using indexOf,
var href = document.location.href ;
var identifiers = {
"station": "Stations & Maps" , //!! map keys to result strings
/* ... */
} ;
identifier_loop: //!! label to identify the current loop
for(var n in identifiers) { //!! iterate map keys
if( href.indexOf(n) !== -1 ) { //!! true if the key n in identifiers is in the href string
var newT = document.createTextNode( identifiers[n] ) ; //!! create new text node with the mapped result string
break identifier_loop ; //!! end iteration to stop spending ressources on the loop
}
}
Your example will show an empty string, cause the last item is empty; so you can simply make:
if (loc_array[loc_array.length-2] == 'stations')
{
var newT = document.createTextNode("Stations & Maps");
}

Categories