diff --git a/js/js.libraries/src/core/domExts.kt b/js/js.libraries/src/core/domExts.kt index 06a7c890cff..e4337144058 100644 --- a/js/js.libraries/src/core/domExts.kt +++ b/js/js.libraries/src/core/domExts.kt @@ -42,122 +42,4 @@ private class HTMLCollectionListView(val collection: HTMLCollection) : AbstractL public fun HTMLCollection.asList(): List = HTMLCollectionListView(this) -private class NodeListAsList(val delegate: NodeList) : AbstractList() { - override fun size(): Int = delegate.length - - override fun get(index: Int): Node = - if (index in 0..size() - 1) delegate.get(index)!! - else throw IndexOutOfBoundsException("index $index is not in range [0 .. ${size() - 1})") -} - -public fun NodeList.asList() : List = NodeListAsList(this) - -/** - * Adds CSS class to element. Has no effect if all specified classes are already in class attribute of the element - */ -public fun Element.addClass(vararg cssClasses: String): Boolean { - val missingClasses = cssClasses.filterNot { hasClass(it) } - if (missingClasses.isNotEmpty()) { - className = StringBuilder { - append(className) - missingClasses.joinTo(this, " ", " ") - }.toString() - return true - } - - return false -} - -/** - * Removes all [cssClasses] from element. Has no effect if all specified classes are missing in class attribute of the element - */ -public fun Element.removeClass(vararg cssClasses: String): Boolean { - if (cssClasses.any { hasClass(it) }) { - val toBeRemoved = cssClasses.toSet() - className = className.splitWithRegex("\\s+").filter { it !in toBeRemoved }.joinToString(" ") - return true - } - - return false -} - -/** - * Adds [cssClasses] to element if []condition] is true or removes it otherwise. - * Has no effect if class attribute already has corresponding content - */ -public fun Element.addOrRemoveClassWhen(condition : Boolean, vararg cssClasses : String) { - if (condition) { - addClass(*cssClasses) - } else { - removeClass(*cssClasses) - } -} - -/** - * Adds [trueClassName] class to element if [condition] is true and removes [falseClassName]. - * If [condition] is false then [trueClassName] will be removed and [falseClassName] will be added. - * Has no effect if class attribute already has corresponding content - */ -public fun Element.swapClassWhen(condition: Boolean, trueClassName: String, falseClassName: String) { - if (condition) { - addClass(trueClassName) - removeClass(falseClassName) - } else { - removeClass(trueClassName) - addClass(falseClassName) - } -} - -/** - * If [condition] is true then [attributeName] with value [attributeValue] will be added to the element, otherwise attribute with - * name [attributeName] will be removed - */ -public fun Element.addOrRemoveAttributeWhen(condition : Boolean, attributeName : String, attributeValue : String = attributeName) { - if (condition) { - setAttribute(attributeName, attributeValue) - } else { - removeAttribute(attributeName) - } -} - -/** Returns true if the element has the given CSS class style in its 'class' attribute */ -public fun Element.hasClass(cssClass: String): Boolean { - val c = this.className - return c.matches("""(^|.*\s+)$cssClass($|\s+.*)""") -} - -/** - * Removes all child nodes - */ -public fun Node.clear() { - while (hasChildNodes()) { - removeChild(firstChild!!) - } -} - -/** - * Removes this node from parent node. Does nothing if no parent node - */ -public fun Node.removeFromParent() { - parentNode?.removeChild(this) -} - -/** - * it is *true* when [Node.nodeType] is TEXT_NODE or CDATA_SECTION_NODE - */ -public val Node.isText : Boolean - get() = nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE - -/** - * Creates text node and append it to the element - */ -public fun Element.appendText(text : String, doc : Document = this.ownerDocument!!) { - appendChild(doc.createTextNode(text)) -} - -/** - * Appends the node to the specified parent element - */ -public fun Node.appendTo(parent : Element) { - parent.appendChild(this) -} +public fun HTMLCollection?.toElementList() : List = this?.asList() ?: emptyList() \ No newline at end of file diff --git a/js/js.libraries/src/core/htmlDom.kt b/js/js.libraries/src/core/htmlDom.kt index cf27ff08be5..b2279477db8 100644 --- a/js/js.libraries/src/core/htmlDom.kt +++ b/js/js.libraries/src/core/htmlDom.kt @@ -188,40 +188,22 @@ public native trait HTMLOptionsCollection { deprecated("Use org.w3c.dom instead") public native trait HTMLDocument : Document { - public native var title: String - public native val referrer: String - public native val domain: String - public native val URL: String - public native var body: HTMLElement - public native val images: HTMLCollection - public native val applets: HTMLCollection - public native val links: HTMLCollection - public native val forms: HTMLCollection - public native val anchors: HTMLCollection - public native var cookie: HTMLCollection public native fun open(): Unit - public native fun close(): Unit public native fun write(text: String): Unit public native fun writeln(text: String): Unit - public native fun getElementsByName(elementName: String): NodeList - public native var compatMode: String - public native var onload: () -> Unit public native var onunload: () -> Unit } deprecated("Use org.w3c.dom instead") public native trait HTMLElement : Element { - public native var id: String public native var title: String public native var lang: String public native var dir: String - public native var className: String public native var style: CSSStyleDeclaration public native var clientWidth: Double public native var clientHeight: Double public native var clientTop: Double public native var clientLeft: Double - public native var innerHTML: String public native var offsetWidth: Double public native var offsetHeight: Double public native var offsetTop: Double diff --git a/js/js.libraries/src/html5/storage.kt b/js/js.libraries/src/html5/storage.kt index 9f1cb2fb292..cfb54e7c4de 100644 --- a/js/js.libraries/src/html5/storage.kt +++ b/js/js.libraries/src/html5/storage.kt @@ -17,10 +17,10 @@ package kotlin.js.dom.html5 native -public val localStorage: org.w3c.dom3.Storage = noImpl +public val localStorage: org.w3c.dom.Storage = noImpl native -public val sessionStorage: org.w3c.dom3.Storage = noImpl +public val sessionStorage: org.w3c.dom.Storage = noImpl native deprecated("Use org.w3c.dom") diff --git a/js/js.libraries/src/stdlib/domCode.kt b/js/js.libraries/src/stdlib/domCode.kt index e358fad2dee..374a3bbdbad 100644 --- a/js/js.libraries/src/stdlib/domCode.kt +++ b/js/js.libraries/src/stdlib/domCode.kt @@ -4,9 +4,7 @@ import org.w3c.dom.Document import org.w3c.dom.Node deprecated("use org.w3c.dom instead: create document directly via constructor Document() or use document.implementation.createDocument") -public fun createDocument(): Document { - return kotlin.js.dom.html.document.implementation.createDocument(null, null, null) -} +public fun createDocument(): Document = Document() deprecated("use org.w3c.dom instead") native public val Node.outerHTML: String get() = noImpl diff --git a/libraries/stdlib/src/kotlin/dom/Dom.kt b/libraries/stdlib/src/kotlin/dom/Dom.kt index 8410ed0e23a..cf6d90b4cea 100644 --- a/libraries/stdlib/src/kotlin/dom/Dom.kt +++ b/libraries/stdlib/src/kotlin/dom/Dom.kt @@ -12,9 +12,7 @@ import java.lang.IndexOutOfBoundsException deprecated("use textContent directly instead") public var Node.text: String - get() { - return textContent - } + get() = textContent ?: "" set(value) { textContent = value } @@ -52,7 +50,6 @@ public var Element.id: String get() = this.getAttribute("id") ?: "" set(value) { this.setAttribute("id", value) - this.setIdAttribute("id", true) } public var Element.style: String @@ -68,10 +65,7 @@ public var Element.classes: String } /** Returns true if the element has the given CSS class style in its 'class' attribute */ -public fun Element.hasClass(cssClass: String): Boolean { - val c = this.classes - return c.matches("""(^|.*\s+)$cssClass($|\s+.*)""") -} +public fun Element.hasClass(cssClass: String): Boolean = classes.matches("""(^|.*\s+)$cssClass($|\s+.*)""") /** Returns the children of the element as a list */ @@ -118,15 +112,9 @@ public fun Document?.elements(namespaceUri: String, localName: String): List { - return if (this == null) { - // TODO the following is easier to convert to JS - emptyList() - } - else { - NodeListAsList(this) - } -} +public fun NodeList?.asList() : List = if (this == null) emptyList() else NodeListAsList(this) +deprecated("use asList instead") +public fun NodeList?.toList(): List = asList() public fun NodeList?.toElementList(): List { return if (this == null) { @@ -184,48 +172,95 @@ public fun Element.get(selector: String): List { // Helper methods -/** TODO this approach generates compiler errors... -fun Element.addClass(varargs cssClasses: Array): Boolean { - val set = this.classSet - var answer = false - for (cs in cssClasses) { - if (set.add(cs)) { - answer = true - } +/** + * Adds CSS class to element. Has no effect if all specified classes are already in class attribute of the element + */ +public fun Element.addClass(vararg cssClasses: String): Boolean { + val missingClasses = cssClasses.filterNot { hasClass(it) } + if (missingClasses.isNotEmpty()) { + classes = StringBuilder { + append(classes) + missingClasses.joinTo(this, " ", " ") + }.toString() + return true } - if (answer) { - this.classSet = classSet - } - return answer + + return false } -fun Element.removeClass(varargs cssClasses: Array): Boolean { - val set = this.classSet - var answer = false - for (cs in cssClasses) { - if (set.remove(cs)) { - answer = true - } +/** + * Removes all [cssClasses] from element. Has no effect if all specified classes are missing in class attribute of the element + */ +public fun Element.removeClass(vararg cssClasses: String): Boolean { + if (cssClasses.any { hasClass(it) }) { + val toBeRemoved = cssClasses.toSet() + classes = classes.split("\\s+").filter { it !in toBeRemoved }.joinToString(" ") + return true } - if (answer) { - this.classSet = classSet - } - return answer + + return false } -*/ -private class NodeListAsList(private 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 - } +/** + * Adds [cssClasses] to element if []condition] is true or removes it otherwise. + * Has no effect if class attribute already has corresponding content + */ +public fun Element.addOrRemoveClassWhen(condition : Boolean, vararg cssClasses : String) { + if (condition) { + addClass(*cssClasses) + } else { + removeClass(*cssClasses) } +} - override fun size(): Int = nodeList.length +/** + * Adds [trueClassName] class to element if [condition] is true and removes [falseClassName]. + * If [condition] is false then [trueClassName] will be removed and [falseClassName] will be added. + * Has no effect if class attribute already has corresponding content + */ +public fun Element.swapClassWhen(condition: Boolean, trueClassName: String, falseClassName: String) { + if (condition) { + addClass(trueClassName) + removeClass(falseClassName) + } else { + removeClass(trueClassName) + addClass(falseClassName) + } +} + +/** + * If [condition] is true then [attributeName] with value [attributeValue] will be added to the element, otherwise attribute with + * name [attributeName] will be removed + */ +public fun Element.addOrRemoveAttributeWhen(condition : Boolean, attributeName : String, attributeValue : String = attributeName) { + if (condition) { + setAttribute(attributeName, attributeValue) + } else { + removeAttribute(attributeName) + } +} + +/** Removes all the children from this node */ +public fun Node.clear() { + while (hasChildNodes()) { + removeChild(firstChild!!) + } +} + +/** + * Removes this node from parent node. Does nothing if no parent node + */ +public fun Node.removeFromParent() { + parentNode?.removeChild(this) +} + +private class NodeListAsList(val delegate: NodeList) : AbstractList() { + override fun size(): Int = delegate.length + + override fun get(index: Int): Node = + if (index in 0..size() - 1) delegate.item(index)!! + else throw IndexOutOfBoundsException("index $index is not in range [0 .. ${size() - 1})") } private class ElementListAsList(private val nodeList: NodeList) : AbstractList() { @@ -244,18 +279,6 @@ private class ElementListAsList(private val nodeList: NodeList) : AbstractList = NextSiblings(this) @@ -291,10 +314,15 @@ private class PreviousSiblings(private var node: Node) : Iterable { } /** Returns true if this node is a Text node or a CDATA node */ -public fun Node.isText(): Boolean { - val nt = nodeType - return nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE -} +deprecated("use property isText instead") +public fun Node.isText() : Boolean = nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE + +/** + * it is *true* when [Node.nodeType] is TEXT_NODE or CDATA_SECTION_NODE + */ +public val Node.isText : Boolean + get() = nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE + /** Returns the attribute value or empty string if its not present */ public fun Element.attribute(name: String): String { @@ -411,3 +439,17 @@ public fun Element.addText(text: String?, doc: Document? = null): Element { } return this } + +/** + * Creates text node and append it to the element + */ +public fun Element.appendText(text : String, doc : Document = this.ownerDocument!!) { + appendChild(doc.createTextNode(text)) +} + +/** + * Appends the node to the specified parent element + */ +public fun Node.appendTo(parent : Element) { + parent.appendChild(this) +}