208 lines
4.9 KiB
Vue
208 lines
4.9 KiB
Vue
<template>
|
||
<v-container v-if="visible">
|
||
<v-card flat>
|
||
<v-alert :value="count !== 50" type="warning">
|
||
{{ count }} cards detected! (Decks should have exactly 50 cards)
|
||
</v-alert>
|
||
<v-alert :value="maximum > 3" type="warning">
|
||
Card with {{ maximum }} copies detected! (Cards should not have more
|
||
than 3 copies)
|
||
</v-alert>
|
||
|
||
<v-textarea
|
||
ref="textarea"
|
||
label="Edit Deck"
|
||
:value="value"
|
||
rows="35"
|
||
hint="Change card counts and/or serial numbers. Names will be updated accordingly!"
|
||
style="font-family: monospace"
|
||
@input="checked = false"
|
||
>
|
||
</v-textarea>
|
||
|
||
<v-card-actions>
|
||
<v-btn color="error" @click.native="close">
|
||
<v-icon>cancel</v-icon>
|
||
cancel
|
||
</v-btn>
|
||
|
||
<v-spacer></v-spacer>
|
||
|
||
<v-btn color="info" @click.native="check">
|
||
<v-icon>check</v-icon>
|
||
validate
|
||
</v-btn>
|
||
|
||
<v-btn color="success" @click.native="save" :disabled="!checked">
|
||
<v-icon>save</v-icon>
|
||
save
|
||
</v-btn>
|
||
</v-card-actions>
|
||
</v-card>
|
||
</v-container>
|
||
</template>
|
||
|
||
<script>
|
||
import * as Cookies from 'js-cookie'
|
||
import axios from '@/plugins/axios'
|
||
|
||
export default {
|
||
name: 'DeckEditor',
|
||
|
||
props: {
|
||
id: Number,
|
||
value: String,
|
||
visible: Boolean
|
||
},
|
||
|
||
data: () => ({
|
||
count: 50,
|
||
maximum: 0,
|
||
checked: false
|
||
}),
|
||
|
||
computed: {
|
||
session: () => Cookies.get('session'),
|
||
|
||
new_deck() {
|
||
try {
|
||
return this.parse_deck(this.$refs.textarea)
|
||
} catch (e) {
|
||
return this.parse_deck(this.value)
|
||
}
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
parse_deck(deck_string) {
|
||
let retval = {
|
||
name: '',
|
||
note: '',
|
||
cards: [],
|
||
count: 0
|
||
}
|
||
|
||
// select all lines containing card serial numbers
|
||
let cardLinesRE = /^.*\b\d-\d{3}[A-Z]?\b.*$/gm
|
||
let cardLines = deck_string.match(cardLinesRE)
|
||
let cardCounts = {}
|
||
|
||
cardLines.forEach(cardLine => {
|
||
// extract serial (guaranteed to be in here!)
|
||
let serialRE = /\b(\d-\d{3})[A-Z]?\b/i
|
||
let serial = serialRE.exec(cardLine)[1]
|
||
|
||
// strip out serial number
|
||
cardLine = cardLine.replace(serialRE, '')
|
||
|
||
let countREs = [
|
||
// prioritize a count with "times" symbol *, x, ×
|
||
/\b([0-9]+)(?:[*×]|[x]\b)/,
|
||
/(?:[*×]|\b[x])([0-9]+)\b/,
|
||
// next priority: count with whitespace
|
||
/\s+([0-9]+)\s+/,
|
||
/\s+([0-9]+)\b/,
|
||
/\b([0-9]+)\s+/,
|
||
// least priority: any simple number
|
||
/\b([0-9]+)\b/
|
||
]
|
||
|
||
// fallback value
|
||
let count = 1
|
||
for (let i = 0; i < countREs.length; i++) {
|
||
let data = countREs[i].exec(cardLine)
|
||
|
||
if (data) {
|
||
count = Number(data[1])
|
||
break
|
||
}
|
||
}
|
||
|
||
// count copies
|
||
if (!cardCounts[serial]) {
|
||
cardCounts[serial] = 0
|
||
}
|
||
cardCounts[serial] += count
|
||
|
||
retval.count += count
|
||
})
|
||
|
||
// push card data into deck
|
||
Object.keys(cardCounts).forEach(serial => {
|
||
retval.cards.push({
|
||
serial: serial,
|
||
count: cardCounts[serial]
|
||
})
|
||
})
|
||
|
||
// strip out lines with serial numbers
|
||
deck_string = deck_string.replace(cardLinesRE, '')
|
||
|
||
// select the line containing 'deck name:'
|
||
// and its successor (ffdecks format)
|
||
let metaRE = /^Deck Name: (.+)$[\s]*?^(.+)$/m
|
||
let metaData = metaRE.exec(deck_string)
|
||
|
||
// fallback
|
||
retval.name = 'Unnamed Deck'
|
||
retval.note = ''
|
||
|
||
if (!metaData) {
|
||
// no ffdecks format found: strip out anything after the first empty line
|
||
deck_string = deck_string.replace(/^[\s]*$[^]*/m, '')
|
||
|
||
// use lax format: <anything>:[deck name][newline][note]
|
||
metaRE = /[^]*?:(.+)$[\s]*?^([^]*)/m
|
||
metaData = metaRE.exec(deck_string)
|
||
}
|
||
|
||
// look again, I am not an else!
|
||
if (metaData) {
|
||
// extract matches
|
||
retval.name = metaData[1].trim()
|
||
retval.note = metaData[2].trim()
|
||
}
|
||
|
||
return retval
|
||
},
|
||
|
||
close() {
|
||
this.checked = false
|
||
this.$emit('close')
|
||
},
|
||
|
||
check() {
|
||
let new_deck = this.parse_deck(this.$refs.textarea.lazyValue)
|
||
|
||
// count number of cards
|
||
this.count = new_deck.count
|
||
|
||
// find most frequent card
|
||
this.maximum = 0
|
||
new_deck.cards.forEach(card => {
|
||
if (card.count > this.maximum) this.maximum = card.count
|
||
})
|
||
|
||
// deck has now been checked
|
||
this.checked = true
|
||
},
|
||
|
||
save() {
|
||
let new_deck = this.parse_deck(this.$refs.textarea.lazyValue)
|
||
|
||
axios
|
||
.post('/decks/modify', {
|
||
session: this.session,
|
||
deckID: this.id,
|
||
deckCards: new_deck
|
||
})
|
||
.then(response => {
|
||
if (response.data.success) {
|
||
this.$emit('change', new_deck)
|
||
this.close()
|
||
}
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|