diff options
Diffstat (limited to 'diplomacy/web/src/gui/forms')
-rw-r--r-- | diplomacy/web/src/gui/forms/connection_form.jsx | 123 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/create_form.jsx | 95 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/find_form.jsx | 70 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/join_form.jsx | 80 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/message_form.jsx | 53 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/power_order_creation_form.jsx | 121 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/select_location_form.jsx | 36 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/select_via_form.jsx | 35 |
8 files changed, 613 insertions, 0 deletions
diff --git a/diplomacy/web/src/gui/forms/connection_form.jsx b/diplomacy/web/src/gui/forms/connection_form.jsx new file mode 100644 index 0000000..eb7e049 --- /dev/null +++ b/diplomacy/web/src/gui/forms/connection_form.jsx @@ -0,0 +1,123 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {UTILS} from "../../diplomacy/utils/utils"; +import PropTypes from "prop-types"; +import {DipStorage} from "../utils/dipStorage"; + +export class ConnectionForm extends React.Component { + constructor(props) { + super(props); + // Load fields values from local storage. + const initialState = this.initState(); + const savedState = DipStorage.getConnectionForm(); + if (savedState) { + if (savedState.hostname) + initialState.hostname = savedState.hostname; + if (savedState.port) + initialState.port = savedState.port; + if (savedState.username) + initialState.username = savedState.username; + if (savedState.showServerFields) + initialState.showServerFields = savedState.showServerFields; + } + this.state = initialState; + this.updateServerFieldsView = this.updateServerFieldsView.bind(this); + this.onChange = this.onChange.bind(this); + } + + initState() { + return { + hostname: window.location.hostname, + port: (window.location.protocol.toLowerCase() === 'https:') ? 8433 : 8432, + username: '', + password: '', + showServerFields: false + }; + } + + updateServerFieldsView() { + DipStorage.setConnectionshowServerFields(!this.state.showServerFields); + this.setState({showServerFields: !this.state.showServerFields}); + } + + onChange(newState) { + const initialState = this.initState(); + if (newState.hostname !== initialState.hostname) + DipStorage.setConnectionHostname(newState.hostname); + else + DipStorage.setConnectionHostname(null); + if (newState.port !== initialState.port) + DipStorage.setConnectionPort(newState.port); + else + DipStorage.setConnectionPort(null); + if (newState.username !== initialState.username) + DipStorage.setConnectionUsername(newState.username); + else + DipStorage.setConnectionUsername(null); + if (this.props.onChange) + this.props.onChange(newState); + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.onChange); + const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit); + return ( + <form> + {Forms.createRow( + Forms.createColLabel('username', 'username:'), + <input className={'form-control'} type={'text'} id={'username'} + value={Forms.getValue(this.state, 'username')} onChange={onChange}/> + )} + {Forms.createRow( + Forms.createColLabel('password', 'password:'), + <input className={'form-control'} type={'password'} id={'password'} + value={Forms.getValue(this.state, 'password')} onChange={onChange}/> + )} + <div> + <div className={this.state.showServerFields ? 'mb-2' : 'mb-4'}> + <span className={'button-server'} onClick={this.updateServerFieldsView}> + server settings {this.state.showServerFields ? UTILS.html.UNICODE_BOTTOM_ARROW : UTILS.html.UNICODE_TOP_ARROW} + </span> + </div> + {this.state.showServerFields && ( + <div className={'mb-4'}> + {Forms.createRow( + <label className={'col'} htmlFor={'hostname'}>hostname:</label>, + <input className={'form-control'} type={'text'} id={'hostname'} + value={Forms.getValue(this.state, 'hostname')} onChange={onChange}/> + )} + {Forms.createRow( + <label className={'col'} htmlFor={'port'}>port:</label>, + <input className={'form-control'} type={'number'} id={'port'} + value={Forms.getValue(this.state, 'port')} + onChange={onChange}/> + )} + </div> + )} + </div> + {Forms.createRow('', Forms.createSubmit('connect', true, onSubmit))} + </form> + ); + } +} + +ConnectionForm.propTypes = { + onChange: PropTypes.func, + onSubmit: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/forms/create_form.jsx b/diplomacy/web/src/gui/forms/create_form.jsx new file mode 100644 index 0000000..6753519 --- /dev/null +++ b/diplomacy/web/src/gui/forms/create_form.jsx @@ -0,0 +1,95 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import PropTypes from "prop-types"; + +export class CreateForm extends React.Component { + constructor(props) { + super(props); + this.state = this.initState(); + } + + initState() { + const state = { + game_id: '', + power_name: '', + n_controls: 7, + deadline: 300, + registration_password: '' + }; + for (let rule of STRINGS.PUBLIC_RULES) + state[`rule_${rule.toLowerCase()}`] = false; + return state; + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.props.onChange); + const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit); + return ( + <form> + {Forms.createRow( + Forms.createColLabel('game_id', 'Game ID (optional)'), + <input id={'game_id'} className={'form-control'} type={'text'} + value={Forms.getValue(this.state, 'game_id')} onChange={onChange}/> + )} + {Forms.createRow( + Forms.createColLabel('power_name', 'power:'), + <select id={'power_name'} className={'form-control custom-select'} + value={Forms.getValue(this.state, 'power_name')} onChange={onChange}> + {Forms.createSelectOptions(STRINGS.ALL_POWER_NAMES, true)} + </select> + )} + {Forms.createRow( + Forms.createColLabel('n_controls', 'number of required players:'), + <input id={'n_controls'} className={'form-control'} type={'number'} + value={Forms.getValue(this.state, 'n_controls')} onChange={onChange}/> + )} + {Forms.createRow( + Forms.createColLabel('deadline', 'deadline (in seconds)'), + <input id={'deadline'} className={'form-control'} type={'number'} + value={Forms.getValue(this.state, 'deadline')} + onChange={onChange}/> + )} + {Forms.createRow( + Forms.createColLabel('registration_password', 'registration password'), + <input id={'registration_password'} className={'form-control'} type={'password'} + value={Forms.getValue(this.state, 'registration_password')} onChange={onChange}/> + )} + <div><strong>RULES:</strong></div> + <div className={'mb-4'}> + {STRINGS.PUBLIC_RULES.map((rule, index) => ( + <div key={index} className={'form-check-inline'}> + {Forms.createCheckbox( + `rule_${rule.toLowerCase()}`, + rule, + Forms.getValue(this.state, `rule_${rule.toLowerCase()}`), + onChange)} + </div> + ))} + </div> + {Forms.createRow('', Forms.createSubmit('create a game', true, onSubmit))} + </form> + ); + } +} + +CreateForm.propTypes = { + onChange: PropTypes.func, + onSubmit: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/forms/find_form.jsx b/diplomacy/web/src/gui/forms/find_form.jsx new file mode 100644 index 0000000..2d67aba --- /dev/null +++ b/diplomacy/web/src/gui/forms/find_form.jsx @@ -0,0 +1,70 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import PropTypes from "prop-types"; + +export class FindForm extends React.Component { + constructor(props) { + super(props); + this.state = this.initState(); + } + + initState() { + return { + game_id: '', + status: '', + include_protected: false, + for_omniscience: false + }; + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.props.onChange); + const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit); + return ( + <form> + {Forms.createRow( + Forms.createColLabel('game_id', 'game id (should contain):'), + <input className={'form-control'} id={'game_id'} type={'text'} + value={Forms.getValue(this.state, 'game_id')} + onChange={onChange}/> + )} + {Forms.createRow( + Forms.createColLabel('status', 'status:'), + (<select className={'form-control custom-select'} + id={'status'} value={Forms.getValue(this.state, 'status')} onChange={onChange}> + {Forms.createSelectOptions(STRINGS.ALL_GAME_STATUSES, true)} + </select>) + )} + <div className={'form-check'}> + {Forms.createCheckbox('include_protected', 'include protected games.', Forms.getValue(this.state, 'include_protected'), onChange)} + </div> + <div className={'form-check mb-4'}> + {Forms.createCheckbox('for_omniscience', 'for omniscience.', Forms.getValue(this.state, 'for_omniscience'), onChange)} + </div> + {Forms.createRow('', Forms.createSubmit('find games', true, onSubmit))} + </form> + ); + } +} + +FindForm.propTypes = { + onChange: PropTypes.func, + onSubmit: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/forms/join_form.jsx b/diplomacy/web/src/gui/forms/join_form.jsx new file mode 100644 index 0000000..e7f8bb2 --- /dev/null +++ b/diplomacy/web/src/gui/forms/join_form.jsx @@ -0,0 +1,80 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import PropTypes from "prop-types"; + +export class JoinForm extends React.Component { + constructor(props) { + super(props); + this.state = this.initState(); + } + + initState() { + return { + [this.getPowerNameID()]: this.getDefaultPowerName(), + [this.getPasswordID()]: '' + }; + } + + getPowerNameID() { + return `power_name_${this.props.game_id}`; + } + + getPasswordID() { + return `registration_password_${this.props.game_id}`; + } + + getDefaultPowerName() { + return (this.props.powers && this.props.powers.length && this.props.powers[0]) || ''; + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.props.onChange); + const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit); + return ( + <form className={'form-inline'}> + <div className={'form-group mr-2'}> + {Forms.createLabel(this.getPowerNameID(), 'Power:')} + <select id={this.getPowerNameID()} className={'from-control custom-select ml-2'} + value={Forms.getValue(this.state, this.getPowerNameID())} onChange={onChange}> + {Forms.createSelectOptions(STRINGS.ALL_POWER_NAMES, true)} + </select> + </div> + {this.props.password_required ? ( + <div className={'form-group mr-2'}> + {Forms.createLabel(this.getPasswordID(), '', 'sr-only')} + <input id={this.getPasswordID()} type={'password'} className={'form-control'} + placeholder={'registration password'} + value={Forms.getValue(this.state, this.getPasswordID())} + onChange={onChange}/> + </div> + ) : ''} + {Forms.createSubmit('join', false, onSubmit)} + </form> + ); + } +} + +JoinForm.propTypes = { + game_id: PropTypes.string.isRequired, + password_required: PropTypes.bool.isRequired, + powers: PropTypes.arrayOf(PropTypes.string), + onChange: PropTypes.func, + onSubmit: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/forms/message_form.jsx b/diplomacy/web/src/gui/forms/message_form.jsx new file mode 100644 index 0000000..d91a753 --- /dev/null +++ b/diplomacy/web/src/gui/forms/message_form.jsx @@ -0,0 +1,53 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {UTILS} from "../../diplomacy/utils/utils"; +import PropTypes from "prop-types"; + +export class MessageForm extends React.Component { + constructor(props) { + super(props); + this.state = this.initState(); + } + + initState() { + return {message: ''}; + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.props.onChange); + const onSubmit = Forms.createOnSubmitCallback(this, this.props.onSubmit, this.initState()); + return ( + <form> + <div className={'form-group'}> + {Forms.createLabel('message', '', 'sr-only')} + <textarea id={'message'} className={'form-control'} + value={Forms.getValue(this.state, 'message')} onChange={onChange}/> + </div> + {Forms.createSubmit(`send (${this.props.sender} ${UTILS.html.UNICODE_SMALL_RIGHT_ARROW} ${this.props.recipient})`, true, onSubmit)} + </form> + ); + } +} + +MessageForm.propTypes = { + sender: PropTypes.string, + recipient: PropTypes.string, + onChange: PropTypes.func, + onSubmit: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/forms/power_order_creation_form.jsx b/diplomacy/web/src/gui/forms/power_order_creation_form.jsx new file mode 100644 index 0000000..f15fff8 --- /dev/null +++ b/diplomacy/web/src/gui/forms/power_order_creation_form.jsx @@ -0,0 +1,121 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from 'react'; +import {Forms} from "../components/forms"; +import {ORDER_BUILDER} from "../utils/order_building"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import PropTypes from "prop-types"; +import {Power} from "../../diplomacy/engine/power"; + +const HotKey = require('react-shortcut'); + +export class PowerOrderCreationForm extends React.Component { + constructor(props) { + super(props); + this.state = this.initState(); + } + + initState() { + return {order_type: this.props.orderType}; + } + + render() { + const onChange = Forms.createOnChangeCallback(this, this.props.onChange); + const onReset = Forms.createOnResetCallback(this, this.props.onChange, this.initState()); + const onSetOrderType = (letter) => { + this.setState({order_type: letter}, () => { + if (this.props.onChange) + this.props.onChange(this.state); + }); + }; + let title = ''; + let titleClass = 'mr-4'; + const header = []; + const votes = []; + if (this.props.orderTypes.length) { + title = 'Create order:'; + header.push(...this.props.orderTypes.map((orderLetter, index) => ( + <div key={index} className={'form-check-inline'}> + {Forms.createRadio('order_type', orderLetter, ORDER_BUILDER[orderLetter].name, this.props.orderType, onChange)} + </div> + ))); + header.push(Forms.createReset('reset', false, onReset)); + } else if (this.props.power.order_is_set) { + title = 'Unorderable power (already locked on server).'; + titleClass += ' neutral'; + } else { + title = 'No orders available for this power.'; + } + if (!this.props.power.order_is_set) { + header.push(Forms.createButton('pass', this.props.onPass)); + } + + if (this.props.role !== STRINGS.OMNISCIENT_TYPE) { + votes.push(<strong key={0} className={'ml-4 mr-2'}>Vote for draw:</strong>); + switch (this.props.power.vote) { + case 'yes': + votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger')); + votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info')); + break; + case 'no': + votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success')); + votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info')); + break; + case 'neutral': + votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success')); + votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger')); + break; + default: + votes.push(Forms.createButton('yes', () => this.props.onVote('yes'), 'success')); + votes.push(Forms.createButton('no', () => this.props.onVote('no'), 'danger')); + votes.push(Forms.createButton('neutral', () => this.props.onVote('neutral'), 'info')); + break; + } + } + return ( + <div> + <div><strong key={'title'} className={titleClass}>{title}</strong></div> + <form className={'form-inline power-actions-form'}> + {header} + {Forms.createButton( + (this.props.power.wait ? 'no wait' : 'wait'), + this.props.onSetWaitFlag, + (this.props.power.wait ? 'success' : 'danger') + )} + {votes} + <HotKey keys={['escape']} onKeysCoincide={onReset}/> + {this.props.orderTypes.map((letter, index) => ( + <HotKey key={index} keys={[letter.toLowerCase()]} + onKeysCoincide={() => onSetOrderType(letter)}/> + ))} + </form> + </div> + ); + } +} + +PowerOrderCreationForm.propTypes = { + orderType: PropTypes.oneOf(Object.keys(ORDER_BUILDER)), + orderTypes: PropTypes.arrayOf(PropTypes.oneOf(Object.keys(ORDER_BUILDER))), + power: PropTypes.instanceOf(Power), + role: PropTypes.string, + onChange: PropTypes.func, + onSubmit: PropTypes.func, + onPass: PropTypes.func, // onPass(), to submit empty orders set (powers want to do nothing at this phase) + onVote: PropTypes.func, // onVote(voteString) + onSetWaitFlag: PropTypes.func, // onSetWaitFlag(), +}; diff --git a/diplomacy/web/src/gui/forms/select_location_form.jsx b/diplomacy/web/src/gui/forms/select_location_form.jsx new file mode 100644 index 0000000..ca7be09 --- /dev/null +++ b/diplomacy/web/src/gui/forms/select_location_form.jsx @@ -0,0 +1,36 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import PropTypes from "prop-types"; +import {Button} from "../components/button"; + +export class SelectLocationForm extends React.Component { + render() { + return ( + <div> + {this.props.locations.map((location, index) => ( + <Button key={index} title={location} large={true} onClick={() => this.props.onSelect(location)}/> + ))} + </div> + ); + } +} + +SelectLocationForm.propTypes = { + locations: PropTypes.arrayOf(PropTypes.string).isRequired, + onSelect: PropTypes.func.isRequired // onSelect(location) +}; diff --git a/diplomacy/web/src/gui/forms/select_via_form.jsx b/diplomacy/web/src/gui/forms/select_via_form.jsx new file mode 100644 index 0000000..b779b8d --- /dev/null +++ b/diplomacy/web/src/gui/forms/select_via_form.jsx @@ -0,0 +1,35 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import PropTypes from "prop-types"; +import {Button} from "../components/button"; + +export class SelectViaForm extends React.Component { + render() { + return ( + <div> + <Button title={'regular move (M)'} large={true} onClick={() => this.props.onSelect('M')}/> + <Button title={'move via (V)'} large={true} onClick={() => this.props.onSelect('V')}/> + </div> + ); + } +} + +SelectViaForm.propTypes = { + onSelect: PropTypes.func.isRequired +}; + |