Hide background-image inline styling from source code - javascript

I needed to create a simple memory game for a course I'm attending and I came up with this:
Simple memory game
$(document).ready(function(){
// Set initial time to 0
var currentTime = 0;
// Set initial score to 0
var score = 0;
// Set initial attempt to 0
var attempts = 0;
// Placeholder
var timeHolder;
// Start the game when clicking the button #start
$('#start').on('click', init);
// Check if user hasn't clicked #start button yet
$('.board_cell').on('click.initialCheck', checkInitial);
function init() {
// Shuffle elements at beginning
shuffle();
// Handle click event and check if elements match
$('.board_cell').on('click', checkAccuracy).off('click.initialCheck');
$('#start').off('click', init);
$('#reset').on('click', reset);
// stop timer
clearInterval(timeHolder)
// Timer function will be called every 100ms
timeHolder = window.setInterval(timer, 100);
}
/*
* Main function to handle click events and do actions
* #checkAccuracy
*/
function checkAccuracy() {
var self = $(this),
allElements = $('.board_cell'),
// Url of background-image
bgUrl = self.children('.back').css('background-image'),
// Get relevant part (the image name) from the url
elementType = bgUrl.slice(bgUrl.lastIndexOf('/') + 1, bgUrl.lastIndexOf('.'));
// Flip the clicked element
self.addClass('flipped ' + elementType);
// Check if clicked element is already visible
if (self.hasClass('success')) {
showMessage('Das ist schon aufgedeckt ;)');
// Abort function by returning false
return false;
}
if($('.flipped').length >= 2) {
// Prevent clicking on other elements when 2 elements are already visible
allElements.off('click');
// Increase attempts
attempts++;
setAttempts();
}
if($('.'+elementType).length == 2) {
// If the same are visible
score++;
setScore();
showMessage(['That was a right one!!!', 'Now you got it!', 'Terrific!']);
toggleClasses('success', function(){
// Callback when toggleClasses has finsihed
if($('.success').length == allElements.length){
// If alle elements are visible
showMessage('Everything exposed, congrats!');
$('#overlay').fadeIn();
// Kill interval to prevent further increasing
clearInterval(timeHolder);
}
});
} else {
// If they are not the same
if($('.flipped').length == 2) {
toggleClasses();
showMessage(['Uhh that was wrong...', 'Are you drunk?', 'Try it again...', 'You better stop playing!',
'Seems like you need to train much more...', 'Annoying?', 'C\'mon!']);
}
}
}
/*
* Function to reset the game
*/
function reset() {
// turn elements and prevent clicking
$('.board_cell').removeClass('success flipped').off('click');
// hide overlay if visible
if($('#overlay').is(':visible')) {
$('#overlay').fadeOut();
}
// stop timer
clearInterval(timeHolder)
// set time to 0
currentTime = 0;
// set attempts to 0
attempts = 0;
setAttempts();
// set score to 0
score = 0;
setScore();
// hide message
showMessage('');
// set visible time to 0
$('#time span').text(currentTime);
// Check if user has clicked #start button
$('.board_cell').on('click.initialCheck', checkInitial);
$('#start').on('click', init);
}
/*
* Function to show a message
*/
function showMessage(msg) {
if(typeof msg == 'object') {
var randomNumber = Math.floor((Math.random()*msg.length)+1);
msg = msg[randomNumber-1];
}
$('#message span').html(msg);
}
/*
* Function to toggleClasses on clickable elements
*/
function toggleClasses(extraClass, callback) {
setTimeout(function(){
$('.flipped').removeClass().addClass('board_cell '+extraClass);
$('.board_cell').on('click', checkAccuracy);
if(typeof callback != 'undefined') {
callback();
}
}, 1000);
}
/*
* Function to increase score
*/
function setScore() {
$('#score span').text(score);
}
/*
* Function to increase attempts
*/
function setAttempts() {
$('#attempts span').text(attempts);
}
/*
* Function for timer
*/
function timer() {
currentTime = currentTime + 1;
$('#time span').text(currentTime/10);
}
/*
* Function for showing message when user hasn't clicked #start button yet
*/
function checkInitial() {
showMessage('You need to press the "Start Game" button to beginn');
}
/*
* Function for shuffling elements
*/
function shuffle() {
var elementsArray = [];
$('.back').each(function(index){
elementsArray.push($(this).css('background-image'))
});
elementsArray.sort(function() {return 0.5 - Math.random()})
$('.back').each(function(index){
$(this).css('background-image', elementsArray[index]);
});
}
});
The hidden images are added through inline styling with background-image and are shuffled on each start/reset but that doesn't prevent a user to cheat during the game (looking at the source code tells the solution immediately).
I'd like to know if there is a way to hide the background-image value in the source code?
I tried some base64 encryption but as the browser interprets this immediately it doesn't serve at all. Another idea I had was to encrypt the background-image with php, display a random output (which was saved in a database for instance) in the markup and communicate through ajax requests with the php file on each click event. I'm not sure if this works, but anyway it seems like a circuitous way of handling it..
Any suggestion on how to solve this in safe and efficient way?

A safe (and overkill) solution would be to do this entirely serverside. Start a new game by generating a random session id and shuffling the squares. Then, your clientside JS requests the square images through AJAX via some sort of API:
GET /<session_id>/square/<x>/<y>
Once you rate limit the requests serverside to prevent a user from downloading all of the images at once, your game is safe.

Related

fail to create function interval to prevent other function run

hello i try to create the function to prevent the other function to run for 10 minutes IF user close the content and refresh the page.
the other function is to show the content when we scroll with 2 argument
first: it will run the function with first argument with no interval, if user click close and refresh. it will run the second argument that give interval
heres my code.
https://jsfiddle.net/8c1ng49a/1/
please look this code
var popUp= document.getElementById("popup");
var closePopUp= document.getElementsByClassName('popup-close');
var halfScreen= document.body.offsetHeight/2;
var showOnce = true;
var delay;
function slideUp(){
popUp.style.maxHeight="400px";
popUp.style.padding="10px 20px";
popUp.style.opacity="1";
if(popUp.className==="closed"){
popUp.className="";
}
}
function slideDown(){
popUp.style.maxHeight="0";
popUp.style.padding="0 20px";
popUp.style.opacity="0";
// add class closed for cache
if(popUp.className===""){
popUp.className="closed";
localStorage.setItem('closed', 'true'); //store state in localStorage
}
}
// start interval
function startDelay() {
delay = setInterval(slideUp, 1000);
}
// clear interval
function clearDelay() {
window.clearTimeout(delay);
}
// check if cache heve class close
window.onload = function() {
var closed = localStorage.getItem('closed');
if(closed === 'true'){
popUp.className="closed";
}
}
// show popup when scroll 50%
window.onscroll = function scroll(ev) {
// first time visited
if ((window.innerHeight+window.scrollY) >= halfScreen && showOnce) {
slideUp();
showOnce = false;
}
//same user mutilple time visited the site
else if((popUp.className==="closed" && window.innerHeight+window.scrollY) >= halfScreen && showOnce ){
startDelay();
showOnce = false;
}
};
// close button when click close
for(var i = 0; i<closePopUp.length; i++){
closePopUp[i].addEventListener('click', function(event) {
slideDown();
});
}
my interval didnt work onthe second argument its fire when i refresh, i dont know why.
but if add startDelay on my first arguments its work. but i need to place the interval on my second argu
When you want to make delay use setTimeout function.
Here is documentation of this function.
setInterval Repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.

Cant figuure out the control flow of my Javascript program

I'm trying to make a simple Javascript/Jquery program which will cycle through a product carousel I have on the front page of a website.
Here is the code:
jQuery(document).ready( function() {
function next() {
if(window.location.href === window.location.origin + '/') {
var nextButton = jQuery('.prevSlide');
nextButton.trigger('click');
console.log('next');
return;
}
}
function prev() {
if(window.location.href === window.location.origin + '/') {
jQuery('.nextSlide').click();
console.log('prev');
return;
}
}
jQuery('.iosSlider').hover( function() {
jQuery(this).addClass('pauseInterval');
}, function () {
jQuery(this).removeClass('pauseInterval');
}
);
function cycleNext() {
if( !(jQuery('.prevSlide').hasClass('disabled'))) {
if( !(jQuery('.iosSlider').hasClass('pauseInterval'))) {
next();
}
} else {
clearInterval(interval);
intervalTwo = setInterval(cyclePrev, 2000);
console.log('interval cleared');
console.log('intervalTwo set');
return;
}
}
function cyclePrev() {
if( !(jQuery('.nextSlide').hasClass('disabled'))) {
if(!(jQuery('.iosSlider').hasClass('pauseInterval'))) {
prev();
}
} else {
clearInterval(intervalTwo);
var interval = setInterval(cycleNext, 2000);
console.log('intervalTwo cleared');
console.log('interval set');
return;
}
}
var interval = setInterval(cycleNext, 2000);
console.log('interval set');
});
In each of the next() and prev() functions, I check whether I am on the home page, and only proceed if so.
There is also some code there to pause the cycle if the mouse is hovering over the product slider.
When the slider is at the very start or end, a class called 'disabled' is added to the prevSldie and nextSlide anchors.
So ideally I want to click through to the end of the slider, and then click back to the start, then the end, etc.
So the control flow, as I understand it, is as follows:
An interval is set so that the next button on my carousel is clicked every two seconds.
The slider reaches the end, that interval ends and a new one is set.
The previous button is clicked every two seconds until the start of the carousel.
This process repeats infinitely.
Things run fine when the slider runs to the end, the start, and the end again, and then things go haywire.
Console output (should click next and prev 5 times each)
(5) next
interval cleared
intervalTwo set
(5) prev
intervalTwo Cleared
interval set
(5) next
interval cleared
intervalTwo set
interval cleared
intervalTwo set
prev
next
(2) prev
next
(2) prev
next
And it only gets more haywire all over the place from there.
I cant figure out why everything works fine for the first few loops and stops working after that, any help would be hugely appreciated.
Are your intervals scoped correctly? You never define intervalTwo, so it becomes a global. Then also in the cyclePrev function, you use var interval again, which will be scoped to this function and hence won't contain the interval outside the function, that you want to clear once cycleNext gets reached again. Try changing:
var interval = setInterval(cycleNext, 2000),
intervalTwo = null;
console.log('interval set');
And then change var interval = setInterval(cycleNext, 2000); inside cyclePrev into interval = setInterval(cycleNext, 2000);

How to handle click event being called multiple times with jquery animation?

I have a click event that has a Jquery animation in it.
How can i guarantee that the animation has finished when multiple click events are being fired.
$(this._ScrollBarTrack).click(function(e) {
if(e.target === this && _self._horizontalClickScrollingFlag === false){
_self._horizontalClickScrollingFlag = true;
if(_self._isVertical){
} else{ //horizontal
if(e.offsetX > (this.firstChild.offsetWidth + this.firstChild.offsetLeft)){ // Moving Towards Right
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep + 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition+ scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition + scrollBarAmountToMove)});
_self._scrollBarCurrentStep += 1;
} else{
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep - 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition - scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition - scrollBarAmountToMove)});
_self._scrollBarCurrentStep -= 1;
}
}
_self._horizontalClickScrollingFlag = false;
}
});
jQuery has a hidden (I'm not sure why it's not in the docs someplace) variable $.timers that you can test against.
I made this function a long time ago to handle situations like this. Mind you, this will test to make sure there are NO animations currently being executed.
function animationsTest (callback) {
var testAnimationInterval = setInterval(function () {
if ($.timers.length === 0) { // any page animations finished
clearInterval(testAnimationInterval);
callback(); // callback function
}
}, 25);
};
Useage: jsFiddle DEMO
animationsTest(function () {
/* your code here will run when no animations are occuring */
});
If you want to test against one individually you could do a class/data route.
$('#thing').addClass('animating').animate({ left: '+=100px' }, function () {
// your callback when the animation is finished
$(this).removeClass('animating');
});
You could declare a global boolean called isAnimating and set it to true right when you begin the animation. Then add a done or complete function to the animation that sets it back to false. Then set your click event to only begin the animation if isAnimating is false.

html5-video download progress only working on firefox

I have the following function to calculate the loading progress of a video (quite common):
function updateProgressBar (video) {
if (video.buffered.length > 0) {
var percent = (video.buffered.end(0) / video.duration) * 100;
$('#loading').css({'width': percent + '%'});
console.log(percent);
if (percent == 100) {
console.log('video loaded!');
//everything is loaded, do something.
$(video).unbind('loadeddata canplaythrough playing'); //prevents the repetition of the callback
}
}
}
...bound to the 'progress' event (and some others as a safety meassure) inside a $(document).ready function:
var videoTest = document.getElementById("videoTest");
$('#videoTest').bind('progress', function () {
updateProgressBar (videoTest);
});
$('#videoTest').bind('loadeddata', function () {
updateProgressBar (videoTest);
});
$('#videoTest').bind('canplaythrough', function () {
updateProgressBar (videoTest);
});
$('#videoTest').bind('playing', function () {
updateProgressBar (videoTest);
});
You can view a live example here: http://www.hidden-workshop.com/video/
As you can see, it all works well on firefox, but in the rest of the browsers, the 'percent' variable never reaches the value of '100' as it would be expected; the function always stops at 90~, and thus I'm unable to know when the video has finished loading (vital for what I'm trying to do).
It's like the 'progress' event stops working before I can get the final value of 'percent', because if you click the 'play' button, the 'playing' event fires and then successfully calculates and reads the 'percent' variable's last value (which is 100).
Am I missing something, or is it a common issue? Is there any workaround I could use?
Thanks in advance!
var videoElement = null; //TODO set reference to video element
var checkVideoLoadingProgressTimerDelay = 50;
var checkVideoLoadingProgressTimerID = -1;
function getVideoLoadingProgress(){
var end = 0;
if(videoElement.buffered.length >= 1){
end = videoElement.buffered.end(0);
}
var progress = end / videoElement.duration;
progress = isNaN(progress) ? 0 : progress;
return progress;
};
function startCheckVideoLoadingProgressTimer(){
checkVideoLoadingProgressTimerID =
setTimeout(checkVideoLoadingProgressTimerHandler, checkVideoLoadingProgressTimerDelay);
};
function checkVideoLoadingProgressTimerHandler(){
var progress = getVideoLoadingProgress();
//TODO update progress bar
if(progress < 1){
startCheckVideoLoadingProgressTimer();
}
};
Also value "auto" for "preload" attribute of video not guarantee that user agent will load whole video.

Stop a javascript function

What I want:
Monitor a player to execute a function when it reach 85% of the movie - Ok
Execute a PHP script that insert some data into a Mysql table - Ok
Do this only one time (stop looping), since I want only one row in the Mysql table - Fail
My code:
jwplayer().onTime(function(evt) {
if (evt.position > ([evt.duration] * (85/100)) && x!=1) {
loadXMLDoc();
var x = 1;
}
});
Thanks
The problem is that x gets reset everytime
jwplayer().onTime(
(function () {
var check=true;
return function(evt) {
if (check && evt.position > ([evt.duration] * (85/100))) {
loadXMLDoc();
check=false;
}
}
})()
);
If you want the function to run only once with each page load, another approach is to make a function that commits suicide.
(function (player) {
var checkAndLoad = function(evt) {
if (evt.position > (evt.duration * (85/100))) {
loadXMLDoc();
checkAndLoad=function(evt){};
}
};
player.onTime(function(evt) {checkAndLoad(evt);});
})(jwplayer());
You need the extra indirection provided by the anonymous wrapper since onTime gets its own copy of the event listener, so overwriting checkAndLoad won't affect the registered listener directly.
If you want the listener to run more than once, register additional listeners that restore checkAndLoad at the appropriate events (e.g. the user seeks back to near the beginning).
(function (player) {
var timeListener;
function checkAndLoad(evt) {
if (evt.position > (evt.duration * (85/100))) {
loadXMLDoc();
timeListener=function(evt){};
}
}
timeListener = checkAndLoad;
player.onTime(function(evt) {timeListener(evt);});
player.onSeek(function(evt) {
if (evt.position < (evt.duration * (15/100))) {
timeListener=checkAndLoad;
}
});
player.onComplete(function (evt) {timeListener=checkAndLoad;});
})(jwplayer());
Better would be to unregister the listener, but the JW Player API doesn't currently expose the removeEventListener method.

Categories

Resources