📄 html_formimpl.cpp
字号:
setHTMLEventListener(EventImpl::BLUR_EVENT,
getDocument()->createHTMLEventListener(attr->value().string(), this));
break;
case ATTR_ONSELECT:
setHTMLEventListener(EventImpl::SELECT_EVENT,
getDocument()->createHTMLEventListener(attr->value().string(), this));
break;
case ATTR_ONCHANGE:
setHTMLEventListener(EventImpl::CHANGE_EVENT,
getDocument()->createHTMLEventListener(attr->value().string(), this));
break;
case ATTR_ONINPUT:
setHTMLEventListener(EventImpl::INPUT_EVENT,
getDocument()->createHTMLEventListener(attr->value().string(), this));
break;
#if APPLE_CHANGES
// Search field and slider attributes all just cause updateFromElement to be called through style
// recalcing.
case ATTR_ONSEARCH:
setHTMLEventListener(EventImpl::SEARCH_EVENT,
getDocument()->createHTMLEventListener(attr->value().string(), this));
break;
case ATTR_RESULTS:
m_maxResults = !attr->isNull() ? attr->value().toInt() : -1;
/* Fall through */
case ATTR_AUTOSAVE:
case ATTR_INCREMENTAL:
case ATTR_PLACEHOLDER:
case ATTR_MIN:
case ATTR_MAX:
case ATTR_PRECISION:
setChanged();
break;
#endif
case ATTR_NAME:
if (m_type == RADIO && checked()) {
// Remove the radio from its old group.
if (!name().isEmpty())
getDocument()->removeRadioButtonGroup(name(), m_form);
// Update our cached reference to the name.
setName(attr->value());
// Add it to its new group.
getDocument()->radioButtonChecked(this, m_form);
}
break;
default:
HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
}
}
bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
{
switch(m_type)
{
case TEXT:
case PASSWORD:
#if APPLE_CHANGES
case SEARCH:
case RANGE:
#endif
case ISINDEX:
case CHECKBOX:
case RADIO:
case SUBMIT:
case IMAGE:
case RESET:
case FILE:
case BUTTON: return HTMLGenericFormElementImpl::rendererIsNeeded(style);
case HIDDEN: return false;
}
assert(false);
return false;
}
RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
{
switch(m_type)
{
case TEXT:
case PASSWORD:
#if APPLE_CHANGES
case SEARCH:
#endif
case ISINDEX: return new (arena) RenderLineEdit(this);
case CHECKBOX: return new (arena) RenderCheckBox(this);
case RADIO: return new (arena) RenderRadioButton(this);
case SUBMIT: return new (arena) RenderSubmitButton(this);
case IMAGE: return new (arena) RenderImageButton(this);
case RESET: return new (arena) RenderResetButton(this);
case FILE: return new (arena) RenderFileButton(this);
case BUTTON: return new (arena) RenderPushButton(this);
#if APPLE_CHANGES
case RANGE: return new (arena) RenderSlider(this);
#endif
case HIDDEN: break;
}
assert(false);
return 0;
}
void HTMLInputElementImpl::attach()
{
if (!m_inited) {
if (!m_haveType)
setType(getAttribute(ATTR_TYPE));
// FIXME: This needs to be dynamic, doesn't it, since someone could set this
// after attachment?
DOMString val = getAttribute(ATTR_VALUE);
if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
// remove newline stuff..
QString nvalue;
for (unsigned int i = 0; i < val.length(); ++i)
if (val[i] >= ' ')
nvalue += val[i];
if (val.length() != nvalue.length())
setAttribute(ATTR_VALUE, nvalue);
}
m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
m_inited = true;
}
// Disallow the width attribute on inputs other than HIDDEN and IMAGE.
// Dumb Web sites will try to set the width as an attribute on form controls that aren't
// images or hidden.
if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
int excCode;
removeAttribute(ATTR_WIDTH, excCode);
}
HTMLGenericFormElementImpl::attach();
if (m_type == IMAGE) {
if (!m_imageLoader)
m_imageLoader = new HTMLImageLoader(this);
m_imageLoader->updateFromElement();
if (renderer()) {
RenderImage* imageObj = static_cast<RenderImage*>(renderer());
imageObj->setImage(m_imageLoader->image());
}
}
#if APPLE_CHANGES
// note we don't deal with calling passwordFieldRemoved() on detach, because the timing
// was such that it cleared our state too early
if (m_type == PASSWORD)
getDocument()->passwordFieldAdded();
#endif
}
void HTMLInputElementImpl::detach()
{
HTMLGenericFormElementImpl::detach();
m_valueMatchesRenderer = false;
}
DOMString HTMLInputElementImpl::altText() const
{
// http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
// also heavily discussed by Hixie on bugzilla
// note this is intentionally different to HTMLImageElementImpl::altText()
DOMString alt = getAttribute( ATTR_ALT );
// fall back to title attribute
if ( alt.isNull() )
alt = getAttribute( ATTR_TITLE );
if ( alt.isNull() )
alt = getAttribute( ATTR_VALUE );
if ( alt.isEmpty() )
#if APPLE_CHANGES
alt = inputElementAltText();
#else
alt = i18n( "Submit" );
#endif
return alt;
}
bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
{
// HTML spec says that buttons must have names
// to be considered successful. However, other browsers
// do not impose this constraint. Therefore, we behave
// differently and can use different buttons than the
// author intended.
// Was: (m_type == SUBMIT && !name().isEmpty())
return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
}
bool HTMLInputElementImpl::isActivatedSubmit() const
{
return m_activeSubmit;
}
void HTMLInputElementImpl::setActivatedSubmit(bool flag)
{
m_activeSubmit = flag;
}
bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
{
// image generates its own names
if (name().isEmpty() && m_type != IMAGE) return false;
switch (m_type) {
case HIDDEN:
case TEXT:
#if APPLE_CHANGES
case SEARCH:
case RANGE:
#endif
case PASSWORD:
// always successful
encoding.appendData(name(), value());
return true;
case CHECKBOX:
case RADIO:
if (checked()) {
encoding.appendData(name(), value());
return true;
}
break;
case BUTTON:
case RESET:
// those buttons are never successful
return false;
case IMAGE:
if (m_activeSubmit)
{
encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
if (!name().isEmpty() && !value().isEmpty())
encoding.appendData(name(), value());
return true;
}
break;
case SUBMIT:
if (m_activeSubmit)
{
QString enc_str = valueWithDefault().string();
if (!enc_str.isEmpty()) {
encoding.appendData(name(), enc_str);
return true;
}
}
break;
case FILE:
{
// can't submit file on GET
// don't submit if display: none or display: hidden
if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
return false;
// if no filename at all is entered, return successful, however empty
// null would be more logical but netscape posts an empty file. argh.
if (value().isEmpty()) {
encoding.appendData(name(), QString(""));
return true;
}
#if APPLE_CHANGES
encoding.appendFile(name(), value());
return true;
#else
KURL fileurl("file:///");
fileurl.setPath(value().string());
KIO::UDSEntry filestat;
if (!KIO::NetAccess::stat(fileurl, filestat)) {
KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
return false;
}
KFileItem fileitem(filestat, fileurl, true, false);
if (fileitem.isDir()) {
return false;
}
QString local;
if ( KIO::NetAccess::download(fileurl, local) )
{
QFile file(local);
if (file.open(IO_ReadOnly))
{
QCString filearray(file.size()+1);
int readbytes = file.readBlock( filearray.data(), file.size());
if ( readbytes >= 0 )
filearray[readbytes] = '\0';
file.close();
encoding.appendData(name(), filearray);
KIO::NetAccess::removeTempFile( local );
return true;
}
return false;
}
else {
KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
return false;
}
break;
#endif
}
case ISINDEX:
encoding.appendData(name(), value());
return true;
}
return false;
}
void HTMLInputElementImpl::reset()
{
if (storesValueSeparateFromAttribute())
setValue(DOMString());
setChecked(m_defaultChecked);
m_useDefaultChecked = true;
}
void HTMLInputElementImpl::setChecked(bool _checked)
{
if (checked() == _checked) return;
if (m_type == RADIO && _checked)
getDocument()->radioButtonChecked(this, m_form);
m_useDefaultChecked = false;
m_checked = _checked;
setChanged();
}
DOMString HTMLInputElementImpl::value() const
{
DOMString value = m_value;
// It's important *not* to fall back to the value attribute for file inputs,
// because that would allow a malicious web page to upload files by setting the
// value attribute in markup.
if (value.isNull() && m_type != FILE)
value = getAttribute(ATTR_VALUE);
// If no attribute exists, then just use "on" or "" based off the checked() state of the control.
if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
return DOMString(checked() ? "on" : "");
return value;
}
DOMString HTMLInputElementImpl::valueWithDefault() const
{
DOMString v = value();
if (v.isEmpty()) {
switch (m_type) {
case RESET:
#if APPLE_CHANGES
v = resetButtonDefaultLabel();
#else
v = i18n("Reset");
#endif
break;
case SUBMIT:
#if APPLE_CHANGES
v = submitButtonDefaultLabel();
#else
v = i18n("Submit");
#endif
break;
case BUTTON:
case CHECKBOX:
case FILE:
case HIDDEN:
case IMAGE:
case ISINDEX:
case PASSWORD:
case RADIO:
#if APPLE_CHANGES
case RANGE:
case SEARCH:
#endif
case TEXT:
break;
}
}
return v;
}
void HTMLInputElementImpl::setValue(const DOMString &value)
{
#ifndef NOKIA_CHANGES
if (m_type == FILE) return;
#endif
m_valueMatchesRenderer = false;
if (storesValueSeparateFromAttribute()) {
m_value = value;
if (m_render)
m_render->updateFromElement();
setChanged();
} else {
setAttribute(ATTR_VALUE, value);
}
}
void HTMLInputElementImpl::setValueFromRenderer(const DOMString &value)
{
m_value = value;
m_valueMatchesRenderer = true;
// Fire the "input" DOM event.
dispatchHTMLEvent(EventImpl::INPUT_EVENT, true, false);
}
bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
{
switch (m_type) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -