diff --git a/app/assets/frontend/README.md b/app/assets/frontend/README.md new file mode 100644 index 0000000..fe55510 --- /dev/null +++ b/app/assets/frontend/README.md @@ -0,0 +1,34 @@ +# Fantasy Football +## EECS 448 - Projects 3 & 4 + +## Structure Info +This project has been wired up to use Vue.js to help organize components of the game. + +These components are defined in files that end in the `.component.js` extension, and are located in the `src/components/` directory. + +The entry point for the project is the `index.html`. This file contains the basic logic for loading Vue, and adding the game board to the page. + +Obviously, we'll flesh out the look-and-feel as we go along. This is just a basic starter for now. + +## How to Run +The easiest way to run this project is by creating a basic static web server using Python. This is super simple: + +1. Open a terminal or command prompt to the root of this project (i.e. the directory this file is in). +2. Start the server: `python -m http.server` + +This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser. + +### Re-generating the documentation +To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just: + +```shell script +cd documentation +./generate.sh +``` + +## Contributors +- Lucas Brakenridge +- Javier Barea Lara +- Garrett Mills +- Evan Powell +- Alec Horlick-Mills diff --git a/app/assets/frontend/documentation/.gitignore b/app/assets/frontend/documentation/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/app/assets/frontend/documentation/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/app/assets/frontend/documentation/README.md b/app/assets/frontend/documentation/README.md new file mode 100644 index 0000000..b5a1c23 --- /dev/null +++ b/app/assets/frontend/documentation/README.md @@ -0,0 +1,45 @@ +# Fantasy Football +## EECS 448 - Projects 3 & 4 + +## Structure Info +This project has been wired up to use Vue.js to help organize components of the game. + +These components are defined in files that end in the `.component.js` extension, and are located in the `src/components/` directory. + +The entry point for the project is the `index.html`. This file contains the basic logic for loading Vue, and adding the game board to the page. + +Obviously, we'll flesh out the look-and-feel as we go along. This is just a basic starter for now. + +## How to Run +The easiest way to run this project is by creating a basic static web server using Python. This is super simple: + +1. Open a terminal or command prompt to the root of this project (i.e. the directory this file is in). +2. Start the server: `python -m http.server` + +This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser. + +### Re-generating the documentation +To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just: + +```shell script +cd documentation +./generate.sh +``` + +## Works Cited +The files in the `lib` directory are external libraries used in this project. + +- Vue.js + - A front-end framework. Used under the terms of the MIT license. + - https://github.com/vuejs/vue +- VuES6.js + - A kind-of crappy loader for defining Vue components using ES6 classes. + - Also used under the terms of the MIT license. + - https://code.garrettmills.dev/garrettmills/vues6 + +## Contributors +- Lucas Brakenridge +- Javier Barea Lara +- Garrett Mills +- Evan Powell +- Alec Horlick-Mills diff --git a/app/assets/frontend/documentation/generate.sh b/app/assets/frontend/documentation/generate.sh new file mode 100755 index 0000000..8b99aab --- /dev/null +++ b/app/assets/frontend/documentation/generate.sh @@ -0,0 +1,3 @@ +#!/bin/sh +yarn install +./node_modules/.bin/jsdoc --destination ./generated --readme ./README.md --recurse ../src diff --git a/app/assets/frontend/documentation/generated/.gitkeep b/app/assets/frontend/documentation/generated/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/frontend/documentation/generated/AddPlayersComponent.html b/app/assets/frontend/documentation/generated/AddPlayersComponent.html new file mode 100644 index 0000000..5af00fc --- /dev/null +++ b/app/assets/frontend/documentation/generated/AddPlayersComponent.html @@ -0,0 +1,1540 @@ + + + + + JSDoc: Class: AddPlayersComponent + + + + + + + + + + +
+ +

Class: AddPlayersComponent

+ + + + + + +
+ +
+ +

AddPlayersComponent()

+ +
A component which represents the "Add Players" page. Allows users to add/remove +players from their team.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new AddPlayersComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

all_players :Array.<object>

+ + + + +
+ All available players, whether they are on the user's team or not. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

filtered_players :Array.<object>

+ + + + +
+ Array of currently displayed players, after the filter has been applied. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

my_team :Array.<object>

+ + + + +
+ Array of players currently on the user's team. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

my_team_only :boolean

+ + + + +
+ If true, then only the players on the user's team will be shown. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

possible_players :Array.<object>

+ + + + +
+ Array of currently displayed players, before the filter has been applied. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

quick_filter :string

+ + + + +
+ The current value of the quick filter for players. If empty string, no filter is applied. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

add_to_team(player)

+ + + + + + +
+ Add the given player to the user's team, if not already there. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_filter_change()

+ + + + + + +
+ Called when the quick-filter changes. Applies the filter to the displayed players. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_photo_hover(player)

+ + + + + + +
+ Called when the user hovers over a player. Toggles the stats to be shown. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

on_photo_leave(player)

+ + + + + + +
+ Called when the user un-hovers over a player. Toggles the stats to hide. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

remove_from_team(player)

+ + + + + + +
+ Remove the given player from the user's team, if there. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
player + + +object + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

to_all_players()

+ + + + + + +
+ When called, change the display to show all available players. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

to_my_team_only()

+ + + + + + +
+ When called, change the display to show only the user's team. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the page is instantiated. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/DraftBoardComponent.html b/app/assets/frontend/documentation/generated/DraftBoardComponent.html new file mode 100644 index 0000000..ec0457c --- /dev/null +++ b/app/assets/frontend/documentation/generated/DraftBoardComponent.html @@ -0,0 +1,181 @@ + + + + + JSDoc: Class: DraftBoardComponent + + + + + + + + + + +
+ +

Class: DraftBoardComponent

+ + + + + + +
+ +
+ +

DraftBoardComponent()

+ +
Component representing the draft board page.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new DraftBoardComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/GridActionButtonComponent.html b/app/assets/frontend/documentation/generated/GridActionButtonComponent.html new file mode 100644 index 0000000..d343e31 --- /dev/null +++ b/app/assets/frontend/documentation/generated/GridActionButtonComponent.html @@ -0,0 +1,1088 @@ + + + + + JSDoc: Class: GridActionButtonComponent + + + + + + + + + + +
+ +

Class: GridActionButtonComponent

+ + + + + + +
+ +
+ +

GridActionButtonComponent()

+ +
Component representing an action button that can be embedded in the shared grid.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new GridActionButtonComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

color :string

+ + + + +
+ The CSS color of the action button. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

hidden :boolean

+ + + + +
+ If true, the action button will be hidden. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

text :string

+ + + + +
+ The text shown on the action button. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

on_click($event)

+ + + + + + +
+ Called when the button is clicked. Emits a click event and updates the text, color, and hide status. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
$event + + +MouseEvent + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

update_color()

+ + + + + + +
+ Determine the color to show on the button based on the column definition. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

update_hidden()

+ + + + + + +
+ Determine whether the button should be shown or not, based on the column definition. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

update_text()

+ + + + + + +
+ Determine the text to show on the button based on the column definition. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is instantiated. Updates the text, color, and hide status. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

watch_col()

+ + + + + + +
+ Called when the column value changes. Updates the text, color, and hide status. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

watch_row()

+ + + + + + +
+ Called when the row value changes. Updates the text, color, and hide status. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/GridComponent.html b/app/assets/frontend/documentation/generated/GridComponent.html new file mode 100644 index 0000000..4717606 --- /dev/null +++ b/app/assets/frontend/documentation/generated/GridComponent.html @@ -0,0 +1,474 @@ + + + + + JSDoc: Class: GridComponent + + + + + + + + + + +
+ +

Class: GridComponent

+ + + + + + +
+ +
+ +

GridComponent()

+ +
Shared grid component used to show tables in various interfaces.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new GridComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

on_col_click(col, row, passcol)

+ + + + + + +
+ Called when the component renderer emits a click event, to pass it along to the column definition. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
col + + +object + + + + the column definition
row + + +object + + + + the row clicked
passcol + + +object + + + + the column emitted from the component
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is instantiated. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/LeagueComponent.html b/app/assets/frontend/documentation/generated/LeagueComponent.html new file mode 100644 index 0000000..4c22d11 --- /dev/null +++ b/app/assets/frontend/documentation/generated/LeagueComponent.html @@ -0,0 +1,439 @@ + + + + + JSDoc: Class: LeagueComponent + + + + + + + + + + +
+ +

Class: LeagueComponent

+ + + + + + +
+ +
+ +

LeagueComponent()

+ +
Component representing the league standings page.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new LeagueComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

column_defs :Array.<object>

+ + + + +
+ Column definitions for the league standings grid. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

data :Array.<object>

+ + + + +
+ Sample data for the league standings grid. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is instantiated. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/LinkComponent.html b/app/assets/frontend/documentation/generated/LinkComponent.html new file mode 100644 index 0000000..125c7b8 --- /dev/null +++ b/app/assets/frontend/documentation/generated/LinkComponent.html @@ -0,0 +1,263 @@ + + + + + JSDoc: Class: LinkComponent + + + + + + + + + + +
+ +

Class: LinkComponent

+ + + + + + +
+ +
+ +

LinkComponent()

+ +
Component providing hyper-links that navigate to other pages in the SPA, +without reloading the page.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new LinkComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

on_click()

+ + + + + + +
+ Called when the link is clicked. Navigates the router. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/MyTeamComponent.html b/app/assets/frontend/documentation/generated/MyTeamComponent.html new file mode 100644 index 0000000..e6d831a --- /dev/null +++ b/app/assets/frontend/documentation/generated/MyTeamComponent.html @@ -0,0 +1,961 @@ + + + + + JSDoc: Class: MyTeamComponent + + + + + + + + + + +
+ +

Class: MyTeamComponent

+ + + + + + +
+ +
+ +

MyTeamComponent()

+ +
Component representing the my-team page.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new MyTeamComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

bench_players :Array.<object>

+ + + + +
+ Players on the bench. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

lineup_column_defs :Array.<object>

+ + + + +
+ Column definitions for the starting/bench lineup grids. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

moving_player :undefined

+ + + + +
+ The player currently being moved. If none, then will be set to undefined. +
+ + + +
Type:
+
    +
  • + +undefined + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

overall_column_defs :Array.<object>

+ + + + +
+ Column definitions for the overall team grid. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

overall_data :Array.<object>

+ + + + +
+ Data for the overall team grid (list of user's team players). +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

show_body :boolean

+ + + + +
+ If true, the body of the page will be shown. Otherwise, hidden. +This is used to refresh the entire component at once. +
+ + + +
Type:
+
    +
  • + +boolean + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

starting_players :Array.<object>

+ + + + +
+ Array of players filling starting line up positions. If no player is in +a position, then only the "postition" key will be set. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

team_name :string

+ + + + +
+ The team name. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

update()

+ + + + + + +
+ Force re-render the entire component by briefly hiding it. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is instantiated. Initializes the bench players data. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/Router.html b/app/assets/frontend/documentation/generated/Router.html new file mode 100644 index 0000000..044686d --- /dev/null +++ b/app/assets/frontend/documentation/generated/Router.html @@ -0,0 +1,1013 @@ + + + + + JSDoc: Class: Router + + + + + + + + + + +
+ +

Class: Router

+ + + + + + +
+ +
+ +

Router()

+ +
A bare-bones history-api based SPA router.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new Router()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

base_path

+ + + + +
+ Returns the APP_BASE_PATH of the application. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

history

+ + + + +
+ Array of router history records. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

route_args :undefined|*

+ + + + +
+ Arguments for the current route. +
+ + + +
Type:
+
    +
  • + +undefined +| + +* + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

subscribers

+ + + + +
+ List of callback functions listening for route changes. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

back()

+ + + + + + +
+ Navigate back one route. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

build_url(…parts) → {string}

+ + + + + + +
+ Given an array of route parts, build a joined URL route. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
parts + + +string + + + + + + + + + + <repeatable>
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ Navigate the app to the given path with the given args. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + +string + + + +
args + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

subscribe(handler) → {object}

+ + + + + + +
+ Subscribe to listen for route changes. Returns an object with an unsubscribe() property. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
handler + + +function + + + + callback called when the route changes
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - subscription manager +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/ScoresComponent.html b/app/assets/frontend/documentation/generated/ScoresComponent.html new file mode 100644 index 0000000..ad59ae0 --- /dev/null +++ b/app/assets/frontend/documentation/generated/ScoresComponent.html @@ -0,0 +1,903 @@ + + + + + JSDoc: Class: ScoresComponent + + + + + + + + + + +
+ +

Class: ScoresComponent

+ + + + + + +
+ +
+ +

ScoresComponent()

+ +
Component representing the scores & match-ups page.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new ScoresComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

column_defs :Array.<object>

+ + + + +
+ Column definitions for the matchups grid. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

current_week :number

+ + + + +
+ The number of the current week shown in the interface +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

data :Array.<object>

+ + + + +
+ The currently shown week's data. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

max_week :number

+ + + + +
+ Most recent week number. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

min_week :number

+ + + + +
+ Least recent week number. +
+ + + +
Type:
+
    +
  • + +number + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

week_x_data :Array.<Array.<object>>

+ + + + +
+ Array of arrays of data for each week with first item being week 1, second being week 2, &c. +
+ + + +
Type:
+
    +
  • + +Array.<Array.<object>> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

to_next_week()

+ + + + + + +
+ When called, advances the data to the next-most recent week, if one exists. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

to_previous_week()

+ + + + + + +
+ When called, advances the data to the next-least recent week, if one exists. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is instantiated. Initializes the current week to the most recent week. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/TopLevelComponent.html b/app/assets/frontend/documentation/generated/TopLevelComponent.html new file mode 100644 index 0000000..f7603c8 --- /dev/null +++ b/app/assets/frontend/documentation/generated/TopLevelComponent.html @@ -0,0 +1,723 @@ + + + + + JSDoc: Class: TopLevelComponent + + + + + + + + + + +
+ +

Class: TopLevelComponent

+ + + + + + +
+ +
+ +

TopLevelComponent()

+ +
Top-level component which manages the display of the entire game.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new TopLevelComponent()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + +

Extends

+ + + + +
    +
  • Component
  • +
+ + + + + + + + + + + + + + + +

Members

+ + + +

current_route :string

+ + + + +
+ The currently loaded page route. +
+ + + +
Type:
+
    +
  • + +string + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + +
+ Array of navigation bar items where "title" is the page name, and "page" is the page route. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

(async) on_route_change(path, args) → {Promise.<void>}

+ + + + + + +
+ Called when the navigation changes. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + +string + + + +
args + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

(async) vue_on_create() → {Promise.<void>}

+ + + + + + +
+ Called when the component is initialized. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +

(async) vue_on_destroy() → {Promise.<void>}

+ + + + + + +
+ Called when the component is destroyed. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Promise.<void> + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/components_Grid.component.js.html b/app/assets/frontend/documentation/generated/components_Grid.component.js.html new file mode 100644 index 0000000..8aef6e8 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_Grid.component.js.html @@ -0,0 +1,123 @@ + + + + + JSDoc: Source: components/Grid.component.js + + + + + + + + + + +
+ +

Source: components/Grid.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+
+/**
+ * An enum representing the different grid cell renderer types for the shared grid.
+ * @type {object}
+ */
+const GridCellRenderType = {
+    Simple: Symbol('simple'),
+    HTML: Symbol('html'),
+    Component: Symbol('component'),
+}
+
+export {GridCellRenderType}
+
+const template = `
+<div class="component-app-grid">
+    <table>
+        <tr>
+            <th v-if="show_row_numbers">#</th>
+            <th v-for="col of column_defs" :title="col.title || ''">{{ col.header || '' }}</th>
+        </tr>
+        <tr v-for="(row, idx) of data">
+            <td v-if="show_row_numbers">{{ idx + 1 }}</td>
+            <td v-for="col of column_defs">
+                <div v-if="!col.type || col.type === GridCellRenderType.Simple">{{ row[col.key] }}</div>
+                <div v-if="col.type === GridCellRenderType.HTML" v-html="col.renderer(row[col.key], row)"></div>
+                <div v-if="col.type === GridCellRenderType.Component">
+                    <component :is="col.component" :row="row" :col="col" :idx="idx" @click="on_col_click(col, $event)"></component>
+                </div>
+            </td>
+        </tr>
+    </table>
+</div>
+`
+
+/**
+ * Shared grid component used to show tables in various interfaces.
+ * @extends Component
+ */
+class GridComponent extends Component {
+    static get selector() { return 'app-grid' }
+    static get template() { return template }
+    static get props() {
+        return [
+            'show_row_numbers',
+            'column_defs',
+            'data',
+        ]
+    }
+
+    GridCellRenderType = GridCellRenderType
+
+    /**
+     * Called when the component is instantiated.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+
+    }
+
+    /**
+     * Called when the component renderer emits a click event, to pass it along to the column definition.
+     * @param {object} col - the column definition
+     * @param {object} row - the row clicked
+     * @param {object} passcol - the column emitted from the component
+     */
+    on_col_click(col, [row, passcol]) {
+        col.on_click(row, passcol)
+    }
+}
+
+export default GridComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_GridActionButton.component.js.html b/app/assets/frontend/documentation/generated/components_GridActionButton.component.js.html new file mode 100644 index 0000000..a757458 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_GridActionButton.component.js.html @@ -0,0 +1,166 @@ + + + + + JSDoc: Source: components/GridActionButton.component.js + + + + + + + + + + +
+ +

Source: components/GridActionButton.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+
+const template = `
+<div class="component-action-button">
+    <button
+        v-if="!hidden"
+        v-bind:style="{border: '2px solid lightgrey', borderRadius: '3px', backgroundColor: color, color: 'white'}"
+        @click="on_click($event)"
+    >{{ text }}</button>
+</div>
+`
+
+/**
+ * Component representing an action button that can be embedded in the shared grid.
+ * @extends Component
+ */
+class GridActionButtonComponent extends Component {
+    static get selector() { return 'app-action-button' }
+    static get template() { return template }
+    static get props() { return ['row', 'col'] }
+
+    /**
+     * The text shown on the action button.
+     * @type {string}
+     */
+    text = ''
+
+    /**
+     * The CSS color of the action button.
+     * @type {string}
+     */
+    color = 'white'
+
+    /**
+     * If true, the action button will be hidden.
+     * @type {boolean}
+     */
+    hidden = false
+
+    /**
+     * Called when the component is instantiated. Updates the text, color, and hide status.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        this.update_text()
+        this.update_color()
+        this.update_hidden()
+    }
+
+    /**
+     * Called when the row value changes. Updates the text, color, and hide status.
+     */
+    watch_row() {
+        this.update_text()
+        this.update_color()
+        this.update_hidden()
+    }
+
+    /**
+     * Called when the column value changes. Updates the text, color, and hide status.
+     */
+    watch_col() {
+        this.update_text()
+        this.update_color()
+        this.update_hidden()
+    }
+
+    /**
+     * Determine the text to show on the button based on the column definition.
+     */
+    update_text() {
+        if ( typeof this.col.button_text === 'function' ) {
+            this.text = this.col.button_text(this.row, this.col)
+        } else {
+            this.text = this.col.button_text || ''
+        }
+    }
+
+    /**
+     * Determine the color to show on the button based on the column definition.
+     */
+    update_color() {
+        if ( typeof this.col.button_color === 'function' ) {
+            this.color = this.col.button_color(this.row, this.col)
+        } else {
+            this.color = this.col.button_color || 'white'
+        }
+    }
+
+    /**
+     * Determine whether the button should be shown or not, based on the column definition.
+     */
+    update_hidden() {
+        if ( !('button_hidden' in this.col) ) {
+            this.hidden = false;
+        } else if ( typeof this.col.button_hidden === 'function' ) {
+            this.hidden = this.col.button_hidden(this.row, this.col)
+        } else {
+            this.hidden = this.col.button_hidden
+        }
+    }
+
+    /**
+     * Called when the button is clicked. Emits a click event and updates the text, color, and hide status.
+     * @param {MouseEvent} $event
+     */
+    on_click($event) {
+        this.$emit('click', [this.row, this.col])
+        this.update_text()
+        this.update_color()
+        this.update_hidden()
+    }
+}
+
+export default GridActionButtonComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_Link.component.js.html b/app/assets/frontend/documentation/generated/components_Link.component.js.html new file mode 100644 index 0000000..8b794a0 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_Link.component.js.html @@ -0,0 +1,76 @@ + + + + + JSDoc: Source: components/Link.component.js + + + + + + + + + + +
+ +

Source: components/Link.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+import {router} from '../module/routing.js'
+
+const template = `
+<a href="#" @click="on_click()">{{ text }}</a>
+`
+
+/**
+ * Component providing hyper-links that navigate to other pages in the SPA,
+ * without reloading the page.
+ */
+class LinkComponent extends Component {
+    static get selector() { return 'app-link' }
+    static get template() { return template }
+    static get props() { return ['href', 'args', 'text'] }
+
+    /**
+     * Called when the link is clicked. Navigates the router.
+     */
+    on_click() {
+        router.navigate(this.href, this.args)
+    }
+}
+
+export default LinkComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_TopLevel.component.js.html b/app/assets/frontend/documentation/generated/components_TopLevel.component.js.html new file mode 100644 index 0000000..c5330f3 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_TopLevel.component.js.html @@ -0,0 +1,152 @@ + + + + + JSDoc: Source: components/TopLevel.component.js + + + + + + + + + + +
+ +

Source: components/TopLevel.component.js

+ + + + + + +
+
+
import {Component} from '../../lib/vues6.js'
+import {router} from '../module/routing.js'
+
+const template = `
+<div class="top-level-container">
+    <div class="navbar-container">
+        <h1 class="title">Fantasy Football</h1>
+        <ul class="navbar">
+            <li class="navbar-item" v-for="item of navbar_items" :class="{ active: current_route === item.page }">
+                <app-link :href="item.page" :text="item.title"></app-link>
+            </li>
+            
+            <li class="navbar-item">
+                <a href="#" @click="on_refresh($event)">Refresh</a>
+            </li>
+        </ul>
+    </div>
+    <div class="page-container">
+        <page-my-team v-if="current_route === 'my-team'"></page-my-team>
+        <page-add-players v-if="current_route === 'my-team/add-players'"></page-add-players>
+        <page-scores v-if="current_route === 'scores'"></page-scores>
+        <page-league v-if="current_route === 'league'"></page-league>
+        <page-draft-board v-if="current_route === 'draft-board'"></page-draft-board>
+    </div>
+</div>
+`
+
+/**
+ * Top-level component which manages the display of the entire game.
+ * @extends Component
+ */
+class TopLevelComponent extends Component {
+    static get selector() { return 'app-top-level' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    /**
+     * The currently loaded page route.
+     * @type {string}
+     */
+    current_route = ''
+
+    /**
+     * Array of navigation bar items where "title" is the page name, and "page" is the page route.
+     * @type {Array<object>}
+     */
+    navbar_items = [
+        { title: 'My Team', page: 'my-team' },
+        { title: 'Add Players', page: 'my-team/add-players' },
+        { title: 'Scores', page: 'scores' },
+        { title: 'League', page: 'league' },
+        { title: 'Draft Board', page: 'draft-board' },
+    ]
+
+    /**
+     * Called when the component is initialized.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        // Listen for navigation changes.
+        this.router_subscription = router.subscribe((path, args) => this.on_route_change(path, args))
+
+        if ( !this.current_route ) {
+            router.navigate('my-team')
+        }
+
+        const url_params = new URLSearchParams(window.location.search)
+        if ( url_params.has('then') ) {
+            const route = url_params.get('then')
+            router.navigate(route)
+        }
+    }
+
+    /**
+     * Called when the component is destroyed.
+     * @return {Promise<void>}
+     */
+    async vue_on_destroy() {
+        // Stop listening for navigation changes.
+        this.router_subscription.unsubscribe()
+    }
+
+    /**
+     * Called when the navigation changes.
+     * @param {string} path
+     * @param {*} args
+     * @return {Promise<void>}
+     */
+    async on_route_change(path, args) {
+        if ( path.startsWith('/') ) path = path.slice(1)
+        if ( path.endsWith('/') ) path = path.slice(0, -1)
+
+        this.current_route = path
+    }
+
+    on_refresh($event) {
+        window.location.href = `/?then=${this.current_route}`
+    }
+}
+
+export default TopLevelComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_pages_AddPlayers.component.js.html b/app/assets/frontend/documentation/generated/components_pages_AddPlayers.component.js.html new file mode 100644 index 0000000..2ac4551 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_pages_AddPlayers.component.js.html @@ -0,0 +1,641 @@ + + + + + JSDoc: Source: components/pages/AddPlayers.component.js + + + + + + + + + + +
+ +

Source: components/pages/AddPlayers.component.js

+ + + + + + +
+
+
import { Component } from '../../../lib/vues6.js'
+
+const template = `
+<div class="page-add-players">
+    <div class="header">
+        <div class="left">
+            <h2>Add Players to Team</h2>
+        </div>
+        <div class="right">
+            <button :class="{ 'disable-click': my_team_only }" @click="to_my_team_only()">My Team</button><button :class="{ 'disable-click': !my_team_only }" @click="to_all_players()">All Players</button>
+        </div>
+        <div class="right">
+            <input type="text" placeholder="Quick filter..." v-model="quick_filter" @keyup="on_filter_change()">
+        </div>
+    </div>
+    <div class="item-grid">
+        <div class="item" v-for="player of filtered_players" @mouseover="on_photo_hover(player)"
+        @mouseleave="on_photo_leave(player)">
+            <div style="display: flex; flex-direction: column; height: 100%;">
+                    <div class="item-icon" v-if="!player.showing_stats">
+                        <img :src="player.image" :alt="player.name">
+                    </div>   
+                    <div class="item-contents" v-if="!player.showing_stats">
+                        <h1>{{ player.name }}</h1>
+                        <p>#{{ player.number }} ({{ player.position }})</p>
+                        <div class="moreStats">
+                            <p>{{ player.stats }}</p>
+                        </div>
+                    </div>
+                    <div class="item-contents" style="flex: 1;" v-else>
+                        Hi! Show stats here.
+                    </div>
+                    <div class="item-button">
+                        <button
+                            v-if="my_team.length < 15 && !my_team.includes(player)"
+                            @click="add_to_team(player)"
+                            class="add"
+                        >Add to Team</button>
+                        <button
+                            v-if="my_team.includes(player)"
+                            @click="remove_from_team(player)"
+                            class="remove"
+                        >Remove from Team</button>
+                    </div>
+            </div>           
+
+        </div>
+    </div>
+</div>
+`
+
+/**
+ * A component which represents the "Add Players" page. Allows users to add/remove
+ * players from their team.
+ * @extends Component
+ */
+class AddPlayersComponent extends Component {
+    static get selector() { return 'page-add-players' }
+    static get props() { return [] }
+    static get template() { return template }
+
+    /**
+     * The current value of the quick filter for players. If empty string, no filter is applied.
+     * @type {string}
+     */
+    quick_filter = ''
+
+    /**
+     * If true, then only the players on the user's team will be shown.
+     * @type {boolean}
+     */
+    my_team_only = false
+
+    /**
+     * Array of players currently on the user's team.
+     * @type {object[]}
+     */
+    my_team = []
+
+    /**
+     * Array of currently displayed players, after the filter has been applied.
+     * @type {object[]}
+     */
+    filtered_players = []
+
+    /**
+     * Array of currently displayed players, before the filter has been applied.
+     * @type {object[]}
+     */
+    possible_players = []
+
+    /**
+     * All available players, whether they are on the user's team or not.
+     * @type {object[]}
+     */
+    all_players = [
+        {
+            "number": 14,
+            "name": "Andy Dalton",
+            "position": "Quarterback",
+            "stats": "Passing: 1,856 YDS",
+            "image": "https://images.generated.photos/-K9iBY4oOkLsqQfoTA1R8X0EKvR_BCbMXk0KNX4EIIs/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0NzY1MjkuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 7,
+            "name": "Ben DiNucci",
+            "position": "Quarterback",
+            "stats": "Passing: 856 YDS",
+            "image": "https://images.generated.photos/EUa6Hmnt6682dl03Q5FPIeMqLnS833rfzOJaJXlYxqI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTk3OTFfMDU1/Nzg5OF8wMzgzMzIw/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 3,
+            "name": "Garrett Gilbert",
+            "position": "Quarterback",
+            "stats": "Passing: 758 YDS",
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+            "showing_stats": false
+        
+        },
+        {
+            "number": 34,
+            "name": "Rico Dowdle",
+            "position": "Running back",
+            "stats": "1,368 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 21,
+            "name": "Ezekiel Elliott",
+            "position": "Running back",
+            "stats": "1,842 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 20,
+            "name": "Tony Pollard",
+            "position": "Running back",
+            "stats": "1,623 YDS",
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 85,
+            "name": "Noah Brown",
+            "position": "Wide receiver",
+            "stats": "666 YDS",
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 19,
+            "name": "Amari Cooper",
+            "position": "Wide receiver",
+            "stats": "256 YDS",
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 13,
+            "name": "Michael Gallup",
+            "position": "Wide receiver",
+            "stats": "13 YDS",
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+            "showing_stats": false
+        
+        },
+        {
+            "number": 88,
+            "name": "CeeDee Lamb",
+            "position": "Wide receiver",
+            "stats": "25 YDS",
+            "image": "https://images.generated.photos/WFV4nHHq5ZaBb1rdmFL5WEZTOanckWHEfkmDA1fOVfw/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTYzNzNfMDI4/Nzc2N18wNzYxNDY3/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 17,
+            "name": "Malik Turner",
+            "position": "Wide receiver",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 11,
+            "name": "Cedrick Wilson Jr.",
+            "position": "Wide receiver",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 80,
+            "name": "Blake Bell",
+            "position": "Tight end",
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 84,
+            "name": "Sean McKeon",
+            "position": "Tight end",
+            "image": "https://images.generated.photos/EUa6Hmnt6682dl03Q5FPIeMqLnS833rfzOJaJXlYxqI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTk3OTFfMDU1/Nzg5OF8wMzgzMzIw/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 86,
+            "name": "Dalton Schultz",
+            "position": "Tight end",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/-K9iBY4oOkLsqQfoTA1R8X0EKvR_BCbMXk0KNX4EIIs/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0NzY1MjkuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 63,
+            "name": "Tyler Biadasz C",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 69,
+            "name": "Brandon Knight T/G",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 70,
+            "name": "Zack Martin G",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 66,
+            "name": "Connor McGovern G",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 64,
+            "name": "Greg Senat T",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/WFV4nHHq5ZaBb1rdmFL5WEZTOanckWHEfkmDA1fOVfw/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTYzNzNfMDI4/Nzc2N18wNzYxNDY3/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 78,
+            "name": "Terence Steele T",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 52,
+            "name": "Connor Williams G",
+            "position": "Offensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 56,
+            "name": "Bradlee Anae DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 92,
+            "name": "Dorance Armstrong DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/EUa6Hmnt6682dl03Q5FPIeMqLnS833rfzOJaJXlYxqI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTk3OTFfMDU1/Nzg5OF8wMzgzMzIw/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 98,
+            "name": "Tyrone Crawford DT/DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/-K9iBY4oOkLsqQfoTA1R8X0EKvR_BCbMXk0KNX4EIIs/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0NzY1MjkuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 96,
+            "name": "Neville Gallimore DT",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 94,
+            "name": "Randy Gregory DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 97,
+            "name": "Everson Griffen DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 79,
+            "name": "Justin Hamilton DT",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 90,
+            "name": "DeMarcus Lawrence DE",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/WFV4nHHq5ZaBb1rdmFL5WEZTOanckWHEfkmDA1fOVfw/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTYzNzNfMDI4/Nzc2N18wNzYxNDY3/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 95,
+            "name": "Dontari Poe DT",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 58,
+            "name": "Aldon Smith DE/OLB",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 99,
+            "name": "Antwaun Woods DT",
+            "position": "Defensive lineman",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 57,
+            "name": "Luke Gifford MLB/OLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/EUa6Hmnt6682dl03Q5FPIeMqLnS833rfzOJaJXlYxqI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTk3OTFfMDU1/Nzg5OF8wMzgzMzIw/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 59,
+            "name": "Justin March OLB/MLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/-K9iBY4oOkLsqQfoTA1R8X0EKvR_BCbMXk0KNX4EIIs/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0NzY1MjkuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 54,
+            "name": "Jaylon Smith OLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 53,
+            "name": "Rashad Smith MLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 48,
+            "name": "Joe Thomas OLB/MLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 55,
+            "name": "Leighton Vander Esch MLB",
+            "position": "Linebacker",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 30,
+            "name": "Anthony Brown CB",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/WFV4nHHq5ZaBb1rdmFL5WEZTOanckWHEfkmDA1fOVfw/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTYzNzNfMDI4/Nzc2N18wNzYxNDY3/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 27,
+            "name": "Trevon Diggs CB",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 29,
+            "name": "C. J. Goodwin CB",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 26,
+            "name": "Jourdan Lewis CB",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 40,
+            "name": "Steven Parker SS/FS",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/EUa6Hmnt6682dl03Q5FPIeMqLnS833rfzOJaJXlYxqI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTk3OTFfMDU1/Nzg5OF8wMzgzMzIw/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 41,
+            "name": "Reggie Robinson FS/CB",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/-K9iBY4oOkLsqQfoTA1R8X0EKvR_BCbMXk0KNX4EIIs/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0NzY1MjkuanBn.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 23,
+            "name": "Darian Thompson SS/FS",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 37,
+            "name": "Donovan Wilson SS/FS",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 25,
+            "name": "Xavier Woods FS",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 28,
+            "name": "Daryl Worley CB/S",
+            "position": "Defensive back",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 6,
+            "name": "Chris Jones P",
+            "position": "Special team",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/WFV4nHHq5ZaBb1rdmFL5WEZTOanckWHEfkmDA1fOVfw/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxNTYzNzNfMDI4/Nzc2N18wNzYxNDY3/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 91,
+            "name": "L. P. Ladouceur LS",
+            "position": "Special team",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+            "showing_stats": false
+        },
+        {
+            "number": 2,
+            "name": "Greg Zuerlein K",
+            "position": "Special team",
+            "stats": "551 YDS",
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+            "showing_stats": false
+        }
+    ]
+
+    /**
+     * Called when the page is instantiated.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        this.possible_players = [...this.all_players];
+        this.filtered_players = [...this.possible_players];
+    }
+
+    /**
+     * Called when the quick-filter changes. Applies the filter to the displayed players.
+     */
+    on_filter_change() {
+        const query = this.quick_filter.toLowerCase()
+        this.filtered_players = this.possible_players.filter(x => {
+            if (!query) return true;
+            return x.name.toLowerCase().includes(query) || x.position.toLowerCase().includes(query)
+        })
+    }
+
+    /**
+     * When called, change the display to show only the user's team.
+     */
+    to_my_team_only() {
+        this.my_team_only = true;
+        this.possible_players = [...this.my_team]
+        this.on_filter_change()
+    }
+
+    /**
+     * When called, change the display to show all available players.
+     */
+    to_all_players() {  
+        this.my_team_only = false;
+        this.possible_players = [...this.all_players]
+        this.on_filter_change()
+    }
+
+    /**
+     * Add the given player to the user's team, if not already there.
+     * @param {object} player
+     */
+    add_to_team(player) {
+        if (!this.my_team.includes(player)) {
+            this.my_team.push(player)
+        }
+    }
+
+    /**
+     * Remove the given player from the user's team, if there.
+     * @param {object} player
+     */
+    remove_from_team(player) {
+        this.my_team = this.my_team.filter(x => x !== player)
+        player.showing_stats = false
+        if (this.my_team_only) this.to_my_team_only()
+    }
+
+    /**
+     * Called when the user hovers over a player. Toggles the stats to be shown.
+     * @param {object} player
+     */
+    on_photo_hover(player) {
+        player.showing_stats = true
+    }
+
+    /**
+     * Called when the user un-hovers over a player. Toggles the stats to hide.
+     * @param {object} player
+     */
+    on_photo_leave(player) {
+        player.showing_stats = false
+    }
+}
+
+export default AddPlayersComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_pages_DraftBoard.component.js.html b/app/assets/frontend/documentation/generated/components_pages_DraftBoard.component.js.html new file mode 100644 index 0000000..db87f4b --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_pages_DraftBoard.component.js.html @@ -0,0 +1,74 @@ + + + + + JSDoc: Source: components/pages/DraftBoard.component.js + + + + + + + + + + +
+ +

Source: components/pages/DraftBoard.component.js

+ + + + + + +
+
+
import {Component} from '../../../lib/vues6.js'
+
+const template = `
+<div class="page-draft-board">
+Draft Board
+</div>
+`
+
+/**
+ * Component representing the draft board page.
+ * @extends Component
+ */
+class DraftBoardComponent extends Component {
+    static get selector() { return 'page-draft-board' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    async vue_on_create() {
+
+    }
+}
+
+export default DraftBoardComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_pages_League.component.js.html b/app/assets/frontend/documentation/generated/components_pages_League.component.js.html new file mode 100644 index 0000000..da73a59 --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_pages_League.component.js.html @@ -0,0 +1,222 @@ + + + + + JSDoc: Source: components/pages/League.component.js + + + + + + + + + + +
+ +

Source: components/pages/League.component.js

+ + + + + + +
+
+
import {Component} from '../../../lib/vues6.js'
+import {GridCellRenderType} from '../Grid.component.js'
+
+const template = `
+<div class="page-league">
+  <div class="header">
+    League Standings
+  </div>
+    <app-grid
+        :column_defs="column_defs"
+        :data="data"
+        :show_row_numbers="false"
+    ></app-grid>
+</div>
+`
+
+/**
+ * Component representing the league standings page.
+ * @extends Component
+ */
+class LeagueComponent extends Component {
+    static get selector() { return 'page-league' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    GridCellRenderType = GridCellRenderType
+
+    /**
+     * Column definitions for the league standings grid.
+     * @type {object[]}
+     */
+    column_defs = [
+        {
+            header: 'Standing',
+            type: GridCellRenderType.HTML,
+            key: 'standing',
+            renderer: (value, row) => {
+                return `
+                    <h1 id="ranking">
+                    Rank: ${row.standing.rank}
+                    </h1>
+                    <h2 id="record">
+                        W/L: ${row.standing.win_loss}
+                    </h2>
+                `
+
+            }
+        },
+        {
+            header: 'Team',
+            type: GridCellRenderType.HTML,
+            key: 'team_name',
+            renderer: (value, row) => {
+                return `
+                    <div class="center">
+                        <img src="${row.team_image}" alt="${row.team_image}">
+                        <span>${row.team_name}</span>
+                    </div>
+                `
+            },
+        },
+        {
+            header: 'Stats',
+            key: 'stats',
+        },
+        {
+            header: '',
+            key: 'team_name',
+            type: GridCellRenderType.Component,
+            component: Vue.component('app-action-button'),
+            button_color: '#CC5746',
+            button_text: 'Test Action',
+            on_click: (row, col) => {
+                console.log('button clicked!')
+            },
+        }
+    ]
+
+    /**
+     * Sample data for the league standings grid.
+     * @type {object[]}
+     */
+    data = [
+        {
+            standing: {
+                rank: 1,
+                win_loss: '3/0',
+            },
+            team_name: 'Team 1',
+            team_image: 'data:image/png;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+            ],
+        },
+        {
+            standing: {
+                rank: 2,
+                win_loss: '3/0',
+            },
+            team_name: 'Team B',
+            team_image: 'data:image/jpeg;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+            ],
+        },
+        {
+            standing: {
+                rank: 3,
+                win_loss: '2/1',
+            },
+            team_name: 'Team C',
+            team_image: 'data:image/png;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+
+            ],
+        },
+        {
+            standing: {
+                rank: 4,
+                win_loss: '2/1',
+            },
+            team_name: 'Team D',
+            team_image: 'data:image/png;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+
+            ],
+        },
+        {
+            standing: {
+                rank: 5,
+                win_loss: '1/2',
+            },
+            team_name: 'Team E',
+            team_image: 'data:image/png;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+
+            ],
+        },
+        {
+            standing: {
+                rank: 6,
+                win_loss: '0/3',
+            },
+            team_name: 'Team F',
+            team_image: 'data:image/jpeg;base64,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',
+            stats: [
+                { name: 'Total Points Scored', value: 1 },
+                { name: 'Total Points Scored Against', value: 2 },
+
+            ],
+        },
+    ]
+
+    /**
+     * Called when the component is instantiated.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+
+    }
+}
+
+export default LeagueComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_pages_MyTeam.component.js.html b/app/assets/frontend/documentation/generated/components_pages_MyTeam.component.js.html new file mode 100644 index 0000000..51bf06b --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_pages_MyTeam.component.js.html @@ -0,0 +1,315 @@ + + + + + JSDoc: Source: components/pages/MyTeam.component.js + + + + + + + + + + +
+ +

Source: components/pages/MyTeam.component.js

+ + + + + + +
+
+
import {Component} from '../../../lib/vues6.js'
+import {GridCellRenderType} from '../Grid.component.js'
+
+const template = `
+<div class="page-my-team">
+    <div class="header">
+        <div class="left team-name">
+            <h2>My Team - </h2><input placeholder="Click to edit team name..." type="text" v-model="team_name">
+        </div>
+    </div>
+    <div class="body" style="display: flex; flex-direction: row; margin-left: 10px; padding-bottom: 50px;" v-if="show_body">
+        <app-grid
+            :column_defs="overall_column_defs"
+            :data="overall_data"
+            :show_row_numbers="true"
+            style="flex: 1;"
+        ></app-grid>
+        <div class="lineup-grids" style="margin-left: 30px; margin-right: 10px; flex: 1;">
+            <h3>Starting Lineup</h3>
+            <app-grid
+                :column_defs="lineup_column_defs"
+                :data="starting_players"
+                :show_row_numbers="false"
+            ></app-grid>
+
+            <h3>Bench</h3>
+            <app-grid
+                :column_defs="lineup_column_defs"
+                :data="bench_players"
+                :show_row_numbers="false"
+            ></app-grid>
+        </div>
+    </div>
+</div>
+`
+
+/**
+ * Component representing the my-team page.
+ * @extends Component
+ */
+class MyTeamComponent extends Component {
+    static get selector() { return 'page-my-team' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    /**
+     * The team name.
+     * @type {string}
+     */
+    team_name = ''
+
+    /**
+     * If true, the body of the page will be shown. Otherwise, hidden.
+     * This is used to refresh the entire component at once.
+     * @type {boolean}
+     */
+    show_body = true
+
+    /**
+     * The player currently being moved. If none, then will be set to undefined.
+     * @type {undefined}
+     */
+    moving_player = undefined
+
+    /**
+     * Array of players filling starting line up positions. If no player is in
+     * a position, then only the "postition" key will be set.
+     * @type {object[]}
+     */
+    starting_players = [
+        {
+            position: 'QB',
+        },
+        {
+            position: 'RB',
+        },
+        {
+            position: 'RB',
+        },
+        {
+            position: 'WR',
+        },
+        {
+            position: 'WR',
+        },
+        {
+            position: 'TE',
+        },
+        {
+            position: 'FLX',
+        },
+        {
+            position: 'DST',
+        },
+    ]
+
+    /**
+     * Players on the bench.
+     * @type {object[]}
+     */
+    bench_players = []
+
+    /**
+     * Column definitions for the starting/bench lineup grids.
+     * @type {object[]}
+     */
+    lineup_column_defs = [
+        {
+            header: 'POS',
+            key: 'position',
+        },
+        {
+            header: 'Player',
+            key: 'player_name',
+            type: GridCellRenderType.HTML,
+            renderer: (_, data) => {
+                if ( !data.player_name ) {
+                    return `<i style="color: darkgrey">none</i>`
+                } else {
+                    return `
+                        <div class="center">
+                            <img src="${data.image}" alt="${data.player_name}" height="50" style="border-radius: 50%">
+                            <span>${data.player_name}</span>
+                        </div>
+                    `
+                }
+            },
+        },
+        {
+            header: '',
+            key: 'player_name',
+            type: GridCellRenderType.Component,
+            component: Vue.component('app-action-button'),
+            button_color: (row, col) => this.moving_player ? '#CC5746' : '#0582CA',
+            button_text: (row, col) => {
+                return this.moving_player ? 'Here' : 'Move'
+            },
+            button_hidden: (row, col) => {
+                if ( this.moving_player && this.moving_player.player_name !== row.player_name ) return false;
+                if ( !row.player_name ) return true;
+                return this.moving_player && this.moving_player.player_name === row.player_name;
+            },
+            on_click: (row, col) => {
+                if ( !this.moving_player ) {
+                    this.moving_player = row;
+                } else {
+                    const old_row = {...row};
+                    row.player_name = this.moving_player.player_name;
+                    row.ecr = this.moving_player.ecr;
+                    row.image = this.moving_player.image;
+
+                    this.moving_player.player_name = old_row.player_name;
+                    this.moving_player.ecr = old_row.ecr;
+                    this.moving_player.image = old_row.image;
+                    this.moving_player = undefined;
+                    console.log(this.moving_player, row);
+                }
+
+                this.$_vue_inst.update();  // $_vue_inst refers to the Vue.component instance, not the data class.
+            },
+        },
+    ]
+
+    /**
+     * Column definitions for the overall team grid.
+     * @type {object[]}
+     */
+    overall_column_defs = [
+        {
+            header: 'Name',
+            key: 'player_name',
+            type: GridCellRenderType.HTML,
+            renderer: (_, data) => `
+                <div class="center">
+                    <img src="${data.image}" alt="${data.player_name}" height="50" style="border-radius: 50%">
+                    <span>${data.player_name}</span>
+                </div>
+            `,
+        },
+        {
+            header: 'POS',
+            key: 'position',
+        },
+        {
+            header: 'ECR',
+            title: 'Expected Coverage Rating',
+            key: 'ecr',
+        },
+    ]
+
+    /**
+     * Data for the overall team grid (list of user's team players).
+     * @type {object[]}
+     */
+    overall_data = [
+        {
+            player_name: 'Christian McCaffrey',
+            position: 'RB1',
+            ecr: '0.0',
+            "image": "https://images.generated.photos/eGoWRgqxtahGFDAD81-l8CNxdz1oe-huz3CQ7m3v0VI/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzNDA0NDlfMDgz/MDY1Nl8wMTk4NTI4/LmpwZw.jpg",
+        },
+        {
+            player_name: 'Ezekiel Elliott',
+            position: 'RB3',
+            ecr: '1.0',
+            "image": "https://images.generated.photos/fd8kkioB4vLw_5MGwQXdDt9Q7Ley2_Ia8Cu390zaNVM/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA0Nzg2ODEuanBn.jpg",
+        },
+        {
+            player_name: 'Dalvin Cook',
+            position: 'RB5',
+            ecr: '0.0',
+            "image": "https://images.generated.photos/PEBx5b8_iPHU_nJpJbh3geUN8cBFglHVAAR9NktzXsk/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAxODI1NzlfMDgx/MTA0OV8wNDQzOTM5/LmpwZw.jpg",
+        },
+        {
+            player_name: 'Alvin Kamara',
+            position: 'RB6',
+            ecr: '-1.0',
+            "image": "https://images.generated.photos/cb3jAo-GBziFLxs85KJGt7a8bJdhz4sSy76PYAXkeg4/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzA1ODU4MDBfMDMy/NjY2OF8wODEwNTA2/LmpwZw.jpg",
+        },
+        {
+            player_name: 'Michael Thomas',
+            position: 'WR1',
+            ecr: '3.0',
+            "image": "https://images.generated.photos/LLiy3FypH5A1suda78U82t_Kcn9AlJwZt1g3w1p5DwE/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODc0NjlfMDUy/MDc0NF8wNzc3NzQ5/LmpwZw.jpg",
+        },
+        {
+            player_name: 'Davante Adams',
+            position: 'WR2',
+            ecr: '4.0',
+            "image": "https://images.generated.photos/dW84LNLE4Kzp73NTTnL68U--dYuq8CCzD-dGTs76U38/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAyNjE1NjZfMDEz/NDM1NF8wMTg5MjI0/LmpwZw.jpg",
+        },
+        {
+            player_name: 'Travis Kelce',
+            position: 'TE1',
+            ecr: '-4.0',
+            "image": "https://images.generated.photos/erudOopARQnXWNaLqkIPRLLMLAVBr8m70aFC_dtYu1Y/rs:fit:128:128/Z3M6Ly9nZW5lcmF0/ZWQtcGhvdG9zL3Yz/XzAzODA5MTVfMDkx/MzIzN18wNDQxMTk4/LmpwZw.jpg",
+        },
+    ]
+
+    /**
+     * Called when the component is instantiated. Initializes the bench players data.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        this.bench_players = this.overall_data.map(x => { x = {...x, position: 'B'}; return x })
+
+        setTimeout(() => {
+            this.update();
+        }, 500);
+    }
+
+    /**
+     * Force re-render the entire component by briefly hiding it.
+     */
+    update() {
+        this.show_body = false;
+
+        this.$nextTick(() => {
+            this.show_body = true;
+        });
+    }
+}
+
+export default MyTeamComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/components_pages_Scores.component.js.html b/app/assets/frontend/documentation/generated/components_pages_Scores.component.js.html new file mode 100644 index 0000000..793ed1e --- /dev/null +++ b/app/assets/frontend/documentation/generated/components_pages_Scores.component.js.html @@ -0,0 +1,398 @@ + + + + + JSDoc: Source: components/pages/Scores.component.js + + + + + + + + + + +
+ +

Source: components/pages/Scores.component.js

+ + + + + + +
+
+
import {Component} from '../../../lib/vues6.js'
+import {GridCellRenderType} from '../Grid.component.js'
+
+const template = `
+<div class="page-scores">
+    <div class="header">
+        <div class="left">
+            <h2>Matchups & Scores - <small>Week {{ current_week }}</small></h2>
+        </div>
+        <div class="right">
+            <button :class="{ 'disable-click': current_week === max_week }" @click="to_next_week()">Next Week</button><button :class="{ 'disable-click': current_week === min_week }" @click="to_previous_week()">Previous Week</button>
+        </div>
+    </div>
+    <app-grid
+        :column_defs="column_defs"
+        :data="data"
+        :show_row_numbers="false"
+    ></app-grid>
+</div>
+`
+
+/**
+ * Component representing the scores & match-ups page.
+ * @extends Component
+ */
+class ScoresComponent extends Component {
+    static get selector() { return 'page-scores' }
+    static get template() { return template }
+    static get props() { return [] }
+
+    /**
+     * The number of the current week shown in the interface
+     * @type {number}
+     */
+    current_week = 6
+
+    /**
+     * Most recent week number.
+     * @type {number}
+     */
+    max_week = 6
+
+    /**
+     * Least recent week number.
+     * @type {number}
+     */
+    min_week = 1
+
+    /**
+     * Array of arrays of data for each week with first item being week 1, second being week 2, &c.
+     * @type {object[][]}
+     */
+    week_x_data = [
+        // Week 1 Data
+        [
+          {
+              "date": "11/2/2020",
+              "team_1": "Team 1",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 50,
+              "team_2": "Team 6",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 73
+          },
+          {
+              "date": "10/23/2020",
+              "team_1": "Team 2",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 66,
+              "team_2": "Team 5",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 71,
+              "winner": "Team 5",
+              "winner_score": "84",
+              "loser_score": "41",
+          },
+          {
+              "date": "10/31/2020",
+              "team_1": "Team 3",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 85,
+              "team_2": "Team 4",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 67
+          },
+        ],
+          // Week 2 Data
+        [
+          {
+              "date": "11/2/2020",
+              "team_1": "Team 1",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 58,
+              "team_2": "Team 6",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 34
+          },
+          {
+              "date": "10/23/2020",
+              "team_1": "Team 2",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 57,
+              "team_2": "Team 5",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 27,
+              "winner": "Team 5",
+              "winner_score": "84",
+              "loser_score": "41",
+          },
+          {
+              "date": "10/31/2020",
+              "team_1": "Team 3",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 48,
+              "team_2": "Team 4",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 49
+          },
+        ],
+          // Week 3 Data
+        [
+          {
+              "date": "11/2/2020",
+              "team_1": "Team 1",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 67,
+              "team_2": "Team 6",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 47
+          },
+          {
+              "date": "10/23/2020",
+              "team_1": "Team 2",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 83,
+              "team_2": "Team 5",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 62,
+              "winner": "Team 5",
+              "winner_score": "84",
+              "loser_score": "41",
+          },
+          {
+              "date": "10/31/2020",
+              "team_1": "Team 3",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 48,
+              "team_2": "Team 4",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 17
+          },
+        ],
+          // Week 4 Data
+        [
+          {
+              "date": "11/2/2020",
+              "team_1": "Team 1",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 30,
+              "team_2": "Team 6",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 41
+          },
+          {
+              "date": "10/23/2020",
+              "team_1": "Team 2",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 65,
+              "team_2": "Team 5",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 27,
+              "winner": "Team 5",
+              "winner_score": "84",
+              "loser_score": "41",
+          },
+          {
+              "date": "10/31/2020",
+              "team_1": "Team 3",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 48,
+              "team_2": "Team 4",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 24
+          },
+        ],
+          // Week 5 Data
+        [
+          {
+              "date": "11/2/2020",
+              "team_1": "Team 1",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 43,
+              "team_2": "Team 6",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 48
+          },
+          {
+              "date": "10/23/2020",
+              "team_1": "Team 2",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 57,
+              "team_2": "Team 5",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 61,
+              "winner": "Team 5",
+              "winner_score": "84",
+              "loser_score": "41",
+          },
+          {
+              "date": "10/31/2020",
+              "team_1": "Team 3",
+              "team_1_logo": "https://via.placeholder.com/150x100",
+              "team_1_projection": 48,
+              "team_2": "Team 4",
+              "team_2_logo": "https://via.placeholder.com/150x100",
+              "team_2_projection": 91
+          },
+        ],
+          // Week 6 Data
+        [
+            {
+                "date": "11/2/2020",
+                "team_1": "Team 1",
+                "team_1_logo": "https://via.placeholder.com/150x100",
+                "team_1_projection": 50,
+                "team_2": "Team 6",
+                "team_2_logo": "https://via.placeholder.com/150x100",
+                "team_2_projection": 37
+            },
+            {
+                "date": "10/23/2020",
+                "team_1": "Team 2",
+                "team_1_logo": "https://via.placeholder.com/150x100",
+                "team_1_projection": 36,
+                "team_2": "Team 5",
+                "team_2_logo": "https://via.placeholder.com/150x100",
+                "team_2_projection": 71,
+                "winner": "Team 5",
+                "winner_score": "84",
+                "loser_score": "41",
+            },
+            {
+                "date": "10/31/2020",
+                "team_1": "Team 3",
+                "team_1_logo": "https://via.placeholder.com/150x100",
+                "team_1_projection": 48,
+                "team_2": "Team 4",
+                "team_2_logo": "https://via.placeholder.com/150x100",
+                "team_2_projection": 1
+            },
+        ]
+    ]
+
+    /**
+     * Column definitions for the matchups grid.
+     * @type {object[]}
+     */
+    column_defs = [
+        {
+            header: 'Date',
+            type: GridCellRenderType.HTML,
+            key: 'date',
+            renderer: (_, data) => {
+                return `${data.date} @ ${data.team_1}`
+            }
+        },
+        {
+            header: 'Team 1',
+            type: GridCellRenderType.HTML,
+            key: 'team_1',
+            renderer: (_, data) => `
+                <div style="display: flex; flex-direction: row;">
+                    <img src="${data.team_1_logo}" alt="${data.team_1}">
+                    <div style="margin-left: 20px">
+                        <b>${data.team_1}</b>
+                        <p>Projection: ${data.team_1_projection}</p>
+                    </div>
+                </div>
+            `
+        },
+        {
+            header: 'Team 2',
+            type: GridCellRenderType.HTML,
+            key: 'team_2',
+            renderer: (_, data) => `
+                <div style="display: flex; flex-direction: row;">
+                    <img src="${data.team_2_logo}" alt="${data.team_2}">
+                    <div style="margin-left: 20px">
+                        <b>${data.team_2}</b>
+                        <p>Projection: ${data.team_2_projection}</p>
+                    </div>
+                </div>
+            `
+        },
+        {
+            header: 'Outcome',
+            type: GridCellRenderType.HTML,
+            key: 'winner',
+            renderer: (_, data) => {
+                if ( data?.winner ) {
+                    return `
+                        <div><b>Winner:</b> ${data.winner}</div>
+                        <div><b>Score: </b> ${data.winner_score} / ${data.loser_score}</div>
+                    `
+                } else {
+                    return `N/A`
+                }
+            },
+        }
+    ]
+
+    /**
+     * The currently shown week's data.
+     * @type {object[]}
+     */
+    data = []
+
+    /**
+     * Called when the component is instantiated. Initializes the current week to the most recent week.
+     * @return {Promise<void>}
+     */
+    async vue_on_create() {
+        this.data = this.week_x_data[this.max_week - 1];
+    }
+
+    /**
+     * When called, advances the data to the next-most recent week, if one exists.
+     */
+    to_next_week() {
+        if ( this.current_week < this.max_week ) {
+            this.current_week += 1;
+            this.data = this.week_x_data[this.current_week - 1];
+        }
+    }
+
+    /**
+     * When called, advances the data to the next-least recent week, if one exists.
+     */
+    to_previous_week() {
+        if ( this.current_week > this.min_week ) {
+            this.current_week -= 1;
+            this.data = this.week_x_data[this.current_week - 1];
+        }
+    }
+}
+
+export default ScoresComponent
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.eot new file mode 100644 index 0000000..5d20d91 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.svg new file mode 100644 index 0000000..3ed7be4 --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.woff new file mode 100644 index 0000000..1205787 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Bold-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot new file mode 100644 index 0000000..1f639a1 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg new file mode 100644 index 0000000..6a2607b --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff new file mode 100644 index 0000000..ed760c0 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-BoldItalic-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.eot new file mode 100644 index 0000000..0c8a0ae Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.svg new file mode 100644 index 0000000..e1075dc --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.svg @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.woff new file mode 100644 index 0000000..ff652e6 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Italic-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.eot new file mode 100644 index 0000000..1486840 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.svg new file mode 100644 index 0000000..11a472c --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.woff new file mode 100644 index 0000000..e786074 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Light-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot new file mode 100644 index 0000000..8f44592 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg new file mode 100644 index 0000000..431d7e3 --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.svg @@ -0,0 +1,1835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff new file mode 100644 index 0000000..43e8b9e Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-LightItalic-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.eot b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.eot new file mode 100644 index 0000000..6bbc3cf Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.eot differ diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.svg b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.svg new file mode 100644 index 0000000..25a3952 --- /dev/null +++ b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.svg @@ -0,0 +1,1831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.woff b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.woff new file mode 100644 index 0000000..e231183 Binary files /dev/null and b/app/assets/frontend/documentation/generated/fonts/OpenSans-Regular-webfont.woff differ diff --git a/app/assets/frontend/documentation/generated/global.html b/app/assets/frontend/documentation/generated/global.html new file mode 100644 index 0000000..c8bf871 --- /dev/null +++ b/app/assets/frontend/documentation/generated/global.html @@ -0,0 +1,201 @@ + + + + + JSDoc: Global + + + + + + + + + + +
+ +

Global

+ + + + + + +
+ +
+ +

+ + +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

(constant) GridCellRenderType :object

+ + + + +
+ An enum representing the different grid cell renderer types for the shared grid. +
+ + + +
Type:
+
    +
  • + +object + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/index.html b/app/assets/frontend/documentation/generated/index.html new file mode 100644 index 0000000..84f4329 --- /dev/null +++ b/app/assets/frontend/documentation/generated/index.html @@ -0,0 +1,112 @@ + + + + + JSDoc: Home + + + + + + + + + + +
+ +

Home

+ + + + + + + + +

+ + + + + + + + + + + + + + + +
+

Fantasy Football

+

EECS 448 - Projects 3 & 4

+

Structure Info

+

This project has been wired up to use Vue.js to help organize components of the game.

+

These components are defined in files that end in the .component.js extension, and are located in the src/components/ directory.

+

The entry point for the project is the index.html. This file contains the basic logic for loading Vue, and adding the game board to the page.

+

Obviously, we'll flesh out the look-and-feel as we go along. This is just a basic starter for now.

+

How to Run

+

The easiest way to run this project is by creating a basic static web server using Python. This is super simple:

+
    +
  1. Open a terminal or command prompt to the root of this project (i.e. the directory this file is in).
  2. +
  3. Start the server: python -m http.server
  4. +
+

This will start a web server on port 8000. You can then run the game by navigating to http://localhost:8000/ from a web browser.

+

Re-generating the documentation

+

To regenerate the docs, you need Node.js and the Yarn package manager installed. Then, just:

+
cd documentation
+./generate.sh
+
+

Works Cited

+

The files in the lib directory are external libraries used in this project.

+
    +
  • Vue.js +
      +
    • A front-end framework. Used under the terms of the MIT license.
    • +
    • https://github.com/vuejs/vue
    • +
    +
  • +
  • VuES6.js +
      +
    • A kind-of crappy loader for defining Vue components using ES6 classes.
    • +
    • Also used under the terms of the MIT license.
    • +
    • https://code.garrettmills.dev/garrettmills/vues6
    • +
    +
  • +
+

Contributors

+
    +
  • Lucas Brakenridge
  • +
  • Javier Barea Lara
  • +
  • Garrett Mills
  • +
  • Evan Powell
  • +
  • Alec Horlick-Mills
  • +
+
+ + + + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/module-routing-Router.html b/app/assets/frontend/documentation/generated/module-routing-Router.html new file mode 100644 index 0000000..931bfa7 --- /dev/null +++ b/app/assets/frontend/documentation/generated/module-routing-Router.html @@ -0,0 +1,1034 @@ + + + + + JSDoc: Class: Router + + + + + + + + + + +
+ +

Class: Router

+ + + + + + +
+ +
+ +

+ routing~Router()

+ +
A bare-bones history-api based SPA router.
+ + +
+ +
+
+ + + + +

Constructor

+ + + +

new Router()

+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +

Members

+ + + +

base_path

+ + + + +
+ Returns the APP_BASE_PATH of the application. +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

history :Array.<object>

+ + + + +
+ Array of router history records. +
+ + + +
Type:
+
    +
  • + +Array.<object> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

route_args :undefined|*

+ + + + +
+ Arguments for the current route. +
+ + + +
Type:
+
    +
  • + +undefined +| + +* + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + +

subscribers :Array.<function()>

+ + + + +
+ List of callback functions listening for route changes. +
+ + + +
Type:
+
    +
  • + +Array.<function()> + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + +

Methods

+ + + + + + + +

back()

+ + + + + + +
+ Navigate back one route. +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

build_url(…parts) → {string}

+ + + + + + +
+ Given an array of route parts, build a joined URL route. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeAttributesDescription
parts + + +string + + + + + + + + + + <repeatable>
+ +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ Navigate the app to the given path with the given args. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + +string + + + +
args + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +

subscribe(handler) → {object}

+ + + + + + +
+ Subscribe to listen for route changes. Returns an object with an unsubscribe() property. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
handler + + +function + + + + callback called when the route changes
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + +
+ - subscription manager +
+ + + +
+
+ Type +
+
+ +object + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/module-routing.html b/app/assets/frontend/documentation/generated/module-routing.html new file mode 100644 index 0000000..5e8883f --- /dev/null +++ b/app/assets/frontend/documentation/generated/module-routing.html @@ -0,0 +1,168 @@ + + + + + JSDoc: Module: routing + + + + + + + + + + +
+ +

Module: routing

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + +

Classes

+ +
+
Router
+
+
+ + + + + + + + + +

Members

+ + + +

(inner, constant) router :Router

+ + + + +
+ Global router instance. +
+ + + +
Type:
+
    +
  • + +Router + + +
  • +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/module-util.html b/app/assets/frontend/documentation/generated/module-util.html new file mode 100644 index 0000000..2ff8b53 --- /dev/null +++ b/app/assets/frontend/documentation/generated/module-util.html @@ -0,0 +1,505 @@ + + + + + JSDoc: Module: util + + + + + + + + + + +
+ +

Module: util

+ + + + + + +
+ +
+ + + +
+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + +

Methods

+ + + + + + + +

(static) appUrl(path) → {string}

+ + + + + + +
+ Generate an absolute URL to a file w/in the project directory. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
path + + +string + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +

(static) clone(obj) → {*}

+ + + + + + +
+ Makes a deep copy of the value passed in. +
+ + + + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
obj + + +* + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +* + + +
+
+ + + + + + + + + + + + + +

(static) uuid_v4() → {string}

+ + + + + + +
+ Generates a UUIDv4. Taken from: https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ + + + + + + +
+ + + + + + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +string + + +
+
+ + + + + + + + + + + + + +
+ +
+ + + + +
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/app/assets/frontend/documentation/generated/module_routing.js.html b/app/assets/frontend/documentation/generated/module_routing.js.html new file mode 100644 index 0000000..9b6cc11 --- /dev/null +++ b/app/assets/frontend/documentation/generated/module_routing.js.html @@ -0,0 +1,145 @@ + + + + + JSDoc: Source: module/routing.js + + + + + + + + + + +
+ +

Source: module/routing.js

+ + + + + + +
+
+
/** @module routing */
+
+/**
+ * A bare-bones history-api based SPA router.
+ */
+class Router {
+    /**
+     * Arguments for the current route.
+     * @type {undefined|*}
+     */
+    route_args = undefined
+
+    /**
+     * List of callback functions listening for route changes.
+     * @type {function[]}
+     */
+    subscribers = []
+
+    /**
+     * Array of router history records.
+     * @type {object[]}
+     */
+    history = []
+
+    /**
+     * Returns the APP_BASE_PATH of the application.
+     * @return {string}
+     */
+    get base_path() {
+        return APP_BASE_PATH
+    }
+
+    /**
+     * Navigate the app to the given path with the given args.
+     * @param {string} path
+     * @param {*} args
+     */
+    navigate(path, args) {
+        this.route_args = args
+        this.history.push({path, args})
+        window.history.pushState({}, path, this.build_url(path))
+        this.subscribers.forEach(sub => sub(path, args))
+    }
+
+    /**
+     * Navigate back one route.
+     */
+    back() {
+        window.history.back()
+        if ( this.history.length < 2 ) return;
+        this.history.pop()
+        const { path, args } = this.history[this.history.length - 1]
+        this.subscribers.forEach(sub => sub(path, args))
+    }
+
+    /**
+     * Subscribe to listen for route changes. Returns an object with an unsubscribe() property.
+     * @param {function} handler - callback called when the route changes
+     * @return {object} - subscription manager
+     */
+    subscribe(handler) {
+        if ( !this.subscribers.includes(handler) ) {
+            this.subscribers.push(handler)
+        }
+
+        return {
+            unsubscribe: () => {
+                this.subscribers = this.subscribers.filter(handler)
+            }
+        }
+    }
+
+    /**
+     * Given an array of route parts, build a joined URL route.
+     * @param {...string} parts
+     * @return {string}
+     */
+    build_url(...parts) {
+        parts = [this.base_path, ...parts].map(part => {
+            if ( part.endsWith('/') ) part = part.slice(0, -1)
+            if ( part.startsWith('/') ) part = part.slice(1)
+            return part
+        })
+
+        return parts.join('/')
+    }
+}
+
+/**
+ * Global router instance.
+ * @type {Router}
+ */
+const router = new Router()
+export { router }
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/module_util.js.html b/app/assets/frontend/documentation/generated/module_util.js.html new file mode 100644 index 0000000..e147dae --- /dev/null +++ b/app/assets/frontend/documentation/generated/module_util.js.html @@ -0,0 +1,92 @@ + + + + + JSDoc: Source: module/util.js + + + + + + + + + + +
+ +

Source: module/util.js

+ + + + + + +
+
+
/** @module util */
+
+/**
+ * Makes a deep copy of the value passed in.
+ * @param {*} obj
+ * @return {*}
+ */
+export function clone(obj) {
+    // If it's just a value, return it.
+    if ( typeof obj !== 'object' || obj === null ) return obj
+
+    // If it's an array, copy its values.
+    if ( Array.isArray(obj) ) return obj.map(x => clone(x))
+
+    // If it's an object, copy its properties.
+    const copy = {}
+    for ( const prop in obj ) {
+        copy[prop] = clone(obj[prop])
+    }
+    return copy
+}
+
+/**
+ * Generate an absolute URL to a file w/in the project directory.
+ * @param {string} path
+ * @return {string}
+ */
+export function appUrl(path) {
+    if ( path.startsWith('/') ) path = path.slice(1)
+    return `${APP_BASE_PATH}${path}`
+}
+
+/**
+ * Generates a UUIDv4. Taken from: https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid
+ * @return {string}
+ */
+export function uuid_v4() {
+    return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
+        (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
+    );
+}
+
+
+
+ + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/documentation/generated/scripts/linenumber.js b/app/assets/frontend/documentation/generated/scripts/linenumber.js new file mode 100644 index 0000000..4354785 --- /dev/null +++ b/app/assets/frontend/documentation/generated/scripts/linenumber.js @@ -0,0 +1,25 @@ +/*global document */ +(() => { + const source = document.getElementsByClassName('prettyprint source linenums'); + let i = 0; + let lineNumber = 0; + let lineId; + let lines; + let totalLines; + let anchorHash; + + if (source && source[0]) { + anchorHash = document.location.hash.substring(1); + lines = source[0].getElementsByTagName('li'); + totalLines = lines.length; + + for (; i < totalLines; i++) { + lineNumber++; + lineId = `line${lineNumber}`; + lines[i].id = lineId; + if (lineId === anchorHash) { + lines[i].className += ' selected'; + } + } + } +})(); diff --git a/app/assets/frontend/documentation/generated/scripts/prettify/Apache-License-2.0.txt b/app/assets/frontend/documentation/generated/scripts/prettify/Apache-License-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/app/assets/frontend/documentation/generated/scripts/prettify/Apache-License-2.0.txt @@ -0,0 +1,202 @@ + + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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/app/assets/frontend/documentation/generated/scripts/prettify/lang-css.js b/app/assets/frontend/documentation/generated/scripts/prettify/lang-css.js new file mode 100644 index 0000000..041e1f5 --- /dev/null +++ b/app/assets/frontend/documentation/generated/scripts/prettify/lang-css.js @@ -0,0 +1,2 @@ +PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", +/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/app/assets/frontend/documentation/generated/scripts/prettify/prettify.js b/app/assets/frontend/documentation/generated/scripts/prettify/prettify.js new file mode 100644 index 0000000..eef5ad7 --- /dev/null +++ b/app/assets/frontend/documentation/generated/scripts/prettify/prettify.js @@ -0,0 +1,28 @@ +var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; +(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= +[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), +l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, +q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, +q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, +"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), +a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} +for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], +"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], +H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], +J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ +I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), +["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", +/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), +["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", +hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= +!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p th:last-child { border-right: 1px solid #ddd; } + +.ancestors, .attribs { color: #999; } +.ancestors a, .attribs a +{ + color: #999 !important; + text-decoration: none; +} + +.clear +{ + clear: both; +} + +.important +{ + font-weight: bold; + color: #950B02; +} + +.yes-def { + text-indent: -1000px; +} + +.type-signature { + color: #aaa; +} + +.name, .signature { + font-family: Consolas, Monaco, 'Andale Mono', monospace; +} + +.details { margin-top: 14px; border-left: 2px solid #DDD; } +.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } +.details dd { margin-left: 70px; } +.details ul { margin: 0; } +.details ul { list-style-type: none; } +.details li { margin-left: 30px; padding-top: 6px; } +.details pre.prettyprint { margin: 0 } +.details .object-value { padding-top: 0; } + +.description { + margin-bottom: 1em; + margin-top: 1em; +} + +.code-caption +{ + font-style: italic; + font-size: 107%; + margin: 0; +} + +.source +{ + border: 1px solid #ddd; + width: 80%; + overflow: auto; +} + +.prettyprint.source { + width: inherit; +} + +.source code +{ + font-size: 100%; + line-height: 18px; + display: block; + padding: 4px 12px; + margin: 0; + background-color: #fff; + color: #4D4E53; +} + +.prettyprint code span.line +{ + display: inline-block; +} + +.prettyprint.linenums +{ + padding-left: 70px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.prettyprint.linenums ol +{ + padding-left: 0; +} + +.prettyprint.linenums li +{ + border-left: 3px #ddd solid; +} + +.prettyprint.linenums li.selected, +.prettyprint.linenums li.selected * +{ + background-color: lightyellow; +} + +.prettyprint.linenums li * +{ + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.params .name, .props .name, .name code { + color: #4D4E53; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 100%; +} + +.params td.description > p:first-child, +.props td.description > p:first-child +{ + margin-top: 0; + padding-top: 0; +} + +.params td.description > p:last-child, +.props td.description > p:last-child +{ + margin-bottom: 0; + padding-bottom: 0; +} + +.disabled { + color: #454545; +} diff --git a/app/assets/frontend/documentation/generated/styles/prettify-jsdoc.css b/app/assets/frontend/documentation/generated/styles/prettify-jsdoc.css new file mode 100644 index 0000000..5a2526e --- /dev/null +++ b/app/assets/frontend/documentation/generated/styles/prettify-jsdoc.css @@ -0,0 +1,111 @@ +/* JSDoc prettify.js theme */ + +/* plain text */ +.pln { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* string content */ +.str { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a keyword */ +.kwd { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a comment */ +.com { + font-weight: normal; + font-style: italic; +} + +/* a type name */ +.typ { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a literal value */ +.lit { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* punctuation */ +.pun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp open bracket */ +.opn { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* lisp close bracket */ +.clo { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a markup tag name */ +.tag { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute name */ +.atn { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a markup attribute value */ +.atv { + color: #006400; + font-weight: normal; + font-style: normal; +} + +/* a declaration */ +.dec { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* a variable name */ +.var { + color: #000000; + font-weight: normal; + font-style: normal; +} + +/* a function name */ +.fun { + color: #000000; + font-weight: bold; + font-style: normal; +} + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} diff --git a/app/assets/frontend/documentation/generated/styles/prettify-tomorrow.css b/app/assets/frontend/documentation/generated/styles/prettify-tomorrow.css new file mode 100644 index 0000000..b6f92a7 --- /dev/null +++ b/app/assets/frontend/documentation/generated/styles/prettify-tomorrow.css @@ -0,0 +1,132 @@ +/* Tomorrow Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* Pretty printing styles. Used with prettify.js. */ +/* SPAN elements with the classes below are added by prettyprint. */ +/* plain text */ +.pln { + color: #4d4d4c; } + +@media screen { + /* string content */ + .str { + color: #718c00; } + + /* a keyword */ + .kwd { + color: #8959a8; } + + /* a comment */ + .com { + color: #8e908c; } + + /* a type name */ + .typ { + color: #4271ae; } + + /* a literal value */ + .lit { + color: #f5871f; } + + /* punctuation */ + .pun { + color: #4d4d4c; } + + /* lisp open bracket */ + .opn { + color: #4d4d4c; } + + /* lisp close bracket */ + .clo { + color: #4d4d4c; } + + /* a markup tag name */ + .tag { + color: #c82829; } + + /* a markup attribute name */ + .atn { + color: #f5871f; } + + /* a markup attribute value */ + .atv { + color: #3e999f; } + + /* a declaration */ + .dec { + color: #f5871f; } + + /* a variable name */ + .var { + color: #c82829; } + + /* a function name */ + .fun { + color: #4271ae; } } +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { + color: #060; } + + .kwd { + color: #006; + font-weight: bold; } + + .com { + color: #600; + font-style: italic; } + + .typ { + color: #404; + font-weight: bold; } + + .lit { + color: #044; } + + .pun, .opn, .clo { + color: #440; } + + .tag { + color: #006; + font-weight: bold; } + + .atn { + color: #404; } + + .atv { + color: #060; } } +/* Style */ +/* +pre.prettyprint { + background: white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + font-size: 12px; + line-height: 1.5; + border: 1px solid #ccc; + padding: 10px; } +*/ + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; } + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ } + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ } diff --git a/app/assets/frontend/documentation/package.json b/app/assets/frontend/documentation/package.json new file mode 100644 index 0000000..51ceb08 --- /dev/null +++ b/app/assets/frontend/documentation/package.json @@ -0,0 +1,9 @@ +{ + "name": "eecs448-project-34", + "version": "0.1.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "jsdoc": "^3.6.5" + } +} diff --git a/app/assets/frontend/documentation/yarn.lock b/app/assets/frontend/documentation/yarn.lock new file mode 100644 index 0000000..9419e2c --- /dev/null +++ b/app/assets/frontend/documentation/yarn.lock @@ -0,0 +1,156 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/parser@^7.9.4": + version "7.11.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" + integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +catharsis@^0.8.11: + version "0.8.11" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.11.tgz#d0eb3d2b82b7da7a3ce2efb1a7b00becc6643468" + integrity sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g== + dependencies: + lodash "^4.17.14" + +entities@~2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +graceful-fs@^4.1.9: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +js2xmlparser@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.1.tgz#670ef71bc5661f089cc90481b99a05a1227ae3bd" + integrity sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw== + dependencies: + xmlcreate "^2.0.3" + +jsdoc@^3.6.5: + version "3.6.5" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.5.tgz#e004372ca6f2dcdf19b3d2ebcd7c725528485502" + integrity sha512-SbY+i9ONuxSK35cgVHaI8O9senTE4CDYAmGSDJ5l3+sfe62Ff4gy96osy6OW84t4K4A8iGnMrlRrsSItSNp3RQ== + dependencies: + "@babel/parser" "^7.9.4" + bluebird "^3.7.2" + catharsis "^0.8.11" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.1" + klaw "^3.0.0" + markdown-it "^10.0.0" + markdown-it-anchor "^5.2.7" + marked "^0.8.2" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + taffydb "2.6.2" + underscore "~1.10.2" + +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + +linkify-it@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" + integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== + dependencies: + uc.micro "^1.0.1" + +lodash@^4.17.14: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +markdown-it-anchor@^5.2.7: + version "5.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz#d549acd64856a8ecd1bea58365ef385effbac744" + integrity sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA== + +markdown-it@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" + integrity sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg== + dependencies: + argparse "^1.0.7" + entities "~2.0.0" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +marked@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/marked/-/marked-0.8.2.tgz#4faad28d26ede351a7a1aaa5fec67915c869e355" + integrity sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw== + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +requizzle@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.3.tgz#4675c90aacafb2c036bd39ba2daa4a1cb777fded" + integrity sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ== + dependencies: + lodash "^4.17.14" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +underscore@~1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf" + integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg== + +xmlcreate@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.3.tgz#df9ecd518fd3890ab3548e1b811d040614993497" + integrity sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ== diff --git a/app/assets/frontend/index.html b/app/assets/frontend/index.html new file mode 100644 index 0000000..89590d8 --- /dev/null +++ b/app/assets/frontend/index.html @@ -0,0 +1,29 @@ + + + + + + Fantasy Football + + + + +
+ + + +
+ + + + + + + diff --git a/app/assets/frontend/lib/README.md b/app/assets/frontend/lib/README.md new file mode 100644 index 0000000..fc03c2a --- /dev/null +++ b/app/assets/frontend/lib/README.md @@ -0,0 +1,9 @@ +The files in this directory are external libraries used in this project. + +- Vue.js + - A front-end framework. Used under the terms of the MIT license. + - https://github.com/vuejs/vue +- VuES6.js + - A kind-of crappy loader for defining Vue components using ES6 classes. + - Also used under the terms of the MIT license. + - https://code.garrettmills.dev/garrettmills/vues6 \ No newline at end of file diff --git a/app/assets/frontend/lib/vue-2.6.11.js b/app/assets/frontend/lib/vue-2.6.11.js new file mode 100644 index 0000000..b96b128 --- /dev/null +++ b/app/assets/frontend/lib/vue-2.6.11.js @@ -0,0 +1,11966 @@ +/*! + * Vue.js v2.6.11 + * (c) 2014-2019 Evan You + * Released under the MIT License. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.Vue = factory()); +}(this, function () { 'use strict'; + + /* */ + + var emptyObject = Object.freeze({}); + + // These helpers produce better VM code in JS engines due to their + // explicitness and function inlining. + function isUndef (v) { + return v === undefined || v === null + } + + function isDef (v) { + return v !== undefined && v !== null + } + + function isTrue (v) { + return v === true + } + + function isFalse (v) { + return v === false + } + + /** + * Check if value is primitive. + */ + function isPrimitive (value) { + return ( + typeof value === 'string' || + typeof value === 'number' || + // $flow-disable-line + typeof value === 'symbol' || + typeof value === 'boolean' + ) + } + + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + function isObject (obj) { + return obj !== null && typeof obj === 'object' + } + + /** + * Get the raw type string of a value, e.g., [object Object]. + */ + var _toString = Object.prototype.toString; + + function toRawType (value) { + return _toString.call(value).slice(8, -1) + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + function isPlainObject (obj) { + return _toString.call(obj) === '[object Object]' + } + + function isRegExp (v) { + return _toString.call(v) === '[object RegExp]' + } + + /** + * Check if val is a valid array index. + */ + function isValidArrayIndex (val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + } + + function isPromise (val) { + return ( + isDef(val) && + typeof val.then === 'function' && + typeof val.catch === 'function' + ) + } + + /** + * Convert a value to a string that is actually rendered. + */ + function toString (val) { + return val == null + ? '' + : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) + ? JSON.stringify(val, null, 2) + : String(val) + } + + /** + * Convert an input value to a number for persistence. + * If the conversion fails, return original string. + */ + function toNumber (val) { + var n = parseFloat(val); + return isNaN(n) ? val : n + } + + /** + * Make a map and return a function for checking if a key + * is in that map. + */ + function makeMap ( + str, + expectsLowerCase + ) { + var map = Object.create(null); + var list = str.split(','); + for (var i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase + ? function (val) { return map[val.toLowerCase()]; } + : function (val) { return map[val]; } + } + + /** + * Check if a tag is a built-in tag. + */ + var isBuiltInTag = makeMap('slot,component', true); + + /** + * Check if an attribute is a reserved attribute. + */ + var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); + + /** + * Remove an item from an array. + */ + function remove (arr, item) { + if (arr.length) { + var index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1) + } + } + } + + /** + * Check whether an object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) + } + + /** + * Create a cached version of a pure function. + */ + function cached (fn) { + var cache = Object.create(null); + return (function cachedFn (str) { + var hit = cache[str]; + return hit || (cache[str] = fn(str)) + }) + } + + /** + * Camelize a hyphen-delimited string. + */ + var camelizeRE = /-(\w)/g; + var camelize = cached(function (str) { + return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) + }); + + /** + * Capitalize a string. + */ + var capitalize = cached(function (str) { + return str.charAt(0).toUpperCase() + str.slice(1) + }); + + /** + * Hyphenate a camelCase string. + */ + var hyphenateRE = /\B([A-Z])/g; + var hyphenate = cached(function (str) { + return str.replace(hyphenateRE, '-$1').toLowerCase() + }); + + /** + * Simple bind polyfill for environments that do not support it, + * e.g., PhantomJS 1.x. Technically, we don't need this anymore + * since native bind is now performant enough in most browsers. + * But removing it would mean breaking code that was able to run in + * PhantomJS 1.x, so this must be kept for backward compatibility. + */ + + /* istanbul ignore next */ + function polyfillBind (fn, ctx) { + function boundFn (a) { + var l = arguments.length; + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + + boundFn._length = fn.length; + return boundFn + } + + function nativeBind (fn, ctx) { + return fn.bind(ctx) + } + + var bind = Function.prototype.bind + ? nativeBind + : polyfillBind; + + /** + * Convert an Array-like object to a real Array. + */ + function toArray (list, start) { + start = start || 0; + var i = list.length - start; + var ret = new Array(i); + while (i--) { + ret[i] = list[i + start]; + } + return ret + } + + /** + * Mix properties into target object. + */ + function extend (to, _from) { + for (var key in _from) { + to[key] = _from[key]; + } + return to + } + + /** + * Merge an Array of Objects into a single Object. + */ + function toObject (arr) { + var res = {}; + for (var i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res + } + + /* eslint-disable no-unused-vars */ + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ + function noop (a, b, c) {} + + /** + * Always return false. + */ + var no = function (a, b, c) { return false; }; + + /* eslint-enable no-unused-vars */ + + /** + * Return the same value. + */ + var identity = function (_) { return _; }; + + /** + * Generate a string containing static keys from compiler modules. + */ + function genStaticKeys (modules) { + return modules.reduce(function (keys, m) { + return keys.concat(m.staticKeys || []) + }, []).join(',') + } + + /** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ + function looseEqual (a, b) { + if (a === b) { return true } + var isObjectA = isObject(a); + var isObjectB = isObject(b); + if (isObjectA && isObjectB) { + try { + var isArrayA = Array.isArray(a); + var isArrayB = Array.isArray(b); + if (isArrayA && isArrayB) { + return a.length === b.length && a.every(function (e, i) { + return looseEqual(e, b[i]) + }) + } else if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime() + } else if (!isArrayA && !isArrayB) { + var keysA = Object.keys(a); + var keysB = Object.keys(b); + return keysA.length === keysB.length && keysA.every(function (key) { + return looseEqual(a[key], b[key]) + }) + } else { + /* istanbul ignore next */ + return false + } + } catch (e) { + /* istanbul ignore next */ + return false + } + } else if (!isObjectA && !isObjectB) { + return String(a) === String(b) + } else { + return false + } + } + + /** + * Return the first index at which a loosely equal value can be + * found in the array (if value is a plain object, the array must + * contain an object of the same shape), or -1 if it is not present. + */ + function looseIndexOf (arr, val) { + for (var i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) { return i } + } + return -1 + } + + /** + * Ensure a function is called only once. + */ + function once (fn) { + var called = false; + return function () { + if (!called) { + called = true; + fn.apply(this, arguments); + } + } + } + + var SSR_ATTR = 'data-server-rendered'; + + var ASSET_TYPES = [ + 'component', + 'directive', + 'filter' + ]; + + var LIFECYCLE_HOOKS = [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated', + 'errorCaptured', + 'serverPrefetch' + ]; + + /* */ + + + + var config = ({ + /** + * Option merge strategies (used in core/util/options) + */ + // $flow-disable-line + optionMergeStrategies: Object.create(null), + + /** + * Whether to suppress warnings. + */ + silent: false, + + /** + * Show production mode tip message on boot? + */ + productionTip: "development" !== 'production', + + /** + * Whether to enable devtools + */ + devtools: "development" !== 'production', + + /** + * Whether to record perf + */ + performance: false, + + /** + * Error handler for watcher errors + */ + errorHandler: null, + + /** + * Warn handler for watcher warns + */ + warnHandler: null, + + /** + * Ignore certain custom elements + */ + ignoredElements: [], + + /** + * Custom user key aliases for v-on + */ + // $flow-disable-line + keyCodes: Object.create(null), + + /** + * Check if a tag is reserved so that it cannot be registered as a + * component. This is platform-dependent and may be overwritten. + */ + isReservedTag: no, + + /** + * Check if an attribute is reserved so that it cannot be used as a component + * prop. This is platform-dependent and may be overwritten. + */ + isReservedAttr: no, + + /** + * Check if a tag is an unknown element. + * Platform-dependent. + */ + isUnknownElement: no, + + /** + * Get the namespace of an element + */ + getTagNamespace: noop, + + /** + * Parse the real tag name for the specific platform. + */ + parsePlatformTagName: identity, + + /** + * Check if an attribute must be bound using property, e.g. value + * Platform-dependent. + */ + mustUseProp: no, + + /** + * Perform updates asynchronously. Intended to be used by Vue Test Utils + * This will significantly reduce performance if set to false. + */ + async: true, + + /** + * Exposed for legacy reasons + */ + _lifecycleHooks: LIFECYCLE_HOOKS + }); + + /* */ + + /** + * unicode letters used for parsing html tags, component names and property paths. + * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * skipping \u10000-\uEFFFF due to it freezing up PhantomJS + */ + var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; + + /** + * Check if a string starts with $ or _ + */ + function isReserved (str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F + } + + /** + * Define a property. + */ + function def (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); + } + + /** + * Parse simple path. + */ + var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); + function parsePath (path) { + if (bailRE.test(path)) { + return + } + var segments = path.split('.'); + return function (obj) { + for (var i = 0; i < segments.length; i++) { + if (!obj) { return } + obj = obj[segments[i]]; + } + return obj + } + } + + /* */ + + // can we use __proto__? + var hasProto = '__proto__' in {}; + + // Browser environment sniffing + var inBrowser = typeof window !== 'undefined'; + var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; + var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase(); + var UA = inBrowser && window.navigator.userAgent.toLowerCase(); + var isIE = UA && /msie|trident/.test(UA); + var isIE9 = UA && UA.indexOf('msie 9.0') > 0; + var isEdge = UA && UA.indexOf('edge/') > 0; + var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android'); + var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios'); + var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; + var isPhantomJS = UA && /phantomjs/.test(UA); + var isFF = UA && UA.match(/firefox\/(\d+)/); + + // Firefox has a "watch" function on Object.prototype... + var nativeWatch = ({}).watch; + + var supportsPassive = false; + if (inBrowser) { + try { + var opts = {}; + Object.defineProperty(opts, 'passive', ({ + get: function get () { + /* istanbul ignore next */ + supportsPassive = true; + } + })); // https://github.com/facebook/flow/issues/285 + window.addEventListener('test-passive', null, opts); + } catch (e) {} + } + + // this needs to be lazy-evaled because vue may be required before + // vue-server-renderer can set VUE_ENV + var _isServer; + var isServerRendering = function () { + if (_isServer === undefined) { + /* istanbul ignore if */ + if (!inBrowser && !inWeex && typeof global !== 'undefined') { + // detect presence of vue-server-renderer and avoid + // Webpack shimming the process + _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'; + } else { + _isServer = false; + } + } + return _isServer + }; + + // detect devtools + var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + + /* istanbul ignore next */ + function isNative (Ctor) { + return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) + } + + var hasSymbol = + typeof Symbol !== 'undefined' && isNative(Symbol) && + typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); + + var _Set; + /* istanbul ignore if */ // $flow-disable-line + if (typeof Set !== 'undefined' && isNative(Set)) { + // use native Set when available. + _Set = Set; + } else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = /*@__PURE__*/(function () { + function Set () { + this.set = Object.create(null); + } + Set.prototype.has = function has (key) { + return this.set[key] === true + }; + Set.prototype.add = function add (key) { + this.set[key] = true; + }; + Set.prototype.clear = function clear () { + this.set = Object.create(null); + }; + + return Set; + }()); + } + + /* */ + + var warn = noop; + var tip = noop; + var generateComponentTrace = (noop); // work around flow check + var formatComponentName = (noop); + + { + var hasConsole = typeof console !== 'undefined'; + var classifyRE = /(?:^|[-_])(\w)/g; + var classify = function (str) { return str + .replace(classifyRE, function (c) { return c.toUpperCase(); }) + .replace(/[-_]/g, ''); }; + + warn = function (msg, vm) { + var trace = vm ? generateComponentTrace(vm) : ''; + + if (config.warnHandler) { + config.warnHandler.call(null, msg, vm, trace); + } else if (hasConsole && (!config.silent)) { + console.error(("[Vue warn]: " + msg + trace)); + } + }; + + tip = function (msg, vm) { + if (hasConsole && (!config.silent)) { + console.warn("[Vue tip]: " + msg + ( + vm ? generateComponentTrace(vm) : '' + )); + } + }; + + formatComponentName = function (vm, includeFile) { + if (vm.$root === vm) { + return '' + } + var options = typeof vm === 'function' && vm.cid != null + ? vm.options + : vm._isVue + ? vm.$options || vm.constructor.options + : vm; + var name = options.name || options._componentTag; + var file = options.__file; + if (!name && file) { + var match = file.match(/([^/\\]+)\.vue$/); + name = match && match[1]; + } + + return ( + (name ? ("<" + (classify(name)) + ">") : "") + + (file && includeFile !== false ? (" at " + file) : '') + ) + }; + + var repeat = function (str, n) { + var res = ''; + while (n) { + if (n % 2 === 1) { res += str; } + if (n > 1) { str += str; } + n >>= 1; + } + return res + }; + + generateComponentTrace = function (vm) { + if (vm._isVue && vm.$parent) { + var tree = []; + var currentRecursiveSequence = 0; + while (vm) { + if (tree.length > 0) { + var last = tree[tree.length - 1]; + if (last.constructor === vm.constructor) { + currentRecursiveSequence++; + vm = vm.$parent; + continue + } else if (currentRecursiveSequence > 0) { + tree[tree.length - 1] = [last, currentRecursiveSequence]; + currentRecursiveSequence = 0; + } + } + tree.push(vm); + vm = vm.$parent; + } + return '\n\nfound in\n\n' + tree + .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm) + ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)") + : formatComponentName(vm))); }) + .join('\n') + } else { + return ("\n\n(found in " + (formatComponentName(vm)) + ")") + } + }; + } + + /* */ + + var uid = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + */ + var Dep = function Dep () { + this.id = uid++; + this.subs = []; + }; + + Dep.prototype.addSub = function addSub (sub) { + this.subs.push(sub); + }; + + Dep.prototype.removeSub = function removeSub (sub) { + remove(this.subs, sub); + }; + + Dep.prototype.depend = function depend () { + if (Dep.target) { + Dep.target.addDep(this); + } + }; + + Dep.prototype.notify = function notify () { + // stabilize the subscriber list first + var subs = this.subs.slice(); + if (!config.async) { + // subs aren't sorted in scheduler if not running async + // we need to sort them now to make sure they fire in correct + // order + subs.sort(function (a, b) { return a.id - b.id; }); + } + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + // The current target watcher being evaluated. + // This is globally unique because only one watcher + // can be evaluated at a time. + Dep.target = null; + var targetStack = []; + + function pushTarget (target) { + targetStack.push(target); + Dep.target = target; + } + + function popTarget () { + targetStack.pop(); + Dep.target = targetStack[targetStack.length - 1]; + } + + /* */ + + var VNode = function VNode ( + tag, + data, + children, + text, + elm, + context, + componentOptions, + asyncFactory + ) { + this.tag = tag; + this.data = data; + this.children = children; + this.text = text; + this.elm = elm; + this.ns = undefined; + this.context = context; + this.fnContext = undefined; + this.fnOptions = undefined; + this.fnScopeId = undefined; + this.key = data && data.key; + this.componentOptions = componentOptions; + this.componentInstance = undefined; + this.parent = undefined; + this.raw = false; + this.isStatic = false; + this.isRootInsert = true; + this.isComment = false; + this.isCloned = false; + this.isOnce = false; + this.asyncFactory = asyncFactory; + this.asyncMeta = undefined; + this.isAsyncPlaceholder = false; + }; + + var prototypeAccessors = { child: { configurable: true } }; + + // DEPRECATED: alias for componentInstance for backwards compat. + /* istanbul ignore next */ + prototypeAccessors.child.get = function () { + return this.componentInstance + }; + + Object.defineProperties( VNode.prototype, prototypeAccessors ); + + var createEmptyVNode = function (text) { + if ( text === void 0 ) text = ''; + + var node = new VNode(); + node.text = text; + node.isComment = true; + return node + }; + + function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) + } + + // optimized shallow clone + // used for static nodes and slot nodes because they may be reused across + // multiple renders, cloning them avoids errors when DOM manipulations rely + // on their elm reference. + function cloneVNode (vnode) { + var cloned = new VNode( + vnode.tag, + vnode.data, + // #7975 + // clone children array to avoid mutating original in case of cloning + // a child. + vnode.children && vnode.children.slice(), + vnode.text, + vnode.elm, + vnode.context, + vnode.componentOptions, + vnode.asyncFactory + ); + cloned.ns = vnode.ns; + cloned.isStatic = vnode.isStatic; + cloned.key = vnode.key; + cloned.isComment = vnode.isComment; + cloned.fnContext = vnode.fnContext; + cloned.fnOptions = vnode.fnOptions; + cloned.fnScopeId = vnode.fnScopeId; + cloned.asyncMeta = vnode.asyncMeta; + cloned.isCloned = true; + return cloned + } + + /* + * not type checking this file because flow doesn't play well with + * dynamically accessing methods on Array prototype + */ + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto); + + var methodsToPatch = [ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' + ]; + + /** + * Intercept mutating methods and emit events + */ + methodsToPatch.forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break + case 'splice': + inserted = args.slice(2); + break + } + if (inserted) { ob.observeArray(inserted); } + // notify change + ob.dep.notify(); + return result + }); + }); + + /* */ + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * In some cases we may want to disable observation inside a component's + * update computation. + */ + var shouldObserve = true; + + function toggleObserving (value) { + shouldObserve = value; + } + + /** + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target + * object's property keys into getter/setters that + * collect dependencies and dispatch updates. + */ + var Observer = function Observer (value) { + this.value = value; + this.dep = new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (Array.isArray(value)) { + if (hasProto) { + protoAugment(value, arrayMethods); + } else { + copyAugment(value, arrayMethods, arrayKeys); + } + this.observeArray(value); + } else { + this.walk(value); + } + }; + + /** + * Walk through all properties and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ + Observer.prototype.walk = function walk (obj) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length; i++) { + defineReactive$$1(obj, keys[i]); + } + }; + + /** + * Observe a list of Array items. + */ + Observer.prototype.observeArray = function observeArray (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + // helpers + + /** + * Augment a target Object or Array by intercepting + * the prototype chain using __proto__ + */ + function protoAugment (target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment a target Object or Array by defining + * hidden properties. + */ + /* istanbul ignore next */ + function copyAugment (target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + */ + function observe (value, asRootData) { + if (!isObject(value) || value instanceof VNode) { + return + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if ( + shouldObserve && + !isServerRendering() && + (Array.isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value._isVue + ) { + ob = new Observer(value); + } + if (asRootData && ob) { + ob.vmCount++; + } + return ob + } + + /** + * Define a reactive property on an Object. + */ + function defineReactive$$1 ( + obj, + key, + val, + customSetter, + shallow + ) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + if ((!getter || setter) && arguments.length === 2) { + val = obj[key]; + } + + var childOb = !shallow && observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter () { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + if (Array.isArray(value)) { + dependArray(value); + } + } + } + return value + }, + set: function reactiveSetter (newVal) { + var value = getter ? getter.call(obj) : val; + /* eslint-disable no-self-compare */ + if (newVal === value || (newVal !== newVal && value !== value)) { + return + } + /* eslint-enable no-self-compare */ + if (customSetter) { + customSetter(); + } + // #7981: for accessor properties without setter + if (getter && !setter) { return } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = !shallow && observe(newVal); + dep.notify(); + } + }); + } + + /** + * Set a property on an object. Adds the new property and + * triggers change notification if the property doesn't + * already exist. + */ + function set (target, key, val) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.length = Math.max(target.length, key); + target.splice(key, 1, val); + return val + } + if (key in target && !(key in Object.prototype)) { + target[key] = val; + return val + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.' + ); + return val + } + if (!ob) { + target[key] = val; + return val + } + defineReactive$$1(ob.value, key, val); + ob.dep.notify(); + return val + } + + /** + * Delete a property and trigger change if necessary. + */ + function del (target, key) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.splice(key, 1); + return + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid deleting properties on a Vue instance or its root $data ' + + '- just set it to null.' + ); + return + } + if (!hasOwn(target, key)) { + return + } + delete target[key]; + if (!ob) { + return + } + ob.dep.notify(); + } + + /** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ + function dependArray (value) { + for (var e = (void 0), i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + if (Array.isArray(e)) { + dependArray(e); + } + } + } + + /* */ + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + */ + var strats = config.optionMergeStrategies; + + /** + * Options with restrictions + */ + { + strats.el = strats.propsData = function (parent, child, vm, key) { + if (!vm) { + warn( + "option \"" + key + "\" can only be used during instance " + + 'creation with the `new` keyword.' + ); + } + return defaultStrat(parent, child) + }; + } + + /** + * Helper that recursively merges two data objects together. + */ + function mergeData (to, from) { + if (!from) { return to } + var key, toVal, fromVal; + + var keys = hasSymbol + ? Reflect.ownKeys(from) + : Object.keys(from); + + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + // in case the object is already observed... + if (key === '__ob__') { continue } + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if ( + toVal !== fromVal && + isPlainObject(toVal) && + isPlainObject(fromVal) + ) { + mergeData(toVal, fromVal); + } + } + return to + } + + /** + * Data + */ + function mergeDataOrFn ( + parentVal, + childVal, + vm + ) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal + } + if (!parentVal) { + return childVal + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn () { + return mergeData( + typeof childVal === 'function' ? childVal.call(this, this) : childVal, + typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal + ) + } + } else { + return function mergedInstanceDataFn () { + // instance merge + var instanceData = typeof childVal === 'function' + ? childVal.call(vm, vm) + : childVal; + var defaultData = typeof parentVal === 'function' + ? parentVal.call(vm, vm) + : parentVal; + if (instanceData) { + return mergeData(instanceData, defaultData) + } else { + return defaultData + } + } + } + } + + strats.data = function ( + parentVal, + childVal, + vm + ) { + if (!vm) { + if (childVal && typeof childVal !== 'function') { + warn( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + + return parentVal + } + return mergeDataOrFn(parentVal, childVal) + } + + return mergeDataOrFn(parentVal, childVal, vm) + }; + + /** + * Hooks and props are merged as arrays. + */ + function mergeHook ( + parentVal, + childVal + ) { + var res = childVal + ? parentVal + ? parentVal.concat(childVal) + : Array.isArray(childVal) + ? childVal + : [childVal] + : parentVal; + return res + ? dedupeHooks(res) + : res + } + + function dedupeHooks (hooks) { + var res = []; + for (var i = 0; i < hooks.length; i++) { + if (res.indexOf(hooks[i]) === -1) { + res.push(hooks[i]); + } + } + return res + } + + LIFECYCLE_HOOKS.forEach(function (hook) { + strats[hook] = mergeHook; + }); + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + function mergeAssets ( + parentVal, + childVal, + vm, + key + ) { + var res = Object.create(parentVal || null); + if (childVal) { + assertObjectType(key, childVal, vm); + return extend(res, childVal) + } else { + return res + } + } + + ASSET_TYPES.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Watchers. + * + * Watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + strats.watch = function ( + parentVal, + childVal, + vm, + key + ) { + // work around Firefox's Object.prototype.watch... + if (parentVal === nativeWatch) { parentVal = undefined; } + if (childVal === nativeWatch) { childVal = undefined; } + /* istanbul ignore if */ + if (!childVal) { return Object.create(parentVal || null) } + { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = {}; + extend(ret, parentVal); + for (var key$1 in childVal) { + var parent = ret[key$1]; + var child = childVal[key$1]; + if (parent && !Array.isArray(parent)) { + parent = [parent]; + } + ret[key$1] = parent + ? parent.concat(child) + : Array.isArray(child) ? child : [child]; + } + return ret + }; + + /** + * Other object hashes. + */ + strats.props = + strats.methods = + strats.inject = + strats.computed = function ( + parentVal, + childVal, + vm, + key + ) { + if (childVal && "development" !== 'production') { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = Object.create(null); + extend(ret, parentVal); + if (childVal) { extend(ret, childVal); } + return ret + }; + strats.provide = mergeDataOrFn; + + /** + * Default strategy. + */ + var defaultStrat = function (parentVal, childVal) { + return childVal === undefined + ? parentVal + : childVal + }; + + /** + * Validate component names + */ + function checkComponents (options) { + for (var key in options.components) { + validateComponentName(key); + } + } + + function validateComponentName (name) { + if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicodeRegExp.source) + "]*$")).test(name)) { + warn( + 'Invalid component name: "' + name + '". Component names ' + + 'should conform to valid custom element name in html5 specification.' + ); + } + if (isBuiltInTag(name) || config.isReservedTag(name)) { + warn( + 'Do not use built-in or reserved HTML elements as component ' + + 'id: ' + name + ); + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + */ + function normalizeProps (options, vm) { + var props = options.props; + if (!props) { return } + var res = {}; + var i, val, name; + if (Array.isArray(props)) { + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + name = camelize(val); + res[name] = { type: null }; + } else { + warn('props must be strings when using array syntax.'); + } + } + } else if (isPlainObject(props)) { + for (var key in props) { + val = props[key]; + name = camelize(key); + res[name] = isPlainObject(val) + ? val + : { type: val }; + } + } else { + warn( + "Invalid value for option \"props\": expected an Array or an Object, " + + "but got " + (toRawType(props)) + ".", + vm + ); + } + options.props = res; + } + + /** + * Normalize all injections into Object-based format + */ + function normalizeInject (options, vm) { + var inject = options.inject; + if (!inject) { return } + var normalized = options.inject = {}; + if (Array.isArray(inject)) { + for (var i = 0; i < inject.length; i++) { + normalized[inject[i]] = { from: inject[i] }; + } + } else if (isPlainObject(inject)) { + for (var key in inject) { + var val = inject[key]; + normalized[key] = isPlainObject(val) + ? extend({ from: key }, val) + : { from: val }; + } + } else { + warn( + "Invalid value for option \"inject\": expected an Array or an Object, " + + "but got " + (toRawType(inject)) + ".", + vm + ); + } + } + + /** + * Normalize raw function directives into object format. + */ + function normalizeDirectives (options) { + var dirs = options.directives; + if (dirs) { + for (var key in dirs) { + var def$$1 = dirs[key]; + if (typeof def$$1 === 'function') { + dirs[key] = { bind: def$$1, update: def$$1 }; + } + } + } + } + + function assertObjectType (name, value, vm) { + if (!isPlainObject(value)) { + warn( + "Invalid value for option \"" + name + "\": expected an Object, " + + "but got " + (toRawType(value)) + ".", + vm + ); + } + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + */ + function mergeOptions ( + parent, + child, + vm + ) { + { + checkComponents(child); + } + + if (typeof child === 'function') { + child = child.options; + } + + normalizeProps(child, vm); + normalizeInject(child, vm); + normalizeDirectives(child); + + // Apply extends and mixins on the child options, + // but only if it is a raw options object that isn't + // the result of another mergeOptions call. + // Only merged options has the _base property. + if (!child._base) { + if (child.extends) { + parent = mergeOptions(parent, child.extends, vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + parent = mergeOptions(parent, child.mixins[i], vm); + } + } + } + + var options = {}; + var key; + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField (key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + */ + function resolveAsset ( + options, + type, + id, + warnMissing + ) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return + } + var assets = options[type]; + // check local registration variations first + if (hasOwn(assets, id)) { return assets[id] } + var camelizedId = camelize(id); + if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } + var PascalCaseId = capitalize(camelizedId); + if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } + // fallback to prototype chain + var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; + if (warnMissing && !res) { + warn( + 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, + options + ); + } + return res + } + + /* */ + + + + function validateProp ( + key, + propOptions, + propsData, + vm + ) { + var prop = propOptions[key]; + var absent = !hasOwn(propsData, key); + var value = propsData[key]; + // boolean casting + var booleanIndex = getTypeIndex(Boolean, prop.type); + if (booleanIndex > -1) { + if (absent && !hasOwn(prop, 'default')) { + value = false; + } else if (value === '' || value === hyphenate(key)) { + // only cast empty string / same name to boolean if + // boolean has higher priority + var stringIndex = getTypeIndex(String, prop.type); + if (stringIndex < 0 || booleanIndex < stringIndex) { + value = true; + } + } + } + // check default value + if (value === undefined) { + value = getPropDefaultValue(vm, prop, key); + // since the default value is a fresh copy, + // make sure to observe it. + var prevShouldObserve = shouldObserve; + toggleObserving(true); + observe(value); + toggleObserving(prevShouldObserve); + } + { + assertProp(prop, key, value, vm, absent); + } + return value + } + + /** + * Get the default value of a prop. + */ + function getPropDefaultValue (vm, prop, key) { + // no default, return undefined + if (!hasOwn(prop, 'default')) { + return undefined + } + var def = prop.default; + // warn against non-factory defaults for Object & Array + if (isObject(def)) { + warn( + 'Invalid default value for prop "' + key + '": ' + + 'Props with type Object/Array must use a factory function ' + + 'to return the default value.', + vm + ); + } + // the raw prop value was also undefined from previous render, + // return previous default value to avoid unnecessary watcher trigger + if (vm && vm.$options.propsData && + vm.$options.propsData[key] === undefined && + vm._props[key] !== undefined + ) { + return vm._props[key] + } + // call factory function for non-Function types + // a value is Function if its prototype is function even across different execution context + return typeof def === 'function' && getType(prop.type) !== 'Function' + ? def.call(vm) + : def + } + + /** + * Assert whether a prop is valid. + */ + function assertProp ( + prop, + name, + value, + vm, + absent + ) { + if (prop.required && absent) { + warn( + 'Missing required prop: "' + name + '"', + vm + ); + return + } + if (value == null && !prop.required) { + return + } + var type = prop.type; + var valid = !type || type === true; + var expectedTypes = []; + if (type) { + if (!Array.isArray(type)) { + type = [type]; + } + for (var i = 0; i < type.length && !valid; i++) { + var assertedType = assertType(value, type[i]); + expectedTypes.push(assertedType.expectedType || ''); + valid = assertedType.valid; + } + } + + if (!valid) { + warn( + getInvalidTypeMessage(name, value, expectedTypes), + vm + ); + return + } + var validator = prop.validator; + if (validator) { + if (!validator(value)) { + warn( + 'Invalid prop: custom validator check failed for prop "' + name + '".', + vm + ); + } + } + } + + var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/; + + function assertType (value, type) { + var valid; + var expectedType = getType(type); + if (simpleCheckRE.test(expectedType)) { + var t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; + } + } else if (expectedType === 'Object') { + valid = isPlainObject(value); + } else if (expectedType === 'Array') { + valid = Array.isArray(value); + } else { + valid = value instanceof type; + } + return { + valid: valid, + expectedType: expectedType + } + } + + /** + * Use function string name to check built-in types, + * because a simple equality check will fail when running + * across different vms / iframes. + */ + function getType (fn) { + var match = fn && fn.toString().match(/^\s*function (\w+)/); + return match ? match[1] : '' + } + + function isSameType (a, b) { + return getType(a) === getType(b) + } + + function getTypeIndex (type, expectedTypes) { + if (!Array.isArray(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1 + } + for (var i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i + } + } + return -1 + } + + function getInvalidTypeMessage (name, value, expectedTypes) { + var message = "Invalid prop: type check failed for prop \"" + name + "\"." + + " Expected " + (expectedTypes.map(capitalize).join(', ')); + var expectedType = expectedTypes[0]; + var receivedType = toRawType(value); + var expectedValue = styleValue(value, expectedType); + var receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += " with value " + expectedValue; + } + message += ", got " + receivedType + " "; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += "with value " + receivedValue + "."; + } + return message + } + + function styleValue (value, type) { + if (type === 'String') { + return ("\"" + value + "\"") + } else if (type === 'Number') { + return ("" + (Number(value))) + } else { + return ("" + value) + } + } + + function isExplicable (value) { + var explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some(function (elem) { return value.toLowerCase() === elem; }) + } + + function isBoolean () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; }) + } + + /* */ + + function handleError (err, vm, info) { + // Deactivate deps tracking while processing error handler to avoid possible infinite rendering. + // See: https://github.com/vuejs/vuex/issues/1505 + pushTarget(); + try { + if (vm) { + var cur = vm; + while ((cur = cur.$parent)) { + var hooks = cur.$options.errorCaptured; + if (hooks) { + for (var i = 0; i < hooks.length; i++) { + try { + var capture = hooks[i].call(cur, err, vm, info) === false; + if (capture) { return } + } catch (e) { + globalHandleError(e, cur, 'errorCaptured hook'); + } + } + } + } + } + globalHandleError(err, vm, info); + } finally { + popTarget(); + } + } + + function invokeWithErrorHandling ( + handler, + context, + args, + vm, + info + ) { + var res; + try { + res = args ? handler.apply(context, args) : handler.call(context); + if (res && !res._isVue && isPromise(res) && !res._handled) { + res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); }); + // issue #9511 + // avoid catch triggering multiple times when nested calls + res._handled = true; + } + } catch (e) { + handleError(e, vm, info); + } + return res + } + + function globalHandleError (err, vm, info) { + if (config.errorHandler) { + try { + return config.errorHandler.call(null, err, vm, info) + } catch (e) { + // if the user intentionally throws the original error in the handler, + // do not log it twice + if (e !== err) { + logError(e, null, 'config.errorHandler'); + } + } + } + logError(err, vm, info); + } + + function logError (err, vm, info) { + { + warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); + } + /* istanbul ignore else */ + if ((inBrowser || inWeex) && typeof console !== 'undefined') { + console.error(err); + } else { + throw err + } + } + + /* */ + + var isUsingMicroTask = false; + + var callbacks = []; + var pending = false; + + function flushCallbacks () { + pending = false; + var copies = callbacks.slice(0); + callbacks.length = 0; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + // Here we have async deferring wrappers using microtasks. + // In 2.5 we used (macro) tasks (in combination with microtasks). + // However, it has subtle problems when state is changed right before repaint + // (e.g. #6813, out-in transitions). + // Also, using (macro) tasks in event handler would cause some weird behaviors + // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109). + // So we now use microtasks everywhere, again. + // A major drawback of this tradeoff is that there are some scenarios + // where microtasks have too high a priority and fire in between supposedly + // sequential events (e.g. #4521, #6690, which have workarounds) + // or even between bubbling of the same event (#6566). + var timerFunc; + + // The nextTick behavior leverages the microtask queue, which can be accessed + // via either native Promise.then or MutationObserver. + // MutationObserver has wider support, however it is seriously bugged in + // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It + // completely stops working after triggering a few times... so, if native + // Promise is available, we will use it: + /* istanbul ignore next, $flow-disable-line */ + if (typeof Promise !== 'undefined' && isNative(Promise)) { + var p = Promise.resolve(); + timerFunc = function () { + p.then(flushCallbacks); + // In problematic UIWebViews, Promise.then doesn't completely break, but + // it can get stuck in a weird state where callbacks are pushed into the + // microtask queue but the queue isn't being flushed, until the browser + // needs to do some other work, e.g. handle a timer. Therefore we can + // "force" the microtask queue to be flushed by adding an empty timer. + if (isIOS) { setTimeout(noop); } + }; + isUsingMicroTask = true; + } else if (!isIE && typeof MutationObserver !== 'undefined' && ( + isNative(MutationObserver) || + // PhantomJS and iOS 7.x + MutationObserver.toString() === '[object MutationObserverConstructor]' + )) { + // Use MutationObserver where native Promise is not available, + // e.g. PhantomJS, iOS7, Android 4.4 + // (#6466 MutationObserver is unreliable in IE11) + var counter = 1; + var observer = new MutationObserver(flushCallbacks); + var textNode = document.createTextNode(String(counter)); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = String(counter); + }; + isUsingMicroTask = true; + } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { + // Fallback to setImmediate. + // Technically it leverages the (macro) task queue, + // but it is still a better choice than setTimeout. + timerFunc = function () { + setImmediate(flushCallbacks); + }; + } else { + // Fallback to setTimeout. + timerFunc = function () { + setTimeout(flushCallbacks, 0); + }; + } + + function nextTick (cb, ctx) { + var _resolve; + callbacks.push(function () { + if (cb) { + try { + cb.call(ctx); + } catch (e) { + handleError(e, ctx, 'nextTick'); + } + } else if (_resolve) { + _resolve(ctx); + } + }); + if (!pending) { + pending = true; + timerFunc(); + } + // $flow-disable-line + if (!cb && typeof Promise !== 'undefined') { + return new Promise(function (resolve) { + _resolve = resolve; + }) + } + } + + /* */ + + var mark; + var measure; + + { + var perf = inBrowser && window.performance; + /* istanbul ignore if */ + if ( + perf && + perf.mark && + perf.measure && + perf.clearMarks && + perf.clearMeasures + ) { + mark = function (tag) { return perf.mark(tag); }; + measure = function (name, startTag, endTag) { + perf.measure(name, startTag, endTag); + perf.clearMarks(startTag); + perf.clearMarks(endTag); + // perf.clearMeasures(name) + }; + } + } + + /* not type checking this file because flow doesn't play well with Proxy */ + + var initProxy; + + { + var allowedGlobals = makeMap( + 'Infinity,undefined,NaN,isFinite,isNaN,' + + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + + 'require' // for Webpack/Browserify + ); + + var warnNonPresent = function (target, key) { + warn( + "Property or method \"" + key + "\" is not defined on the instance but " + + 'referenced during render. Make sure that this property is reactive, ' + + 'either in the data option, or for class-based components, by ' + + 'initializing the property. ' + + 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', + target + ); + }; + + var warnReservedPrefix = function (target, key) { + warn( + "Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " + + 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + + 'prevent conflicts with Vue internals. ' + + 'See: https://vuejs.org/v2/api/#data', + target + ); + }; + + var hasProxy = + typeof Proxy !== 'undefined' && isNative(Proxy); + + if (hasProxy) { + var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); + config.keyCodes = new Proxy(config.keyCodes, { + set: function set (target, key, value) { + if (isBuiltInModifier(key)) { + warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); + return false + } else { + target[key] = value; + return true + } + } + }); + } + + var hasHandler = { + has: function has (target, key) { + var has = key in target; + var isAllowed = allowedGlobals(key) || + (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); + if (!has && !isAllowed) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return has || !isAllowed + } + }; + + var getHandler = { + get: function get (target, key) { + if (typeof key === 'string' && !(key in target)) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return target[key] + } + }; + + initProxy = function initProxy (vm) { + if (hasProxy) { + // determine which proxy handler to use + var options = vm.$options; + var handlers = options.render && options.render._withStripped + ? getHandler + : hasHandler; + vm._renderProxy = new Proxy(vm, handlers); + } else { + vm._renderProxy = vm; + } + }; + } + + /* */ + + var seenObjects = new _Set(); + + /** + * Recursively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + */ + function traverse (val) { + _traverse(val, seenObjects); + seenObjects.clear(); + } + + function _traverse (val, seen) { + var i, keys; + var isA = Array.isArray(val); + if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { + return + } + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return + } + seen.add(depId); + } + if (isA) { + i = val.length; + while (i--) { _traverse(val[i], seen); } + } else { + keys = Object.keys(val); + i = keys.length; + while (i--) { _traverse(val[keys[i]], seen); } + } + } + + /* */ + + var normalizeEvent = cached(function (name) { + var passive = name.charAt(0) === '&'; + name = passive ? name.slice(1) : name; + var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first + name = once$$1 ? name.slice(1) : name; + var capture = name.charAt(0) === '!'; + name = capture ? name.slice(1) : name; + return { + name: name, + once: once$$1, + capture: capture, + passive: passive + } + }); + + function createFnInvoker (fns, vm) { + function invoker () { + var arguments$1 = arguments; + + var fns = invoker.fns; + if (Array.isArray(fns)) { + var cloned = fns.slice(); + for (var i = 0; i < cloned.length; i++) { + invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler"); + } + } else { + // return handler return value for single handlers + return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler") + } + } + invoker.fns = fns; + return invoker + } + + function updateListeners ( + on, + oldOn, + add, + remove$$1, + createOnceHandler, + vm + ) { + var name, def$$1, cur, old, event; + for (name in on) { + def$$1 = cur = on[name]; + old = oldOn[name]; + event = normalizeEvent(name); + if (isUndef(cur)) { + warn( + "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), + vm + ); + } else if (isUndef(old)) { + if (isUndef(cur.fns)) { + cur = on[name] = createFnInvoker(cur, vm); + } + if (isTrue(event.once)) { + cur = on[name] = createOnceHandler(event.name, cur, event.capture); + } + add(event.name, cur, event.capture, event.passive, event.params); + } else if (cur !== old) { + old.fns = cur; + on[name] = old; + } + } + for (name in oldOn) { + if (isUndef(on[name])) { + event = normalizeEvent(name); + remove$$1(event.name, oldOn[name], event.capture); + } + } + } + + /* */ + + function mergeVNodeHook (def, hookKey, hook) { + if (def instanceof VNode) { + def = def.data.hook || (def.data.hook = {}); + } + var invoker; + var oldHook = def[hookKey]; + + function wrappedHook () { + hook.apply(this, arguments); + // important: remove merged hook to ensure it's called only once + // and prevent memory leak + remove(invoker.fns, wrappedHook); + } + + if (isUndef(oldHook)) { + // no existing hook + invoker = createFnInvoker([wrappedHook]); + } else { + /* istanbul ignore if */ + if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { + // already a merged invoker + invoker = oldHook; + invoker.fns.push(wrappedHook); + } else { + // existing plain hook + invoker = createFnInvoker([oldHook, wrappedHook]); + } + } + + invoker.merged = true; + def[hookKey] = invoker; + } + + /* */ + + function extractPropsFromVNodeData ( + data, + Ctor, + tag + ) { + // we are only extracting raw values here. + // validation and default values are handled in the child + // component itself. + var propOptions = Ctor.options.props; + if (isUndef(propOptions)) { + return + } + var res = {}; + var attrs = data.attrs; + var props = data.props; + if (isDef(attrs) || isDef(props)) { + for (var key in propOptions) { + var altKey = hyphenate(key); + { + var keyInLowerCase = key.toLowerCase(); + if ( + key !== keyInLowerCase && + attrs && hasOwn(attrs, keyInLowerCase) + ) { + tip( + "Prop \"" + keyInLowerCase + "\" is passed to component " + + (formatComponentName(tag || Ctor)) + ", but the declared prop name is" + + " \"" + key + "\". " + + "Note that HTML attributes are case-insensitive and camelCased " + + "props need to use their kebab-case equivalents when using in-DOM " + + "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"." + ); + } + } + checkProp(res, props, key, altKey, true) || + checkProp(res, attrs, key, altKey, false); + } + } + return res + } + + function checkProp ( + res, + hash, + key, + altKey, + preserve + ) { + if (isDef(hash)) { + if (hasOwn(hash, key)) { + res[key] = hash[key]; + if (!preserve) { + delete hash[key]; + } + return true + } else if (hasOwn(hash, altKey)) { + res[key] = hash[altKey]; + if (!preserve) { + delete hash[altKey]; + } + return true + } + } + return false + } + + /* */ + + // The template compiler attempts to minimize the need for normalization by + // statically analyzing the template at compile time. + // + // For plain HTML markup, normalization can be completely skipped because the + // generated render function is guaranteed to return Array. There are + // two cases where extra normalization is needed: + + // 1. When the children contains components - because a functional component + // may return an Array instead of a single root. In this case, just a simple + // normalization is needed - if any child is an Array, we flatten the whole + // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep + // because functional components already normalize their own children. + function simpleNormalizeChildren (children) { + for (var i = 0; i < children.length; i++) { + if (Array.isArray(children[i])) { + return Array.prototype.concat.apply([], children) + } + } + return children + } + + // 2. When the children contains constructs that always generated nested Arrays, + // e.g.