Javascript HTML include results in duplicate includes in random places - javascript

This problem has me absolutely stumped. I'm trying to include HTML snippets with Javascript and it works, but for some reason it decides to also include duplicate snippets in various other locations.
Here is a screenshot of what I mean:
It also varies the number and location of these random includes.
This is the function I use to include. It searches through the document and finds div elements with the attribute include="x.html"
function include() {
var allElements;
var fileName;
var includeRequest;
allElements = document.getElementsByTagName("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].getAttribute("include")) {
fileName = allElements[i].getAttribute("include");
includeRequest = new XMLHttpRequest();
includeRequest.open("GET", fileName, true);
includeRequest.onreadystatechange = function() {
if (includeRequest.readyState == 4 && includeRequest.status == 200) {
allElements[i].removeAttribute("include");
allElements[i].innerHTML = includeRequest.responseText;
include();
delete includeRequest;
includeRequest = null;
}
}
includeRequest.send();
return;
}
}
}
This is the function that gets tags from an html file containing articles, and adds them to the list of tags in the box on the right. As you can see, in one place the footer is added to the list instead of the tag. I don't know why.
function getTags() {
var taglist = document.getElementById("taglist");
var tagsRequest = new XMLHttpRequest();
tagsRequest.open("GET", "blogstubs.html", true);
tagsRequest.responseType = "document";
tagsRequest.onreadystatechange = function() {
if (tagsRequest.readyState == 4 && tagsRequest.status == 200) {
var tagsResponse = tagsRequest.responseXML;
var tags = tagsResponse.getElementsByClassName("tag");
var tags = getUnique(tags);
var len = tags.length;
for (var i = 0; i < len; i++) {
var li = document.createElement("li");
li.appendChild(tags[i]);
taglist.appendChild(li);
}
delete tagsRequest;
tagsRequest = null;
}
}
tagsRequest.send();
}
Javascript only solution please. Ideas?

I copied your website (I hope you don't mind) and tested it with my changes, it seems to be working now without this bug. Here's what I did:
1) I created a new function, don't forget to change the name to whatever you prefer:
function newFunction(allElements, includeRequest) {
allElements.removeAttribute("include");
allElements.innerHTML = includeRequest.responseText;
include();
delete includeRequest;
includeRequest = null;
}
2) I changed the include() function to look like this:
function include() {
var allElements;
var fileName;
var includeRequest;
allElements = document.getElementsByTagName("*");
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].getAttribute("include")) {
var element = allElements[i];
fileName = element.getAttribute("include");
includeRequest = new XMLHttpRequest();
includeRequest.open("GET", fileName, true);
includeRequest.onreadystatechange = function() {
if (includeRequest.readyState == 4 && includeRequest.status == 200) {
return newFunction(element, includeRequest);
}
}
includeRequest.send();
return;
}
}
}
I think the problem was caused by async nature of AJAX requests, like I said in the comment. So you need to pass the variables to your AJAX call instead of using the global scope, that's why you need this new callback function.
In other words, in the original code the AJAX variable allElements[i] wasn't in sync with your loop's allElements[i], so while in your loop it would be 5, in AJAX function (which executed separately and not in order with the loop) it would be 3, 6 or whatever else. That is why it would append the html to the element that seems random. Think of AJAX as of someone who doesn't care about the order of your loops, someone who really doesn't like to wait while someone else is counting and does everything in his own order.

Related

Javascript function does not execute, script continues normally

It's been a long night trying to solve this one.
I'm trying to load a small text file, parse it, then use the information to provide the user with video options. I do this when the page loads but I also do it in response to a user event. In both cases I get the same result. The load_playList function does not execute.
The code is below. The window.load and selectVideo(X) routines are the starting points. In both cases the load_Playlist function is ignored.
It seems that load_playList never executes. The alert message is never executed, yet the script continues as if everything were normal. It's as if I typed the function's name wrong, so I did that and the script failed. So, the browser seems to see the function, but ignores it.
var videoList = [];
var videoTitles = [];
var videoCaptions = [];
/*
var videoList = [
'videos/ZionParkParade.mp4',
'videos/Pointless2014.mp4'];
var videoTitles = [
'The 50GT Zion Canyon Cruise',
'The Tinyvette at Sonoma Raceway'];
var videoCaptions = ['Caption 1','Caption 2'];
*/
window.onload = function()
{
alert(0);
load_playList; // Loads and parses a small text file.
alert(1);
load_video(0); // Set up the first video to play.
alert(2);
}
function load_playList()
{
alert('load_playList');
var listFile = ReadFile('videos/PlayList.txt');
var playList = listFile.split('\n');
var j = 0;
for (i = 0; i < math.trunc(playList.length / 3); i++)
{
videoList[i] = playList[j];
videoTitles[i] = playList[j+1];
videoCaptions[i] = playList[j+2];
j++;
j++;
j++
}
}
function selectVideo(X)
{
alert(10);
load_playList; // Loads and parses a small text file.
alert(11);
load_video(Number(X));
alert(12);
}
function FileRead(U)
{
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
X=new XMLHttpRequest();
}
else
{// code for IE6, IE5
X=new ActiveXObject("Microsoft.XMLHTTP");
}
X.open('GET', U, false );
X.setRequestHeader('Content-Type', 'text/html')
X.send();
return X.responseText;
}
function load_video(N)
{
var V = document.getElementById("video_player");
V.pause();
V.src = videoList[N];
V.auto = false;
V.type = "video/mp4";
// Update the title and captions.
document.getElementById('pause_button').innerHTML = "Play";
document.getElementById('videoTitle').innerHTML = videoTitles[N];
document.getElementById('videoCaption').innerHTML = videoCaptions[N];
}
If I un-comment the initial variable declarations, o provide initial values, everything works, except the text file is never loaded.
Thanks in advance.
Edit - I found two problems in the load_playList routine but still can't get that function to run. I don't even see the first alert.
I pasted the load_playList code into the onload routine and it works. I can live with that, but danged if it makes any sense.
window.onload = function()
{
// load_playList; // Loads and parses a small text file.
var listFile = load_file('videos/PlayList.txt');
var playList = listFile.split('\n');
var j = 0;
for (i = 0; i < Math.trunc(playList.length / 3); i++)
{
videoList[i] = playList[j];
videoTitles[i] = playList[j+1];
videoCaptions[i] = playList[j+2];
j++;
j++;
j++
}
load_video(0); // Set up the first video to play.
var vid = document.getElementById("video_player");
vid.volume = 0.2;
}
function load_playList()
{
alert(10);
var listFile = load_file('videos/PlayList.txt');
alert(11);
var playList = listFile.split('\n');
alert('Length = '+playList.length);
alert('Count = '+Math.trunc(playList.length / 3));
var j = 0;
for (i = 0; i < Math.trunc(playList.length / 3); i++)
{
videoList[i] = playList[j];
videoTitles[i] = playList[j+1];
videoCaptions[i] = playList[j+2];
j++;
j++;
j++
}
alert(12);
}
Just include () after the function name. Just calling the name won't run the function.
load_playList();
Refer
Also refer the fiddle for watching a function call
The work-around, pasting that routine's code into the onload routine, worked, but I wasn't satisfied and finally stumbled on this as a solution:
window.onload = function()
{
load_playList(0); // Loads and parses a small text file.
load_dropdown(0); // Populate the dropdown menu.
load_video(0); // Set up the first video to play.
var vid = document.getElementById("video_player");
vid.volume = 0.2;
}
Neither load_playList nor load_dropdown need an argument passed to them but I did anyway, and that worked.
I'm not sure why this is so but I'll take it.

Invalid calling object in IE at the start of a for loop

I have a search function that grabs some 1700 items from an XML list and will search through them by the user's query. Beyond that the user can further filter their results by selecting various filters.
It works flawlessly in Chrome but when testing in IE, anytime I click a filter I get an error "invalid calling object" which references the function sortList() specifically the line for(var i=0; i < loadedList.length; i++) as shown in more detail below.
Again, Chrome has no problem with this, its a total IE thing. Setting watches in Chrome, loadedList is an HTMLCollection and can have a .length method applied but for some reason in IE this does not work.
This script is fairly lengthy but I've tried to include the relevant functions below.
So mapping this out conceptually:
var results = [];
var loadedList;
window.onLoad = loadList();
// actual function
function loadList() {
var items = new XMLHttpRequest();
items.onreadystatechange = function() {
//puts all the xml into the loadedList variable
if (this.readyState == 4 && this.status == 200) {
var xmlDoc = this.responseXML;
loadedList = xmlDoc.getElementsByTagName("itm");
sortList();
}
};
items.open("GET", "item-list-file.xml", true);
items.send();
};
function sortList() {
for (var i = 0; i < loadedList.length; i++) {
for (var j = 0; j < loadedList.length; j++) {
if (boxed[j].checked && boxed[j].id.substr(0, 3) == getElement("category", i).toLowerCase().substring(0, 3)) {
// getElement is just a function with a catch statement to handle any missing info on the xml list
//pushes any relevant results into results array
results.push("<li>" + getElement("title", i) + "</li>");
}
}
}
}
};
That's the gist of what happens when the page loads. There is a search() function which just grab's the user's query and passes it to a returnSearch() function. There are no problems with any of that.
The problem arises after the user has searched once and wants to narrow the search by selecting one or more filters.
There is a function, updateURL(), which both updates the window.location.href (so we can link to the search with specific filters already selected), and then runs sortList() again.
function updateURL(searchType) {
//this resents the results array so that
results = [];
//resorts results based on new criteria
sortList();
//runs search again so that the filters are applied asynchronously
search();
};
From what I could tell for some reason IE did not like having the variable loadedList declared outside of the loadList() function. I don't know why but after the items initially loaded there would always be problems with loadedList whenever sortList() was called again.
I ended up removing the function loadList() and just having the xml in the body (not in a function).
var items = new XMLHttpRequest();
items.onreadystatechange = function() {
//puts all the xml into the loadedList variable
if (this.readyState == 4 && this.status == 200) {
var xmlDoc = this.responseXML;
loadedList = xmlDoc.getElementsByTagName("itm");
sortList();
}
};
items.open("GET", "item-list-file.xml", true);
items.send();
function sortList() {
Still not sure what IE's issue with this was but it works now.

Is looping through all style sheets and classes a good idea in JavaScript?

I have a JavaScript function as given in code below, in an ASP.Net WebForms page i.e. in an aspx page.
The code implements the logic I need in my app i.e. to find a css class, but I am concerned that if there are many style sheets/classes then there could be too many iterations done resulting in slower performance on client-side.
In this code, first all style sheets are obtained, and then for each style sheet all classes are obtained which are then iterated to find a given class.
Question: Is this concern about slow performance valid when there are too many style sheets/classes, and if yes, is there a quicker way to find a css class using JavaScript?
function getStyle(className) {
var styleSheets = document.styleSheets;
var styleSheetsLength = styleSheets.length;
for (var i = 0; i < styleSheetsLength; i++) {
var classes = styleSheets[i].rules || styleSheets[i].cssRules;
var classesLength = classes.length;
for (var x = 0; x < classesLength; x++) {
if (classes[x].selectorText === undefined) {
continue;
}
if (classes[x].selectorText == className || classes[x].selectorText.indexOf(className) >= 0) {
if (classes[x].cssText) {
return classes[x].cssText;
} else {
return classes[x].style.cssText;
}
}
}
}
}
UPDATE 1
I am providing some code from my app to illustrate the use of above JavaScript method. I have no control over which classes are being used since they are coming from some third-party controls in the ASP.Net page.
if ("none" === getStyleAttribute(getStyle(".rwDialog"), "background-image")) {
allDivs[i].style.paddingLeft = "5px";
}
Using really long I think fool-proof by supporting strings and stuff RegExs you can try:
function getItem(selector, item, sheet) {
var group = sheet.substr(sheet.indexOf(selector)).match(/{(?:(["'])((?:(?=(?:\\)*)\\.|.)*?)\1|[\s\S])*?}/)[0];
return group.substr(group.indexOf(item)).match(/\s*:\s*((?:(?=(["'])((?:(?=(?:\\)*)\\.|.)*?)\1).*|.)*?);/)[1].trim();
}
Now put this at the very beginning of your document:
function loadStyleSheets(url, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
callback(xhr.responseText);
}
};
xhr.open("GET", url);
xhr.send();
}
Now:
loadStyleSheets("path/to/style/sheet", function (text) {
alert(getItem('.class1', 'background-image', text));
});
It is a bad idea in principle as it relies on custom "parsing".
Instead, I'd suggest using built-in introspection methods like:
var rwDialogElement = ...;
window.getMatchedCSSRules(rwDialogElement);

JavaScript Find Specific URLs.

Alright, I've been working on a userscript that redirects when a specific page is loaded.
This is what I have so far:
function blockThreadAccess() {
var TopicLink = "http://www.ex.com/Forum/Post.aspx?ID=";
var Topics = [ '57704768', '53496466', '65184688', '41182608', '54037954', '53952944', '8752587', '47171796', '59564382', '59564546', '2247451', '9772680', '5118578', '529641', '63028895', '22916333', '521121', '54646501', '36320226', '54337031' ];
for(var i = 0; i < Topics.length; i++) {
if(window.location.href == TopicLink + Topics[i]) {
// Execute Code
}
}
}
The function is called on the page load, but it doesn't seem execute the code.
What it's supposed to do is check to see if the user is on that specific page, and if he is then execute the code.
Say someone goes to this link - http://www.ex.com/Forum/Post.aspx?ID=54646501, it then redirects the use. I'm trying to make it efficient so I don't have to add a bunch of if statements.
try converting both to lower case before comparing
var loc = window.location.href.toLowerCase();
var topicLnk = TopicLink.toLowerCase();
for(var i = 0; i < Topics.length; i++) {
if(topicLnk + Topics[i] == loc) {
// Execute Code
}
}

mulitple url hashtags not being read in properly

I have recently nabbed an example of reading in multiple hashtags from a url, while the first split works perfectly fine the second time I try to spilt the values a second time it seems not to be read in as seen I have tried to use the alerts to determine the problem and they stop working shot of the keyValuePair is initialized .
var mangaNumber = 0;
var chapterNumber = 0;
var i, variables = window.location.hash.split(';');
if (variables.length > 0) {
// Variables present in hash
for (i = 0; i < variables.length; i++) {
var keyValuePair = variables.split('=');
if (keyValuePair[0] == mangaNo) {
mangaNumber = unescape(keyValuePair[1]);
alert(mangaNumber);
}
if (keyValuePair[0] == chapterNo) {
chapterNumber = unescape(keyValuePair[1]);
alert(chapterNumber);
}
if (keyValuePair[0] == pageNo) {
pageNumber = unescape(keyValuePair[1]);
alert(pageNumber);
}
}
}
else {
// No variables in the hash
alert('this is a fail foo');
}
Perhaps this is just an error you made when you posted it here, but try this:
var keyValuePair = variables[i].split('=');
Also, unless mangaNo etc actually are variables (and not strings), you need to quote them:
if (keyValuePair[0] == "mangaNo") {
mangaNumber = unescape(keyValuePair[1]);
alert(mangaNumber);
}
...
if (keyValuePair[0] == "chapterNo") {
...
if (keyValuePair[0] == "pageNo") {

Categories

Resources