Why am I not getting any events for my anchor element? - gwt

For a quite simple element
public static class ToolHtml extends Anchor {
private Long toolId;
public ToolHtml(ToolDetails toolDetails) {
this.toolId = toolDetails.getToolId();
this.setText(toolDetails.getName());
Style style = this.getElement().getStyle();
style.setColor("orange");
this.getElement().setId(DOM.createUniqueId());
}
public Long getToolId() {
return this.toolId;
}
}
I am trying to add some event handlers. I am interested in the DragStartEvent but not even the ClickEvent seems to work and I simply can't figure out why:
public void addOfferItem(ToolHtml toolHtml) {
Set<ToolHtml> toolHtmlSet = this.toolIdToToolHtml.get(toolHtml.getToolId());
if (toolHtmlSet == null) {
toolHtmlSet = new HashSet<>();
this.toolIdToToolHtml.put(toolHtml.getToolId(), toolHtmlSet);
}
toolHtml.getElement().setAttribute("contenteditable", "false");
toolHtml.getElement().setAttribute("draggable", "true");
toolHtml.addBitlessDomHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
LOGGER.fine("Click");
LOGGER.fine("Click");
LOGGER.fine("Click");
}
}, ClickEvent.getType());
toolHtml.addDomHandler((DragStartEvent event) -> {
LOGGER.fine("HANDLER DRAG START");
},
DragStartEvent.getType());
toolHtml.addDomHandler((DragStartEvent event) -> {
LOGGER.fine("DOM DRAG START");
},
DragStartEvent.getType());
toolHtml.addBitlessDomHandler((DragStartEvent event) -> {
LOGGER.fine("DRAG START");
},
DragStartEvent.getType());
toolHtmlSet.add(toolHtml);
// Attach/append to DOM
this.getElement().appendChild(toolHtml.getElement());
}
Does anybody know what the issue is here?

You append an element, not a Widget to which your handlers have been attached. You need to add a widget to a widget for all the functionality to work.
NB: Instead of toolHtml.addBitlessDomHandler you need to use
toolHtml.addClickHandler

Related

CellTable click swallowed

I've an combo box which is composed of a text field and a popup with a CellTable showing the suggestion items. The text field has a change handler that updates the CellTable's selection.
When typing a character and clicking an already selected suggestion, the first click is swallowed. The second click works and triggers the selection via the CellTable.addDomHandler(...).
Any idea why first click is swallowed?
Example code:
private static class SuggestFieldTextAndPopupSandbox extends SimplePanel {
private final TextField mText;
private CellTable<Handle<String>> mTable;
private SingleSelectionModel<Handle<String>> mTableSelection;
private SingleSelectionModel<Handle<String>> mSelection;
private ProvidesKey<Handle<String>> mKeyProvider = new SimpleKeyProvider<Handle<String>>();
private PopupPanel mPopup;
private List<Handle<String>> mData;
public SuggestFieldTextAndPopupSandbox() {
mData = Lists.newArrayList(new Handle<String>("AAA"), new Handle<String>("AAB"), new Handle<String>("ABB"));
mSelection = new SingleSelectionModel<Handle<String>>();
mText = new TextField();
mText.addKeyPressHandler(new KeyPressHandler() {
#Override
public void onKeyPress(KeyPressEvent pEvent) {
mPopup.showRelativeTo(mText);
}
});
mText.addBlurHandler(new BlurHandler() {
#Override
public void onBlur(BlurEvent pEvent) {
mTableSelection.setSelected(startsWith(mText.getValue()), true);
}
});
mText.addChangeHandler(new ChangeHandler() {
#Override
public void onChange(ChangeEvent pEvent) {
mText.setText(mText.getText().toUpperCase());
}
});
mTable = new CellTable<Handle<String>>(0, GWT.<TableResources>create(TableResources.class));
mTable.setTableLayoutFixed(false);
mTableSelection = new SingleSelectionModel<Handle<String>>(mKeyProvider);
mTable.setSelectionModel(mTableSelection);
mTable.addDomHandler(new ClickHandler() {
#Override
public void onClick(final ClickEvent pEvent) {
Scheduler.get().scheduleFinally(new ScheduledCommand() {
#Override
public void execute() {
mSelection.setSelected(mTableSelection.getSelectedObject(), true);
mText.setFocus(true);
mPopup.hide();
}
});
}
}, ClickEvent.getType());
mTable.addColumn(new TextColumn<Handle<String>>() {
#Override
public String getValue(Handle<String> pObject) {
return pObject.get();
}
});
mTable.setRowData(mData);
mPopup = new PopupPanel();
mPopup.setAutoHideEnabled(true);
mPopup.setWidget(mTable);
mPopup.setWidth("200px");
mPopup.setHeight("200px");
VerticalPanel p = new VerticalPanel();
p.add(mText);
setWidget(p);
}
private Handle<String> startsWith(final String pValue) {
final String val = nullToEmpty(pValue).toLowerCase();
int i = 0;
for (Handle<String> item : mData) {
String value = item.get();
if (value != null && value.toLowerCase().startsWith(val)) {
return item;
}
i++;
}
return null;
}
}
I reproduced your issue and here is the problem:
when you click on the suggestions the following is happening:
The text field is loosing focus which causes the corresponding ChangeEvent to be dealt with followed by the BlurEvent.
The click causes the popup to get the focus now which is why it is swallowed.
If you remove the ChangeHandler and the BlurHandler of the text field the issue disappears. But I think I found another solution
Try replacing the DOM handler of the mTable with a selection handler relative to the mTableSelection as follows:
mTableSelection.addSelectionChangeHandler(new Handler(){
#Override
public void onSelectionChange(SelectionChangeEvent event) {
Scheduler.get().scheduleFinally(new ScheduledCommand() {
#Override
public void execute() {
mSelection.setSelected(mTableSelection.getSelectedObject(), true);
mText.setFocus(true);
mPopup.hide();
}
});
}
});
Found a way how to properly solve this.
Skipping the blur handler when user hovers the suggestion list area seemed to fix that issue, at least from the tests that were done didn't see any more issues.
This was necessary because just before the user clicks a suggestion item, the text is blurred and it fires a selection change. This in turn cancels the selection made when user clicks an item.

GWT Drag and Drop File Upload not working

So I have implemented a very simple drag and drop file upload widget. Basically my widget is a vertical panel with a couple of labels and a button inside. The user can either drag file into vertical panel or click button and browse for file.
My problem is that when I drag a file into the vertical panel it fires the DragLeaveEvent every time I drag the item over the space that the labels or button occupies. I want it to know that the item is in the vertical panel even when it is on top of the label or button. Im sure I am missing something simple. I provide the drag functionality by adding these dom handlers to the vertical panel:
addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
System.out.println("drag enter");
highlight(true);
}
}, DragEnterEvent.getType());
addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
System.out.println("drag leave");
highlight(false);
}
}, DragLeaveEvent.getType());
addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
}
}, DragOverEvent.getType());
addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
System.out.println("drop");
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
if (fileUploadHandler != null) {
handleFiles(event.getDataTransfer(), fileUploadHandler);
}
highlight(false);
}
}, DropEvent.getType());
Check that the event target is a child (or grand child) of your panel, or in this case maybe rather whether the event target is exactly your panel's element:
if (verticalPanel.getElement().isOrHasChild(Node.as(event.getNativeEvent().getEventTarget()))) {
// within the panel (possibly on a child)
}
if (verticalPanel.getElement() == Node.as(event.getNativeEvent().getEventTarget())) {
// targetting exactly the panel (e.g. leaving the panel, not one of its children)
}
Through lots of research I have come to the only solution I could find. I set highlight to true in the dragover handler instead of drag enter.
panel.addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
}
}, DragEnterEvent.getType());
panel.addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
highlight(false);
}
}, DragLeaveEvent.getType());
panel.addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
highlight(true);
}
}, DragOverEvent.getType());
panel.addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
handleFiles(event.getDataTransfer());
highlight(false);
}
}, DropEvent.getType());
I copy pasted your code, but also added a:
RootPanel.get().addHandler(dropHandler, DropEvent.getType());
My drophandler looks like this:
DropHandler dropHandler = new DropHandler() {
#Override
public void onDrop(DropEvent event) {
handleFiles(event.getDataTransfer(), new FileUploadHandler() {
#Override
public TYPE specifyFileType() {
return TYPE.BINARY;
}
#Override
public void handleFileContent(String fileName, String fileContent) {
// do stuff with filename and content
}
#Override
public boolean checkFileName(String fileName) {
return true;
}
});
event.preventDefault();
event.stopPropagation();
}
};
and the file-upload interface:
public interface FileUploadHandler {
static public enum TYPE {
TEXT, BINARY, DATAURL
};
// check the filename and extension and return true if you are happy with
// proceeding
// returnning false will prevent the file from being read
boolean checkFileName(String fileName);
// tell the method to use to read this file
TYPE specifyFileType();
// do your stuff here, eg upload to a server
void handleFileContent(String fileName, String fileContent);
}
and the handle files func: (note you will have to change classpath to the FileUploadHandler-interface)
// native method to make use of the HTML5 file API functionality
private final native void handleFiles(JavaScriptObject dataTransfer, FileUploadHandler fileUploadHandler) /*-{
var files = dataTransfer.files;
var i;
var file;
var reader = new FileReader();
for (i = 0; i < files.length; i++) {
file = files[i];
if (fileUploadHandler.#<classpath_to>.FileUploadHandler::checkFileName(Ljava/lang/String;)(file.name)) {
var type = fileUploadHandler.#<classpath_to>.FileUploadHandler::specifyFileType()();
reader.onload = function(e) {
fileUploadHandler.#<classpath_to>.FileUploadHandler::handleFileContent(Ljava/lang/String;Ljava/lang/String;)(file.name, e.target.result);
}
if (type == "TEXT") {
reader.readAsText(file);
} else if (type == "BINARY") {
reader.readAsBinaryString(file);
} else if (type == "DATAURL") {
reader.readAsDataURL(file);
// not supported
} else if (type == "ARRAYBUFFER") {
reader.readAsArrayBuffer(file);
} else {
}
}
}
}-*/;

Fire a (KEY_ENTER) key press event in GWT

What I'm trying to do is fire an enter key press event in GWT.
This is my keyhandler:
itemBox.addKeyDownHandler(new KeyDownHandler() {
public void onKeyDown(KeyDownEvent event) {
if(event.getNativeKeyCode == KeyCodes.KEY_ENTER) {
// do something
}
Then later I wanna fire an enter key press event but I can't seem to figure out how I do this. I wanna do something like KeyDownEvent.setNativeKeyCode(KEY_ENTER).
textBox.fireEvent(new KeyDownEvent(null));
Is it possible to set these parameters?
You can fire the event using DomEvent.fireNativeEvent, instead of textBox.fireEvent.
Here is a working example how to do this:
final TextBox tb = new TextBox();
tb.addKeyDownHandler(new KeyDownHandler() {
#Override
public void onKeyDown(KeyDownEvent event) {
if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
Window.alert("enter!");
}
}
});
Button b = new Button("keyevent");
b.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
DomEvent.fireNativeEvent(Document.get().createKeyDownEvent(false, false, false, false, KeyCodes.KEY_ENTER), tb);
}
});
RootPanel.get().add(tb);
RootPanel.get().add(b);

style for GXT menu button

I see GXT Menu can only be set on CellButtonBase subclasses' instances through setMenu() method.
I'd like to show an image instead of a button and show a menu when user clicks that image. unfortunately, Image is not a subclass of CellButtonBase and thus I can't attach a GXT Menu to it.
so how can I make TextButton (which seems to be my only choice here) look like an image if I have to use it?
There's no documentation or examples on this subject. I asked on Sencha GXT forum support, but got no response.
ok, I found a way to do this without TextButton. add an Image and call menu.show(...) in click handler.
private void createMenu() {
menu = new Menu();
Image menuButtonImage = new Image(Resources.INSTANCE.nav_preferences());
menuButtonImage.addStyleName(CSS.header_bar_icon());
menuButtonImage.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
menu.showAt(getAbsoluteLeft(), getAbsoluteTop() + MENU_OFFSET_FROM_IMAGE_TOP);
}
});
menu.addShowHandler(new ShowEvent.ShowHandler() {
#Override
public void onShow(ShowEvent event) {
highlight();
}
});
menu.addHideHandler(new HideEvent.HideHandler() {
#Override
public void onHide(HideEvent event) {
removeHighlight();
}
});
menu.setStyleName(CSS.menu());
add(menuButtonImage);
}
private void addUserSettings() {
MenuItem userSettingsItem = new MenuItem("User Settings");
userSettingsItem.addSelectionHandler(new SelectionHandler<Item>() {
#Override
public void onSelection(SelectionEvent<Item> event) {
_coreLayout.showUserSettingsPage();
}
});
userSettingsItem.setStyleName(CSS.menu_item());
menu.add(userSettingsItem);
}
private void highlight() {
addStyleName(CSS.header_bar_icon_box_selected());
}
private void removeHighlight() {
removeStyleName(CSS.header_bar_icon_box_selected());
}

GWT : print button

I am trying to create a button that prints the current browser window.
This is my current code, that uses (or at least it tries to use) JSNI:
private Button print = new Button(constants.print(), new ClickHandler() {
#Override
public void onClick(final ClickEvent event) {
/*-{
if ($wnd.print) {
$wnd.print();
return true;
} else {
return false;
}
}-*/
}
});
But when I click the button, nothing happens. It is my first GWT application, so I am not sure about how to implement it.
new Button(constants.print(), new ClickHandler() {
#Override
public void onClick(final ClickEvent event) {
print();
}
private native boolean print( ) /*-{
if ($wnd.print) {
$wnd.print();
return true;
} else {
return false;
}
}-*/; });
Should work! Always place JSNI within a native method.
Since GWT version 1.5, there's a built-in print function:
import com.google.gwt.user.client.Window
public class PrintHandler implements ClickHandler {
public void onClick (ClickEvent event) {
Window.print()
}
}
Here is my 2 cents:
Create a re-usable class:
public class PrintHandler implements ClickHandler {
public void onClick (ClickEvent event) {
print();
}
private native boolean print ()
/*-{
if ($wnd.print) {
$wnd.print();
return true;
} else {
return false;
}
}-*/;
}
And use it anywhere you like:
new Button( constants.print(), new PrintHandler() )