scala.js's generated JavaScript cannot be called from HTML: "ReferenceError" - scala

I set up a very simple scala.js project with this very simple "application":
package example
import org.scalajs.dom._
import scala.scalajs.js.JSApp
class EverythingWorks extends JSApp {
def main() = {
console.log("It works!")
}
}
The corresponding HTML looks the following:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<script type="text/javascript" src="js/app.js"></script>
<script type="text/javascript">
example.EverythingWorks().main();
</script>
</body>
</html>
Now, I did sbt fastOptJS, copied the generated JS file to js/app.js and the js.map file next to app.js.
Instead of printing "It works!" on the console, I get ReferenceError: example is not defined. I double-checked that app.js is found from the HTML.
What am I missing?

Your main class should be object, not class.

The ScalaJS build process does "dead code elimination." This reduces the size of the build dramatically. However, unless you tell it that some of your top level stuff is NOT dead code, it will be eliminated.
That means you have to use the #JSExport annotation to tell ScalaJS not to remove your top level methods and objects.
From this introduction, the example code:
#JSExport
object ScalaJSExample {
#JSExport
def main(canvas: html.Canvas): Unit = {

Related

How to properly use JSExport methods in a JSExportTopLevel object in Scala.js from a <script> tag?

I have some sjs code:
#JSExportTopLevel("CCRS")
object JsApi {
#JSExport
def makeJobId: JobId = JobId()
// ...
}
I have the following <body> element, which I'll note is properly finding the sjs-generated .js files since I was using a 3rd party SPA framework previously - though the launcher for that is now commented out:
<body>
<script type="application/javascript" src="ace/ace.js" charset="utf-8"></script>
<script type="application/javascript" src="target/web-client-jsdeps.js"></script>
<script type="application/javascript" src="target/web-client-opt.js"></script>
<!-- <script src="target/web-client-launcher.js"></script> -->
<input type="text"
placeholder="Enter a command:"
value="pwd"
onkeydown="oneShotHandler()" />
<div id="one-shot-demo"></div>
<script type="application/javascript">
var oneShotId = CCRS.makeJobId();
</script>
</body>
Upon page load, I get the following error: TypeError: CCRS.makeJobId is not a function.
Not really sure what I should be looking for in the generated web-client-opt.js file (using sjs 0.6.22 currently, with -P:scalajs:sjsDefinedByDefault). But, I do see this line, which I believe should be doing the export:
$e.CCRS = $m_Lorg_xsede_jobrunner_client_JsApi$();
I realized this just as I was finishing typing my question. The beauty of talking it out.
In Scala.js, I needed to add the () to my method:
#JSExport
def makeJobId(): JobId = JobId()

Scala Play load partial template by String name

I have a Scala template like this...
#()
import view.html.partials._header
import view.html.partials._footer
<!DOCTYPE html>
<html lang="en">
#_header()
/* Body of web page */
#_footer
</html>
Every single page has the same header and footer and a different body. I do not want to do this...
Page #1...
#()
import view.html.partials._header
import view.html.partials._footer
import view.html.partials._body1
<!DOCTYPE html>
<html lang="en">
#_header()
#_body1()
#_footer
</html>
Page #2...
#()
import view.html.partials._header
import view.html.partials._footer
import view.html.partials._body2
<!DOCTYPE html>
<html lang="en">
#_header()
#_body2()
#_footer
</html>
Page #3...
#()
import view.html.partials._header
import view.html.partials._footer
import view.html.partials._body3
<!DOCTYPE html>
<html lang="en">
#_header()
#_body3()
#_footer
</html>
Etc.
Is there a way to pass in the name of the partial template you want to render as a parameter? What is the solution to this problem?
p.s. I don't see the solution in... the play template documentation
Instead of having all these repetitions, you can create a main.scala.html file to be used as a default layout:
#(title: String)(content: Html)
#import view.html.partials._header
#import view.html.partials._footer
<!DOCTYPE html>
<html lang="en">
#_header()
<body>
#content
#_footer()
</body>
</html>
The first line says exactly "this view will receive a title argument and also a block of HTML". From that, you can do the following:
Page #1:
#(someParameter: String)
#main("The title of Page #1") {
<h1>Hello, I'm the body of Page #1</h1>
<p>As you can see, I'm calling the main view passing
a title and a block of HTML</p>
}
Page #2:
#(someParameter: String, anotherParameter: Long)
#main("This time Page #2") {
<h1>Hello, I'm the body of Page #2</h1>
<p>Just like Page #1, I'm passing a title
and a block of HTML to the main view.</p>
}
This is all explained at the docs, but in another page:
https://www.playframework.com/documentation/2.0/ScalaTemplateUseCases
Make a switch or case statement like this...
#(bodyCase: ClosedEnumType)
import view.html.partials._header
import view.html.partials._footer
import view.html.partials._body1
import view.html.partials._body2
<!DOCTYPE html>
<html lang="en">
#_header()
#bodyCase match {
case Body1() => {
#_body1()
}
case Body2() => {
#_body2()
}
}
#_footer
</html>

Samsung TV SDK - getting a simple application working

I am attempting to get a very simple HTML/JavaScript application working for SDK 5.0b, the instructions for which are here...
http://samsungtvdev.blogspot.com/2013/04/smamsung-smart-tv-how-to-write-hello.html
I can launch VirtualBox 4.2.16 and see my application in the menu for the emulator. However, when I launch it, the background is black, and I don't see my application. I also see a bunch of warnings in the emulator about 'RegisterType()' and other functions not being available.
I tried posting this on the Samsung SDK forum, but it's pretty dead over there. I also tried the suggestion here, but copying the application manually also doesn't seem to work. Anyone have any ideas on how I can get this working?
Edit: Here is the HTML code. This isn't more than a "hello world" example.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>HelloWorld</title>
<!-- TODO : Common API -->
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"> </script>
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"> </script>
<!-- TODO : Javascript code -->
<script language="javascript" type="text/javascript" src="app/javascript/Main.js"></script>
<!-- TODO : Style sheets code -->
<link rel="stylesheet" href="app/stylesheets/Main.css" type="text/css">
<!-- TODO: Plugins -->
</head>
<body onload="Main.onLoad();" onunload="Main.onUnload();">
<!-- Dummy anchor as focus for key events -->
<!-- TODO: your code here -->
<div id="outputDiv"></div>
</body>
</html>
This is the JavaScript code.
var widgetAPI = new Common.API.Widget();
var tvKey = new Common.API.TVKeyValue();
var Main =
{
};
Main.onLoad = function()
{
// Enable key event processing
this.enableKeys();
widgetAPI.sendReadyEvent();
alert("App loaded!");
};
Main.onUnload = function()
{
};
Main.enableKeys = function()
{
document.getElementById("anchor").focus();
};
Main.keyDown = function()
{
var keyCode = event.keyCode;
alert("Key pressed: " + keyCode);
switch(keyCode)
{
case tvKey.KEY_RETURN:
case tvKey.KEY_PANEL_RETURN:
alert("RETURN");
widgetAPI.sendReturnEvent();
break;
case tvKey.KEY_LEFT:
alert("LEFT");
break;
case tvKey.KEY_RIGHT:
alert("RIGHT");
break;
case tvKey.KEY_UP:
alert("UP");
break;
case tvKey.KEY_DOWN:
alert("DOWN");
break;
case tvKey.KEY_ENTER:
case tvKey.KEY_PANEL_ENTER:
alert("ENTER");
document.getElementById("outputDiv").innerHTML += "<h1>Hello, World!</h1><br/>";
break;
default:
alert("Unhandled key");
break;
}
};
Here are the logs:
http://pastebin.com/mZULDGc6
1.) Look for misspellings, typos and missing commas. Samsung Smart TV SDK seems to be very strict with that and since you have no proper console, you don't get any errors if you forget a comma or something
2.) check your HTML/CSS
Maybe you should post your code so I can have a closer look.
EDIT: You forgot to add the scripts in your HTML head. You have to add every script file that you use in your project, such as Main.js. That would be
<script language="javascript" type="text/javascript" src="app/javascript/Main.js"></script>
and also all Samsung SmartTV API script files that are required.
First what i see, you forgot "anchor" tag in html.
Not included external JS files in html page, and standard smart tv sdk files:
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/Widget.js"> </script>
<script type="text/javascript" language="javascript" src="$MANAGER_WIDGET/Common/API/TVKeyValue.js"> </script>
Then add
<body onload="Main.onLoad();" onunload="Main.onUnload();">
Are you sure that images loaded? Print it in console.
Why div block position inside canvas, move it outside. I think that code started with js error, so you don't see anything. Be more careful.
I had same issue and fixed it by adding background: red; for body tag in css.

Access Javascript Library D3 from GWT

I include the d3 javascript like this
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="http://d3js.org/d3.v2.js"></script>
<script type="text/javascript" src="d3/d3.nocache.js"></script>
</head>
<body>
</body>
</html>
Then when I call it from the entry point d3 is null, why?
package com.example.client;
import com.google.gwt.core.client.EntryPoint;
public class D3 implements EntryPoint {
public void onModuleLoad() {
test();
}
private native void test()/*-{
$wnd.alert($wnd.d3);
}-*/;
}
Well, it seems that the problem was that I named the project D3. Need to call it something else because it seems that it overwrites the D3 of the javascript library.

Incorrectly Linking Javascript File?

I'm working on installing a PhoneGap plugin on an iPhone. The page for the plugin I am attempting to install can be seen here: https://github.com/phonegap/phonegap-plugins/tree/master/iPhone/MessageBox.
I believe I have narrowed down my problem to incorrectly working with the JavaScript file. I am including it on my HTML page like so:
<script language="javascript" type="text/javascript" src="MessageBox.js"></script>
The rest of my HTML page is this:
<script type="text/javascript">
alert("test1");
var messageBox = window.plugins.messageBox;
alert("test2");
messageBox.alert('Title', 'Message', function(button) { console.warn('alert', [this, arguments]); });
</script>
I see an alert saying test1, but not the second alert. This makes me think that the error is on the line:
var messageBox = window.plugins.messageBox;
However, I'm not quite sure what I should be doing differently. From what I can tell, I've done all the necessary steps as described on the plugin's documentation page, seen here:
https://github.com/phonegap/phonegap-plugins/blob/master/iPhone/MessageBox/README.md
(As expected, I also do not see the output of the messageBox.alert... line when viewing this through the iOS simulator.)
I would appreciate any help with this issue, thanks!
NOTE: my initial thread regarding this topic can be seen here: Trouble Installing PhoneGap Plugin
EDIT: I should also add that I have the exact same problem when trying to install a different (but similar) plugin, known as "Prompt"
EDIT2: Here's my index.html:
<script type="text/javascript" charset="utf-8" src="phonegap-1.4.1.js"></script>
<script type="text/javascript" src="MessageBox.js"></script>
<script type="text/javascript">
function onBodyLoad()
{
document.addEventListener("deviceready", onDeviceReady, false);
}
function onDeviceReady()
{
navigator.notification.alert("PhoneGap is working");
window.location.href="otherpage.html";
}
</script>
The problem is that when you try to create your MessageBox, PhoneGap is not ready yet.
You just need to wait for PhoneGap to be ready before you execute your code :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script type="text/javascript" charset="utf-8" src="phonegap-1.4.1.js"></script>
<script type="text/javascript" charset="utf-8">
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.location="otherpage.html";
}
</script>
</head>
<body>
</body>
</html>
Then, on otherpage.html :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<script type="text/javascript" charset="utf-8" src="phonegap-1.4.1.js"></script>
<script type="text/javascript" charset="utf-8" src="MessageBox.js"></script>
</head>
<body onload="onLoad()">
<script type="text/javascript" charset="utf-8">
function onLoad() {
document.addEventListener("deviceready", onDeviceReady, false);
}
// PhoneGap is loaded and it is now safe to make calls PhoneGap methods
//
function onDeviceReady() {
console.log("onLoad");
var messageBox = window.plugins.messageBox;
messageBox.alert('Title', 'Message', function(button) { console.warn('alert', [this, arguments]); });
}
</script>
</body>
</html>
I tested it on PhoneGap 1.4.1