<template> <div class="character-kinks-block" @contextmenu="contextMenu" @touchstart="contextMenu" @touchend="contextMenu"> <div class="compare-highlight-block d-flex justify-content-between"> <div class="expand-custom-kinks-block form-inline"> <button class="btn btn-primary" @click="toggleExpandedCustomKinks" :disabled="loading">{{(expandedCustoms ? 'Collapse' : 'Expand')}} Custom Kinks</button> </div> <div v-if="shared.authenticated" class="quick-compare-block form-inline"> <character-select v-model="characterToCompare"></character-select> <button class="btn btn-outline-secondary" @click="compareKinks()" :disabled="loading || !characterToCompare"> {{ compareButtonText }} </button> </div> <div class="form-inline"> <select v-model="highlightGroup" class="form-control"> <option :value="undefined">None</option> <option v-for="group in kinkGroups" v-if="group" :value="group.id" :key="group.id">{{group.name}}</option> </select> </div> </div> <div class="form-row mt-3" :class="{ highlighting: !!highlightGroup }"> <div class="col-sm-6 col-lg-3 kink-block-favorite"> <div class="card bg-light"> <div class="card-header"> <h4>Favorites</h4> </div> <div class="card-body"> <kink v-for="kink in groupedKinks['favorite']" :kink="kink" :key="kink.key" :highlights="highlighting" :expandedCustom="expandedCustoms" :comparisons="comparison"></kink> </div> </div> </div> <div class="col-sm-6 col-lg-3 kink-block-yes"> <div class="card bg-light"> <div class="card-header"> <h4>Yes</h4> </div> <div class="card-body"> <kink v-for="kink in groupedKinks['yes']" :kink="kink" :key="kink.key" :highlights="highlighting" :expandedCustom="expandedCustoms" :comparisons="comparison"></kink> </div> </div> </div> <div class="col-sm-6 col-lg-3 kink-block-maybe"> <div class="card bg-light"> <div class="card-header"> <h4>Maybe</h4> </div> <div class="card-body"> <kink v-for="kink in groupedKinks['maybe']" :kink="kink" :key="kink.key" :highlights="highlighting" :expandedCustom="expandedCustoms" :comparisons="comparison"></kink> </div> </div> </div> <div class="col-sm-6 col-lg-3 kink-block-no"> <div class="card bg-light"> <div class="card-header"> <h4>No</h4> </div> <div class="card-body"> <kink v-for="kink in groupedKinks['no']" :kink="kink" :key="kink.key" :highlights="highlighting" :expandedCustom="expandedCustoms" :comparisons="comparison"></kink> </div> </div> </div> </div> <context-menu v-if="shared.authenticated && !oldApi" prop-name="custom" ref="context-menu"></context-menu> </div> </template> <script lang="ts"> import * as _ from 'lodash'; import {Component, Prop, Watch, Hook} from '@f-list/vue-ts'; import Vue from 'vue'; import core from '../../chat/core'; import {Kink, KinkChoice, KinkGroup} from '../../interfaces'; import * as Utils from '../utils'; import CopyCustomMenu from './copy_custom_menu.vue'; import {methods, Store} from './data_store'; import {Character, CharacterKink, DisplayKink} from './interfaces'; import KinkView from './kink.vue'; @Component({ components: {'context-menu': CopyCustomMenu, kink: KinkView} }) export default class CharacterKinksView extends Vue { @Prop({required: true}) readonly character!: Character; @Prop readonly oldApi?: true; @Prop({required: true}) readonly autoExpandCustoms!: boolean; shared = Store; characterToCompare = Utils.settings.defaultCharacter; highlightGroup: number | undefined; loading = false; comparing = false; highlighting: {[key: string]: boolean} = {}; comparison: {[key: string]: KinkChoice} = {}; _ = _; expandedCustoms = false; toggleExpandedCustomKinks(): void { this.expandedCustoms = !this.expandedCustoms; } // iterateThroughAllKinks(c: Character, cb: ( resolveKinkChoice(c: Character, kinkValue: string | number | undefined): string | null { if (typeof kinkValue === 'string') { return kinkValue; } if (typeof kinkValue === 'number') { const custom = c.character.customs[kinkValue]; if (custom) { return custom.choice; } } return null; } convertCharacterKinks(c: Character): CharacterKink[] { return _.filter( _.map( c.character.kinks, (kinkValue: string | number | undefined, kinkId: string) => { const resolvedChoice = this.resolveKinkChoice(c, kinkValue); if (!resolvedChoice) return null; return { id: parseInt(kinkId, 10), choice: resolvedChoice as KinkChoice }; } ), (v) => (v !== null) ) as CharacterKink[]; } async compareKinks(overridingCharacter?: Character, forced: boolean = false): Promise<void> { if ((this.comparing) && (!forced)) { this.comparison = {}; this.comparing = false; this.loading = false; return; } try { this.loading = true; this.comparing = true; const kinks = overridingCharacter ? this.convertCharacterKinks(overridingCharacter) : await methods.kinksGet(this.characterToCompare); const toAssign: {[key: number]: KinkChoice} = {}; for(const kink of kinks) toAssign[kink.id] = kink.choice; this.comparison = toAssign; } catch(e) { this.comparing = false; this.comparison = {}; Utils.ajaxError(e, 'Unable to get kinks for comparison.'); } this.loading = false; } @Watch('highlightGroup') highlightKinks(group: number | null): void { this.highlighting = {}; if(group === null) return; const toAssign: {[key: string]: boolean} = {}; for(const kinkId in Store.shared.kinks) { const kink = Store.shared.kinks[kinkId]; if(kink.kink_group === group) toAssign[kinkId] = true; } this.highlighting = toAssign; } @Hook('mounted') async mounted(): Promise<void> { if ((this.character) && (this.character.is_self)) return; this.expandedCustoms = this.autoExpandCustoms; if (core.state.settings.risingAutoCompareKinks) { await this.compareKinks(core.characters.ownProfile, true); } } @Watch('character') async characterChanged(): Promise<void> { if ((this.character) && (this.character.is_self)) return; this.expandedCustoms = this.autoExpandCustoms; if (core.state.settings.risingAutoCompareKinks) { await this.compareKinks(core.characters.ownProfile, true); } } get kinkGroups(): KinkGroup[] { const groups = Store.shared.kinkGroups; return _.sortBy( _.filter( groups, (g) => (!_.isUndefined(g)) ), 'name' ) as KinkGroup[]; } get compareButtonText(): string { if(this.loading) return 'Loading...'; return this.comparing ? 'Clear' : 'Compare'; } get groupedKinks(): {[key in KinkChoice]: DisplayKink[]} { const kinks = Store.shared.kinks; const characterKinks = this.character.character.kinks; const characterCustoms = this.character.character.customs; const displayCustoms: {[key: string]: DisplayKink | undefined} = {}; const outputKinks: {[key: string]: DisplayKink[]} = {favorite: [], yes: [], maybe: [], no: []}; const makeKink = (kink: Kink): DisplayKink => ({ id: kink.id, name: kink.name, description: kink.description, group: kink.kink_group, isCustom: false, hasSubkinks: false, ignore: false, subkinks: [], key: kink.id.toString() }); const kinkSorter = (a: DisplayKink, b: DisplayKink) => { if(this.character.settings.customs_first && a.isCustom !== b.isCustom) return a.isCustom < b.isCustom ? 1 : -1; if(a.name === b.name) return 0; return a.name < b.name ? -1 : 1; }; for(const id in characterCustoms) { const custom = characterCustoms[id]!; displayCustoms[id] = { id: custom.id, name: custom.name, description: custom.description, choice: custom.choice, group: -1, isCustom: true, hasSubkinks: false, ignore: false, subkinks: [], key: `c${custom.id}` }; } for(const kinkId in characterKinks) { const kinkChoice = characterKinks[kinkId]!; const kink = <Kink | undefined>kinks[kinkId]; if(kink === undefined) continue; const newKink = makeKink(kink); if(typeof kinkChoice === 'number' && typeof displayCustoms[kinkChoice] !== 'undefined') { const custom = displayCustoms[kinkChoice]!; newKink.ignore = true; custom.hasSubkinks = true; custom.subkinks.push(newKink); } if(!newKink.ignore) outputKinks[kinkChoice].push(newKink); } for(const customId in displayCustoms) { const custom = displayCustoms[customId]!; if(custom.hasSubkinks) custom.subkinks.sort(kinkSorter); outputKinks[<string>custom.choice].push(custom); } for(const choice in outputKinks) outputKinks[choice].sort(kinkSorter); return <{[key in KinkChoice]: DisplayKink[]}>outputKinks; } contextMenu(event: TouchEvent): void { if(this.shared.authenticated && !this.oldApi) (<CopyCustomMenu>this.$refs['context-menu']).outerClick(event); } } </script>