Feat: Multiplayer sessions added using CRUD database.
This commit is contained in:
172
static/js/pages/base.js
Normal file
172
static/js/pages/base.js
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
import BusinessObjects from "../lib/business_objects/business_objects.js";
|
||||
import Events from "../lib/events.js";
|
||||
import LocalStorage from "../lib/local_storage.js";
|
||||
import API from "../api.js";
|
||||
import DOM from "../dom.js";
|
||||
import Utils from "../lib/utils.js";
|
||||
|
||||
import OverlayConfirm from "../components/common/temporary/overlay_confirm.js";
|
||||
import OverlayError from "../components/common/temporary/overlay_error.js";
|
||||
import Validation from "../lib/validation.js";
|
||||
|
||||
export default class BasePage {
|
||||
constructor(router) {
|
||||
if (!router) {
|
||||
throw new Error("Router is required");
|
||||
}
|
||||
else {
|
||||
Utils.consoleLogIfNotProductionEnvironment("initialising with router: ", router);
|
||||
}
|
||||
this.router = router;
|
||||
this.title = titlePageCurrent;
|
||||
if (this.constructor === BasePage) {
|
||||
throw new Error("Cannot instantiate abstract class");
|
||||
}
|
||||
|
||||
if (!this.constructor.hash) {
|
||||
throw new Error(`Class ${this.constructor.name} must have a static hash attribute.`);
|
||||
}
|
||||
}
|
||||
|
||||
initialize() {
|
||||
throw new Error("Method 'initialize()' must be implemented.");
|
||||
}
|
||||
|
||||
sharedInitialize() {
|
||||
this.logInitialisation();
|
||||
this.hookupCommonElements();
|
||||
}
|
||||
|
||||
logInitialisation() {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Initialising ' + this.title + ' page');
|
||||
}
|
||||
|
||||
hookupCommonElements() {
|
||||
// hookupVideos();
|
||||
this.hookupLogos();
|
||||
this.hookupNavigation();
|
||||
this.hookupOverlays();
|
||||
}
|
||||
hookupLogos() {
|
||||
Events.hookupEventHandler("click", "." + flagImageLogo + "," + "." + flagLogo, (event, element) => {
|
||||
Utils.consoleLogIfNotProductionEnvironment('clicking logo');
|
||||
this.router.navigateToHash(hashPageHome);
|
||||
});
|
||||
}
|
||||
/*
|
||||
hookupEventHandler(eventType, selector, callback) {
|
||||
Events.initialiseEventHandler(selector, flagInitialised, (element) => {
|
||||
element.addEventListener(eventType, (event) => {
|
||||
event.stopPropagation();
|
||||
callback(event, element);
|
||||
});
|
||||
});
|
||||
}
|
||||
*/
|
||||
hookupNavigation() {
|
||||
Events.hookupEventHandler("click", idButtonHamburger, (event, element) => {
|
||||
let overlayHamburger = document.querySelector(idOverlayHamburger);
|
||||
if (overlayHamburger.classList.contains(flagIsCollapsed)) {
|
||||
overlayHamburger.classList.remove(flagIsCollapsed);
|
||||
overlayHamburger.classList.add(flagExpanded);
|
||||
} else {
|
||||
overlayHamburger.classList.remove(flagExpanded);
|
||||
overlayHamburger.classList.add(flagIsCollapsed);
|
||||
}
|
||||
});
|
||||
|
||||
this.hookupButtonsNavUserAccount();
|
||||
this.hookupButtonsNavUserLogout();
|
||||
this.hookupButtonsNavUserLogin();
|
||||
}
|
||||
hookupButtonsNav(buttonSelector) {
|
||||
Events.hookupEventHandler("click", buttonSelector, (event, button) => {
|
||||
let pageHash = buttonSelector.getAttribute('href');
|
||||
this.router.navigateToHash(pageHash);
|
||||
});
|
||||
}
|
||||
hookupButtonsNavUserAccount() {
|
||||
// this.hookupButtonsNav('.' + flagNavUserAccount);
|
||||
}
|
||||
hookupButtonsNavUserLogout() {
|
||||
// this.hookupButtonsNav('.' + flagNavUserLogout);
|
||||
}
|
||||
hookupButtonsNavUserLogin() {
|
||||
Events.hookupEventHandler("click", '.' + flagNavUserLogin, (event, navigator) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.leave();
|
||||
API.loginUser()
|
||||
.then((response) => {
|
||||
if (response.Success) {
|
||||
window.location.href = response[flagCallback];
|
||||
} else {
|
||||
DOM.alertError("Error", response.Message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
hookupOverlays() {
|
||||
this.hookupOverlayFromId(idOverlayConfirm);
|
||||
this.hookupOverlayFromId(idOverlayError);
|
||||
}
|
||||
|
||||
hookupOverlayFromId(idOverlay) {
|
||||
Events.initialiseEventHandler(idOverlay, flagInitialised, (overlay) => {
|
||||
overlay.querySelector('button.' + flagCancel).addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
overlay.style.display = 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
hookupButtonSave() {
|
||||
Events.initialiseEventHandler('.' + flagContainer + '.' + flagSave + '.' + flagCancel + ' button.' + flagSave, flagInitialised, (button) => {
|
||||
button.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
button = event.target;
|
||||
if (button.classList.contains(flagIsCollapsed)) return;
|
||||
Utils.consoleLogIfNotProductionEnvironment('saving page: ', this.title);
|
||||
OverlayConfirm.show();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
leave() {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Leaving ' + this.title + ' page');
|
||||
if (this.constructor === BasePage) {
|
||||
throw new Error("Must implement leave() method.");
|
||||
}
|
||||
}
|
||||
setLocalStoragePage(dataPage) {
|
||||
LocalStorage.setLocalStorage(this.hash, dataPage);
|
||||
}
|
||||
getLocalStoragePage() {
|
||||
return LocalStorage.getLocalStorage(this.hash);
|
||||
}
|
||||
|
||||
toggleShowButtonsSaveCancel(show, buttonContainerSelector = null) { // , buttonSave = null, buttonCancel = null
|
||||
if (Validation.isEmpty(buttonContainerSelector)) buttonContainerSelector = '.' + flagContainer + '.' + flagSave + '.' + flagCancel;
|
||||
let buttonSave = document.querySelector(buttonContainerSelector + ' ' + idButtonSave);
|
||||
let buttonCancel = document.querySelector(buttonContainerSelector + ' ' + idButtonCancel);
|
||||
Utils.consoleLogIfNotProductionEnvironment({ show, buttonContainerSelector, buttonCancel, buttonSave });
|
||||
if (show) {
|
||||
buttonCancel.classList.remove(flagIsCollapsed);
|
||||
buttonSave.classList.remove(flagIsCollapsed);
|
||||
Utils.consoleLogIfNotProductionEnvironment('showing buttons');
|
||||
} else {
|
||||
buttonCancel.classList.add(flagIsCollapsed);
|
||||
buttonSave.classList.add(flagIsCollapsed);
|
||||
Utils.consoleLogIfNotProductionEnvironment('hiding buttons');
|
||||
}
|
||||
}
|
||||
|
||||
static isDirtyFilter(filter) {
|
||||
let isDirty = DOM.updateAndCheckIsElementDirty(filter);
|
||||
if (isDirty) document.querySelectorAll(idTableMain + ' tbody tr').remove();
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
}
|
||||
750
static/js/pages/base_table.js
Normal file
750
static/js/pages/base_table.js
Normal file
@@ -0,0 +1,750 @@
|
||||
|
||||
import BusinessObjects from "../lib/business_objects/business_objects.js";
|
||||
import Events from "../lib/events.js";
|
||||
import LocalStorage from "../lib/local_storage.js";
|
||||
import Validation from "../lib/validation.js";
|
||||
import BasePage from "./base.js";
|
||||
import API from "../api.js";
|
||||
import DOM from "../dom.js";
|
||||
import Utils from "../lib/utils.js";
|
||||
|
||||
import OverlayConfirm from "../components/common/temporary/overlay_confirm.js";
|
||||
import OverlayError from "../components/common/temporary/overlay_error.js";
|
||||
|
||||
export default class TableBasePage extends BasePage {
|
||||
// static hash
|
||||
// static attrIdRowObject
|
||||
// callSaveTableContent
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
this.cursorYInitial = null;
|
||||
this.rowInitial = null;
|
||||
this.placeholder = null;
|
||||
this.dragSrcEl = null;
|
||||
this.dragSrcRow = null;
|
||||
|
||||
this.hookupTableCellDdls = this.hookupTableCellDdls.bind(this);
|
||||
}
|
||||
|
||||
initialize(isPopState = false) {
|
||||
throw new Error("Must implement initialize() method.");
|
||||
}
|
||||
sharedInitialize(isPopState = false, isSinglePageApp = false) {
|
||||
if (!isPopState) {
|
||||
super.sharedInitialize();
|
||||
this.hookupFilters();
|
||||
this.hookupButtonsSaveCancel();
|
||||
this.hookupTableMain();
|
||||
OverlayConfirm.hookup(() => {
|
||||
if (isSinglePageApp) {
|
||||
this.saveRecordsTableDirtySinglePageApp();
|
||||
}
|
||||
else {
|
||||
this.saveRecordsTableDirty();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let dataPage = this.getLocalStoragePage();
|
||||
let filters = dataPage[flagFormFilters];
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let filtersDefault = DOM.convertForm2JSON(formFilters);
|
||||
if (!Validation.areEqualDicts(filters, filtersDefault)) {
|
||||
this.callFilterTableContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
hookupFilters() {
|
||||
if (this.constructor === TableBasePage) {
|
||||
throw new Error("Subclass of TableBasePage must implement method hookupFilters().");
|
||||
}
|
||||
}
|
||||
sharedHookupFilters() {
|
||||
this.hookupButtonApplyFilters();
|
||||
this.hookupSearchTextFilter();
|
||||
}
|
||||
hookupFilterActive() {
|
||||
let filterSelector = idFormFilters + ' #' + flagActiveOnly;
|
||||
let filterActiveOld = document.querySelector(filterSelector);
|
||||
filterActiveOld.removeAttribute('id');
|
||||
let parentDiv = filterActiveOld.parentElement;
|
||||
let isChecked = (DOM.getElementAttributeValuePrevious(parentDiv) == "True");
|
||||
let filterActiveNew = document.querySelector(idFormFilters + ' div.' + flagActiveOnly + '.' + flagContainerInput + ' svg.' + flagActiveOnly);
|
||||
filterActiveNew.setAttribute('id', flagActiveOnly);
|
||||
if (isChecked) filterActiveNew.classList.add(flagIsChecked);
|
||||
|
||||
Events.hookupEventHandler("click", filterSelector, (event, filterActive) => {
|
||||
Utils.consoleLogIfNotProductionEnvironment({ filterActive });
|
||||
Utils.consoleLogIfNotProductionEnvironment({ [filterActive.tagName]: filterActive.tagName });
|
||||
let svgElement = (filterActive.tagName.toUpperCase() == 'SVG') ? filterActive : filterActive.parentElement;
|
||||
let wasChecked = svgElement.classList.contains(flagIsChecked);
|
||||
if (wasChecked) {
|
||||
svgElement.classList.remove(flagIsChecked);
|
||||
}
|
||||
else {
|
||||
svgElement.classList.add(flagIsChecked);
|
||||
}
|
||||
return this.handleChangeFilter(event, filterActive);
|
||||
});
|
||||
let filter = document.querySelector(filterSelector);
|
||||
let filterValuePrevious = DOM.getElementValueCurrent(filter);
|
||||
filter.setAttribute(attrValueCurrent, filterValuePrevious);
|
||||
filter.setAttribute(attrValuePrevious, filterValuePrevious);
|
||||
}
|
||||
hookupFilter(filterFlag, handler = (event, filter) => { return this.handleChangeFilter(event, filter); }) {
|
||||
let filterSelector = idFormFilters + ' #' + filterFlag;
|
||||
Events.hookupEventHandler("change", filterSelector, handler);
|
||||
let filter = document.querySelector(filterSelector);
|
||||
let filterValuePrevious = DOM.getElementValueCurrent(filter);
|
||||
filter.setAttribute(attrValueCurrent, filterValuePrevious);
|
||||
filter.setAttribute(attrValuePrevious, filterValuePrevious);
|
||||
}
|
||||
handleChangeFilter(event, filter) {
|
||||
let isDirtyFilter = DOM.updateAndCheckIsElementDirty(filter);
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let areDirtyFilters = isDirtyFilter || DOM.hasDirtyChildrenContainer(formFilters);
|
||||
let tbody = document.querySelector(idTableMain + ' tbody');
|
||||
let rows = tbody.querySelectorAll(':scope > tr');
|
||||
rows.forEach((row) => {
|
||||
if (areDirtyFilters && !row.classList.contains(flagIsCollapsed)) row.classList.add(flagIsCollapsed);
|
||||
if (!areDirtyFilters && row.classList.contains(flagIsCollapsed)) {
|
||||
row.classList.remove(flagIsCollapsed);
|
||||
let dirtyInputs = row.querySelectorAll('input.' + flagDirty);
|
||||
dirtyInputs.forEach((dirtyInput) => {
|
||||
dirtyInput.value = DOM.getElementAttributeValueCurrent(dirtyInput);
|
||||
});
|
||||
}
|
||||
});
|
||||
if (areDirtyFilters) {
|
||||
/*
|
||||
tbody.querySelectorAll('tr').forEach((tr) => {
|
||||
if (!DOM.hasDirtyChildrenContainer(tr)) tr.remove();
|
||||
});
|
||||
*/
|
||||
tbody.innerHTML = '<div>Press "Apply Filters" to refresh the table.</div>' + tbody.innerHTML;
|
||||
if (!tbody.classList.contains(flagIsCollapsed)) tbody.classList.add(flagIsCollapsed);
|
||||
}
|
||||
else {
|
||||
let isDirtyLabel = tbody.querySelector(":scope > div");
|
||||
if (isDirtyLabel != null) isDirtyLabel.remove();
|
||||
if (tbody.classList.contains(flagIsCollapsed)) tbody.classList.remove(flagIsCollapsed);
|
||||
let initialisedElements = tbody.querySelectorAll('.' + flagInitialised);
|
||||
initialisedElements.forEach((initialisedElement) => {
|
||||
initialisedElement.classList.remove(flagInitialised);
|
||||
});
|
||||
this.hookupTableMain();
|
||||
}
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
hookupFilterIsNotEmpty() {
|
||||
this.hookupFilter(flagIsNotEmpty);
|
||||
}
|
||||
hookupButtonApplyFilters() {
|
||||
Events.hookupEventHandler("click", idButtonApplyFilters, (event, button) => {
|
||||
event.stopPropagation();
|
||||
this.callFilterTableContent();
|
||||
});
|
||||
}
|
||||
hookupSearchTextFilter() {
|
||||
this.hookupFilter(flagSearch);
|
||||
}
|
||||
hookupFilterCommandCategory() {
|
||||
this.hookupFilter(attrIdCommandCategory, (event, filterCommandCategory) => {
|
||||
this.handleChangeFilter();
|
||||
let isDirtyFilter = filterCommandCategory.classList.contains(flagDirty);
|
||||
let idCommandCategory = DOM.getElementValueCurrent(filterCommandCategory);
|
||||
console.log("filter commands unsorted");
|
||||
console.log(Utils.getListFromDict(filterCommands));
|
||||
let commandsInCategory = Utils.getListFromDict(filterCommands).filter(command => command[attrIdCommandCategory] == idCommandCategory);
|
||||
let sortedCommands = commandsInCategory.sort((a, b) => a[flagName].localeCompare(b[flagName]));
|
||||
let filterCommand = document.querySelector(idFormFilters + ' .' + flagCommand);
|
||||
let idCommandPrevious = DOM.getElementAttributeValuePrevious(filterCommand);
|
||||
filterCommand.innerHTML = '';
|
||||
let optionJson, option;
|
||||
option = DOM.createOption(null);
|
||||
filterCommand.appendChild(option);
|
||||
sortedCommands.forEach((command) => {
|
||||
optionJson = BusinessObjects.getOptionJsonFromObjectJson(command, idCommandPrevious);
|
||||
option = DOM.createOption(optionJson);
|
||||
filterCommand.appendChild(option);
|
||||
});
|
||||
filterCommand.dispatchEvent(new Event('change'));
|
||||
return isDirtyFilter;
|
||||
});
|
||||
}
|
||||
hookupFilterCommand() {
|
||||
this.hookupFilter(attrIdCommand);
|
||||
}
|
||||
hookupFilterLocation() {
|
||||
this.hookupFilter(attrIdLocation);
|
||||
}
|
||||
/*
|
||||
getAndLoadFilteredTableContent = () => {
|
||||
this.callFilterTableContent()
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
*/
|
||||
static getFormFilters() {
|
||||
return document.querySelector(idFormFilters);
|
||||
}
|
||||
callFilterTableContent() {
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let filtersJson = DOM.convertForm2JSON(formFilters);
|
||||
Utils.consoleLogIfNotProductionEnvironment("callFilterTableContent");
|
||||
Utils.consoleLogIfNotProductionEnvironment("formFilters");
|
||||
Utils.consoleLogIfNotProductionEnvironment(formFilters);
|
||||
Utils.consoleLogIfNotProductionEnvironment("filtersJson");
|
||||
Utils.consoleLogIfNotProductionEnvironment(filtersJson);
|
||||
this.leave();
|
||||
API.goToHash(this.constructor.hash, filtersJson);
|
||||
}
|
||||
callbackLoadTableContent(response) {
|
||||
let table = TableBasePage.getTableMain();
|
||||
let bodyTable = table.querySelector('tbody');
|
||||
bodyTable.querySelectorAll('tr').forEach(function(row) { row.remove(); });
|
||||
let rowsJson = response.data[flagRows];
|
||||
if (!Validation.isEmpty(rowsJson) && rowsJson.every(row => row.hasOwnProperty('display_order'))) {
|
||||
rowsJson = rowsJson.sort((a, b) => a.display_order - b.display_order);
|
||||
}
|
||||
rowsJson.forEach(this.loadRowTable.bind(this));
|
||||
this.hookupTableMain();
|
||||
}
|
||||
static getTableMain() {
|
||||
return document.querySelector(idTableMain);
|
||||
}
|
||||
loadRowTable(rowJson) {
|
||||
throw new Error("Subclass of TableBasePage must implement method loadRowTable().");
|
||||
}
|
||||
getAndLoadFilteredTableContentSinglePageApp() {
|
||||
this.callFilterTableContent()
|
||||
.then(data => {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Table data received:', data);
|
||||
this.callbackLoadTableContent(data);
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
hookupButtonsSaveCancel() {
|
||||
this.hookupButtonSave();
|
||||
this.hookupButtonCancel();
|
||||
this.toggleShowButtonsSaveCancel(false);
|
||||
}
|
||||
saveRecordsTableDirty() {
|
||||
let records = this.getTableRecords(true);
|
||||
if (records.length == 0) {
|
||||
OverlayError.show('No records to save');
|
||||
return;
|
||||
}
|
||||
let formElement = TableBasePage.getFormFilters();
|
||||
let comment = DOM.getElementValueCurrent(document.querySelector(idTextareaConfirm));
|
||||
/*
|
||||
Utils.consoleLogIfNotProductionEnvironment({ formElement, comment, records });
|
||||
Utils.consoleLogIfNotProductionEnvironment('records');
|
||||
Utils.consoleLogIfNotProductionEnvironment(records);
|
||||
debugger;
|
||||
*/
|
||||
this.callSaveTableContent(records, formElement, comment)
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
if (_verbose) {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||
}
|
||||
this.callFilterTableContent();
|
||||
}
|
||||
else {
|
||||
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||
OverlayError.show(data[flagMessage]);
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
getTableRecords(dirtyOnly = false) {
|
||||
let records = [];
|
||||
let record;
|
||||
document.querySelectorAll(idTableMain + ' > tbody > tr').forEach((row) => {
|
||||
if (dirtyOnly && !DOM.hasDirtyChildrenContainer(row)) return;
|
||||
record = this.getJsonRow(row);
|
||||
records.push(record);
|
||||
});
|
||||
return records;
|
||||
}
|
||||
getJsonRow(row) {
|
||||
throw new Error("Subclass of TableBasePage must implement method getJsonRow().");
|
||||
}
|
||||
saveRecordsTableDirtySinglePageApp() {
|
||||
let records = this.getTableRecords(true);
|
||||
if (records.length == 0) {
|
||||
OverlayError.show('No records to save');
|
||||
return;
|
||||
}
|
||||
let formElement = TableBasePage.getFormFilters();
|
||||
let comment = DOM.getElementValueCurrent(document.querySelector(idTextareaConfirm));
|
||||
this.callSaveTableContent(records, formElement, comment)
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
if (_verbose) {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||
}
|
||||
this.callbackLoadTableContent(data);
|
||||
}
|
||||
else {
|
||||
Utils.consoleLogIfNotProductionEnvironment("error: ", data[flagMessage]);
|
||||
OverlayError.show(data[flagMessage]);
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error:', error));
|
||||
}
|
||||
hookupButtonCancel() {
|
||||
Events.initialiseEventHandler('.' + flagContainer + '.' + flagSave + '.' + flagCancel + ' button.' + flagCancel, flagInitialised, (button) => {
|
||||
button.addEventListener("click", (event) => {
|
||||
event.stopPropagation();
|
||||
button = event.target;
|
||||
if (button.classList.contains(flagIsCollapsed)) return;
|
||||
this.callFilterTableContent();
|
||||
});
|
||||
button.classList.add(flagIsCollapsed);
|
||||
});
|
||||
}
|
||||
handleClickAddRowTable(event, button) {
|
||||
event.stopPropagation();
|
||||
_rowBlank.setAttribute(this.constructor.attrIdRowObject, -1 - _rowBlank.getAttribute(this.constructor.attrIdRowObject));
|
||||
let tbody = document.querySelector(idTableMain + ' tbody');
|
||||
if (tbody.classList.contains(flagIsCollapsed)) return;
|
||||
let row = _rowBlank.cloneNode(true);
|
||||
row.classList.remove(flagInitialised);
|
||||
row.querySelectorAll('.' + flagInitialised).forEach(function(element) {
|
||||
element.classList.remove(flagInitialised);
|
||||
});
|
||||
let countRows = document.querySelectorAll(idTableMain + ' > tbody > tr').length;
|
||||
row.setAttribute(this.constructor.attrIdRowObject, -1 - countRows);
|
||||
this.initialiseRowNew(tbody, row);
|
||||
tbody.prepend(row);
|
||||
tbody.scrollTop = 0;
|
||||
this.hookupTableMain();
|
||||
this.postInitialiseRowNewCallback(tbody);
|
||||
}
|
||||
initialiseRowNew(tbody, row) {
|
||||
if (this.constructor === TableBasePage) {
|
||||
throw new Error("Subclass of TableBasePage must implement method initialiseRowNew().");
|
||||
}
|
||||
// row.classList.remove(flagRowNew);
|
||||
}
|
||||
hookupTableMain() {
|
||||
if (this.constructor === TableBasePage) {
|
||||
throw new Error("Must implement hookupTableMain() method.");
|
||||
}
|
||||
Events.initialiseEventHandler(idTableMain, flagInitialised, (table) => {
|
||||
this.cacheRowBlank();
|
||||
});
|
||||
}
|
||||
cacheRowBlank() {
|
||||
let selectorRowNew = idTableMain + ' tbody tr.' + flagRowNew;
|
||||
let rowBlankTemp = document.querySelector(selectorRowNew);
|
||||
Utils.consoleLogIfNotProductionEnvironment("row blank temp: ", rowBlankTemp);
|
||||
let countRows = document.querySelectorAll(idTableMain + ' > tbody > tr').length;
|
||||
_rowBlank = rowBlankTemp.cloneNode(true);
|
||||
document.querySelectorAll(selectorRowNew).forEach(function(row) {
|
||||
row.remove();
|
||||
});
|
||||
_rowBlank.setAttribute(this.constructor.attrIdRowObject, -1 - countRows);
|
||||
}
|
||||
postInitialiseRowNewCallback(tbody) {
|
||||
if (this.constructor === TableBasePage) {
|
||||
throw new Error("Subclass of TableBasePage must implement method postInitialiseRowNewCallback(tbody).");
|
||||
}
|
||||
}
|
||||
initialiseSliderDisplayOrderRowNew(tbody, row) {
|
||||
// let tdSelector = ':scope > tr > td.' + flagDisplayOrder;
|
||||
// let tbody = document.querySelector('table' + (Validation.isEmpty(flagTable) ? '' : '.' + flagTable) + ' > tbody');
|
||||
let slidersDisplayOrder = tbody.querySelectorAll(':scope > tr > td.' + flagDisplayOrder + ' input.' + flagSlider);
|
||||
let maxDisplayOrder = 0;
|
||||
slidersDisplayOrder.forEach((slider) => {
|
||||
maxDisplayOrder = Math.max(maxDisplayOrder, parseFloat(DOM.getElementValueCurrent(slider)));
|
||||
});
|
||||
let sliderDisplayOrder = row.querySelector('td.' + flagDisplayOrder + ' .' + flagSlider);
|
||||
DOM.setElementValuesCurrentAndPrevious(sliderDisplayOrder, maxDisplayOrder + 1);
|
||||
}
|
||||
hookupSlidersDisplayOrderTable() {
|
||||
let selectorDisplayOrder = idTableMain + ' tbody tr td.' + flagDisplayOrder + ' input.' + flagSlider + '.' + flagDisplayOrder;
|
||||
this.hookupChangeHandlerTableCells(selectorDisplayOrder);
|
||||
}
|
||||
hookupChangeHandlerTableCells(inputSelector, handler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
Events.initialiseEventHandler(inputSelector, flagInitialised, (input) => {
|
||||
input.addEventListener("change", (event) => {
|
||||
handler(event, input);
|
||||
});
|
||||
handler(null, input);
|
||||
});
|
||||
}
|
||||
handleChangeNestedElementCellTable(event, element) {
|
||||
let wasDirtyParentRows = this.getAllIsDirtyRowsInParentTree(element);
|
||||
let wasDirtyElement = element.classList.contains(flagDirty);
|
||||
let isDirtyElement = DOM.updateAndCheckIsElementDirty(element);
|
||||
// Utils.consoleLogIfNotProductionEnvironment({isDirtyElement, wasDirtyElement, wasDirtyParentRows});
|
||||
// let td = DOM.getCellFromElement(element);
|
||||
// DOM.setElementAttributeValueCurrent(td, DOM.getElementAttributeValueCurrent(element));
|
||||
if (isDirtyElement != wasDirtyElement) {
|
||||
// DOM.handleDirtyElement(td, isDirtyElement);
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
this.cascadeChangedIsDirtyNestedElementCellTable(element, isDirtyElement, wasDirtyParentRows);
|
||||
}
|
||||
}
|
||||
getAllIsDirtyRowsInParentTree(element) {
|
||||
let rows = [];
|
||||
let parent = element;
|
||||
let isDirty;
|
||||
while (parent) {
|
||||
if (parent.tagName.toUpperCase() == 'TR') {
|
||||
isDirty = parent.classList.contains(flagDirty)
|
||||
rows.push(isDirty);
|
||||
}
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
cascadeChangedIsDirtyNestedElementCellTable(element, isDirtyElement, wasDirtyParentRows) {
|
||||
if (Validation.isEmpty(wasDirtyParentRows)) return;
|
||||
let tr = DOM.getRowFromElement(element);
|
||||
let isDirtyRow = isDirtyElement || DOM.hasDirtyChildrenContainer(tr);
|
||||
let wasDirtyRow = wasDirtyParentRows.shift();
|
||||
Utils.consoleLogIfNotProductionEnvironment({isDirtyRow, wasDirtyRow});
|
||||
if (isDirtyRow != wasDirtyRow) {
|
||||
DOM.handleDirtyElement(tr, isDirtyRow);
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
this.cascadeChangedIsDirtyNestedElementCellTable(tr.parentElement, isDirtyRow, wasDirtyParentRows);
|
||||
}
|
||||
}
|
||||
hookupChangeHandlerTableCellsWhenNotCollapsed(inputSelector, handler = (event, element) => {
|
||||
if (!element.classList.contains(flagIsCollapsed)) this.handleChangeNestedElementCellTable(event, element);
|
||||
}) {
|
||||
Events.hookupEventHandler("change", inputSelector, handler);
|
||||
}
|
||||
hookupFieldsCodeTable() {
|
||||
this.hookupChangeHandlerTableCells(idTableMain + ' > tbody > tr > td.' + flagCode + ' > .' + flagCode);
|
||||
}
|
||||
hookupFieldsNameTable() {
|
||||
this.hookupChangeHandlerTableCells(idTableMain + ' > tbody > tr > td.' + flagName + ' > .' + flagName);
|
||||
}
|
||||
hookupFieldsDescriptionTable() {
|
||||
this.hookupChangeHandlerTableCells(idTableMain + ' > tbody > tr > td.' + flagDescription + ' > .' + flagDescription);
|
||||
}
|
||||
hookupFieldsNotesTable() {
|
||||
this.hookupChangeHandlerTableCells(idTableMain + ' > tbody > tr > td.' + flagNotes + ' > .' + flagNotes);
|
||||
}
|
||||
hookupFieldsActive(flagTable = '', handleClickRowNew = (event, element) => { this.handleClickAddRowTable(event, element); }) {
|
||||
let selectorButton = 'table.table-main' + (Validation.isEmpty(flagTable) ? '' : '.' + flagTable) + ' > tbody > tr > td.' + flagActive + ' .' + flagButton + '.' + flagActive;
|
||||
let selectorButtonDelete = selectorButton + '.' + flagDelete;
|
||||
let selectorButtonUndelete = selectorButton + ':not(.' + flagDelete + ')';
|
||||
Utils.consoleLogIfNotProductionEnvironment("hookupFieldsActive: ", selectorButtonDelete, selectorButtonUndelete);
|
||||
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete);
|
||||
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete);
|
||||
Events.hookupEventHandler(
|
||||
"click"
|
||||
, 'table.table-main' + (Validation.isEmpty(flagTable) ? '' : '.' + flagTable) + ' > thead > tr > th.' + flagActive + ' .' + flagButton + '.' + flagActive
|
||||
, (event, button) => { handleClickRowNew(event, button); }
|
||||
);
|
||||
}
|
||||
hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
Events.hookupEventHandler("click", selectorButtonDelete, (event, element) => {
|
||||
this.handleClickButtonRowDelete(event, element, selectorButtonDelete, selectorButtonUndelete, (changeEvent, changeElement) => { changeHandler(changeEvent, changeElement); });
|
||||
});
|
||||
}
|
||||
handleClickButtonRowDelete(event, element, selectorButtonDelete, selectorButtonUndelete, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
if (element.tagName.toUpperCase() != 'SVG') element = element.parentElement;
|
||||
let valuePrevious = DOM.getElementAttributeValuePrevious(element);
|
||||
let wasDirty = element.classList.contains(flagDirty);
|
||||
let row = DOM.getRowFromElement(element);
|
||||
if (row.classList.contains(flagRowNew) && !DOM.hasDirtyChildrenContainer(row)) {
|
||||
row.parentNode.removeChild(row);
|
||||
}
|
||||
else {
|
||||
let buttonAddTemplate = document.querySelector(idContainerTemplateElements + ' .' + flagButton + '.' + flagActive + '.' + flagAdd);
|
||||
let buttonAdd = buttonAddTemplate.cloneNode(true);
|
||||
DOM.setElementAttributeValuePrevious(buttonAdd, valuePrevious);
|
||||
DOM.setElementAttributeValueCurrent(buttonAdd, false);
|
||||
if (wasDirty) buttonAdd.classList.add(flagDirty);
|
||||
element.replaceWith(buttonAdd);
|
||||
changeHandler(null, buttonAdd);
|
||||
this.hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete, (changeEvent, changeElement) => { changeHandler(changeEvent, changeElement); });
|
||||
}
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
hookupButtonsRowUndelete(selectorButtonDelete, selectorButtonUndelete, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
Events.hookupEventHandler("click", selectorButtonUndelete, (event, element) => {
|
||||
this.handleClickButtonRowUndelete(event, element, selectorButtonDelete, selectorButtonUndelete, (changeEvent, changeElement) => { changeHandler(changeEvent, changeElement); });
|
||||
});
|
||||
}
|
||||
handleClickButtonRowUndelete(event, element, selectorButtonDelete, selectorButtonUndelete, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
if (element.tagName.toUpperCase() != 'SVG') element = element.parentElement;
|
||||
let valuePrevious = DOM.getElementAttributeValuePrevious(element);
|
||||
let wasDirty = DOM.isElementDirty(element);
|
||||
let buttonDeleteTemplate = document.querySelector(idContainerTemplateElements + ' .' + flagButton + '.' + flagActive + '.' + flagDelete);
|
||||
let buttonDelete = buttonDeleteTemplate.cloneNode(true);
|
||||
DOM.setElementAttributeValuePrevious(buttonDelete, valuePrevious);
|
||||
DOM.setElementAttributeValueCurrent(buttonDelete, true);
|
||||
if (wasDirty) buttonDelete.classList.add(flagDirty);
|
||||
element.replaceWith(buttonDelete);
|
||||
changeHandler(null, buttonDelete);
|
||||
this.hookupButtonsRowDelete(selectorButtonDelete, selectorButtonUndelete, (changeEvent, changeElement) => { changeHandler(changeEvent, changeElement); });
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
hookupTdsAccessLevel() {
|
||||
this.hookupTableCellDdlPreviews(flagAccessLevel, Utils.getListFromDict(accessLevels));
|
||||
}
|
||||
hookupTableCellDdlPreviews(
|
||||
fieldFlag
|
||||
, optionList
|
||||
, cellSelector = null
|
||||
, ddlHookup = (ddlSelector) => { this.hookupTableCellDdls(ddlSelector); }
|
||||
, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }
|
||||
) {
|
||||
if (cellSelector == null) cellSelector = idTableMain + ' > tbody > tr > td.' + fieldFlag;
|
||||
Events.hookupEventHandler("click", cellSelector + ' div.' + fieldFlag, (event, div) => {
|
||||
this.handleClickTableCellDdlPreview(
|
||||
event
|
||||
, div
|
||||
, fieldFlag
|
||||
, optionList
|
||||
, cellSelector
|
||||
, (ddlSelector) => { ddlHookup(
|
||||
ddlSelector
|
||||
, (event, element) => { changeHandler(event, element); }
|
||||
); }
|
||||
);
|
||||
});
|
||||
ddlHookup(cellSelector + ' select.' + fieldFlag);
|
||||
}
|
||||
hookupTableCellDdls(ddlSelector, changeHandler = (event, element) => { this.handleChangeNestedElementCellTable(event, element); }) {
|
||||
this.hookupChangeHandlerTableCells(ddlSelector, (event, element) => { changeHandler(event, element); });
|
||||
}
|
||||
handleClickTableCellDdlPreview(event, div, fieldFlag, optionObjectList, cellSelector = null, ddlHookup = (cellSelector) => { this.hookupTableCellDdls(cellSelector); }) {
|
||||
if (Validation.isEmpty(cellSelector)) cellSelector = idTableMain + ' > tbody > tr > td.' + fieldFlag;
|
||||
let idSelected = DOM.getElementAttributeValueCurrent(div);
|
||||
let td = DOM.getCellFromElement(div);
|
||||
td.innerHTML = '';
|
||||
let ddl = document.createElement('select');
|
||||
ddl.classList.add(fieldFlag);
|
||||
DOM.setElementValuesCurrentAndPrevious(ddl, idSelected);
|
||||
let optionJson, option;
|
||||
if (_verbose) {
|
||||
Utils.consoleLogIfNotProductionEnvironment("click table cell ddl preview");
|
||||
Utils.consoleLogIfNotProductionEnvironment({optionObjectList, cellSelector});
|
||||
}
|
||||
option = DOM.createOption(null);
|
||||
ddl.appendChild(option);
|
||||
optionObjectList.forEach((optionObjectJson) => {
|
||||
optionJson = BusinessObjects.getOptionJsonFromObjectJson(optionObjectJson, idSelected);
|
||||
option = DOM.createOption(optionJson);
|
||||
ddl.appendChild(option);
|
||||
});
|
||||
td.appendChild(ddl);
|
||||
let ddlSelector = cellSelector + ' select.' + fieldFlag;
|
||||
ddlHookup(ddlSelector);
|
||||
}
|
||||
/*
|
||||
hookupTableCellDDlPreviewsWhenNotCollapsed(cellSelector, optionList, ddlHookup = (event, element) => { this.hookupTableCellDdls(event, element); }) {
|
||||
Events.hookupEventHandler("click", cellSelector + ' div', (event, div) => {
|
||||
this.handleClickTableCellDdlPreview(event, div, optionList, cellSelector, (event, element) => { ddlHookup(event, element); });
|
||||
});
|
||||
}
|
||||
*/
|
||||
toggleColumnCollapsed(flagColumn, isCollapsed) {
|
||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagIsCollapsed);
|
||||
}
|
||||
toggleColumnHeaderCollapsed(flagColumn, isCollapsed) {
|
||||
this.toggleColumnHasClassnameFlag(flagColumn, isCollapsed, flagIsCollapsed);
|
||||
}
|
||||
|
||||
hookupFieldsCommandCategory(idTable = null) {
|
||||
if (idTable == null) idTable = idTableMain;
|
||||
this.hookupTableCellDdlPreviews(
|
||||
flagCommandCategory
|
||||
, Utils.getListFromDict(filterCommandCategories).sort((a, b) => a[flagName].localeCompare(b[flagName]))
|
||||
, idTable + ' > tbody > tr > td.' + flagCommandCategory // + ' .' + flagCommandCategory
|
||||
, (cellSelector) => { this.hookupCommandCategoryDdls(cellSelector); }
|
||||
);
|
||||
}
|
||||
hookupCommandCategoryDdls(ddlSelector) {
|
||||
this.hookupChangeHandlerTableCells(ddlSelector, (event, element) => { this.handleChangeCommandCategoryDdl(event, element); });
|
||||
}
|
||||
handleChangeCommandCategoryDdl(event, ddlCategory) {
|
||||
let row = DOM.getRowFromElement(ddlCategory);
|
||||
let idCommandCategoryRowOld = this.getIdCommandCategoryRow(row); // DOM.getElementAttributeValueCurrent(ddlCategory);
|
||||
this.handleChangeNestedElementCellTable(event, ddlCategory);
|
||||
let idCommandCategoryRowNew = this.getIdCommandCategoryRow(row); // DOM.getElementAttributeValueCurrent(ddlCategory);
|
||||
if (
|
||||
idCommandCategoryRowOld == idCommandCategoryRowNew
|
||||
|| idCommandCategoryRowNew == 0
|
||||
) return;
|
||||
console.log({ idCommandCategoryRowNew, idCommandCategoryRowOld });
|
||||
let idCommandCategoryFilter = this.getIdCommandCategoryFilter();
|
||||
let tdCommand = row.querySelector('td.' + flagCommand);
|
||||
tdCommand.dispatchEvent(new Event('click'));
|
||||
let ddlCommand = row.querySelector('td.' + flagCommand + ' select.' + flagCommand);
|
||||
ddlCommand.innerHTML = '';
|
||||
ddlCommand.appendChild(DOM.createOption(null));
|
||||
let optionJson, option;
|
||||
let commandsInCategory = Utils.getListFromDict(filterCommands).filter(command =>
|
||||
(
|
||||
command[attrIdCommandCategory] == idCommandCategoryRowNew
|
||||
|| idCommandCategoryRowNew == 0
|
||||
)
|
||||
&& (
|
||||
command[attrIdCommandCategory] == idCommandCategoryFilter
|
||||
|| idCommandCategoryFilter == 0
|
||||
)
|
||||
);
|
||||
let sortedCommands = commandsInCategory.sort((a, b) => a[flagName].localeCompare(b[flagName]));
|
||||
sortedCommands.forEach((command) => {
|
||||
optionJson = BusinessObjects.getOptionJsonFromObjectJson(command);
|
||||
option = DOM.createOption(optionJson);
|
||||
ddlCommand.appendChild(option);
|
||||
});
|
||||
this.handleChangeNestedElementCellTable(event, ddlCommand);
|
||||
}
|
||||
hookupFieldsCommand(idTable = null) {
|
||||
if (idTable == null) idTable = idTableMain;
|
||||
Events.hookupEventHandler("click", idTable + ' > tbody > tr > td.' + flagCommand + ' div.' + flagCommand, (event, div) => {
|
||||
Utils.consoleLogIfNotProductionEnvironment(div);
|
||||
let parentTr = DOM.getRowFromElement(div);
|
||||
Utils.consoleLogIfNotProductionEnvironment({ div, parentTr });
|
||||
let tdCommandCategory = parentTr.querySelector('td.' + flagCommandCategory);
|
||||
let idCommandCategoryRow = this.getIdCommandCategoryRow(parentTr); // DOM.getElementAttributeValueCurrent(tdCommandCategory);
|
||||
let idCommandCategoryFilter = this.getIdCommandCategoryFilter();
|
||||
let filterCommandList = Utils.getListFromDict(filterCommands);
|
||||
let commandsInCategory = filterCommandList.filter(command =>
|
||||
(
|
||||
command[attrIdCommandCategory] == idCommandCategoryRow
|
||||
|| idCommandCategoryRow == 0
|
||||
)
|
||||
&& (
|
||||
command[attrIdCommandCategory] == idCommandCategoryFilter
|
||||
|| idCommandCategoryFilter == 0
|
||||
)
|
||||
);
|
||||
let sortedCommands = commandsInCategory.sort((a, b) => a[flagName].localeCompare(b[flagName]));
|
||||
Utils.consoleLogIfNotProductionEnvironment({ tdCommandCategory, idCommandCategoryRow, idCommandCategoryFilter, filterCommandList, commandsInCategory });
|
||||
Utils.consoleLogIfNotProductionEnvironment(filterCommandList);
|
||||
this.handleClickTableCellDdlPreview(
|
||||
event
|
||||
, div
|
||||
, flagCommand // fieldFlag
|
||||
, sortedCommands // optionList
|
||||
, idTable + ' > tbody > tr > td.' + flagCommand // cellSelector
|
||||
, (cellSelector) => { this.hookupTableCellDdls(
|
||||
cellSelector
|
||||
, (event, element) => { this.handleChangeCommandDdl(event, element); }
|
||||
); }
|
||||
);
|
||||
});
|
||||
this.hookupTableCellDdls(
|
||||
idTable + ' > tbody > tr > td.' + flagCommand + ' select.' + flagCommand
|
||||
, (event, element) => { this.handleChangeCommandDdl(event, element); }
|
||||
);
|
||||
}
|
||||
handleChangeCommandDdl(event, ddlCommand) {
|
||||
// console.log("handle change command ddl");
|
||||
let row = DOM.getRowFromElement(ddlCommand);
|
||||
this.handleChangeNestedElementCellTable(event, ddlCommand);
|
||||
let idCommandCategoryRowOld = this.getIdCommandCategoryRow(row);
|
||||
let idCommandNew = this.getIdCommandRow(row);
|
||||
let commandNew = filterCommands[idCommandNew];
|
||||
// console.log({ idCommandCategoryRowOld, commandNew });
|
||||
if (commandNew == null || idCommandCategoryRowOld == commandNew[attrIdCommandCategory]) return;
|
||||
let divCommandCategory = row.querySelector('td.' + flagCommandCategory + ' div');
|
||||
if (divCommandCategory) divCommandCategory.dispatchEvent(new Event('click'));
|
||||
let ddlCommandCategory = row.querySelector('td.' + flagCommandCategory + ' select.' + flagCommandCategory);
|
||||
DOM.setElementValueCurrent(ddlCommandCategory, commandNew[attrIdCommandCategory]);
|
||||
// console.log({ ddlCommandCategory, commandNew });
|
||||
this.handleChangeNestedElementCellTable(event, ddlCommandCategory);
|
||||
}
|
||||
getIdCommandCategoryRow(tr) {
|
||||
let elementCommandCategory = tr.querySelector('td.' + flagCommandCategory + ' .' + flagCommandCategory);
|
||||
return DOM.getElementAttributeValueCurrent(elementCommandCategory);
|
||||
}
|
||||
getIdCommandCategoryFilter() {
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let idCommandCategory = 0;
|
||||
if (formFilters == null) return idCommandCategory;
|
||||
let commandCategoryFilter = formFilters.querySelector('#' + attrIdCommandCategory);
|
||||
let commandFilter = formFilters.querySelector('#' + attrIdCommand);
|
||||
let valueCurrentCommandCategoryFilter = DOM.getElementAttributeValueCurrent(commandCategoryFilter);
|
||||
Utils.consoleLogIfNotProductionEnvironment({ valueCurrentCommandCategoryFilter });
|
||||
if (valueCurrentCommandCategoryFilter == "") {
|
||||
let valueCurrentCommandFilter = DOM.getElementAttributeValueCurrent(commandFilter);
|
||||
Utils.consoleLogIfNotProductionEnvironment({ valueCurrentCommandFilter });
|
||||
if (valueCurrentCommandFilter != "") {
|
||||
let command = filterCommands[valueCurrentCommandFilter];
|
||||
idCommandCategory = command[attrIdCommandCategory];
|
||||
}
|
||||
} else {
|
||||
idCommandCategory = Number(valueCurrentCommandCategoryFilter);
|
||||
}
|
||||
return idCommandCategory;
|
||||
}
|
||||
getHasCommandCategoryFilter() {
|
||||
let idCommandCategoryFilter = this.getIdCommandCategoryFilter();
|
||||
return !(Validation.isEmpty(idCommandCategoryFilter) || idCommandCategoryFilter == 0);
|
||||
}
|
||||
getIdCommandRow(tr) {
|
||||
let elementCommand = tr.querySelector('td.' + flagCommand + ' .' + flagCommand);
|
||||
return DOM.getElementAttributeValueCurrent(elementCommand);
|
||||
}
|
||||
getIdCommandFilter() {
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let commandFilter = formFilters.querySelector('#' + attrIdCommand);
|
||||
let valueCurrentCommandFilter = DOM.getElementAttributeValueCurrent(commandFilter);
|
||||
let idCommand = Number(valueCurrentCommandFilter);
|
||||
return idCommand;
|
||||
}
|
||||
getHasCommandFilter() {
|
||||
let idCommandFilter = this.getIdCommandFilter();
|
||||
return !(Validation.isEmpty(idCommandFilter) || idCommandFilter == 0);
|
||||
}
|
||||
/*
|
||||
createTdActive(isActive) {
|
||||
let tdActive = document.createElement("td");
|
||||
tdActive.classList.add(flagActive);
|
||||
let buttonActive = document.createElement("button");
|
||||
buttonActive.classList.add(flagActive);
|
||||
buttonActive.classList.add(isActive ? flagDelete : flagAdd);
|
||||
buttonActive.textContent = isActive ? 'x' : '+';
|
||||
DOM.setElementAttributesValuesCurrentAndPrevious(buttonActive, isActive);
|
||||
tdActive.appendChild(buttonActive);
|
||||
return tdActive;
|
||||
}
|
||||
*/
|
||||
leave() {
|
||||
if (this.constructor === TableBasePage) {
|
||||
throw new Error("Must implement leave() method.");
|
||||
}
|
||||
super.leave();
|
||||
let formFilters = TableBasePage.getFormFilters();
|
||||
let dataPage = {};
|
||||
dataPage[flagFormFilters] = DOM.convertForm2JSON(formFilters);
|
||||
this.setLocalStoragePage(dataPage);
|
||||
}
|
||||
|
||||
toggleColumnHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||
let table = TableBasePage.getTableMain();
|
||||
let columnTh = table.querySelector('th.' + columnFlag);
|
||||
let columnThHasFlag = columnTh.classList.contains(classnameFlag);
|
||||
if (isRequiredFlag == columnThHasFlag) return;
|
||||
DOM.toggleElementHasClassnameFlag(columnTh, isRequiredFlag, classnameFlag);
|
||||
}
|
||||
toggleColumnHeaderHasClassnameFlag(columnFlag, isRequiredFlag, classnameFlag) {
|
||||
let table = TableBasePage.getTableMain();
|
||||
let columnTh = table.querySelector('th.' + columnFlag);
|
||||
DOM.toggleElementHasClassnameFlag(columnTh, isRequiredFlag, classnameFlag);
|
||||
}
|
||||
|
||||
updateAndToggleShowButtonsSaveCancel() {
|
||||
let pageBody = document.querySelector(idPageBody);
|
||||
let isDirty = DOM.hasDirtyChildrenContainer(pageBody);
|
||||
|
||||
console.log({ pageBody, isDirty });
|
||||
|
||||
this.toggleShowButtonsSaveCancel(isDirty);
|
||||
}
|
||||
}
|
||||
17
static/js/pages/legal/accessibility_report.js
Normal file
17
static/js/pages/legal/accessibility_report.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import BasePage from "../base.js";
|
||||
|
||||
export default class PageAccessibilityReport extends BasePage {
|
||||
static hash = hashPageAccessibilityReport;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
17
static/js/pages/legal/accessibility_statement.js
Normal file
17
static/js/pages/legal/accessibility_statement.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import BasePage from "../base.js";
|
||||
|
||||
export default class PageAccessibilityStatement extends BasePage {
|
||||
static hash = hashPageAccessibilityStatement;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
18
static/js/pages/legal/license.js
Normal file
18
static/js/pages/legal/license.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
import BasePage from "../base.js";
|
||||
|
||||
export default class PageLicense extends BasePage {
|
||||
static hash = hashPageLicense;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
18
static/js/pages/legal/privacy_policy.js
Normal file
18
static/js/pages/legal/privacy_policy.js
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
import BasePage from "../base.js";
|
||||
|
||||
export default class PagePrivacyPolicy extends BasePage {
|
||||
static hash = hashPagePrivacyPolicy;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
17
static/js/pages/legal/retention_schedule.js
Normal file
17
static/js/pages/legal/retention_schedule.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import BasePage from "../base.js";
|
||||
|
||||
export default class PageRetentionSchedule extends BasePage {
|
||||
static hash = hashPageDataRetentionSchedule;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
20
static/js/pages/mixin.js
Normal file
20
static/js/pages/mixin.js
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
export default class MixinPage {
|
||||
constructor(pageCurrent) {
|
||||
this.page = pageCurrent;
|
||||
}
|
||||
|
||||
initialize() {
|
||||
Utils.consoleLogIfNotProductionEnvironment('hookup start for ', this.page.hash);
|
||||
this.hookupFilters();
|
||||
this.hookupLocalStorage();
|
||||
}
|
||||
hookupFilters() {
|
||||
}
|
||||
hookupLocalStorage() {
|
||||
|
||||
}
|
||||
|
||||
leave() {}
|
||||
}
|
||||
19
static/js/pages/mixin_table.js
Normal file
19
static/js/pages/mixin_table.js
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
import MixinPage from "./mixin.js";
|
||||
|
||||
export default class TableMixinPage extends MixinPage {
|
||||
constructor(pageCurrent) {
|
||||
super(pageCurrent);
|
||||
}
|
||||
initialize() {
|
||||
super.initialize();
|
||||
this.hookupFilters();
|
||||
this.hookupTable();
|
||||
}
|
||||
hookupFilters() {
|
||||
// Implement filter-specific functionality here
|
||||
}
|
||||
hookupTable() {
|
||||
// Implement table-specific functionality here
|
||||
}
|
||||
}
|
||||
691
static/js/pages/tcg/mtg_game.js
Normal file
691
static/js/pages/tcg/mtg_game.js
Normal file
@@ -0,0 +1,691 @@
|
||||
|
||||
|
||||
import API from "../../api.js";
|
||||
import TableBasePage from "../base_table.js";
|
||||
import DOM from "../../dom.js";
|
||||
import Events from "../../lib/events.js";
|
||||
|
||||
export default class PageMtgGame extends TableBasePage {
|
||||
static hash = hashPageMtgGame;
|
||||
static attrIdRowObject = attrGameId;
|
||||
callSaveTableContent = API.saveGame;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
this.hookupTcgGame();
|
||||
}
|
||||
hookupFilters() {
|
||||
// this.sharedHookupFilters();
|
||||
}
|
||||
loadRowTable(rowJson) {
|
||||
return;
|
||||
}
|
||||
getJsonRow(row) {
|
||||
return;
|
||||
}
|
||||
initialiseRowNew(tbody, row) {
|
||||
|
||||
}
|
||||
postInitialiseRowNewCallback(tbody) {
|
||||
|
||||
}
|
||||
|
||||
hookupTableMain() {
|
||||
super.hookupTableMain();
|
||||
}
|
||||
hookupTcgGame() {
|
||||
this.initGamePage();
|
||||
let pageHeading = document.querySelector('.container.company-name .tcg-title.company-name');
|
||||
pageHeading.innerText = `MTG Game #${gameId}`;
|
||||
}
|
||||
|
||||
initGamePage() {
|
||||
// Load existing game state from API or show setup
|
||||
PageMtgGame.updatePlayerSetup();
|
||||
if (typeof gameId !== 'undefined' && gameId) {
|
||||
this.loadGameFromServer();
|
||||
}
|
||||
/*
|
||||
else {
|
||||
PageMtgGame.updatePlayerSetup();
|
||||
}
|
||||
*/
|
||||
|
||||
PageMtgGame.hookupResetButton();
|
||||
PageMtgGame.hookupPlayerCountInput();
|
||||
this.hookupStartGameButton();
|
||||
/*
|
||||
this.hookupCommanderDeathIncrementButtons();
|
||||
this.hookupEliminateCommanderButtons();
|
||||
this.hookupPlayerLifeIncrementButtons();
|
||||
this.hookupCommanderDamageIncrementButtons();
|
||||
*/
|
||||
}
|
||||
static hookupResetButton() {
|
||||
const resetGameButton = document.querySelector('header.game-header .header-right .btn-tcg.btn-tcg-secondary');
|
||||
if (resetGameButton) {
|
||||
resetGameButton.addEventListener('click', PageMtgGame.resetGame);
|
||||
}
|
||||
}
|
||||
static hookupPlayerCountInput() {
|
||||
const playerCountInput = document.getElementById('playerCount');
|
||||
if (playerCountInput) {
|
||||
playerCountInput.addEventListener('change', PageMtgGame.updatePlayerSetup);
|
||||
}
|
||||
}
|
||||
hookupStartGameButton() {
|
||||
const startGameButton = document.querySelector('.setup-section .setup-actions .btn-tcg');
|
||||
if (startGameButton) {
|
||||
startGameButton.addEventListener('click', () => { this.startGame(); });
|
||||
}
|
||||
}
|
||||
/*
|
||||
hookupCommanderDeathIncrementButtons() {
|
||||
const commanderDeathIncremementButtons = document.querySelectorAll('#players-grid .player-card .commander-deaths .death-btn');
|
||||
if (commanderDeathIncremementButtons) {
|
||||
commanderDeathIncremementButtons.forEach((button) => {
|
||||
button.addEventListener('click', PageMtgGame.changeCommanderDeaths);
|
||||
});
|
||||
}
|
||||
}
|
||||
hookupEliminateCommanderButtons() {
|
||||
const eliminateCommanderButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
||||
if (eliminateCommanderButtons) {
|
||||
eliminateCommanderButtons.forEach((button) => {
|
||||
button.addEventListener('click', PageMtgGame.toggleEliminate);
|
||||
});
|
||||
}
|
||||
}
|
||||
hookupPlayerLifeIncrementButtons() {
|
||||
const playerLifeIncrementButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
||||
if (playerLifeIncrementButtons) {
|
||||
playerLifeIncrementButtons.forEach((button) => {
|
||||
button.addEventListener('click', PageMtgGame.changeLife);
|
||||
});
|
||||
}
|
||||
}
|
||||
hookupCommanderDamageIncrementButtons() {
|
||||
const commanderDamageIncrementButtons = document.querySelector('#players-grid .player-card .eliminate-btn');
|
||||
if (commanderDamageIncrementButtons) {
|
||||
commanderDamageIncrementButtons.forEach((button) => {
|
||||
button.addEventListener('click', PageMtgGame.changeCommanderDamage);
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
async loadGameFromServer() {
|
||||
console.log("loading game from server");
|
||||
try {
|
||||
// Fetch players, rounds, and damage records from API
|
||||
const [playersResponse, roundsResponse, damageResponse] = await Promise.all([
|
||||
API.getGamePlayers(gameId)
|
||||
, API.getGameRounds(gameId)
|
||||
, API.getGameDamageRecords(gameId)
|
||||
]);
|
||||
console.log({ playersResponse, damageResponse });
|
||||
|
||||
let setupSection = document.getElementById('setupSection');
|
||||
let gameSection = document.getElementById('gameSection');
|
||||
setupSection.classList.remove('hidden');
|
||||
gameSection.classList.add('hidden');
|
||||
|
||||
if (playersResponse.status !== 'success') {
|
||||
console.error('Failed to load players:', playersResponse.message);
|
||||
return;
|
||||
}
|
||||
|
||||
const savedPlayers = playersResponse.data || [];
|
||||
const savedRounds = roundsResponse.status === 'success' ? (roundsResponse.data || []) : [];
|
||||
const savedDamageRecords = damageResponse.status === 'success' ? (damageResponse.data || []) : [];
|
||||
|
||||
players = savedPlayers;
|
||||
rounds = savedRounds;
|
||||
damageRecords = savedDamageRecords;
|
||||
|
||||
if (savedPlayers.length === 0) {
|
||||
// No players yet, show setup section
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide setup, show game
|
||||
setupSection.classList.add('hidden');
|
||||
gameSection.classList.remove('hidden');
|
||||
|
||||
console.log({ savedPlayers, damageRecords });
|
||||
|
||||
// Render players to DOM
|
||||
this.renderPlayers();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading game from server:', error);
|
||||
}
|
||||
}
|
||||
|
||||
renderPlayers() {
|
||||
const grid = document.getElementById('playersGrid');
|
||||
grid.innerHTML = '';
|
||||
|
||||
// Build a damage lookup: { playerId: { fromPlayerId: damageAmount } }
|
||||
/*
|
||||
const damageLookup = {};
|
||||
damageRecords.forEach(damage => {
|
||||
if (!damageLookup[damage.player_id]) {
|
||||
damageLookup[damage.player_id] = {};
|
||||
}
|
||||
if (damage.received_from_commander_player_id) {
|
||||
damageLookup[damage.player_id][damage.received_from_commander_player_id] = damage.health_change || 0;
|
||||
}
|
||||
});
|
||||
*/
|
||||
const latestRoundId = PageMtgGame.getLatestRoundId();
|
||||
|
||||
players.forEach((player, index) => {
|
||||
// Build display name: prefer user_name + deck_name, fallback to player name
|
||||
const playerId = player[attrPlayerId];
|
||||
let displayName = PageMtgGame.makePlayerDisplayName(playerId, index);
|
||||
let damagePlayerPairs = [...players, { [attrPlayerId]: null }];
|
||||
let maxCommanderDamageReceived = 0;
|
||||
damagePlayerPairs.forEach(damagePlayerPair => {
|
||||
const sourceId = damagePlayerPair[attrPlayerId];
|
||||
const filteredPlayerDamages = damageRecords.filter(damage => (
|
||||
damage[attrRoundId] == latestRoundId
|
||||
&& damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
||||
)); //[playerId] || {};
|
||||
if (filteredPlayerDamages.length == 0) {
|
||||
damageRecords.push(PageMtgGame.makeDefaultGameRoundPlayerDamage(playerId, sourceId));
|
||||
}
|
||||
maxCommanderDamageReceived = Math.max(
|
||||
maxCommanderDamageReceived
|
||||
, damageRecords.filter(damage => (
|
||||
damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
||||
))
|
||||
.map(damage => damage[flagHealthChange])
|
||||
.reduce((acc, curr) => acc + curr, 0)
|
||||
);
|
||||
});
|
||||
|
||||
const totalDamage = damageRecords.filter(damage => ( damage[attrPlayerId] == playerId ))
|
||||
.map(damage => damage[flagHealthChange])
|
||||
.reduce((acc, curr) => acc + curr, 0);
|
||||
let life = startingLife + totalDamage;
|
||||
|
||||
let isEliminatedByForce = damageRecords.filter(damage => ( damage[attrPlayerId] == playerId ))
|
||||
.map(damage => damage[flagIsEliminated])
|
||||
.some(Boolean);
|
||||
const isEliminated = (
|
||||
isEliminatedByForce
|
||||
|| !player[flagActive]
|
||||
|| life < 1
|
||||
|| maxCommanderDamageReceived >= 21
|
||||
);
|
||||
|
||||
const playerOwnDamage = damageRecords.filter(damage => (
|
||||
damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == null
|
||||
&& damage[attrRoundId] == latestRoundId
|
||||
))[0];
|
||||
const card = document.createElement('div');
|
||||
card.className = `player-card ${isEliminated ? 'eliminated' : ''}`;
|
||||
card.style.animationDelay = `${index * 0.1}s`;
|
||||
card.dataset.playerId = playerId;
|
||||
card.dataset.userName = player.user_name || '';
|
||||
card.dataset.deckName = player.deck_name || '';
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="player-header">
|
||||
<div class="player-info">
|
||||
<div class="player-name">${displayName}</div>
|
||||
<div class="commander-deaths">
|
||||
<span>Commander Deaths:</span>
|
||||
<div class="death-counter">
|
||||
<button class="death-btn death-minus" data-player-id="${playerId}">−</button>
|
||||
<span class="death-display" data-player-id="${playerId}" ${attrValuePrevious}="${playerOwnDamage[flagCommanderDeaths]}">${playerOwnDamage[flagCommanderDeaths]}</span>
|
||||
<button class="death-btn death-plus" data-player-id="${playerId}">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="eliminate-btn" data-player-id="${playerId}" ${attrValuePrevious}="${isEliminated}">
|
||||
${isEliminated ? 'Revive' : 'Eliminate'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="life-total">
|
||||
<input type="hidden" class="life-value" data-player-id="${playerId}" value="${life}">
|
||||
<div class="life-display" data-player-id="${playerId}" ${attrValuePrevious}="${life}">${life}</div>
|
||||
<div class="life-controls">
|
||||
<button class="life-btn" data-player-id="${playerId}" data-amount="-5">-5</button>
|
||||
<button class="life-btn" data-player-id="${playerId}" data-amount="-1">-1</button>
|
||||
<button class="life-btn" data-player-id="${playerId}" data-amount="1">+1</button>
|
||||
<button class="life-btn" data-player-id="${playerId}" data-amount="5">+5</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="commander-damage-section">
|
||||
<div class="section-title">Commander Damage Taken</div>
|
||||
<div class="damage-grid" data-player-id="${playerId}">
|
||||
${PageMtgGame.renderCommanderDamageRows(
|
||||
playerId // playerId
|
||||
, player[attrDeckId] // deckId
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
grid.appendChild(card);
|
||||
});
|
||||
|
||||
// Hookup all event handlers
|
||||
this.hookupPlayerCardEvents();
|
||||
}
|
||||
static makeDefaultGameRoundPlayerDamage(playerId, receivedFromCommanderPlayerId) {
|
||||
let roundId = PageMtgGame.getLatestRoundId();
|
||||
return {
|
||||
[attrDamageId]: -1 - damageRecords.length
|
||||
, [attrRoundId]: roundId
|
||||
, [attrPlayerId]: playerId
|
||||
, [attrReceivedFromCommanderPlayerId]: receivedFromCommanderPlayerId
|
||||
, [flagHealthChange]: 0
|
||||
, [flagCommanderDeaths]: 0
|
||||
, [flagActive]: true
|
||||
};
|
||||
}
|
||||
static getLatestRoundId() {
|
||||
let roundId = -1;
|
||||
if (rounds.length > 0) {
|
||||
let highestRoundDisplayOrder = Math.max(rounds.map(round => { return round[flagDisplayOrder]; }));
|
||||
roundId = rounds.filter(round => round[flagDisplayOrder] == highestRoundDisplayOrder)[0][attrRoundId];
|
||||
console.log({ "method": "getLatestRoundId", highestRoundDisplayOrder, roundId });
|
||||
}
|
||||
return roundId;
|
||||
}
|
||||
static makePlayerDisplayName(playerId, index) {
|
||||
if (playerId == null) {
|
||||
return `Player ${index + 1}`;
|
||||
}
|
||||
const player = players.filter(player => player[attrPlayerId] == playerId)[0];
|
||||
const deckId = player[attrDeckId];
|
||||
const deck = (deckId == null) ? null : decks.filter(deck => deck[attrDeckId] == deckId)[0];
|
||||
const user = (playerId == null) ? null : users[player[attrUserId]];
|
||||
return player[flagName] || `${(user == null) ? 'Error' : user[flagName]} - ${(deck == null) ? 'Error' : deck[flagName]}`;
|
||||
}
|
||||
static renderCommanderDamageRows(playerId) {
|
||||
// const roundId = PageMtgGame.getLatestRoundId();
|
||||
return players
|
||||
.filter(otherPlayer => otherPlayer[attrPlayerId] !== playerId)
|
||||
.map(otherPlayer => {
|
||||
const sourceId = otherPlayer[attrPlayerId];
|
||||
let otherPlayerDisplayName = PageMtgGame.makePlayerDisplayName(sourceId);
|
||||
const totalDamage = damageRecords.filter(damage => (
|
||||
damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == sourceId
|
||||
))
|
||||
.map(damage => -damage[flagHealthChange])
|
||||
.reduce((acc, curr) => acc + curr, 0);
|
||||
const isLethal = totalDamage >= 21;
|
||||
|
||||
return `
|
||||
<div class="damage-row" data-player-id="${playerId}" data-source-id="${sourceId}">
|
||||
<span class="damage-source">from ${otherPlayerDisplayName}</span>
|
||||
<div class="damage-controls">
|
||||
<button class="damage-btn damage-minus" data-player-id="${playerId}" data-source-id="${sourceId}">−</button>
|
||||
<input type="hidden" class="damage-value" data-player-id="${playerId}" data-source-id="${sourceId}" value="${totalDamage}">
|
||||
<span class="damage-display ${isLethal ? 'lethal' : ''}" data-player-id="${playerId}" data-source-id="${sourceId}" ${attrValuePrevious}="${totalDamage}">${totalDamage}</span>
|
||||
<button class="damage-btn damage-plus" data-player-id="${playerId}" data-source-id="${sourceId}">+</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
|
||||
hookupPlayerCardEvents() {
|
||||
// Life buttons
|
||||
let lifeButtonSelector = '.life-btn';
|
||||
Events.hookupEventHandler("click", lifeButtonSelector, (event, button) => {
|
||||
const playerId = button.dataset.playerId;
|
||||
const amount = parseInt(button.dataset.amount);
|
||||
const latestRoundId = PageMtgGame.getLatestRoundId();
|
||||
const damageIndex = damageRecords.findIndex(damage => (
|
||||
damage[attrRoundId] == latestRoundId
|
||||
&& damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == null
|
||||
));
|
||||
this.changeLife(
|
||||
playerId // playerId
|
||||
, amount // amount
|
||||
, true // updateDamage
|
||||
, damageIndex // damageIndex
|
||||
);
|
||||
});
|
||||
|
||||
// Commander death buttons
|
||||
let commanderDeathButtonSelector = '.death-btn';
|
||||
Events.hookupEventHandler("click", commanderDeathButtonSelector, (event, button) => {
|
||||
const playerId = button.dataset.playerId;
|
||||
const isMinusButton = button.classList.contains('death-minus');
|
||||
const amount = (isMinusButton) ? -1 : 1;
|
||||
this.changeCommanderDeaths(playerId, amount);
|
||||
});
|
||||
|
||||
// Commander damage buttons
|
||||
let commmanderDamageButtonSelector = '.damage-btn';
|
||||
Events.hookupEventHandler("click", commmanderDamageButtonSelector, (event, button) => {
|
||||
const playerId = button.dataset.playerId;
|
||||
const sourceId = button.dataset.sourceId;
|
||||
const isMinusButton = button.classList.contains('damage-minus');
|
||||
const amount = (isMinusButton) ? -1 : 1;
|
||||
this.changeCommanderDamage(playerId, sourceId, amount);
|
||||
});
|
||||
|
||||
// Eliminate buttons
|
||||
let eliminatePlayerButtonSelector = '.eliminate-btn';
|
||||
Events.hookupEventHandler("click", eliminatePlayerButtonSelector, (event, button) => {
|
||||
const playerId = button.dataset.playerId;
|
||||
this.toggleEliminate(playerId);
|
||||
});
|
||||
}
|
||||
|
||||
changeLife(playerId, amount, updateDamage = false, damageIndex = null) {
|
||||
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
||||
if (!card || card.classList.contains('eliminated')) return;
|
||||
|
||||
const lifeInput = card.querySelector(`.life-value[data-player-id="${playerId}"]`);
|
||||
const lifeDisplay = card.querySelector(`.life-display[data-player-id="${playerId}"]`);
|
||||
|
||||
const currentLife = parseInt(lifeInput.value) || 0;
|
||||
const newLife = Math.max(0, currentLife + amount);
|
||||
DOM.setElementAttributeValueCurrent(lifeDisplay, newLife);
|
||||
DOM.isElementDirty(lifeDisplay);
|
||||
lifeInput.value = newLife;
|
||||
lifeDisplay.textContent = newLife;
|
||||
|
||||
if (updateDamage) {
|
||||
damageRecords[damageIndex][flagHealthChange] += amount;
|
||||
}
|
||||
|
||||
// PageMtgGame.debouncedSave();
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
|
||||
changeCommanderDamage(playerId, sourceId, amount) {
|
||||
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
||||
if (!card || card.classList.contains('eliminated')) return;
|
||||
|
||||
const damageInput = card.querySelector(`.damage-value[data-player-id="${playerId}"][data-source-id="${sourceId}"]`);
|
||||
const damageDisplay = card.querySelector(`.damage-display[data-player-id="${playerId}"][data-source-id="${sourceId}"]`);
|
||||
|
||||
const currentDamage = parseInt(damageInput.value) || 0;
|
||||
const newDamage = Math.max(0, currentDamage + amount);
|
||||
amount = newDamage - currentDamage;
|
||||
DOM.setElementAttributeValueCurrent(damageDisplay, newDamage);
|
||||
DOM.isElementDirty(damageDisplay);
|
||||
damageInput.value = newDamage;
|
||||
damageDisplay.textContent = newDamage;
|
||||
|
||||
// Update lethal class
|
||||
if (newDamage >= 21) {
|
||||
damageDisplay.classList.add('lethal');
|
||||
} else {
|
||||
damageDisplay.classList.remove('lethal');
|
||||
}
|
||||
|
||||
const latestRoundId = PageMtgGame.getLatestRoundId();
|
||||
const damageIndex = damageRecords.findIndex(damageRecord => (
|
||||
damage[attrRoundId] == latestRoundId
|
||||
&& damageRecord[attrPlayerId] == playerId
|
||||
&& damageRecord[attrReceivedFromCommanderPlayerId] == sourceId
|
||||
));
|
||||
damageRecords[damageIndex][flagHealthChange] -= amount;
|
||||
|
||||
this.changeLife(
|
||||
playerId // playerId
|
||||
, -amount // amount
|
||||
, false // updateDamage
|
||||
, damageIndex // damageIndex
|
||||
);
|
||||
// PageMtgGame.debouncedSave();
|
||||
}
|
||||
|
||||
changeCommanderDeaths(playerId, amount) {
|
||||
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
||||
if (!card || card.classList.contains('eliminated')) return;
|
||||
|
||||
const deathDisplay = card.querySelector(`.death-display[data-player-id="${playerId}"]`);
|
||||
const currentDeaths = parseInt(deathDisplay.textContent) || 0;
|
||||
const newDeaths = Math.max(0, currentDeaths + amount);
|
||||
|
||||
deathDisplay.textContent = newDeaths;
|
||||
DOM.setElementAttributeValueCurrent(deathDisplay, newDeaths);
|
||||
DOM.isElementDirty(deathDisplay);
|
||||
|
||||
const latestRoundId = PageMtgGame.getLatestRoundId();
|
||||
const damageIndex = damageRecords.findIndex(damage => (
|
||||
damage[attrRoundId] == latestRoundId
|
||||
&& damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == null
|
||||
));
|
||||
damageRecords[damageIndex][flagCommanderDeaths] = newDeaths;
|
||||
|
||||
// PageMtgGame.debouncedSave();
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
|
||||
toggleEliminate(playerId) {
|
||||
const card = document.querySelector(`.player-card[data-player-id="${playerId}"]`);
|
||||
if (!card) return;
|
||||
|
||||
const eliminateBtn = card.querySelector(`.eliminate-btn[data-player-id="${playerId}"]`);
|
||||
const wasEliminated = card.classList.contains('eliminated');
|
||||
|
||||
if (wasEliminated) {
|
||||
card.classList.remove('eliminated');
|
||||
eliminateBtn.textContent = 'Eliminate';
|
||||
} else {
|
||||
card.classList.add('eliminated');
|
||||
eliminateBtn.textContent = 'Revive';
|
||||
}
|
||||
const isEliminated = card.classList.contains('eliminated');
|
||||
|
||||
const latestRoundId = PageMtgGame.getLatestRoundId();
|
||||
const damageIndex = damageRecords.findIndex(damage => (
|
||||
damage[attrRoundId] == latestRoundId
|
||||
&& damage[attrPlayerId] == playerId
|
||||
&& damage[attrReceivedFromCommanderPlayerId] == null
|
||||
));
|
||||
damageRecords[damageIndex][flagIsEliminated] = isEliminated;
|
||||
|
||||
DOM.setElementAttributeValueCurrent(eliminateBtn, isEliminated);
|
||||
DOM.isElementDirty(eliminateBtn);
|
||||
// PageMtgGame.debouncedSave();
|
||||
this.updateAndToggleShowButtonsSaveCancel();
|
||||
}
|
||||
|
||||
static updatePlayerSetup() {
|
||||
const playerCountInput = document.getElementById('playerCount');
|
||||
if (!playerCountInput) return;
|
||||
|
||||
const playerCount = parseInt(playerCountInput.value);
|
||||
const grid = document.getElementById('playerSetupGrid');
|
||||
if (!grid) return;
|
||||
|
||||
grid.innerHTML = '';
|
||||
const wrapperTemplate = document.getElementById(playerSetupWrapperTemplateId);
|
||||
let player, wrapper, wrapperHeading, userDdl, deckDdl, nameInput;
|
||||
for (let i = 0; i < playerCount; i++) {
|
||||
if (i < players.length) {
|
||||
player = players[i];
|
||||
}
|
||||
else {
|
||||
player = PageMtgGame.makeDefaultGamePlayer();
|
||||
players.push(player);
|
||||
}
|
||||
wrapper = wrapperTemplate.cloneNode(true);
|
||||
wrapper.removeAttribute("id");
|
||||
wrapper.setAttribute(flagDisplayOrder, i + 1);
|
||||
wrapper.classList.remove(flagIsCollapsed);
|
||||
wrapperHeading = wrapper.querySelector('label');
|
||||
wrapperHeading.innerText = 'Player ' + (i + 1);
|
||||
userDdl = wrapper.querySelector('.playerUser select');
|
||||
DOM.setElementValuesCurrentAndPrevious(userDdl, player[attrUserId]);
|
||||
deckDdl = wrapper.querySelector('.playerDeck select');
|
||||
DOM.setElementValuesCurrentAndPrevious(deckDdl, player[attrDeckId]);
|
||||
nameInput = wrapper.querySelector('.playerName input');
|
||||
DOM.setElementValuesCurrentAndPrevious(nameInput, player[flagName]);
|
||||
console.log('player: ', player);
|
||||
grid.appendChild(wrapper);
|
||||
}
|
||||
}
|
||||
static makeDefaultGamePlayer() {
|
||||
return {
|
||||
[attrPlayerId]: -players.length
|
||||
, [attrGameId]: gameId
|
||||
, [attrUserId]: user[attrUserId]
|
||||
, [attrDeckId]: 0
|
||||
, [flagName]: ""
|
||||
, [flagNotes]: null
|
||||
, [flagDisplayOrder]: players.length
|
||||
, [flagActive]: true
|
||||
};
|
||||
}
|
||||
|
||||
async startGame() {
|
||||
const playerCountInput = document.getElementById('playerCount');
|
||||
if (!playerCountInput) return;
|
||||
|
||||
const playerCount = parseInt(playerCountInput.value);
|
||||
const playersToSave = [];
|
||||
|
||||
let playerSetupWrapper, playerId, player, userDdl, userId, deckDdl, deckId, nameInput, name;
|
||||
for (let i = 0; i < playerCount; i++) {
|
||||
playerSetupWrapper = document.querySelector('.player-name-input-wrapper[' + flagDisplayOrder + '="' + (i + 1) + '"]');
|
||||
userDdl = playerSetupWrapper.querySelector('.playerUser select');
|
||||
deckDdl = playerSetupWrapper.querySelector('.playerDeck select');
|
||||
nameInput = playerSetupWrapper.querySelector('.playerName input');
|
||||
|
||||
userId = DOM.getElementValueCurrent(userDdl);
|
||||
deckId = DOM.getElementValueCurrent(deckDdl);
|
||||
name = nameInput ? nameInput.value.trim() || `Player ${i + 1}` : `Player ${i + 1}`;
|
||||
|
||||
playerId = playerSetupWrapper.getAttribute(attrPlayerId);
|
||||
player = players.filter(p => p[attrPlayerId] == playerId)[0];
|
||||
playersToSave.push({
|
||||
...player
|
||||
, [attrGameId]: gameId
|
||||
, [attrUserId]: userId
|
||||
, [attrDeckId]: deckId
|
||||
, [flagName]: name
|
||||
, [flagDisplayOrder]: i + 1
|
||||
, [flagActive]: true
|
||||
});
|
||||
}
|
||||
|
||||
// Save players to server
|
||||
const comment = 'Save players';
|
||||
const self = this;
|
||||
API.saveGamePlayers(playersToSave, null, comment)
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
self.leave();
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
console.error('Failed to save players:', data[flagMessage]);
|
||||
PageMtgGame.showError('An error occurred while creating the game');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error creating game:', error);
|
||||
PageMtgGame.showError('An error occurred while creating the game');
|
||||
})
|
||||
.finally(() => {
|
||||
});
|
||||
}
|
||||
|
||||
static resetGame() {
|
||||
if (confirm('Are you sure you want to start a new game? Current game will be lost.')) {
|
||||
localStorage.removeItem(`mtgGame_${gameId}`);
|
||||
window.location.href = hashPageGames;
|
||||
}
|
||||
}
|
||||
|
||||
async saveGame() {
|
||||
const gameState = {
|
||||
[flagPlayer]: players
|
||||
, [flagRound]: rounds
|
||||
, [flagDamage]: damageRecords
|
||||
};
|
||||
/*
|
||||
if (gameState[flagPlayer].length > 0) {
|
||||
localStorage.setItem(`mtgGame_${gameId}`, JSON.stringify(gameState));
|
||||
PageMtgGame.showSaveIndicator();
|
||||
}
|
||||
*/
|
||||
const comment = 'Save players';
|
||||
const self = this;
|
||||
API.saveGameRoundPlayerDamages(rounds, damageRecords, null, comment)
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
self.leave();
|
||||
window.location.reload();
|
||||
}
|
||||
else {
|
||||
console.error('Failed to save players:', data[flagMessage]);
|
||||
PageMtgGame.showError('An error occurred while creating the game');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error creating game:', error);
|
||||
PageMtgGame.showError('An error occurred while creating the game');
|
||||
})
|
||||
.finally(() => {
|
||||
});
|
||||
}
|
||||
/*
|
||||
static debouncedSave() {
|
||||
clearTimeout(PageMtgGame._saveTimeout);
|
||||
PageMtgGame._saveTimeout = setTimeout(() => PageMtgGame.saveGame(), 500);
|
||||
}
|
||||
|
||||
static showSaveIndicator() {
|
||||
const indicator = document.getElementById('saveIndicator');
|
||||
if (indicator) {
|
||||
indicator.classList.add('show');
|
||||
setTimeout(() => {
|
||||
indicator.classList.remove('show');
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
*/
|
||||
saveRecordsTableDirty() {
|
||||
this.saveGame();
|
||||
}
|
||||
static showError(message) {
|
||||
// Check if there's an overlay error element
|
||||
const errorOverlay = document.getElementById('overlayError');
|
||||
if (errorOverlay) {
|
||||
const errorLabel = errorOverlay.querySelector('.error-message, #labelError');
|
||||
if (errorLabel) {
|
||||
errorLabel.textContent = message;
|
||||
}
|
||||
errorOverlay.classList.remove('hidden');
|
||||
errorOverlay.style.display = 'flex';
|
||||
} else {
|
||||
// Fallback to alert
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
|
||||
// Static timeout reference for debouncing
|
||||
PageMtgGame._saveTimeout = null;
|
||||
250
static/js/pages/tcg/mtg_games.js
Normal file
250
static/js/pages/tcg/mtg_games.js
Normal file
@@ -0,0 +1,250 @@
|
||||
|
||||
import API from "../../api.js";
|
||||
import TableBasePage from "../base_table.js";
|
||||
import Utils from "../../lib/utils.js";
|
||||
|
||||
export default class PageMtgGames extends TableBasePage {
|
||||
static hash = hashPageMtgGames;
|
||||
static attrIdRowObject = attrGameId;
|
||||
callSaveTableContent = API.saveGame;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
this.hookupTcgGames();
|
||||
}
|
||||
hookupTcgGames() {
|
||||
PageMtgGames.initGamesPage();
|
||||
}
|
||||
static initGamesPage() {
|
||||
// Initialize form submission
|
||||
const newGameForm = document.getElementById('newGameForm');
|
||||
if (newGameForm) {
|
||||
newGameForm.addEventListener('submit', PageMtgGames.handleNewGameSubmit);
|
||||
}
|
||||
|
||||
// Initialize filter form
|
||||
const filterForm = document.getElementById('formFilters');
|
||||
if (filterForm) {
|
||||
filterForm.addEventListener('submit', PageMtgGames.handleFilterSubmit);
|
||||
}
|
||||
|
||||
// Close modal on escape key
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (e.key === 'Escape') {
|
||||
PageMtgGames.hideNewGameForm();
|
||||
}
|
||||
});
|
||||
|
||||
// Close modal on backdrop click
|
||||
const modal = document.getElementById('newGameModal');
|
||||
if (modal) {
|
||||
modal.addEventListener('click', function(e) {
|
||||
if (e.target === modal) {
|
||||
PageMtgGames.hideNewGameForm();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Button onclicks
|
||||
const newGameButton = document.getElementById('btnNewGame');
|
||||
if (newGameButton) {
|
||||
newGameButton.addEventListener('click', PageMtgGames.showNewGameForm);
|
||||
}
|
||||
const cancelNewGameButtons = document.querySelectorAll(
|
||||
'#newGameForm .form-actions .btn-tcg.btn-tcg-secondary'
|
||||
+ ','
|
||||
+ '#newGameModal .modal-content .modal-header .modal-close'
|
||||
);
|
||||
if (cancelNewGameButtons.length > 0) {
|
||||
cancelNewGameButtons.forEach((button) => {
|
||||
button.addEventListener('click', PageMtgGames.hideNewGameForm);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
static showNewGameForm() {
|
||||
const modal = document.getElementById('newGameModal');
|
||||
if (modal) {
|
||||
modal.classList.remove('hidden');
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Focus on first input
|
||||
const firstInput = modal.querySelector('input, select');
|
||||
if (firstInput) {
|
||||
firstInput.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
static hideNewGameForm() {
|
||||
const modal = document.getElementById('newGameModal');
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
document.body.style.overflow = '';
|
||||
|
||||
// Reset form
|
||||
const form = document.getElementById('newGameForm');
|
||||
if (form) {
|
||||
form.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
static async handleNewGameSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const form = e.target;
|
||||
const formData = new FormData(form);
|
||||
|
||||
const gameType = formData.get('game_type');
|
||||
const gameData = {
|
||||
[attrGameId]: -1
|
||||
, [flagIsCommander]: gameType === 'commander'
|
||||
, [flagIsDraft]: gameType === 'draft'
|
||||
, [flagIsSealed]: gameType === 'sealed'
|
||||
, [flagLocationName]: formData.get(flagLocationName) || null
|
||||
, [flagNotes]: formData.get(flagNotes) || null
|
||||
, [flagStartOn]: new Date().toISOString()
|
||||
, [flagStartingLife]: formData.get(flagStartingLife) || 40
|
||||
, [flagActive]: true
|
||||
};
|
||||
|
||||
const submitBtn = form.querySelector('button[type="submit"]');
|
||||
const originalText = submitBtn.textContent;
|
||||
submitBtn.textContent = 'Creating...';
|
||||
submitBtn.disabled = true;
|
||||
|
||||
const games = [gameData];
|
||||
const comment = 'Create new game';
|
||||
debugger;
|
||||
API.saveGame(games, form, comment)
|
||||
.then(data => {
|
||||
if (data[flagStatus] == flagSuccess) {
|
||||
if (_verbose) {
|
||||
Utils.consoleLogIfNotProductionEnvironment('Records saved!');
|
||||
Utils.consoleLogIfNotProductionEnvironment('Data received:', data);
|
||||
}
|
||||
this.callFilterTableContent(gameData.game_id);
|
||||
}
|
||||
else {
|
||||
Utils.consoleLogIfNotProductionEnvironment("error: " + data[flagMessage]);
|
||||
// OverlayError.show(data[flagMessage]);
|
||||
window.location.reload();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error creating game:', error);
|
||||
PageMtgGames.showError('An error occurred while creating the game');
|
||||
})
|
||||
.finally(() => {
|
||||
submitBtn.textContent = originalText;
|
||||
submitBtn.disabled = false;
|
||||
});
|
||||
|
||||
}
|
||||
callFilterTableContent(gameId) {
|
||||
const gamePageHash = `${hashPageGame}/${gameId}`;
|
||||
let filtersJson = {};
|
||||
Utils.consoleLogIfNotProductionEnvironment("callFilterTableContent");
|
||||
this.leave();
|
||||
API.goToHash(gamePageHash, filtersJson);
|
||||
}
|
||||
static handleFilterSubmit(e) {
|
||||
// Let the form submit normally - it will reload with query params
|
||||
// You can add client-side filtering here if needed
|
||||
}
|
||||
static getCSRFToken() {
|
||||
// Try meta tag first
|
||||
const metaTag = document.querySelector('meta[name="csrf-token"]');
|
||||
if (metaTag) {
|
||||
return metaTag.getAttribute('content');
|
||||
}
|
||||
|
||||
// Try hidden input
|
||||
const hiddenInput = document.querySelector('input[name="csrf_token"]');
|
||||
if (hiddenInput) {
|
||||
return hiddenInput.value;
|
||||
}
|
||||
|
||||
// Try cookie
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let cookie of cookies) {
|
||||
const [name, value] = cookie.trim().split('=');
|
||||
if (name === 'csrf_token') {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
static showError(message) {
|
||||
// Check if there's an overlay error element
|
||||
const errorOverlay = document.getElementById('overlayError');
|
||||
if (errorOverlay) {
|
||||
const errorLabel = errorOverlay.querySelector('.error-message, #labelError');
|
||||
if (errorLabel) {
|
||||
errorLabel.textContent = message;
|
||||
}
|
||||
errorOverlay.classList.remove('hidden');
|
||||
errorOverlay.style.display = 'flex';
|
||||
} else {
|
||||
// Fallback to alert
|
||||
alert(message);
|
||||
}
|
||||
}
|
||||
static showSuccess(message) {
|
||||
// Could implement a toast notification here
|
||||
console.log('Success:', message);
|
||||
}
|
||||
static joinGame(gameId) {
|
||||
window.location.href = `${hashPageGame}/${gameId}`;
|
||||
}
|
||||
static async deleteGame(gameId) {
|
||||
if (!confirm('Are you sure you want to delete this game? This action cannot be undone.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const gameData = {
|
||||
'game_id': gameId,
|
||||
'active': false
|
||||
};
|
||||
|
||||
const response = await fetch(hashSaveGame, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': PageMtgGames.getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify({
|
||||
[flagGame]: [gameData],
|
||||
'form-filters': {},
|
||||
'comment': 'Game deleted'
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
// Remove the row from the table
|
||||
const row = document.querySelector(`tr[data-game-id="${gameId}"]`);
|
||||
if (row) {
|
||||
row.style.animation = 'tcg-fadeOut 0.3s ease-out forwards';
|
||||
setTimeout(() => row.remove(), 300);
|
||||
}
|
||||
} else {
|
||||
PageMtgGames.showError(result.message || 'Failed to delete game');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting game:', error);
|
||||
PageMtgGames.showError('An error occurred while deleting the game');
|
||||
}
|
||||
}
|
||||
|
||||
toggleShowButtonsSaveCancel() {}
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
26
static/js/pages/tcg/mtg_home.js
Normal file
26
static/js/pages/tcg/mtg_home.js
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
import API from "../../api.js";
|
||||
import BasePage from "../base.js";
|
||||
import DOM from "../../dom.js";
|
||||
import Events from "../../lib/events.js";
|
||||
|
||||
export default class PageMtgHome extends BasePage {
|
||||
static hash = hashPageMtgHome;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
this.hookupTcgHome();
|
||||
}
|
||||
|
||||
hookupTcgHome() {
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
83
static/js/pages/user/user.js
Normal file
83
static/js/pages/user/user.js
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
import API from "../../api.js";
|
||||
import TableMixinPage from "../mixin_table.js";
|
||||
import DOM from "../../dom.js";
|
||||
import TableBasePage from "../base_table.js";
|
||||
|
||||
export default class PageUser extends TableBasePage {
|
||||
static hash = hashPageUserAccount;
|
||||
static attrIdRowObject = attrUserId;
|
||||
callSaveTableContent = API.saveUsers;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
this.mixin = new TableMixinPage(this);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
this.hookupTableMain();
|
||||
}
|
||||
|
||||
|
||||
hookupFilters() {
|
||||
}
|
||||
|
||||
loadRowTable(rowJson) {
|
||||
if (rowJson == null) return;
|
||||
if (_verbose) { Utils.consoleLogIfNotProductionEnvironment("applying data row: ", rowJson); }
|
||||
}
|
||||
getTableRecords(dirtyOnly = false) {
|
||||
dirtyOnly = true;
|
||||
let container = document.querySelector('.' + flagCard + '.' + flagUser);
|
||||
return [this.getJsonRow(container)];
|
||||
}
|
||||
getJsonRow(container) {
|
||||
console.log("getJsonRow: ", container);
|
||||
if (container == null) return;
|
||||
let inputFirstname = container.querySelector(' #' + flagFirstname);
|
||||
let inputSurname = container.querySelector(' #' + flagSurname);
|
||||
let inputEmail = container.querySelector(' #' + flagEmail);
|
||||
|
||||
let idUser = container.getAttribute(attrUserId);
|
||||
|
||||
let jsonRow = {
|
||||
[attrUserAuth0Id]: null
|
||||
, [flagEmail]: null
|
||||
, [flagIsEmailVerified]: null
|
||||
, [flagIsSuperUser]: null
|
||||
, [flagCanAdminUser]: null
|
||||
};
|
||||
|
||||
jsonRow[attrUserId] = idUser;
|
||||
jsonRow[flagFirstname] = DOM.getElementAttributeValueCurrent(inputFirstname);
|
||||
jsonRow[flagSurname] = DOM.getElementAttributeValueCurrent(inputSurname);
|
||||
jsonRow[flagEmail] = DOM.getElementAttributeValueCurrent(inputEmail);
|
||||
return jsonRow;
|
||||
}
|
||||
|
||||
initialiseRowNew(tbody, row) {
|
||||
}
|
||||
postInitialiseRowNewCallback(tbody) {
|
||||
}
|
||||
|
||||
hookupTableMain() {
|
||||
super.hookupTableMain();
|
||||
this.hookupFieldsFirstname();
|
||||
this.hookupFieldsSurname();
|
||||
this.hookupFieldsEmail();
|
||||
}
|
||||
hookupFieldsFirstname() {
|
||||
this.hookupChangeHandlerTableCells('.' + flagCard + '.' + flagUser + ' #' + flagFirstname);
|
||||
}
|
||||
hookupFieldsSurname() {
|
||||
this.hookupChangeHandlerTableCells('.' + flagCard + '.' + flagUser + ' #' + flagSurname);
|
||||
}
|
||||
hookupFieldsEmail() {
|
||||
this.hookupChangeHandlerTableCells('.' + flagCard + '.' + flagUser + ' #' + flagEmail);
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
86
static/js/pages/user/users.js
Normal file
86
static/js/pages/user/users.js
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
import API from "../../api";
|
||||
import TableMixinPage from "../mixin_table";
|
||||
import DOM from "../../dom";
|
||||
import TableBasePage from "../base_table";
|
||||
import Utils from "../../lib/utils";
|
||||
|
||||
export default class PageUsers extends TableBasePage {
|
||||
static hash = hashPageUserAccounts;
|
||||
static attrIdRowObject = attrUserId;
|
||||
callSaveTableContent = API.saveUsers;
|
||||
|
||||
constructor(router) {
|
||||
super(router);
|
||||
this.mixin = new TableMixinPage(this);
|
||||
}
|
||||
|
||||
initialize() {
|
||||
this.sharedInitialize();
|
||||
}
|
||||
|
||||
hookupFilters() {
|
||||
this.sharedHookupFilters();
|
||||
this.hookupFilterActive();
|
||||
}
|
||||
|
||||
loadRowTable(rowJson) {
|
||||
if (rowJson == null) return;
|
||||
if (_verbose) { Utils.consoleLogIfNotProductionEnvironment("applying data row: ", rowJson); }
|
||||
}
|
||||
getJsonRow(row) {
|
||||
if (row == null) return;
|
||||
let inputFirstname = row.querySelector('td.' + flagFirstname + ' .' + flagFirstname);
|
||||
let inputSurname = row.querySelector('td.' + flagSurname + ' .' + flagSurname);
|
||||
let inputNotes = row.querySelector('td.' + flagNotes + ' .' + flagNotes);
|
||||
let buttonActive = row.querySelector('td.' + flagActive + ' .' + flagActive);
|
||||
|
||||
let jsonRow = {
|
||||
[attrUserAuth0Id]: null
|
||||
, [flagEmail]: null
|
||||
, [flagIsEmailVerified]: null
|
||||
, [flagIsSuperUser]: null
|
||||
, [flagCanAdminUser]: null
|
||||
};
|
||||
jsonRow[attrUserId] = row.getAttribute(attrUserId);
|
||||
jsonRow[flagFirstname] = DOM.getElementAttributeValueCurrent(inputFirstname);
|
||||
jsonRow[flagSurname] = DOM.getElementAttributeValueCurrent(inputSurname);
|
||||
jsonRow[flagNotes] = DOM.getElementAttributeValueCurrent(inputNotes);
|
||||
jsonRow[flagActive] = buttonActive.classList.contains(flagDelete);
|
||||
|
||||
console.log("jsonRow");
|
||||
console.log(jsonRow);
|
||||
|
||||
return jsonRow;
|
||||
}
|
||||
|
||||
initialiseRowNew(tbody, row) {
|
||||
|
||||
}
|
||||
postInitialiseRowNewCallback(tbody) {
|
||||
let newRows = tbody.querySelectorAll('tr.' + flagRowNew);
|
||||
let newestRow = newRows[0];
|
||||
let clickableElementsSelector = [].join('');
|
||||
newestRow.querySelectorAll(clickableElementsSelector).forEach((clickableElement) => {
|
||||
clickableElement.click();
|
||||
});
|
||||
}
|
||||
|
||||
hookupTableMain() {
|
||||
super.hookupTableMain();
|
||||
this.hookupFieldsFirstname();
|
||||
this.hookupFieldsSurname();
|
||||
this.hookupFieldsNotesTable();
|
||||
this.hookupFieldsActive();
|
||||
}
|
||||
hookupFieldsFirstname() {
|
||||
this.hookupChangeHandlerTableCells(flagFirstname);
|
||||
}
|
||||
hookupFieldsSurname() {
|
||||
this.hookupChangeHandlerTableCells(flagSurname);
|
||||
}
|
||||
|
||||
leave() {
|
||||
super.leave();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user