298 lines
18 KiB
HTML
298 lines
18 KiB
HTML
{% load static %}
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Features</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<link rel="stylesheet" href="{% static 'css/uikit.min.css' %}">
|
|
</head>
|
|
<body>
|
|
<div id="feature-form-container">
|
|
<form id="feature-form"
|
|
hx-post="/{{ system }}/feature/new"
|
|
hx-trigger="submit"
|
|
hx-target="#feature-form-container"
|
|
hx-swap="outerHTML"
|
|
method="POST"
|
|
autocomplete="off">
|
|
{% csrf_token %}
|
|
<div class="uk-container">
|
|
<div uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<h1 class="uk-heading-line uk-text-center"><span>Add a Feature</span></h1>
|
|
</div>
|
|
<div class="uk-width-1-1">
|
|
<label class="uk-form-label" for="feature_name">Name</label>
|
|
<div class="uk-form-controls">
|
|
<input class="uk-input" id="feature_name" name="feature_name" type="text" required>
|
|
</div>
|
|
</div>
|
|
<div class="uk-width-1-1">
|
|
<label class="uk-form-label" for="feature_description">Description</label>
|
|
<div class="uk-form-controls">
|
|
<textarea class="uk-textarea" id="feature_description" name="feature_description" rows="3"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="uk-width-1-1">
|
|
<ul uk-tab>
|
|
<li><a href="#">Operations</a></li>
|
|
<li><a href="#">Requirements</a></li>
|
|
|
|
</ul>
|
|
<div class="uk-switcher">
|
|
<div uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<p class="uk-text-muted">By adding an operation to your feature you can have the feature modifier and manipulate
|
|
a characters properties at runtime.
|
|
</p>
|
|
</div>
|
|
<div class="uk-width-1-1">
|
|
<button type="button" class="uk-button uk-button-primary uk-align-right" onclick="addOperation()"><span uk-icon="icon: plus"></span> Add Operation</button>
|
|
</div>
|
|
<div id="operations-body" class="uk-width-1-1" uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<div class="uk-card uk-card-small uk-card-default uk-card-body">
|
|
<h3 class="uk-card-title">Small</h3>
|
|
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
|
<div class="uk-padding uk-padding-remove-top uk-padding-remove-bottom" uk-grid>
|
|
<input class="uk-width-1-4 uk-input" name="operation_attr_${idx}" type="text" placeholder="Affected Attribute (e.g., strength)" value="${attr}">
|
|
<select class="uk-width-1-4 uk-select" name="operation_operation_${idx}">
|
|
<option value="add" ${op==='add'?'selected':''}>Add</option>
|
|
<option value="subtract" ${op==='subtract'?'selected':''}>Subtract</option>
|
|
<option value="multiply" ${op==='multiply'?'selected':''}>Multiply</option>
|
|
<option value="divide" ${op==='divide'?'selected':''}>Divide</option>
|
|
<option value="set" ${op==='set'?'selected':''}>Set</option>
|
|
</select>
|
|
<input class="uk-width-1-4 uk-input" name="operation_value_${idx}" type="text" placeholder="Value or Attribute..." value="${value}">
|
|
<button type='button' class='uk-width-1-4 uk-button uk-button-danger uk-button-small' onclick='this.closest(".uk-card").remove()'><span uk-icon="icon: minus"></span></button>
|
|
</div>
|
|
<div uk-grid>
|
|
<div class='uk-margin-small-top' id='operation-limit-list-${idx}'>
|
|
</div>
|
|
<button type='button' class='uk-button uk-button-secondary uk-button-small' onclick='addLimitField(${idx})'><span uk-icon="icon: plus"></span> Add Limit/Subpart</button>
|
|
|
|
<div class='uk-margin-small-top' id='operation-req-list-${idx}'></div>
|
|
<button type='button' class='uk-button uk-button-primary uk-button-small uk-margin-small-top' onclick='addOperationRequirementField(${idx})'><span uk-icon="icon: plus"></span> Add Requirement</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<button type="button" class="uk-button uk-button-primary " onclick="addRequirement()"><span uk-icon="icon: plus"></span> Add Requirement</button>
|
|
<div id="requirements-list"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="uk-width-1-1">
|
|
<input type="hidden" id="feature_payload" name="feature_payload">
|
|
<button type="submit" class="uk-button uk-button-primary uk-width-1-1">Submit Feature</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<script src="{% static 'js/uikit.min.js' %}"></script>
|
|
<script src="{% static 'js/uikit-icons.min.js' %}"></script>
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
|
<script>
|
|
|
|
document.getElementById('feature-form').addEventListener('submit', function (e) {
|
|
const reqList = document.querySelectorAll('#requirements-list > div');
|
|
let requirements = [];
|
|
reqList.forEach(div => {
|
|
const prop = div.querySelector('[name^="requirement_property_"]')?.value || "";
|
|
const condition = div.querySelector('[name^="requirement_condition_"]')?.value || "";
|
|
const value = div.querySelector('[name^="requirement_value_"]')?.value || "";
|
|
if(prop || condition || value) requirements.push({property: prop, condition, value});
|
|
});
|
|
|
|
|
|
const operationsDivs = document.querySelectorAll('#operations-body > div.uk-width-1-1');
|
|
let operations = [];
|
|
operationsDivs.forEach(div => {
|
|
const attr = div.querySelector('[name^="operation_attr_"]')?.value || "";
|
|
const operation = div.querySelector('[name^="operation_operation_"]')?.value || "";
|
|
const op_val = div.querySelector('[name^="operation_value_"]')?.value || "";
|
|
|
|
const opIdxMatch = attr.match(/operation_attr_(\d+)/);
|
|
let opIdx = null;
|
|
if (opIdxMatch) { opIdx = opIdxMatch[1]; }
|
|
let limits = [];
|
|
if(opIdx !== null) {
|
|
const limitList = div.querySelectorAll(`#operation-limit-list-${opIdx}>div`);
|
|
limitList.forEach(ldiv => {
|
|
const key = ldiv.querySelector(`[name=operation_${opIdx}_limitkey_${ldiv.dataset.idx}]`)?.value || "";
|
|
const type = ldiv.querySelector(`[name=operation_${opIdx}_limittype_${ldiv.dataset.idx}]`)?.value || "";
|
|
const value = ldiv.querySelector(`[name=operation_${opIdx}_limitval_${ldiv.dataset.idx}]`)?.value || "";
|
|
if(key || type || value) limits.push({key, type, value});
|
|
});
|
|
}
|
|
|
|
let opRequirements = [];
|
|
if(opIdx !== null) {
|
|
const reqList = div.querySelectorAll(`#operation-req-list-${opIdx}>div`);
|
|
reqList.forEach(rdiv => {
|
|
const prop = rdiv.querySelector(`[name=operation_${opIdx}_req_property_${rdiv.dataset.idx}]`)?.value || "";
|
|
const condition = rdiv.querySelector(`[name=operation_${opIdx}_req_condition_${rdiv.dataset.idx}]`)?.value || "";
|
|
const value = rdiv.querySelector(`[name=operation_${opIdx}_req_value_${rdiv.dataset.idx}]`)?.value || "";
|
|
if(prop || condition || value) opRequirements.push({property: prop, condition, value});
|
|
});
|
|
}
|
|
operations.push({attribute: attr, operation, value: op_val, limits, requirements: opRequirements});
|
|
});
|
|
|
|
const feature_data = {
|
|
operations: operations
|
|
};
|
|
|
|
const payload = {
|
|
feature_name:document.getElementById('feature_name').value,
|
|
feature_description: document.getElementById('feature_description').value,
|
|
feature_requirements: requirements,
|
|
feature_data: feature_data
|
|
};
|
|
document.getElementById('feature_payload').value = JSON.stringify(payload);
|
|
});
|
|
|
|
function addRequirement(prop='', cond='', val='') {
|
|
const reqList = document.getElementById('requirements-list');
|
|
const idx = reqList.children.length;
|
|
const el = document.createElement('div');
|
|
el.className = 'uk-grid-small uk-child-width-expand@s uk-flex-middle uk-margin-small';
|
|
el.setAttribute('uk-grid', '')
|
|
el.innerHTML = `
|
|
<input class="uk-input" name="requirement_property_${idx}" type="text" placeholder="Property" value="${prop}">
|
|
<select class="uk-select" name="requirement_condition_${idx}">
|
|
<option value="==" ${cond=='==' ? 'selected' : ''}>=</option>
|
|
<option value=">=" ${cond=='>=' ? 'selected' : ''}>≥</option>
|
|
<option value="<=" ${cond=='<=' ? 'selected' : ''}>≤</option>
|
|
<option value="!=" ${cond=='!=' ? 'selected' : ''}>≠</option>
|
|
</select>
|
|
<input class="uk-input" name="requirement_value_${idx}" type="text" placeholder="Value" value="${val}">
|
|
<button type="button" class="uk-button uk-button-danger uk-button-small" onclick="this.parentElement.remove()"><span uk-icon="icon: minus"></span></button>
|
|
`;
|
|
reqList.appendChild(el);
|
|
}
|
|
|
|
|
|
function addOperation(attr='', op='', value='', extra=[]) {
|
|
const operationsBody = document.getElementById('operations-body');
|
|
const op_index = operationsBody.children.length;
|
|
|
|
const main_div = document.createElement('div');
|
|
main_div.setAttribute('class', 'uk-width-1-1')
|
|
|
|
main_div.innerHTML = `
|
|
<div class="uk-card uk-card-small uk-card-default uk-card-body">
|
|
<div class="uk-grid-small" uk-grid>
|
|
<div class="uk-width-1-4">
|
|
<input class="uk-input" name="operation_attr_${op_index}" type="text" placeholder="Affected Attribute (e.g., strength)" value="${attr}">
|
|
</div>
|
|
<div class="uk-width-1-4">
|
|
<select class="uk-select" name="operation_operation_${op_index}">
|
|
<option value="add" ${op==='add'?'selected':''}>Add</option>
|
|
<option value="subtract" ${op==='subtract'?'selected':''}>Subtract</option>
|
|
<option value="multiply" ${op==='multiply'?'selected':''}>Multiply</option>
|
|
<option value="divide" ${op==='divide'?'selected':''}>Divide</option>
|
|
<option value="set" ${op==='set'?'selected':''}>Set</option>
|
|
</select>
|
|
</div>
|
|
<div class="uk-width-1-4">
|
|
<input class="uk-input" name="operation_value_${op_index}" type="text" placeholder="Value or Attribute..." value="${value}">
|
|
</div>
|
|
<div class="uk-width-1-4">
|
|
<button type="button" class="uk-button uk-button-danger" onclick="this.closest(".uk-card").remove()"><span uk-icon="icon: trash"></span></button>
|
|
</div>
|
|
</div>
|
|
<div uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<ul class="uk-accordion-default" uk-accordion>
|
|
<li>
|
|
<a class="uk-accordion-title" href>Operation Limits</a>
|
|
<div class="uk-accordion-content" uk-grid>
|
|
<div class="uk-width-1-1">
|
|
<p class="uk-text-meta">Add a limit to when this operation is applied to a character.</p>
|
|
</div>
|
|
<div class="uk-width-1-1">
|
|
<button type="button" class="uk-button uk-button-secondary" onclick="addLimitField(${op_index})"><span uk-icon="icon: plus"></span> Add Operation Limit</button>
|
|
</div>
|
|
<div class="uk-width-1-1 uk-margin-small-top" id="operation-limit-list-${op_index}"></div>
|
|
</div>
|
|
</li>
|
|
<li>
|
|
<a class="uk-accordion-title" href>Operation Requirements</a>
|
|
<div class="uk-accordion-content">
|
|
<div class="uk-width-1-1">
|
|
<button type="button" class="uk-button uk-button-small uk-button-secondary" onclick="addOperationRequirementField(${op_index})"><span uk-icon="icon: plus"></span> Add Operation Requirement</button>
|
|
</div>
|
|
<div class="uk-width-1-1 uk-margin-small-top" id="operation-req-list-${op_index}"></div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>`
|
|
|
|
operationsBody.appendChild(main_div);
|
|
// add pre-existing subparts if any (extra)
|
|
if (extra && Array.isArray(extra)) {
|
|
extra.forEach(kv => addLimitField(op_index, kv.key, kv.value));
|
|
}
|
|
}
|
|
|
|
function addLimitField(opIdx, k='', v='', t='') {
|
|
const list = document.getElementById('operation-limit-list-' + opIdx);
|
|
const subIdx = (list) ? list.children.length : 0;
|
|
const el = document.createElement('div');
|
|
el.className = 'uk-grid-small uk-child-width-expand@s uk-flex-middle';
|
|
el.setAttribute('uk-grid', '');
|
|
el.innerHTML = `
|
|
<label class="uk-label">Limit</label>
|
|
<input class="uk-input" name="operation_${opIdx}_limitkey_${subIdx}" type="text" placeholder="Extra Key (e.g., limit, min, max)" value="${k||''}">
|
|
<select class="uk-select" name="operation_${opIdx}_limittype_${subIdx}">
|
|
<option value="max" ${t==='max'?'selected':''}>max</option>
|
|
<option value="min" ${t==='min'?'selected':''}>min</option>
|
|
<option value="equals" ${t==='equals'?'selected':''}>equal</option>
|
|
</select>
|
|
<input class="uk-input" name="operation_${opIdx}_limitval_${subIdx}" type="text" placeholder="Value" value="${v||''}">
|
|
<button type='button' class='uk-button uk-button-danger uk-button-small' onclick='this.parentElement.remove()'><span uk-icon="icon: minus"></span></button>
|
|
`;
|
|
list.appendChild(el);
|
|
}
|
|
|
|
function addOperationRequirementField(opIdx, prop='', cond='', val='') {
|
|
const list = document.getElementById('operation-req-list-' + opIdx);
|
|
const subIdx = (list) ? list.children.length : 0;
|
|
const el = document.createElement('div');
|
|
el.className = 'uk-grid-small uk-child-width-expand@s uk-flex-middle uk-margin-small';
|
|
el.setAttribute('uk-grid', '');
|
|
el.innerHTML = `
|
|
<input class="uk-input" name="operation_${opIdx}_req_property_${subIdx}" type="text" placeholder="Requirement Property" value="${prop}">
|
|
<select class="uk-select" name="operation_${opIdx}_req_condition_${subIdx}">
|
|
<option value="==" ${cond=='==' ? 'selected' : ''}>=</option>
|
|
<option value=">=" ${cond=='>=' ? 'selected' : ''}>≥</option>
|
|
<option value="<=" ${cond=='<=' ? 'selected' : ''}>≤</option>
|
|
<option value="!=" ${cond=='!=' ? 'selected' : ''}>≠</option>
|
|
</select>
|
|
<input class="uk-input" name="operation_${opIdx}_req_value_${subIdx}" type="text" placeholder="Value" value="${val}">
|
|
<button type='button' class='uk-button uk-button-danger uk-button-small' onclick='this.parentElement.remove()'><span uk-icon="icon: minus"></span></button>
|
|
`;
|
|
list.appendChild(el);
|
|
}
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if(e.key==="Enter" && e.target.tagName==="INPUT") {
|
|
if (!(e.target.closest('form') && e.target.closest('form').id === 'feature-form')) return;
|
|
e.preventDefault(); return false;
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|