diff --git a/js/js.libraries/src/core/javautil.kt b/js/js.libraries/src/core/javautil.kt index 81cf79bf8bd..166f390544e 100644 --- a/js/js.libraries/src/core/javautil.kt +++ b/js/js.libraries/src/core/javautil.kt @@ -16,7 +16,7 @@ public fun comparator(f : (T, T) -> Int) : Comparator = js.noImpl library -public open class Iterator() { +public trait Iterator { open fun next() : T = js.noImpl open fun hasNext() : Boolean = js.noImpl open fun remove() : Unit = js.noImpl @@ -67,6 +67,14 @@ public trait Collection : java.lang.Iterable { open fun clear() : Unit } +library +public abstract open class AbstractCollection : Collection { +} + +library +public abstract open class AbstractList : AbstractCollection, List { +} + library public trait List : Collection { override fun size() : Int diff --git a/js/js.translator/testFiles/kotlin_lib.js b/js/js.translator/testFiles/kotlin_lib.js index 8453ae4410c..e50f1a9b059 100644 --- a/js/js.translator/testFiles/kotlin_lib.js +++ b/js/js.translator/testFiles/kotlin_lib.js @@ -286,14 +286,16 @@ var Kotlin; Kotlin.Exceptions = {}; Kotlin.Exception = Kotlin.Class.create(); + Kotlin.RuntimeException = Kotlin.Class.create(Kotlin.Exception); Kotlin.Exceptions.IndexOutOfBounds = Kotlin.Class.create(Kotlin.Exception); Kotlin.Exceptions.NullPointerException = Kotlin.Class.create(Kotlin.Exception); + Kotlin.Exceptions.UnsupportedOperationException = Kotlin.Class.create(Kotlin.Exception); + Kotlin.Exceptions.NoSuchElementException = Kotlin.Class.create(Kotlin.Exception); Kotlin.throwNPE = function() { throw new Kotlin.Exceptions.NullPointerException(); }; - Kotlin.ArrayList = Class.create({ initialize:function () { this.array = []; @@ -358,6 +360,50 @@ var Kotlin; }); + Kotlin.AbstractList = Class.create({ + set:function (index, value) { + throw new Kotlin.Exceptions.UnsupportedOperationException(); + }, + iterator:function () { + return new Kotlin.ArrayIterator(this); + }, + isEmpty:function () { + return (this.size() === 0); + }, + add:function (element) { + throw new Kotlin.Exceptions.UnsupportedOperationException(); + }, + addAll:function (collection) { + var it = collection.iterator(); + while (it.hasNext()) { + this.add(it.next()); + } + }, + remove:function(value) { + for (var i = 0; i < this.$size; ++i) { + if (this.array[i] == value) { + this.removeByIndex(i); + return; + } + } + }, + removeByIndex:function (index) { + throw new Kotlin.Exceptions.UnsupportedOperationException(); + }, + clear:function () { + throw new Kotlin.Exceptions.UnsupportedOperationException(); + }, + contains:function (obj) { + for (var i = 0; i < this.$size; ++i) { + if (Kotlin.equals(this.array[i], obj)) { + return true; + } + } + return false; + } + }); + + Kotlin.parseInt = function (str) { return parseInt(str, 10); } @@ -444,6 +490,7 @@ var Kotlin; } }); + Kotlin.RangeIterator = Kotlin.Class.create(Kotlin.Iterator, { initialize:function (start, count, reversed) { this.$start = start; diff --git a/libraries/stdlib/src/kotlin/dom/Dom.kt b/libraries/stdlib/src/kotlin/dom/Dom.kt index 7e2ce26b8ff..62a4cb842aa 100644 --- a/libraries/stdlib/src/kotlin/dom/Dom.kt +++ b/libraries/stdlib/src/kotlin/dom/Dom.kt @@ -76,52 +76,8 @@ set(value) { this.setAttribute("class", value) } -var Element.classSet : Set -get() { - val answer = LinkedHashSet() - val array = this.classes.split("""\s""") - for (s in array) { - if (s != null && s.size > 0) { - answer.add(s) - } - } - return answer -} -set(value) { - this.classes = value.makeString(" ") -} - - // Helper methods -/** Returns true if the element has the given CSS class style in its 'class' attribute */ -fun Element.hasClass(cssClass: String): Boolean { - val c = this.classes - return if (c != null) - c.matches("""(^|.*\s+)$cssClass($|\s+.*)""") - else false -} - -/** Adds the given CSS class to this element's 'class' attribute */ -fun Element.addClass(cssClass: String): Boolean { - val classSet = this.classSet - val answer = classSet.add(cssClass) - if (answer) { - this.classSet = classSet - } - return answer -} - -/** Removes the given CSS class to this element's 'class' attribute */ -fun Element.removeClass(cssClass: String): Boolean { - val classSet = this.classSet - val answer = classSet.remove(cssClass) - if (answer) { - this.classSet = classSet - } - return answer -} - /** TODO this approach generates compiler errors... fun Element.addClass(varargs cssClasses: Array): Boolean { @@ -153,48 +109,39 @@ fun Element.removeClass(varargs cssClasses: Array): Boolean { } */ -/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ -fun Document?.get(selector: String): List { - val root = this?.getDocumentElement() - return if (root != null) { - if (selector == "*") { - elements - } else if (selector.startsWith(".")) { - elements.filter{ it.hasClass(selector.substring(1)) }.toList() - } else if (selector.startsWith("#")) { - val id = selector.substring(1) - val element = this?.getElementById(id) - return if (element != null) - Collections.singletonList(element).sure() as List - else - Collections.EMPTY_LIST.sure() as List +class NodeListAsList(val nodeList: NodeList): AbstractList() { + override fun get(index: Int): Node { + val node = nodeList.item(index) + if (node == null) { + throw IndexOutOfBoundsException("NodeList does not contain a node at index: " + index) } else { - // assume its a vanilla element name - elements(selector) + return node } - } else { - Collections.EMPTY_LIST as List } + + override fun size(): Int = nodeList.getLength() } -/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ -fun Element.get(selector: String): List { - return if (selector == "*") { - elements - } else if (selector.startsWith(".")) { - elements.filter{ it.hasClass(selector.substring(1)) }.toList() - } else if (selector.startsWith("#")) { - val element = this.getOwnerDocument()?.getElementById(selector.substring(1)) - return if (element != null) - Collections.singletonList(element).sure() as List - else - Collections.EMPTY_LIST.sure() as List - } else { - // assume its a vanilla element name - elements(selector) +class ElementListAsList(val nodeList: NodeList): AbstractList() { + override fun get(index: Int): Element { + val node = nodeList.item(index) + if (node is Element) { + return node + } else { + if (node == null) { + throw IndexOutOfBoundsException("NodeList does not contain a node at index: " + index) + } else { + throw IllegalArgumentException("Node is not an Element as expected but is $node") + } + } } + + override fun size(): Int = nodeList.getLength() + } + + /** Returns an [[Iterator]] over the next siblings of this node */ fun Node.nextSiblings() : Iterator = NextSiblingIterator(this) @@ -229,55 +176,20 @@ class PreviousSiblingIterator(var node: Node) : AbstractIterator() { /** Returns true if this node is a Text node or a CDATA node */ fun Node.isText(): Boolean { + /* + This code is easier to convert to JS val nodeType = getNodeType() return nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE + */ + return this is Text || this is CDATASection + } -/** Returns an [[Iterator]] of all the next [[Element]] siblings */ -fun Node.nextElements(): Iterator = nextSiblings().filterIsInstance(javaClass()) - -/** Returns an [[Iterator]] of all the previous [[Element]] siblings */ -fun Node.previousElements(): Iterator = previousSiblings().filterIsInstance(javaClass()) - /** Returns the attribute value or empty string if its not present */ inline fun Element.attribute(name: String): String { return this.getAttribute(name) ?: "" } -/** Returns the children of the element as a list */ -inline fun Element?.children(): List { - return this?.getChildNodes().toList() -} - -/** The child elements of this document */ -val Document?.elements : List -get() = this?.getElementsByTagName("*").toElementList() - -/** The child elements of this elements */ -val Element?.elements : List -get() = this?.getElementsByTagName("*").toElementList() - - -/** Returns all the child elements given the local element name */ -inline fun Element?.elements(localName: String?): List { - return this?.getElementsByTagName(localName).toElementList() -} - -/** Returns all the elements given the local element name */ -inline fun Document?.elements(localName: String?): List { - return this?.getElementsByTagName(localName).toElementList() -} - -/** Returns all the child elements given the namespace URI and local element name */ -inline fun Element?.elements(namespaceUri: String?, localName: String?): List { - return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() -} - -/** Returns all the elements given the namespace URI and local element name */ -inline fun Document?.elements(namespaceUri: String?, localName: String?): List { - return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() -} - val NodeList?.head : Node? get() = if (this != null && this.getLength() > 0) this.item(0) else null diff --git a/libraries/stdlib/src/kotlin/dom/DomJVM.kt b/libraries/stdlib/src/kotlin/dom/DomJVM.kt index c6e338ee881..a904cefca1a 100644 --- a/libraries/stdlib/src/kotlin/dom/DomJVM.kt +++ b/libraries/stdlib/src/kotlin/dom/DomJVM.kt @@ -19,6 +19,135 @@ import javax.xml.transform.stream.StreamResult import org.w3c.dom.* import org.xml.sax.InputSource +/** Returns the children of the element as a list */ +inline fun Element?.children(): List { + return this?.getChildNodes().toList() +} + + +/** Returns an [[Iterator]] of all the next [[Element]] siblings */ +fun Node.nextElements(): Iterator = nextSiblings().filterIsInstance(javaClass()) + +/** Returns an [[Iterator]] of all the previous [[Element]] siblings */ +fun Node.previousElements(): Iterator = previousSiblings().filterIsInstance(javaClass()) + + +/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ +fun Document?.get(selector: String): List { + val root = this?.getDocumentElement() + return if (root != null) { + if (selector == "*") { + elements + } else if (selector.startsWith(".")) { + elements.filter{ it.hasClass(selector.substring(1)) }.toList() + } else if (selector.startsWith("#")) { + val id = selector.substring(1) + val element = this?.getElementById(id) + return if (element != null) + Collections.singletonList(element).sure() as List + else + Collections.EMPTY_LIST.sure() as List + } else { + // assume its a vanilla element name + elements(selector) + } + } else { + Collections.EMPTY_LIST as List + } +} + +/** Searches for elements using the element name, an element ID (if prefixed with dot) or element class (if prefixed with #) */ +fun Element.get(selector: String): List { + return if (selector == "*") { + elements + } else if (selector.startsWith(".")) { + elements.filter{ it.hasClass(selector.substring(1)) }.toList() + } else if (selector.startsWith("#")) { + val element = this.getOwnerDocument()?.getElementById(selector.substring(1)) + return if (element != null) + Collections.singletonList(element).sure() as List + else + Collections.EMPTY_LIST.sure() as List + } else { + // assume its a vanilla element name + elements(selector) + } +} + +/** The child elements of this document */ +val Document?.elements : List +get() = this?.getElementsByTagName("*").toElementList() + +/** The child elements of this elements */ +val Element?.elements : List +get() = this?.getElementsByTagName("*").toElementList() + + +/** Returns all the child elements given the local element name */ +inline fun Element?.elements(localName: String?): List { + return this?.getElementsByTagName(localName).toElementList() +} + +/** Returns all the elements given the local element name */ +inline fun Document?.elements(localName: String?): List { + return this?.getElementsByTagName(localName).toElementList() +} + +/** Returns all the child elements given the namespace URI and local element name */ +inline fun Element?.elements(namespaceUri: String?, localName: String?): List { + return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() +} + +/** Returns all the elements given the namespace URI and local element name */ +inline fun Document?.elements(namespaceUri: String?, localName: String?): List { + return this?.getElementsByTagNameNS(namespaceUri, localName).toElementList() +} + + +var Element.classSet : Set +get() { + val answer = LinkedHashSet() + val array = this.classes.split("""\s""") + for (s in array) { + if (s != null && s.size > 0) { + answer.add(s) + } + } + return answer +} +set(value) { + this.classes = value.makeString(" ") +} + +/** Returns true if the element has the given CSS class style in its 'class' attribute */ +fun Element.hasClass(cssClass: String): Boolean { + val c = this.classes + return if (c != null) + c.matches("""(^|.*\s+)$cssClass($|\s+.*)""") + else false +} + +/** Adds the given CSS class to this element's 'class' attribute */ +fun Element.addClass(cssClass: String): Boolean { + val classSet = this.classSet + val answer = classSet.add(cssClass) + if (answer) { + this.classSet = classSet + } + return answer +} + +/** Removes the given CSS class to this element's 'class' attribute */ +fun Element.removeClass(cssClass: String): Boolean { + val classSet = this.classSet + val answer = classSet.remove(cssClass) + if (answer) { + this.classSet = classSet + } + return answer +} + + /** Converts the node list to an XML String */ fun NodeList?.toXmlString(xmlDeclaration: Boolean = false): String { return if (this == null) @@ -45,37 +174,6 @@ inline fun NodeList?.toElementList(): List { } } -class NodeListAsList(val nodeList: NodeList): AbstractList() { - override fun get(index: Int): Node { - val node = nodeList.item(index) - if (node == null) { - throw IndexOutOfBoundsException("NodeList does not contain a node at index: " + index) - } else { - return node - } - } - - override fun size(): Int = nodeList.getLength() -} - -class ElementListAsList(val nodeList: NodeList): AbstractList() { - override fun get(index: Int): Element { - val node = nodeList.item(index) - if (node is Element) { - return node - } else { - if (node == null) { - throw IndexOutOfBoundsException("NodeList does not contain a node at index: " + index) - } else { - throw IllegalArgumentException("Node is not an Element as expected but is $node") - } - } - } - - override fun size(): Int = nodeList.getLength() - -} - /** Creates a new document with the given document builder*/ public fun createDocument(builder: DocumentBuilder): Document { return builder.newDocument().sure()