Added debouncing for ui update functions
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<attribute-edit
|
||||
v-for="attribute in attributes"
|
||||
v-for="(attribute, index) in attributes"
|
||||
:key="attribute._id"
|
||||
:attribute="attribute"
|
||||
@change="log"
|
||||
@change="e => {writeChange(e, index); log(e)}"
|
||||
/>
|
||||
<div class="ma-4" v-for="(attribute, index) in attributes">
|
||||
{{attribute}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AttributeEdit from '/imports/ui/components/AttributeEdit.vue';
|
||||
import debounceUpdate from '/imports/ui/utility/debounceUpdate.js';
|
||||
export default {
|
||||
components: {
|
||||
AttributeEdit,
|
||||
@@ -34,15 +38,23 @@
|
||||
},
|
||||
],
|
||||
}},
|
||||
methods: {
|
||||
log: console.log,
|
||||
change(index, e){
|
||||
created () {
|
||||
// Doing this here instead of in methods ensures every instance has its
|
||||
// own debounced function
|
||||
this.writeChange = debounceUpdate((e, index) => {
|
||||
// Do work storing the change, this is where we'd write to the database
|
||||
for (let i in e){
|
||||
if (typeof e[i] === 'string'){
|
||||
e[i] = e[i].trim();
|
||||
}
|
||||
this.attributes[index][i] = e[i];
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
methods: {
|
||||
log: console.log,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -3,25 +3,26 @@
|
||||
<v-text-field
|
||||
label="Name"
|
||||
:value="attribute.name"
|
||||
@input="name => $emit('change', {name})"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Variable name"
|
||||
:value="attribute.variableName"
|
||||
@change="variableName => $emit('change', {variableName})"
|
||||
@input="variableName => $emit('change', {variableName})"
|
||||
hint="Use this name in formulae to reference this attribute"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Base Value"
|
||||
type="number"
|
||||
:value="attribute.baseValue"
|
||||
@change="baseValue => $emit('change', {baseValue})"
|
||||
@input="baseValue => $emit('change', {baseValue})"
|
||||
hint="This is the value of the attribute before effects are applied"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Damage"
|
||||
type="number"
|
||||
:value="-attribute.adjustment"
|
||||
@change="damage => $emit('change', {adjustment: -damage})"
|
||||
@input="damage => $emit('change', {adjustment: -damage || null})"
|
||||
/>
|
||||
<v-select
|
||||
label="Type"
|
||||
@@ -29,12 +30,12 @@
|
||||
:items="attributeTypes"
|
||||
:value="attribute.type"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="type => $emit('change', {type})"
|
||||
@input="type => $emit('change', {type})"
|
||||
/>
|
||||
<v-switch
|
||||
label="Allow decimal values"
|
||||
:value="attribute.decimal"
|
||||
@change="decimal => $emit('change', {decimal})"
|
||||
@change="e => $emit('change', {decimal: e})"
|
||||
/>
|
||||
<v-select
|
||||
label="Reset"
|
||||
@@ -44,65 +45,65 @@
|
||||
:items="resetOptions"
|
||||
:value="attribute.reset"
|
||||
:menu-props="{auto: true, lazy: true}"
|
||||
@change="reset => $emit('change', {reset})"
|
||||
@input="reset => $emit('change', {reset})"
|
||||
/>
|
||||
<v-text-field
|
||||
label="Reset Multiplier"
|
||||
type="number"
|
||||
:value="attribute.resetMultiplier"
|
||||
@change="resetMultiplier => $emit('change', {resetMultiplier})"
|
||||
@input="resetMultiplier => $emit('change', {resetMultiplier})"
|
||||
hint="Some attributes, like hit dice, only reset by half their total on a long rest"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
attribute: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
},
|
||||
data(){ return{
|
||||
attributeTypes: [
|
||||
{
|
||||
text: 'Ability score',
|
||||
value: 'ability',
|
||||
}, {
|
||||
text: 'Stat',
|
||||
value: 'stat',
|
||||
}, {
|
||||
text: 'Modifier',
|
||||
value: 'modifier',
|
||||
}, {
|
||||
text: 'Hit dice',
|
||||
value: 'hitDice',
|
||||
}, {
|
||||
text: 'Health bar',
|
||||
value: 'healthBar',
|
||||
}, {
|
||||
text: 'Resource',
|
||||
value: 'resource',
|
||||
}, {
|
||||
text: 'Spell slot',
|
||||
value: 'spellSlot',
|
||||
}, {
|
||||
text: 'Utility',
|
||||
value: 'utility',
|
||||
export default {
|
||||
props: {
|
||||
attribute: {
|
||||
type: Object,
|
||||
default: {},
|
||||
},
|
||||
],
|
||||
resetOptions: [
|
||||
{
|
||||
text: 'Short rest',
|
||||
value: 'shortRest',
|
||||
}, {
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
]
|
||||
}},
|
||||
}
|
||||
},
|
||||
data(){ return{
|
||||
attributeTypes: [
|
||||
{
|
||||
text: 'Ability score',
|
||||
value: 'ability',
|
||||
}, {
|
||||
text: 'Stat',
|
||||
value: 'stat',
|
||||
}, {
|
||||
text: 'Modifier',
|
||||
value: 'modifier',
|
||||
}, {
|
||||
text: 'Hit dice',
|
||||
value: 'hitDice',
|
||||
}, {
|
||||
text: 'Health bar',
|
||||
value: 'healthBar',
|
||||
}, {
|
||||
text: 'Resource',
|
||||
value: 'resource',
|
||||
}, {
|
||||
text: 'Spell slot',
|
||||
value: 'spellSlot',
|
||||
}, {
|
||||
text: 'Utility',
|
||||
value: 'utility',
|
||||
},
|
||||
],
|
||||
resetOptions: [
|
||||
{
|
||||
text: 'Short rest',
|
||||
value: 'shortRest',
|
||||
}, {
|
||||
text: 'Long rest',
|
||||
value: 'longRest',
|
||||
}
|
||||
]
|
||||
}},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:items="operations"
|
||||
:value="this.effect.operation"
|
||||
@change="operation => $emit('change', {operation})"
|
||||
@input="operation => $emit('change', {operation})"
|
||||
>
|
||||
<v-icon
|
||||
class="black--text icon"
|
||||
@@ -35,7 +35,7 @@
|
||||
:value="needsValue ? (effect.calculation) : ' '"
|
||||
:disabled="!needsValue"
|
||||
:hint="!isFinite(effect.calculation) && effect.result ? effect.result + '' : '' "
|
||||
@change="calculation => $emit('change', {calculation})"
|
||||
@input="calculation => $emit('change', {calculation})"
|
||||
/>
|
||||
</v-flex>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
:menu-props="{transition: 'slide-y-transition', lazy: true}"
|
||||
:value="effect.stat"
|
||||
:items="stats"
|
||||
@change="stat => $emit('change', {stat})"
|
||||
@input="stat => $emit('change', {stat})"
|
||||
/>
|
||||
</v-flex>
|
||||
|
||||
|
||||
43
app/imports/ui/utility/debounceUpdate.js
Normal file
43
app/imports/ui/utility/debounceUpdate.js
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Creates a function that takes an object which represents the updates to be
|
||||
* made as key: value pairs. The function collects these updates, (overwriting
|
||||
* duplicates), and runs the given callback with the collated updates after the
|
||||
* `time` has passed without the function being called.
|
||||
*/
|
||||
export default function debounceUpdate(callback, time = 300){
|
||||
let collatedUpdate = {};
|
||||
let interval;
|
||||
|
||||
return (update, ...rest) => {
|
||||
// Every time we're called, collect the update
|
||||
for (key in update){
|
||||
collatedUpdate[key] = update[key];
|
||||
}
|
||||
// Reset the clock and set it again to run the callback
|
||||
clearTimeout(interval);
|
||||
interval = setTimeout(() => {
|
||||
// Clock timed out, apply all the collated updates
|
||||
callback(collatedUpdate, ...rest);
|
||||
// Reset the collation
|
||||
collatedUpdate = {};
|
||||
}, time);
|
||||
};
|
||||
};
|
||||
|
||||
// Example use
|
||||
//
|
||||
// let f = update => {
|
||||
// console.log({wroteUpdate: update});
|
||||
// };
|
||||
// let df = debounceUpdate(f, 300);
|
||||
// df({name: 'john'});
|
||||
// df({name: 'jack'});
|
||||
// df({age: 24, country: 'Ethiopia'});
|
||||
// df({transport: 'bus'});
|
||||
//
|
||||
// --> { wroteUpdate: {
|
||||
// name: 'jack',
|
||||
// age: 24,
|
||||
// country: 'Ethiopia',
|
||||
// transport: 'bus'
|
||||
// }}
|
||||
Reference in New Issue
Block a user