Orbeon xforms window.onbeforeunload handler - handler

When somebody clicks out of an xform I want to achieve the apperance of a custom alert dialog.(Not the one that the browser uses) that alerts the user and gives him the opportunity to choose if he wants to stay or leave the xforms (cancel/ok buttons)
Here is my trick:
<xf:action ev:event="xforms-ready">
<xxf:script>
window.onbeforeunload = function() {
return ORBEON.xforms.Document.dispatchEvent('fr-form-model','clickout')
}
</xxf:script>
</xf:action>
here is my model and event handler:
<xf:model id="fr-form-model" xxf:expose-xpath-types="true" xxf:external-events="clickout">
<xf:action ev:event="clickout">
<xf:dispatch target="cancel_dialog" name="fr-show"/>
</xf:action>
The dialog appears correctly but it doesn't stay there to give the user the oportunity to choose what to do. After 1-2 seconds the Xform is closed,and the user cannot choose leave or stay.Any idea what's the problem?
............................. UPDATE...................................
Thnx for the answer, at least is there a possibility to use a custom message to the default dialog? (I want the message to be in german language)
Based on this, http://wiki.orbeon.com/forms/how-to/logic/alert-users-leaving-a-form-without-saving
I made this trick:
<xxf:script ev:event="xforms-ready">
window.onbeforeunload = function() {
if (ORBEON.xforms.Document.getValue('datastatus') == 'dirty')
return "Sie haben nicht gespeicherte Ă„nderungen.";
}
</xxf:script>
Above in the model...:
1)
<xf:bind id="data-bind" ref="xxf:instance('fr-persistence-instance')/data-status" name="data" />
2)
xf:action ev:event="xforms-model-construct-done" >
<xf:setvalue ref="xxf:instance('fr-persistence-instance')/data-status">clean</xf:setvalue>
</xf:action>
In the view:
<xf:setvalue ev:event="xforms-value-changed" ref="xxf:instance('fr-persistence-instance')/data-status">dirty</xf:setvalue>
.................................
<xf:output bind="data-bind" id="datastatus" />
In the Ui i can see that the value of the output "datastatus",changes correctly from clean to dirty,but window.onbeforeunload doesn't work.(The popup doesn't appear if I exit the form).Any ideas?Thnx in advance.
.................................LAST UPDATE.................................
There is one cancel button,(that exits the form) and the customer wants this button to trigger the same dialog as the windows.onbeforenull default handler triggers (if there are unsaved changes) and I mean the one that the browser shows.
I tried to to something like this:
<xf:trigger id="cancel-control" bind="cancel-bind">
<xf:label ref="$form-resources/cancel/label" />
<xf:action ev:event="DOMActivate" >
<xxf:script if="($calculationsDisabled eq false()) and ((xxf:instance('fr-persistence-instance')/data-status = 'dirty'))">
function() {return "You may lose some unsaved changes.";}
</xxf:script>
<xxf:script if="($calculationsDisabled eq true()) or ((xxf:instance('fr-persistence-instance')/data-status = 'clean'))">
window.parent.closeIframe();
</xxf:script>
</xf:action>
</xf:trigger>
but it doesn't work too.Please notice that the custom dialog method below:
<xf:trigger id="cancel-control" bind="cancel-bind">
<xf:label ref="$form-resources/cancel/label" />
<xf:action ev:event="DOMActivate">
<xf:dispatch target="cancel_dialog" name="fr-show"
if="($calculationsDisabled eq false()) and ((xxf:instance('fr-persistence-instance')/data-status = 'dirty'))" />
</xf:action>
<xf:action ev:event="DOMActivate" if="($calculationsDisabled eq true()) or ((xxf:instance('fr-persistence-instance')/data-status = 'clean'))" >
<xxf:script>window.parent.closeIframe();</xxf:script>
</xf:action>
</xf:trigger>
works well but the customer doesn't want to have 2 different dialog windows(The alert dialog by the browser and the custom "cancel-dialog").Thnx in advance again.

In this case, you can't use your own dialog. This is because the browser will only stop another page from being loaded, or the tab/window from being closed if your onbeforeunload returns anything other than null or undefined, and when that happens it will show users its own dialog.

Related

Vue: Why is my dialog not showing up when the right condition is set?

EDIT: I answered my own question. I don't know how to mark this as resolved, since SO doesn't allow me to vote my own answer right now. Thanks everyone.
I am trying to create a confirmation box (asking to remove a layout) in which the user has to press confirm or cancel - confirm means 'yes, remove the layout and close the confirmation box', cancel means 'just close the box'.
The confirmation box opens when a user presses RemoveButton - this means that RemoveButton doesn't do the job of "removing" until confirm is pressed. Clicking the RemoveButton should make the dialog to show up.
The problem is the my dialog is not showing up. I ran Chrome dev tool and made sure that setShowRemoveLayoutDialog(true) is working, but removeLayoutDialog is not opening. Even when I set a dev tool breakpoint on public removeLayout(layoutName: string), the dev tool could never reach it.
Can anyone tell me what I am doing wrong?
(We don't have to talk about CSS here since it is already built by my other teammates)
(I cannot do .confirm(confirm message) because it will trigger a no-alert error for lint. So I have to insert it into template and make a div or element for that).
Thank you!
This is my Vue/html template:
<RemoveButton #press="setShowRemoveLayoutDialog(true)">
<removeLayoutDialog v-if="showRemoveLayoutDialog"
:layout-name="props.node.name"
#confirm="removeLayout"
#cancel="setShowRemoveLayoutDialog(false)"/>
</RemoveButton>
This is my <script>:
#Component({
removeLayoutDialog,
...
})
export default class ThisClass {
...
public showRemoveLayoutDialog = false;
public removeLayout(layoutName: string) {
this.doRemoveLayout(layoutName);
this.showRemoveLayoutDialog = false;
}
public setShowRemoveLayoutDialog(isShown: boolean) {
this.showRemoveLayoutDialog = isShown;
}
}
I realized that having the dialog inside the button was the problem.
Instead of having <button ... <dialog></dialog> </button>, having <button><dialog> solved the problem.

Is there anyway to prevent v-dialog from closing?

I'm utilizing <v-dialog> component to display a form for my web app. I want to implement an unsaved changes dialog to popup when the user aborts their changes without saving and either close/keep the dialog open depending on a button press. Unfortunately, I'm having a bunch of trouble figuring out exactly how to prevent the default closing actions done by the framework.
So from what I can tell, you can close a dialog 3 different ways:
Setting the v-model property to false.
Clicking outside of the v-dialog modal unless the persistent prop is set to true.
Pressing the escape key.
Let's not worry about the 2nd way to close the dialog I referenced above and assume it is set to true.
Approach #1:
My first approach was to only allow the user to exit the dialog if they hit a cancel button on the form. I quickly hit a snag when I tried to disable the use of the escape button.
Here's what I have tried so far: In my App.vue mounted function:
mounted () {
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
console.log('The escape key was pressed.')
e.preventDefault()
e.returnValue = false
e.stopImmediatePropagation()
}
})
}
This should work. The log message is displayed in the console, but the dialog still closes after the escape key is pressed. I know I should be using key codes here, but this is for readabilities sake. I've also tried keyup and keypress with no success. There has to be something wonky happening in either the Vue.js or Vuetify framework that's messing this up.
Approach #2:
After I failed miserably trying to disable the escape key, I had to try something different. I tried adding this code inside the watch function to try and keep the dialog open if they cancelled:
dialog (val) {
if (val) {
console.log('Dialog is true')
} else if (!val && !confirm('Unsaved changes, do you still want to exit?')) {
console.log('User Wants to Keep Dialog Open')
this.dialog = true
} else {
console.log('Dialog is False')
this.close()
}
}
When I try and close the dialog, the confirm message pops up, and I hit the cancel button. Then, for some reason, the confirm dialog opens again. So, I hit cancel again, then the dialog dismisses like nothing ever happened. Here's what the console reads:
User Wants to Keep Dialog Open
Dialog is true
User Wants to Keep Dialog Open
Dialog is true
I understand why the dialog watch method is being called again, what I don't understand is why the confirm dialog is showing again. That code should never be executing after cancelling the confirm message the first time. The log message shows that there's no way that code should be executing again. Something must be happening behind the scenes that I don't realize.
Anyone have experience with preventing the v-dialog component from closing? Or any help with my two approaches? Thanks in advance.
It's a property on the dialog:
<v-dialog persistent
That will force them to keep it open unless you call the closure programatically by toggling the model.

Changing input type=text to type=submit with javascript trigger the submit

i'm trying to code form where you can navigate inside with a next button ( who will hide the current fieldset and show the next one ) and a previous one ( who will hide the current fieldset and show the previous one ). Those two input have a onclick function that will change the fieldset className to active from inactive depending on which fieldset we are. I want to change the next button input type when the user reach the final fieldset so he can submit, but it seems that it automatically trigger the submit event, which means when the user get to the final fieldset, he cant fill any input because the form will submit automatically.
So here's the code :
//When the last fieldset show
if (fieldset[4].className == "active") {
var next = document.getElementById('next');
next.onclick='';
next.type="submit";
next.value="Submit";
next.id='submit';
}
Is there something that i should add to stop the submit auto-firing ?
I've tested your code in JSFiddle and it works good. It means there is something that trigger submit. May be you can post whole javascript in that page and then I can check what is the issue.
var next = document.getElementById("next");
//next.type="submit";
next.setAttribute('type', 'submit'); // I prefer using .setAttribute method
next.onclick='';
next.value="Submit";
next.id='submit';
<form>
<input name="q" value="hello">
<input type="text" id="next">
</form>
I think instead of trying to "hack" the existing button and turn it into the submit, you could just have two buttons, one "next" and another one "submit-button" (hidden initially), once the user advances to the final step, you can hide the "next" button and show the "submit-button" button.
It can be something like this:
//When the last fieldset show
if (fieldset[4].className == "active") {
// hide the next button
document.getElementById('next').style.display='none';
// show the submit button
document.getElementById('submit-button').style.display='';
}
And it would be not complex to make these buttons to appear exactly on the same place with css, so the user will not notice the replacement.
There are browsers who do not allow you to change the type for security reasons. So you will often have problems with it. Just switch between two inputs as boris mentioned (or replace it completely). But to answer your question:
You can catch the autosubmit with another on submit event. First on click mark the button with a class or data attribute like "preventSubmit". Within the submit event check if this class or data attribute exists and prevent the submit (f.ex with prevent default()) and remove the class that all wanted submits by users clicks are not stopped.
Why not just add an event to submit the form you are currently on:
if (fieldset[4].className == "active") {
var next = document.getElementById('next');
next.onclick=(function() { document.forms[0].submit(); });
//next.type="submit";
next.value="Submit";
next.className="MySubmit"; // try to style it as a button for better UX
//next.id='submit';
}

XPages: how to create a dialog box with callback to the caller

I have an XPage with 2 custom controls. The 1st custom control has a repeat control and the second is used just as a dialog box.
The user can delete a row from the repeat control by clicking on a delete link. then i use rowVar.getDocument.getNoteID and i delete the document.
What i want is to ask the user first: "are you sure you want to delete it?"
I used "window.confirm()" in CSJS but i dont like the default prompt box. So then i used dojo dialog box but i cant use rowVar of repeat control in it to get the documentId.
Currently i have code in the OK button of the dialog but i want to use OK/Cancel buttons only as a true/false and execute the code in the main custom control. Is there a way of passing the value of the button back to the caller?
I have done this in many ways. Basically, write the information you need to find the document to delete to a viewScope variable. Then create a stand alone event handler that is called from the OK or Cancel buttons of the dialog.
So the eventHandler looks like this post by Jeremey Hodge:
<xp:eventHandler
event="onfubar"
id="eventHandler1"
submit="false">
<xp:this.action><![CDATA[#{javascript:
// write the ssjs to save the doc base on viewScope parameters
}]]></xp:this.action>
</xp:eventHandler>
Then the dialog buttons look something like this (based on the Mastering XPages book and many other sources):
XSP.partialRefreshGet("#{id:eventHandler1}", {
params : {action :"OK" },
onComplete : function () {
// do something else if needed
},
onError : function() {
alert("no soup for you!");
}
});

Setting input focus after tab is clicked

When a page has a search box with multiple tabs, one of the tabs is always selected; either the default tab is selected or the user has changed the tab. In either case the search input box of the selected tab should always have the keyboard focus so the user can just start typing their keywords.
Example: search box on http://www.lib.umd.edu/
Do you know how I could get the focus to be in the input box when a different tab is clicked? I got it to work on the first tab, but when I click another tab, the focus is lost.
The script I am using:
<script type="text/javascript" language="JavaScript">
document.forms[''].elements[''].focus();
</script>
$(document).ready(function () {
setTimeout(function () {
// focus on the txtenclude text area first visible and enabled input field or textarea
$(":input:visible:enabled").each(function () {
if ($(this).is('textarea')) {
$(this).focus();
return false;
}
});
}, 1000);
Your code snippet
To set the focus on a certain element you have to specify which element should receive the focus. In your snippet this specification is missing:
document.forms[''].elements[''].focus();
If you want to you can use this line: document.getElementById("DuringSearch").focus();
DuringSearch is the id of the input element that should receive the focus <input id="DuringSearch" type="text">
The problem that needs to be solved is to change the id based on the tab that was clicked.
There are several ways to achieve this. In a previous post is used an attribte named data-tab.
Example to wire up tabs and focus to input
To attach an event handler to a click on a tab you can do the follwing (using jQuery) on document.ready:
// add event handler for click on tab
$("#tabs li").click(function () {
loadTabs(this);
setFocusOnInput(this);
return false;
});
If you click on a tab the attached event fires and executes the 2 functions: loadTabs and setFocusOnInput.
To set the focus you need to know the id of that input-box. In my exmaple i am using an attribute data-tab
<li data-tab="Before">
Before
</li>
In my example i use the following function:
function setFocusOnInput(_this){
var tab = $(_this).attr("data-tab");
var searchId = tab + "Search"
console.log("_this:", _this);
document.getElementById(searchId).focus();
}
See more explanations on my previous post.
Could you elaborate what you want to know. Do you want to know how to wire it up in general or how to do it in a specific case?