I feel like I'm doing something rediculously stupid here, but I've been banging my head against the wall all day, and don't seem to be making any progress! I have this function:
def init_create_reports(self, msg):
if not common.create_report_in_progress and len(common.tracks_selected_for_report) > 0:
common.create_report_in_progress = True
return jp.redirect('/yeeha')
That is called when the user clicks a button. Stepping through it, everything works fine until the redirect function, which seems to fire from within justPy, but then I get nothing. It never redirects to the '/yeeha' route. It seems simple enough according to the godawful justPy documentation, but agaghhhhh!
I've also tried passing the redirect the current webpage: wp.redirect('/yeeha') with the same outcome. Honestly all I need is to set that variable and navigate to another page, and at this point I'm prepared to just do it from a tag.
It seems that there is currently a problem in Justpy with the handling of the event_result of an event callback function. I opened an issue for this problem. See https://github.com/justpy-org/justpy/issues/657
Alternatively to jp.redirect() you can also set the redirect attribute of the webpage.
In your example it would be:
def init_create_reports(self, msg):
if not common.create_report_in_progress and len(common.tracks_selected_for_report) > 0:
common.create_report_in_progress = True
msg.page.redirect = '/yeeha'
Here is a complete example showing a redirect from one justpy webpage to another route:
import justpy as jp
def hello_function() -> jp.WebPage:
wp = jp.WebPage()
jp.P(a=wp, text='Hello there!', classes='text-5xl m-2')
jp.Button(
a=wp,
text="redirect",
on_click=handle_click,
classes="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
)
return wp
def handle_click(self, msg):
"""
handle redirect button click
Args:
self: justpy component that triggered the event
msg: event message
"""
wp = msg.page
wp.redirect = "/bye"
def bye_function() -> jp.WebPage:
wp = jp.WebPage()
wp.add(jp.P(text='Goodbye!', classes='text-5xl m-2'))
return wp
jp.Route('/bye', bye_function)
jp.justpy(hello_function)
See also Login Example
Related
How can i handle alerts and popups in playwright-java?
there are different methods in API like page.onDialog(), page.onPopup(), what is the difference between them and how can i generate a handle?
//code to launch my browser and url
Playwright playwright = Playwright.create();
Browser browser = playwright.chromium().launch(new LaunchOptions().withHeadless(false).withSlowMo(50));
BrowserContext context = browser.newContext();
Page page = context.newPage();
page.navigate("http://myurl.com");
//had to switch to iframe to click on upload button
Frame mypage = page.frameByName("uploadScreenPage");
//below line is triggering the alert
mypage.setInputFiles("//*[#id='fileUpload']",Path.of("C:\\myFile.jar"));
//using this code to handle alert, which is not working
page.onDialog(dialog -> {dialog.accept();});
unable to accept alert using the above code. also alert has occurred after clicking an element that is inside an iframe. how can i handle such alerts?
Dialogs are messages like an alert or a confirm, whereas popups are new pages, like the one you would get by calling window.open.
This is how you can use it :
page.onDialog(dialog -> {
assertEquals("alert", dialog.type());
assertEquals("", dialog.defaultValue());
assertEquals("yo", dialog.message());
dialog.accept();
});
page.evaluate("alert('yo')");
I am happy to answer this question. I encountered the same situation and find the solution. Please see below:
//Handling Pop-up or new page
Page pgdriver1 = pagedriver.waitForPopup(new Runnable()
{
public void run() {
pagedriver.click("text=\"Analiza\"");
}
});
pgdriver1.click("//button[normalize-space(#aria-label)=\"Close dialog\"]/nx-icon");
I hope this answer your question.
//listening to the alert
page.onDialog(dialog -> {dialog.accept();});
//next line will be action that triggers your alert
page.click("//['clickonsomethingthatopensalert']")
MouseEvent.target returns an EventTarget instead of a HTMLElement when clicked inside an iframe, in ScalaJs.
src/main/scala/tutorial/webapp/TutorialApp.scala:
package tutorial.webapp
import org.scalajs.dom._
import org.scalajs.dom.raw._
import scala.scalajs.js
object TutorialApp {
def main(args: Array[String]): Unit = {
window.document.body.innerHTML = "<p><b>main window</b></p>"
val iframe = document.createElement("iframe")
document.body.appendChild(iframe)
val iframeWindow = iframe.asInstanceOf[HTMLIFrameElement].contentWindow
iframeWindow.document.body.innerHTML = "<p><b>iframe</b></p>"
window.document.addEventListener("click", clicked)
// this works as expected:
// clicking on the 'main window' text, produces this console log:
// - clicked an HTMLElement B
// - parent is an HTMLParagraphElement P
iframeWindow.document.addEventListener("click", clicked) // this doesn't
// this does not work as expected:
// clicking on the 'iframe' text, produces this console log:
// - clicked an EventTarget B
// - parent is an HTMLElement P
}
def clicked(mouseEvent: MouseEvent) {
mouseEvent.target match {
case e: HTMLElement => console.log("clicked an HTMLElement", e.asInstanceOf[HTMLElement].tagName)
case e: EventTarget => console.log("clicked an EventTarget", e.asInstanceOf[HTMLElement].tagName)
}
val parent = mouseEvent.target.asInstanceOf[HTMLParagraphElement].parentElement
parent match {
case e: HTMLParagraphElement => console.log("parent is an HTMLParagraphElement", e.asInstanceOf[HTMLElement].tagName)
case e: HTMLElement => console.log("parent is an HTMLElement", e.asInstanceOf[HTMLElement].tagName)
}
}
}
index.html
<html>
<body>
<!-- Include Scala.js compiled code -->
<script type="text/javascript" src="./target/scala-2.12/scala-js-tutorial-fastopt.js"></script>
</body>
</html>
When I click inside the iframe on the <h1>iframe</h1>, I get an EventTarget instead of an HTMLElement. Casting it to HTMLElement works, but e.parentElement is an HTMLElement instead of HTMLParagraphElement.
Why and how to solve it?
Hoping someone will provide a more precise answer, but in the absence of that:
Iframes are typically loaded from other URLs, often from another origin, and their security model reflects that primary use case – the document inside the iframe is quite isolated from the parent document. I'm not quite sure which exact restriction you're hitting though as manually creating iframes like in your example is not very common.
Usually, the Javascript code running inside the iframe needs to be willing to communicate with Javascript code running in the parent window. Currently in your example you only have code running in the parent window, as the iframe itself does not load any scripts.
Depending on your exact use case, there are several ways to achieve this. For example, you could post custom events to the parent window as described in How to communicate between iframe and the parent site?
Iframes can be really annoying if you don't want the isolation that they come with.
I am using the protractor framework. I'd like to write a test checking if User 1 successfully sends message to User 2. Both users should be logged in at 2 different browsers. So, what i want to do is:
it("Test", () => {
let browser2 = browser.forkNewDriverInstance(true);
browser2.Chat.icon.click();
This way i want to click the element icon in the class Chat, which looks like:
export class Chat{
public static icon: p.ElementFinder = element(by.css("#popup > div > div > div > section > header > a"));
}
When i try do do that, the following error appear: Property Chat does not exist on type Protractor
How can i access the elements in the classes from browser2?
So, browser2 in your example is a completely new instance of the browser. The elements on the Chat property are still attached to the initial browser instance (browser). What worked for me is creating a module for switching browser (and element, by, etc.) contexts. The second answer here helped me greatly in creating that library: Multiple browsers and the Page Object pattern
I'm using the page object pattern, so what I had to do was re-instantiate new page objects after I forked the new driver instance. So it ended up something like this (Javascript).
var Loginpage = require('../loginPage.js);
var loginPage = new LoginPage();
it('user1 logs in, sends message to user2' () => {
loginPage.login()
//send your message
});
it('user2 logs in and looks for message' () => {
browser.forkNewDriverInstance(true);
var newBrowserLoginPage = new LoginPage();
newBrowserLoginPage.login()
var newBrowserNotificationsPage = new UserNotificationsPage();
newBrowserNotificationsPage.checkMessages();
});
So, I suggest building the small library for switching browser contexts (and therefore element, by, protractor, etc. contexts).
Presently, a messagebox appears with the failing class name:
Is it possible to override the default behavior in Alfresco? Could we use forms service to present a different message ?
Additional to zladuric answer,
you can use failureCallback method to show message what you want.
But it is difficult to search failureCallback method of workflow forms for a new one because workflow forms such as "Start Workflow", "Task Edit", "Task Detail" are used form engine.
For example, in "Start Workflow" form, you can add our own successCallBack and failureCallBack by writing onBeforeFormRuntimeInit event handler in start-workflow.js like this.
onBeforeFormRuntimeInit: function StartWorkflow_onBeforeFormRuntimeInit(layer, args)
{
var startWorkflowForm = Dom.get(this.generateId + "-form");
Event.addListener(startWorkflowForm, "submit", this._submitInvoked, this);
args[1].runtime.setAJAXSubmit(true,
{
successCallback:
{
fn: this.onFormSubmitSuccess,
scope: this
},
failureCallback:
{
fn: this.onFormSubmitFailure,
scope: this
}
});
}
onFormSubmitSuccess: function StartWorkflow_onFormSubmitSuccess(response)
{
this.navigateForward(true);
// Show your success message or do something.
}
onFormSubmitFailure: function StartWorkflow_onFormSubmitFailure(response)
{
var msgTitle = this.msg(this.options.failureMessageKey);
var msgBody = this.msg(this.options.failureMessageKey);
// example of showing processing response message
// you can write your own logic
if (response.json && response.json.message)
{
if(response.json.message.indexOf("ConcurrencyFailureException") != -1)
{
msgTitle = this.msg("message.concurrencyFailure");
msgBody = this.msg("message.startedAgain");
}
else
msgBody = response.json.message;
}
Alfresco.util.PopupManager.displayPrompt(
{
title: msgTitle,
text: msgBody
});
}
Since Alfresco.component.StartWorkflow(in start-workflow.js) extends Alfresco.component.ShareFormManager(in alfresco.js). You can override onBeforeFormRuntimeInit event in start-workflow.js. I hope this your help you.
I'm not looking at the code right now, but this looks like a regular YUI dialog. So it's fired by YUI. So this YUI is client side, probably in My-tasks dashlet or my tasks page.
Furthermore, the error message looks like it is a status.message from the failed backend message/service.
You could probably locate that client-side javascript file, find the method that starts the task and see what its' failureCallback handler is. Then edit that failureCallback method and make it show something different then the response.status.message or whatever it is. Perhaps something like this.msg("message.my-custom-error-message"); which you then customize on your own.
Modifying YUI dialog scripts will might affect the other functionalities as well.
If we customize start-workflow. js, its only going to be achieved in start workflow form.
So as generic solution, below is the suggestion.
When alfresco is rendering the workflow form , it is rendering the transition button using the activiti-transition.js file.Basically this buttons are doing nothing more but submitting the workflow form.
So the best way would be , customizing this activiti-transition.ftl and activiti-transition.js file , to make an ajax call and handle the response as we want.
I just had a look on full flow of how this front end error is shown.
activiti-transition is submiting the workflow form.
Using a function named as submitForm which resides inside alfresco.js, it is invoking an submit event of form
Inside the forms-runtime.js file there is one function named as _submitInvoked(handles the submit event of form), which is responsible for making an ajax call and submitting the workflow form.If there is error while submitting , it will display the error which is from backend.
Coming from this question, I have a wxComboCtrl with a custom popup made of a panel with a bunch of radiobuttons.. My problem is that when I open the popup the combo doesn't get keystrokes, because the events get handled by the panel itself.. I'd like to redirect those KeyEvents to the textctrl of the combo, but I can't find a way to get it to work :/
Am I going the wrong way? Should I manually handle the textctrl value as the user presses keys? I think that would be a bit cumbersome though.. Since supposedly the textctrl already knows how to handle those events..
Here's my testcase (wxPython 2.8 on Linux), the "on_key" method should be the culprit:
import wx
import wx.combo
class CustomPopup(wx.combo.ComboPopup):
def Create(self, parent):
# Create the popup with a bunch of radiobuttons
self.panel = wx.Panel(parent)
sizer = wx.GridSizer(cols=2)
for x in range(10):
r = wx.RadioButton(self.panel, label="Element "+str(x))
r.Bind(wx.EVT_RADIOBUTTON, self.on_selection)
sizer.Add(r)
self.panel.SetSizer(sizer)
# Handle keyevents
self.panel.Bind(wx.EVT_KEY_UP, self.on_key)
def GetControl(self):
return self.panel
def GetAdjustedSize(self, minWidth, prefHeight, maxHeight):
return wx.Size(200, 150)
def on_key(self, evt):
if evt.GetEventObject() is self.panel:
# Trying to redirect the key event to the combo.. But this always returns false :(
print self.GetCombo().GetTextCtrl().GetEventHandler().ProcessEvent(evt)
evt.Skip()
def on_selection(self, evt):
self.Dismiss()
wx.MessageBox("Selection made")
class CustomFrame(wx.Frame):
def __init__(self):
# Toolbar-shaped frame with a ComboCtrl
wx.Frame.__init__(self, None, -1, "Test", size=(800,50))
combo = wx.combo.ComboCtrl(self)
popup = CustomPopup()
combo.SetPopupControl(popup)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(combo, 0)
self.SetSizer(sizer)
self.Layout()
if __name__ == '__main__':
app = wx.PySimpleApp()
CustomFrame().Show()
app.MainLoop()
Edit:
I found these (unresolved) discussions on the same topic..
"ComboCtrl loses keyboard focus when ComboPopup is shown "
"issue using wx.ComboCtrl"
I had the same problem with a custom ComboPopup control using a panel as the basis of the control.
EmulateKeypress just entered a never-ending loop. I found binding the panel to the EVT_KEY_DOWN and EVT_CHAR to the overridden OnComboKeyEvent function and skipping the event down the event handling chain was all that was required to enable entering text into the textbox of the ComboCtrl with the popup open. I think this makes sense. As the Popup isn't strictly a control its events won't belong anywhere until bound into the the wx.app event loop through the Bind() method.
I've included the overridden OnComboKeyEvent function below so that anyone else can explore this problem.
def create(self, *args, **kwds):
...
self.panel.Bind(wx.EVT_CHAR, self.OnComboKeyEvent)
self.panel.Bind(wx.EVT_KEY_DOWN, self.OnComboKeyEvent)
...
def OnComboKeyEvent(self, evt):
evt_dict = {wx.EVT_TEXT.typeId: "TextEvent",
wx.EVT_CHAR.typeId:"CharEvent",
wx.EVT_CHAR_HOOK.typeId:"CharHookEvent",
wx.EVT_KEY_UP.typeId:"KeyUpEvent",
wx.EVT_KEY_DOWN.typeId:"KeyDownEvent"}
if evt.GetEventType() in evt_dict:
thelogger.debug("oncombokeyevet:%s" % evt_dict[evt.GetEventType()])
super().OnComboKeyEvent(evt)
evt.Skip()
I've got an answer from Robin Dunn himself on wxpython-users:
Sending low-level events to native
widgets like this does not work the
way that most people expect it to.
You are expecting this to result in
the character being added to the text
ctrl,but it can't do that because all
that ProcessEvent does is send the
wx.Event to any bound event handlers
and then it stops. It does not go to
the next step and convert that event
to the equivalent native message and
send it on to the native widget. See
the "Simulating keyboard events"
thread.
It doesn't work especially well on
non-Windows platforms, but you could
try calling EmulateKeypress instead.