HTMLTextAreaElement.cpp [plain text]
#include "config.h"
#include "HTMLTextAreaElement.h"
#include "Document.h"
#include "Event.h"
#include "EventNames.h"
#include "FormDataList.h"
#include "Frame.h"
#include "HTMLNames.h"
#include "Page.h"
#include "RenderStyle.h"
#include "RenderTextControl.h"
#include "Selection.h"
#include "Text.h"
namespace WebCore {
using namespace EventNames;
using namespace HTMLNames;
HTMLTextAreaElement::HTMLTextAreaElement(Document *doc, HTMLFormElement *f)
: HTMLGenericFormElement(textareaTag, doc, f)
, m_rows(2)
, m_cols(20)
, m_wrap(ta_Virtual)
, cachedSelStart(-1)
, cachedSelEnd(-1)
{
setValueMatchesRenderer();
document()->registerFormElementWithState(this);
}
HTMLTextAreaElement::~HTMLTextAreaElement()
{
document()->unregisterFormElementWithState(this);
}
const AtomicString& HTMLTextAreaElement::type() const
{
static const AtomicString textarea("textarea");
return textarea;
}
String HTMLTextAreaElement::stateValue() const
{
return value();
}
void HTMLTextAreaElement::restoreState(const String& state)
{
setDefaultValue(state);
}
int HTMLTextAreaElement::selectionStart()
{
if (renderer()) {
if (document()->focusNode() != this && cachedSelStart >= 0)
return cachedSelStart;
return static_cast<RenderTextControl *>(renderer())->selectionStart();
}
return 0;
}
int HTMLTextAreaElement::selectionEnd()
{
if (renderer()) {
if (document()->focusNode() != this && cachedSelEnd >= 0)
return cachedSelEnd;
return static_cast<RenderTextControl *>(renderer())->selectionEnd();
}
return 0;
}
void HTMLTextAreaElement::setSelectionStart(int start)
{
if (renderer())
static_cast<RenderTextControl*>(renderer())->setSelectionStart(start);
}
void HTMLTextAreaElement::setSelectionEnd(int end)
{
if (renderer())
static_cast<RenderTextControl*>(renderer())->setSelectionEnd(end);
}
void HTMLTextAreaElement::select()
{
if (renderer())
static_cast<RenderTextControl *>(renderer())->select();
}
void HTMLTextAreaElement::setSelectionRange(int start, int end)
{
if (renderer())
static_cast<RenderTextControl*>(renderer())->setSelectionRange(start, end);
}
void HTMLTextAreaElement::childrenChanged()
{
setValue(defaultValue());
}
void HTMLTextAreaElement::parseMappedAttribute(MappedAttribute *attr)
{
if (attr->name() == rowsAttr) {
m_rows = !attr->isNull() ? attr->value().toInt() : 3;
if (renderer())
renderer()->setNeedsLayoutAndMinMaxRecalc();
} else if (attr->name() == colsAttr) {
m_cols = !attr->isNull() ? attr->value().toInt() : 60;
if (renderer())
renderer()->setNeedsLayoutAndMinMaxRecalc();
} else if (attr->name() == wrapAttr) {
if (equalIgnoringCase(attr->value(), "virtual") || equalIgnoringCase(attr->value(), "soft"))
m_wrap = ta_Virtual;
else if (equalIgnoringCase(attr->value(), "physical") || equalIgnoringCase(attr->value(), "hard"))
m_wrap = ta_Physical;
else if (equalIgnoringCase(attr->value(), "on" ))
m_wrap = ta_Physical;
else if (equalIgnoringCase(attr->value(), "off"))
m_wrap = ta_NoWrap;
if (renderer())
renderer()->setNeedsLayoutAndMinMaxRecalc();
} else if (attr->name() == accesskeyAttr) {
} else if (attr->name() == onfocusAttr)
setHTMLEventListener(focusEvent, attr);
else if (attr->name() == onblurAttr)
setHTMLEventListener(blurEvent, attr);
else if (attr->name() == onselectAttr)
setHTMLEventListener(selectEvent, attr);
else if (attr->name() == onchangeAttr)
setHTMLEventListener(changeEvent, attr);
else
HTMLGenericFormElement::parseMappedAttribute(attr);
}
RenderObject* HTMLTextAreaElement::createRenderer(RenderArena* arena, RenderStyle* style)
{
return new (arena) RenderTextControl(this, true);
}
bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool)
{
if (name().isEmpty())
return false;
bool hardWrap = renderer() && wrap() == ta_Physical;
String v = hardWrap ? static_cast<RenderTextControl*>(renderer())->textWithHardLineBreaks() : value();
encoding.appendData(name(), v);
return true;
}
void HTMLTextAreaElement::reset()
{
setValue(defaultValue());
}
bool HTMLTextAreaElement::isKeyboardFocusable() const
{
return HTMLGenericFormElement::isFocusable();
}
bool HTMLTextAreaElement::isMouseFocusable() const
{
return HTMLGenericFormElement::isFocusable();
}
void HTMLTextAreaElement::focus()
{
Document* doc = document();
if (doc->focusNode() == this)
return;
doc->updateLayout();
if (!supportsFocus())
return;
doc->setFocusNode(this);
if (!isFocusable()) {
setNeedsFocusAppearanceUpdate(true);
return;
}
updateFocusAppearance();
}
void HTMLTextAreaElement::updateFocusAppearance()
{
ASSERT(renderer());
if (cachedSelStart == -1) {
ASSERT(cachedSelEnd == -1);
int max = static_cast<RenderTextControl*>(renderer())->text().length();
setSelectionRange(max, max);
} else
setSelectionRange(cachedSelStart, cachedSelEnd);
if (document() && document()->frame())
document()->frame()->revealSelection();
}
void HTMLTextAreaElement::defaultEventHandler(Event *evt)
{
if (renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == blurEvent))
static_cast<RenderTextControl*>(renderer())->forwardEvent(evt);
HTMLGenericFormElement::defaultEventHandler(evt);
}
void HTMLTextAreaElement::rendererWillBeDestroyed()
{
updateValue();
}
void HTMLTextAreaElement::updateValue() const
{
if (!valueMatchesRenderer()) {
ASSERT(renderer());
m_value = static_cast<RenderTextControl*>(renderer())->text();
setValueMatchesRenderer();
}
}
String HTMLTextAreaElement::value() const
{
updateValue();
return m_value;
}
void HTMLTextAreaElement::setValue(const String& value)
{
DeprecatedString valueWithNormalizedLineEndings = value.deprecatedString();
valueWithNormalizedLineEndings.replace("\r\n", "\n");
valueWithNormalizedLineEndings.replace("\r", "\n");
m_value = valueWithNormalizedLineEndings;
setValueMatchesRenderer();
if (renderer())
renderer()->updateFromElement();
if (document()->focusNode() == this && cachedSelStart >= 0) {
ASSERT(cachedSelEnd >= 0);
setSelectionRange(cachedSelStart, cachedSelStart);
}
setChanged(true);
if (document() && document()->frame())
document()->frame()->formElementDidSetValue(this);
}
String HTMLTextAreaElement::defaultValue() const
{
String val = "";
for (Node* n = firstChild(); n; n = n->nextSibling())
if (n->isTextNode())
val += static_cast<Text*>(n)->data();
if (val.length() >= 2 && val[0] == '\r' && val[1] == '\n')
val.remove(0, 2);
else if (val.length() >= 1 && (val[0] == '\r' || val[0] == '\n'))
val.remove(0, 1);
return val;
}
void HTMLTextAreaElement::setDefaultValue(const String& defaultValue)
{
Vector<RefPtr<Node> > textNodes;
for (Node* n = firstChild(); n; n = n->nextSibling())
if (n->isTextNode())
textNodes.append(n);
ExceptionCode ec = 0;
size_t size = textNodes.size();
for (size_t i = 0; i < size; ++i)
removeChild(textNodes[i].get(), ec);
insertBefore(document()->createTextNode(defaultValue), firstChild(), ec);
setValue(defaultValue);
}
void HTMLTextAreaElement::accessKeyAction(bool sendToAnyElement)
{
focus();
}
String HTMLTextAreaElement::accessKey() const
{
return getAttribute(accesskeyAttr);
}
void HTMLTextAreaElement::setAccessKey(const String& value)
{
setAttribute(accesskeyAttr, value);
}
void HTMLTextAreaElement::setCols(int cols)
{
setAttribute(colsAttr, String::number(cols));
}
void HTMLTextAreaElement::setRows(int rows)
{
setAttribute(rowsAttr, String::number(rows));
}
bool HTMLTextAreaElement::willRespondToMouseClickEvents()
{
return !disabled();
}
}