javascript scoping in requirejs and qunit - javascript

I've been trying to puzzle out why the scoping was a little screwy on these 2 prototype objects - the first one is my preloader based on PreloadJS and the second is my QUnit test. I've fixed the issue but I accidently deleted the original thread which someone kindly responded to so I've reposted this working version to say thankyou to that person
'use strict';
define(['preloadjs'], function (PreloadJS) {
var Preloader = function (model) {
this.model = model;
this.totalLoaded = 0;
this.context = model.context;
this.isFinished = false;
this.onStart = (model.onStart != null) ? model.onStart : function (e) {};
this.onUpdate = (model.onUpdate != null) ? model.onUpdate : function (e) {};
this.onComplete = (model.onComplete != null) ? model.onComplete : function (e) {};
this.preload = null;
// make sure assets exists
if (model.assets == null) {
model.assets = {};
}
this.init();
};
/**
* initialise preloader
* #return {null}
*/
Preloader.prototype.init = function() {
var self = this;
var preload = new PreloadJS();
if (this.onStart != null) {
this.onStart();
}
preload.onProgress = function (e) { self.onUpdate(e); };
preload.onComplete = function (e) { self.handleComplete(e); };
preload.onFileLoad = function (e) { self.onFileLoad(e); };
preload.loadManifest(this.model.manifest);
this.preload = preload;
};
Preloader.prototype.handleComplete = function(e) {
this.isFinished = true;
this.onComplete(e);
};
/**
* called when each file in the manifest is loaded - if it's an image,
* create an image object and populate its properties
* #param {event} e event object
* #return {null}
*/
Preloader.prototype.onFileLoad = function(e) {
if (e.type == PreloadJS.IMAGE) {
var self = this;
var img = new Image();
img.src = e.src;
img.onload = function () { self.handleFileComplete(); };
this.model.assets[e.id] = img;
}
};
/**
* iterates totalLoaded when each image has intialised
* #return {null}
*/
Preloader.prototype.handleFileComplete = function() {
this.totalLoaded++;
};
// public interface
return Preloader;
});
and this is the preloader QUnit test
'use strict';
define(function (require) {
var Preloader = require('Preloader');
var manifest = [
{ src : '../app/images/splash-screen.jpg', id : 'splash-screen' }
];
var assets = {};
var startFired = 0;
var updateFired = 0;
var completeFired = 0;
var totalLoaded = 0;
var scopetest = 'test';
var loaded = 0;
var pl = new Preloader({
manifest : manifest,
assets : assets,
onStart : function (e) {
startFired++;
},
onUpdate : function (e) {
updateFired++;
totalLoaded = e.loaded;
},
onComplete : function (e) {
completeFired++;
// adding the unit tests into the onComplete function fixed the inconsistent test results i was getting
test('Preloader tests', function () {
expect(4);
equal(startFired, 1, 'onStart was called once exactly');
ok((updateFired > 0), 'onUpdate was called at least once. Total: ' + updateFired);
equal(completeFired, 1, 'onComplete was called once exactly');
notEqual(pl.model.assets['splash-screen'], undefined, 'there was at least one asset loaded: ' + pl.model.assets['splash-screen']);
});
QUnit.start();
}
});
QUnit.stop();
});
Thankyou for your response and apologies for deleting the thread

This question already answered in the OP - this is my acceptance

Related

javascript DOM object (window) extended property is null on page reload after being idle

I have a custom extended property attached to the window object in JavaScript as follows:
Community.js
(function (window, document, $) {
'use strict';
var containerScrollPositionOnHideList = [];
var scrollToTopOnShowContainerList = [];
var userProfileInfo = {};
window.Community = $.extend({
//init
init: function () {
var Site = window.Site;
Site.run();
this.enableHideShowEventTrigger();
},
setUserInfo: function (userObj) {
if (UtilModule.allowDebug) { debugger; }
window.localStorage.setItem('userInfo', JSON.stringify(userObj));
var d = new $.Deferred();
$.when(this.initUserProfile(userObj.UserId)).done(function () {
d.resolve("ok");
});
},
getUserInfo: function () {
var userJson = window.localStorage.getItem('userInfo');
var userObj = JSON.parse(userJson);
return userObj;
},
})(window, document, jQuery);
The problem is that this extension property window.Community is null in certian scenarios when i refresh the page which i am going to describe below along with flow of code.
and here is a module in JavaScript to force reload scripts even if they are cached every time the page is refreshed as my code heavily depends on javascript calls so I just enabled it to make sure while I am still writing the code page reloads every time, the code is below as follows:
Util.js
var UtilModule = (function () {
var allowDebug = false;
var currentVersion = 0;
var properlyLoadScript = function (scriptPath, callBackAfterLoadScript) {
//get the number of `<script>` elements that have the correct `src` attribute
//debugger;
var d = $.Deferred();
$('script').each(function () {
console.log($(this).attr('src'));
});
if (typeof window.Community == 'undefined') {
//debugger;
console.log('community was undefined till this point');
//the flag was not found, so the code has not run
$.when(forceReloadScript(scriptPath)).done(function () {
callBackAfterLoadScript();
d.resolve("ok");
});
}
else {
console.log('Community loaded already and running now : ' + scriptPath);
callBackAfterLoadScript();
}
return d.promise();
};
var forceReloadScript = function (scriptPath) {
if (UtilModule.allowDebug) { debugger; }
var d = $.Deferred();
initCurrentVersion();
var JSLink = scriptPath + "?version=" + currentVersion;
var JSElement = document.createElement('script');
JSElement.src = JSLink;
JSElement.onload = customCallBack;
document.getElementsByTagName('head')[0].appendChild(JSElement);
function customCallBack() {
d.resolve("ok");
}
return d.promise();
};
var enableDebugger = function () {
allowDebug = true;
};
var disableDebugger = function () {
allowDebug = false;
};
var debugBreakPoint = function () {
if (allowDebug) {
}
};
var initCurrentVersion = function () {
if (currentVersion == 0) {
var dt = new Date();
var ttime = dt.getTime();
currentVersion = ttime;
}
};
var getCurrentVersion = function () {
return currentVersion;
};
return {
forceReloadScript,
properlyLoadScript,
enableDebugger,
disableDebugger,
debugBreakPoint,
allowDebug,
getCurrentVersion
};
})();
Note: I have made deferred objects to resolve only when the JSElement.onload has been called successfully. This step was taken just for testing purpose to make sure that I am not missing something before reaching a point to call the method where I am getting an error.
After that the code where I load scripts using UtilModule in my layout file look like as below:
_Layout.cshtml
<script src = "~/Scripts/Application/Modules/Util.js" ></script>
<script>
$.when(
UtilModule.properlyLoadScript('/Scripts/Application/Community.js', () => {
// Community.init() was supposed to be called here but i was still getting the error so i implemented this using promise that is returned from properlyLoadScript and call Community.init() further in .done callback to make sure that script is properly loading till this point.
//window.Community.init();
})
).done(function() {
window.Community.init();
});
</script>
#RenderSection("scripts", required: false)
Now coming to my main file where My index file is executing having (_layout.chsmtl) as parent layout
is
Index.cshtml
#{
ViewBag.Title = "My Blog";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<article id="BlogPage" style="margin: 5px;">
</article>
#section scripts{
<script type="text/javascript">
$(document).ready(function () {
$.when(UtilModule.properlyLoadScript('/Scripts/Application/Modules/Blog.js', () => {
})).done(function () {
BlogModule.init();
});
});
//});
</script>
}
from what I know is that #section scripts is executed only once all the scripts in the layout page are loaded first so seems like a safe place to initialize the code which is dependent on some script in _Layout.HTML file and further enclosed with $(document).ready() for testing just to make sure that this script loads after everything else is loaded already.
Note: I am running all this code in in-cognito mode in chrome so nothing is cached while this code is running
now my Blog.js file looks like as below
var BlogModule = (function () {
var moduleReference = this;
var PageId = "#BlogPage ";
var currentUser;
var BlogPostList = [];
var blogPostInfo = {};
//init
var init = function () {
if (UtilModule.allowDebug) { debugger; }
//This is where the problem happens
console.log(window.Community);
console.log(window.Community.getUserInfo());
currentUser = window.Community.getUserInfo();
initBlogInformation();
//window.Community.registerModule(BlogModule);
if (Object.keys(window.Community.getUserProfileObject()) <= 0) {
$.when(window.Community.initUserProfile(currentUser.UserId)).then(function () {
$.when(initBlogInformation()).done(function () {
//debugger;
console.log(BlogPostList);
window.WidgetManager.populateWidget(PageId, moduleReference);
loadBlogPostWidget();
loadBlogViewWidget();
loadBlogCommentsWidget();
});
});
}
else {
$.when(initBlogInformation()).done(function () {
window.WidgetManager.populateWidget(PageId, moduleReference);
loadBlogPostWidget();
loadBlogViewWidget();
loadBlogCommentsWidget();
});
}
};
var loadBlogIndexMenuWidget = function () {
if (UtilModule.allowDebug) { debugger; }
};
var loadBlogPostWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogPostWidget";
widgetOptions.container = PageId + "#BlogPostWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
}
var loadBlogViewWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogViewWidget";
widgetOptions.container = PageId + "#BlogViewWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
};
var loadBlogCommentsWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogCommentsWidget";
widgetOptions.container = PageId + "#BlogCommentsWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
};
var initBlogList = function () {
$.when(getBlogPosts()).then(function (results) {
if (UtilModule.allowDebug) { debugger; }
BlogPostList = results.Record;
console.log(BlogPostList);
});
};
var getBlogPosts = function () {
if (UtilModule.allowDebug) { debugger; }
var d = new $.Deferred();
var uri = '/Blog/GetBlogPosts?userId=' + currentUser.UserId;
$.post(uri).done(function (returnData) {
if (UtilModule.allowDebug) { debugger; }
if (returnData.Status == "OK") {
BlogPostList = returnData.Record;
BlogPostList.map(x => {
if (UtilModule.allowDebug) { debugger; }
x.UserName = window.Community.getUserProfileObject().UserName;
if (x.Comments != null) {
x.CommentsObject = JSON.parse(x.Comments);
x.CommentsCount = x.CommentsObject.length;
}
});
console.log(returnData.Record);
d.resolve("ok");
} else {
window.Community.showNotification("Error", returnData.Record, "error");
d.resolve("error");
}
});
return d.promise();
};
var initBlogInformation = function () {
//debugger;
var d = $.Deferred();
getBlogPosts().then(getBlogModelTemplate()).then(function () {
d.resolve("ok");
});
return d.promise();
};
//Get Blog Model
var getBlogModelTemplate = function () {
var d = new $.Deferred();
var uri = '/Blog/GetBlogModel';
$.post(uri).done(function (returnData) {
blogPostInfo = returnData.Record;
d.resolve("ok");
});
return d.promise();
};
return {
init: init,
};
})();
The error I have highlighted below
so the problem is in init function of BlogModule which is BlogModule.init() the page is idle for too long and I reload it I get the following error:
cannot call
window.Community.getUserInfo() of undefined implying that community is undefied
after couple of refreshes its fine and the issue doesn't happen unless I change reasonable portion of code for js files to be recompiled again by browser or the browser is idle for too long and I am not able to understand what is triggering this issue.
below is log from console
p.s. error occurs more repeatedly if i refresh page with f5 but happens rarely if i refresh page with ctrl + f5
Please any help would be of great value
Answering my own question, took a while to figure it out but it was a small mistake on my end just fixing the following function in Util.js fixed it for me
var properlyLoadScript = function(scriptPath, callBackAfterLoadScript) {
//get the number of `<script>` elements that have the correct `src` attribute
//debugger;
var d = $.Deferred();
$('script').each(function() {
console.log($(this).attr('src'));
});
if (typeof window.Community == 'undefined') {
//debugger;
console.log('community was undefined till this point');
//the flag was not found, so the code has not run
$.when(forceReloadScript('/Scripts/Application/Community.js')).done(function() {
//debugger;
$.when(forceReloadScript(scriptPath)).done(function() {
callBackAfterLoadScript();
});
d.resolve("ok");
});
} else {
console.log('Community loaded already and running now : ' + scriptPath);
$.when(forceReloadScript(scriptPath)).done(function() {
callBackAfterLoadScript();
});
}
return d.promise();
};

reaching the btn event outside the revealing patterned applied class

I have an revealing patterned applied class.How can I reach btnMenu event outside of the model
thanks.
MyModel= (function () {
var btnClickEvents = function () {
var btnMenu = $('.btnMenu').on('click', function () {
var date= $(this).attr("data-rezerve-date");
var statu= $(this).attr("data-rezerve-statu");
alert("click"+date+'---'+statu);
});
};
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: btnClickEvents.btnMenu//how can I reach this function outside of model
};
})();
update
I change my code as u show.and add one return function
MyModel = (function () {
var dt = "";
var statu = "";
var rvalue = {};
var btnClickEvents = function () {
$('.btnMenu').on('click', onBtnMenuClick);
};
function onBtnMenuClick(e) {
dt = $(this).attr("data-rezerve-date");
statu = $(this).attr("data-rezerve-statu");
rvalue.date = dt;
rvalue.statu = statu;
console.log(dt);
}
var getRezervationDateAndStatus = function () {
return rvalue;
};
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: getRezervationDateAndStatus
};
})();
and after include my module to my web page calling is like this,
MyModel.asignValues(rezervasyonTable,data);
MyModel.initialize();
var result = MyModel.getRezervationDateAndStatus();
console.log(result.date);
bu console log empty.
As you say it is a " revealing" pattern. You could see what you expose. To be able to use this function outside of the module change your code like this:
MyModel = (function () {
var btnClickEvents = function () {
$('.btnMenu').on('click', onBtnMenuClick);
};
function onBtnMenuClick(e) {
var date = $(this).attr("data-rezerve-date");
var statu = $(this).attr("data-rezerve-statu");
alert("click" + date + '---' + statu);
}
return {
initialize: initialize,
asignValues: asignValues,
getRezervationDateAndStatus: onBtnMenuClick
};
})();

jquery plugin, reference video element in DOM

I have started jQuery plugin where I want to retrieve the .duration and .currentTime on a HTML5 video, from within a bound .on('click', ) event.
I am struggling to capture this information within my plugin.registerClick function, here is my code:
(function ($) {
$.myPlugin = function (element, options) {
var defaults = {
videoOnPage: 0,
dataSource: 'data/jsonIntervals.txt',
registerClick: function () { }
}
var plugin = this;
plugin.settings = {}
var $element = $(element);
element = element;
plugin.init = function () {
plugin.settings = $.extend({}, defaults, options);
$element.on('click', plugin.registerClick);
getJsonIntervals();
}
plugin.registerClick = function () {
var duration = $('video').get(plugin.settings.videoOnPage).duration;
console.log('duration: ' + duration);
}
var startTimes = [];
var dataSet = false;
var getJsonIntervals = function () {
if (dataSet == false) {
//calls a $.getJSON method.
//populates startTimes
//updates dataSet = true;
};
}
plugin.init();
}
$.fn.myPlugin = function (options) {
return this.each(function () {
if (undefined == $(this).data('myPlugin')) {
var plugin = new $.myPlugin(this, options);
$(this).data('myPlugin', plugin);
}
})
};
})(jQuery);
$(function () {
$('#button1').myPlugin();
});
Here my sample jsFiddle Click Here
Seems to work for me:
plugin.registerClick = function () {
var video = $('video').get(0);
console.log('duration: ' + video.duration);
console.log('currenttime: ' + video.currentTime);
}
http://jsfiddle.net/p4w040uz/2/
You need to play the video first then click the button. The browser has to retrieve the meta data first before it can return it.
Additional reference material you can read up:
http://www.w3schools.com/tags/av_event_loadedmetadata.asp
http://www.w3.org/2010/05/video/mediaevents.html

what does window.h mean in javascript?

Probably a really easy question
I've been searching, but I could not find what window.h means? Only some articles about C++ but not about javascript.
view: {
fc: "",
init: function() {
var iframe = $("iframe")[0];
var focused = true;
var unfocusedTimeStart = null;
var unfocusedTime = null;
var loaded = false;
var prevent_bust = 0;
var done = false;
window.onbeforeunload = function() {
prevent_bust++;
};
setInterval(function() {
if (prevent_bust > 0 && !done) {
prevent_bust -= 2;
}
}, 1);
var mySwfStore = new SwfStore({
namespace: "BTCClicks",
swf_url: "/js/storage.swf",
onready: function() {
var fcookie = mySwfStore.get("fcookie");
var randomstring = md5(randomstring);
if (fcookie == null) {
mySwfStore.set("fcookie", randomstring);
}
fcookie = mySwfStore.get("fcookie");
if (fcookie != null) {
BTCClicks.view.fc = fcookie;
}
},
onerror: function() {}
});
$("#viewFrame").load(function() {
if (!loaded) {
$.post("/ajax/vrequest", {
ad: window.h,
fc: BTCClicks.view.fc
}).done(function() {
startTimer();
});
loaded = true;
}
});
Could someone explain what that means?
If refers to a variable named h in the global (window) scope
Whenever you make a global variable in JavaScript you can either refer to it by name or window.[variableName]
In this case you can either do
ad: window.h
or
ad: h
As long as there isn't another local variable named h

HammerJS pull to refresh

I know very little about Javascript but need to use hammer.js in a project I'm working on.
Instead of replacing/refreshing the image im trying to use the pull to refresh scrit to refresh the page.
Ive tried adding
location.reload();
to the script but to no avail, can anyone shed any light on this.
http://eightmedia.github.io/hammer.js/
This is the code im using
/**
* requestAnimationFrame and cancel polyfill
*/
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame =
window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
/**
* pull to refresh
* #type {*}
*/
var PullToRefresh = (function() {
function Main(container, slidebox, slidebox_icon, handler) {
var self = this;
this.breakpoint = 80;
this.container = container;
this.slidebox = slidebox;
this.slidebox_icon = slidebox_icon;
this.handler = handler;
this._slidedown_height = 0;
this._anim = null;
this._dragged_down = false;
this.hammertime = Hammer(this.container)
.on("touch dragdown release", function(ev) {
self.handleHammer(ev);
});
};
/**
* Handle HammerJS callback
* #param ev
*/
Main.prototype.handleHammer = function(ev) {
var self = this;
switch(ev.type) {
// reset element on start
case 'touch':
this.hide();
break;
// on release we check how far we dragged
case 'release':
if(!this._dragged_down) {
return;
}
// cancel animation
cancelAnimationFrame(this._anim);
// over the breakpoint, trigger the callback
if(ev.gesture.deltaY >= this.breakpoint) {
container_el.className = 'pullrefresh-loading';
pullrefresh_icon_el.className = 'icon loading';
this.setHeight(60);
this.handler.call(this);
}
// just hide it
else {
pullrefresh_el.className = 'slideup';
container_el.className = 'pullrefresh-slideup';
this.hide();
}
break;
// when we dragdown
case 'dragdown':
this._dragged_down = true;
// if we are not at the top move down
var scrollY = window.scrollY;
if(scrollY > 5) {
return;
} else if(scrollY !== 0) {
window.scrollTo(0,0);
}
// no requestAnimationFrame instance is running, start one
if(!this._anim) {
this.updateHeight();
}
// stop browser scrolling
ev.gesture.preventDefault();
// update slidedown height
// it will be updated when requestAnimationFrame is called
this._slidedown_height = ev.gesture.deltaY * 0.4;
break;
}
};
/**
* when we set the height, we just change the container y
* #param {Number} height
*/
Main.prototype.setHeight = function(height) {
if(Modernizr.csstransforms3d) {
this.container.style.transform = 'translate3d(0,'+height+'px,0) ';
this.container.style.oTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.msTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.mozTransform = 'translate3d(0,'+height+'px,0)';
this.container.style.webkitTransform = 'translate3d(0,'+height+'px,0) scale3d(1,1,1)';
}
else if(Modernizr.csstransforms) {
this.container.style.transform = 'translate(0,'+height+'px) ';
this.container.style.oTransform = 'translate(0,'+height+'px)';
this.container.style.msTransform = 'translate(0,'+height+'px)';
this.container.style.mozTransform = 'translate(0,'+height+'px)';
this.container.style.webkitTransform = 'translate(0,'+height+'px)';
}
else {
this.container.style.top = height+"px";
}
};
/**
* hide the pullrefresh message and reset the vars
*/
Main.prototype.hide = function() {
container_el.className = '';
this._slidedown_height = 0;
this.setHeight(0);
cancelAnimationFrame(this._anim);
this._anim = null;
this._dragged_down = false;
};
/**
* hide the pullrefresh message and reset the vars
*/
Main.prototype.slideUp = function() {
var self = this;
cancelAnimationFrame(this._anim);
pullrefresh_el.className = 'slideup';
container_el.className = 'pullrefresh-slideup';
this.setHeight(0);
setTimeout(function() {
self.hide();
}, 500);
};
/**
* update the height of the slidedown message
*/
Main.prototype.updateHeight = function() {
var self = this;
this.setHeight(this._slidedown_height);
if(this._slidedown_height >= this.breakpoint){
this.slidebox.className = 'breakpoint';
this.slidebox_icon.className = 'icon arrow arrow-up';
}
else {
this.slidebox.className = '';
this.slidebox_icon.className = 'icon arrow';
}
this._anim = requestAnimationFrame(function() {
self.updateHeight();
});
};
return Main;
})();
function getEl(id) {
return document.getElementById(id);
}
var container_el = getEl('container');
var pullrefresh_el = getEl('pullrefresh');
var pullrefresh_icon_el = getEl('pullrefresh-icon');
var image_el = getEl('random-image');
var refresh = new PullToRefresh(container_el, pullrefresh_el, pullrefresh_icon_el);
// update image onrefresh
refresh.handler = function() {
var self = this;
// a small timeout to demo the loading state
setTimeout(function() {
var preload = new Image();
preload.onload = function() {
image_el.src = this.src;
self.slideUp();
};
preload.src = 'http://lorempixel.com/800/600/?'+ (new Date().getTime());
}, 1000);
};
There is a Beer involved for anyone that can fix this :)
http://jsfiddle.net/zegermens/PDcr9/1/
You're assigning the return value of the location.reload function to the src attribute of an Image element. I'm not sure if the function even has a return value, https://developer.mozilla.org/en-US/docs/Web/API/Location.reload
Try this:
// update image onrefresh
refresh.handler = function() {
var self = this;
// a small timeout to demo the loading state
setTimeout(function() {
window.location.reload();
}, 1000);
};

Categories