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.
Related
Given :
const display = document.querySelector('.display');
document.addEventListener("click", (event) => {
if (!event.target.closest("button")) return;
if(event.target.id === "button") {
if(event.target.textContent === "left"){
display.style.transform += "translateX(50px)";
} else if (event.target.textContent === "right"){
display.style.transform += "translateX(-50px)";
}
console.log("left :" + display.style.offsetLeft + ", right : " + display.style.offsetRight);
console.log("left :" + display.parentNode.style.offsetLeft + ", right : " + display.parentNode.style.offsetRight);
}
});
.meta-div {
box-shadow: 0 0 25px rgba(0, 0, 0, 0.4);
position: relative;
border-radius: 0.5em;
overflow: hidden; /* allows the border-radius to be visible. */
width: 14rem;
}
.outer-div {
color: black;
text-overflow: normal;
white-space: nowrap;
overflow: hidden;
text-align: right;
border-left: 30px solid black;
border-right: 30px solid black;
}
.display {
float:right;
padding-right: 5px;
transition: transform 250ms;
}
<div class="meta-div">
<div class="outer-div">
<div class="display">111 + 222 + 333 + 444 + 555 + 666 + 777 + 888 + 999</div>
</div>
</div>
<button id="button">left</button>
<button id="button">right</button>
my goal is to find a way to extract the display's text position relative to its container (which I set to relative for offsetLeft to work), such that the left/right buttons don't work when the text has reached the respective left or right maximal position. Basically, I want the text to minimally start at "111 + ..." or maximally end at "... + 999".
In other words, I want to set a limit to the display.style.transform += "translateX(50px)"; function call both from the left and from the right.
Looking online the solution seems to be to use offset. In my case, the offset seems to be undefined in both directions for both the display text element and its parent container. Could this be because of the float:right property? I am short of ideas on how to implement this small feature. I suspect I may not even be using the right function at all (offset) ?
Does anyone have any tips or ideas?
The main problem with your code is that, the attribute that should be used is display.offsetLeft and display.offsetTop. You are currently using display.style.offsetLeft.
Apart from that, there is no attribute called offsetRight. If you want to do that, you will have to calculate it yourself.
Hence your code can be rewritten like so:
const display = document.querySelector('.display');
document.addEventListener("click", (event) => {
if (!event.target.closest("button")) return;
if(event.target.id === "button") {
if(event.target.textContent === "left"){
display.style.transform += "translateX(50px)";
} else if (event.target.textContent === "right"){
display.style.transform += "translateX(-50px)";
}
console.log("left :" + display.offsetLeft);
}
});
Apart from this, you could also use the getBoundingClientRect() function, and then calculate the difference in the offsets between the parent and the child elements. But since, I don't know the use case, I could be wrong about this. getBoundingClientRect can be used as follows though:
const display = document.querySelector('.display');
const container = document.querySelector('.outer-div');
document.addEventListener("click", (event) => {
if (!event.target.closest("button")) return;
const eleRect = container.getBoundingClientRect();
const targetRect = display.getBoundingClientRect();
if(event.target.id === "button") {
if(event.target.textContent === "left"){
display.style.transform += "translateX(50px)";
} else if (event.target.textContent === "right"){
display.style.transform += "translateX(-50px)";
}
// Calculate the top and left positions
const top = eleRect.top - targetRect.top;
const left = eleRect.left - targetRect.left;
console.log("left :" + left);
}
});
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.
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..
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/CSS">
#custom{
font-family: monospace;
font-size: 16px;
max-width: 650px;
border-style: solid;
border-color: black;
border-width: 1px;
border-radius: 5px;
padding: 8px;
padding-bottom: 15px;
padding-left: 12px;
padding-right: 12px;
}
img{
margin-top: 3px;
float: left;
}
#bar, #currentTime, #duration, #skip{
display: inline-block;
}
#currentTime, #duration, #skip{
margin: 0px;
padding: 0px;
margin-top: 3px;
margin-left: 10px;
}
#bar{
margin-top: 10px;
height: 14px;
width: 400px;
background: lightgrey;
border-radius: 50px;
margin-left: 9px;
}
#slider{
height: 14px;
width: 15px;
background: black;
border-radius: 50px;
}
</style>
</head>
<body onLoad="count()">
<script type="text/javascript">
var track = 0;
function count(){
var music = document.getElementById("myAudio");
var duration = music.duration;
var durationInMins = Math.floor(duration/60);
var durationInSecs = Math.floor(duration-(durationInMins*60));
if(durationInSecs < 10){
var durationInSecs = "0" + durationInSecs;
}
if(durationInMins < 10){
var durationInMins = "0" + durationInMins;
}
document.getElementById("duration").innerHTML = durationInMins + ":" + durationInSecs;
var timer = setInterval(
function(){
var music = document.getElementById("myAudio");
var currentTime = music.currentTime;
if(currentTime > 60){
var min = Math.floor(currentTime/60);
var sec = Math.floor(currentTime-(min*60));
}else{
var min = "0";
var sec = Math.floor(music.currentTime); }
if(sec < 10){
var sec = "0" + sec;
}
if(min < 10){
var min = "0" + min;
}
document.getElementById("currentTime").innerHTML = min + ":" + sec; var percent = 100 * (music.currentTime/duration) - 2;
document.getElementById("slider").style.marginLeft=percent + "%";
}
, 1000);
}
function toggleP(){
var music = document.getElementById("myAudio");
if(music.paused == true){
music.play();
}else if(music.paused == false){
music.pause();
}
}
function skip(){
var trackList = ["http://fidelak.free.fr/reprises/The%20Doors%20-%20People%20are%20Strange.mp3", "http://mp3light.net/assets/songs/14000-14999/14781-december-1963-oh-what-a-night-four-seasons--1411568407.mp3"];
if(go == "back"){
track = track - 1;
}
if(go == "forward"){
track = track + 1;
}
var aa = clearInterval("timer");
var music = document.getElementById("myAudio");
music.pause();
music.src=trackList[track];
music.load();
var a = setTimeout(function(){music.play(); count();} , 6000);
}
</script>
<audio id="myAudio" src="http://fidelak.free.fr/reprises/The%20Doors%20-%20People%20are%20Strange.mp3">
</audio>
<br>
<div id="custom">
<img onClick="toggleP()" src="img/media-play-pause-resume.png" height="30px"/>
<p id="currentTime">00:00</p>
<div id="bar">
<div id="slider"></div>
</div>
<p id="duration">00:00</p>
<p id="skip"><strong><a onClick="go = 'back'; skip()"><<</a> <a onClick="go = 'forward'; skip()">>></a><strong></p>
</div>
</body>
Could anyone tell me why the song duration slider jumps forwards and backwards after you skip to the second song? And why the duration bar cannot be moved down with margin-top without moving everything with it. I just can't figure it out. Any help would be greatly appreciated, Thanks.
jsBin demo
Don't use inline JS in your HTML! Makes code hard to debug. Keep your logic away from your presentation/template.
To start from, how variables work?
Once you set a var, there's no need to instantiate the same var again using var inside your code. Simply use/modify it. So once you set at the top
function el(id){return document.getElementById(id);} // Helps get easily an element
var el_music = el("myAudio"), // see?
el_trackInfo= el("trackInfo"),
el_duration = el("duration"),
el_currTime = el("currentTime"),
el_slider = el("slider"),
el_prev = el("prev"), // assign ID to your prev/next buttons!
el_next = el("next"),
el_togg = el("toggle"),
currentTime,
trackList = [],
track = -1, // Later we'll set it to 0 index triggering auto start
totTrack = trackList.length;
...you're good to go. No more var statements further in your code.
You probably want to show some more info to the user.
A good way to store your data is to create Objects with the desired properties:
trackList = [
{
artist : "The Doors",
fileName : "People Are Strange",
file : "http://fidelak.free.fr/reprises/The%20Doors%20-%20People%20are%20Strange.mp3"
},
{
artist : "ACDC",
fileName : "Back In Black",
file : "http://upload.wikimedia.org/wikipedia/en/4/45/ACDC_-_Back_In_Black-sample.ogg"
},
{
artist : "Four Seasons",
fileName : "Oh What A Night",
file : "http://mp3light.net/assets/songs/14000-14999/14781-december-1963-oh-what-a-night-four-seasons--1411568407.mp3"
}
]
now you can not only get the desired audio path, but also show the user more info about a track.
Don't Repeat Yourself. Calculating times all over the place makes your code not modular but messy. Instead create a function that'll help you return the desired formatted time:
function getTime(t) { // `t` is some time value
var m = ~~(t / 60),
s = ~~(t % 60);
return (m<10?"0"+m:m) +':'+ (s<10?"0"+s:s); // returns i.e: "01:25"
}
Create a progress function like:
function progress() {
el_currTime.innerHTML = getTime(el_music.currentTime); // see how our getTime fn is used?
el_duration.innerHTML = getTime(el_music.duration);
el_slider.style.marginLeft = Math.floor(100/el_music.duration*el_music.currentTime) + "%";
}
than a play/pause one:
function playPause(){
var isPaused = el_music.paused;
el_music[isPaused ? "play" : "pause"]();
el_togg.innerHTML = isPaused ? "❚❚" : "►" ;
}
for the PREV/NEXT, assign IDs to your buttons id="prev" and id="next" and again create a function that will handle both click cases:
function skip(){ // This gets triggered by both prev / next buttons.
track = this.id==="next" ? ++track : --track; // Next clicked' increment, else decr.
track = track < 0 ? totTrack-1 : track%totTrack; // Allows you to loop infinitely the index
var trackToPlay = trackList[ track ]; // Get the Track Object "{}"
el_trackInfo.innerHTML = trackToPlay.artist+' '+trackToPlay.fileName;
el_music.src = trackToPlay.file;
el_music.addEventListener('canplaythrough', el_music.play);
}
Believe it or not - you're done!
Having all those nifty functions in place, what you need now is some event listeners:
el_prev.addEventListener("click", skip);
el_next.addEventListener("click", skip);
el_togg.addEventListener("click", playPause);
el_music.addEventListener("timeupdate", progress);
el_music.addEventListener("ended", playPause);
el_next.click(); // Auto Start playing!
Now you probably wonder where's your interval 1000 function gone? It's simply handled by el_music.addEventListener("timeupdate", progress);.
The skipping may be caused by the fact that the interval is never stopped, and is still running for the previous song.
I have a javascript which opens up a window just before a surfer enters my site which has 24 hours cookie meaning it will popup again after the surfer visits my site again after 24 hours.
Right now one can only close the div if the red "x" button is pressed. Also when I run it I can only add images or iframes but I'd like o add some text like "welcome to my site".
Here is the code
var floatingAd={
run: function (e, t) {
if (e === 2 || e === 1 && (this.getCookie("floatingAd") === null || this.getCookie("floatingAd") === "")) {
document.write('<div id="floatingAdFixed" style="bottom: 0px; background: #fff; font-family: Arial, Helvetica, sans-serif; left: 0; padding: 0px 0; position: fixed; font-size: 16px; width: 100%; z-index: 99999; float: left; vertical-align: middle; margin: 0px 0 0; opacity: 0.88; font-weight: bold;">');
document.write('<div style="text-align: right; width: 710px; margin: 340px auto;"><img onclick="floatingAd.close(' + e + ');" style="position: absolute; margin-top: -11px; margin-left: -23px; cursor: pointer;" src="data:image/png;base64,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"></div>');
document.write('<div id="floatingAd" style="text-align: center; width: 710px; margin: 300px auto; ">');
document.write("</div>");
document.write("</div>");
document.getElementById("floatingAd").innerHTML = t
}
},
close: function (e) {
if (e === 1) {
this.setCookie("floatingAd", 1, 1)
}
document.getElementById("floatingAdFixed").style.display = "none"
},
setCookie: function (t, n, r) {
var i = new Date;
i.setDate(i.getDate() + r);
var s = escape(n) + (r == null ? "" : "; expires=" + i.toUTCString());
document.cookie = t + "=" + s + ";path=/"
},
getCookie: function (e) {
var t = document.cookie;
var n = t.indexOf(" " + e + "=");
if (n == -1) {
n = t.indexOf(e + "=")
}
if (n == -1) {
t = null
} else {
n = t.indexOf("=", n) + 1;
var r = t.indexOf(";", n);
if (r == -1) {
r = t.length
}
t = unescape(t.substring(n, r))
}
return t
}
}
/**
* Run the script
* 1 = 24 hours cookie, 2 = refresh
*/
floatingAd.run(1, '');
Two questions:
How do I make it to close if you click anywhere on the screen?
Hwo do I make it to show text in the floatingAd.run(1, '');?
For 1 check out How do I detect a click outside an element?
EDIT: If you would like to have the window closed if "you click anywhere on the screen", just use your object in the following way:
$('html').click(function() {
// You may skip the following if statement, it may work without it
if (document.getElementById("floatingAdFixed").style.display != "none")
// The following line is what you'll definitely need
floatingAd.close(1);
});
For 2, just add it as another variable in run like this
var floatingAd={
run: function (e, t, text) {
// ...
document.write('<div id="textContainer">' + text + '</div>');
// ...
}
Then use it like this:
floatingAd.run(1, '', 'Writing some text');
DEMO HERE