Skip to content

Commit b8e0119

Browse files
committed
fist commit
0 parents  commit b8e0119

8 files changed

Lines changed: 239 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__target__
2+
*.xdc
3+
*~

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2022 Asiel Díaz Benítez
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Webxdc development with Python
2+
3+
This is an example project to show how to develop webxdc apps with Python.
4+
5+
## Requirements
6+
7+
This project depends on:
8+
- [Python](https://python.org/)
9+
- [Transcrypt](https://www.transcrypt.org/)
10+
11+
Check their documentation to know how to install them.
12+
13+
## Building
14+
15+
To convert your Python code to JavaScript, execute:
16+
17+
```sh
18+
python -m transcrypt app.py
19+
```
20+
21+
## Testing
22+
23+
After building, you are ready to test the app. The project comes with an
24+
small simulator that allows to test your app in your browser, to do it
25+
just go to the root of the project and run this command:
26+
27+
```sh
28+
python -m http.server
29+
```
30+
31+
then open in your browser the URL that is displayed in the shell.
32+
33+
## Packaging
34+
35+
To use the app in Delta Chat, you need to package it in a `.xdc` archive,
36+
the `create-xdc.sh` script helps you to do that:
37+
38+
```sh
39+
./create-xdc.sh
40+
```

app.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
def sendMsg():
2+
textfield = document.getElementById("input")
3+
textfield.focus()
4+
text = textfield.value
5+
if text: # ignore empty field
6+
window.webxdc.sendUpdate(
7+
{
8+
"payload": {
9+
"sender": window.webxdc.selfName(),
10+
"text": text,
11+
}
12+
},
13+
f'someone typed "{text}"',
14+
)
15+
textfield.value = ""
16+
17+
18+
def receiveUpdate(update):
19+
msg = update.payload
20+
msgs = document.getElementById("msgs")
21+
msgs.innerHTML += f"<strong>&lt;{msg['sender']}&gt;</strong> {msg['text']}<br>"
22+
23+
24+
def onInput():
25+
if event.key == "Enter":
26+
sendMsg()
27+
28+
29+
def _onload():
30+
body = document.getElementsByTagName("body")[0]
31+
body.innerHTML += (
32+
'<input id="input" type="text" onkeydown="app.onInput();"/>'
33+
+ '<button onclick="app.sendMsg();">Send</button>'
34+
+ '<p id="msgs"></p>'
35+
)
36+
37+
window.webxdc.setUpdateListener(receiveUpdate) # process incoming messages
38+
window.webxdc.getAllUpdates().forEach(receiveUpdate) # restore app state
39+
40+
41+
window.onload = _onload

create-xdc.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
3+
case "$1" in
4+
"-h" | "--help")
5+
echo "usage: ${0##*/} [PACKAGE_NAME]"
6+
exit
7+
;;
8+
"")
9+
PACKAGE_NAME=${PWD##*/} # '##*/' removes everything before the last slash and the last slash
10+
;;
11+
*)
12+
PACKAGE_NAME=${1%.xdc} # '%.xdc' removes the extension and allows PACKAGE_NAME to be given with or without extension
13+
;;
14+
esac
15+
16+
rm $PACKAGE_NAME.xdc 2> /dev/null
17+
zip -9 --recurse-paths $PACKAGE_NAME.xdc * --exclude README.md webxdc.js "*.sh" "*.xdc" "*.py" "*.project"
18+
19+
echo "success, archive contents:"
20+
unzip -l $PACKAGE_NAME.xdc

index.html

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
7+
<script src="webxdc.js"></script>
8+
</head>
9+
<body>
10+
11+
<script type="module">import * as app from './__target__/app.js'; window.app = app;</script>
12+
</body>
13+
</html>

manifest.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
name = "Python app"

webxdc.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// debug friend: document.writeln(JSON.stringify(value));
2+
window.webxdc = (() => {
3+
var updateListener = () => {};
4+
var updatesKey = "__xdcUpdatesKey__";
5+
window.addEventListener('storage', (event) => {
6+
if (event.key == null) {
7+
window.location.reload();
8+
} else if (event.key === updatesKey) {
9+
var updates = JSON.parse(event.newValue);
10+
var update = updates[updates.length-1];
11+
console.log("[Webxdc] " + JSON.stringify(update));
12+
updateListener(update);
13+
}
14+
});
15+
16+
return {
17+
selfAddr: () => {
18+
var params = new URLSearchParams(window.location.hash.substr(1));
19+
return params.get("addr") || "device0@local.host";
20+
},
21+
selfName: () => {
22+
var params = new URLSearchParams(window.location.hash.substr(1));
23+
return params.get("name") || "device0";
24+
},
25+
setUpdateListener: (cb) => (updateListener = cb),
26+
getAllUpdates: () => {
27+
var updatesJSON = window.localStorage.getItem(updatesKey);
28+
return updatesJSON ? JSON.parse(updatesJSON) : [];
29+
},
30+
sendUpdate: (update, description) => {
31+
// alert(description+"\n\n"+JSON.stringify(payload));
32+
update = {payload: update.payload, summary: update.summary, info: update.info}
33+
console.log('[Webxdc] description="' + description + '", ' + JSON.stringify(update));
34+
updateListener(update);
35+
var updatesJSON = window.localStorage.getItem(updatesKey);
36+
var updates = updatesJSON ? JSON.parse(updatesJSON) : [];
37+
updates.push(update);
38+
window.localStorage.setItem(updatesKey, JSON.stringify(updates));
39+
},
40+
};
41+
})();
42+
43+
window.addXdcPeer = () => {
44+
var loc = window.location;
45+
// get next peer ID
46+
var params = new URLSearchParams(loc.hash.substr(1));
47+
var peerId = Number(params.get("next_peer")) || 1;
48+
49+
// open a new window
50+
var peerName = "device" + peerId;
51+
var url = loc.protocol + "//" + loc.host + loc.pathname + "#name=" + peerName + "&addr=" + peerName + "@local.host";
52+
window.open(url);
53+
54+
// update next peer ID
55+
params.set("next_peer", peerId + 1);
56+
window.location.hash = "#" + params.toString();
57+
}
58+
59+
window.clearXdcStorage = () => {
60+
window.localStorage.clear();
61+
window.location.reload();
62+
}
63+
64+
window.alterXdcApp = () => {
65+
var styleControlPanel = 'position: fixed; bottom:1em; left:1em; background-color: #000; opacity:0.8; padding:.5em; font-family: sans-serif; color:#fff; z-index: 9999';
66+
var styleMenuLink = 'color:#fff; text-decoration: none; vertical-align: middle';
67+
var styleAppIcon = 'height: 1.5em; width: 1.5em; margin-right: 0.5em; border-radius:10%; vertical-align: middle';
68+
var title = document.getElementsByTagName('title')[0];
69+
if (typeof title == 'undefined') {
70+
title = document.createElement('title');
71+
document.getElementsByTagName('head')[0].append(title);
72+
}
73+
title.innerText = window.webxdc.selfAddr();
74+
75+
if (window.webxdc.selfName() === "device0") {
76+
var div = document.createElement('div');
77+
div.innerHTML =
78+
'<div style="' + styleControlPanel + '">' +
79+
'<a href="javascript:window.addXdcPeer();" style="' + styleMenuLink + '">Add Peer</a>' +
80+
'<span style="' + styleMenuLink + '"> | </span>' +
81+
'<a href="javascript:window.clearXdcStorage();" style="' + styleMenuLink + '">Clear Storage</a>' +
82+
'<div>';
83+
var controlPanel = div.firstChild;
84+
85+
function loadIcon(name) {
86+
var tester = new Image();
87+
tester.onload = () => {
88+
div.innerHTML = '<img src="' + name + '" style="' + styleAppIcon +'">';
89+
controlPanel.insertBefore(div.firstChild, controlPanel.firstChild);
90+
};
91+
tester.src = name;
92+
}
93+
loadIcon("icon.png");
94+
loadIcon("icon.jpg");
95+
96+
document.getElementsByTagName('body')[0].append(controlPanel);
97+
}
98+
}
99+
100+
window.addEventListener("load", window.alterXdcApp);

0 commit comments

Comments
 (0)