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 "css/cssstyleselector.h"
40 #include "css/cssproperties.h"
41 #include "css/csshelper.h"
42 #include "xml/dom_textimpl.h"
43 #include "xml/dom2_eventsimpl.h"
44 #include "khtml_ext.h"
46 #include "rendering/render_form.h"
48 #include <kcharsets.h>
51 #include <kmimetype.h>
52 #include <kmessagebox.h>
54 #include <netaccess.h>
55 #include <kfileitem.h>
57 #include <qtextcodec.h>
61 #include <ksslkeygen.h>
65 using namespace khtml;
69 struct FormDataListItem {
70 FormDataListItem(const QCString &data) : m_data(data) { }
71 FormDataListItem(const QString &path) : m_path(path) { }
79 FormDataList(QTextCodec *);
81 void appendData(const DOMString &key, const DOMString &value)
82 { appendString(key.string()); appendString(value.string()); }
83 void appendData(const DOMString &key, const QString &value)
84 { appendString(key.string()); appendString(value); }
85 void appendData(const DOMString &key, const QCString &value)
86 { appendString(key.string()); appendString(value); }
87 void appendData(const DOMString &key, int value)
88 { appendString(key.string()); appendString(QString::number(value)); }
89 void appendFile(const DOMString &key, const DOMString &filename);
91 QValueListConstIterator<FormDataListItem> begin() const
92 { return m_list.begin(); }
93 QValueListConstIterator<FormDataListItem> end() const
94 { return m_list.end(); }
97 void appendString(const QCString &s);
98 void appendString(const QString &s);
101 QValueList<FormDataListItem> m_list;
104 HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc)
105 : HTMLElementImpl(doc)
110 m_autocomplete = true;
112 m_doingsubmit = false;
114 m_enctype = "application/x-www-form-urlencoded";
115 m_boundary = "----------0xKhTmLbOuNdArY";
116 m_acceptcharset = "UNKNOWN";
120 HTMLFormElementImpl::~HTMLFormElementImpl()
122 delete collectionInfo;
124 for (unsigned i = 0; i < formElements.count(); ++i)
125 formElements[i]->m_form = 0;
126 for (unsigned i = 0; i < dormantFormElements.count(); ++i)
127 dormantFormElements[i]->m_form = 0;
128 for (unsigned i = 0; i < imgElements.count(); ++i)
129 imgElements[i]->m_form = 0;
132 NodeImpl::Id HTMLFormElementImpl::id() const
139 bool HTMLFormElementImpl::formWouldHaveSecureSubmission(const DOMString &url)
144 return getDocument()->completeURL(url.string()).startsWith("https:", false);
149 void HTMLFormElementImpl::attach()
151 HTMLElementImpl::attach();
153 if (getDocument()->isHTMLDocument()) {
154 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
155 document->addNamedImageOrForm(oldNameAttr);
156 document->addNamedImageOrForm(oldIdAttr);
160 // note we don't deal with calling secureFormRemoved() on detach, because the timing
161 // was such that it cleared our state too early
162 if (formWouldHaveSecureSubmission(m_url))
163 getDocument()->secureFormAdded();
167 void HTMLFormElementImpl::detach()
169 if (getDocument()->isHTMLDocument()) {
170 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
171 document->removeNamedImageOrForm(oldNameAttr);
172 document->removeNamedImageOrForm(oldIdAttr);
175 HTMLElementImpl::detach();
178 long HTMLFormElementImpl::length() const
181 for (unsigned i = 0; i < formElements.count(); ++i)
182 if (formElements[i]->isEnumeratable())
190 void HTMLFormElementImpl::submitClick()
192 bool submitFound = false;
193 for (unsigned i = 0; i < formElements.count(); ++i) {
194 if (formElements[i]->id() == ID_INPUT) {
195 HTMLInputElementImpl *element = static_cast<HTMLInputElementImpl *>(formElements[i]);
196 if (element->isSuccessfulSubmitButton() && element->renderer()) {
198 element->click(false);
203 if (!submitFound) // submit the form without a submit or image input
207 #endif // APPLE_CHANGES
209 static QCString encodeCString(const QCString& e)
211 // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
212 // safe characters like NS handles them for compatibility
213 static const char *safe = "-._*";
214 int elen = e.length();
215 QCString encoded(( elen+e.contains( '\n' ) )*3+1);
218 //QCString orig(e.data(), e.size());
220 for(int pos = 0; pos < elen; pos++) {
221 unsigned char c = e[pos];
223 if ( (( c >= 'A') && ( c <= 'Z')) ||
224 (( c >= 'a') && ( c <= 'z')) ||
225 (( c >= '0') && ( c <= '9')) ||
228 encoded[enclen++] = c;
230 encoded[enclen++] = '+';
231 else if ( c == '\n' || ( c == '\r' && e[pos+1] != '\n' ) )
233 encoded[enclen++] = '%';
234 encoded[enclen++] = '0';
235 encoded[enclen++] = 'D';
236 encoded[enclen++] = '%';
237 encoded[enclen++] = '0';
238 encoded[enclen++] = 'A';
240 else if ( c != '\r' )
242 encoded[enclen++] = '%';
243 unsigned int h = c / 16;
244 h += (h > 9) ? ('A' - 10) : '0';
245 encoded[enclen++] = h;
247 unsigned int l = c % 16;
248 l += (l > 9) ? ('A' - 10) : '0';
249 encoded[enclen++] = l;
252 encoded[enclen++] = '\0';
253 encoded.truncate(enclen);
258 // Change plain CR and plain LF to CRLF pairs.
259 static QCString fixLineBreaks(const QCString &s)
261 // Compute the length.
263 const char *p = s.data();
264 while (char c = *p++) {
266 // Safe to look ahead because of trailing '\0'.
268 // Turn CR into CRLF.
271 } else if (c == '\n') {
272 // Turn LF into CRLF.
275 // Leave other characters alone.
279 if (newLen == s.length()) {
283 // Make a copy of the string.
285 QCString result(newLen + 1);
286 char *q = result.data();
287 while (char c = *p++) {
289 // Safe to look ahead because of trailing '\0'.
291 // Turn CR into CRLF.
295 } else if (c == '\n') {
296 // Turn LF into CRLF.
300 // Leave other characters alone.
309 void HTMLFormElementImpl::i18nData()
311 QString foo1 = i18n( "You're about to send data to the Internet "
312 "via an unencrypted connection. It might be possible "
313 "for others to see this information.\n"
314 "Do you want to continue?");
315 QString foo2 = i18n("KDE Web browser");
316 QString foo3 = i18n("When you send a password unencrypted to the Internet, "
317 "it might be possible for others to capture it as plain text.\n"
318 "Do you want to continue?");
319 QString foo5 = i18n("Your data submission is redirected to "
320 "an insecure site. The data is sent unencrypted.\n"
321 "Do you want to continue?");
322 QString foo6 = i18n("The page contents expired. You can repost the form"
323 "data by using <a href=\"javascript:go(0);\">Reload</a>");
328 bool HTMLFormElementImpl::formData(FormData &form_data) const
331 kdDebug( 6030 ) << "form: formData()" << endl;
334 QCString enc_string = ""; // used for non-multipart data
336 // find out the QTextcodec to use
337 QString str = m_acceptcharset.string();
338 str.replace(',', ' ');
339 QStringList charsets = QStringList::split(' ', str);
340 QTextCodec* codec = 0;
341 KHTMLPart *part = getDocument()->part();
342 for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
345 if(enc.contains("UNKNOWN"))
347 // use standard document encoding
350 enc = part->encoding();
352 if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
357 codec = QTextCodec::codecForLocale();
360 QStringList fileUploads;
363 for (unsigned i = 0; i < formElements.count(); ++i) {
364 HTMLGenericFormElementImpl* current = formElements[i];
365 FormDataList lst(codec);
367 if (!current->disabled() && current->appendFormData(lst, m_multipart))
369 //kdDebug(6030) << "adding name " << current->name().string() << endl;
370 for(QValueListConstIterator<FormDataListItem> it = lst.begin(); it != lst.end(); ++it )
374 // handle ISINDEX / <input name=isindex> special
375 // but only if its the first entry
376 if ( enc_string.isEmpty() && (*it).m_data == "isindex" ) {
378 enc_string += encodeCString( (*it).m_data );
381 if(!enc_string.isEmpty())
384 enc_string += encodeCString((*it).m_data);
387 enc_string += encodeCString((*it).m_data);
393 hstr += m_boundary.string().latin1();
395 hstr += "Content-Disposition: form-data; name=\"";
396 hstr += (*it).m_data.data();
399 // if the current type is FILE, then we also need to
400 // include the filename
401 if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
402 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
404 QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
406 if (path.length()) fileUploads << path;
409 // FIXME: This won't work if the filename includes a " mark,
410 // or control characters like CR or LF. This also does strange
411 // things if the filename includes characters you can't encode
412 // in the website's character set.
413 hstr += "; filename=\"";
414 hstr += codec->fromUnicode(path.mid(path.findRev('/') + 1));
417 if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
420 QString mimeType = part ? KWQ(part)->mimeTypeForFileName(path) : QString();
422 KMimeType::Ptr ptr = KMimeType::findByURL(KURL(path));
423 QString mimeType = ptr->name();
425 if (!mimeType.isEmpty()) {
426 hstr += "\r\nContent-Type: ";
427 hstr += mimeType.ascii();
436 form_data.appendData(hstr.data(), hstr.length());
438 const FormDataListItem &item = *it;
439 size_t dataSize = item.m_data.size();
441 form_data.appendData(item.m_data, dataSize - 1);
442 else if (!item.m_path.isEmpty())
443 form_data.appendFile(item.m_path);
445 form_data.appendData((*it).m_data, (*it).m_data.size() - 1);
447 form_data.appendData("\r\n", 2);
454 if (fileUploads.count()) {
455 int result = KMessageBox::warningContinueCancelList( 0,
456 i18n("You're about to transfer the following files from "
457 "your local computer to the Internet.\n"
458 "Do you really want to continue?"),
462 if (result == KMessageBox::Cancel) {
469 enc_string = ("--" + m_boundary.string() + "--\r\n").ascii();
471 form_data.appendData(enc_string.data(), enc_string.length());
475 void HTMLFormElementImpl::setEnctype( const DOMString& type )
477 if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1)
479 m_enctype = "multipart/form-data";
482 } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1)
484 m_enctype = "text/plain";
489 m_enctype = "application/x-www-form-urlencoded";
494 void HTMLFormElementImpl::setBoundary( const DOMString& bound )
499 bool HTMLFormElementImpl::prepareSubmit()
501 KHTMLPart *part = getDocument()->part();
502 if(m_insubmit || !part || part->onlyLocalReferences())
506 m_doingsubmit = false;
508 if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,false,true) && !m_doingsubmit )
509 m_doingsubmit = true;
516 return m_doingsubmit;
519 void HTMLFormElementImpl::submit( bool activateSubmitButton )
521 KHTMLView *view = getDocument()->view();
522 KHTMLPart *part = getDocument()->part();
523 if (!view || !part) {
528 m_doingsubmit = true;
535 kdDebug( 6030 ) << "submitting!" << endl;
538 HTMLGenericFormElementImpl* firstSuccessfulSubmitButton = 0;
539 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
542 KWQ(part)->clearRecordedFormValues();
544 for (unsigned i = 0; i < formElements.count(); ++i) {
545 HTMLGenericFormElementImpl* current = formElements[i];
547 // Our app needs to get form values for password fields for doing password autocomplete,
548 // so we are more lenient in pushing values, and let the app decide what to save when.
549 if (current->id() == ID_INPUT) {
550 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl*>(current);
551 if (input->inputType() == HTMLInputElementImpl::TEXT
552 || input->inputType() == HTMLInputElementImpl::PASSWORD
553 || input->inputType() == HTMLInputElementImpl::SEARCH)
555 KWQ(part)->recordFormValue(input->name().string(), input->value().string(), this);
556 if (input->renderer() && input->inputType() == HTMLInputElementImpl::SEARCH)
557 static_cast<RenderLineEdit*>(input->renderer())->addSearchResult();
561 if (current->id() == ID_INPUT &&
562 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::TEXT &&
563 static_cast<HTMLInputElementImpl*>(current)->autoComplete() )
565 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl *>(current);
566 view->addFormCompletionItem(input->name().string(), input->value().string());
570 if (needButtonActivation) {
571 if (current->isActivatedSubmit()) {
572 needButtonActivation = false;
573 } else if (firstSuccessfulSubmitButton == 0 && current->isSuccessfulSubmitButton()) {
574 firstSuccessfulSubmitButton = current;
579 if (needButtonActivation && firstSuccessfulSubmitButton) {
580 firstSuccessfulSubmitButton->setActivatedSubmit(true);
584 if (formData(form_data)) {
586 part->submitForm( "post", m_url.string(), form_data,
589 boundary().string() );
592 part->submitForm( "get", m_url.string(), form_data,
597 if (needButtonActivation && firstSuccessfulSubmitButton) {
598 firstSuccessfulSubmitButton->setActivatedSubmit(false);
601 m_doingsubmit = m_insubmit = false;
604 void HTMLFormElementImpl::reset( )
606 KHTMLPart *part = getDocument()->part();
607 if(m_inreset || !part) return;
612 kdDebug( 6030 ) << "reset pressed!" << endl;
615 // ### DOM2 labels this event as not cancelable, however
616 // common browsers( sick! ) allow it be cancelled.
617 if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) {
622 for (unsigned i = 0; i < formElements.count(); ++i)
623 formElements[i]->reset();
628 void HTMLFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
635 bool oldURLWasSecure = formWouldHaveSecureSubmission(m_url);
637 m_url = khtml::parseURL(attr->value());
639 bool newURLIsSecure = formWouldHaveSecureSubmission(m_url);
641 if (m_attached && (oldURLWasSecure != newURLIsSecure))
643 getDocument()->secureFormAdded();
645 getDocument()->secureFormRemoved();
650 m_target = attr->value();
653 if ( strcasecmp( attr->value(), "post" ) == 0 )
655 else if ( strcasecmp( attr->value(), "get" ) == 0 )
659 setEnctype( attr->value() );
661 case ATTR_ACCEPT_CHARSET:
662 // space separated list of charsets the server
663 // accepts - see rfc2045
664 m_acceptcharset = attr->value();
667 // ignore this one for the moment...
669 case ATTR_AUTOCOMPLETE:
670 m_autocomplete = strcasecmp( attr->value(), "off" );
673 setHTMLEventListener(EventImpl::SUBMIT_EVENT,
674 getDocument()->createHTMLEventListener(attr->value().string(), this));
677 setHTMLEventListener(EventImpl::RESET_EVENT,
678 getDocument()->createHTMLEventListener(attr->value().string(), this));
682 QString newNameAttr = attr->value().string();
683 if (attached() && getDocument()->isHTMLDocument()) {
684 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
685 document->removeNamedImageOrForm(oldNameAttr);
686 document->addNamedImageOrForm(newNameAttr);
688 oldNameAttr = newNameAttr;
693 QString newIdAttr = attr->value().string();
694 if (attached() && getDocument()->isHTMLDocument()) {
695 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
696 document->removeNamedImageOrForm(oldIdAttr);
697 document->addNamedImageOrForm(newIdAttr);
699 oldIdAttr = newIdAttr;
703 HTMLElementImpl::parseHTMLAttribute(attr);
707 void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
709 for (unsigned i = 0; i < formElements.count(); ++i) {
710 HTMLGenericFormElementImpl *current = formElements[i];
711 if (current->id() == ID_INPUT &&
712 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
713 current != caller && current->form() == caller->form() && current->name() == caller->name()) {
714 static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
719 template<class T> static void appendToVector(QPtrVector<T> &vec, T *item)
721 unsigned size = vec.size();
722 unsigned count = vec.count();
724 vec.resize(size == 0 ? 8 : (int)(size * 1.5));
725 vec.insert(count, item);
728 template<class T> static void removeFromVector(QPtrVector<T> &vec, T *item)
730 int pos = vec.findRef(item);
731 int count = vec.count();
736 for (int i = pos; i < count - 1; i++) {
737 vec.insert(i, vec[i+1]);
739 vec.remove(count - 1);
742 void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
744 appendToVector(formElements, e);
745 removeFromVector(dormantFormElements, e);
748 void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
750 removeFromVector(formElements, e);
751 removeFromVector(dormantFormElements, e);
754 void HTMLFormElementImpl::makeFormElementDormant(HTMLGenericFormElementImpl *e)
756 appendToVector(dormantFormElements, e);
757 removeFromVector(formElements, e);
760 bool HTMLFormElementImpl::isURLAttribute(AttributeImpl *attr) const
762 return attr->id() == ATTR_ACTION;
765 void HTMLFormElementImpl::registerImgElement(HTMLImageElementImpl *e)
767 appendToVector(imgElements, e);
770 void HTMLFormElementImpl::removeImgElement(HTMLImageElementImpl *e)
772 removeFromVector(imgElements, e);
775 // -------------------------------------------------------------------------
777 HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
778 : HTMLElementImpl(doc)
780 m_disabled = m_readOnly = false;
789 m_form->registerFormElement(this);
792 HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl()
795 m_form->removeFormElement(this);
796 if (m_name) m_name->deref();
799 void HTMLGenericFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
806 setDisabled( !attr->isNull() );
810 bool m_oldreadOnly = m_readOnly;
811 m_readOnly = !attr->isNull();
812 if (m_oldreadOnly != m_readOnly) setChanged();
816 HTMLElementImpl::parseHTMLAttribute(attr);
820 void HTMLGenericFormElementImpl::attach()
824 // FIXME: This handles the case of a new form element being created by
825 // JavaScript and inserted inside a form. What it does not handle is
826 // a form element being moved from inside a form to outside, or from one
827 // inside one form to another. The reason this other case is hard to fix
828 // is that during parsing, we may have been passed a form that we are not
829 // inside, DOM-tree-wise. If so, it's hard for us to know when we should
830 // be removed from that form's element list.
834 m_form->registerFormElement(this);
837 HTMLElementImpl::attach();
839 // The call to updateFromElement() needs to go after the call through
840 // to the base class's attach() because that can sometimes do a close
843 m_render->updateFromElement();
845 // Delayed attachment in order to prevent FOUC can result in an object being
846 // programmatically focused before it has a render object. If we have been focused
847 // (i.e., if we are the focusNode) then go ahead and focus our corresponding native widget.
848 // (Attach/detach can also happen as a result of display type changes, e.g., making a widget
849 // block instead of inline, and focus should be restored in that case as well.)
850 if (getDocument()->focusNode() == this && m_render->isWidget() &&
851 static_cast<RenderWidget*>(renderer())->widget())
852 static_cast<RenderWidget*>(renderer())->widget()->setFocus();
856 void HTMLGenericFormElementImpl::insertedIntoDocument()
858 if (m_form && m_dormant)
859 m_form->registerFormElement(this);
863 HTMLElementImpl::insertedIntoDocument();
866 void HTMLGenericFormElementImpl::removedFromDocument()
869 m_form->makeFormElementDormant(this);
873 HTMLElementImpl::removedFromDocument();
876 HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
878 NodeImpl *p = parentNode();
881 if( p->id() == ID_FORM )
882 return static_cast<HTMLFormElementImpl *>(p);
886 kdDebug( 6030 ) << "couldn't find form!" << endl;
891 DOMString HTMLGenericFormElementImpl::name() const
893 if (m_name) return m_name;
896 // DOMString n = getDocument()->htmlMode() != DocumentImpl::XHtml ?
897 // getAttribute(ATTR_NAME) : getAttribute(ATTR_ID);
898 DOMString n = getAttribute(ATTR_NAME);
900 return new DOMStringImpl("");
905 void HTMLGenericFormElementImpl::setName(const DOMString& name)
907 if (m_name) m_name->deref();
908 m_name = name.implementation();
909 if (m_name) m_name->ref();
912 void HTMLGenericFormElementImpl::onSelect()
914 // ### make this work with new form events architecture
915 dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false);
918 void HTMLGenericFormElementImpl::onChange()
920 // ### make this work with new form events architecture
921 dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false);
924 bool HTMLGenericFormElementImpl::disabled() const
929 void HTMLGenericFormElementImpl::setDisabled( bool _disabled )
931 if ( m_disabled != _disabled ) {
932 m_disabled = _disabled;
937 void HTMLGenericFormElementImpl::recalcStyle( StyleChange ch )
939 //bool changed = changed();
940 HTMLElementImpl::recalcStyle( ch );
942 if (m_render /*&& changed*/)
943 m_render->updateFromElement();
946 bool HTMLGenericFormElementImpl::isFocusable() const
948 if (!m_render || (m_render->style() && m_render->style()->visibility() != VISIBLE) || m_render->width() == 0 || m_render->height() == 0)
953 bool HTMLGenericFormElementImpl::isKeyboardFocusable() const
956 if (m_render->isWidget()) {
957 return static_cast<RenderWidget*>(m_render)->widget() &&
958 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::TabFocus);
960 if (getDocument()->part())
961 return getDocument()->part()->tabsToAllControls();
966 bool HTMLGenericFormElementImpl::isMouseFocusable() const
969 if (m_render->isWidget()) {
970 return static_cast<RenderWidget*>(m_render)->widget() &&
971 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::ClickFocus);
974 // For <input type=image> and <button>, we will assume no mouse focusability. This is
975 // consistent with OS X behavior for buttons.
984 void HTMLGenericFormElementImpl::defaultEventHandler(EventImpl *evt)
986 if (evt->target()==this)
988 // Report focus in/out changes to the browser extension (editable widgets only)
989 KHTMLPart *part = getDocument()->part();
990 if (evt->id()==EventImpl::DOMFOCUSIN_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
991 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
992 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
994 ext->editableWidgetFocused(widget);
998 // We don't want this default key event handling, we'll count on
999 // Cocoa event dispatch if the event doesn't get blocked.
1001 if (evt->id()==EventImpl::KEYDOWN_EVENT ||
1002 evt->id()==EventImpl::KEYUP_EVENT)
1004 KeyboardEventImpl * k = static_cast<KeyboardEventImpl *>(evt);
1005 if (k->keyVal() == QChar('\n').unicode() && m_render && m_render->isWidget() && k->qKeyEvent)
1006 QApplication::sendEvent(static_cast<RenderWidget *>(m_render)->widget(), k->qKeyEvent);
1010 if (evt->id()==EventImpl::DOMFOCUSOUT_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
1011 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
1012 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
1014 ext->editableWidgetBlurred(widget);
1016 // ### Don't count popup as a valid reason for losing the focus (example: opening the options of a select
1017 // combobox shouldn't emit onblur)
1020 HTMLElementImpl::defaultEventHandler(evt);
1023 bool HTMLGenericFormElementImpl::isEditable()
1028 // Special chars used to encode form state strings.
1029 // We pick chars that are unlikely to be used in an HTML attr, so we rarely have to really encode.
1030 const char stateSeparator = '&';
1031 const char stateEscape = '<';
1032 static const char stateSeparatorMarker[] = "<A";
1033 static const char stateEscapeMarker[] = "<<";
1035 // Encode an element name so we can put it in a state string without colliding
1036 // with our separator char.
1037 static QString encodedElementName(QString str)
1039 int sepLoc = str.find(stateSeparator);
1040 int escLoc = str.find(stateSeparator);
1041 if (sepLoc >= 0 || escLoc >= 0) {
1042 QString newStr = str;
1043 // replace "<" with "<<"
1044 while (escLoc >= 0) {
1045 newStr.replace(escLoc, 1, stateEscapeMarker);
1046 escLoc = str.find(stateSeparator, escLoc+1);
1048 // replace "&" with "<A"
1049 while (sepLoc >= 0) {
1050 newStr.replace(sepLoc, 1, stateSeparatorMarker);
1051 sepLoc = str.find(stateSeparator, sepLoc+1);
1059 QString HTMLGenericFormElementImpl::state( )
1061 // Build a string that contains ElementName&ElementType&
1062 return encodedElementName(name().string()) + stateSeparator + type().string() + stateSeparator;
1065 QString HTMLGenericFormElementImpl::findMatchingState(QStringList &states)
1067 QString encName = encodedElementName(name().string());
1068 QString typeStr = type().string();
1069 for (QStringList::Iterator it = states.begin(); it != states.end(); ++it) {
1070 QString state = *it;
1071 int sep1 = state.find(stateSeparator);
1072 int sep2 = state.find(stateSeparator, sep1+1);
1076 QString nameAndType = state.left(sep2);
1077 if (encName.length() + typeStr.length() + 1 == (uint)sep2
1078 && nameAndType.startsWith(encName)
1079 && nameAndType.endsWith(typeStr))
1082 return state.mid(sep2+1);
1085 return QString::null;
1088 // -------------------------------------------------------------------------
1090 HTMLButtonElementImpl::HTMLButtonElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1091 : HTMLGenericFormElementImpl(doc, f)
1095 m_activeSubmit = false;
1098 HTMLButtonElementImpl::~HTMLButtonElementImpl()
1102 NodeImpl::Id HTMLButtonElementImpl::id() const
1107 DOMString HTMLButtonElementImpl::type() const
1109 return getAttribute(ATTR_TYPE);
1112 void HTMLButtonElementImpl::blur()
1114 if(getDocument()->focusNode() == this)
1115 getDocument()->setFocusNode(0);
1118 void HTMLButtonElementImpl::focus()
1120 getDocument()->setFocusNode(this);
1123 void HTMLButtonElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1128 if ( strcasecmp( attr->value(), "submit" ) == 0 )
1130 else if ( strcasecmp( attr->value(), "reset" ) == 0 )
1132 else if ( strcasecmp( attr->value(), "button" ) == 0 )
1136 m_value = attr->value();
1137 m_currValue = m_value;
1139 case ATTR_ACCESSKEY:
1142 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1143 getDocument()->createHTMLEventListener(attr->value().string(), this));
1146 setHTMLEventListener(EventImpl::BLUR_EVENT,
1147 getDocument()->createHTMLEventListener(attr->value().string(), this));
1150 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1154 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
1156 if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT)) {
1158 if(m_form && m_type == SUBMIT) {
1159 m_activeSubmit = true;
1160 m_form->prepareSubmit();
1161 m_activeSubmit = false; // in case we were canceled
1163 if(m_form && m_type == RESET) m_form->reset();
1165 HTMLGenericFormElementImpl::defaultEventHandler(evt);
1168 bool HTMLButtonElementImpl::isSuccessfulSubmitButton() const
1170 // HTML spec says that buttons must have names
1171 // to be considered successful. However, other browsers
1172 // do not impose this constraint. Therefore, we behave
1173 // differently and can use different buttons than the
1175 // Remove the name constraint for now.
1176 // Was: m_type == SUBMIT && !m_disabled && !name().isEmpty()
1177 return m_type == SUBMIT && !m_disabled;
1180 bool HTMLButtonElementImpl::isActivatedSubmit() const
1182 return m_activeSubmit;
1185 void HTMLButtonElementImpl::setActivatedSubmit(bool flag)
1187 m_activeSubmit = flag;
1190 bool HTMLButtonElementImpl::appendFormData(FormDataList& encoding, bool /*multipart*/)
1192 if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
1194 encoding.appendData(name(), m_currValue);
1198 void HTMLButtonElementImpl::click(bool sendMouseEvents)
1202 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1203 // using this method gives us nice Cocoa user interface feedback
1204 static_cast<QButton *>(widget)->click(sendMouseEvents);
1208 HTMLGenericFormElementImpl::click(sendMouseEvents);
1211 void HTMLButtonElementImpl::accessKeyAction(bool sendToAnyElement)
1213 // send the mouse button events iff the
1214 // caller specified sendToAnyElement
1215 click(sendToAnyElement);
1218 // -------------------------------------------------------------------------
1220 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1221 : HTMLGenericFormElementImpl(doc, f)
1225 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
1229 bool HTMLFieldSetElementImpl::isFocusable() const
1234 NodeImpl::Id HTMLFieldSetElementImpl::id() const
1239 DOMString HTMLFieldSetElementImpl::type() const
1244 RenderObject* HTMLFieldSetElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
1246 return new (arena) RenderFieldset(this);
1249 // -------------------------------------------------------------------------
1251 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1252 : HTMLGenericFormElementImpl(doc, f), m_imageLoader(0), m_valueMatchesRenderer(false)
1258 m_defaultChecked = false;
1259 m_useDefaultChecked = true;
1262 m_activeSubmit = false;
1263 m_autocomplete = true;
1274 m_autocomplete = f->autoComplete();
1277 HTMLInputElementImpl::~HTMLInputElementImpl()
1279 if (getDocument()) getDocument()->deregisterMaintainsState(this);
1280 delete m_imageLoader;
1283 NodeImpl::Id HTMLInputElementImpl::id() const
1288 void HTMLInputElementImpl::setType(const DOMString& t)
1292 if ( strcasecmp( t, "password" ) == 0 )
1294 else if ( strcasecmp( t, "checkbox" ) == 0 )
1296 else if ( strcasecmp( t, "radio" ) == 0 )
1298 else if ( strcasecmp( t, "submit" ) == 0 )
1300 else if ( strcasecmp( t, "reset" ) == 0 )
1302 else if ( strcasecmp( t, "file" ) == 0 )
1304 else if ( strcasecmp( t, "hidden" ) == 0 )
1306 else if ( strcasecmp( t, "image" ) == 0 )
1308 else if ( strcasecmp( t, "button" ) == 0 )
1310 else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
1313 else if ( strcasecmp( t, "search" ) == 0 )
1315 else if ( strcasecmp( t, "range" ) == 0 )
1321 // ### IMPORTANT: Don't allow the type to be changed to FILE after the first
1322 // type change, otherwise a JavaScript programmer would be able to set a text
1323 // field's value to something like /etc/passwd and then change it to a file field.
1324 if (m_type != newType) {
1325 if (newType == FILE && m_haveType) {
1326 // Set the attribute back to the old value.
1327 // Useful in case we were called from inside parseHTMLAttribute.
1328 setAttribute(ATTR_TYPE, type());
1330 bool wasAttached = m_attached;
1333 bool didStoreValue = storesValueSeparateFromAttribute();
1335 bool willStoreValue = storesValueSeparateFromAttribute();
1336 if (didStoreValue && !willStoreValue && !m_value.isNull()) {
1337 setAttribute(ATTR_VALUE, m_value);
1338 m_value = DOMString();
1340 if (!didStoreValue && willStoreValue) {
1341 m_value = getAttribute(ATTR_VALUE);
1350 DOMString HTMLInputElementImpl::type() const
1352 // needs to be lowercase according to DOM spec
1354 case TEXT: return "text";
1355 case PASSWORD: return "password";
1356 case CHECKBOX: return "checkbox";
1357 case RADIO: return "radio";
1358 case SUBMIT: return "submit";
1359 case RESET: return "reset";
1360 case FILE: return "file";
1361 case HIDDEN: return "hidden";
1362 case IMAGE: return "image";
1363 case BUTTON: return "button";
1365 case SEARCH: return "search";
1366 case RANGE: return "range";
1368 case ISINDEX: return "";
1373 QString HTMLInputElementImpl::state( )
1375 assert(m_type != PASSWORD); // should never save/restore password fields
1377 QString state = HTMLGenericFormElementImpl::state();
1381 return state + (checked() ? "on" : "off");
1383 return state + value().string()+'.'; // Make sure the string is not empty!
1387 void HTMLInputElementImpl::restoreState(QStringList &states)
1389 assert(m_type != PASSWORD); // should never save/restore password fields
1391 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
1392 if (state.isNull()) return;
1397 setChecked((state == "on"));
1400 setValue(DOMString(state.left(state.length()-1)));
1405 void HTMLInputElementImpl::select( )
1407 if(!m_render) return;
1411 static_cast<RenderFileButton*>(m_render)->select();
1418 static_cast<RenderLineEdit*>(m_render)->select();
1435 void HTMLInputElementImpl::click(bool sendMouseEvents)
1437 switch (inputType()) {
1439 // a no-op for this type
1449 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1450 // using this method gives us nice Cocoa user interface feedback
1451 static_cast<QButton *>(widget)->click(sendMouseEvents);
1456 HTMLGenericFormElementImpl::click(sendMouseEvents);
1461 static_cast<RenderFileButton *>(renderer())->click(sendMouseEvents);
1465 HTMLGenericFormElementImpl::click(sendMouseEvents);
1475 HTMLGenericFormElementImpl::click(sendMouseEvents);
1480 void HTMLInputElementImpl::accessKeyAction(bool sendToAnyElement)
1482 switch (inputType()) {
1484 // a no-op for this type
1507 // send the mouse button events iff the
1508 // caller specified sendToAnyElement
1509 click(sendToAnyElement);
1514 bool HTMLInputElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
1521 result = eUniversal;
1524 result = eReplaced; // Share with <img> since the alignment behavior is the same.
1530 return HTMLElementImpl::mapToEntry(attr, result);
1533 void HTMLInputElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1537 case ATTR_AUTOCOMPLETE:
1538 m_autocomplete = strcasecmp( attr->value(), "off" );
1541 setType(attr->value());
1542 if (m_type != IMAGE && m_imageLoader) {
1543 delete m_imageLoader;
1548 // We only need to setChanged if the form is looking at the default value right now.
1549 if (m_value.isNull())
1551 m_valueMatchesRenderer = false;
1554 m_defaultChecked = !attr->isNull();
1555 if (m_useDefaultChecked) {
1556 setChecked(m_defaultChecked);
1557 m_useDefaultChecked = true;
1560 case ATTR_MAXLENGTH:
1561 m_maxLen = !attr->isNull() ? attr->value().toInt() : -1;
1565 m_size = !attr->isNull() ? attr->value().toInt() : 20;
1568 if (m_render && m_type == IMAGE)
1569 static_cast<RenderImage*>(m_render)->updateAltText();
1572 if (m_render && m_type == IMAGE) {
1574 m_imageLoader = new HTMLImageLoader(this);
1575 m_imageLoader->updateFromElement();
1579 case ATTR_ACCESSKEY:
1580 // ### ignore for the moment
1583 addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
1584 addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
1587 addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
1588 addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
1591 addHTMLAlignment(attr);
1594 addCSSLength(attr, CSS_PROP_WIDTH, attr->value() );
1597 addCSSLength(attr, CSS_PROP_HEIGHT, attr->value() );
1600 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1601 getDocument()->createHTMLEventListener(attr->value().string(), this));
1604 setHTMLEventListener(EventImpl::BLUR_EVENT,
1605 getDocument()->createHTMLEventListener(attr->value().string(), this));
1608 setHTMLEventListener(EventImpl::SELECT_EVENT,
1609 getDocument()->createHTMLEventListener(attr->value().string(), this));
1612 setHTMLEventListener(EventImpl::CHANGE_EVENT,
1613 getDocument()->createHTMLEventListener(attr->value().string(), this));
1616 setHTMLEventListener(EventImpl::INPUT_EVENT,
1617 getDocument()->createHTMLEventListener(attr->value().string(), this));
1620 // Search field and slider attributes all just cause updateFromElement to be called through style
1623 setHTMLEventListener(EventImpl::SEARCH_EVENT,
1624 getDocument()->createHTMLEventListener(attr->value().string(), this));
1627 m_maxResults = !attr->isNull() ? attr->value().toInt() : -1;
1630 case ATTR_INCREMENTAL:
1631 case ATTR_PLACEHOLDER:
1634 case ATTR_PRECISION:
1639 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1643 bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
1660 case BUTTON: return HTMLGenericFormElementImpl::rendererIsNeeded(style);
1661 case HIDDEN: return false;
1667 RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1676 case ISINDEX: return new (arena) RenderLineEdit(this);
1677 case CHECKBOX: return new (arena) RenderCheckBox(this);
1678 case RADIO: return new (arena) RenderRadioButton(this);
1679 case SUBMIT: return new (arena) RenderSubmitButton(this);
1680 case IMAGE: return new (arena) RenderImageButton(this);
1681 case RESET: return new (arena) RenderResetButton(this);
1682 case FILE: return new (arena) RenderFileButton(this);
1683 case BUTTON: return new (arena) RenderPushButton(this);
1685 case RANGE: return new (arena) RenderSlider(this);
1693 void HTMLInputElementImpl::attach()
1697 setType(getAttribute(ATTR_TYPE));
1699 // FIXME: This needs to be dynamic, doesn't it, since someone could set this
1700 // after attachment?
1701 DOMString val = getAttribute(ATTR_VALUE);
1702 if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
1703 // remove newline stuff..
1705 for (unsigned int i = 0; i < val.length(); ++i)
1709 if (val.length() != nvalue.length())
1710 setAttribute(ATTR_VALUE, nvalue);
1713 m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
1718 // Disallow the width attribute on inputs other than HIDDEN and IMAGE.
1719 // Dumb Web sites will try to set the width as an attribute on form controls that aren't
1720 // images or hidden.
1721 if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
1723 removeAttribute(ATTR_WIDTH, excCode);
1726 HTMLGenericFormElementImpl::attach();
1728 if (m_type == IMAGE) {
1730 m_imageLoader = new HTMLImageLoader(this);
1731 m_imageLoader->updateFromElement();
1733 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
1734 imageObj->setImage(m_imageLoader->image());
1739 // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
1740 // was such that it cleared our state too early
1741 if (m_type == PASSWORD)
1742 getDocument()->passwordFieldAdded();
1746 void HTMLInputElementImpl::detach()
1748 HTMLGenericFormElementImpl::detach();
1749 m_valueMatchesRenderer = false;
1752 DOMString HTMLInputElementImpl::altText() const
1754 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1755 // also heavily discussed by Hixie on bugzilla
1756 // note this is intentionally different to HTMLImageElementImpl::altText()
1757 DOMString alt = getAttribute( ATTR_ALT );
1758 // fall back to title attribute
1760 alt = getAttribute( ATTR_TITLE );
1762 alt = getAttribute( ATTR_VALUE );
1763 if ( alt.isEmpty() )
1765 alt = inputElementAltText();
1767 alt = i18n( "Submit" );
1773 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1775 // HTML spec says that buttons must have names
1776 // to be considered successful. However, other browsers
1777 // do not impose this constraint. Therefore, we behave
1778 // differently and can use different buttons than the
1780 // Was: (m_type == SUBMIT && !name().isEmpty())
1781 return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1784 bool HTMLInputElementImpl::isActivatedSubmit() const
1786 return m_activeSubmit;
1789 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1791 m_activeSubmit = flag;
1794 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1796 // image generates its own names
1797 if (name().isEmpty() && m_type != IMAGE) return false;
1807 // always successful
1808 encoding.appendData(name(), value());
1814 encoding.appendData(name(), value());
1821 // those buttons are never successful
1827 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1828 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1829 if (!name().isEmpty() && !value().isEmpty())
1830 encoding.appendData(name(), value());
1838 QString enc_str = valueWithDefault().string();
1839 if (!enc_str.isEmpty()) {
1840 encoding.appendData(name(), enc_str);
1848 // can't submit file on GET
1849 // don't submit if display: none or display: hidden
1850 if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1853 // if no filename at all is entered, return successful, however empty
1854 // null would be more logical but netscape posts an empty file. argh.
1855 if (value().isEmpty()) {
1856 encoding.appendData(name(), QString(""));
1861 encoding.appendFile(name(), value());
1864 KURL fileurl("file:///");
1865 fileurl.setPath(value().string());
1866 KIO::UDSEntry filestat;
1868 if (!KIO::NetAccess::stat(fileurl, filestat)) {
1869 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1873 KFileItem fileitem(filestat, fileurl, true, false);
1874 if (fileitem.isDir()) {
1879 if ( KIO::NetAccess::download(fileurl, local) )
1882 if (file.open(IO_ReadOnly))
1884 QCString filearray(file.size()+1);
1885 int readbytes = file.readBlock( filearray.data(), file.size());
1886 if ( readbytes >= 0 )
1887 filearray[readbytes] = '\0';
1890 encoding.appendData(name(), filearray);
1891 KIO::NetAccess::removeTempFile( local );
1898 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1905 encoding.appendData(name(), value());
1911 void HTMLInputElementImpl::reset()
1913 if (storesValueSeparateFromAttribute())
1914 setValue(DOMString());
1915 setChecked(m_defaultChecked);
1916 m_useDefaultChecked = true;
1919 void HTMLInputElementImpl::setChecked(bool _checked)
1921 if (checked() == _checked) return;
1923 if (m_form && m_type == RADIO && _checked && !name().isEmpty())
1924 m_form->radioClicked(this);
1926 m_useDefaultChecked = false;
1927 m_checked = _checked;
1932 DOMString HTMLInputElementImpl::value() const
1934 DOMString value = m_value;
1936 // It's important *not* to fall back to the value attribute for file inputs,
1937 // because that would allow a malicious web page to upload files by setting the
1938 // value attribute in markup.
1939 if (value.isNull() && m_type != FILE)
1940 value = getAttribute(ATTR_VALUE);
1942 // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1943 if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
1944 return DOMString(checked() ? "on" : "");
1949 DOMString HTMLInputElementImpl::valueWithDefault() const
1951 DOMString v = value();
1956 v = resetButtonDefaultLabel();
1964 v = submitButtonDefaultLabel();
1989 void HTMLInputElementImpl::setValue(const DOMString &value)
1991 if (m_type == FILE) return;
1993 if (storesValueSeparateFromAttribute()) {
1997 setAttribute(ATTR_VALUE, value);
1999 m_valueMatchesRenderer = false;
2002 void HTMLInputElementImpl::setValueFromRenderer(const DOMString &value)
2005 m_valueMatchesRenderer = true;
2007 // Fire the "input" DOM event.
2008 dispatchHTMLEvent(EventImpl::INPUT_EVENT, true, false);
2011 bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
2037 void HTMLInputElementImpl::blur()
2039 if(getDocument()->focusNode() == this)
2040 getDocument()->setFocusNode(0);
2043 void HTMLInputElementImpl::focus()
2045 getDocument()->setFocusNode(this);
2048 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
2050 if (evt->isMouseEvent() &&
2051 ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
2054 // record the mouse position for when we get the DOMActivate event
2055 MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
2056 int offsetX, offsetY;
2057 m_render->absolutePosition(offsetX,offsetY);
2058 xPos = me->clientX()-offsetX;
2059 yPos = me->clientY()-offsetY;
2061 me->setDefaultHandled();
2064 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
2065 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
2066 // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
2067 // must dispatch a DOMActivate event - a click event will not do the job.
2068 if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
2069 (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
2074 if (m_type == RESET) {
2078 m_activeSubmit = true;
2079 if (!m_form->prepareSubmit()) {
2083 m_activeSubmit = false;
2088 // Use key press event here since sending simulated mouse events
2089 // on key down blocks the proper sending of the key press event.
2090 if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
2091 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2100 // Simulate mouse click for enter or spacebar for these types of elements.
2101 // The AppKit already does this for spacebar for some, but not all, of them.
2102 if (key == "U+000020" || key == "Enter") {
2104 evt->setDefaultHandled();
2113 // Simulate mouse click on the default form button for enter for these types of elements.
2114 if (key == "Enter" && m_form) {
2115 m_form->submitClick();
2116 evt->setDefaultHandled();
2123 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2126 bool HTMLInputElementImpl::isEditable()
2128 return ((m_type == TEXT) || (m_type == PASSWORD) ||
2129 (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
2132 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
2134 return (attr->id() == ATTR_SRC);
2137 // -------------------------------------------------------------------------
2139 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
2140 : HTMLElementImpl(doc)
2144 HTMLLabelElementImpl::~HTMLLabelElementImpl()
2148 bool HTMLLabelElementImpl::isFocusable() const
2153 NodeImpl::Id HTMLLabelElementImpl::id() const
2158 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2163 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2164 getDocument()->createHTMLEventListener(attr->value().string(), this));
2167 setHTMLEventListener(EventImpl::BLUR_EVENT,
2168 getDocument()->createHTMLEventListener(attr->value().string(), this));
2171 HTMLElementImpl::parseHTMLAttribute(attr);
2175 ElementImpl *HTMLLabelElementImpl::formElement()
2177 DOMString formElementId = getAttribute(ATTR_FOR);
2178 if (formElementId.isNull()) {
2179 // Search children of the label element for a form element.
2180 NodeImpl *node = this;
2181 while ((node = node->traverseNextNode(this))) {
2182 if (node->isHTMLElement()) {
2183 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
2184 if (element->isGenericFormElement()) {
2191 if (formElementId.isEmpty())
2193 return getDocument()->getElementById(formElementId);
2196 void HTMLLabelElementImpl::accessKeyAction(bool sendToAnyElement)
2198 ElementImpl *element = formElement();
2200 element->accessKeyAction(sendToAnyElement);
2203 // -------------------------------------------------------------------------
2205 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2206 : HTMLGenericFormElementImpl(doc, f)
2210 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2214 bool HTMLLegendElementImpl::isFocusable() const
2219 NodeImpl::Id HTMLLegendElementImpl::id() const
2224 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2226 return new (arena) RenderLegend(this);
2229 DOMString HTMLLegendElementImpl::type() const
2234 // -------------------------------------------------------------------------
2236 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2237 : HTMLGenericFormElementImpl(doc, f), m_options(0)
2240 m_recalcListItems = false;
2241 // 0 means invalid (i.e. not set)
2246 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2248 if (getDocument()) getDocument()->deregisterMaintainsState(this);
2250 m_options->detach();
2255 NodeImpl::Id HTMLSelectElementImpl::id() const
2260 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2262 if (hasChangedChild() && m_render) {
2263 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2266 HTMLGenericFormElementImpl::recalcStyle( ch );
2270 DOMString HTMLSelectElementImpl::type() const
2272 return (m_multiple ? "select-multiple" : "select-one");
2275 long HTMLSelectElementImpl::selectedIndex() const
2277 // return the number of the first option selected
2279 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2280 for (unsigned int i = 0; i < items.size(); i++) {
2281 if (items[i]->id() == ID_OPTION) {
2282 if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2287 Q_ASSERT(m_multiple);
2291 void HTMLSelectElementImpl::setSelectedIndex( long index )
2293 // deselect all other options and select only the new one
2294 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2296 for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2297 if (items[listIndex]->id() == ID_OPTION)
2298 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2300 listIndex = optionToListIndex(index);
2302 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2307 long HTMLSelectElementImpl::length() const
2311 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2312 for (i = 0; i < items.size(); i++) {
2313 if (items[i]->id() == ID_OPTION)
2319 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2321 if (!element || element->id() != ID_OPTION)
2324 int exceptioncode = 0;
2325 insertBefore(element, before, exceptioncode);
2327 setRecalcListItems();
2330 void HTMLSelectElementImpl::remove( long index )
2332 int exceptioncode = 0;
2333 int listIndex = optionToListIndex(index);
2335 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2336 if(listIndex < 0 || index >= int(items.size()))
2337 return; // ### what should we do ? remove the last item?
2339 removeChild(items[listIndex], exceptioncode);
2340 if( !exceptioncode )
2341 setRecalcListItems();
2344 void HTMLSelectElementImpl::blur()
2346 if(getDocument()->focusNode() == this)
2347 getDocument()->setFocusNode(0);
2350 void HTMLSelectElementImpl::focus()
2352 getDocument()->setFocusNode(this);
2355 DOMString HTMLSelectElementImpl::value( )
2358 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2359 for (i = 0; i < items.size(); i++) {
2360 if ( items[i]->id() == ID_OPTION
2361 && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2362 return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2364 return DOMString("");
2367 void HTMLSelectElementImpl::setValue(DOMStringImpl* value)
2369 // find the option with value() matching the given parameter
2370 // and make it the current selection.
2371 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2372 for (unsigned i = 0; i < items.size(); i++)
2373 if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2374 static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2379 QString HTMLSelectElementImpl::state( )
2384 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2386 int l = items.count();
2389 QChar stateChars[l];
2391 for(int i = 0; i < l; i++)
2392 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2393 stateChars[i] = 'X';
2395 stateChars[i] = '.';
2396 QString state(stateChars, l);
2397 #else /* APPLE_CHANGES not defined */
2399 for(int i = 0; i < l; i++)
2400 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2402 #endif /* APPLE_CHANGES not defined */
2404 return HTMLGenericFormElementImpl::state() + state;
2407 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2409 QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2410 if (_state.isNull()) return;
2414 QString state = _state;
2415 if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2416 qWarning("should not happen in restoreState!");
2418 // KWQString doesn't support this operation. Should never get here anyway.
2425 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2427 int l = items.count();
2428 for(int i = 0; i < l; i++) {
2429 if(items[i]->id() == ID_OPTION) {
2430 HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2431 oe->setSelected(state[i] == 'X');
2437 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2439 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2441 setRecalcListItems();
2445 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2447 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2448 if( !exceptioncode )
2449 setRecalcListItems();
2453 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2455 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2456 if( !exceptioncode )
2457 setRecalcListItems();
2461 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2463 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2464 if( !exceptioncode )
2465 setRecalcListItems();
2470 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2472 setRecalcListItems();
2473 return HTMLGenericFormElementImpl::addChild(newChild);
2476 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2481 m_size = QMAX( attr->value().toInt(), 1 );
2484 m_minwidth = QMAX( attr->value().toInt(), 0 );
2487 m_multiple = (!attr->isNull());
2489 case ATTR_ACCESSKEY:
2490 // ### ignore for the moment
2493 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2494 getDocument()->createHTMLEventListener(attr->value().string(), this));
2497 setHTMLEventListener(EventImpl::BLUR_EVENT,
2498 getDocument()->createHTMLEventListener(attr->value().string(), this));
2501 setHTMLEventListener(EventImpl::CHANGE_EVENT,
2502 getDocument()->createHTMLEventListener(attr->value().string(), this));
2505 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2509 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2511 return new (arena) RenderSelect(this);
2514 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2516 bool successful = false;
2517 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2520 for (i = 0; i < items.size(); i++) {
2521 if (items[i]->id() == ID_OPTION) {
2522 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2523 if (option->selected()) {
2524 encoded_values.appendData(name(), option->value());
2530 // ### this case should not happen. make sure that we select the first option
2531 // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2532 // we return the first one if it was a combobox select
2533 if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2534 (items[0]->id() == ID_OPTION) ) {
2535 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2536 if (option->value().isNull())
2537 encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2539 encoded_values.appendData(name(), option->value());
2546 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2548 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2549 if (optionIndex < 0 || optionIndex >= int(items.size()))
2553 int optionIndex2 = 0;
2555 optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2556 listIndex++) { // not a typo!
2557 if (items[listIndex]->id() == ID_OPTION)
2564 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2566 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2567 if (listIndex < 0 || listIndex >= int(items.size()) ||
2568 items[listIndex]->id() != ID_OPTION)
2571 int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2573 for (i = 0; i < listIndex; i++)
2574 if (items[i]->id() == ID_OPTION)
2579 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2582 m_options = new HTMLOptionsCollectionImpl(this);
2588 void HTMLSelectElementImpl::recalcListItems()
2590 NodeImpl* current = firstChild();
2591 m_listItems.resize(0);
2592 HTMLOptionElementImpl* foundSelected = 0;
2594 if (current->id() == ID_OPTGROUP && current->firstChild()) {
2595 // ### what if optgroup contains just comments? don't want one of no options in it...
2596 m_listItems.resize(m_listItems.size()+1);
2597 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2598 current = current->firstChild();
2600 if (current->id() == ID_OPTION) {
2601 m_listItems.resize(m_listItems.size()+1);
2602 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2603 if (!foundSelected && !m_multiple && m_size <= 1) {
2604 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2605 foundSelected->m_selected = true;
2607 else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2608 foundSelected->m_selected = false;
2609 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2612 NodeImpl *parent = current->parentNode();
2613 current = current->nextSibling();
2616 current = parent->nextSibling();
2619 m_recalcListItems = false;
2622 void HTMLSelectElementImpl::childrenChanged()
2624 setRecalcListItems();
2626 HTMLGenericFormElementImpl::childrenChanged();
2629 void HTMLSelectElementImpl::setRecalcListItems()
2631 m_recalcListItems = true;
2633 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2637 void HTMLSelectElementImpl::reset()
2639 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2641 for (i = 0; i < items.size(); i++) {
2642 if (items[i]->id() == ID_OPTION) {
2643 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2644 bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2645 option->setSelected(selected);
2649 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2653 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2655 if (selected && !m_multiple) {
2656 // deselect all other options
2657 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2659 for (i = 0; i < items.size(); i++) {
2660 if (items[i]->id() == ID_OPTION)
2661 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2665 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2672 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2674 // Use key press event here since sending simulated mouse events
2675 // on key down blocks the proper sending of the key press event.
2676 if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2678 if (!m_form || !m_render || !evt->isKeyboardEvent())
2681 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2683 if (key == "Enter") {
2684 m_form->submitClick();
2685 evt->setDefaultHandled();
2688 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2691 #endif // APPLE_CHANGES
2693 void HTMLSelectElementImpl::accessKeyAction(bool sendToAnyElement)
2698 // -------------------------------------------------------------------------
2700 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2701 : HTMLSelectElementImpl(doc, f)
2703 QStringList keys = KSSLKeyGen::supportedKeySizes();
2704 for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2705 HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2707 o->addChild(new TextImpl(doc, DOMString(*i)));
2711 NodeImpl::Id HTMLKeygenElementImpl::id() const
2716 DOMString HTMLKeygenElementImpl::type() const
2721 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2725 case ATTR_CHALLENGE:
2726 m_challenge = attr->value();
2729 m_keyType = attr->value();
2732 // skip HTMLSelectElementImpl parsing!
2733 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2737 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2740 // Only RSA is supported at this time.
2741 if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2744 QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2745 if (value.isNull()) {
2748 encoded_values.appendData(name(), value.utf8());
2751 bool successful = false;
2753 // pop up the fancy certificate creation dialog here
2754 KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
2757 successful = (QDialog::Accepted == kg->exec());
2761 encoded_values.appendData(name(), "deadbeef");
2767 // -------------------------------------------------------------------------
2769 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2770 : HTMLGenericFormElementImpl(doc, f)
2774 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
2778 bool HTMLOptGroupElementImpl::isFocusable() const
2783 NodeImpl::Id HTMLOptGroupElementImpl::id() const
2788 DOMString HTMLOptGroupElementImpl::type() const
2793 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2795 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
2796 if ( !exceptioncode )
2797 recalcSelectOptions();
2801 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2803 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2805 recalcSelectOptions();
2809 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2811 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2812 if( !exceptioncode )
2813 recalcSelectOptions();
2817 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2819 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2820 if( !exceptioncode )
2821 recalcSelectOptions();
2825 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
2827 recalcSelectOptions();
2829 return HTMLGenericFormElementImpl::addChild(newChild);
2832 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2834 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2835 recalcSelectOptions();
2838 void HTMLOptGroupElementImpl::recalcSelectOptions()
2840 NodeImpl *select = parentNode();
2841 while (select && select->id() != ID_SELECT)
2842 select = select->parentNode();
2844 static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
2847 // -------------------------------------------------------------------------
2849 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2850 : HTMLGenericFormElementImpl(doc, f)
2855 bool HTMLOptionElementImpl::isFocusable() const
2860 NodeImpl::Id HTMLOptionElementImpl::id() const
2865 DOMString HTMLOptionElementImpl::type() const
2870 DOMString HTMLOptionElementImpl::text() const
2874 // WinIE does not use the label attribute, so as a quirk, we ignore it.
2875 if (getDocument() && !getDocument()->inCompatMode()) {
2876 DOMString text = getAttribute(ATTR_LABEL);
2877 if (!text.isEmpty())
2881 const NodeImpl *n = this;
2882 while ((n = n->traverseNextNode(this))) {
2883 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
2884 text += n->nodeValue();
2890 long HTMLOptionElementImpl::index() const
2892 // Let's do this dynamically. Might be a bit slow, but we're sure
2893 // we won't forget to update a member variable in some cases...
2894 QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
2895 int l = items.count();
2896 int optionIndex = 0;
2897 for(int i = 0; i < l; i++) {
2898 if(items[i]->id() == ID_OPTION)
2900 if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
2905 kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
2909 void HTMLOptionElementImpl::setIndex( long )
2911 kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
2915 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2920 m_selected = (!attr->isNull());
2923 m_value = attr->value();
2926 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2930 DOMString HTMLOptionElementImpl::value() const
2932 if ( !m_value.isNull() )
2934 // Use the text if the value wasn't set.
2935 return text().string().stripWhiteSpace();
2938 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
2940 setAttribute(ATTR_VALUE, value);
2943 void HTMLOptionElementImpl::setSelected(bool _selected)
2945 if(m_selected == _selected)
2947 m_selected = _selected;
2948 HTMLSelectElementImpl *select = getSelect();
2950 select->notifyOptionSelected(this,_selected);
2953 void HTMLOptionElementImpl::childrenChanged()
2955 HTMLSelectElementImpl *select = getSelect();
2957 select->childrenChanged();
2960 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
2962 NodeImpl *select = parentNode();
2963 while (select && select->id() != ID_SELECT)
2964 select = select->parentNode();
2965 return static_cast<HTMLSelectElementImpl*>(select);
2968 // -------------------------------------------------------------------------
2970 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2971 : HTMLGenericFormElementImpl(doc, f), m_valueIsValid(false), m_valueMatchesRenderer(false)
2973 // DTD requires rows & cols be specified, but we will provide reasonable defaults
2976 m_wrap = ta_Virtual;
2979 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
2981 if (getDocument()) getDocument()->deregisterMaintainsState(this);
2984 NodeImpl::Id HTMLTextAreaElementImpl::id() const
2989 DOMString HTMLTextAreaElementImpl::type() const
2994 QString HTMLTextAreaElementImpl::state( )
2996 // Make sure the string is not empty!
2997 return HTMLGenericFormElementImpl::state() + value().string()+'.';
3000 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
3002 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
3003 if (state.isNull()) return;
3004 setDefaultValue(state.left(state.length()-1));
3005 // the close() in the rendertree will take care of transferring defaultvalue to 'value'
3008 void HTMLTextAreaElementImpl::select( )
3011 static_cast<RenderTextArea*>(m_render)->select();
3015 void HTMLTextAreaElementImpl::childrenChanged()
3017 setValue(defaultValue());
3020 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
3025 m_rows = !attr->isNull() ? attr->value().toInt() : 3;
3027 renderer()->setNeedsLayoutAndMinMaxRecalc();
3030 m_cols = !attr->isNull() ? attr->value().toInt() : 60;
3032 renderer()->setNeedsLayoutAndMinMaxRecalc();
3035 // virtual / physical is Netscape extension of HTML 3.0, now deprecated
3036 // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
3037 if ( strcasecmp( attr->value(), "virtual" ) == 0 || strcasecmp( attr->value(), "soft") == 0)
3038 m_wrap = ta_Virtual;
3039 else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
3040 m_wrap = ta_Physical;
3041 else if(strcasecmp( attr->value(), "on" ) == 0)
3042 m_wrap = ta_Physical;
3043 else if(strcasecmp( attr->value(), "off") == 0)
3046 renderer()->setNeedsLayoutAndMinMaxRecalc();
3048 case ATTR_ACCESSKEY:
3049 // ignore for the moment
3052 setHTMLEventListener(EventImpl::FOCUS_EVENT,
3053 getDocument()->createHTMLEventListener(attr->value().string(), this));
3056 setHTMLEventListener(EventImpl::BLUR_EVENT,
3057 getDocument()->createHTMLEventListener(attr->value().string(), this));
3060 setHTMLEventListener(EventImpl::SELECT_EVENT,
3061 getDocument()->createHTMLEventListener(attr->value().string(), this));
3064 setHTMLEventListener(EventImpl::CHANGE_EVENT,
3065 getDocument()->createHTMLEventListener(attr->value().string(), this));
3068 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3072 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
3074 return new (arena) RenderTextArea(this);
3077 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
3079 if (name().isEmpty()) return false;
3080 encoding.appendData(name(), value());
3084 void HTMLTextAreaElementImpl::reset()
3086 setValue(defaultValue());
3089 void HTMLTextAreaElementImpl::updateValue()
3091 if ( !m_valueIsValid ) {
3093 m_value = static_cast<RenderTextArea*>( m_render )->text();
3094 m_valueMatchesRenderer = true;
3096 m_value = defaultValue().string();
3097 m_valueMatchesRenderer = false;
3099 m_valueIsValid = true;
3103 DOMString HTMLTextAreaElementImpl::value()
3106 return m_value.isNull() ? DOMString("") : m_value;
3109 void HTMLTextAreaElementImpl::setValue(const DOMString &value)
3111 m_value = value.string();
3112 m_valueIsValid = true;
3113 m_valueMatchesRenderer = false;
3118 DOMString HTMLTextAreaElementImpl::defaultValue()
3121 // there may be comments - just grab the text nodes
3123 for (n = firstChild(); n; n = n->nextSibling())
3124 if (n->isTextNode())
3125 val += static_cast<TextImpl*>(n)->data();
3126 if (val[0] == '\r' && val[1] == '\n') {
3130 else if (val[0] == '\r' || val[0] == '\n') {
3138 void HTMLTextAreaElementImpl::setDefaultValue(const DOMString &defaultValue)
3140 // there may be comments - remove all the text nodes and replace them with one
3141 QPtrList<NodeImpl> toRemove;
3143 for (n = firstChild(); n; n = n->nextSibling())
3144 if (n->isTextNode())
3146 QPtrListIterator<NodeImpl> it(toRemove);
3147 int exceptioncode = 0;
3148 for (; it.current(); ++it) {
3149 removeChild(it.current(), exceptioncode);
3151 insertBefore(getDocument()->createTextNode(defaultValue),firstChild(), exceptioncode);
3152 setValue(defaultValue);
3155 void HTMLTextAreaElementImpl::blur()
3157 if(getDocument()->focusNode() == this)
3158 getDocument()->setFocusNode(0);
3161 void HTMLTextAreaElementImpl::focus()
3163 getDocument()->setFocusNode(this);
3166 bool HTMLTextAreaElementImpl::isEditable()
3171 void HTMLTextAreaElementImpl::accessKeyAction(bool sendToAnyElement)
3176 void HTMLTextAreaElementImpl::detach()
3178 HTMLGenericFormElementImpl::detach();
3179 m_valueMatchesRenderer = false;
3182 // -------------------------------------------------------------------------
3184 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3185 : HTMLInputElementImpl(doc, f)
3191 NodeImpl::Id HTMLIsIndexElementImpl::id() const
3196 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
3201 setValue(attr->value());
3203 // don't call HTMLInputElement::parseHTMLAttribute here, as it would
3204 // accept attributes this element does not support
3205 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3209 // -------------------------------------------------------------------------
3211 unsigned long HTMLOptionsCollectionImpl::length() const
3213 // Not yet implemented.
3217 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3219 // Not yet implemented.
3222 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3224 // Not yet implemented.
3228 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3230 // Not yet implemented.
3234 // -------------------------------------------------------------------------
3236 FormDataList::FormDataList(QTextCodec *c)
3241 void FormDataList::appendString(const QCString &s)
3246 void FormDataList::appendString(const QString &s)
3248 QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3249 cstr.truncate(cstr.length());
3250 m_list.append(cstr);
3253 void FormDataList::appendFile(const DOMString &key, const DOMString &filename)
3255 appendString(key.string());
3256 m_list.append(filename.string());