Safari resends same form after redirect - safari

I am currently experiencing a bug that only occurs in the current version of Safari (5.1.5) and was wondering if anyone here could come up with any workarounds for it. I tested it in 5.1.2 and it worked fine there, I'm not sure about 5.1.3 and 5.1.4 as I don't have access to those releases.
The bug requires three pages, I'll show the source of them and then explain what is going on:
FirstPageWithForm.htm
<form id="theForm" action="ActionHandler.ashx" method="post">
<input type="hidden" name="differentField" value="1234"/>
<input type="hidden" name="sameField" value="1111"/>
</form>
<script type="text/javascript">
var theForm = document.getElementById("theForm");
theForm.submit();
</script>
SecondPageWithForm.htm
<form id="theForm" action="ActionHandler.ashx" method="post">
<input type="hidden" name="differentField" value="5678"/>
<input type="hidden" name="sameField" value="1111"/>
</form>
<script type="text/javascript">
var theForm = document.getElementById("theForm");
theForm.submit();
</script>
ActionHandler.ashx
public void ProcessRequest(HttpContext context)
{
var referrer = context.Request.UrlReferrer;
var differentField = context.Request["differentField"];
context.Response.Write(differentField);
if (differentField == "1234")
{
if (referrer.ToString().Contains("Second"))
context.Response.Write("Failure");
else
{
context.Response.Redirect("SecondPageWithForm.htm");
}
}
else
context.Response.Write("Success");
}
As you notice both forms have the same field name but one of the fields has a different value. However, in Safari when this code is run, the value "1234" is sent as differentField instead of "5678". I do not believe this bug has anything to do with .NET but I don't have an easy way to test another language to be sure about that.
Things I already tried:
Putting the form submission code in a function and then calling that.
Requiring Jquery and calling it in the $(document).ready() function.
Putting the function call in a setTimeout().
Replacing the function with a button that I press.
Copying the Handler and sending the second form to the copy instead.
Every single one of these methods had the same effect, which is to print "Failure" instead of Success.
I will be filing this bug on the Safari forums (I don't have an Apple Developer account and it's not working to create a new one at the moment), but I was hoping that someone could help me come up with a suitable workaround for this problem until they fix it.
EDIT: The Safari forum bug report: https://discussions.apple.com/thread/3921507

NicolasIgot on my safari forum figured out a solution to my problem.
I just added autocomplete="off" to the form tag on the second form and everything started working again. I haven't tried it on my real problem, but it works on my simple test case, so I have confidence in it.

Related

Cypress doesn't find input field (maybe because inside a form?)

Page source (only iFrame part which contains to form i need to fill)
<iframe title="Form 0" id="hs-form-iframe-0" >
#document
<html>
<body>
<form id="hsForm_405e4c3f-98da-4eb1-bd27-c1886a1f811e">
<div>
<label placeholder="Enter your Vorname">Vorname</span>
<div class="input">
<input name="firstname">
</input>
</div>
</div>
</form>
</body>
</html>
</iframe>
Code i tried:
cy.get('#hs-form-iframe-0').its('0.contentDocument').should('exist')
cy.get('input[name="firstname"]').type( 'Smith') //failes as never found. Is the iFrame the cause of it? Of the form?
TLDR The correct way would be to use .find() on the iframe contentWindow.
cy.get('#hs-form-iframe-0').its('0.contentWindow').should('exist')
.its('body').should('not.be.undefined')
.find('input[name="firstname"]').type( 'Smith')
Example from Working with iframes in Cypress
const getIframeWindow = () => {
return cy.get('iframe[data-cy="the-frame"]')
.its('0.contentWindow').should('exist')
.its('body').should('not.be.undefined')
}
cy.getIframeBody().find('#run-button').should('have.text', 'Try it').click()
There are other potential problems, such as delayed loading of the iframe source. The .should('exist') check on the iframe window does not cover all situations, nor does performing visibility checks on the input.
The cypress-iframe package has a lot more checks built in, so it's a safer way to handle iframes.
You have found the iframe and access its contents but then you search for the input at the root of your DOM instead of the iframe. You can continue the chain of commands by removing the second cy.
cy.get('#hs-form-iframe-0')
.its('0.contentDocument')
.should('exist')
.get('input[name="firstname"]')
.should('be.visible') // always good to check before action
.type( 'Smith')

Calling Post method using HTML.ActionLink

I have read multiple posts on similar issue but did not work.
I have fixed footer buttons and facing issue in calling "Post" version Edit action in Project controller. Here is what I'm trying to do
Let me know if question needs further explaination.
(I tried using Ajax.ActionLink which is suggested in multiple posts too but did not work out.
Similar Question
Finally I managed to fix it by some workarounds. Posting solution here to help someone.
Like I said earlier, I tried using Ajax.ActionLink but I was not able to achieve the same. Instead I looked for Calling Form Submit action from outside of form that's what I actually need here.
Form: Name your Form something, say "editProjDetailsForm"
#using (Html.BeginForm(null, null, FormMethod.Post,
new { #class = "form-horizontal",
name = "editProjDetailsForm" }))
Footer: Call this method from the footer button.
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes" />
I tried this one too in footer but it did not workout:
#Ajax.ActionLink("Save Changes", "Edit", new { id = Model.ProjectId },
new AjaxOptions { HttpMethod = "POST" })
Helpful Posts
Naming A form using Begin Form
Submit Button outside HTML.BeginForm
Submit Button outside HTML.BeginForm (another link)
ASP.net ActionLink and POST Method
Error in case you have parameterized constructor in ViewModel and
did not declare parameterless constructor
Display Issue if you are using bootstrap In footer I had one input type = button and one action link with class= button. Both nested in one btn-group but there height were appearing different as visible in following snapshot:
Fix: Found that it is a known issue and there is one suggested solution but did not work out much for me (i.e. for Internet Explorer).
input type=submit and anchor button in btn-group appear as different sizes
Solution: add .btn { line-height:normal!important; } or if you want to do only for a specific button lets say the above input button then do this:
<input type="button" onclick="document.editProjDetailsForm.submit();"
class="btn btn-primary"
value="Save Changes"
style="line-height:normal!important;" />

JavaScript .innerHTMLworking only when called manually

I've got a very simple function, of replacing the innerHTML of a element. I've been trying to debug this for hours but simply can't, and it's infuriating.
When called from a button press the JavaScript (as follows) works well, but when called from another function it doesn't work. I am totally lost as to why this might be, and its a fairly core part of my app
// This loaded function in my actual code is a document listener
// checking for when Cordova is loaded which then calls the loaded function
loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
Button press and HTML to replace
<div id="main">
<input type='button' onclick='changeText()' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
It is also here in full on JSFiddle
You are already changed the innerHTML by calling the function loaded(); on onLoad.
Put this in an empty file and same as .html and open with browser and try. I have commented the function loaded();. Now it will be changed in onclick.
<div id="main">
<input type='button' onclick='changeText();' value='Change Text'/>
<p>Change this text >> <b id='boldStuff'> THIS TEXT</b> </p>
</div>
<script>
//loaded();
function loaded() {
alert("loaded");
changeText();
}
function changeText() {
alert("started");
document.getElementById('boldStuff').innerHTML = 'Fred Flinstone';
}
</script>
The problem here is, that the element you're trying to manipulate is not yet existing when you are calling the changeText() function.
To ensure that the code is only executed after the page has finished loading (and all elements are in place) you can use the onload handler on the body element like this:
<body onload="loaded();">
Additionally you should know, that it's very bad practice to manipulate values by using the innerHTML property. The correct way is to use DOM Manipulations, maybe this can help you.
You script loads before the element (boldStuff) is loaded,
Test Link - 1 - Put the js in a seperate file
Test Link - 2 - put the js at the very end, before closing the <body>

jQuery: Select elements with Incrementing ID names?

and thanks in advance for your help!
Here's my situation: I have a set of divs whose IDs have an incrementing number applied to the end of the name using PHP. Each of these divs are added dynamically with PHP (They are a series of FAQ questions with a hidden div container with the answers, that slide down when the question is clicked.) [Live Example][1]
There is no limit to the number of questions that appear on the page, because this is being used for a Wordpress theme and my client wants to add new questions as they go along.
Here's an example of the structure for each FAQ question using the PHP:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Now this is what I have currently in jQuery, and it works, but only if I add a new one every time my client wants to add a new question.
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$("#faqwrap1 a:not(div.slidebox a)").click(function() {
$("#faqbox1.slidebox").slideToggle('normal');
$('div.slidebox:not(#faqbox1)').slideUp('normal');
return false;
});
});
I thought of maybe doing something with a declared variable, like this:
for (var x = 0; x < 100; x++;) {
$('#[id^=faqwrap]'+ x 'a:not(div.slidebox a)')...
}
I hope this is clear enough for you! Again, I thank you in advance. :)
The best way to handle this is to not use the IDs, but use classes for the outer element. So your PHP would be altered like this:
<?php var $faqnum = 0; $faqnum++; ?>
<div id="faqwrap<?php $faqnum; ?>" class="question">
<h4>What data is shared?</h4>
<div id="faqbox<?php $faqnum; ?>" class="slidebox">
<p>Data sharing is defined by the type of service:</p>
<ul class="list">
<li>Third-party access to data (Enhanced Services only is strictly controlled and determined by the SDA)</li>
<li>All members must participate in points of contact and conjunction assessment but can choose whether to participate in other services</li>
<li>Participation in a service requires the member to provide associated data<br />
</ul>
</div>
</div>
Your JQuery would be rewritten with the selector for the class "question".
$(document).ready(function() {
$('.slidebox*').hide();
// toggles the slidebox on clicking the noted link
$(".question a:not(div.slidebox a)").click(function() {
/* close everything first */
$('div.slidebox').slideUp('normal');
/* selects and opens the the slidebox inside the div */
$(".slidebox", this).slideToggle('normal');
return false;
});
});
This will get you the effect you are looking for. The key differences in the JQuery is the way you get the slidebox inside the question that got clicked. I'm using the scoped selection $(".slidebox", this) to get just the slidebox inside the clicked ".question" element.
The subtle visual difference is that the slideUp() happens before the slideToggle(). This will essentially close any open queries before it opens the desired one. If you keep your animations fast, this will be more than fine. The advantage of this approach is that you don't have to worry about the count of questions on a page, and the selectors are most likely more optimized than the for loop.
Edit
I adjusted the PHP code to use a class for "slidetoggle" instead of an id. It's technically an HTML error to have multiple IDs that are the same. It can throw off some assistive technologies for people with dissabilities. I'm assuming that section of code was repeated several times on the page.
Without changing your current markup, this would work:
// toggles the slidebox on clicking the noted link
$("div[id=^faqwrap]").each(function () {
var $faqwrap= $(this);
$faqwrap.find("h4 > a").click(function () {
var $currentSlidebox = $faqwrap.children(".slidebox");
$currentSlidebox.slideToggle('normal');
$('div.slidebox').not($currentSlidebox).slideUp('normal');
return false;
});
});
Maybe you can find a few suggestions in the above code that help you.
Like #Berin, I'd also recommend giving a separate CSS class to the outer DIV and using that as a selector, instead of $("div[id=^faqwrap]").

Problem with Stripes' submit

I'm currently experiencing a problem with submit button in Stripes. It completely ignores event, that it should call. Actionbean is working on links with no problems... Im stuck on that for like 3 hours.
event in actionbean
#HandlesEvent("addc")
public Resolution addc() {
log.debug("addc() contract={}", contract);
contractFacade.create(contract);
return new RedirectResolution(this.getClass(), "all");
}
jsp:
<s:form beanclass="actionbean.ContractsActionBean">
<%#include file="forms/formContractDetails.jsp"%>
<ul>
<li><s:submit name="addc" class="submit" title="">Add C</s:submit></li>
<li><s:link href="/all">Cancel</s:link></li>
</ul>
</s:form>
Actionbean was #UrlBind-ed on {$event}, changed it to /ab/{$event} and it works now. Probably some interference with index.jsp or something. This is the kind of stuff that will kill me some day. Whole day lost over 4 chars. Hope it will help someone else at least.