Skip to content

Commit bbb1342

Browse files
author
robert masen
committed
Add example
1 parent a508589 commit bbb1342

File tree

10 files changed

+351
-2
lines changed

10 files changed

+351
-2
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ members = [
5252
"examples/asm.js",
5353
"examples/char",
5454
"examples/import_js",
55+
"examples/comments"
5556
]
5657

5758
[profile.release]

crates/cli-support/src/js/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,9 @@ impl<'a> Context<'a> {
489489
.method(true)
490490
.ret(&Some(descriptor))?
491491
.finish("", &format!("wasm.{}", wasm_getter));
492+
if !dst.ends_with("\n") {
493+
dst.push_str("\n");
494+
}
492495
dst.push_str(&field.comments);
493496
dst.push_str("get ");
494497
dst.push_str(&field.name);
@@ -509,7 +512,6 @@ impl<'a> Context<'a> {
509512
}}
510513
", shared::free_function(&name)));
511514
ts_dst.push_str("free(): void;\n");
512-
513515
dst.push_str(&class.contents);
514516
ts_dst.push_str(&class.typescript);
515517
dst.push_str("}\n");
@@ -1505,6 +1507,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
15051507
.finish("", &format!("wasm.{}", wasm_name));
15061508
let class = self.cx.exported_classes.entry(class_name.to_string())
15071509
.or_insert(ExportedClass::default());
1510+
class.contents.push_str(&format_doc_comments(&export.comments));
15081511
if !export.method {
15091512
class.contents.push_str("static ");
15101513
class.typescript.push_str("static ");
@@ -1521,7 +1524,6 @@ impl<'a, 'b> SubContext<'a, 'b> {
15211524
1 => Some(constructors[0].clone()),
15221525
x @ _ => bail!("there must be only one constructor, not {}", x),
15231526
};
1524-
15251527
class.contents.push_str(&export.function.name);
15261528
class.contents.push_str(&js);
15271529
class.contents.push_str("\n");

examples/comments/Cargo.toml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "comments"
3+
version = "0.1.0"
4+
authors = ["robert masen <[email protected]>"]
5+
6+
[dependencies]
7+
# Here we're using a path dependency to use what's already in this repository,
8+
# but you'd use the commented out version below if you're copying this into your
9+
# project.
10+
wasm-bindgen = { path = "../.." }
11+
#wasm-bindgen = "0.2"
12+
13+
[lib]
14+
crate-type = ['cdylib']

examples/comments/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# TODO

examples/comments/build.sh

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
3+
set -ex
4+
# Build the comments project
5+
cargo +nightly build --target wasm32-unknown-unknown
6+
7+
# Run the `wasm-bindgen` CLI tool to postprocess the wasm file emitted by the
8+
# Rust compiler to emit the JS support glue that's necessary
9+
#
10+
# Here we're using the version of the CLI in this repository, but for external
11+
# usage you'd use the commented out version below
12+
cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
13+
--bin wasm-bindgen -- .\
14+
./../target/wasm32-unknown-unknown/debug/comments.wasm --out-dir .
15+
# wasm-bindgen ../../target/wasm32-unknown-unknown/hello_world.wasm --out-dir .
16+
17+
# Finally, package everything up using Webpack and start a server so we can
18+
# browse the result
19+
npm install
20+
npm run serve

examples/comments/index.html

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<html>
2+
<head>
3+
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
4+
</head>
5+
<style>
6+
body > * {
7+
font-family: sans-serif;
8+
box-sizing: border-box;
9+
}
10+
#comments {
11+
width: 500px;
12+
display: flex;
13+
flex-flow: column;
14+
margin: auto;
15+
background: darkgrey;
16+
padding: 5px;
17+
border-radius: 5px;
18+
}
19+
#comments > .comment {
20+
width: calc(100% - 14px);
21+
display: flex;
22+
flex-flow: column;
23+
margin-bottom: 5px;
24+
padding: 5px;
25+
border-radius: 5px;
26+
}
27+
28+
#comments > .comment.blue {
29+
border: 2px solid lightcyan;
30+
}
31+
#comments > .comment.pink {
32+
border: 2px solid lightpink;
33+
}
34+
#comments > .comment > .comment-top {
35+
display: flex;
36+
flex-flow: row;
37+
}
38+
#comments > .comment > .comment-top > .count {
39+
margin: 0 5px;
40+
}
41+
#comments > .comment > .comment-bottom {
42+
display: flex;
43+
flex-flow: column;
44+
justify-content: flex-start;
45+
align-items: flex-start;
46+
}
47+
#comments > .comment > .comment-bottom > .comment-title {
48+
font-weight: bold;
49+
text-decoration: underline;
50+
}
51+
#comments > .comment > .comment-bottom > .comment-text {
52+
background: white;
53+
margin-top: 5px;
54+
padding: 5px;
55+
border-radius: 5px;
56+
width: calc(100% - 10px);
57+
}
58+
#new-comment {
59+
display: flex;
60+
flex-flow: column;
61+
align-items: flex-end;
62+
width: 500px;
63+
margin: auto;
64+
}
65+
#new-comment > .input-group {
66+
display: flex;
67+
flex-flow: column;
68+
justify-content: flex-start;
69+
width: 100%;
70+
}
71+
</style>
72+
<body>
73+
<div id="comments"></div>
74+
<div id="input-container">
75+
<form id="new-comment">
76+
<div class="input-group">
77+
<label for="name">Name</label>
78+
<input type="text" id="name" required validation-message="name is required" />
79+
</div>
80+
<div class="input-group">
81+
<label for="name">Comment</label>
82+
<textarea type="text" id="comment" required validation-message="comment is required" ></textarea>
83+
</div>
84+
<button type="button" id="add-comment-button">Add</button>
85+
</form>
86+
<span id="error"></span>
87+
</div>
88+
<script src='./index.js'></script>
89+
</body>
90+
</html>

examples/comments/index.js

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
const mod = import('./comments');
2+
let wasm;
3+
mod.then(m => {
4+
wasm = m;
5+
let button = document.getElementById('add-comment-button');
6+
if (!button) return console.error('Unable to find add button');
7+
button.addEventListener('click', newComment);
8+
displayComments();
9+
});
10+
11+
/**
12+
* Click event handler for add button
13+
* @param {MouseEvent} ev
14+
*/
15+
function newComment(ev) {
16+
clearError();
17+
let name = document.getElementById('name');
18+
if (!name) return console.error('Failed to find name input');
19+
if (name.value == '') return displayError('Name cannot be blank');
20+
let comment = document.getElementById('comment');
21+
if (!comment) return console.error('Failed to find comment input');
22+
if (comment.value == '') return displayError('comment cannot be blank');
23+
addComment(name.value, comment.value);
24+
name.form.reset();
25+
displayComments();
26+
}
27+
28+
/**
29+
* Add a comment to the list
30+
* @param {string} name The name of the person submitting
31+
* @param {string} content The actual text of the comment
32+
*/
33+
function addComment(name, content) {
34+
let existing = comments();
35+
let count = existing.length;
36+
existing.push(new wasm.Comment(name, content, count));
37+
storeComments();
38+
}
39+
40+
/**
41+
* Convert the rust comments to JSON comments and store
42+
* in local storage
43+
*/
44+
function storeComments() {
45+
let json = comments().map(c => {
46+
console.log('mapping comments for storage', c);
47+
return {
48+
name: c.name(),
49+
comment: c.comment(),
50+
count: c.count,
51+
}
52+
});
53+
localStorage.setItem('comments', JSON.stringify(json));
54+
}
55+
/**
56+
* Get the comments from local storage and convert them to
57+
* rust comments
58+
*/
59+
function getComments() {
60+
let json = localStorage.getItem('comments');
61+
if (!json) return [];
62+
let raw = JSON.parse(json);
63+
return raw.map(c => new wasm.Comment(c.name, c.comment, c.count));
64+
}
65+
66+
/**A in memory cache of the localStorage comments for this site */
67+
let cachedComments = null;
68+
/**
69+
* Get a list of comments for this page
70+
* @param {boolean} refresh force a refresh from localStorage
71+
*/
72+
function comments(refresh = false) {
73+
if (refresh || !cachedComments) {
74+
cachedComments = getComments();
75+
}
76+
return cachedComments;
77+
}
78+
79+
/**
80+
* Clear the comments section and re-render with the
81+
* current comments list
82+
*/
83+
function displayComments() {
84+
let node = document.getElementById('comments');
85+
if (!node) return console.error('Failed to get comments container');
86+
while (node.hasChildNodes()) {
87+
node.removeChild(node.lastChild);
88+
}
89+
for (let comment of comments()) {
90+
node.appendChild(renderComment(comment));
91+
}
92+
}
93+
94+
/**
95+
* Generate the HTML needed to display a single comment
96+
* @param {Comment} comment the comment to display
97+
* @returns {HTMLDivElement} The div containing the comment html
98+
*/
99+
function renderComment(comment) {
100+
let cls = `comment ${comment.color() == wasm.Color.Blue ? 'blue' : 'pink'}`;
101+
let div = document.createElement('div');
102+
div.setAttribute('class', cls);
103+
let top = document.createElement('div');
104+
top.setAttribute('class', 'comment-top');
105+
let ct = document.createElement('span');
106+
ct.setAttribute('class', 'count');
107+
ct.appendChild(document.createTextNode(`${comment.count}:`));
108+
let name = document.createElement('span');
109+
name.setAttribute('class', 'user-name');
110+
name.appendChild(document.createTextNode(`${comment.name()}`));
111+
top.appendChild(ct);
112+
top.appendChild(name);
113+
let bottom = document.createElement('div');
114+
bottom.setAttribute('class', 'comment-bottom');
115+
let title = document.createElement('span');
116+
title.setAttribute('class', 'comment-title');
117+
title.appendChild(document.createTextNode('comment'));
118+
bottom.appendChild(title);
119+
let text = document.createElement('span');
120+
text.setAttribute('class', 'comment-text');
121+
text.appendChild(document.createTextNode(comment.comment()))
122+
bottom.appendChild(text);
123+
div.appendChild(top);
124+
div.appendChild(bottom)
125+
return div;
126+
}
127+
128+
function displayError(message) {
129+
let e = document.getElementById('error');
130+
if (!e) return console.error('Failed to find error container');
131+
if (e.innerHTML != '') return setTimeout(displayError, 1000, message);
132+
e.innerHTML = message;
133+
setTimeout(clearError, 3000);
134+
}
135+
136+
function clearError() {
137+
let e = document.getElementById('error');
138+
if (!e) return console.error('Failed to find error container');
139+
e.innerHTML = '';
140+
}

examples/comments/package.json

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"scripts": {
3+
"serve": "webpack-dev-server"
4+
},
5+
"devDependencies": {
6+
"webpack": "^4.8.1",
7+
"webpack-cli": "^2.0.10",
8+
"webpack-dev-server": "^3.1.0"
9+
}
10+
}

examples/comments/src/lib.rs

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#![feature(proc_macro, wasm_custom_section, wasm_import_module)]
2+
3+
extern crate wasm_bindgen;
4+
5+
use wasm_bindgen::prelude::*;
6+
7+
#[wasm_bindgen]
8+
/// A user defined comment
9+
pub struct Comment {
10+
name: String,
11+
comment: String,
12+
/// The position this comment
13+
/// should exist at
14+
pub count: u32,
15+
color: Color,
16+
}
17+
18+
19+
#[wasm_bindgen]
20+
impl Comment {
21+
#[wasm_bindgen(method)]
22+
/// The name of the user who
23+
/// posted this comment
24+
pub fn name(&self) -> String {
25+
self.name.clone()
26+
}
27+
#[wasm_bindgen(method)]
28+
/// The content of this comment
29+
pub fn comment(&self) -> String {
30+
self.comment.clone()
31+
}
32+
33+
#[wasm_bindgen(constructor)]
34+
pub fn new(name: String, comment: String, count: u32) -> Comment {
35+
let color = if count % 2 == 0 {
36+
Color::Blue
37+
} else {
38+
Color::Pink
39+
};
40+
Comment {
41+
name,
42+
comment,
43+
count,
44+
color,
45+
}
46+
}
47+
#[wasm_bindgen(method)]
48+
/// What color should this comment be
49+
pub fn color(&self) -> Color {
50+
self.color.clone()
51+
}
52+
}
53+
54+
/// The border of a comment
55+
#[wasm_bindgen]
56+
#[derive(Clone)]
57+
pub enum Color {
58+
Blue,
59+
Pink,
60+
}

0 commit comments

Comments
 (0)