JavaScript in pwa/p2js
Obviously more complete references can be found easily enough - the whole point of this is to hook
into the Edita/Edix F1 Help system, and that way speed up the development of pwa/p2js itself.
Again, this is of no particular help to anyone actually using pwa/p2js.
There may be some subtle implications of using these routines from an imperative mindset (as opposed to say a prototype or object orientated mindset) that may be clearer here than elsewhere, plus there may be for instance optional parameters and the like (of the javascript builtin functions listed below) that pwa/p2js does not use and/or specifically advises against. Lastly, by only documenting those fields and methods actually used, they should be a tad easier to locate, and hopefully impose significantly less cognitive overload.
Apart from an initial trawl, entries are likely to be added on an ad-hoc basis, as I realise it is now the Nth time I’ve had to go to MDN (the definititive fount of all knowledge) or w3schools (what it lacks in detail it makes up for in navigability). Things I use very rarely or are easily cribbed are unlikely to get a mention in here, for instance I’m not about to try and document JavaScript regular expressions.
Note that p2js.js in particular implements many of the standard Phix builtins, and others are auto-translated, so if you spot something rather familiar, perhaps you should treat it as such.
This covers both the use of JavaScript in p2js.js and pGUI.js, as well as providing some explanation for the sort of code that pwa/p2js.exw spits out. Several pages such as atom and length have JavaScript-links to this page in their "See Also"/p2js sections, rather than have that weird little popup when Phix.chm opens whereby despite their different cases both number and Number lookups (from eg xpEditer) would ask you to pick between atom and javascript, and then mess up the focus, often with the newly opened chm window hidden/relegated to the background. Obviously Phix gets preference over JavaScript in respect of which it opens first/by default.
Transpilation is largely a mechanical process of mapping between language syntax and compatible features, for example
"procedure p() end procedure" <==> "function p() { }" with no return statement.
Javascript is a typeless language, however to keep the output legible/reversible I have opted for eg "integer i" <==> "let /*integer*/ i;".
Phix sequences are actually a much closer match to JavaScript Arrays than Objects, so we use [] syntax rather than {}.
Phix sequences are 1-based, whereas Javascript Arrays are (loosely) 0-based, so we use eg `{1,2,3}` <==> `["sequence",1,2,3]`.
Obviously, p2js.js and pGUI.js should only expose identifiers that would normally be considered builtin and available to the desktop environment, not any of its internal bits. To be honest, I had read so much hand-wringing and whining and moaning about this, I thought it was going to be difficult, turns out it is trivial and you simply don’t need any of that anonymous iife drivel (don’t ask). There are however a tiny number that would be useful, and thankfully JavaScript allows $ in identifier names, so any of $catch, $charArray, $conCat, $docBody, $ocument_createElement, $paranormalise, $prefer_backtick, $repe, $repss, $sidii, $seed, $storeAttr, $subse, $subss, $topZindex, or $typeCheckError [told you it was a fairly short list] are just things we don’t want to interfere with or be accidentally accessible from transpiled user-code-land.
whereas s14 is the JavaScript equivalent of the Phix sequence {1,2,3,4}, namely ["sequence",1,2,3,4].
/*Array*/ res =
Array.from(
myvar);
/*bool*/ res =
Array.isArray(
myvar);
array.forEach(
fn);
/*integer*/ res =
array.indexOf(
x);
/*integer*/ res =
array.length;
/*integer*/ len =
array.push(
item);
/*object*/ item =
array.pop(
);
/*Array*/ res =
array.slice(
start, end);
/*Array*/ res =
array.splice(
index [,deleteCount [,item...]]);
/*integer*/ res =
string.codePointAt(
idx);
/*string*/ res =
String.fromCodePoint(
arg1[, ...argN]);
/*integer*/ res =
string.length;
/*atom*/ res =
parseFloat(
/* string*/ s);
/*integer*/ res =
parseInt(
/* string*/ s[, radix]);
/*string*/ res =
string.slice(
start, end);
/*string*/ res =
string.toUpperCase();
/*elem*/ res =
document.createElement(
/*string*/ tag);
elem.addEventListener(
/*elem*/ child =
elem.appendChild(
/*elem*/ child);
/*NodeList*/ res =
elem.childNodes(
);
/*HTMLCollection*/ res =
elem.children;
/*DOMTokenList*/ res =
elem.classList;
elem.classList.add(
/*string*/ token);
/*bool*/ res =
elem.classList.contains(
/*string*/ token);
elem.classList.remove(
/*string*/ token);
/*bool*/ res =
elem.classList.toggle(
/*string*/ token, /*bool*/ bForce);
/*string*/ res =
elem.className;
/*string*/ res =
elem.clientHeight;
elem.clientWidth;
/*bool*/ res =
elem.disabled;
/*elem*/ res =
elem.firstElementChild;
/*string*/ res =
elem.getAttribute(
/*string*/ attributename);
/*object*/ res =
getComputedStyle(
elem);
/*NodeList*/ res =
elem.getElementsByClassName(
/*string*/ classname);
/*string*/ res =
elem.innerHTML;
/*string*/ res =
elem.innerText;
/*bool*/ res =
elem.isConnected;
/*elem*/ res =
elem.nextElementSibling;
/*string*/ res =
elem.offsetHeight;
elem.offsetLeft;
elem.offsetTop;
elem.offsetWidth;
/*elem*/ res =
elem.parentNode;
/*elem*/ res =
elem.querySelector(
/*string*/ query);
/*NodeList*/ res =
elem.querySelectorAll(
/*string*/ query);
elem.removeAttribute(
/*string*/ attributename);
elem.removeChild(
/*elem*/ node);
elem.setAttribute(
/*string*/ attributename, /*string*/ attributevalue);
/*CSSStyleDeclaration*/ res =
elem.style;
/*string*/ res =
elem.textContent;
/*string*/ res =
elem.title;
/*integer*/ res =
elem.width/height;
/*CanvasRenderingContext2D*/
ctx =
canvas.getContext("2d");
ctx.beginPath()
ctx.bezierCurveTo(
xc1, xc2, yc1, yc2, x2, y2);
ctx.closePath();
ctx.ellipse(
x, y, radiusX, radiusY,
rotation, startAngle, endAngle,
counterclockwise);
ctx.fill();
ctx.fillRect(
x, y, w, h);
ctx.font = "bold 12px sans-serif";
ctx.getImageData(
x, y, w, h);
ctx.lineTo(
x, y);
ctx.moveTo(
x, y);
ctx.stroke();
ctx.strokeRect(
x, y, w, h);
event.currentTarget;
event.preventDefault();
event.stopPropagation();
event.target;
setTimeout(
fn, delay[, params...]);
/*string*/ res =
typeof(obj);
this is avoided at all costs in p2js/xpGUI.js. Besides, rather than say dlg.show(), we use gShow(dlg).
Note the following might have been complete for pGUI.js, but for xpGUI.js it is very much a subset, only those I could be bothered to write something about. Should you figure out something useful to add (beyond "document $all"), let me know.
There may be some subtle implications of using these routines from an imperative mindset (as opposed to say a prototype or object orientated mindset) that may be clearer here than elsewhere, plus there may be for instance optional parameters and the like (of the javascript builtin functions listed below) that pwa/p2js does not use and/or specifically advises against. Lastly, by only documenting those fields and methods actually used, they should be a tad easier to locate, and hopefully impose significantly less cognitive overload.
Apart from an initial trawl, entries are likely to be added on an ad-hoc basis, as I realise it is now the Nth time I’ve had to go to MDN (the definititive fount of all knowledge) or w3schools (what it lacks in detail it makes up for in navigability). Things I use very rarely or are easily cribbed are unlikely to get a mention in here, for instance I’m not about to try and document JavaScript regular expressions.
Note that p2js.js in particular implements many of the standard Phix builtins, and others are auto-translated, so if you spot something rather familiar, perhaps you should treat it as such.
This covers both the use of JavaScript in p2js.js and pGUI.js, as well as providing some explanation for the sort of code that pwa/p2js.exw spits out. Several pages such as atom and length have JavaScript-links to this page in their "See Also"/p2js sections, rather than have that weird little popup when Phix.chm opens whereby despite their different cases both number and Number lookups (from eg xpEditer) would ask you to pick between atom and javascript, and then mess up the focus, often with the newly opened chm window hidden/relegated to the background. Obviously Phix gets preference over JavaScript in respect of which it opens first/by default.
Transpilation is largely a mechanical process of mapping between language syntax and compatible features, for example
"procedure p() end procedure" <==> "function p() { }" with no return statement.
Javascript is a typeless language, however to keep the output legible/reversible I have opted for eg "integer i" <==> "let /*integer*/ i;".
Phix sequences are actually a much closer match to JavaScript Arrays than Objects, so we use [] syntax rather than {}.
Phix sequences are 1-based, whereas Javascript Arrays are (loosely) 0-based, so we use eg `{1,2,3}` <==> `["sequence",1,2,3]`.
Obviously, p2js.js and pGUI.js should only expose identifiers that would normally be considered builtin and available to the desktop environment, not any of its internal bits. To be honest, I had read so much hand-wringing and whining and moaning about this, I thought it was going to be difficult, turns out it is trivial and you simply don’t need any of that anonymous iife drivel (don’t ask). There are however a tiny number that would be useful, and thankfully JavaScript allows $ in identifier names, so any of $catch, $charArray, $conCat, $docBody, $ocument_createElement, $paranormalise, $prefer_backtick, $repe, $repss, $sidii, $seed, $storeAttr, $subse, $subss, $topZindex, or $typeCheckError [told you it was a fairly short list] are just things we don’t want to interfere with or be accidentally accessible from transpiled user-code-land.
arrays
In the following, assume that a14 is the pure JavaScript Array [1,2,3,4],whereas s14 is the JavaScript equivalent of the Phix sequence {1,2,3,4}, namely ["sequence",1,2,3,4].
Self explanatory: create a real Array from something array-like, such as a NodeList. Note that Array.from(string)
produces lots of diddy-strings whereas $charArray (see below) produces the array of codePointAt I was expecting,
and eg both compare() and equal() use that internally, when one argument is a string and the other is an Array.
There is also a from pseudo-keyword on a for in statement, were you looking for that.
There is also a from pseudo-keyword on a for in statement, were you looking for that.
Self explanatory: returns false for numbers, strings, and JavaScript Objects.
Phix sequences are actually Arrays, however the standard sequence() [which uses this] is clearly better.
Obviously eg myvar.isArray(myvar) [arg rqd] only half-works/crashes on types with no isArray method/is pretty much useless, so always use the "Array" form.
Phix sequences are actually Arrays, however the standard sequence() [which uses this] is clearly better.
Obviously eg myvar.isArray(myvar) [arg rqd] only half-works/crashes on types with no isArray method/is pretty much useless, so always use the "Array" form.
Similar to papply(). fn should be of the form function(ai[,idx]), not returning anything,
possibly inlined/fat arrow - however giving it a sensible name makes the code much more self documenting, as in
"function addSizer(id,idx) {...} rd.forEach(addSizer);" clearly beats "rd.forEach((id, idx) => { ...} );" in my book.
Self explanatory. Note that s14.indexOf(1) is 1, whereas a14.indexOf(1) is 0, of course.
While s14 has that special marker of s14[0]==="sequence", there is nothing similar on strings, so the odd +1 is required. Also note that JavaScript does not have a character type, so indexOf() behaves more like match() on Strings, but more like find() on Arrays. array.lastIndexOf() should require no further explanation.
Returns -1 if not found.
While s14 has that special marker of s14[0]==="sequence", there is nothing similar on strings, so the odd +1 is required. Also note that JavaScript does not have a character type, so indexOf() behaves more like match() on Strings, but more like find() on Arrays. array.lastIndexOf() should require no further explanation.
Returns -1 if not found.
Not quite what you might expect. Technically it returns the largest numeric index plus 1, and p2js puts "sequence" in array[0]
before using 1-based indices to match Phix. Even if p2js omitted s[0] (and used 1-based indices) it would still be "out-by-one".
Note that s14.length is 5, whereas length(s14) is 4, a14.length is 4, and length(a14) should trigger an error.
In JavaScript it is permitted to set .length directly, and in fact just set empty_array[100] without hitch, which achieves much the same effect, ie/eg
In JavaScript it is permitted to set .length directly, and in fact just set empty_array[100] without hitch, which achieves much the same effect, ie/eg
a[100]:=x
automatically sets the length property to max(a.length,100+1),
as in that is what all browsers and other JavaScript implementations do, as opposed to something my or your code does.
See also string.length below.
Equivalent to array = append(array,item), and in fact used to implement that.
pGUI.js only ever pushes a single item, and does not use the returned new length.
pGUI.js only ever pushes a single item, and does not use the returned new length.
Inverse of array.push.
NB shallow copy, 0-based. a14.slice(2) is [3,4], and a14.slice(1,2) is [2].
Note that Phix deliberately does not have a slice builtin. See also string.slice below.
Note that Phix deliberately does not have a slice builtin. See also string.slice below.
a14.splice(1,1) sets a14 to [1,3,4].
r = a14.splice(1,1,'ache','bug') sets r to [2] and a14 to [1,'ache','bug',3,4].
r = a14.splice(1,1,'ache','bug') sets r to [2] and a14 to [1,'ache','bug',3,4].
strings
Obtain the unicode code point starting at idx. Note that idx is 0-based and UTF-16 surrogate-pair-based, MDN recommends using ...
(the spread operator) or for...of and codePointAt(0), rather than a traditional index. While p2js.js and xpGUI.js use this to
convert say a colour of "#80FF00" which should be fine, there may be some s[i] -> $subse() and the like which require manually
calling utf8_to_utf32() or similar to get some things to work (and there is certainly one such case already on rosettacode).
Self explanatory. Needed because JavaScript has no character type, and coerces eg "A" + 65 to "A65" rather than "AA".
String.fromCodePoint(65) is "A", String.fromCodePoint(65,66,67) is "ABC". Always use String.fromCodePoint() as opposed to s.fromCodePoint() (because it is a static method of String, whatever that really means).
String.fromCodePoint(65) is "A", String.fromCodePoint(65,66,67) is "ABC". Always use String.fromCodePoint() as opposed to s.fromCodePoint() (because it is a static method of String, whatever that really means).
Self explanatory. Note that unlike array.length, both string.length and length(string) yield
the same result.
Coerces s to a string, strips leading whitespace, and converts the first number to a floating point [or Nan].
Note that anything after the first number is simply ignored, and it also parses ["-"]"Infinity" as [-]Infinity.
/*atom*/ res = Number(v) is probably better, since it coerces the parameter to a number primitive, including BigInts (provided they fit), fails when there is trailing garbage, converts booleans to 0 or 1, and handles leading "0x", "0b", and "0o", which parseFloat does not.
Note that "new Number()" (which MDN warns you should rarely use) is one of those completely whacko OOP jobbies that does my head in, eg new Number(42) !== 42, ie new Number(42) === 42 yields false but the less strict new Number(42) == 42 yields true.
Note that anything after the first number is simply ignored, and it also parses ["-"]"Infinity" as [-]Infinity.
/*atom*/ res = Number(v) is probably better, since it coerces the parameter to a number primitive, including BigInts (provided they fit), fails when there is trailing garbage, converts booleans to 0 or 1, and handles leading "0x", "0b", and "0o", which parseFloat does not.
Note that "new Number()" (which MDN warns you should rarely use) is one of those completely whacko OOP jobbies that does my head in, eg new Number(42) !== 42, ie new Number(42) === 42 yields false but the less strict new Number(42) == 42 yields true.
Coerces s to a string, strips leading whitespace, and converts the first number to an integer [or Nan].
The radix defaults to 10 unless s begins [+/-]0x (or X) in which case it becomes 16. No other bases are supported, and neither is scientific notation: like parseFloat it ignores (what it thinks is) trailing garbage and "1e3"/"1.3"/"1_3"/"1,3" yield 1.
The radix defaults to 10 unless s begins [+/-]0x (or X) in which case it becomes 16. No other bases are supported, and neither is scientific notation: like parseFloat it ignores (what it thinks is) trailing garbage and "1e3"/"1.3"/"1_3"/"1,3" yield 1.
Extracts part of a string, eg "1234".slice(1,3) is "23".
Note that JavaScript indexes are 0-based, so what that is actually saying is
from s[1](==='2') up to but not including s[3](==='4').
In other words the start is as expected off-by-one, but the end works just
like Phix’s 1-based indexes would (inclusive).
So we have str[i..j] <==> s.slice(i-1,j); though do bear in mind some of the
direct uses in p2js.js may bear little resemblence to Phix <==> js transpilation.
If the second parameter is omitted, it yields all of the rest of the string,
same as supplying string.length (===length(string)).
Negative subscripts are also supported, for example if s="the lazy dog." then s.slice(-4) is "dog." and s.slice(-9, -5) is "lazy".
string.substring(start,end) is similar, but treats negative subscripts as 0 and swaps start>end.
Note that JavaScript indexes are 0-based, so what that is actually saying is
from s[1](==='2') up to but not including s[3](==='4').
In other words the start is as expected off-by-one, but the end works just
like Phix’s 1-based indexes would (inclusive).
So we have str[i..j] <==> s.slice(i-1,j); though do bear in mind some of the
direct uses in p2js.js may bear little resemblence to Phix <==> js transpilation.
If the second parameter is omitted, it yields all of the rest of the string,
same as supplying string.length (===length(string)).
Negative subscripts are also supported, for example if s="the lazy dog." then s.slice(-4) is "dog." and s.slice(-9, -5) is "lazy".
string.substring(start,end) is similar, but treats negative subscripts as 0 and swaps start>end.
Self explanatory, ditto toLowerCase().
elements
Self explanatory. tag may be "a", "button", "canvas", "div", "fieldset", "input", "label", "legend", "li", "nav", "option", "progress",
"script", "select", "table", "tbody", "td", "th", "thead", "tr", "textarea", "ul", etc.
The following values are not (currently) used by xpGUI.js: "b", "br", "i", "hr", "output", "p", etc.
xpGUI.js does not use (or understand) the options argument - ignore that if you don’t know what it means.
xpGUI.js contains a trivial $ocument_createElement() shim that, for some but not all uses, assigns a .ID which is used within printf() to mimic the integer id of xpGUI.e strictly for diagnostic purposes, but is otherwise completely unused.
createElementNS(namespace, tag) is similar but allows/requires a namespace to be specified, in xpGUI.js that would (always) be "http://www.w3.org/2000/svg", and at least in xpGUI.js only ever uses the tags "svg" and "path".
createTextNode(text) is similar but will html-escape the text.
The following values are not (currently) used by xpGUI.js: "b", "br", "i", "hr", "output", "p", etc.
xpGUI.js does not use (or understand) the options argument - ignore that if you don’t know what it means.
xpGUI.js contains a trivial $ocument_createElement() shim that, for some but not all uses, assigns a .ID which is used within printf() to mimic the integer id of xpGUI.e strictly for diagnostic purposes, but is otherwise completely unused.
createElementNS(namespace, tag) is similar but allows/requires a namespace to be specified, in xpGUI.js that would (always) be "http://www.w3.org/2000/svg", and at least in xpGUI.js only ever uses the tags "svg" and "path".
createTextNode(text) is similar but will html-escape the text.
Reasonably self explanatory.
event_type can be 'click', 'contextmenu', 'dblclick', 'DOMContentLoaded', 'keydown', 'keypress', 'keyup', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseup', 'resize', etc.
fn: a listener function which optionally accepts a single event parameter (sometimes inlined/fat arrow).
use_capture: true (parent before child) or false (child before parent, aka bubbling) [I think]
Assigning .onclick, .oncontextmenu, .ondblclick, .ondragstart, .onkeydown, .onkeyup, .onmousedown, .onmousemove, .onmouseup, .onresize, .onselectstart, etc is equivalent (sans use_capture setting).
event_type can be 'click', 'contextmenu', 'dblclick', 'DOMContentLoaded', 'keydown', 'keypress', 'keyup', 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseup', 'resize', etc.
fn: a listener function which optionally accepts a single event parameter (sometimes inlined/fat arrow).
use_capture: true (parent before child) or false (child before parent, aka bubbling) [I think]
Assigning .onclick, .oncontextmenu, .ondblclick, .ondragstart, .onkeydown, .onkeyup, .onmousedown, .onmousemove, .onmouseup, .onresize, .onselectstart, etc is equivalent (sans use_capture setting).
Self explanatory
Probably better to use children instead, since this contains elements, text(/whitespace), and comments.
That said, xpGUI.js should not be creating text and comment nodes in the DOM it is explicitly creating.
/*bool*/ res = elem.hasChildNodes(); would return true should there be any/only such guff.
That said, xpGUI.js should not be creating text and comment nodes in the DOM it is explicitly creating.
/*bool*/ res = elem.hasChildNodes(); would return true should there be any/only such guff.
Actual elements-only, otherwise self explanatory. elem.childElementCount; returns the (ditto) length.
A DOMTokenList is an Array-like collection of the class attributes of the element.
Self explanatory
Self explanatory
Self explanatory (quietly does nothing if token is not present)
Self explanatory, the (space-separated) plain text version of classList.
(read-only) eg "100px". padding+content (w/o border/margin).
Self explanatory, can also be set. Implements ACTIVE, but may not perfectly match desktop/Phix.
Self explanatory. elem.firstChild is similar, but does not skip text and comment nodes.
Likewise elem.lastElementChild and elem.lastChild
Likewise elem.lastElementChild and elem.lastChild
Self explanatory, as in say an elem of
<div data="thing">
, elem.getAttribute('data')
yields "thing", or null (some older browsers may return "") if no such attribute exists.
Erm, might be best to avoid using this if at all possible...
Similar to querySelectorAll, likewise a classname of "this that" would obtain the same results as querySelectorAll(".this, .that").
Can be set or retrieved, otherwise pretty self explanatory, unlike innerText it is parsed when set.
It also retrieves everything, whereas innerText omits any hidden parts.
It also retrieves everything, whereas innerText omits any hidden parts.
Can be set or retrieved, otherwise pretty self explanatory, pGUI.js should only use this on plain (and visible) text rather than nested nodes.
Unlike elem.textContent, this returns something close to what the user sees, no styles(/aka applied), nothing hidden, line breaks honoured.
Unlike elem.textContent, this returns something close to what the user sees, no styles(/aka applied), nothing hidden, line breaks honoured.
Pretty self explanatory, true if part of the document, false if not yet added.
Self explanatory. elem.nextSibling is similar, but does not skip text and comment nodes.
Likewise elem.previousElementSibling and elem.previousSibling.
Likewise elem.previousElementSibling and elem.previousSibling.
(read-only) eg "100px". border+padding+content (w/o margin).
Self explanatory.
returns the first child element that matches the CSS selector.
query is a CSS selector such as
'.selected' (the first sub-element of that class), or 'ul' (the first <ul> sub-element).
'.selected' (the first sub-element of that class), or 'ul' (the first <ul> sub-element).
query is a CSS selector such as
'.nestmenu, .menuitem' (all sub-element children that are of either class),
'.topmenu > span' (all span sub-elements with a parent of topmenu class),
'td' (all <td> sub-elements).
The result can often be treated as an Array, but sometimes needs res = Array.from(res);
'.nestmenu, .menuitem' (all sub-element children that are of either class),
'.topmenu > span' (all span sub-elements with a parent of topmenu class),
'td' (all <td> sub-elements).
The result can often be treated as an Array, but sometimes needs res = Array.from(res);
Self explanatory (quietly does nothing if attributename is not present)
Self explanatory (quietly does nothing if node is not present)
Self explanatory, can be used for custom attributes such as ('data-sorted', 'A'/'D') or even ('class','fill'). Another
useful one is ('tabindex','0') which means "can recieve focus, in document order".
Too many to fully list, but the fields pGUI.js uses, with examples, are:
elem.style.alignItems = "flex-start"; /* or "center"/"stretch"/"flex-end" */
elem.style.alignSelf = "flex-start"; /* or "center"/"stretch"/"flex-end" */
elem.style.background = "transparent";
elem.style.backgroundColor = "#808080";
elem.style.color = "#FF0080";
elem.style.cursor = "nw-resize"; /* nw can also ne jn/ne/e/nw */
elem.style.display = "flex"; /* or"block"/"none" */
elem.style.flexBasis = "200px"; /* ?? */
elem.style.flexDirection = "row"; /* or "column" */
elem.style.flexGrow = 1; /* ?? */
elem.style.fontFamily = "Arial";
elem.style.fontSize = "10px"; /* or "10pt" */
elem.style.fontStyle = "italic";
elem.style.fontWeight = "bold";
elem.style.justifyContent = "flex-start"; /* or "center"/"space-between"/"space-evenly"/"flex-end" */
elem.style.margin = "1px"; /* or ..."1px 2px 3px 4px", see here */
elem.style.marginBottom = "1px";
elem.style.marginLeft = "1px";
elem.style.marginRight = "1px";
elem.style.marginTop = "1px";
elem.style.opacity = 0.5; /* 0 is transparent, 1 fully opaque */
elem.style.paddingBottom = "1px";
elem.style.paddingLeft = "1px";
elem.style.paddingRight = "1px";
elem.style.paddingTop = "1px";
elem.style.position = "absolute"; /* or "relative"/"fixed" */
elem.style.textAlign = "left"; /* or "center"/"right" */
elem.style.textBaseline = "top"; /* or "middle"/"bottom" */
elem.style.textDecoration = "underline"; /* or "line-through" */
elem.style.transform = "rotate(90deg)";
elem.style.height = "80px"; /* only has effect on block-level or absolute/fixed position elements */
elem.style.width = "240px"; /* ditto */
elem.style.left = "100px";
elem.style.top = "100px";
also [?]: bottom, right, maxWidth, and zIndex.
elem.style.alignItems = "flex-start"; /* or "center"/"stretch"/"flex-end" */
elem.style.alignSelf = "flex-start"; /* or "center"/"stretch"/"flex-end" */
elem.style.background = "transparent";
elem.style.backgroundColor = "#808080";
elem.style.color = "#FF0080";
elem.style.cursor = "nw-resize"; /* nw can also ne jn/ne/e/nw */
elem.style.display = "flex"; /* or"block"/"none" */
elem.style.flexBasis = "200px"; /* ?? */
elem.style.flexDirection = "row"; /* or "column" */
elem.style.flexGrow = 1; /* ?? */
elem.style.fontFamily = "Arial";
elem.style.fontSize = "10px"; /* or "10pt" */
elem.style.fontStyle = "italic";
elem.style.fontWeight = "bold";
elem.style.justifyContent = "flex-start"; /* or "center"/"space-between"/"space-evenly"/"flex-end" */
elem.style.margin = "1px"; /* or ..."1px 2px 3px 4px", see here */
elem.style.marginBottom = "1px";
elem.style.marginLeft = "1px";
elem.style.marginRight = "1px";
elem.style.marginTop = "1px";
elem.style.opacity = 0.5; /* 0 is transparent, 1 fully opaque */
elem.style.paddingBottom = "1px";
elem.style.paddingLeft = "1px";
elem.style.paddingRight = "1px";
elem.style.paddingTop = "1px";
elem.style.position = "absolute"; /* or "relative"/"fixed" */
elem.style.textAlign = "left"; /* or "center"/"right" */
elem.style.textBaseline = "top"; /* or "middle"/"bottom" */
elem.style.textDecoration = "underline"; /* or "line-through" */
elem.style.transform = "rotate(90deg)";
elem.style.height = "80px"; /* only has effect on block-level or absolute/fixed position elements */
elem.style.width = "240px"; /* ditto */
elem.style.left = "100px";
elem.style.top = "100px";
also [?]: bottom, right, maxWidth, and zIndex.
Can be set or retrieved, otherwise pretty self explanatory.
Unlike elem.innerText, this returns a sort of html-stripped innerHTML, with hidden text, scraps of styles, and line breaks ignored.
Unlike elem.innerText, this returns a sort of html-stripped innerHTML, with hidden text, scraps of styles, and line breaks ignored.
(also settable) The "title" in this case means/is shown as a tooltip, and implements TIP.
Erm... width/height of embedded objects... xpGUI.js should probably not be using these...
canvas
Get a drawing context, on which all drawing operations occur.
When OpenGL is being used, "webgl" instead of "2d" yields a similar /*WebGLRenderingContext*/.
When OpenGL is being used, "webgl" instead of "2d" yields a similar /*WebGLRenderingContext*/.
Start a new path by emptying the list of sub-paths.
Extend the path with a bezier curve.
The current position is used as x1,y1.
Use stroke() or fill() to draw the path.
The current position is used as x1,y1.
Use stroke() or fill() to draw the path.
Extend the path with a line from the current position to the start.
Use stroke() or fill() to draw the path.
x,y: ellipse centre
radiusX: major axis radius
radiusY: minor axis radius
rotation: in radians
startAngle: "", clockwise from x axis
endAngle: ditto. 0..2*PI is full.
counterclockwise: self explanatory
radiusX: major axis radius
radiusY: minor axis radius
rotation: in radians
startAngle: "", clockwise from x axis
endAngle: ditto. 0..2*PI is full.
counterclockwise: self explanatory
Draw the path and fill it.
Draw and fill a recangle. (does not change the current path)
Note this is quite different from the way most other elements use the style to set the font.
Obtain an ImageData object representing the underlying pixel data for a specified portion of the canvas.
Extend the path with a line from the current position to x,y.
Use stroke() or fill() to draw the path.
Move the current position to x,y.
Draw the path, without filling it.
Draw a recangle, without filling it. (does not change the current path)
events
The element to which the listener was attached, rather than the element actually clicked. See also event.target.
This is often the better choice, for instance if you want the containing li clicked on, rather than a specifc scrap of bold or italic text within that li.
This is often the better choice, for instance if you want the containing li clicked on, rather than a specifc scrap of bold or italic text within that li.
Self explanatory
Self explanatory
The element that was clicked. See also event.currentTarget.
event.srcElement was the name used for this in IE6-8 and should be replaced without hesitation (ie changed to event.target).
event.srcElement was the name used for this in IE6-8 and should be replaced without hesitation (ie changed to event.target).
Invoke fn with params after delay milliseconds.
Technically a prefix operator, it is used as a function in p2js/pGUI.js. Valid results are "string",
"number", "undefined", "boolean", "function", and "object". Note the latter is returned for arrays,
see isArray.
operators
Operator | Meaning |
---|---|
! | Logical not, equivalent to "not" in Phix. |
+ |
In JavaScript, the plus operator not only performs mathematical addition, but also string concatenation. The binary operator casts both operands to strings unless both operands are numbers. In contrast, the - operator always casts both operands to numbers, as do both the unary forms of + and -. Use with caution (that is, in p2js.js and pGUI.js). |
++ |
Avoid (ditto --), in particular because of the "blind spot" that is the difference between ++i and i++, ie when asked like that,
easily stated, but when (casually) reading code, those sort of errors can be almost impossible to spot. For instance, the result
of i = i++; is formally both
unspecified and
undefined behaviour - while a specific compiler(/browser) may (or may not) produce
predictable results, it won’t be hard to find a different compiler/browser that gives different results.
|
& | Bitwise and operation, similar to and_bits(). In Phix & performs concatenation. |
&& | Logical and operation, similar to and_bits(). In Phix && is bitwise. |
=== |
In JavaScript, the = operator is always assignment, so eg if (a=b) {} is almost always just plain wrong, and always bad style. Always use === in preference to == since the latter performs type coercion, eg "0"==0 is true, whereas "0"===0 is false. |
... | The spread operator. Used for eg fn(...args) much like call_func(fn,args). It might have been good for cloning arrays, but it only performs a shallow copy, see notes above. |
Note the following might have been complete for pGUI.js, but for xpGUI.js it is very much a subset, only those I could be bothered to write something about. Should you figure out something useful to add (beyond "document $all"), let me know.
Globals | Meaning |
---|---|
$catch() | In Javascript a catch(e) can receive a string, number, boolean, or object, this just quietly maps such to a more desktop/Phix compatible sequence, so that a subsequent e[E_USER] (for example) does not crash. Obviously you won’t get much in the way of source file and line number out of the browser, at best it will correspond to the transpiler output rather than its input, which if nothing else should teach you to debug things properly on the desktop first. |
$charArray() |
Needed because Array.from(string) produces lots of diddy-strings, whereas this produces the array of codePointAt I was expecting. Should only ever be passed a string argument, and crashes when that is not the case. Note that res[0] is "sequence". Only used in p2js.js, should not be emitted in generated code. |
$conCat() |
Replacement for the & operator of Phix, which internally uses += for strings and array.concat(slice) for sequences. Will be emitted in generated code. Note that since JavaScript does not have reference counts, you have / p2js_emit has to explicitly distinguish s = $conCat(s,x,false) [ie do not clone] from s = $conCat(t,x[,true])
[ie must clone t and that way leave the original undamaged]. Also note that, due to ref counts, desktop/Phix knows when,
in something like s = [tmp57:=]<expr> & x aka s = $conCat([tmp57:=]<expr>,x) it
can safely (re)use the hidden/unnamed tmp57, whereas JavaScript (and for the most part p2js) cannot, hence should
you rework code to have more <var> = $conCat(<var>,.. then there will be fewer
(hidden/unnamed temps and as a direct consequence) unnecessary clones, and therefore more speed.
Of course more <var> &= .. is/achieves the very same thing.
|
$docBody |
Set to document.body for normal/stand-alone use, but the output panel when running in the online repl. Only used in p2js.js (for puts) and pGUI.js, should not be emitted in generated code. |
$ocument_createElement | A trivial wrapper to createElement which sets a dummy (integer) id to mimic desktop/Phix, in case we try to print it. |
|
A hand-translated version of the (private) paranormalise() routine from pGUI.e. There are now also five others, ~_traa(), ~_qraa(), ~_raa(), ~_taa(), and ~_paab() in xpGUI.js. Only used in [x]pGUI.js, should not be emitted in generated code. |
$repe(s,idx,x,idii) |
Replacement for subscript assignment, uses String.fromCodePoint(x) and zero-based indexes for string(s), 1-based slices for sequences. The first three parameters, s, idx, and x should be self-explanatory (s[idx] := x). The optional fourth parameter, idii, is a sequence of nested subscripts, eg/ie s[g][h][i] = x maps to $repe(s,i,x,["sequence",h,g])
(a "backwards" idii proved a tiny smidgen easier but that’s not set in stone).Will be emitted in generated code. Note this takes advantage of JavaScript’s pass-by-sharing semantics. |
$repss(s,ss,se,x,idii) |
Replacement for slice assignment, uses String.slice(ss-1,se) (as in JavaScript they are 0-based), but
Array.slice(ss,se+1) for dword-sequences (since we put a "sequence" in at s[0]). The first four parameters, s, ss, se, and x, should be self-explanatory (s[ss..se] = x). The optional fifth parameter, idii, is a sequence of nested subscripts, eg/ie s[i][j][k][ss..se] maps to $repss(s,ss,se,x,["sequence",k,j,i]) (ditto "backwards" idii). Will be emitted in generated code. Note this takes advantage of JavaScript’s pass-by-sharing semantics. |
$sidii(s,idii) |
Common code for $repe(), $repss(), $subse(), and $subss(). Also handles negative subscripts, as do those four. Only used in p2js.js, should not be emitted in generated code. |
$storeAttr[] |
element-specific attribute handlers/setters, eg $storeAttr["dialog"]["TITLE"] is set_dialog, a (private) routine
(defined in pGUI.js) for setting the dialog title (and other things). Only used in pGUI.js, should not be emitted in generated code. |
$subse(s,idx) |
Replacement for subscripting, uses s.codePointAt(idx-1) for strings, s[idx] for sequences. Will be emitted in generated code. Note that s[i][j][k] produces nested calls to this routine. |
$subss(s,ss,se) |
Replacement for slicing, uses String.slice(ss-1,se) for strings (as in JavaScript they are 0-based), but
Array.slice(ss,se+1) for dword-sequences (since we’ve put a "sequence" in at s[0]). Will be emitted in generated code. Note that s[i][j][k][ss..se] just uses nested $subse calls. |
|
Common code for integer()/atom()/string()/sequence()/object(). If the optional second parameter is passed it should be
a string holding the variable name and triggers a fatal runtime error, if omitted then false can be returned.
In p2js.js the standard five types just named also accept an optional second (name) parameter.
Generally the fatal option is only used (by hand) on a few selected builtins, at the very top of the routine,
and the usual desktop practice of checking after assignment is omitted. Will not be emitted in generated code, except indirectly as above (and thus far without a name). |