I want to play the songs only if the user press the button 'play',
without Waiting to load all the 21 songs.
when I press the button 'play' the page jump up like refreshing ,it is not normal.
what I can do to improve my code.
please try to play the songs in the example site and see the problem.
many thanks.
var Music = {
init:function(){
song = new Audio();
//speaKer = document.getElementById("imgSpeaker");
this.volume = 0.08;
this.isMute = false;
canPlayMP3 = (typeof song.canPlayType === "function" && song.canPlayType("audio/mpeg") !== "");
song.src = canPlayMP3 ? "http://rafih.co.il/wp-content/uploads/2013/07/1.mp3" : "http://rafih.co.il/wp-content/uploads/2013/07/1.ogg";
song.preload = 'auto';
},
/* start:function(){
song.src = canPlayMP3 ? "http://rafih.co.il/wp-content/uploads/2013/07/1.mp3" : "http://rafih.co.il/wp-content/uploads/2013/07/1.ogg";
song.volume = 0.08;
song.autoplay = true;
song.load();
},*/
play: function () {
song.volume = 0.08;
song.autoplay = true;
song.load();
// Music.speaker();
},
stop: function () {
if (!song.ended) {
song.pause();
}
},
next: function () {
if (curr < count) {
curr++;
}else curr = 1;
song.src = canPlayMP3 ? "http://rafih.co.il/wp-content/uploads/2013/07/" + curr + ".mp3" : "http://rafih.co.il/wp-content/uploads/2013/07/" + curr + ".ogg";
},
};
function load() {
Music.init();
}
You need to return false from the play buttons event handler, to prevent the page from scrolling to the top.
Change:
<div id="play" onclick='Music.play()'>
To:
<div id="play" onclick='Music.play(); return false;'>
That's because of the anchor in your link, such as href="#". A very simple fix would be to add return false; in to your inline handler attribute, such as onclick="Music.play(); return false;", however that isin't a good approach and is considered a bad practice.
Instead you could add your handlers programmatically, it will also make your code more modular and testable:
var Music = {
init: function (options) {
var playBtn = this.playBtn = document.querySelector(options.playBtn);
playBtn.addEventListener('click', this._onPlayBtnClick.bind(this));
//...
return this;
},
_onPlayBtnClick: function (e) {
e.preventDefault(); //prevents the browser's default behaviour
this.play();
},
//...
};
Then you could do something like:
function load() {
var musicController = Object.create(Music).init({
playBtn: '#play',
//...
});
}
You could also use it as a singleton like:
Music.init({ ... });
Related
I am making an app on visual studio 2012. I am navigating from home page to levelOne. On a button click on level one i'm doing some animation,during animation if i get back to home page using windows back button, and then again come back to level one i get the animation running ,i want this animation to get stopped.
This is my first page where the animation will occur:
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/levelOne/levelOne.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function initiazlize(element, options) {
document.getElementById("play").addEventListener("click",function initial(){
roundCount++;
if (flag1 == false) {
//if flag1 is false that means its time for next storyboard
j = 0;
var r3 = Math.random();
if (r3 <= 0.333) {
$(Left).animate({ marginTop: '-=100px' }, 500);
$(Left).animate({ marginTop: '+=100px' }, 500, animateAsync);
//document.getElementById("play").disabled = false;
}
else if (r3 <= 0.666) {
$(midle).animate({ marginTop: '-=100px' }, 500);
$(midle).animate({ marginTop: '+=100px' }, 500, animateAsync);
//document.getElementById("play").disabled = false;
}
else {
$("#bowlThree").animate({ marginTop: '-=100px' }, 500);
$("#bowlThree").animate({ marginTop: '+=100px' }, 500, animateAsync);
//document.getElementById("play").disabled = false;
}
//inside animate Async(), some more animation on capOne,capTwo,capThree and on object, I want to stop animation on these
//There is a counter j, when j reachs 100 animation is stopped
}
});
document.onbeforeunload = function () {
j = 100;
flag1 = true;
$("#capOne").stop(true, false);
$("#capTwo").stop(true, false);
$("#capThree").stop(true, false);
clearTimeout(variableTimer);
window.cancelAnimationFrame(variableTimer);
Debug;
};
},
unload: function () {
// TODO: Respond to navigations away from this page.
$("#capOne").stop();
$("#capOne").css({ "margin-top": "360px", "margin-left": "250px" })
$("#capTwo").css({ "margin-top": "360px", "margin-left": "580px" })
$("#capThree").css({ "margin-top": "360px", "margin-left": "910px" })
////return false;
$("#capOne").fadeOut(100);
WinJS.UI.disableAnimations();
flag1 = true;//if flag1=false then animation is stopped
$("#capOne").stop(true, false);
$("#capTwo").stop(true, false);
$("#capThree").stop(true, false);
clearTimeout(document.variableTimer);
window.cancelAnimationFrame(document.variableTimer);
debugger;
},
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
// TODO: Respond to changes in viewState.
}
});
})();
Here is the navigator.js file
(function () {
"use strict";
var appView = Windows.UI.ViewManagement.ApplicationView;
var nav = WinJS.Navigation;
WinJS.Namespace.define("Application", {
PageControlNavigator: WinJS.Class.define(
// Define the constructor function for the PageControlNavigator.
function PageControlNavigator(element, options) {
this._element = element || document.createElement("div");
this._element.appendChild(this._createPageElement());
this.home = options.home;
this._lastViewstate = appView.value;
nav.onnavigated = this._navigated.bind(this);
window.onresize = this._resized.bind(this);
document.body.onkeyup = this._keyupHandler.bind(this);
document.body.onkeypress = this._keypressHandler.bind(this);
document.body.onmspointerup = this._mspointerupHandler.bind(this);
Application.navigator = this;
}, {
home: "",
/// <field domElement="true" />
_element: null,
_lastNavigationPromise: WinJS.Promise.as(),
_lastViewstate: 0,
// This is the currently loaded Page object.
pageControl: {
get: function () { return this.pageElement && this.pageElement.winControl; }
},
// This is the root element of the current page.
pageElement: {
get: function () { return this._element.firstElementChild; }
},
// Creates a container for a new page to be loaded into.
_createPageElement: function () {
var element = document.createElement("div");
element.style.width = "100%";
element.style.height = "100%";
return element;
},
// Retrieves a list of animation elements for the current page.
// If the page does not define a list, animate the entire page.
_getAnimationElements: function () { //IHDAr
if (this.pageControl && this.pageControl.getAnimationElements) {
return this.pageControl.getAnimationElements();
}
return this.pageElement;
},
// Navigates back whenever the backspace key is pressed and
// not captured by an input field.
_keypressHandler: function (args) {
if (args.key === "Backspace") {
nav.back();
}
},
// Navigates back or forward when alt + left or alt + right
// key combinations are pressed.
_keyupHandler: function (args) {
if ((args.key === "Left" && args.altKey) || (args.key === "BrowserBack")) {
nav.back();
} else if ((args.key === "Right" && args.altKey) || (args.key === "BrowserForward")) {
nav.forward();
}
},
// This function responds to clicks to enable navigation using
// back and forward mouse buttons.
_mspointerupHandler: function (args) {
if (args.button === 3) {
nav.back();
} else if (args.button === 4) {
nav.forward();
}
},
// Responds to navigation by adding new pages to the DOM.
_navigated: function (args) {
var newElement = this._createPageElement();
var parentedComplete;
var parented = new WinJS.Promise(function (c) { parentedComplete = c; });
this._lastNavigationPromise.cancel();
this._lastNavigationPromise = WinJS.Promise.timeout().then(function () {
return WinJS.UI.Pages.render(args.detail.location, newElement,args.detail.state, parented);
}).then(function parentElement(control) {
var oldElement = this.pageElement;
if (oldElement.winControl && oldElement.winControl.unload) {
oldElement.winControl.unload();
}
this._element.appendChild(newElement);
this._element.removeChild(oldElement);
oldElement.innerText = "";
this._updateBackButton();
parentedComplete();
var history = args.detail.state;
WinJS.UI.Animation.enterPage(this._getAnimationElements()).done(
function () {
}
);//IDHAR
}.bind(this));
args.detail.setPromise(this._lastNavigationPromise);//IDHAR BHI
},
// Responds to resize events and call the updateLayout function
// on the currently loaded page.
_resized: function (args) {
if (this.pageControl && this.pageControl.updateLayout) {
this.pageControl.updateLayout.call(this.pageControl, this.pageElement, appView.value, this._lastViewstate);
}
this._lastViewstate = appView.value;
},
// Updates the back button state. Called after navigation has
// completed.
_updateBackButton: function () {
var backButton = this.pageElement.querySelector("header[role=banner] .win-backbutton");
if (backButton) {
backButton.onclick = function () { nav.back(); };
if (nav.canGoBack) {
backButton.removeAttribute("disabled");
} else {
backButton.setAttribute("disabled", "disabled");
}
}
},
}
)
});
})();
When using ng-click on a div:
<div ng-click="doSomething()">bla bla</div>
ng-click fires even if the user only selects or drags the div. How do I prevent that, while still enabling text selection?
In requiring something similar, where the usual text selection behavior is required on an element which should otherwise respond to ngClick, I wrote the following directive, which may be of use:
.directive('selectableText', function($window, $timeout) {
var i = 0;
return {
restrict: 'A',
priority: 1,
compile: function (tElem, tAttrs) {
var fn = '$$clickOnNoSelect' + i++,
_ngClick = tAttrs.ngClick;
tAttrs.ngClick = fn + '($event)';
return function(scope) {
var lastAnchorOffset, lastFocusOffset, timer;
scope[fn] = function(event) {
var selection = $window.getSelection(),
anchorOffset = selection.anchorOffset,
focusOffset = selection.focusOffset;
if(focusOffset - anchorOffset !== 0) {
if(!(lastAnchorOffset === anchorOffset && lastFocusOffset === focusOffset)) {
lastAnchorOffset = anchorOffset;
lastFocusOffset = focusOffset;
if(timer) {
$timeout.cancel(timer);
timer = null;
}
return;
}
}
lastAnchorOffset = null;
lastFocusOffset = null;
// delay invoking click so as to watch for user double-clicking
// to select words
timer = $timeout(function() {
scope.$eval(_ngClick, {$event: event});
timer = null;
}, 250);
};
};
}
};
});
Plunker: http://plnkr.co/edit/kkfXfiLvGXqNYs3N6fTz?p=preview
I had to deal with this, too, and came up with something much simpler. Basically you store the x-position on mousedown and then compare new x-position on mouseup:
ng-mousedown="setCurrentPos($event)"
ng-mouseup="doStuff($event)"
Function setCurrentPos():
var setCurrentPos = function($event) {
$scope.currentPos = $event.offsetX;
}
Function doStuff():
var doStuff = function ($event) {
if ($event.offsetX == $scope.currentPos) {
// Only do stuff here, when mouse was NOT dragged
} else {
// Do other stuff, which includes mouse dragging
}
}
I am trying to use the history api to make some rudimentary filtering a bit more usable for people using my site.
I have it working quite well for the most part but I am stuck on some edge cases: hitting the start of the history chain (and avoiding infinte back) and loosing the forward button.
The full source with working examples can be found here: http://jsfiddle.net/YDFCS/
The JS code:
$(document).ready(function () {
"use strict";
var $noResults, $searchBox, $entries, searchTimeout, firstRun, loc, hist, win;
$noResults = $('#noresults');
$searchBox = $('#searchinput');
$entries = $('#workshopBlurbEntries');
searchTimeout = null;
firstRun = true;
loc = location;
hist = history;
win = window;
function reset() {
if (hist.state !== undefined) { // Avoid infinite loops
hist.pushState({"tag": undefined}, "theMetaCity - Workshop", "/workshop/");
}
$noResults.hide();
$entries.fadeOut(150, function () {
$('header ul li', this).removeClass('searchMatchTag');
$('header h1 a span', this).removeClass('searchMatchTitle'); // The span remains but it is destroyed when filtering using the text() function
$(".workshopentry", this).show();
});
$entries.fadeIn(150);
}
function filter(searchTerm) {
if (searchTerm === undefined) { // Only history api should push undefined to this, explicitly taken care of otherwise
reset();
} else {
var rePattern = searchTerm.replace(/[.?*+^$\[\]\\(){}|]/g, "\\$&"), searchPattern = new RegExp('(' + rePattern + ')', 'ig'); // The brackets add a capture group
$entries.fadeOut(150, function () {
$noResults.hide();
$('header', this).each(function () {
$(this).parent().hide();
// Clear results of previous search
$('li', this).removeClass('searchMatchTag');
// Check the title
$('h1', this).each(function () {
var textToCheck = $('a', this).text();
if (textToCheck.match(searchPattern)) {
textToCheck = textToCheck.replace(searchPattern, '<span class="searchMatchTitle">$1</span>'); //capture group ($1) used so that the replacement matches the case and you don't get weird capitolisations
$('a', this).html(textToCheck);
$(this).closest('.workshopentry').show();
} else {
$('a', this).html(textToCheck);
}
});
// Check the tags
$('li', this).each(function () {
if ($(this).text().match(searchPattern)) {
$(this).addClass('searchMatchTag');
$(this).closest('.workshopentry').show();
}
});
});
if ($('.workshopentry[style*="block"]').length === 0) {
$noResults.show();
}
$entries.fadeIn(150);
});
}
}
$('header ul li a', $entries).on('click', function () {
hist.pushState({"tag": $(this).text()}, "theMetaCity - Workshop - " + $(this).text(), "/workshop/tag/" + $(this).text());
$searchBox.val('');
filter($(this).text());
return false; // Using the history API so no page reloads/changes
});
$searchBox.on('keyup', function () {
clearTimeout(searchTimeout);
if ($(this).val().length) {
searchTimeout = setTimeout(function () {
var searchVal = $searchBox.val();
hist.pushState({"tag": searchVal}, "theMetaCity - Workshop - " + searchVal, "/workshop/tag/" + searchVal);
filter(searchVal);
}, 500);
}
if ($(this).val().length === 0) {
searchTimeout = setTimeout(function () {
reset();
}, 500);
}
});
$('#reset').on('click', function () {
$searchBox.val('');
reset();
});
win.addEventListener("popstate", function (event) {
console.info(hist.state);
if (event.state === null) { // Start of history chain on this page, direct entry to page handled by firstRun)
reset();
} else {
$searchBox.val(event.state.tag);
filter(event.state.tag);
}
});
$noResults.hide();
if (firstRun) { // 0 1 2 3 4 (if / present)
var locArray = loc.pathname.split('/'); // '/workshop/tag/searchString/
if (locArray[2] === 'tag' && locArray[3] !== undefined) { // Check for direct link to tag (i.e. if something in [3] search for it)
hist.pushState({"tag": locArray[3]}, "theMetaCity - Workshop - " + locArray[3], "/workshop/tag/" + locArray[3]);
filter(locArray[3]);
} else if (locArray[2] === '') { // Root page and really shouldn't do anything
hist.pushState({"tag": undefined}, "theMetaCity - Workshop", "/workshop/");
} // locArray[2] === somepagenum is an actual page and what should be allowed to happen by itself
firstRun = false;
// Save state on first page load
}
});
I feel that there is something I am not quite getting with the history api. Any help would be appreciated.
You need to use onpopstate event handler for the back and forward capabilities:
https://developer.mozilla.org/en-US/docs/Web/API/window.onpopstate
Check out this question I answered a while back, I believe they had the same issues you are facing:
history.pushstate fails browser back and forward button
I have the following code snippet that controls an embedded youtube player. It works great on Chrome and Safari but not on Firefox.
jsfiddle : http://jsfiddle.net/fuSSn/4/
Code from my app:
the iframe:
<div class="tubeframe" id="video-frame-155" style="">
<iframe title="YouTube video player" width="350" height="262" src="http://www.youtube.com/embed/hc5xkf9JqoE?HD=1;rel=0;showinfo=0;autohide=1" frameborder="0" allowfullscreen="" id="video-frame-155-frame"></iframe>
</div>
my javascript:
var source_tag = document.createElement("script");
var first_source_tag = document.getElementsByTagName("script")[0];
first_source_tag.parentNode.insertBefore(source_tag, first_source_tag);
// This function will be called when the API is fully loaded
function onYouTubeIframeAPIReady() {
YT_ready(true)
console.log("api loaded! yikes")
}
function getFrameID(id){
var elem = document.getElementById(id);
if (elem) {
if(/^iframe$/i.test(elem.tagName)) return id; //Frame, OK
// else: Look for frame
var elems = elem.getElementsByTagName("iframe");
if (!elems.length) return null; //No iframe found, FAILURE
for (var i=0; i<elems.length; i++) {
if (/^https?:\/\/(?:www\.)?youtube(?:-nocookie)?\.com(\/|$)/i.test(elems[i].src)) break;
}
elem = elems[i]; //The only, or the best iFrame
if (elem.id) return elem.id; //Existing ID, return it
// else: Create a new ID
do { //Keep postfixing `-frame` until the ID is unique
id += "-frame";
} while (document.getElementById(id));
elem.id = id;
return id;
}
// If no element, return null.
return null;
}
// Define YT_ready function.
var YT_ready = (function(){
var onReady_funcs = [], api_isReady = false;
return function(func, b_before){
if (func === true) {
api_isReady = true;
while(onReady_funcs.length > 0){
// Removes the first func from the array, and execute func
onReady_funcs.shift()();
}
}
else if(typeof func == "function") {
if (api_isReady) func();
else onReady_funcs[b_before?"unshift":"push"](func);
}
}
})();
var video = function ( videoid, frameid) {
var player;
var that;
var seconds;
var duration;
var stateChangeCallback;
var update_play = 0;
return {
setOnStateChangeCallback: function(callback) {
stateChangeCallback = callback;
},
getCurrentTime: function() {
return player.getCurrentTime();
},
getPlayer: function () {
return player;
},
getVideoFrameId: function () {
return "video-frame-" + videoid;
},
initVideo: function (second) {
console.log("initing")
that = this;
YT_ready(function(){
var frameID = getFrameID("video-frame-" + videoid);
console.log("creating player")
console.log(frameID)
if (frameID) { //If the frame exists
console.log("frame exists")
player = new YT.Player(frameID, {
events: {
"onStateChange": that.stateChange
}
});
console.log("Player Created!");
if (second) {
console.log(second)
setTimeout(function() { console.log("seek to"); player.seekTo(second, false); player.stopVideo()}, 1000);
}
}
});
},
stateChange: function (event) {
console.log("event.data = ", event.data);
switch(event.data) {
case YT.PlayerState.PLAYING:
{
if (stateChangeCallback)
stateChangeCallback("play", player.getCurrentTime(), player.getDuration());
onsole.log("play");
}
break;
case YT.PlayerState.PAUSED:
case YT.PlayerState.CUED:
case YT.PlayerState.ENDED:
{
if (stateChangeCallback)
stateChangeCallback("pause", player.getCurrentTime(), player.getDuration());
console.log("pause");
}
break;
}
},
pauseVideo: function () {
player.stopVideo();
console.log('player.stopVid()');
},
seekTo: function(second) {
player.seekTo(second, false);
}
};
};
function onStateChange(vid, action, second, total) {
if (Videos[vid]) {
console.log( (second / total) * 100);
}
};
$(document).ready(function () {
var Videos = {};
logger.info("heyyy")
var videoId=155;
//if (videoId) {
Videos[videoId] = video(videoId, 155);
console.log(Videos[155])
Videos[155].initVideo();
Videos[155].setOnStateChangeCallback(function(action, second, total) {
onStateChange(155, action, second, total);
});
//}
Videos[155].seekTo(1000, false);
onStateChange(155, "start", 0, 0);
});
I know that the required script tags are being added, I can test that from console. I also know that onYouTubePlayerAPIReady() is actually called. But I still receive errors like
TypeError: player.stopVideo is not a function
When I run the three lines that adds the source tag again from the web console on firefox, the api seems to load and everything starts working again.
I have been struggling with this for days and I really need help figuring out what might be wrong. If it helps my application is developed in ruby on rails but I don't think this is relevant information.
Thanks
There is no problem with the above code. My video was loaded in a bootstrap modal. Modal's hide property would make it invisible to firefox and firefox would not load the api at all. So I removed the modal hide class and instead of display:none I used item.css("visibility", "visible"); and item.css("visibility", "hidden"); which made firefox load the api.
How can I track the browser idle time? I am using IE8.
I am not using any session management and don't want to handle it on server side.
Here is pure JavaScript way to track the idle time and when it reach certain limit do some action:
var IDLE_TIMEOUT = 60; //seconds
var _idleSecondsTimer = null;
var _idleSecondsCounter = 0;
document.onclick = function() {
_idleSecondsCounter = 0;
};
document.onmousemove = function() {
_idleSecondsCounter = 0;
};
document.onkeypress = function() {
_idleSecondsCounter = 0;
};
_idleSecondsTimer = window.setInterval(CheckIdleTime, 1000);
function CheckIdleTime() {
_idleSecondsCounter++;
var oPanel = document.getElementById("SecondsUntilExpire");
if (oPanel)
oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
if (_idleSecondsCounter >= IDLE_TIMEOUT) {
window.clearInterval(_idleSecondsTimer);
alert("Time expired!");
document.location.href = "logout.html";
}
}
#SecondsUntilExpire { background-color: yellow; }
You will be auto logged out in <span id="SecondsUntilExpire"></span> seconds.
This code will wait 60 seconds before showing alert and redirecting, and any action will "reset" the count - mouse click, mouse move or key press.
It should be as cross browser as possible, and straight forward. It also support showing the remaining time, if you add element to your page with ID of SecondsUntilExpire.
The above code should work fine, however has several downsides, e.g. it does not allow any other events to run and does not support multiply tabs. Refactored code that include both of these is following: (no need to change HTML)
var IDLE_TIMEOUT = 60; //seconds
var _localStorageKey = 'global_countdown_last_reset_timestamp';
var _idleSecondsTimer = null;
var _lastResetTimeStamp = (new Date()).getTime();
var _localStorage = null;
AttachEvent(document, 'click', ResetTime);
AttachEvent(document, 'mousemove', ResetTime);
AttachEvent(document, 'keypress', ResetTime);
AttachEvent(window, 'load', ResetTime);
try {
_localStorage = window.localStorage;
}
catch (ex) {
}
_idleSecondsTimer = window.setInterval(CheckIdleTime, 1000);
function GetLastResetTimeStamp() {
var lastResetTimeStamp = 0;
if (_localStorage) {
lastResetTimeStamp = parseInt(_localStorage[_localStorageKey], 10);
if (isNaN(lastResetTimeStamp) || lastResetTimeStamp < 0)
lastResetTimeStamp = (new Date()).getTime();
} else {
lastResetTimeStamp = _lastResetTimeStamp;
}
return lastResetTimeStamp;
}
function SetLastResetTimeStamp(timeStamp) {
if (_localStorage) {
_localStorage[_localStorageKey] = timeStamp;
} else {
_lastResetTimeStamp = timeStamp;
}
}
function ResetTime() {
SetLastResetTimeStamp((new Date()).getTime());
}
function AttachEvent(element, eventName, eventHandler) {
if (element.addEventListener) {
element.addEventListener(eventName, eventHandler, false);
return true;
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, eventHandler);
return true;
} else {
//nothing to do, browser too old or non standard anyway
return false;
}
}
function WriteProgress(msg) {
var oPanel = document.getElementById("SecondsUntilExpire");
if (oPanel)
oPanel.innerHTML = msg;
else if (console)
console.log(msg);
}
function CheckIdleTime() {
var currentTimeStamp = (new Date()).getTime();
var lastResetTimeStamp = GetLastResetTimeStamp();
var secondsDiff = Math.floor((currentTimeStamp - lastResetTimeStamp) / 1000);
if (secondsDiff <= 0) {
ResetTime();
secondsDiff = 0;
}
WriteProgress((IDLE_TIMEOUT - secondsDiff) + "");
if (secondsDiff >= IDLE_TIMEOUT) {
window.clearInterval(_idleSecondsTimer);
ResetTime();
alert("Time expired!");
document.location.href = "logout.html";
}
}
The refactored code above is using local storage to keep track of when the counter was last reset, and also reset it on each new tab that is opened which contains the code, then the counter will be the same for all tabs, and resetting in one will result in reset of all tabs. Since Stack Snippets do not allow local storage, it's pointless to host it there so I've made a fiddle:
http://jsfiddle.net/yahavbr/gpvqa0fj/3/
Hope this is what you are looking for
jquery-idletimer-plugin
Too late to reply, but this might help someone to write clean and practical solution. This is an ideal solution, when you do not need to display time left for session expire. Good to ignore setInterval(), which keeps on running the script through out the application running time.
var inactivityTimeOut = 10 * 1000, //10 seconds
inactivitySessionExpireTimeOut = '';
setSessionExpireTimeOut();
function setSessionExpireTimeOut () {
'use strict';
clearSessionExpireTimeout();
inactivitySessionExpireTimeOut = setTimeout(function() {
expireSessionIdleTime();
}, inactivityTimeOut);
}
function expireSessionIdleTime () {
'use strict';
console.log('user inactive for ' + inactivityTimeOut + " seconds");
console.log('session expired');
alert('time expired');
clearSessionExpireTimeout();
document.location.href = "logout.html";
}
function clearSessionExpireTimeout () {
'use strict';
clearTimeout(inactivitySessionExpireTimeOut);
}
Running example: Timeout alert will be popped up in 10 seconds
Here's an approach using jquery as I needed to preserve existing keyboard events on the document.
I also needed to do different things at different idle times so I wrapped it in a function
var onIdle = function (timeOutSeconds,func){
//Idle detection
var idleTimeout;
var activity=function() {
clearTimeout(idleTimeout);
console.log('to cleared');
idleTimeout = setTimeout(func, timeOutSeconds * 1000);
}
$(document).on('mousedown mousemove keypress',activity);
activity();
}
onIdle(60*60,function(){
location.reload();
});
onIdle(30,function(){
if(currentView!=='welcome'){
loadView('welcome');
}
});
I needed a similar thing and created this :https://github.com/harunurhan/idlejs
It simple, configurable and powerful in a way, without any dependencies. Here's an example.
import { Idle } from 'idlejs/dist';
// with predefined events on `document`
const idle = new Idle()
.whenNotInteractive()
.within(60)
.do(() => console.log('IDLE'))
.start();
You can also use custom event targets and events
const idle = new Idle()
.whenNot([{
events: ['click', 'hover'],
target: buttonEl,
},
{
events: ['click', 'input'],
target: inputEl,
},
])
.within(10)
.do(() => called = true)
.start();
(Written in typescript and compiled to es5)