1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "JSHTMLCollection.h"
22
23 #include "AtomicString.h"
24 #include "HTMLCollection.h"
25 #include "HTMLOptionsCollection.h"
26 #include "JSHTMLAllCollection.h"
27 #include "JSHTMLOptionsCollection.h"
28 #include "JSNamedNodesCollection.h"
29 #include "JSNode.h"
30 #include "Node.h"
31 #include "JSDOMBinding.h"
32 #include <wtf/Vector.h>
33
34 using namespace JSC;
35
36 namespace WebCore {
37
getNamedItems(ExecState * exec,JSHTMLCollection * collection,const Identifier & propertyName)38 static JSValue getNamedItems(ExecState* exec, JSHTMLCollection* collection, const Identifier& propertyName)
39 {
40 Vector<RefPtr<Node> > namedItems;
41 collection->impl()->namedItems(propertyName, namedItems);
42
43 if (namedItems.isEmpty())
44 return jsUndefined();
45
46 if (namedItems.size() == 1)
47 return toJS(exec, collection->globalObject(), namedItems[0].get());
48
49 return new (exec) JSNamedNodesCollection(exec, collection->globalObject(), namedItems);
50 }
51
52 // HTMLCollections are strange objects, they support both get and call,
53 // so that document.forms.item(0) and document.forms(0) both work.
callHTMLCollection(ExecState * exec,JSObject * function,JSValue,const ArgList & args)54 static JSValue JSC_HOST_CALL callHTMLCollection(ExecState* exec, JSObject* function, JSValue, const ArgList& args)
55 {
56 if (args.size() < 1)
57 return jsUndefined();
58
59 // Do not use thisObj here. It can be the JSHTMLDocument, in the document.forms(i) case.
60 JSHTMLCollection* jsCollection = static_cast<JSHTMLCollection*>(function);
61 HTMLCollection* collection = jsCollection->impl();
62
63 // Also, do we need the TypeError test here ?
64
65 if (args.size() == 1) {
66 // Support for document.all(<index>) etc.
67 bool ok;
68 UString string = args.at(0).toString(exec);
69 unsigned index = string.toUInt32(&ok, false);
70 if (ok)
71 return toJS(exec, jsCollection->globalObject(), collection->item(index));
72
73 // Support for document.images('<name>') etc.
74 return getNamedItems(exec, jsCollection, Identifier(exec, string));
75 }
76
77 // The second arg, if set, is the index of the item we want
78 bool ok;
79 UString string = args.at(0).toString(exec);
80 unsigned index = args.at(1).toString(exec).toUInt32(&ok, false);
81 if (ok) {
82 String pstr = string;
83 Node* node = collection->namedItem(pstr);
84 while (node) {
85 if (!index)
86 return toJS(exec, jsCollection->globalObject(), node);
87 node = collection->nextNamedItem(pstr);
88 --index;
89 }
90 }
91
92 return jsUndefined();
93 }
94
getCallData(CallData & callData)95 CallType JSHTMLCollection::getCallData(CallData& callData)
96 {
97 callData.native.function = callHTMLCollection;
98 return CallTypeHost;
99 }
100
canGetItemsForName(ExecState *,HTMLCollection * collection,const Identifier & propertyName)101 bool JSHTMLCollection::canGetItemsForName(ExecState*, HTMLCollection* collection, const Identifier& propertyName)
102 {
103 Vector<RefPtr<Node> > namedItems;
104 collection->namedItems(propertyName, namedItems);
105 return !namedItems.isEmpty();
106 }
107
nameGetter(ExecState * exec,const Identifier & propertyName,const PropertySlot & slot)108 JSValue JSHTMLCollection::nameGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot)
109 {
110 JSHTMLCollection* thisObj = static_cast<JSHTMLCollection*>(asObject(slot.slotBase()));
111 return getNamedItems(exec, thisObj, propertyName);
112 }
113
item(ExecState * exec,const ArgList & args)114 JSValue JSHTMLCollection::item(ExecState* exec, const ArgList& args)
115 {
116 bool ok;
117 uint32_t index = args.at(0).toString(exec).toUInt32(&ok, false);
118 if (ok)
119 return toJS(exec, globalObject(), impl()->item(index));
120 return getNamedItems(exec, this, Identifier(exec, args.at(0).toString(exec)));
121 }
122
namedItem(ExecState * exec,const ArgList & args)123 JSValue JSHTMLCollection::namedItem(ExecState* exec, const ArgList& args)
124 {
125 return getNamedItems(exec, this, Identifier(exec, args.at(0).toString(exec)));
126 }
127
toJS(ExecState * exec,JSDOMGlobalObject * globalObject,HTMLCollection * collection)128 JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, HTMLCollection* collection)
129 {
130 if (!collection)
131 return jsNull();
132
133 DOMObject* wrapper = getCachedDOMObjectWrapper(exec->globalData(), collection);
134
135 if (wrapper)
136 return wrapper;
137
138 switch (collection->type()) {
139 case SelectOptions:
140 wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, HTMLOptionsCollection, collection);
141 break;
142 case DocAll:
143 typedef HTMLCollection HTMLAllCollection;
144 wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, HTMLAllCollection, collection);
145 break;
146 default:
147 wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, HTMLCollection, collection);
148 break;
149 }
150
151 return wrapper;
152 }
153
154 } // namespace WebCore
155