js: DOM API. Part 1 (#12296)

pull/12314/head
playX 2021-10-27 23:18:09 +03:00 committed by GitHub
parent 0ff23eeb74
commit cfecb62299
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1032 additions and 2 deletions

View File

@ -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.

View File

@ -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())
})
}

View File

@ -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>

View File

@ -917,3 +917,10 @@ pub fn (_rune string) utf32_code() int {
return res
}
pub fn tos(jsstr JS.String) string {
res := ''
#res.str = jsstr
return res
}

View File

@ -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

View File

@ -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);
}

View File

@ -0,0 +1,3 @@
module ctx
pub struct WebGLRenderingContext {}

View File

@ -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)
#});
}

186
vlib/jsdom/dom.js.v 100644
View File

@ -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;
}

10
vlib/jsdom/dom.v 100644
View File

@ -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
}
}

View File

@ -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
}

View File

@ -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)
#});
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
#});
}

View File

@ -164,7 +164,7 @@ fn (mut g JsGen) method_call(node ast.CallExpr) {
g.expr(it.left)
mut ltyp := it.left_type
for ltyp.is_ptr() {
g.write('.val')
g.write('.valueOf()')
ltyp = ltyp.deref()
}
g.write('.')

View File

@ -2718,7 +2718,7 @@ fn (mut g JsGen) gen_index_expr(expr ast.IndexExpr) {
fn (mut g JsGen) gen_deref_ptr(ty ast.Type) {
mut t := ty
for t.is_ptr() {
g.write('.val')
g.write('.valueOf()')
t = t.deref()
}
}