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;
71 FormDataList(QTextCodec *);
73 void appendData(const DOMString &key, const DOMString &value)
74 { appendString(key.string()); appendString(value.string()); }
75 void appendData(const DOMString &key, const QString &value)
76 { appendString(key.string()); appendString(value); }
77 void appendData(const DOMString &key, const QCString &value)
78 { appendString(key.string()); appendString(value); }
79 void appendData(const DOMString &key, int value)
80 { appendString(key.string()); appendString(QString::number(value)); }
81 void appendFile(const DOMString &key, const DOMString &filename);
84 QValueListConstIterator<QCString> begin() const;
85 QValueListConstIterator<QCString> end() const;
88 void appendString(const QCString &s);
89 void appendString(const QString &s);
92 QValueList<QCString> m_strings;
95 HTMLFormElementImpl::HTMLFormElementImpl(DocumentPtr *doc)
96 : HTMLElementImpl(doc)
100 m_autocomplete = true;
102 m_doingsubmit = false;
104 m_enctype = "application/x-www-form-urlencoded";
105 m_boundary = "----------0xKhTmLbOuNdArY";
106 m_acceptcharset = "UNKNOWN";
110 HTMLFormElementImpl::~HTMLFormElementImpl()
112 for (unsigned i = 0; i < formElements.count(); ++i)
113 formElements[i]->m_form = 0;
114 for (unsigned i = 0; i < dormantFormElements.count(); ++i)
115 dormantFormElements[i]->m_form = 0;
116 for (unsigned i = 0; i < imgElements.count(); ++i)
117 imgElements[i]->m_form = 0;
120 NodeImpl::Id HTMLFormElementImpl::id() const
127 bool HTMLFormElementImpl::formWouldHaveSecureSubmission(const DOMString &url)
132 return getDocument()->completeURL(url.string()).startsWith("https:", false);
137 void HTMLFormElementImpl::attach()
139 HTMLElementImpl::attach();
141 if (getDocument()->isHTMLDocument()) {
142 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
143 document->addNamedImageOrForm(oldNameAttr);
144 document->addNamedImageOrForm(oldIdAttr);
148 // note we don't deal with calling secureFormRemoved() on detach, because the timing
149 // was such that it cleared our state too early
150 if (formWouldHaveSecureSubmission(m_url))
151 getDocument()->secureFormAdded();
155 void HTMLFormElementImpl::detach()
157 if (getDocument()->isHTMLDocument()) {
158 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
159 document->removeNamedImageOrForm(oldNameAttr);
160 document->removeNamedImageOrForm(oldIdAttr);
163 HTMLElementImpl::detach();
166 long HTMLFormElementImpl::length() const
169 for (unsigned i = 0; i < formElements.count(); ++i)
170 if (formElements[i]->isEnumeratable())
178 void HTMLFormElementImpl::submitClick()
180 bool submitFound = false;
181 for (unsigned i = 0; i < formElements.count(); ++i) {
182 if (formElements[i]->id() == ID_INPUT) {
183 HTMLInputElementImpl *element = static_cast<HTMLInputElementImpl *>(formElements[i]);
184 if (element->isSuccessfulSubmitButton() && element->renderer()) {
191 if (!submitFound) // submit the form without a submit or image input
195 #endif // APPLE_CHANGES
197 static QCString encodeCString(const QCString& e)
199 // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
200 // safe characters like NS handles them for compatibility
201 static const char *safe = "-._*";
202 int elen = e.length();
203 QCString encoded(( elen+e.contains( '\n' ) )*3+1);
206 //QCString orig(e.data(), e.size());
208 for(int pos = 0; pos < elen; pos++) {
209 unsigned char c = e[pos];
211 if ( (( c >= 'A') && ( c <= 'Z')) ||
212 (( c >= 'a') && ( c <= 'z')) ||
213 (( c >= '0') && ( c <= '9')) ||
216 encoded[enclen++] = c;
218 encoded[enclen++] = '+';
219 else if ( c == '\n' || ( c == '\r' && e[pos+1] != '\n' ) )
221 encoded[enclen++] = '%';
222 encoded[enclen++] = '0';
223 encoded[enclen++] = 'D';
224 encoded[enclen++] = '%';
225 encoded[enclen++] = '0';
226 encoded[enclen++] = 'A';
228 else if ( c != '\r' )
230 encoded[enclen++] = '%';
231 unsigned int h = c / 16;
232 h += (h > 9) ? ('A' - 10) : '0';
233 encoded[enclen++] = h;
235 unsigned int l = c % 16;
236 l += (l > 9) ? ('A' - 10) : '0';
237 encoded[enclen++] = l;
240 encoded[enclen++] = '\0';
241 encoded.truncate(enclen);
246 // Change plain CR and plain LF to CRLF pairs.
247 static QCString fixLineBreaks(const QCString &s)
249 // Compute the length.
251 const char *p = s.data();
252 while (char c = *p++) {
254 // Safe to look ahead because of trailing '\0'.
256 // Turn CR into CRLF.
259 } else if (c == '\n') {
260 // Turn LF into CRLF.
263 // Leave other characters alone.
267 if (newLen == s.length()) {
271 // Make a copy of the string.
273 QCString result(newLen + 1);
274 char *q = result.data();
275 while (char c = *p++) {
277 // Safe to look ahead because of trailing '\0'.
279 // Turn CR into CRLF.
283 } else if (c == '\n') {
284 // Turn LF into CRLF.
288 // Leave other characters alone.
297 void HTMLFormElementImpl::i18nData()
299 QString foo1 = i18n( "You're about to send data to the Internet "
300 "via an unencrypted connection. It might be possible "
301 "for others to see this information.\n"
302 "Do you want to continue?");
303 QString foo2 = i18n("KDE Web browser");
304 QString foo3 = i18n("When you send a password unencrypted to the Internet, "
305 "it might be possible for others to capture it as plain text.\n"
306 "Do you want to continue?");
307 QString foo5 = i18n("Your data submission is redirected to "
308 "an insecure site. The data is sent unencrypted.\n"
309 "Do you want to continue?");
310 QString foo6 = i18n("The page contents expired. You can repost the form"
311 "data by using <a href=\"javascript:go(0);\">Reload</a>");
316 bool HTMLFormElementImpl::formData(FormData &form_data) const
319 kdDebug( 6030 ) << "form: formData()" << endl;
322 QCString enc_string = ""; // used for non-multipart data
324 // find out the QTextcodec to use
325 QString str = m_acceptcharset.string();
326 str.replace(',', ' ');
327 QStringList charsets = QStringList::split(' ', str);
328 QTextCodec* codec = 0;
329 KHTMLPart *part = getDocument()->part();
330 for ( QStringList::Iterator it = charsets.begin(); it != charsets.end(); ++it )
333 if(enc.contains("UNKNOWN"))
335 // use standard document encoding
338 enc = part->encoding();
340 if((codec = KGlobal::charsets()->codecForName(enc.latin1())))
345 codec = QTextCodec::codecForLocale();
348 QStringList fileUploads;
351 for (unsigned i = 0; i < formElements.count(); ++i) {
352 HTMLGenericFormElementImpl* current = formElements[i];
353 FormDataList lst(codec);
355 if (!current->disabled() && current->appendFormData(lst, m_multipart))
357 //kdDebug(6030) << "adding name " << current->name().string() << endl;
358 for(QValueListConstIterator<QCString> it = lst.begin(); it != lst.end(); ++it )
362 // handle ISINDEX / <input name=isindex> special
363 // but only if its the first entry
364 if ( enc_string.isEmpty() && *it == "isindex" ) {
366 enc_string += encodeCString( *it );
369 if(!enc_string.isEmpty())
372 enc_string += encodeCString(*it);
375 enc_string += encodeCString(*it);
381 hstr += m_boundary.string().latin1();
383 hstr += "Content-Disposition: form-data; name=\"";
384 hstr += (*it).data();
387 // if the current type is FILE, then we also need to
388 // include the filename
389 if (current->nodeType() == Node::ELEMENT_NODE && current->id() == ID_INPUT &&
390 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::FILE)
392 QString path = static_cast<HTMLInputElementImpl*>(current)->value().string();
394 if (path.length()) fileUploads << path;
397 // FIXME: This won't work if the filename includes a " mark,
398 // or control characters like CR or LF. This also does strange
399 // things if the filename includes characters you can't encode
400 // in the website's character set.
401 hstr += "; filename=\"";
402 hstr += codec->fromUnicode(path.mid(path.findRev('/') + 1));
405 if(!static_cast<HTMLInputElementImpl*>(current)->value().isEmpty())
408 QString mimeType = part ? KWQ(part)->mimeTypeForFileName(path) : QString();
410 KMimeType::Ptr ptr = KMimeType::findByURL(KURL(path));
411 QString mimeType = ptr->name();
413 if (!mimeType.isEmpty()) {
414 hstr += "\r\nContent-Type: ";
415 hstr += mimeType.ascii();
424 form_data.appendData(hstr.data(), hstr.length());
425 form_data.appendData(*it, (*it).size() - 1);
426 form_data.appendData("\r\n", 2);
433 if (fileUploads.count()) {
434 int result = KMessageBox::warningContinueCancelList( 0,
435 i18n("You're about to transfer the following files from "
436 "your local computer to the Internet.\n"
437 "Do you really want to continue?"),
441 if (result == KMessageBox::Cancel) {
448 enc_string = ("--" + m_boundary.string() + "--\r\n").ascii();
450 form_data.appendData(enc_string.data(), enc_string.length());
454 void HTMLFormElementImpl::setEnctype( const DOMString& type )
456 if(type.string().find("multipart", 0, false) != -1 || type.string().find("form-data", 0, false) != -1)
458 m_enctype = "multipart/form-data";
461 } else if (type.string().find("text", 0, false) != -1 || type.string().find("plain", 0, false) != -1)
463 m_enctype = "text/plain";
468 m_enctype = "application/x-www-form-urlencoded";
473 void HTMLFormElementImpl::setBoundary( const DOMString& bound )
478 bool HTMLFormElementImpl::prepareSubmit()
480 KHTMLPart *part = getDocument()->part();
481 if(m_insubmit || !part || part->onlyLocalReferences())
485 m_doingsubmit = false;
487 if ( dispatchHTMLEvent(EventImpl::SUBMIT_EVENT,false,true) && !m_doingsubmit )
488 m_doingsubmit = true;
495 return m_doingsubmit;
498 void HTMLFormElementImpl::submit( bool activateSubmitButton )
500 KHTMLView *view = getDocument()->view();
501 KHTMLPart *part = getDocument()->part();
502 if (!view || !part) {
507 m_doingsubmit = true;
514 kdDebug( 6030 ) << "submitting!" << endl;
517 HTMLGenericFormElementImpl* firstSuccessfulSubmitButton = 0;
518 bool needButtonActivation = activateSubmitButton; // do we need to activate a submit button?
521 KWQ(part)->clearRecordedFormValues();
523 for (unsigned i = 0; i < formElements.count(); ++i) {
524 HTMLGenericFormElementImpl* current = formElements[i];
526 // Our app needs to get form values for password fields for doing password autocomplete,
527 // so we are more lenient in pushing values, and let the app decide what to save when.
528 if (current->id() == ID_INPUT) {
529 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl*>(current);
530 if (input->inputType() == HTMLInputElementImpl::TEXT
531 || input->inputType() == HTMLInputElementImpl::PASSWORD
532 || input->inputType() == HTMLInputElementImpl::SEARCH)
534 KWQ(part)->recordFormValue(input->name().string(), input->value().string(), this);
535 if (input->renderer() && input->inputType() == HTMLInputElementImpl::SEARCH)
536 static_cast<RenderLineEdit*>(input->renderer())->addSearchResult();
540 if (current->id() == ID_INPUT &&
541 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::TEXT &&
542 static_cast<HTMLInputElementImpl*>(current)->autoComplete() )
544 HTMLInputElementImpl *input = static_cast<HTMLInputElementImpl *>(current);
545 view->addFormCompletionItem(input->name().string(), input->value().string());
549 if (needButtonActivation) {
550 if (current->isActivatedSubmit()) {
551 needButtonActivation = false;
552 } else if (firstSuccessfulSubmitButton == 0 && current->isSuccessfulSubmitButton()) {
553 firstSuccessfulSubmitButton = current;
558 if (needButtonActivation && firstSuccessfulSubmitButton) {
559 firstSuccessfulSubmitButton->setActivatedSubmit(true);
563 if (formData(form_data)) {
565 part->submitForm( "post", m_url.string(), form_data,
568 boundary().string() );
571 part->submitForm( "get", m_url.string(), form_data,
576 if (needButtonActivation && firstSuccessfulSubmitButton) {
577 firstSuccessfulSubmitButton->setActivatedSubmit(false);
580 m_doingsubmit = m_insubmit = false;
583 void HTMLFormElementImpl::reset( )
585 KHTMLPart *part = getDocument()->part();
586 if(m_inreset || !part) return;
591 kdDebug( 6030 ) << "reset pressed!" << endl;
594 // ### DOM2 labels this event as not cancelable, however
595 // common browsers( sick! ) allow it be cancelled.
596 if ( !dispatchHTMLEvent(EventImpl::RESET_EVENT,true, true) ) {
601 for (unsigned i = 0; i < formElements.count(); ++i)
602 formElements[i]->reset();
607 void HTMLFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
614 bool oldURLWasSecure = formWouldHaveSecureSubmission(m_url);
616 m_url = khtml::parseURL(attr->value());
618 bool newURLIsSecure = formWouldHaveSecureSubmission(m_url);
620 if (m_attached && (oldURLWasSecure != newURLIsSecure))
622 getDocument()->secureFormAdded();
624 getDocument()->secureFormRemoved();
629 m_target = attr->value();
632 if ( strcasecmp( attr->value(), "post" ) == 0 )
634 else if ( strcasecmp( attr->value(), "get" ) == 0 )
638 setEnctype( attr->value() );
640 case ATTR_ACCEPT_CHARSET:
641 // space separated list of charsets the server
642 // accepts - see rfc2045
643 m_acceptcharset = attr->value();
646 // ignore this one for the moment...
648 case ATTR_AUTOCOMPLETE:
649 m_autocomplete = strcasecmp( attr->value(), "off" );
652 setHTMLEventListener(EventImpl::SUBMIT_EVENT,
653 getDocument()->createHTMLEventListener(attr->value().string()));
656 setHTMLEventListener(EventImpl::RESET_EVENT,
657 getDocument()->createHTMLEventListener(attr->value().string()));
661 QString newNameAttr = attr->value().string();
662 if (attached() && getDocument()->isHTMLDocument()) {
663 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
664 document->removeNamedImageOrForm(oldNameAttr);
665 document->addNamedImageOrForm(newNameAttr);
667 oldNameAttr = newNameAttr;
672 QString newIdAttr = attr->value().string();
673 if (attached() && getDocument()->isHTMLDocument()) {
674 HTMLDocumentImpl *document = static_cast<HTMLDocumentImpl *>(getDocument());
675 document->removeNamedImageOrForm(oldIdAttr);
676 document->addNamedImageOrForm(newIdAttr);
678 oldIdAttr = newIdAttr;
682 HTMLElementImpl::parseHTMLAttribute(attr);
686 void HTMLFormElementImpl::radioClicked( HTMLGenericFormElementImpl *caller )
688 for (unsigned i = 0; i < formElements.count(); ++i) {
689 HTMLGenericFormElementImpl *current = formElements[i];
690 if (current->id() == ID_INPUT &&
691 static_cast<HTMLInputElementImpl*>(current)->inputType() == HTMLInputElementImpl::RADIO &&
692 current != caller && current->form() == caller->form() && current->name() == caller->name()) {
693 static_cast<HTMLInputElementImpl*>(current)->setChecked(false);
698 template<class T> static void appendToVector(QPtrVector<T> &vec, T *item)
700 unsigned size = vec.size();
701 unsigned count = vec.count();
703 vec.resize(size == 0 ? 8 : (int)(size * 1.5));
704 vec.insert(count, item);
707 template<class T> static void removeFromVector(QPtrVector<T> &vec, T *item)
709 int pos = vec.findRef(item);
710 int count = vec.count();
712 printf("item: 0x%x; pos: %d; vec[0]: 0x%x\n", (unsigned)item, pos, count ? (unsigned)vec[0] : 0);
717 for (int i = pos; i < count - 1; i++) {
718 vec.insert(i, vec[i+1]);
720 vec.remove(count - 1);
723 void HTMLFormElementImpl::registerFormElement(HTMLGenericFormElementImpl *e)
725 appendToVector(formElements, e);
726 removeFromVector(dormantFormElements, e);
729 void HTMLFormElementImpl::removeFormElement(HTMLGenericFormElementImpl *e)
731 removeFromVector(formElements, e);
732 removeFromVector(dormantFormElements, e);
735 void HTMLFormElementImpl::makeFormElementDormant(HTMLGenericFormElementImpl *e)
737 appendToVector(dormantFormElements, e);
738 removeFromVector(formElements, e);
741 bool HTMLFormElementImpl::isURLAttribute(AttributeImpl *attr) const
743 return attr->id() == ATTR_ACTION;
746 void HTMLFormElementImpl::registerImgElement(HTMLImageElementImpl *e)
748 appendToVector(imgElements, e);
751 void HTMLFormElementImpl::removeImgElement(HTMLImageElementImpl *e)
753 removeFromVector(imgElements, e);
756 // -------------------------------------------------------------------------
758 HTMLGenericFormElementImpl::HTMLGenericFormElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
759 : HTMLElementImpl(doc)
761 m_disabled = m_readOnly = false;
770 m_form->registerFormElement(this);
773 HTMLGenericFormElementImpl::~HTMLGenericFormElementImpl()
776 m_form->removeFormElement(this);
777 if (m_name) m_name->deref();
780 void HTMLGenericFormElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
787 setDisabled( !attr->isNull() );
791 bool m_oldreadOnly = m_readOnly;
792 m_readOnly = !attr->isNull();
793 if (m_oldreadOnly != m_readOnly) setChanged();
797 HTMLElementImpl::parseHTMLAttribute(attr);
801 void HTMLGenericFormElementImpl::attach()
805 // FIXME: This handles the case of a new form element being created by
806 // JavaScript and inserted inside a form. What it does not handle is
807 // a form element being moved from inside a form to outside, or from one
808 // inside one form to another. The reason this other case is hard to fix
809 // is that during parsing, we may have been passed a form that we are not
810 // inside, DOM-tree-wise. If so, it's hard for us to know when we should
811 // be removed from that form's element list.
815 m_form->registerFormElement(this);
818 HTMLElementImpl::attach();
820 // The call to updateFromElement() needs to go after the call through
821 // to the base class's attach() because that can sometimes do a close
824 m_render->updateFromElement();
826 // Delayed attachment in order to prevent FOUC can result in an object being
827 // programmatically focused before it has a render object. If we have been focused
828 // (i.e., if we are the focusNode) then go ahead and focus our corresponding native widget.
829 // (Attach/detach can also happen as a result of display type changes, e.g., making a widget
830 // block instead of inline, and focus should be restored in that case as well.)
831 if (getDocument()->focusNode() == this && m_render->isWidget() &&
832 static_cast<RenderWidget*>(renderer())->widget())
833 static_cast<RenderWidget*>(renderer())->widget()->setFocus();
837 void HTMLGenericFormElementImpl::insertedIntoDocument()
839 if (m_form && m_dormant)
840 m_form->registerFormElement(this);
844 HTMLElementImpl::insertedIntoDocument();
847 void HTMLGenericFormElementImpl::removedFromDocument()
850 m_form->makeFormElementDormant(this);
854 HTMLElementImpl::removedFromDocument();
857 HTMLFormElementImpl *HTMLGenericFormElementImpl::getForm() const
859 NodeImpl *p = parentNode();
862 if( p->id() == ID_FORM )
863 return static_cast<HTMLFormElementImpl *>(p);
867 kdDebug( 6030 ) << "couldn't find form!" << endl;
872 DOMString HTMLGenericFormElementImpl::name() const
874 if (m_name) return m_name;
877 // DOMString n = getDocument()->htmlMode() != DocumentImpl::XHtml ?
878 // getAttribute(ATTR_NAME) : getAttribute(ATTR_ID);
879 DOMString n = getAttribute(ATTR_NAME);
881 return new DOMStringImpl("");
886 void HTMLGenericFormElementImpl::setName(const DOMString& name)
888 if (m_name) m_name->deref();
889 m_name = name.implementation();
890 if (m_name) m_name->ref();
893 void HTMLGenericFormElementImpl::onSelect()
895 // ### make this work with new form events architecture
896 dispatchHTMLEvent(EventImpl::SELECT_EVENT,true,false);
899 void HTMLGenericFormElementImpl::onChange()
901 // ### make this work with new form events architecture
902 dispatchHTMLEvent(EventImpl::CHANGE_EVENT,true,false);
905 bool HTMLGenericFormElementImpl::disabled() const
910 void HTMLGenericFormElementImpl::setDisabled( bool _disabled )
912 if ( m_disabled != _disabled ) {
913 m_disabled = _disabled;
918 void HTMLGenericFormElementImpl::recalcStyle( StyleChange ch )
920 //bool changed = changed();
921 HTMLElementImpl::recalcStyle( ch );
923 if (m_render /*&& changed*/)
924 m_render->updateFromElement();
927 bool HTMLGenericFormElementImpl::isFocusable() const
929 if (!m_render || (m_render->style() && m_render->style()->visibility() != VISIBLE) || m_render->width() == 0 || m_render->height() == 0)
934 bool HTMLGenericFormElementImpl::isKeyboardFocusable() const
937 if (m_render->isWidget()) {
938 return static_cast<RenderWidget*>(m_render)->widget() &&
939 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::TabFocus);
941 if (getDocument()->part())
942 return getDocument()->part()->tabsToAllControls();
947 bool HTMLGenericFormElementImpl::isMouseFocusable() const
950 if (m_render->isWidget()) {
951 return static_cast<RenderWidget*>(m_render)->widget() &&
952 (static_cast<RenderWidget*>(m_render)->widget()->focusPolicy() & QWidget::ClickFocus);
955 // For <input type=image> and <button>, we will assume no mouse focusability. This is
956 // consistent with OS X behavior for buttons.
965 void HTMLGenericFormElementImpl::defaultEventHandler(EventImpl *evt)
967 if (evt->target()==this)
969 // Report focus in/out changes to the browser extension (editable widgets only)
970 KHTMLPart *part = getDocument()->part();
971 if (evt->id()==EventImpl::DOMFOCUSIN_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
972 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
973 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
975 ext->editableWidgetFocused(widget);
979 // We don't want this default key event handling, we'll count on
980 // Cocoa event dispatch if the event doesn't get blocked.
982 if (evt->id()==EventImpl::KEYDOWN_EVENT ||
983 evt->id()==EventImpl::KEYUP_EVENT)
985 KeyboardEventImpl * k = static_cast<KeyboardEventImpl *>(evt);
986 if (k->keyVal() == QChar('\n').unicode() && m_render && m_render->isWidget() && k->qKeyEvent)
987 QApplication::sendEvent(static_cast<RenderWidget *>(m_render)->widget(), k->qKeyEvent);
991 if (evt->id()==EventImpl::DOMFOCUSOUT_EVENT && isEditable() && part && m_render && m_render->isWidget()) {
992 KHTMLPartBrowserExtension *ext = static_cast<KHTMLPartBrowserExtension *>(part->browserExtension());
993 QWidget *widget = static_cast<RenderWidget*>(m_render)->widget();
995 ext->editableWidgetBlurred(widget);
997 // ### Don't count popup as a valid reason for losing the focus (example: opening the options of a select
998 // combobox shouldn't emit onblur)
1001 HTMLElementImpl::defaultEventHandler(evt);
1004 bool HTMLGenericFormElementImpl::isEditable()
1009 // Special chars used to encode form state strings.
1010 // We pick chars that are unlikely to be used in an HTML attr, so we rarely have to really encode.
1011 const char stateSeparator = '&';
1012 const char stateEscape = '<';
1013 static const char stateSeparatorMarker[] = "<A";
1014 static const char stateEscapeMarker[] = "<<";
1016 // Encode an element name so we can put it in a state string without colliding
1017 // with our separator char.
1018 static QString encodedElementName(QString str)
1020 int sepLoc = str.find(stateSeparator);
1021 int escLoc = str.find(stateSeparator);
1022 if (sepLoc >= 0 || escLoc >= 0) {
1023 QString newStr = str;
1024 // replace "<" with "<<"
1025 while (escLoc >= 0) {
1026 newStr.replace(escLoc, 1, stateEscapeMarker);
1027 escLoc = str.find(stateSeparator, escLoc+1);
1029 // replace "&" with "<A"
1030 while (sepLoc >= 0) {
1031 newStr.replace(sepLoc, 1, stateSeparatorMarker);
1032 sepLoc = str.find(stateSeparator, sepLoc+1);
1040 QString HTMLGenericFormElementImpl::state( )
1042 // Build a string that contains ElementName&ElementType&
1043 return encodedElementName(name().string()) + stateSeparator + type().string() + stateSeparator;
1046 QString HTMLGenericFormElementImpl::findMatchingState(QStringList &states)
1048 QString encName = encodedElementName(name().string());
1049 QString typeStr = type().string();
1050 for (QStringList::Iterator it = states.begin(); it != states.end(); ++it) {
1051 QString state = *it;
1052 int sep1 = state.find(stateSeparator);
1053 int sep2 = state.find(stateSeparator, sep1+1);
1057 QString nameAndType = state.left(sep2);
1058 if (encName.length() + typeStr.length() + 1 == (uint)sep2
1059 && nameAndType.startsWith(encName)
1060 && nameAndType.endsWith(typeStr))
1063 return state.mid(sep2+1);
1066 return QString::null;
1069 // -------------------------------------------------------------------------
1071 HTMLButtonElementImpl::HTMLButtonElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1072 : HTMLGenericFormElementImpl(doc, f)
1076 m_activeSubmit = false;
1079 HTMLButtonElementImpl::~HTMLButtonElementImpl()
1083 NodeImpl::Id HTMLButtonElementImpl::id() const
1088 DOMString HTMLButtonElementImpl::type() const
1090 return getAttribute(ATTR_TYPE);
1093 void HTMLButtonElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1098 if ( strcasecmp( attr->value(), "submit" ) == 0 )
1100 else if ( strcasecmp( attr->value(), "reset" ) == 0 )
1102 else if ( strcasecmp( attr->value(), "button" ) == 0 )
1106 m_value = attr->value();
1107 m_currValue = m_value;
1109 case ATTR_ACCESSKEY:
1112 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1113 getDocument()->createHTMLEventListener(attr->value().string()));
1116 setHTMLEventListener(EventImpl::BLUR_EVENT,
1117 getDocument()->createHTMLEventListener(attr->value().string()));
1120 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1124 void HTMLButtonElementImpl::defaultEventHandler(EventImpl *evt)
1126 if (m_type != BUTTON && (evt->id() == EventImpl::DOMACTIVATE_EVENT)) {
1128 if(m_form && m_type == SUBMIT) {
1129 m_activeSubmit = true;
1130 m_form->prepareSubmit();
1131 m_activeSubmit = false; // in case we were canceled
1133 if(m_form && m_type == RESET) m_form->reset();
1135 HTMLGenericFormElementImpl::defaultEventHandler(evt);
1138 bool HTMLButtonElementImpl::isSuccessfulSubmitButton() const
1140 // HTML spec says that buttons must have names
1141 // to be considered successful. However, other browsers
1142 // do not impose this constraint. Therefore, we behave
1143 // differently and can use different buttons than the
1145 // Remove the name constraint for now.
1146 // Was: m_type == SUBMIT && !m_disabled && !name().isEmpty()
1147 return m_type == SUBMIT && !m_disabled;
1150 bool HTMLButtonElementImpl::isActivatedSubmit() const
1152 return m_activeSubmit;
1155 void HTMLButtonElementImpl::setActivatedSubmit(bool flag)
1157 m_activeSubmit = flag;
1160 bool HTMLButtonElementImpl::appendFormData(FormDataList& encoding, bool /*multipart*/)
1162 if (m_type != SUBMIT || name().isEmpty() || !m_activeSubmit)
1164 encoding.appendData(name(), m_currValue);
1168 void HTMLButtonElementImpl::click()
1172 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1173 // using this method gives us nice Cocoa user interface feedback
1174 static_cast<QButton *>(widget)->click();
1178 HTMLGenericFormElementImpl::click();
1181 void HTMLButtonElementImpl::accessKeyAction()
1186 // -------------------------------------------------------------------------
1188 HTMLFieldSetElementImpl::HTMLFieldSetElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1189 : HTMLGenericFormElementImpl(doc, f)
1193 HTMLFieldSetElementImpl::~HTMLFieldSetElementImpl()
1197 bool HTMLFieldSetElementImpl::isFocusable() const
1202 NodeImpl::Id HTMLFieldSetElementImpl::id() const
1207 DOMString HTMLFieldSetElementImpl::type() const
1212 RenderObject* HTMLFieldSetElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
1214 return new (arena) RenderFieldset(this);
1217 // -------------------------------------------------------------------------
1219 HTMLInputElementImpl::HTMLInputElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
1220 : HTMLGenericFormElementImpl(doc, f), m_imageLoader(0)
1226 m_defaultChecked = false;
1227 m_useDefaultChecked = true;
1230 m_activeSubmit = false;
1231 m_autocomplete = true;
1242 m_autocomplete = f->autoComplete();
1245 HTMLInputElementImpl::~HTMLInputElementImpl()
1247 if (getDocument()) getDocument()->deregisterMaintainsState(this);
1248 delete m_imageLoader;
1251 NodeImpl::Id HTMLInputElementImpl::id() const
1256 void HTMLInputElementImpl::setType(const DOMString& t)
1260 if ( strcasecmp( t, "password" ) == 0 )
1262 else if ( strcasecmp( t, "checkbox" ) == 0 )
1264 else if ( strcasecmp( t, "radio" ) == 0 )
1266 else if ( strcasecmp( t, "submit" ) == 0 )
1268 else if ( strcasecmp( t, "reset" ) == 0 )
1270 else if ( strcasecmp( t, "file" ) == 0 )
1272 else if ( strcasecmp( t, "hidden" ) == 0 )
1274 else if ( strcasecmp( t, "image" ) == 0 )
1276 else if ( strcasecmp( t, "button" ) == 0 )
1278 else if ( strcasecmp( t, "khtml_isindex" ) == 0 )
1281 else if ( strcasecmp( t, "search" ) == 0 )
1283 else if ( strcasecmp( t, "range" ) == 0 )
1289 // ### IMPORTANT: Don't allow the type to be changed to FILE after the first
1290 // type change, otherwise a JavaScript programmer would be able to set a text
1291 // field's value to something like /etc/passwd and then change it to a file field.
1292 if (m_type != newType) {
1293 if (newType == FILE && m_haveType) {
1294 // Set the attribute back to the old value.
1295 // Useful in case we were called from inside parseHTMLAttribute.
1296 setAttribute(ATTR_TYPE, type());
1298 bool wasAttached = m_attached;
1301 bool didStoreValue = storesValueSeparateFromAttribute();
1303 bool willStoreValue = storesValueSeparateFromAttribute();
1304 if (didStoreValue && !willStoreValue && !m_value.isNull()) {
1305 setAttribute(ATTR_VALUE, m_value);
1306 m_value = DOMString();
1308 if (!didStoreValue && willStoreValue) {
1309 m_value = getAttribute(ATTR_VALUE);
1318 DOMString HTMLInputElementImpl::type() const
1320 // needs to be lowercase according to DOM spec
1322 case TEXT: return "text";
1323 case PASSWORD: return "password";
1324 case CHECKBOX: return "checkbox";
1325 case RADIO: return "radio";
1326 case SUBMIT: return "submit";
1327 case RESET: return "reset";
1328 case FILE: return "file";
1329 case HIDDEN: return "hidden";
1330 case IMAGE: return "image";
1331 case BUTTON: return "button";
1333 case SEARCH: return "search";
1334 case RANGE: return "range";
1336 case ISINDEX: return "";
1341 QString HTMLInputElementImpl::state( )
1343 assert(m_type != PASSWORD); // should never save/restore password fields
1345 QString state = HTMLGenericFormElementImpl::state();
1349 return state + (checked() ? "on" : "off");
1351 return state + value().string()+'.'; // Make sure the string is not empty!
1355 void HTMLInputElementImpl::restoreState(QStringList &states)
1357 assert(m_type != PASSWORD); // should never save/restore password fields
1359 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
1360 if (state.isNull()) return;
1365 setChecked((state == "on"));
1368 setValue(DOMString(state.left(state.length()-1)));
1373 void HTMLInputElementImpl::select( )
1375 if(!m_render) return;
1377 if (m_type == TEXT || m_type == PASSWORD)
1378 static_cast<RenderLineEdit*>(m_render)->select();
1379 else if (m_type == FILE)
1380 static_cast<RenderFileButton*>(m_render)->select();
1383 void HTMLInputElementImpl::click()
1385 switch (inputType()) {
1387 // a no-op for this type
1397 if (renderer() && (widget = static_cast<RenderWidget *>(renderer())->widget())) {
1398 // using this method gives us nice Cocoa user interface feedback
1399 static_cast<QButton *>(widget)->click();
1404 HTMLGenericFormElementImpl::click();
1409 static_cast<RenderFileButton *>(renderer())->click();
1413 HTMLGenericFormElementImpl::click();
1423 HTMLGenericFormElementImpl::click();
1428 void HTMLInputElementImpl::accessKeyAction()
1430 switch (inputType()) {
1432 // a no-op for this type
1459 bool HTMLInputElementImpl::mapToEntry(NodeImpl::Id attr, MappedAttributeEntry& result) const
1466 result = eUniversal;
1469 result = eReplaced; // Share with <img> since the alignment behavior is the same.
1475 return HTMLElementImpl::mapToEntry(attr, result);
1478 void HTMLInputElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
1482 case ATTR_AUTOCOMPLETE:
1483 m_autocomplete = strcasecmp( attr->value(), "off" );
1486 setType(attr->value());
1487 if (m_type != IMAGE && m_imageLoader) {
1488 delete m_imageLoader;
1493 // We only need to setChanged if the form is looking at the default value right now.
1494 if (m_value.isNull())
1498 m_defaultChecked = !attr->isNull();
1499 if (m_useDefaultChecked) {
1500 setChecked(m_defaultChecked);
1501 m_useDefaultChecked = true;
1504 case ATTR_MAXLENGTH:
1505 m_maxLen = !attr->isNull() ? attr->value().toInt() : -1;
1509 m_size = !attr->isNull() ? attr->value().toInt() : 20;
1512 if (m_render && m_type == IMAGE)
1513 static_cast<RenderImage*>(m_render)->updateAltText();
1516 if (m_render && m_type == IMAGE) {
1518 m_imageLoader = new HTMLImageLoader(this);
1519 m_imageLoader->updateFromElement();
1523 case ATTR_ACCESSKEY:
1524 // ### ignore for the moment
1527 addCSSLength(attr, CSS_PROP_MARGIN_TOP, attr->value());
1528 addCSSLength(attr, CSS_PROP_MARGIN_BOTTOM, attr->value());
1531 addCSSLength(attr, CSS_PROP_MARGIN_LEFT, attr->value());
1532 addCSSLength(attr, CSS_PROP_MARGIN_RIGHT, attr->value());
1535 addHTMLAlignment(attr);
1538 addCSSLength(attr, CSS_PROP_WIDTH, attr->value() );
1541 addCSSLength(attr, CSS_PROP_HEIGHT, attr->value() );
1544 setHTMLEventListener(EventImpl::FOCUS_EVENT,
1545 getDocument()->createHTMLEventListener(attr->value().string()));
1548 setHTMLEventListener(EventImpl::BLUR_EVENT,
1549 getDocument()->createHTMLEventListener(attr->value().string()));
1552 setHTMLEventListener(EventImpl::SELECT_EVENT,
1553 getDocument()->createHTMLEventListener(attr->value().string()));
1556 setHTMLEventListener(EventImpl::CHANGE_EVENT,
1557 getDocument()->createHTMLEventListener(attr->value().string()));
1560 setHTMLEventListener(EventImpl::INPUT_EVENT,
1561 getDocument()->createHTMLEventListener(attr->value().string()));
1564 // Search field and slider attributes all just cause updateFromElement to be called through style
1567 setHTMLEventListener(EventImpl::SEARCH_EVENT,
1568 getDocument()->createHTMLEventListener(attr->value().string()));
1571 m_maxResults = !attr->isNull() ? attr->value().toInt() : 0;
1574 case ATTR_INCREMENTAL:
1575 case ATTR_PLACEHOLDER:
1578 case ATTR_PRECISION:
1583 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
1587 bool HTMLInputElementImpl::rendererIsNeeded(RenderStyle *style)
1604 case BUTTON: return HTMLGenericFormElementImpl::rendererIsNeeded(style);
1605 case HIDDEN: return false;
1611 RenderObject *HTMLInputElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
1620 case ISINDEX: return new (arena) RenderLineEdit(this);
1621 case CHECKBOX: return new (arena) RenderCheckBox(this);
1622 case RADIO: return new (arena) RenderRadioButton(this);
1623 case SUBMIT: return new (arena) RenderSubmitButton(this);
1624 case IMAGE: return new (arena) RenderImageButton(this);
1625 case RESET: return new (arena) RenderResetButton(this);
1626 case FILE: return new (arena) RenderFileButton(this);
1627 case BUTTON: return new (arena) RenderPushButton(this);
1629 case RANGE: return new (arena) RenderSlider(this);
1637 void HTMLInputElementImpl::attach()
1641 setType(getAttribute(ATTR_TYPE));
1643 // FIXME: This needs to be dynamic, doesn't it, since someone could set this
1644 // after attachment?
1645 DOMString val = getAttribute(ATTR_VALUE);
1646 if ((uint) m_type <= ISINDEX && !val.isEmpty()) {
1647 // remove newline stuff..
1649 for (unsigned int i = 0; i < val.length(); ++i)
1653 if (val.length() != nvalue.length())
1654 setAttribute(ATTR_VALUE, nvalue);
1657 m_defaultChecked = (!getAttribute(ATTR_CHECKED).isNull());
1662 // Disallow the width attribute on inputs other than HIDDEN and IMAGE.
1663 // Dumb Web sites will try to set the width as an attribute on form controls that aren't
1664 // images or hidden.
1665 if (hasMappedAttributes() && m_type != HIDDEN && m_type != IMAGE && !getAttribute(ATTR_WIDTH).isEmpty()) {
1667 removeAttribute(ATTR_WIDTH, excCode);
1670 HTMLGenericFormElementImpl::attach();
1672 if (m_type == IMAGE) {
1674 m_imageLoader = new HTMLImageLoader(this);
1675 m_imageLoader->updateFromElement();
1677 RenderImage* imageObj = static_cast<RenderImage*>(renderer());
1678 imageObj->setImage(m_imageLoader->image());
1683 // note we don't deal with calling passwordFieldRemoved() on detach, because the timing
1684 // was such that it cleared our state too early
1685 if (m_type == PASSWORD)
1686 getDocument()->passwordFieldAdded();
1690 DOMString HTMLInputElementImpl::altText() const
1692 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen
1693 // also heavily discussed by Hixie on bugzilla
1694 // note this is intentionally different to HTMLImageElementImpl::altText()
1695 DOMString alt = getAttribute( ATTR_ALT );
1696 // fall back to title attribute
1698 alt = getAttribute( ATTR_TITLE );
1700 alt = getAttribute( ATTR_VALUE );
1701 if ( alt.isEmpty() )
1703 alt = inputElementAltText();
1705 alt = i18n( "Submit" );
1711 bool HTMLInputElementImpl::isSuccessfulSubmitButton() const
1713 // HTML spec says that buttons must have names
1714 // to be considered successful. However, other browsers
1715 // do not impose this constraint. Therefore, we behave
1716 // differently and can use different buttons than the
1718 // Was: (m_type == SUBMIT && !name().isEmpty())
1719 return !m_disabled && (m_type == IMAGE || m_type == SUBMIT);
1722 bool HTMLInputElementImpl::isActivatedSubmit() const
1724 return m_activeSubmit;
1727 void HTMLInputElementImpl::setActivatedSubmit(bool flag)
1729 m_activeSubmit = flag;
1732 bool HTMLInputElementImpl::appendFormData(FormDataList &encoding, bool multipart)
1734 // image generates its own names
1735 if (name().isEmpty() && m_type != IMAGE) return false;
1745 // always successful
1746 encoding.appendData(name(), value());
1752 encoding.appendData(name(), value());
1759 // those buttons are never successful
1765 encoding.appendData(name().isEmpty() ? QString::fromLatin1("x") : (name().string() + ".x"), clickX());
1766 encoding.appendData(name().isEmpty() ? QString::fromLatin1("y") : (name().string() + ".y"), clickY());
1774 QString enc_str = value().string();
1775 if (enc_str.isEmpty())
1776 enc_str = static_cast<RenderSubmitButton*>(m_render)->defaultLabel();
1777 if (!enc_str.isEmpty()) {
1778 encoding.appendData(name(), enc_str);
1786 // can't submit file on GET
1787 // don't submit if display: none or display: hidden
1788 if(!multipart || !renderer() || renderer()->style()->visibility() != khtml::VISIBLE)
1791 // if no filename at all is entered, return successful, however empty
1792 // null would be more logical but netscape posts an empty file. argh.
1793 if (value().isEmpty()) {
1794 encoding.appendData(name(), QString(""));
1798 KURL fileurl("file:///");
1799 fileurl.setPath(value().string());
1800 KIO::UDSEntry filestat;
1802 if (!KIO::NetAccess::stat(fileurl, filestat)) {
1804 // FIXME: Figure out how to report this error.
1806 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1811 KFileItem fileitem(filestat, fileurl, true, false);
1812 if (fileitem.isDir()) {
1817 if ( KIO::NetAccess::download(fileurl, local) )
1820 if (file.open(IO_ReadOnly))
1822 QCString filearray(file.size()+1);
1823 int readbytes = file.readBlock( filearray.data(), file.size());
1824 if ( readbytes >= 0 )
1825 filearray[readbytes] = '\0';
1828 encoding.appendData(name(), filearray);
1829 KIO::NetAccess::removeTempFile( local );
1837 // FIXME: Figure out how to report this error.
1839 KMessageBox::sorry(0L, i18n("Error fetching file for submission:\n%1").arg(KIO::NetAccess::lastErrorString()));
1846 encoding.appendData(name(), value());
1852 void HTMLInputElementImpl::reset()
1854 if (storesValueSeparateFromAttribute())
1855 setValue(DOMString());
1856 setChecked(m_defaultChecked);
1857 m_useDefaultChecked = true;
1860 void HTMLInputElementImpl::setChecked(bool _checked)
1862 if (checked() == _checked) return;
1864 if (m_form && m_type == RADIO && _checked && !name().isEmpty())
1865 m_form->radioClicked(this);
1867 m_useDefaultChecked = false;
1868 m_checked = _checked;
1873 DOMString HTMLInputElementImpl::value() const
1875 DOMString value = m_value;
1877 // It's important *not* to fall back to the value attribute for file inputs,
1878 // because that would allow a malicious web page to upload files by setting the
1879 // value attribute in markup.
1880 if (value.isNull() && m_type != FILE)
1881 value = getAttribute(ATTR_VALUE);
1883 // If no attribute exists, then just use "on" or "" based off the checked() state of the control.
1884 if (value.isNull() && (m_type == CHECKBOX || m_type == RADIO))
1885 return DOMString(checked() ? "on" : "");
1891 void HTMLInputElementImpl::setValue(const DOMString &value)
1893 if (m_type == FILE) return;
1895 if (storesValueSeparateFromAttribute()) {
1899 setAttribute(ATTR_VALUE, value);
1903 bool HTMLInputElementImpl::storesValueSeparateFromAttribute() const
1929 void HTMLInputElementImpl::blur()
1931 if(getDocument()->focusNode() == this)
1932 getDocument()->setFocusNode(0);
1935 void HTMLInputElementImpl::focus()
1937 getDocument()->setFocusNode(this);
1940 void HTMLInputElementImpl::defaultEventHandler(EventImpl *evt)
1942 if (evt->isMouseEvent() &&
1943 ( evt->id() == EventImpl::KHTML_CLICK_EVENT || evt->id() == EventImpl::KHTML_DBLCLICK_EVENT ) &&
1946 // record the mouse position for when we get the DOMActivate event
1947 MouseEventImpl *me = static_cast<MouseEventImpl*>(evt);
1948 int offsetX, offsetY;
1949 m_render->absolutePosition(offsetX,offsetY);
1950 xPos = me->clientX()-offsetX;
1951 yPos = me->clientY()-offsetY;
1953 me->setDefaultHandled();
1956 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means
1957 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks
1958 // on the element, or presses enter while it is the active element. Javacsript code wishing to activate the element
1959 // must dispatch a DOMActivate event - a click event will not do the job.
1960 if ((evt->id() == EventImpl::DOMACTIVATE_EVENT) &&
1961 (m_type == IMAGE || m_type == SUBMIT || m_type == RESET)){
1963 if (!m_form || !m_render)
1966 if (m_type == RESET) {
1970 m_activeSubmit = true;
1971 if (!m_form->prepareSubmit()) {
1975 m_activeSubmit = false;
1980 // Use key press event here since sending simulated mouse events
1981 // on key down blocks the proper sending of the key press event.
1982 if (evt->id() == EventImpl::KEYPRESS_EVENT && evt->isKeyboardEvent()) {
1983 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
1992 // Simulate mouse click for enter or spacebar for these types of elements.
1993 // The AppKit already does this for spacebar for some, but not all, of them.
1994 if (key == "U+000020" || key == "Enter") {
1996 evt->setDefaultHandled();
2005 // Simulate mouse click on the default form button for enter for these types of elements.
2006 if (key == "Enter" && m_form) {
2007 m_form->submitClick();
2008 evt->setDefaultHandled();
2015 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2018 bool HTMLInputElementImpl::isEditable()
2020 return ((m_type == TEXT) || (m_type == PASSWORD) ||
2021 (m_type == SEARCH) || (m_type == ISINDEX) || (m_type == FILE));
2024 bool HTMLInputElementImpl::isURLAttribute(AttributeImpl *attr) const
2026 return (attr->id() == ATTR_SRC);
2029 // -------------------------------------------------------------------------
2031 HTMLLabelElementImpl::HTMLLabelElementImpl(DocumentPtr *doc)
2032 : HTMLElementImpl(doc)
2036 HTMLLabelElementImpl::~HTMLLabelElementImpl()
2040 bool HTMLLabelElementImpl::isFocusable() const
2045 NodeImpl::Id HTMLLabelElementImpl::id() const
2050 void HTMLLabelElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2055 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2056 getDocument()->createHTMLEventListener(attr->value().string()));
2059 setHTMLEventListener(EventImpl::BLUR_EVENT,
2060 getDocument()->createHTMLEventListener(attr->value().string()));
2063 HTMLElementImpl::parseHTMLAttribute(attr);
2067 ElementImpl *HTMLLabelElementImpl::formElement()
2069 DOMString formElementId = getAttribute(ATTR_FOR);
2070 if (formElementId.isNull()) {
2071 // Search children of the label element for a form element.
2072 NodeImpl *node = this;
2073 while ((node = node->traverseNextNode(this))) {
2074 if (node->isHTMLElement()) {
2075 HTMLElementImpl *element = static_cast<HTMLElementImpl *>(node);
2076 if (element->isGenericFormElement()) {
2083 if (formElementId.isEmpty())
2085 return getDocument()->getElementById(formElementId);
2088 void HTMLLabelElementImpl::accessKeyAction()
2090 ElementImpl *element = formElement();
2092 element->accessKeyAction();
2095 // -------------------------------------------------------------------------
2097 HTMLLegendElementImpl::HTMLLegendElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2098 : HTMLGenericFormElementImpl(doc, f)
2102 HTMLLegendElementImpl::~HTMLLegendElementImpl()
2106 bool HTMLLegendElementImpl::isFocusable() const
2111 NodeImpl::Id HTMLLegendElementImpl::id() const
2116 RenderObject* HTMLLegendElementImpl::createRenderer(RenderArena* arena, RenderStyle* style)
2118 return new (arena) RenderLegend(this);
2121 DOMString HTMLLegendElementImpl::type() const
2126 // -------------------------------------------------------------------------
2128 HTMLSelectElementImpl::HTMLSelectElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2129 : HTMLGenericFormElementImpl(doc, f), m_options(0)
2132 m_recalcListItems = false;
2133 // 0 means invalid (i.e. not set)
2138 HTMLSelectElementImpl::~HTMLSelectElementImpl()
2140 if (getDocument()) getDocument()->deregisterMaintainsState(this);
2142 m_options->detach();
2147 NodeImpl::Id HTMLSelectElementImpl::id() const
2152 void HTMLSelectElementImpl::recalcStyle( StyleChange ch )
2154 if (hasChangedChild() && m_render) {
2155 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2158 HTMLGenericFormElementImpl::recalcStyle( ch );
2162 DOMString HTMLSelectElementImpl::type() const
2164 return (m_multiple ? "select-multiple" : "select-one");
2167 long HTMLSelectElementImpl::selectedIndex() const
2169 // return the number of the first option selected
2171 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2172 for (unsigned int i = 0; i < items.size(); i++) {
2173 if (items[i]->id() == ID_OPTION) {
2174 if (static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2179 Q_ASSERT(m_multiple);
2183 void HTMLSelectElementImpl::setSelectedIndex( long index )
2185 // deselect all other options and select only the new one
2186 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2188 for (listIndex = 0; listIndex < int(items.size()); listIndex++) {
2189 if (items[listIndex]->id() == ID_OPTION)
2190 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(false);
2192 listIndex = optionToListIndex(index);
2194 static_cast<HTMLOptionElementImpl*>(items[listIndex])->setSelected(true);
2199 long HTMLSelectElementImpl::length() const
2203 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2204 for (i = 0; i < items.size(); i++) {
2205 if (items[i]->id() == ID_OPTION)
2211 void HTMLSelectElementImpl::add( HTMLElementImpl *element, HTMLElementImpl *before )
2213 if (!element || element->id() != ID_OPTION)
2216 int exceptioncode = 0;
2217 insertBefore(element, before, exceptioncode);
2219 setRecalcListItems();
2222 void HTMLSelectElementImpl::remove( long index )
2224 int exceptioncode = 0;
2225 int listIndex = optionToListIndex(index);
2227 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2228 if(listIndex < 0 || index >= int(items.size()))
2229 return; // ### what should we do ? remove the last item?
2231 removeChild(items[listIndex], exceptioncode);
2232 if( !exceptioncode )
2233 setRecalcListItems();
2236 void HTMLSelectElementImpl::blur()
2238 if(getDocument()->focusNode() == this)
2239 getDocument()->setFocusNode(0);
2242 void HTMLSelectElementImpl::focus()
2244 getDocument()->setFocusNode(this);
2247 DOMString HTMLSelectElementImpl::value( )
2250 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2251 for (i = 0; i < items.size(); i++) {
2252 if ( items[i]->id() == ID_OPTION
2253 && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2254 return static_cast<HTMLOptionElementImpl*>(items[i])->value();
2256 return DOMString("");
2259 void HTMLSelectElementImpl::setValue(DOMStringImpl* value)
2261 // find the option with value() matching the given parameter
2262 // and make it the current selection.
2263 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2264 for (unsigned i = 0; i < items.size(); i++)
2265 if (items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->value() == value) {
2266 static_cast<HTMLOptionElementImpl*>(items[i])->setSelected(true);
2271 QString HTMLSelectElementImpl::state( )
2276 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2278 int l = items.count();
2281 QChar stateChars[l];
2283 for(int i = 0; i < l; i++)
2284 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2285 stateChars[i] = 'X';
2287 stateChars[i] = '.';
2288 QString state(stateChars, l);
2289 #else /* APPLE_CHANGES not defined */
2291 for(int i = 0; i < l; i++)
2292 if(items[i]->id() == ID_OPTION && static_cast<HTMLOptionElementImpl*>(items[i])->selected())
2294 #endif /* APPLE_CHANGES not defined */
2296 return HTMLGenericFormElementImpl::state() + state;
2299 void HTMLSelectElementImpl::restoreState(QStringList &_states)
2301 QString _state = HTMLGenericFormElementImpl::findMatchingState(_states);
2302 if (_state.isNull()) return;
2306 QString state = _state;
2307 if(!state.isEmpty() && !state.contains('X') && !m_multiple) {
2308 qWarning("should not happen in restoreState!");
2310 // KWQString doesn't support this operation. Should never get here anyway.
2317 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2319 int l = items.count();
2320 for(int i = 0; i < l; i++) {
2321 if(items[i]->id() == ID_OPTION) {
2322 HTMLOptionElementImpl* oe = static_cast<HTMLOptionElementImpl*>(items[i]);
2323 oe->setSelected(state[i] == 'X');
2329 NodeImpl *HTMLSelectElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2331 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode );
2333 setRecalcListItems();
2337 NodeImpl *HTMLSelectElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2339 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2340 if( !exceptioncode )
2341 setRecalcListItems();
2345 NodeImpl *HTMLSelectElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2347 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2348 if( !exceptioncode )
2349 setRecalcListItems();
2353 NodeImpl *HTMLSelectElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2355 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2356 if( !exceptioncode )
2357 setRecalcListItems();
2362 NodeImpl* HTMLSelectElementImpl::addChild(NodeImpl* newChild)
2364 setRecalcListItems();
2365 return HTMLGenericFormElementImpl::addChild(newChild);
2368 void HTMLSelectElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2373 m_size = QMAX( attr->value().toInt(), 1 );
2376 m_minwidth = QMAX( attr->value().toInt(), 0 );
2379 m_multiple = (!attr->isNull());
2381 case ATTR_ACCESSKEY:
2382 // ### ignore for the moment
2385 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2386 getDocument()->createHTMLEventListener(attr->value().string()));
2389 setHTMLEventListener(EventImpl::BLUR_EVENT,
2390 getDocument()->createHTMLEventListener(attr->value().string()));
2393 setHTMLEventListener(EventImpl::CHANGE_EVENT,
2394 getDocument()->createHTMLEventListener(attr->value().string()));
2397 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2401 RenderObject *HTMLSelectElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2403 return new (arena) RenderSelect(this);
2406 bool HTMLSelectElementImpl::appendFormData(FormDataList& encoded_values, bool)
2408 bool successful = false;
2409 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2412 for (i = 0; i < items.size(); i++) {
2413 if (items[i]->id() == ID_OPTION) {
2414 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2415 if (option->selected()) {
2416 encoded_values.appendData(name(), option->value());
2422 // ### this case should not happen. make sure that we select the first option
2423 // in any case. otherwise we have no consistency with the DOM interface. FIXME!
2424 // we return the first one if it was a combobox select
2425 if (!successful && !m_multiple && m_size <= 1 && items.size() &&
2426 (items[0]->id() == ID_OPTION) ) {
2427 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[0]);
2428 if (option->value().isNull())
2429 encoded_values.appendData(name(), option->text().string().stripWhiteSpace());
2431 encoded_values.appendData(name(), option->value());
2438 int HTMLSelectElementImpl::optionToListIndex(int optionIndex) const
2440 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2441 if (optionIndex < 0 || optionIndex >= int(items.size()))
2445 int optionIndex2 = 0;
2447 optionIndex2 < int(items.size()) && optionIndex2 <= optionIndex;
2448 listIndex++) { // not a typo!
2449 if (items[listIndex]->id() == ID_OPTION)
2456 int HTMLSelectElementImpl::listToOptionIndex(int listIndex) const
2458 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2459 if (listIndex < 0 || listIndex >= int(items.size()) ||
2460 items[listIndex]->id() != ID_OPTION)
2463 int optionIndex = 0; // actual index of option not counting OPTGROUP entries that may be in list
2465 for (i = 0; i < listIndex; i++)
2466 if (items[i]->id() == ID_OPTION)
2471 HTMLOptionsCollectionImpl *HTMLSelectElementImpl::options()
2474 m_options = new HTMLOptionsCollectionImpl(this);
2480 void HTMLSelectElementImpl::recalcListItems()
2482 NodeImpl* current = firstChild();
2483 m_listItems.resize(0);
2484 HTMLOptionElementImpl* foundSelected = 0;
2486 if (current->id() == ID_OPTGROUP && current->firstChild()) {
2487 // ### what if optgroup contains just comments? don't want one of no options in it...
2488 m_listItems.resize(m_listItems.size()+1);
2489 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2490 current = current->firstChild();
2492 if (current->id() == ID_OPTION) {
2493 m_listItems.resize(m_listItems.size()+1);
2494 m_listItems[m_listItems.size()-1] = static_cast<HTMLGenericFormElementImpl*>(current);
2495 if (!foundSelected && !m_multiple && m_size <= 1) {
2496 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2497 foundSelected->m_selected = true;
2499 else if (foundSelected && !m_multiple && static_cast<HTMLOptionElementImpl*>(current)->selected()) {
2500 foundSelected->m_selected = false;
2501 foundSelected = static_cast<HTMLOptionElementImpl*>(current);
2504 NodeImpl *parent = current->parentNode();
2505 current = current->nextSibling();
2508 current = parent->nextSibling();
2511 m_recalcListItems = false;
2514 void HTMLSelectElementImpl::childrenChanged()
2516 setRecalcListItems();
2518 HTMLGenericFormElementImpl::childrenChanged();
2521 void HTMLSelectElementImpl::setRecalcListItems()
2523 m_recalcListItems = true;
2525 static_cast<khtml::RenderSelect*>(m_render)->setOptionsChanged(true);
2529 void HTMLSelectElementImpl::reset()
2531 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2533 for (i = 0; i < items.size(); i++) {
2534 if (items[i]->id() == ID_OPTION) {
2535 HTMLOptionElementImpl *option = static_cast<HTMLOptionElementImpl*>(items[i]);
2536 bool selected = (!option->getAttribute(ATTR_SELECTED).isNull());
2537 option->setSelected(selected);
2541 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2545 void HTMLSelectElementImpl::notifyOptionSelected(HTMLOptionElementImpl *selectedOption, bool selected)
2547 if (selected && !m_multiple) {
2548 // deselect all other options
2549 QMemArray<HTMLGenericFormElementImpl*> items = listItems();
2551 for (i = 0; i < items.size(); i++) {
2552 if (items[i]->id() == ID_OPTION)
2553 static_cast<HTMLOptionElementImpl*>(items[i])->m_selected = (items[i] == selectedOption);
2557 static_cast<RenderSelect*>(m_render)->setSelectionChanged(true);
2564 void HTMLSelectElementImpl::defaultEventHandler(EventImpl *evt)
2566 // Use key press event here since sending simulated mouse events
2567 // on key down blocks the proper sending of the key press event.
2568 if (evt->id() == EventImpl::KEYPRESS_EVENT) {
2570 if (!m_form || !m_render || !evt->isKeyboardEvent())
2573 DOMString key = static_cast<KeyboardEventImpl *>(evt)->keyIdentifier();
2575 if (key == "Enter") {
2576 m_form->submitClick();
2577 evt->setDefaultHandled();
2580 HTMLGenericFormElementImpl::defaultEventHandler(evt);
2583 #endif // APPLE_CHANGES
2585 void HTMLSelectElementImpl::accessKeyAction()
2590 // -------------------------------------------------------------------------
2592 HTMLKeygenElementImpl::HTMLKeygenElementImpl(DocumentPtr* doc, HTMLFormElementImpl* f)
2593 : HTMLSelectElementImpl(doc, f)
2595 QStringList keys = KSSLKeyGen::supportedKeySizes();
2596 for (QStringList::Iterator i = keys.begin(); i != keys.end(); ++i) {
2597 HTMLOptionElementImpl* o = new HTMLOptionElementImpl(doc, form());
2599 o->addChild(new TextImpl(doc, DOMString(*i)));
2603 NodeImpl::Id HTMLKeygenElementImpl::id() const
2608 DOMString HTMLKeygenElementImpl::type() const
2613 void HTMLKeygenElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
2617 case ATTR_CHALLENGE:
2618 m_challenge = attr->value();
2621 m_keyType = attr->value();
2624 // skip HTMLSelectElementImpl parsing!
2625 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2629 bool HTMLKeygenElementImpl::appendFormData(FormDataList& encoded_values, bool)
2632 // Only RSA is supported at this time.
2633 if (!m_keyType.isNull() && strcasecmp(m_keyType, "rsa")) {
2636 QString value = KSSLKeyGen::signedPublicKeyAndChallengeString(selectedIndex(), m_challenge.string(), getDocument()->part()->baseURL());
2637 if (value.isNull()) {
2640 encoded_values.appendData(name(), value.utf8());
2643 bool successful = false;
2645 // pop up the fancy certificate creation dialog here
2646 KSSLKeyGen *kg = new KSSLKeyGen(static_cast<RenderWidget *>(m_render)->widget(), "Key Generator", true);
2649 successful = (QDialog::Accepted == kg->exec());
2653 encoded_values.appendData(name(), "deadbeef");
2659 // -------------------------------------------------------------------------
2661 HTMLOptGroupElementImpl::HTMLOptGroupElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2662 : HTMLGenericFormElementImpl(doc, f)
2666 HTMLOptGroupElementImpl::~HTMLOptGroupElementImpl()
2670 bool HTMLOptGroupElementImpl::isFocusable() const
2675 NodeImpl::Id HTMLOptGroupElementImpl::id() const
2680 DOMString HTMLOptGroupElementImpl::type() const
2685 NodeImpl *HTMLOptGroupElementImpl::insertBefore ( NodeImpl *newChild, NodeImpl *refChild, int &exceptioncode )
2687 NodeImpl *result = HTMLGenericFormElementImpl::insertBefore(newChild,refChild, exceptioncode);
2688 if ( !exceptioncode )
2689 recalcSelectOptions();
2693 NodeImpl *HTMLOptGroupElementImpl::replaceChild ( NodeImpl *newChild, NodeImpl *oldChild, int &exceptioncode )
2695 NodeImpl *result = HTMLGenericFormElementImpl::replaceChild(newChild,oldChild, exceptioncode);
2697 recalcSelectOptions();
2701 NodeImpl *HTMLOptGroupElementImpl::removeChild ( NodeImpl *oldChild, int &exceptioncode )
2703 NodeImpl *result = HTMLGenericFormElementImpl::removeChild(oldChild, exceptioncode);
2704 if( !exceptioncode )
2705 recalcSelectOptions();
2709 NodeImpl *HTMLOptGroupElementImpl::appendChild ( NodeImpl *newChild, int &exceptioncode )
2711 NodeImpl *result = HTMLGenericFormElementImpl::appendChild(newChild, exceptioncode);
2712 if( !exceptioncode )
2713 recalcSelectOptions();
2717 NodeImpl* HTMLOptGroupElementImpl::addChild(NodeImpl* newChild)
2719 recalcSelectOptions();
2721 return HTMLGenericFormElementImpl::addChild(newChild);
2724 void HTMLOptGroupElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2726 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2727 recalcSelectOptions();
2730 void HTMLOptGroupElementImpl::recalcSelectOptions()
2732 NodeImpl *select = parentNode();
2733 while (select && select->id() != ID_SELECT)
2734 select = select->parentNode();
2736 static_cast<HTMLSelectElementImpl*>(select)->setRecalcListItems();
2739 // -------------------------------------------------------------------------
2741 HTMLOptionElementImpl::HTMLOptionElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2742 : HTMLGenericFormElementImpl(doc, f)
2747 bool HTMLOptionElementImpl::isFocusable() const
2752 NodeImpl::Id HTMLOptionElementImpl::id() const
2757 DOMString HTMLOptionElementImpl::type() const
2762 DOMString HTMLOptionElementImpl::text() const
2765 // WinIE does not use the label attribute, so as a quirk, we ignore it.
2766 if (getDocument() && !getDocument()->inCompatMode())
2767 label = getAttribute(ATTR_LABEL);
2768 if (label.isEmpty() && firstChild() && firstChild()->nodeType() == Node::TEXT_NODE) {
2769 if (firstChild()->nextSibling()) {
2771 NodeImpl *n = firstChild();
2772 for (; n; n = n->nextSibling()) {
2773 if (n->nodeType() == Node::TEXT_NODE ||
2774 n->nodeType() == Node::CDATA_SECTION_NODE)
2775 ret += n->nodeValue();
2780 return firstChild()->nodeValue();
2786 long HTMLOptionElementImpl::index() const
2788 // Let's do this dynamically. Might be a bit slow, but we're sure
2789 // we won't forget to update a member variable in some cases...
2790 QMemArray<HTMLGenericFormElementImpl*> items = getSelect()->listItems();
2791 int l = items.count();
2792 int optionIndex = 0;
2793 for(int i = 0; i < l; i++) {
2794 if(items[i]->id() == ID_OPTION)
2796 if (static_cast<HTMLOptionElementImpl*>(items[i]) == this)
2801 kdWarning() << "HTMLOptionElementImpl::index(): option not found!" << endl;
2805 void HTMLOptionElementImpl::setIndex( long )
2807 kdWarning() << "Unimplemented HTMLOptionElementImpl::setIndex(long) called" << endl;
2811 void HTMLOptionElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2816 m_selected = (!attr->isNull());
2819 m_value = attr->value();
2822 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2826 DOMString HTMLOptionElementImpl::value() const
2828 if ( !m_value.isNull() )
2830 // Use the text if the value wasn't set.
2831 return text().string().stripWhiteSpace();
2834 void HTMLOptionElementImpl::setValue(DOMStringImpl* value)
2836 setAttribute(ATTR_VALUE, value);
2839 void HTMLOptionElementImpl::setSelected(bool _selected)
2841 if(m_selected == _selected)
2843 m_selected = _selected;
2844 HTMLSelectElementImpl *select = getSelect();
2846 select->notifyOptionSelected(this,_selected);
2849 void HTMLOptionElementImpl::childrenChanged()
2851 HTMLSelectElementImpl *select = getSelect();
2853 select->childrenChanged();
2856 HTMLSelectElementImpl *HTMLOptionElementImpl::getSelect() const
2858 NodeImpl *select = parentNode();
2859 while (select && select->id() != ID_SELECT)
2860 select = select->parentNode();
2861 return static_cast<HTMLSelectElementImpl*>(select);
2864 // -------------------------------------------------------------------------
2866 HTMLTextAreaElementImpl::HTMLTextAreaElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
2867 : HTMLGenericFormElementImpl(doc, f)
2869 // DTD requires rows & cols be specified, but we will provide reasonable defaults
2872 m_wrap = ta_Virtual;
2873 m_dirtyvalue = true;
2876 HTMLTextAreaElementImpl::~HTMLTextAreaElementImpl()
2878 if (getDocument()) getDocument()->deregisterMaintainsState(this);
2881 NodeImpl::Id HTMLTextAreaElementImpl::id() const
2886 DOMString HTMLTextAreaElementImpl::type() const
2891 QString HTMLTextAreaElementImpl::state( )
2893 // Make sure the string is not empty!
2894 return HTMLGenericFormElementImpl::state() + value().string()+'.';
2897 void HTMLTextAreaElementImpl::restoreState(QStringList &states)
2899 QString state = HTMLGenericFormElementImpl::findMatchingState(states);
2900 if (state.isNull()) return;
2901 setDefaultValue(state.left(state.length()-1));
2902 // the close() in the rendertree will take care of transferring defaultvalue to 'value'
2905 void HTMLTextAreaElementImpl::select( )
2908 static_cast<RenderTextArea*>(m_render)->select();
2912 void HTMLTextAreaElementImpl::childrenChanged()
2914 setValue(defaultValue());
2917 void HTMLTextAreaElementImpl::parseHTMLAttribute(HTMLAttributeImpl *attr)
2922 m_rows = !attr->isNull() ? attr->value().toInt() : 3;
2924 renderer()->setNeedsLayoutAndMinMaxRecalc();
2927 m_cols = !attr->isNull() ? attr->value().toInt() : 60;
2929 renderer()->setNeedsLayoutAndMinMaxRecalc();
2932 // virtual / physical is Netscape extension of HTML 3.0, now deprecated
2933 // soft/ hard / off is recommendation for HTML 4 extension by IE and NS 4
2934 if ( strcasecmp( attr->value(), "virtual" ) == 0 || strcasecmp( attr->value(), "soft") == 0)
2935 m_wrap = ta_Virtual;
2936 else if ( strcasecmp ( attr->value(), "physical" ) == 0 || strcasecmp( attr->value(), "hard") == 0)
2937 m_wrap = ta_Physical;
2938 else if(strcasecmp( attr->value(), "on" ) == 0)
2939 m_wrap = ta_Physical;
2940 else if(strcasecmp( attr->value(), "off") == 0)
2943 renderer()->setNeedsLayoutAndMinMaxRecalc();
2945 case ATTR_ACCESSKEY:
2946 // ignore for the moment
2949 setHTMLEventListener(EventImpl::FOCUS_EVENT,
2950 getDocument()->createHTMLEventListener(attr->value().string()));
2953 setHTMLEventListener(EventImpl::BLUR_EVENT,
2954 getDocument()->createHTMLEventListener(attr->value().string()));
2957 setHTMLEventListener(EventImpl::SELECT_EVENT,
2958 getDocument()->createHTMLEventListener(attr->value().string()));
2961 setHTMLEventListener(EventImpl::CHANGE_EVENT,
2962 getDocument()->createHTMLEventListener(attr->value().string()));
2965 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
2969 RenderObject *HTMLTextAreaElementImpl::createRenderer(RenderArena *arena, RenderStyle *style)
2971 return new (arena) RenderTextArea(this);
2974 bool HTMLTextAreaElementImpl::appendFormData(FormDataList& encoding, bool)
2976 if (name().isEmpty()) return false;
2977 encoding.appendData(name(), value());
2981 void HTMLTextAreaElementImpl::reset()
2983 setValue(defaultValue());
2986 DOMString HTMLTextAreaElementImpl::value()
2988 if ( m_dirtyvalue) {
2990 m_value = static_cast<RenderTextArea*>( m_render )->text();
2992 m_value = defaultValue().string();
2993 m_dirtyvalue = false;
2996 if ( m_value.isNull() ) return "";
3001 void HTMLTextAreaElementImpl::setValue(DOMString _value)
3003 m_value = _value.string();
3004 m_dirtyvalue = false;
3009 DOMString HTMLTextAreaElementImpl::defaultValue()
3012 // there may be comments - just grab the text nodes
3014 for (n = firstChild(); n; n = n->nextSibling())
3015 if (n->isTextNode())
3016 val += static_cast<TextImpl*>(n)->data();
3017 if (val[0] == '\r' && val[1] == '\n') {
3021 else if (val[0] == '\r' || val[0] == '\n') {
3029 void HTMLTextAreaElementImpl::setDefaultValue(DOMString _defaultValue)
3031 // there may be comments - remove all the text nodes and replace them with one
3032 QPtrList<NodeImpl> toRemove;
3034 for (n = firstChild(); n; n = n->nextSibling())
3035 if (n->isTextNode())
3037 QPtrListIterator<NodeImpl> it(toRemove);
3038 int exceptioncode = 0;
3039 for (; it.current(); ++it) {
3040 removeChild(it.current(), exceptioncode);
3042 insertBefore(getDocument()->createTextNode(_defaultValue),firstChild(), exceptioncode);
3043 setValue(_defaultValue);
3046 void HTMLTextAreaElementImpl::blur()
3048 if(getDocument()->focusNode() == this)
3049 getDocument()->setFocusNode(0);
3052 void HTMLTextAreaElementImpl::focus()
3054 getDocument()->setFocusNode(this);
3057 bool HTMLTextAreaElementImpl::isEditable()
3062 void HTMLTextAreaElementImpl::accessKeyAction()
3067 // -------------------------------------------------------------------------
3069 HTMLIsIndexElementImpl::HTMLIsIndexElementImpl(DocumentPtr *doc, HTMLFormElementImpl *f)
3070 : HTMLInputElementImpl(doc, f)
3076 NodeImpl::Id HTMLIsIndexElementImpl::id() const
3081 void HTMLIsIndexElementImpl::parseHTMLAttribute(HTMLAttributeImpl* attr)
3086 setValue(attr->value());
3088 // don't call HTMLInputElement::parseHTMLAttribute here, as it would
3089 // accept attributes this element does not support
3090 HTMLGenericFormElementImpl::parseHTMLAttribute(attr);
3094 // -------------------------------------------------------------------------
3096 unsigned long HTMLOptionsCollectionImpl::length() const
3098 // Not yet implemented.
3102 void HTMLOptionsCollectionImpl::setLength(unsigned long length)
3104 // Not yet implemented.
3107 NodeImpl *HTMLOptionsCollectionImpl::item(unsigned long index) const
3109 // Not yet implemented.
3113 NodeImpl *HTMLOptionsCollectionImpl::namedItem(const DOMString &name) const
3115 // Not yet implemented.
3119 // -------------------------------------------------------------------------
3121 FormDataList::FormDataList(QTextCodec *c)
3126 void FormDataList::appendString(const QCString &s)
3128 m_strings.append(s);
3131 void FormDataList::appendString(const QString &s)
3133 QCString cstr = fixLineBreaks(m_codec->fromUnicode(s));
3134 cstr.truncate(cstr.length());
3135 m_strings.append(cstr);
3138 QValueListConstIterator<QCString> FormDataList::begin() const
3140 return m_strings.begin();
3143 QValueListConstIterator<QCString> FormDataList::end() const
3145 return m_strings.end();