add mailboxes
This commit is contained in:
Binary file not shown.
Vendored
+59
-5
@@ -131,6 +131,19 @@
|
||||
);
|
||||
return proxyState;
|
||||
}
|
||||
function persistState(localStorageKey, state) {
|
||||
state.subscribe(() => {
|
||||
const stringifiedValue = state.toString();
|
||||
localStorage.setItem(localStorageKey, stringifiedValue);
|
||||
});
|
||||
}
|
||||
function restoreState(localStorageKey, initialStateValue) {
|
||||
const storedString = localStorage.getItem(localStorageKey) ?? JSON.stringify(initialStateValue);
|
||||
const convertedValue = JSON.parse(storedString);
|
||||
const state = new State(convertedValue);
|
||||
persistState(localStorageKey, state);
|
||||
return state;
|
||||
}
|
||||
function createElement(tagName, attributes = {}, ...children) {
|
||||
const element = document.createElement(tagName);
|
||||
if (attributes != null)
|
||||
@@ -159,13 +172,13 @@
|
||||
try {
|
||||
const [listState, toElement] = value;
|
||||
listState.handleAddition((newItem) => {
|
||||
const child = toElement(newItem, listState);
|
||||
const child = toElement(newItem);
|
||||
listState.handleRemoval(
|
||||
newItem,
|
||||
() => child.remove()
|
||||
);
|
||||
element.append(child);
|
||||
child.scrollIntoView();
|
||||
element.scrollTop = element.scrollHeight;
|
||||
});
|
||||
} catch {
|
||||
throw `error: cannot process subscribe:children directive because ListItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation`;
|
||||
@@ -225,6 +238,8 @@
|
||||
};
|
||||
messageHandler = (data) => {
|
||||
};
|
||||
mailboxHandler = (mailboxId2) => {
|
||||
};
|
||||
// init
|
||||
set onconnect(handler) {
|
||||
this.connectionHandler = handler;
|
||||
@@ -235,6 +250,9 @@
|
||||
set onmessage(handler) {
|
||||
this.messageHandler = handler;
|
||||
}
|
||||
set onmailbox(handler) {
|
||||
this.mailboxHandler = handler;
|
||||
}
|
||||
// utility methods
|
||||
send(messageObject) {
|
||||
if (this.ws == void 0) return false;
|
||||
@@ -244,15 +262,23 @@
|
||||
}
|
||||
// public methods
|
||||
connect(address) {
|
||||
this.disconnect();
|
||||
this.ws = new WebSocket(address);
|
||||
this.ws.addEventListener("open", this.connectionHandler);
|
||||
this.ws.addEventListener("close", this.disconnectionHandler);
|
||||
this.ws.addEventListener("message", (message) => {
|
||||
const dataString = message.data.toString();
|
||||
const data = JSON.parse(dataString);
|
||||
this.messageHandler(data);
|
||||
if (data.assignedMailboxId) {
|
||||
return this.mailboxHandler(data.assignedMailboxId);
|
||||
} else {
|
||||
this.messageHandler(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
disconnect() {
|
||||
this.ws?.close();
|
||||
}
|
||||
sendMessage(channel, body) {
|
||||
const messageObject = {
|
||||
messageChannel: channel,
|
||||
@@ -272,10 +298,24 @@
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
requestMailbox() {
|
||||
const messageObject = {
|
||||
requestingMailboxSetup: true
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
accessMailbox(mailboxId2) {
|
||||
const messageObject = {
|
||||
requestedMailbox: mailboxId2
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
};
|
||||
|
||||
// src/translations.tsx
|
||||
var staticTextEnglish = {
|
||||
mailbox: "Mailbox",
|
||||
requestMailbox: "Request Mailbox",
|
||||
channel: "Channel",
|
||||
channel_placeholder: "my-channel",
|
||||
disconnected: "Server disconnected",
|
||||
@@ -298,6 +338,8 @@
|
||||
var translations = {
|
||||
en: staticTextEnglish,
|
||||
es: {
|
||||
mailbox: "Buz\xF3n",
|
||||
requestMailbox: "Solicitar buz\xF3n",
|
||||
channel: "Canal",
|
||||
channel_placeholder: "mi-canal",
|
||||
disconnected: "Sin coneci\xF3n",
|
||||
@@ -318,6 +360,8 @@
|
||||
unsubscribe: "Cancelar"
|
||||
},
|
||||
de: {
|
||||
mailbox: "Briefkasten",
|
||||
requestMailbox: "Briefkasten beantragen",
|
||||
channel: "Kanal",
|
||||
channel_placeholder: "mein-kanal",
|
||||
disconnected: "Verbindung getrennt",
|
||||
@@ -352,12 +396,15 @@
|
||||
this.channel = channel;
|
||||
this.body = body;
|
||||
}
|
||||
uuid = new UUID();
|
||||
id = UUID();
|
||||
};
|
||||
var UDN = new UDNFrontend();
|
||||
UDN.onconnect = () => {
|
||||
isDisconnected.value = false;
|
||||
updateStats();
|
||||
if (mailboxId.value != "") {
|
||||
UDN.accessMailbox(mailboxId.value);
|
||||
}
|
||||
};
|
||||
UDN.onmessage = (data) => {
|
||||
lastReceivedMessage.value = JSON.stringify(data, null, 4);
|
||||
@@ -367,6 +414,9 @@
|
||||
if (messageBody) messages.add(messageObject);
|
||||
}
|
||||
};
|
||||
UDN.onmailbox = (id) => {
|
||||
mailboxId.value = id;
|
||||
};
|
||||
UDN.ondisconnect = () => {
|
||||
isDisconnected.value = true;
|
||||
setTimeout(connect, 2e3);
|
||||
@@ -376,6 +426,7 @@
|
||||
}
|
||||
connect();
|
||||
var isDisconnected = new State(true);
|
||||
var mailboxId = restoreState("mailbox-id", "");
|
||||
var messages = new ListState();
|
||||
var lastReceivedMessage = new State(
|
||||
getText("noMessagesReceived")
|
||||
@@ -411,6 +462,9 @@
|
||||
UDN.sendMessage(newMessageChannel.value, newMessageBody.value);
|
||||
newMessageBody.value = "";
|
||||
}
|
||||
function requestMailbox() {
|
||||
UDN.requestMailbox();
|
||||
}
|
||||
|
||||
// src/infoScreen.tsx
|
||||
function InfoScreen() {
|
||||
@@ -419,7 +473,7 @@
|
||||
|
||||
// src/mainScreen.tsx
|
||||
function MainScreen() {
|
||||
return /* @__PURE__ */ createElement("article", { id: "main-screen" }, /* @__PURE__ */ createElement("header", null, getText("settings")), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "tile width-input" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, getText("messageLastReceived")), /* @__PURE__ */ createElement("p", { class: "secondary", "subscribe:innerText": lastReceivedMessage }))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, getText("subscribeToChannel")), /* @__PURE__ */ createElement(
|
||||
return /* @__PURE__ */ createElement("article", { id: "main-screen" }, /* @__PURE__ */ createElement("header", null, getText("settings")), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("div", { class: "tile width-input" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, getText("messageLastReceived")), /* @__PURE__ */ createElement("p", { class: "secondary", "subscribe:innerText": lastReceivedMessage }))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "tile width-input" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("b", null, getText("mailbox")), /* @__PURE__ */ createElement("p", { class: "secondary", "subscribe:innerText": mailboxId }))), /* @__PURE__ */ createElement("div", { class: "flex-row width-input justify-end" }, /* @__PURE__ */ createElement("button", { class: "primary width-100", "on:click": requestMailbox }, getText("requestMailbox"), /* @__PURE__ */ createElement("span", { class: "icon" }, "inbox"))), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, getText("subscribeToChannel")), /* @__PURE__ */ createElement(
|
||||
"input",
|
||||
{
|
||||
placeholder: getText("channel_placeholder"),
|
||||
|
||||
+39
-21
@@ -21,6 +21,7 @@ touch src/index.tsx dist/index.html
|
||||
```
|
||||
|
||||
The following build script will be enough:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"scripts": {
|
||||
@@ -102,6 +103,7 @@ listState.remove(newItem);
|
||||
## Persistence
|
||||
|
||||
States can persist through reloads via LocalStorage. To implement this, modify your code like this:
|
||||
|
||||
```diff
|
||||
-const myState = new React.State("hello");
|
||||
+const myState = React.restoreState("my-state", "hello");
|
||||
@@ -213,44 +215,60 @@ document.body.append(
|
||||
```
|
||||
|
||||
# Changelog
|
||||
|
||||
## 1.1.0
|
||||
- Improve code
|
||||
- Add missing `break` statements for directives
|
||||
- Add `toggle` directive
|
||||
- Improve documentation
|
||||
|
||||
- Improve code
|
||||
- Add missing `break` statements for directives
|
||||
- Add `toggle` directive
|
||||
- Improve documentation
|
||||
|
||||
## 1.1.1
|
||||
- Improve documentation
|
||||
|
||||
- Improve documentation
|
||||
|
||||
## 1.1.2
|
||||
- Remove `console.log()` calls
|
||||
- Improve documentation
|
||||
|
||||
- Remove `console.log()` calls
|
||||
- Improve documentation
|
||||
|
||||
## 1.1.3
|
||||
- Add `on:enter` directive
|
||||
|
||||
- Add `on:enter` directive
|
||||
|
||||
## 1.2.0
|
||||
|
||||
**BREAKING CHANGES**
|
||||
- Replace UUID class with function;
|
||||
- `new UUID()` => `UUID() returns string`
|
||||
- Replace definition of `Identifiable`
|
||||
- now has `id: string` instead of `uuid: UUID()`
|
||||
|
||||
- Replace UUID class with function;
|
||||
- `new UUID()` => `UUID() returns string`
|
||||
- Replace definition of `Identifiable`
|
||||
- now has `id: string` instead of `uuid: UUID()`
|
||||
|
||||
Other changes:
|
||||
- Add State persistence
|
||||
- Add error description when utilizing `subscribe:children` incorrectly
|
||||
- Fix bug where ListState subscriptions were not called
|
||||
- Improve documentation
|
||||
|
||||
- Add State persistence
|
||||
- Add error description when utilizing `subscribe:children` incorrectly
|
||||
- Fix bug where ListState subscriptions were not called
|
||||
- Improve documentation
|
||||
|
||||
## 1.2.1
|
||||
- Add `set:<attribute>` directive
|
||||
|
||||
- Add `set:<attribute>` directive
|
||||
|
||||
## 1.2.2
|
||||
- Remove list parameter from `ListItemConverter`
|
||||
- Add `clear()` method to `ListState`
|
||||
|
||||
- Remove list parameter from `ListItemConverter`
|
||||
- Add `clear()` method to `ListState`
|
||||
|
||||
## 1.2.3
|
||||
- Allow `toggle:<attribute>` to be used without a state
|
||||
|
||||
- Allow `toggle:<attribute>` to be used without a state
|
||||
|
||||
## 1.2.4
|
||||
- On `subscribe:children`, scroll new elements into view
|
||||
|
||||
- On `subscribe:children`, scroll new elements into view
|
||||
|
||||
## 1.2.5
|
||||
|
||||
- Instead of using `scrollIntoView()`, `subscribe:children` now scrolls to the bottom
|
||||
+3
-6
@@ -205,19 +205,16 @@ export function createElement(
|
||||
try {
|
||||
const [listState, toElement] = value as [
|
||||
listState: ListState<any>,
|
||||
(
|
||||
item: any,
|
||||
listState: ListState<any>
|
||||
) => HTMLElement
|
||||
ListItemConverter<any>
|
||||
];
|
||||
|
||||
listState.handleAddition((newItem) => {
|
||||
const child = toElement(newItem, listState);
|
||||
const child = toElement(newItem);
|
||||
listState.handleRemoval(newItem, () =>
|
||||
child.remove()
|
||||
);
|
||||
element.append(child);
|
||||
child.scrollIntoView();
|
||||
element.scrollTop = element.scrollHeight;
|
||||
});
|
||||
} catch {
|
||||
throw `error: cannot process subscribe:children directive because ListItemConverter is not defined. Usage: "subscribe:children={[list, converter]}"; you can find a more detailed example in the documentation`;
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bloatless-react",
|
||||
"version": "1.2.4",
|
||||
"version": "1.2.5-beta1",
|
||||
"description": "very minimal and flexible react alternative",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
+19
-2
@@ -35,10 +35,18 @@ UDN.unsubscribe("my-channel");
|
||||
|
||||
```TypeScript
|
||||
export interface Message {
|
||||
// connecting to server
|
||||
requestingServerConnection?: boolean;
|
||||
|
||||
// mailbox
|
||||
requestingMailboxSetup?: boolean;
|
||||
assignedMailboxId?: string; // sent by server
|
||||
requestedMailbox?: string;
|
||||
|
||||
// subscribing to channel
|
||||
subscribeChannel?: string;
|
||||
unsubscribeChannel?: string;
|
||||
subscribed?: boolean; // sent by the server to confirm subscription
|
||||
subscribed?: boolean; // sent by server to confirm subscription
|
||||
|
||||
//sending message
|
||||
messageChannel?: string;
|
||||
@@ -46,7 +54,7 @@ export interface Message {
|
||||
}
|
||||
|
||||
export default class UDNFrontend {
|
||||
private ws: WebSocket | undefined;
|
||||
ws: WebSocket | undefined;
|
||||
|
||||
// handlers
|
||||
private connectionHandler = () => {};
|
||||
@@ -60,6 +68,7 @@ export default class UDNFrontend {
|
||||
|
||||
// methods
|
||||
connect(address: string): void;
|
||||
disconnect(address: string): void;
|
||||
sendMessage(channel: string, body: string): boolean; // true if message is sent
|
||||
subscribe(channel: string): boolean; // true if request is sent, NOT inherently when subscribed
|
||||
unsubscribe(channel: string): boolean; // true if request is sent, NOT inherently when unsubscribed
|
||||
@@ -75,3 +84,11 @@ export default class UDNFrontend {
|
||||
## 1.0.2
|
||||
|
||||
- minor fixes
|
||||
|
||||
## 1.0.3
|
||||
|
||||
- add `disconnect()` method
|
||||
|
||||
## 1.0.4
|
||||
|
||||
- make ws public
|
||||
+41
-4
@@ -1,8 +1,16 @@
|
||||
export interface Message {
|
||||
// connecting to server
|
||||
requestingServerConnection?: boolean;
|
||||
|
||||
// mailbox
|
||||
requestingMailboxSetup?: boolean;
|
||||
assignedMailboxId?: string; // sent by server
|
||||
requestedMailbox?: string;
|
||||
|
||||
// subscribing to channel
|
||||
subscribeChannel?: string;
|
||||
unsubscribeChannel?: string;
|
||||
subscribed?: boolean; // sent by the server to confirm subscription
|
||||
subscribed?: boolean; // sent by server to confirm subscription
|
||||
|
||||
//sending message
|
||||
messageChannel?: string;
|
||||
@@ -10,12 +18,13 @@ export interface Message {
|
||||
}
|
||||
|
||||
export default class UDNFrontend {
|
||||
private ws: WebSocket | undefined;
|
||||
ws: WebSocket | undefined;
|
||||
|
||||
// handlers
|
||||
private connectionHandler = () => {};
|
||||
private disconnectionHandler = () => {};
|
||||
private messageHandler = (data: Message) => {};
|
||||
private mailboxHandler = (mailboxId: string) => {};
|
||||
|
||||
// init
|
||||
set onconnect(handler: () => void) {
|
||||
@@ -27,9 +36,12 @@ export default class UDNFrontend {
|
||||
set onmessage(handler: (data: Message) => void) {
|
||||
this.messageHandler = handler;
|
||||
}
|
||||
set onmailbox(handler: (mailboxId: string) => void) {
|
||||
this.mailboxHandler = handler;
|
||||
}
|
||||
|
||||
// utility methods
|
||||
private send(messageObject: Object): boolean {
|
||||
private send(messageObject: Message): boolean {
|
||||
if (this.ws == undefined) return false;
|
||||
|
||||
const messageString = JSON.stringify(messageObject);
|
||||
@@ -39,16 +51,27 @@ export default class UDNFrontend {
|
||||
|
||||
// public methods
|
||||
connect(address: string): void {
|
||||
this.disconnect();
|
||||
|
||||
this.ws = new WebSocket(address);
|
||||
this.ws.addEventListener("open", this.connectionHandler);
|
||||
this.ws.addEventListener("close", this.disconnectionHandler);
|
||||
this.ws.addEventListener("message", (message) => {
|
||||
const dataString = message.data.toString();
|
||||
const data = JSON.parse(dataString);
|
||||
this.messageHandler(data);
|
||||
|
||||
if (data.assignedMailboxId) {
|
||||
return this.mailboxHandler(data.assignedMailboxId);
|
||||
} else {
|
||||
this.messageHandler(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
disconnect(): void {
|
||||
this.ws?.close();
|
||||
}
|
||||
|
||||
sendMessage(channel: string, body: string): boolean {
|
||||
const messageObject = {
|
||||
messageChannel: channel,
|
||||
@@ -70,4 +93,18 @@ export default class UDNFrontend {
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
|
||||
requestMailbox(): boolean {
|
||||
const messageObject = {
|
||||
requestingMailboxSetup: true,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
|
||||
accessMailbox(mailboxId: string): boolean {
|
||||
const messageObject = {
|
||||
requestedMailbox: mailboxId,
|
||||
};
|
||||
return this.send(messageObject);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "udn-frontend",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.4-beta2",
|
||||
"description": "TypeScript library for UDN apps",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"bloatless-react": "^1.2.4",
|
||||
"bloatless-react": "1.2.5-beta1",
|
||||
"esbuild": "latest",
|
||||
"udn-frontend": "^1.0.2"
|
||||
"udn-frontend": "1.0.4-beta2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "esbuild src/index.tsx --bundle --outdir=dist"
|
||||
|
||||
@@ -3,8 +3,10 @@ import * as React from "bloatless-react";
|
||||
import {
|
||||
isMessageEmpty,
|
||||
lastReceivedMessage,
|
||||
mailboxId,
|
||||
newMessageBody,
|
||||
newMessageChannel,
|
||||
requestMailbox,
|
||||
sendMessage,
|
||||
subscribe,
|
||||
subscriptionChannel,
|
||||
@@ -28,6 +30,22 @@ export function MainScreen() {
|
||||
|
||||
<hr></hr>
|
||||
|
||||
<div class="tile width-input">
|
||||
<div>
|
||||
<b>{getText("mailbox")}</b>
|
||||
<p class="secondary" subscribe:innerText={mailboxId}></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-row width-input justify-end">
|
||||
<button class="primary width-100" on:click={requestMailbox}>
|
||||
{getText("requestMailbox")}
|
||||
<span class="icon">inbox</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr></hr>
|
||||
|
||||
<label class="tile">
|
||||
<div>
|
||||
<span>{getText("subscribeToChannel")}</span>
|
||||
|
||||
+13
-1
@@ -4,7 +4,7 @@ import UDNFrontend from "udn-frontend";
|
||||
import { getText } from "./translations";
|
||||
|
||||
export class Message implements React.Identifiable {
|
||||
uuid = new React.UUID();
|
||||
id = React.UUID();
|
||||
|
||||
constructor(public channel: string, public body: string) {}
|
||||
}
|
||||
@@ -15,6 +15,9 @@ const UDN = new UDNFrontend();
|
||||
UDN.onconnect = () => {
|
||||
isDisconnected.value = false;
|
||||
updateStats();
|
||||
if (mailboxId.value != "") {
|
||||
UDN.accessMailbox(mailboxId.value);
|
||||
}
|
||||
};
|
||||
|
||||
UDN.onmessage = (data) => {
|
||||
@@ -27,6 +30,10 @@ UDN.onmessage = (data) => {
|
||||
}
|
||||
};
|
||||
|
||||
UDN.onmailbox = (id) => {
|
||||
mailboxId.value = id;
|
||||
};
|
||||
|
||||
UDN.ondisconnect = () => {
|
||||
isDisconnected.value = true;
|
||||
setTimeout(connect, 2000);
|
||||
@@ -40,6 +47,7 @@ connect();
|
||||
// STATE
|
||||
// connection
|
||||
export const isDisconnected = new React.State(true);
|
||||
export const mailboxId = React.restoreState("mailbox-id", "");
|
||||
|
||||
// messages
|
||||
export const messages = new React.ListState<Message>();
|
||||
@@ -93,3 +101,7 @@ export function sendMessage() {
|
||||
UDN.sendMessage(newMessageChannel.value, newMessageBody.value);
|
||||
newMessageBody.value = "";
|
||||
}
|
||||
|
||||
export function requestMailbox() {
|
||||
UDN.requestMailbox();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// STATIC
|
||||
export const staticTextEnglish = {
|
||||
mailbox: "Mailbox",
|
||||
requestMailbox: "Request Mailbox",
|
||||
channel: "Channel",
|
||||
channel_placeholder: "my-channel",
|
||||
disconnected: "Server disconnected",
|
||||
@@ -23,6 +25,8 @@ export const staticTextEnglish = {
|
||||
export const translations: { [key: string]: typeof staticTextEnglish } = {
|
||||
en: staticTextEnglish,
|
||||
es: {
|
||||
mailbox: "Buzón",
|
||||
requestMailbox: "Solicitar buzón",
|
||||
channel: "Canal",
|
||||
channel_placeholder: "mi-canal",
|
||||
disconnected: "Sin coneción",
|
||||
@@ -43,6 +47,8 @@ export const translations: { [key: string]: typeof staticTextEnglish } = {
|
||||
unsubscribe: "Cancelar",
|
||||
},
|
||||
de: {
|
||||
mailbox: "Briefkasten",
|
||||
requestMailbox: "Briefkasten beantragen",
|
||||
channel: "Kanal",
|
||||
channel_placeholder: "mein-kanal",
|
||||
disconnected: "Verbindung getrennt",
|
||||
|
||||
Reference in New Issue
Block a user