;
}
on_name_change(event) {
this.setState({name: event.target.value});
}
on_parent_change(items) {
let item = items[0] || {};
this.setState({parent: item.name || '', parent_id: item.id || null});
}
add_field(event) {
event.preventDefault();
this.setState({fields: [...this.state.fields, {name: '', value: ''}], validated: false});
}
remove_field(event) {
let fields = [...this.state.fields];
fields.splice(event.target.dataset.index, 1);
this.setState({fields: fields, validated: false});
}
on_field_change(event) {
const index = event.target.dataset.index;
let fields = [...this.state.fields];
let field = {...this.state.fields[index]};
field[event.target.dataset.field] = event.target.value;
fields[index] = field;
this.setState({fields: fields, validated: false});
}
async on_parents_search(q) {
this.setState({parents_searching: true});
let token = await this.context.get_token();
let response = await fetch('/api/search', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/x-www-form-urlencoded',
},
body: 'q=' + encodeURIComponent(q),
});
let data = await response.json();
this.setState({parents: data, parents_searching: false});
}
validate() {
let errors = {};
if (this.state.name === '') {
errors.name = 'Name must be specified';
}
if (this.state.parent !== '' && this.state.parent_id === null) {
errors.parent = 'Parent must be empty or set to a valid value';
}
this.state.fields.forEach(function(field, index) {
if (field.name === '') {
errors[`field-${index}-name`] = 'Name must be specified';
}
if (field.value === '') {
errors[`field-${index}-value`] = 'Value must be specified';
}
});
this.setState({validated: true, errors: errors});
// Clear existing errors
document.querySelectorAll('form :invalid').forEach(e => e.setCustomValidity(''));
for (let key in errors) {
document.getElementById(key).setCustomValidity(errors[key]);
}
if (errors.length > 0) {
return false;
}
return true;
}
}
class ViewNode extends React.Component {
static contextType = UserContext;
constructor(props) {
super(props);
let node = null;
if (props.location.state !== undefined) {
node = props.location.state.node;
}
this.state = {
ready: node !== null,
node: node,
};
this.mounted = false;
this.loading_id = null;
this.load_abort = null;
this.load_signal = null;
}
async componentDidMount() {
this.mounted = true;
try {
await this.load();
} catch (error) {
if (!(error instanceof DOMException && error.code === 20)) {
throw error;
}
}
}
componentWillUnmount() {
this.mounted = false;
}
async componentDidUpdate() {
// Set and reload if we have received a new node in the location state
if (this.state.node !== null && this.props.location.state !== undefined && this.props.location.state.node !== null
&& this.state.node.id !== this.props.location.state.node.id) {
this.setState({node: this.props.location.state.node});
try {
await this.load();
} catch (error) {
if (!(error instanceof DOMException && error.code === 20)) {
throw error;
}
}
}
// Load if the current node is not set, or if the node's id does not match the param id
if (this.state.node === null || this.props.match.params.id !== this.state.node.id) {
try {
await this.load();
} catch (error) {
if (!(error instanceof DOMException && error.code === 20)) {
throw error;
}
}
}
}
render() {
if (!this.state.ready) {
return Loading…;
}
return ;
}
async load() {
if (!this.mounted || this.loading_id === this.props.match.params.id) {
return;
}
if (this.load_abort !== null && !this.load_signal.aborted) {
this.load_abort.abort();
}
let abort = this.load_abort = new AbortController();
let signal = this.load_signal = abort.signal;
this.loading_id = this.props.match.params.id;
if (this.state.node === null && this.state.ready) {
this.setState({ready: false});
}
const token = await this.context.get_token();
let response = await fetch(`/api/nodes/${this.props.match.params.id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
signal: signal,
});
const node = await response.json();
if (signal.aborted) {
return;
}
set_children_parents(node);
if (this.mounted && node.id === this.props.match.params.id) {
this.setState({node: node, ready: true});
}
}
}
class UserHome extends React.Component {
static contextType = UserContext;
constructor(props) {
super(props);
this.state = {
ready: false,
nodes: [],
};
}
async componentDidMount() {
const token = await this.context.get_token()
let response = await fetch('/api/nodes', {
headers: {
Authorization: `Bearer ${token}`,
}
});
const nodes = await response.json();
nodes.forEach(set_children_parents);
this.setState({nodes: nodes, ready: true});
}
render() {
if (!this.state.ready) {
return Loading…;
}
return
{this.state.nodes.map(item => )}
;
}
}
function Main() {
const user = useContext(UserContext);
if (user.is_logged_in) {
return ;
}
return
Unmess
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla pharetra fringilla dolor, sed tempor est. Maecenas malesuada feugiat nisl ut hendrerit. Donec faucibus augue quis mi fermentum, ac tempus neque dignissim. Nullam egestas bibendum enim, at feugiat lorem consectetur eu. Ut faucibus, dolor gravida ultricies malesuada, leo ex volutpat turpis, at placerat lectus mauris ut tortor. Phasellus sit amet lorem laoreet nunc sollicitudin pharetra. Pellentesque laoreet est lacinia velit porta aliquam ut quis sem. Sed vel convallis purus. Nunc elementum fermentum leo sit amet elementum.