/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
/*
* Created on Jan 15, 2006
*/
package org.lobobrowser.html.domimpl;
import java.util.ArrayList;
import org.eclipse.jdt.annotation.NonNull;
import org.lobobrowser.html.FormInput;
import org.lobobrowser.html.js.Event;
import org.lobobrowser.html.js.NotGetterSetter;
import org.lobobrowser.ua.ImageResponse;
import org.lobobrowser.ua.ImageResponse.State;
import org.mozilla.javascript.Function;
import org.w3c.dom.Node;
import org.w3c.dom.html.HTMLFormElement;
public abstract class HTMLBaseInputElement extends HTMLAbstractUIElement {
public HTMLBaseInputElement(final String name) {
super(name);
}
protected InputContext inputContext;
protected String deferredValue;
protected Boolean deferredChecked;
protected Boolean deferredReadonly;
protected Boolean deferredDisabled;
public void setInputContext(final @NonNull InputContext ic) {
String dv = null;
Boolean defDisabled = null;
Boolean defReadonly = null;
Boolean defChecked = null;
synchronized (this) {
this.inputContext = ic;
dv = this.deferredValue;
defDisabled = this.deferredDisabled;
defReadonly = this.deferredReadonly;
defChecked = this.deferredChecked;
}
if (dv != null) {
ic.setValue(dv);
}
if (defDisabled != null) {
ic.setDisabled(defDisabled.booleanValue());
}
if (defReadonly != null) {
ic.setDisabled(defReadonly.booleanValue());
}
if (defChecked != null) {
ic.setDisabled(defChecked.booleanValue());
}
}
public String getDefaultValue() {
return this.getAttribute("defaultValue");
}
public void setDefaultValue(final String defaultValue) {
this.setAttribute("defaultValue", defaultValue);
}
public HTMLFormElement getForm() {
Node parent = this.getParentNode();
while ((parent != null) && !(parent instanceof HTMLFormElement)) {
parent = parent.getParentNode();
}
return (HTMLFormElement) parent;
}
public void submitForm(final FormInput[] extraFormInputs) {
final HTMLFormElementImpl form = (HTMLFormElementImpl) this.getForm();
if (form != null) {
form.submit(extraFormInputs);
}
}
public void resetForm() {
final HTMLFormElement form = this.getForm();
if (form != null) {
form.reset();
}
}
public String getAccept() {
return this.getAttribute("accept");
}
public void setAccept(final String accept) {
this.setAttribute("accept", accept);
}
public String getAccessKey() {
return this.getAttribute("accessKey");
}
public void setAccessKey(final String accessKey) {
this.setAttribute("accessKey", accessKey);
}
public String getAlign() {
return this.getAttribute("align");
}
public void setAlign(final String align) {
this.setAttribute("align", align);
}
public String getAlt() {
return this.getAttribute("alit");
}
public void setAlt(final String alt) {
this.setAttribute("alt", alt);
}
public String getName() {
// TODO: Should this return value of "id"?
return this.getAttribute("name");
}
public void setName(final String name) {
this.setAttribute("name", name);
}
public boolean getDisabled() {
final InputContext ic = this.inputContext;
if (ic == null) {
final Boolean db = this.deferredDisabled;
return db == null ? false : db.booleanValue();
} else {
return ic.getDisabled();
}
}
public void setDisabled(final boolean disabled) {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.setDisabled(disabled);
} else {
this.deferredDisabled = Boolean.valueOf(disabled);
}
}
public boolean getReadOnly() {
final InputContext ic = this.inputContext;
if (ic == null) {
final Boolean db = this.deferredReadonly;
return db == null ? false : db.booleanValue();
} else {
return ic.getReadOnly();
}
}
public void setReadOnly(final boolean readOnly) {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.setReadOnly(readOnly);
} else {
this.deferredReadonly = Boolean.valueOf(readOnly);
}
}
public boolean getChecked() {
final InputContext ic = this.inputContext;
if (ic == null) {
final Boolean db = this.deferredChecked;
return db == null ? false : db.booleanValue();
} else {
return ic.getChecked();
}
}
public void setChecked(final boolean value) {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.setChecked(value);
} else {
this.deferredChecked = Boolean.valueOf(value);
}
}
public int getTabIndex() {
final InputContext ic = this.inputContext;
return ic == null ? 0 : ic.getTabIndex();
}
public void setTabIndex(final int tabIndex) {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.setTabIndex(tabIndex);
}
}
public String getValue() {
final InputContext ic = this.inputContext;
if (ic != null) {
// Note: Per HTML Spec, setValue does not set attribute.
return ic.getValue();
} else {
final String dv = this.deferredValue;
if (dv != null) {
return dv;
} else {
final String val = this.getAttribute("value");
return val == null ? "" : val;
}
}
}
protected java.io.File getFileValue() {
final InputContext ic = this.inputContext;
if (ic != null) {
return ic.getFileValue();
} else {
return null;
}
}
public void setValue(final String value) {
InputContext ic = null;
synchronized (this) {
ic = this.inputContext;
if (ic == null) {
this.deferredValue = value;
}
}
if (ic != null) {
ic.setValue(value);
}
}
@Override
public void blur() {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.blur();
}
}
@Override
public void focus() {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.focus();
}
}
public void select() {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.select();
}
}
/*
* (non-Javadoc)
*
* @see
* org.xamjwg.html.domimpl.HTMLElementImpl#assignAttributeField(java.lang.
* String, java.lang.String)
*/
/*
@Override
protected void assignAttributeField(final String normalName, final String value) {
if ("value".equals(normalName)) {
this.setValue(value);
} else if ("checked".equals(normalName)) {
this.setChecked(value != null);
} else if ("disabled".equals(normalName)) {
this.setDisabled(value != null);
} else if ("readonly".equals(normalName)) {
this.setReadOnly(value != null);
} else if ("src".equals(normalName)) {
// TODO: Should check whether "type" == "image"
this.loadImage(value);
} else {
super.assignAttributeField(normalName, value);
}
}*/
@Override
protected void handleAttributeChanged(String name, String oldValue, String newValue) {
super.handleAttributeChanged(name, oldValue, newValue);
if ("value".equals(name)) {
this.setValue(newValue);
} else if ("checked".equals(name)) {
this.setChecked(newValue != null);
} else if ("disabled".equals(name)) {
this.setDisabled(newValue != null);
} else if ("readonly".equals(name)) {
this.setReadOnly(newValue != null);
} else if ("src".equals(name)) {
// TODO: Should check whether "type" == "image"
this.loadImage(newValue);
}
}
private Function onload;
public Function getOnload() {
return this.getEventFunction(this.onload, "onload");
}
public void setOnload(final Function onload) {
this.onload = onload;
}
private ImageResponse imageResponse = null;
private String imageSrc;
private void loadImage(final String src) {
final HTMLDocumentImpl document = (HTMLDocumentImpl) this.document;
if (document != null) {
synchronized (this.imageListeners) {
this.imageSrc = src;
this.imageResponse = null;
}
if (src != null) {
document.loadImage(src, new LocalImageListener(src));
}
}
}
private final ArrayList<ImageListener> imageListeners = new ArrayList<>(1);
/**
* Adds a listener of image loading events. The listener gets called right
* away if there's already an image.
*
* @param listener
*/
public void addImageListener(final ImageListener listener) {
final ArrayList<ImageListener> l = this.imageListeners;
ImageResponse currentImageResponse;
synchronized (l) {
currentImageResponse = this.imageResponse;
l.add(listener);
}
if (currentImageResponse.state != State.loading) {
// Call listener right away if there's already an
// image; holding no locks.
listener.imageLoaded(new ImageEvent(this, currentImageResponse));
// Should not call onload handler here. That's taken
// care of otherwise.
}
}
public void removeImageListener(final ImageListener listener) {
final ArrayList<ImageListener> l = this.imageListeners;
synchronized (l) {
l.remove(l);
}
}
void resetInput() {
final InputContext ic = this.inputContext;
if (ic != null) {
ic.resetInput();
}
}
private void dispatchEvent(final String expectedImgSrc, final ImageEvent event) {
final ArrayList<ImageListener> l = this.imageListeners;
ImageListener[] listenerArray;
synchronized (l) {
if (!expectedImgSrc.equals(this.imageSrc)) {
return;
}
this.imageResponse = event.imageResponse;
// Get array of listeners while holding lock.
listenerArray = l.toArray(ImageListener.EMPTY_ARRAY);
}
final int llength = listenerArray.length;
for (int i = 0; i < llength; i++) {
// Inform listener, holding no lock.
listenerArray[i].imageLoaded(event);
}
// TODO: With this change, setOnLoad method should add a listener with dispatch mechanism. Best implemented in a parent class.
dispatchEvent(new Event("load", this));
/*
final Function onload = this.getOnload();
if (onload != null) {
// TODO: onload event object?
Executor.executeFunction(HTMLBaseInputElement.this, onload, null);
}*/
}
private class LocalImageListener implements ImageListener {
private final String expectedImgSrc;
public LocalImageListener(final String imgSrc) {
this.expectedImgSrc = imgSrc;
}
public void imageLoaded(final ImageEvent event) {
dispatchEvent(this.expectedImgSrc, event);
}
public void imageAborted() {
// Do nothing
}
}
@NotGetterSetter
public void setCustomValidity(final String message) {
// TODO Implement
System.out.println("TODO: HTMLBaseInputElement.setCustomValidity() " + message);
}
}