| JavaScript |
Dart |
TIScript |
Code embedding |
<script src='program.js'></script>
|
// Note: This will only work in Dartium (a build of
// Chromium with Dart VM)
<script type='application/dart' src='program.dart'>
</script>
// Also, you'll need this to kickstart the Dart engine.
<script type='text/javascript'>
if (navigator.webkitStartDart) {
navigator.webkitStartDart();
</script>
|
<script type='text/tiscript' src='program.js' />
|
Printing to the console |
console.log('Level completed.');
|
print('Level completed.');
|
stdout.println("Level completed.");
stdout.printf("Level %d completed.\n", levelNo);
// use of stringizer
stdout.$n(Level {levelNo} completed.");
|
Code modularity |
Define a library |
// No native implementation.
// Consider require.js and AMD
|
// declares the following is in the animals library
#library('animals');
class Dog {
noise() => 'BARK!';
}
|
// declares the following in the animals namespace,
// file animals.tis:
namespace animals {
class Dog {
function noise() { return "BARK!"; }
}
}
|
Use a library |
// No native implementation.
// Consider require.js and AMD
|
#import('animals');
var fido = new Dog();
// prefixes are supported to avoid namespace collisions
#import('animals', prefix: 'pets');
var fido = new pets.Dog();
|
include("animals.tis");
var fido = new animals.Dog();
// to avoid namespace collisions include the file in
// other namespace
namespace Zoo {
include("animals.tis");
}
var fido = new Zoo.animals.Dog();
|
Variables
Create + assign variable |
var myName = 'Aaron';
|
// Dart variables can be typed...
String myName = 'Aaron';
// but they don't need to be
var myOtherName = 'Aaron';
|
var myName = 'Aaron';
|
Hoisting |
// JavaScript "hoists" variables to the top of
// their scope. So the following function:
function printName() {
console.log('Hello, ' + name);
var name = 'Bob';
}
// is equivalent to this function:
function printName() {
var name;
console.log('Hello, ' + name);
name = 'Bob';
}
printName();
// Hello, undefined
|
// Dart does not hoist variables. The following
// method will issue a compilation error
// of "cannot resolve name"
printName() {
print('Hello, $name'); // compilation error here
var name = 'Bob';
}
|
// TIScript does not hoist variables. The following
// method will issue a runtime error
// of "Variable 'name' not found"
function printName() {
stdout.printf("Hello, %s\n",name); // error here
var name = "Bob";
}
|
Final variables |
// no support
|
final name = 'Bob';
// you can combine types and final
final String name = 'Bob';
// Trying to reassign a final variable raises an error
name = 'Alice';
// ERROR: cannot assign value to final variable
|
const name = "Bob";
// Trying to reassign a const raises an error
name = "Alice";
// ERROR: cannot assign to read-only variable
|
Collections
Arrays / Lists |
var a = new Array();
var a = [];
var a = [1, 2, 3];
|
var a = new List();
var a = [];
var a = [1, 2, 3];
|
// same as in JavaScript.
// No need for new entities here.
var a = new Array();
var a = [];
var a = [1, 2, 3];
|
var a = ["apple", "banana", "cherry"];
// returns the new length of the array
a.push("donut");
// == 4
a.length;
// == 4
a.pop();
// == "donut"
|
var a = ['apple', 'banana', 'cherry'];
// returns null
a.add('donut');
// == null
a.length
// == 4
a.removeLast()
// == 'donut'
|
// same as in JavaScript.
var a = ["apple", "banana", "cherry"];
// returns the new length of the array
a.push("donut");
// == 4
a.length;
// == 4
a.pop();
// == "donut"
|
Custom sort |
var numbers = [42, 2.1, 5, 0.1, 391];
numbers.sort(function(a, b) {
return a - b;
});
// == [0.1, 2.1, 5, 42, 391]
|
var numbers = [42, 2.1, 5, 0.1, 391];
numbers.sort((a, b) => a - b);
// == [0.1, 2.1, 5, 42, 391];
|
// use of short anonymous function notation:
var numbers = [42, 2.1, 5, 0.1, 391];
numbers.sort( :a, b: a - b );
// == [0.1, 2.1, 5, 42, 391]
|
Key-value pairs |
// An empty key-value pair can be declared
// in two different ways in JavaScript
var periodic = new Object();
var periodic = {};
|
// Dart has a Map interface (interface?)
// for key-value pairs
var periodic = {};
var periodic = new Map();
|
// Same as in JavaScript
var periodic = new Object();
var periodic = {};
|
Appropriate keys |
var periodic1 = {
gold: 'AU',
silver: 'AG'
};
var periodic2 = {
'gold': 'AU',
'silver': 'AG'
};
|
// Keys in Dart must be string literals
var periodic = {
'gold' : 'AU',
'silver' : 'AG'
};
|
// keys - symbols
var periodic1 = {
gold: "AU",
silver: "AG"
};
// keys - strings
var periodic2 = {
"gold": "AU",
"silver": "AG"
};
// symbol and string are two distinct types.
|
Accessing values |
periodic1.gold // == 'AU'
periodic1['gold'] // == 'AU'
periodic2.gold = 'Glitter';
periodic2['gold'] = 'Glitter';
|
// Values can only be 'get' or 'set' by using
// the square bracket notation.
// Dot notation does not work
periodic['gold'] // == 'AU'
periodic['gold'] = 'Glitter';
|
periodic1.gold // == "AU"
periodic1["gold"] // == undefined
periodic2.gold // == undefined
periodic2["gold"] // == "AU"
// replaces old value
periodic1.gold = "Glitter";
// creates new entry under "gold" key
periodic1["gold"] = "Glitter";
|
Sets (collections of unique items) |
// no native JavaScript equivalent
|
var fruits = new Set();
fruits.add('oranges');
fruits.add('apples');
fruits.length // == 2
// duplicates existing item:
fruits.add('oranges');
fruits.length // == 2
|
var fruits = {};
fruits["oranges"] = true;
fruits["apples"] = true;
fruits.length // == 2
// duplicates existing item:
fruits["oranges"] = true;
fruits.length // == 2
|
Queues (FIFO) |
var queue = [];
queue.push('event:32342');
queue.push('event:49309');
console.log(queue.length); // 2
var eventId = queue.shift();
console.log(eventId === 'event:32342');
console.log(queue.length); // 1
|
// Queues are optimized for removing items
// from the head
var queue = new Queue();
queue.add('event:32342');
queue.add('event:49309');
print(queue.length); // 2
var eventId = queue.removeFirst();
print(eventId == 'event:32342'); // true
print(queue.length); // 1
|
var queue = [];
queue.push("event:32342");
queue.push("event:49309");
stdout.println(queue.length); // 2
var eventId = queue.shift();
stdout.println(eventId === "event:32342");
stdout.println(queue.length); // 1
|
Strings
Raw strings |
// JavaScript does not have 'raw' strings.
// All escaping must be done manually.
var escapedString = 'A tab looks like \\t';
|
var rawString
= @'The following is not expanded to a tab \t';
var escapedString
= 'The following is not expanded to a tab \\t';
rawString == escapedString // == true
|
// TIScript does not have 'raw' strings.
// All escaping must be done manually.
var escapedString = 'A tab looks like \\t';
|
Interpolation |
var name = 'Aaron';
var greeting = 'My name is ' + name;
var greetingPolish
= 'My Polish name would be ' + name + 'ski';
element.style.top = (top + 20) + 'px';
|
var name = 'Aaron';
var greeting = 'My name is $name.';
var greetingPolish
= 'My Polish name would be ${name}ski.';
// calculations can be performed
// in string interpolation
element.style.top = '${top + 20}px';
|
// TIScript has "stringizer" functions -
// string literal combined with function call:
var name = 'Aaron';
var greeting = String.$(My name is {name}.);
var greetingPolish
= String.$(My Polish name would be {name}ski.);
// calculations can be performed
// in string interpolation
element.style.top = String.$({top + 20}px);
|
Substring |
'doghouses'.substring(3, 8) // == 'houses'
'doghouses'.substr(3, 5) // == 'houses'
|
'doghouses'.substring(3, 8); // == 'houses'
|
// Good old JS:
"doghouses".substring(3, 8) // == "houses"
"doghouses".substr(3, 5) // == "houses"
|
Replace all occurences |
'doghouses'.replace(/s/g, 'z') // == 'doghouzez'
|
'doghouses'.replaceAll('s','z'); // == 'doghouzez'
|
"doghouses".replace(/s/g, "z") // == 'doghouzez'
"doghouses".replace("s", "z") // == 'doghouzez'
|
Replace one occurence |
'racecar'.replace(/r/, 'sp') // == 'spacecar'
|
'racecar'.replaceFirst('r', 'sp'); // == 'spacecar'
|
"racecar".replace(/r/, "sp") // == "spacecar"
|
Multi-line strings |
var string =
'This is a string that spans\n' +
'many lines.\n';
|
// Dart ignores the first new-line
// (if it is directly after the quotes),
// but not the last.
var string = '''
This is a string that spans
many lines.
''';
|
// consequent string literals are collapsed
// into single literal:
var string1 =
"This is a string that spans\n"
"many lines.\n";
// string literals can span multiple lines:
var string2 =
"This is a string that spans
many lines.
";
|
Split into array |
var animals = 'dogs, cats, gophers, zebras';
var individualAnimals = animals.split(', ');
// == ['dogs', 'cats', 'gophers', 'zebras'];
|
var animals = 'dogs, cats, gophers, zebras';
var individualAnimals = animals.split(', ');
// == ['dogs', 'cats', 'gophers', 'zebras'];
|
var animals = "dogs, cats, gophers, zebras";
var individualAnimals = animals.split(", ");
// == ['dogs', 'cats', 'gophers', 'zebras'];
|
Test whether a string starts with a substring |
// JavaScript has no built-in startsWith function
String.prototype.startsWith = function(beginning)
{
var head = this.substr(0, beginning.length);
return head == beginning;
}
'racecar'.startsWith('race') // == true
'racecar'.startsWith('pace') // == false
|
// Dart string objects have a
// built-in startsWith method
'racecar'.startsWith('race'); // == true
'racecar'.startsWith('pace'); // == false
|
"racecar".indexOf("race") == 0; // == true
"racecar".indexOf("pace") == 0; // == false
// If someone wants exactly startsWith method then
// String class can be extended by such method:
function String.startsWith(str) {
return this.indexOf(str) == 0;
}
|
Booleans
If statement |
var bugNumbers = [3234,4542,944,124];
if (bugNumbers.length > 0) {
console.log('Not ready for release');
}
|
var bugNumbers = [3234,4542,944,124];
if (bugNumbers.length > 0) {
print('Not ready for release');
}
|
var bugNumbers = [3234,4542,944,124];
if (bugNumbers.length > 0) {
stderr.println("Not ready for release");
}
// or just
if (bugNumbers)
stderr.$n(Not ready for release);
|
Ternary statements |
var bugNumbers = [3234,4542,944,124];
var status = bugNumbers.length > 0
? 'RED' : 'GREEN';
console.log('The build is ' + status);
|
var bugNumbers = [3234,4542,944,124];
var status = bugNumbers.length > 0
? 'RED' : 'GREEN';
print('The build is $status');
|
var bugNumbers = [3234,4542,944,124];
var status = bugNumbers ? "RED" : "GREEN";
stdout.$n(The build is {status});
|
Checking for empty string |
var emptyString = '';
if (!emptyString) {
console.log('empty strings are' +
' treated as false');
}
|
var emptyString = '';
if (emptyString.isEmpty()) {
print('use isEmpty()');
}
|
var emptyString = "";
if (!emptyString) {
stdout.$n(empty strings are treated as false);
}
|
Checking for zero |
var zero = 0;
if (!zero) {
console.log('0 is treated as false');
}
|
var zero = 0;
if (zero == 0) {
print('use == 0 to check zero');
}
|
var zero = 0;
if (!zero) {
stdout.$(0 is treated as false);
}
|
Checking for null |
var myNull = null;
if (!myNull) {
console.log('null is treated as false');
}
|
var myNull = null;
if (myNull == null) {
print('use == null to check null');
}
|
var myNull = null;
if (!myNull)
stdout.$n(null is treated as false);
|
Checking for NaN |
var myNaN = NaN;
if (!myNaN) {
console.log('NaN is treated as false');
}
|
var myNan = 0/0;
if (myNaN.isNaN()) {
print('use isNaN to check if a number is NaN');
}
|
var myNaN = 0.0/0.0;
if (myNaN.isNaN())
stdout.println("use Float.isNaN()");
|
Checking for undefined |
var isUndefined;
if (!isUndefined) {
console.log('undefined is treated as false');
}
|
// Dart does not have a concept of undefined
|
var isUndefined;
if (!isUndefined)
stdout.println("undefined is treated as false");
if (isUndefined === undefined)
stdout.println("test for exactly undefined");
|
Value and identity equality |
var letterA = 'A';
var charA = String.fromCharCode(65);
// JavaScript converts both values to the
// same type before checking their value
// with 'double equals'.
letterA == charA // == true
// Similarly...
var number5 = 5;
var char5 = '5';
// This comparison triggers type conversion
number1 == char1 // == true
// 'triple equals' checks type and value
letterA === charA // == true
number5 === char5 // == false
|
// NOTE: the follow is BRAND NEW and implementations
// do not yet match the below semantics. The below is
// how it will work.
/*
* In Dart, == will check the following, in order:
* 1) if x === y then return true (=== is identity).
* Otherwise:
* 2) if either x or y is null, return false. Otherwise
* 3) return the result of x.equals(y)
* (pending: might become eq())
*/
/*
* This means:
* a) use x == null instead of x === null
* b) there's almost no reason to every use === or !==
* c) when implementing equals() you don't have to worry
* about manually checking for null arg
* d) you can't define your own type that considers itself
* equal to null
* e) null == null
*/
// therefore, the following code will work:
var letterA = 'A';
var charA = new String.fromCharCodes([65]);
// String defines equals() as
// 'same character codes in same order'
letterA == charA // == true
// However, the following is different than JavaScript
var number5 = 5;
var char5 = '5';
number1 != char1 // == true, because of different types
|
var charcodeA = 'A'; // integer equal to UNICODE
// codepoint of 'A'
var letterA = "A";
var charA = String.fromCharCode(65);
// letterA and charA are strings
// but unicodeA is an integer:
letterA == charA // == true
charcodeA == charA // == false, different types
// Similarly...
var number5 = 5;
var char5 = "5"; // note, string
// This comparison does not trigger
// type conversion:
number1 == char1; // == false
|
Functions
Function definition |
function fn() { return 'Hello'; }
fn(); // == 'Hello'
(function(){})() // == returns undefined
|
// Like JavaScript, use the 'return' keyword in a function
// definition to return a value.
fn() { return 'Hello'; }
fn(); // == 'Hello'
// A function with no return value returns null.
((){})(); // == returns null
// if the body of the function is returning
// a single expression,
// this is the short form
fn() => true;
|
function fn() { return "Hello"; }
fn(); // == 'Hello'
(function(){})() // == returns undefined
|
Assign a function to a variable, anonymous functions |
var loudify = function(msg) {
return msg.toUpperCase();
}
loudify('not gonna take it anymore');
// == NOT GONNA TAKE IT ANYMORE
|
var loudify = (msg) => msg.toUpperCase();
loudify('not gonna take it anymore');
// == NOT GONNA TAKE IT ANYMORE
|
// TIScript has three forms of
// defining anonymous functions,
// 1. Single expression function:
var loudify1 = : msg : msg.toUpperCase();
// 2. Block of expressions function:
var loudify2 = : msg { return msg.toUpperCase(); }
// 3. Statndard JS way:
var loudify3 = function(msg)
{ return msg.toUpperCase(); }
loudifyN("not gonna take it anymore");
// == NOT GONNA TAKE IT ANYMORE
|
Optional parameters |
function fn(a, b, c) { return c; };
fn(1) // == undefined
fn(1, 2, 3) // == 3
|
fn(a, b, c) => c;
fn(1); // ERROR: NoSuchMethodException
fn(1, 2, 3); // == 3
// Dart specifies optional parameters with square braces
fn(a, [b, c]) => c;
fn('a'); // == null
|
// Same as in JS
function fn(a, b, c) { return c; };
fn(1) // == undefined
fn(1, 2, 3) // == 3
|
Default parameters |
function send(msg, rate) {
rate = rate || 'First Class';
return msg + " was sent via " + rate;
}
send('hello')
// == 'hello was sent via First Class'
send("I'm cheap", '4th class')
// == "I'm cheap was sent via 4th class
|
send(msg, [rate='First Class']) {
return '${msg} was sent via ${rate}';
}
send('hello');
// == 'hello was sent via First Class'
send("I'm cheap", '4th class');
// == "I'm cheap was sent via 4th class"
|
// JavaScript version will work as it is.
// As also this one:
function send(msg, rate = "First Class") {
return String.$({msg} was sent via {rate});
}
send("hello")
// == 'hello was sent via First Class'
send("I'm cheap", "4th class")
// == "I'm cheap was sent via 4th class
|
Named parameters |
// JavaScript does not have
// native support for named parameters
|
send(msg, [rate='First Class']) {
return '${msg} was sent via ${rate}';
}
// you can use named parameters
// if the argument is optional
send("I'm cheap", rate:'4th class');
// == "I'm cheap was sent via 4th class"
|
// TIScript has special notation for
// calling functions that accept single
// object parameter:
function send(params) {
var rate = params.rate || "First Class";
return String.$({params.msg} sent {rate});
}
// Short form - call-with-object:
send {msg:"I'm cheap",rate:"4th class"};
|
Variable number of arguments |
function superHeroes() {
for (var i = 0; i < arguments.length; i++) {
console.log("There's no stopping "
+ arguments[i]);
}
}
superHeroes('UberMan',
'Exceptional Woman',
'The Hunk');
|
// Dart does not support
// variable numbers of arguments
|
// If last parameter is marked by '..'
// then it will take array of values passed:
function superHeroes(msg, heroes..) {
for (var hero in heroes)
stdout.println(msg, hero);
}
superHeroes(
"There's no stopping",
"UberMan",
"Exceptional Woman",
"The Hunk");
|
Iterators
For loops for lists |
var colors = ['red', 'orange', 'green'];
for (var i = 0; i < colors.length; i++) {
console.log(colors[i]);
}
|
var colors = ['red', 'orange', 'green'];
for (var i = 0; i < colors.length; i++) {
print(colors[i]);
}
|
var colors = ["red", "orange", "green"];
for (var i = 0; i < colors.length; i++)
stdout.println(colors[i]);
|
For-in loops |
var fruits = ['orange', 'apple', 'banana'];
// 'in' notation in JavaScript returns the
// indices of the array, not the values
for (var i in fruits) {
console.log(fruits[i]);
}
|
var fruits = ['orange', 'apple', 'banana'];
// 'in' notation in Dart returns the element
// of the list, not the index
for (var fruit in fruits) {
print(fruit);
}
|
var fruits = ['orange', 'apple', 'banana'];
// 'in' notation in TIScript returns the
// element of the list, not the index
for (var fruit in fruits)
stdout.println(fruit);
// If indexes are needed then use this form
for (var (i,fruit) in fruits)
stdout.$({i}. {fruit});
|
For-in loops for objects/maps |
var data = { … };
for (var key in data) {
console.log('key', key);
console.log('value', data[key]);
}
|
var data = { … };
for (var key in data.getKeys()) {
print('$key, ${data[key]}');
}
// Alternatively, the forEach loop
// is a method on a Map in Dart.
data.forEach((key, value){
print('${key}, ${value}');
});
|
//JavaScript code will work as it is in TIscript
//And to enumerate keys and values
//at the same time use this form
for (var (key,val) in data) {
stdout.print("key", key);
stdout.println("value", val);
}
|
Closures and counters in loop |
var callbacks = [];
// A closure must be used to preserve the
// return for each function at each step of
// the loop. Otherwise every entry in callbacks
// will return 2;
for (var i = 0; i < 2; i++) {
(function(_i) {
callbacks.push(function() {
return _i;
});
})(i);
}
// Without the internal closure, the result is 2
callbacks[0]() // == 0
// ECMAScript 6 can support this with the use
// of blocks
let callbacks = [];
for (let i = 0; i < 10; i++) {
let j = i;
callbacks.push(function() { print(j) });
}
|
// Dart doesn't reuse and close over the same
// loop variable in each iteration
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks[0]() // == 0
|
var callbacks = [];
// A closure must be used to preserve the return for
// each function at each step of the loop. Otherwise
// every entry in callbacks will return 2;
for (var i = 0; i < 2; i++)
(:_i:callbacks.push(::_i))(i);
// Without the internal closure, the result is 2
callbacks[0]() // == 0
|
Classes
Define |
function Person() {
this.name = null;
};
Person.prototype.greet = function() {
return 'Hello, ' + this.name;
}
|
class Person {
var name;
greet() => 'Hello, $name';
}
|
class Person {
function this() // constructor
{ this.name = null; }
function greet()
{ return String.$(Hello,{this.name});
}
|
Constructor with parameter |
function Person(name) {
this.name = name;
};
|
class Person {
var name;
Person(name) {
this.name = name;
}
}
// shorter alternative
class Person {
var name;
// parameters prefixed by 'this.' will
// assign to instance variables automatically
Person(this.name);
}
|
class Person {
function this(name)
{ this.name = name; }
}
|
Instantiate |
var person = new Person();
|
var person = new Person();
|
var person = new Person();
|
Reflection |
var name = 'Bob';
typeof name // == 'String'
|
// There currently is no way to get the class of an
// object. Reflection support coming soon.
|
var name = "Bob";
typeof name; // == #string
name.prototype === String; // true
name instanceof String; // true
|
Check the type |
var name = 'Bob';
name instanceof String // == true
(!(name instanceof Number)) // == true
|
var name = 'Bob';
name is String // == true
name is! int // == true
|
var name = "Bob";
name instanceof String; // == true
name !instanceof Integer; // == true
|
Subclass |
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return 'Hello, ' + this.name;
}
function Employee(name, salary) {
Person.call(this, name);
this.salary = salary;
}
Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
Employee.prototype.grantRaise = function(percent){
this.salary = (this.salary * percent).toInt();
}
|
class Person {
var name;
Person(this.name);
greet() => 'Hello, $name';
}
class Employee extends Person {
var salary;
Employee(name, this.salary) : super(name);
grantRaise(percent) {
salary = (salary * percent).toInt();
}
}
|
class Person {
function this(name) { this.name = name; }
function greet() {
return String.$(Hello, {name});
}
class Employee: Person {
function this(name, salary) {
super(name); // call of ctor of super class
this.salary = salary;
}
function grantRaise(percent) {
this.salary
= (this.salary * percent).toInteger();
}
}
|
Runtime program manipulation
eval |
eval('alert("hello from eval")');
|
// Dart doesn't support eval(). This is not a bug.
|
var script = "alert(\"hello from eval\")";
// general case:
eval(script);
// controlled eval:
eval(script,
{
alert: function() {/*nothing!*/},
self: null,
document: null,
window: null
});
// the object passed serves role of global
// namespace inside the script.
|
Adding method to class or namespace |
String.prototype.startsWith = function(beginning){
var head = this.substr(0, beginning.length);
return head == beginning;
}
|
// Dart doesn't support changing a class after
// the program has been compiled
|
// adding method startsWith to all strings:
function String.startsWith(head)
{
return this.indexOf(head) == 0;
}
function String.endsWith(tail)
{
return this.indexOf(tail) ==
this.length - tail.length;
}
|
Operator overloading |
// not supported
|
class Point {
var x, y;
Point(this.x, this.y);
operator + (Point p) => new Point(x + p.x, y + p.y);
toString() => 'x:$x, y:$y';
}
main() {
var p1 = new Point(1, 1);
var p2 = new Point(2, 2);
var p3 = p1 + p2;
print(p3);
}
|
// not supported yet
|
Finding elements in DOM |
document.getElementById('main')
document.querySelector('#main')
|
document.query('#main')
|
self.select("#main")
self.$(#main) // stringizer form of the select
|
Find one element by class |
document.getElementsByClassName('visible')[0]
document.querySelector('.visible')
|
document.query('.visible')
|
self.select(".visible")
self.$(.visible)
|
Find all elements with class |
document.getElementsByClassName('visible')
document.querySelectorAll('.visible')
|
document.queryAll('.visible')
|
// Methods return array of element references:
self.selectAll(".visible");
self.$$(.visible);
|
Find elements by tag, name and class |
document
.getElementById('main')
.getElementsByTagName('div')[0]
.getElementsByClassName('visible')
document.querySelectorAll
('#main div:first-of-type .visible')
|
document.queryAll
('#main div:first-of-type .visible')
|
self.selectAll
("#main div:first-of-type .visible")
self.$$(#main div:first-of-type .visible)
|
Get sub-element by selector |
// no such feature,
// consider use jQuery find() method.
|
// no such feature
|
elem.selectAll("li");
elem.$$(li);
// in select's the :root selector
// designates "lookup root" so to
// select immediate childern of the element
// use one of these:
elem.selectAll(":root > li");
elem.$$(:root > li);
|
Iterate over list of elements |
for (var i = 0, el; el = els[i]; i++) {
doSomethingWithEl(el);
}
|
for (var el in els) {
doSomethingWithEl(el);
}
|
for (var el in els) {
doSomethingWithEl(el);
}
|
Access the first child |
elem.firstChild()
|
elem.nodes[0]
|
// Element is an array of its children, so:
elem[0]
|
Test if an element has children elements |
elem.hasChildNodes() // not exactly actually
|
!elem.nodes.isEmpty()
|
// Element is an array of its children, so:
elem.length > 0;
|
Manipulating DOM
Create an element |
var element = document.createElement('div');
|
#import('dart:html');
var element = new Element.tag('div');
|
var element = new Element("div");
|
Set element content |
var element = document.createElement('p');
element.innerHTML
= 'brown <em>fox</em>';
|
var element =
new Element.html('<p>brown <em>fox</em></p>');
|
var element = new Element("p");
parent.append(element);
element.html = "<p>brown <em>fox</em></p>"; // or
element.$content(<p>brown <em>fox</em></p>);
|
Add an element to a parent |
element.appendChild(newElement);
|
element.nodes.add(newElement);
|
element.append(newElement);
element.prepend(newElement);
element.insert(12,newElement);
element.$append(<p>...</p>);
element.$prepend(<p>...</p>);
// add the markup after the element
element.$after(<p>...</p>);
// insert the markup before the element
element.$before(<p>...</p>);
|
Remove an element |
element.parentNode.removeChild(element);
|
element.remove();
|
element.remove();
|
Regular expressions |
var email = 'test@example.com';
email.match(/@/)
// == ['@']
|
var email = 'test@example.com';
(new RegExp(@'o')).firstMatch(email)
// == Match Object
|
var email = 'test@example.com';
email.match(/@/)
// == ['@']
|
var invalidEmail = 'f@il@example.com';
invalidEmail.match(/@/g)
// == ['@', '@']
|
var invalidEmail = 'f@il@example.com';
(new RegExp(@'o')).allMatches(invalidEmail)
// == Iterable Match Object
|
var invalidEmail = 'f@il@example.com';
invalidEmail.match(/@/g)
// == ['@', '@']
|
Exceptions
Throw an exception |
throw new Error("Intruder Alert!!");
// or...
throw "Intruder Alert!!";
|
throw new Exception("Intruder Alert!!");
|
throw "Intruder Alert!!";
|
Catch an exception |
try {
undefinedFunction();
} catch(e) {
if (e instanceof ReferenceError) {
console.log(
'You called a function that does not exist');
}
} finally {
console.log(
'This runs even if an exception is thrown');
}
|
try {
Math.parseInt("three");
} catch(BadNumberFormatException bnfe) {
print("Ouch! Detected: $bnfe");
} catch(var e) {
print("If some other type of exception");
} finally {
print("This runs even if an exception is thrown");
}
|
try {
undefinedFunction();
} catch(e) {
stderr.println(e);
} finally {
stdout.println(
"This runs even if an exception is thrown");
}
|
Event handling
Attach an event handler |
element.addEventListener(
'click', handleOnClick, false);
|
element.on.click.add(handleOnClick);
|
element.onClick = handleOnClick;
// or
element.subscribe(
handleOnClick,
Event.BEHAVIOR_EVENT,
Event.BUTTON_CLICK);
// or by using decorators:
@click @on "button#some" :
{
// do some on button#some click
}
|
Remove an event handler |
element.removeEventListener(
'click', handleOnClick, false);
|
element.on.click.remove(handleOnClick);
|
element.onClick = undefined;
// or
element.unsubscribe(handleOnClick);
|
Timing
Schedule a future event |
setTimeout(function() { … }, 500);
|
window.setTimeout(() { … }, 500);
|
element.timer(500, function() {...} );
//the function will be called with 'this'
//set to the element.
|
Measure the execution time of a function |
function measure(fn) {
var start = Date.now();
fn();
return Date.now() - start;
}
|
measure(fn) {
Stopwatch watch = new Stopwatch.start();
fn();
return watch.elapsedInMs();
}
|
function measure(fn) {
// Date.ticks() - milliseconds
// since system start
var start = Date.ticks();
fn();
return Date.ticks() - start;
}
|
HTML attributes
Get HTML attribute |
element.getAttribute('href')
|
element.attributes['href']
|
element.attributes["href"]
// or
element.@["href"]
|
element.setAttribute('playable', true);
|
element.attributes['playable'] = true;
|
element.attributes["playable"] = true;
//or
element.@["playable"] = true;
|
Remove HTML attribute |
element.removeAttribute('playable');
|
element.attributes.remove('playable');
|
element.attributes["playable"] = undefined;
|
Check for HTML attribute existence |
element.hasAttribute('href')
|
element.attributes.contains('href')
|
element.attributes["playable"] !== undefined;
|
CSS classes
Add CSS class |
element.className += ' new-class';
element.classList.add('new-class');
|
element.classes.add('new-class');
|
element.attributes.addClass("new-class");
|
Remove CSS class |
element.className
= element.className.replace(/ new-class/, '');
element.classList.remove('new-class');
|
element.classes.remove('new-class');
|
element.attributes.removeClass("new-class");
|
AJAX
Request data |
var client = new XMLHttpRequest;
client.onreadystatechange = function() {
if (this.readyState == 4) {
processData(this);
}
}
client.open('GET', 'data.json');
client.send();
function processData(request) {
console.log('data received: '
+ request.responseText);
}
|
// The getTEMPNAME method name will be changed.
var xhr = new XMLHttpRequest.getTEMPNAME(
"/data.json", (req) {
print("data received: ${req.responseText}");
});
|
function onDataArrived(data) {
// data is an object - already parsed JSON
this.html = String.printf("Got data %V", data);
// String.printf("%V", data) is
// exactly JSON.stringize()
}
// sends HTTP GET request to the server,
// parses response and calls onDataArrived
// when ready:
element.request(
onDataArrived, #get, "/data.json" );
// While the request is executing the element
// gets :busy CSS state flag. So you can define
// that spinning thing on the element.
|
jQuery features
React to document finishing loading |
$(document).ready(function(){
console.log('Content is loaded');
});
|
window.on.contentLoaded.add(
(e) => print('Content is loaded');
);
// However, main() will normally run
// after DOMContentLoaded in Dartium,
// and soon Frog.
|
function self.ready()
{
stdout.println("Content is loaded");
}
// in Sciter script code is executed only
// when DOM is complete.
// self.ready() is called after
// DOM elements will get their styles and
// all behaviors are attached.
|
Element lookup |
var els = jQuery('div');
|
List els = document.query('div');
|
var el = $("div"); // first
var els = $$("div"); // all
|
Nearest parent lookup |
var nearestUL = els.parent('ul');
|
// no such feature
|
var nearestUL = el.selectParent("ul"); // or
var nearestUL = el.$p(ul);
|
Test if an element matches a selector |
// true if element is a <li> inside
// an unordered list
el.is('ul > li')
|
// no such feature
|
// true if element is a <li> inside
// an unordered list
el.$is(ul > li)
|
Node creation |
var pic = $('<img/>');
pic.addClass('avatar');
pic.toggleClass('main');
pic.attr('src', 'myPic.jpg');
$('body').append(pic);
|
var pic = new Element.tag('img');
pic.classes.add('avatar');
pic.classes.toggle('main');
pic.attributes['src'] = 'myPic.jpg';
document.body.nodes.add(pic);
|
$(body).$append(<img src='mypic.jpg'
class='avatar main' >);
|
Event handling |
$('a.person').click(function(e){
console.log('Person clicked');
})
|
document.queryAll('a.person').forEach((el) {
el.on.click.add((e) => print('Person clicked'));
});
// coming soon!!
document.queryAll('a.person')
.on.click.add((e) => print('Person clicked'));
|
function handler()
{ stdout.println("Person clicked"); }
for(var el in $$(a.person))
el.onClick = handler;
|
Relative nodes |
var myNode = $('div:first');
var parent = myNode.parent();
var next = myNode.next();
|
var myNode = document.query('div');
var parent = myNode.parent;
var next = myNode.nextNode;
|
var myNode = $(div);
var parent = myNode.parent;
var next = myNode.next;
|
Children |
var myNode = $('div:first');
// If there are children, remove them
if (!myNode.is(':empty')) {
myNode.empty();
}
|
var myNode = document.query('div');
if (!myNode.nodes.isEmpty()) {
myNode.nodes.clear();
}
|
var myNode = $(div);
// If there are children, remove them
if (!myNode.$is(:empty))
myNode.clear();
// or
if (myNode.length)
myNode.clear();
|
Clone |
var clonedElement = $('#about').clone();
|
var clonedElement
= document.query('#about').clone(true);
|
var clonedElement = $(#about).clone();
|
Scripting behaviors
Declaring Behavior class |
// No direct equivalent,
// consider use of XUL in FF.
|
// No such feature at all?
|
class ButtonWithPopup : Behavior
{
// on mouse down show contained
// <menu> element as a popup window below (2)
// this element:
function onMouse(evt) {
if(evt.type == Event.MOUSE_DOWN) {
this.popup( this.$(menu), 2);
return true; // event handled, done
}
}
}
|
Assigning behavior to all matched DOM elements |
In CSS using becss:
button.popup-menu
{
binding:url(button-with-popup.xul);
}
// in script
button.style.binding = "button-with-popup.xul";
|
// No such feature at all?
|
// In CSS:
button.popup-menu
{
prototype: ButtonWithPopup url(button-with-popup.tis);
}
// In script (using runtime subclassing)
for(var btn in $$(button.popup-menu))
btn.prototype = ButtonWithPopup;
|