js: DOM API. Part 1 (#12296)
parent
0ff23eeb74
commit
cfecb62299
|
@ -0,0 +1,7 @@
|
||||||
|
Drawing with mouse events using DOM API. Adopted from MDN examples.
|
||||||
|
|
||||||
|
# Compiling
|
||||||
|
```
|
||||||
|
v -b js_browser examples/js_dom_draw/draw.v
|
||||||
|
```
|
||||||
|
Then you can open `index.html` with your favourite browser.
|
|
@ -0,0 +1,72 @@
|
||||||
|
import jsdom
|
||||||
|
import jsdom.ctx
|
||||||
|
|
||||||
|
fn get_2dcontext(canvas jsdom.IElement) ?ctx.CanvasRenderingContext2D {
|
||||||
|
if canvas is jsdom.HTMLCanvasElement {
|
||||||
|
c := canvas.get_context('2d')
|
||||||
|
match c {
|
||||||
|
ctx.CanvasRenderingContext2D {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return error('cannot fetch 2d context')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return error('canvas is not an HTMLCanvasElement')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_line(context ctx.CanvasRenderingContext2D, x1 int, y1 int, x2 int, y2 int) {
|
||||||
|
context.begin_path()
|
||||||
|
context.set_stroke_style('black')
|
||||||
|
context.set_line_width(1)
|
||||||
|
context.move_to(x1, y1)
|
||||||
|
context.line_to(x2, y2)
|
||||||
|
context.stroke()
|
||||||
|
context.close_path()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
document := jsdom.document
|
||||||
|
|
||||||
|
elem := document.get_element_by_id('myButton') ?
|
||||||
|
elemc := document.get_element_by_id('myCanvas') or { panic('no canvas') }
|
||||||
|
canv := jsdom.get_html_canvas_element(elemc) or { panic('expected canvas') }
|
||||||
|
|
||||||
|
context := get_2dcontext(canv) or { panic('wow') }
|
||||||
|
mut drawing := false
|
||||||
|
mut x := int(0)
|
||||||
|
mut y := int(0)
|
||||||
|
canv.add_event_listener('mousedown', fn [mut drawing, mut x, mut y] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
||||||
|
drawing = true
|
||||||
|
if event is jsdom.MouseEvent {
|
||||||
|
x = event.offset_x()
|
||||||
|
y = event.offset_y()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
canv.add_event_listener('mousemove', fn [context, drawing, mut x, mut y] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
||||||
|
if drawing {
|
||||||
|
if event is jsdom.MouseEvent {
|
||||||
|
draw_line(context, x, y, event.offset_x(), event.offset_y())
|
||||||
|
x = event.offset_x()
|
||||||
|
y = event.offset_y()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
jsdom.window.add_event_listener('mouseup', fn [context, mut drawing, mut x, mut y] (_ jsdom.IEventTarget, event jsdom.IEvent) {
|
||||||
|
if drawing {
|
||||||
|
if event is jsdom.MouseEvent {
|
||||||
|
draw_line(context, x, y, event.offset_x(), event.offset_y())
|
||||||
|
}
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
drawing = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
elem.add_event_listener('click', fn [context, canv] (_ jsdom.IEventTarget, _ jsdom.IEvent) {
|
||||||
|
context.clear_rect(0, 0, canv.width(), canv.height())
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<body class="main">
|
||||||
|
<title>Drawing with mouse events</title>
|
||||||
|
<input type="button" id="myButton" value="Clear canvas">
|
||||||
|
<canvas style="border: 1px solid black;" width="720" height="480" id="myCanvas"></canvas>
|
||||||
|
<script type="text/javascript" src="draw.js"></script>
|
||||||
|
|
||||||
|
</body>
|
|
@ -917,3 +917,10 @@ pub fn (_rune string) utf32_code() int {
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tos(jsstr JS.String) string {
|
||||||
|
res := ''
|
||||||
|
#res.str = jsstr
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
// Wrapper around 2d context and WebGL APIs
|
||||||
|
|
||||||
|
module ctx
|
||||||
|
|
||||||
|
pub struct ContextAttributes {
|
||||||
|
pub:
|
||||||
|
alpha bool
|
||||||
|
desynchronized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PowerPreference {
|
||||||
|
default_
|
||||||
|
high_performance
|
||||||
|
low_performance
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WebGLAttributes {
|
||||||
|
pub:
|
||||||
|
alpha bool
|
||||||
|
desynchronized bool
|
||||||
|
antialias bool
|
||||||
|
depth bool
|
||||||
|
fail_if_major_perf_caveat bool
|
||||||
|
power_preference PowerPreference
|
||||||
|
premultiplied_alpha bool
|
||||||
|
preserve_drawing_buffer bool
|
||||||
|
stencil bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NoneContext {}
|
||||||
|
|
||||||
|
pub type ContextResult = CanvasRenderingContext2D | NoneContext | WebGLRenderingContext
|
|
@ -0,0 +1,67 @@
|
||||||
|
module ctx
|
||||||
|
|
||||||
|
struct JS.CanvasRenderingContext2D {
|
||||||
|
mut:
|
||||||
|
lineWidth JS.Number
|
||||||
|
lineCap JS.String
|
||||||
|
lineJoin JS.String
|
||||||
|
miterLimit JS.Number
|
||||||
|
lineDashOffset JS.Number
|
||||||
|
font JS.String
|
||||||
|
textAlign JS.String
|
||||||
|
textBaseline JS.String
|
||||||
|
direction JS.String
|
||||||
|
fillStyle voidptr
|
||||||
|
strokeStyle voidptr
|
||||||
|
shadowBlur JS.Number
|
||||||
|
shadowColor JS.String
|
||||||
|
shadowOffsetX JS.Number
|
||||||
|
shadowOffsetY JS.Number
|
||||||
|
globalAlpha JS.Number
|
||||||
|
globalCompositeOperation JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CanvasRenderingContext2D {
|
||||||
|
ctx JS.CanvasRenderingContext2D [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type StrokeStyle = string
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) begin_path() {
|
||||||
|
#ctx.ctx.beginPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) set_stroke_style(style StrokeStyle) {
|
||||||
|
#ctx.ctx.strokeStyle = style.str;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) line_width() int {
|
||||||
|
res := 0
|
||||||
|
#res.val = ctx.ctx.lineWidth
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) set_line_width(width int) {
|
||||||
|
#ctx.ctx.lineWidth = width.val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) move_to(x int, y int) {
|
||||||
|
#ctx.ctx.moveTo(x.val,y.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) line_to(x int, y int) {
|
||||||
|
#ctx.ctx.lineTo(x.val,y.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) stroke() {
|
||||||
|
#ctx.ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) close_path() {
|
||||||
|
#ctx.ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ctx CanvasRenderingContext2D) clear_rect(x int, y int, width int, height int) {
|
||||||
|
#ctx.ctx.clearRect(x.val,y.val,width.val,height.val);
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
module ctx
|
||||||
|
|
||||||
|
pub struct WebGLRenderingContext {}
|
|
@ -0,0 +1,230 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub struct JS.Document {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Document {
|
||||||
|
Node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Location {
|
||||||
|
mut:
|
||||||
|
loc JS.Location [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) str() string {
|
||||||
|
mut res := 'Location{\n'
|
||||||
|
res += ' origin: $l.origin()\n'
|
||||||
|
res += ' href: $l.href()\n'
|
||||||
|
res += ' protocol: $l.protocol()\n'
|
||||||
|
res += ' host: $l.host()\n'
|
||||||
|
res += ' hostname: $l.hostname()\n'
|
||||||
|
res += ' port: $l.port()\n'
|
||||||
|
res += ' pathname: $l.pathname()\n'
|
||||||
|
res += ' search: $l.search()\n'
|
||||||
|
res += ' hash: $l.hash()\n'
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) assign(url string) {
|
||||||
|
#l.val.loc.assign(url.str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) reload() {
|
||||||
|
#l.loc.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) replace(url string) {
|
||||||
|
#l.val.loc.replace(url.str)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) origin() string {
|
||||||
|
return tos(l.loc.origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) href() string {
|
||||||
|
return tos(l.loc.href)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_href(href string) {
|
||||||
|
l.loc.href = href.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) protocol() string {
|
||||||
|
return tos(l.loc.protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_protocol(protocol string) {
|
||||||
|
l.loc.protocol = protocol.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) host() string {
|
||||||
|
return tos(l.loc.host)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_host(host string) {
|
||||||
|
l.loc.host = host.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) hostname() string {
|
||||||
|
return tos(l.loc.hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_hostname(hostname string) {
|
||||||
|
l.loc.hostname = hostname.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) port() string {
|
||||||
|
return tos(l.loc.port)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_port(port string) {
|
||||||
|
l.loc.port = port.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) pathname() string {
|
||||||
|
return tos(l.loc.pathname)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_pathname(pathname string) {
|
||||||
|
l.loc.pathname = pathname.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) hash() string {
|
||||||
|
return tos(l.loc.hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_hash(hash string) {
|
||||||
|
l.loc.hash = hash.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (l Location) search() string {
|
||||||
|
return tos(l.loc.search)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut l Location) set_search(search string) {
|
||||||
|
l.loc.search = search.str
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.Location {
|
||||||
|
pub:
|
||||||
|
origin JS.String
|
||||||
|
mut:
|
||||||
|
href JS.String
|
||||||
|
protocol JS.String
|
||||||
|
host JS.String
|
||||||
|
hostname JS.String
|
||||||
|
port JS.String
|
||||||
|
pathname JS.String
|
||||||
|
search JS.String
|
||||||
|
hash JS.String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (doc Document) active_element() Element {
|
||||||
|
mut elem := Element{}
|
||||||
|
#elem.node = doc.node.activeElement;
|
||||||
|
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (doc Document) get(name string) ?Element {
|
||||||
|
mut elem := Element{}
|
||||||
|
#elem.node = doc.node[name.str];
|
||||||
|
#console.log(elem.node)
|
||||||
|
#if (elem.node === null || elem.node === undefined) return new $ref(new Option({state: new byte(2),err: none__}));
|
||||||
|
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
|
// location returns URI of the document
|
||||||
|
pub fn (doc Document) location() Location {
|
||||||
|
mut loc := Location{}
|
||||||
|
#loc.loc = doc.node.location;
|
||||||
|
|
||||||
|
return loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// get_title returns current title of document
|
||||||
|
pub fn (doc Document) get_title() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = doc.node.title;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// set_title updates document title
|
||||||
|
pub fn (doc Document) set_title(title string) {
|
||||||
|
#doc.node.title = title.str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// url returns document location as a string
|
||||||
|
pub fn (doc Document) url() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = doc.node.URL;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// node casts `Document` back to `Node`.
|
||||||
|
pub fn (doc Document) node() Node {
|
||||||
|
node := Node{}
|
||||||
|
#node.node = doc.node
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (doc Document) get_element_by_id(id string) ?IElement {
|
||||||
|
mut elem := IElement(Element{})
|
||||||
|
found := false
|
||||||
|
#let tmp = doc.node.getElementById(id.str);
|
||||||
|
#elem = jsdom__dispatch_event_target(tmp);
|
||||||
|
#found.val = !(elem.node == null)
|
||||||
|
if !found {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DocumentPrepend = Node | string
|
||||||
|
|
||||||
|
pub fn (doc Document) prepend(nodes_or_strings ...DocumentPrepend) ? {
|
||||||
|
caught := false
|
||||||
|
err := ''
|
||||||
|
#try {
|
||||||
|
|
||||||
|
for elem in nodes_or_strings {
|
||||||
|
match elem {
|
||||||
|
string {
|
||||||
|
#doc.node.prepend(elem.str)
|
||||||
|
}
|
||||||
|
Node {
|
||||||
|
#doc.node.prepend(elem.node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#} catch (e) { caught.val = true; err.str = e.toString(); }
|
||||||
|
if caught {
|
||||||
|
return error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (doc Document) create_element(tag_name string) Element {
|
||||||
|
elem := Element{}
|
||||||
|
#elem.node = doc.node.createElement(tag_name.str)
|
||||||
|
|
||||||
|
return elem
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_document() Document {
|
||||||
|
doc := Document{}
|
||||||
|
#doc.node = document;
|
||||||
|
|
||||||
|
return doc
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem Document) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
// DOM API for JS backend
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
[heap]
|
||||||
|
pub struct JS.Node {
|
||||||
|
baseURI JS.String [noinit]
|
||||||
|
childNodes JS.NodeList [noinit]
|
||||||
|
firstChild voidptr [noinit]
|
||||||
|
isConnected JS.bool [noinit]
|
||||||
|
lastChild voidptr [noinit]
|
||||||
|
nextSibling voidptr [noinit]
|
||||||
|
nodeName JS.String [noinit]
|
||||||
|
nodeType NodeType [noinit]
|
||||||
|
nodeValue voidptr [noinit]
|
||||||
|
ownerDocument JS.Document [noinit]
|
||||||
|
parentNode voidptr [noinit]
|
||||||
|
parentElement JS.Element [noinit]
|
||||||
|
previousSibling voidptr [noinit]
|
||||||
|
textContext voidptr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.NodeList {
|
||||||
|
pub mut:
|
||||||
|
length JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NodeType {
|
||||||
|
element = 1
|
||||||
|
attribute = 2
|
||||||
|
text = 3
|
||||||
|
cdata_section = 4
|
||||||
|
entity_reference = 5
|
||||||
|
entity = 6
|
||||||
|
processing_instruction = 7
|
||||||
|
comment = 8
|
||||||
|
document = 9
|
||||||
|
document_type = 10
|
||||||
|
document_fragment = 11
|
||||||
|
notation = 12
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Node {
|
||||||
|
node JS.Node [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n Node) typ() NodeType {
|
||||||
|
return n.node.nodeType
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEventTarget interface is implemented by objects that can receive events and may have listeners for them.
|
||||||
|
// In other words, any target of events implements the three methods associated with this interface.
|
||||||
|
// TODO: remove_event_listener and dispatch_event
|
||||||
|
pub interface IEventTarget {
|
||||||
|
add_event_listener(event string, cb EventCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The DOM Node interface is an abstract base class upon which many other DOM API objects are based, thus
|
||||||
|
// letting those object types to be used similarly and often interchangeably. As an abstract class,
|
||||||
|
// there is no such thing as a plain Node object. All objects that implement Node functionality are based on one of its subclasses.
|
||||||
|
// Most notable are Document, Element, and DocumentFragment.
|
||||||
|
pub interface INode {
|
||||||
|
IEventTarget
|
||||||
|
typ() NodeType
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem Node) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) is_(ty NodeType) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = n.node.nodeType == ty
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) document() ?Document {
|
||||||
|
res := Document{}
|
||||||
|
if n.is_(.document) {
|
||||||
|
#res.node = n.node
|
||||||
|
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) element() ?Element {
|
||||||
|
res := Element{}
|
||||||
|
if n.is_(.element) {
|
||||||
|
#res.node = n.node
|
||||||
|
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) append_child(child INode) {
|
||||||
|
#n.node.appendChild(child.node)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) clone_node(deep ...int) INode {
|
||||||
|
cloned := Node{}
|
||||||
|
if deep.len == 0 {
|
||||||
|
#cloned.node = n.node.cloneNode()
|
||||||
|
} else {
|
||||||
|
#cloned.node = n.node.cloneNode(deep.arr.get(new int(0)).val)
|
||||||
|
}
|
||||||
|
return cloned
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) contains(other INode) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = n.node.contains(other.node)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) get_root_node() INode {
|
||||||
|
root := Node{}
|
||||||
|
#root.node = n.node.getRootNode()
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) has_child_nodes() bool {
|
||||||
|
res := false
|
||||||
|
#res.val = n.node.hasChildNodes()
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) insert_before(new_node INode, reference_node INode) Node {
|
||||||
|
inserted := Node{}
|
||||||
|
#inserted.node = n.node.insertBefore(new_node.node,reference_node.node)
|
||||||
|
|
||||||
|
return inserted
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn (x Node) == (y Node) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = x.node.isEqualNode(y.node)
|
||||||
|
|
||||||
|
return res
|
||||||
|
}*/
|
||||||
|
|
||||||
|
pub fn (n INode) remove_child(child INode) {
|
||||||
|
#n.node.removeChild(child.node)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (n INode) replace_child(new_child INode, old_child INode) INode {
|
||||||
|
#old_child.node = n.node.replace_child(new_child.node,old_child.node)
|
||||||
|
|
||||||
|
return old_child
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.EventTarget {}
|
||||||
|
|
||||||
|
fn dispatch_event_target(target JS.EventTarget) IEventTarget {
|
||||||
|
mut ret := IEventTarget(Element{})
|
||||||
|
#if (target instanceof HTMLCanvasElement) { ret = new jsdom__HTMLCanvasElement({}); ret.node = target; }
|
||||||
|
#else if (target instanceof HTMLElement) { ret = new jsdom__HTMLElement({}); ret.node = target; }
|
||||||
|
#else if (target instanceof Window) { ret = new jsdom__Window({}); ret.node = target;}
|
||||||
|
#else if (target instanceof SVGElement) { ret = new jsdom__SVGElement({}); ret.node = target; }
|
||||||
|
#else if (target instanceof Element) { ret = new jsdom__Element({}); ret.node = target; }
|
||||||
|
#else if (target instanceof Document) { ret = new jsdom__Document({}); ret.node = target; }
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type EventCallback = fn (_ IEventTarget, _ IEvent)
|
||||||
|
|
||||||
|
pub const (
|
||||||
|
document = Document{}
|
||||||
|
window = Window{}
|
||||||
|
)
|
||||||
|
|
||||||
|
fn init() {
|
||||||
|
#jsdom__document.node = document;
|
||||||
|
#jsdom__window.node = window;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
// DOM API wrapper for JS backend
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub fn get_html_canvas_element(elem IElement) ?HTMLCanvasElement {
|
||||||
|
if elem is HTMLCanvasElement {
|
||||||
|
return *elem
|
||||||
|
} else {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub struct JS.DOMString {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.DOMTokenList {
|
||||||
|
length JS.Number
|
||||||
|
value JS.DOMString
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DOMTokenList {
|
||||||
|
list JS.DOMTokenList [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) len() int {
|
||||||
|
res := 0
|
||||||
|
#res.val = x.list.length;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) item(idx int) ?string {
|
||||||
|
res := ''
|
||||||
|
#let tmp = x.list.item(idx.list.val)
|
||||||
|
#if (tmp === undefined) return new Option({state: new byte(2),err: none__});
|
||||||
|
#res.val = tmp
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) contains(token string) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = x.list.contains(token.str);
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) add(tokens ...string) {
|
||||||
|
for token in tokens {
|
||||||
|
#x.list.add(token.str);
|
||||||
|
|
||||||
|
_ := token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) remove(tokens ...string) {
|
||||||
|
for token in tokens {
|
||||||
|
#x.list.remove(token.str);
|
||||||
|
|
||||||
|
_ := token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) replace(old_token string, new_token string) bool {
|
||||||
|
is_replaced := false
|
||||||
|
#is_replaced.val = x.list.replace(old_token.str,new_token.str);
|
||||||
|
|
||||||
|
return is_replaced
|
||||||
|
}
|
||||||
|
|
||||||
|
// supports returns true if the given `token` is in the associated attibute's supported tokens.
|
||||||
|
pub fn (x DOMTokenList) supports(token string) bool {
|
||||||
|
supports := false
|
||||||
|
#supports.val = x.list.supports(token.str)
|
||||||
|
|
||||||
|
return supports
|
||||||
|
}
|
||||||
|
|
||||||
|
// toggle removes a given token from the list and returns `false`. If token does not exist
|
||||||
|
// it is added and function returns `true`.
|
||||||
|
pub fn (x DOMTokenList) toggle(token string, force bool) bool {
|
||||||
|
res := false
|
||||||
|
#res.val = x.list.toggle(token.str, force.val);
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// entries returns array of all tokens in this token list
|
||||||
|
pub fn (x DOMTokenList) values() []string {
|
||||||
|
mut res := []string{}
|
||||||
|
#for (let [_,value] of x.list.entries()) array_push(res, new string(value));
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (x DOMTokenList) str() string {
|
||||||
|
mut fmt := 'DOMTokenList['
|
||||||
|
values := x.values()
|
||||||
|
for i, val in values {
|
||||||
|
fmt += '"' + val + '"'
|
||||||
|
if i != values.len - 1 {
|
||||||
|
fmt += ','
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt += ']'
|
||||||
|
return fmt
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub struct JS.Element {
|
||||||
|
classList JS.DOMTokenList
|
||||||
|
childElementCount JS.Number
|
||||||
|
className JS.String
|
||||||
|
clientHeight JS.Number
|
||||||
|
clientWidth JS.Number
|
||||||
|
clientTop JS.Number
|
||||||
|
clientLeft JS.Number
|
||||||
|
id JS.String
|
||||||
|
innerHTML JS.String
|
||||||
|
namespaceURI JS.String
|
||||||
|
outerHTML JS.String
|
||||||
|
scrollHeight JS.Number
|
||||||
|
scrollLeft JS.Number
|
||||||
|
scrollTop JS.Number
|
||||||
|
scrollWidth JS.Number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Element {
|
||||||
|
Node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (e Element) str() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = e.node + ''
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem Element) typ() NodeType {
|
||||||
|
return .element
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (e Element) class_name() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = e.node.className
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (e Element) class_list() DOMTokenList {
|
||||||
|
list := DOMTokenList{}
|
||||||
|
#list.list = e.node.classList
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// node casts `Element` back to `Node`.
|
||||||
|
pub fn (elem Element) node() Node {
|
||||||
|
node := Node{}
|
||||||
|
#node.node = elem.node
|
||||||
|
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem Element) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub interface IElement {
|
||||||
|
INode
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct HTMLElement {
|
||||||
|
Element
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem HTMLElement) typ() NodeType {
|
||||||
|
return .element
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem HTMLElement) access_key() string {
|
||||||
|
res := ''
|
||||||
|
#res.str = elem.node.accessKey;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut elem HTMLElement) set_access_key(key string) {
|
||||||
|
#elem.val.node.accessKey = key.str;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem HTMLElement) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub interface IEvent {
|
||||||
|
composed_path() []IEventTarget
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JS.Event {}
|
||||||
|
|
||||||
|
pub struct JS.MouseEvent {}
|
||||||
|
|
||||||
|
pub struct Event {
|
||||||
|
event JS.Event [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ev Event) composed_path() []IEventTarget {
|
||||||
|
mut composed := []IEventTarget{}
|
||||||
|
#ev.event.composedPath().forEach((item) => {
|
||||||
|
#array_push(composed, jsdom__dispatch_event())
|
||||||
|
#})
|
||||||
|
|
||||||
|
return composed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UIEvent {
|
||||||
|
Event
|
||||||
|
}
|
||||||
|
|
||||||
|
// detail returns `int` with detail about the event, depending on the event type.
|
||||||
|
pub fn (ev UIEvent) detail() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.detail
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MouseEvent {
|
||||||
|
UIEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// button returns the button number that was pressed (if applicable) when the mouse event was fired.
|
||||||
|
pub fn (ev MouseEvent) button() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.button;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// alt_key returns `true` if the `alt` key was down when the mouse event was fired.
|
||||||
|
pub fn (ev MouseEvent) alt_key() bool {
|
||||||
|
ret := false
|
||||||
|
#ret.val = ev.event.altKey;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// buttons returns the buttons being depressed (if any) when the mouse event was fired.
|
||||||
|
pub fn (ev MouseEvent) buttons() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.buttons;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// client_x returns the X coordinate of the mouse pointer in local coordinates.
|
||||||
|
pub fn (ev MouseEvent) client_x() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.clientX;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// client_y returns the Y coordinate of the mouse pointer in local coordinates.
|
||||||
|
pub fn (ev MouseEvent) client_y() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.clientY;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// ctrl_key returns `true` if the `ctrl` key was down when the mouse event was fired.
|
||||||
|
pub fn (ev MouseEvent) ctrl_key() bool {
|
||||||
|
ret := false
|
||||||
|
#ret.val = ev.event.ctrlKey;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// meta_key returns `true` if the `meta` key was down when the mouse event was fired.
|
||||||
|
pub fn (ev MouseEvent) meta_key() bool {
|
||||||
|
ret := false
|
||||||
|
#ret.val = ev.event.metaKey;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// movenet_x reaturns the X coordinate of the mouse pointer relative to the position of the last `mousemove` event.
|
||||||
|
pub fn (ev MouseEvent) movement_x() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.movementX;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// movenet_y reaturns the Y coordinate of the mouse pointer relative to the position of the last `mousemove` event.
|
||||||
|
pub fn (ev MouseEvent) movement_y() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.movementY;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// offset_x returns the X coordinate of the mouse pointer relative to the position of the padding edge of the target node.
|
||||||
|
pub fn (ev MouseEvent) offset_x() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.offsetX;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// offset_y reaturns the Y coordinate of the mouse pointer relative to the position of the padding edge of the target node.
|
||||||
|
pub fn (ev MouseEvent) offset_y() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = ev.event.offsetY;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ev MouseEvent) composed_path() []IEventTarget {
|
||||||
|
mut composed := []IEventTarget{}
|
||||||
|
#ev.event.composedPath().forEach((item) => {
|
||||||
|
#array_push(composed, jsdom__dispatch_event())
|
||||||
|
#})
|
||||||
|
|
||||||
|
return composed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AbortSignal {
|
||||||
|
Event
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (ev AbortSignal) composed_path() []IEventTarget {
|
||||||
|
mut composed := []IEventTarget{}
|
||||||
|
#ev.event.composedPath().forEach((item) => {
|
||||||
|
#array_push(composed, jsdom__dispatch_event(item))
|
||||||
|
#})
|
||||||
|
|
||||||
|
return composed
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (sig AbortSignal) aborted() bool {
|
||||||
|
res := false
|
||||||
|
#res.val = sig.event.aborted;
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispatch_event(event JS.Event) IEvent {
|
||||||
|
mut ret := IEvent(Event{})
|
||||||
|
#if (event instanceof AbortSignal) { ret = new jsdom__AbortSignal({}); }
|
||||||
|
#else if (event instanceof MouseEvent) { ret = new jsdom__MouseEvent({}); }
|
||||||
|
#ret.event = event
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
import jsdom.ctx
|
||||||
|
|
||||||
|
pub struct HTMLCanvasElement {
|
||||||
|
HTMLElement
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (cv HTMLCanvasElement) height() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = cv.node.height;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (cv HTMLCanvasElement) width() int {
|
||||||
|
ret := 0
|
||||||
|
#ret.val = cv.node.width;
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (cv HTMLCanvasElement) typ() NodeType {
|
||||||
|
return .element
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem HTMLCanvasElement) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem HTMLCanvasElement) get_context(ctx_ string) ctx.ContextResult {
|
||||||
|
mut res := ctx.NoneContext{}
|
||||||
|
#let ctx = elem.node.getContext(ctx_.str);
|
||||||
|
#if (ctx instanceof CanvasRenderingContext2D) { res = new jsdom__ctx__CanvasRenderingContext2D(ctx); res.ctx = ctx; }
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
module jsdom
|
||||||
|
|
||||||
|
pub struct JS.Window {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Window {
|
||||||
|
node JS.Window [noinit]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (elem Window) add_event_listener(event string, cb EventCallback) {
|
||||||
|
#elem.node.addEventListener(event.str, function (event) { let e = jsdom__dispatch_event_target(this);
|
||||||
|
#let ev = jsdom__dispatch_event(event); ev.event = event;
|
||||||
|
#return cb(e,ev)
|
||||||
|
#});
|
||||||
|
}
|
|
@ -164,7 +164,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
|
||||||
g.expr(it.left)
|
g.expr(it.left)
|
||||||
mut ltyp := it.left_type
|
mut ltyp := it.left_type
|
||||||
for ltyp.is_ptr() {
|
for ltyp.is_ptr() {
|
||||||
g.write('.val')
|
g.write('.valueOf()')
|
||||||
ltyp = ltyp.deref()
|
ltyp = ltyp.deref()
|
||||||
}
|
}
|
||||||
g.write('.')
|
g.write('.')
|
||||||
|
|
|
@ -2718,7 +2718,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
|
||||||
fn (mut g JsGen) gen_deref_ptr(ty ast.Type) {
|
fn (mut g JsGen) gen_deref_ptr(ty ast.Type) {
|
||||||
mut t := ty
|
mut t := ty
|
||||||
for t.is_ptr() {
|
for t.is_ptr() {
|
||||||
g.write('.val')
|
g.write('.valueOf()')
|
||||||
t = t.deref()
|
t = t.deref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue