From dfe289850f068f19ba4a83ab4e7e22a7e09c13c9 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sat, 26 Jan 2013 13:17:21 -0600 Subject: Rename a number of libraries and executables to avoid conflicts with KDE4 --- tdehtml/html/html_formimpl.cpp | 2980 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2980 insertions(+) create mode 100644 tdehtml/html/html_formimpl.cpp (limited to 'tdehtml/html/html_formimpl.cpp') diff --git a/tdehtml/html/html_formimpl.cpp b/tdehtml/html/html_formimpl.cpp new file mode 100644 index 000000000..f8c566511 --- /dev/null +++ b/tdehtml/html/html_formimpl.cpp @@ -0,0 +1,2980 @@ +/* + * This file is part of the DOM implementation for KDE. + * + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * (C) 2004, 2005, 2006 Apple Computer, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#undef FORMS_DEBUG +//#define FORMS_DEBUG + +#include "html/html_formimpl.h" + +#include "tdehtmlview.h" +#include "tdehtml_part.h" +#include "html/html_documentimpl.h" +#include "tdehtml_settings.h" +#include "misc/htmlhashes.h" + +#include "css/cssstyleselector.h" +#include "css/cssproperties.h" +#include "css/cssvalues.h" +#include "css/csshelper.h" +#include "xml/dom_textimpl.h" +#include "xml/dom_docimpl.h" +#include "xml/dom2_eventsimpl.h" +#include "xml/dom_restyler.h" +#include "tdehtml_ext.h" + +#include "rendering/render_form.h" + +#include +#include +#include +#include +#include +#include +#include +#ifndef KHTML_NO_WALLET +#include +#endif +#include +#include +#include +#include +#include + +// for keygen +#include +#include + +#include + + +using namespace DOM; +using namespace tdehtml; + +HTMLFormElementImpl::HTMLFormElementImpl(DocumentImpl *doc, bool implicit) + : HTMLElementImpl(doc) +{ + m_implicit = implicit; + m_post = false; + m_multipart = false; + m_autocomplete = true; + m_insubmit = false; + m_doingsubmit = false; + m_inreset = false; + m_enctype = "application/x-www-form-urlencoded"; + m_boundary = "----------" + TDEApplication::randomString( 42 + 13 ); + m_acceptcharset = "UNKNOWN"; + m_malformed = false; +} + +HTMLFormElementImpl::~HTMLFormElementImpl() +{ + if (getDocument() && getDocument()->view() && getDocument()->view()->part()) { + getDocument()->view()->part()->dequeueWallet(this); + } + TQPtrListIterator it(formElements); + for (; it.current(); ++it) + it.current()->m_form = 0; + TQPtrListIterator it2(imgElements); + for (; it2.current(); ++it2) + it2.current()->m_form = 0; +} + +NodeImpl::Id HTMLFormElementImpl::id() const +{ + return ID_FORM; +} + +long HTMLFormElementImpl::length() const +{ + int len = 0; + TQPtrListIterator it(formElements); + for (; it.current(); ++it) + if (it.current()->isEnumeratable()) + ++len; + + return len; +} + +static TQCString encodeCString(const TQCString& e) +{ + // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 + // safe characters like NS handles them for compatibility + static const char *safe = "-._*"; + TQCString encoded(( e.length()+e.contains( '\n' ) )*3 + +e.contains('\r') * 3 + 1); + int enclen = 0; + bool crmissing = false; + unsigned char oldc; + unsigned char c ='\0'; + + //TQCString orig(e.data(), e.size()); + + unsigned len = e.length(); + for(unsigned pos = 0; pos < len; pos++) { + oldc = c; + c = e[pos]; + + if (crmissing && c != '\n') { + encoded[enclen++] = '%'; + encoded[enclen++] = '0'; + encoded[enclen++] = 'D'; + crmissing = false; + } + + if ( (( c >= 'A') && ( c <= 'Z')) || + (( c >= 'a') && ( c <= 'z')) || + (( c >= '0') && ( c <= '9')) || + (strchr(safe, c)) + ) + encoded[enclen++] = c; + else if ( c == ' ' ) + encoded[enclen++] = '+'; + else if ( c == '\n' ) + { + encoded[enclen++] = '%'; + encoded[enclen++] = '0'; + encoded[enclen++] = 'D'; + encoded[enclen++] = '%'; + encoded[enclen++] = '0'; + encoded[enclen++] = 'A'; + crmissing = false; + } + else if (c == '\r' && oldc != '\n') { + crmissing = true; + } + else if ( c != '\r' ) + { + encoded[enclen++] = '%'; + unsigned int h = c / 16; + h += (h > 9) ? ('A' - 10) : '0'; + encoded[enclen++] = h; + + unsigned int l = c % 16; + l += (l > 9) ? ('A' - 10) : '0'; + encoded[enclen++] = l; + } + } + encoded[enclen++] = '\0'; + encoded.truncate(enclen); + + return encoded; +} + +// ### This function only encodes to numeric ampersand escapes, +// ### we could use standard ampersand values as well. +inline static TQString escapeUnencodeable(const TQTextCodec* codec, const TQString& s) { + TQString enc_string; + const int len = s.length(); + for(int i=0; i canEncode(c)) + enc_string.append(c); + else { + TQString ampersandEscape; + ampersandEscape.sprintf("&#%u;", c.unicode()); + enc_string.append(ampersandEscape); + } + } + return enc_string; +} + +inline static TQCString fixUpfromUnicode(const TQTextCodec* codec, const TQString& s) +{ + TQCString str = codec->fromUnicode(escapeUnencodeable(codec,s)); + str.truncate(str.length()); + return str; +} + +TQByteArray HTMLFormElementImpl::formData(bool& ok) +{ +#ifdef FORMS_DEBUG + kdDebug( 6030 ) << "form: formData()" << endl; +#endif + + TQByteArray form_data(0); + TQCString enc_string = ""; // used for non-multipart data + + // find out the QTextcodec to use + const TQString str = m_acceptcharset.string(); + const TQChar space(' '); + const unsigned int strLength = str.length(); + for(unsigned int i=0; i < strLength; ++i) if(str[i].latin1() == ',') str[i] = space; + const TQStringList charsets = TQStringList::split(' ', str); + TQTextCodec* codec = 0; + KHTMLView *view = getDocument()->view(); + { + TQStringList::ConstIterator it = charsets.begin(); + const TQStringList::ConstIterator itEnd = charsets.end(); + + for ( ; it != itEnd; ++it ) + { + TQString enc = (*it); + if(enc.contains("UNKNOWN")) + { + // use standard document encoding + enc = "ISO 8859-1"; + if(view && view->part()) + enc = view->part()->encoding(); + } + if((codec = TDEGlobal::charsets()->codecForName(enc.latin1()))) + break; + } + } + if(!codec) + codec = TQTextCodec::codecForLocale(); + + // we need to map visual hebrew to logical hebrew, as the web + // server alsways expects responses in logical ordering + if ( codec->mibEnum() == 11 ) + codec = TQTextCodec::codecForMib( 85 ); + + m_encCharset = codec->name(); + const unsigned int m_encCharsetLength = m_encCharset.length(); + for(unsigned int i=0; i < m_encCharsetLength; ++i) + m_encCharset[i] = m_encCharset[i].latin1() == ' ' ? TQChar('-') : m_encCharset[i].lower(); + + TQStringList fileUploads, fileNotUploads; + + for (TQPtrListIterator it(formElements); it.current(); ++it) { + HTMLGenericFormElementImpl* const current = it.current(); + tdehtml::encodingList lst; + + if (!current->disabled() && current->encoding(codec, lst, m_multipart)) + { + //kdDebug(6030) << "adding name '" << current->name().string() << "'" << endl; + tdehtml::encodingList::ConstIterator it = lst.begin(); + const tdehtml::encodingList::ConstIterator itEnd = lst.end(); + for( it = lst.begin(); it != itEnd; ++it ) + { + if (!m_multipart) + { + // handle ISINDEX / special + // but only if its the first entry + if ( enc_string.isEmpty() && *it == "isindex" ) { + ++it; + enc_string += encodeCString( *it ); + } + else { + if(!enc_string.isEmpty()) + enc_string += '&'; + + enc_string += encodeCString(*it); + enc_string += "="; + ++it; + enc_string += encodeCString(*it); + } + } + else + { + TQCString hstr("--"); + hstr += m_boundary.latin1(); + hstr += "\r\n"; + hstr += "Content-Disposition: form-data; name=\""; + hstr += (*it).data(); + hstr += "\""; + + // if the current type is FILE, then we also need to + // include the filename + if (current->id() == ID_INPUT && + static_cast(current)->inputType() == HTMLInputElementImpl::FILE && + current->renderer()) + { + KURL path; + TQString val = static_cast(current)->value().string().stripWhiteSpace(); + if (!val.isEmpty() && + TQDir::isRelativePath(val) && + TQFile::exists(TDEGlobalSettings::documentPath() + val)) { + path.setPath(TDEGlobalSettings::documentPath() + val); + } else { + path = KURL::fromPathOrURL(val); + } + + hstr += fixUpfromUnicode(codec, "; filename=\"" + path.fileName() + "\""); + if (path.isValid()) { + fileUploads << path.prettyURL(0, KURL::StripFileProtocol); + const KMimeType::Ptr ptr = KMimeType::findByURL(path); + if (!ptr->name().isEmpty()) { + hstr += "\r\nContent-Type: "; + hstr += ptr->name().ascii(); + } + } else if (!val.isEmpty()) { + fileNotUploads << path.prettyURL(0, KURL::StripFileProtocol); + } + } + + hstr += "\r\n\r\n"; + ++it; + + // append body + const unsigned int old_size = form_data.size(); + form_data.resize( old_size + hstr.length() + (*it).size() + 1); + memcpy(form_data.data() + old_size, hstr.data(), hstr.length()); + memcpy(form_data.data() + old_size + hstr.length(), *it, (*it).size()); + form_data[form_data.size()-2] = '\r'; + form_data[form_data.size()-1] = '\n'; + + // reset unsubmittedFormChange flag + if (current->id() == ID_INPUT && + static_cast(current)->inputType() == HTMLInputElementImpl::TEXT) + static_cast(current)->setUnsubmittedFormChange(false); + + if (current->id() == ID_TEXTAREA) + static_cast(current)->setUnsubmittedFormChange(false); + + } + } + } + } + + if (fileNotUploads.count()) { + const int result = KMessageBox::warningContinueCancelList( 0, + i18n("The following files will not be uploaded" + " because they could not be found.\n" + "Do you want to continue?"), + fileNotUploads, + i18n("Submit Confirmation"),KGuiItem(i18n("&Submit Anyway"))); + + + if (result == KMessageBox::Cancel) { + ok = false; + return TQByteArray(); + } + } + + if (fileUploads.count()) { + const int result = KMessageBox::warningContinueCancelList( 0, + i18n("You're about to transfer the following files from " + "your local computer to the Internet.\n" + "Do you really want to continue?"), + fileUploads, + i18n("Send Confirmation"),KGuiItem(i18n("&Send Files"))); + + + if (result == KMessageBox::Cancel) { + ok = false; + return TQByteArray(); + } + } + + if (m_multipart) + enc_string = ("--" + m_boundary + "--\r\n").ascii(); + + const int old_size = form_data.size(); + form_data.resize( form_data.size() + enc_string.length() ); + memcpy(form_data.data() + old_size, enc_string.data(), enc_string.length() ); + + ok = true; + return form_data; +} + +void HTMLFormElementImpl::setEnctype( const DOMString& type ) +{ + if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1) + { + m_enctype = "multipart/form-data"; + m_multipart = true; + m_post = true; + } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1) + { + m_enctype = "text/plain"; + m_multipart = false; + } + else + { + m_enctype = "application/x-www-form-urlencoded"; + m_multipart = false; + } + m_encCharset = TQString::null; +} + +static TQString calculateAutoFillKey(const HTMLFormElementImpl& e) +{ + KURL k(e.getDocument()->URL()); + k.setRef(TQString::null); + k.setQuery(TQString::null); + // ensure that we have the user / password inside the url + // otherwise we might have a potential security problem + // by saving passwords under wrong lookup key. + const TQString name = e.getAttribute(ATTR_NAME).string().stripWhiteSpace(); + const TQRegExp re("[;,!]"); + const TQStringList url = TQStringList::split(re, k.url()); + return url[0] + '#' + name; +} + +void HTMLFormElementImpl::doAutoFill() +{ +#ifndef KHTML_NO_WALLET + const TQString key = calculateAutoFillKey(*this); + + if (KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), + KWallet::Wallet::FormDataFolder(), + key)) + return; + + // assert(view()) + getDocument()->view()->part()->openWallet(this); +#endif // KHTML_NO_WALLET +} + + +void HTMLFormElementImpl::walletOpened(KWallet::Wallet *w) { +#ifndef KHTML_NO_WALLET + assert(w); + const TQString key = calculateAutoFillKey(*this); + if (!w->hasFolder(KWallet::Wallet::FormDataFolder())) { + return; // failed + } + w->setFolder(KWallet::Wallet::FormDataFolder()); + TQMap map; + if (w->readMap(key, map)) + return; // failed, abort + + for (TQPtrListIterator it(formElements); it.current(); ++it) { + if (it.current()->id() == ID_INPUT) { + HTMLInputElementImpl* const current = static_cast(it.current()); + if ((current->inputType() == HTMLInputElementImpl::PASSWORD || + current->inputType() == HTMLInputElementImpl::TEXT) && + !current->readOnly() && + map.contains(current->name().string())) { + getDocument()->setFocusNode(current); + current->setValue(map[current->name().string()]); + } + } + } +#endif // KHTML_NO_WALLET +} + +void HTMLFormElementImpl::submitFromKeyboard() +{ + // Activate the first nondisabled submit button + // if there is none, do a submit anyway if not more + // than one or + unsigned int inputtext = 0; + for (TQPtrListIterator it(formElements); it.current(); ++it) { + if (it.current()->id() == ID_BUTTON) { + HTMLButtonElementImpl* const current = static_cast(it.current()); + if (current->buttonType() == HTMLButtonElementImpl::SUBMIT && !current->disabled()) { + current->click(); + return; + } + } else if (it.current()->id() == ID_INPUT) { + HTMLInputElementImpl* const current = static_cast(it.current()); + switch(current->inputType()) { + case HTMLInputElementImpl::SUBMIT: + case HTMLInputElementImpl::IMAGE: + if(!current->disabled()) { + current->click(); + return; + } + break; + case HTMLInputElementImpl::TEXT: + case HTMLInputElementImpl::PASSWORD: + ++inputtext; + default: + break; + } + } + } + + if (inputtext <= 1) + prepareSubmit(); +} + + +void HTMLFormElementImpl::gatherWalletData() +{ +#ifndef KHTML_NO_WALLET + KHTMLView* const view = getDocument()->view(); + // check if we have any password input's + m_walletMap.clear(); + m_havePassword = false; + m_haveTextarea = false; + const KURL formUrl(getDocument()->URL()); + if (view && !view->nonPasswordStorableSite(formUrl.host())) { + for (TQPtrListIterator it(formElements); it.current(); ++it) { + if (it.current()->id() == ID_INPUT) { + HTMLInputElementImpl* const c = static_cast (it.current()); + if ((c->inputType() == HTMLInputElementImpl::TEXT || + c->inputType() == HTMLInputElementImpl::PASSWORD) && + !c->readOnly()) { + m_walletMap.insert(c->name().string(), c->value().string()); + if (c->inputType() == HTMLInputElementImpl::PASSWORD && + !c->value().isEmpty()) + m_havePassword = true; + } + } + else if (it.current()->id() == ID_TEXTAREA) + m_haveTextarea = true; + } + } +#endif // KHTML_NO_WALLET +} + + +bool HTMLFormElementImpl::prepareSubmit() +{ + KHTMLView* const view = getDocument()->view(); + if(m_insubmit || !view || !view->part() || view->part()->onlyLocalReferences()) + return m_insubmit; + + gatherWalletData(); + + m_insubmit = true; + m_doingsubmit = false; + + if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,true,true) && !m_doingsubmit ) + m_doingsubmit = true; + + m_insubmit = false; + + if ( m_doingsubmit ) + submit(); + + return m_doingsubmit; +} + +void HTMLFormElementImpl::submit( ) +{ + if ( m_insubmit ) { + m_doingsubmit = true; + return; + } + + m_insubmit = true; + +#ifdef FORMS_DEBUG + kdDebug( 6030 ) << "submitting!" << endl; +#endif + + bool ok; + KHTMLView* const view = getDocument()->view(); + const TQByteArray form_data = formData(ok); + const KURL formUrl(getDocument()->URL()); + + if (ok && view) { + if (m_walletMap.isEmpty()) { + gatherWalletData(); + } +#ifndef KHTML_NO_WALLET + if (m_havePassword && !m_haveTextarea && KWallet::Wallet::isEnabled()) { + const TQString key = calculateAutoFillKey(*this); + const bool doesnotexist = KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::FormDataFolder(), key); + KWallet::Wallet* const w = view->part()->wallet(); + bool login_changed = false; + + if (!doesnotexist && w) { + // check if the login information changed from what + // we had so far. + if (w->hasFolder(KWallet::Wallet::FormDataFolder())) { + w->setFolder(KWallet::Wallet::FormDataFolder()); + TQMap map; + if (!w->readMap(key, map)) { + TQMapConstIterator it = map.begin(); + const TQMapConstIterator itEnd = map.end(); + for ( ; it != itEnd; ++it ) + if ( map[it.key()] != m_walletMap[it.key()] ) { + login_changed = true; + break; + } + } else { + login_changed = true; + } + } + } + + if ( doesnotexist || !w || login_changed ) { + // TODO use KMessageBox::questionYesNoCancel() again, if you can pass a KGuiItem for Cancel + KDialogBase* const dialog = new KDialogBase(i18n("Save Login Information"), + KDialogBase::Yes | KDialogBase::No | KDialogBase::Cancel, + KDialogBase::Yes, KDialogBase::Cancel, + 0, "questionYesNoCancel", true, true, + i18n("Store"), KGuiItem(i18n("Ne&ver for This Site")), i18n("Do Not Store")); + + bool checkboxResult = false; + const int savePassword = KMessageBox::createKMessageBox(dialog, TQMessageBox::Information, + i18n("Store passwords on this page?"), + TQStringList(), TQString::null, &checkboxResult, KMessageBox::Notify); + + if ( savePassword == KDialogBase::Yes ) { + // ensure that we have the user / password inside the url + // otherwise we might have a potential security problem + // by saving passwords under wrong lookup key. + + if (view->part()) { + view->part()->saveToWallet(key, m_walletMap); + } + } else if ( savePassword == KDialogBase::No ) { + view->addNonPasswordStorableSite(formUrl.host()); + } + } + } +#endif // KHTML_NO_WALLET + + const DOMString url(tdehtml::parseURL(getAttribute(ATTR_ACTION))); + if(m_post) { + view->part()->submitForm( "post", url.string(), form_data, + m_target.string(), + enctype().string(), + m_boundary ); + } + else { + view->part()->submitForm( "get", url.string(), form_data, + m_target.string() ); + } + } + + m_walletMap.clear(); // done with it + m_havePassword = m_haveTextarea= false; + m_doingsubmit = m_insubmit = false; +} + +void HTMLFormElementImpl::reset( ) +{ + KHTMLView* const view = getDocument()->view(); + if(m_inreset || !view || !view->part()) return; + + m_inreset = true; + +#ifdef FORMS_DEBUG + kdDebug( 6030 ) << "reset pressed!" << endl; +#endif + + // ### DOM2 labels this event as not cancelable, however + // common browsers( sick! ) allow it be cancelled. + if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) { + m_inreset = false; + return; + } + + for (TQPtrListIterator it(formElements); it.current(); ++it) + it.current()->reset(); + + m_inreset = false; +} + +void HTMLFormElementImpl::parseAttribute(AttributeImpl *attr) +{ + switch(attr->id()) + { + case ATTR_ACTION: + break; + case ATTR_TARGET: + m_target = attr->value(); + break; + case ATTR_METHOD: + m_post = ( strcasecmp( attr->value(), "post" ) == 0 ); + break; + case ATTR_ENCTYPE: + setEnctype( attr->value() ); + break; + case ATTR_ACCEPT_CHARSET: + // space separated list of charsets the server + // accepts - see rfc2045 + m_acceptcharset = attr->value(); + break; + case ATTR_ACCEPT: + // ignore this one for the moment... + break; + case ATTR_AUTOCOMPLETE: + m_autocomplete = strcasecmp( attr->value(), "off" ); + break; + case ATTR_ONSUBMIT: + setHTMLEventListener(EventImpl::SUBMIT_EVENT, + getDocument()->createHTMLEventListener(attr->value().string(), "onsubmit", this)); + break; + case ATTR_ONRESET: + setHTMLEventListener(EventImpl::RESET_EVENT, + getDocument()->createHTMLEventListener(attr->value().string(), "onreset", this)); + break; + case ATTR_NAME: + if (inDocument() && m_name != attr->value()) { + getDocument()->underDocNamedCache().remove(m_name.string(), this); + getDocument()->underDocNamedCache().add (attr->value().string(), this); + } + m_name = attr->value(); + //Fallthrough intentional + default: + HTMLElementImpl::parseAttribute(attr); + } +} + +void HTMLFormElementImpl::removedFromDocument() +{ + getDocument()->underDocNamedCache().remove(m_name.string(), this); + HTMLElementImpl::removedFromDocument(); +} + +void HTMLFormElementImpl::insertedIntoDocument() +{ + getDocument()->underDocNamedCache().add(m_name.string(), this); + HTMLElementImpl::insertedIntoDocument(); +} + +void HTMLFormElementImpl::removeId(const TQString& id) +{ + getDocument()->underDocNamedCache().remove(id, this); + HTMLElementImpl::removeId(id); +} + +void HTMLFormElementImpl::addId (const TQString& id) +{ + getDocument()->underDocNamedCache().add(id, this); + HTMLElementImpl::addId(id); +} + + +void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller ) +{ + for (TQPtrListIterator it(formElements); it.current(); ++it) { + HTMLGenericFormElementImpl* const current = it.current(); + if (current->id() == ID_INPUT && + static_cast(current)->inputType() == HTMLInputElementImpl::RADIO && + current != caller && current->form() == caller->form() && current->name() == caller->name()) + static_cast(current)->setChecked(false); + } +} + +void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e) +{ + formElements.append(e); +} + +void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e) +{ + formElements.remove(e); +} + +void HTMLFormElementImpl::registerImgElement(HTMLImageElementImpl *e) +{ + imgElements.append(e); +} + +void HTMLFormElementImpl::removeImgElement(HTMLImageElementImpl *e) +{ + imgElements.remove(e); +} + +// ------------------------------------------------------------------------- + +HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentImpl *doc, HTMLFormElementImpl *f) + : HTMLElementImpl(doc) +{ + m_disabled = m_readOnly = false; + m_name = 0; + + if (f) + m_form = f; + else + m_form = getForm(); + if (m_form) + m_form->registerFormElement(this); +} + +void HTMLGenericFormElementImpl::insertedIntoDocument() +{ + HTMLElementImpl::insertedIntoDocument(); + + if (!m_form) { + HTMLFormElementImpl* const newform = getForm(); + if (newform) { + m_form = newform; + m_form->registerFormElement(this); + } + } +} + +void HTMLGenericFormElementImpl::removedFromDocument() +{ + HTMLElementImpl::removedFromDocument(); + + if (m_form) + m_form->removeFormElement(this); + + m_form = 0; +} + +HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl() +{ + if (m_form) + m_form->removeFormElement(this); + if (m_name) m_name->deref(); +} + +void HTMLGenericFormElementImpl::parseAttribute(AttributeImpl *attr) +{ + switch(attr->id()) + { + case ATTR_DISABLED: + setDisabled( attr->val() != 0 ); + break; + case ATTR_READONLY: + { + const bool m_oldreadOnly = m_readOnly; + m_readOnly = attr->val() != 0; + if (m_oldreadOnly != m_readOnly) setChanged(); + break; + } + default: + HTMLElementImpl::parseAttribute(attr); + } +} + +void HTMLGenericFormElementImpl::attach() +{ + assert(!attached()); + + if (m_render) { + assert(m_render->style()); + parentNode()->renderer()->addChild(m_render, nextRenderer()); + } + + // FIXME: This handles the case of a new form element being created by + // JavaScript and inserted inside a form. What it does not handle is + // a form element being moved from inside a form to outside, or from one + // inside one form to another. The reason this other case is hard to fix + // is that during parsing, we may have been passed a form that we are not + // inside, DOM-tree-wise. If so, it's hard for us to know when we should + // be removed from that form's element list. + if (!m_form) { + m_form = getForm(); + if (m_form) + m_form->registerFormElement(this); + } + + NodeBaseImpl::attach(); + + // The call to updateFromElement() needs to go after the call through + // to the base class's attach() because that can sometimes do a close + // on the renderer. + if (m_render) + m_render->updateFromElement(); + +} + +HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const +{ + NodeImpl *p = parentNode(); + while(p) + { + if( p->id() == ID_FORM ) + return static_cast(p); + if( p->parentNode() && p->parentNode()->id() == ID_TABLE && p->previousSibling() ) + { + p = p->previousSibling(); + continue; + } + p = p->parentNode(); + } +#ifdef FORMS_DEBUG + kdDebug( 6030 ) << "couldn't find form!" << endl; + kdDebug( 6030 ) << kdBacktrace() << endl; +#endif + return 0; +} + +DOMString HTMLGenericFormElementImpl::name() const +{ + if (m_name) return m_name; + +// ### +// DOMString n = getDocument()->htmlMode() != DocumentImpl::XHtml ? +// getAttribute(ATTR_NAME) : getAttribute(ATTR_ID); + const DOMString n = getAttribute(ATTR_NAME); + if (n.isNull()) + return new DOMStringImpl(""); + + return n; +} + +void HTMLGenericFormElementImpl::setName(const DOMString& name) +{ + if (m_name) m_name->deref(); + m_name = name.implementation(); + setAttribute( ATTR_NAME, name ); + if (m_name) m_name->ref(); +} + +void HTMLGenericFormElementImpl::onSelect() +{ + // ### make this work with new form events architecture + dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false); +} + +void HTMLGenericFormElementImpl::onChange() +{ + // ### make this work with new form events architecture + dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false); +} + +void HTMLGenericFormElementImpl::setDisabled( bool _disabled ) +{ + if ( m_disabled != _disabled ) { + m_disabled = _disabled; + // Trigger dynamic restyles + getDocument()->dynamicDomRestyler().restyleDepedent(this, OtherStateDependency); + // We need to update rendering under all circumstances + if (!changed() && m_render) { + m_render->updateFromElement(); + } + } +} + +bool HTMLGenericFormElementImpl::isFocusable() const +{ + if (disabled()) + return false; + + //Non-widget INPUT TYPE="image" and