xref: /inferno-os/appl/charon/jscript.b (revision 54041ca415f1fdfa1c3dcd82d524223cfa890940)
137da2899SCharles.Forsythimplement JScript;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "common.m";
437da2899SCharles.Forsythinclude "ecmascript.m";
537da2899SCharles.Forsyth
637da2899SCharles.ForsythES: Ecmascript;
737da2899SCharles.Forsyth	Exec, Obj, Call, Prop, Val, Ref, RefVal, Builtin, ReadOnly: import ES;
837da2899SCharles.Forsythme: ESHostobj;
937da2899SCharles.Forsyth
1037da2899SCharles.Forsyth# local copies from CU
1137da2899SCharles.Forsythsys: Sys;
1237da2899SCharles.ForsythCU: CharonUtils;
1337da2899SCharles.Forsyth
1437da2899SCharles.ForsythD: Draw;
1537da2899SCharles.ForsythS: String;
1637da2899SCharles.ForsythT: StringIntTab;
1737da2899SCharles.ForsythC: Ctype;
1837da2899SCharles.ForsythB: Build;
1937da2899SCharles.Forsyth	Item: import B;
2037da2899SCharles.ForsythCH: Charon;
2137da2899SCharles.ForsythL: Layout;
2237da2899SCharles.Forsyth	Frame, Control: import L;
2337da2899SCharles.ForsythU: Url;
2437da2899SCharles.Forsyth	Parsedurl: import U;
2537da2899SCharles.ForsythE: Events;
2637da2899SCharles.Forsyth	Event, ScriptEvent: import E;
2737da2899SCharles.Forsyth
2837da2899SCharles.ForsythG : Gui;
2937da2899SCharles.Forsyth
3037da2899SCharles.ForsythJScript: module
3137da2899SCharles.Forsyth{
3237da2899SCharles.Forsyth	# First, conform to Script interface
3337da2899SCharles.Forsyth	defaultStatus: string;
3437da2899SCharles.Forsyth	jevchan: chan of ref ScriptEvent;
3537da2899SCharles.Forsyth	versions: array of string;
3637da2899SCharles.Forsyth
3737da2899SCharles.Forsyth	init: fn(cu: CharonUtils): string;
3837da2899SCharles.Forsyth	frametreechanged: fn(top: ref Layout->Frame);
3937da2899SCharles.Forsyth	havenewdoc: fn(f: ref Layout->Frame);
4037da2899SCharles.Forsyth	evalscript: fn(f: ref Layout->Frame, s: string) : (string, string, string);
4137da2899SCharles.Forsyth	framedone: fn(f : ref Layout->Frame, hasscripts : int);
4237da2899SCharles.Forsyth
4337da2899SCharles.Forsyth	#
4437da2899SCharles.Forsyth	# implement the host object interface, too
4537da2899SCharles.Forsyth	#
4637da2899SCharles.Forsyth	get:		fn(ex: ref Exec, o: ref Obj, property: string): ref Val;
4737da2899SCharles.Forsyth	put:		fn(ex: ref Exec, o: ref Obj, property: string, val: ref Val);
4837da2899SCharles.Forsyth	canput:	fn(ex: ref Exec, o: ref Obj, property: string): ref Val;
4937da2899SCharles.Forsyth	hasproperty:	fn(ex: ref Exec, o: ref Obj, property: string): ref Val;
5037da2899SCharles.Forsyth	delete:		fn(ex: ref Exec, o: ref Obj, property: string);
5137da2899SCharles.Forsyth	defaultval:	fn(ex: ref Exec, o: ref Obj, tyhint: int): ref Val;
5237da2899SCharles.Forsyth	call:		fn(ex: ref Exec, func, this: ref Obj, args: array of ref Val, eval: int): ref Ref;
5337da2899SCharles.Forsyth	construct:	fn(ex: ref Exec, func: ref Obj, args: array of ref Val): ref Obj;
5437da2899SCharles.Forsyth};
5537da2899SCharles.Forsyth
5637da2899SCharles.Forsythversions = array [] of {
5737da2899SCharles.Forsyth	"javascript",
5837da2899SCharles.Forsyth	"javascript1.0",
5937da2899SCharles.Forsyth	"javascript1.1",
6037da2899SCharles.Forsyth	"javascript1.2",
6137da2899SCharles.Forsyth	"javascript1.3",
6237da2899SCharles.Forsyth};
6337da2899SCharles.Forsyth
6437da2899SCharles.Forsyth# Call init() before calling anything else.
6537da2899SCharles.Forsyth# It makes a global object (a Window) for the browser's top level frame,
6637da2899SCharles.Forsyth# and also puts a navaigator object in it.  The document can't be filled
6737da2899SCharles.Forsyth# in until the first document gets loaded.
6837da2899SCharles.Forsyth#
6937da2899SCharles.Forsyth# This module keeps track of the correspondence between the Script Window
7037da2899SCharles.Forsyth# objects and the corresponding Layout Frames, using the ScriptWin adt to
7137da2899SCharles.Forsyth# build a tree mirroring the structure.  The root of the tree never changes
7237da2899SCharles.Forsyth# after first being set (but changing its document essentially resets all of the
7337da2899SCharles.Forsyth# other data structures).  After charon has built its top-level window, it
7437da2899SCharles.Forsyth# should call frametreechanged(top).
7537da2899SCharles.Forsyth#
7637da2899SCharles.Forsyth# When a frame gets reset or gets some frame children added, call frametreechanged(f),
7737da2899SCharles.Forsyth# where f is the changed frame.  This module will update its ScriptWin tree as needed.
7837da2899SCharles.Forsyth#
7937da2899SCharles.Forsyth# Whenever the document in a (Layout) Frame f changes, call havenewdoc(f)
8037da2899SCharles.Forsyth# after the frame's doc field is set. This causes this module to initialize the document
8137da2899SCharles.Forsyth# object in the corresponding window object.
8237da2899SCharles.Forsyth#
8337da2899SCharles.Forsyth# From within the build process, call evalscript(containing frame, script) to evaluate
8437da2899SCharles.Forsyth# global code fragments as needed.  The return value is two strings: a possible error
8537da2899SCharles.Forsyth# description, and HTML that is the result of a document.write (so it should be spliced
8637da2899SCharles.Forsyth# in at the point where the <SCRIPT> element occurred).  evalscript() also handles
8737da2899SCharles.Forsyth# the job of synching up the Docinfo data (on the Build side) with the document object
8837da2899SCharles.Forsyth# (on the Script side).
8937da2899SCharles.Forsyth#
9037da2899SCharles.Forsyth# For use by other external routines, the xfertoscriptobjs() and xferfromscriptobjs()
9137da2899SCharles.Forsyth# functions that do the just-described synch-up are available for external callers.
9237da2899SCharles.Forsyth
9337da2899SCharles.Forsyth# Adt for keeping track of correspondence between Image objects
9437da2899SCharles.Forsyth# and their corresponding Build items.
9537da2899SCharles.ForsythScriptImg: adt
9637da2899SCharles.Forsyth{
9737da2899SCharles.Forsyth	item: ref Build->Item.Iimage;
9837da2899SCharles.Forsyth	obj: ref Obj;
9937da2899SCharles.Forsyth};
10037da2899SCharles.Forsyth
10137da2899SCharles.ForsythScriptForm : adt {
10237da2899SCharles.Forsyth	form : ref Build->Form;
10337da2899SCharles.Forsyth	obj : ref Obj;
10437da2899SCharles.Forsyth	ix : int;		# index in document.forms array
10537da2899SCharles.Forsyth	fields : list of (ref Build->Formfield, ref Obj);
10637da2899SCharles.Forsyth};
10737da2899SCharles.Forsyth
10837da2899SCharles.Forsyth# Adt for keeping track of correspondence between Window
10937da2899SCharles.Forsyth# objects and their corresponding Frames.
11037da2899SCharles.Forsyth
11137da2899SCharles.ForsythScriptWin: adt
11237da2899SCharles.Forsyth{
11337da2899SCharles.Forsyth	frame: ref Layout->Frame;
11437da2899SCharles.Forsyth	ex: ref Exec;		# ex.global is frame's Window obj
11537da2899SCharles.Forsyth	locobj: ref Obj;		# Location object for window
11637da2899SCharles.Forsyth	val : ref Val;		# val of ex.global - used to side-effect entry in parent.frames[]
11737da2899SCharles.Forsyth
11837da2899SCharles.Forsyth	parent: ref ScriptWin;
11937da2899SCharles.Forsyth	forms: list of ref ScriptForm;	# no guaranteed order
12037da2899SCharles.Forsyth	kids: cyclic list of ref ScriptWin;
12137da2899SCharles.Forsyth	imgs: list of ref ScriptImg;
12237da2899SCharles.Forsyth	newloc: string;		# url to go to after script finishes executing
12337da2899SCharles.Forsyth	newloctarg: string;	# target frame for newloc
12437da2899SCharles.Forsyth	docwriteout: string;
12537da2899SCharles.Forsyth	inbuild: int;
12637da2899SCharles.Forsyth	active: int;		# frame or sub-frame has scripts
12737da2899SCharles.Forsyth	error: int;
12837da2899SCharles.Forsyth	imgrelocs: list of ref Obj;
12937da2899SCharles.Forsyth
13037da2899SCharles.Forsyth	new: fn(f: ref Layout->Frame, ex: ref Exec, loc: ref Obj, par: ref ScriptWin) : ref ScriptWin;
13137da2899SCharles.Forsyth	addkid: fn(sw: self ref ScriptWin, f: ref Layout->Frame);
13237da2899SCharles.Forsyth	dummy: fn(): ref ScriptWin;
13337da2899SCharles.Forsyth#	findbyframe: fn(sw: self ref ScriptWin, f: ref Layout->Frame) : ref ScriptWin;
13437da2899SCharles.Forsyth	findbyframeid: fn(sw: self ref ScriptWin, fid: int) : ref ScriptWin;
13537da2899SCharles.Forsyth	findbydoc: fn(sw: self ref ScriptWin, d: ref Build->Docinfo) : ref ScriptWin;
13637da2899SCharles.Forsyth	findbyobj: fn(sw : self ref ScriptWin, obj : ref Obj) : ref ScriptWin;
13737da2899SCharles.Forsyth	findbyname: fn(sw : self ref ScriptWin, name : string) : ref ScriptWin;
13837da2899SCharles.Forsyth};
13937da2899SCharles.Forsyth
14037da2899SCharles.Forsythopener: ref ScriptWin;
14137da2899SCharles.Forsythwinclose: int;
14237da2899SCharles.Forsyth
14337da2899SCharles.Forsyth# Helper adts for initializing objects.
14437da2899SCharles.Forsyth# Methods go in prototype, properties go in objects
14537da2899SCharles.Forsyth
14637da2899SCharles.ForsythMethSpec: adt
14737da2899SCharles.Forsyth{
14837da2899SCharles.Forsyth	name: string;
14937da2899SCharles.Forsyth	args: array of string;
15037da2899SCharles.Forsyth};
15137da2899SCharles.Forsyth
15237da2899SCharles.Forsyth
15337da2899SCharles.ForsythIVundef, IVnull, IVtrue, IVfalse, IVnullstr, IVzero, IVzerostr, IVarray: con iota;
15437da2899SCharles.Forsyth
15537da2899SCharles.ForsythPropSpec: adt
15637da2899SCharles.Forsyth{
15737da2899SCharles.Forsyth	name: string;
15837da2899SCharles.Forsyth	attr: int;
15937da2899SCharles.Forsyth	initval: int;	# one of IVnull, etc.
16037da2899SCharles.Forsyth};
16137da2899SCharles.Forsyth
16237da2899SCharles.ForsythObjSpec: adt
16337da2899SCharles.Forsyth{
16437da2899SCharles.Forsyth	name: string;
16537da2899SCharles.Forsyth	methods: array of MethSpec;
16637da2899SCharles.Forsyth	props: array of PropSpec;
16737da2899SCharles.Forsyth};
16837da2899SCharles.Forsyth
16937da2899SCharles.ForsythMimeSpec: adt
17037da2899SCharles.Forsyth{
17137da2899SCharles.Forsyth	description: string;
17237da2899SCharles.Forsyth	suffixes: string;
17337da2899SCharles.Forsyth	ty: string;
17437da2899SCharles.Forsyth};
17537da2899SCharles.Forsyth
17637da2899SCharles.Forsyth# Javascript 1.1 (Netscape 3) client objects
17737da2899SCharles.Forsyth
17837da2899SCharles.Forsythobjspecs := array[] of {
17937da2899SCharles.Forsyth    ObjSpec("Anchor",
18037da2899SCharles.Forsyth	nil,
18137da2899SCharles.Forsyth	array[] of {PropSpec
18237da2899SCharles.Forsyth		("name", ReadOnly, IVnullstr) }
18337da2899SCharles.Forsyth	),
18437da2899SCharles.Forsyth    ObjSpec("Applet",
18537da2899SCharles.Forsyth	nil,
18637da2899SCharles.Forsyth	nil
18737da2899SCharles.Forsyth	),
18837da2899SCharles.Forsyth    ObjSpec("document",
18937da2899SCharles.Forsyth	array[] of {MethSpec
19037da2899SCharles.Forsyth		("close", nil),
19137da2899SCharles.Forsyth		("open", array[] of { "mimetype", "replace" }),
19237da2899SCharles.Forsyth		("write", array[] of { "string" }),
19337da2899SCharles.Forsyth		("writeln", array[] of { "string" }) },
19437da2899SCharles.Forsyth	array[] of {PropSpec
19537da2899SCharles.Forsyth		("alinkColor", 0, IVnullstr),
19637da2899SCharles.Forsyth		("anchors", ReadOnly, IVarray),
19737da2899SCharles.Forsyth		("applets", ReadOnly, IVarray),
19837da2899SCharles.Forsyth		("bgColor", 0, IVnullstr),
19937da2899SCharles.Forsyth		("cookie", 0, IVnullstr),
20037da2899SCharles.Forsyth		("domain", 0, IVnullstr),
20137da2899SCharles.Forsyth		("embeds", ReadOnly, IVarray),
20237da2899SCharles.Forsyth		("fgColor", 0, IVnullstr),
20337da2899SCharles.Forsyth		("forms", ReadOnly, IVarray),
20437da2899SCharles.Forsyth		("images", ReadOnly, IVarray),
20537da2899SCharles.Forsyth		("lastModified", ReadOnly, IVnullstr),
20637da2899SCharles.Forsyth		("linkColor", 0, IVnullstr),
20737da2899SCharles.Forsyth		("links", ReadOnly, IVarray),
20837da2899SCharles.Forsyth		("location", 0, IVnullstr),
20937da2899SCharles.Forsyth		("plugins", ReadOnly, IVarray),
21037da2899SCharles.Forsyth		("referrer", ReadOnly, IVnullstr),
21137da2899SCharles.Forsyth		("title", ReadOnly, IVnullstr),
21237da2899SCharles.Forsyth		("URL", ReadOnly, IVnullstr),
21337da2899SCharles.Forsyth		("vlinkColor", 0, IVnullstr) }
21437da2899SCharles.Forsyth	),
21537da2899SCharles.Forsyth    ObjSpec("Form",
21637da2899SCharles.Forsyth	array[] of {MethSpec
21737da2899SCharles.Forsyth		("reset", nil),
21837da2899SCharles.Forsyth		("submit", nil) },
21937da2899SCharles.Forsyth	array[] of {PropSpec
22037da2899SCharles.Forsyth		("action", 0, IVnullstr),
22137da2899SCharles.Forsyth		("elements", ReadOnly, IVarray),
22237da2899SCharles.Forsyth		("encoding", 0, IVnullstr),
22337da2899SCharles.Forsyth		("length", ReadOnly, IVzero),
22437da2899SCharles.Forsyth		("method", 0, IVnullstr),
22537da2899SCharles.Forsyth		("name", 0, IVnullstr),
22637da2899SCharles.Forsyth		("target", 0, IVnullstr) }
22737da2899SCharles.Forsyth	),
22837da2899SCharles.Forsyth   # This is merge of Netscape objects (to save code & data space):
22937da2899SCharles.Forsyth   # Button, Checkbox, Hidden, Radio, Reset, Select, Text, and Textarea
23037da2899SCharles.Forsyth    ObjSpec("FormField",
23137da2899SCharles.Forsyth	array[] of {MethSpec
23237da2899SCharles.Forsyth		("blur", nil),
23337da2899SCharles.Forsyth		("click", nil),
23437da2899SCharles.Forsyth		("focus", nil),
23537da2899SCharles.Forsyth		("select", nil) },
23637da2899SCharles.Forsyth	array[] of {PropSpec
23737da2899SCharles.Forsyth		("checked", 0, IVundef),
23837da2899SCharles.Forsyth		("defaultChecked", 0, IVundef),
23937da2899SCharles.Forsyth		("defaultValue", 0, IVundef),
24037da2899SCharles.Forsyth		("form", ReadOnly, IVundef),
24137da2899SCharles.Forsyth		("length", 0, IVundef),
24237da2899SCharles.Forsyth		("name", 0, IVnullstr),
24337da2899SCharles.Forsyth		("options", 0, IVundef),
24437da2899SCharles.Forsyth		("type", ReadOnly, IVundef),
24537da2899SCharles.Forsyth		("selectedIndex", 0, IVundef),
24637da2899SCharles.Forsyth		("value", 0, IVnullstr) }
24737da2899SCharles.Forsyth	),
24837da2899SCharles.Forsyth    ObjSpec("History",
24937da2899SCharles.Forsyth	array[] of {MethSpec
25037da2899SCharles.Forsyth		("back", nil),
25137da2899SCharles.Forsyth		("forward", nil),
25237da2899SCharles.Forsyth		("go", array[] of { "location-or-delta" }) },
25337da2899SCharles.Forsyth	array[] of {PropSpec
25437da2899SCharles.Forsyth		("current", ReadOnly, IVnullstr),
25537da2899SCharles.Forsyth		("length", ReadOnly, IVzero),
25637da2899SCharles.Forsyth		("next", ReadOnly, IVnullstr),
25737da2899SCharles.Forsyth		("previous", ReadOnly, IVnullstr) }
25837da2899SCharles.Forsyth	),
25937da2899SCharles.Forsyth    ObjSpec("Image",
26037da2899SCharles.Forsyth	nil,
26137da2899SCharles.Forsyth	array[] of {PropSpec
26237da2899SCharles.Forsyth		("border", ReadOnly, IVzerostr),
26337da2899SCharles.Forsyth		("complete", ReadOnly, IVfalse),
26437da2899SCharles.Forsyth		("height", ReadOnly, IVzerostr),
26537da2899SCharles.Forsyth		("hspace", ReadOnly, IVzerostr),
26637da2899SCharles.Forsyth		("lowsrc", 0, IVnullstr),
26737da2899SCharles.Forsyth		("name", ReadOnly, IVnullstr),
26837da2899SCharles.Forsyth		("src", 0, IVnullstr),
26937da2899SCharles.Forsyth		("vspace", ReadOnly, IVzerostr),
27037da2899SCharles.Forsyth		("width", ReadOnly, IVzerostr) }
27137da2899SCharles.Forsyth	),
27237da2899SCharles.Forsyth    ObjSpec("Link",
27337da2899SCharles.Forsyth	nil,
27437da2899SCharles.Forsyth	array[] of {PropSpec
27537da2899SCharles.Forsyth		("hash", 0, IVnullstr),
27637da2899SCharles.Forsyth		("host", 0, IVnullstr),
27737da2899SCharles.Forsyth		("hostname", 0, IVnullstr),
27837da2899SCharles.Forsyth		("href", 0, IVnullstr),
27937da2899SCharles.Forsyth		("pathname", 0, IVnullstr),
28037da2899SCharles.Forsyth		("port", 0, IVnullstr),
28137da2899SCharles.Forsyth		("protocol", 0, IVnullstr),
28237da2899SCharles.Forsyth		("search", 0, IVnullstr),
28337da2899SCharles.Forsyth		("target", 0, IVnullstr) }
28437da2899SCharles.Forsyth	),
28537da2899SCharles.Forsyth    ObjSpec("Location",
28637da2899SCharles.Forsyth	array[] of {MethSpec
28737da2899SCharles.Forsyth		("reload", array[] of { "forceGet" }),
28837da2899SCharles.Forsyth		("replace", array[] of { "URL" }) },
28937da2899SCharles.Forsyth	array[] of {PropSpec
29037da2899SCharles.Forsyth		("hash", 0, IVnullstr),
29137da2899SCharles.Forsyth		("host", 0, IVnullstr),
29237da2899SCharles.Forsyth		("hostname", 0, IVnullstr),
29337da2899SCharles.Forsyth		("href", 0, IVnullstr),
29437da2899SCharles.Forsyth		("pathname", 0, IVnullstr),
29537da2899SCharles.Forsyth		("port", 0, IVnullstr),
29637da2899SCharles.Forsyth		("protocol", 0, IVnullstr),
29737da2899SCharles.Forsyth		("search", 0, IVnullstr) }
29837da2899SCharles.Forsyth	),
29937da2899SCharles.Forsyth    ObjSpec("MimeType",
30037da2899SCharles.Forsyth	nil,
30137da2899SCharles.Forsyth	array[] of {PropSpec
30237da2899SCharles.Forsyth		("description", ReadOnly, IVnullstr),
30337da2899SCharles.Forsyth		("enabledPlugin", ReadOnly, IVnull),
30437da2899SCharles.Forsyth		("suffixes", ReadOnly, IVnullstr),
30537da2899SCharles.Forsyth		("type", ReadOnly, IVnullstr) }
30637da2899SCharles.Forsyth	),
30737da2899SCharles.Forsyth    ObjSpec("Option",
30837da2899SCharles.Forsyth	nil,
30937da2899SCharles.Forsyth	array[] of {PropSpec
31037da2899SCharles.Forsyth		("defaultSelected", 0, IVfalse),
31137da2899SCharles.Forsyth		("index", 0, IVundef),
31237da2899SCharles.Forsyth		("selected", 0, IVfalse),
31337da2899SCharles.Forsyth		("text", 0, IVnullstr),
31437da2899SCharles.Forsyth		("value", 0, IVnullstr) }
31537da2899SCharles.Forsyth	),
31637da2899SCharles.Forsyth    ObjSpec("navigator",
31737da2899SCharles.Forsyth	array[] of {MethSpec
31837da2899SCharles.Forsyth		("javaEnabled", nil),
31937da2899SCharles.Forsyth		("plugins.refresh", nil),
32037da2899SCharles.Forsyth		("taintEnabled", nil) },
32137da2899SCharles.Forsyth	array[] of {PropSpec
32237da2899SCharles.Forsyth		("appCodeName", ReadOnly, IVnullstr),
32337da2899SCharles.Forsyth		("appName", ReadOnly, IVnullstr),
32437da2899SCharles.Forsyth		("appVersion", ReadOnly, IVnullstr),
32537da2899SCharles.Forsyth		("mimeTypes", ReadOnly, IVarray),
32637da2899SCharles.Forsyth		("platform", ReadOnly, IVnullstr),
32737da2899SCharles.Forsyth		("plugins", ReadOnly, IVarray),
32837da2899SCharles.Forsyth		("userAgent", ReadOnly, IVnullstr) }
32937da2899SCharles.Forsyth	),
33037da2899SCharles.Forsyth    ObjSpec("Plugin",
33137da2899SCharles.Forsyth	nil,
33237da2899SCharles.Forsyth	array[] of {PropSpec
33337da2899SCharles.Forsyth		("description", 0, IVnullstr),
33437da2899SCharles.Forsyth		("filename", 0, IVnullstr),
33537da2899SCharles.Forsyth		("length", 0, IVzero),
33637da2899SCharles.Forsyth		("name", 0, IVnullstr) }
33737da2899SCharles.Forsyth	),
33837da2899SCharles.Forsyth     ObjSpec("Screen",
33937da2899SCharles.Forsyth	nil,
34037da2899SCharles.Forsyth	array[] of {PropSpec
34137da2899SCharles.Forsyth		("availHeight", ReadOnly, IVzero),
34237da2899SCharles.Forsyth		("availWidth", ReadOnly, IVzero),
34337da2899SCharles.Forsyth		("availLeft", ReadOnly, IVzero),
34437da2899SCharles.Forsyth		("availTop", ReadOnly, IVzero),
34537da2899SCharles.Forsyth		("colorDepth", ReadOnly, IVzero),
34637da2899SCharles.Forsyth		("pixelDepth", ReadOnly, IVzero),
34737da2899SCharles.Forsyth		("height", ReadOnly, IVzero),
34837da2899SCharles.Forsyth		("width", ReadOnly, IVzero) }
34937da2899SCharles.Forsyth	),
35037da2899SCharles.Forsyth     ObjSpec("Window",
35137da2899SCharles.Forsyth	array[] of {MethSpec
35237da2899SCharles.Forsyth		("alert", array[] of { "msg" }),
35337da2899SCharles.Forsyth		("blur", nil),
35437da2899SCharles.Forsyth		("clearInterval", array[] of { "intervalid" }),
35537da2899SCharles.Forsyth		("clearTimeout", array[] of { "timeoutid" }),
35637da2899SCharles.Forsyth		("close", nil),
35737da2899SCharles.Forsyth		("confirm", array[] of  { "msg" }),
35837da2899SCharles.Forsyth		("focus", nil),
35937da2899SCharles.Forsyth		("moveBy", array[] of { "dx", "dy" }),
36037da2899SCharles.Forsyth		("moveTo", array[] of { "x", "y" }),
36137da2899SCharles.Forsyth		("open", array[] of { "url", "winname", "winfeatures" }),
36237da2899SCharles.Forsyth		("prompt", array[] of { "msg", "inputdflt" }),
36337da2899SCharles.Forsyth		("resizeBy", array[] of { "dh", "dw" }),
36437da2899SCharles.Forsyth		("resizeTo", array[] of { "width", "height" }),
36537da2899SCharles.Forsyth		("scroll", array[] of { "x", "y"  }),
36637da2899SCharles.Forsyth		("scrollBy", array[] of { "dx", "dy" }),
36737da2899SCharles.Forsyth		("scrollTo", array[] of { "x", "y" }),
36837da2899SCharles.Forsyth		("setInterval", array[] of { "code", "msec" }),
36937da2899SCharles.Forsyth		("setTimeout", array[] of { "expr", "msec" }) },
37037da2899SCharles.Forsyth	array[] of {PropSpec
37137da2899SCharles.Forsyth		("closed", ReadOnly, IVfalse),
37237da2899SCharles.Forsyth		("defaultStatus", 0, IVnullstr),
37337da2899SCharles.Forsyth		("document", 0, IVnull),
37437da2899SCharles.Forsyth		("frames", ReadOnly, IVnull),	# array, really
37537da2899SCharles.Forsyth		("history", 0, IVnull),	# array, really
37637da2899SCharles.Forsyth		("length", ReadOnly, IVzero),
37737da2899SCharles.Forsyth		("location", 0, IVnullstr),
37837da2899SCharles.Forsyth#		("Math", ReadOnly, IVnull),
37937da2899SCharles.Forsyth		("name", 0, IVnullstr),
38037da2899SCharles.Forsyth		("navigator", ReadOnly, IVnull),
38137da2899SCharles.Forsyth		("offscreenBuffering", 0, IVnullstr),
38237da2899SCharles.Forsyth		("opener", 0, IVnull),
38337da2899SCharles.Forsyth		("parent", ReadOnly, IVnull),
38437da2899SCharles.Forsyth		("screen", 0, IVnull),
38537da2899SCharles.Forsyth		("self", ReadOnly, IVnull),
38637da2899SCharles.Forsyth		("status", 0, IVnullstr),
38737da2899SCharles.Forsyth		("top", ReadOnly, IVnull),
38837da2899SCharles.Forsyth		("window", ReadOnly, IVnull) }
38937da2899SCharles.Forsyth	)
39037da2899SCharles.Forsyth};
39137da2899SCharles.Forsyth
39237da2899SCharles.Forsyth# Currently supported charon mime types
39337da2899SCharles.Forsythmimespecs := array[] of {
39437da2899SCharles.Forsyth    MimeSpec("HTML",
39537da2899SCharles.Forsyth	"htm,html",
39637da2899SCharles.Forsyth	"text/html"
39737da2899SCharles.Forsyth	),
39837da2899SCharles.Forsyth    MimeSpec("Plain text",
39937da2899SCharles.Forsyth	"txt,text",
40037da2899SCharles.Forsyth	"text/plain"
40137da2899SCharles.Forsyth	),
40237da2899SCharles.Forsyth   MimeSpec("Gif Image",
40337da2899SCharles.Forsyth	"gif",
40437da2899SCharles.Forsyth	"image/gif"
40537da2899SCharles.Forsyth	),
40637da2899SCharles.Forsyth    MimeSpec("Jpeg Image",
40737da2899SCharles.Forsyth	"jpeg,jpg,jpe",
40837da2899SCharles.Forsyth	"image/jpeg"
40937da2899SCharles.Forsyth	),
41037da2899SCharles.Forsyth    MimeSpec("X Bitmap Image",
41137da2899SCharles.Forsyth	"",
41237da2899SCharles.Forsyth	"image/x-xbitmap"
41337da2899SCharles.Forsyth	)
41437da2899SCharles.Forsyth};
41537da2899SCharles.Forsyth
41637da2899SCharles.Forsyth# charon's 's' debug flag:
41737da2899SCharles.Forsyth#	1:	basic syntax and runtime errors
41837da2899SCharles.Forsyth#	2:	'event' logging and DOM actions
41937da2899SCharles.Forsyth#	3:	print parsed code and ops as executed
42037da2899SCharles.Forsyth#	4:	print value of expression statements and abort on runtime errors
42137da2899SCharles.Forsythdbg := 0;
42237da2899SCharles.Forsythdbgdom := 0;
42337da2899SCharles.Forsyth
42437da2899SCharles.Forsythtop: ref ScriptWin;
42537da2899SCharles.Forsythcreatedimages : list of ref Obj;
42637da2899SCharles.Forsythnullstrval: ref Val;
42737da2899SCharles.Forsythzeroval: ref Val;
42837da2899SCharles.Forsythzerostrval: ref Val;
42937da2899SCharles.Forsyth
43037da2899SCharles.Forsyth# Call this after charon's main (top) frame has been built
43137da2899SCharles.Forsythinit(cu: CharonUtils) : string
43237da2899SCharles.Forsyth{
43337da2899SCharles.Forsyth	CU = cu;
43437da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
43537da2899SCharles.Forsyth	D = load Draw Draw->PATH;
43637da2899SCharles.Forsyth	S = load String String->PATH;
43737da2899SCharles.Forsyth	T = load StringIntTab StringIntTab->PATH;
43837da2899SCharles.Forsyth	U = load Url Url->PATH;
43937da2899SCharles.Forsyth	if (U != nil)
44037da2899SCharles.Forsyth		U->init();
44137da2899SCharles.Forsyth	C = cu->C;
44237da2899SCharles.Forsyth	B = cu->B;
44337da2899SCharles.Forsyth	L = cu->L;
44437da2899SCharles.Forsyth	E = cu->E;
44537da2899SCharles.Forsyth	CH = cu->CH;
44637da2899SCharles.Forsyth	G = cu->G;
44737da2899SCharles.Forsyth	dbg = int (CU->config).dbg['s'];
44837da2899SCharles.Forsyth	if (dbg > 1)
44937da2899SCharles.Forsyth		dbgdom = 1;
45037da2899SCharles.Forsyth	ES = load Ecmascript Ecmascript->PATH;
45137da2899SCharles.Forsyth	if(ES == nil)
45237da2899SCharles.Forsyth		return sys->sprint("could not load module %s: %r", Ecmascript->PATH);
45337da2899SCharles.Forsyth	err := ES->init();
45437da2899SCharles.Forsyth	if (err != nil)
45537da2899SCharles.Forsyth		return sys->sprint("ecmascript error: %s", err);
45637da2899SCharles.Forsyth
45737da2899SCharles.Forsyth	me = load ESHostobj SELF;
45837da2899SCharles.Forsyth	if(me == nil)
45937da2899SCharles.Forsyth		return sys->sprint("jscript: could not load  self as a ESHostobj: %r");
46037da2899SCharles.Forsyth	if(dbg >= 3) {
46137da2899SCharles.Forsyth		ES->debug['p'] = 1;	# print parsed code
46237da2899SCharles.Forsyth		ES->debug['e'] = 1;	# prinv ops as they are executed
46337da2899SCharles.Forsyth		if(dbg >= 4) {
46437da2899SCharles.Forsyth			ES->debug['e'] = 2;
46537da2899SCharles.Forsyth			ES->debug['v'] = 1;	# print value of expression statements
46637da2899SCharles.Forsyth			ES->debug['r'] = 1;	# print and abort if runtime errors
46737da2899SCharles.Forsyth		}
46837da2899SCharles.Forsyth	}
46937da2899SCharles.Forsyth
47037da2899SCharles.Forsyth	# some constant values, for initialization
47137da2899SCharles.Forsyth	nullstrval = ES->strval("");
47237da2899SCharles.Forsyth	zeroval = ES->numval(0.);
47337da2899SCharles.Forsyth	zerostrval = ES->strval("0");
47437da2899SCharles.Forsyth	jevchan = chan of ref ScriptEvent;
47537da2899SCharles.Forsyth	spawn jevhandler();
47637da2899SCharles.Forsyth	return nil;
47737da2899SCharles.Forsyth}
47837da2899SCharles.Forsyth
47937da2899SCharles.Forsythdoneevent := ScriptEvent(-1,0,0,0,0,0,0,0,0,nil,nil,0);
48037da2899SCharles.Forsyth
48137da2899SCharles.Forsyth# Used to receive and act upon ScriptEvents from main charon thread.
48237da2899SCharles.Forsyth# Want to queue the events up, so that the main thread doesn't have
48337da2899SCharles.Forsyth# to wait, and spawn off a do_on, one at a time, so that they don't
48437da2899SCharles.Forsyth# interfere with each other.
48537da2899SCharles.Forsyth# When do_on is finished, it must send a copy of doneevent
48637da2899SCharles.Forsyth# so that jevhandler knows it can spawn another do_on.
48737da2899SCharles.Forsythjevhandler()
48837da2899SCharles.Forsyth{
48937da2899SCharles.Forsyth	q := array[10] of ref ScriptEvent;
49037da2899SCharles.Forsyth	qhead := 0;
49137da2899SCharles.Forsyth	qtail := 0;
49237da2899SCharles.Forsyth	spawnok := 1;
49337da2899SCharles.Forsyth	for(;;) {
49437da2899SCharles.Forsyth		jev := <- jevchan;
49537da2899SCharles.Forsyth		if(jev.kind == -1)
49637da2899SCharles.Forsyth			spawnok = 1;
49737da2899SCharles.Forsyth		else
49837da2899SCharles.Forsyth			q[qtail++] = jev;
49937da2899SCharles.Forsyth		jev = nil;
50037da2899SCharles.Forsyth
50137da2899SCharles.Forsyth		# remove next event to process, if ok to and there is one
50237da2899SCharles.Forsyth		if(spawnok && qhead < qtail)
50337da2899SCharles.Forsyth			jev = q[qhead++];
50437da2899SCharles.Forsyth
50537da2899SCharles.Forsyth		# adjust queue to make sure there is room for next event
50637da2899SCharles.Forsyth		if(qhead == qtail) {
50737da2899SCharles.Forsyth			qhead = 0;
50837da2899SCharles.Forsyth			qtail = 0;
50937da2899SCharles.Forsyth		}
51037da2899SCharles.Forsyth		if(qtail == len q) {
51137da2899SCharles.Forsyth			if(qhead > 0) {
51237da2899SCharles.Forsyth				q[0:] = q[qhead:qtail];
51337da2899SCharles.Forsyth				qtail -= qhead;
51437da2899SCharles.Forsyth				qhead = 0;
51537da2899SCharles.Forsyth			}
51637da2899SCharles.Forsyth			else {
51737da2899SCharles.Forsyth				newq := array[len q + 10] of ref ScriptEvent;
51837da2899SCharles.Forsyth				newq[0:] = q;
51937da2899SCharles.Forsyth				q = newq;
52037da2899SCharles.Forsyth			}
52137da2899SCharles.Forsyth		}
52237da2899SCharles.Forsyth
52337da2899SCharles.Forsyth		# process next event, if any
52437da2899SCharles.Forsyth		if(jev != nil) {
52537da2899SCharles.Forsyth			spawnok = 0;
52637da2899SCharles.Forsyth			spawn do_on(jev);
52737da2899SCharles.Forsyth		}
52837da2899SCharles.Forsyth	}
52937da2899SCharles.Forsyth}
53037da2899SCharles.Forsyth
53137da2899SCharles.Forsyth# Create an execution context for the frame.
53237da2899SCharles.Forsyth# The global object of the frame is the frame's Window object.
53337da2899SCharles.Forsyth# Return the execution context and the Location object for the window.
53437da2899SCharles.Forsythmakeframeex(f : ref Layout->Frame) : (ref Exec, ref Obj)
53537da2899SCharles.Forsyth{
53637da2899SCharles.Forsyth	winobj := mkhostobj(nil, "Window");
53737da2899SCharles.Forsyth	ex := ES->mkexec(winobj);
53837da2899SCharles.Forsyth	winobj.prototype = ex.objproto;
53937da2899SCharles.Forsyth	winobj.prototype = mkprototype(ex, specindex("Window"));
54037da2899SCharles.Forsyth
54137da2899SCharles.Forsyth	navobj := mknavobj(ex);
54237da2899SCharles.Forsyth	reinitprop(winobj, "navigator", ES->objval(navobj));
54337da2899SCharles.Forsyth
54437da2899SCharles.Forsyth	histobj := mkhostobj(ex, "History");
54537da2899SCharles.Forsyth	(length, current, next, previous) := CH->histinfo();
54637da2899SCharles.Forsyth	reinitprop(histobj, "current", ES->strval(current));
54737da2899SCharles.Forsyth	reinitprop(histobj, "length", ES->numval(real length));
54837da2899SCharles.Forsyth	reinitprop(histobj, "next", ES->strval(next));
54937da2899SCharles.Forsyth	reinitprop(histobj, "previous", ES->strval(previous));
55037da2899SCharles.Forsyth	ES->put(ex, winobj, "history", ES->objval(histobj));
55137da2899SCharles.Forsyth
55237da2899SCharles.Forsyth	locobj := mkhostobj(ex, "Location");
55337da2899SCharles.Forsyth	src : ref U->Parsedurl;
55437da2899SCharles.Forsyth	di := f.doc;
55537da2899SCharles.Forsyth	if (di != nil && di.src != nil) {
55637da2899SCharles.Forsyth		src = di.src;
55737da2899SCharles.Forsyth		reinitprop(locobj, "hash", ES->strval("#" + src.frag));
55837da2899SCharles.Forsyth		reinitprop(locobj, "host", ES->strval(src.host + ":" + src.port));
55937da2899SCharles.Forsyth		reinitprop(locobj, "hostname", ES->strval(src.host));
56037da2899SCharles.Forsyth		reinitprop(locobj, "href", ES->strval(src.tostring()));
56137da2899SCharles.Forsyth		reinitprop(locobj, "pathname", ES->strval(src.path));
56237da2899SCharles.Forsyth		reinitprop(locobj, "port", ES->strval(src.port));
56337da2899SCharles.Forsyth		reinitprop(locobj, "protocol", ES->strval(src.scheme + ":"));
56437da2899SCharles.Forsyth		reinitprop(locobj, "search", ES->strval("?" + src.query));
56537da2899SCharles.Forsyth	}
56637da2899SCharles.Forsyth	ES->put(ex, winobj, "location", ES->objval(locobj));
56737da2899SCharles.Forsyth
56837da2899SCharles.Forsyth	scrobj := mkhostobj(ex, "Screen");
56937da2899SCharles.Forsyth	scr := (CU->G->display).image;
57037da2899SCharles.Forsyth	scrw := D->(scr.r.dx)();
57137da2899SCharles.Forsyth	scrh := D->(scr.r.dy)();
57237da2899SCharles.Forsyth	reinitprop(scrobj, "availHeight", ES->numval(real scrh));
57337da2899SCharles.Forsyth	reinitprop(scrobj, "availWidth", ES->numval(real scrw));
57437da2899SCharles.Forsyth	reinitprop(scrobj, "availLeft", ES->numval(real scr.r.min.x));
57537da2899SCharles.Forsyth	reinitprop(scrobj, "availTop", ES->numval(real scr.r.min.y));
57637da2899SCharles.Forsyth	reinitprop(scrobj, "colorDepth", ES->numval(real scr.depth));
57737da2899SCharles.Forsyth	reinitprop(scrobj, "pixelDepth", ES->numval(real scr.depth));
57837da2899SCharles.Forsyth	reinitprop(scrobj, "height", ES->numval(real scrh));
57937da2899SCharles.Forsyth	reinitprop(scrobj, "width", ES->numval(real scrw));
58037da2899SCharles.Forsyth	ES->put(ex, winobj, "screen", ES->objval(scrobj));
58137da2899SCharles.Forsyth
58237da2899SCharles.Forsyth	# make the non-core constructor objects
58337da2899SCharles.Forsyth#	improto := mkprototype(ex, specindex("Image"));
58437da2899SCharles.Forsyth	o := ES->biinst(winobj, Builtin("Image", "Image", array[] of {"width", "height"}, 2),
58537da2899SCharles.Forsyth			ex.funcproto, me);
58637da2899SCharles.Forsyth	o.construct = o.call;
58737da2899SCharles.Forsyth
58837da2899SCharles.Forsyth	o = ES->biinst(winobj, Builtin("Option", "Option", array[] of {"text", "value", "defaultSelected", "selected"}, 4),
58937da2899SCharles.Forsyth			ex.funcproto, me);
59037da2899SCharles.Forsyth	o.construct = o.call;
59137da2899SCharles.Forsyth	defaultStatus = "";
59237da2899SCharles.Forsyth	return (ex, locobj);
59337da2899SCharles.Forsyth}
59437da2899SCharles.Forsyth
59537da2899SCharles.Forsythmknavobj(ex: ref Exec) : ref Obj
59637da2899SCharles.Forsyth{
59737da2899SCharles.Forsyth	navobj := mkhostobj(ex, "navigator");
59837da2899SCharles.Forsyth	reinitprop(navobj, "appCodeName", ES->strval("Mozilla"));
59937da2899SCharles.Forsyth	reinitprop(navobj, "appName", ES->strval("Netscape"));
60037da2899SCharles.Forsyth#	reinitprop(navobj, "appVersion", ES->strval("3.0 (Inferno, U)"));
60137da2899SCharles.Forsyth#	reinitprop(navobj, "userAgent", ES->strval("Mozilla/3.0 (Inferno; U)"));
60237da2899SCharles.Forsyth	reinitprop(navobj, "appVersion", ES->strval("4.08 (Charon; Inferno)"));
60337da2899SCharles.Forsyth	reinitprop(navobj, "userAgent", ES->strval("Mozilla/4.08 (Charon; Inferno)"));
60437da2899SCharles.Forsyth
60537da2899SCharles.Forsyth	omty := getobj(ex, navobj, "mimeTypes");
60637da2899SCharles.Forsyth	for(i := 0; i < len mimespecs; i++) {
60737da2899SCharles.Forsyth		sp := mimespecs[i];
60837da2899SCharles.Forsyth		v := mkhostobj(ex, "MimeType");
60937da2899SCharles.Forsyth		reinitprop(v, "description", ES->strval(sp.description));
61037da2899SCharles.Forsyth		reinitprop(v, "suffixes", ES->strval(sp.suffixes));
61137da2899SCharles.Forsyth		reinitprop(v, "type", ES->strval(sp.ty));
61237da2899SCharles.Forsyth		arrayput(ex, omty, i, sp.ty, ES->objval(v));
61337da2899SCharles.Forsyth	}
61437da2899SCharles.Forsyth	return navobj;
61537da2899SCharles.Forsyth}
61637da2899SCharles.Forsyth
61737da2899SCharles.Forsyth# Something changed in charon's frame tree
61837da2899SCharles.Forsythframetreechanged(t: ref Layout->Frame)
61937da2899SCharles.Forsyth{
62037da2899SCharles.Forsyth	rebuild : ref ScriptWin;
62137da2899SCharles.Forsyth	if (top == nil) {
62237da2899SCharles.Forsyth		(ex, loc) := makeframeex(t);
62337da2899SCharles.Forsyth		top = ScriptWin.new(t, ex, loc, nil);
62437da2899SCharles.Forsyth		rebuild = top;
62537da2899SCharles.Forsyth	} else {
62637da2899SCharles.Forsyth		rebuild = top.findbyframeid(t.id);
62737da2899SCharles.Forsyth		# t could be new frame - need to look for parent
62837da2899SCharles.Forsyth		while (rebuild == nil && t.parent != nil) {
62937da2899SCharles.Forsyth			t = t.parent;
63037da2899SCharles.Forsyth			rebuild = top.findbyframeid(t.id);
63137da2899SCharles.Forsyth		}
63237da2899SCharles.Forsyth		# if we haven't found it by now, it's not in the official Frame
63337da2899SCharles.Forsyth		# hierarchy, so ignore it
63437da2899SCharles.Forsyth	}
63537da2899SCharles.Forsyth	if (rebuild != nil)
63637da2899SCharles.Forsyth		wininstant(rebuild);
63737da2899SCharles.Forsyth}
63837da2899SCharles.Forsyth
63937da2899SCharles.Forsyth# Frame f has just been reset, then given a new doc field
64037da2899SCharles.Forsyth# (with initial values for src, base, refresh, chset).
64137da2899SCharles.Forsyth# We'll defer doing any actual building of the script objects
64237da2899SCharles.Forsyth# until an evalscript; that way, pages that don't use scripts
64337da2899SCharles.Forsyth# incur minimum penalties).
64437da2899SCharles.Forsythhavenewdoc(f: ref Layout->Frame)
64537da2899SCharles.Forsyth{
64637da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
64737da2899SCharles.Forsyth	if(sw != nil) {
64837da2899SCharles.Forsyth		sw.inbuild = 1;
64937da2899SCharles.Forsyth		sw.forms = nil;
65037da2899SCharles.Forsyth		(sw.ex, sw.locobj) = makeframeex(f);
65137da2899SCharles.Forsyth		if (sw.val != nil)
65237da2899SCharles.Forsyth			# global object is referenced via parent.frames array
65337da2899SCharles.Forsyth			sw.val.obj = sw.ex.global;
65437da2899SCharles.Forsyth		wininstant(sw);
65537da2899SCharles.Forsyth	}
65637da2899SCharles.Forsyth}
65737da2899SCharles.Forsyth
65837da2899SCharles.Forsyth# returns (error, output, value)
65937da2899SCharles.Forsyth# error: error message
66037da2899SCharles.Forsyth# output: result of any document.writes
66137da2899SCharles.Forsyth# value: value of last statement executed (used for handling "javascript:" URL scheme)
66237da2899SCharles.Forsyth#
66337da2899SCharles.Forsythevalscript(f: ref Layout->Frame, s: string) : (string, string, string)
66437da2899SCharles.Forsyth{
66537da2899SCharles.Forsyth	if (top.error)
66637da2899SCharles.Forsyth		return("scripts disabled for this document", "", "");
66737da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
66837da2899SCharles.Forsyth	if (sw == nil)
66937da2899SCharles.Forsyth		return("cannot find script window", "", "");
67037da2899SCharles.Forsyth	if (sw.ex == nil)
67137da2899SCharles.Forsyth		return("script window has no execution context", "", "");
67237da2899SCharles.Forsyth	if(sw == nil || sw.ex == nil)
67337da2899SCharles.Forsyth		return ("", "", "");
67437da2899SCharles.Forsyth
67537da2899SCharles.Forsyth	ex := sw.ex;
67637da2899SCharles.Forsyth	sw.docwriteout = "";
67737da2899SCharles.Forsyth	expval := "";
67837da2899SCharles.Forsyth	createdimages = nil;
67937da2899SCharles.Forsyth	{
68037da2899SCharles.Forsyth		xfertoscriptobjs(f, 1);
68137da2899SCharles.Forsyth		if(s != "") {
68237da2899SCharles.Forsyth			ex.error = nil;
68337da2899SCharles.Forsyth			c := ES->eval(ex, s);
68437da2899SCharles.Forsyth			if (c.kind == ES->CThrow && dbg) {
68537da2899SCharles.Forsyth				sys->print("unhandled error:\n\tvalue:%s\n\treason:%s\n",
68637da2899SCharles.Forsyth					ES->toString(ex, c.val), ex.error);
68737da2899SCharles.Forsyth				sys->print("%s\n", s);
68837da2899SCharles.Forsyth			}
68937da2899SCharles.Forsyth			if (c.kind == ES->CNormal && c.val != nil) {
69037da2899SCharles.Forsyth				if (ES->isstr(c.val))
69137da2899SCharles.Forsyth					expval = c.val.str;
69237da2899SCharles.Forsyth			}
69337da2899SCharles.Forsyth			xferfromscriptobjs(f, 1);
69437da2899SCharles.Forsyth			checknewlocs(top);
69537da2899SCharles.Forsyth			checkopener();
69637da2899SCharles.Forsyth		}
69737da2899SCharles.Forsyth		w := sw.docwriteout;
69837da2899SCharles.Forsyth		sw.docwriteout = nil;
69937da2899SCharles.Forsyth		return("", w, expval);
70037da2899SCharles.Forsyth	}exception exc{
70137da2899SCharles.Forsyth	"*" =>
70237da2899SCharles.Forsyth		if(dbg) {
70337da2899SCharles.Forsyth			sys->print("fatal error %q executing evalscript: %s\nscript=", exc, ex.error);
70437da2899SCharles.Forsyth			sa := array of byte s;
70537da2899SCharles.Forsyth			sys->write(sys->fildes(1), sa, len sa);
70637da2899SCharles.Forsyth			sys->print("\n");
70737da2899SCharles.Forsyth		}
70837da2899SCharles.Forsyth		top.error = 1;
70937da2899SCharles.Forsyth		emsg := "Fatal error processing script\n\nScript processing suspended for this page";
71037da2899SCharles.Forsyth		G->alert(emsg);
71137da2899SCharles.Forsyth		w := sw.docwriteout;
71237da2899SCharles.Forsyth		sw.docwriteout = nil;
71337da2899SCharles.Forsyth		return (ex.error, w, "");
71437da2899SCharles.Forsyth	}
71537da2899SCharles.Forsyth}
71637da2899SCharles.Forsyth
71737da2899SCharles.Forsythxfertoscriptobjs(f: ref Layout->Frame, inbuild: int)
71837da2899SCharles.Forsyth{
71937da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
72037da2899SCharles.Forsyth	if(sw == nil)
72137da2899SCharles.Forsyth		return;
72237da2899SCharles.Forsyth	ex := sw.ex;
72337da2899SCharles.Forsyth	ow := ex.global;
72437da2899SCharles.Forsyth	di := f.doc;
72537da2899SCharles.Forsyth
72637da2899SCharles.Forsyth	for(el := di.events; el != nil; el = tl el) {
72737da2899SCharles.Forsyth		e := hd el;
72837da2899SCharles.Forsyth		hname := "";
72937da2899SCharles.Forsyth		dhname := "";
73037da2899SCharles.Forsyth		case e.attid {
73137da2899SCharles.Forsyth		Lex->Aonblur =>
73237da2899SCharles.Forsyth			hname = "onblur";
73337da2899SCharles.Forsyth			di.evmask |= E->SEonblur;
73437da2899SCharles.Forsyth		Lex->Aonerror =>
73537da2899SCharles.Forsyth			hname = "onerror";
73637da2899SCharles.Forsyth			di.evmask |= E->SEonerror;
73737da2899SCharles.Forsyth		Lex->Aonfocus =>
73837da2899SCharles.Forsyth			hname = "onfocus";
73937da2899SCharles.Forsyth			di.evmask |= E->SEonfocus;
74037da2899SCharles.Forsyth		Lex->Aonload =>
74137da2899SCharles.Forsyth			hname = "onload";
74237da2899SCharles.Forsyth			di.evmask |= E->SEonload;
74337da2899SCharles.Forsyth		Lex->Aonresize =>
74437da2899SCharles.Forsyth			hname = "onresize";
74537da2899SCharles.Forsyth			di.evmask |= E->SEonresize;
74637da2899SCharles.Forsyth		Lex->Aonunload =>
74737da2899SCharles.Forsyth			hname = "onunload";
74837da2899SCharles.Forsyth			di.evmask |= E->SEonunload;
74937da2899SCharles.Forsyth		Lex->Aondblclick =>
75037da2899SCharles.Forsyth			dhname = "ondblclick";
75137da2899SCharles.Forsyth			di.evmask |= E->SEondblclick;
75237da2899SCharles.Forsyth		Lex->Aonkeydown =>
75337da2899SCharles.Forsyth			dhname = "onkeydown";
75437da2899SCharles.Forsyth			di.evmask |= E->SEonkeydown;
75537da2899SCharles.Forsyth		Lex->Aonkeypress =>
75637da2899SCharles.Forsyth			dhname = "onkeypress";
75737da2899SCharles.Forsyth			di.evmask |= E->SEonkeypress;
75837da2899SCharles.Forsyth		Lex->Aonkeyup =>
75937da2899SCharles.Forsyth			dhname = "onkeyup";
76037da2899SCharles.Forsyth			di.evmask |= E->SEonkeyup;
76137da2899SCharles.Forsyth		Lex->Aonmousedown =>
76237da2899SCharles.Forsyth			dhname = "onmousedown";
76337da2899SCharles.Forsyth			di.evmask |= E->SEonmousedown;
76437da2899SCharles.Forsyth		Lex->Aonmouseup =>
76537da2899SCharles.Forsyth			dhname = "onmouseup";
76637da2899SCharles.Forsyth			di.evmask |= E->SEonmouseup;
76737da2899SCharles.Forsyth		}
76837da2899SCharles.Forsyth		if(hname != "")
76937da2899SCharles.Forsyth			puthandler(ex, ow, hname, e.value);
77037da2899SCharles.Forsyth		if(dhname != ""){
77137da2899SCharles.Forsyth			od := getobj(ex, ow, "document");
77237da2899SCharles.Forsyth			if(od == nil) {
77337da2899SCharles.Forsyth				reinitprop(ow, "document", docinstant(ex, f));
77437da2899SCharles.Forsyth				od = getobj(ex, ow, "document");
77537da2899SCharles.Forsyth			}
77637da2899SCharles.Forsyth			puthandler(ex, od, dhname, e.value);
77737da2899SCharles.Forsyth		}
77837da2899SCharles.Forsyth	}
77937da2899SCharles.Forsyth	di.events = nil;
78037da2899SCharles.Forsyth
78137da2899SCharles.Forsyth	od := getobj(ex, ow, "document");
78237da2899SCharles.Forsyth	if(od == nil) {
78337da2899SCharles.Forsyth		reinitprop(ow, "document", docinstant(ex, f));
78437da2899SCharles.Forsyth		od = getobj(ex, ow, "document");
78537da2899SCharles.Forsyth		CU->assert(od != nil);
78637da2899SCharles.Forsyth	}
78737da2899SCharles.Forsyth	else if(inbuild) {
78837da2899SCharles.Forsyth		docfill(ex, od, f);
78937da2899SCharles.Forsyth		ES->put(ex, od, "location", ES->objval(sw.locobj));
79037da2899SCharles.Forsyth	}
79137da2899SCharles.Forsyth	for(frml := sw.forms; frml != nil; frml = tl frml) {
79237da2899SCharles.Forsyth		frm := hd frml;
79337da2899SCharles.Forsyth		for (fldl := frm.fields; fldl != nil; fldl = tl fldl) {
79437da2899SCharles.Forsyth			(fld, ofield) := hd fldl;
79537da2899SCharles.Forsyth			if (ofield == nil)
79637da2899SCharles.Forsyth				continue;
79737da2899SCharles.Forsyth			if(fld.ctlid >= 0 && fld.ctlid < len f.controls) {
79837da2899SCharles.Forsyth				pick c := f.controls[fld.ctlid] {
79937da2899SCharles.Forsyth				Centry =>
80037da2899SCharles.Forsyth					reinitprop(ofield, "value", ES->strval(c.s));
80137da2899SCharles.Forsyth				Ccheckbox =>
80237da2899SCharles.Forsyth					cv := ES->false;
80337da2899SCharles.Forsyth					if(c.flags&Layout->CFactive)
80437da2899SCharles.Forsyth						cv = ES->true;
80537da2899SCharles.Forsyth					reinitprop(ofield, "checked", cv);
80637da2899SCharles.Forsyth				Cselect =>
80737da2899SCharles.Forsyth					for(i := 0; i < len c.options; i++) {
80837da2899SCharles.Forsyth						if(c.options[i].selected) {
80937da2899SCharles.Forsyth							reinitprop(ofield, "selectedIndex", ES->numval(real i));
81037da2899SCharles.Forsyth							# hack for common mistake in scripts
81137da2899SCharles.Forsyth							# (implemented by other browsers)
81237da2899SCharles.Forsyth							opts := getobj(ex, ofield, "options");
81337da2899SCharles.Forsyth							if (opts != nil)
81437da2899SCharles.Forsyth								reinitprop(opts, "selectedIndex", ES->numval(real i));
81537da2899SCharles.Forsyth						}
81637da2899SCharles.Forsyth					}
81737da2899SCharles.Forsyth				}
81837da2899SCharles.Forsyth			}
81937da2899SCharles.Forsyth		}
82037da2899SCharles.Forsyth	}
82137da2899SCharles.Forsyth	for(sil := sw.imgs; sil != nil; sil = tl sil) {
82237da2899SCharles.Forsyth		si := hd sil;
82337da2899SCharles.Forsyth		if(si.item.ci.complete != 0)
82437da2899SCharles.Forsyth			reinitprop(si.obj, "complete", ES->true);
82537da2899SCharles.Forsyth	}
82637da2899SCharles.Forsyth}
82737da2899SCharles.Forsyth
82837da2899SCharles.Forsythxferfromscriptobjs(f: ref Layout->Frame, inbuild: int)
82937da2899SCharles.Forsyth{
83037da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
83137da2899SCharles.Forsyth	if(sw == nil)
83237da2899SCharles.Forsyth		return;
83337da2899SCharles.Forsyth	ex := sw.ex;
83437da2899SCharles.Forsyth	ow := ex.global;
83537da2899SCharles.Forsyth	od := getobj(ex, ow, "document");
83637da2899SCharles.Forsyth	if(od != nil) {
83737da2899SCharles.Forsyth		if(inbuild) {
83837da2899SCharles.Forsyth			di := f.doc;
83937da2899SCharles.Forsyth			di.doctitle = strxfer(ex, od, "title", di.doctitle);
84037da2899SCharles.Forsyth			di.background.color = colorxfer(ex, od, "bgColor", di.background.color);
84137da2899SCharles.Forsyth			di.text = colorxfer(ex, od, "fgColor", di.text);
84237da2899SCharles.Forsyth			di.alink = colorxfer(ex, od, "alinkColor", di.alink);
84337da2899SCharles.Forsyth			di.link = colorxfer(ex, od, "linkColor", di.link);
84437da2899SCharles.Forsyth			di.vlink = colorxfer(ex, od, "vlinkColor", di.vlink);
84537da2899SCharles.Forsyth			if(createdimages != nil) {
84637da2899SCharles.Forsyth				for(oil := createdimages; oil != nil; oil = tl oil) {
84737da2899SCharles.Forsyth					oi := hd oil;
84837da2899SCharles.Forsyth					vsrc := ES->get(ex, oi, "src");
84937da2899SCharles.Forsyth					if(ES->isstr(vsrc)) {
85037da2899SCharles.Forsyth						u := U->parse(vsrc.str);
85137da2899SCharles.Forsyth						if(u.path != "") {
85237da2899SCharles.Forsyth							u = U->mkabs(u, di.base);
85337da2899SCharles.Forsyth							it := Item.newimage(di, u, nil, "", B->Anone,
85437da2899SCharles.Forsyth								0, 0, 0, 0, 0, 0, 0, nil, nil, nil);
85537da2899SCharles.Forsyth							di.images = it :: di.images;
85637da2899SCharles.Forsyth						}
85737da2899SCharles.Forsyth					}
85837da2899SCharles.Forsyth				}
85937da2899SCharles.Forsyth			}
86037da2899SCharles.Forsyth		}
86137da2899SCharles.Forsyth		else {
86237da2899SCharles.Forsyth			for (ol := sw.imgrelocs; ol != nil; ol = tl ol) {
86337da2899SCharles.Forsyth				oi := hd ol;
86437da2899SCharles.Forsyth				vnewsrc := ES->get(ex, oi, "src");
86537da2899SCharles.Forsyth				if(ES->isstr(vnewsrc) && vnewsrc.str != nil) {
86637da2899SCharles.Forsyth					for(sil := sw.imgs; sil != nil; sil = tl sil) {
86737da2899SCharles.Forsyth						si := hd sil;
86837da2899SCharles.Forsyth						if(si.obj == oi) {
86937da2899SCharles.Forsyth							f.swapimage(si.item, vnewsrc.str);
87037da2899SCharles.Forsyth							break;
87137da2899SCharles.Forsyth						}
87237da2899SCharles.Forsyth					}
87337da2899SCharles.Forsyth				}
87437da2899SCharles.Forsyth			}
87537da2899SCharles.Forsyth			sw.imgrelocs = nil;
87637da2899SCharles.Forsyth		}
87737da2899SCharles.Forsyth	}
87837da2899SCharles.Forsyth}
87937da2899SCharles.Forsyth
88037da2899SCharles.Forsyth# Check ScriptWin tree for non-empty newlocs.
88137da2899SCharles.Forsyth# When found, generate a go event to the new place.
88237da2899SCharles.Forsyth# If found, don't recurse into children, because those
88337da2899SCharles.Forsyth# child frames are about to go away anyway.
88437da2899SCharles.Forsyth# Otherwise, recurse into all kids -- this might generate
88537da2899SCharles.Forsyth# multiple go events.
88637da2899SCharles.Forsyth# BUG: if multiple events are generated, later ones will
88737da2899SCharles.Forsyth# interrupt (STOP!) loading of pages specified by preceding
88837da2899SCharles.Forsyth# events.  To fix, need to queue them up, probably in
88937da2899SCharles.Forsyth# main charon module.
89037da2899SCharles.Forsythchecknewlocs(sw: ref ScriptWin)
89137da2899SCharles.Forsyth{
89237da2899SCharles.Forsyth	if(sw.newloc != "") {
89337da2899SCharles.Forsyth		E->evchan <-= ref Event.Ego(sw.newloc, sw.newloctarg, 0, E->EGnormal);
89437da2899SCharles.Forsyth		sw.newloc = "";
89537da2899SCharles.Forsyth	}
89637da2899SCharles.Forsyth	else {
89737da2899SCharles.Forsyth		for(l := sw.kids; l != nil; l = tl l)
89837da2899SCharles.Forsyth			checknewlocs(hd l);
89937da2899SCharles.Forsyth	}
90037da2899SCharles.Forsyth}
90137da2899SCharles.Forsyth
90237da2899SCharles.Forsythcheckopener()
90337da2899SCharles.Forsyth{
90437da2899SCharles.Forsyth	if(opener != nil && opener.newloc != "") {
90537da2899SCharles.Forsyth		CH->sendopener(sys->sprint("L %s", opener.newloc));	# just location for now
90637da2899SCharles.Forsyth		opener.newloc = "";
90737da2899SCharles.Forsyth	}
90837da2899SCharles.Forsyth	if(winclose)
90937da2899SCharles.Forsyth		G->exitcharon();
91037da2899SCharles.Forsyth}
91137da2899SCharles.Forsyth
91237da2899SCharles.Forsyth# if e.anchorid >= 0	=> target is Link
91337da2899SCharles.Forsyth# if e.fieldid > 0	=> target is FormField (and e.formid > 0)
91437da2899SCharles.Forsyth# if e.formid > 0	=> target is Form (e.fieldid == -1)
91537da2899SCharles.Forsyth# if e.imageid >= 0	=> target is Image
91637da2899SCharles.Forsyth# otherwise		=> target is window
91737da2899SCharles.Forsythdo_on(e: ref ScriptEvent)
91837da2899SCharles.Forsyth{
91937da2899SCharles.Forsyth	if(dbgdom)
92037da2899SCharles.Forsyth		sys->print("do_on %d, frameid=%d, formid=%d, fieldid=%d, anchorid=%d, imageid=%d, x=%d, y=%d, which=%d\n",
92137da2899SCharles.Forsyth			e.kind, e.frameid, e.formid, e.fieldid, e.anchorid, e.imageid, e.x, e.y, e.which);
92237da2899SCharles.Forsyth	if (top.error) {
92337da2899SCharles.Forsyth		if (dbgdom)
92437da2899SCharles.Forsyth			sys->print("do_on() previous error prevents processing\n");
92537da2899SCharles.Forsyth		if (e.reply != nil)
92637da2899SCharles.Forsyth			e.reply <-= nil;
92737da2899SCharles.Forsyth		jevchan <-= ref doneevent;
92837da2899SCharles.Forsyth		return;
92937da2899SCharles.Forsyth	}
93037da2899SCharles.Forsyth	sw := top.findbyframeid(e.frameid);
93137da2899SCharles.Forsyth	# BUG FIX: Frame can be reset by Charon main thread
93237da2899SCharles.Forsyth	# between us getting its ref and using it
93337da2899SCharles.Forsyth	# WARNING - xferfromscriptobjs() will not update non-ref-type members of frame adt
93437da2899SCharles.Forsyth	# (currently not a problem) as updates will go to our copy
93537da2899SCharles.Forsyth	f : ref Frame;
93637da2899SCharles.Forsyth	if (sw != nil && !sw.inbuild) {
93737da2899SCharles.Forsyth		f = ref *sw.frame;
93837da2899SCharles.Forsyth		if (f.doc == nil)
93937da2899SCharles.Forsyth			f = nil;
94037da2899SCharles.Forsyth	}
94137da2899SCharles.Forsyth	if (f == nil) {
94237da2899SCharles.Forsyth		if(e.reply != nil)
94337da2899SCharles.Forsyth			e.reply <-= nil;
94437da2899SCharles.Forsyth		jevchan <-= ref doneevent;
94537da2899SCharles.Forsyth		if (dbgdom)
94637da2899SCharles.Forsyth			sys->print("do_on() failed to find frame %d\n", e.frameid);
94737da2899SCharles.Forsyth		return;
94837da2899SCharles.Forsyth	}
94937da2899SCharles.Forsyth	ex := sw.ex;
95037da2899SCharles.Forsyth	ow := ex.global;
95137da2899SCharles.Forsyth	od := getobj(ex, ow, "document");
95237da2899SCharles.Forsyth	sw.docwriteout = nil;
95337da2899SCharles.Forsyth
95437da2899SCharles.Forsyth{
95537da2899SCharles.Forsyth	# event target types
95637da2899SCharles.Forsyth	TAnchor, TForm, TFormField, TImage, TDocument, TWindow, Tnone: con iota;
95737da2899SCharles.Forsyth	ttype := Tnone;
95837da2899SCharles.Forsyth	target, oform: ref Obj;
95937da2899SCharles.Forsyth	if(e.anchorid >= 0) {
96037da2899SCharles.Forsyth		ttype = TAnchor;
96137da2899SCharles.Forsyth		target = getanchorobj(ex, e.frameid, e.anchorid);
96237da2899SCharles.Forsyth	} else if(e.formid > 0) {
96337da2899SCharles.Forsyth		oform = getformobj(ex, e.frameid, e.formid);
96437da2899SCharles.Forsyth		if(e.fieldid > 0) {
96537da2899SCharles.Forsyth			ttype = TFormField;
96637da2899SCharles.Forsyth			target = getformfieldobj(e.frameid, e.formid, e.fieldid);
96737da2899SCharles.Forsyth		} else {
96837da2899SCharles.Forsyth			ttype = TForm;
96937da2899SCharles.Forsyth			target = oform;
97037da2899SCharles.Forsyth		}
97137da2899SCharles.Forsyth	} else if(e.imageid >= 0) {
97237da2899SCharles.Forsyth		ttype = TImage;
97337da2899SCharles.Forsyth		target = getimageobj(ex, e.frameid, e.imageid);
97437da2899SCharles.Forsyth	} else if(e.kind == E->SEondblclick || e.kind == E->SEonkeydown ||
97537da2899SCharles.Forsyth		    e.kind == E->SEonkeypress || e.kind == E->SEonkeyup ||
97637da2899SCharles.Forsyth		    e.kind == E->SEonmousedown || e.kind == E->SEonmouseup){
97737da2899SCharles.Forsyth		ttype = TDocument;
97837da2899SCharles.Forsyth		target = od;
97937da2899SCharles.Forsyth	} else {
98037da2899SCharles.Forsyth		ttype = TWindow;
98137da2899SCharles.Forsyth		target = ow;
98237da2899SCharles.Forsyth	}
98337da2899SCharles.Forsyth	if(target != nil) {
98437da2899SCharles.Forsyth		oscript: ref Obj;
98537da2899SCharles.Forsyth		scrname := "";
98637da2899SCharles.Forsyth		case e.kind {
98737da2899SCharles.Forsyth		E->SEonabort =>
98837da2899SCharles.Forsyth			scrname = "onabort";
98937da2899SCharles.Forsyth		E->SEonblur =>
99037da2899SCharles.Forsyth			scrname = "onblur";
99137da2899SCharles.Forsyth		E->SEonchange =>
99237da2899SCharles.Forsyth			scrname = "onchange";
99337da2899SCharles.Forsyth		E->SEonclick =>
99437da2899SCharles.Forsyth			scrname = "onclick";
99537da2899SCharles.Forsyth		E->SEondblclick =>
99637da2899SCharles.Forsyth			scrname = "ondblclick";
99737da2899SCharles.Forsyth		E->SEonerror =>
99837da2899SCharles.Forsyth			scrname = "onerror";
99937da2899SCharles.Forsyth		E->SEonfocus =>
100037da2899SCharles.Forsyth			scrname = "onfocus";
100137da2899SCharles.Forsyth		E->SEonkeydown =>
100237da2899SCharles.Forsyth			scrname = "onkeydown";
100337da2899SCharles.Forsyth		E->SEonkeypress =>
100437da2899SCharles.Forsyth			scrname = "onkeypress";
100537da2899SCharles.Forsyth		E->SEonkeyup =>
100637da2899SCharles.Forsyth			scrname = "onkeyup";
100737da2899SCharles.Forsyth		E->SEonload =>
100837da2899SCharles.Forsyth			scrname = "onload";
100937da2899SCharles.Forsyth		E->SEonmousedown =>
101037da2899SCharles.Forsyth			scrname = "onmousedown";
101137da2899SCharles.Forsyth		E->SEonmouseout =>
101237da2899SCharles.Forsyth			scrname = "onmouseout";
101337da2899SCharles.Forsyth		E->SEonmouseover =>
101437da2899SCharles.Forsyth			scrname = "onmouseover";
101537da2899SCharles.Forsyth		E->SEonmouseup =>
101637da2899SCharles.Forsyth			scrname = "onmouseup";
101737da2899SCharles.Forsyth		E->SEonreset =>
101837da2899SCharles.Forsyth			scrname = "onreset";
101937da2899SCharles.Forsyth		E->SEonresize =>
102037da2899SCharles.Forsyth			scrname = "onresize";
102137da2899SCharles.Forsyth		E->SEonselect =>
102237da2899SCharles.Forsyth			scrname = "onselect";
102337da2899SCharles.Forsyth		E->SEonsubmit =>
102437da2899SCharles.Forsyth			scrname = "onsubmit";
102537da2899SCharles.Forsyth		E->SEonunload =>
102637da2899SCharles.Forsyth			scrname = "onunload";
102737da2899SCharles.Forsyth		E->SEtimeout or
102837da2899SCharles.Forsyth		E->SEinterval =>
102937da2899SCharles.Forsyth			oscript = dotimeout(ex, target, e);
103037da2899SCharles.Forsyth		E->SEscript =>
103137da2899SCharles.Forsyth			# TODO - handle document text from evalscript
103237da2899SCharles.Forsyth			# need to determine if document is 'open' or not.
10338911721eSCharles.Forsyth			(nil, nil, val) := evalscript(f, e.script);
103437da2899SCharles.Forsyth			if (e.reply != nil)
103537da2899SCharles.Forsyth				e.reply <- = val;
103637da2899SCharles.Forsyth			e.reply = nil;
103737da2899SCharles.Forsyth		}
103837da2899SCharles.Forsyth		if(scrname != "")
103937da2899SCharles.Forsyth			oscript = getobj(ex, target, scrname);
104037da2899SCharles.Forsyth		if(oscript != nil) {
104137da2899SCharles.Forsyth			xfertoscriptobjs(f, 0);
104237da2899SCharles.Forsyth			if(dbgdom)
104337da2899SCharles.Forsyth				sys->print("calling script\n");
104437da2899SCharles.Forsyth			# establish scope chain per Rhino p. 287 (3rd edition)
104537da2899SCharles.Forsyth			oldsc := ex.scopechain;
104637da2899SCharles.Forsyth			sc := ow :: nil;
104737da2899SCharles.Forsyth			if(ttype != TWindow) {
104837da2899SCharles.Forsyth				sc = od :: sc;
104937da2899SCharles.Forsyth				if(ttype == TFormField)
105037da2899SCharles.Forsyth					sc = oform :: sc;
105137da2899SCharles.Forsyth				if(ttype != TDocument)
105237da2899SCharles.Forsyth					sc = target :: sc;
105337da2899SCharles.Forsyth			}
105437da2899SCharles.Forsyth			ex.scopechain = sc;
105537da2899SCharles.Forsyth			v := ES->call(ex, oscript, target, nil, 1).val;
105637da2899SCharles.Forsyth			# 'fix' for onsubmit
105737da2899SCharles.Forsyth			# JS references state that if the handler returns false
105837da2899SCharles.Forsyth			# then the action is cancelled.
105937da2899SCharles.Forsyth			# other browsers interpret this as "if and only if the handler
106037da2899SCharles.Forsyth			# returns false."
106137da2899SCharles.Forsyth			# When a function completes normally without returning a value
106237da2899SCharles.Forsyth			# its value is 'undefined', toBoolean(undefined) = false
106337da2899SCharles.Forsyth			if (v == ES->undefined)
106437da2899SCharles.Forsyth				v = ES->true;
106537da2899SCharles.Forsyth			else
106637da2899SCharles.Forsyth				v = ES->toBoolean(ex, v);
106737da2899SCharles.Forsyth			ex.scopechain = oldsc;
106837da2899SCharles.Forsyth			# onreset/onsubmit reply channel
106937da2899SCharles.Forsyth			if(e.reply != nil) {
107037da2899SCharles.Forsyth				ans : string;
107137da2899SCharles.Forsyth				if(v == ES->true)
107237da2899SCharles.Forsyth					ans = "true";
107337da2899SCharles.Forsyth				e.reply <-= ans;
107437da2899SCharles.Forsyth				e.reply = nil;
107537da2899SCharles.Forsyth			}
107637da2899SCharles.Forsyth			xferfromscriptobjs(f, 0);
107737da2899SCharles.Forsyth			checknewlocs(top);
107837da2899SCharles.Forsyth			checkopener();
107937da2899SCharles.Forsyth
108037da2899SCharles.Forsyth			if (ttype == TFormField && e.kind == E->SEonclick && v == ES->true)
108137da2899SCharles.Forsyth				E->evchan <-= ref Event.Eformfield(e.frameid, e.formid, e.fieldid, E->EFFclick);
108237da2899SCharles.Forsyth			if (ttype == TAnchor && e.kind == E->SEonclick && v == ES->true) {
108337da2899SCharles.Forsyth				gohref := getstr(ex, target, "href");
108437da2899SCharles.Forsyth				gotarget := getstr(ex, target, "target");
108537da2899SCharles.Forsyth				if (gotarget == "")
108637da2899SCharles.Forsyth					gotarget = "_self";
108737da2899SCharles.Forsyth				E->evchan <-= ref Event.Ego(gohref, gotarget, 0, E->EGnormal);
108837da2899SCharles.Forsyth			}
108937da2899SCharles.Forsyth		}
109037da2899SCharles.Forsyth	}
109137da2899SCharles.Forsyth	if(e.reply != nil)
109237da2899SCharles.Forsyth		e.reply <-= nil;
109337da2899SCharles.Forsyth	checkdocwrite(top);
109437da2899SCharles.Forsyth	jevchan <-= ref doneevent;
109537da2899SCharles.Forsyth}
109637da2899SCharles.Forsythexception exc{
109737da2899SCharles.Forsyth	"*" =>
109837da2899SCharles.Forsyth		if (exc == "throw") {
109937da2899SCharles.Forsyth			# ignore ecmascript runtime errors
110037da2899SCharles.Forsyth			if(dbgdom)
110137da2899SCharles.Forsyth				sys->print("error executing 'on' handler: %s\n", ex.error);
110237da2899SCharles.Forsyth		} else {
110337da2899SCharles.Forsyth			# fatal error
110437da2899SCharles.Forsyth			top.error = 1;
110537da2899SCharles.Forsyth			emsg := "Fatal error in script ("+exc+"):\n" + ex.error + "\n";
110637da2899SCharles.Forsyth			G->alert(emsg);
110737da2899SCharles.Forsyth		}
110837da2899SCharles.Forsyth		if(e.reply != nil)
110937da2899SCharles.Forsyth			e.reply <-= nil;
111037da2899SCharles.Forsyth		jevchan <-= ref doneevent;
111137da2899SCharles.Forsyth		return;
111237da2899SCharles.Forsyth}
111337da2899SCharles.Forsyth}
111437da2899SCharles.Forsyth
111537da2899SCharles.Forsythxferframeset(sw : ref ScriptWin)
111637da2899SCharles.Forsyth{
111737da2899SCharles.Forsyth	if (!sw.inbuild)
111837da2899SCharles.Forsyth		xfertoscriptobjs(sw.frame, 1);
111937da2899SCharles.Forsyth	for (k := sw.kids; k != nil; k = tl k)
112037da2899SCharles.Forsyth		xferframeset(hd k);
112137da2899SCharles.Forsyth}
112237da2899SCharles.Forsyth
112337da2899SCharles.Forsythframedone(f : ref Frame, hasscripts : int)
112437da2899SCharles.Forsyth{
112537da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
112637da2899SCharles.Forsyth	if (sw != nil) {
112737da2899SCharles.Forsyth		if (!top.active && hasscripts) {
112837da2899SCharles.Forsyth			# need to transfer entire frame tree
112937da2899SCharles.Forsyth			# as one frame can reference objects in another
113037da2899SCharles.Forsyth			xferframeset(top);
113137da2899SCharles.Forsyth		}
113237da2899SCharles.Forsyth		sw.active |= hasscripts;
113337da2899SCharles.Forsyth		top.active |= hasscripts;
113437da2899SCharles.Forsyth		if (top.active)
113537da2899SCharles.Forsyth			xfertoscriptobjs(f, 1);
113637da2899SCharles.Forsyth		sw.inbuild = 0;
113737da2899SCharles.Forsyth	}
113837da2899SCharles.Forsyth}
113937da2899SCharles.Forsyth
114037da2899SCharles.Forsythcheckdocwrite(sw : ref ScriptWin) : int
114137da2899SCharles.Forsyth{
114237da2899SCharles.Forsyth	if (sw.inbuild)
114337da2899SCharles.Forsyth		return 0;
114437da2899SCharles.Forsyth
114537da2899SCharles.Forsyth	if (sw.docwriteout != nil) {
114637da2899SCharles.Forsyth		# The URL is bogus - not sure what the correct value should be
114737da2899SCharles.Forsyth		ev := ref Event.Esettext(sw.frame.id, sw.frame.src, sw.docwriteout);
114837da2899SCharles.Forsyth		sw.docwriteout = "";
114937da2899SCharles.Forsyth		E->evchan <- = ev;
115037da2899SCharles.Forsyth		return 1;
115137da2899SCharles.Forsyth	}
115237da2899SCharles.Forsyth	for (k := sw.kids; k != nil; k = tl k)
115337da2899SCharles.Forsyth		if (checkdocwrite(hd k))
115437da2899SCharles.Forsyth			break;
115537da2899SCharles.Forsyth	return 0;
115637da2899SCharles.Forsyth}
115737da2899SCharles.Forsyth
115837da2899SCharles.Forsyth#
115937da2899SCharles.Forsyth# interface for host objects
116037da2899SCharles.Forsyth#
116137da2899SCharles.Forsythget(ex: ref Exec, o: ref Obj, property: string): ref Val
116237da2899SCharles.Forsyth{
116337da2899SCharles.Forsyth	if(o.class == "document" && property == "cookie") {
116437da2899SCharles.Forsyth		ans := "";
116537da2899SCharles.Forsyth		target := top.findbyobj(o);
116637da2899SCharles.Forsyth		if(target != nil) {
116737da2899SCharles.Forsyth			url := target.frame.doc.src;
116837da2899SCharles.Forsyth			ans = CU->getcookies(url.host, url.path, url.scheme == "https");
116937da2899SCharles.Forsyth		}
117037da2899SCharles.Forsyth		return ES->strval(ans);
117137da2899SCharles.Forsyth	}
117237da2899SCharles.Forsyth	if(o.class == "Window" && property == "opener"){
117337da2899SCharles.Forsyth		if(!CH->hasopener() || top.ex.global != o)
117437da2899SCharles.Forsyth			v := ES->undefined;
117537da2899SCharles.Forsyth		else{
117637da2899SCharles.Forsyth			if(opener == nil)
117737da2899SCharles.Forsyth				opener = ScriptWin.dummy();
117837da2899SCharles.Forsyth			v = ES->objval(opener.ex.global);
117937da2899SCharles.Forsyth		}
118037da2899SCharles.Forsyth		reinitprop(o, "opener", v);
118137da2899SCharles.Forsyth	}
118237da2899SCharles.Forsyth	return ES->get(ex, o, property);
118337da2899SCharles.Forsyth}
118437da2899SCharles.Forsyth
118537da2899SCharles.Forsyth
118637da2899SCharles.Forsythput(ex: ref Exec, o: ref Obj, property: string, val: ref Val)
118737da2899SCharles.Forsyth{
118837da2899SCharles.Forsyth	if(dbgdom)
118937da2899SCharles.Forsyth		sys->print("put property %s in cobj of class %s\n", property, o.class);
119037da2899SCharles.Forsyth
119137da2899SCharles.Forsyth	url : ref Parsedurl;
119237da2899SCharles.Forsyth	target : ref ScriptWin;
119337da2899SCharles.Forsyth	str := ES->toString(ex, val);
119437da2899SCharles.Forsyth	ev := E->SEnone;
119537da2899SCharles.Forsyth
119637da2899SCharles.Forsyth	case o.class {
119737da2899SCharles.Forsyth	"Array" =>
119837da2899SCharles.Forsyth		# we 'host' the Formfield.options array so as we can
119937da2899SCharles.Forsyth		# track changes to the options list
120037da2899SCharles.Forsyth		vformfield := ES->get(ex, o, "@PRIVformfield");
120137da2899SCharles.Forsyth		if (!ES->isobj(vformfield))
120237da2899SCharles.Forsyth			# not one of our 'options' arrays
120337da2899SCharles.Forsyth			break;
120437da2899SCharles.Forsyth		ix := prop2index(property);
120537da2899SCharles.Forsyth		if (property != "length" && ix == -1)
120637da2899SCharles.Forsyth			# not a property that affects us
120737da2899SCharles.Forsyth			break;
120837da2899SCharles.Forsyth		oformfield := vformfield.obj;
120937da2899SCharles.Forsyth		oform := getobj(ex, oformfield, "form");
121037da2899SCharles.Forsyth		if (oform == nil)
121137da2899SCharles.Forsyth			break;
121237da2899SCharles.Forsyth		ES->put(ex, o, property, val);
121337da2899SCharles.Forsyth		if (ES->isobj(val) && val.obj.class == "Option") {
121437da2899SCharles.Forsyth			ES->put(ex, val.obj, "@PRIVformfield", vformfield);
121537da2899SCharles.Forsyth			ES->put(ex, val.obj, "form", ES->objval(oform));
121637da2899SCharles.Forsyth			reinitprop(val.obj, "index", ES->numval(real ix));
121737da2899SCharles.Forsyth		}
121837da2899SCharles.Forsyth		updateffopts(ex, oform, oformfield, ix);
121937da2899SCharles.Forsyth		return;
122037da2899SCharles.Forsyth	"Window" =>
122137da2899SCharles.Forsyth		case property {
122237da2899SCharles.Forsyth		"defaultStatus" or
122337da2899SCharles.Forsyth		"status" =>
122437da2899SCharles.Forsyth			if(ES->isstr(val)) {
122537da2899SCharles.Forsyth				if(property == "defaultStatus")
122637da2899SCharles.Forsyth					defaultStatus = val.str;
122737da2899SCharles.Forsyth				G->setstatus(val.str);
122837da2899SCharles.Forsyth			}
122937da2899SCharles.Forsyth		"location" =>
123037da2899SCharles.Forsyth			target = top.findbyobj(o);
123137da2899SCharles.Forsyth			if (target == nil)
123237da2899SCharles.Forsyth				break;
123337da2899SCharles.Forsyth			url = U->parse(str);
123437da2899SCharles.Forsyth			# TODO: be more defensive
123537da2899SCharles.Forsyth			url = U->mkabs(url, target.frame.doc.base);
123637da2899SCharles.Forsyth		"name" =>
123737da2899SCharles.Forsyth			sw := top.findbyobj(o);
123837da2899SCharles.Forsyth			if (sw == nil)
123937da2899SCharles.Forsyth				break;
124037da2899SCharles.Forsyth			name := ES->toString(ex, val);
124137da2899SCharles.Forsyth			if (sw.parent != nil) {
124237da2899SCharles.Forsyth				w := sw.parent.ex.global;
124337da2899SCharles.Forsyth				v := sw.val;
124437da2899SCharles.Forsyth				if (sw.frame.name != nil)
124537da2899SCharles.Forsyth					ES->delete(ex, w, sw.frame.name);
124637da2899SCharles.Forsyth				ES->varinstant(w, 0, name, ref RefVal(v));
124737da2899SCharles.Forsyth			}
124837da2899SCharles.Forsyth			# Window.name is used for determining TARGET of <A> etc.
124937da2899SCharles.Forsyth			# update Charon's Frame info so as new name gets used properly
125037da2899SCharles.Forsyth			sw.frame.name = name;
125137da2899SCharles.Forsyth		"offscreenBuffering" =>
125237da2899SCharles.Forsyth			if(ES->isstr(val) || val == ES->true || val == ES->false){
125337da2899SCharles.Forsyth			}
125437da2899SCharles.Forsyth		"onblur" =>
125537da2899SCharles.Forsyth			ev = E->SEonblur;
125637da2899SCharles.Forsyth		"onerror" =>
125737da2899SCharles.Forsyth			ev = E->SEonerror;
125837da2899SCharles.Forsyth		"onfocus" =>
125937da2899SCharles.Forsyth			ev = E->SEonfocus;
126037da2899SCharles.Forsyth		"onload" =>
126137da2899SCharles.Forsyth			ev = E->SEonload;
126237da2899SCharles.Forsyth		"onresize" =>
126337da2899SCharles.Forsyth			ev = E->SEonresize;
126437da2899SCharles.Forsyth		"onunload" =>
126537da2899SCharles.Forsyth			ev = E->SEonunload;
126637da2899SCharles.Forsyth		"opener" =>
126737da2899SCharles.Forsyth			;
126837da2899SCharles.Forsyth		}
126937da2899SCharles.Forsyth		if(ev != E->SEnone) {
127037da2899SCharles.Forsyth			target = top.findbyobj(o);
127137da2899SCharles.Forsyth			if(target == nil)
127237da2899SCharles.Forsyth				break;
127337da2899SCharles.Forsyth			di := target.frame.doc;
127437da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
127537da2899SCharles.Forsyth				di.evmask &= ~ev;
127637da2899SCharles.Forsyth			else
127737da2899SCharles.Forsyth				di.evmask |= ev;
127837da2899SCharles.Forsyth		}
127937da2899SCharles.Forsyth	"Link" =>
128037da2899SCharles.Forsyth		case property {
128137da2899SCharles.Forsyth		"onclick" =>
128237da2899SCharles.Forsyth			ev = E->SEonclick;
128337da2899SCharles.Forsyth		"ondblclick" =>
128437da2899SCharles.Forsyth			ev = E->SEondblclick;
128537da2899SCharles.Forsyth		"onkeydown" =>
128637da2899SCharles.Forsyth			ev = E->SEonkeydown;
128737da2899SCharles.Forsyth		"onkeypress" =>
128837da2899SCharles.Forsyth			ev = E->SEonkeypress;
128937da2899SCharles.Forsyth		"onkeyup" =>
129037da2899SCharles.Forsyth			ev = E->SEonkeyup;
129137da2899SCharles.Forsyth		"onmousedown" =>
129237da2899SCharles.Forsyth			ev = E->SEonmousedown;
129337da2899SCharles.Forsyth		"onmouseout" =>
129437da2899SCharles.Forsyth			ev = E->SEonmouseout;
129537da2899SCharles.Forsyth		"onmouseover" =>
129637da2899SCharles.Forsyth			ev = E->SEonmouseover;
129737da2899SCharles.Forsyth		"onmouseup" =>
129837da2899SCharles.Forsyth			ev = E->SEonmouseup;
129937da2899SCharles.Forsyth		}
130037da2899SCharles.Forsyth		if(ev != E->SEnone) {
130137da2899SCharles.Forsyth			vframeid := ES->get(ex, o, "@PRIVframeid");
130237da2899SCharles.Forsyth			vanchorid := ES->get(ex, o, "@PRIVanchorid");
130337da2899SCharles.Forsyth			if(!ES->isnum(vframeid) || !ES->isnum(vanchorid))
130437da2899SCharles.Forsyth				break;
130537da2899SCharles.Forsyth			frameid := ES->toInt32(ex, vframeid);
130637da2899SCharles.Forsyth			anchorid := ES->toInt32(ex, vanchorid);
130737da2899SCharles.Forsyth			target = top.findbyframeid(frameid);
130837da2899SCharles.Forsyth			if(target == nil)
130937da2899SCharles.Forsyth				break;
131037da2899SCharles.Forsyth			anchor: ref B->Anchor;
131137da2899SCharles.Forsyth			for(al := target.frame.doc.anchors; al != nil; al = tl al) {
131237da2899SCharles.Forsyth				a := hd al;
131337da2899SCharles.Forsyth				if(a.index == anchorid) {
131437da2899SCharles.Forsyth					anchor = a;
131537da2899SCharles.Forsyth					break;
131637da2899SCharles.Forsyth				}
131737da2899SCharles.Forsyth			}
131837da2899SCharles.Forsyth			if(anchor == nil)
131937da2899SCharles.Forsyth				break;
132037da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
132137da2899SCharles.Forsyth				anchor.evmask &= ~ev;
132237da2899SCharles.Forsyth			else
132337da2899SCharles.Forsyth				anchor.evmask |= ev;
132437da2899SCharles.Forsyth		}
132537da2899SCharles.Forsyth	"Location" =>
132637da2899SCharles.Forsyth		target = top.findbyobj(o);
132737da2899SCharles.Forsyth		if (target == nil) {
132837da2899SCharles.Forsyth			break;
132937da2899SCharles.Forsyth		}
133037da2899SCharles.Forsyth		url = ref *target.frame.doc.src;
133137da2899SCharles.Forsyth		case property {
133237da2899SCharles.Forsyth		"hash" =>
133337da2899SCharles.Forsyth			if (str != nil && str[0] == '#')
133437da2899SCharles.Forsyth				str = str[1:];
133537da2899SCharles.Forsyth			url.frag = str;
133637da2899SCharles.Forsyth		"host" =>
133737da2899SCharles.Forsyth			# host:port
133837da2899SCharles.Forsyth			(h, p) := S->splitl(str, ":");
133937da2899SCharles.Forsyth			if (p != nil)
134037da2899SCharles.Forsyth				p = p[1:];
134137da2899SCharles.Forsyth			if (h != nil)
134237da2899SCharles.Forsyth				url.host = h;
134337da2899SCharles.Forsyth			if (p != nil)
134437da2899SCharles.Forsyth				url.port = p;
134537da2899SCharles.Forsyth		"hostname" =>
134637da2899SCharles.Forsyth			url.host = str;
134737da2899SCharles.Forsyth		"href" or
134837da2899SCharles.Forsyth		"pathname" =>
134937da2899SCharles.Forsyth			url = U->mkabs(U->parse(str), target.frame.doc.base);
135037da2899SCharles.Forsyth		"port" =>
135137da2899SCharles.Forsyth			url.port = str;
135237da2899SCharles.Forsyth		"protocol" =>
135337da2899SCharles.Forsyth			url.scheme = S->tolower(str);
135437da2899SCharles.Forsyth		"search" =>
135537da2899SCharles.Forsyth			url.query = str;
135637da2899SCharles.Forsyth		* =>
135737da2899SCharles.Forsyth			url = nil;
135837da2899SCharles.Forsyth		}
135937da2899SCharles.Forsyth	"Image" =>
136037da2899SCharles.Forsyth		case property {
136137da2899SCharles.Forsyth		"src" or
136237da2899SCharles.Forsyth		"lowsrc" =>
136337da2899SCharles.Forsyth			# making URLs absolute matches Netscape
136437da2899SCharles.Forsyth			target = top.findbyobj(o);
136537da2899SCharles.Forsyth			if(target == nil)
136637da2899SCharles.Forsyth				break;
136737da2899SCharles.Forsyth			url = U->mkabs(U->parse(str), target.frame.doc.base);
136837da2899SCharles.Forsyth			val = ES->strval(url.tostring());
136937da2899SCharles.Forsyth			target.imgrelocs = o :: target.imgrelocs;
137037da2899SCharles.Forsyth			url = nil;
137137da2899SCharles.Forsyth		"onabort" =>
137237da2899SCharles.Forsyth			ev = E->SEonabort;
137337da2899SCharles.Forsyth		"ondblclick" =>
137437da2899SCharles.Forsyth			ev = E->SEondblclick;
137537da2899SCharles.Forsyth		"onkeydown" =>
137637da2899SCharles.Forsyth			ev = E->SEonkeydown;
137737da2899SCharles.Forsyth		"onkeypress" =>
137837da2899SCharles.Forsyth			ev = E->SEonkeypress;
137937da2899SCharles.Forsyth		"onkeyup" =>
138037da2899SCharles.Forsyth			ev = E->SEonkeyup;
138137da2899SCharles.Forsyth		"onerror" =>
138237da2899SCharles.Forsyth			ev = E->SEonerror;
138337da2899SCharles.Forsyth		"onload" =>
138437da2899SCharles.Forsyth			ev = E->SEonload;
138537da2899SCharles.Forsyth		"onmousedown" =>
138637da2899SCharles.Forsyth			ev = E->SEonmousedown;
138737da2899SCharles.Forsyth		"onmouseout" =>
138837da2899SCharles.Forsyth			ev = E->SEonmouseout;
138937da2899SCharles.Forsyth		"onmouseover" =>
139037da2899SCharles.Forsyth			ev = E->SEonmouseover;
139137da2899SCharles.Forsyth		"onmouseup" =>
139237da2899SCharles.Forsyth			ev = E->SEonmouseup;
139337da2899SCharles.Forsyth		}
139437da2899SCharles.Forsyth		if(ev != E->SEnone) {
139537da2899SCharles.Forsyth			target = top.findbyobj(o);
139637da2899SCharles.Forsyth			if(target == nil)
139737da2899SCharles.Forsyth				break;
139837da2899SCharles.Forsyth			vimageid := ES->get(ex, o, "@PRIVimageid");
139937da2899SCharles.Forsyth			if(!ES->isnum(vimageid))
140037da2899SCharles.Forsyth				break;
140137da2899SCharles.Forsyth			imageid := ES->toInt32(ex, vimageid);
140237da2899SCharles.Forsyth			image: ref (Build->Item).Iimage;
140337da2899SCharles.Forsyth		forloop:
140437da2899SCharles.Forsyth			for(il := target.frame.doc.images; il != nil; il = tl il) {
140537da2899SCharles.Forsyth				pick im := hd il {
140637da2899SCharles.Forsyth				Iimage =>
140737da2899SCharles.Forsyth					if(im.imageid == imageid) {
140837da2899SCharles.Forsyth						image = im;
140937da2899SCharles.Forsyth						break forloop;
141037da2899SCharles.Forsyth					}
141137da2899SCharles.Forsyth				}
141237da2899SCharles.Forsyth			}
141337da2899SCharles.Forsyth			# BUG: if image has no genattr then the event handler update
141437da2899SCharles.Forsyth			# will not be done - can never set a handler for an image that
141537da2899SCharles.Forsyth			# didn't have a handler
141637da2899SCharles.Forsyth			if(image == nil || image.genattr == nil)
141737da2899SCharles.Forsyth				break;
141837da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
141937da2899SCharles.Forsyth				image.genattr.evmask &= ~ev;
142037da2899SCharles.Forsyth			else
142137da2899SCharles.Forsyth				image.genattr.evmask |= ev;
142237da2899SCharles.Forsyth		}
142337da2899SCharles.Forsyth	"Form" =>
142437da2899SCharles.Forsyth		action := "";
142537da2899SCharles.Forsyth		case property {
142637da2899SCharles.Forsyth		"onreset" =>
142737da2899SCharles.Forsyth			ev = E->SEonreset;
142837da2899SCharles.Forsyth		"onsubmit" =>
142937da2899SCharles.Forsyth			ev = E->SEonsubmit;
143037da2899SCharles.Forsyth		"action" =>
143137da2899SCharles.Forsyth			action = str;
143237da2899SCharles.Forsyth		* =>
143337da2899SCharles.Forsyth			break;
143437da2899SCharles.Forsyth		}
143537da2899SCharles.Forsyth		vframeid := ES->get(ex, o, "@PRIVframeid");
143637da2899SCharles.Forsyth		vformid := ES->get(ex, o, "@PRIVformid");
143737da2899SCharles.Forsyth		if(!ES->isnum(vframeid) || !ES->isnum(vformid))
143837da2899SCharles.Forsyth			break;
143937da2899SCharles.Forsyth		frameid := ES->toInt32(ex, vframeid);
144037da2899SCharles.Forsyth		formid := ES->toInt32(ex, vformid);
144137da2899SCharles.Forsyth		target = top.findbyframeid(frameid);
144237da2899SCharles.Forsyth		if(target == nil)
144337da2899SCharles.Forsyth			break;
144437da2899SCharles.Forsyth		form: ref B->Form;
144537da2899SCharles.Forsyth		for(fl := target.frame.doc.forms; fl != nil; fl = tl fl) {
144637da2899SCharles.Forsyth			f := hd fl;
144737da2899SCharles.Forsyth			if(f.formid == formid) {
144837da2899SCharles.Forsyth				form = f;
144937da2899SCharles.Forsyth				break;
145037da2899SCharles.Forsyth			}
145137da2899SCharles.Forsyth		}
145237da2899SCharles.Forsyth		if(form == nil)
145337da2899SCharles.Forsyth			break;
145437da2899SCharles.Forsyth		if (ev != E->SEnone) {
145537da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
145637da2899SCharles.Forsyth				form.evmask &= ~ev;
145737da2899SCharles.Forsyth			else
145837da2899SCharles.Forsyth				form.evmask |= ev;
145937da2899SCharles.Forsyth			break;
146037da2899SCharles.Forsyth		}
146137da2899SCharles.Forsyth		if (action != "")
146237da2899SCharles.Forsyth			form.action = U->mkabs(U->parse(action), target.frame.doc.base);
146337da2899SCharles.Forsyth	"FormField" =>
146437da2899SCharles.Forsyth		oform := getobj(ex, o, "form");
146537da2899SCharles.Forsyth		vframeid := ES->get(ex, oform, "@PRIVframeid");
146637da2899SCharles.Forsyth		vformid := ES->get(ex, oform, "@PRIVformid");
146737da2899SCharles.Forsyth		vfieldid := ES->get(ex, o, "@PRIVfieldid");
146837da2899SCharles.Forsyth		if(!ES->isnum(vframeid) || !ES->isnum(vformid) || !ES->isnum(vfieldid))
146937da2899SCharles.Forsyth			break;
147037da2899SCharles.Forsyth		frameid := ES->toInt32(ex, vframeid);
147137da2899SCharles.Forsyth		formid := ES->toInt32(ex, vformid);
147237da2899SCharles.Forsyth		fieldid := ES->toInt32(ex, vfieldid);
147337da2899SCharles.Forsyth		target = top.findbyframeid(frameid);
147437da2899SCharles.Forsyth		if(target == nil)
147537da2899SCharles.Forsyth			break;
147637da2899SCharles.Forsyth		form: ref B->Form;
147737da2899SCharles.Forsyth		for(fl := target.frame.doc.forms; fl != nil; fl = tl fl) {
147837da2899SCharles.Forsyth			f := hd fl;
147937da2899SCharles.Forsyth			if(f.formid == formid) {
148037da2899SCharles.Forsyth				form = f;
148137da2899SCharles.Forsyth				break;
148237da2899SCharles.Forsyth			}
148337da2899SCharles.Forsyth		}
148437da2899SCharles.Forsyth		if(form == nil)
148537da2899SCharles.Forsyth			break;
148637da2899SCharles.Forsyth		field: ref B->Formfield;
148737da2899SCharles.Forsyth		for(ffl := form.fields; ffl != nil; ffl = tl ffl) {
148837da2899SCharles.Forsyth			ff := hd ffl;
148937da2899SCharles.Forsyth			if(ff.fieldid == fieldid) {
149037da2899SCharles.Forsyth				field = ff;
149137da2899SCharles.Forsyth			break;
149237da2899SCharles.Forsyth			}
149337da2899SCharles.Forsyth		}
149437da2899SCharles.Forsyth		if(field == nil)
149537da2899SCharles.Forsyth			break;
149637da2899SCharles.Forsyth		case property {
149737da2899SCharles.Forsyth		"onblur" =>
149837da2899SCharles.Forsyth			ev = E->SEonblur;
149937da2899SCharles.Forsyth		"onchange" =>
150037da2899SCharles.Forsyth			ev = E->SEonchange;
150137da2899SCharles.Forsyth		"onclick" =>
150237da2899SCharles.Forsyth			ev = E->SEonclick;
150337da2899SCharles.Forsyth		"ondblclick" =>
150437da2899SCharles.Forsyth			ev = E->SEondblclick;
150537da2899SCharles.Forsyth		"onfocus" =>
150637da2899SCharles.Forsyth			ev = E->SEonfocus;
150737da2899SCharles.Forsyth		"onkeydown" =>
150837da2899SCharles.Forsyth			ev = E->SEonkeydown;
150937da2899SCharles.Forsyth		"onkeypress" =>
151037da2899SCharles.Forsyth			ev = E->SEonkeypress;
151137da2899SCharles.Forsyth		"onkeyup" =>
151237da2899SCharles.Forsyth			ev = E->SEonkeyup;
151337da2899SCharles.Forsyth		"onmousedown" =>
151437da2899SCharles.Forsyth			ev = E->SEonmousedown;
151537da2899SCharles.Forsyth		"onmouseup" =>
151637da2899SCharles.Forsyth			ev = E->SEonmouseup;
151737da2899SCharles.Forsyth		"onselect" =>
151837da2899SCharles.Forsyth			ev = E->SEonselect;
151937da2899SCharles.Forsyth		"value" =>
152037da2899SCharles.Forsyth			field.value = str;
152137da2899SCharles.Forsyth			if(target.frame.controls == nil ||
152237da2899SCharles.Forsyth			   field.ctlid < 0 ||
152337da2899SCharles.Forsyth			   field.ctlid > len target.frame.controls){
152437da2899SCharles.Forsyth				break;
152537da2899SCharles.Forsyth			}
152637da2899SCharles.Forsyth			c := target.frame.controls[field.ctlid];
152737da2899SCharles.Forsyth			pick ctl := c {
152837da2899SCharles.Forsyth			Centry =>
152937da2899SCharles.Forsyth				ctl.s = str;
153037da2899SCharles.Forsyth				ctl.sel = (0, 0);
153137da2899SCharles.Forsyth				E->evchan <-= ref Event.Eformfield(frameid, formid, fieldid, E->EFFredraw);
153237da2899SCharles.Forsyth			}
153337da2899SCharles.Forsyth		}
153437da2899SCharles.Forsyth
153537da2899SCharles.Forsyth		if(ev != E->SEnone) {
153637da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
153737da2899SCharles.Forsyth				field.evmask &= ~ev;
153837da2899SCharles.Forsyth			else
153937da2899SCharles.Forsyth				field.evmask |= ev;
154037da2899SCharles.Forsyth		}
154137da2899SCharles.Forsyth	"document" =>
154237da2899SCharles.Forsyth		case property {
154337da2899SCharles.Forsyth		"location" =>
154437da2899SCharles.Forsyth			target = top.findbyobj(o);
154537da2899SCharles.Forsyth			if (target == nil)
154637da2899SCharles.Forsyth				break;
154737da2899SCharles.Forsyth			# TODO: be more defensive
154837da2899SCharles.Forsyth			url = U->mkabs(U->parse(str), target.frame.doc.base);
154937da2899SCharles.Forsyth		"cookie" =>
155037da2899SCharles.Forsyth			target = top.findbyobj(o);
155137da2899SCharles.Forsyth			if(target != nil && (CU->config).docookies > 0) {
155237da2899SCharles.Forsyth				url = target.frame.doc.src;
155337da2899SCharles.Forsyth				CU->setcookie(url.host, url.path, str);
155437da2899SCharles.Forsyth			}
155537da2899SCharles.Forsyth			return;
155637da2899SCharles.Forsyth		"ondblclick" =>
155737da2899SCharles.Forsyth			ev = E->SEondblclick;
155837da2899SCharles.Forsyth		"onkeydown" =>
155937da2899SCharles.Forsyth			ev = E->SEonkeydown;
156037da2899SCharles.Forsyth		"onkeypress" =>
156137da2899SCharles.Forsyth			ev = E->SEonkeypress;
156237da2899SCharles.Forsyth		"onkeyup" =>
156337da2899SCharles.Forsyth			ev = E->SEonkeyup;
156437da2899SCharles.Forsyth		"onmousedown" =>
156537da2899SCharles.Forsyth			ev = E->SEonmousedown;
156637da2899SCharles.Forsyth		"onmouseup" =>
156737da2899SCharles.Forsyth			ev = E->SEonmouseup;
156837da2899SCharles.Forsyth		}
156937da2899SCharles.Forsyth		if(ev != E->SEnone){
157037da2899SCharles.Forsyth			target = top.findbyobj(o);
157137da2899SCharles.Forsyth			if(target == nil)
157237da2899SCharles.Forsyth				break;
157337da2899SCharles.Forsyth			di := target.frame.doc;
157437da2899SCharles.Forsyth			if(!ES->isobj(val) || val.obj.call == nil)
157537da2899SCharles.Forsyth				di.evmask &= ~ev;
157637da2899SCharles.Forsyth			else
157737da2899SCharles.Forsyth				di.evmask |= ev;
157837da2899SCharles.Forsyth		}
157937da2899SCharles.Forsyth	"Option" =>
158037da2899SCharles.Forsyth		vformfield := ES->get(ex, o, "@PRIVformfield");
158137da2899SCharles.Forsyth		vindex := ES->get(ex, o, "index");
158237da2899SCharles.Forsyth		if (!ES->isobj(vformfield) || !ES->isnum(vindex))
158337da2899SCharles.Forsyth			# not one of our 'options' objects
158437da2899SCharles.Forsyth			break;
158537da2899SCharles.Forsyth		oformfield := vformfield.obj;
158637da2899SCharles.Forsyth		oform := getobj(ex, oformfield, "form");
158737da2899SCharles.Forsyth		if (oform == nil)
158837da2899SCharles.Forsyth			break;
158937da2899SCharles.Forsyth		ES->put(ex, o, property, val);
159037da2899SCharles.Forsyth		index := ES->toInt32(ex, vindex);
159137da2899SCharles.Forsyth		updateffopts(ex, oform, oformfield, index);
159237da2899SCharles.Forsyth	}
159337da2899SCharles.Forsyth	ES->put(ex, o, property, val);
159437da2899SCharles.Forsyth
159537da2899SCharles.Forsyth	if (url != nil && target != nil) {
159637da2899SCharles.Forsyth		if (!CU->urlequal(url, target.frame.doc.src)) {
159737da2899SCharles.Forsyth			target.newloc = url.tostring();
159837da2899SCharles.Forsyth			target.newloctarg = "_top";
159937da2899SCharles.Forsyth			if(target.frame != nil)
160037da2899SCharles.Forsyth				target.newloctarg = target.frame.name;
160137da2899SCharles.Forsyth		}
160237da2899SCharles.Forsyth	}
160337da2899SCharles.Forsyth}
160437da2899SCharles.Forsyth
160537da2899SCharles.Forsythcanput(ex: ref Exec, o: ref Obj, property: string): ref Val
160637da2899SCharles.Forsyth{
160737da2899SCharles.Forsyth	return ES->canput(ex, o, property);
160837da2899SCharles.Forsyth}
160937da2899SCharles.Forsyth
161037da2899SCharles.Forsythhasproperty(ex: ref Exec, o: ref Obj, property: string): ref Val
161137da2899SCharles.Forsyth{
161237da2899SCharles.Forsyth	return ES->hasproperty(ex, o, property);
161337da2899SCharles.Forsyth}
161437da2899SCharles.Forsyth
161537da2899SCharles.Forsythdelete(ex: ref Exec, o: ref Obj, property: string)
161637da2899SCharles.Forsyth{
161737da2899SCharles.Forsyth	ES->delete(ex, o, property);
161837da2899SCharles.Forsyth}
161937da2899SCharles.Forsyth
162037da2899SCharles.Forsythdefaultval(ex: ref Exec, o: ref Obj, tyhint: int): ref Val
162137da2899SCharles.Forsyth{
162237da2899SCharles.Forsyth	return ES->defaultval(ex, o, tyhint);
162337da2899SCharles.Forsyth}
162437da2899SCharles.Forsyth
162537da2899SCharles.Forsythcall(ex: ref Exec, func, this: ref Obj, args: array of ref Val, nil: int): ref Ref
162637da2899SCharles.Forsyth{
162737da2899SCharles.Forsyth	if(dbgdom)
162837da2899SCharles.Forsyth		sys->print("call %x (class %s), val %s\n", func, func.class, func.val.str);
162937da2899SCharles.Forsyth	ans := ES->valref(ES->true);
163037da2899SCharles.Forsyth	case func.val.str{
163137da2899SCharles.Forsyth	"document.prototype.open" =>
163237da2899SCharles.Forsyth		sw := top.findbyobj(this);
163337da2899SCharles.Forsyth		if (sw != nil)
163437da2899SCharles.Forsyth			sw.docwriteout = "";
163537da2899SCharles.Forsyth	"document.prototype.close" =>
163637da2899SCharles.Forsyth		# ignore for now
163737da2899SCharles.Forsyth		;
163837da2899SCharles.Forsyth	"document.prototype.write" =>
163937da2899SCharles.Forsyth		sw := top.findbyobj(this);
164037da2899SCharles.Forsyth		if (sw != nil) {
164137da2899SCharles.Forsyth			for (ai := 0; ai < len args; ai++)
164237da2899SCharles.Forsyth				sw.docwriteout += ES->toString(ex, ES->biarg(args, ai));
164337da2899SCharles.Forsyth		}
164437da2899SCharles.Forsyth	"document.prototype.writeln" =>
164537da2899SCharles.Forsyth		sw := top.findbyobj(this);
164637da2899SCharles.Forsyth		if (sw != nil) {
164737da2899SCharles.Forsyth			for (ai := 0; ai < len args; ai++)
164837da2899SCharles.Forsyth				sw.docwriteout += ES->toString(ex, ES->biarg(args, ai));
164937da2899SCharles.Forsyth			sw.docwriteout += "\n";
165037da2899SCharles.Forsyth		}
165137da2899SCharles.Forsyth	"navigator.prototype.javaEnabled" or
165237da2899SCharles.Forsyth	"navigator.prototype.taintEnabled" =>
165337da2899SCharles.Forsyth		ans = ES->valref(ES->false);
165437da2899SCharles.Forsyth	"Form.prototype.reset" or "Form.prototype.submit"=>
165537da2899SCharles.Forsyth		vframeid := ES->get(ex, this, "@PRIVframeid");
165637da2899SCharles.Forsyth		vformid := ES->get(ex, this, "@PRIVformid");
165737da2899SCharles.Forsyth		if(ES->isnum(vframeid) && ES->isnum(vformid)) {
165837da2899SCharles.Forsyth			frameid := ES->toInt32(ex, vframeid);
165937da2899SCharles.Forsyth			formid := ES->toInt32(ex, vformid);
166037da2899SCharles.Forsyth			ftype : int;
166137da2899SCharles.Forsyth			if(func.val.str == "Form.prototype.reset")
166237da2899SCharles.Forsyth				ftype = E->EFreset;
166337da2899SCharles.Forsyth			else
166437da2899SCharles.Forsyth				ftype = E->EFsubmit;
166537da2899SCharles.Forsyth			E->evchan <-= ref Event.Eform(frameid, formid, ftype);
166637da2899SCharles.Forsyth		}
166737da2899SCharles.Forsyth	"FormField.prototype.blur" or
166837da2899SCharles.Forsyth	"FormField.prototype.click" or
166937da2899SCharles.Forsyth	"FormField.prototype.focus" or
167037da2899SCharles.Forsyth	"FormField.prototype.select" =>
167137da2899SCharles.Forsyth		oform := getobj(ex, this, "form");
167237da2899SCharles.Forsyth		vformid := ES->get(ex, oform, "@PRIVformid");
167337da2899SCharles.Forsyth		vframeid := ES->get(ex, oform, "@PRIVframeid");
167437da2899SCharles.Forsyth		vfieldid := ES->get(ex, this, "@PRIVfieldid");
167537da2899SCharles.Forsyth		if(ES->isnum(vframeid) && ES->isnum(vformid) && ES->isnum(vfieldid)) {
167637da2899SCharles.Forsyth			frameid := ES->toInt32(ex, vframeid);
167737da2899SCharles.Forsyth			formid := ES->toInt32(ex, vformid);
167837da2899SCharles.Forsyth			fieldid := ES->toInt32(ex, vfieldid);
167937da2899SCharles.Forsyth			fftype : int;
168037da2899SCharles.Forsyth			case func.val.str{
168137da2899SCharles.Forsyth			"FormField.prototype.blur" =>
168237da2899SCharles.Forsyth				fftype = E->EFFblur;
168337da2899SCharles.Forsyth			"FormField.prototype.click" =>
168437da2899SCharles.Forsyth				fftype = E->EFFclick;
168537da2899SCharles.Forsyth			"FormField.prototype.focus" =>
168637da2899SCharles.Forsyth				fftype = E->EFFfocus;
168737da2899SCharles.Forsyth			"FormField.prototype.select" =>
168837da2899SCharles.Forsyth				fftype = E->EFFselect;
168937da2899SCharles.Forsyth			* =>
169037da2899SCharles.Forsyth				fftype = E->EFFnone;
169137da2899SCharles.Forsyth			}
169237da2899SCharles.Forsyth			E->evchan <-= ref Event.Eformfield(frameid, formid, fieldid, fftype);
169337da2899SCharles.Forsyth		}
169437da2899SCharles.Forsyth	"History.prototype.back" =>
169537da2899SCharles.Forsyth		E->evchan <-= ref Event.Ego("", "", 0, E->EGback);
169637da2899SCharles.Forsyth	"History.prototype.forward" =>
169737da2899SCharles.Forsyth		E->evchan <-= ref Event.Ego("", "", 0, E->EGforward);
169837da2899SCharles.Forsyth	"History.prototype.go" =>
169937da2899SCharles.Forsyth		ego : ref Event.Ego;
170037da2899SCharles.Forsyth		v := ES->biarg(args, 0);
170137da2899SCharles.Forsyth		if(ES->isstr(v))
170237da2899SCharles.Forsyth			ego = ref Event.Ego(v.str, "", 0, E->EGlocation);
170337da2899SCharles.Forsyth		else if(ES->isnum(v)) {
170437da2899SCharles.Forsyth			delta := ES->toInt32(ex, v);
170537da2899SCharles.Forsyth			case delta {
170637da2899SCharles.Forsyth			-1 =>
170737da2899SCharles.Forsyth				ego = ref Event.Ego("", "", 0, E->EGback);
170837da2899SCharles.Forsyth			0 =>
170937da2899SCharles.Forsyth				ego = ref Event.Ego("", "", 0, E->EGreload);
171037da2899SCharles.Forsyth			1 =>
171137da2899SCharles.Forsyth				ego = ref Event.Ego("", "", 0, E->EGforward);
171237da2899SCharles.Forsyth			* =>
171337da2899SCharles.Forsyth				ego = ref Event.Ego("", "", delta,  E->EGdelta);
171437da2899SCharles.Forsyth			}
171537da2899SCharles.Forsyth		}
171637da2899SCharles.Forsyth		if(ego != nil)
171737da2899SCharles.Forsyth			E->evchan <-= ego;
171837da2899SCharles.Forsyth	"Location.prototype.reload" =>
171937da2899SCharles.Forsyth		# ignore 'force' argument for now
172037da2899SCharles.Forsyth		E->evchan <-= ref Event.Ego("", "", 0, E->EGreload);
172137da2899SCharles.Forsyth	"Location.prototype.replace" =>
172237da2899SCharles.Forsyth		v := ES->biarg(args, 0);
172337da2899SCharles.Forsyth		if(ES->isstr(v)) {
172437da2899SCharles.Forsyth			sw := top.findbyobj(this);
172537da2899SCharles.Forsyth			if(sw == nil)
172637da2899SCharles.Forsyth				fname := "_top";
172737da2899SCharles.Forsyth			else
172837da2899SCharles.Forsyth				fname = sw.frame.name;
172937da2899SCharles.Forsyth			if (v.str != nil) {
173037da2899SCharles.Forsyth				url := U->mkabs(U->parse(v.str), sw.frame.doc.base);
173137da2899SCharles.Forsyth				E->evchan <-= ref Event.Ego(url.tostring(), fname, 0, E->EGreplace);
173237da2899SCharles.Forsyth			}
173337da2899SCharles.Forsyth		}
173437da2899SCharles.Forsyth	"Window.prototype.alert" =>
173537da2899SCharles.Forsyth		G->alert(ES->toString(ex, ES->biarg(args, 0)));
173637da2899SCharles.Forsyth	"Window.prototype.blur" =>
173737da2899SCharles.Forsyth		;
173837da2899SCharles.Forsyth#		sw := top.findbyobj(this);
173937da2899SCharles.Forsyth#		if (sw != nil)
174037da2899SCharles.Forsyth#			E->evchan <-= ref Event.Eframefocus(sw.frame.id, 0);
174137da2899SCharles.Forsyth
174237da2899SCharles.Forsyth	"Window.prototype.clearTimeout" or
174337da2899SCharles.Forsyth	"Window.prototype.clearInterval" =>
174437da2899SCharles.Forsyth		v := ES->biarg(args, 0);
174537da2899SCharles.Forsyth		id := ES->toInt32(ex, v);
174637da2899SCharles.Forsyth		clrtimeout(ex, this, id);
174737da2899SCharles.Forsyth	"Window.prototype.close" =>
174837da2899SCharles.Forsyth		if(this == top.ex.global)
174937da2899SCharles.Forsyth			winclose = 1;
175037da2899SCharles.Forsyth		# no-op
175137da2899SCharles.Forsyth		;
175237da2899SCharles.Forsyth	"Window.prototype.confirm" =>
175337da2899SCharles.Forsyth		code := G->confirm(ES->toString(ex, ES->biarg(args, 0)));
175437da2899SCharles.Forsyth		if(code != 1)
175537da2899SCharles.Forsyth			ans = ES->valref(ES->false);
175637da2899SCharles.Forsyth	"Window.prototype.focus" =>
175737da2899SCharles.Forsyth		;
175837da2899SCharles.Forsyth#		sw := top.findbyobj(this);
175937da2899SCharles.Forsyth#		if (sw != nil)
176037da2899SCharles.Forsyth#			E->evchan <-= ref Event.Eframefocus(sw.frame.id, 1);
176137da2899SCharles.Forsyth	"Window.prototype.moveBy" or
176237da2899SCharles.Forsyth	"Window.prototype.moveTo" =>
176337da2899SCharles.Forsyth		# no-op
176437da2899SCharles.Forsyth		;
176537da2899SCharles.Forsyth	"Window.prototype.open" =>
176637da2899SCharles.Forsyth		if (dbgdom)
176737da2899SCharles.Forsyth			sys->print("window.open called\n");
176837da2899SCharles.Forsyth		u := ES->toString(ex, ES->biarg(args, 0));
176937da2899SCharles.Forsyth		n := ES->toString(ex, ES->biarg(args, 1));
177037da2899SCharles.Forsyth		sw : ref ScriptWin;
177137da2899SCharles.Forsyth		if (n != "")
177237da2899SCharles.Forsyth			sw = top.findbyname(n);
177337da2899SCharles.Forsyth		newch := 0;
177437da2899SCharles.Forsyth		if (sw == nil){
177537da2899SCharles.Forsyth			sw = top;
177637da2899SCharles.Forsyth			newch = 1;
177737da2899SCharles.Forsyth		}
177837da2899SCharles.Forsyth		if(u != "") {
177937da2899SCharles.Forsyth			# Want to replace window by navigation to u
178037da2899SCharles.Forsyth			sw.newloc = u;
178137da2899SCharles.Forsyth			if (sw.frame.name != "")
178237da2899SCharles.Forsyth				sw.newloctarg = sw.frame.name;
178337da2899SCharles.Forsyth			else
178437da2899SCharles.Forsyth				sw.newloctarg = "_top";
178537da2899SCharles.Forsyth			url : ref U->Parsedurl;
178637da2899SCharles.Forsyth			if (sw.frame.doc != nil && sw.frame.doc.base != nil)
178737da2899SCharles.Forsyth				url = U->mkabs(U->parse(u), sw.frame.doc.base);
178837da2899SCharles.Forsyth			else
178937da2899SCharles.Forsyth				url = CU->makeabsurl(u);
179037da2899SCharles.Forsyth			sw.newloc = url.tostring();
179137da2899SCharles.Forsyth		}
179237da2899SCharles.Forsyth		if(newch){
179337da2899SCharles.Forsyth			# create dummy window
179437da2899SCharles.Forsyth			dw := ScriptWin.dummy();
179537da2899SCharles.Forsyth			spawn newcharon(sw.newloc, sw.newloctarg, sw);
179637da2899SCharles.Forsyth			sw.newloc = "";
179737da2899SCharles.Forsyth			sw.newloctarg = "";
179837da2899SCharles.Forsyth			ans = ES->valref(dw.val);
179937da2899SCharles.Forsyth		}
180037da2899SCharles.Forsyth		else
180137da2899SCharles.Forsyth			ans = ES->valref(sw.val);
180237da2899SCharles.Forsyth	"Window.prototype.prompt" =>
180337da2899SCharles.Forsyth		msg := ES->toString(ex, ES->biarg(args, 0));
180437da2899SCharles.Forsyth		dflt := ES->toString(ex, ES->biarg(args, 1));
180537da2899SCharles.Forsyth		(code, input) := G->prompt(msg, dflt);
180637da2899SCharles.Forsyth		v := ES->null;
180737da2899SCharles.Forsyth		if(code == 1)
180837da2899SCharles.Forsyth			v = ES->strval(input);
180937da2899SCharles.Forsyth		ans = ES->valref(v);
181037da2899SCharles.Forsyth	"Window.prototype.resizeBy" or
181137da2899SCharles.Forsyth	"Window.prototype.resizeTo" =>
181237da2899SCharles.Forsyth		# no-op
181337da2899SCharles.Forsyth		;
181437da2899SCharles.Forsyth	"Window.prototype.scroll" or
181537da2899SCharles.Forsyth	"Window.prototype.scrollTo" =>
181637da2899SCharles.Forsyth		# scroll is done via an event to avoid race in calls to
181737da2899SCharles.Forsyth		# Layout->fixframegeom() [made by scroll code]
181837da2899SCharles.Forsyth		sw := top.findbyobj(this);
181937da2899SCharles.Forsyth		if (sw != nil) {
182037da2899SCharles.Forsyth			(xv, yv) := (ES->biarg(args, 0), ES->biarg(args, 1));
182137da2899SCharles.Forsyth			pt := Draw->Point(ES->toInt32(ex, xv), ES->toInt32(ex, yv));
182237da2899SCharles.Forsyth			E->evchan <-= ref Event.Escroll(sw.frame.id, pt);
182337da2899SCharles.Forsyth		}
182437da2899SCharles.Forsyth	"Window.prototype.scrollBy" =>
182537da2899SCharles.Forsyth		sw := top.findbyobj(this);
182637da2899SCharles.Forsyth		if (sw != nil) {
182737da2899SCharles.Forsyth			(dxv, dyv) := (ES->biarg(args, 0), ES->biarg(args, 1));
182837da2899SCharles.Forsyth			pt := Draw->Point(ES->toInt32(ex, dxv), ES->toInt32(ex, dyv));
182937da2899SCharles.Forsyth			E->evchan <-= ref Event.Escrollr(sw.frame.id, pt);
183037da2899SCharles.Forsyth		}
183137da2899SCharles.Forsyth	"Window.prototype.setTimeout" =>
183237da2899SCharles.Forsyth		(v1, v2) := (ES->biarg(args, 0), ES->biarg(args, 1));
183337da2899SCharles.Forsyth		cmd := ES->toString(ex, v1);
183437da2899SCharles.Forsyth		ms := ES->toInt32(ex, v2);
183537da2899SCharles.Forsyth		id := addtimeout(ex, this, cmd, ms, E->SEtimeout);
183637da2899SCharles.Forsyth		ans = ES->valref(ES->numval(real id));
183737da2899SCharles.Forsyth	"Window.prototype.setInterval" =>
183837da2899SCharles.Forsyth		(v1, v2) := (ES->biarg(args, 0), ES->biarg(args, 1));
183937da2899SCharles.Forsyth		cmd := ES->toString(ex, v1);
184037da2899SCharles.Forsyth		ms := ES->toInt32(ex, v2);
184137da2899SCharles.Forsyth		id := addtimeout(ex, this, cmd, ms, E->SEinterval);
184237da2899SCharles.Forsyth		ans = ES->valref(ES->numval(real id));
184337da2899SCharles.Forsyth	* =>
184437da2899SCharles.Forsyth		ES->runtime(ex, nil, "unknown or unimplemented func "+func.val.str+" in host call");
184537da2899SCharles.Forsyth		return nil;
184637da2899SCharles.Forsyth	}
184737da2899SCharles.Forsyth	return ans;
184837da2899SCharles.Forsyth}
184937da2899SCharles.Forsyth
185037da2899SCharles.Forsythconstruct(ex: ref Exec, func: ref Obj, args: array of ref Val): ref Obj
185137da2899SCharles.Forsyth{
185237da2899SCharles.Forsyth	if(dbgdom)
185337da2899SCharles.Forsyth		sys->print("construct %x (class %s), val %s\n", func, func.class, func.val.str);
185437da2899SCharles.Forsyth	params: array of string;
185537da2899SCharles.Forsyth	o: ref Obj;
185637da2899SCharles.Forsyth#sys->print("Construct(%s)\n", func.val.str);
185737da2899SCharles.Forsyth	case func.val.str {
185837da2899SCharles.Forsyth	"Image" =>
185937da2899SCharles.Forsyth		o = mkhostobj(ex, "Image");
186037da2899SCharles.Forsyth		params = array [] of {"width", "height"};
186137da2899SCharles.Forsyth		createdimages = o :: createdimages;
186237da2899SCharles.Forsyth	"Option" =>
186337da2899SCharles.Forsyth		o = mkhostobj(ex, "Option");
186437da2899SCharles.Forsyth		params = array [] of {"text", "value", "defaultSelected", "selected"};
186537da2899SCharles.Forsyth	* =>
186637da2899SCharles.Forsyth		return nil;
186737da2899SCharles.Forsyth	}
186837da2899SCharles.Forsyth	for (i := 0; i < len args && i < len params; i++)
186937da2899SCharles.Forsyth		reinitprop(o, params[i], args[i]);
187037da2899SCharles.Forsyth	return o;
187137da2899SCharles.Forsyth}
187237da2899SCharles.Forsyth
187337da2899SCharles.Forsythupdateffopts(ex: ref Exec, oform, oformfield: ref Obj, ix: int)
187437da2899SCharles.Forsyth{
187537da2899SCharles.Forsyth	vframeid := ES->get(ex, oform, "@PRIVframeid");
187637da2899SCharles.Forsyth	vformid := ES->get(ex, oform, "@PRIVformid");
187737da2899SCharles.Forsyth	vfieldid := ES->get(ex, oformfield, "@PRIVfieldid");
187837da2899SCharles.Forsyth	if(!ES->isnum(vframeid) || !ES->isnum(vformid) || !ES->isnum(vfieldid))
187937da2899SCharles.Forsyth		return;
188037da2899SCharles.Forsyth	frameid := ES->toInt32(ex, vframeid);
188137da2899SCharles.Forsyth	formid := ES->toInt32(ex, vformid);
188237da2899SCharles.Forsyth	fieldid := ES->toInt32(ex, vfieldid);
188337da2899SCharles.Forsyth
188437da2899SCharles.Forsyth	target := top.findbyframeid(frameid);
188537da2899SCharles.Forsyth	if(target == nil)
188637da2899SCharles.Forsyth		return;
188737da2899SCharles.Forsyth	form: ref B->Form;
188837da2899SCharles.Forsyth	for(fl := target.frame.doc.forms; fl != nil; fl = tl fl) {
188937da2899SCharles.Forsyth		f := hd fl;
189037da2899SCharles.Forsyth		if(f.formid == formid) {
189137da2899SCharles.Forsyth			form = f;
189237da2899SCharles.Forsyth			break;
189337da2899SCharles.Forsyth		}
189437da2899SCharles.Forsyth	}
189537da2899SCharles.Forsyth	if(form == nil)
189637da2899SCharles.Forsyth		return;
189737da2899SCharles.Forsyth	field: ref B->Formfield;
189837da2899SCharles.Forsyth	for(ffl := form.fields; ffl != nil; ffl = tl ffl) {
189937da2899SCharles.Forsyth		ff := hd ffl;
190037da2899SCharles.Forsyth		if(ff.fieldid == fieldid) {
190137da2899SCharles.Forsyth			field = ff;
190237da2899SCharles.Forsyth			break;
190337da2899SCharles.Forsyth		}
190437da2899SCharles.Forsyth	}
190537da2899SCharles.Forsyth	if(field == nil)
190637da2899SCharles.Forsyth		return;
190737da2899SCharles.Forsyth
190837da2899SCharles.Forsyth	selctl : ref Control.Cselect;
190937da2899SCharles.Forsyth	pick ctl := target.frame.controls[field.ctlid] {
191037da2899SCharles.Forsyth	Cselect =>
191137da2899SCharles.Forsyth		selctl = ctl;
191237da2899SCharles.Forsyth	* =>
191337da2899SCharles.Forsyth		return;
191437da2899SCharles.Forsyth	}
191537da2899SCharles.Forsyth
191637da2899SCharles.Forsyth	(opts, nopts) := getarraywithlen(ex, oformfield, "options");
191737da2899SCharles.Forsyth	if (opts == nil)
191837da2899SCharles.Forsyth		return;
191937da2899SCharles.Forsyth	optl: list of ref B->Option;
192037da2899SCharles.Forsyth	selobj, firstobj: ref Obj;
192137da2899SCharles.Forsyth	selopt, firstopt: ref B->Option;
192237da2899SCharles.Forsyth	noptl := 0;
192337da2899SCharles.Forsyth	for (i := 0; i < nopts; i++) {
192437da2899SCharles.Forsyth		vopt := ES->get(ex, opts, string i);
192537da2899SCharles.Forsyth		if (!ES->isobj(vopt) || vopt.obj.class != "Option")
192637da2899SCharles.Forsyth			continue;
192737da2899SCharles.Forsyth		oopt := vopt.obj;
192837da2899SCharles.Forsyth		sel := ES->get(ex, oopt, "selected") == ES->true;
192937da2899SCharles.Forsyth		val := ES->toString(ex, ES->get(ex, oopt, "value"));
193037da2899SCharles.Forsyth		text := ES->toString(ex, ES->get(ex, oopt, "text"));
193137da2899SCharles.Forsyth		option := ref B->Option(sel, val, text);
193237da2899SCharles.Forsyth		optl = option :: optl;
193337da2899SCharles.Forsyth		if (noptl++ == 0) {
193437da2899SCharles.Forsyth			firstobj = oopt;
193537da2899SCharles.Forsyth			firstopt = option;
193637da2899SCharles.Forsyth		}
193737da2899SCharles.Forsyth		if (sel && (selobj == nil || ix == i)) {
193837da2899SCharles.Forsyth			selobj = oopt;
193937da2899SCharles.Forsyth			selopt = option;
194037da2899SCharles.Forsyth		}
194137da2899SCharles.Forsyth		if (! int(field.flags & B->FFmultiple)) {
194237da2899SCharles.Forsyth			ES->put(ex, oopt, "selected", ES->false);
194337da2899SCharles.Forsyth			option.selected = 0;
194437da2899SCharles.Forsyth		}
194537da2899SCharles.Forsyth	}
194637da2899SCharles.Forsyth	if (selobj != nil)
194737da2899SCharles.Forsyth		ES->put(ex, selobj, "selected", ES->true);
194837da2899SCharles.Forsyth	else if (firstobj != nil)
194937da2899SCharles.Forsyth		ES->put(ex, firstobj, "selected", ES->true);
195037da2899SCharles.Forsyth	if (selopt != nil)
195137da2899SCharles.Forsyth		selopt.selected = 1;
195237da2899SCharles.Forsyth	else if (firstopt != nil)
195337da2899SCharles.Forsyth		firstopt.selected = 1;
195437da2899SCharles.Forsyth	opta := array [noptl] of B->Option;
195537da2899SCharles.Forsyth	for (i = noptl - 1; i >= 0; i--)
195637da2899SCharles.Forsyth		(opta[i], optl) = (*hd optl, tl optl);
195737da2899SCharles.Forsyth	# race here with charon.b:form_submit() and layout code
195837da2899SCharles.Forsyth	selctl.options = opta;
195937da2899SCharles.Forsyth	E->evchan <-= ref Event.Eformfield(frameid, formid, fieldid, E->EFFredraw);
196037da2899SCharles.Forsyth}
196137da2899SCharles.Forsyth
196237da2899SCharles.Forsythtimeout(e : ref ScriptEvent, ms : int)
196337da2899SCharles.Forsyth{
196437da2899SCharles.Forsyth	sys->sleep(ms);
196537da2899SCharles.Forsyth	jevchan <- = e;
196637da2899SCharles.Forsyth}
196737da2899SCharles.Forsyth
196837da2899SCharles.Forsyth# BUGS
196937da2899SCharles.Forsyth#	cannot set a timeout for a window just created by window.open()
197037da2899SCharles.Forsyth#	because it will not have an entry in the ScriptWin tree
197137da2899SCharles.Forsyth#	(This is really a problem with the ScriptEvent adt only taking a frame id)
197237da2899SCharles.Forsyth#
197337da2899SCharles.Forsythaddtimeout(ex : ref Exec, win : ref Obj, cmd : string, ms : int, evk: int) : int
197437da2899SCharles.Forsyth{
197537da2899SCharles.Forsyth	sw := top.findbyobj(win);
197637da2899SCharles.Forsyth	if (sw == nil || cmd == nil || ms <= 0)
197737da2899SCharles.Forsyth		return -1;
197837da2899SCharles.Forsyth
197937da2899SCharles.Forsyth	# check for timeout handler array, create if doesn't exist
198037da2899SCharles.Forsyth	(toa, n) := getarraywithlen(ex, win, "@PRIVtoa");
198137da2899SCharles.Forsyth	if (toa == nil) {
198237da2899SCharles.Forsyth		toa = ES->mkobj(ex.arrayproto, "Array");
198337da2899SCharles.Forsyth		ES->varinstant(toa, ES->DontEnum|ES->DontDelete, "length", ref RefVal(ES->numval(0.)));
198437da2899SCharles.Forsyth		ES->varinstant(win, ES->DontEnum|ES->DontDelete, "@PRIVtoa", ref RefVal(ES->objval(toa)));
198537da2899SCharles.Forsyth	}
198637da2899SCharles.Forsyth	# find first free handler
198737da2899SCharles.Forsyth	for (ix := 0; ix < n; ix++) {
198837da2899SCharles.Forsyth		hv := ES->get(ex, toa, string ix);
198937da2899SCharles.Forsyth
199037da2899SCharles.Forsyth		if (hv == nil)
199137da2899SCharles.Forsyth			break;
199237da2899SCharles.Forsyth		# val == null		Timeout has been cancelled, but timer still running
199337da2899SCharles.Forsyth		# val == undefined	Timeout has expired
199437da2899SCharles.Forsyth		if (hv == ES->undefined)
199537da2899SCharles.Forsyth			break;
199637da2899SCharles.Forsyth	}
199737da2899SCharles.Forsyth
199837da2899SCharles.Forsyth	# construct a private handler for the timeout
199937da2899SCharles.Forsyth	# The code is always executed in the scope of the window object
200037da2899SCharles.Forsyth	# for which the timeout is being set.
200137da2899SCharles.Forsyth	oldsc := ex.scopechain;
200237da2899SCharles.Forsyth	ex.scopechain = win :: nil;
200337da2899SCharles.Forsyth	ES->eval(ex, "function PRIVhandler() {" + cmd + "}");
200437da2899SCharles.Forsyth	hobj := getobj(ex, win, "PRIVhandler");
200537da2899SCharles.Forsyth	ex.scopechain = oldsc;
200637da2899SCharles.Forsyth	if(hobj == nil)
200737da2899SCharles.Forsyth		return -1;
200837da2899SCharles.Forsyth	ES->put(ex, toa, string ix, ES->objval(hobj));
200937da2899SCharles.Forsyth	ev := ref ScriptEvent(evk, sw.frame.id, -1, -1, -1, -1, 0, 0, ix, nil, nil, ms);
201037da2899SCharles.Forsyth	spawn timeout(ev, ms);
201137da2899SCharles.Forsyth	return ix;
201237da2899SCharles.Forsyth}
201337da2899SCharles.Forsyth
201437da2899SCharles.Forsythdotimeout(ex : ref Exec, win : ref Obj, e: ref ScriptEvent) : ref Ecmascript->Obj
201537da2899SCharles.Forsyth{
201637da2899SCharles.Forsyth	id := e.which;
201737da2899SCharles.Forsyth	if (id < 0)
201837da2899SCharles.Forsyth		return nil;
201937da2899SCharles.Forsyth
202037da2899SCharles.Forsyth	(toa, n) := getarraywithlen(ex, win, "@PRIVtoa");
202137da2899SCharles.Forsyth	if (toa == nil || id >= n)
202237da2899SCharles.Forsyth		return nil;
202337da2899SCharles.Forsyth
202437da2899SCharles.Forsyth	handler := getobj(ex, toa, string id);
202537da2899SCharles.Forsyth	if (handler == nil)
202637da2899SCharles.Forsyth		return nil;
202737da2899SCharles.Forsyth	if(e.kind == E->SEinterval){
202837da2899SCharles.Forsyth		ev := ref ScriptEvent;
202937da2899SCharles.Forsyth		*ev = *e;
203037da2899SCharles.Forsyth		spawn timeout(ev, e.ms);
203137da2899SCharles.Forsyth		return handler;
203237da2899SCharles.Forsyth	}
203337da2899SCharles.Forsyth	if (id == n-1)
203437da2899SCharles.Forsyth		ES->put(ex, toa, "length", ES->numval(real (n-1)));
203537da2899SCharles.Forsyth	else
203637da2899SCharles.Forsyth		ES->put(ex, toa, string id, ES->undefined);
203737da2899SCharles.Forsyth	return handler;
203837da2899SCharles.Forsyth}
203937da2899SCharles.Forsyth
204037da2899SCharles.Forsythclrtimeout(ex : ref Exec, win : ref Obj, id : int)
204137da2899SCharles.Forsyth{
204237da2899SCharles.Forsyth	if (id < 0)
204337da2899SCharles.Forsyth		return;
204437da2899SCharles.Forsyth	(toa, n) := getarraywithlen(ex, win, "@PRIVtoa");
204537da2899SCharles.Forsyth	if (toa == nil || id >= n)
204637da2899SCharles.Forsyth		return;
204737da2899SCharles.Forsyth
204837da2899SCharles.Forsyth	ES->put(ex, toa, string id, ES->null);
204937da2899SCharles.Forsyth}
205037da2899SCharles.Forsyth
205137da2899SCharles.Forsyth# Make a host object with given class.
205237da2899SCharles.Forsyth# Get the prototype from the objspecs array
205337da2899SCharles.Forsyth# (if none yet, make one up and install the methods).
205437da2899SCharles.Forsyth# Put in required properties, with undefined values initially.
205537da2899SCharles.Forsyth# If mainex is nil (it will be for bootstrapping the initial object),
205637da2899SCharles.Forsyth# the prototype has to be filled in later.
205737da2899SCharles.Forsythmkhostobj(ex : ref Exec, class: string) : ref Obj
205837da2899SCharles.Forsyth{
205937da2899SCharles.Forsyth	ci := specindex(class);
206037da2899SCharles.Forsyth	proto : ref Obj;
206137da2899SCharles.Forsyth	if(ex != nil)
206237da2899SCharles.Forsyth		proto = mkprototype(ex, ci);
206337da2899SCharles.Forsyth	ans := ES->mkobj(proto, class);
206437da2899SCharles.Forsyth	initprops(ex, ans, objspecs[ci].props);
206537da2899SCharles.Forsyth	ans.host = me;
206637da2899SCharles.Forsyth	return ans;
206737da2899SCharles.Forsyth}
206837da2899SCharles.Forsyth
206937da2899SCharles.Forsythinitprops(ex : ref Exec, o: ref Obj, props: array of PropSpec)
207037da2899SCharles.Forsyth{
207137da2899SCharles.Forsyth	if(props == nil)
207237da2899SCharles.Forsyth		return;
207337da2899SCharles.Forsyth	for(i := 0; i < len props; i++) {
207437da2899SCharles.Forsyth		v := ES->undefined;
207537da2899SCharles.Forsyth		case props[i].initval {
207637da2899SCharles.Forsyth		IVundef =>
207737da2899SCharles.Forsyth			v = ES->undefined;
207837da2899SCharles.Forsyth		IVnull =>
207937da2899SCharles.Forsyth			v = ES->null;
208037da2899SCharles.Forsyth		IVtrue =>
208137da2899SCharles.Forsyth			v = ES->true;
208237da2899SCharles.Forsyth		IVfalse =>
208337da2899SCharles.Forsyth			v = ES->false;
208437da2899SCharles.Forsyth		IVnullstr =>
208537da2899SCharles.Forsyth			v = nullstrval;
208637da2899SCharles.Forsyth		IVzero =>
208737da2899SCharles.Forsyth			v = zeroval;
208837da2899SCharles.Forsyth		IVzerostr =>
208937da2899SCharles.Forsyth			v = zerostrval;
209037da2899SCharles.Forsyth		IVarray =>
209137da2899SCharles.Forsyth			# need a separate one for each array,
209237da2899SCharles.Forsyth			# since we'll update these rather than replacing
209337da2899SCharles.Forsyth			ao := ES->mkobj(ex.arrayproto, "Array");
209437da2899SCharles.Forsyth			ES->varinstant(ao, ES->DontEnum|ES->DontDelete, "length", ref RefVal(ES->numval(0.)));
209537da2899SCharles.Forsyth			v = ES->objval(ao);
209637da2899SCharles.Forsyth		* =>
209737da2899SCharles.Forsyth			CU->assert(0);
209837da2899SCharles.Forsyth		}
209937da2899SCharles.Forsyth		ES->varinstant(o, props[i].attr | ES->DontDelete, props[i].name, ref RefVal(v));
210037da2899SCharles.Forsyth	}
210137da2899SCharles.Forsyth}
210237da2899SCharles.Forsyth
210337da2899SCharles.Forsyth# Return index into objspecs where class is specified
210437da2899SCharles.Forsythspecindex(class: string) : int
210537da2899SCharles.Forsyth{
210637da2899SCharles.Forsyth	for(i := 0; i < len objspecs; i++)
210737da2899SCharles.Forsyth		if(objspecs[i].name == class)
210837da2899SCharles.Forsyth			break;
210937da2899SCharles.Forsyth	if(i == len objspecs)
2110*54041ca4Sforsyth		raise "EXInternal: couldn't find host object class " + class;
211137da2899SCharles.Forsyth	return i;
211237da2899SCharles.Forsyth}
211337da2899SCharles.Forsyth
211437da2899SCharles.Forsyth# Make a prototype for host object specified by objspecs[ci]
211537da2899SCharles.Forsythmkprototype(ex : ref Exec, ci : int) : ref Obj
211637da2899SCharles.Forsyth{
211737da2899SCharles.Forsyth	CU->assert(ex != nil);
211837da2899SCharles.Forsyth	class := objspecs[ci].name;
211937da2899SCharles.Forsyth	prototype := ES->mkobj(ex.objproto, class);
212037da2899SCharles.Forsyth	meths := objspecs[ci].methods;
212137da2899SCharles.Forsyth	for(k := 0; k < len meths; k++) {
212237da2899SCharles.Forsyth		name := meths[k].name;
212337da2899SCharles.Forsyth		fullname := class + ".prototype." + name;
212437da2899SCharles.Forsyth		args := meths[k].args;
212537da2899SCharles.Forsyth		ES->biinst(prototype, Builtin(name, fullname, args, len args),
212637da2899SCharles.Forsyth			ex.funcproto, me);
212737da2899SCharles.Forsyth	}
212837da2899SCharles.Forsyth	return prototype;
212937da2899SCharles.Forsyth}
213037da2899SCharles.Forsyth
213137da2899SCharles.Forsyth
213237da2899SCharles.Forsythgetframeobj(frameid: int) : ref Obj
213337da2899SCharles.Forsyth{
213437da2899SCharles.Forsyth	sw := top.findbyframeid(frameid);
213537da2899SCharles.Forsyth	if(sw != nil)
213637da2899SCharles.Forsyth		return sw.ex.global;
213737da2899SCharles.Forsyth	return nil;
213837da2899SCharles.Forsyth}
213937da2899SCharles.Forsyth
214037da2899SCharles.Forsythgetdocobj(ex : ref Exec, frameid: int) : ref Obj
214137da2899SCharles.Forsyth{
214237da2899SCharles.Forsyth	return getobj(ex, getframeobj(frameid), "document");
214337da2899SCharles.Forsyth}
214437da2899SCharles.Forsyth
214537da2899SCharles.Forsythgetformobj(ex : ref Exec, frameid, formid: int) : ref Obj
214637da2899SCharles.Forsyth{
214737da2899SCharles.Forsyth	# frameids are 1-origin, document.forms is 0-origin
214837da2899SCharles.Forsyth	return getarrayelem(ex, getdocobj(ex, frameid), "forms", formid-1);
214937da2899SCharles.Forsyth}
215037da2899SCharles.Forsyth
215137da2899SCharles.Forsythgetformfieldobj(frameid, formid, fieldid: int) : ref Obj
215237da2899SCharles.Forsyth{
215337da2899SCharles.Forsyth	sw := top.findbyframeid(frameid);
215437da2899SCharles.Forsyth	if (sw == nil)
215537da2899SCharles.Forsyth		return nil;
215637da2899SCharles.Forsyth	flds : list of (ref Build->Formfield, ref Obj);
215737da2899SCharles.Forsyth	for (fl := sw.forms; fl != nil; fl = tl fl) {
215837da2899SCharles.Forsyth		sf := hd fl;
215937da2899SCharles.Forsyth		if (sf.form.formid == formid) {
216037da2899SCharles.Forsyth			flds = sf.fields;
216137da2899SCharles.Forsyth			break;
216237da2899SCharles.Forsyth		}
216337da2899SCharles.Forsyth	}
216437da2899SCharles.Forsyth	for (; flds != nil; flds = tl flds) {
216537da2899SCharles.Forsyth		(fld, obj) := hd flds;
216637da2899SCharles.Forsyth		if (fld.fieldid == fieldid)
216737da2899SCharles.Forsyth			return obj;
216837da2899SCharles.Forsyth	}
216937da2899SCharles.Forsyth	return nil;
217037da2899SCharles.Forsyth}
217137da2899SCharles.Forsyth
217237da2899SCharles.Forsythgetanchorobj(ex: ref Exec, frameid, anchorid: int) : ref Obj
217337da2899SCharles.Forsyth{
217437da2899SCharles.Forsyth	od := getdocobj(ex, frameid);
217537da2899SCharles.Forsyth	if(od != nil) {
217637da2899SCharles.Forsyth		(olinks, olinkslen) := getarraywithlen(ex, od, "links");
217737da2899SCharles.Forsyth		if(olinks != nil) {
217837da2899SCharles.Forsyth			for(i := 0; i < olinkslen; i++) {
217937da2899SCharles.Forsyth				ol := getobj(ex, olinks, string i);
218037da2899SCharles.Forsyth				if(ol != nil) {
218137da2899SCharles.Forsyth					v := ES->get(ex, ol, "@PRIVanchorid");
218237da2899SCharles.Forsyth					if(ES->isnum(v) && ES->toInt32(ex, v) == anchorid)
218337da2899SCharles.Forsyth						return ol;
218437da2899SCharles.Forsyth				}
218537da2899SCharles.Forsyth			}
218637da2899SCharles.Forsyth		}
218737da2899SCharles.Forsyth	}
218837da2899SCharles.Forsyth	return nil;
218937da2899SCharles.Forsyth}
219037da2899SCharles.Forsyth
219137da2899SCharles.Forsythgetimageobj(ex: ref Exec, frameid, imageid: int) : ref Obj
219237da2899SCharles.Forsyth{
219337da2899SCharles.Forsyth	od := getdocobj(ex, frameid);
219437da2899SCharles.Forsyth	if(od != nil) {
219537da2899SCharles.Forsyth		(oimages, oimageslen) := getarraywithlen(ex, od, "images");
219637da2899SCharles.Forsyth		if(oimages != nil) {
219737da2899SCharles.Forsyth			for(i := 0; i < oimageslen; i++) {
219837da2899SCharles.Forsyth				oi := getobj(ex, oimages, string i);
219937da2899SCharles.Forsyth				if(oi != nil) {
220037da2899SCharles.Forsyth					v := ES->get(ex, oi, "@PRIVimageid");
220137da2899SCharles.Forsyth					if(ES->isnum(v) && ES->toInt32(ex, v) == imageid)
220237da2899SCharles.Forsyth						return oi;
220337da2899SCharles.Forsyth				}
220437da2899SCharles.Forsyth			}
220537da2899SCharles.Forsyth		}
220637da2899SCharles.Forsyth	}
220737da2899SCharles.Forsyth	return nil;
220837da2899SCharles.Forsyth}
220937da2899SCharles.Forsyth
221037da2899SCharles.Forsyth# return nil if none such, or not an object
221137da2899SCharles.Forsythgetobj(ex : ref Exec, o: ref Obj, prop: string) : ref Obj
221237da2899SCharles.Forsyth{
221337da2899SCharles.Forsyth	if(o != nil) {
221437da2899SCharles.Forsyth		v := ES->get(ex, o, prop);
221537da2899SCharles.Forsyth		if(ES->isobj(v))
221637da2899SCharles.Forsyth			return ES->toObject(ex, v);
221737da2899SCharles.Forsyth	}
221837da2899SCharles.Forsyth	return nil;
221937da2899SCharles.Forsyth}
222037da2899SCharles.Forsyth
222137da2899SCharles.Forsyth# return nil if none such, or not an object
222237da2899SCharles.Forsythgetarrayelem(ex : ref Exec, o: ref Obj, arrayname: string, index: int) : ref Obj
222337da2899SCharles.Forsyth{
222437da2899SCharles.Forsyth	oarr := getobj(ex, o, arrayname);
222537da2899SCharles.Forsyth	if(oarr != nil) {
222637da2899SCharles.Forsyth		v := ES->get(ex, oarr, string index);
222737da2899SCharles.Forsyth		if(ES->isobj(v))
222837da2899SCharles.Forsyth			return ES->toObject(ex, v);
222937da2899SCharles.Forsyth	}
223037da2899SCharles.Forsyth	return nil;
223137da2899SCharles.Forsyth}
223237da2899SCharles.Forsyth
223337da2899SCharles.Forsyth# return "" if none such, or not a string
223437da2899SCharles.Forsythgetstr(ex : ref Exec, o: ref Obj, prop: string) : string
223537da2899SCharles.Forsyth{
223637da2899SCharles.Forsyth
223737da2899SCharles.Forsyth	if(o != nil) {
223837da2899SCharles.Forsyth		v := ES->get(ex, o, prop);
223937da2899SCharles.Forsyth		if(ES->isstr(v))
224037da2899SCharles.Forsyth			return ES->toString(ex, v);
224137da2899SCharles.Forsyth	}
224237da2899SCharles.Forsyth	return "";
224337da2899SCharles.Forsyth}
224437da2899SCharles.Forsyth
224537da2899SCharles.Forsyth# Property index, -1 if doesn't exist
224637da2899SCharles.Forsythpind(o: ref Obj, prop: string) : int
224737da2899SCharles.Forsyth{
224837da2899SCharles.Forsyth	props := o.props;
224937da2899SCharles.Forsyth	for(i := 0; i < len props; i++){
225037da2899SCharles.Forsyth		if(props[i] != nil && props[i].name == prop)
225137da2899SCharles.Forsyth			return i;
225237da2899SCharles.Forsyth	}
225337da2899SCharles.Forsyth	return -1;
225437da2899SCharles.Forsyth}
225537da2899SCharles.Forsyth
225637da2899SCharles.Forsyth# Reinitialize property prop of object o to value v
225737da2899SCharles.Forsyth# (pay no attention to ReadOnly status, so can't use ES->put).
225837da2899SCharles.Forsyth# Assume the property exists already.
225937da2899SCharles.Forsythreinitprop(o: ref Obj, prop: string, v: ref Val)
226037da2899SCharles.Forsyth{
226137da2899SCharles.Forsyth	i := pind(o, prop);
226237da2899SCharles.Forsyth	if(i < 0) {
226337da2899SCharles.Forsyth		# set up dummy ex for now - needs sorting out
226437da2899SCharles.Forsyth		ex := ref Exec;
226537da2899SCharles.Forsyth		ES->runtime(ex, nil, "missing property " + prop); # shouldn't happen
226637da2899SCharles.Forsyth	}
226737da2899SCharles.Forsyth	CU->assert(i >= 0);
226837da2899SCharles.Forsyth	o.props[i].val.val = v;
226937da2899SCharles.Forsyth}
227037da2899SCharles.Forsyth
227137da2899SCharles.Forsyth# Get the array object named aname from o, and also find its current
227237da2899SCharles.Forsyth# length value.  If there is any problem, return (nil, 0).
227337da2899SCharles.Forsythgetarraywithlen(ex : ref Exec, o: ref Obj, aname: string) : (ref Obj, int)
227437da2899SCharles.Forsyth{
227537da2899SCharles.Forsyth	varray := ES->get(ex, o, aname);
227637da2899SCharles.Forsyth	if(ES->isobj(varray)) {
227737da2899SCharles.Forsyth		oarray := ES->toObject(ex, varray);
227837da2899SCharles.Forsyth		vlen := ES->get(ex, oarray, "length");
227937da2899SCharles.Forsyth		if(vlen != ES->undefined)
228037da2899SCharles.Forsyth			return (oarray, ES->toInt32(ex, vlen));
228137da2899SCharles.Forsyth	}
228237da2899SCharles.Forsyth	return (nil, 0);
228337da2899SCharles.Forsyth}
228437da2899SCharles.Forsyth
228537da2899SCharles.Forsyth# Put val v as property "index" of object oarray.
228637da2899SCharles.Forsyth# Also, if the name doesn't conflict with array properties, add the val as
228737da2899SCharles.Forsyth# a "name" property too
228837da2899SCharles.Forsytharrayput(ex : ref Exec, oarray: ref Obj, index: int, name: string, v: ref Val)
228937da2899SCharles.Forsyth{
229037da2899SCharles.Forsyth	ES->put(ex, oarray, string index, v);
229137da2899SCharles.Forsyth	if (name != "length" && prop2index(name) == -1)
229237da2899SCharles.Forsyth		ES->put(ex, oarray, name, v);
229337da2899SCharles.Forsyth}
229437da2899SCharles.Forsyth
229537da2899SCharles.Forsythprop2index(p: string): int
229637da2899SCharles.Forsyth{
229737da2899SCharles.Forsyth	if (p == nil)
229837da2899SCharles.Forsyth		return -1;
229937da2899SCharles.Forsyth	v := 0;
230037da2899SCharles.Forsyth	for (i := 0; i < len p; i++) {
230137da2899SCharles.Forsyth		c := p[i];
230237da2899SCharles.Forsyth		if (c < '0' || c > '9')
230337da2899SCharles.Forsyth			return -1;
230437da2899SCharles.Forsyth		v = 10 * v + c - '0';
230537da2899SCharles.Forsyth	}
230637da2899SCharles.Forsyth	return v;
230737da2899SCharles.Forsyth}
230837da2899SCharles.Forsyth
230937da2899SCharles.Forsyth# Instantiate window object.
231037da2899SCharles.Forsyth# mkhostobj has already put the property names and default initial values in;
231137da2899SCharles.Forsyth# we have to fill in the proper values.
231237da2899SCharles.Forsythwininstant(sw: ref ScriptWin)
231337da2899SCharles.Forsyth{
231437da2899SCharles.Forsyth	ex := sw.ex;
231537da2899SCharles.Forsyth	w := ex.global;
231637da2899SCharles.Forsyth	f := sw.frame;
231737da2899SCharles.Forsyth
231837da2899SCharles.Forsyth	sw.error = 0;
231937da2899SCharles.Forsyth	prevkids := sw.kids;
232037da2899SCharles.Forsyth	sw.kids = nil;
232137da2899SCharles.Forsyth	sw.forms = nil;
232237da2899SCharles.Forsyth	sw.imgs = nil;
232337da2899SCharles.Forsyth	sw.active = 0;
232437da2899SCharles.Forsyth
232537da2899SCharles.Forsyth	# document to be init'd by xfertoscriptobjs - WRONG,
232637da2899SCharles.Forsyth	# has to be init'd up-front as one frame may refer
232737da2899SCharles.Forsyth	# to another's document object (esp. for document.write calls)
232837da2899SCharles.Forsyth	od := getobj(ex, w, "document");
232937da2899SCharles.Forsyth	if(od == nil) {
233037da2899SCharles.Forsyth		docv := ES->objval(mkhostobj(ex, "document"));
233137da2899SCharles.Forsyth		reinitprop(w, "document", docv);
233237da2899SCharles.Forsyth		od = getobj(ex, w, "document");
233337da2899SCharles.Forsyth		CU->assert(od != nil);
233437da2899SCharles.Forsyth	}
233537da2899SCharles.Forsyth
233637da2899SCharles.Forsyth	# frames[ ]
233737da2899SCharles.Forsyth	ao := ES->mkobj(ex.arrayproto, "Array");
233837da2899SCharles.Forsyth	ES->varinstant(ao, ES->DontEnum|ES->DontDelete, "length", ref RefVal(ES->numval(0.)));
233937da2899SCharles.Forsyth	reinitprop(w, "frames", ES->objval(ao));
234037da2899SCharles.Forsyth	for (kl := f.kids; kl != nil; kl = tl kl) {
234137da2899SCharles.Forsyth		klf := hd kl;
234237da2899SCharles.Forsyth		# look for original ScriptWin
234337da2899SCharles.Forsyth		for (oldkl := prevkids; oldkl != nil; oldkl = tl oldkl) {
234437da2899SCharles.Forsyth			oldksw := hd oldkl;
234537da2899SCharles.Forsyth			if (oldksw.frame == klf) {
234637da2899SCharles.Forsyth				wininstant(oldksw);
234737da2899SCharles.Forsyth				sw.kids = oldksw :: sw.kids;
234837da2899SCharles.Forsyth				break;
234937da2899SCharles.Forsyth			}
235037da2899SCharles.Forsyth		}
235137da2899SCharles.Forsyth		if (oldkl == nil)
235237da2899SCharles.Forsyth			sw.addkid(klf);
235337da2899SCharles.Forsyth	}
235437da2899SCharles.Forsyth	kn := 0;
235537da2899SCharles.Forsyth	for (swkl := sw.kids; swkl != nil; swkl = tl swkl) {
235637da2899SCharles.Forsyth		k := hd swkl;
235737da2899SCharles.Forsyth		# Yes, frame name should be defined as property of parent
235837da2899SCharles.Forsyth		arrayput(ex, ao, kn++, "", k.val);
235937da2899SCharles.Forsyth		if (k.frame != nil && k.frame.name != nil) {
236037da2899SCharles.Forsyth			ES->put(ex, ao, k.frame.name, k.val);
236137da2899SCharles.Forsyth			ES->varinstant(w, 0, k.frame.name, ref RefVal(k.val));
236237da2899SCharles.Forsyth		}
236337da2899SCharles.Forsyth	}
236437da2899SCharles.Forsyth
236537da2899SCharles.Forsyth	reinitprop(w, "length", ES->numval(real len f.kids));
236637da2899SCharles.Forsyth
236737da2899SCharles.Forsyth	v := ref Val;
236837da2899SCharles.Forsyth	if (sw.parent == nil)
236937da2899SCharles.Forsyth		v = ES->objval(w);
237037da2899SCharles.Forsyth	else
237137da2899SCharles.Forsyth		v = ES->objval(sw.parent.ex.global);
237237da2899SCharles.Forsyth	reinitprop(w, "parent", v);
237337da2899SCharles.Forsyth
237437da2899SCharles.Forsyth	if (f.name != nil)
237537da2899SCharles.Forsyth		reinitprop(w, "name", ES->strval(f.name));
237637da2899SCharles.Forsyth	reinitprop(w, "self", ES->objval(w));
237737da2899SCharles.Forsyth	reinitprop(w, "window", ES->objval(w));
237837da2899SCharles.Forsyth	reinitprop(w, "top", ES->objval(top.ex.global));
237937da2899SCharles.Forsyth	reinitprop(w, "Math", ES->get(ex, top.ex.global, "Math"));
238037da2899SCharles.Forsyth	reinitprop(w, "navigator", ES->get(ex, top.ex.global, "navigator"));
238137da2899SCharles.Forsyth}
238237da2899SCharles.Forsyth
238337da2899SCharles.Forsyth# Return initial document object value, based on d
238437da2899SCharles.Forsythdocinstant(ex: ref Exec, f: ref Layout->Frame) : ref Val
238537da2899SCharles.Forsyth{
238637da2899SCharles.Forsyth	od := mkhostobj(ex, "document");
238737da2899SCharles.Forsyth	docfill(ex, od, f);
238837da2899SCharles.Forsyth	return ES->objval(od);
238937da2899SCharles.Forsyth}
239037da2899SCharles.Forsyth
239137da2899SCharles.Forsyth# Fill in properties of doc object, based on d.
239237da2899SCharles.Forsyth# Can be called at various points during build.
239337da2899SCharles.Forsythdocfill(ex: ref Exec, od: ref Obj, f: ref Layout->Frame)
239437da2899SCharles.Forsyth{
239537da2899SCharles.Forsyth	sw := top.findbyframeid(f.id);
239637da2899SCharles.Forsyth	if(sw == nil)
239737da2899SCharles.Forsyth		return;
239837da2899SCharles.Forsyth	di := f.doc;
239937da2899SCharles.Forsyth	if(di.src != nil) {
240037da2899SCharles.Forsyth		reinitprop(od, "URL", ES->strval(di.src.tostring()));
240137da2899SCharles.Forsyth		reinitprop(od, "domain", ES->strval(di.src.host));
240237da2899SCharles.Forsyth	}
240337da2899SCharles.Forsyth	if(di.referrer != nil)
240437da2899SCharles.Forsyth		reinitprop(od, "referrer", ES->strval(di.referrer.tostring()));
240537da2899SCharles.Forsyth	if(di.doctitle != "")
240637da2899SCharles.Forsyth		reinitprop(od, "title", ES->strval(di.doctitle));
240737da2899SCharles.Forsyth	reinitprop(od, "lastModified", ES->strval(di.lastModified));
240837da2899SCharles.Forsyth	reinitprop(od, "bgColor", colorval(di.background.color));
240937da2899SCharles.Forsyth	reinitprop(od, "fgColor", colorval(di.text));
241037da2899SCharles.Forsyth	reinitprop(od, "alinkColor", colorval(di.alink));
241137da2899SCharles.Forsyth	reinitprop(od, "linkColor", colorval(di.link));
241237da2899SCharles.Forsyth	reinitprop(od, "vlinkColor", colorval(di.vlink));
241337da2899SCharles.Forsyth
241437da2899SCharles.Forsyth	# Forms in d.forms are in reverse order of appearance.
241537da2899SCharles.Forsyth	# Add any that aren't already in the document.forms object,
241637da2899SCharles.Forsyth	# assuming that the relative lengths will tell us what needs
241737da2899SCharles.Forsyth	# to be done.
241837da2899SCharles.Forsyth	if(di.forms != nil) {
241937da2899SCharles.Forsyth		newformslen := len di.forms;
242037da2899SCharles.Forsyth		oldformslen := len sw.forms;
242137da2899SCharles.Forsyth		oforms := getobj(ex, od, "forms");
242237da2899SCharles.Forsyth
242337da2899SCharles.Forsyth		# oforms should be non-nil, because the object is initialized
242437da2899SCharles.Forsyth		# to an empty array and is readonly.  The following test
242537da2899SCharles.Forsyth		# is just defensive.
242637da2899SCharles.Forsyth		if(oforms != nil) {
242737da2899SCharles.Forsyth			# run through our existing list of forms, looking
242837da2899SCharles.Forsyth			# for any not marked as Transferred (happens as a result
242937da2899SCharles.Forsyth			# of a script being called in the body of a form, while it is
243037da2899SCharles.Forsyth			# still being parsed)
243137da2899SCharles.Forsyth			for (sfl := sw.forms; sfl != nil; sfl = tl sfl) {
243237da2899SCharles.Forsyth				sf := hd sfl;
243337da2899SCharles.Forsyth				form := sf.form;
243437da2899SCharles.Forsyth				if (form.state != B->FormTransferred) {
243537da2899SCharles.Forsyth#					(sf.obj, sf.fields) = forminstant(ex, form, di.frameid);
243637da2899SCharles.Forsyth					(newobj, newfields) := forminstant(ex, form, di.frameid);
243737da2899SCharles.Forsyth					*sf.obj = *newobj;
243837da2899SCharles.Forsyth					sf.fields = newfields;
243937da2899SCharles.Forsyth				}
244037da2899SCharles.Forsyth				if (form.state == B->FormDone)
244137da2899SCharles.Forsyth					form.state = B->FormTransferred;
244237da2899SCharles.Forsyth			}
244337da2899SCharles.Forsyth
244437da2899SCharles.Forsyth			# process additional forms
244537da2899SCharles.Forsyth			fl := di.forms;
244637da2899SCharles.Forsyth			for(i := newformslen-1; i >= oldformslen; i--) {
244737da2899SCharles.Forsyth				form := hd fl;
244837da2899SCharles.Forsyth				fl = tl fl;
244937da2899SCharles.Forsyth				if (form.state != B->FormTransferred) {
245037da2899SCharles.Forsyth					sf := ref ScriptForm (form, nil, i, nil);
245137da2899SCharles.Forsyth					(sf.obj, sf.fields) = forminstant(ex, form, di.frameid);
245237da2899SCharles.Forsyth					arrayput(ex, oforms, i, form.name, ES->objval(sf.obj));
245337da2899SCharles.Forsyth					if(form.name != "")
245437da2899SCharles.Forsyth						ES->put(ex, od, form.name, ES->objval(sf.obj));
245537da2899SCharles.Forsyth					sw.forms = sf :: sw.forms;
245637da2899SCharles.Forsyth				}
245737da2899SCharles.Forsyth				if (form.state == B->FormDone)
245837da2899SCharles.Forsyth					form.state = B->FormTransferred;
245937da2899SCharles.Forsyth			}
246037da2899SCharles.Forsyth		}
246137da2899SCharles.Forsyth	}
246237da2899SCharles.Forsyth
246337da2899SCharles.Forsyth	# Charon calls "DestAnchor" what Netscape calls "Anchor".
246437da2899SCharles.Forsyth	# Use same method as for forms to discover new ones.
246537da2899SCharles.Forsyth	if(di.dests != nil) {
246637da2899SCharles.Forsyth		newdestslen := len di.dests;
246737da2899SCharles.Forsyth		(oanchors, oldanchorslen) := getarraywithlen(ex, od, "anchors");
246837da2899SCharles.Forsyth		if(oanchors != nil) {
246937da2899SCharles.Forsyth			dl := di.dests;
247037da2899SCharles.Forsyth			for(i := newdestslen-1; i >= oldanchorslen; i--) {
247137da2899SCharles.Forsyth				dest := hd dl;
247237da2899SCharles.Forsyth				dl = tl dl;
247337da2899SCharles.Forsyth				arrayput(ex, oanchors, i, dest.name, anchorinstant(ex, dest.name));
247437da2899SCharles.Forsyth			}
247537da2899SCharles.Forsyth		}
247637da2899SCharles.Forsyth	}
247737da2899SCharles.Forsyth
247837da2899SCharles.Forsyth	# Charon calls "Anchor" what Netscape calls "Link" (how confusing for us!).
247937da2899SCharles.Forsyth	# Use same method as for forms to discover new ones.
248037da2899SCharles.Forsyth	# BUG: Areas are supposed to be in this list too.
248137da2899SCharles.Forsyth	if(di.anchors != nil) {
248237da2899SCharles.Forsyth		newanchorslen := len di.anchors;
248337da2899SCharles.Forsyth		(olinks, oldlinkslen) := getarraywithlen(ex, od, "links");
248437da2899SCharles.Forsyth		if(olinks != nil) {
248537da2899SCharles.Forsyth			al := di.anchors;
248637da2899SCharles.Forsyth			for(i := newanchorslen-1; i >= oldlinkslen; i--) {
248737da2899SCharles.Forsyth				a := hd al;
248837da2899SCharles.Forsyth				al = tl al;
248937da2899SCharles.Forsyth				arrayput(ex, olinks, i, a.name,  linkinstant(ex, a, f.id));
249037da2899SCharles.Forsyth			}
249137da2899SCharles.Forsyth		}
249237da2899SCharles.Forsyth	}
249337da2899SCharles.Forsyth
249437da2899SCharles.Forsyth	if(di.images != nil) {
249537da2899SCharles.Forsyth		newimageslen := len di.images;
249637da2899SCharles.Forsyth		(oimages, oldimageslen) := getarraywithlen(ex, od, "images");
249737da2899SCharles.Forsyth		if(oimages != nil) {
249837da2899SCharles.Forsyth			il := di.images;
249937da2899SCharles.Forsyth			for(i := newimageslen-1; i >= oldimageslen; i--) {
250037da2899SCharles.Forsyth				imit := hd il;
250137da2899SCharles.Forsyth				il = tl il;
250237da2899SCharles.Forsyth				pick ii := imit {
250337da2899SCharles.Forsyth				Iimage =>
250437da2899SCharles.Forsyth					vim := imageinstant(ex, ii);
250537da2899SCharles.Forsyth					arrayput(ex, oimages, i, ii.name, vim);
250637da2899SCharles.Forsyth					ES->put(ex, od, ii.name, vim);
250737da2899SCharles.Forsyth					if(ES->isobj(vim)) {
250837da2899SCharles.Forsyth						sw.imgs = ref ScriptImg(ii, vim.obj) :: sw.imgs;
250937da2899SCharles.Forsyth					}
251037da2899SCharles.Forsyth				}
251137da2899SCharles.Forsyth			}
251237da2899SCharles.Forsyth		}
251337da2899SCharles.Forsyth	}
251437da2899SCharles.Forsyth
251537da2899SCharles.Forsyth	# private variables
251637da2899SCharles.Forsyth	ES->varinstant(od, ES->DontEnum|ES->DontDelete, "@PRIVframeid",
251737da2899SCharles.Forsyth			ref RefVal(ES->numval(real di.frameid)));
251837da2899SCharles.Forsyth}
251937da2899SCharles.Forsyth
252037da2899SCharles.Forsythforminstant(ex : ref Exec, form: ref Build->Form, frameid: int) : (ref Obj, list of (ref Build->Formfield, ref Obj))
252137da2899SCharles.Forsyth{
252237da2899SCharles.Forsyth	fields : list of (ref Build->Formfield, ref ES->Obj);
252337da2899SCharles.Forsyth	oform := mkhostobj(ex, "Form");
252437da2899SCharles.Forsyth	reinitprop(oform, "action", ES->strval(form.action.tostring()));
252537da2899SCharles.Forsyth	reinitprop(oform, "encoding", ES->strval("application/x-www-form-urlencoded"));
252637da2899SCharles.Forsyth	reinitprop(oform, "length", ES->numval(real form.nfields));
252737da2899SCharles.Forsyth	reinitprop(oform, "method", ES->strval(CU->hmeth[form.method]));
252837da2899SCharles.Forsyth	reinitprop(oform, "name", ES->strval(form.name));
252937da2899SCharles.Forsyth	reinitprop(oform, "target", ES->strval(form.target));
253037da2899SCharles.Forsyth	ffl := form.fields;
253137da2899SCharles.Forsyth	if(ffl != nil) {
253237da2899SCharles.Forsyth		velements := ES->get(ex, oform, "elements");
253337da2899SCharles.Forsyth		if(ES->isobj(velements)) {
253437da2899SCharles.Forsyth			oelements := ES->toObject(ex, velements);
253537da2899SCharles.Forsyth			for(i := 0; i < form.nfields; i++) {
253637da2899SCharles.Forsyth				field := hd ffl;
253737da2899SCharles.Forsyth				ffl = tl ffl;
253837da2899SCharles.Forsyth				vfield := fieldinstant(ex, field, oform);
253937da2899SCharles.Forsyth
254037da2899SCharles.Forsyth				# convert multiple fields of same name to an array
254137da2899SCharles.Forsyth				prev := ES->get(ex, oform, field.name);
254237da2899SCharles.Forsyth				if (prev != nil && ES->isobj(prev)) {
254337da2899SCharles.Forsyth					newix := 0;
254437da2899SCharles.Forsyth					ar : ref Obj;
254537da2899SCharles.Forsyth					if (ES->isarray(prev.obj)) {
254637da2899SCharles.Forsyth						ar = prev.obj;
254737da2899SCharles.Forsyth						vlen := ES->get(ex, ar, "length");
254837da2899SCharles.Forsyth						newix = ES->toInt32(ex, vlen);
254937da2899SCharles.Forsyth					} else {
255037da2899SCharles.Forsyth						# create a new array
255137da2899SCharles.Forsyth						ar = ES->mkobj(ex.arrayproto, "Array");
255237da2899SCharles.Forsyth						ES->varinstant(ar, ES->DontEnum|ES->DontDelete, "length", ref RefVal(ES->numval(real 2)));
255337da2899SCharles.Forsyth						ES->put(ex, oform, field.name, ES->objval(ar));
255437da2899SCharles.Forsyth						arrayput(ex, ar, 0, "", prev);
255537da2899SCharles.Forsyth						newix = 1;
255637da2899SCharles.Forsyth					}
255737da2899SCharles.Forsyth					arrayput(ex, ar, newix, "", vfield);
255837da2899SCharles.Forsyth				} else {
255937da2899SCharles.Forsyth					# first time we have seen a field of this name
256037da2899SCharles.Forsyth					ES->put(ex, oform, field.name, vfield);
256137da2899SCharles.Forsyth				}
256237da2899SCharles.Forsyth				# although it is incorrect to add field name to
256337da2899SCharles.Forsyth				# elements array (as well as being indexed)
256437da2899SCharles.Forsyth				# - gives rise to name clashes, e.g radio buttons
256537da2899SCharles.Forsyth				# do it because other browsers do and some fools use it!
256637da2899SCharles.Forsyth				arrayput(ex, oelements, i, field.name, vfield);
256737da2899SCharles.Forsyth				fields = (field, ES->toObject(ex, vfield)) :: fields;
256837da2899SCharles.Forsyth			}
256937da2899SCharles.Forsyth		}
257037da2899SCharles.Forsyth	}
257137da2899SCharles.Forsyth	for(el := form.events; el != nil; el = tl el) {
257237da2899SCharles.Forsyth		e := hd el;
257337da2899SCharles.Forsyth		hname := "";
257437da2899SCharles.Forsyth		case e.attid {
257537da2899SCharles.Forsyth		Lex->Aonreset =>
257637da2899SCharles.Forsyth			hname = "onreset";
257737da2899SCharles.Forsyth			form.evmask |= E->SEonreset;
257837da2899SCharles.Forsyth		Lex->Aonsubmit =>
257937da2899SCharles.Forsyth			hname = "onsubmit";
258037da2899SCharles.Forsyth			form.evmask |= E->SEonsubmit;
258137da2899SCharles.Forsyth		}
258237da2899SCharles.Forsyth		if(hname != "")
258337da2899SCharles.Forsyth			puthandler(ex, oform, hname, e.value);
258437da2899SCharles.Forsyth	}
258537da2899SCharles.Forsyth#	form.events = nil;
258637da2899SCharles.Forsyth	# private variables
258737da2899SCharles.Forsyth	ES->varinstant(oform, ES->DontEnum|ES->DontDelete, "@PRIVformid",
258837da2899SCharles.Forsyth			ref RefVal(ES->numval(real form.formid)));
258937da2899SCharles.Forsyth	ES->varinstant(oform, ES->DontEnum|ES->DontDelete, "@PRIVframeid",
259037da2899SCharles.Forsyth			ref RefVal(ES->numval(real frameid)));
259137da2899SCharles.Forsyth	return (oform, fields);
259237da2899SCharles.Forsyth}
259337da2899SCharles.Forsyth
259437da2899SCharles.Forsythfieldinstant(ex : ref Exec, field: ref Build->Formfield, oform: ref Obj) : ref Val
259537da2899SCharles.Forsyth{
259637da2899SCharles.Forsyth	ofield := mkhostobj(ex, "FormField");
259737da2899SCharles.Forsyth	reinitprop(ofield, "form", ES->objval(oform));
259837da2899SCharles.Forsyth	reinitprop(ofield, "name", ES->strval(field.name));
259937da2899SCharles.Forsyth	reinitprop(ofield, "value", ES->strval(field.value));
260037da2899SCharles.Forsyth	reinitprop(ofield, "defaultValue", ES->strval(field.value));
260137da2899SCharles.Forsyth	chkd := ES->false;
260237da2899SCharles.Forsyth	if((field.flags & Build->FFchecked) != byte 0)
260337da2899SCharles.Forsyth		chkd = ES->true;
260437da2899SCharles.Forsyth	reinitprop(ofield, "checked", chkd);
260537da2899SCharles.Forsyth	reinitprop(ofield, "defaultChecked", chkd);
260637da2899SCharles.Forsyth	nopts := len field.options;
260737da2899SCharles.Forsyth	reinitprop(ofield, "length", ES->numval(real nopts));
260837da2899SCharles.Forsyth	reinitprop(ofield, "selectedIndex", ES->numval(-1.0)); # BUG: search for selected option
260937da2899SCharles.Forsyth	ty : string;
261037da2899SCharles.Forsyth	case field.ftype {
261137da2899SCharles.Forsyth	Build->Ftext =>
261237da2899SCharles.Forsyth		ty = "text";
261337da2899SCharles.Forsyth		reinitprop(ofield, "value", ES->strval(field.value));
261437da2899SCharles.Forsyth	Build->Fpassword =>
261537da2899SCharles.Forsyth		ty = "password";
261637da2899SCharles.Forsyth	Build->Fcheckbox =>
261737da2899SCharles.Forsyth		ty = "checkbox";
261837da2899SCharles.Forsyth	Build->Fradio =>
261937da2899SCharles.Forsyth		ty = "radio";
262037da2899SCharles.Forsyth	Build->Fsubmit =>
262137da2899SCharles.Forsyth		ty = "submit";
262237da2899SCharles.Forsyth	Build->Fhidden =>
262337da2899SCharles.Forsyth		ty = "hidden";
262437da2899SCharles.Forsyth	Build->Fimage =>
262537da2899SCharles.Forsyth		ty = "image";
262637da2899SCharles.Forsyth	Build->Freset =>
262737da2899SCharles.Forsyth		ty = "reset";
262837da2899SCharles.Forsyth	Build->Ffile =>
262937da2899SCharles.Forsyth		ty = "fileupload";
263037da2899SCharles.Forsyth	Build->Fbutton =>
263137da2899SCharles.Forsyth		ty = "button";
263237da2899SCharles.Forsyth	Build->Fselect =>
263337da2899SCharles.Forsyth		ty = "select";
263437da2899SCharles.Forsyth		si := -1;
263537da2899SCharles.Forsyth		options := ES->mkobj(ex.arrayproto, "Array");
263637da2899SCharles.Forsyth		ES->varinstant(options, ES->DontEnum|ES->DontDelete, "length",
263737da2899SCharles.Forsyth					ref RefVal(ES->numval(real nopts)));
263837da2899SCharles.Forsyth		reinitprop(ofield, "options", ES->objval(options));
263937da2899SCharles.Forsyth		optl := field.options;
264037da2899SCharles.Forsyth		vfield := ES->objval(ofield);
264137da2899SCharles.Forsyth		for(i := 0; i < nopts; i++) {
264237da2899SCharles.Forsyth			opt := hd optl;
264337da2899SCharles.Forsyth			optl = tl optl;
264437da2899SCharles.Forsyth			oopt := mkhostobj(ex, "Option");
264537da2899SCharles.Forsyth			reinitprop(oopt, "index", ES->numval(real i));
264637da2899SCharles.Forsyth			reinitprop(oopt, "value", ES->strval(opt.value));
264737da2899SCharles.Forsyth			reinitprop(oopt, "text", ES->strval(opt.display));
264837da2899SCharles.Forsyth			# private variables
264937da2899SCharles.Forsyth			ES->put(ex, oopt, "@PRIVformfield", vfield);
265037da2899SCharles.Forsyth			if(opt.selected) {
265137da2899SCharles.Forsyth				si = i;
265237da2899SCharles.Forsyth				reinitprop(oopt, "selected", ES->true);
265337da2899SCharles.Forsyth				reinitprop(oopt, "defaultSelected", ES->true);
265437da2899SCharles.Forsyth				reinitprop(ofield, "selectedIndex", ES->numval(real i));
265537da2899SCharles.Forsyth			}
265637da2899SCharles.Forsyth			ES->put(ex, options, string i, ES->objval(oopt));
265737da2899SCharles.Forsyth		}
265837da2899SCharles.Forsyth		ES->put(ex, options, "selectedIndex", ES->numval(real si));
265937da2899SCharles.Forsyth		ES->put(ex, options, "@PRIVformfield", vfield);
266037da2899SCharles.Forsyth		options.host = me;
266137da2899SCharles.Forsyth	Build->Ftextarea =>
266237da2899SCharles.Forsyth		ty = "textarea";
266337da2899SCharles.Forsyth	}
266437da2899SCharles.Forsyth	reinitprop(ofield, "type", ES->strval(ty));
266537da2899SCharles.Forsyth	for(el := field.events; el != nil; el = tl el) {
266637da2899SCharles.Forsyth		e := hd el;
266737da2899SCharles.Forsyth		hname := "";
266837da2899SCharles.Forsyth		case e.attid {
266937da2899SCharles.Forsyth		Lex->Aonblur =>
267037da2899SCharles.Forsyth			hname = "onblur";
267137da2899SCharles.Forsyth			field.evmask |= E->SEonblur;
267237da2899SCharles.Forsyth		Lex->Aonchange =>
267337da2899SCharles.Forsyth			hname = "onchange";
267437da2899SCharles.Forsyth			field.evmask |= E->SEonchange;
267537da2899SCharles.Forsyth		Lex->Aonclick =>
267637da2899SCharles.Forsyth			hname = "onclick";
267737da2899SCharles.Forsyth			field.evmask |= E->SEonclick;
267837da2899SCharles.Forsyth		Lex->Aondblclick =>
267937da2899SCharles.Forsyth			hname = "ondblclick";
268037da2899SCharles.Forsyth			field.evmask |= E->SEondblclick;
268137da2899SCharles.Forsyth		Lex->Aonfocus =>
268237da2899SCharles.Forsyth			hname = "onfocus";
268337da2899SCharles.Forsyth			field.evmask |= E->SEonfocus;
268437da2899SCharles.Forsyth		Lex->Aonkeydown =>
268537da2899SCharles.Forsyth			hname = "onkeydown";
268637da2899SCharles.Forsyth			field.evmask |= E->SEonkeydown;
268737da2899SCharles.Forsyth		Lex->Aonkeypress =>
268837da2899SCharles.Forsyth			hname = "onkeypress";
268937da2899SCharles.Forsyth			field.evmask |= E->SEonkeypress;
269037da2899SCharles.Forsyth		Lex->Aonkeyup =>
269137da2899SCharles.Forsyth			hname = "onkeyup";
269237da2899SCharles.Forsyth			field.evmask |= E->SEonkeyup;
269337da2899SCharles.Forsyth		Lex->Aonmousedown =>
269437da2899SCharles.Forsyth			hname = "onmousedown";
269537da2899SCharles.Forsyth			field.evmask |= E->SEonmousedown;
269637da2899SCharles.Forsyth		Lex->Aonmouseup =>
269737da2899SCharles.Forsyth			hname = "onmouseup";
269837da2899SCharles.Forsyth			field.evmask |= E->SEonmouseup;
269937da2899SCharles.Forsyth		Lex->Aonselect =>
270037da2899SCharles.Forsyth			hname = "onselect";
270137da2899SCharles.Forsyth			field.evmask |= E->SEonselect;
270237da2899SCharles.Forsyth		}
270337da2899SCharles.Forsyth		if(hname != "")
270437da2899SCharles.Forsyth			puthandler(ex, ofield, hname, e.value);
270537da2899SCharles.Forsyth	}
270637da2899SCharles.Forsyth#	field.events = nil;
270737da2899SCharles.Forsyth	# private variables
270837da2899SCharles.Forsyth	ES->varinstant(ofield, ES->DontEnum|ES->DontDelete, "@PRIVfieldid",
270937da2899SCharles.Forsyth			ref RefVal(ES->numval(real field.fieldid)));
271037da2899SCharles.Forsyth	return ES->objval(ofield);
271137da2899SCharles.Forsyth}
271237da2899SCharles.Forsyth
271337da2899SCharles.Forsyth# Make an event handler named hname in o, with given body.
271437da2899SCharles.Forsythputhandler(ex: ref Exec, o: ref Obj, hname: string, hbody: string)
271537da2899SCharles.Forsyth{
27168911721eSCharles.Forsyth	ES->eval(ex, "function PRIVhandler() {" + hbody + "}");
271737da2899SCharles.Forsyth	hobj := getobj(ex, ex.global, "PRIVhandler");
271837da2899SCharles.Forsyth	if(hobj != nil) {
271937da2899SCharles.Forsyth		ES->put(ex, o, hname, ES->objval(hobj));
272037da2899SCharles.Forsyth	}
272137da2899SCharles.Forsyth}
272237da2899SCharles.Forsyth
272337da2899SCharles.Forsythanchorinstant(ex : ref Exec, nm: string) : ref Val
272437da2899SCharles.Forsyth{
272537da2899SCharles.Forsyth	oanchor := mkhostobj(ex, "Anchor");
272637da2899SCharles.Forsyth	reinitprop(oanchor, "name", ES->strval(nm));
272737da2899SCharles.Forsyth	return ES->objval(oanchor);
272837da2899SCharles.Forsyth}
272937da2899SCharles.Forsyth
273037da2899SCharles.Forsyth# Build ensures that the anchor href has been made absolute
273137da2899SCharles.Forsythlinkinstant(ex: ref Exec, anchor: ref Build->Anchor, frameid: int) : ref Val
273237da2899SCharles.Forsyth{
273337da2899SCharles.Forsyth	olink := mkhostobj(ex, "Link");
273437da2899SCharles.Forsyth	u := anchor.href;
273537da2899SCharles.Forsyth	if(u != nil) {
273637da2899SCharles.Forsyth		if(u.frag != "")
273737da2899SCharles.Forsyth			reinitprop(olink, "hash", ES->strval("#" + u.frag));
273837da2899SCharles.Forsyth		host := u.host;
273937da2899SCharles.Forsyth		if(u.user != "" || u.passwd != "") {
274037da2899SCharles.Forsyth			host = u.user;
274137da2899SCharles.Forsyth			if(u.passwd != "")
274237da2899SCharles.Forsyth				host += ":" + u.passwd;
274337da2899SCharles.Forsyth			host += "@" + u.host;
274437da2899SCharles.Forsyth		}
274537da2899SCharles.Forsyth		reinitprop(olink, "host",  ES->strval(host));
274637da2899SCharles.Forsyth		hostname := host;
274737da2899SCharles.Forsyth		if(u.port != "")
274837da2899SCharles.Forsyth			hostname += ":" + u.port;
274937da2899SCharles.Forsyth		reinitprop(olink, "hostname", ES->strval(hostname));
275037da2899SCharles.Forsyth		reinitprop(olink, "href", ES->strval(u.tostring()));
275137da2899SCharles.Forsyth		reinitprop(olink, "pathname", ES->strval(u.path));
275237da2899SCharles.Forsyth		if(u.port != "")
275337da2899SCharles.Forsyth			reinitprop(olink, "port", ES->strval(u.port));
275437da2899SCharles.Forsyth		reinitprop(olink, "protocol", ES->strval(u.scheme + ":"));
275537da2899SCharles.Forsyth		if(u.query != "")
275637da2899SCharles.Forsyth			reinitprop(olink, "search", ES->strval("?" + u.query));
275737da2899SCharles.Forsyth	}
275837da2899SCharles.Forsyth	if(anchor.target != "")
275937da2899SCharles.Forsyth		reinitprop(olink, "target", ES->strval(anchor.target));
276037da2899SCharles.Forsyth
276137da2899SCharles.Forsyth	for(el := anchor.events; el != nil; el = tl el) {
276237da2899SCharles.Forsyth		e := hd el;
276337da2899SCharles.Forsyth		hname := "";
276437da2899SCharles.Forsyth		case e.attid {
276537da2899SCharles.Forsyth		Lex->Aonclick =>
276637da2899SCharles.Forsyth			hname = "onclick";
276737da2899SCharles.Forsyth			anchor.evmask |= E->SEonclick;
276837da2899SCharles.Forsyth		Lex->Aondblclick =>
276937da2899SCharles.Forsyth			hname = "ondblclick";
277037da2899SCharles.Forsyth			anchor.evmask |= E->SEondblclick;
277137da2899SCharles.Forsyth		Lex->Aonkeydown =>
277237da2899SCharles.Forsyth			hname = "onkeydown";
277337da2899SCharles.Forsyth			anchor.evmask |= E->SEonkeydown;
277437da2899SCharles.Forsyth		Lex->Aonkeypress =>
277537da2899SCharles.Forsyth			hname = "onkeypress";
277637da2899SCharles.Forsyth			anchor.evmask |= E->SEonkeypress;
277737da2899SCharles.Forsyth		Lex->Aonkeyup =>
277837da2899SCharles.Forsyth			hname = "onkeyup";
277937da2899SCharles.Forsyth			anchor.evmask |= E->SEonkeyup;
278037da2899SCharles.Forsyth		Lex->Aonmousedown =>
278137da2899SCharles.Forsyth			hname = "onmousedown";
278237da2899SCharles.Forsyth			anchor.evmask |= E->SEonmousedown;
278337da2899SCharles.Forsyth		Lex->Aonmouseout =>
278437da2899SCharles.Forsyth			hname = "onmouseout";
278537da2899SCharles.Forsyth			anchor.evmask |= E->SEonmouseout;
278637da2899SCharles.Forsyth		Lex->Aonmouseover =>
278737da2899SCharles.Forsyth			hname = "onmouseover";
278837da2899SCharles.Forsyth			anchor.evmask |= E->SEonmouseover;
278937da2899SCharles.Forsyth		Lex->Aonmouseup =>
279037da2899SCharles.Forsyth			hname = "onmouseup";
279137da2899SCharles.Forsyth			anchor.evmask |= E->SEonmouseup;
279237da2899SCharles.Forsyth		}
279337da2899SCharles.Forsyth		if(hname != "")
279437da2899SCharles.Forsyth			puthandler(ex, olink, hname, e.value);
279537da2899SCharles.Forsyth	}
279637da2899SCharles.Forsyth	anchor.events = nil;
279737da2899SCharles.Forsyth	# private variable
279837da2899SCharles.Forsyth	ES->varinstant(olink, ES->DontEnum|ES->DontDelete, "@PRIVanchorid",
279937da2899SCharles.Forsyth			ref RefVal(ES->numval(real anchor.index)));
280037da2899SCharles.Forsyth	ES->varinstant(olink, ES->DontEnum|ES->DontDelete, "@PRIVframeid",
280137da2899SCharles.Forsyth			ref RefVal(ES->numval(real frameid)));
280237da2899SCharles.Forsyth
280337da2899SCharles.Forsyth	return ES->objval(olink);
280437da2899SCharles.Forsyth}
280537da2899SCharles.Forsyth
280637da2899SCharles.Forsythimageinstant(ex: ref Exec, im: ref Build->Item.Iimage) : ref Val
280737da2899SCharles.Forsyth{
280837da2899SCharles.Forsyth	oim := mkhostobj(ex, "Image");
280937da2899SCharles.Forsyth	src := im.ci.src.tostring();
281037da2899SCharles.Forsyth	reinitprop(oim, "border", ES->numval(real im.border));
281137da2899SCharles.Forsyth	reinitprop(oim, "height", ES->numval(real im.imheight));
281237da2899SCharles.Forsyth	reinitprop(oim, "hspace", ES->numval(real im.hspace));
281337da2899SCharles.Forsyth	reinitprop(oim, "name", ES->strval(im.name));
281437da2899SCharles.Forsyth	reinitprop(oim, "src", ES->strval(src));
281537da2899SCharles.Forsyth	if(im.ci.lowsrc != nil)
281637da2899SCharles.Forsyth		reinitprop(oim, "lowsrc", ES->strval(im.ci.lowsrc.tostring()));
281737da2899SCharles.Forsyth	reinitprop(oim, "vspace", ES->numval(real im.vspace));
281837da2899SCharles.Forsyth	reinitprop(oim, "width", ES->numval(real im.imwidth));
281937da2899SCharles.Forsyth	if(im.ci.complete == 0)
282037da2899SCharles.Forsyth		done := ES->false;
282137da2899SCharles.Forsyth	else
282237da2899SCharles.Forsyth		done = ES->true;
282337da2899SCharles.Forsyth	reinitprop(oim, "complete", done);
282437da2899SCharles.Forsyth
282537da2899SCharles.Forsyth	el : list of Lex->Attr = nil;
282637da2899SCharles.Forsyth	if(im.genattr != nil)
282737da2899SCharles.Forsyth		el = im.genattr.events;
282837da2899SCharles.Forsyth	for(; el != nil; el = tl el) {
282937da2899SCharles.Forsyth		e := hd el;
283037da2899SCharles.Forsyth		hname := "";
283137da2899SCharles.Forsyth		case e.attid {
283237da2899SCharles.Forsyth		Lex->Aonabort =>
283337da2899SCharles.Forsyth			hname = "onabort";
283437da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonabort;
283537da2899SCharles.Forsyth		Lex->Aondblclick =>
283637da2899SCharles.Forsyth			hname = "ondblclick";
283737da2899SCharles.Forsyth			im.genattr.evmask |= E->SEondblclick;
283837da2899SCharles.Forsyth		Lex->Aonerror =>
283937da2899SCharles.Forsyth			hname = "onerror";
284037da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonerror;
284137da2899SCharles.Forsyth		Lex->Aonkeydown =>
284237da2899SCharles.Forsyth			hname = "onkeydown";
284337da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonkeydown;
284437da2899SCharles.Forsyth		Lex->Aonkeypress =>
284537da2899SCharles.Forsyth			hname = "onkeypress";
284637da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonkeypress;
284737da2899SCharles.Forsyth		Lex->Aonkeyup =>
284837da2899SCharles.Forsyth			hname = "onkeyup";
284937da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonkeyup;
285037da2899SCharles.Forsyth		Lex->Aonload =>
285137da2899SCharles.Forsyth			hname = "onload";
285237da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonload;
285337da2899SCharles.Forsyth		Lex->Aonmousedown =>
285437da2899SCharles.Forsyth			hname = "onmousedown";
285537da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonmousedown;
285637da2899SCharles.Forsyth		Lex->Aonmouseout =>
285737da2899SCharles.Forsyth			hname = "onmouseout";
285837da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonmouseout;
285937da2899SCharles.Forsyth		Lex->Aonmouseover =>
286037da2899SCharles.Forsyth			hname = "onmouseover";
286137da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonmouseover;
286237da2899SCharles.Forsyth		Lex->Aonmouseup =>
286337da2899SCharles.Forsyth			hname = "onmouseup";
286437da2899SCharles.Forsyth			im.genattr.evmask |= E->SEonmouseup;
286537da2899SCharles.Forsyth		}
286637da2899SCharles.Forsyth		if(hname != "")
286737da2899SCharles.Forsyth			puthandler(ex, oim, hname, e.value);
286837da2899SCharles.Forsyth	}
286937da2899SCharles.Forsyth	if(im.genattr != nil)
287037da2899SCharles.Forsyth		im.genattr.events = nil;
287137da2899SCharles.Forsyth
287237da2899SCharles.Forsyth	# private variables
287337da2899SCharles.Forsyth	ES->varinstant(oim, ES->DontEnum|ES->DontDelete, "@PRIVimageid",
287437da2899SCharles.Forsyth			ref RefVal(ES->numval(real im.imageid)));
287537da2899SCharles.Forsyth	# to keep track of src as currently known in item
287637da2899SCharles.Forsyth#	ES->varinstant(oim, ES->DontEnum|ES->DontDelete, "@PRIVsrc",
287737da2899SCharles.Forsyth#			ref RefVal(ES->strval(src)));
287837da2899SCharles.Forsyth	return ES->objval(oim);
287937da2899SCharles.Forsyth}
288037da2899SCharles.Forsyth
288137da2899SCharles.Forsythcolorval(v: int) : ref Val
288237da2899SCharles.Forsyth{
288337da2899SCharles.Forsyth	return ES->strval(sys->sprint("%.6x", v));
288437da2899SCharles.Forsyth}
288537da2899SCharles.Forsyth
288637da2899SCharles.Forsyth# If the o.name is a recognizable color, return it, else dflt
288737da2899SCharles.Forsythcolorxfer(ex: ref Exec, o: ref Obj, name: string, dflt: int) : int
288837da2899SCharles.Forsyth{
288937da2899SCharles.Forsyth	v := ES->get(ex, o, name);
289037da2899SCharles.Forsyth	if(v == ES->undefined)
289137da2899SCharles.Forsyth		return dflt;
289237da2899SCharles.Forsyth	return CU->color(ES->toString(ex, v), dflt);
289337da2899SCharles.Forsyth}
289437da2899SCharles.Forsyth
289537da2899SCharles.Forsythstrxfer(ex : ref Exec, o: ref Obj, name: string, dflt: string) : string
289637da2899SCharles.Forsyth{
289737da2899SCharles.Forsyth	v := ES->get(ex, o, name);
289837da2899SCharles.Forsyth	if(v == ES->undefined)
289937da2899SCharles.Forsyth		return dflt;
290037da2899SCharles.Forsyth	return ES->toString(ex, v);
290137da2899SCharles.Forsyth}
290237da2899SCharles.Forsyth
290337da2899SCharles.ForsythScriptWin.new(f: ref Layout->Frame, ex: ref Exec, loc: ref Obj, par: ref ScriptWin) : ref ScriptWin
290437da2899SCharles.Forsyth{
290537da2899SCharles.Forsyth	return ref ScriptWin(f, ex, loc, ES->objval(ex.global), par, nil, nil, nil, "", "", "", 1, 0, 0, nil);
290637da2899SCharles.Forsyth}
290737da2899SCharles.Forsyth
290837da2899SCharles.Forsyth# Make a new ScriptWin with f as frame and new, empty
290937da2899SCharles.Forsyth# Window object as obj, to be a child window of sw's window.
291037da2899SCharles.ForsythScriptWin.addkid(sw: self ref ScriptWin, f: ref Layout->Frame)
291137da2899SCharles.Forsyth{
291237da2899SCharles.Forsyth	(cex, clocobj) := makeframeex(f);
291337da2899SCharles.Forsyth	csw := ScriptWin.new(f, cex, clocobj, sw);
291437da2899SCharles.Forsyth	wininstant(csw);
291537da2899SCharles.Forsyth	sw.kids = csw :: sw.kids;
291637da2899SCharles.Forsyth}
291737da2899SCharles.Forsyth
291837da2899SCharles.ForsythScriptWin.dummy(): ref ScriptWin
291937da2899SCharles.Forsyth{
292037da2899SCharles.Forsyth	f := ref Layout->Frame;
292137da2899SCharles.Forsyth	f.doc = ref Build->Docinfo;
292237da2899SCharles.Forsyth	f.doc.base = U->parse("");
292337da2899SCharles.Forsyth	f.doc.src = U->parse("");
292437da2899SCharles.Forsyth	(cex, clocobj) := makeframeex(f);
292537da2899SCharles.Forsyth	csw := ScriptWin.new(f, cex, clocobj, nil);
292637da2899SCharles.Forsyth	wininstant(csw);
292737da2899SCharles.Forsyth	return csw;
292837da2899SCharles.Forsyth}
292937da2899SCharles.Forsyth
293037da2899SCharles.Forsyth# Find the ScriptWin in the tree with sw as root that has
293137da2899SCharles.Forsyth# f as frame, returning nil if none.
293237da2899SCharles.Forsyth#ScriptWin.findbyframe(sw: self ref ScriptWin, f: ref Layout->Frame) : ref ScriptWin
293337da2899SCharles.Forsyth#{
293437da2899SCharles.Forsyth#	if(sw.frame.id == f.id)
293537da2899SCharles.Forsyth#		return sw;
293637da2899SCharles.Forsyth#	for(l := sw.kids; l != nil; l = tl l) {
293737da2899SCharles.Forsyth#		x := (hd l).findbyframe(f);
293837da2899SCharles.Forsyth#		if(x != nil)
293937da2899SCharles.Forsyth#			return x;
294037da2899SCharles.Forsyth#	}
294137da2899SCharles.Forsyth#	return nil;
294237da2899SCharles.Forsyth#}
294337da2899SCharles.Forsyth
294437da2899SCharles.Forsyth# Find the ScriptWin in the tree with sw as root that has
294537da2899SCharles.Forsyth# fid as frame id, returning nil if none.
294637da2899SCharles.ForsythScriptWin.findbyframeid(sw: self ref ScriptWin, fid: int) : ref ScriptWin
294737da2899SCharles.Forsyth{
294837da2899SCharles.Forsyth	if(sw.frame.id == fid)
294937da2899SCharles.Forsyth		return sw;
295037da2899SCharles.Forsyth	for(l := sw.kids; l != nil; l = tl l) {
295137da2899SCharles.Forsyth		x := (hd l).findbyframeid(fid);
295237da2899SCharles.Forsyth		if(x != nil)
295337da2899SCharles.Forsyth			return x;
295437da2899SCharles.Forsyth	}
295537da2899SCharles.Forsyth	return nil;
295637da2899SCharles.Forsyth}
295737da2899SCharles.Forsyth
295837da2899SCharles.Forsyth# Find the ScriptWin in the tree with sw as root that has
295937da2899SCharles.Forsyth# d as doc for the frame, returning nil if none.
296037da2899SCharles.ForsythScriptWin.findbydoc(sw: self ref ScriptWin, d: ref Build->Docinfo) : ref ScriptWin
296137da2899SCharles.Forsyth{
296237da2899SCharles.Forsyth	if(sw.frame.doc == d)
296337da2899SCharles.Forsyth		return sw;
296437da2899SCharles.Forsyth	for(l := sw.kids; l != nil; l = tl l) {
296537da2899SCharles.Forsyth		x := (hd l).findbydoc(d);
296637da2899SCharles.Forsyth		if(x != nil)
296737da2899SCharles.Forsyth			return x;
296837da2899SCharles.Forsyth	}
296937da2899SCharles.Forsyth	return nil;
297037da2899SCharles.Forsyth}
297137da2899SCharles.Forsyth
297237da2899SCharles.Forsyth# obj can either be the frame's Window obj, Location obj, or document obj,
297337da2899SCharles.Forsyth# or an Image object within the frame
297437da2899SCharles.ForsythScriptWin.findbyobj(sw : self ref ScriptWin, obj : ref Obj) : ref ScriptWin
297537da2899SCharles.Forsyth{
297637da2899SCharles.Forsyth	if (sw.locobj == obj || sw.ex.global == obj || obj == getdocobj(sw.ex, sw.frame.id))
297737da2899SCharles.Forsyth		return sw;
297837da2899SCharles.Forsyth	if(opener != nil && (opener.locobj == obj || opener.ex.global == obj))
297937da2899SCharles.Forsyth		return opener;
298037da2899SCharles.Forsyth	for(sil := sw.imgs; sil != nil; sil = tl sil) {
298137da2899SCharles.Forsyth		if((hd sil).obj == obj)
298237da2899SCharles.Forsyth			return sw;
298337da2899SCharles.Forsyth	}
298437da2899SCharles.Forsyth	for (l := sw.kids; l != nil; l = tl l) {
298537da2899SCharles.Forsyth		x := (hd l).findbyobj(obj);
298637da2899SCharles.Forsyth		if (x != nil)
298737da2899SCharles.Forsyth			return x;
298837da2899SCharles.Forsyth	}
298937da2899SCharles.Forsyth	return nil;
299037da2899SCharles.Forsyth}
299137da2899SCharles.Forsyth
299237da2899SCharles.ForsythScriptWin.findbyname(sw : self ref ScriptWin, name : string) : ref ScriptWin
299337da2899SCharles.Forsyth{
299437da2899SCharles.Forsyth	if (sw.frame != nil && sw.frame.name == name)
299537da2899SCharles.Forsyth		return sw;
299637da2899SCharles.Forsyth	for (l := sw.kids; l != nil; l = tl l) {
299737da2899SCharles.Forsyth		x := (hd l).findbyname(name);
299837da2899SCharles.Forsyth		if (x != nil)
299937da2899SCharles.Forsyth			return x;
300037da2899SCharles.Forsyth	}
300137da2899SCharles.Forsyth	return nil;
300237da2899SCharles.Forsyth}
300337da2899SCharles.Forsyth
300437da2899SCharles.Forsythnewcharon(url: string, nm: string, sw: ref ScriptWin)
300537da2899SCharles.Forsyth{
300637da2899SCharles.Forsyth	cs := chan of string;
300737da2899SCharles.Forsyth
300837da2899SCharles.Forsyth	spawn CH->startcharon(url, cs);
300937da2899SCharles.Forsyth	for(;;){
301037da2899SCharles.Forsyth		alt{
301137da2899SCharles.Forsyth			s := <- cs =>
301237da2899SCharles.Forsyth				if(s == "B")
301337da2899SCharles.Forsyth					continue;
301437da2899SCharles.Forsyth				if(s == "E")
301537da2899SCharles.Forsyth					exit;
30168911721eSCharles.Forsyth				(nil, l) := sys->tokenize(s, " ");
301737da2899SCharles.Forsyth				case hd l{
301837da2899SCharles.Forsyth					"L" =>
301937da2899SCharles.Forsyth						sw.newloc = hd tl l;
302037da2899SCharles.Forsyth						sw.newloctarg = nm;
302137da2899SCharles.Forsyth						checknewlocs(sw);
302237da2899SCharles.Forsyth				}
302337da2899SCharles.Forsyth		}
302437da2899SCharles.Forsyth	}
302537da2899SCharles.Forsyth}
3026