HTML / javascript dynamically creating different postmessage replies depending on user input - javascript

Sorry for the confusing title, I'm not quite sure how I should name this better.
Anyway, I'm dealing with a postmessage interface that receives and sends data between its iframe child. It basically sends very simple messages: either score related to the game in the iframe or save/load requests.
What I'm trying to do is make it possible for the user to have more than one save "file" at once, using the concat method. I'm basically making separate save states into one large string by combining them with a separator and separating them when I need to access them for load requests.
Here's how I handle save requests from the game at the moment:
var states = JSON.stringify(data.gameState);
var newstate = {state: gameState};
var savesArray = savestring.split("||");
savesArray.unshift(newstate);
if (savesArray.length > 5){
savesArray.pop();
}
var state = savesArray.join("||");
and then I send the 'state' back to the database.
The problem that I'm having is how I would be able to let the user decide which of the 0-5 save files he wants to choose to open (=> send back as a load request).
What I'm doing at the moment as a way to avoid the problem altogether is send the first state using
var first_state = loaded_state.split("||")[0];
but I was wondering if there's any neat way to give the user a button box/div when the load request is received in the parent HTML with buttons deciding which index save state is sent back to the iframe. The biggest problem I have with this is how I can properly build the button to communicate & send the load request dynamically.
I already have a function that I use for other things in the page to dynamically create a button, but I'm not 100% sure if I can work with it to suit my needs here or if it's even the best approach in the first place.
function play(name, URL) {
var element = document.createElement("button");
//Assign different attributes to the element.
element.setAttribute("value", URL);
element.setAttribute("id", "gamebutton");
element.innerHTML = name;
element.setAttribute("style", "display:block");
element.setAttribute("class", "btn btn-success btn-block");
element.onclick = function () {
document.getElementById("iframeID").src = this.getAttribute("value");
document.getElementById("iframeID").width = "95%";
document.getElementById("iframeID").height = "750 px";
document.getElementById("iframeID").style.display = "block";
document.getElementById("hiddenScore").style.display = "block";
var gameelement = document.getElementById("gamediv");
gameelement.style.display = "block";
var miscarea = document.getElementById("misc_div");
miscarea.style.display = "none";
};
I was thinking of making it into a modal box, but the uncertainty of whether or not I would be able to smoothly create the buttons I need for it has made me hesitate whether or not I want to go the extra mile to make multiple saves possible.
Edit:
This is how the message is sent back to the iframe. As you can see, being able to create buttons for each of the indexes (var first_state = loaded_state.split("||")[0];) would mean that the code would otherwise be the same for all buttons
$.ajax({
type: "GET",
url: "{% url 'get_detail_game_instance' game.pk %}",
beforeSend: function (xhr, settings) {
$.ajaxSettings.beforeSend(xhr, settings);
},
success: function (data) {
var loaded_state = JSON.parse(data.state);
var first_state = loaded_state.split("||")[0];
console.log(loaded_state);
var message = {
"messageType" : "LOAD",
"gameState" : first_state
};
event.source.postMessage(message, eventSave.origin);
},
failure: function (errMsg) {
console.log(errMsg);
}
});
The event is received through a simple eventlistener and the event data contains whether or not it's a score, load or save request

Related

Return Content with alert in Controller

I'm trying to somewhat replicate what I saw in this question, particularly in this answer, but not quite the same.
My intent is, if the zip has no files (it can happen because the folder could be empty) I want to return an alert just so the user is warned that is not possible to obtain the file at the time.
But I'm missing on the redirection point, I don't want the alert to redirect the user to a blank page refering the Action, I want it to stay in the page, also due to some filters.
Is this possible? I couldn't find anything that would stop the redirection from happening.
Here is my the Action Controller code:
public ActionResult DownloadZip(List<int> things)
{
// Create zip with files
if (!zip.Any())
{
return Content(#"<script language='javascript' type='text/javascript'>
alert('Message');
</script>
");
}
// Return zip
}
Here is the call from the view:
$("#btnExportToZip").on("click", function (e) {
var grid = $("#gridThings").data("kendoGrid");
var items = grid.dataSource.data();
var lstIds = [];
$.each(items, function (index, elem) {
if (elem.Checked) {
lstIds.push(elem.Id);
}
});
if (lstIds.length > 0) {
var params = lstIds.join("&listAmostras=")
var url = '/Search/DownloadZip?listAmostras=' + params;
window.location.href = url;
}
});
If you do a redirect as you're doing here, it's too late to take it back once you've determined the zip file is empty. Your best bet here is probably to do an AJAX file download. Bear in mind, though, that this will require that the browser supports the HTML5 File API, so IE 9 and under are out.
$.ajax({
url: url,
async: false,
xhrFields: {
responseType: 'blob'
},
success: function (data) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
a.click();
window.URL.revokeObjectURL(url);
}
});
Essentially what this does is request the zip file via AJAX. Once the file data has been received, an anchor link is added to the DOM (not visible) and dynamically "clicked" to approximate the behavior of user click a link to a static file. In other words, a download prompt will pop as soon as the AJAX request completes successfully. However, this code only removes the need to redirect. You still need to conditionally pop the download only if the zip file has something in. There's two ways you can accomplish that.
In the success callback of the AJAX, you would wrap the code there in a conditional that checks that data.size > 0. However, that might not actually work. I've never looked at an empty zip file, but it's entirely possible that there's file headers in the binary that would cause the blob to actually have a size greater than zero, even though it's "empty".
The better approach is to return an error response in your zip action when the zip file is empty. Off the top of my head, I'm not sure what the most appropriate error response code would be, but anything in 400-500 range will work for triggering the appropriate AJAX callback. Then, you just need to add and error handler to this AJAX. In that handler, you could then notify the user however you like that there's no download because the zip would be empty.
As per my understanding, alert is redirect the user to the blank page because in the javascript you have the line window.location.href = url; which might be redirect to the same action again which shows the alert.
So try to give the different url to the window.location.href
for ex:window.location.href = '../somecontroller/someaction';
thanks
Karthik

Create a link with POST data from chrome extension

I have created a chrome extension that sends a POST request to some server and gets its response then displays an number badge according to the data.
Now I want to create a link inside the popup.html based on the data used to send the POST request to the server it self so the users can see the data on the website (data source).
This is the code I use in popup.js to send the POST request
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://someserver/path', true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.onload = function () {
var regex = new RegExp(/ID:\d+/g);
var testregex = regex.test(this.responseText);
if (testregex == true) {
var count = this.responseText.match(/ID:\d+/g).length;
var countext = count.toString();
chrome.browserAction.setBadgeText({text: countext});
} else {
chrome.browserAction.setBadgeText({text: "0"});
}
};
getCurrentTabUrl(function(url) {
var cleanurl = url.match(/^https?\:\/\/([^\/:?#]+)(?:[\/:?#]|$)/i);
xhr.send('search=' + cleanurl[1] +'&submit=Search');
});
Question is how do I create a link with the same POST data I used before?
Thanks for the help
So, you want to query an external service, then display some information in the popup with a link to more information.
Let's make a scaffold of how you're going to display it. In your popup, include the following:
<div id="data-container">
<div id="data-loading">
<!-- Maybe add an animated spinner here, or something else -->
Loading...
</div>
<div id="data-display">
<!-- Currently empty, will add a link here -->
</div>
</div>
Style this as you wish. Then, from your XHR:
xhr.onload = function () {
/* ... */
// Hide the loading notice
document.getElementById("data-loading").style.display = "none";
// Create the element that will show more details;
// <a href="#"> works okay, but consider making a button
var link = document.createElement("a");
link.href = "#";
link.text = "More details..." // Add data from xhr.responseText?
link.addEventListener("click", clickHandler);
var container = document.getElementById("data-display");
// Make sure the container is empty (in case we're calling this again)
while (container.lastChild) node.removeChild(container.lastChild);
// Append more elements if you want to display some data
container.appendChild(link);
};
Now the interesting part: the clickHandler click handler. To open a new tab from the popup, you should use chrome.tabs.create():
function clickHandler() {
chrome.tabs.create({
url: /* ??? */
});
}
It would be trivial if we wanted to open a normal GET page. To open a POST page, we have to cheat. There are two main possibilities:
Open a javascript: URL that performs a POST. Conceptually easier, but only works for short parameters.
Open a helper page in your extension that will perform POST. This allows you to pass arbitrarily large arguments before the POST happens.
Both are covered in this question: Chrome Extension Development - POST to new tab

pre-select html select option after window.location redirect

I have problem where after the page is redirected, I want the select to have the previously selected option as the selected choice after the page has been redirected.
here I have an onchange for my select which will redirect the user depending on their selection(refresh page basically), however after the page refresh the selected option gets reset and the first option in the list get selected.
$("#reportTypes").change(function () {
var reportTypeID = $(this).val();
var deviceTypeID = $('#hDeviceTypeID').val();
window.location.href = "http://127.0.0.1:6543/new_device/" + deviceTypeID + "/" + reportTypeID;
$('#reportTypes').val(reportTypeID);//tried to select the previous option but this doesn't seem to work
});
How can I get my select to display the chosen option without getting reset after the page load?
This is your second question regarding the same problem and I have a strong feeling you don't have a clear picture of what happens where and when. I wish I could give you a link to some "how the Web works" intro, but unfortunately I don't know any. No offense, just saying...
Very briefly, in the context of a Pyramid app, things happen in the following order:
Browser sends a request to the server, which is basically a blob of text
Pyramid application receives and parses the request, and finds a view function to invoke to handle the request.
The view function does some useful stuff, for example it queries data from database and returns a Python dictionary, which Pyramid then passes to the template engine (Jinja2 in your case)
Template engine uses a template (a text blob) and the data returned by your view function to generate another text blob, which represents your rendered HTML page. That blob is then sent to the browser, along with HTTP headers etc. Note that for Pyramid there's actually no HTML, DOM, JavaScript variables or anything like that. Like any web application, your Pyramid app is just a program to receive text blobs and generate other text blobs in response.
Browser receives the server response and interprets it - for example, it may decide that this is an HTML page with some inline <script /> tags. The browser then renders the HTML, loads images and stylesheets, executes scripts etc.
The moment you click on a link or change window.location (let's ignore various AJAX scenarios for the moment) - the moment you do that, the browser abandons your current page and sends another HTTP request (see #1 above). It then waits for the server response and render a completely new page which has absolutely no "memory of" the previous page. This is why HTTP is called "stateless protocol".
My point is: the moment you do
window.location.href = "http://127.0.0.1:6543/new_device/" + deviceTypeID + "/" + reportTypeID;
it makes absolutely no sense to do
$('#reportTypes').val(reportTypeID);//tried to select the previous option but this doesn't seem to work
because the current page is going to be abandoned, a new text blob will be sent from the server and rendered as a new web page.
Now, after this theoretical background, you can see that one of the options to solve your problem would be to send some parameter to the server which would tell it "please give me the same page only with this new reportTypeID pre-selected".
It looks like you already have access to deviceTypeID and reportTypeID in your view function. Now you need to pass them to the template and use them to render selected="selected" attribute on the option which should be pre-selected. In pseudocode it would look something like
%for report_type in all_report_types:
%if report.id == report_type_id:
<option value="${report_type.id}" selected="selected">${report_type.name}</option>
%else:
<option value="${report_type.id}">${report_type.name}</option>
%endif
%endfor
If you are sending the parameters to the same page as GET request parameters and causing a page reload, then you could use JavaScript to parse the url parameters and then set the dropdown to the specified value upon page load.
Taking the function specified by #BrunoLM here for url param parsing: How can I get query string values in JavaScript?
var urlParams = (function(a) {
if (a == "") return {};
var b = {};
for (var i = 0; i < a.length; ++i)
{
var p=a[i].split('=');
if (p.length != 2) continue;
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split('&'));
Now we execute this function upon page load to grab the values:
//$(function {}); is a shorthand for $(document).ready(function() {});
$(function() {
//execute this code to grab the url params
var urlParams = (function(a) {
if (a == "") return {};
var b = {};
for (var i = 0; i < a.length; ++i)
{
var p=a[i].split('=');
if (p.length != 2) continue;
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
return b;
})(window.location.search.substr(1).split('&'));
//now we check to see if the parameter was passed and if so, set the dropdown value
if (urlParams['reportTypeId']) {
$('#reportTypes').val(urlParams['reportTypeId']);
}
});
This all assumes that you pass an HTTP GET parameter called reportTypeId like so: "reportTypeId=203"

What's the best way to force a hashchange?

My website uses hashchange-triggered AJAX (to make it more bookmark-friendly). The problem I am having is that when I click "submit" in a form, all the form data that is serialize()'d to be sent via $.post() gets lost. I know this because I get the "Flag 1" alert after I click submit, and various other tests (alerting, echoing, etc.) show this to be true.
Here's my current code:
$(document).ready(function() {
var data = '';
var hash = '';
newPage();
alert('Flag 1');
$(window).bind('hashchange', function() {
hash = window.location.hash;
if (hash == '') {
path = window.location.pathname;
hash = '#' + path.replace(/^\/+/, '');
}
data += '&func=' + hash;
var xhr = $.post(hash, data, function(result) {
$("maincontent").html(result);
})
.done(newPage);
});
// Initialize vars and handle new form elements
function newPage() {
data = '';
$('form').submit(function() {
data = $(this).serialize();
// Flag 2 - What do I do here?
});
}
// Load ajax content on first run of document
if ($('#maincontent').html() == '')
$(window).trigger('hashchange');
});
What I am trying to do is manually fire a hashchange event while also changing the URL. The trouble is that if I just set window.location.hash = $(this).attr('action'); then return false; where the "Flag 2" comment is, then I wind up getting unwanted trash in the URL, possibly due to the hashmark being encoded for a URL (...%23, etc).
I am wondering what the best way to set the hash is, and whether there is a simpler way to do what I am trying to do to begin with.
(I'm also open to comments suggesting alternate approaches for the style of navigation I am trying to achieve)
Well, I understand there are lots of errors doing this. But we have alternative options for this you will surely like:
jQuery History Plugin : http://plugins.jquery.com/history/ (Demo: http://4nf.org/)
History JS: https://github.com/browserstate/history.js/
But I would recommend HTML5 history.pushState if you are willing to avoid older browser support. (Demo: https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history)
Good luck!!

How to get content from another page

I have struggled with this problem for 2 days now. I've found MANY tutorials on similar topics but none have helped me solve my issue yet.
On a Volusion shopping cart I am trying to remotely grab content from the product page and save it's information in a variable for use on the shopping cart. I am unable to use php (not supported by Volusion) and am forced to do this by using javascript (as far as I know). The following code searches the cart items for a certain brand name "Palliser". If that name is present, it grabs the link, uses ajax to send a request to the page associated with the link, and grabs the info I need. It GETS the info I need, but in the process my page turns white and it leaves behind the year, 2013... I have NO idea why this is happening. This is my first time working with ajax so could someone PLEASE help!?!?
$(window).load(function(){
var seat_count = 0;
var i = 0;
var prodLinks = [];
var numSeats = '';
$('b.cart-item-name:contains("Palliser")').filter(function(index) {
prodLinks[i] = 'http://xepwk.cjvgn.servertrust.com/'+$(this).parent('a').attr('href');
$.ajax({
url:prodLinks[i],
//data:string,
async:false,
success: function(result){
var html = jQuery('<div>').html(result);
var prodInfoArray = html.find('span.PageText_L660n').parent('b').parent('td').html().split('<br>');
var numSeats = prodInfoArray[1];
alert(numSeats);
}
});
i+=1;
});
Here is a link to the info that helped me get as far as I did: Get the content of another page's div with jQuery Ajax
You can start ajax requests when DOM ready event fired. Because you don't need images and other staffs to begin ajax requests. Also async:true must be help in your situation.
var seat_count = 0;
var i = 0;
var prodLinks = [];
var numSeats = '';
$(document).ready(function() {
$('b.cart-item-name:contains("Palliser")').filter(function(index) {
prodLinks[i] = 'http://xepwk.cjvgn.servertrust.com/'+
$(this).parent('a').attr('href');
$.ajax({
url:prodLinks[i++],
//data:string,
async:true,
success: function(result){
var html = jQuery('<div>').html(result);
var prodInfoArray = html.find('span.PageText_L660n')
.parent('b').parent('td').html().split('<br>');
var numSeats = prodInfoArray[1];
alert(numSeats);
}
});
});
});
Just a thought, Having:
async:false
Loads your ajax-request synchronously and the request has to complete before you can do anything else. Try to change it to true or remove it (it is true by default).

Categories