khtml Library API Documentation

html_miscimpl.cpp

00001 
00024 // -------------------------------------------------------------------------
00025 #include "html/html_miscimpl.h"
00026 #include "html/html_formimpl.h"
00027 
00028 #include "misc/htmlhashes.h"
00029 #include "dom/dom_node.h"
00030 
00031 using namespace DOM;
00032 
00033 #include <kdebug.h>
00034 
00035 HTMLBaseFontElementImpl::HTMLBaseFontElementImpl(DocumentPtr *doc)
00036     : HTMLElementImpl(doc)
00037 {
00038 }
00039 
00040 HTMLBaseFontElementImpl::~HTMLBaseFontElementImpl()
00041 {
00042 }
00043 
00044 NodeImpl::Id HTMLBaseFontElementImpl::id() const
00045 {
00046     return ID_BASEFONT;
00047 }
00048 
00049 // -------------------------------------------------------------------------
00050 
00051 HTMLCollectionImpl::HTMLCollectionImpl(NodeImpl *_base, int _type)
00052 {
00053     base = _base;
00054     base->ref();
00055     type = _type;
00056     currentItem = 0L;
00057     idsDone = false;
00058 }
00059 
00060 HTMLCollectionImpl::~HTMLCollectionImpl()
00061 {
00062     base->deref();
00063 }
00064 
00065 unsigned long HTMLCollectionImpl::calcLength(NodeImpl *current) const
00066 {
00067     unsigned long len = 0;
00068     while(current)
00069     {
00070         if(current->nodeType() == Node::ELEMENT_NODE)
00071         {
00072             bool deep = true;
00073             HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
00074             switch(type)
00075             {
00076             case DOC_IMAGES:
00077                 if(e->id() == ID_IMG)
00078                     len++;
00079                 break;
00080             case DOC_FORMS:
00081                 if(e->id() == ID_FORM)
00082                     len++;
00083                 break;
00084             case TABLE_TBODIES:
00085                 if(e->id() == ID_TBODY)
00086                     len++;
00087                 else if(e->id() == ID_TABLE)
00088                     deep = false;
00089                 break;
00090             case TR_CELLS:
00091                 if(e->id() == ID_TD || e->id() == ID_TH)
00092                     len++;
00093                 else if(e->id() == ID_TABLE)
00094                     deep = false;
00095                 break;
00096             case TABLE_ROWS:
00097             case TSECTION_ROWS:
00098                 if(e->id() == ID_TR)
00099                     len++;
00100                 else if(e->id() == ID_TABLE)
00101                     deep = false;
00102                 break;
00103             case SELECT_OPTIONS:
00104                 if(e->id() == ID_OPTION)
00105                     len++;
00106                 break;
00107             case MAP_AREAS:
00108                 if(e->id() == ID_AREA)
00109                     len++;
00110                 break;
00111             case DOC_APPLETS:   // all OBJECT and APPLET elements
00112                 if(e->id() == ID_OBJECT || e->id() == ID_APPLET)
00113                     len++;
00114                 break;
00115             case DOC_LINKS:     // all A _and_ AREA elements with a value for href
00116                 if(e->id() == ID_A || e->id() == ID_AREA)
00117                     if(!e->getAttribute(ATTR_HREF).isNull())
00118                         len++;
00119                 break;
00120             case DOC_ANCHORS:      // all A elements with a value for name and/or id
00121                 if(e->id() == ID_A) {
00122                     if(e->hasID() || !e->getAttribute(ATTR_NAME).isNull())
00123                         len++;
00124                 }
00125                 break;
00126             case DOC_ALL:      // "all" elements
00127                 len++;
00128                 break;
00129             case NODE_CHILDREN: // first-level children
00130                 len++;
00131                 deep = false;
00132                 break;
00133             default:
00134                 kdDebug( 6030 ) << "Error in HTMLCollection, wrong tagId!" << endl;
00135             }
00136             if(deep && current->firstChild())
00137                 len += calcLength(current->firstChild());
00138         }
00139         current = current->nextSibling();
00140     }
00141     return len;
00142 }
00143 
00144 // since the collections are to be "live", we have to do the
00145 // calculation every time...
00146 unsigned long HTMLCollectionImpl::length() const
00147 {
00148     return calcLength(base->firstChild());
00149 }
00150 
00151 NodeImpl *HTMLCollectionImpl::getItem(NodeImpl *current, int index, int &len) const
00152 {
00153     while(current)
00154     {
00155         if(current->nodeType() == Node::ELEMENT_NODE)
00156         {
00157             bool deep = true;
00158             HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
00159             switch(type)
00160             {
00161             case DOC_IMAGES:
00162                 if(e->id() == ID_IMG)
00163                     len++;
00164                 break;
00165             case DOC_FORMS:
00166                 if(e->id() == ID_FORM)
00167                     len++;
00168                 break;
00169             case TABLE_TBODIES:
00170                 if(e->id() == ID_TBODY)
00171                     len++;
00172                 else if(e->id() == ID_TABLE)
00173                     deep = false;
00174                 break;
00175             case TR_CELLS:
00176                 if(e->id() == ID_TD || e->id() == ID_TH)
00177                     len++;
00178                 else if(e->id() == ID_TABLE)
00179                     deep = false;
00180                 break;
00181             case TABLE_ROWS:
00182             case TSECTION_ROWS:
00183                 if(e->id() == ID_TR)
00184                     len++;
00185                 else if(e->id() == ID_TABLE)
00186                     deep = false;
00187                 break;
00188             case SELECT_OPTIONS:
00189                 if(e->id() == ID_OPTION)
00190                     len++;
00191                 break;
00192             case MAP_AREAS:
00193                 if(e->id() == ID_AREA)
00194                     len++;
00195                 break;
00196             case DOC_APPLETS:   // all OBJECT and APPLET elements
00197                 if(e->id() == ID_OBJECT || e->id() == ID_APPLET)
00198                     len++;
00199                 break;
00200             case DOC_LINKS:     // all A _and_ AREA elements with a value for href
00201                 if(e->id() == ID_A || e->id() == ID_AREA)
00202                     if(!e->getAttribute(ATTR_HREF).isNull())
00203                         len++;
00204                 break;
00205             case DOC_ANCHORS:      // all A elements with a value for name or an id attribute
00206                 if(e->id() == ID_A) {
00207                     if(e->hasID() || !e->getAttribute(ATTR_NAME).isNull())
00208                         len++;
00209                 }
00210                 break;
00211             case DOC_ALL:
00212                 len++;
00213                 break;
00214             case NODE_CHILDREN:
00215                 len++;
00216                 deep = false;
00217                 break;
00218             default:
00219                 kdDebug( 6030 ) << "Error in HTMLCollection, wrong tagId!" << endl;
00220             }
00221             if(len == (index + 1)) return current;
00222             NodeImpl *retval=0;
00223             if(deep && current->firstChild())
00224                 retval = getItem(current->firstChild(), index, len);
00225             if(retval) return retval;
00226         }
00227         current = current->nextSibling();
00228     }
00229     return 0;
00230 }
00231 
00232 NodeImpl *HTMLCollectionImpl::item( unsigned long index ) const
00233 {
00234     int pos = 0;
00235     return getItem(base->firstChild(), index, pos);
00236 }
00237 
00238 NodeImpl *HTMLCollectionImpl::firstItem() const
00239 {
00240     int pos = 0;
00241     currentItem = getItem(base->firstChild(), 0, pos);
00242     return currentItem;
00243 }
00244 
00245 NodeImpl *HTMLCollectionImpl::nextItem() const
00246 {
00247     int pos = 0;
00248     // Look for the 'second' item. The first one is currentItem, already given back.
00249     NodeImpl *retval = getItem(currentItem, 1, pos);
00250     if (retval)
00251     {
00252         currentItem = retval;
00253         return retval;
00254     }
00255     // retval was 0, means we have to go up
00256     while( !retval && currentItem->parentNode()
00257            && currentItem->parentNode() != base )
00258     {
00259         currentItem = currentItem->parentNode();
00260         if (currentItem->nextSibling())
00261         {
00262             // ... and to take the first one from there
00263             pos = 0;
00264             retval = getItem(currentItem->nextSibling(), 0, pos);
00265         }
00266     }
00267     currentItem = retval;
00268     return currentItem;
00269 }
00270 
00271 NodeImpl *HTMLCollectionImpl::getNamedItem( NodeImpl *current, int attr_id,
00272                                             const DOMString &name ) const
00273 {
00274     if(name.isEmpty())
00275         return 0;
00276 
00277     while(current)
00278     {
00279         if(current->nodeType() == Node::ELEMENT_NODE)
00280         {
00281             bool deep = true;
00282             bool check = false;
00283             HTMLElementImpl *e = static_cast<HTMLElementImpl *>(current);
00284             switch(type)
00285             {
00286             case DOC_IMAGES:
00287                 if(e->id() == ID_IMG)
00288                     check = true;
00289                 break;
00290             case DOC_FORMS:
00291                 if(e->id() == ID_FORM)
00292                     check = true;
00293                 break;
00294             case TABLE_TBODIES:
00295                 if(e->id() == ID_TBODY)
00296                     check = true;
00297                 else if(e->id() == ID_TABLE)
00298                     deep = false;
00299                 break;
00300             case TR_CELLS:
00301                 if(e->id() == ID_TD || e->id() == ID_TH)
00302                     check = true;
00303                 else if(e->id() == ID_TABLE)
00304                     deep = false;
00305                 break;
00306             case TABLE_ROWS:
00307             case TSECTION_ROWS:
00308                 if(e->id() == ID_TR)
00309                     check = true;
00310                 else if(e->id() == ID_TABLE)
00311                     deep = false;
00312                 break;
00313             case SELECT_OPTIONS:
00314                 if(e->id() == ID_OPTION)
00315                     check = true;
00316                 break;
00317             case MAP_AREAS:
00318                 if(e->id() == ID_AREA)
00319                     check = true;
00320                 break;
00321             case DOC_APPLETS:   // all OBJECT and APPLET elements
00322                 if(e->id() == ID_OBJECT || e->id() == ID_APPLET)
00323                     check = true;
00324                 break;
00325             case DOC_LINKS:     // all A _and_ AREA elements with a value for href
00326                 if(e->id() == ID_A || e->id() == ID_AREA)
00327                     if(!e->getAttribute(ATTR_HREF).isNull())
00328                         check = true;
00329                 break;
00330             case DOC_ANCHORS:      // all A elements with a value for name
00331                 if(e->id() == ID_A) {
00332                     if(e->hasID() || !e->getAttribute(ATTR_NAME).isNull())
00333                         check = true;
00334                 }
00335                 break;
00336             case DOC_ALL:
00337                 check = true;
00338                 break;
00339             case NODE_CHILDREN:
00340                 check = true;
00341                 deep = false;
00342                 break;
00343             default:
00344                 kdDebug( 6030 ) << "Error in HTMLCollection, wrong tagId!" << endl;
00345                 break;
00346             }
00347             if(check && e->getAttribute(attr_id) == name)
00348             {
00349                 //kdDebug( 6030 ) << "found node: " << e << " " << current << " " << e->id() << " " << e->tagName().string() << endl;
00350                 return current;
00351             }
00352             NodeImpl *retval = 0;
00353             if(deep && current->firstChild())
00354                 retval = getNamedItem(current->firstChild(), attr_id, name);
00355             if(retval)
00356             {
00357                 //kdDebug( 6030 ) << "got a return value " << retval << endl;
00358                 return retval;
00359             }
00360         }
00361         current = current->nextSibling();
00362     }
00363     return 0;
00364 }
00365 
00366 NodeImpl *HTMLCollectionImpl::namedItem( const DOMString &name ) const
00367 {
00368     // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/nameditem.asp
00369     // This method first searches for an object with a matching id
00370     // attribute. If a match is not found, the method then searches for an
00371     // object with a matching name attribute, but only on those elements
00372     // that are allowed a name attribute.
00373     idsDone = false;
00374     currentItem = getNamedItem(base->firstChild(), ATTR_ID, name);
00375     if(currentItem)
00376         return currentItem;
00377     idsDone = true;
00378     currentItem = getNamedItem(base->firstChild(), ATTR_NAME, name);
00379     return currentItem;
00380 }
00381 
00382 NodeImpl *HTMLCollectionImpl::nextNamedItem( const DOMString &name ) const
00383 {
00384     // nextNamedItemInternal can return an item that has both id=<name> and name=<name>
00385     // Here, we have to filter out such cases.
00386     NodeImpl *impl = nextNamedItemInternal( name );
00387     if (!idsDone) // looking for id=<name> -> no filtering
00388         return impl;
00389     // looking for name=<name> -> filter out if id=<name>
00390     bool ok = false;
00391     while (impl && !ok)
00392     {
00393         if(impl->nodeType() == Node::ELEMENT_NODE)
00394         {
00395             HTMLElementImpl *e = static_cast<HTMLElementImpl *>(impl);
00396             ok = (e->getAttribute(ATTR_ID) != name);
00397             if (!ok)
00398                 impl = nextNamedItemInternal( name );
00399         } else // can't happen
00400             ok = true;
00401     }
00402     return impl;
00403 }
00404 
00405 NodeImpl *HTMLCollectionImpl::nextNamedItemInternal( const DOMString &name ) const
00406 {
00407     //kdDebug() << "\nHTMLCollectionImpl::nextNamedItem starting at " << currentItem << endl;
00408     // Go to next item first (to avoid returning the same)
00409     currentItem = nextItem();
00410     //kdDebug() << "*HTMLCollectionImpl::nextNamedItem next item is " << currentItem << endl;
00411 
00412     if ( currentItem )
00413     {
00414         // Then look for next matching named item
00415         NodeImpl *retval = getNamedItem(currentItem, idsDone ? ATTR_NAME : ATTR_ID, name);
00416         if ( retval )
00417         {
00418             //kdDebug() << "*HTMLCollectionImpl::nextNamedItem found " << retval << endl;
00419             currentItem = retval;
00420             return retval;
00421         }
00422 
00423         // retval was 0, means we have to go up
00424         while( !retval && currentItem->parentNode()
00425                && currentItem->parentNode() != base )
00426         {
00427             currentItem = currentItem->parentNode();
00428             if (currentItem->nextSibling())
00429             {
00430                 // ... and to take the first one from there
00431                 retval = getNamedItem(currentItem->nextSibling(), idsDone ? ATTR_NAME : ATTR_ID, name);
00432             }
00433         }
00434         if ( retval )
00435         {
00436             //kdDebug() << "*HTMLCollectionImpl::nextNamedItem found after going up " << retval << endl;
00437             currentItem = retval;
00438             return currentItem;
00439         }
00440     }
00441 
00442     if ( idsDone )
00443         return 0;
00444     // After doing all ATTR_ID, do ATTR_NAME
00445     //kdDebug() << "*HTMLCollectionImpl::nextNamedItem going to ATTR_NAME now" << endl;
00446     idsDone = true;
00447     currentItem = getNamedItem(base->firstChild(), ATTR_NAME, name);
00448     return currentItem;
00449 
00450 }
00451 
00452 // -----------------------------------------------------------------------------
00453 
00454 unsigned long HTMLFormCollectionImpl::calcLength(NodeImpl*) const
00455 {
00456     QPtrList<HTMLGenericFormElementImpl> l = static_cast<HTMLFormElementImpl*>( base )->formElements;
00457 
00458     int len = 0;
00459     for ( unsigned i = 0; i < l.count(); i++ )
00460         if ( l.at( i )->isEnumeratable() )
00461             ++len;
00462 
00463     return len;
00464 }
00465 
00466 NodeImpl* HTMLFormCollectionImpl::getItem(NodeImpl *, int index, int&) const
00467 {
00468     QPtrList<HTMLGenericFormElementImpl> l = static_cast<HTMLFormElementImpl*>( base )->formElements;
00469 
00470     for ( unsigned i = 0; i < l.count(); i++ ) {
00471 
00472         if( l.at( i )->isEnumeratable() ) {
00473             if ( !index )
00474                 return l.at( i );
00475 
00476             --index;
00477         }
00478     }
00479 
00480     return 0;
00481 }
00482 
00483 NodeImpl* HTMLFormCollectionImpl::getNamedItem(NodeImpl*, int attr_id, const DOMString& name) const
00484 {
00485     currentPos = 0;
00486     return getNamedFormItem( attr_id, name, 0 );
00487 }
00488 
00489 NodeImpl* HTMLFormCollectionImpl::getNamedFormItem(int attr_id, const DOMString& name, int duplicateNumber) const
00490 {
00491     if(base->nodeType() == Node::ELEMENT_NODE)
00492     {
00493         HTMLElementImpl* e = static_cast<HTMLElementImpl*>(base);
00494         bool foundInputElements = false;
00495         if(e->id() == ID_FORM)
00496         {
00497             HTMLGenericFormElementImpl* element;
00498             HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(e);
00499 
00500             for(element = f->formElements.first(); element; element = f->formElements.next())
00501                 if(element->isEnumeratable() && element->getAttribute(attr_id) == name)
00502                 {
00503                     if (!duplicateNumber)
00504                         return element;
00505                     --duplicateNumber;
00506                     foundInputElements = true;
00507                 }
00508         }
00509         // IE looks at <img> only if no <input> has the same name
00510         if ( !foundInputElements )
00511         {
00512             HTMLImageElementImpl* element;
00513             HTMLFormElementImpl* f = static_cast<HTMLFormElementImpl*>(e);
00514 
00515             for(element = f->imgElements.first(); element; element = f->imgElements.next())
00516                 if(element->getAttribute(attr_id) == name)
00517                 {
00518                     if (!duplicateNumber)
00519                         return element;
00520                     --duplicateNumber;
00521                     foundInputElements = true;
00522                 }
00523         }
00524     }
00525     return 0;
00526 }
00527 
00528 NodeImpl * HTMLFormCollectionImpl::firstItem() const
00529 {
00530     currentPos = 0;
00531     int dummy = 0;
00532     return getItem(0 /*base->firstChild() unused*/, currentPos, dummy);
00533 }
00534 
00535 NodeImpl * HTMLFormCollectionImpl::nextItem() const
00536 {
00537     // This implementation loses the whole benefit of firstItem/nextItem :(
00538     int dummy = 0;
00539     return getItem(0 /*base->firstChild() unused*/, ++currentPos, dummy);
00540 }
00541 
00542 NodeImpl * HTMLFormCollectionImpl::nextNamedItemInternal( const DOMString &name ) const
00543 {
00544     NodeImpl *retval = getNamedFormItem( idsDone ? ATTR_NAME : ATTR_ID, name, ++currentPos );
00545     if ( retval )
00546         return retval;
00547     if ( idsDone ) // we're done
00548         return 0;
00549     // After doing all ATTR_ID, do ATTR_NAME
00550     idsDone = true;
00551     return getNamedItem(base->firstChild(), ATTR_NAME, name);
00552 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:16:35 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001