Skip to content

Commit e0ca6fb

Browse files
committed
Merge branch 'gh-pages' of https://github.com/LivelyKernel/lively4-core into gh-pages
2 parents 1677382 + 7b61a85 commit e0ca6fb

File tree

15 files changed

+550
-12
lines changed

15 files changed

+550
-12
lines changed

demos/markdown/mle-workspaces.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Workspace Example
2+
3+
This is an Example of a workspace embedded in HTML/Markdown that will persist it's code in browser local storage.
4+
<lively-script><script>import focalStorage from 'src/external/focalStorage.js'; import {SocketSingleton} from 'src/components/mle/socket.js'; const idMap = new Map(); const enclosingDiv = <div />; var mle = {}; async function startUp(){ await SocketSingleton.get(); let i = 0; while(await focalStorage.getItem(`markdown_workspace_${i}`)){ await new Pane(i, await focalStorage.getItem(`markdown_workspace_${i}_kind`)).create(); i++; } } class Pane { constructor(id, kind){ if(id !== undefined){ this._id = id; this.kind = kind; } else { this._id = idMap.size; } idMap.set(this.textStorageId, this); } onDoIt() { this.saveText() this.workspace.tryBoundEval(this.workspace.value) } async onReset() { if(this.kind) this.socket = await SocketSingleton.reset(); this.logarea.value = "LOGS"; this.drawarea.innerHTML = ""; } get defaultText() { return "sql`SELECT * FROM students`" } get textStorageId() { return `markdown_workspace_${this._id}` } async loadText() { var loaded = await focalStorage.getItem(this.textStorageId); if (loaded) return loaded; return this.defaultText; } async saveText() { focalStorage.setItem(this.textStorageId, this.workspace.value); focalStorage.setItem(`${this.textStorageId}_kind`, this.kind); } log(s) { this.logarea.value += s + ""; } async create() { // #TODO #META style and pre tags are problematic in Markdown scripts this.kind = this.kind === undefined ? await lively.confirm("MLE Workspace? Ok for yes, Cancel for No.") : this.kind; var style = document.createElement("style"); style.textContent = ` lively-code-mirror { border: 1px solid gray; flex: 4; }`; var buttons = <div> <button click={() => {this.onDoIt()} }>DoIt</button> <button click={() => {this.onReset()} }>reset</button> </div>; this.workspace = await (<lively-code-mirror></lively-code-mirror>); this.workspace.value = await this.loadText(); this.workspace.doitContext = this; this.logarea = <textarea disabled style="flex: 2;"/>; this.logarea.value = "LOGS"; this.drawarea = <div></div>; if(this.kind){ this.workspace.boundEval = async function(s) { this.socket = this.socket || await SocketSingleton.get(); this.socket.emit("test", {id: this.textStorageId, func: "evaluate", parameters: [s]}); const value = await new Promise((res) => { this.socket.on("result", r => { if(!r) return; if(r.id !== this.textStorageId) return; console.log(r.data) res(JSON.parse(r.data)); }); }); this.outData = value; Object.defineProperty(window, `$${this._id}`, {configurable: true, value}); this.log(JSON.stringify(value)); this.saveText(); return {value}; } this.workspace.boundEval = this.workspace.boundEval.bind(this); } enclosingDiv.appendChild( <div style="padding: 10px; width:90%;"> {style} <h4>{this.kind ? "MLE" : "DOM"} Workspace ${this._id}</h4> {buttons} <div style="display: flex;"> {this.workspace} {this.logarea} </div> {this.drawarea} </div> ); } } startUp().then(t => <div> <button click={() => new Pane().create()}>New workspace</button> {enclosingDiv} </div>)</script> </lively-script>
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
<!-- markdown-config presentation=true -->
2+
3+
<link rel="stylesheet" type="text/css" href="../../../src/client/presentation.css" />
4+
<link rel="stylesheet" type="text/css" href="../../../src/client/lively.css" />
5+
<link rel="stylesheet" type="text/css" href="../../../templates/livelystyle.css" />
6+
7+
<style>
8+
9+
.centered {
10+
display: block;
11+
margin-left: auto;
12+
margin-right: auto;
13+
}
14+
15+
.left {
16+
position: absolute;
17+
width: 40%;
18+
left: 20px;
19+
top: 150px;
20+
}
21+
22+
.right {
23+
position: absolute;
24+
width: 50%;
25+
right: 10px;
26+
top: 100px;
27+
}
28+
29+
30+
.bottomLeft {
31+
width: 50%;
32+
position: absolute;
33+
bottom: 40px;
34+
left: 20px;
35+
}
36+
37+
.bottomRight {
38+
width: 50%;
39+
position: absolute;
40+
bottom: 40px;
41+
right: 20px;
42+
}
43+
44+
h2 {
45+
text-align: left;
46+
}
47+
48+
a:visited.plain, a:link.plain {
49+
color: inherit;
50+
text-decoration: none;
51+
}
52+
53+
h2.sub {
54+
margin-top: -20px;
55+
}
56+
57+
58+
59+
60+
61+
62+
63+
</style>
64+
65+
66+
![](knuth_1972_page1.png){style="position:absolute; top:40px; left:40px; width:400px; border: 1px solid lightgray"}
67+
68+
---
69+
70+
![](knuth_1972_page1.png){style="position:absolute; top:40px; left:40px; width:400px; border: 1px solid lightgray"}
71+
72+
![](knuth_1972_cistern.png){style="position:absolute; top:50px; left:450px; width:500px; border: 1px solid lightgray"}
73+
74+
75+
76+
---
77+
78+
![](knuth_1972_page1.png){style="position:absolute; top:40px; left:40px; width:400px; border: 1px solid lightgray"}
79+
80+
![](knuth_1972_cistern.png){style="position:absolute; top:50px; left:450px; width:500px; border: 1px solid lightgray"}
81+
82+
![](babylonian_smalltalk_motivation.png){style="position:absolute; top:290px; left:130px; width:800px; border: 1px solid lightgray"}
83+
84+
85+
---
86+
87+
![](babylonian_lion.png){style="width: 200px; position: absolute; right: 20px; bottom: 20px;"}
88+
89+
<div class="title">
90+
<a class="plain" href="https://arxiv.org/pdf/1902.00549">
91+
Babylonian-style Programming
92+
</a>
93+
</div>
94+
<div class="subtitle">
95+
Design and Implementation of a General-purpose Editor<br>Supporting the Integration of Live Examples into Source Code
96+
</div>
97+
98+
<div class="authors">
99+
David Rauch, Patrick Rein, Stefan Ramson, Jens Lincke, and Robert Hirschfeld
100+
</div>
101+
102+
103+
<div class="credentials">
104+
<br>
105+
<a class="plain" href="https://www.hpi.uni-potsdam.de/hirschfeld/">Software Architecture Group<br>
106+
Hasso Plattner Institute, University of Potsdam, Germany</a>
107+
<br>
108+
<br>
109+
<a class="plain" href="https://2019.programming-conference.org/"><b>‹Programming› 2019<br> Mon 1 - Thu 4 April 2019 Genoa, Italy</b></a>
110+
</div>
111+
112+
113+
114+
---
115+
## Existing Example-based Systems
116+
117+
![](example_based_systems.png){.centered}
118+
119+
---
120+
# Design
121+
## Probes {.sub}
122+
123+
- Probe source code for values
124+
- Attach to syntax elements
125+
- See values for examples
126+
- See changes during statement
127+
- Chronological order
128+
- Object inspector supported
129+
130+
![](design_probes.png){.right style="width:58%"}
131+
132+
---
133+
# Design
134+
## State over Time {.sub}
135+
136+
- Sliders
137+
- Attach to flow control structures
138+
- Scroll through iterations
139+
- Probes filter values
140+
- Easier correlation of values
141+
142+
![](design_state_over_time.png){.right style="width:40%"}
143+
144+
145+
---
146+
# Design
147+
## Objects and Data Structures {.sub}
148+
149+
- Supported by probes
150+
- Usable in examples
151+
- (Custom) instance templates
152+
- Links
153+
154+
![](design_objects_and_data_structures_1.png){.bottomLeft}
155+
![](design_objects_and_data_structures_2.png){.right}
156+
157+
<!-- #TODO source: @rhi, Fibonacci -> similar.... -->
158+
159+
---
160+
# Design
161+
## Behavioral Highlighting {.sub}
162+
163+
- Examples indicate intent
164+
- Fade out code that was not reached
165+
- Quickly find relevant code
166+
- Examine conditions without probes
167+
168+
169+
![](design_behavioural_highlighting.png){.right}
170+
171+
<!-- Behavioral highlighting for a conditional -->
172+
173+
---
174+
# Design
175+
## Persistent Examples {.sub}
176+
177+
- Serialized to JSON
178+
- Saved as comments
179+
- Before and after syntax elements
180+
- On load: parse and hide
181+
182+
![](design_persistent_examples.png){.right}
183+
184+
---
185+
# Design
186+
## Additional Features {.sub}
187+
188+
- Replacements
189+
- Replace source code
190+
- Only for example evaluation
191+
- Pre- and postscript
192+
- Run before and after example
193+
- Similar to setup and teardown
194+
195+
![](design_additional_features.png){.right}
196+
197+
198+
---
199+
<!-- #TODO pull this up into presentation? -->
200+
<script>
201+
202+
203+
204+
// poor men's slide master #Hack #TODO How to pull this better into lively-presentation?
205+
var ctx = this;
206+
(async () => {
207+
await lively.sleep(500)
208+
var presentation = lively.query(ctx, "lively-presentation")
209+
if (presentation && presentation.slides) {
210+
presentation.slides().forEach(ea => {
211+
var img = document.createElement("img")
212+
img.classList.add("logo")
213+
img.src="https://lively-kernel.org/lively4/lively4-seminars/PX2018/media/hpi_logo.png"
214+
img.setAttribute("width", "50px")
215+
ea.appendChild(img)
216+
var div = document.createElement("div")
217+
div.classList.add("page-number")
218+
ea.appendChild(div)
219+
});
220+
}
221+
222+
// hot fix
223+
await lively.sleep(500)
224+
Array.from(lively.allElements(true))
225+
.filter(ea => ea.textContent && ea.textContent.match(/^Like douc/)).forEach(ea => ea.textContent = "Like documentation")
226+
227+
228+
229+
return ""
230+
})()
231+
</script>

src/client/lang/lang-ext.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ extend(Object.prototype, {
6767
traverseAsAST(visitor) {
6868
return babel.traverse(this, visitor);
6969
},
70-
inspect() {
70+
openInInspector() {
7171
lively.openInspector(this);
7272
}
7373

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
here we go....
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"source":"/src/client/reactive/babel-plugin-polymorphic-identifiers/playground.js","plugin":"https://lively-kernel.org/lively4/aexpr/src/client/reactive/babel-plugin-polymorphic-identifiers/polymorphic-identifiers.js","options":{"autoUpdateAST":true,"autoUpdateTransformation":false,"autoExecute":true,"systemJS":false,"autoRunTests":false,"autoSaveWorkspace":false},"pluginSelection":[{"url":"https://lively-kernel.org/lively4/aexpr/src/client/reactive/babel-plugin-polymorphic-identifiers/polymorphic-identifiers.js"}]}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
const SHARED_FLAG_GENERATED_IMPORT_IDENTIFIER = 'SHARED_FLAG_GENERATED_IMPORT_IDENTIFIER';
3+
4+
export default function ({ types: t, template }) {
5+
return {
6+
name: 'polymorphic-identifiers',
7+
visitor: {
8+
Program: {
9+
enter(path, state) {
10+
function addCustomTemplate(file, name) {
11+
const declar = file.declarations[name];
12+
if (declar) {
13+
return declar;
14+
}
15+
16+
const identifier = file.declarations[name] = file.addImport("polymorphic-identifiers", name, name);
17+
identifier[SHARED_FLAG_GENERATED_IMPORT_IDENTIFIER] = true;
18+
return identifier;
19+
}
20+
21+
function hasDirective(path, name) {
22+
let foundDirective = false;
23+
path.traverse({
24+
Directive(path) {
25+
if (path.get("value").node.value === name) {
26+
foundDirective = true;
27+
}
28+
}
29+
});
30+
return foundDirective;
31+
}
32+
33+
debugger
34+
const shouldTransform = state.opts.executedIn === 'workspace' || hasDirective(path, "pi");
35+
if (!shouldTransform) {
36+
return;
37+
}
38+
39+
path.traverse({
40+
TaggedTemplateExpression(path) {
41+
if (path.node.visitedByPI) {
42+
return;
43+
}
44+
path.node.visitedByPI = true;
45+
46+
const tagTemplate = template(`MAKE_REF(TAG_NODE, {
47+
thisReference: this,
48+
evalFunction: str => eval(str)
49+
})`);
50+
const tagPath = path.get('tag');
51+
tagPath.replaceWith(tagTemplate({
52+
MAKE_REF: addCustomTemplate(state.file, 'makeRef'),
53+
TAG_NODE: tagPath.node
54+
}));
55+
56+
path.replaceWith(t.memberExpression(path.node, t.identifier('access')));
57+
58+
const parentPath = path.parentPath;
59+
if (parentPath.isBinaryExpression() && path.parentKey === 'left' && parentPath.node.operator === "<<") {
60+
parentPath.replaceWith(parentPath.node.right);
61+
62+
// find something we can embed an assignment expression in
63+
const preStatementAncestor = parentPath.find(p => {
64+
const parent = p.parentPath;
65+
return parent && (parent.isStatement() || (parent.isArrowFunctionExpression() && p.parentKey === "body"))
66+
});
67+
preStatementAncestor.replaceWith(t.assignmentExpression('=', path.node, preStatementAncestor.node));
68+
}
69+
}
70+
});
71+
}
72+
}
73+
}
74+
};
75+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Polymorphic-Identifiers
2+
3+
```JavaScript
4+
import { PIReference } from 'polymorphic-identifiers';
5+
6+
// example scheme
7+
class qa extends PIReference {
8+
read() {
9+
const { elements } = this.parse();
10+
return elements;
11+
}
12+
write(v) {
13+
const { elements, type, prop } = this.parse();
14+
15+
if (type === 'style') {
16+
return elements.forEach(e => e.style[prop] = v)
17+
}
18+
elements.forEach(e => e.innerHTML = v)
19+
}
20+
21+
// helper
22+
parse() {
23+
const [selector, type, prop] = this.strings.first.split('/');
24+
const elements = this.query(selector);
25+
return { selector, type, prop, elements };
26+
}
27+
query(selector) {
28+
return Array.from(document.querySelectorAll(selector));
29+
}
30+
}
31+
32+
// usage
33+
// calls `read`
34+
qa`lively-window`.forEach(lw => lively.showElement(lw))
35+
36+
// assignments with <<
37+
// calls `write`
38+
qa`#rect` << 'html'
39+
qa`#rect/style/border-color` << 'green'
40+
```

0 commit comments

Comments
 (0)