Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
Daniel Asher Resnick | ffd5dc4d77 | 2 years ago |
Daniel Asher Resnick | e6d89e11a7 | 2 years ago |
Daniel Asher Resnick | d740e9a96a | 2 years ago |
Daniel Asher Resnick | 4e570a2ba2 | 2 years ago |
Daniel Asher Resnick | a6ce5d9635 | 2 years ago |
Daniel Asher Resnick | 458721c55b | 2 years ago |
Daniel Asher Resnick | 962f5fff48 | 2 years ago |
Daniel Asher Resnick | 050c71e872 | 2 years ago |
Daniel Asher Resnick | 0df9eb8bca | 2 years ago |
Daniel Asher Resnick | 06f581fb78 | 2 years ago |
@ -0,0 +1,67 @@ |
||||
a.panel-title:link,.panel-title a:link { text-decoration: none; } |
||||
a.panel-title:visited,.panel-title a:visited { text-decoration: none; } |
||||
a.panel-title:hover,.panel-title a:hover { text-decoration: underline; } |
||||
a.panel-title:active,.panel-title a:active { text-decoration: underline; } |
||||
|
||||
input.editable-name { |
||||
color: #333; |
||||
display: inline; |
||||
width: 12em; |
||||
} |
||||
input.editable-line { |
||||
color: #333; |
||||
} |
||||
input.editable-num { |
||||
color: #333; |
||||
display: inline; |
||||
width: 3em; |
||||
} |
||||
input.editable-name.not-editing { |
||||
background: #F5F5F5; |
||||
font-weight: bold; |
||||
} |
||||
input.editable-line.not-editing { |
||||
background: #F5F5F5; |
||||
} |
||||
input.editable-num.not-editing { |
||||
background: #F5F5F5; |
||||
} |
||||
|
||||
.add-skills-traits-container { |
||||
margin-top: 1em; |
||||
margin-bottom: 1em; |
||||
} |
||||
|
||||
.horizontal-input-pair { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 0.5em; |
||||
} |
||||
.horizontal-input-pair label { |
||||
margin-bottom: 0; |
||||
} |
||||
.horizontal-input-pair input { |
||||
flex-grow: 1; |
||||
} |
||||
div.skill-even { |
||||
} |
||||
div.skill-odd { |
||||
background: #F5F5F5; |
||||
} |
||||
tr.trait-even { |
||||
background: lightgray; |
||||
} |
||||
tr.trait-odd { |
||||
background: #F5F5F5; |
||||
} |
||||
textarea.trait-desc { |
||||
height: 5em; |
||||
width: 98%; |
||||
margin: 1em; |
||||
} |
||||
table.traits{ |
||||
width: 100%; |
||||
} |
||||
table.traits input.editable-name { |
||||
width: 100%; |
||||
} |
@ -0,0 +1,388 @@ |
||||
// class TimeLogger {
|
||||
// constructor() {
|
||||
// this.logs = [];
|
||||
// this.unlabelled_id = 0;
|
||||
// this.start = this.previous = Date.now();
|
||||
// this.log('start');
|
||||
// }
|
||||
// log(label) {
|
||||
// var now = Date.now();
|
||||
// var log = {
|
||||
// 'when': now,
|
||||
// 'label': label,
|
||||
// 'elapsed': now - this.previous,
|
||||
// 'total': now - this.start
|
||||
// };
|
||||
// this.logs.push(log);
|
||||
// this.previous = now;
|
||||
// return log;
|
||||
// }
|
||||
// }
|
||||
|
||||
// const timelogger = new TimeLogger;
|
||||
// console.log(timelogger.logs[0]);
|
||||
//
|
||||
// console.log(timelogger.log("post-data"));
|
||||
|
||||
// Settings
|
||||
|
||||
function StockedSetting(name, charredSettingData) { |
||||
this.isSubsetting = false; |
||||
if(result = name.match(/(.*) setting/i)) { |
||||
this.name = result[1]; |
||||
} else if(result = name.match(/(.*) subsetting/i)) { |
||||
this.name = result[1]; |
||||
this.isSubsetting = true; |
||||
} else { |
||||
this.name = name; |
||||
} |
||||
this.lifepaths = []; |
||||
for (let name in charredSettingData) { |
||||
this.lifepaths.push(new StockedLifePath(name, charredSettingData[name])); |
||||
} |
||||
} |
||||
StockedSetting.prototype.addLifepath = function() { |
||||
this.lifepaths.push(new StockedLifePath(this.newLifepathName, {})); |
||||
this.newLifepathName = ""; |
||||
} |
||||
StockedSetting.prototype.removeLifepath = function(index) { |
||||
this.lifepaths.splice(index, 1); |
||||
} |
||||
StockedSetting.prototype.toCharred = function() { |
||||
// let name = this.name + (this.isSubsetting ? " Subsetting" : " Setting";
|
||||
|
||||
let charred = {}; |
||||
for(let lp of this.lifepaths) { |
||||
charred[lp.name] = lp.toCharred(); |
||||
} |
||||
// common traits
|
||||
// stride
|
||||
return charred; |
||||
} |
||||
|
||||
function StockedLifePath(name, charredPathData) { |
||||
if(charredPathData) { |
||||
this.name = name; |
||||
this.time = charredPathData.time; |
||||
this.res = charredPathData.res; |
||||
this.requires = charredPathData.requires; |
||||
this.restrict = charredPathData.restrict; |
||||
this.stat = new StockedLifePathStats(charredPathData.stat); |
||||
this.skills = new StockedLifePathSkills(charredPathData.skills); |
||||
this.traits = new StockedLifePathTraits(charredPathData.traits); |
||||
} else { |
||||
this.stat = new StockedLifePathStats(); |
||||
this.skills = new StockedLifePathSkills(); |
||||
this.traits = new StockedLifePathTraits(); |
||||
} |
||||
|
||||
this.leads_dict = {}; |
||||
if(charredPathData.leads) { |
||||
for(let lead of charredPathData.leads) { this.leads_dict[lead] = true; } |
||||
} |
||||
this.leads = () => Object.keys(this.leads_dict).filter(l => this.leads_dict[l]); |
||||
} |
||||
StockedLifePath.prototype.toCharred = function() { |
||||
let charred = {}; |
||||
charred.time = this.time; |
||||
charred.res = this.res; |
||||
charred.requires = this.requires; |
||||
charred.restrict = this.restrict; |
||||
charred.stat = this.stat.toCharred(); |
||||
charred.skills = this.skills.toCharred(); |
||||
charred.traits = this.traits.toCharred(); |
||||
charred.leads = this.leads(); |
||||
return charred; |
||||
} |
||||
|
||||
function StockedLifePathStats(charredStatData) { |
||||
this.P = 0; |
||||
this.M = 0; |
||||
this.PM = 0; |
||||
if(charredStatData) { |
||||
for (let stat of charredStatData) { |
||||
if(stat[1].toUpperCase() == 'P') { |
||||
this.P += stat[0]; |
||||
} |
||||
else if(stat[1].toUpperCase() == 'M') { |
||||
this.M += stat[0]; |
||||
} |
||||
else if(stat[1].toUpperCase() == 'PM' || stat[0].toUpperCase() == 'MP') { |
||||
this.PM += stat[0]; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
StockedLifePathStats.prototype.toString = function() { |
||||
let strs = []; |
||||
if (this.P) { strs.push("+" + this.P + "P"); } |
||||
if (this.M) { strs.push("+" + this.M + "M"); } |
||||
if (this.PM) { strs.push("+" + this.PM + "P/M"); } |
||||
return strs.join(","); |
||||
}; |
||||
StockedLifePathStats.prototype.toCharred = function() { |
||||
let charred = []; |
||||
if(this.P > 0) charred.push([this.P, "p"]); |
||||
if(this.M > 0) charred.push([this.M, "m"]); |
||||
if(this.PM > 0) charred.push([this.PM, "pm"]); |
||||
return charred; |
||||
} |
||||
|
||||
function StockedLifePathSkills(charredLpSkillData) { |
||||
this.lpPoints = 0; |
||||
this.generalPoints = 0; |
||||
this.lpSkills = []; |
||||
if (charredLpSkillData) { |
||||
for (let skill of charredLpSkillData) { |
||||
if(skill.length == 1) { |
||||
this.lpPoints = skill[0]; |
||||
} |
||||
if(skill.length >= 2) { |
||||
if(skill[1].toLowerCase() == "general") { |
||||
this.generalPoints += skill[0]; |
||||
} else { |
||||
this.lpPoints += skill[0]; |
||||
this.lpSkills = this.lpSkills.concat(skill.slice(1)); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
StockedLifePathSkills.prototype.removeSkill = function(index) { |
||||
this.lpSkills.splice(index, 1); |
||||
} |
||||
StockedLifePathSkills.prototype.addSkill = function(skill) { |
||||
this.lpSkills.push(skill); |
||||
} |
||||
StockedLifePathSkills.prototype.toString = function() { |
||||
let strs = []; |
||||
if (this.lpPoints) { strs.push(StockedUtil.pts(this.lpPoints, this.lpSkills)); } |
||||
if (this.generalPoints) { strs.push(StockedUtil.pts(this.generalPoints, ["General"])); } |
||||
return strs.join("; "); |
||||
}; |
||||
StockedLifePathSkills.prototype.toCharred = function() { |
||||
let charred = []; |
||||
if(this.lpSkills.length > 0 || this.lpPoints > 0){ |
||||
charred.push([this.lpPoints].concat(this.lpSkills)); |
||||
} |
||||
if(this.generalPoints > 0) |
||||
charred.push([this.generalPoints, "General"]); |
||||
return charred; |
||||
} |
||||
|
||||
function StockedLifePathTraits(charredTraitData) { |
||||
this.lpTraits = []; |
||||
if(charredTraitData) { |
||||
this.points = charredTraitData[0]; |
||||
this.lpTraits = charredTraitData.slice(1); |
||||
} |
||||
} |
||||
StockedLifePathTraits.prototype.removeTrait = function(index) { |
||||
this.lpTraits.splice(index, 1); |
||||
} |
||||
StockedLifePathTraits.prototype.addTrait = function(skill) { |
||||
this.lpTraits.push(skill); |
||||
} |
||||
StockedLifePathTraits.prototype.toString = function() { |
||||
return StockedUtil.pts(this.points, this.lpTraits); |
||||
} |
||||
StockedLifePathTraits.prototype.toCharred = function() { |
||||
return [this.points].concat(this.lpTraits); |
||||
} |
||||
|
||||
|
||||
// Skills
|
||||
|
||||
function StockedSkill(name, charredSkillData) { |
||||
this.name = name; |
||||
this.magic = charredSkillData.magic ? true : false; |
||||
this.roots = { |
||||
Perception: false, |
||||
Will: false, |
||||
Forte: false, |
||||
Power: false, |
||||
Agility: false, |
||||
Speed: false, |
||||
}; |
||||
if(charredSkillData.roots){ |
||||
charredSkillData.roots.map(rootName => this.roots[rootName] = true); |
||||
} |
||||
this.stockSpecific = "TODO"; |
||||
} |
||||
|
||||
// Traits
|
||||
|
||||
function StockedTrait(name, charredTraitData) { |
||||
this.name = name; |
||||
this.cost = charredTraitData.cost; |
||||
this.type = charredTraitData.type; |
||||
this.desc = charredTraitData.desc; |
||||
|
||||
// No logic for these yet
|
||||
this.bonus = charredTraitData.bonus; |
||||
this.restrict = charredTraitData.restrict; |
||||
} |
||||
|
||||
//Ctrl
|
||||
|
||||
var testscope; |
||||
|
||||
function StockedCtrl($scope, $http, burningData) { |
||||
$scope.to_id = function(input) { return input.replaceAll(/\W/g, '_'); }; |
||||
$scope.StockedUtil = StockedUtil; |
||||
|
||||
$scope.TRAIT_TYPES = ["character", "die", "call_on"]; |
||||
|
||||
$scope.settings = []; |
||||
|
||||
/* testing */ |
||||
testscope = $scope; |
||||
$scope.general = { |
||||
'Name': 'Foo', |
||||
'Stride': 7, |
||||
'CommonTraits': [], |
||||
'selectedTrait': '' |
||||
}; |
||||
|
||||
// $scope.parseStock = function (stockData){
|
||||
// let settings = [];
|
||||
// for (let name in stockData) {
|
||||
// settings.push(new StockedSetting(name, stockData[name]));
|
||||
// }
|
||||
// return settings;
|
||||
// };
|
||||
|
||||
// $scope.parseSkills = function (skillsData){
|
||||
// let skills = [];
|
||||
// for (let name in skillsData) {
|
||||
// skills.push(new StockedSkill(name, skillsData[name]));
|
||||
// }
|
||||
// return skills;
|
||||
// };
|
||||
|
||||
// $scope.parseTraits = function (traitsData){
|
||||
// let traits = [];
|
||||
// for (let name in traitsData) {
|
||||
// traits.push(new StockedTrait(name, traitsData[name]));
|
||||
// }
|
||||
// return traits;
|
||||
// };
|
||||
|
||||
/* end testing */ |
||||
|
||||
/* Input/Output */ |
||||
/* end Input/Output */ |
||||
|
||||
$scope.addSetting = function (){ |
||||
this.settings.push(new StockedSetting(this.newSettingName, {})); |
||||
this.newSettingName = ""; |
||||
}; |
||||
|
||||
$scope.removeSetting = function (index) { |
||||
this.settings.splice(index, 1); |
||||
}; |
||||
|
||||
$scope.addSkill = function (){ |
||||
this.skills.push(new StockedSkill("New", {})); |
||||
}; |
||||
$scope.removeSkill = function (index) { |
||||
this.skills.splice(index, 1); |
||||
}; |
||||
|
||||
$scope.addTrait = function (){ |
||||
this.traits.push(new StockedTrait("New", {})); |
||||
}; |
||||
$scope.removeTrait = function (index) { |
||||
this.traits.splice(index, 1); |
||||
}; |
||||
|
||||
$scope.collapseBody = function(data_target, $event) { |
||||
$(data_target).collapse("toggle"); |
||||
if($event) { $event.stopPropagation(); } |
||||
}; |
||||
$scope.editField = function($event, edit) { |
||||
$($event.target).toggleClass("not-editing"); |
||||
}; |
||||
burningData.registerOnAllDatasetsLoaded(function() { |
||||
onLifepathsLoad_Stocked($scope, burningData); |
||||
}); |
||||
|
||||
$scope.editLeads = function($event) { |
||||
let container = $($event.target).closest('.path-leads'); |
||||
container.find(".path-leads-read").toggle(false); |
||||
container.find(".path-leads-write").toggle(true); |
||||
}; |
||||
$scope.readLeads = function($event) { |
||||
let container = $($event.target).closest('.path-leads'); |
||||
container.find(".path-leads-read").toggle(true); |
||||
container.find(".path-leads-write").toggle(false); |
||||
}; |
||||
|
||||
$scope.stocked_loadCharredModel = function() { |
||||
file = document.getElementById("stocked_charred_file"); |
||||
file.files[0].text().then((text) => loadCharredModel(this, JSON.parse(text))); |
||||
}; |
||||
$scope.stocked_downLoadCharredModel = function() { |
||||
model = serializeToCharredModel(this); |
||||
$http.post("/stocked_download", model). |
||||
success(function(data,status,headers,config){ |
||||
console.log("huzzah, converting stocked model to charred succeeded. File URL: " + data); |
||||
var frame = document.getElementById("downloadframe"); |
||||
if ( frame ){ |
||||
frame.src = data; |
||||
} |
||||
}). |
||||
error(function(data,status,headers,config){ |
||||
console.log("boo, converting stocked model to charred failed. File URL: " + data); |
||||
$scope.addAlert('tools', "converting stocked model to charred failed: " + data); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// Accepts an object, JSON text should be parsed first
|
||||
function loadCharredModel($scope, model) { |
||||
let settings = []; |
||||
for (let name in model) { |
||||
settings.push(new StockedSetting(name, model[name])); |
||||
} |
||||
$scope.settings = settings; |
||||
$scope.$apply(); |
||||
} |
||||
|
||||
function serializeToCharredModel($scope) { |
||||
let model = {}; |
||||
model.settings = {}; |
||||
model.Name = $scope.general.Name; |
||||
$scope.settings.forEach((s) => |
||||
model.settings[s.name + (s.isSubsetting ? " Subsetting" : " Setting")] = s.toCharred()) |
||||
return JSON.stringify(model); |
||||
} |
||||
|
||||
function onLifepathsLoad_Stocked($scope, burningData) { |
||||
// $scope.settings = $scope.parseStock(test_data);
|
||||
// $scope.skills = $scope.parseSkills(test_skills_data);
|
||||
// $scope.traits = $scope.parseTraits(test_traits_data);
|
||||
$scope.charredTraits = Object.keys(burningData.traits); |
||||
$scope.charredSkills = Object.keys(burningData.skills); |
||||
} |
||||
|
||||
var StockedUtil = { |
||||
"pluralize": function(num, thing, withE, nospace) { |
||||
str = ""; |
||||
str += num; |
||||
if (!nospace) { str += ' '; } |
||||
str += thing; |
||||
if(num != 1) { |
||||
if (withE) { str += 'e'; } |
||||
str += 's'; |
||||
} |
||||
return str; |
||||
}, |
||||
"pts": function(num, entries) { |
||||
let str = StockedUtil.pluralize(num, "pt") + ": "; |
||||
if(Array.isArray(entries) && entries.length > 0) { str += entries.join(", "); } |
||||
else { str += "—" } |
||||
return str; |
||||
}//, "filter$properties": (key, value) => (key.startsWith('$') ? undefined : value)
|
||||
|
||||
}; |
@ -0,0 +1,42 @@ |
||||
function EditableInputController($scope, $element, $attrs) { |
||||
console.log($scope); |
||||
console.log($element); |
||||
var ctrl = this; |
||||
ctrl.isEditing = false; |
||||
|
||||
ctrl.handleModeChange = function() { |
||||
if (ctrl.isEditing) { |
||||
ctrl.onUpdate({value: ctrl.modelValue}); |
||||
ctrl.modelValueCopy = ctrl.modelValue; |
||||
} |
||||
ctrl.isEditing = !ctrl.isEditing; |
||||
}; |
||||
|
||||
ctrl.reset = function() { |
||||
ctrl.modelValue = ctrl.modelValueCopy; |
||||
}; |
||||
|
||||
ctrl.$onInit = function() { |
||||
// Make a copy of the initial value to be able to reset it later
|
||||
ctrl.modelValueCopy = ctrl.modelValue; |
||||
|
||||
// Set a default inputType
|
||||
if (!ctrl.inputType) { |
||||
ctrl.inputType = 'text'; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
export function register(module) { |
||||
console.log(module); |
||||
module.component('editableInput', { |
||||
templateUrl: '/stocked/editableInput_partial', |
||||
controller: EditableInputController, |
||||
bindings: { |
||||
modelValue: '<', |
||||
inputID: '<', |
||||
inputType: '@?', |
||||
onUpdate: '&' |
||||
} |
||||
}); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@ |
||||
{ |
||||
"Foo Setting": { |
||||
"Born Foo": { |
||||
"time": 1, |
||||
"res": 5, |
||||
"stat": [ |
||||
[1, "pm"] |
||||
], |
||||
"leads": [ |
||||
"Bar" |
||||
], |
||||
"key_leads": [ |
||||
"Bar Setting" |
||||
], |
||||
"skills": [ |
||||
[3, "General"] |
||||
], |
||||
"traits": [1], |
||||
"common_traits": [] |
||||
} |
||||
}, |
||||
"Bar Setting": {} |
||||
} |
@ -0,0 +1,377 @@ |
||||
<div class='container' ng-controller='StockedCtrl'> |
||||
<h1 id='intro'>Stocked</h1> |
||||
<div class='well'> |
||||
Stocked (Stock·ed) |
||||
<br> |
||||
<br> |
||||
<ol> |
||||
<li><i>adj.</i> Furnished with more than enough. <i>(ref https://www.vocabulary.com/dictionary/stocked)</i></li> |
||||
<li><i>n.</i> A portmanteau of <i>stock</i> and <i>editor</i>.</li> |
||||
</ol> |
||||
</div> |
||||
<div class='panel panel-default'> |
||||
<div class='panel-heading' > |
||||
<h4 class='panel-title'> |
||||
<a href='' ng-click='collapseBody("#collapse_tools")'>▸</a> |
||||
Tools |
||||
</h4> |
||||
</div> |
||||
<div class='panel-collapse collapse in' id='collapse_tools'> |
||||
<div class='panel-body'> |
||||
<div class='alert alert-danger alert-dismissable' ng-repeat="warn in alertsOfType('tools', 'warn')"> |
||||
<button aria-hidden='true' class='close' ng-click="removeAlert('tools',warn)" type='button'>×</button> |
||||
{{warn}} |
||||
</div> |
||||
<div class='alert alert-success alert-dismissable' ng-repeat="warn in alertsOfType('tools', 'succ')"> |
||||
<button aria-hidden='true' class='close' ng-click="removeAlert('tools',warn)" type='button'>×</button> |
||||
{{warn}} |
||||
</div> |
||||
<div class='container'> |
||||
<div class='row'> |
||||
<div class='col-md-3'> |
||||
<input type="file" id="stocked_charred_file"/> |
||||
<a href='' ng-click='stocked_loadCharredModel()'> |
||||
TODO: Load charred stock model |
||||
</a> |
||||
</div> |
||||
<div class='col-md-3'> |
||||
<a href='' ng-click='stocked_downloadCharredModel()'> |
||||
TODO: Download charred stock model |
||||
</a> |
||||
</div> |
||||
<div class='col-md-3'> |
||||
<a href='' ng-click='stocked_generateMarkdown()'> |
||||
TODO: Generate Markdown |
||||
</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel-heading'> |
||||
<h4 class='panel-title'> |
||||
<a href='' ng-click='collapseBody("#collapse_general")'>▸</a> |
||||
General |
||||
</h4> |
||||
</div> |
||||
<div class='panel-collapse collapse in' id='collapse_general'> |
||||
<div class='panel-body'> |
||||
<label for='stock-name'>Name:</label> |
||||
<input class='form-control input-lg not-editing editable-name' name='stock-name' id='stock-name' |
||||
ng-model="general.Name" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
|
||||
<label for='stock-stride'>Stride:</label> |
||||
<input type="number" class='not-editing editable-num' name='stock-stride' id='stock-stride' |
||||
ng-model="general.Stride" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<br /> |
||||
<div> |
||||
<span>Common traits: {{general.CommonTraits.join(", ")}}</span> |
||||
<select class='form-control' ng-model='general.selectedTrait' ng-options='t for t in charredTraits'></select> |
||||
</div> |
||||
<div> |
||||
<a href='' ng-click='general.CommonTraits.push(general.selectedTrait)'>Add trait</a> |
||||
</div> |
||||
<div> |
||||
<a href='' ng-click=''>TODO: Add new trait</a> |
||||
</div> |
||||
<br /> |
||||
TODO: other things in General section? |
||||
</div> |
||||
</div> |
||||
<div class='panel-heading'> |
||||
<h4 class='panel-title'> |
||||
<a href='' ng-click='collapseBody("#collapse_settings")'>▸</a> |
||||
Settings |
||||
</h4> |
||||
</div> |
||||
<div class='panel-collapse collapse in' id='collapse_settings'> |
||||
<div class='panel-body'> |
||||
<span class="note-label">Note:</span> |
||||
<span class="note-content"> |
||||
Settings will have " Setting" (or " Subsetting" for subsettings) |
||||
appended to the name in the generated charred model, which is how charred will display them. |
||||
</span> |
||||
<br /> |
||||
|
||||
<a ng-click='collapseBody(".collapse_all_settings", $event)' href=''> |
||||
collapse/expand all settings |
||||
</a> |
||||
<div class='list-group'> |
||||
<div ng-repeat="setting in settings" class='list-group-item'> |
||||
<div class='panel-heading'> |
||||
<a href='' class="panel-title" ng-click='collapseBody("#collapse_" + to_id(setting.name))'>▸</a> |
||||
<input class='form-control input-lg not-editing editable-name' |
||||
ng-model="setting.name" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<span class="panel-title" style="font-weight: bold;"> |
||||
<input type="checkbox" ng-model="setting.isSubsetting" /> Subsetting? |
||||
</span> |
||||
<a href='' ng-click='removeSetting($index)'>[X]</a> |
||||
</div> |
||||
<div class='panel-collapse collapse in collapse_all_settings' id='collapse_{{to_id(setting.name)}}'> |
||||
<div class='panel-body'> |
||||
<div class="panel"> |
||||
<div class="panel-body"> |
||||
<span class="note-label">Note:</span> |
||||
<span class="note-content"> |
||||
Prefix a lifepath's name with "Born " to have charred consider it a born lifepath; |
||||
i.e. selectable if and only if it is the first lifepath. |
||||
</span> |
||||
<br /> |
||||
|
||||
<a ng-click='collapseBody(".collapse_all_"+to_id(setting.name), $event)' href=''> |
||||
collapse/expand all paths in setting |
||||
</a> |
||||
<div class='container-fluid'> |
||||
<div class='row'> |
||||
<div class='h4 col-md-3'>Lifepath</div> |
||||
<div class='h4 col-md-1'>Time</div> |
||||
<div class='h4 col-md-1'>Res</div> |
||||
<div class='h4 col-md-3'>Stat</div> |
||||
<div class='h4 col-md-4'>Leads</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div ng-repeat="path in setting.lifepaths"> |
||||
<div class='panel-heading'> |
||||
<div class='container-fluid'> |
||||
<div class='row'> |
||||
<div class="col-md-3"> |
||||
<a href='' class="panel-title" ng-click='collapseBody("#collapse_" + to_id(path.name))'>▸</a> |
||||
<input ng-model="path.name" |
||||
class='form-control input-lg not-editing editable-name' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<a href='' ng-click='setting.removeLifepath($index)'>[X]</a> |
||||
</div> |
||||
|
||||
<div class="col-md-1"> |
||||
<input type="number" ng-model="path.time" |
||||
class='not-editing editable-num' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<span>yrs</span> |
||||
</div> |
||||
|
||||
<div class="col-md-1"> |
||||
<input type="number" ng-model="path.res" |
||||
class='not-editing editable-num' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</div> |
||||
|
||||
<div class="col-md-3"> |
||||
<label for="{{to_id(path.name)}}_M">M: </label> |
||||
<input type="number" ng-model="path.stat.M" id="{{to_id(path.name)}}_M" |
||||
class='not-editing editable-num' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<label for="{{to_id(path.name)}}_P">P: </label> |
||||
<input type="number" ng-model="path.stat.P" id="{{to_id(path.name)}}_M" |
||||
class='not-editing editable-num' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<label for="{{to_id(path.name)}}_PM">P/M: </label> |
||||
<input type="number" ng-model="path.stat.PM" id="{{to_id(path.name)}}_M" |
||||
class='not-editing editable-num' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</div> |
||||
|
||||
<div class='h5 col-md-4 path-leads'> |
||||
<div class="path-leads-read"> |
||||
<span>Leads: </span><i>{{path.leads().join(", ")}}</i> |
||||
<a href='' ng-click='editLeads($event)'>Edit</a> |
||||
</div> |
||||
<div class="path-leads-write" hidden="hidden"> |
||||
<div ng-repeat="setting in settings"> |
||||
<input type="checkbox" id='{{to_id(path.name)}}-to-{{to_id(setting.name)}}' |
||||
ng-model='path.leads_dict[setting.name]' value='{{to_id(setting.name)}}' /> |
||||
<label for='{{to_id(path.name)}}-to-{{to_id(setting.name)}}'> |
||||
{{setting.name}} |
||||
</label> |
||||
</div> |
||||
<a href='' ng-click='readLeads($event)'>Done</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel-collapse collapse in collapse_all_{{to_id(setting.name)}}' id='collapse_{{to_id(path.name)}}'> |
||||
<div class='panel-body'> |
||||
<span ng-if='$first'>TODO: Born/common traits</span> |
||||
|
||||
<div> |
||||
<b><i>Skills:</i></b> |
||||
<span ng-if='path.skills.lpSkills.length > 0' ng-click='editPoints($event)'> |
||||
{{StockedUtil.pluralize(path.skills.lpPoints, "pt")}}: |
||||
</span> |
||||
<div style="display: inline;" ng-repeat='skill in path.skills.lpSkills track by $index'> |
||||
{{skill}}<a href='' ng-click='path.skills.removeSkill($index)'>[X]</a><!-- |
||||
--><span ng-if='!$last'>,</span></div><!-- |
||||
--><span ng-if='path.skills.lpSkills.length > 0 && path.skills.generalPoints > 0'>;</span> |
||||
<span ng-if='path.skills.generalPoints > 0'>{{StockedUtil.pluralize(path.skills.generalPoints, "pt")}}: General</span> |
||||
</div> |
||||
|
||||
<div> |
||||
<b><i>Traits:</i></b> |
||||
<span ng-if='path.traits.lpTraits.length == 0'>—</span> |
||||
<span ng-if='path.traits.lpTraits.length > 0' ng-click='editPoints($event)'> |
||||
{{StockedUtil.pluralize(path.traits.points, "pt")}}: |
||||
</span> |
||||
<div style="display: inline;" ng-repeat='trait in path.traits.lpTraits track by $index'> |
||||
{{trait}}<a href='' ng-click='path.traits.removeTrait($index)'>[X]</a><!-- |
||||
--><span ng-if='!$last'>,</span></div> |
||||
</div> |
||||
|
||||
<div ng-if="path.requires" class="horizontal-input-pair"> |
||||
<label for="{{to_id(path.name)}}-requires"><b><i>Requires: </i></b></label> |
||||
<input ng-model="path.requires" id="{{to_id(path.name)}}-requires" |
||||
class='form-control not-editing editable-line' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</div> |
||||
<div ng-if="path.restrict" class="horizontal-input-pair"> |
||||
<label for="{{to_id(path.name)}}-restrict"><b><i>Restrictions: </i></b></label> |
||||
<input ng-model="path.restrict" id="{{to_id(path.name)}}-restrict" |
||||
class='form-control not-editing editable-line' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</div> |
||||
|
||||
<div class="add-skills-traits-container" class="container"> |
||||
<div class='row'> |
||||
<div class='col-md-3'> |
||||
<select class='form-control' ng-model='path.selectedSkill' ng-options='s for s in charredSkills'></select> |
||||
</div> |
||||
<div class='col-md-1'> |
||||
<a href='' ng-click='path.skills.addSkill(path.selectedSkill)'>Add skill</a> |
||||
</div> |
||||
<div class='col-md-2'> |
||||
<a href='' ng-click=''>TODO: Add new skill</a> |
||||
</div> |
||||
|
||||
<div class='col-md-3'> |
||||
<select class='form-control' ng-model='path.selectedTrait' ng-options='t for t in charredTraits'></select> |
||||
</div> |
||||
<div class='col-md-1'> |
||||
<a href='' ng-click='path.traits.addTrait(path.selectedTrait)'>Add trait</a> |
||||
</div> |
||||
<div class='col-md-2'> |
||||
<a href='' ng-click=''>TODO: Add new trait</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<span>WISHLIST: requires expression</span> |
||||
|
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel panel-default'> |
||||
<input class='form-control input-lg not-editing editable-name' |
||||
name='new-lifepath-name' id='new-lifepath-name' |
||||
ng-model="setting.newLifepathName" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<a href='' ng-click='setting.addLifepath()'>Add new lifepath</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel panel-default'> |
||||
<input class='form-control input-lg not-editing editable-name' |
||||
name='new-setting-name' id='new-setting-name' |
||||
ng-model="newSettingName" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
<a href='' ng-click='addSetting()'>Add new setting</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel-heading'> |
||||
<h4 class='panel-title'> |
||||
<a href='' ng-click='collapseBody("#collapse_skills")'>▸</a> |
||||
Skills |
||||
</h4> |
||||
</div> |
||||
<div class='panel-collapse collapse in' id='collapse_skills'> |
||||
<div class='panel-body'> |
||||
<div class='container-fluid'> |
||||
<div class='row'> |
||||
<div class='h4 col-md-3'>Skill</div> |
||||
<div class='h4 col-md-1'>Sorcerous?</div> |
||||
<div class='h4 col-md-8'>Roots</div> |
||||
<%# <div class='h4 col-md-2'>Stock specific?</div> %> |
||||
</div> |
||||
</div> |
||||
<div ng-repeat='skill in skills' class='row' ng-class-even="'skill-even'" ng-class-odd="'skill-odd'"> |
||||
<div class='h4 col-md-3'> |
||||
<input ng-model="skill.name" |
||||
class='form-control input-lg not-editing editable-name' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</div> |
||||
<div class='h4 col-md-1'><input type="checkbox" ng-model='skill.magic'></div> |
||||
<div class='h4 col-md-8'> |
||||
<div class="skill-roots-write"> |
||||
<span ng-repeat="(root,is) in skill.roots"> |
||||
<input type="checkbox" id='{{to_id(skill.name)-to_id(root)}}' ng-model='is'/> |
||||
<label for='{{to_id(skill.name)-to_id(root)}}'> {{root}} </label> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='row'> |
||||
<div class='h4 col-md-12'><a href='' ng-click='addSkill()'>Add new skill</a></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<div class='panel-heading'> |
||||
<h4 class='panel-title'> |
||||
<a href='' ng-click='collapseBody("#collapse_traits")'>▸</a> |
||||
Traits |
||||
</h4> |
||||
</div> |
||||
<div class='panel-collapse collapse in' id='collapse_traits'> |
||||
<div class='panel-body'> |
||||
<table class="traits"> |
||||
<tr> |
||||
<th>Trait</th> |
||||
<th>Cost</th> |
||||
<th>Type</th> |
||||
<%# <div class='h4 col-md-2'>Bonus</div> %> |
||||
<%# <div class='h4 col-md-2'>Restrictions</div> %> |
||||
</tr> |
||||
<%# </div> %> |
||||
<tr ng-repeat-start='trait in traits' ng-class-even="'trait-even'" ng-class-odd="'trait-odd'"> |
||||
<td> |
||||
<input ng-model="trait.name" |
||||
class='form-control input-lg not-editing editable-name' |
||||
ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</td> |
||||
<td> |
||||
<input type="number" class='not-editing editable-num' |
||||
ng-model="trait.cost" ng-click="$event.stopPropagation()" |
||||
ng-focus='editField($event, true)' ng-blur='editField($event, false)' /> |
||||
</td> |
||||
<td> |
||||
<select class='form-control' ng-model='trait.type' ng-options='t for t in TRAIT_TYPES'></select> |
||||
</td> |
||||
<td><a href='' ng-click='removeTrait($index)'>[X]</a></td> |
||||
</tr> |
||||
<%# <div class='h4 col-md-2'>WISHLIST</div> %> |
||||
<%# <div class='h4 col-md-2'>WISHLIST</div> %> |
||||
<tr ng-repeat-end ng-class-even="'trait-even'" ng-class-odd="'trait-odd'"> |
||||
<td colspan="99"><textarea class='trait-desc' ng-model='trait.desc'></textarea></td> |
||||
</tr> |
||||
</table> |
||||
<div class='row'> |
||||
<div class='h4 col-md-12'><a href='' ng-click='addTrait()'>Add new trait</a></div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,6 @@ |
||||
<span ng-if='$ctrl.label' for='{{$ctrl.inputID}}'>{{$ctrl.label}}</span> |
||||
<span ng-switch='$ctrl.isEditing'> |
||||
<input ng-switch-when="true" ng-model='$ctrl.modelValue' ng-blur='$ctrl.handleModeChange()' |
||||
id='{{$ctrl.inputID}}' type='{{$ctrl.inputType}}' class="editable-input editing"> |
||||
<span ng-switch-default class="editable-input">{{$ctrl.modelValue}}</span> |
||||
</span> |
Loading…
Reference in new issue