From 9ec5806bc721734923ff4c93f7ef1f97a6a03248 Mon Sep 17 00:00:00 2001 From: nsensfel Date: Thu, 13 Sep 2018 16:51:08 +0200 Subject: Starting an browser extension for TO... --- LICENSE | 191 +++++++++++++++ Makefile | 36 +++ elm-package.json | 19 ++ images/to-favicon.svg | 511 +++++++++++++++++++++++++++++++++++++++ manifest.json | 23 ++ src/Comm/GetBattles.elm | 41 ++++ src/Comm/GetID.elm | 43 ++++ src/Comm/Okay.elm | 21 ++ src/Comm/Send.elm | 67 +++++ src/Comm/SetPlayer.elm | 26 ++ src/ElmModule/Init.elm | 18 ++ src/ElmModule/Subscriptions.elm | 17 ++ src/ElmModule/Update.elm | 38 +++ src/ElmModule/View.elm | 64 +++++ src/Main.elm | 23 ++ src/Struct/BattleSummary.elm | 65 +++++ src/Struct/Error.elm | 45 ++++ src/Struct/Event.elm | 25 ++ src/Struct/Model.elm | 64 +++++ src/Struct/Player.elm | 107 ++++++++ src/Struct/ServerReply.elm | 23 ++ src/Struct/UI.elm | 62 +++++ src/Update/HandleServerReply.elm | 104 ++++++++ src/View/BattleListing.elm | 92 +++++++ src/View/Header.elm | 79 ++++++ www/index.html | 12 + 26 files changed, 1816 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 elm-package.json create mode 100644 images/to-favicon.svg create mode 100644 manifest.json create mode 100644 src/Comm/GetBattles.elm create mode 100644 src/Comm/GetID.elm create mode 100644 src/Comm/Okay.elm create mode 100644 src/Comm/Send.elm create mode 100644 src/Comm/SetPlayer.elm create mode 100644 src/ElmModule/Init.elm create mode 100644 src/ElmModule/Subscriptions.elm create mode 100644 src/ElmModule/Update.elm create mode 100644 src/ElmModule/View.elm create mode 100644 src/Main.elm create mode 100644 src/Struct/BattleSummary.elm create mode 100644 src/Struct/Error.elm create mode 100644 src/Struct/Event.elm create mode 100644 src/Struct/Model.elm create mode 100644 src/Struct/Player.elm create mode 100644 src/Struct/ServerReply.elm create mode 100644 src/Struct/UI.elm create mode 100644 src/Update/HandleServerReply.elm create mode 100644 src/View/BattleListing.elm create mode 100644 src/View/Header.elm create mode 100644 www/index.html diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bdaf40e --- /dev/null +++ b/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2018 Nathanael Sensfelder + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b58a08 --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +################################################################################ +## CONFIG ###################################################################### +################################################################################ +SRC_DIR ?= src +WWW_DIR ?= www +WWW_SCRIPT_DIR ?= $(WWW_DIR)/script + +ELM_CC ?= elm-make --warn + +MAIN_MODULE ?= $(SRC_DIR)/Main.elm + +################################################################################ +## MAKEFILE MAGIC ############################################################## +################################################################################ +SUB_MODULES = $(shell find $(SRC_DIR) -type f | grep "elm$$") + +################################################################################ +## SANITY CHECKS ############################################################### +################################################################################ + +################################################################################ +## TARGET RULES ################################################################ +################################################################################ +build: $(WWW_SCRIPT_DIR)/main.js + +clean: + rm -f $(WWW_SCRIPT_DIR)/main.js + +reset: + rm -rf elm-stuff + +################################################################################ +## INTERNAL RULES ############################################################## +################################################################################ +$(WWW_SCRIPT_DIR)/main.js: $(MAIN_MODULE) $(SUB_MODULES) + $(ELM_CC) $(MAIN_MODULE) --output $@ diff --git a/elm-package.json b/elm-package.json new file mode 100644 index 0000000..a8b8580 --- /dev/null +++ b/elm-package.json @@ -0,0 +1,19 @@ +{ + "version": "1.0.0", + "summary": "helpful summary of your project, less than 80 characters", + "repository": "https://github.com/nsensfel/tacticians-extension.git", + "license": "Apache 2.0", + "source-directories": [ + "src" + ], + "exposed-modules": [], + "dependencies": { + "NoRedInk/elm-decode-pipeline": "3.0.0 <= v < 4.0.0", + "andrewMacmurray/elm-delay": "2.0.3 <= v < 3.0.0", + "elm-lang/core": "5.1.1 <= v < 6.0.0", + "elm-lang/dom": "1.1.1 <= v < 2.0.0", + "elm-lang/html": "2.0.0 <= v < 3.0.0", + "elm-lang/http": "1.0.0 <= v < 2.0.0" + }, + "elm-version": "0.18.0 <= v < 0.19.0" +} diff --git a/images/to-favicon.svg b/images/to-favicon.svg new file mode 100644 index 0000000..6757b03 --- /dev/null +++ b/images/to-favicon.svg @@ -0,0 +1,511 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..f9fb2e6 --- /dev/null +++ b/manifest.json @@ -0,0 +1,23 @@ +{ + + "name": "Tacticians Online - Active Battles", + + "manifest_version": 1, + "version": "0.1", + + "description": + "Regularly checks if it's your turn to play on Tacticians Online.", + + "icons": { + "48": "images/to-favicon.svg", + "96": "images/to-favicon.svg" + }, + + "permissions": [ ], + + "browser_action": { + "default_icon": "images/to-favicon.svg", + "default_title": "TO - Active Battles", + "default_popup": "www/index.html" + } +} diff --git a/src/Comm/GetBattles.elm b/src/Comm/GetBattles.elm new file mode 100644 index 0000000..59b8d1d --- /dev/null +++ b/src/Comm/GetBattles.elm @@ -0,0 +1,41 @@ +module Comm.GetBattles exposing (try) + +-- Elm ------------------------------------------------------------------------- +import Json.Encode + +-- Extension ------------------------------------------------------------------- +import Comm.Send +import Struct.Event +import Struct.Model + +-------------------------------------------------------------------------------- +-- TYPES ------------------------------------------------------------------------ +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +try_encoding : String -> Struct.Model.Type -> (Maybe Json.Encode.Value) +try_encoding player_id model = + let + encoded_player_id = (Json.Encode.string player_id) + in + (Just + (Json.Encode.object + [ + ("id", encoded_player_id) + ] + ) + ) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +try : Struct.Model.Type -> String -> (Maybe (Cmd Struct.Event.Type)) +try model player_id = + (Comm.Send.try_sending + model + -- FIXME: this is a param now... + Constants.IO.get_battles_handler + (try_encoding player_id) + ) diff --git a/src/Comm/GetID.elm b/src/Comm/GetID.elm new file mode 100644 index 0000000..14d668c --- /dev/null +++ b/src/Comm/GetID.elm @@ -0,0 +1,43 @@ +module Comm.GetID exposing (try) + +-- Elm ------------------------------------------------------------------------- +import Json.Encode + +-- Extension ------------------------------------------------------------------- +import Comm.Send + +import Constants.IO + +import Struct.Event +import Struct.Model + +-------------------------------------------------------------------------------- +-- TYPES ------------------------------------------------------------------------ +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +try_encoding : String -> Struct.Model.Type -> (Maybe Json.Encode.Value) +try_encoding player_id model = + let + encoded_player_id = (Json.Encode.string player_id) + in + (Just + (Json.Encode.object + [ + ("id", encoded_player_id) + ] + ) + ) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +try : Struct.Model.Type -> String -> (Maybe (Cmd Struct.Event.Type)) +try model = + (Comm.Send.try_sending + model + Constants.IO.get_battles_handler + (try_encoding player_id) + ) diff --git a/src/Comm/Okay.elm b/src/Comm/Okay.elm new file mode 100644 index 0000000..ca7a2eb --- /dev/null +++ b/src/Comm/Okay.elm @@ -0,0 +1,21 @@ +module Comm.Okay exposing (decode) + +-- Elm ------------------------------------------------------------------------- +import Json.Decode + +-- Battlemap ------------------------------------------------------------------- +import Struct.ServerReply + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +decode : (Json.Decode.Decoder Struct.ServerReply.Type) +decode = (Json.Decode.succeed Struct.ServerReply.Okay) diff --git a/src/Comm/Send.elm b/src/Comm/Send.elm new file mode 100644 index 0000000..dd9dc28 --- /dev/null +++ b/src/Comm/Send.elm @@ -0,0 +1,67 @@ +module Comm.Send exposing (try_sending) + +-- Elm ------------------------------------------------------------------------- +import Http + +import Json.Decode +import Json.Encode + +-- Extension ------------------------------------------------------------------- +import Comm.Okay +import Comm.SetBattles + +import Struct.Event +import Struct.ServerReply +import Struct.Model + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +internal_decoder : String -> (Json.Decode.Decoder Struct.ServerReply.Type) +internal_decoder reply_type = + case reply_type of + "okay" -> (Comm.Okay.decode) + "set_battles" -> (Comm.SetBattles.decode) + other -> + (Json.Decode.fail + ( + "Unknown server command \"" + ++ other + ++ "\"" + ) + ) + +decode : (Json.Decode.Decoder Struct.ServerReply.Type) +decode = + (Json.Decode.field "msg" Json.Decode.string) + |> (Json.Decode.andThen (internal_decoder)) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-- TODO: turn this into a multi-server version. +try_sending : ( + Struct.Model.Type -> + String -> + (Struct.Model.Type -> (Maybe Json.Encode.Value)) -> + (Maybe (Cmd Struct.Event.Type)) + ) +try_sending model recipient try_encoding_fun = + case (try_encoding_fun model) of + (Just serial) -> + (Just + (Http.send + Struct.Event.ServerReplied + (Http.post + recipient + (Http.jsonBody serial) + (Json.Decode.list (decode)) + ) + ) + ) + + Nothing -> Nothing diff --git a/src/Comm/SetPlayer.elm b/src/Comm/SetPlayer.elm new file mode 100644 index 0000000..a595777 --- /dev/null +++ b/src/Comm/SetPlayer.elm @@ -0,0 +1,26 @@ +module Comm.SetPlayer exposing (decode) + +-- Elm ------------------------------------------------------------------------- +import Json.Decode + +-- Map ------------------------------------------------------------------------- +import Struct.Player +import Struct.ServerReply + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +internal_decoder : Struct.Player.Type -> Struct.ServerReply.Type +internal_decoder player = + (Struct.ServerReply.SetPlayer player) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +decode : (Json.Decode.Decoder Struct.ServerReply.Type) +decode = + (Json.Decode.map (internal_decoder) (Struct.Player.decoder)) diff --git a/src/ElmModule/Init.elm b/src/ElmModule/Init.elm new file mode 100644 index 0000000..705cff7 --- /dev/null +++ b/src/ElmModule/Init.elm @@ -0,0 +1,18 @@ +module ElmModule.Init exposing (init) + +-- Elm ------------------------------------------------------------------------- + +-- Main Menu ------------------------------------------------------------------- +import Struct.Event +import Struct.Flags +import Struct.Model + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +init : Struct.Flags.Type -> (Struct.Model.Type, (Cmd Struct.Event.Type)) +init flags = (Struct.Model.new flags) diff --git a/src/ElmModule/Subscriptions.elm b/src/ElmModule/Subscriptions.elm new file mode 100644 index 0000000..e9b557e --- /dev/null +++ b/src/ElmModule/Subscriptions.elm @@ -0,0 +1,17 @@ +module ElmModule.Subscriptions exposing (..) + +-- Elm ------------------------------------------------------------------------- + +-- Main Menu ------------------------------------------------------------------- +import Struct.Model +import Struct.Event + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +subscriptions : Struct.Model.Type -> (Sub Struct.Event.Type) +subscriptions model = Sub.none diff --git a/src/ElmModule/Update.elm b/src/ElmModule/Update.elm new file mode 100644 index 0000000..18b2077 --- /dev/null +++ b/src/ElmModule/Update.elm @@ -0,0 +1,38 @@ +module ElmModule.Update exposing (update) + +-- Elm ------------------------------------------------------------------------- + +-- Main Menu ------------------------------------------------------------------- +import Struct.Event +import Struct.Model + +import Update.HandleServerReply +import Update.SelectTab + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +update : ( + Struct.Event.Type -> + Struct.Model.Type -> + (Struct.Model.Type, (Cmd Struct.Event.Type)) + ) +update event model = + let + new_model = (Struct.Model.clear_error model) + in + case event of + Struct.Event.None -> (model, Cmd.none) + + (Struct.Event.Failed err) -> + ( + (Struct.Model.invalidate err new_model), + Cmd.none + ) + + (Struct.Event.ServerReplied result) -> + (Update.HandleServerReply.apply_to model result) diff --git a/src/ElmModule/View.elm b/src/ElmModule/View.elm new file mode 100644 index 0000000..0d6a321 --- /dev/null +++ b/src/ElmModule/View.elm @@ -0,0 +1,64 @@ +module ElmModule.View exposing (view) + +-- Elm ------------------------------------------------------------------------- +import Html +import Html.Attributes + +-- Shared ---------------------------------------------------------------------- +import Util.Html + +-- Main Menu ------------------------------------------------------------------- +import Struct.Error +import Struct.Event +import Struct.Model +import Struct.Player + +import View.BattleListing +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +view : Struct.Model.Type -> (Html.Html Struct.Event.Type) +view model = + (Html.div + [ + (Html.Attributes.class "fullscreen-module") + ] + [ + (Html.main_ + [ + ] + [ + (View.BattleListing.get_html + "Campaigns" + "main-menu-campaigns" + (Struct.Player.get_campaigns model.player) + ), + (View.BattleListing.get_html + "Invasions" + "main-menu-invasions" + (Struct.Player.get_invasions model.player) + ), + (View.BattleListing.get_html + "Events" + "main-menu-events" + (Struct.Player.get_events model.player) + ) + ] + ), + ( + case model.error of + Nothing -> (Util.Html.nothing) + (Just err) -> + (Html.div + [] + [ + (Html.text (Struct.Error.to_string err)) + ] + ) + ) + ] + ) diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..8140041 --- /dev/null +++ b/src/Main.elm @@ -0,0 +1,23 @@ +-- Elm ------------------------------------------------------------------------ +import Html + +-- Map ------------------------------------------------------------------- +import Struct.Model +import Struct.Event +import Struct.Flags + +import ElmModule.Init +import ElmModule.Subscriptions +import ElmModule.View +import ElmModule.Update + +main : (Program Struct.Flags.Type Struct.Model.Type Struct.Event.Type) +main = + (Html.programWithFlags + { + init = ElmModule.Init.init, + view = ElmModule.View.view, + update = ElmModule.Update.update, + subscriptions = ElmModule.Subscriptions.subscriptions + } + ) diff --git a/src/Struct/BattleSummary.elm b/src/Struct/BattleSummary.elm new file mode 100644 index 0000000..adab965 --- /dev/null +++ b/src/Struct/BattleSummary.elm @@ -0,0 +1,65 @@ +module Struct.BattleSummary exposing + ( + Type, + get_id, + get_name, + get_last_edit, + is_players_turn, + decoder, + none + ) + +-- Elm ------------------------------------------------------------------------- +import Json.Decode +import Json.Decode.Pipeline + +-- Main Menu ------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type alias Type = + { + id : String, + name : String, + last_edit : String, + is_players_turn : Bool + } + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +get_id : Type -> String +get_id t = t.id + +get_name : Type -> String +get_name t = t.name + +get_last_edit : Type -> String +get_last_edit t = t.last_edit + +is_players_turn : Type -> Bool +is_players_turn t = t.is_players_turn + +decoder : (Json.Decode.Decoder Type) +decoder = + (Json.Decode.Pipeline.decode + Type + |> (Json.Decode.Pipeline.required "id" Json.Decode.string) + |> (Json.Decode.Pipeline.required "nme" Json.Decode.string) + |> (Json.Decode.Pipeline.required "ldt" Json.Decode.string) + |> (Json.Decode.Pipeline.required "ipt" Json.Decode.bool) + ) + +none : Type +none = + { + id = "", + name = "Unknown", + last_edit = "Never", + is_players_turn = False + } diff --git a/src/Struct/Error.elm b/src/Struct/Error.elm new file mode 100644 index 0000000..5f40c09 --- /dev/null +++ b/src/Struct/Error.elm @@ -0,0 +1,45 @@ +module Struct.Error exposing (Type, Mode(..), new, to_string) + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type Mode = + IllegalAction + | Programming + | Unimplemented + | Networking + | Failure + +type alias Type = + { + mode: Mode, + message: String + } + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +new : Mode -> String -> Type +new mode str = + { + mode = mode, + message = str + } + +to_string : Type -> String +to_string e = + ( + (case e.mode of + Failure -> "The action failed: " + IllegalAction -> "Request discarded: " + Programming -> "Error in the program (please report): " + Unimplemented -> "Update discarded due to unimplemented feature: " + Networking -> "Error while conversing with the server: " + ) + ++ e.message + ) + diff --git a/src/Struct/Event.elm b/src/Struct/Event.elm new file mode 100644 index 0000000..419ef51 --- /dev/null +++ b/src/Struct/Event.elm @@ -0,0 +1,25 @@ +module Struct.Event exposing (Type(..), attempted) + +-- Elm ------------------------------------------------------------------------- +import Http + +-- Main Menu ------------------------------------------------------------------- +import Struct.Error +import Struct.ServerReply +import Struct.UI + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type Type = + None + | Failed Struct.Error.Type + | ServerReplied (Result Http.Error (List Struct.ServerReply.Type)) + | TabSelected Struct.UI.Tab + +attempted : (Result.Result err val) -> Type +attempted act = + case act of + (Result.Ok _) -> None + (Result.Err msg) -> + (Failed (Struct.Error.new Struct.Error.Failure (toString msg))) diff --git a/src/Struct/Model.elm b/src/Struct/Model.elm new file mode 100644 index 0000000..747a39e --- /dev/null +++ b/src/Struct/Model.elm @@ -0,0 +1,64 @@ +module Struct.Model exposing + ( + Type, + new, + invalidate, + reset, + clear_error + ) + +-- Elm ------------------------------------------------------------------------- + +-- Shared ---------------------------------------------------------------------- +import Struct.Flags + +-- Main Menu ------------------------------------------------------------------- +import Struct.Error +import Struct.Player +import Struct.UI + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type alias Type = + { + flags: Struct.Flags.Type, + error: (Maybe Struct.Error.Type), + player_id: String, + session_token: String, + player: Struct.Player.Type, + ui: Struct.UI.Type + } + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +new : Struct.Flags.Type -> Type +new flags = + { + flags = flags, + error = Nothing, + player_id = flags.user_id, + session_token = flags.token, + player = (Struct.Player.none), + ui = (Struct.UI.default) + } + +reset : Type -> Type +reset model = + {model | + error = Nothing + } + +invalidate : Struct.Error.Type -> Type -> Type +invalidate err model = + {model | + error = (Just err) + } + +clear_error : Type -> Type +clear_error model = {model | error = Nothing} diff --git a/src/Struct/Player.elm b/src/Struct/Player.elm new file mode 100644 index 0000000..73fbdb3 --- /dev/null +++ b/src/Struct/Player.elm @@ -0,0 +1,107 @@ +module Struct.Player exposing + ( + Type, + get_id, + get_username, + get_maps, + get_campaigns, + get_invasions, + get_events, + get_roster_id, + get_inventory_id, + decoder, + none + ) + +-- Elm ------------------------------------------------------------------------- +import Json.Decode +import Json.Decode.Pipeline + +-- Main Menu ------------------------------------------------------------------- +import Struct.BattleSummary +import Struct.MapSummary + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type alias Type = + { + id : String, + name : String, + maps : (List Struct.MapSummary.Type), + campaigns : (List Struct.BattleSummary.Type), + invasions : (List Struct.BattleSummary.Type), + events : (List Struct.BattleSummary.Type), + roster_id : String, + inventory_id : String + } + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +get_id : Type -> String +get_id t = t.id + +get_username : Type -> String +get_username t = t.name + +get_maps : Type -> (List Struct.MapSummary.Type) +get_maps t = t.maps + +get_campaigns : Type -> (List Struct.BattleSummary.Type) +get_campaigns t = t.campaigns + +get_invasions : Type -> (List Struct.BattleSummary.Type) +get_invasions t = t.invasions + +get_events : Type -> (List Struct.BattleSummary.Type) +get_events t = t.events + +get_roster_id : Type -> String +get_roster_id t = t.roster_id + +get_inventory_id : Type -> String +get_inventory_id t = t.inventory_id + +decoder : (Json.Decode.Decoder Type) +decoder = + (Json.Decode.Pipeline.decode + Type + |> (Json.Decode.Pipeline.required "id" Json.Decode.string) + |> (Json.Decode.Pipeline.required "nme" Json.Decode.string) + |> (Json.Decode.Pipeline.required + "maps" + (Json.Decode.list Struct.MapSummary.decoder) + ) + |> (Json.Decode.Pipeline.required + "cmps" + (Json.Decode.list Struct.BattleSummary.decoder) + ) + |> (Json.Decode.Pipeline.required + "invs" + (Json.Decode.list Struct.BattleSummary.decoder) + ) + |> (Json.Decode.Pipeline.required + "evts" + (Json.Decode.list Struct.BattleSummary.decoder) + ) + |> (Json.Decode.Pipeline.required "rtid" Json.Decode.string) + |> (Json.Decode.Pipeline.required "ivid" Json.Decode.string) + ) + +none : Type +none = + { + id = "", + name = "Unknown", + maps = [], + campaigns = [], + invasions = [], + events = [], + roster_id = "", + inventory_id = "" + } diff --git a/src/Struct/ServerReply.elm b/src/Struct/ServerReply.elm new file mode 100644 index 0000000..fb4967b --- /dev/null +++ b/src/Struct/ServerReply.elm @@ -0,0 +1,23 @@ +module Struct.ServerReply exposing (Type(..)) + +-- Elm ------------------------------------------------------------------------- + +-- Main Menu ------------------------------------------------------------------- +import Struct.Player + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +type Type = + Okay + | Disconnected + | SetPlayer Struct.Player.Type + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- diff --git a/src/Struct/UI.elm b/src/Struct/UI.elm new file mode 100644 index 0000000..6cf853c --- /dev/null +++ b/src/Struct/UI.elm @@ -0,0 +1,62 @@ +module Struct.UI exposing + ( + Type, + Tab(..), + default, + -- Tab + try_getting_displayed_tab, + set_displayed_tab, + reset_displayed_tab, + to_string + ) + +-- Main Menu ------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +type Tab = + CampaignsTab + | InvasionsTab + | EventsTab + | CharactersTab + | MapsEditorTab + | AccountTab + +type alias Type = + { + displayed_tab : (Maybe Tab) + } + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +default : Type +default = + { + displayed_tab = Nothing + } + +-- Tab ------------------------------------------------------------------------- +try_getting_displayed_tab : Type -> (Maybe Tab) +try_getting_displayed_tab ui = ui.displayed_tab + +set_displayed_tab : Tab -> Type -> Type +set_displayed_tab tab ui = {ui | displayed_tab = (Just tab)} + +reset_displayed_tab : Type -> Type +reset_displayed_tab ui = {ui | displayed_tab = Nothing} + +to_string : Tab -> String +to_string tab = + case tab of + CampaignsTab -> "Campaigns" + InvasionsTab -> "Invasions" + EventsTab -> "Events" + CharactersTab -> "Character Editor" + MapsEditorTab -> "Map Editor" + AccountTab -> "Account Settings" diff --git a/src/Update/HandleServerReply.elm b/src/Update/HandleServerReply.elm new file mode 100644 index 0000000..d68496c --- /dev/null +++ b/src/Update/HandleServerReply.elm @@ -0,0 +1,104 @@ +module Update.HandleServerReply exposing (apply_to) + +-- Elm ------------------------------------------------------------------------- +import Http + +-- Shared ---------------------------------------------------------------------- +import Action.Ports + +import Struct.Flags + +-- Main Menu ------------------------------------------------------------------- +import Constants.IO + +import Struct.Error +import Struct.Event +import Struct.Model +import Struct.Player +import Struct.ServerReply + +-------------------------------------------------------------------------------- +-- TYPES ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +disconnected : ( + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) -> + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) + ) +disconnected current_state = + let (model, cmds) = current_state in + ( + model, + [ + (Action.Ports.go_to + ( + Constants.IO.base_url + ++ "/login/?action=disconnect&goto=" + ++ + (Http.encodeUri + ( + "/main-menu/?" + ++ (Struct.Flags.get_params_as_url model.flags) + ) + ) + ) + ) + ] + ) + +set_player : ( + Struct.Player.Type -> + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) -> + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) + ) +set_player player current_state = + let (model, cmds) = current_state in + ({model | player = player}, cmds) + +apply_command : ( + Struct.ServerReply.Type -> + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) -> + (Struct.Model.Type, (List (Cmd Struct.Event.Type))) + ) +apply_command command current_state = + case command of + Struct.ServerReply.Disconnected -> (disconnected current_state) + (Struct.ServerReply.SetPlayer player) -> (set_player player current_state) + Struct.ServerReply.Okay -> current_state + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +apply_to : ( + Struct.Model.Type -> + (Result Http.Error (List Struct.ServerReply.Type)) -> + (Struct.Model.Type, (Cmd Struct.Event.Type)) + ) +apply_to model query_result = + case query_result of + (Result.Err error) -> + ( + (Struct.Model.invalidate + (Struct.Error.new Struct.Error.Networking (toString error)) + model + ), + Cmd.none + ) + + (Result.Ok commands) -> + let + (new_model, elm_commands) = + (List.foldl (apply_command) (model, [Cmd.none]) commands) + in + ( + new_model, + ( + case elm_commands of + [] -> Cmd.none + [cmd] -> cmd + _ -> (Cmd.batch elm_commands) + ) + ) diff --git a/src/View/BattleListing.elm b/src/View/BattleListing.elm new file mode 100644 index 0000000..9b667ac --- /dev/null +++ b/src/View/BattleListing.elm @@ -0,0 +1,92 @@ +module View.BattleListing exposing (get_html) + +-- Elm ------------------------------------------------------------------------- +import Html +import Html.Attributes +-- import Html.Events + +-- Map ------------------------------------------------------------------- +import Struct.BattleSummary +import Struct.Event + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +get_item_html : Struct.BattleSummary.Type -> (Html.Html Struct.Event.Type) +get_item_html item = + (Html.a + [ + (Html.Attributes.href + ( + "/battle/?id=" + ++ (Struct.BattleSummary.get_id item) + ) + ), + ( + if (Struct.BattleSummary.is_players_turn item) + then + (Html.Attributes.class "main-menu-battle-summary-is-active") + else + (Html.Attributes.class "main-menu-battle-summary-is-inactive") + ) + ] + [ + (Html.div + [ + (Html.Attributes.class "main-menu-battle-summary-name") + ] + [ + (Html.text (Struct.BattleSummary.get_name item)) + ] + ), + (Html.div + [ + (Html.Attributes.class "main-menu-battle-summary-date") + ] + [ + (Html.text (Struct.BattleSummary.get_last_edit item)) + ] + ) + ] + ) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +get_html : ( + String -> + String -> + (List Struct.BattleSummary.Type) -> + (Html.Html Struct.Event.Type) + ) +get_html name class battle_summaries = + (Html.div + [ + (Html.Attributes.class class), + (Html.Attributes.class "main-menu-battle-listing") + ] + [ + (Html.div + [ + (Html.Attributes.class "main-menu-battle-listing-header") + ] + [ + (Html.text name) + ] + ), + (Html.div + [ + (Html.Attributes.class "main-menu-battle-listing-body") + ] + (List.map (get_item_html) battle_summaries) + ), + (Html.div + [ + (Html.Attributes.class "main-menu-battle-listing-add-new") + ] + [ + (Html.text "New") + ] + ) + ] + ) diff --git a/src/View/Header.elm b/src/View/Header.elm new file mode 100644 index 0000000..fd8e693 --- /dev/null +++ b/src/View/Header.elm @@ -0,0 +1,79 @@ +module View.Header exposing (get_html) + +-- Elm ------------------------------------------------------------------------- +import Html +import Html.Attributes + +-- Map ------------------------------------------------------------------- +import Struct.Event + +-------------------------------------------------------------------------------- +-- LOCAL ----------------------------------------------------------------------- +-------------------------------------------------------------------------------- +link_html : String -> String -> Bool -> (Html.Html Struct.Event.Type) +link_html src label is_active = + (Html.a + [ + (Html.Attributes.href src) + ] + [ + ( + if (is_active) + then (Html.text label) + else (Html.s [] [(Html.text label)]) + ) + ] + ) + +navigation_html : (Html.Html Struct.Event.Type) +navigation_html = + (Html.nav + [] + [ + (link_html "/about.html" "About" True), + (link_html "/news/" "News" False), + (link_html "/community/" "Community" False), + (link_html "/login/?action=disconnect" "Disconnect" True) + ] + ) + +-------------------------------------------------------------------------------- +-- EXPORTED -------------------------------------------------------------------- +-------------------------------------------------------------------------------- +get_html : (Html.Html Struct.Event.Type) +get_html = + (Html.header + [] + [ + (Html.div + [ + (Html.Attributes.class "main-server-logo") + ] + [ + (Html.a + [ + (Html.Attributes.href "http://127.0.0.1") + ] + [ + (Html.img + [ + (Html.Attributes.src "/asset/svg/to-logo-no-bg.svg") + ] + [ + ] + ) + ] + ) + ] + ), + (Html.div + [ + (Html.Attributes.class "main-server-version") + ] + [ + (Html.text "Latest Dev. Build (Mon, 10 Sep 2018 10:30:17 +0000)") + ] + ), + (navigation_html) + ] + ) diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..f0fc53c --- /dev/null +++ b/www/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + -- cgit v1.2.3-70-g09d2