1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "JSHTMLAllCollection.h" 28 29 #include "HTMLAllCollection.h" 30 #include "JSDOMBinding.h" 31 #include "JSHTMLAllCollection.h" 32 #include "JSNode.h" 33 #include "JSNodeList.h" 34 #include "Node.h" 35 #include "StaticNodeList.h" 36 #include <runtime/JSValue.h> 37 #include <wtf/Vector.h> 38 #include <wtf/text/AtomicString.h> 39 40 using namespace JSC; 41 42 namespace WebCore { 43 44 static JSValue getNamedItems(ExecState* exec, JSHTMLAllCollection* collection, const Identifier& propertyName) 45 { 46 Vector<RefPtr<Node> > namedItems; 47 collection->impl()->namedItems(identifierToAtomicString(propertyName), namedItems); 48 49 if (namedItems.isEmpty()) 50 return jsUndefined(); 51 if (namedItems.size() == 1) 52 return toJS(exec, collection->globalObject(), namedItems[0].get()); 53 54 // FIXME: HTML5 specifies that this should be a DynamicNodeList. 55 // FIXME: HTML5 specifies that non-HTMLOptionsCollection collections should return 56 // the first matching item instead of a NodeList. 57 return toJS(exec, collection->globalObject(), StaticNodeList::adopt(namedItems).get()); 58 } 59 60 // HTMLCollections are strange objects, they support both get and call, 61 // so that document.forms.item(0) and document.forms(0) both work. 62 static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec) 63 { 64 if (exec->argumentCount() < 1) 65 return JSValue::encode(jsUndefined()); 66 67 // Do not use thisObj here. It can be the JSHTMLDocument, in the document.forms(i) case. 68 JSHTMLAllCollection* jsCollection = static_cast<JSHTMLAllCollection*>(exec->callee()); 69 HTMLAllCollection* collection = static_cast<HTMLAllCollection*>(jsCollection->impl()); 70 71 // Also, do we need the TypeError test here ? 72 73 if (exec->argumentCount() == 1) { 74 // Support for document.all(<index>) etc. 75 bool ok; 76 UString string = exec->argument(0).toString(exec); 77 unsigned index = Identifier::toUInt32(string, ok); 78 if (ok) 79 return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection->item(index))); 80 81 // Support for document.images('<name>') etc. 82 return JSValue::encode(getNamedItems(exec, jsCollection, Identifier(exec, string))); 83 } 84 85 // The second arg, if set, is the index of the item we want 86 bool ok; 87 UString string = exec->argument(0).toString(exec); 88 unsigned index = Identifier::toUInt32(exec->argument(1).toString(exec), ok); 89 if (ok) { 90 String pstr = ustringToString(string); 91 Node* node = collection->namedItem(pstr); 92 while (node) { 93 if (!index) 94 return JSValue::encode(toJS(exec, jsCollection->globalObject(), node)); 95 node = collection->nextNamedItem(pstr); 96 --index; 97 } 98 } 99 100 return JSValue::encode(jsUndefined()); 101 } 102 103 CallType JSHTMLAllCollection::getCallData(CallData& callData) 104 { 105 callData.native.function = callHTMLAllCollection; 106 return CallTypeHost; 107 } 108 109 bool JSHTMLAllCollection::canGetItemsForName(ExecState*, HTMLAllCollection* collection, const Identifier& propertyName) 110 { 111 Vector<RefPtr<Node> > namedItems; 112 collection->namedItems(identifierToAtomicString(propertyName), namedItems); 113 return !namedItems.isEmpty(); 114 } 115 116 JSValue JSHTMLAllCollection::nameGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName) 117 { 118 JSHTMLAllCollection* thisObj = static_cast<JSHTMLAllCollection*>(asObject(slotBase)); 119 return getNamedItems(exec, thisObj, propertyName); 120 } 121 122 JSValue JSHTMLAllCollection::item(ExecState* exec) 123 { 124 bool ok; 125 uint32_t index = Identifier::toUInt32(exec->argument(0).toString(exec), ok); 126 if (ok) 127 return toJS(exec, globalObject(), impl()->item(index)); 128 return getNamedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec))); 129 } 130 131 JSValue JSHTMLAllCollection::namedItem(ExecState* exec) 132 { 133 return getNamedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec))); 134 } 135 136 } // namespace WebCore 137