Skip to content

Commit 78ef1c9

Browse files
formalSpec hero parser and method arguments display
1 parent 3bd2eb2 commit 78ef1c9

File tree

9 files changed

+209
-2
lines changed

9 files changed

+209
-2
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "cache-visual-editor",
33
"printableName": "Cache Visual Editor",
44
"packageName": "VisualEditor",
5-
"version": "0.8.1",
5+
"version": "0.8.3",
66
"description": "Visual class editor for InterSystems Caché",
77
"main": "index.js",
88
"keywords": [

source/client/js/classEditor/class/code.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { addChange } from "../changes";
33
import { Toast } from "../../toast";
44
import { updateGrid } from "../index";
55
import { getKeywordView } from "./keyword";
6+
import { getFormalSpecEditor } from "./formalSpecEditor";
67

78
/**
89
* Returns if the method code has routines.
@@ -44,6 +45,10 @@ export function getCodeCaptionView ({ manifest, name, data, savePath }) {
4445
vb.appendChild(useRoutinesToggle);
4546
useRoutinesBlock.appendChild(nb);
4647
useRoutinesBlock.appendChild(vb);
48+
header.appendChild(getFormalSpecEditor({
49+
formalSpec: data[`FormalSpec`],
50+
savePath: savePath.concat(`FormalSpec`)
51+
}));
4752
if (returnTypeProp)
4853
header.appendChild(getKeywordView({
4954
propManifest: manifest[returnTypeProp],
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { getTypePickerView } from "./typePicker";
2+
import { block, autoSizeInput } from "../../domUtils";
3+
4+
/**
5+
* Replaces the strings with spaces
6+
* @param string
7+
* @returns {string}
8+
*/
9+
function padSpace (string) {
10+
return string.replace(
11+
/"([^"]*)"/g,
12+
(a, part) => `"${ part.replace(/[\s\S]/g, " ")}"`
13+
);
14+
}
15+
16+
/**
17+
* A hero function that handles formalSpec string like 'test2:%String(VALUELIST="1,2,3",MAXLEN=1)={"test"+"best"+{"a":1}},noType,typeOnly:Cinema.TicketOrder={##class(TestPack.MyType).%New("AHA!, AHAHA, AA!",1)},defaultOnly="lol"'
18+
* @param {string} formalSpec =
19+
* @returns {string[]}
20+
*/
21+
function splitArguments (formalSpec = "") {
22+
23+
let braceStack = [{ el: "" }],
24+
padStr = padSpace(formalSpec), // replace strings with spaces, so "test" turns to " ".
25+
braceArr = padStr.split("");
26+
27+
braceArr.forEach((el, pos, arr) => {
28+
if (["{", "}", "(", ")"].indexOf(el) === -1)
29+
return el;
30+
if (
31+
(el === "}" && braceStack[braceStack.length - 1].el === "{")
32+
|| (el === ")" && braceStack[braceStack.length - 1].el === "(")
33+
) {
34+
for (let i = braceStack.pop().pos + 1; i < pos; i++) {
35+
arr[i] = " ";
36+
}
37+
} else {
38+
braceStack.push({ el: el, pos: pos });
39+
}
40+
return el;
41+
});
42+
43+
let braceStr = braceArr.join(""), // at this point we have replaced all non-control commas
44+
args = [];
45+
46+
braceStr.replace(/[^,]+/g, (part, pos) => {
47+
args.push({
48+
str: formalSpec.substr(pos, part.length),
49+
pad: padStr.substr(pos, part.length)
50+
});
51+
});
52+
53+
args.forEach(({ str, pad }, pos, arr) => {
54+
let parArr = [],
55+
def = "",
56+
hasTypeParams = false;
57+
pad.replace(/^[\w]+:[^\(=]+\(([^\)]*)\)/, (part, params, pos) => {
58+
hasTypeParams = true;
59+
let originParams = str.substr(pos + part.length - params.length - 1, params.length),
60+
padOrigin = padSpace(originParams);
61+
padOrigin.replace(/[^,]+/g, (part, pos) => {
62+
let par = originParams.substr(pos, part.length),
63+
name = (par.match(/^([^=]+)=/) || {})[1] || "";
64+
parArr.push({
65+
name: name,
66+
value: par.substr(name.length + 1)
67+
});
68+
});
69+
});
70+
pad.replace(
71+
hasTypeParams ? /\)=([\s\S]+)$/ : /=([\s\S]+)$/,
72+
(part, d, pos) => def = str.substr(pos + 1 + (hasTypeParams ? 1 : 0), d.length)
73+
);
74+
arr[pos] = {
75+
name: str.match(/^[^\.:=]+/)[0],
76+
type: (str.match(/:([^\(=]+)/) || {})[1] || "",
77+
parameters: parArr,
78+
default: def
79+
};
80+
});
81+
82+
return args;
83+
}
84+
85+
function show (element) {
86+
element.style.display = "";
87+
}
88+
89+
function hide (element) {
90+
element.style.display = "none";
91+
}
92+
93+
export function getFormalSpecEditor ({ formalSpec = "", savePath }) {
94+
95+
let container = block(`div`, `formalSpecEdit`),
96+
args = splitArguments(formalSpec);
97+
98+
args.forEach((arg, i) => {
99+
100+
let span = block(`span`, `argument`),
101+
name = autoSizeInput({ placeholder: `Name`, value: arg.name, className: `nameInput` }),
102+
asSpan = block(`span`, `typeSpan`),
103+
defaultSpan = block(`span`);
104+
105+
if (i > 0)
106+
span.appendChild(block(`span`, ``, `, `));
107+
108+
span.appendChild(name);
109+
asSpan.appendChild(block(`span`, ``, ` As `));
110+
let typeInput = autoSizeInput({ placeholder: `Type`, value: arg.type || "" });
111+
if (!arg.type) {
112+
hide(asSpan);
113+
}
114+
asSpan.appendChild(typeInput);
115+
span.appendChild(asSpan);
116+
span.appendChild(defaultSpan);
117+
118+
container.appendChild(span);
119+
});
120+
121+
return container;
122+
123+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { block, autoSizeInput } from "../../domUtils";
2+
3+
/**
4+
* @param {boolean} inline
5+
*/
6+
export function getTypePickerView ({ inline }) {
7+
8+
let input = inline ? autoSizeInput({ placeholder: "Type" }) : block(`input`);
9+
10+
if (!inline)
11+
input.setAttribute(`type`, `text`);
12+
13+
return input;
14+
15+
}

source/client/js/domUtils.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,49 @@ export function block (element = "div", className, textContent) {
1212
return el;
1313
}
1414

15+
/**
16+
* @param {string} type
17+
* @param {string} minWidth - CSS minWidth
18+
* @param {string} maxWidth - CSS maxWidth
19+
* @param {string} placeholder - placeholder of input.
20+
* @param {string} value
21+
* @param {string} className
22+
* @returns {Element}
23+
*/
24+
export function autoSizeInput ({
25+
type = "text", minWidth = "30px", maxWidth = "100%", placeholder, value, className
26+
}) {
27+
28+
let input = block(`input`, `auto${ className ? " " + className : "" }`);
29+
30+
function updateInput () {
31+
let style = window.getComputedStyle(input),
32+
ghost = document.createElement(`span`);
33+
ghost.style.cssText = `box-sizing:content-box;display:inline-block;height:0;`
34+
+ `overflow:hidden;position:absolute;top:0;visibility:hidden;white-space:nowrap;`
35+
+ `font-family:${ style.fontFamily };font-size:${ style.fontSize };`
36+
+ `padding:${ style.padding }`;
37+
ghost.textContent = input.value;
38+
document.body.appendChild(ghost);
39+
input.style.width = ghost.offsetWidth + 4 + "px";
40+
document.body.removeChild(ghost);
41+
}
42+
43+
input.setAttribute(`type`, type);
44+
input.style.minWidth = minWidth;
45+
input.style.maxWidth = maxWidth;
46+
input.setAttribute(`placeholder`, placeholder);
47+
input.style.width = minWidth;
48+
if (value) {
49+
input.value = value;
50+
setTimeout(() => updateInput(), 1);
51+
}
52+
input.addEventListener(`input`, () => updateInput());
53+
54+
return input;
55+
56+
}
57+
1558
/**
1659
* Safely detach element from the DOM.
1760
* @param {HTMLElement} element

source/client/scss/basic.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ select {
6565

6666
}
6767

68+
input.auto {
69+
text-align: center;
70+
71+
}
72+
6873
button {
6974
padding: 0;
7075
background: #eee;
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.formalSpecEdit {
2+
3+
.argument {
4+
5+
.nameInput {
6+
7+
}
8+
9+
.typeSpan {
10+
display: inline-block;
11+
}
12+
13+
}
14+
15+
}

source/client/scss/index.scss

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
@import "domUtils";
77
@import "basic";
88
@import "autoGrid/cards";
9-
@import "classBuilder/card";
9+
@import "classEditor/formalSpecEdit";
10+
@import "classEditor/card";
1011
@import "icons";
1112
@import "toast/toast";

0 commit comments

Comments
 (0)