How to select global object inserted dynamically to page with ScalaJS - scala.js

I tried to insert the Google ReCaptcha script to the page, but I couldn't select the global grecaptcha.
val script = dom.document.createElement("script").asInstanceOf[HTMLScriptElement]
script.setAttribute("src", "https://www.google.com/recaptcha/api.js")
script.setAttribute("async", "true")
script.onload = { (_: Event) =>
println(Dynamic.global.selectDynamic("grecaptcha")) // --> got undefined
}
dom.document.body.appendChild(script)
In the Console window, I can get grecaptcha:
The question is how to select global grecaptcha object?

According to this answer in a vanilla JavaScript environment, you simply have an ordering problem. The steps should be
Append the script to the document
Set the onload event
Set the src attribute
val script = dom.document.createElement("script").asInstanceOf[HTMLScriptElement]
dom.document.body.appendChild(script)
script.onload = { (_: Event) =>
println(Dynamic.global.selectDynamic("grecaptcha"))
}
script.setAttribute("src", "https://www.google.com/recaptcha/api.js")
script.setAttribute("async", "true")

Related

draggable on ScalaJS removeEventListener does not work

based on that js demo: http://jsfiddle.net/wfbY8/737/
class Draggable(element: HTMLDivElement) {
var offX: Double = 0
var offY: Double = 0
val divMove = (e:MouseEvent) => {
//element.style.position = 'absolute';
element.style.top = (e.clientY-offY) + "px"
element.style.left = (e.clientX-offX) + "px"
}
val mouseDown = (e:MouseEvent) => {
offY = e.clientY - element.offsetTop
offX = e.clientX - element.offsetLeft
window.addEventListener("mousemove", divMove, useCapture = true)
println("added")
}
val mouseUp = (e:MouseEvent) => {
window.removeEventListener("mousemove", divMove, useCapture = true)
println("removed")
}
def addListeners(){
element.addEventListener("mousedown", mouseDown, useCapture = false)
window.addEventListener("mouseup", mouseUp, useCapture = false)
}
addListeners()
}
From the client code I use it like:
val panelElem = document.getElementById(COMPONENT_ID).asInstanceOf[HTMLDivElement]
if (draggable == null) {
draggable = new Draggable(panelElem)
}
I see "added" and "removed" on my log. But the element still movable (when I move mouse without pressing it) for me as if I did not removed mousemove event from the listener (on mouseUp).
I wonder why..
This happens because you're effectively converting the Scala function (the lambda) into a JS function separately for add and remove. In Scala.js, Scala functions are implicitly converted to JS functions as needed. However, the conversion yields a different JS function every time (it does not have the same identity). Therefore, the function you're trying to remove is not the same as the one you added, and of course that has no effect.
You can fix this by forcing the conversion to happen early, so that then you add and remove the same function. To do so, simply add an explicit type to your function vals as JS functions:
val divMove: js.Function1[MouseEvent, Unit] = (e:MouseEvent) => {
...
}
This way, the conversion from Scala function to JS function happens only once, and it is the same JS function that is given to add- and removeEventListener.

Scala Set different operations

So here is my code snippet:
val check = collection.mutable.Set[String]()
if (check.isEmpty) {
println("There is no transfer data available yet, please use the 'load' command to initialize the application!")
}
val userSelection = scala.io.StdIn.readLine("Enter your command or type 'help' for more information:")
val loadCommand = """^(?:load)\s+(.*)$""".r
userSelection match {
case loadCommand(fileName) => check add fileName ;print(check);val l= loadOperation(fileName);println(l.length); if (check.contains(fileName)){
programSelector()
}else{ loadOperation(fileName)}
So first of all I have an input with the match and one case is the "load" input.
Now my program is able to load different .csv files and store it to a List. However I want my program whenever it loads a new .csv file to check if it was loaded previously. If it was loaded before, it should not be loaded twice!!
So i thought it could work with checking with an Set but it always overwrites my previous fileName entry...
Your set operations are fine. The issue is the check add fileName straight after case loadCommand(fileName) should be in the else block. (One of those "d'oh" moments that we have now and then!?) :)
Update
Code
val check = collection.mutable.Set[String]()
def process(userSelection: String): String = {
val loadCommand = """^(?:load)\s+(.*)$""".r
userSelection match {
case loadCommand(fileName) =>
if (check.contains(fileName))
s"Already processed $fileName"
else {
check add fileName
s"Process $fileName"
}
case _ =>
"User selection not recognised"
}
}
process("load 2013Q1.csv")
process("load 2013Q2.csv")
process("load 2013Q1.csv")
Output
res1: String = Process 2013Q1.csv
res2: String = Process 2013Q2.csv
res3: String = Already processed 2013Q1.csv

Can I use non volatile external variables in Scala Enumeratee?

I need to group output of my Enumerator in different ZipEntries, based on specific property (providerId), original chartPreparations stream is ordered by providerId, so I can just keep reference to provider, and add a new entry when provider chages
Enumerator.outputStream(os => {
val currentProvider = new AtomicReference[String]()
// Step 1. Creating zipped output file
val zipOs = new ZipOutputStream(os, Charset.forName("UTF8"))
// Step 2. Processing chart preparation Enumerator
val chartProcessingTask = (chartPreparations) run Iteratee.foreach(cp => {
// Step 2.1. Write new entry if needed
if(currentProvider.get() == null || cp.providerId != currentProvider.get()) {
if (currentProvider.get() != null) {
zipOs.write("</body></html>".getBytes(Charset.forName("UTF8")))
}
currentProvider.set(cp.providerId)
zipOs.putNextEntry(new ZipEntry(cp.providerName + ".html"))
zipOs.write(HTML_HEADER)
}
// Step 2.2 Write chart preparation in HTML format
zipOs.write(toHTML(cp).getBytes(Charset.forName("UTF8")))
})
// Step 3. On Complete close stream
chartProcessingTask.onComplete(_ => zipOs.close())
})
Since current provider reference, is changing, during the output, I made it AtomicReference, so that I could handle references from different threads.
Can currentProvider just be a var Option[String], and why?

how to get autocomplete text box value using lift web

I am using Lift web framework.
I am implementing an auto-complete text box. When I enter some value in the box a drop-down list opens. If I select a value from that list, only then I am able to access value of text box. If I write a value by myself then I get an empty value.
My code :
var friend_name=""
"#bdayReminder" #> AutoComplete("",
getAllName _,
value => takeAction(value),
List("minChars" -> "3"))
private def takeAction(str: String) {
friend_name = str
}
Please suggest a solution
Disclaimer: I'm the author of following library.
I think lift-combobox could achieve what you want, since it has a feature that let user created the value on-the fly. It use select2 jQuery plugin, so you will have a nice look and feel for the drop-down menu.
For example if you need to get the user-created value, it will simply as the following, note that we usually using Option[T] to denote that the value may not be presented, for example, the user may not selected any item in drop-menu at all:
var friend_name: Option[String] = None
val friendsMenu = new ComboBox(
default = None,
allowCreate = true
) {
// This is where you build your combox suggestion
override def onSearching(term: String): List[ComboItem] = {
val names = List(
ComboItem("f1", "Brian"), ComboItem("f2", "Alice"),
ComboItem("f3", "Luke"), ComboItem("f4", "Smith"),
ComboItem("f5", "Brandon")
)
names.filter(_.text.contains(term))
}
override def onItemSelected(selected: Option[ComboItem]): JsCmd = {
friend_name = selected
// The returned JsCmd will be executed on client side.
Alert("You selected:" + selected)
}
// What you want to do if user added an item that
// does not exist when allowCreate = true.
override def onItemAdded(text: String): JsCmd = {
friend_name = Some(text)
}
}
"#bdayReminder" #> friendsMenu.combobox

Liftweb - WiringUI and attributes bug using AutoComplete

My problem is happening when I use some attributes in
I have the following error displayed on my webpage:
error on line 146 at column 80: AttValue: " or ' expected
Here is the corresponding line:
try{jQuery("#F114215951950RGX25X").each(function(i) {this.innerHTML = "<span id=\"F114215951957PA3NZS\"></span>";});} catch (e) {}
Here is the code in my snippet:
import net.liftweb.util.ValueCell
import http.SHtml
import net.liftweb.widgets.autocomplete.AutoComplete
object SearchMenu {
/* A valueCell on which WiringUI is used */
val wiringCell= ValueCell(true)
/* The function called in html template */
def display = WiringUI.apply(wiringCell)(displayAjax)
/* The cell to be updated using autocomplete */
val cell = ValueCell("")
/* The function to create and display the autocomplete box */
def displayAjax(value: Boolean)(ns:NodeSeq):NodeSeq = {
def buildQueryName(current: String, limit: Int): Seq[String] = {
if (current.length == 0) Nil
else (1 to limit).map(n => current+""+n).take(limit)
}
AutoComplete("", buildQueryName _, cell.set _)
}
}
Here is the code in my HTML page:
<form class="lift:form.ajax">
<div class="lift:display"> </div>
</form>
Note: the code works if I call displayAjax(true) instead of display, that is to say, if I don't use Wiring.
Note: I think the problem might come from the fact that autocomplete uses a script that is not loaded when using Wiring UI.
It seems like I found 2 bugs in lift for the autocomplete widget. Here is the thread in the official lift mailing list: https://groups.google.com/forum/?fromgroups#!topic/liftweb/Zu5DBqSSW4U