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 * Copyright (C) 2003 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
24 // -------------------------------------------------------------------------
25 #include "html/html_miscimpl.h"
26 #include "html/html_formimpl.h"
27 #include "html/html_imageimpl.h"
28 #include "html/html_documentimpl.h"
30 #include "misc/htmlhashes.h"
31 #include "dom/dom_node.h"
37 HTMLBaseFontElementImpl::HTMLBaseFontElementImpl(DocumentPtr *doc)
38 : HTMLElementImpl(doc)
42 HTMLBaseFontElementImpl::~HTMLBaseFontElementImpl()
46 NodeImpl::Id HTMLBaseFontElementImpl::id() const
51 // -------------------------------------------------------------------------
53 HTMLCollectionImpl::HTMLCollectionImpl(NodeImpl *_base, int _type)
59 info = base->isDocumentNode() ? static_cast<HTMLDocumentImpl*>(base->getDocument())->collectionInfo(type) : new CollectionInfo;
62 HTMLCollectionImpl::~HTMLCollectionImpl()
64 if (!base->isDocumentNode())
69 void HTMLCollectionImpl::resetCollectionInfo() const
71 unsigned int docversion = static_cast<HTMLDocumentImpl*>(base->getDocument())->domTreeVersion();
72 if (info->version != docversion) {
76 info->haslength = false;
77 info->version = docversion;
82 NodeImpl *HTMLCollectionImpl::traverseNextItem(NodeImpl *current) const
84 current = current->traverseNextNode();
87 if(current->nodeType() == Node::ELEMENT_NODE) {
90 HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
97 if(e->id() == ID_FORM)
101 if(e->id() == ID_TBODY)
103 else if(e->id() == ID_TABLE)
107 if(e->id() == ID_TD || e->id() == ID_TH)
109 else if(e->id() == ID_TABLE)
116 else if(e->id() == ID_TABLE)
120 if(e->id() == ID_OPTION)
124 if(e->id() == ID_AREA)
127 case DOC_APPLETS: // all OBJECT and APPLET elements
128 if(e->id() == ID_OBJECT || e->id() == ID_APPLET)
131 case DOC_EMBEDS: // all EMBED elements
132 if(e->id() == ID_EMBED)
135 case DOC_LINKS: // all A _and_ AREA elements with a value for href
136 if(e->id() == ID_A || e->id() == ID_AREA)
137 if(!e->getAttribute(ATTR_HREF).isNull())
140 case DOC_ANCHORS: // all A elements with a value for name or an id attribute
142 if(!e->getAttribute(ATTR_NAME).isNull())
153 kdDebug( 6030 ) << "Error in HTMLCollection, wrong tagId!" << endl;
159 current = current->traverseNextNode(base);
163 current = current->traverseNextSibling(base);
169 unsigned long HTMLCollectionImpl::calcLength() const
171 unsigned long len = 0;
173 for (NodeImpl *current = traverseNextItem(base); current; current = traverseNextItem(current)) {
180 // since the collections are to be "live", we have to do the
181 // calculation every time if anything has changed
182 unsigned long HTMLCollectionImpl::length() const
184 resetCollectionInfo();
185 if (!info->haslength) {
186 info->length = calcLength();
187 info->haslength = true;
192 NodeImpl *HTMLCollectionImpl::item( unsigned long index ) const
194 resetCollectionInfo();
195 if (info->current && info->position == index) {
196 return info->current;
198 if (info->haslength && info->length <= index) {
201 if (!info->current || info->position > index) {
202 info->current = traverseNextItem(base);
207 NodeImpl *node = info->current;
208 for (unsigned pos = info->position; pos < index; pos++) {
209 node = traverseNextItem(node);
211 info->current = node;
212 info->position = index;
213 return info->current;
216 NodeImpl *HTMLCollectionImpl::firstItem() const
221 NodeImpl *HTMLCollectionImpl::nextItem() const
223 resetCollectionInfo();
225 // Look for the 'second' item. The first one is currentItem, already given back.
226 NodeImpl *retval = traverseNextItem(info->current);
227 info->current = retval;
232 bool HTMLCollectionImpl::checkForNameMatch(NodeImpl *node, bool checkName, const DOMString &name, bool caseSensitive) const
234 ElementImpl *e = static_cast<ElementImpl *>(node);
237 return e->getAttribute(ATTR_NAME) == name && e->getAttribute(ATTR_ID) != name;
239 return e->getAttribute(ATTR_ID) == name;
243 return e->getAttribute(ATTR_NAME).domString().lower() == name.lower() &&
244 e->getAttribute(ATTR_ID).domString().lower() != name.lower();
246 return e->getAttribute(ATTR_ID).domString().lower() == name.lower();
252 NodeImpl *HTMLCollectionImpl::namedItem( const DOMString &name, bool caseSensitive ) const
254 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
255 // This method first searches for an object with a matching id
256 // attribute. If a match is not found, the method then searches for an
257 // object with a matching name attribute, but only on those elements
258 // that are allowed a name attribute.
259 resetCollectionInfo();
263 for (n = traverseNextItem(base); n; n = traverseNextItem(n)) {
264 if (checkForNameMatch(n, idsDone, name, caseSensitive)) {
271 return info->current;
274 for (n = traverseNextItem(base); n; n = traverseNextItem(n)) {
275 if (checkForNameMatch(n, idsDone, name, caseSensitive)) {
281 return info->current;
284 QValueList<Node> HTMLCollectionImpl::namedItems(const DOMString &name) const
286 resetCollectionInfo();
288 QValueList<Node> idResults;
289 QValueList<Node> nameResults;
291 for (NodeImpl *n = traverseNextItem(base); n; n = traverseNextItem(n)) {
292 if (checkForNameMatch(n, false, name, true)) {
293 idResults.append(Node(n));
295 if (checkForNameMatch(n, true, name, true)) {
296 nameResults.append(Node(n));
300 if (idResults.isEmpty())
303 for (QValueListIterator<Node> iter = nameResults.begin(); iter != nameResults.end(); ++iter) {
304 idResults.append(*iter);
311 NodeImpl *HTMLCollectionImpl::nextNamedItem( const DOMString &name ) const
313 resetCollectionInfo();
315 for (NodeImpl *n = traverseNextItem(info->current ? info->current : base); n; n = traverseNextItem(n)) {
316 if (checkForNameMatch(n, idsDone, name, true)) {
328 for (NodeImpl *n = traverseNextItem(info->current ? info->current : base); n; n = traverseNextItem(n)) {
329 if (checkForNameMatch(n, idsDone, name, true)) {
338 // -----------------------------------------------------------------------------
340 HTMLFormCollectionImpl::FormCollectionInfo::FormCollectionInfo()
345 void::HTMLFormCollectionImpl::FormCollectionInfo::reset()
347 elementsArrayPosition = 0;
350 void HTMLFormCollectionImpl::resetCollectionInfo() const
352 unsigned int docversion = static_cast<HTMLDocumentImpl*>(base->getDocument())->domTreeVersion();
353 if (info->version != docversion) {
356 HTMLCollectionImpl::resetCollectionInfo();
359 unsigned long HTMLFormCollectionImpl::calcLength() const
361 QPtrVector<HTMLGenericFormElementImpl> &l = static_cast<HTMLFormElementImpl*>( base )->formElements;
364 for ( unsigned i = 0; i < l.count(); i++ )
365 if ( l.at( i )->isEnumeratable() )
371 NodeImpl *HTMLFormCollectionImpl::item(unsigned long index) const
373 resetCollectionInfo();
375 if (info->current && info->position == index) {
376 return info->current;
378 if (info->haslength && info->length <= index) {
381 if (!info->current || info->position > index) {
384 formInfo.elementsArrayPosition = 0;
387 QPtrVector<HTMLGenericFormElementImpl> &l = static_cast<HTMLFormElementImpl*>( base )->formElements;
388 unsigned currentIndex = info->position;
390 for (unsigned i = formInfo.elementsArrayPosition; i < l.count(); i++) {
391 if (l[i]->isEnumeratable() ) {
392 if (index == currentIndex) {
393 info->position = index;
394 info->current = l[i];
395 formInfo.elementsArrayPosition = i;
406 NodeImpl* HTMLFormCollectionImpl::getNamedItem(NodeImpl*, int attr_id, const DOMString& name, bool caseSensitive) const
409 return getNamedFormItem( attr_id, name, 0, caseSensitive );
412 NodeImpl* HTMLFormCollectionImpl::getNamedFormItem(int attr_id, const DOMString& name, int duplicateNumber, bool caseSensitive) const
414 if(base->nodeType() == Node::ELEMENT_NODE)
416 HTMLElementImpl* baseElement = static_cast<HTMLElementImpl*>(base);
417 bool foundInputElements = false;
418 if(baseElement->id() == ID_FORM)
420 HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(baseElement);
421 for (unsigned i = 0; i < f->formElements.count(); ++i) {
422 HTMLGenericFormElementImpl* e = f->formElements[i];
423 if (e->isEnumeratable()) {
426 found = e->getAttribute(attr_id) == name;
428 found = e->getAttribute(attr_id).domString().lower() == name.lower();
430 foundInputElements = true;
431 if (!duplicateNumber)
439 if ( !foundInputElements )
441 HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(baseElement);
443 for(unsigned i = 0; i < f->imgElements.count(); ++i)
445 HTMLImageElementImpl* e = f->imgElements[i];
448 found = e->getAttribute(attr_id) == name;
450 found = e->getAttribute(attr_id).domString().lower() == name.lower();
452 if (!duplicateNumber)
462 NodeImpl * HTMLFormCollectionImpl::firstItem() const
467 NodeImpl * HTMLFormCollectionImpl::nextItem() const
469 return item(info->position + 1);
472 NodeImpl * HTMLFormCollectionImpl::nextNamedItemInternal( const DOMString &name ) const
474 NodeImpl *retval = getNamedFormItem( idsDone ? ATTR_NAME : ATTR_ID, name, ++info->position, true );
477 if ( idsDone ) // we're done
479 // After doing all ATTR_ID, do ATTR_NAME
481 return getNamedItem(base->firstChild(), ATTR_NAME, name, true);
484 NodeImpl *HTMLFormCollectionImpl::namedItem( const DOMString &name, bool caseSensitive ) const
486 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
487 // This method first searches for an object with a matching id
488 // attribute. If a match is not found, the method then searches for an
489 // object with a matching name attribute, but only on those elements
490 // that are allowed a name attribute.
491 resetCollectionInfo();
493 info->current = getNamedItem(base->firstChild(), ATTR_ID, name, true);
495 return info->current;
497 info->current = getNamedItem(base->firstChild(), ATTR_NAME, name, true);
498 return info->current;
502 NodeImpl *HTMLFormCollectionImpl::nextNamedItem( const DOMString &name ) const
504 // nextNamedItemInternal can return an item that has both id=<name> and name=<name>
505 // Here, we have to filter out such cases.
506 NodeImpl *impl = nextNamedItemInternal( name );
507 if (!idsDone) // looking for id=<name> -> no filtering
509 // looking for name=<name> -> filter out if id=<name>
513 if(impl->nodeType() == Node::ELEMENT_NODE)
515 HTMLElementImpl *e = static_cast<HTMLElementImpl *>(impl);
516 ok = (e->getAttribute(ATTR_ID) != name);
518 impl = nextNamedItemInternal( name );
519 } else // can't happen
525 QValueList<Node> HTMLFormCollectionImpl::namedItems(const DOMString &name) const
528 return QValueList<Node>();
531 resetCollectionInfo();
533 QValueList<Node> idResults;
534 QValueList<Node> nameResults;
536 if (base->nodeType() != Node::ELEMENT_NODE ||static_cast<HTMLElementImpl*>(base)->id() != ID_FORM)
539 HTMLElementImpl* baseElement = static_cast<HTMLElementImpl*>(base);
541 bool foundInputElements = false;
542 HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(baseElement);
543 for (unsigned i = 0; i < f->formElements.count(); ++i) {
544 HTMLGenericFormElementImpl* e = f->formElements[i];
545 if (e->isEnumeratable()) {
546 if (checkForNameMatch(e, false, name, true)) {
547 idResults.append(Node(e));
548 foundInputElements = true;
550 if (checkForNameMatch(e, true, name, true)) {
551 nameResults.append(Node(e));
552 foundInputElements = true;
557 if (!foundInputElements) {
558 HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(baseElement);
560 for (unsigned i = 0; i < f->imgElements.count(); ++i) {
561 HTMLImageElementImpl* e = f->imgElements[i];
563 if (checkForNameMatch(e, false, name, true)) {
564 idResults.append(Node(e));
566 if (checkForNameMatch(e, true, name, true)) {
567 nameResults.append(Node(e));
572 if (idResults.isEmpty())
575 for (QValueListIterator<Node> iter = nameResults.begin(); iter != nameResults.end(); ++iter) {
576 idResults.append(*iter);