Jquery Plugin. Options for each instances - javascript

I've created a jquery plugin that is called several times inside the same page. Each time I call the plugin I pass differents parameters and a callback function that returns the ID of the element, that it's passed as parameter but I always receive the ID of the last element that has been applied the plugin.
I always thought that everytime I call a plugin a new instance is generated.
This is my plugin code:
(function ($) {
$.audioRecorder = {
constants: {
},
options: {
domain: "http://example.com",
storageUrl: "/services/uploader/uploadtoazure",
storageUrlIOSDevice: "/services/uploader/uploadaudiofromiosdevice",
storageAudioContainer: null,
storageAudioPath: null,
storageMimeType: "audio/mpeg",
storageExtension: "mp3",
container: null,
handlerInterval: null,
callbackAudioSaved: null,
callbackPlay: null,
callbackStop: null,
id: null
},
methods: {
init: function (options) {
$.extend(true, $.audioRecorder.options, options);
window.microm = new Microm();
$.audioRecorder.options.container = $(this);
$.audioRecorder.methods.build();
$.audioRecorder.methods.bind();
},
build: function () {
var template = $.audioRecorder.templates.recorder.replace(/##domain##/g, $.audioRecorder.options.domain.replace('https','http'));
$.audioRecorder.options.container.html(template);
$.audioRecorder.methods.showRecordButton();
if ($.audioRecorder.methods.isIOSDevice()) {
$.audioRecorder.options.container.find(".audio-recorder-timer").hide();
}
},
bind: function () {
$.audioRecorder.options.container.find(".audio-recorder-record").click($.audioRecorder.methods.record);
$.audioRecorder.options.container.find(".audio-recorder-stop").click($.audioRecorder.methods.stop);
$.audioRecorder.options.container.find(".audio-recorder-uploader").change($.audioRecorder.methods.saveAudioFromFileUpload);
},
record: function () {
if ($.audioRecorder.methods.isIOSDevice()) {
$.audioRecorder.options.container.find(".audio-recorder-uploader").click();
}
else {
microm.record().then(function () {
$.audioRecorder.methods.initTimer();
$.audioRecorder.methods.showStopButton();
console.log('Recording...');
}).catch(function (error) {
console.log('error recording', error);
});
}
},
stop: function () {
$.audioRecorder.methods.stopTimer();
$.audioRecorder.methods.showLoading();
microm.stop().then(function (mp3) {
$.audioRecorder.methods.saveAudio(mp3);
console.log('Stop record');
});
},
saveAudio: function (mp3) {
var fd = new FormData();
fd.append('data', mp3.blob);
fd.append('container', $.audioRecorder.options.storageAudioContainer);
fd.append('path', $.audioRecorder.options.storageAudioPath);
fd.append('extension', $.audioRecorder.options.storageExtension);
fd.append('mimeType', $.audioRecorder.options.storageMimeType);
$.ajax({
url: $.audioRecorder.options.domain + $.audioRecorder.options.storageUrl,
type: 'post',
data: fd,
processData: false,
contentType: false,
success: function (url) {
$.audioRecorder.methods.audioSaved(url);
},
error: function () {
$.audioRecorder.methods.showRecordButton();
}
});
},
saveAudioFromFileUpload: function () {
if ($.audioRecorder.options.container.find(".audio-recorder-uploader")[0].files == null || $.audioRecorder.options.container.find(".audio-recorder-uploader")[0].files.length == 0) {
return;
}
$.audioRecorder.methods.showLoading();
var file = $.audioRecorder.options.container.find(".audio-recorder-uploader")[0].files[0];
var fd = new FormData();
fd.append('data', file);
fd.append('container', $.audioRecorder.options.storageAudioContainer);
fd.append('path', $.audioRecorder.options.storageAudioPath);
fd.append('mimeType', $.audioRecorder.options.storageMimeType);
$.ajax({
url: $.audioRecorder.options.domain + $.audioRecorder.options.storageUrlIOSDevice,
type: 'post',
data: fd,
processData: false,
contentType: false,
success: function (data) {
$.audioRecorder.methods.audioSaved(data.url, data.duration);
},
error: function () {
$.audioRecorder.methods.showRecordButton();
}
});
},
audioSaved: function (url, duration) {
$.audioRecorder.methods.showRecordButton();
var timer = $.audioRecorder.methods.getTimer();
$.audioRecorder.methods.resetTimer();
if (duration != null) {
var seconds = duration % 60;
var minutes = Math.floor(duration / 60);
timer = minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
}
var template = $.audioRecorder.templates.player;
template = template.replace(/##link##/g, url);
template = template.replace(/##length##/g, timer);
template = template.replace(/##domain##/g, $.audioRecorder.options.domain.replace('https','http'));
if ($.audioRecorder.options.callbackPlay != null) {
template = template.replace(/##callbackPlay##/g, $.audioRecorder.options.callbackPlay.name + "(event)");
}
else {
template = template.replace(/##callbackPlay##/g, "");
}
if ($.audioRecorder.options.callbackStop != null) {
template = template.replace(/##callbackStop##/g, $.audioRecorder.options.callbackStop.name + "(event)");
}
else {
template = template.replace(/##callbackStop##/g, "");
}
if ($.audioRecorder.options.callbackAudioSaved != null) {
$.audioRecorder.options.callbackAudioSaved(url, template, $.audioRecorder.options.container);
}
else {
$.audioRecorder.options.container.append(template);
}
},
initTimer: function () {
$.audioRecorder.methods.resetTimer();
$.audioRecorder.options.handlerInterval = setInterval($.audioRecorder.methods.addSecondToTimer, 1000);
},
resetTimer: function () {
$.audioRecorder.options.container.find(".audio-recorder-timer").text("0:00");
},
addSecondToTimer: function () {
var timerText = $.audioRecorder.options.container.find(".audio-recorder-timer").text().split(":");
var minutes = parseInt(timerText[0]);
var seconds = parseInt(timerText[1]);
seconds++;
if (seconds >= 60) {
minutes++;
seconds = 0;
}
timerText = minutes + ":" + (seconds < 10 ? "0" + seconds : seconds);
$.audioRecorder.options.container.find(".audio-recorder-timer").text(timerText);
},
stopTimer: function () {
clearInterval($.audioRecorder.options.handlerInterval);
},
getTimer: function () {
return $.audioRecorder.options.container.find(".audio-recorder-timer").text();
},
getSecondsTimer: function () {
var timerText = $.audioRecorder.options.container.find(".audio-recorder-timer").text().split(":");
var minutes = parseInt(timerText[0]);
var seconds = parseInt(timerText[1]);
return minutes * 60 + seconds;
},
showRecordButton: function () {
$.audioRecorder.options.container.find(".audio-recorder-record").show();
$.audioRecorder.options.container.find(".audio-recorder-stop").hide();
$.audioRecorder.options.container.find(".audio-recorder-loading").hide();
},
showStopButton: function () {
$.audioRecorder.options.container.find(".audio-recorder-record").hide();
$.audioRecorder.options.container.find(".audio-recorder-stop").show();
$.audioRecorder.options.container.find(".audio-recorder-loading").hide();
},
showLoading: function () {
$.audioRecorder.options.container.find(".audio-recorder-record").hide();
$.audioRecorder.options.container.find(".audio-recorder-stop").hide();
$.audioRecorder.options.container.find(".audio-recorder-loading").show();
},
playerPlay: function (event) {
event.stopPropagation();
event.preventDefault();
var player = $(event.target).closest('.audio-recorder-player');
player.find('audio')[0].play();
$.audioRecorder.methods.stopPlayerTimer(player);
$.audioRecorder.methods.initPlayerTimer(player);
$.audioRecorder.methods.showPlayerStopButton(player);
},
playerStop: function (event) {
event.stopPropagation();
event.preventDefault();
var player = $(event.target).closest('.audio-recorder-player');
player.find('audio')[0].pause();
player.find('audio')[0].currentTime = 0;
$.audioRecorder.methods.stopPlayerTimer(player);
$.audioRecorder.methods.resetPlayerTimer(player);
$.audioRecorder.methods.showPlayerPlayButton(player);
},
initPlayerTimer: function (player) {
$.audioRecorder.methods.resetPlayerTimer(player);
player.prop("interval", setInterval(function () { $.audioRecorder.methods.addSecondToPlayerTimer(player); }, 1000));
},
resetPlayerTimer: function (player) {
player.find(".audio-recorder-player-current-seek").text("0:00");
player.find(".audio-recorder-player-progress-bar").width(0);
},
addSecondToPlayerTimer: function (player) {
if (player.find(".audio-recorder-player-current-seek").text() == player.find(".audio-recorder-player-total-time").text()) {
$.audioRecorder.methods.stopPlayerTimer(player);
$.audioRecorder.methods.showPlayerPlayButton(player);
return;
}
var timerText = player.find(".audio-recorder-player-current-seek").text().split(":");
var minutes = parseInt(timerText[0]);
var seconds = parseInt(timerText[1]);
seconds++;
if (seconds >= 60) {
minutes++;
seconds = 0;
}
timerText = minutes + ":" + (seconds < 10 ? "0" + seconds : seconds);
player.find(".audio-recorder-player-current-seek").text(timerText);
// Progress bar
var currentSecons = $.audioRecorder.methods.getSecondsPlayerTimer(player);
var totalSecons = $.audioRecorder.methods.getSecondsTotalPlayerTimer(player);
var progress = parseFloat(currentSecons) / parseFloat(totalSecons);
var totalWidth = player.find(".audio-recorder-player-progress-bar-parent").width();
player.find(".audio-recorder-player-progress-bar").width(progress * totalWidth);
},
stopPlayerTimer: function (player) {
clearInterval(player.prop("interval"));
},
getSecondsPlayerTimer: function (player) {
var timerText = player.find(".audio-recorder-player-current-seek").text().split(":");
var minutes = parseInt(timerText[0]);
var seconds = parseInt(timerText[1]);
return minutes * 60 + seconds;
},
getSecondsTotalPlayerTimer: function (player) {
var timerText = player.find(".audio-recorder-player-total-time").text().split(":");
var minutes = parseInt(timerText[0]);
var seconds = parseInt(timerText[1]);
return minutes * 60 + seconds;
},
showPlayerPlayButton: function (player) {
player.find(".audio-recorder-player-play").show();
player.find(".audio-recorder-player-stop").hide();
},
showPlayerStopButton: function (player) {
player.find(".audio-recorder-player-play").hide();
player.find(".audio-recorder-player-stop").show();
},
isIOSDevice() {
return navigator.platform != null && ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
}
},
templates: {
recorder: "<img src='##domain##/images/audiorecorder/audio-recorder-record.png' class='audio-recorder-record' style='float: left;' title='Grabar archivo de sonido' />" +
"<img src='##domain##/images/audiorecorder/audio-recorder-stop.png' class='audio-recorder-stop' style='float: left;' title='Detener grabacion' />" +
//"<img src='##domain##/images/audiorecorder/audio-recorder-loading.gif' class='audio-recorder-loading' style='float: left;' />" +
"<span class='audio-recorder-loading' style='float: left; font-size: 12px; width: 48px; overflow: hidden; margin-top: 18px;'>Cargando...</span>" +
"<span class='audio-recorder-timer' style='float: left; margin-top: 12px; font-size: 25px; margin-left: 10px;'>0:00</span>" +
"<input type='file' class='audio-recorder-uploader' style='display: none;' accept='audio/*;capture=microphone' />",
player: "<div class='audio-recorder-player'>" +
"<a href='##link##' target='_blank' style='float: left;'>" +
"<img src='##domain##/images/audiorecorder/audio-recorder-play.png' class='audio-recorder-player-play' style='float: left;' onclick='$.audioRecorder.methods.playerPlay(event); ##callbackPlay##' title='Reproducir audio' />" +
"<img src='##domain##/images/audiorecorder/audio-recorder-stop.png' class='audio-recorder-player-stop' style='display: none; float: left;' onclick='$.audioRecorder.methods.playerStop(event); ##callbackStop##' title='Detener audio' />" +
"</a>" +
"<audio src='##link##'></audio>" +
"<span class='audio-recorder-player-current-seek' style='float: left; margin-top: 17px; margin-left: 10px;'>0:00</span>" +
"<div class='audio-recorder-player-progress-bar-parent' style='float: left; margin-top: 14px; margin-left: 3px; width: 204px; height: 22px; box-sizing: border-box; border: 1px solid #AAA; padding: 1px; background-color: #FFF;'>" +
"<div class='audio-recorder-player-progress-bar' style='float: left; height: 18px; background-color: #BCD100;font-size:1px'> </div>" +
"</div>" +
"<span class='audio-recorder-player-total-time' style='float: left; margin-top: 17px; margin-left: 3px;'>##length##</span>" +
"</div>"
}
}
// Privates
//
$.fn.audioRecorder = function (method) {
if ($.audioRecorder.methods[method]) {
return $.audioRecorder.methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return $.audioRecorder.methods.init.apply(this, arguments);
} else {
$.error(method + ' no definido en noteges.audio-recorder.js');
}
};
})(jQuery);
And I call the plugin this way;
$("#" + ID1).audioRecorder({
domain: 'https://example.com',
storageUrl: "/services/uploader/uploadtoazure",
storageAudioContainer: self.azureContainer,
storageAudioPath: self.azureContainerAudio,
callbackAudioSaved: audioSaved,
callbackPlay: null,
id: audioID
});
$("#" + ID2).audioRecorder({
domain: 'https://example.com',
storageUrl: "/services/uploader/uploadtoazure",
storageAudioContainer: self.azureContainer,
storageAudioPath: self.azureContainerAudio,
callbackAudioSaved: audioSaved,
callbackPlay: null,
id: audioID
});

I always thought that everytime I call a plugin a new instance is
generated.
Your plugin function has the context of a new jQuery object instance, but $.audioOptions is not part of that. It is a property on the jQuery global object so a new one isn't created each time the plugin function is called. You can tell this because you keep having to use $.audioOptions.methods to call a method instead of a method call like this.record()
You can refactor your code to create a new object, or a new instance (if changing it to a constructor function), each time the plugin is called. Then you can save the options on the new object/instance, call methods from the it, etc.
Note you could place your methods on the jQuery object instance but that would be polluting it and possibly overwriting jQuery methods.
$.audioRecorder = {
/* other code */
methods: {
init:function(options,$element){
this.options = $.extend(true,{},$.audioRecorder.options,options);
this.options.container = $element;
this.bind();
},
bind: function () {
//uses arrow function to help maintain context and for less code,
//change if supporting older browsers
this.options.container.find(".audio-recorder-record").click(e=>this.record());
}
}
};
$.fn.audioRecorder = function(options){
//if only supposed to use a single element
//otherwise use code in a this.each() callback
var $element = this.first();
var arInstance = Object.create($.audioRecorder.methods);
arInstance.init(options,$element);
$element.data("audioRecorder",arInstance);
return this;
};
Demo
(function($){
$.audioRecorder = {
options:{},
methods: {
init:function(options,$element){
this.options = $.extend(true,{},$.audioRecorder.options,options);
this.options.container = $element;
this.build();
this.bind();
},
build:function(){
this.options.container.append( $.audioRecorder.templates.aTemplate );
},
bind: function () {
this.options.container.find("button").click(e=>this.record());
},
record:function(){
console.log("Record called for id: "+this.options.id);
}
},
templates:{
aTemplate:"<button>Hit to record</button>"
}
};
$.fn.audioRecorder = function(options){
var $element = this.first();
var arInstance = Object.create($.audioRecorder.methods);
arInstance.init(options,$element);
$element.data("audioRecorder",arInstance);
return this;
};
})(jQuery);
jQuery("#container").audioRecorder({
id:"firstRecorder"
});
jQuery("#container1").audioRecorder({
id:"secondRecorder"
});
jQuery("#container2").audioRecorder({
id:"thirdRecorder"
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container"></div>
<div id="container1"></div>
<div id="container2"></div>

Related

This my button and function for it. My question is, after click that button.. how to make it disable for 30 mins?

Down there is my button n function for that button in php, how to add disable button for 30 mins after clicking on it? I need help for it because im still newbie on php coding..
<button class="btn btn-primary" style="width: 200px; outline: none;" id="testar" onclick="enviar()">START</button>
This my function:
<script title="ajax do checker">
function enviar() {
var linha = $("#lista").val();
var linhaenviar = linha.split("\n");
var total = linhaenviar.length;
var ap = 0;
var ed = 0;
var rp = 0;
linhaenviar.forEach(function(value, index) {
setTimeout(
function() {
var sec = $("#sec").val();
$.ajax({
url: 'g3api.php?lista=' + value,
type: 'GET',
async: true,
success: function(resultado) {
if (resultado.match("Approved")) {
removelinha();
ap++;
aprovadas(resultado + "");
}else if(resultado.match("CCN")) {
removelinha();
ed++;
edrovadas(resultado + "");
}else {
removelinha();
rp++;
reprovadas(resultado + "");
}
$('#carregadas').html(total);
var fila = parseInt(ap) + parseInt(ed) + parseInt(rp);
$('#cLive').html(ap);
$('#cWarn').html(ed);
$('#cDie').html(rp);
$('#total').html(fila);
$('#cLive2').html(ap);
$('#cWarn2').html(ed);
$('#cDie2').html(rp);
}
});
}, 5000 * index);
});
}
function aprovadas(str) {
$(".aprovadas").append(str + "<br>");
}
function reprovadas(str) {
$(".reprovadas").append(str + "<br>");
}
function edrovadas(str) {
$(".edrovadas").append(str + "<br>");
}
function removelinha() {
var lines = $("#lista").val().split('\n');
lines.splice(0, 1);
$("#lista").val(lines.join("\n"));
}
function iloveyou(){
alert('PEKPEK')}
</script>
My question is: How to make the button disabled for 30 minutes after it's clicked?
button.addEventListener('click', () => {
if (localStorage.getItem('clicked') === 'true') return;
localStorage.setItem('clicked', 'true');
button.disabled = true;
setTimeout(() => {
localStorage.removeItem('clicked');
button.disabled = false;
}, 60000 * 10);
});

I want to add a loading png in LiveSearch

I am using a plugin for live search .. everything is working fine .. i just want to add a loading png that appear on start of ajax request and disappear on results ..
please help me to customize the code just to add class where form id="search-kb-form" .. and remove the class when results are completed.
<form id="search-kb-form" class="search-kb-form" method="get" action="<?php echo home_url('/'); ?>" autocomplete="off">
<div class="wrapper-kb-fields">
<input type="text" id="s" name="s" placeholder="Search what you’re looking for" title="* Please enter a search term!">
<input type="submit" class="submit-button-kb" value="">
</div>
<div id="search-error-container"></div>
</form>
This is the plugin code
jQuery.fn.liveSearch = function (conf) {
var config = jQuery.extend({
url: {'jquery-live-search-result': 'search-results.php?q='},
id: 'jquery-live-search',
duration: 400,
typeDelay: 200,
loadingClass: 'loading',
onSlideUp: function () {},
uptadePosition: false,
minLength: 0,
width: null
}, conf);
if (typeof(config.url) == "string") {
config.url = { 'jquery-live-search-result': config.url }
} else if (typeof(config.url) == "object") {
if (typeof(config.url.length) == "number") {
var urls = {}
for (var i = 0; i < config.url.length; i++) {
urls['jquery-live-search-result-' + i] = config.url[i];
}
config.url = urls;
}
}
var searchStatus = {};
var liveSearch = jQuery('#' + config.id);
var loadingRequestCounter = 0;
// Create live-search if it doesn't exist
if (!liveSearch.length) {
liveSearch = jQuery('<div id="' + config.id + '"></div>')
.appendTo(document.body)
.hide()
.slideUp(0);
for (key in config.url) {
liveSearch.append('<div id="' + key + '"></div>');
searchStatus[key] = false;
}
// Close live-search when clicking outside it
jQuery(document.body).click(function(event) {
var clicked = jQuery(event.target);
if (!(clicked.is('#' + config.id) || clicked.parents('#' + config.id).length || clicked.is('input'))) {
liveSearch.slideUp(config.duration, function () {
config.onSlideUp();
});
}
});
}
return this.each(function () {
var input = jQuery(this).attr('autocomplete', 'off');
var liveSearchPaddingBorderHoriz = parseInt(liveSearch.css('paddingLeft'), 10) + parseInt(liveSearch.css('paddingRight'), 10) + parseInt(liveSearch.css('borderLeftWidth'), 10) + parseInt(liveSearch.css('borderRightWidth'), 10);
// Re calculates live search's position
var repositionLiveSearch = function () {
var tmpOffset = input.offset();
var tmpWidth = input.outerWidth();
if (config.width != null) {
tmpWidth = config.width;
}
var inputDim = {
left: tmpOffset.left,
top: tmpOffset.top,
width: tmpWidth,
height: input.outerHeight()
};
inputDim.topPos = inputDim.top + inputDim.height;
inputDim.totalWidth = inputDim.width - liveSearchPaddingBorderHoriz;
liveSearch.css({
position: 'absolute',
left: inputDim.left + 'px',
top: inputDim.topPos + 'px',
width: inputDim.totalWidth + 'px'
});
};
var showOrHideLiveSearch = function () {
if (loadingRequestCounter == 0) {
showStatus = false;
for (key in config.url) {
if( searchStatus[key] == true ) {
showStatus = true;
break;
}
}
if (showStatus == true) {
for (key in config.url) {
if( searchStatus[key] == false ) {
liveSearch.find('#' + key).html('');
}
}
showLiveSearch();
} else {
hideLiveSearch();
}
}
};
// Shows live-search for this input
var showLiveSearch = function () {
// Always reposition the live-search every time it is shown
// in case user has resized browser-window or zoomed in or whatever
repositionLiveSearch();
// We need to bind a resize-event every time live search is shown
// so it resizes based on the correct input element
jQuery(window).unbind('resize', repositionLiveSearch);
jQuery(window).bind('resize', repositionLiveSearch);
liveSearch.slideDown(config.duration)
};
// Hides live-search for this input
var hideLiveSearch = function () {
liveSearch.slideUp(config.duration, function () {
config.onSlideUp();
for (key in config.url) {
liveSearch.find('#' + key).html('');
}
});
};
input
// On focus, if the live-search is empty, perform an new search
// If not, just slide it down. Only do this if there's something in the input
.focus(function () {
if (this.value.length > config.minLength ) {
showOrHideLiveSearch();
}
})
// Auto update live-search onkeyup
.keyup(function () {
// Don't update live-search if it's got the same value as last time
if (this.value != this.lastValue) {
input.addClass(config.loadingClass);
var q = this.value;
// Stop previous ajax-request
if (this.timer) {
clearTimeout(this.timer);
}
if( q.length > config.minLength ) {
// Start a new ajax-request in X ms
this.timer = setTimeout(function () {
for (url_key in config.url) {
loadingRequestCounter += 1;
jQuery.ajax({
key: url_key,
url: config.url[url_key] + q,
success: function(data){
if (data.length) {
searchStatus[this.key] = true;
liveSearch.find("#" + this.key).html(data);
} else {
searchStatus[this.key] = false;
}
loadingRequestCounter -= 1;
showOrHideLiveSearch();
}
});
}
}, config.typeDelay);
}
else {
for (url_key in config.url) {
searchStatus[url_key] = false;
}
hideLiveSearch();
}
this.lastValue = this.value;
}
});
});
};
add a background to the loading class
.loading {
background:url('http://path_to_your_picture');
}

Need help changing default js toggle state on page load

I'm using a Youtube-TV JS plugin for a client site (https://github.com/Giorgio003/Youtube-TV ). The player loads with a playlist in an open state, and I need to have it load with the toggle closed, showing the array of playlists, can anyone help?
my codepen for the player is here
http://codepen.io/raldesign/pen/OVYXvK
(function(win, doc) {
'use strict';
var apiKey = 'AIzaSyAFMzeux_Eu933wk5U8skMzUzA-urgVgsY';
var YTV = YTV || function(id, opts){
var noop = function(){},
settings = {
apiKey: apiKey,
element: null,
user: null,
channelId: null,
fullscreen: false,
accent: '#fff',
controls: true,
annotations: false,
autoplay: false,
chainVideos: true,
browsePlaylists: false,
playerTheme: 'dark',
listTheme: 'dark',
responsive: false,
playId:'',
sortList: false,
reverseList: false,
shuffleList: false,
wmode: 'opaque',
events: {
videoReady: noop,
stateChange: noop
}
},
cache = {
data: {},
remove: function (url) {
delete cache.data[url];
},
exist: function (url) {
return cache.data.hasOwnProperty(url) && cache.data[url] !== null;
},
get: function (url) {
return cache.data[url];
},
set: function (url, data) {
cache.remove(url);
cache.data[url] = data;
}
},
utils = {
events: {
addEvent: function addEvent(element, eventName, func) {
if (element.addEventListener) {
return element.addEventListener(eventName, func, false);
} else if (element.attachEvent) {
return element.attachEvent("on" + eventName, func);
}
},
removeEvent: function addEvent(element, eventName, func) {
if (element.addEventListener) {
return element.removeEventListener(eventName, func, false);
} else if (element.attachEvent) {
return element.detachEvent("on" + eventName, func);
}
},
prevent: function(e) {
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
}
},
addCSS: function(css){
var head = doc.getElementsByTagName('head')[0],
style = doc.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(doc.createTextNode(css));
}
head.appendChild(style);
},
addCommas: function(str){
var x = str.split('.'),
x1 = x[0],
x2 = x.length > 1 ? '.' + x[1] : '',
rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
},
parentUntil: function(el, attr) {
while (el.parentNode) {
if (el.getAttribute && el.getAttribute(attr)){
return el;
}
el = el.parentNode;
}
return null;
},
ajax: {
get: function(url, fn){
if (cache.exist(url)) {
fn.call(this, JSON.parse(cache.get(url)));
} else {
var handle;
if (win.XDomainRequest && !(navigator.appVersion.indexOf("MSIE 8")==-1 || navigator.appVersion.indexOf("MSIE 9")==-1)) { // CORS for IE8,9
handle = new XDomainRequest();
handle.onload = function(){
cache.set(url, handle.responseText);
fn.call(this, JSON.parse(handle.responseText));
if (Object.prototype.hasOwnProperty.call(JSON.parse(handle.responseText), 'error')){
cache.remove(url);
var e = JSON.parse(handle.responseText);
console.log('Youtube-TV Error: Youtube API Response: '+e.error.errors[0].reason+'\n'+ 'Details: '+e.error.errors[0].message);
}
};
} else if (win.XMLHttpRequest){ // Modern Browsers
handle = new XMLHttpRequest();
}
handle.onreadystatechange = function(){
if (handle.readyState === 4 && handle.status === 200){
cache.set(url, handle.responseText);
fn.call(this, JSON.parse(handle.responseText));
} else if (handle.readyState === 4){
var e = JSON.parse(handle.responseText);
console.log('Youtube-TV Error: Youtube API Response: '+e.error.errors[0].reason+'\n'+ 'Details: '+e.error.errors[0].message);
}
};
handle.open("GET",url,true);
handle.send();
}
}
},
endpoints: {
base: 'https://www.googleapis.com/youtube/v3/',
userInfo: function(){
return utils.endpoints.base+'channels?'+settings.cid+'&key='+apiKey+'&part=snippet,contentDetails,statistics';
},
playlistInfo: function(pid){
return utils.endpoints.base+'playlists?id='+pid+'&key='+apiKey+'&maxResults=50&part=snippet';
},
userPlaylists: function(){
return utils.endpoints.base+'playlists?channelId='+settings.channelId+'&key='+apiKey+'&maxResults=50&part=snippet';
},
playlistVids: function(){
return utils.endpoints.base+'playlistItems?playlistId='+settings.pid+'&key='+apiKey+'&maxResults=50&part=contentDetails';
},
videoInfo: function(){
return utils.endpoints.base+'videos?id='+settings.videoString+'&key='+apiKey+'&maxResults=50&part=snippet,contentDetails,status,statistics';
}
},
deepExtend: function(destination, source) {
var property;
for (property in source) {
if (source[property] && source[property].constructor && source[property].constructor === Object) {
destination[property] = destination[property] || {};
utils.deepExtend(destination[property], source[property]);
} else {
destination[property] = source[property];
}
}
return destination;
}
},
prepare = {
youtube: function(){
if(typeof YT=='undefined'){
var tag = doc.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = doc.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
},
build: function(){
if (settings.channelId){
settings.cid = 'id='+settings.channelId;
} else if(settings.user){
settings.cid = 'forUsername='+settings.user;
}
settings.element.className = "ytv-canvas";
if(settings.fullscreen){
settings.element.className += " ytv-full";
}
utils.addCSS( '#'+id+' .ytv-list .ytv-active a{border-left-color: '+(settings.accent)+';}' );
// Responsive CSS
if(settings.responsive){
utils.addCSS('#'+id+' .ytv-video{'
+'position: relative; padding-bottom: 39.4%; /* 16:9 of 70%*/'
+'height: 0; width: 70%;'
+'} #'+id+' .ytv-video iframe{'
+'position: absolute; top: 0; left: 0;'
+'} #'+id+' .ytv-list{'
+'width: 30%;'
+'} #'+id+' .ytv-playlist-open .ytv-arrow{'
+'top: 0px;}'
+'#media only screen and (max-width:992px) {'
+'#'+id+' .ytv-list{'
+'position: relative; display: block;'
+'width: 0; padding-bottom: 40%;'
+'left: auto; right: auto;'
+'top: auto; width: 100%;'
+'} #'+id+' .ytv-video{'
+'position: relative; padding-bottom: 56.25%; /* 16:9 */'
+'height: 0; position: relative;'
+'display: block; left: auto;'
+'right: auto; top: auto; width: 100%;'
+'}}'
);
}
// Temp Scroll Bar fix
if (settings.listTheme == 'dark'){
utils.addCSS( ' #'+id+'.ytv-canvas ::-webkit-scrollbar{border-left: 1px solid #000;}'
+ ' #'+id+'.ytv-canvas ::-webkit-scrollbar-thumb{background: rgba(255,255,255,0.2);}');
}
// Optional Light List Theme
if(settings.listTheme == 'light'){
utils.addCSS( ' #'+id+'.ytv-canvas{background: #ccc;}'
+ ' #'+id+'.ytv-canvas ::-webkit-scrollbar{border-left: 1px solid rgba(28,28,28,0.1);}'
+ ' #'+id+'.ytv-canvas ::-webkit-scrollbar-thumb{background: rgba(28,28,28,0.3);}'
+ ' #'+id+' .ytv-list .ytv-active a{background: rgba(0,0,0,0.2);}'
+ ' #'+id+' .ytv-list a{color: #282828; border-top: 1px solid rgba(0,0,0,0.1); border-bottom: 1px solid rgba(204,204,204,0.5);}'
+ ' #'+id+' .ytv-list a:hover, #'+id+' .ytv-list-header .ytv-playlists a:hover{ background: rgba(0,0,0,0.2);}'
+ ' #'+id+' .ytv-list a:active, #'+id+' .ytv-list-header .ytv-playlists a:active{ background: rgba(0,0,0,0.2);}'
+ ' #'+id+' .ytv-list .ytv-thumb-stroke{outline: 1px solid rgba(0,0,0,0.1);}'
+ ' #'+id+' .ytv-list .ytv-thumb{outline: 1px solid rgba(255,255,255,0.5);}'
+ ' #'+id+' .ytv-list-header{-webkit-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2); -moz-box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2); box-shadow: 0 1px 2px rgba(255, 255, 255, 0.2);}'
+ ' #'+id+' .ytv-list-header a{background: rgba(0,0,0,0.2);}'
+ ' #'+id+' .ytv-playlists{background: #ccc;}'
);
}
},
userUploads: function(userInfo){
if (userInfo && userInfo.items.length > 0){
settings.pid = userInfo.items[0].contentDetails.relatedPlaylists.uploads;
utils.ajax.get( utils.endpoints.playlistVids(), prepare.compileVideos );
} else console.log ('Youtube-TV Error: API returned no matches for: '+(settings.channelId ? settings.channelId : settings.user)+'\nPlease ensure it was entered correctly and in the appropriate field shown below. \nuser: \'username\' or channelId: \'UCxxxx...\'');
},
selectedPlaylist: function(playlistInfo){
if (playlistInfo && playlistInfo.items.length > 0) {
if (!settings.channelId && !settings.user){
settings.cid = ('id='+(settings.channelId = playlistInfo.items[0].snippet.channelId));
}
settings.currentPlaylist = playlistInfo.items[0].snippet.title;
settings.pid = playlistInfo.items[0].id;
utils.ajax.get( utils.endpoints.playlistVids(), prepare.compileVideos );
} else console.log ('Youtube-TV Error: API returned no matches for playlist(s): '+settings.playlist);
},
compileVideos: function(res){
if (res && res.items.length > 0){
var playlists = res.items,
i;
settings.videoString = '';
for(i=0; i<playlists.length; i++){
settings.videoString += playlists[i].contentDetails.videoId;
if (i<playlists.length-1){ settings.videoString += ',';}
}
utils.ajax.get( utils.endpoints.videoInfo(), prepare.compileList );
} else console.log ('Youtube-TV Error: Empty playlist');
},
playlists: function(res){
if(res && res.items.length > 0){
var list = '<div class="ytv-playlists"><ul>',
playlists = res.items,
i;
for(i=0; i<playlists.length; i++){
var data = {
title: playlists[i].snippet.title,
plid: playlists[i].id,
thumb: playlists[i].snippet.thumbnails.medium.url
};
list += '<a href="#" data-ytv-playlist="'+(data.plid)+'">';
list += '<div class="ytv-thumb"><div class="ytv-thumb-stroke"></div><img src="'+(data.thumb)+'"></div>';
list += '<span>'+(data.title)+'</span>';
list += '</a>';
}
list += '</ul></div>';
var lh = settings.element.getElementsByClassName('ytv-list-header')[0],
headerLink = lh.children[0];
headerLink.href="#";
headerLink.target="";
headerLink.setAttribute('data-ytv-playlist-toggle', 'true');
settings.element.getElementsByClassName('ytv-list-header')[0].innerHTML += list;
lh.className += ' ytv-has-playlists';
} else console.log ('Youtube-TV Error: Returned no playlists');
},
compileList: function(data){
if(data && data.items.length > 0){
utils.ajax.get( utils.endpoints.userInfo(), function(userInfo){
var list = '',
user = {
title: userInfo.items[0].snippet.title,
url: '//youtube.com/channel/'+userInfo.items[0].id,
thumb: userInfo.items[0].snippet.thumbnails['default'].url,
summary: userInfo.items[0].snippet.description,
subscribers: userInfo.items[0].statistics.subscriberCount,
views: userInfo.items[0].statistics.viewCount
},
videos = data.items,
first = true,
i;
settings.channelId = userInfo.items[0].id;
if(settings.currentPlaylist) user.title += ' · '+(settings.currentPlaylist);
if (settings.sortList) videos.sort(function(a,b){if(a.snippet.publishedAt > b.snippet.publishedAt) return -1;if(a.snippet.publishedAt < b.snippet.publishedAt) return 1;return 0;});
if (settings.reverseList) videos.reverse();
if (settings.shuffleList) {
videos = function (){for(var j, x, i = videos.length; i; j = Math.floor(Math.random() * i), x = videos[--i], videos[i] = videos[j], videos[j] = x);return videos;}();
}
list += '<div class="ytv-list-header">';
list += '<a href="'+(user.url)+'" target="_blank">';
list += '<img src="'+(user.thumb)+'">';
list += '<span><i class="ytv-arrow down"></i>'+(user.title)+'</span>';
list += '</a>';
list += '</div>';
list += '<div class="ytv-list-inner"><ul>';
for(i=0; i<videos.length; i++){
if(videos[i].status.embeddable){
var video = {
title: videos[i].snippet.title,
slug: videos[i].id,
link: 'https://www.youtube.com/watch?v='+videos[i].id,
published: videos[i].snippet.publishedAt,
stats: videos[i].statistics,
duration: (videos[i].contentDetails.duration),
thumb: videos[i].snippet.thumbnails.medium.url
};
var durationString = video.duration.match(/[0-9]+[HMS]/g);
var h = 0, m = 0, s = 0, time = '';
durationString.forEach(function (duration) {
var unit = duration.charAt(duration.length-1);
var amount = parseInt(duration.slice(0,-1));
switch (unit) {
case 'H': h = (amount > 9 ? '' + amount : '0' + amount); break;
case 'M': m = (amount > 9 ? '' + amount : '0' + amount); break;
case 'S': s = (amount > 9 ? '' + amount : '0' + amount); break;
}
});
if (h){ time += h+':';}
if (m){ time += m+':';} else { time += '00:';}
if (s){ time += s;} else { time += '00';}
var isFirst = '';
if(settings.playId==video.slug){
isFirst = ' class="ytv-active"';
first = video.slug;
} else if(first===true){
first = video.slug;
}
list += '<li'+isFirst+'><a href="#" data-ytv="'+(video.slug)+'" class="ytv-clear">';
list += '<div class="ytv-thumb"><div class="ytv-thumb-stroke"></div><span>'+(time)+'</span><img src="'+(video.thumb)+'"></div>';
list += '<div class="ytv-content"><b>'+(video.title)+'</b>';
if (video.stats)
{
list+='</b><span class="ytv-views">'+utils.addCommas(video.stats.viewCount)+' Views</span>';
}
list += '</div></a></li>';
}
}
list += '</ul></div>';
settings.element.innerHTML = '<div class="ytv-relative"><div class="ytv-video"><div id="ytv-video-player"></div></div><div class="ytv-list">'+list+'</div></div>';
if(settings.element.getElementsByClassName('ytv-active').length===0){
settings.element.getElementsByTagName('li')[0].className = "ytv-active";
}
var active = settings.element.getElementsByClassName('ytv-active')[0];
active.parentNode.parentNode.scrollTop = active.offsetTop;
action.logic.loadVideo(first, settings.autoplay);
if (settings.playlist){
utils.ajax.get( utils.endpoints.playlistInfo(settings.playlist), prepare.playlists );
} else if(settings.browsePlaylists){
utils.ajax.get( utils.endpoints.userPlaylists(), prepare.playlists );
}
});
} else console.log ('Youtube-TV Error: Empty video list');
}
},
action = {
logic: {
playerStateChange: function(d){
console.log(d);
},
loadVideo: function(slug, autoplay){
var house = settings.element.getElementsByClassName('ytv-video')[0];
var counter = settings.element.getElementsByClassName('ytv-video-playerContainer').length;
house.innerHTML = '<div id="ytv-video-player'+id+counter+'" class="ytv-video-playerContainer"></div>';
cache.player = new YT.Player('ytv-video-player'+id+counter, {
videoId: slug,
events: {
onReady: settings.events.videoReady,
onStateChange: function(e){
if( (e.target.getPlayerState()===0) && settings.chainVideos ){
var ns = settings.element.getElementsByClassName('ytv-active')[0].nextSibling,
link = ns.children[0];
link.click();
}
settings.events.stateChange.call(this, e);
}
},
playerVars: {
enablejsapi: 1,
origin: doc.domain,
controls: settings.controls ? 1 : 0,
rel: 0,
showinfo: 0,
iv_load_policy: settings.annotations ? '' : 3,
autoplay: autoplay ? 1 : 0,
theme: settings.playerTheme,
wmode: settings.wmode
}
});
}
},
endpoints: {
videoClick: function(e){
var target = utils.parentUntil(e.target ? e.target : e.srcElement, 'data-ytv');
if(target){
if(target.getAttribute('data-ytv')){
// Load Video
utils.events.prevent(e);
var activeEls = settings.element.getElementsByClassName('ytv-active'),
i;
for(i=0; i<activeEls.length; i++){
activeEls[i].className="";
}
target.parentNode.className="ytv-active";
action.logic.loadVideo(target.getAttribute('data-ytv'), true);
}
}
},
playlistToggle: function(e){
var target = utils.parentUntil(e.target ? e.target : e.srcElement, 'data-ytv-playlist-toggle');
if(target && target.getAttribute('data-ytv-playlist-toggle')){
// Toggle Playlist
utils.events.prevent(e);
var lh = settings.element.getElementsByClassName('ytv-list-header')[0];
if(lh.className.indexOf('ytv-playlist-open')===-1){
lh.className += ' ytv-playlist-open';
} else {
lh.className = lh.className.replace(' ytv-playlist-open', '');
}
}
},
playlistClick: function(e){
var target = utils.parentUntil(e.target ? e.target : e.srcElement, 'data-ytv-playlist');
if(target && target.getAttribute('data-ytv-playlist')){
// Load Playlist
utils.events.prevent(e);
settings.pid = target.getAttribute('data-ytv-playlist');
target.children[1].innerHTML = 'Loading...';
utils.ajax.get( utils.endpoints.playlistInfo(settings.pid), function(res){
var lh = settings.element.getElementsByClassName('ytv-list-header')[0];
lh.className = lh.className.replace(' ytv-playlist-open', '');
prepare.selectedPlaylist(res);
});
}
}
},
bindEvents: function(){
utils.events.addEvent( settings.element, 'click', action.endpoints.videoClick );
utils.events.addEvent( settings.element, 'click', action.endpoints.playlistToggle );
utils.events.addEvent( settings.element, 'click', action.endpoints.playlistClick );
}
},
initialize = function(id, opts){
utils.deepExtend(settings, opts);
if(settings.apiKey.length===0){
alert("Missing APIkey in settings or as global vaiable.");
}
apiKey = settings.apiKey;
settings.element = (typeof id==='string') ? doc.getElementById(id) : id;
if(settings.element && (settings.user || settings.channelId || settings.playlist)){
prepare.youtube();
prepare.build();
action.bindEvents();
if (settings.playlist) {
utils.ajax.get( utils.endpoints.playlistInfo(settings.playlist), prepare.selectedPlaylist );
} else {
utils.ajax.get( utils.endpoints.userInfo(), prepare.userUploads );
}
} else console.log ('Youtube-TV Error: Missing either user, channelId, or playlist');
};
/* Public */
this.destroy = function(){
utils.events.removeEvent( settings.element, 'click', action.endpoints.videoClick );
utils.events.removeEvent( settings.element, 'click', action.endpoints.playlistToggle );
utils.events.removeEvent( settings.element, 'click', action.endpoints.playlistClick );
settings.element.className = '';
settings.element.innerHTML = '';
};
this.fullscreen = {
state: function(){
return (settings.element.className).indexOf('ytv-full') !== -1;
},
enter: function(){
if( (settings.element.className).indexOf('ytv-full') === -1 ){
settings.element.className += 'ytv-full';
}
},
exit: function(){
if( (settings.element.className).indexOf('ytv-full') !== -1 ){
settings.element.className = (settings.element.className).replace('ytv-full', '');
}
}
};
initialize(id, opts);
};
if ((typeof module !== 'undefined') && module.exports) {
module.exports = YTV;
}
if (typeof ender === 'undefined') {
this.YTV = YTV;
}
if ((typeof define === "function") && define.amd) {
define("YTV", [], function() {
return YTV;
});
}
if ((typeof jQuery !== 'undefined')) {
jQuery.fn.extend({
ytv: function(options) {
return this.each(function() {
new YTV(this.id, options);
});
}
});
}
}).call(this, window, document);
Replace this
list += '<div class="ytv-list-header">';
with
list += '<div class="ytv-list-header ytv-playlist-open">';
There is two playlist one is "list of all playlists". And other is "list of videos in a playlist".
"ytv-playlist-open" indicate the open status for "list of all playlist". So when it is added it will close "videos in a playlist" and show "list of all playlist" which you want to show there.

JQuery: How to refactor JQuery interaction with interface?

The question is very simple but also a bit theoretical.
Let's imagine you have a long JQuery script which modifies and animate the graphics of the web site. It's objective is to handle the UI. The UI has to be responsive so the real need for this JQuery is to mix some state of visualization (sportlist visible / not visible) with some need due to Responsive UI.
Thinking from an MVC / AngularJS point of view. How should a programmer handle that?
How to refactor JS / JQuery code to implement separation of concerns described by MVC / AngularJS?
I provide an example of JQuery code to speak over something concrete.
$.noConflict();
jQuery(document).ready(function ($) {
/*variables*/
var sliderMenuVisible = false;
/*dom object variables*/
var $document = $(document);
var $window = $(window);
var $pageHost = $(".page-host");
var $sportsList = $("#sports-list");
var $mainBody = $("#mainBody");
var $toTopButtonContainer = $('#to-top-button-container');
/*eventHandlers*/
var displayError = function (form, error) {
$("#error").html(error).removeClass("hidden");
};
var calculatePageLayout = function () {
$pageHost.height($(window).height());
if ($window.width() > 697) {
$sportsList.removeAttr("style");
$mainBody
.removeAttr("style")
.unbind('touchmove')
.removeClass('stop-scroll');
if ($(".betslip-access-button")[0]) {
$(".betslip-access-button").fadeIn(500);
}
sliderMenuVisible = false;
} else {
$(".betslip-access-button").fadeOut(500);
}
};
var formSubmitHandler = function (e) {
var $form = $(this);
// We check if jQuery.validator exists on the form
if (!$form.valid || $form.valid()) {
$.post($form.attr("action"), $form.serializeArray())
.done(function (json) {
json = json || {};
// In case of success, we redirect to the provided URL or the same page.
if (json.success) {
window.location = json.redirect || location.href;
} else if (json.error) {
displayError($form, json.error);
}
})
.error(function () {
displayError($form, "Login service not available, please try again later.");
});
}
// Prevent the normal behavior since we opened the dialog
e.preventDefault();
};
//preliminary functions//
$window.on("load", calculatePageLayout);
$window.on("resize", calculatePageLayout);
//$(document).on("click","a",function (event) {
// event.preventDefault();
// window.location = $(this).attr("href");
//});
/*evet listeners*/
$("#login-form").submit(formSubmitHandler);
$("section.navigation").on("shown hidden", ".collapse", function (e) {
var $icon = $(this).parent().children("button").children("i").first();
if (!$icon.hasClass("icon-spin")) {
if (e.type === "shown") {
$icon.removeClass("icon-caret-right").addClass("icon-caret-down");
} else {
$icon.removeClass("icon-caret-down").addClass("icon-caret-right");
}
}
toggleBackToTopButton();
e.stopPropagation();
});
$(".collapse[data-src]").on("show", function () {
var $this = $(this);
if (!$this.data("loaded")) {
var $icon = $this.parent().children("button").children("i").first();
$icon.removeClass("icon-caret-right icon-caret-down").addClass("icon-refresh icon-spin");
console.log("added class - " + $icon.parent().html());
$this.load($this.data("src"), function () {
$this.data("loaded", true);
$icon.removeClass("icon-refresh icon-spin icon-caret-right").addClass("icon-caret-down");
console.log("removed class - " + $icon.parent().html());
});
}
toggleBackToTopButton();
});
$("#sports-list-button").on("click", function (e)
{
if (!sliderMenuVisible)
{
$sportsList.animate({ left: "0" }, 500);
$mainBody.animate({ left: "85%" }, 500)
.bind('touchmove', function (e2) { e2.preventDefault(); })
.addClass('stop-scroll');
$(".betslip-access-button").fadeOut(500);
sliderMenuVisible = true;
}
else
{
$sportsList.animate({ left: "-85%" }, 500).removeAttr("style");
$mainBody.animate({ left: "0" }, 500).removeAttr("style")
.unbind('touchmove').removeClass('stop-scroll');
$(".betslip-access-button").fadeIn(500);
sliderMenuVisible = false;
}
e.preventDefault();
});
$mainBody.on("click", function (e) {
if (sliderMenuVisible) {
$sportsList.animate({ left: "-85%" }, 500).removeAttr("style");
$mainBody.animate({ left: "0" }, 500)
.removeAttr("style")
.unbind('touchmove')
.removeClass('stop-scroll');
$(".betslip-access-button").fadeIn(500);
sliderMenuVisible = false;
e.stopPropagation();
e.preventDefault();
}
});
$document.on("click", "div.event-info", function () {
if (!sliderMenuVisible) {
var url = $(this).data("url");
if (url) {
window.location = url;
}
}
});
function whatDecimalSeparator() {
var n = 1.1;
n = n.toLocaleString().substring(1, 2);
return n;
}
function getValue(textBox) {
var value = textBox.val();
var separator = whatDecimalSeparator();
var old = separator == "," ? "." : ",";
var converted = parseFloat(value.replace(old, separator));
return converted;
}
$(document).on("click", "a.selection", function (e) {
if (sliderMenuVisible) {
return;
}
var $this = $(this);
var isLive = $this.data("live");
var url = "/" + _language + "/BetSlip/Add/" + $this.data("selection") + "?odds=" + $this.data("odds") + "&live=" + isLive;
var urlHoveringBtn = "/" + _language + '/BetSlip/AddHoveringButton/' + $this.data("selection") + "?odds=" + $this.data("odds") + "&live=" + isLive;
$.ajax(urlHoveringBtn).done(function (dataBtn) {
if ($(".betslip-access-button").length == 0 && dataBtn.length > 0) {
$("body").append(dataBtn);
}
});
$.ajax(url).done(function (data) {
if ($(".betslip-access").length == 0 && data.length > 0) {
$(".navbar").append(data);
$pageHost.addClass("betslipLinkInHeader");
var placeBetText = $("#live-betslip-popup").data("placebettext");
var continueText = $("#live-betslip-popup").data("continuetext");
var useQuickBetLive = $("#live-betslip-popup").data("usequickbetlive").toLowerCase() == "true";
var useQuickBetPrematch = $("#live-betslip-popup").data("usequickbetprematch").toLowerCase() == "true";
if ((isLive && useQuickBetLive) || (!isLive && useQuickBetPrematch)) {
var dialog = $("#live-betslip-popup").dialog({
modal: true,
dialogClass: "fixed-dialog"
});
dialog.dialog("option", "buttons", [
{
text: placeBetText,
click: function () {
var placeBetUrl = "/" + _language + "/BetSlip/QuickBet?amount=" + getValue($("#live-betslip-popup-amount")) + "&live=" + $this.data("live");
window.location = placeBetUrl;
}
},
{
text: continueText,
click: function () {
dialog.dialog("close");
}
}
]);
}
}
if (data.length > 0) {
$this.addClass("in-betslip");
}
});
e.preventDefault();
});
$(document).on("click", "a.selection.in-betslip", function (e) {
if (sliderMenuVisible) {
return;
}
var $this = $(this);
var isLive = $this.data("live");
var url = "/" + _language + "/BetSlip/RemoveAjax/" + $this.data("selection") + "?odds=" + $this.data("odds") + "&live=" + isLive;
$.ajax(url).done(function (data) {
if (data.success) {
$this.removeClass("in-betslip");
if (data.selections == 0) {
$(".betslip-access").remove();
$(".betslip-access-button").remove();
$(".page-host").removeClass("betslipLinkInHeader");
}
}
});
e.preventDefault();
});
$("section.betslip .total-stake button.live-betslip-popup-plusminus").click(function (e) {
if (sliderMenuVisible) {
return;
}
e.preventDefault();
var action = $(this).data("action");
var amount = parseFloat($(this).data("amount"));
if (!isNumeric(amount)) amount = 1;
var totalStake = $("#live-betslip-popup-amount").val();
if (isNumeric(totalStake)) {
totalStake = parseFloat(totalStake);
} else {
totalStake = 0;
}
if (action == "decrease") {
if (totalStake < 1.21) {
totalStake = 1.21;
}
totalStake -= amount;
} else if (action == "increase") {
totalStake += amount;
}
$("#live-betslip-popup-amount").val(totalStake);
});
toggleBackToTopButton();
function toggleBackToTopButton() {
isScrollable() ? $toTopButtonContainer.show() : $toTopButtonContainer.hide();
}
$("#to-top-button").on("click", function () { $("#mainBody").animate({ scrollTop: 0 }); });
function isScrollable() {
return $("section.navigation").height() > $(window).height() + 93;
}
var isNumeric = function (string) {
return !isNaN(string) && isFinite(string) && string != "";
};
function enableQuickBet() {
}
});
My steps in such cases are:
First of all write (at least) one controller
Replace all eventhandler with ng-directives (ng-click most of all)
Pull the view state out of the controller with ng-style and ng-class. In most of all cases ng-show and ng-hide will be sufficed
If there is code that will be used more than once, consider writing a directive.
And code that has nothing todo with the view state - put the code in a service
write unit tests (i guess there is no one until now:) )

Accessing a jQuery Closure function outside

I have this code embedded in my file for managing session time out. This was referred from http://www.fairwaytech.com/2012/01/handling-session-timeout-gracefully/
I want to call SessionManager.extend() for all the ajax request
complete. So i can automatically refresh my session manager time.
This is what i tried
<script type="text/javascript">
$(document).ajaxSuccess(function (event, xhr, settings) {
if (xhr.status === 200) {
SessionManager().extend();
}
});
</script>
Getting an error that SessionManager object not found. How do we call this?
Below is the library code taken from that site
$(function () { // Wrap it all in jQuery documentReady because we use jQuery UI Dialog
// HtmlHelpers Module
// Call by using HtmlHelpers.getQueryStringValue("myname");
var HtmlHelpers = function () {
return {
// Based on http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
getQueryStringValue: function (name) {
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}
};
} ();
// StringHelpers Module
// Call by using StringHelpers.padLeft("1", "000");
var StringHelpers = function () {
return {
// Pad string using padMask. string '1' with padMask '000' will produce '001'.
padLeft: function (string, padMask) {
string = '' + string;
return (padMask.substr(0, (padMask.length - string.length)) + string);
}
};
} ();
// SessionManager Module
var SessionManager = function () {
// NOTE: globalTimeoutPeriod is defined in _Layout.cshtml
var sessionTimeoutSeconds = HtmlHelpers.getQueryStringValue('smt') || (globalTimeoutPeriod),
countdownSeconds = HtmlHelpers.getQueryStringValue('smc') || 300,
secondsBeforePrompt = sessionTimeoutSeconds - countdownSeconds,
$dlg,
displayCountdownIntervalId,
promptToExtendSessionTimeoutId,
originalTitle = document.title,
count = countdownSeconds,
extendSessionUrl = '/Session/Extend',
expireSessionUrl = '/Session/Expire?returnUrl=' + location.pathname;
var endSession = function () {
$dlg.dialog('close');
location.href = expireSessionUrl;
};
var displayCountdown = function () {
var countdown = function () {
var cd = new Date(count * 1000),
minutes = cd.getUTCMinutes(),
seconds = cd.getUTCSeconds(),
minutesDisplay = minutes === 1 ? '1 minute ' : minutes === 0 ? '' : minutes + ' minutes ',
secondsDisplay = seconds === 1 ? '1 second' : seconds + ' seconds',
cdDisplay = minutesDisplay + secondsDisplay;
document.title = 'Expire in ' +
StringHelpers.padLeft(minutes, '00') + ':' +
StringHelpers.padLeft(seconds, '00');
$('#sm-countdown').html(cdDisplay);
if (count === 0) {
document.title = 'Session Expired';
endSession();
}
count--;
};
countdown();
displayCountdownIntervalId = window.setInterval(countdown, 1000);
};
var promptToExtendSession = function () {
$dlg = $('#sm-countdown-dialog')
.dialog({
title: 'Session Timeout Warning',
height: 250,
width: 350,
bgiframe: true,
modal: true,
buttons: {
'Continue': function () {
$(this).dialog('close');
refreshSession();
document.title = originalTitle;
},
'Log Out': function () {
endSession(false);
}
}
});
count = countdownSeconds;
displayCountdown();
};
var refreshSession = function () {
window.clearInterval(displayCountdownIntervalId);
var img = new Image(1, 1);
img.src = extendSessionUrl;
window.clearTimeout(promptToExtendSessionTimeoutId);
startSessionManager();
};
var startSessionManager = function () {
promptToExtendSessionTimeoutId =
window.setTimeout(promptToExtendSession, secondsBeforePrompt * 1000);
};
// Public Functions
return {
start: function () {
startSessionManager();
},
extend: function () {
refreshSession();
}
};
} ();
SessionManager.start();
});
Remove the var prefix from SessionManager.
Bit of info here about scope, http://msdn.microsoft.com/en-us/library/ie/bzt2dkta(v=vs.94).aspx

Categories

Resources