JavaScript localStorage of image src doesn't work with Firefox - javascript

I have 2 array of path items:
var images = [
imgPath + 'earth-png/a1.png',
imgPath + 'earth-png/a2.png',
...
var images2 = [
imgPath + 'eye-lens/01.png',
imgPath + 'eye-lens/02.png',
imgPath + 'eye-lens/03.png',
...
Then in order to make an animation with multiple images, I try to load it first :
this.loadImages = function() {
if (typeof(Storage) == "undefined" ) {
console.log("Your browser does not support HTML5 localStorage. Try upgrading.");
return false;
}
else {
console.log("Both localStorage and sessionStorage support is there.");
}
var totalImg = images.length + images2.length
i = 0,
j = 0
var myImages1 = [];
var myImages2 = [];
function loadImgs() {
if (i < totalImg && (myImages1Storage.length > 0 && myImages2Storage.length > 0)) {
if (i < 20) {
$.ajax({
type: 'GET',
url: images[i],
crossDomain: true,
xhrFields: {
withCredentials: false
},
complete: function() {
myImages1.push(images[i]);
i++;
loadImgs();
}
});
} else {
$.ajax({
type: 'GET',
url: images2[j],
crossDomain: true,
xhrFields: {
withCredentials: false
},
complete: function() {
myImages2.push(images2[j]);
j++;
i++;
loadImgs();
}
});
}
} else {
try {
localStorage.setItem("images1", JSON.stringify(myImages1));
localStorage.setItem("images2", JSON.stringify(myImages2));
}
catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
console.log("Error: Local Storage limit exceeds.");
} else {
console.log("Error: Saving to local storage.");
}
}
}
}
loadImgs();
};
And then, to the TimelineMax:
eyeLensAnimation
.to(obj, 0.5, {
curImg: images2.length,
roundProps: "curImg",
immediateRender: true,
ease: Linear.easeNone,
onUpdate: function() {
//next image on update
eyePng.src = images2[obj.curImg];
}
});
Well, here comes my question.
As you can see, I store the data in a localStorage. It seems to be successful when I go through the array load with a:
JSON.parse(localStorage.getItem("images1"));
Nevertheless, it seems to work only with Chrome.
With Firefox, it continues to request a get when it's time to trigger the animation (on scroll with scrollmagic).
So, is there something I do wrong?
Should I load first the array stored and use the array loaded as path for my animation or does it not occur if - at least - the path asked is already stored in cache?

Related

How to add dynamically attribute value using Jquery?

I have logic where i am trying to add host url dynamically so it work in all env based on hosst, so below trying to find a file that is there in host but its never going into $.each statement , if call url directly http://18.35.168.87:6000/Sdk/wrapper-sdk/client/out.json it worked and rendered data, any idea what could have wrong in below code to achieve this task ?
main.js
function myFunction(val) {
var url = "../../wrapper-sdk/" + client + "/out.json";
if (window.location.hostname.indexOf("localhost") !== -1 ||
window.location.host.indexOf("localhost") !== -1) {
var scripts = document.getElementsByTagName('script');
var host = '';
$.each(scripts, function (idx, item) {
if (item.src.indexOf('Sdk/wrapper-sdk') !== -1 && (item.src.indexOf('out.json') !== -1)) {
host = item.src.split('?')[0];
host = host.replace('wrapper-sdk/' + client + '/out.json', '');
}
});
url = url.replace('../../', host);
}
$.ajax({
url: url + "?no_cache=" + new Date().getTime(),
dataType: "json",
"async": false,
success: function (data) {
console.log(data);
},
error: function () {
console.log('error while accessing api.json.')
}
});
}
I would suggest breaking up some of your checks into their own function. Makes it just a bit easier to follow the logic.
function validIp(str) {
var parts = str.split(".");
var result = true;
$.each(parts, function(i, p) {
if (parseInt(p) > 0 && parseInt(p) < 255) {
result = result && true;
}
});
return result;
}
function checkLocalUrl(str) {
var result = 0;
if (str.indexOf("localhost") >= 0) {
result = 1;
}
if (validIp(str)) {
result = -1;
}
/*
0 = Some Domain or Host Name, not LocalHost
1 = LocalHost
-1 = IP Address
*/
return result;
}
function changeSources(client) {
if (checkLocalUrl(window.location.hostname) || checkLocalUrl(window.location.host) {
var scripts = $("script");
var host = '';
scripts.each(function(i, el) {
var src = $(el).attr("src");
var nUrl = new URL(src);
var pro = nUrl.protocol;
var hn = nUrl.hostname;
if (nUrl.pathname.indexOf('/Sdk/wrapper-sdk') == 0 && nUrl.pathname.indexOf('out.json') > 0) {
host = pro + "://" + hn + "/wrapper-sdk/" + client + "/out.json";
}
$.ajax({
url: host
data: { no_cache: new Date().getTime() },
dataType: "json",
async: false,
success: function(data) {
console.log(data);
},
error: function() {
console.log('error while accessing api.json.')
}
});
});
}
}
}
See also: new URL()
You can send a string to checkLocalUrl() and it will return 1 or true if it's potentially a localhost URL. It will return 0 or false if it's any other domain pattern or -1 or false if it's an IP address.
In changeSources() we can use this to check for local urls and perform the AJAX you defined.

jQuery Promise each loop

I am creating a UserScript that will generate a list of URLs to a users photo gallery. A user gallery may have multiple pages, each page has multiple thumbnails that have a link to a page which contains the full-sized image url.
I am using jQuery to request the pages though I'm not getting the desired results when a user gallery only contains 1 page. I get some results when a user gallery contains multiple pages but I only get 1 page worth of results.
var userID = 0;
function getUserID() {
var query = window.location.search;
var regex = /UserID=(\d+)/;
var regexResult = query.match(regex);
if (regexResult !== null) {
return regexResult[0].replace('UserID=', '');
} else {
return 0;
}
}
function getGallery(userID) {
function getGalleryPage(userID, page, gallery) {
var data = {};
if(page > 0) {
data = { btnNext: ">", PageNo: page };
}
var url = 'http://www.domain.com/' + userID;
return $.ajax({
method: 'POST',
url: url,
data: data,
dataType: 'html'
}).then(function(result){
$result = $(result);
$result.find('form[name="frmGallery"]').find('img').each(function() {
var url = ''
// Do stuff to get url
getGalleryImage(url).done(function(imageLink) {
gallery.push(imageLink);
});
});
$btnNext = $result.find('input[name="btnNext"]');
if($btnNext.length > 0) {
page += 1;
return getGalleryPage(userID, page, gallery);
} else {
return(gallery);
}
});
}
return getGalleryPage(userID, 0, []);
}
function getGalleryImage(url) {
return $.ajax({
method: 'GET',
url: url,
dataType: 'html'
}).then(function(result){
var imageUrl = '';
// Do stuff to get full sized image url
return imageUrl;
});
}
jQuery(document).ready(function($) {
userID = getUserID();
if(userID === 0)
return;
getGallery(userID).done(function(gallery) {
$.each(gallery, function(index, value) {
console.log(value);
});
});
});
I think this part of my script is not correct:
$result.find('form[name="frmGallery"]').find('img').each(function() {
var url = ''
// Do stuff to get url
getGalleryImage(url).done(function(imageLink) {
gallery.push(imageLink);
});
});
As written, there's no attempt to aggregate the inner promises returned by getGalleryImage().
You need to map the delivered img elements to an array of promises and aggregate them with jQuery.when().
I would write it something like this :
jQuery(function($) {
var userID;
function getUserID() {
var query = window.location.search;
var regex = /UserID=(\d+)/;
var regexResult = query.match(regex);
if (regexResult !== null) {
return regexResult[0].replace('UserID=', '');
} else {
return 0;
}
}
function getGallery(userID) {
var gallery = [];
var page = 0;
var url = 'http://www.domain.com/' + userID;
function getGalleryPage() {
var data = (page > 0) ? { btnNext: ">", PageNo: page } : {};
return $.ajax({
method: 'POST',
url: url,
data: data,
dataType: 'html'
}).then(function(result) {
$result = $(result);
//map jQuery collection of img elements to Array of promises
var promises = $result.find('form[name="frmGallery"]').find('img').map(function(imgElement, i) {
var url = ''
// Do stuff to get url
return getGalleryImage(url);
}).get();// .get() is necessary to unwrap jQuery and return Array
//aggregate promises
return $.when.apply(null, promises).then(function() {
//accumulate results
gallery = gallery.concat(Array.prototype.slice.call(arguments));
// recurse/terminate
if($result.find('input[name="btnNext"]').length > 0) {
page += 1;
return getGalleryPage();
} else {
return gallery;
}
});
});
}
return getGalleryPage();
}
function getGalleryImage(url) {
return $.ajax({
method: 'GET',
url: url,
dataType: 'html'
}).then(function(result) {
var imageUrl = '';
// Do stuff to get full sized image url
return imageUrl;
});
}
userID = getUserID();
if(userID !== 0) {
getGallery(userID).then(function(gallery) {
$.each(gallery, function(index, value) {
console.log(value);
});
});
}
});
You should also impose a limit on the number of recursions, just in case one day some userID yields thousands of pages.

Getting total page size: syncronicity problems

I'm trying to set up a script to get total page size, including images. I'm having serious problems with ajax asyncronicity and JQuery throws error when I try to set async: false due to negative effects in user experience.
The problem is, ajax calls to get image size return NaN in a random and very frequent way, surely due to too many concurrent connections.
Is there a way you can think to overcome this?
This is my code (it was much shorter in origin, callback approach was based on this post, but didn't work):
function getPageSize(callback)
{
var pageWeight = 0;
var lastWeight = 0;
var xhr = $.ajax({
type: "HEAD",
// async: false,
url: "test01.html",
success: function(msg)
{
if (xhr.readyState == 4)
{
if (xhr.status == 200 || xhr.status == 0)
{
if ( !isNaN(xhr.getResponseHeader('Content-Length')) && !isNaN($('#size').html()) )
{
pageWeight = parseInt(xhr.getResponseHeader('Content-Length'));
callback(pageWeight);
// lastWeight = parseInt($('#size').html());
// $('#size').html(pageWeight + lastWeight);
console.log("Page " + pageWeight);
}
}
}
}
});
}
function getImagesSize(callback)
{
var imageWeight = 0;
var lastWeight = 0;
$('img').each(function()
{
var imgPath = $(this).attr('src');
xhr = null;
xhr = $.ajax(
{
type: "HEAD",
url: $(this).attr('src'),
async: false,
success: function(msg)
{
if (xhr.readyState == 4)
{
if (xhr.status == 200 || xhr.status == 0)
{
if (!isNaN(xhr.getResponseHeader('Content-Length')) && !isNaN($('#size').html()) )
{
imageWeight = parseInt(xhr.getResponseHeader('Content-Length'));
callback(imageWeight);
// lastWeight = parseInt($('#size').html());
// $('#size').html(imageWeight + lastWeight);
console.log("Image " + imgPath + ": " + imageWeight);
}
}
}
}
});
});
}
function updateTotalPageSize(size)
{
var lastWeight = 0;
lastWeight = parseInt($('#size').html());
$('#size').html(size + lastWeight);
}
$(document).ready(function()
{
getPageSize(function(size)
{
//alert(size);
updateTotalPageSize(size);
});
getImagesSize(function(size)
{
//alert(size);
updateTotalPageSize(size);
});
});
SOLUTION by #Regent
function getImagesSize(callback)
{
var allImages = $('img');
function handleNext(index)
{
if (index >= allImages.length)
{
return;
}
var imgPath = allImages.eq(index).attr('src');
$.ajax({
type: "HEAD",
url: imgPath,
success: function(msg, status, xhr)
{
if (!isNaN(xhr.getResponseHeader('Content-Length')) && !isNaN($('#size').html()))
{
var imageWeight = parseInt(xhr.getResponseHeader('Content-Length'));
callback(imageWeight);
console.log("Image " + imgPath + ": " + imageWeight);
handleNext(index + 1);
}
}
});
}
handleNext(0);
}

Function as a KnockoutJS observable

I have the following script (see below). I have two questions regarding it:
1.What does the following line mean in the context of Knockoutjs?
ko.observable(null);
2.How can I invoke a function not yet defined as in here:
that.activePollingXhr(...
Here is the full script:
$(document).ready(function() {
function ChatViewModel() {
var that = this;
that.userName = ko.observable('');
that.chatContent = ko.observable('');
that.message = ko.observable('');
that.messageIndex = ko.observable(0);
that.activePollingXhr = ko.observable(null);
var keepPolling = false;
that.joinChat = function() {
if (that.userName().trim() != '') {
keepPolling = true;
pollForMessages();
}
}
function pollForMessages() {
if (!keepPolling) {
return;
}
var form = $("#joinChatForm");
that.activePollingXhr($.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
}));
$('#message').focus();
}
that.postMessage = function() {
if (that.message().trim() != '') {
var form = $("#postMessageForm");
$.ajax({url: form.attr("action"), type: "POST",
data: "message=[" + that.userName() + "] " + $("#postMessageForm input[name=message]").val(),
error: function(xhr) {
console.error("Error posting chat message: status=" + xhr.status + ", statusText=" + xhr.statusText);
}
});
that.message('');
}
}
that.leaveChat = function() {
that.activePollingXhr(null);
resetUI();
this.userName('');
}
function resetUI() {
keepPolling = false;
that.activePollingXhr(null);
that.message('');
that.messageIndex(0);
that.chatContent('');
}
}
//Activate knockout.js
ko.applyBindings(new ChatViewModel());
});
ko.observable(null); creates an observable with a value of null. Nothing different than ko.observable(5);, where the value would be 5.
I see that you're using the that.activePollingXhr observable by passing it the result of an ajax call. However, this call is asynchronous and $.ajax doesn't return the data it got from the server, but rather a jquery deferred. You need to use that.activePollingXhr insude the success callback. Here's is how your code might look like:
$.ajax({url: form.attr("action"), type: "GET", data: form.serialize(), cache: false,
success: function(messages) {
console.log(messages);
for (var i = 0; i < messages.length; i++) {
that.chatContent(that.chatContent() + messages[i] + "\n");
that.messageIndex(that.messageIndex() + 1);
}
that.activePollingXhr(messages); // <-- Note where the call to activePollingXhr is
},
error: function(xhr) {
if (xhr.statusText != "abort" && xhr.status != 503) {
resetUI();
console.error("Unable to retrieve chat messages. Chat ended.");
}
},
complete: pollForMessages
});
As for the comment under your question: that.activePollingXhr is defined as that.activePollingXhr = ko.observable(null); - an observable with value of null.
That just initializes an observable with null as the initial value.
If you need to invoke a function that is an observable, just add a second set of parenthesis.
that.activePollingXhr()()

Setting html5 media source using ajax

I needed to aid authentication headers for my audio files i was grabbing from a external server. So now im trying to use ajax, i can grab the files fine, but i cant set them as the media source for my player. How do you approach setting a ajax loaded file as a audio source?
EDIT
Ended up fixing it in case someone comes back this way.
if (this.mAudioPlayer.canPlayType("audio/mpeg")) {
this.mExtension = '.mp3';
}else if (this.mAudioPlayer.canPlayType("audio/ogg")) {
this.mExtension = '.ogg';
} else if (this.mAudioPlayer.canPlayType("audio/mp4")) {
this.mExtension = '.m4a';
}
this.CreateAudioData = function() {
//downloading audio for use in data:uri
$.ajax({
url: aAudioSource + this.mExtension + '.txt',
type: 'GET',
context: this,
async: false,
beforeSend: function(xhr) {xhr.setRequestHeader('Authorization', window.userId);},
success: this.EncodeAudioData,
error: function(xhr, aStatus, aError) { HandleError('Audio Error: ' + aStatus); }
});
};
this.EncodeAudioData = function(aData) {
//this.mAudioData = base64_encode(aData);
this.mAudioData = aData;
if (this.mExtension == '.m4a') {
Debug("playing m4a");
this.mAudioSrc = "data:audio/mp4;base64," + this.mAudioData;
} else if (this.mExtension == '.ogg') {
Debug("playing ogg");
this.mAudioSrc = "data:audio/ogg;base64," + this.mAudioData;
} else if (this.mExtension == '.mp3') {
Debug("playing mp3");
this.mAudioSrc = "data:audio/mp3;base64," + this.mAudioData;
}
};
this.play = function() {
if (this.mAudioPlayer.src != this.mAudioSrc) {
this.mAudioPlayer.src = this.mAudioSrc;
}
this.mAudioPlayer.load();
this.mAudioPlayer.play();
};
Had to do asynch:false, otherwise i would get a small chunk of the audio instead of all of it. Though removing the asynch made debugging easier in the end.
Are you actually downloading the file, or returning it in base64 encoded format (i.e. as a Data URI)?
Changing the source of an audio element via JavaScript is quite straightforward.
<audio id="myAudio" controls />
And then once you have the source,:
var audio = document.getElementById("myAudio");
audio.src = myAudioFile;
audio.type = "type/ogg"; // ony showing an OGG example here
if (this.mAudioPlayer.canPlayType("audio/mpeg")) {
this.mExtension = '.mp3';
}else if (this.mAudioPlayer.canPlayType("audio/ogg")) {
this.mExtension = '.ogg';
} else if (this.mAudioPlayer.canPlayType("audio/mp4")) {
this.mExtension = '.m4a';
}
this.CreateAudioData = function() {
//downloading audio for use in data:uri
$.ajax({
url: aAudioSource + this.mExtension + '.txt',
type: 'GET',
context: this,
async: false,
beforeSend: function(xhr) {xhr.setRequestHeader('Authorization', window.userId);},
success: this.EncodeAudioData,
error: function(xhr, aStatus, aError) { HandleError('Audio Error: ' + aStatus); }
});
};
this.EncodeAudioData = function(aData) {
//this.mAudioData = base64_encode(aData);
this.mAudioData = aData;
if (this.mExtension == '.m4a') {
Debug("playing m4a");
this.mAudioSrc = "data:audio/mp4;base64," + this.mAudioData;
} else if (this.mExtension == '.ogg') {
Debug("playing ogg");
this.mAudioSrc = "data:audio/ogg;base64," + this.mAudioData;
} else if (this.mExtension == '.mp3') {
Debug("playing mp3");
this.mAudioSrc = "data:audio/mp3;base64," + this.mAudioData;
}
};
this.play = function() {
if (this.mAudioPlayer.src != this.mAudioSrc) {
this.mAudioPlayer.src = this.mAudioSrc;
}
this.mAudioPlayer.load();
this.mAudioPlayer.play();
};
Had to do asynch:false, otherwise i would get a small chunk of the audio instead of all of it. Though removing the asynch made debugging easier in the end.

Categories

Resources