Skip to content

Commit 9e753fd

Browse files
committed
Bobril implementation
1 parent b6b8791 commit 9e753fd

File tree

6 files changed

+278
-0
lines changed

6 files changed

+278
-0
lines changed

bobril-v4.42.0/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Bobril v4.42.0</title><link rel="stylesheet" href="dist/a.css"></head><body><script type="text/javascript" src="dist/a.js" charset="utf-8"></script></body></html>

bobril-v4.42.0/package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "js-framework-benchmark-bobril",
3+
"version": "1.0.0",
4+
"description": "Bobril demo",
5+
"main": "src/app.js",
6+
"scripts": {
7+
"build-dev": "bb",
8+
"build-prod": "bb b -v dist",
9+
"start": "http-server -c-1 ."
10+
},
11+
"keywords": [
12+
"bobril",
13+
"bobril-build"
14+
],
15+
"author": "Boris Letocha",
16+
"license": "Apache-2.0",
17+
"homepage": "https://github.com/krausest/js-framework-benchmark",
18+
"repository": {
19+
"type": "git",
20+
"url": "https://github.com/krausest/js-framework-benchmark.git"
21+
},
22+
"devDependencies": {
23+
"bobril-build": "*"
24+
},
25+
"dependencies": {
26+
"bobril": "^4.42.0"
27+
},
28+
"bobril": {
29+
"title": "Bobril v4.42.0",
30+
"dir": ".",
31+
"head": "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
32+
}
33+
}

bobril-v4.42.0/src/app.ts

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import * as b from 'bobril';
2+
import { Store } from "./store";
3+
4+
// For who ever will read this: in Bobril you normally don't use bootstrap or class names directly, you use b.styleDef instead.
5+
b.asset("../../css/bootstrap/dist/css/bootstrap.min.css");
6+
b.asset("../../css/main.css");
7+
8+
var startTime: number;
9+
var lastMeasure: string;
10+
var startMeasure = function (name) {
11+
startTime = performance.now();
12+
lastMeasure = name;
13+
}
14+
var stopMeasure = function () {
15+
var last = lastMeasure;
16+
if (lastMeasure) {
17+
window.setTimeout(function () {
18+
lastMeasure = null;
19+
var stop = performance.now();
20+
var duration = 0;
21+
console.log(last + " took " + (stop - startTime));
22+
}, 0);
23+
}
24+
}
25+
26+
function divWithClass(name: string, children: b.IBobrilChildren) {
27+
return { tag: "div", className: name, children };
28+
}
29+
30+
function tdWithClass(name: string, children: b.IBobrilChildren) {
31+
return { tag: "td", className: name, children };
32+
}
33+
34+
let store = new Store();
35+
36+
interface IButtonData {
37+
children?: b.IBobrilChildren;
38+
id: string;
39+
action: () => void;
40+
}
41+
42+
interface IButtonCtx extends b.IBobrilCtx {
43+
data: IButtonData;
44+
}
45+
46+
const Button = b.createVirtualComponent<IButtonData>({
47+
render(ctx: IButtonCtx, me: b.IBobrilNode) {
48+
const d = ctx.data;
49+
me.tag = "button";
50+
me.className = "btn btn-primary btn-block";
51+
me.attrs = { id: d.id };
52+
me.children = d.children;
53+
},
54+
onClick(ctx: IButtonCtx): boolean {
55+
startMeasure(ctx.data.id);
56+
ctx.data.action();
57+
b.invalidate();
58+
return true;
59+
}
60+
});
61+
62+
interface IHeaderData {
63+
}
64+
65+
interface IHeaderCtx extends b.IBobrilCtx {
66+
data: IHeaderData;
67+
}
68+
69+
const Header = b.createComponent<IHeaderData>({
70+
shouldChange() { return false; },
71+
render(ctx: IHeaderCtx, me: b.IBobrilNode) {
72+
const d = ctx.data;
73+
me.className = "jumbotron";
74+
me.children = divWithClass("row", [
75+
divWithClass("col-md-6", { tag: 'h1', children: "Bobril v4.42.0" }),
76+
divWithClass("col-md-6", [
77+
divWithClass("col-sm-6 smallpad", Button({ id: "run", action: () => store.run() }, "Create 1,000 rows")),
78+
divWithClass("col-sm-6 smallpad", Button({ id: "runlots", action: () => store.runLots() }, "Create 10,000 rows")),
79+
divWithClass("col-sm-6 smallpad", Button({ id: "add", action: () => store.add() }, "Append 1,000 rows")),
80+
divWithClass("col-sm-6 smallpad", Button({ id: "update", action: () => store.update() }, "Update every 10th row")),
81+
divWithClass("col-sm-6 smallpad", Button({ id: "clear", action: () => store.clear() }, "Clear")),
82+
divWithClass("col-sm-6 smallpad", Button({ id: "swaprows", action: () => store.swapRows() }, "Swap Rows")),
83+
])
84+
]);
85+
}
86+
});
87+
88+
const ClickSelect = {
89+
onClick(ctx: { data: number }) {
90+
startMeasure("select");
91+
store.select(ctx.data);
92+
b.invalidate();
93+
return true;
94+
}
95+
};
96+
97+
const ClickRemove = {
98+
onClick(ctx: { data: number }) {
99+
startMeasure("delete");
100+
store.delete(ctx.data);
101+
b.invalidate();
102+
return true;
103+
}
104+
};
105+
106+
interface IRowData {
107+
item: { id: number, label: string };
108+
selected: boolean;
109+
}
110+
111+
interface IRowCtx extends b.IBobrilCtx {
112+
data: IRowData;
113+
}
114+
115+
const Row = b.createVirtualComponent<IRowData>({
116+
init(ctx: IRowCtx) {
117+
},
118+
shouldChange(ctx: IRowCtx, me: b.IBobrilNode): boolean {
119+
return ctx.data.item !== me.data.item || ctx.data.selected !== me.data.selected;
120+
},
121+
render(ctx: IRowCtx, me: b.IBobrilNode) {
122+
const d = ctx.data;
123+
me.tag = "tr";
124+
me.className = d.selected ? "danger" : "";
125+
const id = d.item.id;
126+
me.children = [
127+
tdWithClass("col-md-1", id),
128+
tdWithClass("col-md-4", { tag: "a", data: id, component: ClickSelect, children: d.item.label }),
129+
tdWithClass("col-md-1", { tag: "a", data: id, component: ClickRemove, children: { tag: "span", className: "glyphicon glyphicon-remove", attrs: { "aria-hidden": "true" } } }),
130+
tdWithClass("col-md-6", "")
131+
];
132+
}
133+
});
134+
135+
b.init(() => {
136+
return {
137+
tag: "div", className: "container", component: {
138+
postUpdateDom: stopMeasure
139+
}, children: [
140+
Header(),
141+
{
142+
tag: "table", className: "table table-hover table-striped test-data", children: {
143+
tag: "tbody", children: store.data.map((item) => b.withKey(Row({ item, selected: item.id === store.selected }), <any>item.id))
144+
}
145+
},
146+
{ tag: "span", className: "preloadicon glyphicon glyphicon-remove", attrs: { "aria-hidden": "true" } }
147+
]
148+
};
149+
});

bobril-v4.42.0/src/store.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
function _random(max) {
2+
return Math.round(Math.random()*1000)%max;
3+
}
4+
5+
export class Store {
6+
data: { id:number, label:string }[];
7+
backup: { id:number, label:string }[];
8+
selected: number;
9+
id: number;
10+
constructor() {
11+
this.data = [];
12+
this.selected = undefined;
13+
this.id = 1;
14+
}
15+
buildData(count = 1000) {
16+
var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
17+
var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
18+
var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
19+
var data = [];
20+
for (var i = 0; i < count; i++)
21+
data.push({id: this.id++, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] });
22+
return data;
23+
}
24+
updateData(mod = 10) {
25+
for (let i=0;i<this.data.length;i+=10) {
26+
this.data[i] = Object.assign({}, this.data[i], {label: this.data[i].label + ' !!!'});
27+
}
28+
}
29+
delete(id:number) {
30+
const idx = this.data.findIndex(d => d.id==id);
31+
this.data = this.data.filter((e,i) => i!=idx);
32+
return this;
33+
}
34+
deleteNext(id) {
35+
const idx = this.data.findIndex(d => d.id==id);
36+
this.data = this.data.filter((e,i) => i!=idx+1);
37+
return this;
38+
}
39+
run() {
40+
this.data = this.buildData();
41+
this.selected = undefined;
42+
}
43+
add() {
44+
this.data = this.data.concat(this.buildData(1000));
45+
this.selected = undefined;
46+
}
47+
update() {
48+
this.updateData();
49+
this.selected = undefined;
50+
}
51+
select(id:number) {
52+
this.selected = id;
53+
}
54+
hideAll() {
55+
this.backup = this.data;
56+
this.data = [];
57+
this.selected = undefined;
58+
}
59+
showAll() {
60+
this.data = this.backup;
61+
this.backup = null;
62+
this.selected = undefined;
63+
}
64+
runLots() {
65+
this.data = this.buildData(10000);
66+
this.selected = undefined;
67+
}
68+
clear() {
69+
this.data = [];
70+
this.selected = undefined;
71+
}
72+
swapRows() {
73+
if(this.data.length > 10) {
74+
var a = this.data[4];
75+
this.data[4] = this.data[9];
76+
this.data[9] = a;
77+
}
78+
}
79+
}

bobril-v4.42.0/tsconfig.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es6",
4+
"module": "commonjs",
5+
"moduleResolution": "node",
6+
"jsx": "react",
7+
"reactNamespace": "b"
8+
},
9+
"compileOnSave": false,
10+
"files": [
11+
"node_modules/bobril/jsx.d.ts",
12+
"src/app.ts",
13+
"src/store.ts"
14+
]
15+
}

webdriver-java/src/main/java/net/stefankrause/App.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class App {
3333
new Framework("angular-v1.5.7"),
3434
new Framework("angular-v2.0.0-rc4"),
3535
new Framework("aurelia-v1.0.0-rc1.0.0"),
36+
new Framework("bobril-v4.42.0"),
3637
new Framework("cyclejs-v6.0.3"),
3738
new Framework("cyclejs-v7.0.0"),
3839
new Framework("ember-v2.6.1", "ember-v2.6.1/dist"),

0 commit comments

Comments
 (0)