I am trying to add a javascript file that generated via Transcrypt from Python file.
However, when I add that script to my HTML file, there are some errors appeared in Console and I failed.
The Python file that I used: try.py
def greet():
name = document.getElementById("Name").value
if name == "" or name.length == 0 or name == null:
document.getElementById("groet").innerHTML = '<p><font color="#ff0000">Hello Anonymous, may I know yor name? Please insert it below:</font></p>'
else:
document.getElementById("groet").innerHTML = '<p><font color="#00ff00">Hello, '+name+', thank you for introducing you</font></p>'
After that script, I ran the command python3 -m transcrypt -b try.py and a folder called "target" created automatically and it contains a file "try.js".
So, I wrote a HTML file which is a basic sample that shows a greeting message: hello.html
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="__target__/try.js"></script>
</head>
<title>Insert Text</title>
<body onload=try.greet()>
<h2>Hello Demo Name</h2>
<p>
<div id = "groet">...</div>
</p>
<p>Your Name: <input name="name" type="text" maxlength="80" id="Name" value=""/> [Please enter your name]<br><br>
<button onclick=try.greet()>Refresh the greeting!</button>
</p>
</body>
</html>
I am expecting that when I clicked the button or reload the file the greeting message should be placed. However, in console I got two errors:
Uncaught SyntaxError: import declarations may only appear at top level of a module try.js:1:13
Uncaught SyntaxError: missing { before try block hello.html:1:3
So, what is the problem guys?
[EDIT]
After the T.J's answer, I updated the html file as following:
'use strict';import{AssertionError,AttributeError,BaseException,DeprecationWarning,Exception,IndexError,IterableError,KeyError,NotImplementedError,RuntimeWarning,StopIteration,UserWarning,ValueError,Warning,__JsIterator__,__PyIterator__,__Terminal__,__add__,__and__,__call__,__class__,__envir__,__eq__,__floordiv__,__ge__,__get__,__getcm__,__getitem__,__getslice__,__getsm__,__gt__,__i__,__iadd__,__iand__,__idiv__,__ijsmod__,__ilshift__,__imatmul__,__imod__,__imul__,__in__,__init__,__ior__,__ipow__,
__irshift__,__isub__,__ixor__,__jsUsePyNext__,__jsmod__,__k__,__kwargtrans__,__le__,__lshift__,__lt__,__matmul__,__mergefields__,__mergekwargtrans__,__mod__,__mul__,__ne__,__neg__,__nest__,__or__,__pow__,__pragma__,__proxy__,__pyUseJsNext__,__rshift__,__setitem__,__setproperty__,__setslice__,__sort__,__specialattrib__,__sub__,__super__,__t__,__terminal__,__truediv__,__withblock__,__xor__,abs,all,any,assert,bool,bytearray,bytes,callable,chr,copy,deepcopy,delattr,dict,dir,divmod,enumerate,filter,float,
getattr,hasattr,input,int,isinstance,issubclass,len,list,map,max,min,object,ord,pow,print,property,py_TypeError,py_iter,py_metatype,py_next,py_reversed,py_typeof,range,repr,round,set,setattr,sorted,str,sum,tuple,zip}from"./org.transcrypt.__runtime__.js";var __name__="__main__";export var greet=function(){var py_name=document.getElementById("Name").value;if(py_name==""||py_name.length==0||py_name==null)document.getElementById("groet").innerHTML='<p><font color="#ff0000">Hello Anonymous, may I know yor name? Please insert it below:</font></p>';
else document.getElementById("groet").innerHTML='<p><font color="#00ff00">Hello, '+py_name+", thank you for introducing you</font></p>"};
//# sourceMappingURL=hello.map
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script type="module">
import { greet } from "./hello.js";
document.getElementById("greetButton").onclick=greet();
</script>
</head>
<title>Insert Text</title>
<body>
<h2>Hello Demo Name</h2>
<p>
<div id = "groet">...</div>
</p>
<p>Your Name: <input name="name" type="text" maxlength="80" id="Name" value=""/> [Please enter your name]<br><br>
<button id="greetButton">Refresh the greeting!</button>
</p>
</body>
</html>
import declarations may only appear at top level of a module
is fairly clear: You're not loading the script as a module, so you can't use import. Add type="module" to the script tag. (But be sure that your target browsers support modules -- all modern major ones do, but you don't have to go more than a few versions back in some before module support isn't there.)
missing { before try block
You have
<body onload=try.greet()>
try is a keyword in JavaScript, you can't use it as an identifier. You'll need to use a different name for your try object. (I'll use xtry in the rest of this answer.)
If your code really is a module, you also won't be able to use your xtry as a global, even if it's declared at the top level of your code, because the top level scope of a module isn't global scope. You'll need to import it to use it. That also means you don't need a script tag for try.js since the import will do it. Remove the onload and your current script tag and instead:
<script type="module">
import { xtry } from "__target__/try.js";
xtry.greet();
</script>
That won't run until the HTML has been fully parsed and the DOM has been populated (because of the type="module").
Side note: onload attribute handlers are generally not best practice, for two reasons: 1. They can only use globals, and 2. The load event happens very late in the page load cycle, waiting for all resources (including all images) to load. Sometimes that's what you want, but not often. Instead, use modern event handling (if you really need to hook up a handler on load) and use modern script techniques (type="module", defer, ...).
In addition to #T.J. Crowder's answer, I changed the script in html as:
<script type="module">
import * as hello from "./__target__/hello.js";
window.hello = hello;
</script>
As explained in the tutorial of Transcrypt.
With this way, I can call the Python function on button's click.
A call to numericInput(), like this:
numericInput("obs", "Observations:", 10, min = 1, max = 100)
constructs HTML code like this:
<div class="form-group shiny-input-container">
<label for="obs">Observations:</label>
<input id="obs" type="number" class="form-control" value="10" min="1" max="100"/>
</div>
Then, presumably, in the browser, JavaScript code provided by one of the scripts included in the HTML doc's header finds that <input> element and renders it with the interactive widget displayed below:
I'm having a hard time, though, figuring out where the code that finds that <input> element and then triggers production of the corresponding widget is stored. Is it in Shiny's own JavaScript, or in that borrowed from by Bootstrap or jQuery UI or one of the other plugins that ship with shiny?
My question(s):
Where is the JavaScript code that provides the widget pictured above and associates it with the HTML <input> element? And how, from the code that's involved, might I have learned that on my own?
More only possibly useful details
This section of the script "shiny.js" finds the <input> element of interest, and provides methods that can get and set the widget's value. It doesn't (as far as I can see) provide the widget itself.
var numberInputBinding = {};
$.extend(numberInputBinding, textInputBinding, {
find: function(scope) {
return $(scope).find('input[type="number"]');
},
getValue: function(el) {
var numberVal = $(el).val();
if (/^\s*$/.test(numberVal)) // Return null if all whitespace
return null;
else if (!isNaN(numberVal)) // If valid Javascript number string, coerce to number
return +numberVal;
else
return numberVal; // If other string like "1e6", send it unchanged
},
setValue: function(el, value) {
el.value = value;
[... snip ...]
}
});
inputBindings.register(numberInputBinding, 'shiny.numberInput');
And here is a copy of the <head> section of the the shiny-generated HTML file that results in the numericInput widget. The scripts it references can mostly be found here
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="application/shiny-singletons"></script>
<script type="application/html-dependencies">json2[2014.02.04];jquery[1.11.0];shiny[0.12.2];bootstrap[3.3.1]</script>
<script src="shared/json2-min.js"></script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/shim/html5shiv.min.js"></script>
<script src="shared/bootstrap/shim/respond.min.js"></script>
<title>Hello Shiny!</title>
</head>
Here's the incorrect assumption that made this so hard for me to figure out:
Then, presumably, in the browser, JavaScript code provided
by one of the scripts included in the HTML doc's header finds that
element and renders it with the interactive widget displayed
below:
In fact, as #epascarello points out, modern browsers themselves support <input type="number">.
(For further documentation of this fact, along with a long list of the features whose support was enabled by the incorporation of JavaScript in these modern web browsers, see Chapter 4 of "HTML for Web Designers".)
I have some dynamic javascript that creates elements, with a click event element handler... the script is included from another domain.
However with Firefox at runtime it gives a security warning and does not process the click event (Chrome works fine).
A simplified version below
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<h2 id="headertitle">TEST</h2>
<br/>
<script type="text/javascript" src="somewhereelse.com/script.js">
</script>
</body>
</html>
Javascript include:
document.getElementById("headertitle").insertAdjacentHTML('beforeBegin',
"<button value='TEST' onclick='clickHandler(this)' >Button</button>");
function clickHandler(evt){
alert("clicked");
}
Warning Message:
Security wrapper denied access to property undefined on privileged
Javascript object. Support for exposing privileged objects to
untrusted content via exposedProps is being gradually removed -
use WebIDL bindings or Components.utils.cloneInto instead. Note that
only the first denied property access from a given global object will
be reported.
I tried your code here and it worked fine for me on Firefox 50.1.0. =/
However, I strongly recommend you use JQuery to deal with events triggered by dynamically created elements. JQuery handles the DOM differently, it's cross-browser and it's just made for this kind of situation. It may solve your problem. =D
Try and change your html to
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<h2 id="headertitle">TEST</h2>
<br/>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="somewhereelse.com/script.js">
</script>
</body>
</html>
and your JS code to
document.getElementById("headertitle").insertAdjacentHTML('beforeBegin',
'<button value="TEST" class="clickable" id="btn1">Button</button>');
$('.clickable').on('click', function() {
alert($(this).attr('id') + ' was clicked');
});
That should make it work!
Cheers! =)
I'm getting more into jQuery and so have set up a HTML/Javascript/CSS base site which I use for all my tests.
Since these tests will eventually turn into PHP and ASP.NET MVC websites, I want to use this opportunity to get the basics down right again for modern browsers and web standards before building the scripting languages on top of it.
I've selected to use:
XHTML 1.0 Strict
UTF-8 encoding
as few CSS references as possible (put everything in 1 CSS file for loading speed)
as few Javascript references as possible (1 javascript file plus the jquery code base reference - I assume using the Google jQuery code base is best practice for speed)
I check my code as I build it with the http://validator.w3.org
Is there anything else I need to consider?
Here is an example of one of my test websites:
index.htm:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<title>Text XHTML Page</title>
<link href="css/main.css" rel="stylesheet" type="text/css" media="all"/>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript" src="javascript/main.js"></script>
</head>
<body>
<h1 class="highlightTitle">Text</h1>
<p class="main">First</p>
<p>Second</p>
<p id="selected" class="regular">Third</p>
<p>Fourth</p>
<form action="">
<div>
<input type="button" value="highlight it" onclick="highlightIt();countThem()" />
<input type="button" value="highlight title" onclick="highlightTitle()" />
<p>here is another paragraph</p>
</div>
</form>
</body>
</html>
main.cs:
p.highlighted {
background-color:orange;
}
h1.highlightTitle {
background-color:yellow;
}
h1.deselected {
background-color:#eee;
}
p.regular {
font-weight: bold;
}
main.js:
google.load("jquery", "1.3.2");
function highlightIt() {
$('#selected')
.toggleClass('highlighted');
}
function countThem() {
alert("there are " + $("p.main").size() + " paragraphs");
}
function highlightTitle() {
$("h1").toggleClass("deselected");
}
Personally I would bind to the click event via jQuery to ensure nice separation, like this:
$("#yourId").bind("click", highlightIt);
This way you can bind to multiple event handlers. If you just use onclick AFAIK you can only ever use one handler.
BTW you can also use custom event and event namespaces:
$("#yourId").bind("beforeHighlighting", doSomething);
is triggered by
$("#yourId").trigger("beforeHighlighting");
and
$(".hasAHelptext").bind("helptext.click", showHelptextFct);
$(".hasAHelptext").bind("click", otherFct);
// will only remove the showHelptextFct event handler
$(".hasAHelptext").unbind("helptext.click");
HTH
Alex
Move the <script> blocks to the bottom of the page.
With regard to CSS and JS files in general, I wouldn't combine all JS files to a single file during development. It gets very hard to develop in one big JS file. Rather use a module that combines them on-the-fly or during deployment.
I usually go with (both CSS and JS):
one general file:
project.css
and one per page:
project_welcome.css
and any special components (login controls, ad area views etc) have a seperate one as well.
That way you can apply some organizing techniques and won't go crazy managing that single large file.
HTH
Alex
I would recommend putting the JS calls below the body tag. If your scripts are hanging, then the page can load and let the behavior (JS) load after the fact. I've noticed that speed greatly improves with this method.
Check this out: http://stevesouders.com/hpws/rule-js-bottom.php