Add dialog for join form

This commit is contained in:
Simon Ser 2021-03-08 16:23:16 +01:00
parent 996d7d06d4
commit 30157383e8
4 changed files with 165 additions and 10 deletions

View file

@ -5,8 +5,10 @@ import BufferList from "./buffer-list.js";
import BufferHeader from "./buffer-header.js";
import MemberList from "./member-list.js";
import Connect from "./connect.js";
import Join from "./join.js";
import Composer from "./composer.js";
import ScrollManager from "./scroll-manager.js";
import Dialog from "./dialog.js";
import { html, Component, createRef } from "../lib/index.js";
import { strip as stripANSI } from "../lib/ansi.js";
import { SERVER_BUFFER, BufferType, ReceiptType, NetworkStatus, Unread } from "../state.js";
@ -151,6 +153,7 @@ export default class App extends Component {
networks: new Map(),
buffers: new Map(),
activeBuffer: null,
dialog: null,
error: null,
};
clients = new Map();
@ -165,11 +168,13 @@ export default class App extends Component {
super(props);
this.handleConnectSubmit = this.handleConnectSubmit.bind(this);
this.handleJoinSubmit = this.handleJoinSubmit.bind(this);
this.handleBufferListClick = this.handleBufferListClick.bind(this);
this.handleComposerSubmit = this.handleComposerSubmit.bind(this);
this.handleNickClick = this.handleNickClick.bind(this);
this.autocomplete = this.autocomplete.bind(this);
this.handleBufferScrollTop = this.handleBufferScrollTop.bind(this);
this.handleDialogDismiss = this.handleDialogDismiss.bind(this);
this.dismissError = this.dismissError.bind(this);
this.saveReceipts = debounce(this.saveReceipts.bind(this), 500);
@ -833,14 +838,15 @@ export default class App extends Component {
}
handleJoinClick(netID) {
var channel = prompt("Join channel:");
if (!channel) {
return;
}
this.setState({ dialog: "join", joinDialog: { network: netID } });
}
var client = this.clients.get(netID);
handleJoinSubmit(data) {
var client = this.clients.get(this.state.joinDialog.network);
client.send({ command: "JOIN", params: [channel] });
client.send({ command: "JOIN", params: [data.channel] });
this.setState({ dialog: null, joinDialog: null });
}
autocomplete(prefix) {
@ -903,6 +909,10 @@ export default class App extends Component {
});
}
handleDialogDismiss() {
this.setState({ dialog: null });
}
componentDidMount() {
if (this.state.connectParams.autoconnect) {
this.connect(this.state.connectParams);
@ -947,6 +957,17 @@ export default class App extends Component {
`;
}
var dialog = null;
switch (this.state.dialog) {
case "join":
dialog = html`
<${Dialog} title="Join channel" onDismiss=${this.handleDialogDismiss}>
<${Join} onSubmit=${this.handleJoinSubmit}/>
</>
`;
break;
}
var error = null;
if (this.state.error) {
error = html`
@ -966,6 +987,7 @@ export default class App extends Component {
</>
${memberList}
<${Composer} ref=${this.composer} readOnly=${activeBuffer && activeBuffer.type == BufferType.SERVER} onSubmit=${this.handleComposerSubmit} autocomplete=${this.autocomplete}/>
${dialog}
${error}
`;
}

61
components/dialog.js Normal file
View file

@ -0,0 +1,61 @@
import { html, Component, createRef } from "../lib/index.js";
export default class Dialog extends Component {
body = createRef();
constructor(props) {
super(props);
this.handleCloseClick = this.handleCloseClick.bind(this);
this.handleBackdropClick = this.handleBackdropClick.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
}
dismiss() {
this.props.onDismiss();
}
handleCloseClick(event) {
event.preventDefault();
this.dismiss();
}
handleBackdropClick(event) {
if (event.target.className == "dialog") {
this.dismiss();
}
}
handleKeyDown(event) {
if (event.key == "Escape") {
this.dismiss();
}
}
componentDidMount() {
window.addEventListener("keydown", this.handleKeyDown);
var autofocus = this.body.current.querySelector("input[autofocus]");
if (autofocus) {
autofocus.focus();
}
}
componentWillUnmount() {
window.removeEventListener("keydown", this.handleKeyDown);
}
render() {
return html`
<div class="dialog" onClick=${this.handleBackdropClick}>
<div class="dialog-body" ref=${this.body}>
<div class="dialog-header">
<a href="#" class="dialog-close" onClick=${this.handleCloseClick}>×</span>
<h2>${this.props.title}</h2>
</div>
${this.props.children}
</div>
</div>
`;
}
}

45
components/join.js Normal file
View file

@ -0,0 +1,45 @@
import { html, Component } from "../lib/index.js";
export default class Join extends Component {
state = {
channel: "#",
};
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
var target = event.target;
var value = target.type == "checkbox" ? target.checked : target.value;
this.setState({ [target.name]: value });
}
handleSubmit(event) {
event.preventDefault();
var params = {
channel: this.state.channel,
};
this.props.onSubmit(params);
}
render() {
return html`
<form onChange=${this.handleChange} onSubmit=${this.handleSubmit}>
<label>
Channel:<br/>
<input type="text" name="channel" value=${this.state.channel} autofocus required/>
</label>
<br/>
<br/>
<button>Join</button>
</form>
`;
}
}

View file

@ -136,10 +136,11 @@ body {
margin: 0 auto;
max-width: 300px;
}
#connect input[type="text"],
#connect input[type="username"],
#connect input[type="password"],
#connect input[type="url"] {
form input[type="text"],
form input[type="username"],
form input[type="password"],
form input[type="url"] {
box-sizing: border-box;
width: 100%;
}
@ -274,3 +275,29 @@ details summary {
.error-text {
color: red;
}
.dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
}
.dialog .dialog-body {
background-color: white;
margin: auto;
margin-top: 20px;
max-width: 500px;
padding: 15px;
border: 1px solid rgba(0, 0, 0, 0.6);
}
.dialog a.dialog-close {
float: right;
text-decoration: none;
font-size: 1.5em;
color: inherit;
}
.dialog h2 {
margin-top: 0;
}