// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.ui;
import com.google.collide.client.common.BaseResources.Resources;
import com.google.collide.client.util.CssUtils;
import com.google.collide.client.util.Elements;
import com.google.collide.json.shared.JsonArray;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.events.MouseEvent;
import elemental.html.Element;
import elemental.html.HTMLCollection;
import elemental.js.html.JsElement;
/**
* An object which manages a list of elements and treats them as tabs.
*/
public class TabController<T> {
/**
* Creates a TabController for a list of elements.
*/
public static <T> TabController<T> create(Resources res, TabClickedListener<T> listener,
Element tabContainer, JsonArray<TabElement<T>> headers) {
TabController<T> controller = new TabController<T>(res, listener, tabContainer);
// Create the tab headers
for (int i = 0; i < headers.size(); i++) {
TabElement<T> element = headers.get(i);
if (controller.activeTab == null) {
controller.setActiveTab(element);
}
tabContainer.appendChild(element);
}
return controller;
}
public interface TabClickedListener<T> {
public void onTabClicked(TabElement<T> element);
}
/**
* An javascript overlay which encapsulates the tab identifier associated with
* each tab header.
*/
public static class TabElement<T> extends JsElement {
/**
* Creates a tab element from an element and data.
*/
public static <T> TabElement<T> create(Resources res, String label, T data) {
@SuppressWarnings("unchecked")
TabElement<T> element = (TabElement<T>) Elements.createDivElement(res.baseCss().tab());
element.setTextContent(label);
element.setTabData(data);
return element;
}
protected TabElement() {
// javascript overlay
}
public final native void setTabData(T data) /*-{
this.__tabData = data;
}-*/;
public final native T getTabData() /*-{
return this.__tabData;
}-*/;
}
private final Resources res;
private final TabClickedListener<T> listener;
private final Element container;
private TabElement<T> activeTab;
private TabController(Resources res, TabClickedListener<T> listener, Element container) {
this.container = container;
this.res = res;
this.listener = listener;
attachHandlers();
}
private void attachHandlers() {
container.addEventListener(Event.CLICK, new EventListener() {
@Override
public void handleEvent(Event evt) {
MouseEvent event = (MouseEvent) evt;
// we could really just use the event target but this is for future
// expandability I guess.
Element element = CssUtils.getAncestorOrSelfWithClassName(
(Element) event.getTarget(), res.baseCss().tab());
if (element != null) {
@SuppressWarnings("unchecked")
TabElement<T> tabElement = (TabElement<T>) element;
selectTab(tabElement);
}
}
}, false);
}
/**
* Selects the supplied tab dispatching the listeners clicked event.
*/
public void selectTab(TabElement<T> element) {
if (activeTab == element) {
return;
}
setActiveTab(element);
listener.onTabClicked(element);
}
public T getActiveTab() {
return activeTab.getTabData();
}
/**
* Sets the active tab based on the provided tab data without dispatching the
* listeners clicked event.
*/
public boolean setActiveTab(T tab) {
if (getActiveTab() == tab) {
return true;
}
HTMLCollection nodes = container.getChildren();
for (int i = 0; i < nodes.getLength(); i++) {
@SuppressWarnings("unchecked")
TabElement<T> element = (TabElement<T>) nodes.item(i);
if (element.getTabData().equals(tab)) {
setActiveTab(element);
return true;
}
}
return false;
}
/**
* Sets the active tab without triggering the {@link TabClickedListener}
* callback.
*/
private void setActiveTab(TabElement<T> element) {
if (activeTab != null) {
activeTab.removeClassName(res.baseCss().activeTab());
}
element.addClassName(res.baseCss().activeTab());
activeTab = element;
}
}