diff options
Diffstat (limited to 'diplomacy/web/src/gui')
| -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 | 
40 files changed, 302 insertions, 227 deletions
| 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.`); +    } +} | 
