Skip to content

Commit

Permalink
Merge pull request #13 from mbasso/webcomponents
Browse files Browse the repository at this point in the history
Support WebComponents and improve JS APIs
  • Loading branch information
mbasso committed Jan 5, 2018
2 parents 0170899 + 6555aa8 commit ddf9810
Show file tree
Hide file tree
Showing 72 changed files with 1,639 additions and 218 deletions.
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"presets": ["es2015", "stage-0"],
"plugins": [
"macros",
"dynamic-import-webpack",
"transform-object-rest-spread",
"transform-es3-member-expression-literals",
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_js:
- "6"
- "7"
- "8"
- "9"
install: true
script:
- npm install --ignore-scripts
Expand Down
43 changes: 14 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ At the beginning asm-dom is born from the idea to test the powerful of WebAssemb

## Inline Example

```c++
```
#include "asm-dom.hpp"
using namespace asmdom;
Expand All @@ -42,34 +42,18 @@ int main() {
Config config = Config();
init(config);
VNode* vnode = h("div",
Data(
Callbacks {
{"onclick", [](emscripten::val e) -> bool {
emscripten::val::global("console").call<void>("log", emscripten::val("clicked"));
return true;
}}
}
),
Children {
h("span",
Data(
Attrs {
{"style", "font-weight: bold"}
}
),
std::string("This is bold")
),
h(" and this is just normal text", true),
h("a",
Data(
Attrs {
{"href", "/foo"}
}
),
std::string("I'll take you places!")
)
}
// asm-dom can be used with a JSX like syntax thanks to gccx
VNode* vnode = (
<div
onclick={[](emscripten::val e) -> bool {
emscripten::val::global("console").call<void>("log", emscripten::val("clicked"));
return true;
}}
>
<span style="font-weight: bold">This is bold</span>
and this is just normal text
<a href="/foo">I'll take you places!</a>
</div>
);
// Patch into empty DOM element – this modifies the DOM as a side effect
Expand All @@ -81,6 +65,7 @@ int main() {
vnode
);
// without gccx
VNode* newVnode = h("div",
Data(
Callbacks {
Expand Down
Binary file modified compiled/asm-dom.a
Binary file not shown.
Binary file modified compiled/asm-dom.bc
Binary file not shown.
Binary file modified compiled/asm-dom.o
Binary file not shown.
2 changes: 1 addition & 1 deletion compiled/asmjs/asm-dom.asm.js

Large diffs are not rendered by default.

Binary file modified compiled/wasm/asm-dom.wasm
Binary file not shown.
47 changes: 36 additions & 11 deletions cpp/Diff/diff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,21 @@ namespace asmdom {

emscripten::val elm = emscripten::val::global("window")["asmDomHelpers"]["nodes"][vnode->elm];

EM_ASM_({
window['asmDomHelpers']['nodes'][$0]['asmDomRaws'] = [];
}, vnode->elm);

for (auto& it : oldVnode->data.props) {
if (!vnode->data.props.count(it.first)) {
elm.set(it.first.c_str(), emscripten::val::undefined());
}
}

for (auto& it : vnode->data.props) {
EM_ASM_({
window['asmDomHelpers']['nodes'][$0]['asmDomRaws'].push(Module['UTF8ToString']($1));
}, vnode->elm, it.first.c_str());

if (
!oldVnode->data.props.count(it.first) ||
!it.second.strictlyEquals(oldVnode->data.props.at(it.first)) ||
Expand All @@ -82,25 +90,42 @@ namespace asmdom {
void diffCallbacks(VNode* __restrict__ const oldVnode, VNode* __restrict__ const vnode) {
if (oldVnode->data.callbacks.empty() && vnode->data.callbacks.empty()) return;

EM_ASM_({
window['asmDomHelpers']['nodes'][$0]['asmDomRaws'] = [];
}, vnode->elm);

for (auto& it : oldVnode->data.callbacks) {
if (!vnode->data.callbacks.count(it.first)) {
EM_ASM_({
window['asmDomHelpers']['nodes'][$0][Module['UTF8ToString']($1)] = undefined;
var key = Module['UTF8ToString']($1).replace(/^on/, "");
var elm = window['asmDomHelpers']['nodes'][$0];
elm.removeEventListener(
key,
window['asmDomHelpers']['eventProxy'],
false
);
delete elm['asmDomEvents'][key];
}, vnode->elm, it.first.c_str());
}
}

EM_ASM_({
var elm = window['asmDomHelpers']['nodes'][$0];
elm.asmDomVNode = $1;
if (elm['asmDomEvents'] === undefined) {
elm['asmDomEvents'] = {};
}
}, vnode->elm, reinterpret_cast<std::uintptr_t>(vnode));

for (auto& it : vnode->data.callbacks) {
EM_ASM_({
var key = Module['UTF8ToString']($2);
window['asmDomHelpers']['nodes'][$1][key] =
window['asmDomHelpers']['functionCallback']($0, key);
window['asmDomHelpers']['nodes'][$1]['asmDomRaws'].push(key);
}, reinterpret_cast<std::uintptr_t>(vnode), vnode->elm, it.first.c_str());
if (!oldVnode->data.callbacks.count(it.first)) {
EM_ASM_({
var key = Module['UTF8ToString']($1).replace(/^on/, "");
var elm = window['asmDomHelpers']['nodes'][$0];
elm.addEventListener(
key,
window['asmDomHelpers']['eventProxy'],
false
);
elm['asmDomEvents'][key] = window['asmDomHelpers']['eventProxy'];
}, vnode->elm, it.first.c_str());
}
}
};

Expand Down
6 changes: 2 additions & 4 deletions cpp/Init/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ namespace asmdom {
#ifndef ASMDOM_JS_SIDE

EM_ASM(
window['asmDomHelpers']['functionCallback'] = function(vnode, callback) {
return function(event) {
return Module['functionCallback'](vnode, callback, event);
};
window['asmDomHelpers']['eventProxy'] = function(e) {
return Module['functionCallback'](this.asmDomVNode, e.type, e)
};
);

Expand Down
10 changes: 4 additions & 6 deletions cpp/Patch/patch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,12 @@ namespace asmdom {
}
}
}
if (oldStartIdx > oldEndIdx) {
if (newEndIdx + 1 <= newCh.size() - 1) {
addVNodes(parentElm, newCh[newEndIdx+1]->elm, newCh, newStartIdx, newEndIdx);
if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) {
if (oldStartIdx > oldEndIdx) {
addVNodes(parentElm, newEndIdx + 1 <= newCh.size() - 1 ? newCh[newEndIdx+1]->elm : 0, newCh, newStartIdx, newEndIdx);
} else {
addVNodes(parentElm, 0, newCh, newStartIdx, newEndIdx);
removeVNodes(oldCh, oldStartIdx, oldEndIdx);
}
} else if (newStartIdx > newEndIdx) {
removeVNodes(oldCh, oldStartIdx, oldEndIdx);
}
delete oldKeyToIdx;
oldKeyToIdx = NULL;
Expand Down
7 changes: 6 additions & 1 deletion cpp/VNode/VNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ namespace asmdom {
#ifndef ASMDOM_JS_SIDE

emscripten::val functionCallback(const std::uintptr_t& vnode, const std::string& callback, emscripten::val event) {
return emscripten::val(reinterpret_cast<VNode*>(vnode)->data.callbacks[callback](event));
Callbacks cbs = reinterpret_cast<VNode*>(vnode)->data.callbacks;
std::string cb = callback;
if (!cbs.count(callback)) {
cb = "on" + cb;
}
return emscripten::val(cbs[cb](event));
};

EMSCRIPTEN_BINDINGS(function_callback) {
Expand Down
2 changes: 1 addition & 1 deletion cpp/asm-dom.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 12 additions & 2 deletions cpp/domRecycler.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,21 @@ var recycler = {
i = node.attributes !== undefined ? node.attributes.length : 0;
while (i--) {
node.removeAttribute(node.attributes[i].name);
}if (node.asmDomRaws !== undefined && node.asmDomRaws.length > 0) {
}node.asmDomVNode = undefined;
if (node.asmDomRaws !== undefined) {
node.asmDomRaws.forEach(function (raw) {
node[raw] = undefined;
});
node.asmDomRaws = [];
node.asmDomRaws = undefined;
}
if (node.asmDomEvents !== undefined) {
var keys = Object.keys(node.asmDomEvents);
i = keys.length;
// eslint-disable-next-line
while (i--) {
node.removeEventListener(keys[i], node.asmDomEvents[keys[i]], false);
}
node.asmDomEvents = undefined;
}
if (node.textContent !== null && node.textContent !== '') {
node.textContent = '';
Expand Down
Loading

0 comments on commit ddf9810

Please sign in to comment.