Skip to content

Commit c9e170e

Browse files
committed
Add Crank.js
1 parent 4aa2af0 commit c9e170e

File tree

4 files changed

+286
-0
lines changed

4 files changed

+286
-0
lines changed

frameworks/keyed/crank/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<title>Crank</title>
6+
<link href="/css/currentStyle.css" rel="stylesheet"/>
7+
</head>
8+
<body>
9+
<div id='main'></div>
10+
<script src='dist/main.js'></script>
11+
</body>
12+
</html>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "js-framework-benchmark-crank",
3+
"version": "0.1.0",
4+
"description": "Benchmark for Crank.js",
5+
"main": "index.js",
6+
"js-framework-benchmark": {
7+
"frameworkVersionFromPackage": "@bikeshaving/crank"
8+
},
9+
"scripts": {
10+
"build-dev": "CRANK_ENV=development webpack",
11+
"build-prod": "webpack"
12+
},
13+
"keywords": [
14+
"crank",
15+
"webpack"
16+
],
17+
"author": "Stefan Krause",
18+
"license": "Apache-2.0",
19+
"homepage": "https://github.com/krausest/js-framework-benchmark",
20+
"repository": {
21+
"type": "git",
22+
"url": "https://github.com/krausest/js-framework-benchmark.git"
23+
},
24+
"devDependencies": {
25+
"@babel/core": "7.4.5",
26+
"babel-loader": "8.0.6",
27+
"babel-preset-crank": "^0.1.0",
28+
"terser-webpack-plugin": "1.3.0",
29+
"webpack": "4.34.0",
30+
"webpack-cli": "3.3.4"
31+
},
32+
"dependencies": {
33+
"@bikeshaving/crank": "0.2.1"
34+
}
35+
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import {Copy, createElement} from "@bikeshaving/crank";
2+
import {renderer} from "@bikeshaving/crank/dom";
3+
4+
function random(max) { return Math.round(Math.random() * 1000) % max; }
5+
6+
const A = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean",
7+
"elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive",
8+
"cheap", "expensive", "fancy"];
9+
const C = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
10+
const N = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse",
11+
"keyboard"];
12+
13+
let nextId = 1;
14+
15+
function buildData(count) {
16+
const data = new Array(count);
17+
for (let i = 0; i < count; i++) {
18+
data[i] = {
19+
id: nextId++,
20+
label: `${A[random(A.length)]} ${C[random(C.length)]} ${N[random(N.length)]}`,
21+
};
22+
}
23+
return data;
24+
}
25+
26+
function Button({id, title}) {
27+
return (
28+
<div class="col-sm-6 smallpad">
29+
<button type="button" class="btn btn-primary btn-block" id={id}>
30+
{title}
31+
</button>
32+
</div>
33+
);
34+
}
35+
36+
37+
function Jumbotron() {
38+
this.addEventListener("click", (ev) => {
39+
if (ev.target.tagName === "BUTTON") {
40+
switch (ev.target.id) {
41+
case "run":
42+
this.dispatchEvent(new CustomEvent("jsfb_set", {
43+
bubbles: true,
44+
detail: {amount: 1000},
45+
}));
46+
break;
47+
case "runlots":
48+
this.dispatchEvent(new CustomEvent("jsfb_set", {
49+
bubbles: true,
50+
detail: {amount: 10000},
51+
}));
52+
break;
53+
case "add":
54+
this.dispatchEvent(new CustomEvent("jsfb_add", {
55+
bubbles: true,
56+
detail: {amount: 1000},
57+
}));
58+
break;
59+
case "update":
60+
this.dispatchEvent(new Event("jsfb_update", {bubbles: true}));
61+
break;
62+
case "clear":
63+
this.dispatchEvent(new Event("jsfb_clear", {bubbles: true}));
64+
break;
65+
case "swaprows":
66+
this.dispatchEvent(new Event("jsfb_swap", {bubbles: true}));
67+
break;
68+
}
69+
}
70+
});
71+
72+
return (
73+
<div class="jumbotron">
74+
<div class="row">
75+
<div class="col-md-6">
76+
<h1>Crank</h1>
77+
</div>
78+
<div class="col-md-6">
79+
<div class="row">
80+
<Button id="run" title="Create 1,000 rows" />
81+
<Button id="runlots" title="Create 10,000 rows" />
82+
<Button id="add" title="Append 1,000 rows" />
83+
<Button id="update" title="Update every 10th row" />
84+
<Button id="clear" title="Clear" />
85+
<Button id="swaprows" title="Swap Rows" />
86+
</div>
87+
</div>
88+
</div>
89+
</div>
90+
);
91+
}
92+
93+
function *Row({selected, item}) {
94+
const onselect = () => {
95+
this.dispatchEvent(new CustomEvent("jsfb_select", {
96+
bubbles: true,
97+
detail: {id: item.id},
98+
}));
99+
};
100+
101+
const ondelete = () => {
102+
this.dispatchEvent(new CustomEvent("jsfb_remove", {
103+
bubbles: true,
104+
detail: {id: item.id},
105+
}));
106+
};
107+
108+
let initial = true;
109+
for (const newProps of this) {
110+
if (
111+
initial ||
112+
selected !== newProps.selected ||
113+
item !== newProps.item
114+
) {
115+
initial = false;
116+
selected = newProps.selected;
117+
item = newProps.item;
118+
yield (
119+
<tr class={selected ? "danger" : null}>
120+
<td class="col-md-1">{item.id}</td>
121+
<td class="col-md-4">
122+
<a onclick={onselect}>{item.label}</a>
123+
</td>
124+
<td class="col-md-1">
125+
<a onclick={ondelete}>
126+
<span class="glyphicon glyphicon-remove" aria-hidden="true" />
127+
</a>
128+
</td>
129+
<td class="col-md-6" />
130+
</tr>
131+
);
132+
} else {
133+
yield <Copy />;
134+
}
135+
}
136+
}
137+
138+
function *Main() {
139+
let data = [];
140+
let selected;
141+
this.addEventListener("jsfb_set", (ev) => {
142+
data = buildData(ev.detail.amount);
143+
this.refresh();
144+
});
145+
146+
this.addEventListener("jsfb_add", (ev) => {
147+
data = data.concat(buildData(ev.detail.amount));
148+
this.refresh();
149+
});
150+
151+
this.addEventListener("jsfb_update", (ev) => {
152+
for (let i = 0; i < data.length; i += 10) {
153+
const item = data[i];
154+
data[i] = {...item, label: data[i].label + " !!!"};
155+
}
156+
157+
this.refresh();
158+
});
159+
160+
this.addEventListener("jsfb_clear", () => {
161+
data = [];
162+
this.refresh();
163+
});
164+
165+
this.addEventListener("jsfb_swap", () => {
166+
if (data.length > 998) {
167+
[data[1], data[998]] = [data[998], data[1]];
168+
this.refresh();
169+
}
170+
});
171+
172+
this.addEventListener("jsfb_remove", (ev) => {
173+
const i = data.findIndex((item) => item.id === ev.detail.id);
174+
data.splice(i, 1);
175+
this.refresh();
176+
});
177+
178+
this.addEventListener("jsfb_select", (ev) => {
179+
selected = ev.detail.id;
180+
this.refresh();
181+
});
182+
183+
while (true) {
184+
yield (
185+
<div class="container">
186+
<Jumbotron />
187+
<table class="table table-hover table-striped test-data">
188+
<tbody>
189+
{data.map((item) => (
190+
<Row
191+
crank-key={item.id}
192+
item={item}
193+
selected={item.id === selected}
194+
/>
195+
))}
196+
</tbody>
197+
</table>
198+
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true" />
199+
</div>
200+
);
201+
}
202+
}
203+
204+
renderer.render(<Main />, document.getElementById("main"));
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const path = require('path');
2+
const webpack = require('webpack');
3+
const TerserPlugin = require('terser-webpack-plugin');
4+
5+
const development = process.env.CRANK_ENV === "development";
6+
module.exports = {
7+
mode: development ? "development" : "production",
8+
entry: {
9+
main: path.join(__dirname, 'src', 'main.jsx'),
10+
},
11+
output: {
12+
path: path.join(__dirname, 'dist'),
13+
filename: '[name].js'
14+
},
15+
resolve: {
16+
extensions: ['.js', '.jsx']
17+
},
18+
module: {
19+
rules: [{
20+
test: /\.jsx?$/,
21+
exclude: /node_modules/,
22+
use: [
23+
{
24+
loader: 'babel-loader',
25+
options: {
26+
presets: ['babel-preset-crank'],
27+
}
28+
}
29+
]
30+
}]
31+
},
32+
optimization: {
33+
minimizer: [new TerserPlugin()],
34+
},
35+
};

0 commit comments

Comments
 (0)