2 * This file is part of the DOM implementation for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2001 Dirk Mueller (mueller@kde.org)
7 * Copyright (C) 2004 Apple Computer, Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
29 #include "html/html_formimpl.h"
31 #include "khtmlview.h"
32 #include "khtml_part.h"
33 #include "html/html_documentimpl.h"
34 #include "html_imageimpl.h"
35 #include "khtml_settings.h"
36 #include "misc/htmlhashes.h"
37 #include "misc/formdata.h"
39 #include "dom/dom_exception.h"
40 #include "css/cssstyleselector.h"
41 #include "css/cssproperties.h"
42 #include "css/csshelper.h"
43 #include "xml/dom_textimpl.h"
44 #include "xml/dom2_eventsimpl.h"
45 #include "khtml_ext.h"
47 #include "rendering/render_form.h"
49 #include <kcharsets.h>
52 #include <kmimetype.h>
53 #include <kmessagebox.h>
55 #include <netaccess.h>
56 #include <kfileitem.h>
58 #include <qtextcodec.h>
62 #include <ksslkeygen.h>
66 using namespace khtml;
70 struct FormDataListItem {
71 FormDataListItem(const QCString &data) : m_data(data) { }
72 FormDataListItem(const QString &path) : m_path(path) { }
80 FormDataList(QTextCodec *);
82 void appendData(const DOMString &key, const DOMString &value)
83 { appendString(key.string()); appendString(value.string()); }
84 void appendData(const DOMString &key, const QString &value)
85 { appendString(key.string()); appendString(value); }
86 void appendData(const DOMString &key, const QCString &value)
87 { appendString(key.string()); appendString(value); }
88 void appendData(const DOMString &key, int value)
89 { appendString(key.string()); appendString(QString::number(value)); }
90 void appendFile(const DOMString &key, const DOMString &filename);
92 QValueListConstIterator<FormDataListItem> begin() const
93 { return m_list.begin(); }
94 QValueListConstIterator<FormDataListItem> end() const
95 { return m_list.end(); }
98 void appendString(const QCString &s);
99 void appendString(const QString &s);
102 QValueList<FormDataListItem> m_list;
105 HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc)
106 : HTMLElementImpl(doc)
111 m_autocomplete = true;
113 m_doingsubmit = false;
115 m_enctype = "application/x-www-form-urlencoded";
116 m_boundary = "----------0xKhTmLbOuNdArY";
117 m_acceptcharset = "UNKNOWN";
121 HTMLFormElementImpl::~HTMLFormElementImpl()
123 delete collectionInfo;
125 for (unsigned i = 0; i < formElements.count(); ++i)
126 formElements[i]->m_form = 0;
127 for (unsigned i = 0; i < dormantFormElements.count(); ++i)
128 dormantFormElements[i]->m_form = 0;
129 for (unsigned i = 0; i < imgElements.count(); ++i)
130 imgElements[i]->m_form = 0;
133 NodeImpl::Id HTMLFormElementImpl::id() const
140 bool HTMLFormElementImpl::formWouldHaveSecureSubmission(const DOMString &url)
145 return getDocument()->completeURL(url.string()).startsWith("https:", false);
150 void HTMLFormElementImpl::attach()
152 HTMLElementImpl::attach();
154 if (getDocument()->isHTMLDocument()) {
155 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
156 document->addNamedImageOrForm(oldNameAttr);
157 document->addNamedImageOrForm(oldIdAttr);
161 // note we don't deal with calling secureFormRemoved() on detach, because the timing
162 // was such that it cleared our state too early
163 if (formWouldHaveSecureSubmission(m_url))
164 getDocument()->secureFormAdded();
168 void HTMLFormElementImpl::detach()
170 if (getDocument()->isHTMLDocument()) {
171 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
172 document->removeNamedImageOrForm(oldNameAttr);
173 document->removeNamedImageOrForm(oldIdAttr);
176 HTMLElementImpl::detach();
179 long HTMLFormElementImpl::length() const
182 for (unsigned i = 0; i < formElements.count(); ++i)
183 if (formElements[i]->isEnumeratable())
191 void HTMLFormElementImpl::submitClick()
193 bool submitFound = false;
194 for (unsigned i = 0; i < formElements.count(); ++i) {
195 if (formElements[i]->id() == ID_INPUT) {
196 HTMLInputElementImpl *element = static_cast<HTMLInputElementImpl *>(formElements[i]);
197 if (element->isSuccessfulSubmitButton() && element->renderer()) {
199 element->click(false);
204 if (!submitFound) // submit the form without a submit or image input
208 #endif // APPLE_CHANGES
210 static QCString encodeCString(const QCString& e)
212 // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
213 // safe characters like NS handles them for compatibility
214 static const char *safe = "-._*";
215 int elen = e.length();
216 QCString encoded(( elen+e.contains( '\n' ) )*3+1);
219 //QCString orig(e.data(), e.size());
221 for(int pos = 0; pos < elen; pos++) {
222 unsigned char c = e[pos];
224 if ( (( c >= 'A') && ( c <= 'Z')) ||
225 (( c >= 'a') && ( c <= 'z')) ||
226 (( c >= '0') && ( c <= '9')) ||
229 encoded[enclen++] = c;
231 encoded[enclen++] = '+';
232 else if ( c == '\n' || ( c == '\r' && e[pos+1] != '\n' ) )
234 encoded[enclen++] = '%';
235 encoded[enclen++] = '0';
236 encoded[enclen++] = 'D';
237 encoded[enclen++] = '%';
238 encoded[enclen++] = '0';
239 encoded[enclen++] = 'A';
241 else if ( c != '\r' )
243 encoded[enclen++] = '%';
244 unsigned int h = c / 16;
245 h += (h > 9) ? ('A' - 10) : '0';
246 encoded[enclen++] = h;
248 unsigned int l = c % 16;
249 l += (l > 9) ? ('A' - 10) : '0';
250 encoded[enclen++] = l;
253 encoded[enclen++] = '\0';
254 encoded.truncate(enclen);
259 // Change plain CR and plain LF to CRLF pairs.
260 static QCString fixLineBreaks(const QCString &s)
262 // Compute the length.
264 const char *p = s.data();
265 while (char c = *p++) {
267 // Safe to look ahead because of trailing '\0'.
269 // Turn CR into CRLF.
272 } else if (c == '\n') {
273 // Turn LF into CRLF.
276 // Leave other characters alone.
280 if (newLen == s.length()) {
284 // Make a copy of the string.
286 QCString result(newLen + 1);
287 char *q = result.data();
288 while (char c = *p++) {
290 // Safe to look ahead because of trailing '\0'.
292 // Turn CR into CRLF.
296 } else if (c == '\n') {
297 // Turn LF into CRLF.
301 // Leave other characters alone.
310 void HTMLFormElementImpl::i18nData()
312 QString foo1 = i18n( "You're about to send data to the Internet "
313 "via an unencrypted connection. It might be possible "
314 "for others to see this information.\n"
315 "Do you want to continue?");
316 QString foo2 = i18n("KDE Web browser");
317 QString foo3 = i18n("When you send a password unencrypted to the Internet, "
318 "it might be possible for others to capture it as plain text.\n"
319 "Do you want to continue?");
320 QString foo5 = i18n("Your data submission is redirected to "
321 "an insecure site. The data is sent unencrypted.\n"
322 "Do you want to continue?");
323 QString foo6 = i18n("The page contents expired. You can repost the form"
324 "data by using <a href=\"javascript:go(0);\">Reload</a>");
329 bool HTMLFormElementImpl::formData(FormData &form_data) const
332 kdDebug( 6030 ) << "form: formData()" << endl;
335 QCString enc_string = ""; // used for non-multipart data
337 // find out the QTextcodec to use
338 QString str = m_acceptcharset.string();
339 str.replace(',', ' ');
340 QStringList charsets = QStringList::split(' ', str);
341 QTextCodec* codec = 0;
342 KHTMLPart *part = getDocument()->part();
343 for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
346 if(enc.contains("UNKNOWN"))
348 // use standard document encoding
351 enc = part->encoding();
353 if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
358 codec = QTextCodec::codecForLocale();
361 QStringList fileUploads;
364 for (unsigned i = 0; i < formElements.count(); ++i) {
365 HTMLGenericFormElementImpl* current = formElements[i];
366 FormDataList lst(codec);
368 if (!current->disabled() && current->appendFormData(lst, m_multipart))
370 //kdDebug(6030) << "adding name " << current->name().string() << endl;
371 for(QValueListConstIterator<FormDataListItem> it = lst.begin(); it != lst.end(); ++it )
375 // handle ISINDEX / <input name=isindex> special
376 // but only if its the first entry
377 if ( enc_string.isEmpty() && (*it).m_data == "isindex" ) {
379 enc_string += encodeCString( (*it).m_data );
382 if(!enc_string.isEmpty())
385 enc_string += encodeCString((*it).m_data);
388 enc_string += encodeCString((*it).m_data);
394 hstr += m_boundary.string().latin1();
396 hstr += "Content-Disposition: form-data; name=\"";
397 hstr += (*it).m_data.data();
400 // if the current type is FILE, then we also need to
401 // include the filename
402 if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
403 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
405 QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
407 if (path.length()) fileUploads << path;
410 // FIXME: This won't work if the filename includes a " mark,
411 // or control characters like CR or LF. This also does strange
412 // things if the filename includes characters you can't encode
413 // in the website's character set.
414 hstr += "; filename=\"";
415 hstr += codec->fromUnicode(path.mid(path.findRev('/') + 1));
418 if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
421 QString mimeType = part ? KWQ(part)->mimeTypeForFileName(path) : QString();
423 KMimeType::Ptr ptr = KMimeType::findByURL(KURL(path));
424 QString mimeType = ptr->name();
426 if (!mimeType.isEmpty()) {
427 hstr += "\r\nContent-Type: ";
428 hstr += mimeType.ascii();
437 form_data.appendData(hstr.data(), hstr.length());
439 const FormDataListItem &item = *it;
440 size_t dataSize = item.m_data.size();
442 form_data.appendData(item.m_data, dataSize - 1);
443 else if (!item.m_path.isEmpty())
444 form_data.appendFile(item.m_path);
446 form_data.appendData((*it).m_data, (*it).m_data.size() - 1);
448 form_data.appendData("\r\n", 2);
455 if (fileUploads.count()) {
456 int result = KMessageBox::warningContinueCancelList( 0,
457 i18n("You're about to transfer the following files from "
458 "your local computer to the Internet.\n"
459 "Do you really want to continue?"),
463 if (result == KMessageBox::Cancel) {
470 enc_string = ("--" + m_boundary.string() + "--\r\n").ascii();
472 form_data.appendData(enc_string.data(), enc_string.length());
476 void HTMLFormElementImpl::parseEnctype( const DOMString& type )
478 if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1)
480 m_enctype = "multipart/form-data";
483 } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1)
485 m_enctype = "text/plain";
490 m_enctype = "application/x-www-form-urlencoded";
495 void HTMLFormElementImpl::setBoundary( const DOMString& bound )
500 bool HTMLFormElementImpl::prepareSubmit()
502 KHTMLPart *part = getDocument()->part();
503 if(m_insubmit || !part || part->onlyLocalReferences())
507 m_doingsubmit = false;
509 if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,false,true) && !m_doingsubmit )
510 m_doingsubmit = true;
517 return m_doingsubmit;
520 void HTMLFormElementImpl::submit( bool activateSubmitButton )
522 KHTMLView *view = getDocument()->view();
523 KHTMLPart *part = getDocument()->part();
524 if (!view || !part) {
529 m_doingsubmit = true;
536 kdDebug( 6030 ) << "submitting!" << endl;
539 HTMLGenericFormElementImpl* firstSuccessfulSubmitButton = 0;
540 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
543 KWQ(part)->clearRecordedFormValues();
545 for (unsigned i = 0; i < formElements.count(); ++i) {
546 HTMLGenericFormElementImpl* current = formElements[i];
548 // Our app needs to get form values for password fields for doing password autocomplete,
549 // so we are more lenient in pushing values, and let the app decide what to save when.
550 if (current->id() == ID_INPUT) {
551 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl*>(current);
552 if (input->inputType() == HTMLInputElementImpl::TEXT
553 || input->inputType() == HTMLInputElementImpl::PASSWORD
554 || input->inputType() == HTMLInputElementImpl::SEARCH)
556 KWQ(part)->recordFormValue(input->name().string(), input->value().string(), this);
557 if (input->renderer() && input->inputType() == HTMLInputElementImpl::SEARCH)
558 static_cast<RenderLineEdit*>(input->renderer())->addSearchResult();
562 if (current->id() == ID_INPUT &&
563 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::TEXT &&
564 static_cast<HTMLInputElementImpl*>(current)->autoComplete() )
566 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl *>(current);
567 view->addFormCompletionItem(input->name().string(), input->value().string());
571 if (needButtonActivation) {
572 if (current->isActivatedSubmit()) {
573 needButtonActivation = false;
574 } else if (firstSuccessfulSubmitButton == 0 && current->isSuccessfulSubmitButton()) {
575 firstSuccessfulSubmitButton = current;
580 if (needButtonActivation && firstSuccessfulSubmitButton) {
581 firstSuccessfulSubmitButton->setActivatedSubmit(true);
585 if (formData(form_data)) {
587 part->submitForm( "post", m_url.string(), form_data,
590 boundary().string() );
593 part->submitForm( "get", m_url.string(), form_data,
598 if (needButtonActivation && firstSuccessfulSubmitButton) {
599 firstSuccessfulSubmitButton->setActivatedSubmit(false);
602 m_doingsubmit = m_insubmit = false;
605 void HTMLFormElementImpl::reset( )
607 KHTMLPart *part = getDocument()->part();
608 if(m_inreset || !part) return;
613 kdDebug( 6030 ) << "reset pressed!" << endl;
616 // ### DOM2 labels this event as not cancelable, however
617 // common browsers( sick! ) allow it be cancelled.
618 if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) {
623 for (unsigned i = 0; i < formElements.count(); ++i)
624 formElements[i]->reset();
629 void HTMLFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
636 bool oldURLWasSecure = formWouldHaveSecureSubmission(m_url);
638 m_url = khtml::parseURL(attr->value());
640 bool newURLIsSecure = formWouldHaveSecureSubmission(m_url);
642 if (m_attached && (oldURLWasSecure != newURLIsSecure))
644 getDocument()->secureFormAdded();
646 getDocument()->secureFormRemoved();
651 m_target = attr->value();
654 if ( strcasecmp( attr->value(), "post" ) == 0 )
656 else if ( strcasecmp( attr->value(), "get" ) == 0 )
660 parseEnctype(attr->value());
662 case ATTR_ACCEPT_CHARSET:
663 // space separated list of charsets the server
664 // accepts - see rfc2045
665 m_acceptcharset = attr->value();
668 // ignore this one for the moment...
670 case ATTR_AUTOCOMPLETE:
671 m_autocomplete = strcasecmp( attr->value(), "off" );
674 setHTMLEventListener(EventImpl::SUBMIT_EVENT,
675 getDocument()->createHTMLEventListener(attr->value().string(), this));
678 setHTMLEventListener(EventImpl::RESET_EVENT,
679 getDocument()->createHTMLEventListener(attr->value().string(), this));
683 QString newNameAttr = attr->value().string();
684 if (attached() && getDocument()->isHTMLDocument()) {
685 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
686 document->removeNamedImageOrForm(oldNameAttr);
687 document->addNamedImageOrForm(newNameAttr);
689 oldNameAttr = newNameAttr;
694 QString newIdAttr = attr->value().string();
695 if (attached() && getDocument()->isHTMLDocument()) {
696 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
697 document->removeNamedImageOrForm(oldIdAttr);
698 document->addNamedImageOrForm(newIdAttr);
700 oldIdAttr = newIdAttr;
704 HTMLElementImpl::parseHTMLAttribute(attr);
708 void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
710 for (unsigned i = 0; i < formElements.count(); ++i) {
711 HTMLGenericFormElementImpl *current = formElements[i];
712 if (current->id() == ID_INPUT &&
713 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
714 current != caller && current->form() == caller->form() && current->name() == caller->name()) {
715 static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
720 template<class T> static void appendToVector(QPtrVector<T> &vec, T *item)
722 unsigned size = vec.size();
723 unsigned count = vec.count();
725 vec.resize(size == 0 ? 8 : (int)(size * 1.5));
726 vec.insert(count, item);
729 template<class T> static void removeFromVector(QPtrVector<T> &vec, T *item)
731 int pos = vec.findRef(item);
732 int count = vec.count();
737 for (int i = pos; i < count - 1; i++) {
738 vec.insert(i, vec[i+1]);
740 vec.remove(count - 1);
743 void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
745 appendToVector(formElements, e);
746 removeFromVector(dormantFormElements, e);
749 void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
751 removeFromVector(formElements, e);
752 removeFromVector(dormantFormElements, e);
755 void HTMLFormElementImpl::makeFormElementDormant(HTMLGenericFormElementImpl *e)
757 appendToVector(dormantFormElements, e);
758 removeFromVector(formElements, e);
761 bool HTMLFormElementImpl::isURLAttribute(AttributeImpl *attr) const
763 return attr->id() == ATTR_ACTION;
766 void HTMLFormElementImpl::registerImgElement(HTMLImageElementImpl *e)
768 appendToVector(imgElements, e);
771 void HTMLFormElementImpl::removeImgElement(HTMLImageElementImpl *e)
773 removeFromVector(imgElements, e);
776 SharedPtr<HTMLCollectionImpl> HTMLFormElementImpl::elements()
778 return SharedPtr<HTMLCollectionImpl>(new HTMLFormCollectionImpl(this));
781 DOMString HTMLFormElementImpl::name() const
783 return getAttribute(ATTR_NAME);
786 void HTMLFormElementImpl::setName(const DOMString &value)
788 setAttribute(ATTR_NAME, value);
791 DOMString HTMLFormElementImpl::acceptCharset() const
793 return getAttribute(ATTR_ACCEPT_CHARSET);
796 void HTMLFormElementImpl::setAcceptCharset(const DOMString &value)
798 setAttribute(ATTR_ACCEPT_CHARSET, value);
801 DOMString HTMLFormElementImpl::action() const
803 return getAttribute(ATTR_ACTION);
806 void HTMLFormElementImpl::setAction(const DOMString &value)
808 setAttribute(ATTR_ACTION, value);
811 void HTMLFormElementImpl::setEnctype(const DOMString &value)
813 setAttribute(ATTR_ENCTYPE, value);
816 DOMString HTMLFormElementImpl::method() const
818 return getAttribute(ATTR_METHOD);
821 void HTMLFormElementImpl::setMethod(const DOMString &value)
823 setAttribute(ATTR_METHOD, value);
826 DOMString HTMLFormElementImpl::target() const
828 return getAttribute(ATTR_TARGET);
831 void HTMLFormElementImpl::setTarget(const DOMString &value)
833 setAttribute(ATTR_TARGET, value);
836 // -------------------------------------------------------------------------
838 HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
839 : HTMLElementImpl(doc)
841 m_disabled = m_readOnly = false;
849 m_form->registerFormElement(this);
852 HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl()
855 m_form->removeFormElement(this);
858 void HTMLGenericFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
864 case ATTR_DISABLED: {
865 bool oldDisabled = m_disabled;
866 m_disabled = !attr->isNull();
867 if (oldDisabled != m_disabled)
871 case ATTR_READONLY: {
872 bool oldReadOnly = m_readOnly;
873 m_readOnly = !attr->isNull();
874 if (oldReadOnly != m_readOnly) setChanged();
878 HTMLElementImpl::parseHTMLAttribute(attr);
882 void HTMLGenericFormElementImpl::attach()
886 // FIXME: This handles the case of a new form element being created by
887 // JavaScript and inserted inside a form. What it does not handle is
888 // a form element being moved from inside a form to outside, or from one
889 // inside one form to another. The reason this other case is hard to fix
890 // is that during parsing, we may have been passed a form that we are not
891 // inside, DOM-tree-wise. If so, it's hard for us to know when we should
892 // be removed from that form's element list.
896 m_form->registerFormElement(this);
899 HTMLElementImpl::attach();
901 // The call to updateFromElement() needs to go after the call through
902 // to the base class's attach() because that can sometimes do a close
905 m_render->updateFromElement();
907 // Delayed attachment in order to prevent FOUC can result in an object being
908 // programmatically focused before it has a render object. If we have been focused
909 // (i.e., if we are the focusNode) then go ahead and focus our corresponding native widget.
910 // (Attach/detach can also happen as a result of display type changes, e.g., making a widget
911 // block instead of inline, and focus should be restored in that case as well.)
912 if (getDocument()->focusNode() == this && m_render->isWidget() &&
913 static_cast<RenderWidget*>(renderer())->widget())
914 static_cast<RenderWidget*>(renderer())->widget()->setFocus();
918 void HTMLGenericFormElementImpl::insertedIntoDocument()
920 if (m_form && m_dormant)
921 m_form->registerFormElement(this);
925 HTMLElementImpl::insertedIntoDocument();
928 void HTMLGenericFormElementImpl::removedFromDocument()
931 m_form->makeFormElementDormant(this);
935 HTMLElementImpl::removedFromDocument();
938 HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
940 NodeImpl *p = parentNode();
943 if( p->id() == ID_FORM )
944 return static_cast<HTMLFormElementImpl *>(p);
948 kdDebug( 6030 ) << "couldn't find form!" << endl;
953 DOMString HTMLGenericFormElementImpl::name() const
955 if (!m_overrideName.isNull())
956 return m_overrideName;
958 DOMString n = getAttribute(ATTR_NAME);
959 return n.isNull() ? "" : n;
962 void HTMLGenericFormElementImpl::setName(const DOMString &value)
964 setAttribute(ATTR_NAME, value);
967 void HTMLGenericFormElementImpl::setOverrideName(const DOMString& value)
969 m_overrideName = value;
972 void HTMLGenericFormElementImpl::onSelect()
974 // ### make this work with new form events architecture
975 dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false);
978 void HTMLGenericFormElementImpl::onChange()
980 // ### make this work with new form events architecture
981 dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false);
984 bool HTMLGenericFormElementImpl::disabled() const
989 void HTMLGenericFormElementImpl::setDisabled(bool b)
991 setAttribute(ATTR_DISABLED, b ? "" : 0);
994 void HTMLGenericFormElementImpl::setReadOnly(bool b)
996 setAttribute(ATTR_READONLY, b ? "" : 0);
999 void HTMLGenericFormElementImpl::recalcStyle( StyleChange ch )
1001 //bool changed = changed();
1002 HTMLElementImpl::recalcStyle( ch );
1004 if (m_render /*&& changed*/)
1005 m_render->updateFromElement();
1008 bool HTMLGenericFormElementImpl::isFocusable() const
1010 if (!m_render || (m_render->style() && m_render->style()->visibility() != VISIBLE) || m_render->width() == 0 || m_render->height() == 0)
1015 bool HTMLGenericFormElementImpl::isKeyboardFocusable() const
1017 if (isFocusable()) {
1018 if (m_render->isWidget()) {
1019 return static_cast<RenderWidget*>(m_render)->widget() &&
1020 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::TabFocus);
1022 if (getDocument()->part())
1023 return getDocument()->part()->tabsToAllControls();
1028 bool HTMLGenericFormElementImpl::isMouseFocusable() const
1030 if (isFocusable()) {
1031 if (m_render->isWidget()) {
1032 return static_cast<RenderWidget*>(m_render)->widget() &&
1033 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::ClickFocus);
1036 // For <input type=image> and <button>, we will assume no mouse focusability. This is
1037 // consistent with OS X behavior for buttons.
1046 void HTMLGenericFormElementImpl::defaultEventHandler(EventImpl *evt)
1048 if (evt->target()==this)
1050 // Report focus in/out changes to the browser extension (editable widgets only)
1051 KHTMLPart *part = getDocument()->part();
1052 if (evt->id()==EventImpl::DOMFOCUSIN_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
1053 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
1054 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
1056 ext->editableWidgetFocused(widget);
1060 // We don't want this default key event handling, we'll count on
1061 // Cocoa event dispatch if the event doesn't get blocked.
1063 if (evt->id()==EventImpl::KEYDOWN_EVENT ||
1064 evt->id()==EventImpl::KEYUP_EVENT)
1066 KeyboardEventImpl * k = static_cast<KeyboardEventImpl *>(evt);
1067 if (k->keyVal() == QChar('\n').unicode() && m_render && m_render->isWidget() && k->qKeyEvent)
1068 QApplication::sendEvent(static_cast<RenderWidget *>(m_render)->widget(), k->qKeyEvent);
1072 if (evt->id()==EventImpl::DOMFOCUSOUT_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
1073 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
1074 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
1076 ext->editableWidgetBlurred(widget);
1078 // ### Don't count popup as a valid reason for losing the focus (example: opening the options of a select
1079 // combobox shouldn't emit onblur)
1082 HTMLElementImpl::defaultEventHandler(evt);
1085 bool HTMLGenericFormElementImpl::isEditable()
1090 // Special chars used to encode form state strings.
1091 // We pick chars that are unlikely to be used in an HTML attr, so we rarely have to really encode.
1092 const char stateSeparator = '&';
1093 const char stateEscape = '<';
1094 static const char stateSeparatorMarker[] = "<A";
1095 static const char stateEscapeMarker[] = "<<";
1097 // Encode an element name so we can put it in a state string without colliding
1098 // with our separator char.
1099 static QString encodedElementName(QString str)
1101 int sepLoc = str.find(stateSeparator);
1102 int escLoc = str.find(stateSeparator);
1103 if (sepLoc >= 0 || escLoc >= 0) {
1104 QString newStr = str;
1105 // replace "<" with "<<"
1106 while (escLoc >= 0) {
1107 newStr.replace(escLoc, 1, stateEscapeMarker);
1108 escLoc = str.find(stateSeparator, escLoc+1);
1110 // replace "&" with "<A"
1111 while (sepLoc >= 0) {
1112 newStr.replace(sepLoc, 1, stateSeparatorMarker);
1113 sepLoc = str.find(stateSeparator, sepLoc+1);
1121 QString HTMLGenericFormElementImpl::state( )
1123 // Build a string that contains ElementName&ElementType&
1124 return encodedElementName(name().string()) + stateSeparator + type().string() + stateSeparator;
1127 QString HTMLGenericFormElementImpl::findMatchingState(QStringList &states)
1129 QString encName = encodedElementName(name().string());
1130 QString typeStr = type().string();
1131 for (QStringList::Iterator it = states.begin(); it != states.end(); ++it) {
1132 QString state = *it;
1133 int sep1 = state.find(stateSeparator);
1134 int sep2 = state.find(stateSeparator, sep1+1);
1138 QString nameAndType = state.left(sep2);
1139 if (encName.length() + typeStr.length() + 1 == (uint)sep2
1140 && nameAndType.startsWith(encName)
1141 && nameAndType.endsWith(typeStr))
1144 return state.mid(sep2+1);
1147 return QString::null;
1150 long HTMLGenericFormElementImpl::tabIndex() const
1152 return getAttribute(ATTR_TABINDEX).toInt();
1155 void HTMLGenericFormElementImpl::setTabIndex(long value)
1157 setAttribute(ATTR_TABINDEX, QString::number(value));
1160 // -------------------------------------------------------------------------
1162 HTMLButtonElementImpl::HTMLButtonElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1163 : HTMLGenericFormElementImpl(doc, f)
1167 m_activeSubmit = false;
1170 HTMLButtonElementImpl::~HTMLButtonElementImpl()
1174 NodeImpl::Id HTMLButtonElementImpl::id() const
1179 DOMString HTMLButtonElementImpl::type() const
1181 return getAttribute(ATTR_TYPE);
1184 void HTMLButtonElementImpl::blur()
1186 if(getDocument()->focusNode() == this)
1187 getDocument()->setFocusNode(0);
1190 void HTMLButtonElementImpl::focus()
1192 getDocument()->setFocusNode(this);
1195 void HTMLButtonElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1200 if ( strcasecmp( attr->value(), "submit" ) == 0 )
1202 else if ( strcasecmp( attr->value(), "reset" ) == 0 )
1204 else if ( strcasecmp( attr->value(), "button" ) == 0 )
1208 m_value = attr->value();
1209 m_currValue = m_value;
1211 case ATTR_ACCESSKEY:
1214 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1215 getDocument()->createHTMLEventListener(attr->value().string(), this));
1218 setHTMLEventListener(EventImpl::BLUR_EVENT,
1219 getDocument()->createHTMLEventListener(attr->value().string(), this));
1222 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1226 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
1228 if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT)) {
1230 if(m_form && m_type == SUBMIT) {
1231 m_activeSubmit = true;
1232 m_form->prepareSubmit();
1233 m_activeSubmit = false; // in case we were canceled
1235 if(m_form && m_type == RESET) m_form->reset();
1237 HTMLGenericFormElementImpl::defaultEventHandler(evt);
1240 bool HTMLButtonElementImpl::isSuccessfulSubmitButton() const
1242 // HTML spec says that buttons must have names
1243 // to be considered successful. However, other browsers
1244 // do not impose this constraint. Therefore, we behave
1245 // differently and can use different buttons than the
1247 // Remove the name constraint for now.
1248 // Was: m_type == SUBMIT && !m_disabled && !name().isEmpty()
1249 return m_type == SUBMIT && !m_disabled;
1252 bool HTMLButtonElementImpl::isActivatedSubmit() const
1254 return m_activeSubmit;
1257 void HTMLButtonElementImpl::setActivatedSubmit(bool flag)
1259 m_activeSubmit = flag;
1262 bool HTMLButtonElementImpl::appendFormData(FormDataList& encoding, bool /*multipart*/)
1264 if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
1266 encoding.appendData(name(), m_currValue);
1270 void HTMLButtonElementImpl::click(bool sendMouseEvents)
1274 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1275 // using this method gives us nice Cocoa user interface feedback
1276 static_cast<QButton *>(widget)->click(sendMouseEvents);
1280 HTMLGenericFormElementImpl::click(sendMouseEvents);
1283 void HTMLButtonElementImpl::accessKeyAction(bool sendToAnyElement)
1285 // send the mouse button events iff the
1286 // caller specified sendToAnyElement
1287 click(sendToAnyElement);
1290 DOMString HTMLButtonElementImpl::accessKey() const
1292 return getAttribute(ATTR_ACCESSKEY);
1295 void HTMLButtonElementImpl::setAccessKey(const DOMString &value)
1297 setAttribute(ATTR_ACCESSKEY, value);
1300 DOMString HTMLButtonElementImpl::value() const
1302 return getAttribute(ATTR_VALUE);
1305 void HTMLButtonElementImpl::setValue(const DOMString &value)
1307 setAttribute(ATTR_VALUE, value);
1310 // -------------------------------------------------------------------------
1312 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1313 : HTMLGenericFormElementImpl(doc, f)
1317 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
1321 bool HTMLFieldSetElementImpl::isFocusable() const
1326 NodeImpl::Id HTMLFieldSetElementImpl::id() const
1331 DOMString HTMLFieldSetElementImpl::type() const
1336 RenderObject* HTMLFieldSetElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
1338 return new (arena) RenderFieldset(this);
1341 // -------------------------------------------------------------------------
1343 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1344 : HTMLGenericFormElementImpl(doc, f), m_imageLoader(0), m_valueMatchesRenderer(false)
1350 m_defaultChecked = false;
1351 m_useDefaultChecked = true;
1354 m_activeSubmit = false;
1355 m_autocomplete = true;
1364 m_autocomplete = f->autoComplete();
1367 HTMLInputElementImpl::~HTMLInputElementImpl()
1369 if (getDocument()) getDocument()->deregisterMaintainsState(this);
1370 delete m_imageLoader;
1373 NodeImpl::Id HTMLInputElementImpl::id() const
1378 void HTMLInputElementImpl::setType(const DOMString& t)
1382 if ( strcasecmp( t, "password" ) == 0 )
1384 else if ( strcasecmp( t, "checkbox" ) == 0 )
1386 else if ( strcasecmp( t, "radio" ) == 0 )
1388 else if ( strcasecmp( t, "submit" ) == 0 )
1390 else if ( strcasecmp( t, "reset" ) == 0 )
1392 else if ( strcasecmp( t, "file" ) == 0 )
1394 else if ( strcasecmp( t, "hidden" ) == 0 )
1396 else if ( strcasecmp( t, "image" ) == 0 )
1398 else if ( strcasecmp( t, "button" ) == 0 )
1400 else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
1403 else if ( strcasecmp( t, "search" ) == 0 )
1405 else if ( strcasecmp( t, "range" ) == 0 )
1411 // ### IMPORTANT: Don't allow the type to be changed to FILE after the first
1412 // type change, otherwise a JavaScript programmer would be able to set a text
1413 // field's value to something like /etc/passwd and then change it to a file field.
1414 if (m_type != newType) {
1415 if (newType == FILE && m_haveType) {
1416 // Set the attribute back to the old value.
1417 // Useful in case we were called from inside parseHTMLAttribute.
1418 setAttribute(ATTR_TYPE, type());
1420 bool wasAttached = m_attached;
1423 bool didStoreValue = storesValueSeparateFromAttribute();
1425 bool willStoreValue = storesValueSeparateFromAttribute();
1426 if (didStoreValue && !willStoreValue && !m_value.isNull()) {
1427 setAttribute(ATTR_VALUE, m_value);
1428 m_value = DOMString();
1430 if (!didStoreValue && willStoreValue) {
1431 m_value = getAttribute(ATTR_VALUE);
1440 DOMString HTMLInputElementImpl::type() const
1442 // needs to be lowercase according to DOM spec
1444 case TEXT: return "text";
1445 case PASSWORD: return "password";
1446 case CHECKBOX: return "checkbox";
1447 case RADIO: return "radio";
1448 case SUBMIT: return "submit";
1449 case RESET: return "reset";
1450 case FILE: return "file";
1451 case HIDDEN: return "hidden";
1452 case IMAGE: return "image";
1453 case BUTTON: return "button";
1455 case SEARCH: return "search";
1456 case RANGE: return "range";
1458 case ISINDEX: return "";
1463 QString HTMLInputElementImpl::state( )
1465 assert(m_type != PASSWORD); // should never save/restore password fields
1467 QString state = HTMLGenericFormElementImpl::state();
1471 return state + (checked() ? "on" : "off");
1473 return state + value().string()+'.'; // Make sure the string is not empty!
1477 void HTMLInputElementImpl::restoreState(QStringList &states)
1479 assert(m_type != PASSWORD); // should never save/restore password fields
1481 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
1482 if (state.isNull()) return;
1487 setChecked((state == "on"));
1490 setValue(DOMString(state.left(state.length()-1)));
1495 void HTMLInputElementImpl::select( )
1497 if(!m_render) return;
1501 static_cast<RenderFileButton*>(m_render)->select();
1508 static_cast<RenderLineEdit*>(m_render)->select();
1525 void HTMLInputElementImpl::click(bool sendMouseEvents)
1527 switch (inputType()) {
1529 // a no-op for this type
1539 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1540 // using this method gives us nice Cocoa user interface feedback
1541 static_cast<QButton *>(widget)->click(sendMouseEvents);
1546 HTMLGenericFormElementImpl::click(sendMouseEvents);
1551 static_cast<RenderFileButton *>(renderer())->click(sendMouseEvents);
1555 HTMLGenericFormElementImpl::click(sendMouseEvents);
1565 HTMLGenericFormElementImpl::click(sendMouseEvents);
1570 void HTMLInputElementImpl::accessKeyAction(bool sendToAnyElement)
1572 switch (inputType()) {
1574 // a no-op for this type
1597 // send the mouse button events iff the
1598 // caller specified sendToAnyElement
1599 click(sendToAnyElement);
1604 bool HTMLInputElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
1611 result = eUniversal;
1614 result = eReplaced; // Share with <img> since the alignment behavior is the same.
1620 return HTMLElementImpl::mapToEntry(attr, result);
1623 void HTMLInputElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1627 case ATTR_AUTOCOMPLETE:
1628 m_autocomplete = strcasecmp( attr->value(), "off" );
1631 setType(attr->value());
1632 if (m_type != IMAGE && m_imageLoader) {
1633 delete m_imageLoader;
1638 // We only need to setChanged if the form is looking at the default value right now.
1639 if (m_value.isNull())
1641 m_valueMatchesRenderer = false;
1644 m_defaultChecked = !attr->isNull();
1645 if (m_useDefaultChecked) {
1646 setChecked(m_defaultChecked);
1647 m_useDefaultChecked = true;
1650 case ATTR_MAXLENGTH:
1651 m_maxLen = !attr->isNull() ? attr->value().toInt() : -1;
1655 m_size = !attr->isNull() ? attr->value().toInt() : 20;
1658 if (m_render && m_type == IMAGE)
1659 static_cast<RenderImage*>(m_render)->updateAltText();
1662 if (m_render && m_type == IMAGE) {
1664 m_imageLoader = new HTMLImageLoader(this);
1665 m_imageLoader->updateFromElement();
1669 case ATTR_ACCESSKEY:
1670 // ### ignore for the moment
1673 addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
1674 addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
1677 addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
1678 addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
1681 addHTMLAlignment(attr);
1684 addCSSLength(attr, CSS_PROP_WIDTH, attr->value() );
1687 addCSSLength(attr, CSS_PROP_HEIGHT, attr->value() );
1690 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1691 getDocument()->createHTMLEventListener(attr->value().string(), this));
1694 setHTMLEventListener(EventImpl::BLUR_EVENT,
1695 getDocument()->createHTMLEventListener(attr->value().string(), this));
1698 setHTMLEventListener(EventImpl::SELECT_EVENT,
1699 getDocument()->createHTMLEventListener(attr->value().string(), this));
1702 setHTMLEventListener(EventImpl::CHANGE_EVENT,
1703 getDocument()->createHTMLEventListener(attr->value().string(), this));
1706 setHTMLEventListener(EventImpl::INPUT_EVENT,
1707 getDocument()->createHTMLEventListener(attr->value().string(), this));
1709 // Search field and slider attributes all just cause updateFromElement to be called through style
1712 setHTMLEventListener(EventImpl::SEARCH_EVENT,
1713 getDocument()->createHTMLEventListener(attr->value().string(), this));
1716 m_maxResults = !attr->isNull() ? attr->value().toInt() : -1;
1719 case ATTR_INCREMENTAL:
1720 case ATTR_PLACEHOLDER:
1723 case ATTR_PRECISION:
1727 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1731 bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
1748 case BUTTON: return HTMLGenericFormElementImpl::rendererIsNeeded(style);
1749 case HIDDEN: return false;
1755 RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1764 case ISINDEX: return new (arena) RenderLineEdit(this);
1765 case CHECKBOX: return new (arena) RenderCheckBox(this);
1766 case RADIO: return new (arena) RenderRadioButton(this);
1767 case SUBMIT: return new (arena) RenderSubmitButton(this);
1768 case IMAGE: return new (arena) RenderImageButton(this);
1769 case RESET: return new (arena) RenderResetButton(this);
1770 case FILE: return new (arena) RenderFileButton(this);
1771 case BUTTON: return new (arena) RenderPushButton(this);
1773 case RANGE: return new (arena) RenderSlider(this);
1781 void HTMLInputElementImpl::attach()
1785 setType(getAttribute(ATTR_TYPE));
1787 // FIXME: This needs to be dynamic, doesn't it, since someone could set this
1788 // after attachment?
1789 DOMString val = getAttribute(ATTR_VALUE);
1790 if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
1791 // remove newline stuff..
1793 for (unsigned int i = 0; i < val.length(); ++i)
1797 if (val.length() != nvalue.length())
1798 setAttribute(ATTR_VALUE, nvalue);
1801 m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
1806 // Disallow the width attribute on inputs other than HIDDEN and IMAGE.
1807 // Dumb Web sites will try to set the width as an attribute on form controls that aren't
1808 // images or hidden.
1809 if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
1811 removeAttribute(ATTR_WIDTH, excCode);
1814 HTMLGenericFormElementImpl::attach();
1816 if (m_type == IMAGE) {
1818 m_imageLoader = new HTMLImageLoader(this);
1819 m_imageLoader->updateFromElement();
1821 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
1822 imageObj->setImage(m_imageLoader->image());
1827 // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
1828 // was such that it cleared our state too early
1829 if (m_type == PASSWORD)
1830 getDocument()->passwordFieldAdded();
1834 void HTMLInputElementImpl::detach()
1836 HTMLGenericFormElementImpl::detach();
1837 m_valueMatchesRenderer = false;
1840 DOMString HTMLInputElementImpl::altText() const
1842 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1843 // also heavily discussed by Hixie on bugzilla
1844 // note this is intentionally different to HTMLImageElementImpl::altText()
1845 DOMString alt = getAttribute( ATTR_ALT );
1846 // fall back to title attribute
1848 alt = getAttribute( ATTR_TITLE );
1850 alt = getAttribute( ATTR_VALUE );
1851 if ( alt.isEmpty() )
1853 alt = inputElementAltText();
1855 alt = i18n( "Submit" );
1861 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1863 // HTML spec says that buttons must have names
1864 // to be considered successful. However, other browsers
1865 // do not impose this constraint. Therefore, we behave
1866 // differently and can use different buttons than the
1868 // Was: (m_type == SUBMIT && !name().isEmpty())
1869 return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1872 bool HTMLInputElementImpl::isActivatedSubmit() const
1874 return m_activeSubmit;
1877 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1879 m_activeSubmit = flag;
1882 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1884 // image generates its own names
1885 if (name().isEmpty() && m_type != IMAGE) return false;
1895 // always successful
1896 encoding.appendData(name(), value());
1902 encoding.appendData(name(), value());
1909 // those buttons are never successful
1915 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1916 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1917 if (!name().isEmpty() && !value().isEmpty())
1918 encoding.appendData(name(), value());
1926 QString enc_str = valueWithDefault().string();
1927 if (!enc_str.isEmpty()) {
1928 encoding.appendData(name(), enc_str);
1936 // can't submit file on GET
1937 // don't submit if display: none or display: hidden
1938 if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1941 // if no filename at all is entered, return successful, however empty
1942 // null would be more logical but netscape posts an empty file. argh.
1943 if (value().isEmpty()) {
1944 encoding.appendData(name(), QString(""));
1949 encoding.appendFile(name(), value());
1952 KURL fileurl("file:///");
1953 fileurl.setPath(value().string());
1954 KIO::UDSEntry filestat;
1956 if (!KIO::NetAccess::stat(fileurl, filestat)) {
1957 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1961 KFileItem fileitem(filestat, fileurl, true, false);
1962 if (fileitem.isDir()) {
1967 if ( KIO::NetAccess::download(fileurl, local) )
1970 if (file.open(IO_ReadOnly))
1972 QCString filearray(file.size()+1);
1973 int readbytes = file.readBlock( filearray.data(), file.size());
1974 if ( readbytes >= 0 )
1975 filearray[readbytes] = '\0';
1978 encoding.appendData(name(), filearray);
1979 KIO::NetAccess::removeTempFile( local );
1986 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1993 encoding.appendData(name(), value());
1999 void HTMLInputElementImpl::reset()
2001 if (storesValueSeparateFromAttribute())
2002 setValue(DOMString());
2003 setChecked(m_defaultChecked);
2004 m_useDefaultChecked = true;
2007 void HTMLInputElementImpl::setChecked(bool _checked)
2009 if (checked() == _checked) return;
2011 if (m_form && m_type == RADIO && _checked && !name().isEmpty())
2012 m_form->radioClicked(this);
2014 m_useDefaultChecked = false;
2015 m_checked = _checked;
2020 DOMString HTMLInputElementImpl::value() const
2022 DOMString value = m_value;
2024 // It's important *not* to fall back to the value attribute for file inputs,
2025 // because that would allow a malicious web page to upload files by setting the
2026 // value attribute in markup.
2027 if (value.isNull() && m_type != FILE)
2028 value = getAttribute(ATTR_VALUE);
2030 // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
2031 if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
2032 return DOMString(checked() ? "on" : "");
2037 DOMString HTMLInputElementImpl::valueWithDefault() const
2039 DOMString v = value();
2044 v = resetButtonDefaultLabel();
2052 v = submitButtonDefaultLabel();
2077 void HTMLInputElementImpl::setValue(const DOMString &value)
2079 if (m_type == FILE) return;
2081 if (storesValueSeparateFromAttribute()) {
2085 setAttribute(ATTR_VALUE, value);
2087 m_valueMatchesRenderer = false;
2090 void HTMLInputElementImpl::setValueFromRenderer(const DOMString &value)
2093 m_valueMatchesRenderer = true;
2095 // Fire the "input" DOM event.
2096 dispatchHTMLEvent(EventImpl::INPUT_EVENT, true, false);
2099 bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
2125 void HTMLInputElementImpl::blur()
2127 if(getDocument()->focusNode() == this)
2128 getDocument()->setFocusNode(0);
2131 void HTMLInputElementImpl::focus()
2133 getDocument()->setFocusNode(this);
2136 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
2138 if (evt->isMouseEvent() &&
2139 ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
2142 // record the mouse position for when we get the DOMActivate event
2143 MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
2144 int offsetX, offsetY;
2145 m_render->absolutePosition(offsetX,offsetY);
2146 xPos = me->clientX()-offsetX;
2147 yPos = me->clientY()-offsetY;
2149 me->setDefaultHandled();
2152 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2153 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2154 // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
2155 // must dispatch a DOMActivate event - a click event will not do the job.
2156 if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
2157 (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
2162 if (m_type == RESET) {
2166 m_activeSubmit = true;
2167 if (!m_form->prepareSubmit()) {
2171 m_activeSubmit = false;
2176 // Use key press event here since sending simulated mouse events
2177 // on key down blocks the proper sending of the key press event.
2178 if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
2179 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2188 // Simulate mouse click for enter or spacebar for these types of elements.
2189 // The AppKit already does this for spacebar for some, but not all, of them.
2190 if (key == "U+000020" || key == "Enter") {
2192 evt->setDefaultHandled();
2201 // Simulate mouse click on the default form button for enter for these types of elements.
2202 if (key == "Enter" && m_form) {
2203 m_form->submitClick();
2204 evt->setDefaultHandled();
2211 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2214 bool HTMLInputElementImpl::isEditable()
2216 return ((m_type == TEXT) || (m_type == PASSWORD) ||
2217 (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
2220 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
2222 return (attr->id() == ATTR_SRC);
2225 DOMString HTMLInputElementImpl::defaultValue() const
2227 return getAttribute(ATTR_VALUE);
2230 void HTMLInputElementImpl::setDefaultValue(const DOMString &value)
2232 setAttribute(ATTR_VALUE, value);
2235 bool HTMLInputElementImpl::defaultChecked() const
2237 return !getAttribute(ATTR_CHECKED).isNull();
2240 void HTMLInputElementImpl::setDefaultChecked(bool defaultChecked)
2242 setAttribute(ATTR_CHECKED, defaultChecked ? "" : 0);
2245 DOMString HTMLInputElementImpl::accept() const
2247 return getAttribute(ATTR_ACCEPT);
2250 void HTMLInputElementImpl::setAccept(const DOMString &value)
2252 setAttribute(ATTR_ACCEPT, value);
2255 DOMString HTMLInputElementImpl::accessKey() const
2257 return getAttribute(ATTR_ACCESSKEY);
2260 void HTMLInputElementImpl::setAccessKey(const DOMString &value)
2262 setAttribute(ATTR_ACCESSKEY, value);
2265 DOMString HTMLInputElementImpl::align() const
2267 return getAttribute(ATTR_ALIGN);
2270 void HTMLInputElementImpl::setAlign(const DOMString &value)
2272 setAttribute(ATTR_ALIGN, value);
2275 DOMString HTMLInputElementImpl::alt() const
2277 return getAttribute(ATTR_ALT);
2280 void HTMLInputElementImpl::setAlt(const DOMString &value)
2282 setAttribute(ATTR_ALT, value);
2285 void HTMLInputElementImpl::setMaxLength(long _maxLength)
2287 setAttribute(ATTR_MAXLENGTH, QString::number(_maxLength));
2290 DOMString HTMLInputElementImpl::sizeDOM() const
2292 return getAttribute(ATTR_SIZE);
2295 void HTMLInputElementImpl::setSize(const DOMString &value)
2297 setAttribute(ATTR_SIZE, value);
2300 DOMString HTMLInputElementImpl::src() const
2302 return getDocument()->completeURL(getAttribute(ATTR_SRC));
2305 void HTMLInputElementImpl::setSrc(const DOMString &value)
2307 setAttribute(ATTR_SRC, value);
2310 DOMString HTMLInputElementImpl::useMap() const
2312 return getAttribute(ATTR_USEMAP);
2315 void HTMLInputElementImpl::setUseMap(const DOMString &value)
2317 setAttribute(ATTR_USEMAP, value);
2320 // -------------------------------------------------------------------------
2322 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
2323 : HTMLElementImpl(doc)
2327 HTMLLabelElementImpl::~HTMLLabelElementImpl()
2331 bool HTMLLabelElementImpl::isFocusable() const
2336 NodeImpl::Id HTMLLabelElementImpl::id() const
2341 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2346 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2347 getDocument()->createHTMLEventListener(attr->value().string(), this));
2350 setHTMLEventListener(EventImpl::BLUR_EVENT,
2351 getDocument()->createHTMLEventListener(attr->value().string(), this));
2354 HTMLElementImpl::parseHTMLAttribute(attr);
2358 ElementImpl *HTMLLabelElementImpl::formElement()
2360 DOMString formElementId = getAttribute(ATTR_FOR);
2361 if (formElementId.isNull()) {
2362 // Search children of the label element for a form element.
2363 NodeImpl *node = this;
2364 while ((node = node->traverseNextNode(this))) {
2365 if (node->isHTMLElement()) {
2366 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
2367 if (element->isGenericFormElement()) {
2374 if (formElementId.isEmpty())
2376 return getDocument()->getElementById(formElementId);
2379 void HTMLLabelElementImpl::accessKeyAction(bool sendToAnyElement)
2381 ElementImpl *element = formElement();
2383 element->accessKeyAction(sendToAnyElement);
2386 HTMLFormElementImpl *HTMLLabelElementImpl::form()
2388 ElementImpl *element = formElement();
2389 if (element && isGenericFormElement())
2390 return static_cast<HTMLGenericFormElementImpl *>(element)->form();
2394 DOMString HTMLLabelElementImpl::accessKey() const
2396 return getAttribute(ATTR_ACCESSKEY);
2399 void HTMLLabelElementImpl::setAccessKey(const DOMString &value)
2401 setAttribute(ATTR_ACCESSKEY, value);
2404 DOMString HTMLLabelElementImpl::htmlFor() const
2406 return getAttribute(ATTR_FOR);
2409 void HTMLLabelElementImpl::setHtmlFor(const DOMString &value)
2411 setAttribute(ATTR_FOR, value);
2414 // -------------------------------------------------------------------------
2416 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2417 : HTMLGenericFormElementImpl(doc, f)
2421 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2425 bool HTMLLegendElementImpl::isFocusable() const
2430 NodeImpl::Id HTMLLegendElementImpl::id() const
2435 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2437 return new (arena) RenderLegend(this);
2440 DOMString HTMLLegendElementImpl::type() const
2445 DOMString HTMLLegendElementImpl::accessKey() const
2447 return getAttribute(ATTR_ACCESSKEY);
2450 void HTMLLegendElementImpl::setAccessKey(const DOMString &value)
2452 setAttribute(ATTR_ACCESSKEY, value);
2455 DOMString HTMLLegendElementImpl::align() const
2457 return getAttribute(ATTR_ALIGN);
2460 void HTMLLegendElementImpl::setAlign(const DOMString &value)
2462 setAttribute(ATTR_ALIGN, value);
2465 // -------------------------------------------------------------------------
2467 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2468 : HTMLGenericFormElementImpl(doc, f), m_options(0)
2471 m_recalcListItems = false;
2472 // 0 means invalid (i.e. not set)
2477 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2479 if (getDocument()) getDocument()->deregisterMaintainsState(this);
2481 m_options->detach();
2486 NodeImpl::Id HTMLSelectElementImpl::id() const
2491 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2493 if (hasChangedChild() && m_render) {
2494 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2497 HTMLGenericFormElementImpl::recalcStyle( ch );
2501 DOMString HTMLSelectElementImpl::type() const
2503 return (m_multiple ? "select-multiple" : "select-one");
2506 long HTMLSelectElementImpl::selectedIndex() const
2508 // return the number of the first option selected
2510 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2511 for (unsigned int i = 0; i < items.size(); i++) {
2512 if (items[i]->id() == ID_OPTION) {
2513 if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2518 Q_ASSERT(m_multiple);
2522 void HTMLSelectElementImpl::setSelectedIndex( long index )
2524 // deselect all other options and select only the new one
2525 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2527 for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2528 if (items[listIndex]->id() == ID_OPTION)
2529 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2531 listIndex = optionToListIndex(index);
2533 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2538 long HTMLSelectElementImpl::length() const
2542 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2543 for (i = 0; i < items.size(); i++) {
2544 if (items[i]->id() == ID_OPTION)
2550 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2552 if (!element || element->id() != ID_OPTION)
2555 int exceptioncode = 0;
2556 insertBefore(element, before, exceptioncode);
2558 setRecalcListItems();
2561 void HTMLSelectElementImpl::remove( long index )
2563 int exceptioncode = 0;
2564 int listIndex = optionToListIndex(index);
2566 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2567 if(listIndex < 0 || index >= int(items.size()))
2568 return; // ### what should we do ? remove the last item?
2570 removeChild(items[listIndex], exceptioncode);
2571 if( !exceptioncode )
2572 setRecalcListItems();
2575 void HTMLSelectElementImpl::blur()
2577 if(getDocument()->focusNode() == this)
2578 getDocument()->setFocusNode(0);
2581 void HTMLSelectElementImpl::focus()
2583 getDocument()->setFocusNode(this);
2586 DOMString HTMLSelectElementImpl::value( )
2589 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2590 for (i = 0; i < items.size(); i++) {
2591 if ( items[i]->id() == ID_OPTION
2592 && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2593 return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2595 return DOMString("");
2598 void HTMLSelectElementImpl::setValue(const DOMString &value)
2602 // find the option with value() matching the given parameter
2603 // and make it the current selection.
2604 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2605 for (unsigned i = 0; i < items.size(); i++)
2606 if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2607 static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2612 QString HTMLSelectElementImpl::state( )
2617 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2619 int l = items.count();
2622 QChar stateChars[l];
2624 for(int i = 0; i < l; i++)
2625 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2626 stateChars[i] = 'X';
2628 stateChars[i] = '.';
2629 QString state(stateChars, l);
2630 #else /* APPLE_CHANGES not defined */
2632 for(int i = 0; i < l; i++)
2633 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2635 #endif /* APPLE_CHANGES not defined */
2637 return HTMLGenericFormElementImpl::state() + state;
2640 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2642 QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2643 if (_state.isNull()) return;
2647 QString state = _state;
2648 if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2649 qWarning("should not happen in restoreState!");
2651 // KWQString doesn't support this operation. Should never get here anyway.
2658 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2660 int l = items.count();
2661 for(int i = 0; i < l; i++) {
2662 if(items[i]->id() == ID_OPTION) {
2663 HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2664 oe->setSelected(state[i] == 'X');
2670 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2672 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2674 setRecalcListItems();
2678 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2680 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2681 if( !exceptioncode )
2682 setRecalcListItems();
2686 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2688 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2689 if( !exceptioncode )
2690 setRecalcListItems();
2694 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2696 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2697 if( !exceptioncode )
2698 setRecalcListItems();
2703 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2705 setRecalcListItems();
2706 return HTMLGenericFormElementImpl::addChild(newChild);
2709 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2714 m_size = kMax( attr->value().toInt(), 1 );
2717 m_minwidth = kMax( attr->value().toInt(), 0 );
2720 m_multiple = (!attr->isNull());
2722 case ATTR_ACCESSKEY:
2723 // ### ignore for the moment
2726 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2727 getDocument()->createHTMLEventListener(attr->value().string(), this));
2730 setHTMLEventListener(EventImpl::BLUR_EVENT,
2731 getDocument()->createHTMLEventListener(attr->value().string(), this));
2734 setHTMLEventListener(EventImpl::CHANGE_EVENT,
2735 getDocument()->createHTMLEventListener(attr->value().string(), this));
2738 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2742 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2744 return new (arena) RenderSelect(this);
2747 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2749 bool successful = false;
2750 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2753 for (i = 0; i < items.size(); i++) {
2754 if (items[i]->id() == ID_OPTION) {
2755 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2756 if (option->selected()) {
2757 encoded_values.appendData(name(), option->value());
2763 // ### this case should not happen. make sure that we select the first option
2764 // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2765 // we return the first one if it was a combobox select
2766 if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2767 (items[0]->id() == ID_OPTION) ) {
2768 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2769 if (option->value().isNull())
2770 encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2772 encoded_values.appendData(name(), option->value());
2779 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2781 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2782 if (optionIndex < 0 || optionIndex >= int(items.size()))
2786 int optionIndex2 = 0;
2788 optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2789 listIndex++) { // not a typo!
2790 if (items[listIndex]->id() == ID_OPTION)
2797 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2799 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2800 if (listIndex < 0 || listIndex >= int(items.size()) ||
2801 items[listIndex]->id() != ID_OPTION)
2804 int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2806 for (i = 0; i < listIndex; i++)
2807 if (items[i]->id() == ID_OPTION)
2812 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2815 m_options = new HTMLOptionsCollectionImpl(this);
2821 // FIXME: Delete once the above function is working well enough to use for real.
2822 SharedPtr<HTMLCollectionImpl> HTMLSelectElementImpl::optionsHTMLCollection()
2824 return SharedPtr<HTMLCollectionImpl>(new HTMLCollectionImpl(this, HTMLCollectionImpl::SELECT_OPTIONS));
2827 void HTMLSelectElementImpl::recalcListItems()
2829 NodeImpl* current = firstChild();
2830 m_listItems.resize(0);
2831 HTMLOptionElementImpl* foundSelected = 0;
2833 if (current->id() == ID_OPTGROUP && current->firstChild()) {
2834 // ### what if optgroup contains just comments? don't want one of no options in it...
2835 m_listItems.resize(m_listItems.size()+1);
2836 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2837 current = current->firstChild();
2839 if (current->id() == ID_OPTION) {
2840 m_listItems.resize(m_listItems.size()+1);
2841 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2842 if (!foundSelected && !m_multiple && m_size <= 1) {
2843 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2844 foundSelected->m_selected = true;
2846 else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2847 foundSelected->m_selected = false;
2848 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2851 NodeImpl *parent = current->parentNode();
2852 current = current->nextSibling();
2855 current = parent->nextSibling();
2858 m_recalcListItems = false;
2861 void HTMLSelectElementImpl::childrenChanged()
2863 setRecalcListItems();
2865 HTMLGenericFormElementImpl::childrenChanged();
2868 void HTMLSelectElementImpl::setRecalcListItems()
2870 m_recalcListItems = true;
2872 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2876 void HTMLSelectElementImpl::reset()
2878 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2880 for (i = 0; i < items.size(); i++) {
2881 if (items[i]->id() == ID_OPTION) {
2882 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2883 bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2884 option->setSelected(selected);
2888 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2892 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2894 if (selected && !m_multiple) {
2895 // deselect all other options
2896 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2898 for (i = 0; i < items.size(); i++) {
2899 if (items[i]->id() == ID_OPTION)
2900 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2904 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2909 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2911 // Use key press event here since sending simulated mouse events
2912 // on key down blocks the proper sending of the key press event.
2913 if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2915 if (!m_form || !m_render || !evt->isKeyboardEvent())
2918 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2920 if (key == "Enter") {
2921 m_form->submitClick();
2922 evt->setDefaultHandled();
2925 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2928 void HTMLSelectElementImpl::accessKeyAction(bool sendToAnyElement)
2933 void HTMLSelectElementImpl::setMultiple(bool multiple)
2935 setAttribute(ATTR_MULTIPLE, multiple ? "" : 0);
2938 void HTMLSelectElementImpl::setSize(long size)
2940 setAttribute(ATTR_SIZE, QString::number(size));
2943 // -------------------------------------------------------------------------
2945 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2946 : HTMLSelectElementImpl(doc, f)
2948 QStringList keys = KSSLKeyGen::supportedKeySizes();
2949 for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2950 HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2952 o->addChild(new TextImpl(doc, DOMString(*i)));
2956 NodeImpl::Id HTMLKeygenElementImpl::id() const
2961 DOMString HTMLKeygenElementImpl::type() const
2966 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2970 case ATTR_CHALLENGE:
2971 m_challenge = attr->value();
2974 m_keyType = attr->value();
2977 // skip HTMLSelectElementImpl parsing!
2978 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2982 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2985 // Only RSA is supported at this time.
2986 if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2989 QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2990 if (value.isNull()) {
2993 encoded_values.appendData(name(), value.utf8());
2996 bool successful = false;
2998 // pop up the fancy certificate creation dialog here
2999 KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
3002 successful = (QDialog::Accepted == kg->exec());
3006 encoded_values.appendData(name(), "deadbeef");
3012 // -------------------------------------------------------------------------
3014 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3015 : HTMLGenericFormElementImpl(doc, f)
3019 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
3023 bool HTMLOptGroupElementImpl::isFocusable() const
3028 NodeImpl::Id HTMLOptGroupElementImpl::id() const
3033 DOMString HTMLOptGroupElementImpl::type() const
3038 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
3040 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
3041 if ( !exceptioncode )
3042 recalcSelectOptions();
3046 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
3048 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
3050 recalcSelectOptions();
3054 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
3056 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
3057 if( !exceptioncode )
3058 recalcSelectOptions();
3062 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
3064 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
3065 if( !exceptioncode )
3066 recalcSelectOptions();
3070 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
3072 recalcSelectOptions();
3074 return HTMLGenericFormElementImpl::addChild(newChild);
3077 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
3079 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3080 recalcSelectOptions();
3083 void HTMLOptGroupElementImpl::recalcSelectOptions()
3085 NodeImpl *select = parentNode();
3086 while (select && select->id() != ID_SELECT)
3087 select = select->parentNode();
3089 static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
3092 DOMString HTMLOptGroupElementImpl::label() const
3094 return getAttribute(ATTR_LABEL);
3097 void HTMLOptGroupElementImpl::setLabel(const DOMString &value)
3099 setAttribute(ATTR_LABEL, value);
3102 // -------------------------------------------------------------------------
3104 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3105 : HTMLGenericFormElementImpl(doc, f)
3110 bool HTMLOptionElementImpl::isFocusable() const
3115 NodeImpl::Id HTMLOptionElementImpl::id() const
3120 DOMString HTMLOptionElementImpl::type() const
3125 DOMString HTMLOptionElementImpl::text() const
3129 // WinIE does not use the label attribute, so as a quirk, we ignore it.
3130 if (getDocument() && !getDocument()->inCompatMode()) {
3131 DOMString text = getAttribute(ATTR_LABEL);
3132 if (!text.isEmpty())
3136 const NodeImpl *n = this;
3137 while ((n = n->traverseNextNode(this))) {
3138 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
3139 text += n->nodeValue();
3145 void HTMLOptionElementImpl::setText(const DOMString &text, int &exception)
3147 // Handle the common special case where there's exactly 1 child node, and it's a text node.
3148 NodeImpl *child = firstChild();
3149 if (child && child->isTextNode() && !child->nextSibling()) {
3150 static_cast<TextImpl *>(child)->setData(text, exception);
3155 appendChild(new TextImpl(docPtr(), text), exception);
3158 long HTMLOptionElementImpl::index() const
3160 // Let's do this dynamically. Might be a bit slow, but we're sure
3161 // we won't forget to update a member variable in some cases...
3162 QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
3163 int l = items.count();
3164 int optionIndex = 0;
3165 for(int i = 0; i < l; i++) {
3166 if(items[i]->id() == ID_OPTION)
3168 if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
3173 kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
3177 void HTMLOptionElementImpl::setIndex(long, int &exception)
3179 exception = DOMException::NO_MODIFICATION_ALLOWED_ERR;
3180 kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
3184 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
3189 m_selected = (!attr->isNull());
3192 m_value = attr->value();
3195 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3199 DOMString HTMLOptionElementImpl::value() const
3201 if ( !m_value.isNull() )
3203 // Use the text if the value wasn't set.
3204 return text().string().stripWhiteSpace();
3207 void HTMLOptionElementImpl::setValue(const DOMString &value)
3209 setAttribute(ATTR_VALUE, value);
3212 void HTMLOptionElementImpl::setSelected(bool _selected)
3214 if(m_selected == _selected)
3216 m_selected = _selected;
3217 HTMLSelectElementImpl *select = getSelect();
3219 select->notifyOptionSelected(this,_selected);
3222 void HTMLOptionElementImpl::childrenChanged()
3224 HTMLSelectElementImpl *select = getSelect();
3226 select->childrenChanged();
3229 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
3231 NodeImpl *select = parentNode();
3232 while (select && select->id() != ID_SELECT)
3233 select = select->parentNode();
3234 return static_cast<HTMLSelectElementImpl*>(select);
3237 bool HTMLOptionElementImpl::defaultSelected() const
3239 return !getAttribute(ATTR_SELECTED).isNull();
3242 void HTMLOptionElementImpl::setDefaultSelected(bool b)
3244 setAttribute(ATTR_SELECTED, b ? "" : 0);
3247 DOMString HTMLOptionElementImpl::label() const
3249 return getAttribute(ATTR_LABEL);
3252 void HTMLOptionElementImpl::setLabel(const DOMString &value)
3254 setAttribute(ATTR_LABEL, value);
3257 // -------------------------------------------------------------------------
3259 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3260 : HTMLGenericFormElementImpl(doc, f), m_valueIsValid(false), m_valueMatchesRenderer(false)
3262 // DTD requires rows & cols be specified, but we will provide reasonable defaults
3265 m_wrap = ta_Virtual;
3268 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
3270 if (getDocument()) getDocument()->deregisterMaintainsState(this);
3273 NodeImpl::Id HTMLTextAreaElementImpl::id() const
3278 DOMString HTMLTextAreaElementImpl::type() const
3283 QString HTMLTextAreaElementImpl::state( )
3285 // Make sure the string is not empty!
3286 return HTMLGenericFormElementImpl::state() + value().string()+'.';
3289 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
3291 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
3292 if (state.isNull()) return;
3293 setDefaultValue(state.left(state.length()-1));
3294 // the close() in the rendertree will take care of transferring defaultvalue to 'value'
3297 void HTMLTextAreaElementImpl::select( )
3300 static_cast<RenderTextArea*>(m_render)->select();
3304 void HTMLTextAreaElementImpl::childrenChanged()
3306 setValue(defaultValue());
3309 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
3314 m_rows = !attr->isNull() ? attr->value().toInt() : 3;
3316 renderer()->setNeedsLayoutAndMinMaxRecalc();
3319 m_cols = !attr->isNull() ? attr->value().toInt() : 60;
3321 renderer()->setNeedsLayoutAndMinMaxRecalc();
3324 // virtual / physical is Netscape extension of HTML 3.0, now deprecated
3325 // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
3326 if ( strcasecmp( attr->value(), "virtual" ) == 0 || strcasecmp( attr->value(), "soft") == 0)
3327 m_wrap = ta_Virtual;
3328 else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
3329 m_wrap = ta_Physical;
3330 else if(strcasecmp( attr->value(), "on" ) == 0)
3331 m_wrap = ta_Physical;
3332 else if(strcasecmp( attr->value(), "off") == 0)
3335 renderer()->setNeedsLayoutAndMinMaxRecalc();
3337 case ATTR_ACCESSKEY:
3338 // ignore for the moment
3341 setHTMLEventListener(EventImpl::FOCUS_EVENT,
3342 getDocument()->createHTMLEventListener(attr->value().string(), this));
3345 setHTMLEventListener(EventImpl::BLUR_EVENT,
3346 getDocument()->createHTMLEventListener(attr->value().string(), this));
3349 setHTMLEventListener(EventImpl::SELECT_EVENT,
3350 getDocument()->createHTMLEventListener(attr->value().string(), this));
3353 setHTMLEventListener(EventImpl::CHANGE_EVENT,
3354 getDocument()->createHTMLEventListener(attr->value().string(), this));
3357 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3361 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
3363 return new (arena) RenderTextArea(this);
3366 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
3368 if (name().isEmpty()) return false;
3369 encoding.appendData(name(), value());
3373 void HTMLTextAreaElementImpl::reset()
3375 setValue(defaultValue());
3378 void HTMLTextAreaElementImpl::updateValue()
3380 if ( !m_valueIsValid ) {
3382 m_value = static_cast<RenderTextArea*>( m_render )->text();
3383 m_valueMatchesRenderer = true;
3385 m_value = defaultValue().string();
3386 m_valueMatchesRenderer = false;
3388 m_valueIsValid = true;
3392 DOMString HTMLTextAreaElementImpl::value()
3395 return m_value.isNull() ? DOMString("") : m_value;
3398 void HTMLTextAreaElementImpl::setValue(const DOMString &value)
3400 m_value = value.string();
3401 m_valueIsValid = true;
3402 m_valueMatchesRenderer = false;
3407 DOMString HTMLTextAreaElementImpl::defaultValue()
3410 // there may be comments - just grab the text nodes
3412 for (n = firstChild(); n; n = n->nextSibling())
3413 if (n->isTextNode())
3414 val += static_cast<TextImpl*>(n)->data();
3415 if (val[0] == '\r' && val[1] == '\n') {
3419 else if (val[0] == '\r' || val[0] == '\n') {
3427 void HTMLTextAreaElementImpl::setDefaultValue(const DOMString &defaultValue)
3429 // there may be comments - remove all the text nodes and replace them with one
3430 QPtrList<NodeImpl> toRemove;
3432 for (n = firstChild(); n; n = n->nextSibling())
3433 if (n->isTextNode())
3435 QPtrListIterator<NodeImpl> it(toRemove);
3436 int exceptioncode = 0;
3437 for (; it.current(); ++it) {
3438 removeChild(it.current(), exceptioncode);
3440 insertBefore(getDocument()->createTextNode(defaultValue),firstChild(), exceptioncode);
3441 setValue(defaultValue);
3444 void HTMLTextAreaElementImpl::blur()
3446 if(getDocument()->focusNode() == this)
3447 getDocument()->setFocusNode(0);
3450 void HTMLTextAreaElementImpl::focus()
3452 getDocument()->setFocusNode(this);
3455 bool HTMLTextAreaElementImpl::isEditable()
3460 void HTMLTextAreaElementImpl::accessKeyAction(bool sendToAnyElement)
3465 void HTMLTextAreaElementImpl::detach()
3467 HTMLGenericFormElementImpl::detach();
3468 m_valueMatchesRenderer = false;
3471 DOMString HTMLTextAreaElementImpl::accessKey() const
3473 return getAttribute(ATTR_ACCESSKEY);
3476 void HTMLTextAreaElementImpl::setAccessKey(const DOMString &value)
3478 setAttribute(ATTR_ACCESSKEY, value);
3481 void HTMLTextAreaElementImpl::setCols(long cols)
3483 setAttribute(ATTR_COLS, QString::number(cols));
3486 void HTMLTextAreaElementImpl::setRows(long rows)
3488 setAttribute(ATTR_ROWS, QString::number(rows));
3491 // -------------------------------------------------------------------------
3493 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3494 : HTMLInputElementImpl(doc, f)
3497 setOverrideName("isindex");
3500 NodeImpl::Id HTMLIsIndexElementImpl::id() const
3505 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
3510 setValue(attr->value());
3512 // don't call HTMLInputElement::parseHTMLAttribute here, as it would
3513 // accept attributes this element does not support
3514 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3518 DOMString HTMLIsIndexElementImpl::prompt() const
3520 return getAttribute(ATTR_PROMPT);
3523 void HTMLIsIndexElementImpl::setPrompt(const DOMString &value)
3525 setAttribute(ATTR_PROMPT, value);
3528 // -------------------------------------------------------------------------
3530 unsigned long HTMLOptionsCollectionImpl::length() const
3532 // Not yet implemented.
3536 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3538 // Not yet implemented.
3541 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3543 // Not yet implemented.
3547 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3549 // Not yet implemented.
3553 // -------------------------------------------------------------------------
3555 FormDataList::FormDataList(QTextCodec *c)
3560 void FormDataList::appendString(const QCString &s)
3565 void FormDataList::appendString(const QString &s)
3567 QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3568 cstr.truncate(cstr.length());
3569 m_list.append(cstr);
3572 void FormDataList::appendFile(const DOMString &key, const DOMString &filename)
3574 appendString(key.string());
3575 m_list.append(filename.string());