I made a puzzle game using HTML5, just now I tried to add local storage to the game, but failed.
I wrote three functions. The problem is: If I put all the functions in one .js file, none is defined when debugging(via chrome). If I split these three functions to another file and add a tag to the .html file, I'm told these are not defined.
So how to solve this problem?
Sorry for my poor English, hope you understand what I means.
Here are my functions and html file.
<html>
<head>
<meta charset="utf-8">
<title>Puzzle</title>
<script src="puzzle-localstorage.js"></script>
<script src="puzzle.js"></script></script>
</head>
<body onLoad="Init()" onkeydown="keydown()">
<p align="center">
<canvas id="board" height="600" width="600" style="border-style:double">
Your Browser doesn't support canvas
</canvas>
</p>
<p id="moves">Moves: <span id="movecount">0</span>
<input type="number" id="boardEdgeNum" value="3"/>
<input type="file" id="imgSrc"/>
</p>
function supportsLocalStorage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch (e) {
return false;
}
}
function saveGameState() {
if (!supportsLocalStorage()) { return false; }
localStorage["puzzle.boardEdge"] = boardEdge;
localStorage["puzzle.blockPixel"] = blockPixel;
for (var i = 0; i < boardEdge; i++) {
for(var j=0;j<boardEdge;j++){
localStorage["puzzle.gameStatus."+i+j] = gameStatus[i][j];
}
}
localStorage["puzzle.image.src"]=imgElement.src;
localStorage["puzzle.move.count"] = moveCount.textContent;
if(gameInProgress)localStorage["puzzle.game.in.progress"] = "true";
else localStorage["puzzle.game.in.progress"]="false";
localStorage["puzzle.empty.block.X"] = emptyBlock.X;
localStorage["puzzle.empty.block.Y"] = emptyBlock.Y;
return true;
}
function resumeGame() {
if (!supportsLocalStorage()) {return false;}
if(!localStorage["puzzle.game.in.progress"]=="true"){return false;}
boardEdge=parseInt(localStorage["puzzle.boardEdge"]);
blockPixel=parseInt(localStorage["puzzle.blockPixel"]);
imgElement=new Image();
imgElement.src=localStorage["puzzle.image.src"];
gameStatus=new Array(boardEdge);
gameCompStatus=new Array(boardEdge);
for (var i = 0; i < boardEdge; i++) {
gameStatus[i]=new Array(boardEdge);
gameCompStatus[i]=new Array(boardEdge);
for(var j=0;j<boardEdge;j++){
gameStatus[i][j]=parseInt(localStorage["puzzle.gameStatus."+i+j]);
var x=(gameStatus[i][j]-1)%boardEdge;
var y=(gameStatus[i][j]-1-j)/boardEdge;
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
drawLines();
}
}
gameStatus[boardEdge-1][boardEdge-1]=0;
gameCompStatus[boardEdge-1][boardEdge-1]=0;
moveCount.textContent=localStorage["puzzle.move.count"];
gameInProgress=(localStorage["puzzle.game.in.progress"] =="true");
emptyBlock=new Cell(parseInt(localStorage["puzzle.empty.block.X"]),parseInt(localStorage["puzzle.empty.block.Y"]));
return true;
}
<script src="puzzle.js"></script></script>
What is this? Is it typo? Or in your real code it is so too? Try to remove them. Javascript should see your functions. Where is declarations for Init and keydown functions? Does javascript see them?
Have you checked for any errors? I see one in the loop of resumeGame:
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
should probably be:
drawingContext.drawImage(imgElement,x*blockPixel,y*blockPixel,blockPixel,blockPixel,
j*blockPixel,i*blockPixel,blockPixel,blockPixel);
Your url might be wrong. You are using a relative url instead of an absolute url, consequently the JS file must be in the same folder as the HTML Document.
Try an absolute url (e.g. http://www.servername.com/puzzle/js/puzzle.js") instead and check if that accomplishes anything.
Related
I'm working on a project for a friend and he wants a pure walk cycle with only HTML/JS (no CSS). So I've tried to work it out but the image only shows up on the webpage.
It doesn't move when I press any buttons or anything at all.
Please show me where I went wrong. I'm used to using HTML and CSS but this is my first JS so I don't know many terms.
How it appears in the website:
My code (HTML + JS):
<!DOCTYPE html>
<html>
<head>
<title>Javascript Animation</title>
<script language="Javascript">
<!--
var walker = new Array(6);
var curWalker = 0;
var startWalking;
for(var i=0; i<6; i++) {
walker[i] = new Image();
walker[i].src = "walker"+i+".png";
}
function marathon() {
if(curWalker == 5) curWalker == 0;
else ++curWalker;
document.animation.src = walker[curWalker].src;
}
-->
</script>
</head>
<body>
<p><img src="walk1.png" name="animation"> </p>
<form>
<input type="button" name="walk" value="walk" onclick="startWalking=setInterval('marathon(),100);">
<input type="button" name="stop" value="stop" onclick="clearsetInterval(startwalking);">
</form>
</body>
</html>
Here it is how I did it get to work (I had to build my simple images with Paint in order to use them in the animation):
<html>
<head>
<title>Javascript Animation</title>
</head>
<body>
<p><img src="walker1.png" id="animation"> </p>
<form>
<input type="button" name="walk" value="walk" onclick="startWalking=setInterval(marathon,100);">
<input type="button" name="stop" value="stop" onclick="clearInterval(startWalking);">
</form>
<script>
var walker = [];
var curWalker = 0;
var startWalking;
for(var i=0; i<6; i++) {
walker[i] = new Image();
walker[i].src = "walker"+i+".png";
}
function marathon() {
if(curWalker == 5)
curWalker = 0;
else
++curWalker;
document.getElementById("animation").src = walker[curWalker].src;
}
</script>
</body>
</html>
I had to correct several typos/mistakes:
Put the JS just before the </body> closing tag
The first paramether of setInterval() must be a function name, so it must be marathon (you had 'marathon(); note that leading single quote)
In order to get the image to be substituted it is better to access the element though Id instead of name attribute. So I changed the image to <img src="walker1.png" id="animation"> (animation is now the Id) and accessed it through document.getElementById("animation")
Now the animation starts... but stops to the last image instead of restarting to the first.
That was because you used to check the curWalker variable instead of performing an assignment: I put curWalker = 0; instead of curWalker == 0;
Almost there. The loop is complete, but the stop button doesn't work. Two typos are preventing this to work:
clearsetInterval doesn't exist. The function to be called is clearInterval
Javascript is a case sensitive language. You use startwalking variable as a parameter, but the correct variable name is startWalking. So you have to correct the onclick event writing clearInterval(startWalking); instead of clearsetInterval(startwalking);
Your animation is now complete.
Note: as correctly noted by #Mike 'Pomax' Kamermans, nowadays you can avoid the use of onclick as you can attach events to the document (such as "click") by using document.addEventListener.
<html>
<head>
<script type="text/javascript">
var image = document.getElementById(image);
var desc = document.getElementById(desc);
var images = ["http://i.imgur.com/XAgFPiD.jpg", "http://i.imgur.com/XAgFPiD.jpg"]
var descs = ["1", "2"]
var num = 0;
var total = images.length;
function clicked(){
num = num + 1;
if (num > total){
num = 0;
}
image.src = images[num];
desc.innerHTML = images[num];
}
document.getElementById(submit).onclick(clicked());
</script>
</head>
<body>
<div><h2>Project |</h2><h2> | herbykit</h2></div>
<div>
<button id="submit">Next</button><br/>
<img id="image" src="http://i.imgur.com/XAgFPiD.jpg" height="20%" width="50%"/>
<p id="desc">first desc.</p>
</div>
</body>
</html>
The line "document.getElementById(submit).onclick(clicked());" throws an error
"ReferenceError: submit is not defined"
When I tried accessing buttons in general
[through getElementsByClassName & getElementsByTagName]
it gave an error of "ReferenceError: button is not defined"
Using strings in getElementById it throws the error "getElementById is null"
I found several questions and answers to this.
Only one of them I understood how to implement, due to the use of PHP and that being the error on most others. Other solutions I found involved errors numerically.
On this error I tried a fix of printwindow.document.getElementById(..etc
This gives me an error of "ReferenceError: printwindow is not defined"
Browsers run JavaScript as soon as possible in order to speed up rendering. So when you receive this code:
<html>
<head>
<script type="text/javascript">
var image = document.getElementById(image); // Missing quotes, typo?
... in runs intermediately. There's no <foo id="image"> on page yet, so you get null. Finally, you get the rest of the page rendered, including:
<img id="image" src="http://i.imgur.com/XAgFPiD.jpg" height="20%" width="50%"/>
It's too late for your code, which finished running long ago.
You need to bind a window.onload even handler and run your code when the DOM is ready (or move all JavaScript to page bottom, after the picture).
It should be document.getElementById('submit').onclick(clicked());
your must enclose the id you are searching for in quotes:
document.getElementById('ID_to_look_up');
You are executing javascript before your 'body' rendered. Thus document.getElementById("submit") would return null. Because there are no "submit" DOM element yet.
One solution is to move your javascripts under 'body', Or use JQuery with
$(document).ready(function() {
...
});
Your variable also has scope problem, your function cannot access variable declared outside this function with 'var' declaration. If you really need that variable, you should remove 'var' declaration.
A better way is to move all your variable inside clicked function. like following code
<html>
<head>
</head>
<body>
<div><h2>Project |</h2><h2> | herbykit</h2></div>
<div>
<button id="submit">Next</button><br/>
<img id="image" src="http://i.imgur.com/XAgFPiD.jpg" height="20%" width="50%"/>
<p id="desc">first desc.</p>
</div>
</body>
<script type="text/javascript">
function clicked(){
var image = document.getElementById("image");
var desc = document.getElementById("desc");
var images = ["http://i.imgur.com/XAgFPiD.jpg", "http://i.imgur.com/XAgFPiE.jpg"];
var descs = ["1", "2"];
var num = 0;
var total = images.length;
num = num + 1;
if (num > total){
num = 0;
}
image.src = images[num];
desc.innerHTML = images[num];
}
document.getElementById("submit").onclick = clicked;
</script>
</html>
I have a static page, which I'm using for viewing pictures, and the javascript does the slide show; however, I would like to dump the pictures in same directory and when page is opened, the javascript will create an array with all the pictures without me having to edit the array for every scenario.... is this possible?... I know javascript has some security restrains when it comes to read from local filesystem. here's the static page and javascript
<!doctype html>
<html lang="en">
<head>
<title>Picture Show</title>
<link type="text/css" rel="stylesheet" href="stylesheet.css" />
<script type="text/javascript" src="slideshow.js"></script>
</head>
<body>
<!-- Insert your content here -->
<div id="container">
<div id="header">
<h1>Slide Show</h1>
<a id="link" href="javascript:slideShow()"></a>
</div>
<div id="slideShow">
<img name="image" alt="Slide Show" src="pics/0.jpg" />
</div>
</div>
</body>
</html>
javascript
//javascript code for slideshow
//pictures
var imgs = [ "pics\/0.jpg", "pics\/1.jpg", "pics\/2.jpg", "pics\/3.jpg", "pics\/4.jpg", "pics\/5.jpg" ];
var imgNum = 0;
var imgsLength = imgs.length-1;
var time = 0;
//changing images function
function changeImg(n) {
imgNum += n;
//last position of array
if (imgNum > imgsLength) {
imgNum = 0;
}
//first position of array
if (imgNum < 0) {
imgNum = imgsLength;
}
//console.log(images.tagName);
document.image.src = imgs[imgNum];
return false;
}
//slideshow function
function slideShow() {
var tag = document.getElementById('link').innerHTML;
if(tag == "Stop") {
clearInterval(time); //stoping slideshow
document.getElementById('link').innerHTML = "Start";
document.getElementById('link').style.background = "yellow";
}
else { //all other cases come here
time = setInterval("changeImg(1)", 4000);
document.getElementById('link').innerHTML = "Stop";
document.getElementById('link').style.background = "green";
}
}
window.addEventListener('load', slideShow);
It's not possible to automatically read a directory with in-browser javascript because of security issues. You have two options here:
Make a multiple file input and let the user select the images to display. He could just use "ctrl+a" inside a directory to select everything ... of course this is bad cuz it requires a file select for every slideshow.
or...
Make a server side application that will upload the files or a list with their path. This will do the trick just the way you want, but the application must be installed and running on the machine in order to work. This could be easily achieved with nodejs and I bet you will find a module that will help you.
EDIT
Thank you all for your assistance. I have made the modifications to the script, with try and catch (err), however, i still do not get the alert when the code is run. I've also replaced "studentInfo[i].getElementsByTagName("id")[i].childNodes[i].nodeValue" with "studentInfo[i].getElementsByTagName("id")[0].childNodes[0].nodeValue" as well as all similar references, except now, it won't even return the first loop. It seems to be exiting the function before it hits "catch" for some reason.I've marked the changes in bold.
I know this has been posted quite a bit on this site, but none of the answers seem to quite be able to help me. I have a for loop that stops iterating after the first loop. The data from the first loop is correct, but I need it to keep looping through. I've used a couple different lint tools and they say my code is valid, so I must be forcing it to exit the loop some how. Someone help me figure out what I'm doing wrong, please.
<html>
<head>
<title>Tardy Reporting</title>
<script type="text/javascript" src="students.js">
</script>
</head>
<body>
<h1>Scan in Student ID</h1>
<form method="POST" name="idForm" id="idForm" />
<input type="text" name="idNumber" id="idNumber"/>
<input type="button" name="Search" value="Search" onClick="getId(document.idForm.idNumber.value);" />
</form>
<br></br>
<div id="div1"></div>
<p>
</body>
</html>
var ajxObj;
if(window.XMLHttpRequest){
ajxObj = new XMLHttpRequest();
}
else{
ajxObj = new ActiveXObject('Microsoft.XMLHTTP');
}
ajxObj.open("GET","studentbase.xml",false);
ajxObj.send();
xmlData = ajxObj.responseXML;
var studentInfo = xmlData.getElementsByTagName("student");
function getId(studentId) {
**try{**
for(var i = 0; i < studentInfo.length; i++) {
if(studentId == **studentInfo[i].getElementsByTagName("id")[0].childNodes[0].nodeValue || studentId === studentInfo[i].getElementsByTagName("name")[0].childNodes[0].nodeValue**){
document.getElementById('div1').innerHTML=(studentInfo[i].getElementsByTagName("name")[0].childNodes[0].nodeValue);
}
else {
document.getElementById('div1').innerHTML="Error: Not Found"
}
}
**}catch (err){
alert(err.ToString());
}**
}
<?xml version="1.0" encoding="UTF-8" ?>
<thebase>
<student>
<id>50011234</id>
<name>Mike Simpson</name>
<grade>n/a</grade>
<teacher>George Washington</teacher>
<tardies>0</tardies>
</student>
<student>
<id>50012345</id>
<name>Greg Pollard</name>
<grade>n/a</grade>
<teacher>Darth Vadar</teacher>
<tardies>0</tardies>
</student>
<student>
<id>50013456</id>
<name>Jason Vigil</name>
<grade>n/a</grade>
<teacher>Obi Wan Kenobi </teacher>
<tardies>0</tardies>
</student>
</thebase>
I suspect your code is throwing an error and you are not aware of this. I suspect the reference "studentInfo[i].getElementsByTagName("id")[i].childNodes[i].nodeValue" should be "studentInfo[i].getElementsByTagName("id")[0].childNodes[0].nodeValue".
Try putting a "try...catch" around the "for" loop, like so:
function getId(studentId) {
try {
for(var i = 0; i < studentInfo.length; i++) {
if (studentId == studentInfo[i].getElementsByTagName("id")[i].childNodes[i].nodeValue || studentId === studentInfo[i].getElementsByTagName("name")[i].childNodes[i].nodeValue){
document.getElementById('div1').innerHTML=(studentInfo[i].getElementsByTagName("name")[0].childNodes[0].nodeValue);
}
else {
document.getElementById('div1').innerHTML="Error: Not Found"
}
}
} catch (err) {
alert(err.ToString());
}
}
There needed to be three equal signs (ie. "===") in the if statement.
I have an application that needs to retrieve a value out of a hidden input form field. However, this application has a base page which calls another page that is in an iFrame and then it also can call itself inside another iFrame:
default.asp -> screen.asp (in iFrame)
screen.asp -> a new instance of screen.asp (in iFrame)
document.getElementById('focusValue').value
window.frames[0].document.getElementById('focusValue').value
parent.frames[arrVal].document.getElementById('focusValue').value
When I reference the hidden input form field from default -> screen I can use the standard document.getElementById('focusValue').value;. Then when I'm in the 1st level iFrame I have to use window.frames[0].document.getElementById('focusValue').value;. Then when I'm in the 2+ levels in an iFrame I have to use the parent.frames[arrVal].document.getElementById('focusValue').value;.
A common structure that I'm starting to see is this:
if(document.getElementById('focusValue') == undefined){
window.frames[0].document.getElementById('focusValue').value = focusValue;
console.log('1');
}else if((parent.frames.length -1) == arrVal){
console.log('2');
if (arrVal > 0) {
parent.frames[arrVal].document.getElementById('focusValue').value = focusValue;
}
}else{
document.getElementById('focusValue').value = focusValue;
console.log('3');
}
Now I can certainly do this but outside of writing a novel worth of comments I'm concerned with other programmers(or me 1 month from now) looking at this code and wondering what I was doing.
My question is there a way to achieve what I'm looking to do in a standard form? I'm really hoping that there is a better way to achieve this.
I would suggest you have each page do the work of finding the value you want by calling a method. Basically exposing a lookup interface. Then you only need to call a method on the target page from the parent page. Proper naming will help developers understand what is going on and using methods will simplify the logic.
Or if you only need to get the value from the parent page, then you could register a hook with each page in an iframe using a common interface. Each page can just call that hook to get the value. This prevents your complex logic of determining what level the page is. Something like
iframe1.GetValueHook = this.GetValue;
iframe2.GetValueHook = this.GetValue;
Then each page can just call
var x = this.GetValueHook();
If you have nested pages, you could make this recursive. If you need communication between all pages then use the same approach but with a registration process. Each page registers itself (and it's children) with it's parent. But if you need to do this then you should reevaluate your architecture.
Example:
register.js
var __FRAMENAME = "Frame1";
var __FIELDID = "fieldId";
var __frames = [];
function RegisterFrame(frame) {
__frames.push(frame);
for (var i = 0; i < frame.children.length; i++) {
__frames.push(frame.children[i]);
}
RegisterWithParent();
}
function RegisterWithParent() {
var reg = {
name: __FRAMENAME,
getvalue: GetFieldValue,
children: __frames
};
if(parent != undefined && parent != this) {
parent.RegisterFrame(reg);
}
}
function SetupFrame(name, fieldId) {
__FRAMENAME = name;
__FIELDID = fieldId;
RegisterWithParent();
}
function GetFieldValue() {
return document.getElementById(__FIELDID).value;
}
function GetValueFrom(name) {
for (var i = 0; i < __frames.length; i++) {
if (__frames[i].name == name) {
return __frames[i].getvalue();
}
}
}
index.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
PAGE
<input type="hidden" id="hid123" value="123" />
<iframe id="frame1" src="frame1.html"></iframe>
<iframe id="frame2" src="frame2.html"></iframe>
<script type="text/javascript">
SetupFrame("Index", "hid123");
setTimeout(function () { //Only here for demonstration. Make sure the pages are registred
alert(GetValueFrom("frame3"));
}, 2000);
</script>
</body></html>
frame1.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid" value="eterert" />
<script type="text/javascript">
SetupFrame("frame1", "hid");
</script>
</body></html>
frame2.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid456" value="sdfsdf" />
<iframe id="frame2" src="frame3.html"></iframe>
<script type="text/javascript">
SetupFrame("frame2", "hid456");
</script>
</body></html>
frame3.html
<html>
<head>
<script language="javascript" type="text/javascript" src="register.js"></script>
</head>
<body>
<input type="hidden" id="hid999" value="bnmbnmbnm" />
<script type="text/javascript">
SetupFrame("frame3", "hid999");
</script>
</body></html>
This would be better if you can change it up to use a dictionary/hash tbale instead of loops.
Your best bet will be to set varables named correctly so it's self documenting. Something like this...
var screenFrame = window.frames[0];
var screenFrame2 = parent.frames[arrVal];
var value = screenFrame2.document.getElementById('focusValue').value
This will make it easier to read.
If you really must search frames for a given element, then you should just make your own function to do that and use that function everywhere. Put a lot of comments in the function explaining why/what you're doing and give the function a meaningful name so it will be more obvious to future programmers looking at your code what you are doing or where they can look to find what you are doing.
function setValueByIdFrames(name) {
if(document.getElementById(name) == undefined){
window.frames[0].document.getElementById(name).value = name;
console.log('1');
} else if((parent.frames.length -1) == arrVal){
console.log('2');
if (arrVal > 0) {
parent.frames[arrVal].document.getElementById(name).value = name;
}
} else {
document.getElementById(name).value = name;
console.log('3');
}
}