Initial commit
This commit is contained in:
43
app/plugins/initiativetracker/controllers/initiative.php
Normal file
43
app/plugins/initiativetracker/controllers/initiative.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/initiativetracker/controllers/initiative.php
|
||||
*
|
||||
* This is the home controller for the initiativetracker plugin.
|
||||
*
|
||||
* @package TP InitiativeTracker
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Controllers;
|
||||
|
||||
use TheTempusProject\Houdini\Classes\Views;
|
||||
use TheTempusProject\Classes\Controller;
|
||||
use TheTempusProject\Models\Inithistory;
|
||||
use TheTempusProject\Houdini\Classes\Issues;
|
||||
use TheTempusProject\Houdini\Classes\Components;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Initiative extends Controller {
|
||||
protected static $initiativeHistory;
|
||||
|
||||
public function __construct() {
|
||||
self::$title = 'Initiative Tracker - {SITENAME}';
|
||||
self::$pageDescription = 'This is for tracking player and creature turns and initiatives.';
|
||||
self::$initiativeHistory = new Inithistory;
|
||||
if ( ! App::$isLoggedIn ) {
|
||||
Issues::add( 'info', 'If you register an account and log in, you can save your initiatives.' );
|
||||
Components::set( 'initiativeHistory', '' );
|
||||
} else {
|
||||
$history = self::$initiativeHistory->userHistory();
|
||||
$historyView = Views::simpleView( 'initiativetracker.historyElement', $history );
|
||||
Components::set( 'initiativeHistory', $historyView );
|
||||
}
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function index() {
|
||||
Views::view( 'initiativetracker.index' );
|
||||
}
|
||||
}
|
35
app/plugins/initiativetracker/css/initiative.css
Normal file
35
app/plugins/initiativetracker/css/initiative.css
Normal file
@ -0,0 +1,35 @@
|
||||
.initiative-container {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.character-form {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
.list-controls {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.round-footer {
|
||||
padding-right: 15px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.list-controls-center,.list-controls,.character-form {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-controls-last {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: right;
|
||||
}
|
||||
|
||||
.list-controls-first {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: left;
|
||||
}
|
414
app/plugins/initiativetracker/js/initiative.js
Normal file
414
app/plugins/initiativetracker/js/initiative.js
Normal file
@ -0,0 +1,414 @@
|
||||
$(document).ready(function() {
|
||||
// Top Checkbox Controls
|
||||
$('input[type="checkbox"]').change(function() {
|
||||
var name = $(this).attr('name');
|
||||
if ( 'trackAC' == name ) {
|
||||
var eles = document.getElementsByClassName('ac-tracker');
|
||||
}
|
||||
if ( 'trackHP' == name ) {
|
||||
var eles = document.getElementsByClassName('hp-tracker');
|
||||
}
|
||||
if ( 'trackRounds' == name ) {
|
||||
var eles = document.getElementsByClassName('rounds-tracker');
|
||||
}
|
||||
if ($(this).is(':checked')) {
|
||||
Array.prototype.forEach.call(eles, function(ele) {
|
||||
ele.style.display = '';
|
||||
});
|
||||
} else {
|
||||
Array.prototype.forEach.call(eles, function(ele) {
|
||||
ele.style.display = 'none';
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '.character-remove', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-round-character-id="${characterId}"]`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.remove();
|
||||
});
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.remove();
|
||||
});
|
||||
|
||||
findByIdAndRemove( characterId, characterInitiativeList );
|
||||
});
|
||||
|
||||
$(document).on('click', '.hp-minus', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
var dataValue = parseInt($(this).data('value'), 10);
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
var $input = $(tr).find('input[name="hp"]');
|
||||
var newValue = parseInt($input.val(), 10) - dataValue;
|
||||
$input.val(newValue);
|
||||
});
|
||||
|
||||
var hpIndex = findById( characterId );
|
||||
hpIndex.hp = parseInt(hpIndex.hp) - dataValue;
|
||||
});
|
||||
|
||||
$(document).on('click', '.hp-plus', function() {
|
||||
var characterId = $(this).closest('tr').data('character-id');
|
||||
var dataValue = parseInt($(this).data('value'), 10);
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterId}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
var $input = $(tr).find('input[name="hp"]');
|
||||
var newValue = parseInt($input.val(), 10) + dataValue;
|
||||
$input.val(newValue);
|
||||
});
|
||||
|
||||
var hpIndex = findById( characterId );
|
||||
hpIndex.hp = parseInt(hpIndex.hp) + dataValue;
|
||||
});
|
||||
});
|
||||
|
||||
let currentCharacter;
|
||||
let roundCount = 0;
|
||||
let roundHistory = [];
|
||||
let characterInitiativeList = [];
|
||||
|
||||
function findById(id) {
|
||||
return characterInitiativeList.find(item => item.id === id);
|
||||
}
|
||||
function findByIdAndRemove(id, array) {
|
||||
const index = array.findIndex(item => item.id === id);
|
||||
if (index !== -1) {
|
||||
array.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const resetCharBtn = document.getElementById('character-reset');
|
||||
const resetCharacter = async function (event) {
|
||||
formReset();
|
||||
}
|
||||
|
||||
const resetListBtn = document.getElementById('list-reset');
|
||||
const resetListEvent = async function (event) {
|
||||
resetList();
|
||||
}
|
||||
|
||||
const nextCharBtn = document.getElementById('list-next');
|
||||
const nextCharacter = async function (event) {
|
||||
cycleCharacter();
|
||||
}
|
||||
function cycleCharacter() {
|
||||
if ( !currentCharacter ) {
|
||||
currentCharacter = 0;
|
||||
}
|
||||
if ( currentCharacter == characterInitiativeList.length ) {
|
||||
currentCharacter = 0;
|
||||
roundCount++;
|
||||
addRoundHistory();
|
||||
updateRoundCount();
|
||||
}
|
||||
if ( !characterInitiativeList[currentCharacter] ) {
|
||||
currentCharacter = 0;
|
||||
}
|
||||
|
||||
var allTrs = document.querySelectorAll(`tr`);
|
||||
allTrs.forEach(function(tr) {
|
||||
tr.classList.remove("success");
|
||||
});
|
||||
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr[data-character-id="${characterInitiativeList[currentCharacter].id}"]`);
|
||||
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.classList.add("success");
|
||||
});
|
||||
currentCharacter++;
|
||||
}
|
||||
|
||||
const clearListBtn = document.getElementById('list-clear');
|
||||
const clearListEvent = async function (event) {
|
||||
clearList();
|
||||
hideList();
|
||||
}
|
||||
|
||||
const sortCharBtn = document.getElementById('character-sort');
|
||||
const sortCharacters = async function (event) {
|
||||
event.preventDefault();
|
||||
sortthem();
|
||||
}
|
||||
function sortthem() {
|
||||
var fieldName = document.getElementById('sortBy').value;
|
||||
|
||||
clearListHTML();
|
||||
resetList();
|
||||
|
||||
var newList = sortCharacterListByField( fieldName, characterInitiativeList );
|
||||
|
||||
for (let i = 0; i < newList.length; i++) {
|
||||
addCharacterRow( newList[i] );
|
||||
}
|
||||
}
|
||||
function sortCharacterListByField( fieldName, list ) {
|
||||
if ( 'id' == fieldName ) {
|
||||
return list;
|
||||
}
|
||||
|
||||
let sortedList = [...list];
|
||||
sortedList.sort( ( a, b ) => {
|
||||
let fieldA = a[fieldName];
|
||||
let fieldB = b[fieldName];
|
||||
if ( 'type' == fieldName || 'name' == fieldName ) {
|
||||
return fieldA.localeCompare(fieldB);
|
||||
}
|
||||
if (fieldA > fieldB) {
|
||||
return -1;
|
||||
}
|
||||
if (fieldA < fieldB) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return sortedList;
|
||||
}
|
||||
|
||||
const addCharBtn = document.getElementById('character-add');
|
||||
const addCharacter = function (event) {
|
||||
createCharacterFromForm();
|
||||
}
|
||||
function createCharacterFromForm() {
|
||||
showList();
|
||||
var id = Date.now().toString(36) + Math.random().toString(36).substring(2);;
|
||||
var name = document.getElementById('name').value;
|
||||
if ( !name ) {
|
||||
name = '4816';
|
||||
}
|
||||
var initiative = document.getElementById('initiative').value;
|
||||
if ( !initiative ) {
|
||||
initiative = getRandomInt( 1, 21 );
|
||||
}
|
||||
initiative = parseInt( initiative );
|
||||
var ac = document.getElementById('ac').value;
|
||||
if ( !ac ) {
|
||||
ac = 0;
|
||||
}
|
||||
ac = parseInt( ac );
|
||||
var hp = document.getElementById('hp').value;
|
||||
if ( !hp ) {
|
||||
hp = 0;
|
||||
}
|
||||
hp = parseInt( hp );
|
||||
var characterType = document.querySelector('input[name="characterType"]:checked').value;
|
||||
var character = {
|
||||
id: id,
|
||||
name: name,
|
||||
initiative: initiative,
|
||||
ac: ac,
|
||||
hp: hp,
|
||||
type: characterType,
|
||||
};
|
||||
characterInitiativeList.push( character );
|
||||
|
||||
// re-order the list by initiative to keep the next character working properly
|
||||
characterInitiativeList = sortCharacterListByField( 'initiative', characterInitiativeList );
|
||||
|
||||
addCharacterRow( character );
|
||||
addRoundRow( character );
|
||||
}
|
||||
|
||||
const d20Btn = document.getElementById('d20-roll');
|
||||
const rollD20 = async function (event) {
|
||||
event.preventDefault();
|
||||
var resultDiv = document.getElementById('initiative');
|
||||
resultDiv.value = getRandomInt( 1, 21 );
|
||||
}
|
||||
|
||||
const resetRoundsBtn = document.getElementById('rounds-reset');
|
||||
const resetRoundsEvent = async function (event) {
|
||||
resetRoundCount();
|
||||
}
|
||||
|
||||
const clearRoundsBtn = document.getElementById('rounds-clear');
|
||||
const clearRoundsEvent = async function (event) {
|
||||
clearRounds();
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', (event) => {
|
||||
d20Btn.addEventListener('click', rollD20);
|
||||
addCharBtn.addEventListener('click', addCharacter);
|
||||
resetCharBtn.addEventListener('click', resetCharacter);
|
||||
resetListBtn.addEventListener('click', resetListEvent);
|
||||
clearListBtn.addEventListener('click', clearListEvent);
|
||||
nextCharBtn.addEventListener('click', nextCharacter);
|
||||
resetRoundsBtn.addEventListener('click', resetRoundsEvent);
|
||||
clearRoundsBtn.addEventListener('click', clearRoundsEvent);
|
||||
sortCharBtn.addEventListener('click', sortCharacters);
|
||||
updateRoundCount();
|
||||
});
|
||||
|
||||
function formReset() {
|
||||
document.getElementById('name').value = null;
|
||||
document.getElementById('initiative').value = null;
|
||||
document.getElementById('ac').value = null;
|
||||
document.getElementById('hp').value = null;
|
||||
}
|
||||
|
||||
function showList() {
|
||||
var tbody = document.getElementById('character-container');
|
||||
tbody.style.display = '';
|
||||
}
|
||||
|
||||
function addCharacterRow( character ) {
|
||||
var characterList = document.getElementById('character-list');
|
||||
var pcList = document.getElementById('character-list-pc');
|
||||
var npcList = document.getElementById('character-list-npc');
|
||||
var row = document.createElement('tr');
|
||||
row.setAttribute('data-character-id', character.id);
|
||||
|
||||
var hpStyle = '';
|
||||
var acStyle = '';
|
||||
|
||||
var checkbox = document.getElementById('trackHP');
|
||||
if ( !checkbox.checked ) {
|
||||
var hpStyle = 'style="display: none;"';
|
||||
}
|
||||
|
||||
var checkbox = document.getElementById('trackAC');
|
||||
if ( !checkbox.checked ) {
|
||||
var acStyle = 'style="display: none;"';
|
||||
}
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${character.name}</td>
|
||||
<td class="text-center">${character.initiative}</td>
|
||||
<td class="ac-tracker text-center"${acStyle}>${character.ac}</td>
|
||||
<td class="hp-tracker text-center"${hpStyle}>
|
||||
<div class="form-group hp-tracker list-controls-center">
|
||||
<div class="input-group col-lg-6">
|
||||
<div class="input-group-btn">
|
||||
<button class="hp-minus btn btn-danger" data-value="1" aria-label="Remove 1 hp">-1</button>
|
||||
<button class="hp-minus btn btn-danger" data-value="5" aria-label="Remove 5 hp">-5</button>
|
||||
<button class="hp-minus btn btn-danger" data-value="10" aria-label="Remove 10 hp">-10</button>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="hp" value="${character.hp}">
|
||||
<div class="input-group-btn">
|
||||
<button class="hp-plus btn btn-success" data-value="10" aria-label="Add 10 hp">+10</button>
|
||||
<button class="hp-plus btn btn-success" data-value="5" aria-label="Add 5 hp">+5</button>
|
||||
<button class="hp-plus btn btn-success" data-value="1" aria-label="Add 1 hp">+1</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-center">${character.type}</td>
|
||||
<td class="text-right"><button class="btn btn-danger btn-sm character-remove" aria-label="Add 10 hp"><span class="glyphicon glyphicon-trash"></span></button></td>
|
||||
`;
|
||||
|
||||
// Append the new row to the table body
|
||||
characterList.appendChild(row);
|
||||
|
||||
if ( 'pc' == character.type ) {
|
||||
var pc_row = row.cloneNode(true);
|
||||
pcList.appendChild(pc_row);
|
||||
}
|
||||
|
||||
if ( 'npc' == character.type ) {
|
||||
var npc_row = row.cloneNode(true);
|
||||
npcList.appendChild(npc_row);
|
||||
}
|
||||
}
|
||||
|
||||
function hideList() {
|
||||
var tbody = document.getElementById('character-container');
|
||||
tbody.style.display = 'none';
|
||||
}
|
||||
|
||||
function clearList() {
|
||||
characterInitiativeList = [];
|
||||
clearListHTML();
|
||||
}
|
||||
|
||||
function clearListHTML() {
|
||||
var tbody = document.getElementById('character-list');
|
||||
tbody.innerHTML = '';
|
||||
var tbody = document.getElementById('character-list-pc');
|
||||
tbody.innerHTML = '';
|
||||
var tbody = document.getElementById('character-list-npc');
|
||||
tbody.innerHTML = '';
|
||||
}
|
||||
|
||||
function resetList() {
|
||||
currentCharacter = 0;
|
||||
var allTrsWithCharacterId = document.querySelectorAll(`tr`);
|
||||
allTrsWithCharacterId.forEach(function(tr) {
|
||||
tr.classList.remove("success");
|
||||
});
|
||||
}
|
||||
|
||||
function clearRounds() {
|
||||
var headers = document.getElementById('rounds-history-header-row');
|
||||
var thElements = headers.getElementsByTagName('th');
|
||||
|
||||
// Loop through the th elements in reverse order to safely remove them without affecting the iteration
|
||||
for (var i = thElements.length - 1; i > 0; i--) {
|
||||
thElements[i].parentNode.removeChild(thElements[i]);
|
||||
}
|
||||
|
||||
var history = document.getElementById('rounds-history');
|
||||
var trElements = history.getElementsByTagName('tr');
|
||||
|
||||
for (var i = 0; i < trElements.length; i++) {
|
||||
|
||||
var elements = trElements[i].getElementsByTagName('td');
|
||||
for (var x = elements.length - 1; x > 0; x--) {
|
||||
elements[x].parentNode.removeChild(elements[x]);
|
||||
}
|
||||
|
||||
}
|
||||
roundCount = 0;
|
||||
updateRoundCount();
|
||||
}
|
||||
|
||||
function clearCharacters() {
|
||||
var history = document.getElementById('rounds-history');
|
||||
var trElements = history.getElementsByTagName('tr');
|
||||
|
||||
for (var i = 0; i < trElements.length; i++) {
|
||||
trElements[i].remove();
|
||||
}
|
||||
}
|
||||
|
||||
function resetRoundCount() {
|
||||
roundCount = 0;
|
||||
updateRoundCount();
|
||||
}
|
||||
|
||||
function updateRoundCount() {
|
||||
var round = document.getElementById('round-count');
|
||||
round.innerText = roundCount;
|
||||
}
|
||||
|
||||
function addRoundRow( character ) {
|
||||
var characterList = document.getElementById('rounds-history');
|
||||
var row = document.createElement('tr');
|
||||
|
||||
row.setAttribute('data-round-character-id', character.id);
|
||||
row.innerHTML = `<td class="char-name">${character.name}</td>`;
|
||||
characterList.appendChild(row);
|
||||
}
|
||||
|
||||
function addRoundHistory() {
|
||||
var headers = document.getElementById('rounds-history-header');
|
||||
var newHeader = document.createElement('th');
|
||||
newHeader.innerText = "Round " + roundCount;
|
||||
newHeader.classList.add("text-center");
|
||||
headers.after( newHeader );
|
||||
|
||||
for (let i = 0; i < characterInitiativeList.length; i++) {
|
||||
var char = characterInitiativeList[i];
|
||||
var newCol = document.createElement('td');
|
||||
newCol.innerText = char.hp;
|
||||
newCol.classList.add("text-center");
|
||||
|
||||
var allTrsWithCharacterId = document.querySelector(`tr[data-round-character-id="${char.id}"]`);
|
||||
var indexd = allTrsWithCharacterId.getElementsByClassName('char-name');
|
||||
indexd[0].after( newCol );
|
||||
}
|
||||
}
|
105
app/plugins/initiativetracker/models/inithistory.php
Normal file
105
app/plugins/initiativetracker/models/inithistory.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/feedback/models/feedback.php
|
||||
*
|
||||
* This class is used for the manipulation of the feedback database table.
|
||||
*
|
||||
* @todo make this send a confirmation email
|
||||
*
|
||||
* @package TP Feedback
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Models;
|
||||
|
||||
use TheTempusProject\Bedrock\Classes\Config;
|
||||
use TheTempusProject\Bedrock\Functions\Check;
|
||||
use TheTempusProject\Canary\Canary as Debug;
|
||||
use TheTempusProject\Classes\DatabaseModel;
|
||||
use TheTempusProject\Plugins\Feedback as Plugin;
|
||||
use TheTempusProject\TheTempusProject as App;
|
||||
|
||||
class Inithistory extends DatabaseModel {
|
||||
public $tableName = 'feedback';
|
||||
public $databaseMatrix = [
|
||||
[ 'name', 'varchar', '128' ],
|
||||
[ 'time', 'int', '10' ],
|
||||
[ 'email', 'varchar', '128' ],
|
||||
[ 'ip', 'varchar', '64' ],
|
||||
[ 'feedback', 'text', '' ],
|
||||
];
|
||||
public $plugin;
|
||||
|
||||
/**
|
||||
* The model constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->plugin = new Plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a feedback form to the db.
|
||||
*
|
||||
* @param string $name -the name on the form
|
||||
* @param string $email -the email provided
|
||||
* @param string $feedback -contents of the feedback form.
|
||||
* @return bool
|
||||
*/
|
||||
public function create( $name, $email, $feedback ) {
|
||||
if ( !$this->plugin->checkEnabled() ) {
|
||||
Debug::info( 'Feedback is disabled in the config.' );
|
||||
return false;
|
||||
}
|
||||
$fields = [
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'feedback' => $feedback,
|
||||
'time' => time(),
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
];
|
||||
if ( !self::$db->insert( $this->tableName, $fields ) ) {
|
||||
Debug::info( 'Feedback::create - failed to insert to db' );
|
||||
return false;
|
||||
}
|
||||
return self::$db->lastId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to clear feedback from the DB.
|
||||
*
|
||||
* @todo is there a way i could check for success here I'm pretty sure this is just a bad idea?
|
||||
* @return bool
|
||||
*/
|
||||
public function clear() {
|
||||
if ( empty( self::$log ) ) {
|
||||
self::$log = new Log;
|
||||
}
|
||||
self::$db->delete( $this->tableName, ['ID', '>=', '0'] );
|
||||
self::$log->admin( 'Cleared Feedback' );
|
||||
Debug::info( 'Feedback Cleared' );
|
||||
return true;
|
||||
}
|
||||
|
||||
public function userHistory( $limit = 0 ) {
|
||||
$whereClause = [
|
||||
'userID', '=', App::$activeUser->ID,
|
||||
'AND',
|
||||
'deletedAt', '=', '0',
|
||||
'AND',
|
||||
'expiresAt', '<', time(),
|
||||
];
|
||||
if ( empty( $limit ) ) {
|
||||
$notifications = self::$db->get( $this->tableName, $whereClause );
|
||||
} else {
|
||||
$notifications = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
|
||||
}
|
||||
if ( !$notifications->count() ) {
|
||||
Debug::info( 'No Notifications found.' );
|
||||
return false;
|
||||
}
|
||||
return $this->filter( $notifications->results() );
|
||||
}
|
||||
}
|
49
app/plugins/initiativetracker/plugin.php
Normal file
49
app/plugins/initiativetracker/plugin.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* app/plugins/initiativetracker/plugin.php
|
||||
*
|
||||
* This houses all of the main plugin info and functionality.
|
||||
*
|
||||
* @package TP InitiativeTracker
|
||||
* @version 3.0
|
||||
* @author Joey Kimsey <Joey@thetempusproject.com>
|
||||
* @link https://TheTempusProject.com
|
||||
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
|
||||
*/
|
||||
namespace TheTempusProject\Plugins;
|
||||
|
||||
use TheTempusProject\Classes\Plugin;
|
||||
|
||||
class Initiativetracker extends Plugin {
|
||||
public $pluginName = 'TP InitiativeTracker';
|
||||
public $pluginAuthor = 'JoeyK';
|
||||
public $pluginWebsite = 'https://TheTempusProject.com';
|
||||
public $modelVersion = '1.0';
|
||||
public $pluginVersion = '3.0';
|
||||
public $pluginDescription = 'A simple plugin which adds a simple initiative tracker.';
|
||||
public $configName = 'initiativeTracker';
|
||||
public $configMatrix = [
|
||||
'enabled' => [
|
||||
'type' => 'radio',
|
||||
'pretty' => 'Enable tracker usage.',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $permissionMatrix = [
|
||||
'useInitiativeTracker' => [
|
||||
'pretty' => 'Can use the tracker',
|
||||
'default' => true,
|
||||
],
|
||||
];
|
||||
public $main_links = [
|
||||
[
|
||||
'text' => 'Initiative',
|
||||
'url' => '{ROOT_URL}initiative/index',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// need to add a way to save the initiative history ( both personal, and for the table )
|
||||
// need a way to save characters for the autofill
|
||||
// need to add a "clear" button for initiative roller
|
||||
// if you have tables, and are a DM, your group can access the initiative history
|
210
app/plugins/initiativetracker/views/index.html
Normal file
210
app/plugins/initiativetracker/views/index.html
Normal file
@ -0,0 +1,210 @@
|
||||
<link rel="stylesheet" href="{ROOT_URL}app/plugins/initiativetracker/css/initiative.css" crossorigin="anonymous">
|
||||
<script src="{ROOT_URL}app/plugins/initiativetracker/js/initiative.js" type="module" defer></script>
|
||||
|
||||
<div id="initiative-container" class="initiative-container">
|
||||
|
||||
<div class="row">
|
||||
<h2>Initiative Tracker</h2>
|
||||
</div>
|
||||
|
||||
<!-- Tracker Settings -->
|
||||
<div class="row well well-sm">
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackHP" id="trackHP"> Track HP</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackAC" id="trackAC"> Track AC</label>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label><input type="checkbox" name="trackRounds" id="trackRounds"> Track Rounds</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Character Form -->
|
||||
<div id="character-form" class="character-form row well well-sm">
|
||||
<div class="form-group col-lg-3">
|
||||
<label for="name">Name</label>
|
||||
<input type="text" class="form-control" name="name" id="name" autocomplete="on">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<label for="initiative">Initiative</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id="d20-roll" class="btn btn-default" aria-label="Roll a d20 for initiative.">Roll</button>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="initiative" id="initiative">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-lg-1 ac-tracker" style="display: none;">
|
||||
<label for="ac">AC</label>
|
||||
<input type="number" class="form-control" name="ac" id="ac">
|
||||
</div>
|
||||
<div class="form-group col-lg-1 hp-tracker" style="display: none;">
|
||||
<label for="hp">HP</label>
|
||||
<input type="number" class="form-control" name="hp" id="hp">
|
||||
</div>
|
||||
<div class="form-group col-lg-2">
|
||||
<label for="pc">Type</label><br>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="characterType" id="pc" value="pc" checked> PC
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="characterType" id="npc" value="npc"> NPC
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="character-add" class="btn btn-primary">
|
||||
Add
|
||||
</button>
|
||||
<button id="character-reset" class="btn btn-danger">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Initiative List -->
|
||||
<div id="character-container" style="display: none;">
|
||||
|
||||
<div id="initiative-list" class="well well-sm">
|
||||
<!-- Tab Header -->
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="active">
|
||||
<a data-target="#cmb-list" role="tab" data-toggle="tab">
|
||||
Combined
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-target="#pc-list" role="tab" data-toggle="tab">
|
||||
PC
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-target="#npc-list" role="tab" data-toggle="tab">
|
||||
NPC
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<!-- Combined List -->
|
||||
<div role="tabpanel" class="tab-pane active" id="cmb-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- PC List -->
|
||||
<div role="tabpanel" class="tab-pane" id="pc-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list-pc">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- NPC List -->
|
||||
<div role="tabpanel" class="tab-pane" id="npc-list">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center">Initiative</th>
|
||||
<th class="ac-tracker text-center" style="display: none;">AC</th>
|
||||
<th class="hp-tracker text-center" style="display: none;">HP</th>
|
||||
<th class="text-center">Type</th>
|
||||
<th class="text-right"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="character-list-npc">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List Controls -->
|
||||
<div class="row list-controls row">
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="list-reset" class="d4-die die-btn btn btn-warning">
|
||||
Reset Round
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<div class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button id="character-sort" class="btn btn-primary" aria-label="Sort the List.">Sort</button>
|
||||
</div>
|
||||
<select class="form-control" id="sortBy">
|
||||
<option value="initiative">Initiative</option>
|
||||
<option value="name">Name</option>
|
||||
<option value="ac">AC</option>
|
||||
<option value="hp">HP</option>
|
||||
<option value="type">Type</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col-lg-3">
|
||||
<button id="list-next" class="btn btn-success">
|
||||
Next Character
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-group col-lg-3 list-controls-last">
|
||||
<button id="list-clear" class="btn btn-danger">
|
||||
Clear List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Round Controls -->
|
||||
<div class="row rounds-tracker" style="display: none;">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Round History</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr id="rounds-history-header-row">
|
||||
<th id="rounds-history-header">Character</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rounds-history">
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="form-group col-lg-2">
|
||||
<button id="rounds-clear" class="d4-die die-btn btn btn-danger">
|
||||
Clear History
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer round-footer">
|
||||
<b>Round Count</b>: <span id="round-count"></span>
|
||||
<span class="pull-right round-reset">
|
||||
<button id="rounds-reset" class="btn btn-warning">
|
||||
Reset Round Count
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Reference in New Issue
Block a user