package com.codename1.ui.html;
import com.codename1.ui.Button;
import com.codename1.ui.CheckBox;
import com.codename1.ui.Component;
import com.codename1.ui.List;
import com.codename1.ui.RadioButton;
import com.codename1.ui.TextArea;
import com.codename1.ui.TextField;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.events.DataChangedListener;
import com.codename1.ui.events.FocusListener;
import com.codename1.ui.events.SelectionListener;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* This class serves as a aggregator of all the event listeners for all the active components within the HTML page.
* It is in itself an ActionListener and a FocusListener, and it creates SelectionListeners and DataChangedListeners if needed.
* Upon events it both updates the DOM if needed, and dispatches event methods on HTMLCallback
*
* @author Ofir Leitner
*/
class HTMLEventsListener implements ActionListener,FocusListener {
Hashtable comps = new Hashtable();
Hashtable listeners = new Hashtable();
HTMLComponent htmlC;
public HTMLEventsListener(HTMLComponent htmlC) {
this.htmlC=htmlC;
}
/**
* Registeres the specified component/element duo to listen to all available events
*
* @param cmp The actual component
* @param element The element representing the component
*/
void registerComponent(final Component cmp,final HTMLElement element) {
comps.put(cmp, element);
cmp.addFocusListener(this);
if (cmp instanceof Button) { // catches Button, CheckBox, RadioButton
((Button)cmp).addActionListener(this);
} else if (cmp instanceof List) { // catches ComboBox
final List list = (List)cmp;
list.addActionListener(this);
SelectionListener sl = new SelectionListener() { // We create a listener and not listen ourself since the listener's method does not pass the event origin, so we need to make one listener per component
public void selectionChanged(int oldSelected, int newSelected) {
if (htmlC.getHTMLCallback()!=null) {
htmlC.getHTMLCallback().selectionChanged(oldSelected, newSelected, htmlC, list, element);
}
}
};
list.addSelectionListener(sl);
listeners.put(cmp, sl);
} else if (cmp instanceof TextArea) {
((TextArea)cmp).addActionListener(this);
if (cmp instanceof TextField) {
final TextField tf = (TextField)cmp;
DataChangedListener dcl = new DataChangedListener() { // We create a listener and not listen ourself since the listener's method does not pass the event origin, so we need to make one listener per component
public void dataChanged(int type, int index) {
element.setAttributeById(HTMLElement.ATTR_VALUE, tf.getText());
if (htmlC.getHTMLCallback()!=null) {
htmlC.getHTMLCallback().dataChanged(type, index, htmlC, tf, element);
}
}
};
tf.addDataChangedListener(dcl);
listeners.put(cmp, dcl);
}
}
}
/**
* Deregisters all the listeners, happens before a new page is loaded
*/
void deregisterAll() {
for(Enumeration e=comps.keys();e.hasMoreElements();) {
Component cmp = (Component)e.nextElement();
cmp.removeFocusListener(this);
if (cmp instanceof Button) { // catches Button, CheckBox, RadioButton
((Button)cmp).removeActionListener(this);
} else if (cmp instanceof List) { // catches ComboBox
((List)cmp).removeSelectionListener((SelectionListener)listeners.get(cmp));
} else if (cmp instanceof TextArea) {
((TextArea)cmp).removeActionListener(this);
if (cmp instanceof TextField) {
((TextField)cmp).removeDataChangeListener((DataChangedListener)listeners.get(cmp));
}
}
}
comps=new Hashtable();
listeners=new Hashtable();
}
private void toggleChecked(HTMLElement element,boolean checkedX) {
if (checkedX) {
element.setAttributeById(HTMLElement.ATTR_CHECKED, "checked");
} else {
element.removeAttributeById(HTMLElement.ATTR_CHECKED);
}
}
/**
* {{@inheritDoc}}
*/
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
HTMLElement element=(HTMLElement)comps.get(evt.getSource());
if (src instanceof CheckBox) {
toggleChecked(element,((CheckBox)src).isSelected());
} else if (src instanceof RadioButton) {
String curDomState = element.getAttributeById(HTMLElement.ATTR_CHECKED);
if ((curDomState==null) || (!curDomState.equals("checked"))) {
String name=element.getAttributeById(HTMLElement.ATTR_NAME);
if (name!=null) { // If this is named radiobutton, we need to set the status of the others accordingly
for(Enumeration e=comps.keys();e.hasMoreElements();) {
Component cmp = (Component)e.nextElement();
if (cmp instanceof RadioButton) {
HTMLElement rbElem = (HTMLElement)comps.get(cmp);
String rbName=rbElem.getAttributeById(HTMLElement.ATTR_NAME);
if ((rbName!=null) && (rbName.equals(name))) {
rbElem.removeAttributeById(HTMLElement.ATTR_CHECKED);
}
}
}
}
}
toggleChecked(element, ((RadioButton)src).isSelected());
//element.setAttributeById(HTMLElement.ATTR_CHECKED, ((RadioButton)src).isSelected()?"checked":null);
} else if (src instanceof TextArea) {
String text=((TextArea)src).getText();
if (element.getNumChildren()==0) {
HTMLElement textElem=new HTMLElement(text, true);
element.addChild(textElem);
} else {
HTMLElement textElem=(HTMLElement)element.getChildAt(0);
if (textElem.isTextElement()) { // If the HTML is malformed we may have a different element - and we ignore
textElem.setText(text);
} else {
System.out.println("Malformed HTML - Found a non-text element under TEXTAREA tag - ignoring");
}
}
} else if (src instanceof List) { //combobox
String item = ((List)src).getSelectedItem().toString();
Vector v=element.getDescendantsByTagId(HTMLElement.TAG_OPTION); // This is activated on the SELECT tag - we take descendants and not only children due to OPTGROUP
for(Enumeration e=v.elements();e.hasMoreElements();) {
HTMLElement option=(HTMLElement)e.nextElement();
if (option.getNumChildren()==1) { //we expect only a text element, if not the HTML is malformed and we ignore
HTMLElement textElem=(HTMLElement)option.getChildAt(0);
if (textElem.isTextElement()) { // If the HTML is malformed we may have a different element - and we ignore
if (textElem.getText().equalsIgnoreCase(item)) {
option.setAttributeById(HTMLElement.ATTR_SELECTED, "selected");
} else {
option.removeAttributeById(HTMLElement.ATTR_SELECTED);
}
} else {
System.out.println("Malformed HTML - Found a non-text element under OPTION tag - ignoring");
}
} else {
System.out.println("Malformed HTML - Found illegal tags as children of the OPTION tag - ignoring");
}
}
}
if (htmlC.getHTMLCallback()!=null) {
htmlC.getHTMLCallback().actionPerformed(evt, htmlC, element);
}
}
/**
* {{@inheritDoc}}
*/
public void focusGained(Component cmp) {
if (htmlC.getHTMLCallback()!=null) {
htmlC.getHTMLCallback().focusGained(cmp, htmlC, (HTMLElement)comps.get(cmp));
}
}
/**
* {{@inheritDoc}}
*/
public void focusLost(Component cmp) {
if (htmlC.getHTMLCallback()!=null) {
htmlC.getHTMLCallback().focusLost(cmp, htmlC, (HTMLElement)comps.get(cmp));
}
}
}