EDIT: CSS
Javascript
My code is by no means demanding so I'm not sure why this is happening.
It doesn't seem to work on JSFiddle either. Every time I try to load it on the website I get a 404 error.
This only happened after I made a small change in my code:
function runDisplay(data, id) {
var reader = document.getElementById(id);
var index = 0;
if (timer) {
clearInterval(timer);
}
if (data.length) {
timer = setInterval(function() {
reader.innerHTML = data[index++];
var punctuation = [".", ",", ":", ";", "!", "?"];
var word = data[index++];
for (var j = 0; j < punctuation.length; j++) {
if (!(word.indexOf(punctuation[j]) === -1)) {
word = string.replace(punctuation[j], '');
}
index = index % data.length;
}, getTextSpeed()); // change speed dynamically in real time
}
}
function getTextSpeed() {
var speeds = document.getElementById("speed");
return speeds.options[speed.selectedIndex].value;
}
I changed a textSpeed variable to a direct call to the method getTextSpeed in an attempt to get the speed of the text to change dynamically.
Essentially what this class is supposed to display text word-by-word, with font-size and the speed (which must be implemented with setInterval() and clearInterval()) by which the words are displayed being changeable by the user of the webpage.
If a word contains punctuation, then it is removed and the delay between that word and the next is doubled (234 ms instead of 117 ms). If there is more than one character of punctuation (ex: ...) then only one character of punctuation is removed.
Can you help me figure out what's causing this? Is it an error in my implementation? Did I accidentally create an infinite loop somewhere?
Related
I'm trying to make a Hangman game with Javascript, where the user enters a word for another person to guess. The word is sent to a function (makeUnderlines) and is made into an array of underlines and returned to the player with a prompt to enter a letter that they want to guess. The letter and the word is sent to a function that finds the positions of the letters (getPosition) in the word and sends the positions to another function. The function (insertLetters) is supposed replace the underlines with the letter at the positions given. All of this works except that the function doesn't replace anything in the array. It only replaces the first letter if it only occurs once in the word. Any advice to solving this would be greatly appreciated. I would also like to know if there is a way to prevent the user to entering a number in a word or as a guess.
<!DOCTYPE HTML>
<HTML>
<HEAD>
<META CHARSET="UTF-8">
<TITLE>Hangman</TITLE>
</HEAD>
<BODY>
<SCRIPT TYPE="text/javascript">
function makeUnderlines(word) {
for(i = 0; i < word.length; i++){
underlines.push("\"_\"");
}
return underlines;
}
function getPositions(word, letter) {
for(var i=0; i< word.length;i++) {
if (word[i] === letter) positions.push(i);
}
insertLetters(underlines, positions, letter)
}
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
let word = prompt("Choose a word for the player!");
underlines = [];
positions = [];
makeUnderlines(word);
for(i = 7; i > 0; i--){
letter = prompt("["+underlines+"]\n Guess a letter. You have " + i + " guesses left");
getPositions(word, letter);
}
</SCRIPT>
</BODY>
</HTML>
One way to start digging into this is by tracing the flow of the application with a debugger. Chrome Dev Tools has a debugger that lets you step line by line to see what the current values of your variables are.
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
From looking at insertLetters, positions should be an array of integer index values but it is being directly used as an integer. Maybe try iterating through the values in positions and using those to index underlines.
function insertLetters(underlines, positions, letter){
for (let i = 0; i < positions.length; i++) {
const pos = positions[i];
underlines[pos] = letter;
}
}
And I think the last thing you could do in getPositions is to clear out the positions array with positions = [];.
Overall your code looks quite functional. Take care to try and pass variables to functions directly instead of relying on global variables.
I'm trying to extract a few lines representing some XML elements from a file.
The user provides a file using a simple <input type="file"> tag, and than this file is read as text with FileReader, and given as the parameter to this function:
var relevantDelimiters = [{"begin":"<header>","end":"</header>"}
,{"begin":" <someElement>","end":"</someElement>"}];
function dealWithString(invalidXML) {
var validXML = "";
for (var i=0; i<relevantDelimiters.length; i++) {
delimiter = relevantDelimiters[i];
while (invalidXML.indexOf(delimiter.begin) != -1) {
//while there are relevant elements of this kind left:
startPos = invalidXML.indexOf(delimiter.begin);
endPos = invalidXML.indexOf(delimiter.end);
//append to end result:
validXML+=invalidXML.substring(startPos,endPos+delimiter.end.length)+"\n";
//take this item out of the input to process next item
invalidXML = invalidXML.replace(invalidXML.substring(startPos,endPos+delimiter.end.length),"");
}
}
//return fixed data
return validXML;
}
This approach seems to work just fine with a small amount of matches in the input text file, but given a file of 1.5MB, script is stuck (Running with Google Chrome, making it's tab non-responsive). This file contains about a million "relevant elements", meaning matches from relevantDelimiters.
How can I optimize this?
Instead of repeatedly "taking the item out of the input" by calling replace on it, you should use the second argument to indexOf: fromIndex. That way, it'll search the next occurence after the given index, and you can loop through the very large input without needing to touch it.
function dealWithString(invalidXML) {
var validXML = "";
for (var i=0; i<relevantDelimiters.length; i++) {
var delimiter = relevantDelimiters[i],
pos = 0,
startPos;
while ((startPos = invalidXML.indexOf(delimiter.begin, pos)) != -1) {
//while there are relevant elements of this kind left:
var endPos = invalidXML.indexOf(delimiter.end, startPos);
// assert(endPos != -1) - otherwise this could go horribly wrong
pos = endPos+delimiter.end.length;
//append to end result:
validXML += invalidXML.slice(startPos, pos) + "\n";
}
}
return validXML;
}
Where's the time being spent? I assume you could break up this big synchronous action into a couple of async hopes. (Every couple of while-iterations, you could store your index and set-timeout before resuming. This way you don't lock the UI thread.
I have a piece of JavaScript that generates every possible combination of a charset for the length provided. Since I'm using it for a length of 12, it's a very long loop that freezes and crashes the browser.
I've tried replacing the for loop with a setInterval() but it only seemed to break it.
How can I slow down my loop?
Here's the script:
var charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890',
charset_length = charset.length;
function recurse(width, pos, base) {
for (var i = 0; i < charset_length; i++) {
if (pos < width - 1) {
recurse(width, pos+1, base + charset[i]);
}
console.log(base + charset[i]); // replaced later
}
}
recurse(12, 0, '');
EDIT: Because each output will open a new tab (that will close itself once done), I want to slow it down so a maximum of 5 tabs approx. are open at the same time.
I'm having trouble with this code. I've tried to troubleshoot it many times and seem to have isolated the issue, but can't figure out the cause.
If the variable called string is set to something in the form of "text v. text," the code runs fine and the first if-statement triggers the sentence. If the string contains text but no "v." i.e. nothing that meets the search separator value, the function fails and does not execute the second if-statement.
Link to Fiddle: http://jsfiddle.net/qsq4we99/
Snippet of code, there also would need to be a html div with ID "outputtext."
function brokenCode()
{
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
brokenCode();
In this simplified example there is no clear explanation why the search operations need to occur (they are there because in the real code they are needed... but something about them seems to be causing the problem (even in this simple example). If the two searches are removed, the code runs smoothly.
You can't start setting variables from the array without checking for length. Before setting findText1 & findText2, check to make sure the length of the array is greater than zero.
function brokenCode() {
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
if (number > 0) {
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
}
brokenCode();
Code:
http://jsfiddle.net/s4UQP/
^ Here is the best way to see the code and how it works with the divs
But here is the code anyway:
function move(from, to) {
document.getElementById('progress').innerHTML = '...';
from = parseInt(from,10);
to = parseInt(to,10);
tbc = document.getElementById(from);
before = document.getElementById(to);
containr = document.getElementById('alldivs');
neworder = 'Order: <select><option onclick="move(' + to + ',1)">1</option><option onclick="move(' + to + ',2)">2</option><option onclick="move(' + to + ',3)">3</option></select> <br>Send up | Send down<br>Bring to front (#1) | Send to back (#4)';
document.getElementById(from).getElementsByClassName('order')[0].innerHTML = neworder;
document.getElementById(from).getElementsByClassName('number')[0].innerHTML = to;
tempdiv = document.createElement('div');
tmphtml = document.getElementById(from).innerHTML;
tempdiv.className = 'holder';
tempdiv.innerHTML = tmphtml;
n = 0;
npieces = 4;
if (from < to) {
nochanges = to - from;
fromone = from + 1;
//alert(n+' '+to+' '+fromone);
for (n = fromone; n <= to; n++) {
//alert('down');
idnum = parseInt(document.getElementById(n).id,10);
//alert(idnum);
document.getElementById(n).getElementsByClassName('number')[0].innerHTML = (idnum - 1);
alert(document.getElementById(n).id);
document.getElementById(n).id = (idnum - 1);
//alert('down '+idnum+' to '+(idnum-1));
}
}
if (from > to) {
nochanges = from - to;
totone = to + 1;
for (n = to; n < from; n++) {
//alert('n is '+n+' going to '+to+' ends at '+totone);
//alert('up');
idnum = parseInt(document.getElementById(n).id,10);
//alert(idnum);
document.getElementById(n).getElementsByClassName('number')[0].innerHTML = (idnum + 1);
alert(document.getElementById(n).id);
document.getElementById(n).id = (idnum + 1);
//alert('up '+idnum+' to '+(idnum+1));
}
}
//tempdiv.id = 'span'+to;
if (from > to) {
containr.insertBefore(tempdiv, before);
}
if (from < to) {
before = to + 1;
containr.insertBefore(tempdiv, document.getElementById(before));
}
tbc.parentNode.removeChild(tbc);
tempdiv.id = to;
document.getElementById('progress').innerHTML = 'done';
}
The script works as you move a block (or div) up or down, but when you try to move a different block (e.g. the one at the top), it just switches around the first two blocks beneath it.
Could anyone give me any advice?
I don't know whether it's because of the order that the script was done in, or if it's something else. It's been confusing me for some time, and I'd really appreciate it if someone could look through it and give me some advice.
(I don't want to code it in jQuery, this is really just me trying to learn more JavaScript by coding something. If it's not the most efficient, secure, whatever, it's still just something with which I'm trying to teach myself JavaScript.)
Thank you for reading. (Please don't edit the JS Fiddle itself, but rather post any edits/improvements here. Thank you.)
[Edit: I'm not really writing a cliche sci-fi, they're just example divs because I couldn't think of anything better]
In the statement neworder =... you change the values of the onclick functions, but you only do this for the block that is about to be moved. The problem is that the other blocks also change positions. For instance, if you click on 'Send up' for block 2, then block 2 moves up to position 1 and block 1 moves down to position 2. But only the event handlers on block 2 are updated accordingly. So the next time you click on (what was originally) block 1, it will not behave correctly.
One solution would be to update the event handlers on all of the blocks that are affected every time one of them is moved. For instance, make a function called updateEventHandlers(blockNumber) and call it for all of the affected blocks.
However relying on IDs to indicate the position of a block and then fiddling with the IDs after they are moved can lead to all sorts of confusion. It is better either to keep an array or dictionary recording the positions of the blocks, or loop through them to determine their positions in the DOM each time you want to move them.
For instance the following code provides moveup, movedown and moveto functions using the latter method (it finds where the element is in the DOM and swaps it with the holder before or after). (JSFIDDLE)
function E(id) { return document.getElementById(id);}
var holders = document.getElementsByClassName('holder');
function moveup(id) {
for (var i = 0; i < holders.length - 1; i++) {
// Find the holder before the one we're interested in
if (holders[i + 1] == E(id)) {
// Swap their positions
E('alldivs').insertBefore(E(id), holders[i]);
break;
}
}
resetNumbers();
}
function movedown(id) {
for (var i = 1; i < holders.length; i++) {
// Find the holder after the one we're interested in
if (holders[i - 1] == E(id)) {
// Swap their positions
E('alldivs').insertBefore(holders[i], E(id));
break;
}
}
resetNumbers();
}
function moveto(id, position) {
if (position == holders.length) { // move to end
E('alldivs').appendChild(E(id));
}
else { // move before another holder
E('alldivs').insertBefore(E(id), holders[position - 1]);
}
resetNumbers();
}
function resetNumbers() {
// Reset all the numbers to reflect their current position
var numbers = document.getElementsByClassName('number');
for (var i = 0; i < numbers.length; i++) {
numbers[i].innerHTML = i + 1;
}
}
A few other points:
clicking on the selects in your original code won't do anything initially, because no event handler is assigned to it until after one of the elements has been moved
there is a missing </div> from the end of the html
it is good practice to declare variables using var somewhere in your code
appendChild and insertBefore remove a node from its current position in the DOM before appending/inserting it in its new position, so there is no need to remove the element explicitly.
having moveup and movedown functions is better than only having moveto, which requires you to insert the current, preceding and following positions into the html and refresh them every time a block is moved.