How to create an arcade style name input in Javascript? - javascript

I'm trying to create an arcade style name input for a highscore list. I'd like it to work using just the arrow keys on the keyboard, so up/down arrow for character selection and left/right for input box selection. I'm using a MakeyMakey for this project, so I want to keep user/keyboard interaction as minimal as possible.
Right now I'm rendering select boxes containing the entire alphabet in option tags, however, a select box always drops down, and your choice has to be confirmed using Enter or a mouse-click.
I'd like to stay at least a little semantically correct on the input, so I'm thinking 3 inputs that each select one letter, then concatenating these in a hidden input field, of which I can pass the value to Rails.
I'm using the following jQuery-plugin (from: http://ole.michelsen.dk/blog/navigate-form-fields-with-arrow-keys.html) to navigate between select boxes using the left/right arrow keys.
(function($) {
$.fn.formNavigation = function() {
$(this).each(function() {
$(this).find('select').on('keyup', function(e) {
switch (e.which) {
case 39:
$(this).closest('td').next().find('select').focus();
break;
case 37:
$(this).closest('td').prev().find('select').focus();
}
});
});
};
})(jQuery);
What I want to implement next is three input boxes that have the entire (infinitely looped) alphabet as choices, navigable by up/down arrow. I'd rather not type out the entire alphabet so I want to generate the options for each box and probably bind a keyhandler somewhere. How would I generate such an input box and integrate the required code into my existing script?
Screenshots
This is how it looks now:
Ideally, it will look like this:

I think Banana had a great answer, but I wanted to try making it look a little more expressive.
KEYCODES = { left: 37, up: 38, right: 39, down: 40 };
$('.cyclic_input').on('keydown',function(ev){
input = $(this);
val = $(this).text();
switch (ev.keyCode) {
case KEYCODES.right:
input.next().focus();
break;
case KEYCODES.left:
input.prev().focus();
break;
case KEYCODES.up:
input.text(advanceCharBy(val, 1));
break;
case KEYCODES.down:
input.text(advanceCharBy(val, -1));
break;
default:
if (ev.keyCode >= 65 && ev.keyCode <= 65 + 26) {
input.text(String.fromCharCode(ev.keyCode));
input.next().focus();
}
};
ev.preventDefault();
});
advanceCharBy = function(char, distance) {
oldCode = char.charCodeAt(0);
newCode = 65 + (oldCode - 65 + 26 + distance) % 26;
return String.fromCharCode(newCode);
};
.cyclic_input {
float: left;
padding: 1rem;
font-size: 5rem;
position: relative;
display: table-cell;
vertical-align: middle;
text-align: center;
}
.cyclic_input:before,
.cyclic_input:after {
display: block;
position: absolute;
left: 50%;
font-size: 1rem;
transform: translateX(-50%);
}
.cyclic_input:before {
content: '▲';
top: 0;
}
.cyclic_input:after {
content: '▼';
bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cyclic_input" tabindex="0">A</div>
<div class="cyclic_input" tabindex="0">A</div>
<div class="cyclic_input" tabindex="0">A</div>
Forked Codepen but also works fine in the snippet. My thoughts:
I don't know keycodes, I don't want to know keycodes.
We're not interested in keypresses on the whole document, just the initials inputs.
If you must have branching logic, be clear how many paths there are, one.
If these are our form inputs, then they deserve at least tabindex. In reality I would use <input>s but that would have just added a bunch of CSS to the demo.
The whole point is keyboard support. I'm pretty sure we need to handle the case where a user types a letter.
Let's not jerk the page around when someone presses an arrow key.

Its rather simple, all you need is a few calculations:
if you have any questions, feel free to ask.
$(function() {
$(document).on("keydown", function(ev) {
if (ev.keyCode == 39) {
var idx = $('.active').index();
var next_idx = (+idx + 1) % $('.cyclic_input').length;
$('.active').removeClass('active');
$('.cyclic_input').eq(next_idx).addClass('active');
}
if (ev.keyCode == 37) {
var idx = $('.active').index();
var next_idx = ((+idx - 1) + $('.cyclic_input').length) % $('.cyclic_input').length;
$('.active').removeClass('active');
$('.cyclic_input').eq(next_idx).addClass('active');
}
if (ev.keyCode == 38) {
var char = $(".active").text();
var ascii = char.charCodeAt(0);
var nextAscii = 65 + (ascii + 1 - 65) % 26;
$(".active").text(String.fromCharCode(nextAscii));
}
if (ev.keyCode == 40) {
var char = $(".active").text();
var ascii = char.charCodeAt(0);
var nextAscii = 65 + ((ascii - 1 - 65) + 26) % 26;
$(".active").text(String.fromCharCode(nextAscii));
}
});
});
.cyclic_input {
width: 50px;
height: 50px;
display: inline-block;
border: 5px solid red;
font-size: 3em;
}
.active {
border-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cyclic_input active">A</div>
<div class="cyclic_input">A</div>
<div class="cyclic_input">A</div>
and here is a Fiddle
PS: the snippet here doesnt work too well, but if you test the code or check the jsfiddle it will work fine.

Related

On key up event working only once in JavaScript

I am trying to create a JavaScript game. There, I have created a function that whenever we press the right arrow key, the DIV should move to the right. When I press it for the first time, it works fine. However, when I press it after that, it does not work. Here is the code I have tried so far:
<html>
<head>
<style>
.runobj {
width: 80px;
height: 80px;
position: absolute;
background-color: #00ff00;
top: 0;
left: 0;
}
</style>
</head>
<body onkeydown="moveObj(event)">
<div class="runobj" id="runobj"></div>
<script>
function moveObj(event) {
var runobj = document.getElementById("runobj");
if (event.keyCode === 37) {
runobj.style.left -= 10;
} else if (event.keyCode === 39) {
runobj.style.left += 10;
}
}
</script>
</body>
</html>
What am I doing wrong here? Any help would be appreciated. Thankyou!
style.left is a string property with a unit (ie: "10px"). To add or take units of it you first need to parse it to a number or use another property (ie: offsetLeft) and after assign it back with the unit.
function moveObj(element, event){
console.log('keycode', event.keyCode);
//REM: Looking up the same element all the time is not ideal. Maybe pass it instead?
var runobj = element || document.getElementById("runobj");
//REM: You need to turn "style.left" into a number
var tCurrentLeft = parseFloat(runobj.style.left) || 0;
//REM: Just use a switch, since it looks like you are going to implement more key actions
switch(event.keyCode){
case 37:
//REM: Do not forget to add the unit
runobj.style.left = tCurrentLeft - 10 + 'px';
break
case 39:
//REM: Do not forget to add the unit
runobj.style.left = tCurrentLeft + 10 + 'px'
};
console.log('left', runobj.style.left)
};
//REM: It is better to fully split the javascript from the HTML markup. Also you can just pass the element and avoid lookups.
window.addEventListener('keydown', moveObj.bind(this, document.getElementById("runobj")));
.runobj {
width: 80px;
height: 80px;
position: absolute;
background-color: #00ff00;
top: 0;
left: 0;
}
<body>
<div class="runobj" id="runobj"></div>
</body>
Modified your code to handle the postfix px for left attribute:
<html>
<head>
<style>
.runobj {
width: 80px;
height: 80px;
position: absolute;
background-color: #00ff00;
top: 0;
left: 0;
}
</style>
</head>
<body onkeydown="moveObj(event)">
<div class="runobj" id="runobj"></div>
<script>
var _left = 0;
function moveObj(event) {
var runobj = document.getElementById("runobj");
if (event.keyCode === 37) {
_left -= 10;
} else if (event.keyCode === 39) {
_left += 10;
}
runobj.style.left = _left + 'px';
}
</script>
</body>
</html>
Make the function recursive so that on every click event it should moved automatically without refreshing it to the initials .
After the first modification, the value of the left property is the string '10px'. So to continue adding values, you need to extract that value before adding a new values, for example:
runobj.style.left = parseInt(runobj.style.left || 0, 10) + 10;
(The '|| 0' is for the first iteration, because it receives an empty string)
// cache the element
var runobj = document.getElementById("runobj");
function moveObj(event) {
var left = runobj.getBoundingClientRect().left;
if (event.keyCode === 37) {
left -= 10;
} else if (event.keyCode === 39) {
left += 10;
}
runobj.style.left = left + "px";
}
Working example
We need to convert style.left from String datatype to Number datatype inorder to increment or decrement the value.
After the first modification, the value of the left property is the string '10px'.
So when you tried to increment style.left by number 10 after the first modification, it becomes 10px10 which is not a valid value for style.left property.That's why it only works for the first time.
var runobj = document.getElementById("runobj");
function moveObj(event) {
/* Converting the left style value from String type to Number type.
'|| 0' is for the first iteration, because it receives an empty string */
var current = parseFloat(runobj.style.left) || 0;
if (event.keyCode === 37) {
current += 20;
} else if (event.keyCode === 39) {
current -= 20;
}
// Updating the value
runobj.style.left = current;
}

How can i make a keypress action to this code?

I am new to JavaScript and jQuery so here is my question. How can i add to this code a simple key press action.
Like if i press Right Arrow, go to the next image. and if i press the left arrow, go to the previous image.
I've looked it up and tried something myself but i couldn't integrate anything into this particular code.
Now, i could simply use another code and use a lightbox gallery or something, but i don't want that because i've alredy got somewhere with the website and i can't make it all over again.
function showImage(smSrc, lgSrc) {
document.getElementById('largeImg').src = smSrc;
showLargeImagePanel();
unselectAll();
setTimeout(function() {
document.getElementById('largeImg').src = lgSrc;
}, 1)
}
function showLargeImagePanel() {
document.getElementById('largeImgPanel').style.display = 'block';
}
function unselectAll() {
if (document.selection)
document.selection.empty();
if (window.getSelection)
window.getSelection().removeAllRanges();
}
#largeImgPanel {
text-align: center;
display: none;
position: fixed;
z-index: 100;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(100, 100, 100, 0.8);
}
<img src="./images/t_p0001.jpg" style="cursor:pointer" onclick="showImage(this.src, './images/p0001.JPG');" />
<img src="./images/t_p0002.jpg" style="cursor:pointer" onclick="showImage(this.src, './images/p0002.JPG');" />
<img src="./images/t_p0003.jpg" style="cursor:pointer" onclick="showImage(this.src, './images/p0003.JPG');" />
<img src="./images/t_p0004.jpg" style="cursor:pointer" onclick="showImage(this.src, './images/p0004.JPG');" />
<div id="largeImgPanel" onclick="this.style.display='none'">
<img id="largeImg" style="height:100%; margin:0; padding:0;" />
</div>
To detect key press using JQuery, you can bind a function to the keydownevent :
$(document).keydown(function(e) {
switch(e.which) {
case 37: // left
break;
case 38: // up
break;
case 39: // right
break;
case 40: // down
break;
default: return; // exit this handler for other keys
}
e.preventDefault(); // prevent the default action (scroll / move caret)
});
(taken from there)
To change the displayed img, what you could do is something along the lines of this :
$("#largeImgPanel").html('<img src="./images/t_p0001.jpg" style="cursor:pointer"');
Then you'd have to implement a system to know which image is being displayed, and use this information to determine the next image to show.
EDIT : as requested, to make it go through the images :
var imgs = ["./images/t_p0001.jpg", "./images/...", etc];
var currentImg = 0;
Then in the keydown event handler, you'd have :
case 37: // left
if (currentImg === 0) {
currentImg = imgs.length - 1;
}
else {
currentImg--;
}
break;
case 39: // right
if (currentImg === imgs.length - 1) {
currentImg = 0;
}
else {
currentImg++;
}
break;
Then you just have to update the src property of your img tag (after the switch) :
if (e.which === 37 || e.which === 39) {
$("#largeImgPanel>img").attr("src", imgs[currentImg]);
}

Sorting large number of DOM elements

I'm pulling a large number of nodes from sharepoint list and I'll try to sort them into a html table hopefully in orderly fashion. The way i need to do this is I need to split these z:rows into 5 different tables. Example should be self explanatory: https://jsfiddle.net/jse21z9d/1/
$(document).ready(function(){
$('#execB').click(function(){
$('.myUl li').each(function(){
var liText = $(this).text().toLowerCase();
var newliText = liText.replace(/[{()}]/g, "");
var textArray = newliText.split(/[,]/);
console.log(textArray);
$(textArray).each(function(index){
switch(true){
case (textArray[index].indexOf('pol') != -1):
$('#polDiv').append(liText+"<br>");
break;
case (textArray[index].indexOf('uk') != -1)
|| (textArray[index].indexOf('ire') != -1):
$('#ukDiv').append(liText+"<br>");
break;
case (textArray[index].indexOf('ger') != -1):
$('#gerDiv').append(liText+"<br>");
break;
case (textArray[index].indexOf('san') != -1):
$('#sanDiv').append(liText+"<br>");
break;
}
});
});
});
});
so that's what i got so far, and I'm wondering maybe there is a better way to do this as I think this code I wrote might slow the entire load up a lot if we are talking about 1000+ z:rows(li in this case) to go through?
I modified your own code with the following:
- Less appends: The iterations generate a string instead of multiple appends thus less actions are done over the DOM.
- Less searches: Even though a search by ID is generally an easy search. Its still better to execute the it once, and append the generated string.
Source:
https://jsfiddle.net/mamtkjw4/
$(document).ready(function(){
$('#execB').click(function(){
var polStr = "";
var ukStr = "";
var gerStr = "";
var sanStr = "";
$('.myUl li').each(function(){
var liText = $(this).text().toLowerCase();
var newliText = liText.replace(/[{()}]/g, "");
var textArray = newliText.split(/[,]/);
console.log(textArray);
$(textArray).each(function(index){
switch(true){
case (textArray[index].indexOf('pol') != -1):
polStr = polStr + liText+"<br>";
break;
case (textArray[index].indexOf('uk') != -1)
|| (textArray[index].indexOf('ire') != -1):
ukStr = ukStr + liText+"<br>";
break;
case (textArray[index].indexOf('ger') != -1):
gerStr = gerStr + liText+"<br>";
break;
case (textArray[index].indexOf('san') != -1):
sanStr = sanStr + liText+"<br>";
break;
}
});
});
if (polStr) {
$('#polDiv').append(polStr+"<br>");
}
if (ukStr) {
$('#ukDiv').append(ukStr+"<br>");
}
if (gerStr) {
$('#gerDiv').append(gerStr+"<br>");
}
if (sanStr) {
$('#sanDiv').append(sanStr+"<br>");
}
});
});
.holders{
background: gray;
width: 100px;
height: 200px;
margin-left: 15px;
margin-bottom: 15px;
float: left;
}
<button id="execB">execB</button>
<ul class="myUl">
<li>(UK/IRE, POL)</li>
<li>(UK/IRE)</li>
<li>(POL)</li>
<li>(SAN)</li>
<li>(GER, POL)</li>
<li>(GER)</li>
<li>(SAN, UK/IRE)</li>
</ul>
<div id="gerDiv" class="holders"><p>german div:</p><ul></ul></div>
<div id="ukDiv" class="holders"><p>uk/ire div:</p><ul></ul></div>
<div id="polDiv" class="holders"><p>pol div:</p><ul></ul></div>
<div id="sanDiv" class="holders"><p>san div:</p><ul></ul></div>
This is about as short and sweet as it gets. Also, this will multiply your text entry every time you click, so you can see how it handles as it gets larger.
$(document).ready(function() {
var clickCount = 1;
$("#execB").on("click", function() {
clickCount++;
$(this).text("Count("+clickCount+")");
$(".myUl li").each(function() {
var liText = new Array(clickCount).join($(this).text().toLowerCase() + "\n"),
textArray = liText.replace(/[{()}]/g, "").split(/[,]/);
$(textArray).each(function(i) {
switch (!0) {
case -1 != textArray[i].indexOf("pol"):
$("#polDiv").append(liText + "<br>");
break;
case -1 != textArray[i].indexOf("uk") || -1 != textArray[i].indexOf("ire"):
$("#ukDiv").append(liText + "<br>");
break;
case -1 != textArray[i].indexOf("ger"):
$("#gerDiv").append(liText + "<br>");
break;
case -1 != textArray[i].indexOf("san"):
$("#sanDiv").append(liText + "<br>")
}
});
});
$(document).scrollTop($(document).height());
})
});
.holders{
background: gray;
width: 100px;
height: 200px;
margin-left: 15px;
margin-bottom: 15px;
float: left;
}
button { position: fixed; top: .6em; }
ul { margin-top: 2.25em; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="execB">execB</button>
<ul class="myUl">
<li>(UK/IRE, POL)</li>
<li>(UK/IRE)</li>
<li>(POL)</li>
<li>(SAN)</li>
<li>(GER, POL)</li>
<li>(GER)</li>
<li>(SAN, UK/IRE)</li>
</ul>
<div id="gerDiv" class="holders"><p>german div:</p><ul></ul></div>
<div id="ukDiv" class="holders"><p>uk/ire div:</p><ul></ul></div>
<div id="polDiv" class="holders"><p>pol div:</p><ul></ul></div>
<div id="sanDiv" class="holders"><p>san div:</p><ul></ul></div>
Also it will auto scroll so you can just keep pushing the button ...
If it helps any, on system I'm currently on [HP ProBook 650 G1 Win7 Pro64], in Chrome, it didn't start slowing down till count of clicks on button was around 100, on FF around 95 and on IE Edge, also around 100. That would be that ul text 100 times

Checking function for sliding puzzle javascript

I created a sliding puzzle with different formats like: 3x3, 3x4, 4x3 and 4x4. When you run my code you can see on the right side a selection box where you can choose the 4 formats. The slidingpuzzle is almost done. But I need a function which checks after every move if the puzzle is solved and if that is the case it should give out a line like "Congrantulations you solved it!" or "You won!". Any idea how to make that work?
In the javascript code you can see the first function loadFunc() is to replace every piece with the blank one and the functions after that are to select a format and change the format into it. The function Shiftpuzzlepieces makes it so that you can move each piece into the blank space. Function shuffle randomizes every pieces position. If you have any more question or understanding issues just feel free to ask in the comments. Many thanks in advance.
Since I don't have enough reputation I will post a link to the images here: http://imgur.com/a/2nMlt . These images are just placeholders right now.
Here is the jsfiddle:
http://jsfiddle.net/Cuttingtheaces/vkyxgwo6/19/
As always, there is a "hacky", easy way to do this, and then there is more elegant but one that requires significant changes to your code.
Hacky way
To accomplish this as fast and dirty as possible, I would go with parsing id-s of pieces to check if they are in correct order, because they have this handy pattern "position" + it's expected index or "blank":
function isFinished() {
var puzzleEl = document.getElementById('slidingpuzzleContainer').children[0];
// convert a live list of child elements into regular array
var pieces = [].slice.call(puzzleEl.children);
return pieces
.map(function (piece) {
return piece.id.substr(8); // strip "position" prefix
})
.every(function (id, index, arr) {
if (arr.length - 1 == index) {
// last peace, check if it's blank
return id == "blank";
}
// check that every piece has an index that matches its expected position
return index == parseInt(id);
});
}
Now we need to check it somewhere, and naturally the best place would be after each move, so shiftPuzzlepieces() should be updated to call isFinished() function, and show the finishing message if it returns true:
function shiftPuzzlepieces(el) {
// ...
if (isFinished()) {
alert("You won!");
}
}
And voilà: live version.
How would I implement this game
For me, the proper way of implementing this would be to track current positions of pieces in some data structure and check it in similar way, but without traversing DOM or checking node's id-s. Also, it would allow to implement something like React.js application: onclick handler would mutate current game's state and then just render it into the DOM.
Here how I would implement the game:
/**
* Provides an initial state of the game
* with default size 4x4
*/
function initialState() {
return {
x: 4,
y: 4,
started: false,
finished: false
};
}
/**
* Inits a game
*/
function initGame() {
var gameContainer = document.querySelector("#slidingpuzzleContainer");
var gameState = initialState();
initFormatControl(gameContainer, gameState);
initGameControls(gameContainer, gameState);
// kick-off rendering
render(gameContainer, gameState);
}
/**
* Handles clicks on the container element
*/
function initGameControls(gameContainer, gameState) {
gameContainer.addEventListener("click", function hanldeClick(event) {
if (!gameState.started || gameState.finished) {
// game didn't started yet or already finished, ignore clicks
return;
}
if (event.target.className.indexOf("piece") == -1) {
// click somewhere not on the piece (like, margins between them)
return;
}
// try to move piece somewhere
movePiece(gameState, parseInt(event.target.dataset.index));
// check if we're done here
checkFinish(gameState);
// render the state of game
render(gameContainer, gameState);
event.stopPropagation();
return false;
});
}
/**
* Checks whether game is finished
*/
function checkFinish(gameState) {
gameState.finished = gameState.pieces.every(function(id, index, arr) {
if (arr.length - 1 == index) {
// last peace, check if it's blank
return id == "blank";
}
// check that every piece has an index that matches its expected position
return index == id;
});
}
/**
* Moves target piece around if there's blank somewhere near it
*/
function movePiece(gameState, targetIndex) {
if (isBlank(targetIndex)) {
// ignore clicks on the "blank" piece
return;
}
var blankPiece = findBlankAround();
if (blankPiece == null) {
// nowhere to go :(
return;
}
swap(targetIndex, blankPiece);
function findBlankAround() {
var up = targetIndex - gameState.x;
if (targetIndex >= gameState.x && isBlank(up)) {
return up;
}
var down = targetIndex + gameState.x;
if (targetIndex < ((gameState.y - 1) * gameState.x) && isBlank(down)) {
return down;
}
var left = targetIndex - 1;
if ((targetIndex % gameState.x) > 0 && isBlank(left)) {
return left;
}
var right = targetIndex + 1;
if ((targetIndex % gameState.x) < (gameState.x - 1) && isBlank(right)) {
return right;
}
}
function isBlank(index) {
return gameState.pieces[index] == "blank";
}
function swap(i1, i2) {
var t = gameState.pieces[i1];
gameState.pieces[i1] = gameState.pieces[i2];
gameState.pieces[i2] = t;
}
}
/**
* Handles form for selecting and starting the game
*/
function initFormatControl(gameContainer, state) {
var formatContainer = document.querySelector("#formatContainer");
var formatSelect = formatContainer.querySelector("select");
var formatApply = formatContainer.querySelector("button");
formatSelect.addEventListener("change", function(event) {
formatApply.disabled = false;
});
formatContainer.addEventListener("submit", function(event) {
var rawValue = event.target.format.value;
var value = rawValue.split("x");
// update state
state.x = parseInt(value[0], 10);
state.y = parseInt(value[1], 10);
state.started = true;
state.pieces = generatePuzzle(state.x * state.y);
// render game
render(gameContainer, state);
event.preventDefault();
return false;
});
}
/**
* Renders game's state into container element
*/
function render(container, state) {
var numberOfPieces = state.x * state.y;
updateClass(container, state.x, state.y);
clear(container);
var containerHTML = "";
if (!state.started) {
for (var i = 0; i < numberOfPieces; i++) {
containerHTML += renderPiece("", i) + "\n";
}
} else if (state.finished) {
containerHTML = "<div class='congratulation'><h2 >You won!</h2><p>Press 'Play!' to start again.</p></div>";
} else {
containerHTML = state.pieces.map(renderPiece).join("\n");
}
container.innerHTML = containerHTML;
function renderPiece(id, index) {
return "<div class='piece' data-index='" + index + "'>" + id + "</div>";
}
function updateClass(container, x, y) {
container.className = "slidingpuzzleContainer" + x + "x" + y;
}
function clear(container) {
container.innerHTML = "";
}
}
/**
* Generates a shuffled array of id-s ready to be rendered
*/
function generatePuzzle(n) {
var pieces = ["blank"];
for (var i = 0; i < n - 1; i++) {
pieces.push(i);
}
return shuffleArray(pieces);
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
}
body {
font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Helvetica, Arial, sans-serif;
font-size: 12px;
color: #000;
}
#formatContainer {
position: absolute;
top: 50px;
left: 500px;
}
#formatContainer label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
}
#formatContainer select {
display: block;
width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
#formatContainer button {
display: inline-block;
width: 100%;
}
.piece {
width: 96px;
height: 96px;
margin: 1px;
float: left;
border: 1px solid black;
}
.slidingpuzzleContainer3x3,
.slidingpuzzleContainer3x4,
.slidingpuzzleContainer4x3,
.slidingpuzzleContainer4x4 {
position: absolute;
top: 50px;
left: 50px;
border: 10px solid black;
}
.slidingpuzzleContainer3x3 {
width: 300px;
height: 300px;
}
.slidingpuzzleContainer3x4 {
width: 300px;
height: 400px;
}
.slidingpuzzleContainer4x3 {
width: 400px;
height: 300px;
}
.slidingpuzzleContainer4x4 {
width: 400px;
height: 400px;
}
.congratulation {
margin: 10px;
}
}
<body onload="initGame();">
<div id="slidingpuzzleContainer"></div>
<form id="formatContainer">
<label for="format">select format:</label>
<select name="format" id="format" size="1">
<option value="" selected="true" disabled="true"></option>
<option value="3x3">Format 3 x 3</option>
<option value="3x4">Format 3 x 4</option>
<option value="4x3">Format 4 x 3</option>
<option value="4x4">Format 4 x 4</option>
</select>
<button type="submit" disabled="true">Play!</button>
</form>
</body>
Here we have the initGame() function that starts everything. When called it will create an initial state of the game (we have default size and state properties to care about there), add listeners on the controls and call render() function with the current state.
initGameControls() sets up a listener for clicks on the field that will 1) call movePiece() which will try to move clicked piece on the blank spot if the former is somewhere around, 2) check if after move game is finished with checkFinish(), 3) call render() with updated state.
Now render() is a pretty simple function: it just gets the state and updates the DOM on the page accordingly.
Utility function initFormatControl() handles clicks and updates on the form for field size selection, and when the 'Play!' button is pressed will generate initial order of the pieces on the field and call render() with new state.
The main benefit of this approach is that almost all functions are decoupled from one another: you can tweak logic for finding blank space around target piece, to allow, for example, to swap pieces with adjacent ids, and even then functions for rendering, initialization and click handling will stay the same.
$(document).on('click','.puzzlepiece', function(){
var count = 0;
var imgarray = [];
var test =[0,1,2,3,4,5,6,7,8,'blank']
$('#slidingpuzzleContainer img').each(function(i){
var imgalt = $(this).attr('alt');
imgarray[i] = imgalt;
count++;
});
var is_same = (imgarray.length == test.length) && imgarray.every(function(element, index) {
return element === array2[index];
});
console.log(is_same); ///it will true if two array is same
});
try this... this is for only 3*3.. you pass the parameter and makethe array value as dynamically..

Licenseplate formatting & validation

I've got a blackout... I haven't got a clue how to apply the javascript to the text area...
Also; what is best? Load it using onfocus, onblur or onclick?
I have a text area like this:
<input type="text" name="c_Kenteken" id="invoerKenteken" class="zoek_kentekenplaat" />
And this script:
<script language="javascript" type="text/javascript">
function GetSidecodeLicenseplate(Licenseplate){
var arrSC = new Array;
var scUitz = '';
Licenseplate = Licenseplate.replace('-', '').toUpperCase();
arrSC[0] = /^[a-zA-Z]{2}[\d]{2}[\d]{2}$/ // 1 XX-99-99
arrSC[1] = /^[\d]{2}[\d]{2}[a-zA-Z]{2}$/ // 2 99-99-XX
arrSC[2] = /^[\d]{2}[a-zA-Z]{2}[\d]{2}$/ // 3 99-XX-99
arrSC[3] = /^[a-zA-Z]{2}[\d]{2}[a-zA-Z]{2}$/ // 4 XX-99-XX
arrSC[4] = /^[a-zA-Z]{2}[a-zA-Z]{2}[\d]{2}$/ // 5 XX-XX-99
arrSC[5] = /^[\d]{2}[a-zA-Z]{2}[a-zA-Z]{2}$/ // 6 99-XX-XX
arrSC[6] = /^[\d]{2}[a-zA-Z]{3}[\d]{1}$/ // 7 99-XXX-9
arrSC[7] = /^[\d]{1}[a-zA-Z]{3}[\d]{2}$/ // 8 9-XXX-99
arrSC[8] = /^[a-zA-Z]{2}[\d]{3}[a-zA-Z]{1}$/ // 9 XX-999-X
arrSC[9] = /^[a-zA-Z]{1}[\d]{3}[a-zA-Z]{2}$/ // 10 X-999-XX
//except licenseplates for diplomats
scUitz = '^CD[ABFJNST][0-9]{1,3}$' //for example: CDB1 of CDJ45
for(i=0;i<arrSC.length;i++){
if (Licenseplate.match(arrSC[i])) {
return i+1;
}
}
if (Licenseplate.match(scUitz)) {
return 'CD';
}
return false;
}
function FormatLicenseplate(Licenseplate,Sidecode) {
Licenseplate = Licenseplate.replace('-', '').toUpperCase();
if (Sidecode <= 6) {
return Licenseplate.substr(0, 2) + '-' + Licenseplate.substr(2, 2) + '-' + Licenseplate.substr(4, 2)
}
if (Sidecode == 7 || Sidecode == 9) {
return Licenseplate.substr(0, 2) + '-' + Licenseplate.substr(2, 3) + '-' + Licenseplate.substr(5, 1)
}
if (Sidecode == 8 || Sidecode == 10) {
return Licenseplate.substr(0, 1) + '-' + Licenseplate.substr(1, 3) + '-' + Licenseplate.substr(4, 2)
}
return Licenseplate
}
</script>
The CSS:
input.zoek_kentekenplaat
{
border:none;
border-color:#F0F0F0;
font-size: 18px;
font-weight: bold;
line-height: 0px;
width: 125px;
height: 30px; /*background-color: #f4be04;*/
padding-left: 20px; /*border: 1px solid #ffcc00;*/
padding-bottom: 0px;
padding-top: 0px;
text-transform: uppercase;
/*margin-left: 10px;*/
margin-top: 2px;
background: url(http://email.allianz.nl/public/ANG/278b2c33c92f75d6795b0c75e3a18e21/kenteken_125_2_2.jpg) no-repeat;
/*margin-bottom: 21px;*/
}
Here's the JSFIDDLE: http://jsfiddle.net/jazperader/676sD/
I got the distinct feeling that it's just something tiny and stupid.
I know there isn't a onfocus, onblur or onclick in the text area HTML.
I'd like your expert opinion on this ;-)
Thanks!
Jazper
What you are trying to do is common, however, it brings up some performance concerns. Since you would ideally like to have the formatting applied as they type what you could do is use the keydown or keyup event so something like:
<input type="text" onkeyup="myFunction()">
Again, this would fire every time the user typed and removed their finger from the key. So you are potentially creating a performance issue since the event will fire frequently. In your situation it may not be a big deal since you are only dealing with a small amount of text so the event may only fire 10 times or so.
If you do want to optimize your code a bit have a look at this http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/ You will see an example of how to throttle your events so your code is not executed every time.

Categories