package com.todomvc.client;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import javax.inject.Inject;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.todomvc.client.command.CommandController;
import com.todomvc.client.util.ErrorDialog;
import com.todomvc.shared.model.ToDo;
A view for the ToDoPresenter
.
public class ToDoView extends Composite implements ToDoPresenter.Display {
private static ToDoViewUiBinder uiBinder = GWT.create(ToDoViewUiBinder.class);
interface ToDoViewUiBinder extends UiBinder<Widget, ToDoView> {
}
@UiField
Hyperlink routingAll;
@UiField
Hyperlink routingActive;
@UiField
Hyperlink routingCompleted;
@UiField
TextBoxWithPlaceholder taskText;
@UiField
Element remainingTasksCount;
@UiField
SpanElement remainingTasksLabel;
@UiField
Element mainSection;
@UiField
Element todoStatsContainer;
@UiField
SpanElement clearTasksCount;
@UiField
Button clearCompleted;
@UiField
InputElement toggleAll;
@UiField(provided = true)
CellList<ToDo> todoTable;
Calling add
, remove
or set(int, Object)
in the list wrapped by a ListDataProvider causes any associated Cell widget to re-render. See addDataDisplay()
call below.
private final ListDataProvider<ToDo> displayedToDos;
private final ToDoPresenter presenter;
@Inject
public ToDoView(ToDoPresenter presenter, CommandController commandController) {
this.presenter = checkNotNull(presenter);
checkNotNull(commandController);
displayedToDos = new ListDataProvider<ToDo>();
todoTable = new CellList<ToDo>(new ToDoCell(presenter, commandController));
Changes to displayedToDos
list will be automatically rendered by the cells in todoTable
.
displayedToDos.addDataDisplay(todoTable);
initWidget(uiBinder.createAndBindUi(this));
Removes the yellow highlight.
todoTable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED);
Add IDs to the elements that have ui:field attributes. This is required because the UiBinder does not permit the addition of ID attributes to elements marked with ui:field.
mainSection.setId("main");
clearCompleted.getElement().setId("clear-completed");
taskText.getElement().setId("new-todo");
todoStatsContainer.setId("footer");
toggleAll.setId("toggle-all");
this.presenter.bindView(this);
}
@Override
public ToDoPresenter getPresenter() {
return presenter;
}
@Override
public String getTaskText() {
return taskText.getText();
}
Wire-up the events from the UI to the presenter.
@Override
public void addhandler(final ToDoPresenter.Display.EventHandler handler) {
// The TodoMVC project template has a markup / style that is not compatible with the markup
// generated by the GWT CheckBox control. For this reason, here we are using an InputElement
// directly. As a result, we handle low-level DOM events rather than the GWT higher level
// abstractions, e.g. ClickHandlers. A typical GWT application would not do this, however,
// this nicely illustrates how you can develop GWT applications
// that program directly against the DOM.
final com.google.gwt.dom.client.Element clientToggleElement = toggleAll.cast();
DOM.sinkEvents(clientToggleElement, Event.ONCLICK);
DOM.setEventListener(clientToggleElement, new EventListener() {
@Override
public void onBrowserEvent(Event event) {
handler.markAllCompleted(toggleAll.isChecked());
}
});
taskText.addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
handler.addTask();
}
}
});
clearCompleted.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
handler.clearCompletedTasks();
}
});
}
@Override
public List<ToDo> getDisplayedToDos() {
return displayedToDos.getList();
}
@Override
public void clearTaskText() {
taskText.setText("");
}
@Override
public void setTaskStatistics(int totalTasks, int completedTasks) {
int remainingTasks = totalTasks - completedTasks;
displayOrHide(mainSection, totalTasks);
displayOrHide(todoStatsContainer, totalTasks);
displayOrHide(clearCompleted.getElement(), completedTasks);
remainingTasksCount.setInnerText(Integer.toString(remainingTasks));
remainingTasksLabel.setInnerText(remainingTasks > 1 || remainingTasks == 0 ? "items" : "item");
clearTasksCount.setInnerHTML(Integer.toString(completedTasks));
toggleAll.setChecked(totalTasks == completedTasks);
}
@Override
public void setRouting(ToDoRouting routing) {
selectRoutingHyperlink(routingAll, ToDoRouting.ALL, routing);
selectRoutingHyperlink(routingActive, ToDoRouting.ACTIVE, routing);
selectRoutingHyperlink(routingCompleted, ToDoRouting.COMPLETED, routing);
}
private void selectRoutingHyperlink(Hyperlink hyperlink, ToDoRouting currentRoutingState,
ToDoRouting routingStateToMatch) {
if (currentRoutingState == routingStateToMatch) {
hyperlink.getElement().addClassName("selected");
} else {
hyperlink.getElement().removeClassName("selected");
}
}
@Override
public void showError(String message) {
ErrorDialog errorDialog = new ErrorDialog(message);
errorDialog.show();
}
private void displayOrHide(Element element, int count) {
if (count == 0) {
element.getStyle().setDisplay(Display.NONE);
} else {
element.getStyle().setDisplay(Display.BLOCK);
}
}
}