Hi, I am learning Nim and I was trying to create a custom element (web component). This web component I am trying to create with Nim is called WordCount and it is trying to count the words in a text where it resides. To count the words I was trying to split the text by white space and get the length of the resulting array. I was able to import the std/strutils library in JS but the split function only returns "1". The code to count the words seems to work when tested in the playground so it should work in JS.
This is the code that works in the playground:
import std/strutils
var a: cstring = "a b c"
echo splitWhitespace($a).len
#3
Note that here I am using cstring instead of string because string in JS is cstring.
import std/strutils
import jsffi
{.emit: """
// Create a class for the element
class WordCount extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
// count words in element's parent element
// const wcParent = this.parentNode;
// function countWords(node){
// const text = node.innerText || node.textContent;
// return text.trim().split(/\s+/g).filter(a => a.trim().length > 0).length;
// }
const count = "Words: " + this.countWords(this);
// Create a shadow root
const shadow = this['attachShadow']({mode: 'open'});
// Create text node and add word count to it
const text = document.createElement('span');
text.textContent = count;
// Append it to the shadow root
shadow.appendChild(text);
var self = this;
// Update count when element content changes
setInterval(function() {
const count = "Words: " + self.countWords(self);
text.textContent = count;
}, 200);
}
countWords(obj) {
return 100;
}
}
""".}
type ParentNode = ref object
textContent: string
innerText: string
type WordCount = ref object
parentNode: ParentNode
proc addFuncToWordCount(
methodName: cstring,
functionBody: auto) {.importjs: "WordCount.prototype[#] = #".}
addFuncToWordCount("countWords", proc (self: WordCount): int =
let text: string = $(if self.parentNode.innerText == "": self.parentNode.textContent else: self.parentNode.innerText)
#text.split(" ").len # does not work as well
text.splitWhitespace.len
)
{.emit: """
customElements.define('word-count', WordCount, { extends: 'p' });
""".}
sample html
<html>
<body>
<article>
<p>Hello world</p>
<p is="word-count"></p>
</article>
<script src="main.js"></script>
</body>
</html>
Is this a bug or should I be using another library or is it something else?
Change the definition of ParentNode to use cstrings and it works correctly:
type ParentNode = ref object
textContent: cstring
innerText: cstring
As mentioned by @Araq, strutils works on the js backend but if you are operating on JS cstrings it is more efficient to wrap js functions than to have your code convert cstring->string to use strutils
I mean fixing the data types for ParentNode enabled splitting with std/strutils but using karax/jstrutils not only enabled using the js equivalent of split but also allowed me to just use
let text = if self.parentNode.innerText == "": self.parentNode.textContent else: self.parentNode.innerText
instead of having to wrap it with $ like
let text = $(if self.parentNode.innerText == "": self.parentNode.textContent else: self.parentNode.innerText)