I'm not sure if we are just 20 people in the world using dart right now and maybe just 10% of us try to use widgets..anyway, I seem not to understand if I'm doing something wrong with DWT or there is a bug. Here is a very simple example. I don't understand why the event are not even fired.
void main() {
ui.HorizontalPanel panel = new ui.HorizontalPanel();
ui.ToggleButton t1;
t1= new ui.ToggleButton.fromText("click",handler: new event.ClickHandlerAdapter((event.ClickEvent e) {
hans(panel,t1);
} ));
ui.ToggleButton t3;
t3 = new ui.ToggleButton.fromText("click");
t3.addClickHandler(new event.ClickHandlerAdapter((event.ClickEvent event) {
window.alert("Stop poking me!");
}));
panel.add(t1);
panel.add(t3);
ui.RootLayoutPanel.get().add(panel);
}
void hans(ui.Panel panel,ui.ToggleButton button){
var iter = panel.iterator();
while (iter.moveNext()) {
var butt = iter.current;
if (butt is ui.ToggleButton){
if (butt != button) {
butt.setDown(true);
}
}
}
Not really an answer to your question, but something I've noticed:
Not sure if bug or by design, but seems like the first node of a Tree does not handle clicks properly. I've created a tree with two ui.Label(s) in it and the first ui.Label does not respond to clicks. No aparent reason for that.
If I insert these ui.Label(s) in reversed order the situation is still the same: the first ui.Label (the other ui.Label, this time) does not respond to clicks.
So, I've circumvented the trouble by adding a Label in the beginning as "/" which is absolutely useless but does not need to respond to any clicks anyway.
Related
I have an AjaxButton. The event fires, and I'm testing a scenario where I need to add a feedback and return without committing the change. I add the feedback at the page level (our feedback only shows page level messages...others are showing on component level feedback panels). I add the WebMarkupContainer that contains the feedback panel to the target. This exact thing works on every other button on the page.
But for this button, which happens to be the only one where defaultformprocessing is not false, the feedback doesn't show. To the user's view, nothing happens except our processing veil appears and then disappears. If I hit submit again, THEN the message and feedback are shown. I stuck a timestamp on it to see if it was showing the one from the 2nd request or the 1st. It's from the 1st.
What's more, a breakpoint in the feedback's filter shows that the filter was never called in the 1st request, but is called BEFORE the event processing on the 2nd request. It accepts the message as intended.
I set defaultformprocessing to FALSE on this button as a test, and in fact, messages suddenly work. But of course, that also means the form doesn't get processed. Can someone help me square this circle?
AjaxButton:
add(new AjaxButton("btnCreateRequest", getForm()) {
#Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
//stuff happens
target.add(getFeedbackPanelForAjax());
String date = new Date().toGMTString();
System.out.println("ADDING MESSAGE - " + date);
getPage().error("This is a message! " + date);
return;
}
#Override
public void onError(AjaxRequestTarget target, Form<?> form) {
getPage().error("There was an error processing your request");
target.add(getFeedbackPanelForAjax());
target.add(form);
}
}.setVisible(enabled));
UPDATE:
getFeedbackPanelForAjax returns the web markup container that the feedback resides in. I've also tried adding the feedback directly to the target.
public Component getFeedbackPanelForAjax() {
return (Component) getForm().get("feedbackWmc");
}
Where the feedback is added:
feedback = new FRFeedbackPanel("feedback") {
#Override
public boolean isVisible() {
if(anyMessage()){
return true;
} else {
return false;
}
}
};
// feedback container
WebMarkupContainer feedbackWmc = new WebMarkupContainer("feedbackWmc");
getForm().add(feedbackWmc.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
feedbackWmc.add(feedback.setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
I can say that through debugging, I put a breakpoint in anyMessage() and it returns false in this case at the same time that getPage().getFeedbackMessages() returns the message correctly. I commented out this override of isVisible() and indeed, the message shows. The problem is, that it means the artifacts of the feedback panel show when there are no messages as well, which is not what we want.
This anyMessage() solution works perfectly when I'm in an event that is defaultformprocessing=false. I suppose I could do an anyMessage() || getPage().getFeedbackMessages(), but my understanding was that anyMessage was supposed to find if there was ANY message in the hierarchy for this panel. Is that not so?
I assume you cannot replicate the problem in a small quickstart?
One idea: I've seen similar problems when the FeedbackPanel collects its messages too early, i.e. before you add the error to the page.
FeedbackMessagesModel keeps the messages to render until the end of the request - maybe some of your code triggers this by accessing the messages model.
It seems that if Find.Execute finds a result inside a ContentControl, it will cause the ContentControlOnEnter and ContentControlOnExit events to fire. It's particularly annoying because the exit event fires even if the selection is still in the content control, so any code which sets the states of buttons dependent upon a content control being active will appear to be in the incorrect state.
Given a document containing a single content control with the word "test", and the following code:
// In setup
Application.ActiveDocument.ContentControlOnEnter += ActiveDocument_ContentControlOnEnter;
private void ActiveDocument_ContentControlOnEnter(Word.ContentControl ContentControl)
{
var selRange = _Application.Selection.Range;
_logger.Debug(m => m("Selection: {0}-{1}", selRange.Start, selRange.End));
}
//Later in another method
var finder = _Application.ActiveDocument.Range().Find;
_logger.Debug("Find.Execute start");
finder.Execute("test);
_logger.Debug("Find.Execute end");
The following gets logged:
38137 [VSTA_Main] DEBUG - Find.Execute start
38141 [VSTA_Main] DEBUG - Selection: 1-5
38149 [VSTA_Main] DEBUG - Find.Execute end
We have a lot of code that handles ContentControlOnEnter and ContentControlOnExit events, and having the find operation cause them to be called is really causing problems!
Is there any way to use Find.Execute without having it trigger these events? Failing that, is there a good way to distinguish between the Find-triggered ones and the genuine user ones? I have tried using the time between the enter and exit events, but this is not reliable.
I had similar problems in Word, though it was about the Selection event. I tried many solutions, but only one helped. In your case, make a new field bool _skipEnterAndExitEvents and set it true before calling
finder.Execute("test) and false after calling. And in the enter and exit event handlers check this field, if the field is true then just skip. This solutions is not beautiful, looks like a hack, but other solutions are even uglier and don't really work.
I think I found a decent solution:
private bool _doIgnoreNextExit = false;
private void ActiveDocument_ContentControlOnEnter(Word.ContentControl ContentControl)
{
if (Application.Selection.Find.Found)
{
_logger.Debug("Ignoring CC enter event caused by Find operation");
_doIgnoreNextExit = true;
return;
}
// Do things
}
private void ActiveDocument_ContentControlOnExit(Word.ContentControl ContentControl)
{
if(_doIgnoreNextExit)
{
_logger.Debug("Ignoring fake exit");
_doIgnoreNextExit = false;
return;
}
// Do things
}
here is the part of code:
val lsv_syns = new ListView[String]()
val scp_syns = new ScrollPane() {
listenTo(lsv_syns.mouse.moves,lsv_syns.selection)
reactions += {
case me: MouseExited => {
txf_mot.requestFocus()
}
case SelectionChanged(`lsv_syns`)=> {
println("sélection:"+lsv_syns.selection.items(0))
}
}
}
As you can see, the listView is in a scrollPane; don't pay attention to the mouseExited event, the interesting thing is the selectionChanged, which seems to be called twice when I only click on time on an other line, because the println is called two times.
thanks.
Well i also recently worked with a ListView and now that you mentioned it, it also does my calculation twice.
The answer seems to be related to mouse events. Following the stack trace SelectionChanged is called twice. One coming from the Java event MousePressed and one from MouseReleased.
When you change the selection with KeyEvents it is only called once.
My first (and I guess not nice) idea to avoid the problem would be to ignore one of the events:
reactions += {
case SelectionChanged(`lsv_syns`) if !lsv_syns.selection.adjusting => {
println("sélection:"+lsv_syns.selection.items(0))
}
}
Both ListSelection events share the same data except getValueIsAdjusting. So if you check for it you can avoid doing your stuff twice.
Warning: !lsv_syns.selection.adjusting will result in printing on key release and not on press!
If you put lsv_syns.selection.adjusting it will correspond to key press but it will also filter key events. As I said. Not nice at all...
I want to set a minimum and a maximum zoom level in my map.
My first idea was to listen to 'zoomstart' events, but the org.gwtopenmaps.openlayers.client.Map class doesn't implement any listener with such event type. Then I tried to listen to 'zoomend' events. My idea was to check the zoomlevel after the zoom event and if it is higher/lower than a threshold value than i zoom to that threshold value. Example code:
#Override
public void onMapZoom(MapZoomEvent eventObject) {
if (eventObject.getSource().getZoom() > 18) {
eventObject.getSource().zoomTo(18);
}
}
But i found, the zoomTo event doesn't fire in this case. Has anybody got a solution to this problem?
Great idea Imreking.
I have added this to the GWT-Openlayers library.
So if you download the latest version from github now you can do :
map.setMinMaxZoomLevel(6, 8);
And you no longer need some javascript method in your own code.
I actually also added a showcase but having difficulties uploading it to our website.
Uploading the new showcase has now succeeded.
See http://demo.gwt-openlayers.org/gwt_ol_showcase/GwtOpenLayersShowcase.html?example=Min%20max%20zoom%20example to see an example of newly added Map.setMinMaxZoomLevel(minZoom, maxZoom).
I don't think this is possible in OpenLayers (normal and GWT).
According to me two solutions are available.
Option 1
This is ugly for the user. As he sees the map getting zoomed, and just after this going back to the previous zoomlevel.
The Timer is needed to give OL the chance to animate the zoom.
map.addMapZoomListener(new MapZoomListener()
{
#Override
public void onMapZoom(final MapZoomEvent eventObject)
{
Timer t = new Timer()
{
#Override
public void run()
{
if (eventObject.getSource().getZoom() > 15)
{
map.zoomTo(15);
}
else if (eventObject.getSource().getZoom() < 10)
{
map.zoomTo(10);
}
}
};
t.schedule(500);
}
});
Option 2
Don't use the zoom default zoom control but create your own zoom buttons (using normal GWT), and putting these on top of the map. If you want you can style these buttons in the same way as the normal buttons. The trick 'create in normal GWT, and make it look like OL' is a trick I use a lot (for example to create a much more advanced layer switcher).
Note : I am one of the developers of GWT-OpenLayers, if you want I can add an example to our showcase displaying how to do 'Option 2'.
Knarf, thank you for your reply. I tried the 'Option 1' and it worked, but i found another solution which is maybe more acceptable for the users.
My solution is:
map.isValidZoomLevel = function(zoomLevel) {
return ((zoomLevel != null) &&
(zoomLevel >= minZoomLevel) &&
(zoomLevel <= maxZoomLevel) &&
(zoomLevel < this.getNumZoomLevels()));
}
I overrode the isValidZoomLevel method. The minZoomLevel and maxZoomLevel variables were set when the application started. I don't like calling javascript from GWT code, but here i didn't have any other opportunity.
I want to block scrolling page "out of the iPhone screen" (when gray Safari's background behind the page border is visible). To do this, I'm cancelling touchmove event:
// Disables scrolling the page out of the screen.
function DisableTouchScrolling()
{
document.addEventListener("touchmove", function TouchHandler(e) { e.preventDefault(); }, true);
}
Unfortunately, this also disables mousemove event: when I tap on a button then move my finger out of it, then release the screen, the button's onclick event is triggered anyway.
I've tried mapping touch events on mouse events, as desribed here: http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/, but to no avail (the same behavior).
Any ideas?
From what I understand of your question, you've attempted to combine the code you've presented above with the code snippet provided by Ross Boucher on Posterous. Attempting to combine these two snippets back-to-back won't work, because in disabling touchmove, you've also disabled the shim that allows mousemove to work via his sample.
This question and its answers sketch out a workable solution to your problem. You should try these two snippets to see if they resolve your issue:
This snippet, which disables the old scrolling behavior:
elementYouWantToScroll.ontouchmove = function(e) {
e.stopPropagation();
};
Or this one, from the same:
document.ontouchmove = function(e) {
var target = e.currentTarget;
while(target) {
if(checkIfElementShouldScroll(target))
return;
target = target.parentNode;
}
e.preventDefault();
};
Then, drop in the code on Posterous:
function touchHandler(event)
{
var touches = event.changedTouches,
first = touches[0],
type = "";
switch(event.type)
{
case "touchstart": type = "mousedown"; break;
case "touchmove": type="mousemove"; break;
case "touchend": type="mouseup"; break;
default: return;
}
//initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
And that should do it for you. If it doesn't, something else isn't working with Mobile Safari.
Unfortunately I haven't had the time to check out to above yet but was working on an identical problem and found that the nesting of elements in the DOM and which relation you apply it to affects the handler a lot (guess the above solves that, too - 'var target = e.currentTarget').
I used a slightly different approach (I'd love feedback on) by basically using a class "locked" that I assign to every element which (including all its children) i don't want the site to scroll when someone touchmoves on it.
E.g. in HTML:
<header class="locked">...</header>
<div id="content">...</div>
<footer class="locked"></div>
Then I have an event-listener running on that class (excuse my lazy jquery-selector):
$('.ubq_locked').on('touchmove', function(e) {
e.preventDefault();
});
This works pretty well for me on iOs and Android and at least gives me the control to not attach the listener to an element which I know causes problems. You do need to watch your z-index values by the way.
Plus I only attach the listener if it is a touch-device, e.g. like this:
function has_touch() {
var isTouchPad = (/hp-tablet/gi).test(navigator.appVersion);
return 'ontouchstart' in window && !isTouchPad;
}
This way non-touch devices will not be affected.
If you don't want to spam your HTML you could of course just write the selectors into an array and run through those ontouchmove, but I would expect that to be more costly in terms of performance (my knowledge there is limited though). Hope this can help.