diff options
author | notoraptor <notoraptor@users.noreply.github.com> | 2019-07-17 15:16:43 -0400 |
---|---|---|
committer | Philip Paquette <pcpaquette@gmail.com> | 2019-07-17 15:16:43 -0400 |
commit | 2701df1e3b03c7c605ccf212a02987d53fbd0609 (patch) | |
tree | d3637573d8585e32914c33cbd03ec0baf9c68ae3 /diplomacy/web | |
parent | e9872eea32d4f66b9c7ca8c14d530c18f6c18506 (diff) |
[web] Make button "Delete all" remove only orders from current se… (#49)
- Make button "Delete all" remove only orders from current selected power.
- Reorganize code
- [web] Remove bugged and useless function gameReloaded() from game page.
- This function caused error `engine.getPhaseType is not a function` for
games with deadlines.
- Move function saveGameToDisk into its own file.
- [web] Add documentation to methods involved in orders management to help understand what happens.
- Move methods getServerOrders() from game GUI component to game engine object.
- Rename method onSetNoOrders to onSetEmptyOrdersSet.
- Rename property in PowerActionsForm: onNoOrders => onPass.
- [web] Update sending orders to send request clearOrders when local orders list is null.
- Renamed local file:
- components/power_order => power_orders
- forms/power_actions_form => power_order_creation_form
- Move power orders buttons bar to a separate file:
- components/power_orders_actions_bar
- [web] Improve messages about local/server defined orders.
Diffstat (limited to 'diplomacy/web')
-rw-r--r-- | diplomacy/web/src/diplomacy/engine/game.js | 24 | ||||
-rw-r--r-- | diplomacy/web/src/diplomacy/utils/diplog.js | 2 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/action.jsx (renamed from diplomacy/web/src/gui/core/action.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/button.jsx (renamed from diplomacy/web/src/gui/core/button.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/delete_button.jsx (renamed from diplomacy/web/src/gui/core/delete_button.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/fancybox.jsx (renamed from diplomacy/web/src/gui/core/fancybox.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/forms.jsx (renamed from diplomacy/web/src/gui/core/forms.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/help.jsx (renamed from diplomacy/web/src/gui/diplomacy/widgets/help.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/layouts.jsx (renamed from diplomacy/web/src/gui/core/layouts.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/message_view.jsx (renamed from diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/navigation.jsx (renamed from diplomacy/web/src/gui/diplomacy/widgets/navigation.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/page_context.jsx (renamed from diplomacy/web/src/gui/diplomacy/widgets/page_context.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/power_orders.jsx (renamed from diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx) | 10 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/power_orders_actions_bar.js | 26 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/tab.jsx (renamed from diplomacy/web/src/gui/core/tab.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/table.jsx (renamed from diplomacy/web/src/gui/core/table.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/components/tabs.jsx (renamed from diplomacy/web/src/gui/core/tabs.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/connection_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/create_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/create_form.jsx) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/find_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/find_form.jsx) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/join_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/join_form.jsx) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/message_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/message_form.jsx) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/power_order_creation_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx) | 14 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/select_location_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx) | 2 | ||||
-rw-r--r-- | diplomacy/web/src/gui/forms/select_via_form.jsx (renamed from diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx) | 2 | ||||
-rw-r--r-- | diplomacy/web/src/gui/map/dom_order_builder.js (renamed from diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/map/dom_past_map.js (renamed from diplomacy/web/src/gui/diplomacy/map/dom_past_map.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/map/map.jsx (renamed from diplomacy/web/src/gui/diplomacy/map/map.jsx) | 2 | ||||
-rw-r--r-- | diplomacy/web/src/gui/map/renderer.js (renamed from diplomacy/web/src/gui/diplomacy/map/renderer.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/pages/content_connection.jsx (renamed from diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx) | 6 | ||||
-rw-r--r-- | diplomacy/web/src/gui/pages/content_game.jsx (renamed from diplomacy/web/src/gui/diplomacy/contents/content_game.jsx) | 385 | ||||
-rw-r--r-- | diplomacy/web/src/gui/pages/content_games.jsx (renamed from diplomacy/web/src/gui/diplomacy/contents/content_games.jsx) | 12 | ||||
-rw-r--r-- | diplomacy/web/src/gui/pages/page.jsx (renamed from diplomacy/web/src/gui/core/page.jsx) | 14 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/dipStorage.jsx (renamed from diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/inline_game_view.jsx (renamed from diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx) | 8 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/load_game_from_disk.js (renamed from diplomacy/web/src/gui/diplomacy/utils/load_game_from_disk.js) | 4 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/map_data.js (renamed from diplomacy/web/src/gui/diplomacy/utils/map_data.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/order.js (renamed from diplomacy/web/src/gui/diplomacy/utils/order.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/order_building.js (renamed from diplomacy/web/src/gui/diplomacy/utils/order_building.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/power_view.jsx (renamed from diplomacy/web/src/gui/diplomacy/utils/power_view.jsx) | 2 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/province.js (renamed from diplomacy/web/src/gui/diplomacy/utils/province.js) | 0 | ||||
-rw-r--r-- | diplomacy/web/src/gui/utils/saveGameToDisk.js | 18 | ||||
-rw-r--r-- | diplomacy/web/src/index.js | 2 |
43 files changed, 328 insertions, 229 deletions
diff --git a/diplomacy/web/src/diplomacy/engine/game.js b/diplomacy/web/src/diplomacy/engine/game.js index 93da77c..e44fdf6 100644 --- a/diplomacy/web/src/diplomacy/engine/game.js +++ b/diplomacy/web/src/diplomacy/engine/game.js @@ -19,6 +19,7 @@ import {STRINGS} from "../utils/strings"; import {SortedDict} from "../utils/sorted_dict"; import {Power} from "./power"; import {Message} from "./message"; +import {Order} from "../../gui/utils/order"; export function comparablePhase(shortPhaseName) { /** Return a unique integer corresponding to given short phase name, so that @@ -420,6 +421,29 @@ export class Game { return [this.role]; } + getServerOrders() { + /** Return a dictionary of server orders. + * Returned dictionary maps each power name to either: + * - a dictionary of orders, mapping a loc to an Order object with boolean flag `local` set to false. + * - an empty dictionary, to represent an empty orders set. + * - null value, if power.order_is_set is false. + * **/ + const orders = {}; + const controllablePowers = this.getControllablePowers(); + for (let powerName of controllablePowers) { + const powerOrders = {}; + let countOrders = 0; + const power = this.powers[powerName]; + for (let orderString of power.orders) { + const serverOrder = new Order(orderString, false); + powerOrders[serverOrder.loc] = serverOrder; + ++countOrders; + } + orders[powerName] = (countOrders || power.order_is_set) ? powerOrders : null; + } + return orders; + } + getMessageChannels(role, all) { const messageChannels = {}; role = role || this.role; diff --git a/diplomacy/web/src/diplomacy/utils/diplog.js b/diplomacy/web/src/diplomacy/utils/diplog.js index 1e4a753..261a8f4 100644 --- a/diplomacy/web/src/diplomacy/utils/diplog.js +++ b/diplomacy/web/src/diplomacy/utils/diplog.js @@ -25,7 +25,7 @@ export class Diplog { } static info(msg) { - console.info(msg); + console.log(msg); } static success(msg) { diff --git a/diplomacy/web/src/gui/core/action.jsx b/diplomacy/web/src/gui/components/action.jsx index 73fe8cb..73fe8cb 100644 --- a/diplomacy/web/src/gui/core/action.jsx +++ b/diplomacy/web/src/gui/components/action.jsx diff --git a/diplomacy/web/src/gui/core/button.jsx b/diplomacy/web/src/gui/components/button.jsx index 0d5dadd..0d5dadd 100644 --- a/diplomacy/web/src/gui/core/button.jsx +++ b/diplomacy/web/src/gui/components/button.jsx diff --git a/diplomacy/web/src/gui/core/delete_button.jsx b/diplomacy/web/src/gui/components/delete_button.jsx index 59141fd..59141fd 100644 --- a/diplomacy/web/src/gui/core/delete_button.jsx +++ b/diplomacy/web/src/gui/components/delete_button.jsx diff --git a/diplomacy/web/src/gui/core/fancybox.jsx b/diplomacy/web/src/gui/components/fancybox.jsx index 66a1efe..66a1efe 100644 --- a/diplomacy/web/src/gui/core/fancybox.jsx +++ b/diplomacy/web/src/gui/components/fancybox.jsx diff --git a/diplomacy/web/src/gui/core/forms.jsx b/diplomacy/web/src/gui/components/forms.jsx index da7250d..da7250d 100644 --- a/diplomacy/web/src/gui/core/forms.jsx +++ b/diplomacy/web/src/gui/components/forms.jsx diff --git a/diplomacy/web/src/gui/diplomacy/widgets/help.jsx b/diplomacy/web/src/gui/components/help.jsx index 1ec1a54..1ec1a54 100644 --- a/diplomacy/web/src/gui/diplomacy/widgets/help.jsx +++ b/diplomacy/web/src/gui/components/help.jsx diff --git a/diplomacy/web/src/gui/core/layouts.jsx b/diplomacy/web/src/gui/components/layouts.jsx index 78189e4..78189e4 100644 --- a/diplomacy/web/src/gui/core/layouts.jsx +++ b/diplomacy/web/src/gui/components/layouts.jsx diff --git a/diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx b/diplomacy/web/src/gui/components/message_view.jsx index 927ff52..927ff52 100644 --- a/diplomacy/web/src/gui/diplomacy/widgets/message_view.jsx +++ b/diplomacy/web/src/gui/components/message_view.jsx diff --git a/diplomacy/web/src/gui/diplomacy/widgets/navigation.jsx b/diplomacy/web/src/gui/components/navigation.jsx index 5d961bc..5d961bc 100644 --- a/diplomacy/web/src/gui/diplomacy/widgets/navigation.jsx +++ b/diplomacy/web/src/gui/components/navigation.jsx diff --git a/diplomacy/web/src/gui/diplomacy/widgets/page_context.jsx b/diplomacy/web/src/gui/components/page_context.jsx index cfb8252..cfb8252 100644 --- a/diplomacy/web/src/gui/diplomacy/widgets/page_context.jsx +++ b/diplomacy/web/src/gui/components/page_context.jsx diff --git a/diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx b/diplomacy/web/src/gui/components/power_orders.jsx index 4ed4d8a..b702a9d 100644 --- a/diplomacy/web/src/gui/diplomacy/widgets/power_order.jsx +++ b/diplomacy/web/src/gui/components/power_orders.jsx @@ -16,9 +16,9 @@ // ============================================================================== import React from "react"; import PropTypes from 'prop-types'; -import {Button} from "../../core/button"; +import {Button} from "./button"; -export class PowerOrder extends React.Component { +export class PowerOrders extends React.Component { render() { const orderEntries = this.props.orders ? Object.entries(this.props.orders) : null; let display = null; @@ -50,10 +50,8 @@ export class PowerOrder extends React.Component { } else { if (this.props.serverCount < 0) { display = <div className={'no-orders'}>No orders!</div>; - } else if (this.props.serverCount === 0) { - display = <div className={'empty-orders'}>Empty orders set</div>; } else { - display = (<div className={'empty-orders'}>Local empty orders set</div>); + display = <div className={'empty-orders'}>Asking to unset orders</div>; } } return ( @@ -70,7 +68,7 @@ export class PowerOrder extends React.Component { } } -PowerOrder.propTypes = { +PowerOrders.propTypes = { wait: PropTypes.bool, name: PropTypes.string, orders: PropTypes.object, diff --git a/diplomacy/web/src/gui/components/power_orders_actions_bar.js b/diplomacy/web/src/gui/components/power_orders_actions_bar.js new file mode 100644 index 0000000..2e33a6e --- /dev/null +++ b/diplomacy/web/src/gui/components/power_orders_actions_bar.js @@ -0,0 +1,26 @@ +import React from 'react'; +import {Button} from "./button"; +import {Bar} from "./layouts"; +import PropTypes from 'prop-types'; + +export class PowerOrdersActionBar extends React.Component { + render() { + return ( + <Bar className={'p-2'}> + <strong className={'mr-4'}>Orders:</strong> + <Button title={'reset'} onClick={this.props.onReset}/> + <Button title={'delete all'} onClick={this.props.onDeleteAll}/> + <Button color={'primary'} title={'update'} onClick={this.props.onUpdate}/> + {(!this.props.onProcess && + <Button color={'danger'} title={'process game'} onClick={this.props.onProcess}/>) || ''} + </Bar> + ); + } +} + +PowerOrdersActionBar.propTypes = { + onReset: PropTypes.func.isRequired, + onDeleteAll: PropTypes.func.isRequired, + onUpdate: PropTypes.func.isRequired, + onProcess: PropTypes.func +}; diff --git a/diplomacy/web/src/gui/core/tab.jsx b/diplomacy/web/src/gui/components/tab.jsx index f1ad4aa..f1ad4aa 100644 --- a/diplomacy/web/src/gui/core/tab.jsx +++ b/diplomacy/web/src/gui/components/tab.jsx diff --git a/diplomacy/web/src/gui/core/table.jsx b/diplomacy/web/src/gui/components/table.jsx index cb729e7..cb729e7 100644 --- a/diplomacy/web/src/gui/core/table.jsx +++ b/diplomacy/web/src/gui/components/table.jsx diff --git a/diplomacy/web/src/gui/core/tabs.jsx b/diplomacy/web/src/gui/components/tabs.jsx index a3f6b9b..a3f6b9b 100644 --- a/diplomacy/web/src/gui/core/tabs.jsx +++ b/diplomacy/web/src/gui/components/tabs.jsx diff --git a/diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx b/diplomacy/web/src/gui/forms/connection_form.jsx index 49ba381..eb7e049 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/connection_form.jsx +++ b/diplomacy/web/src/gui/forms/connection_form.jsx @@ -15,8 +15,8 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; -import {UTILS} from "../../../diplomacy/utils/utils"; +import {Forms} from "../components/forms"; +import {UTILS} from "../../diplomacy/utils/utils"; import PropTypes from "prop-types"; import {DipStorage} from "../utils/dipStorage"; diff --git a/diplomacy/web/src/gui/diplomacy/forms/create_form.jsx b/diplomacy/web/src/gui/forms/create_form.jsx index 48c733e..6753519 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/create_form.jsx +++ b/diplomacy/web/src/gui/forms/create_form.jsx @@ -15,8 +15,8 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; -import {STRINGS} from "../../../diplomacy/utils/strings"; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; import PropTypes from "prop-types"; export class CreateForm extends React.Component { diff --git a/diplomacy/web/src/gui/diplomacy/forms/find_form.jsx b/diplomacy/web/src/gui/forms/find_form.jsx index c73d2b1..2d67aba 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/find_form.jsx +++ b/diplomacy/web/src/gui/forms/find_form.jsx @@ -15,8 +15,8 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; -import {STRINGS} from "../../../diplomacy/utils/strings"; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; import PropTypes from "prop-types"; export class FindForm extends React.Component { diff --git a/diplomacy/web/src/gui/diplomacy/forms/join_form.jsx b/diplomacy/web/src/gui/forms/join_form.jsx index 5b3ec13..e7f8bb2 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/join_form.jsx +++ b/diplomacy/web/src/gui/forms/join_form.jsx @@ -15,8 +15,8 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; -import {STRINGS} from "../../../diplomacy/utils/strings"; +import {Forms} from "../components/forms"; +import {STRINGS} from "../../diplomacy/utils/strings"; import PropTypes from "prop-types"; export class JoinForm extends React.Component { diff --git a/diplomacy/web/src/gui/diplomacy/forms/message_form.jsx b/diplomacy/web/src/gui/forms/message_form.jsx index a7c377a..d91a753 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/message_form.jsx +++ b/diplomacy/web/src/gui/forms/message_form.jsx @@ -15,8 +15,8 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; -import {UTILS} from "../../../diplomacy/utils/utils"; +import {Forms} from "../components/forms"; +import {UTILS} from "../../diplomacy/utils/utils"; import PropTypes from "prop-types"; export class MessageForm extends React.Component { diff --git a/diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx b/diplomacy/web/src/gui/forms/power_order_creation_form.jsx index 2f7c1f5..f15fff8 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/power_actions_form.jsx +++ b/diplomacy/web/src/gui/forms/power_order_creation_form.jsx @@ -15,15 +15,15 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Forms} from "../../core/forms"; +import {Forms} from "../components/forms"; import {ORDER_BUILDER} from "../utils/order_building"; -import {STRINGS} from "../../../diplomacy/utils/strings"; +import {STRINGS} from "../../diplomacy/utils/strings"; import PropTypes from "prop-types"; -import {Power} from "../../../diplomacy/engine/power"; +import {Power} from "../../diplomacy/engine/power"; const HotKey = require('react-shortcut'); -export class PowerActionsForm extends React.Component { +export class PowerOrderCreationForm extends React.Component { constructor(props) { super(props); this.state = this.initState(); @@ -61,7 +61,7 @@ export class PowerActionsForm extends React.Component { title = 'No orders available for this power.'; } if (!this.props.power.order_is_set) { - header.push(Forms.createButton('pass', this.props.onNoOrders)); + header.push(Forms.createButton('pass', this.props.onPass)); } if (this.props.role !== STRINGS.OMNISCIENT_TYPE) { @@ -108,14 +108,14 @@ export class PowerActionsForm extends React.Component { } } -PowerActionsForm.propTypes = { +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, - onNoOrders: PropTypes.func, // onNoOrders() + 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/diplomacy/forms/select_location_form.jsx b/diplomacy/web/src/gui/forms/select_location_form.jsx index 6b966d0..ca7be09 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/select_location_form.jsx +++ b/diplomacy/web/src/gui/forms/select_location_form.jsx @@ -16,7 +16,7 @@ // ============================================================================== import React from "react"; import PropTypes from "prop-types"; -import {Button} from "../../core/button"; +import {Button} from "../components/button"; export class SelectLocationForm extends React.Component { render() { diff --git a/diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx b/diplomacy/web/src/gui/forms/select_via_form.jsx index 51f3306..b779b8d 100644 --- a/diplomacy/web/src/gui/diplomacy/forms/select_via_form.jsx +++ b/diplomacy/web/src/gui/forms/select_via_form.jsx @@ -16,7 +16,7 @@ // ============================================================================== import React from "react"; import PropTypes from "prop-types"; -import {Button} from "../../core/button"; +import {Button} from "../components/button"; export class SelectViaForm extends React.Component { render() { diff --git a/diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js b/diplomacy/web/src/gui/map/dom_order_builder.js index 8b7072e..14ba743 100644 --- a/diplomacy/web/src/gui/diplomacy/map/dom_order_builder.js +++ b/diplomacy/web/src/gui/map/dom_order_builder.js @@ -14,10 +14,10 @@ // 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 {UTILS} from "../../../diplomacy/utils/utils"; +import {UTILS} from "../../diplomacy/utils/utils"; import $ from "jquery"; import {extendOrderBuilding} from "../utils/order_building"; -import {Diplog} from "../../../diplomacy/utils/diplog"; +import {Diplog} from "../../diplomacy/utils/diplog"; function parseLocation(txt) { if (txt.length > 2 && txt[1] === ' ' && ['A', 'F'].includes(txt[0])) diff --git a/diplomacy/web/src/gui/diplomacy/map/dom_past_map.js b/diplomacy/web/src/gui/map/dom_past_map.js index eb44616..eb44616 100644 --- a/diplomacy/web/src/gui/diplomacy/map/dom_past_map.js +++ b/diplomacy/web/src/gui/map/dom_past_map.js diff --git a/diplomacy/web/src/gui/diplomacy/map/map.jsx b/diplomacy/web/src/gui/map/map.jsx index 2a2949f..1130563 100644 --- a/diplomacy/web/src/gui/diplomacy/map/map.jsx +++ b/diplomacy/web/src/gui/map/map.jsx @@ -16,7 +16,7 @@ // ============================================================================== import React from "react"; import SVG from 'react-inlinesvg'; -import mapSVG from '../../../standard.svg'; +import mapSVG from '../../standard.svg'; import {Renderer} from "./renderer"; import {MapData} from "../utils/map_data"; import {DOMOrderBuilder} from "./dom_order_builder"; diff --git a/diplomacy/web/src/gui/diplomacy/map/renderer.js b/diplomacy/web/src/gui/map/renderer.js index e2586af..e2586af 100644 --- a/diplomacy/web/src/gui/diplomacy/map/renderer.js +++ b/diplomacy/web/src/gui/map/renderer.js diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx b/diplomacy/web/src/gui/pages/content_connection.jsx index 5947e01..8cd1d6e 100644 --- a/diplomacy/web/src/gui/diplomacy/contents/content_connection.jsx +++ b/diplomacy/web/src/gui/pages/content_connection.jsx @@ -15,12 +15,12 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from 'react'; -import {Connection} from "../../../diplomacy/client/connection"; +import {Connection} from "../../diplomacy/client/connection"; import {ConnectionForm} from "../forms/connection_form"; import {DipStorage} from "../utils/dipStorage"; import {Helmet} from "react-helmet"; -import {Navigation} from "../widgets/navigation"; -import {PageContext} from "../widgets/page_context"; +import {Navigation} from "../components/navigation"; +import {PageContext} from "../components/page_context"; export class ContentConnection extends React.Component { constructor(props) { diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_game.jsx b/diplomacy/web/src/gui/pages/content_game.jsx index b3d933b..f1bc76c 100644 --- a/diplomacy/web/src/gui/diplomacy/contents/content_game.jsx +++ b/diplomacy/web/src/gui/pages/content_game.jsx @@ -19,29 +19,32 @@ import Scrollchor from 'react-scrollchor'; import {SelectLocationForm} from "../forms/select_location_form"; import {SelectViaForm} from "../forms/select_via_form"; import {Order} from "../utils/order"; -import {Bar, Row} from "../../core/layouts"; -import {Tabs} from "../../core/tabs"; +import {Row} from "../components/layouts"; +import {Tabs} from "../components/tabs"; import {Map} from "../map/map"; import {extendOrderBuilding, ORDER_BUILDER, POSSIBLE_ORDERS} from "../utils/order_building"; -import {PowerActionsForm} from "../forms/power_actions_form"; +import {PowerOrderCreationForm} from "../forms/power_order_creation_form"; import {MessageForm} from "../forms/message_form"; -import {UTILS} from "../../../diplomacy/utils/utils"; -import {Message} from "../../../diplomacy/engine/message"; -import {PowerOrder} from "../widgets/power_order"; -import {MessageView} from "../widgets/message_view"; -import {STRINGS} from "../../../diplomacy/utils/strings"; -import {Diplog} from "../../../diplomacy/utils/diplog"; -import {Table} from "../../core/table"; +import {UTILS} from "../../diplomacy/utils/utils"; +import {Message} from "../../diplomacy/engine/message"; +import {PowerOrders} from "../components/power_orders"; +import {MessageView} from "../components/message_view"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import {Diplog} from "../../diplomacy/utils/diplog"; +import {Table} from "../components/table"; import {PowerView} from "../utils/power_view"; -import {FancyBox} from "../../core/fancybox"; +import {FancyBox} from "../components/fancybox"; import {DipStorage} from "../utils/dipStorage"; import Helmet from 'react-helmet'; -import {Navigation} from "../widgets/navigation"; -import {PageContext} from "../widgets/page_context"; +import {Navigation} from "../components/navigation"; +import {PageContext} from "../components/page_context"; import PropTypes from 'prop-types'; -import {Help} from "../widgets/help"; -import {Tab} from "../../core/tab"; -import {Button} from "../../core/button"; +import {Help} from "../components/help"; +import {Tab} from "../components/tab"; +import {Button} from "../components/button"; +import {saveGameToDisk} from "../utils/saveGameToDisk"; +import {Game} from '../../diplomacy/engine/game'; +import {PowerOrdersActionBar} from "../components/power_orders_actions_bar"; const HotKey = require('react-shortcut'); @@ -68,12 +71,6 @@ const TABLE_POWER_VIEW = { wait: ['Waiting', 3] }; -function gameReloaded(game, updates) { - if (updates) - return Object.assign({}, updates, game); - return Object.assign({}, game); -} - export class ContentGame extends React.Component { constructor(props) { @@ -145,11 +142,11 @@ export class ContentGame extends React.Component { this.onOrderBuilding = this.onOrderBuilding.bind(this); this.onOrderBuilt = this.onOrderBuilt.bind(this); this.onProcessGame = this.onProcessGame.bind(this); - this.onRemoveAllOrders = this.onRemoveAllOrders.bind(this); + this.onRemoveAllCurrentPowerOrders = this.onRemoveAllCurrentPowerOrders.bind(this); this.onRemoveOrder = this.onRemoveOrder.bind(this); this.onSelectLocation = this.onSelectLocation.bind(this); this.onSelectVia = this.onSelectVia.bind(this); - this.onSetNoOrders = this.onSetNoOrders.bind(this); + this.onSetEmptyOrdersSet = this.onSetEmptyOrdersSet.bind(this); this.reloadServerOrders = this.reloadServerOrders.bind(this); this.renderOrders = this.renderOrders.bind(this); this.sendMessage = this.sendMessage.bind(this); @@ -170,25 +167,6 @@ export class ContentGame extends React.Component { return title; } - static saveGameToDisk(game, page) { - if (game.client) { - game.client.save() - .then((savedData) => { - const domLink = document.createElement('a'); - domLink.setAttribute( - 'href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedData))); - domLink.setAttribute('download', `${game.game_id}.json`); - domLink.style.display = 'none'; - document.body.appendChild(domLink); - domLink.click(); - document.body.removeChild(domLink); - }) - .catch(exc => page.error(`Error while saving game: ${exc.toString()}`)); - } else { - page.error(`Cannot save this game.`); - } - } - static getServerWaitFlags(engine) { const wait = {}; const controllablePowers = engine.getControllablePowers(); @@ -198,23 +176,6 @@ export class ContentGame extends React.Component { return wait; } - static getServerOrders(engine) { - const orders = {}; - const controllablePowers = engine.getControllablePowers(); - for (let powerName of controllablePowers) { - const powerOrders = {}; - let countOrders = 0; - const power = engine.powers[powerName]; - for (let orderString of power.orders) { - const serverOrder = new Order(orderString, false); - powerOrders[serverOrder.loc] = serverOrder; - ++countOrders; - } - orders[powerName] = (countOrders || power.order_is_set) ? powerOrders : null; - } - return orders; - } - static getOrderBuilding(powerName, orderType, orderPath) { return { type: orderType, @@ -224,6 +185,10 @@ export class ContentGame extends React.Component { }; } + getPage() { + return this.context; + } + closeFancyBox() { this.setState({ fancy_title: null, @@ -233,6 +198,8 @@ export class ContentGame extends React.Component { }); } + // [ Methods used to handle current map. + setSelectedLocation(location, powerName, orderType, orderPath) { if (!location) return; @@ -283,30 +250,7 @@ export class ContentGame extends React.Component { }); } - __get_orders(engine) { - const orders = ContentGame.getServerOrders(engine); - if (this.state.orders) { - for (let powerName of Object.keys(orders)) { - const serverPowerOrders = orders[powerName]; - const localPowerOrders = this.state.orders[powerName]; - if (localPowerOrders) { - for (let localOrder of Object.values(localPowerOrders)) { - localOrder.local = ( - !serverPowerOrders - || !serverPowerOrders.hasOwnProperty(localOrder.loc) - || serverPowerOrders[localOrder.loc].order !== localOrder.order - ); - } - } - orders[powerName] = localPowerOrders; - } - } - return orders; - } - - __get_wait(engine) { - return this.state.wait ? this.state.wait : ContentGame.getServerWaitFlags(engine); - } + // ] getMapInfo() { return this.getPage().availableMaps[this.props.data.map_name]; @@ -326,7 +270,7 @@ export class ContentGame extends React.Component { engine.deadline_timer = 0; this.clearScheduleTimeout(); } - this.getPage().load(`game: ${engine.game_id}`, <ContentGame data={gameReloaded(engine)}/>); + this.getPage().load(`game: ${engine.game_id}`, <ContentGame data={engine}/>); } reloadDeadlineTimer(networkGame) { @@ -348,6 +292,13 @@ export class ContentGame extends React.Component { }); } + // [ Network game notifications. + + /** + * Return True if given network game is the game currently displayed on the interface. + * @param {NetworkGame} networkGame - network game to check + * @returns {boolean} + */ networkGameIsDisplayed(networkGame) { return this.getPage().getName() === `game: ${networkGame.local.game_id}`; } @@ -450,6 +401,8 @@ export class ContentGame extends React.Component { } } + // ] + onChangeCurrentPower(event) { this.setState({power: event.target.value, tabPastMessages: null, tabCurrentMessages: null}); } @@ -486,33 +439,145 @@ export class ContentGame extends React.Component { .catch(error => page.error(error.toString())); } + onProcessGame() { + const page = this.getPage(); + this.props.data.client.process() + .then(() => page.success('Game processed.')) + .catch(err => { + page.error(err.toString()); + }); + } + + /** + * Get name of current power selected on the game page. + * @returns {null|string} + */ + getCurrentPowerName() { + const engine = this.props.data; + const controllablePowers = engine.getControllablePowers(); + return this.state.power || (controllablePowers.length && controllablePowers[0]); + } + + __get_wait(engine) { + return this.state.wait ? this.state.wait : ContentGame.getServerWaitFlags(engine); + } + + // [ Methods involved in orders management. + + /** + * Return a dictionary of local orders for given game engine. + * Returned dictionary maps each power name to either: + * - a dictionary of orders, mapping a location to an Order object with boolean flag `local` correctly set + * to determine if that order is a new local order or is a copy of an existing server order for this power. + * - null or empty dictionary, if there are no local orders defined for this power. + * @param {Game} engine - game engine from which we must get local orders + * @returns {{}} + * @private + */ + __get_orders(engine) { + const orders = engine.getServerOrders(); + if (this.state.orders) { + for (let powerName of Object.keys(orders)) { + const serverPowerOrders = orders[powerName]; + const localPowerOrders = this.state.orders[powerName]; + if (localPowerOrders) { + for (let localOrder of Object.values(localPowerOrders)) { + localOrder.local = ( + !serverPowerOrders + || !serverPowerOrders.hasOwnProperty(localOrder.loc) + || serverPowerOrders[localOrder.loc].order !== localOrder.order + ); + } + } + orders[powerName] = localPowerOrders; + } + } + return orders; + } + + /** + * Save given orders into local storage. + * @param orders - orders to save + * @private + */ __store_orders(orders) { - // Save local orders into local storage. const username = this.props.data.client.channel.username; const gameID = this.props.data.game_id; const gamePhase = this.props.data.phase; - if (!orders) { + if (!orders) return DipStorage.clearUserGameOrders(username, gameID); - } for (let entry of Object.entries(orders)) { const powerName = entry[0]; let powerOrdersList = null; - if (entry[1]) { + if (entry[1]) powerOrdersList = Object.values(entry[1]).map(order => order.order); - } DipStorage.clearUserGameOrders(username, gameID, powerName); DipStorage.addUserGameOrders(username, gameID, gamePhase, powerName, powerOrdersList); } } + /** + * Reset local orders and replace them with current server orders. + */ reloadServerOrders() { - const serverOrders = ContentGame.getServerOrders(this.props.data); + // TODO: This method should reset orders to server version only for current powers, not for all powers as she currently does. + const serverOrders = this.props.data.getServerOrders(); this.__store_orders(serverOrders); this.setState({orders: serverOrders}); } + /** + * Remove given order from local orders of given power name. + * @param {string} powerName - power name + * @param {Order} order - order to remove + */ + onRemoveOrder(powerName, order) { + const orders = this.__get_orders(this.props.data); + if (orders.hasOwnProperty(powerName) + && orders[powerName].hasOwnProperty(order.loc) + && orders[powerName][order.loc].order === order.order) { + delete orders[powerName][order.loc]; + if (!UTILS.javascript.count(orders[powerName])) + orders[powerName] = null; + this.__store_orders(orders); + this.setState({orders: orders}); + } + } + + /** + * Remove all local orders for current selected power + */ + onRemoveAllCurrentPowerOrders() { + const currentPowerName = this.getCurrentPowerName(); + if (currentPowerName) { + const engine = this.props.data; + const allOrders = this.__get_orders(engine); + if (!allOrders.hasOwnProperty(currentPowerName)) { + this.getPage().error(`Unknown power ${currentPowerName}.`); + return; + } + allOrders[currentPowerName] = null; + this.__store_orders(allOrders); + this.setState({orders: allOrders}); + } + } + + /** + * Set an empty local orders set for given power name. + * @param {string} powerName - power name + */ + onSetEmptyOrdersSet(powerName) { + const orders = this.__get_orders(this.props.data); + orders[powerName] = {}; + this.__store_orders(orders); + this.setState({orders: orders}); + } + + /** + * Send local orders to server. + */ setOrders() { - const serverOrders = ContentGame.getServerOrders(this.props.data); + const serverOrders = this.props.data.getServerOrders(); const orders = this.__get_orders(this.props.data); for (let entry of Object.entries(orders)) { @@ -523,24 +588,20 @@ export class ContentGame extends React.Component { if (serverPowerOrders === null) { // No orders set on server. - if (localPowerOrders === null) - same = true; + same = localPowerOrders === null; // Otherwise, we have local orders set (even empty local orders). } else if (serverPowerOrders.length === 0) { // Empty orders set on server. - // If local orders are null or empty, then we assume - // it's the same thing as empty order set on server. - if (localPowerOrders === null || !localPowerOrders.length) - same = true; - // Otherwise, we have local non-empty orders set. + // If we have empty orders set locally, then it's same thing. + same = localPowerOrders && localPowerOrders.length === 0; + // Otherwise, we have either local non-empty orders set or local null order. } else { // Orders set on server. Identical to local orders only if we have exactly same orders on server and locally. if (localPowerOrders && localPowerOrders.length === serverPowerOrders.length) { localPowerOrders.sort(); serverPowerOrders.sort(); - const length = localPowerOrders.length; same = true; - for (let i = 0; i < length; ++i) { + for (let i = 0; i < localPowerOrders.length; ++i) { if (localPowerOrders[i] !== serverPowerOrders[i]) { same = false; break; @@ -553,8 +614,15 @@ export class ContentGame extends React.Component { Diplog.warn(`Orders not changed for ${powerName}.`); continue; } - Diplog.info('Sending orders for ' + powerName + ': ' + JSON.stringify(localPowerOrders)); - this.props.data.client.setOrders({power_name: powerName, orders: localPowerOrders || []}) + + Diplog.info(`Sending orders for ${powerName}: ${localPowerOrders ? JSON.stringify(localPowerOrders) : null}`); + let requestCall = null; + if (localPowerOrders) { + requestCall = this.props.data.client.setOrders({power_name: powerName, orders: localPowerOrders}); + } else { + requestCall = this.props.data.client.clearOrders({power_name: powerName}); + } + requestCall .then(() => { this.getPage().success('Orders sent.'); }) @@ -567,37 +635,7 @@ export class ContentGame extends React.Component { } } - onProcessGame() { - const page = this.getPage(); - this.props.data.client.process() - .then(() => page.success('Game processed.')) - .catch(err => { - page.error(err.toString()); - }); - } - - onRemoveOrder(powerName, order) { - const orders = this.__get_orders(this.props.data); - if (orders.hasOwnProperty(powerName) - && orders[powerName].hasOwnProperty(order.loc) - && orders[powerName][order.loc].order === order.order) { - delete orders[powerName][order.loc]; - if (!UTILS.javascript.count(orders[powerName])) - orders[powerName] = null; - this.__store_orders(orders); - this.setState({orders: orders}); - } - } - - onRemoveAllOrders() { - const orders = {}; - const controllablePowers = this.props.data.getControllablePowers(); - for (let powerName of controllablePowers) { - orders[powerName] = null; - } - this.__store_orders(orders); - this.setState({orders: orders}); - } + // ] onOrderBuilding(powerName, path) { const pathToSave = path.slice(1); @@ -634,13 +672,6 @@ export class ContentGame extends React.Component { this.setState(state); } - onSetNoOrders(powerName) { - const orders = this.__get_orders(this.props.data); - orders[powerName] = {}; - this.__store_orders(orders); - this.setState({orders: orders}); - } - onChangeOrderType(form) { this.setState({ orderBuildingType: form.order_type, @@ -730,19 +761,6 @@ export class ContentGame extends React.Component { this.setState({historyShowOrders: event.target.checked}); } - renderOrders(engine, currentPowerName) { - const serverOrders = ContentGame.getServerOrders(this.props.data); - const orders = this.__get_orders(engine); - const wait = this.__get_wait(engine); - - const render = []; - render.push(<PowerOrder key={currentPowerName} name={currentPowerName} wait={wait[currentPowerName]} - orders={orders[currentPowerName]} - serverCount={serverOrders[currentPowerName] ? UTILS.javascript.count(serverOrders[currentPowerName]) : -1} - onRemove={this.onRemoveOrder}/>); - return render; - } - onClickMessage(message) { if (!message.read) { message.read = true; @@ -765,6 +783,21 @@ export class ContentGame extends React.Component { }); } + // [ Rendering methods. + + renderOrders(engine, currentPowerName) { + const serverOrders = this.props.data.getServerOrders(); + const orders = this.__get_orders(engine); + const wait = this.__get_wait(engine); + + const render = []; + render.push(<PowerOrders key={currentPowerName} name={currentPowerName} wait={wait[currentPowerName]} + orders={orders[currentPowerName]} + serverCount={serverOrders[currentPowerName] ? UTILS.javascript.count(serverOrders[currentPowerName]) : -1} + onRemove={this.onRemoveOrder}/>); + return render; + } + renderPastMessages(engine, role) { const messageChannels = engine.getMessageChannels(role, true); const tabNames = []; @@ -1061,15 +1094,13 @@ export class ContentGame extends React.Component { {/* Orders. */} <div className={'panel-orders mb-4'}> {currentTabOrderCreation ? <div className="mb-4">{currentTabOrderCreation}</div> : ''} - <Bar className={'p-2'}> - <strong className={'mr-4'}>Orders:</strong> - <Button title={'reset'} onClick={this.reloadServerOrders}/> - <Button title={'delete all'} onClick={this.onRemoveAllOrders}/> - <Button color={'primary'} title={'update'} onClick={this.setOrders}/> - {(!this.props.data.isPlayerGame() && this.props.data.observer_level === STRINGS.MASTER_TYPE && - <Button color={'danger'} title={'process game'} - onClick={this.onProcessGame}/>) || ''} - </Bar> + <PowerOrdersActionBar + onReset={this.reloadServerOrders} + onDeleteAll={this.onRemoveAllCurrentPowerOrders} + onUpdate={this.setOrders} + onProcess={(!this.props.data.isPlayerGame() + && this.props.data.observer_level === STRINGS.MASTER_TYPE) ? + this.onProcessGame : null}/> <div className={'orders'}>{this.renderOrders(this.props.data, powerName)}</div> <div className={'table-responsive'}> <Table className={'table table-striped table-sm'} @@ -1085,9 +1116,9 @@ export class ContentGame extends React.Component { ); } - getPage() { - return this.context; - } + // ] + + // [ React.Component overridden methods. render() { this.props.data.displayed = true; @@ -1097,7 +1128,7 @@ export class ContentGame extends React.Component { const navigation = [ ['Help', () => page.loadFancyBox('Help', () => <Help/>)], ['Load a game from disk', page.loadGameFromDisk], - ['Save game to disk', () => ContentGame.saveGameToDisk(engine)], + ['Save game to disk', () => saveGameToDisk(engine, page.error)], [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Games`, () => page.loadGames()], [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Leave game`, () => page.leaveGame(engine.game_id)], [`${UTILS.html.UNICODE_SMALL_LEFT_ARROW} Logout`, page.logout] @@ -1172,14 +1203,14 @@ export class ContentGame extends React.Component { const currentTabOrderCreation = hasTabCurrentPhase && ( <div> - <PowerActionsForm orderType={orderBuildingType} - orderTypes={allowedPowerOrderTypes} - onChange={this.onChangeOrderType} - onNoOrders={() => this.onSetNoOrders(currentPowerName)} - onSetWaitFlag={() => this.setWaitFlag(!currentPower.wait)} - onVote={this.vote} - role={engine.role} - power={currentPower}/> + <PowerOrderCreationForm orderType={orderBuildingType} + orderTypes={allowedPowerOrderTypes} + onChange={this.onChangeOrderType} + onPass={() => this.onSetEmptyOrdersSet(currentPowerName)} + onSetWaitFlag={() => this.setWaitFlag(!currentPower.wait)} + onVote={this.vote} + role={engine.role} + power={currentPower}/> {(allowedPowerOrderTypes.length && ( <span> <strong>Orderable locations</strong>: {orderTypeToLocs[orderBuildingType].join(', ')} @@ -1262,9 +1293,11 @@ export class ContentGame extends React.Component { document.onkeydown = null; } + // ] + } ContentGame.contextType = PageContext; ContentGame.propTypes = { - data: PropTypes.object.isRequired + data: PropTypes.instanceOf(Game).isRequired }; diff --git a/diplomacy/web/src/gui/diplomacy/contents/content_games.jsx b/diplomacy/web/src/gui/pages/content_games.jsx index 4ae9f2f..31bd1af 100644 --- a/diplomacy/web/src/gui/diplomacy/contents/content_games.jsx +++ b/diplomacy/web/src/gui/pages/content_games.jsx @@ -15,18 +15,18 @@ // with this program. If not, see <https://www.gnu.org/licenses/>. // ============================================================================== import React from "react"; -import {Tabs} from "../../core/tabs"; -import {Table} from "../../core/table"; +import {Tabs} from "../components/tabs"; +import {Table} from "../components/table"; import {FindForm} from "../forms/find_form"; import {CreateForm} from "../forms/create_form"; import {InlineGameView} from "../utils/inline_game_view"; -import {STRINGS} from "../../../diplomacy/utils/strings"; +import {STRINGS} from "../../diplomacy/utils/strings"; import {Helmet} from "react-helmet"; -import {Navigation} from "../widgets/navigation"; -import {PageContext} from "../widgets/page_context"; +import {Navigation} from "../components/navigation"; +import {PageContext} from "../components/page_context"; import {ContentGame} from "./content_game"; import PropTypes from 'prop-types'; -import {Tab} from "../../core/tab"; +import {Tab} from "../components/tab"; const TABLE_LOCAL_GAMES = { game_id: ['Game ID', 0], diff --git a/diplomacy/web/src/gui/core/page.jsx b/diplomacy/web/src/gui/pages/page.jsx index 5e7aee2..cd36f6c 100644 --- a/diplomacy/web/src/gui/core/page.jsx +++ b/diplomacy/web/src/gui/pages/page.jsx @@ -17,15 +17,15 @@ /** Main class to use to create app GUI. **/ import React from "react"; -import {ContentConnection} from "../diplomacy/contents/content_connection"; +import {ContentConnection} from "./content_connection"; import {UTILS} from "../../diplomacy/utils/utils"; import {Diplog} from "../../diplomacy/utils/diplog"; -import {FancyBox} from "./fancybox"; -import {DipStorage} from "../diplomacy/utils/dipStorage"; -import {PageContext} from "../diplomacy/widgets/page_context"; -import {ContentGames} from "../diplomacy/contents/content_games"; -import {loadGameFromDisk} from "../diplomacy/utils/load_game_from_disk"; -import {ContentGame} from "../diplomacy/contents/content_game"; +import {FancyBox} from "../components/fancybox"; +import {DipStorage} from "../utils/dipStorage"; +import {PageContext} from "../components/page_context"; +import {ContentGames} from "./content_games"; +import {loadGameFromDisk} from "../utils/load_game_from_disk"; +import {ContentGame} from "./content_game"; export class Page extends React.Component { diff --git a/diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx b/diplomacy/web/src/gui/utils/dipStorage.jsx index db5baad..db5baad 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/dipStorage.jsx +++ b/diplomacy/web/src/gui/utils/dipStorage.jsx diff --git a/diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx b/diplomacy/web/src/gui/utils/inline_game_view.jsx index b6c9e67..ec2ca46 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/inline_game_view.jsx +++ b/diplomacy/web/src/gui/utils/inline_game_view.jsx @@ -16,10 +16,10 @@ // ============================================================================== import React from "react"; import {JoinForm} from "../forms/join_form"; -import {STRINGS} from "../../../diplomacy/utils/strings"; -import {ContentGame} from "../contents/content_game"; -import {Button} from "../../core/button"; -import {DeleteButton} from "../../core/delete_button"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import {ContentGame} from "../pages/content_game"; +import {Button} from "../components/button"; +import {DeleteButton} from "../components/delete_button"; export class InlineGameView { constructor(page, gameData) { diff --git a/diplomacy/web/src/gui/diplomacy/utils/load_game_from_disk.js b/diplomacy/web/src/gui/utils/load_game_from_disk.js index 1e13f4f..ca49aa0 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/load_game_from_disk.js +++ b/diplomacy/web/src/gui/utils/load_game_from_disk.js @@ -1,6 +1,6 @@ import $ from "jquery"; -import {STRINGS} from "../../../diplomacy/utils/strings"; -import {Game} from "../../../diplomacy/engine/game"; +import {STRINGS} from "../../diplomacy/utils/strings"; +import {Game} from "../../diplomacy/engine/game"; export function loadGameFromDisk(onLoad, onError) { const input = $(document.createElement('input')); diff --git a/diplomacy/web/src/gui/diplomacy/utils/map_data.js b/diplomacy/web/src/gui/utils/map_data.js index 73d5338..73d5338 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/map_data.js +++ b/diplomacy/web/src/gui/utils/map_data.js diff --git a/diplomacy/web/src/gui/diplomacy/utils/order.js b/diplomacy/web/src/gui/utils/order.js index e314b9f..e314b9f 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/order.js +++ b/diplomacy/web/src/gui/utils/order.js diff --git a/diplomacy/web/src/gui/diplomacy/utils/order_building.js b/diplomacy/web/src/gui/utils/order_building.js index 3758898..3758898 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/order_building.js +++ b/diplomacy/web/src/gui/utils/order_building.js diff --git a/diplomacy/web/src/gui/diplomacy/utils/power_view.jsx b/diplomacy/web/src/gui/utils/power_view.jsx index 62b488e..df76da4 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/power_view.jsx +++ b/diplomacy/web/src/gui/utils/power_view.jsx @@ -14,7 +14,7 @@ // 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 {STRINGS} from "../../../diplomacy/utils/strings"; +import {STRINGS} from "../../diplomacy/utils/strings"; import React from "react"; function getName(power) { diff --git a/diplomacy/web/src/gui/diplomacy/utils/province.js b/diplomacy/web/src/gui/utils/province.js index fe54a82..fe54a82 100644 --- a/diplomacy/web/src/gui/diplomacy/utils/province.js +++ b/diplomacy/web/src/gui/utils/province.js diff --git a/diplomacy/web/src/gui/utils/saveGameToDisk.js b/diplomacy/web/src/gui/utils/saveGameToDisk.js new file mode 100644 index 0000000..aae69a4 --- /dev/null +++ b/diplomacy/web/src/gui/utils/saveGameToDisk.js @@ -0,0 +1,18 @@ +export function saveGameToDisk(game, onError) { + if (game.client) { + game.client.save() + .then((savedData) => { + const domLink = document.createElement('a'); + domLink.setAttribute( + 'href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(savedData))); + domLink.setAttribute('download', `${game.game_id}.json`); + domLink.style.display = 'none'; + document.body.appendChild(domLink); + domLink.click(); + document.body.removeChild(domLink); + }) + .catch(exc => onError(`Error while saving game: ${exc.toString()}`)); + } else { + onError(`Cannot save this game.`); + } +} diff --git a/diplomacy/web/src/index.js b/diplomacy/web/src/index.js index d074bce..66547af 100644 --- a/diplomacy/web/src/index.js +++ b/diplomacy/web/src/index.js @@ -16,7 +16,7 @@ // ============================================================================== import React from 'react'; import ReactDOM from 'react-dom'; -import {Page} from "./gui/core/page"; +import {Page} from "./gui/pages/page"; import 'popper.js'; import 'bootstrap/dist/js/bootstrap'; import 'bootstrap/dist/css/bootstrap.min.css'; |