Fixed warnings

This commit is contained in:
Mr. Stallion 2019-07-06 11:49:19 -05:00
parent 093ab4e7eb
commit 6671fd9374
23 changed files with 261 additions and 173 deletions

View File

@ -54,7 +54,7 @@
@Prop()
readonly classes?: string;
@Prop()
readonly value?: string;
readonly value?: string | undefined;
@Prop()
readonly disabled?: boolean;
@Prop()
@ -66,7 +66,8 @@
preview = false;
previewWarnings: ReadonlyArray<string> = [];
previewResult = '';
text = this.value !== undefined ? this.value : '';
// tslint:disable-next-line: no-unnecessary-type-assertion
text: string = (this.value !== undefined ? this.value : '') as string;
element!: HTMLTextAreaElement;
sizer!: HTMLTextAreaElement;
maxHeight!: number;
@ -191,14 +192,19 @@
apply(button: EditorButton): void {
// Allow emitted variations for custom buttons.
this.$once('insert', (startText: string, endText: string) => this.applyText(startText, endText));
// noinspection TypeScriptValidateTypes
if(button.handler !== undefined)
return button.handler.call(this, this);
if(button.startText === undefined)
button.startText = `[${button.tag}]`;
if(button.endText === undefined)
button.endText = `[/${button.tag}]`;
if(this.text.length + button.startText.length + button.endText.length > this.maxlength) return;
this.applyText(button.startText, button.endText);
const ebl = button.endText ? button.endText.length : 0;
const sbl = button.startText ? button.startText.length : 0;
if(this.text.length + sbl + ebl > this.maxlength) return;
this.applyText(button.startText || '', button.endText || '');
this.lastInput = Date.now();
}
@ -278,6 +284,7 @@
this.previewWarnings = [];
this.previewResult = '';
const previewElement = (<BBCodeElement>targetElement.firstChild);
// noinspection TypeScriptValidateTypes
if(previewElement.cleanup !== undefined) previewElement.cleanup();
if(targetElement.firstChild !== null) targetElement.removeChild(targetElement.firstChild);
} else {

View File

@ -35,12 +35,12 @@
@Prop({required: true})
readonly domain!: string;
@Hook("beforeDestroy")
@Hook('beforeDestroy')
beforeDestroy(): void {
this.dismiss();
}
@Hook("deactivated")
@Hook('deactivated')
deactivate(): void {
this.dismiss();
}

View File

@ -17,6 +17,7 @@ function fixURL(url: string): string {
return url.replace(/ /g, '%20');
}
// tslint:disable-next-line: max-line-length
export function analyzeUrlTag(parser: BBCodeParser, param: string, content: string): {success: boolean, url?: string, domain?: string, textContent: string} {
let url: string | undefined, textContent: string = content;
let success = true;

View File

@ -209,6 +209,8 @@
if(!core.state.settings.showNeedsReply) return false;
for(let i = conversation.messages.length - 1; i >= 0; --i) {
const sender = (<Partial<Conversation.ChatMessage>>conversation.messages[i]).sender;
// noinspection TypeScriptValidateTypes
if(sender !== undefined)
return sender !== core.characters.ownCharacter;
}

View File

@ -75,7 +75,7 @@
<div v-show="adAutoPostNextAd" class="next">
<h5>{{l('admgr.comingNext')}}</h5>
<div>{{(adAutoPostNextAd ? adAutoPostNextAd.substr(0, 50) : '')}}...</div>
<div>{{(adAutoPostNextAd ? adAutoPostNextAd.substr(0, 64) : '')}}...</div>
</div>
<a class="btn btn-sm btn-outline-primary renew-autoposts" @click="renewAutoPosting()">{{l('admgr.renew')}}</a>
@ -147,7 +147,7 @@
import {Keys} from '../keys';
import {BBCodeView, Editor} from './bbcode';
import CommandHelp from './CommandHelp.vue';
import { characterImage, getByteLength, getKey } from "./common";
import { characterImage, getByteLength, getKey } from './common';
import ConversationSettings from './ConversationSettings.vue';
import core from './core';
import {Channel, channelModes, Character, Conversation, Settings} from './interfaces';
@ -419,22 +419,20 @@
toggleAutoPostAds(): void {
if(this.isAutopostingAds()) {
if(this.isAutopostingAds())
this.stopAutoPostAds();
} else {
else
this.conversation.adManager.start();
}
this.refreshAutoPostingTimer();
}
refreshAutoPostingTimer() {
if (this.autoPostingUpdater) {
refreshAutoPostingTimer(): void {
if (this.autoPostingUpdater)
window.clearInterval(this.autoPostingUpdater);
}
if(this.isAutopostingAds() === false) {
if (!this.isAutopostingAds()) {
this.adAutoPostUpdate = null;
this.adAutoPostNextAd = null;
return;
@ -473,6 +471,7 @@
hasSFC(message: Conversation.Message): message is Conversation.SFCMessage {
// noinspection TypeScriptValidateTypes
return (<Partial<Conversation.SFCMessage>>message).sfc !== undefined;
}

View File

@ -20,81 +20,91 @@
<script lang="ts">
import {Component, Hook} from '@f-list/vue-ts';
import Vue from 'vue';
import {EventBus} from './event-bus';
import { EventBus, EventBusEvent } from './event-bus';
import {domain} from '../bbcode/core';
import {ImagePreviewMutator} from './image-preview-mutator';
import {Point, screen} from 'electron';
import {Point, screen, WebviewTag} from 'electron';
import Timer = NodeJS.Timer;
interface DidFailLoadEvent extends Event {
errorCode: number;
errorDescription: string;
}
interface DidNavigateEvent extends Event {
httpResponseCode: number;
httpStatusText: string;
}
@Component
export default class ImagePreview extends Vue {
private readonly MinTimePreviewVisible = 500;
public visible: boolean = false;
visible = false;
public externalUrlVisible: boolean = false;
public internalUrlVisible: boolean = false;
externalUrlVisible = false;
internalUrlVisible = false;
public externalUrl: string | null = null;
public internalUrl: string | null = null;
externalUrl: string | null = null;
internalUrl: string | null = null;
public url: string | null = null;
public domain: string | undefined;
url: string | null = null;
domain: string | undefined;
private jsMutator = new ImagePreviewMutator();
private interval: any = null;
sticky = false;
runJs = true;
debug = false;
private exitInterval: any = null;
private jsMutator = new ImagePreviewMutator(this.debug);
private interval: Timer | null = null;
private exitInterval: Timer | null = null;
private exitUrl: string | null = null;
private initialCursorPosition: Point | null = null;
private shouldDismiss = false;
private visibleSince = 0;
sticky = false;
runJs = true;
debug = false;
@Hook('mounted')
onMounted(): void {
EventBus.$on(
'imagepreview-dismiss',
(eventData: any) => {
(eventData: EventBusEvent) => {
// console.log('Event dismiss', eventData.url);
this.dismiss(eventData.url);
this.dismiss(eventData.url as string);
}
);
EventBus.$on(
'imagepreview-show',
(eventData: any) => {
(eventData: EventBusEvent) => {
// console.log('Event show', eventData.url);
this.show(eventData.url);
this.show(eventData.url as string);
}
);
EventBus.$on(
'imagepreview-toggle-stickyness',
(eventData: any) => {
if ((this.url === eventData.url) && (this.visible))
(eventData: EventBusEvent) => {
if ((this.url === (eventData.url as string)) && (this.visible))
this.sticky = !this.sticky;
}
);
const webview = this.$refs.imagePreviewExt as any;
const webview = this.$refs.imagePreviewExt as WebviewTag;
webview.addEventListener(
'dom-ready',
(event: any) => {
(event: EventBusEvent) => {
const url = webview.getURL();
const js = this.jsMutator.getMutatorJsForSite(url);
if (this.debug) {
if (this.debug)
console.log('ImagePreview dom-ready', event, js);
// webview.openDevTools();
}
if ((js) && (this.runJs))
webview.executeJavaScript(js);
@ -103,27 +113,29 @@
webview.addEventListener(
'did-fail-load',
(event: any) => {
const js = this.jsMutator.getErrorMutator(event.errorCode, event.errorDescription);
(event: Event) => {
const e = event as DidFailLoadEvent;
if (this.debug) {
const js = this.jsMutator.getErrorMutator(e.errorCode, e.errorDescription);
if (this.debug)
console.log('ImagePreview did-fail-load', event, js);
}
if ((js) && (this.runJs) && (event.errorCode >= 400))
if ((js) && (this.runJs) && (e.errorCode >= 400))
webview.executeJavaScript(js);
}
);
webview.addEventListener(
'did-navigate',
(event: any) => {
if (event.httpResponseCode >= 400) {
const js = this.jsMutator.getErrorMutator(event.httpResponseCode, event.httpStatusText);
(event: Event) => {
const e = event as DidNavigateEvent;
if (this.debug) {
if (e.httpResponseCode >= 400) {
const js = this.jsMutator.getErrorMutator(e.httpResponseCode, e.httpStatusText);
if (this.debug)
console.log('ImagePreview did-navigate', event, js);
}
if ((js) && (this.runJs))
webview.executeJavaScript(js);
@ -134,13 +146,13 @@
// webview.getWebContents().on(
webview.addEventListener(
'did-finish-load',
(event: any)=> {
(event: Event) => {
if (this.debug)
console.log('ImagePreview did-finish-load', event);
webview.getWebContents().session.on(
'will-download',
(e: any) => {
(e: Event) => {
e.preventDefault();
}
);
@ -160,18 +172,23 @@
);
}
hide(): void {
this.cancelExitTimer();
this.url = null;
this.visible = false;
if (this.externalUrlVisible) {
const webview = this.$refs.imagePreviewExt as WebviewTag;
webview.executeJavaScript(this.jsMutator.getHideMutator());
}
this.internalUrlVisible = false;
this.externalUrlVisible = false;
this.externalUrl = 'about:blank';
this.internalUrl = 'about:blank';
// this.externalUrl = null; // 'about:blank';
this.internalUrl = null; // 'about:blank';
this.exitUrl = null;
this.exitInterval = null;
@ -181,7 +198,6 @@
this.sticky = false;
}
dismiss(url: string): void {
if (this.url !== url)
return; // simply ignore
@ -210,13 +226,13 @@
// This timeout makes the preview window disappear with a slight delay, which helps UX
// when dealing with situations such as quickly scrolling text that moves the cursor away
// from the link
// tslint:disable-next-line no-unnecessary-type-assertion
this.exitInterval = setTimeout(
() => this.hide(),
due
);
) as Timer;
}
show(url: string): void {
// console.log('SHOW');
@ -239,6 +255,7 @@
// This timer makes sure that just by accidentally brushing across a link won't show (blink) the preview
// -- you actually have to pause on it
// tslint:disable-next-line no-unnecessary-type-assertion
this.interval = setTimeout(
() => {
const isInternal = this.isInternalUrl();
@ -257,7 +274,7 @@
this.initialCursorPosition = screen.getCursorScreenPoint();
},
due
);
) as Timer;
}
hasMouseMovedSince(): boolean {
@ -301,23 +318,22 @@
return !((this.domain === 'f-list.net') || (this.domain === 'static.f-list.net'));
}
isInternalUrl(): boolean {
return !this.isExternalUrl();
}
toggleDevMode(): void {
this.debug = !this.debug;
this.jsMutator.setDebug(this.debug);
if (this.debug) {
const webview = this.$refs.imagePreviewExt as any;
const webview = this.$refs.imagePreviewExt as WebviewTag;
webview.openDevTools();
}
}
toggleStickyMode(): void {
this.sticky = !this.sticky;
@ -325,15 +341,13 @@
this.hide();
}
toggleJsMode(): void {
this.runJs = !this.runJs;
}
reloadUrl(): void {
if (this.externalUrlVisible) {
const webview = this.$refs.imagePreviewExt as any;
const webview = this.$refs.imagePreviewExt as WebviewTag;
webview.reload();
}

View File

@ -1,4 +1,5 @@
import { Conversation } from './interfaces';
import Timer = NodeJS.Timer;
export class AdManager {
static readonly POSTING_PERIOD = 3 * 60 * 60 * 1000;
@ -13,7 +14,7 @@ export class AdManager {
private nextPostDue?: Date;
private expireDue?: Date;
private firstPost?: Date;
private interval?: any;
private interval?: Timer;
constructor(conversation: Conversation) {
this.conversation = conversation;
@ -43,12 +44,13 @@ export class AdManager {
this.adIndex = this.adIndex + 1;
this.nextPostDue = new Date(Date.now() + nextInMs);
// tslint:disable-next-line: no-unnecessary-type-assertion
this.interval = setTimeout(
async() => {
await this.sendNextPost();
},
nextInMs
);
) as Timer;
}
getAds(): string[] {
@ -85,6 +87,7 @@ export class AdManager {
this.nextPostDue = new Date(Date.now() + initialWait);
this.expireDue = new Date(Date.now() + AdManager.POSTING_PERIOD);
// tslint:disable-next-line: no-unnecessary-type-assertion
this.interval = setTimeout(
async() => {
this.firstPost = new Date();
@ -92,7 +95,7 @@ export class AdManager {
await this.sendNextPost();
},
initialWait
);
) as Timer;
}
stop(): void {

View File

@ -7,7 +7,7 @@ import ChannelView from './ChannelTagView.vue';
import {characterImage} from './common';
import core from './core';
import {Character} from './interfaces';
import UrlView from '../bbcode/UrlTagView.vue';
import {default as UrlView} from '../bbcode/UrlTagView.vue';
import UserView from './user_view';
export const BBCodeView: Component = {

View File

@ -77,6 +77,7 @@ export function messageToString(this: void | never, msg: Conversation.Message, t
}
export function getKey(e: KeyboardEvent): Keys {
// tslint:disable-next-line deprecation
return e.keyCode;
}

View File

@ -1,3 +1,9 @@
import Vue from 'vue';
export interface EventBusEvent {
// tslint:disable: no-any
[key: string]: any;
}
export const EventBus = new Vue();

View File

@ -2,10 +2,10 @@
import * as _ from 'lodash';
import { domain } from '../bbcode/core';
import { domain as extractDomain } from '../bbcode/core';
export interface PreviewMutator {
match: string|RegExp;
match: string | RegExp;
injectJs: string;
}
@ -13,12 +13,21 @@ export interface ImagePreviewMutatorCollection {
[key: string]: PreviewMutator;
}
export class ImagePreviewMutator {
// tslint:disable: prefer-function-over-method
private hostMutators: ImagePreviewMutatorCollection = {};
private regexMutators: PreviewMutator[] = [];
private debug: boolean;
constructor() {
constructor(debug: boolean) {
this.init();
this.debug = debug;
}
setDebug(debug: boolean): void {
this.debug = debug;
}
getMutatorJsForSite(url: string): string | undefined {
@ -30,9 +39,8 @@ export class ImagePreviewMutator {
return this.wrapJs(mutator.injectJs);
}
matchMutator(url: string): PreviewMutator | undefined {
const urlDomain = domain(url);
const urlDomain = extractDomain(url);
if (!urlDomain)
return;
@ -50,13 +58,11 @@ export class ImagePreviewMutator {
);
}
protected wrapJs(mutatorJs: string) {
protected wrapJs(mutatorJs: string): string {
return `(() => { try { ${mutatorJs} } catch (err) { console.error('Mutator error', err); } })();`;
}
protected add(domain: string|RegExp, mutatorJs: string) {
protected add(domain: string | RegExp, mutatorJs: string): void {
if (domain instanceof RegExp) {
this.regexMutators.push(
{
@ -74,7 +80,7 @@ export class ImagePreviewMutator {
};
}
protected init() {
protected init(): void {
this.add('default', this.getBaseJsMutatorScript('#video, #image, video, img'));
this.add('e621.net', this.getBaseJsMutatorScript('#image, video'));
this.add('e-hentai.org', this.getBaseJsMutatorScript('#img, video'));
@ -97,6 +103,7 @@ export class ImagePreviewMutator {
this.add(/^media[0-9]\.giphy\.com$/, this.getBaseJsMutatorScript('video, img[alt]'));
// tslint:disable max-line-length
this.add(
'imgur.com',
`
@ -118,10 +125,14 @@ export class ImagePreviewMutator {
);
}
getBaseJsMutatorScript(imageSelector: string, skipElementRemove: boolean = false): string {
getBaseJsMutatorScript(elSelector: string, skipElementRemove: boolean = false): string {
return `const body = document.querySelector('body');
const img = Array.from(document.querySelectorAll('${imageSelector}'))
.filter((i) => ((i.width !== 1) && (i.height !== 1))).shift()
let selected = Array.from(document.querySelectorAll('${elSelector}'))
.filter((i) => ((i.width !== 1) && (i.height !== 1)));
const img = selected.shift();
${this.debug ? `console.log('Selector', '${elSelector}'); console.log('Selected', selected); console.log('Img', img);` : ''}
if (!img) { return; }
@ -139,10 +150,6 @@ export class ImagePreviewMutator {
body.append(el);
body.class = '';
// console.log(el);
// console.log(img);
// console.log('${imageSelector}');
body.style = 'border: 0 !important; padding: 0 !important; margin: 0 !important; overflow: hidden !important;'
+ 'width: 100% !important; height: 100% !important; opacity: 1 !important;'
+ 'top: 0 !important; left: 0 !important;';
@ -154,11 +161,16 @@ export class ImagePreviewMutator {
img.class = '';
el.class = '';
${this.debug ? "console.log('Wrapper', el);" : ''}
if (img.play) { img.muted = true; img.play(); }
let removeList = [];
body.childNodes.forEach((el) => { if((el.id !== 'flistWrapper') && (el.id !== 'flistError')) { removeList.push(el); } });
// ${skipElementRemove ? '' : 'removeList.forEach((el) => el.remove());'}
const safeIds = ['flistWrapper', 'flistError', 'flistHider'];
body.childNodes.forEach((el) => ((safeIds.indexOf(el.id) < 0) ? removeList.push(el) : true)
${skipElementRemove ? '' : 'removeList.forEach((el) => el.remove());'}
removeList = [];
`;
}
@ -207,19 +219,40 @@ export class ImagePreviewMutator {
">${description}</p></div>
`;
return this.injectHtmlJs(errorHtml);
}
protected injectHtmlJs(html: string): string {
return this.wrapJs(`
const range = document.createRange();
range.selectNode(document.body);
const error = range.createContextualFragment(\`${errorHtml}\`);
const error = range.createContextualFragment(\`${html}\`);
document.body.appendChild(error);
`);
}
getHideMutator(): string {
return this.injectHtmlJs(`
<div id="flistHider" style="
width: 100% !important;
height: 100% !important;
background-color: black !important;
position: absolute !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
z-index: 300000 !important;
margin: 0 !important;
padding: 0 !important;
line-height: 100% !important;
border: 0 !important;
opacity: 1 !important;
text-align: center !important;
"></div>
`);
}
}

View File

@ -20,6 +20,7 @@ import {
import '../site/directives/vue-select'; //tslint:disable-line:no-import-side-effect
import * as Utils from '../site/utils';
import core from './core';
import { EventBus } from './event-bus';
const parserSettings = {
siteDomain: 'https://www.f-list.net/',
@ -66,7 +67,8 @@ async function characterData(name: string | undefined): Promise<Character> {
}
parserSettings.inlineDisplayMode = data.current_user.inline_mode;
parserSettings.animatedIcons = core.state.settings.animatedEicons;
return {
const charData = {
is_self: false,
character: {
id: data.id,
@ -92,6 +94,10 @@ async function characterData(name: string | undefined): Promise<Character> {
bookmarked: core.characters.get(data.name).isBookmarked,
self_staff: false
};
EventBus.$emit('character-data', charData);
return charData;
}
function contactMethodIconUrl(name: string): string {

View File

@ -45,6 +45,7 @@
@Prop()
readonly title?: string;
filter = '';
// noinspection TypeScriptValidateTypes
selected: object | object[] | undefined = this.value !== undefined ? this.value : (this.multiple !== undefined ? [] : undefined);
keepOpen = false;

View File

@ -97,7 +97,9 @@
const parent = electron.remote.getCurrentWindow().webContents;
log.info('About to load keytar');
/*tslint:disable:no-any*///because this is hacky
/* tslint:disable: no-any no-unsafe-any */ //because this is hacky
const keyStore = nativeRequire<{
getPassword(account: string): Promise<string>
setPassword(account: string, password: string): Promise<void>
@ -257,6 +259,7 @@
openProfileInBrowser(): void {
electron.remote.shell.openExternal(`https://www.f-list.net/c/${this.profileName}`);
// tslint:disable-next-line: no-any no-unsafe-any
(this.$refs.profileViewer as any).hide();
}
@ -268,6 +271,7 @@
conversation.show();
// tslint:disable-next-line: no-any no-unsafe-any
(this.$refs.profileViewer as any).hide();
}

View File

@ -26,6 +26,10 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
## Todo / Ideas
* Preview mode should allow detaching from the main window
* Split chat view
* Improvements to log browsing
* Highlight ads from characters most interesting to you
* Fix broken BBCode, such as `[big]` in character profiles
# F-List Exported

View File

@ -157,25 +157,23 @@
return this.load();
}
async load(mustLoad = true) {
async load(mustLoad: boolean = true): Promise<void> {
this.loading = true;
this.error = '';
try {
const due: Promise<any>[] = [];
const due: Promise<void>[] = [];
if(this.name === undefined || this.name.length === 0)
return;
await methods.fieldsGet();
if ((this.selfCharacter === undefined) && (Utils.Settings.defaultCharacter >= 0)) {
if ((this.selfCharacter === undefined) && (Utils.Settings.defaultCharacter >= 0))
due.push(this.loadSelfCharacter());
}
if((mustLoad === true) || (this.character === undefined)) {
if((mustLoad) || (this.character === undefined))
due.push(this._getCharacter());
}
await Promise.all(due);
} catch(e) {
@ -189,7 +187,7 @@
}
async countGuestbookPosts() {
async countGuestbookPosts(): Promise<void> {
try {
if ((!this.character) || (!_.get(this.character, 'settings.guestbook'))) {
this.guestbookPostCount = null;
@ -206,7 +204,7 @@
}
async countGroups() {
async countGroups(): Promise<void> {
try {
if ((!this.character) || (this.oldApi)) {
this.groupCount = null;
@ -223,7 +221,7 @@
}
async countFriends() {
async countFriends(): Promise<void> {
try {
if (
(!this.character)
@ -251,7 +249,7 @@
Vue.set(this.character!, 'bookmarked', state);
}
protected async loadSelfCharacter(): Promise<Character> {
protected async loadSelfCharacter(): Promise<void> {
// console.log('SELF');
const ownChar = core.characters.ownCharacter;
@ -261,8 +259,6 @@
// console.log('SELF LOADED');
this.updateMatches();
return this.selfCharacter;
}
private async _getCharacter(): Promise<void> {
@ -279,17 +275,22 @@
this.updateMatches();
// no awaits on these on purpose
// No awaits on these on purpose:
// tslint:disable-next-line no-floating-promises
this.countGuestbookPosts();
// tslint:disable-next-line no-floating-promises
this.countGroups();
// tslint:disable-next-line no-floating-promises
this.countFriends();
}
private updateMatches(): void {
if ((!this.selfCharacter) || (!this.character)) {
if ((!this.selfCharacter) || (!this.character))
return;
}
this.characterMatch = Matcher.generateReport(this.selfCharacter.character, this.character.character);

View File

@ -13,7 +13,8 @@
import { DisplayInfotag } from './interfaces';
// import { Character as CharacterInfo } from '../../interfaces';
import {Store} from './data_store';
import { MatchReport, Score, TagId } from './matcher';
import { MatchReport, TagId } from './matcher';
import { CssClassMap } from './match-report.vue';
@Component
@ -24,11 +25,9 @@
@Prop({required: true})
private readonly characterMatch!: MatchReport;
get tagClasses() {
const styles: any = {
infotag: true,
get tagClasses(): CssClassMap {
const styles: CssClassMap = {
infotag: true
};
// console.log(`Infotag ${this.infotag.id}: ${this.label}`);
@ -40,7 +39,7 @@
: (this.yourInterestIsRelevant(id) ? this.characterMatch.you.scores : null);
if (scores) {
const score = scores[id] as Score;
const score = scores[id];
styles[score.getRecommendedClass()] = true;
styles['match-score'] = true;
@ -57,7 +56,7 @@
yourInterestIsRelevant(id: number): boolean {
return ((id === TagId.Gender) || (id === TagId.Age) || (id === TagId.Species))
return ((id === TagId.Gender) || (id === TagId.Age) || (id === TagId.Species));
}

View File

@ -35,9 +35,8 @@
readonly characterMatch!: MatchReport;
get groupedInfotags(): DisplayInfotagGroup[] {
if ((!this.character) || (!this.character.character)) {
if ((!this.character) || (!this.character.character))
return [];
}
const groups = Store.kinks.infotag_groups;
const infotags = Store.kinks.infotags;

View File

@ -34,8 +34,10 @@
readonly highlights!: {[key: number]: boolean};
@Prop({required: true})
readonly comparisons!: {[key: number]: string | undefined};
@Prop({required: false})
expandedCustom: boolean = false;
// tslint:disable-next-line: vue-props
expandedCustom = false;
listClosed = true;
showTooltip = false;
@ -61,7 +63,7 @@
'custom-kink': this.kink.isCustom,
highlighted: !this.kink.isCustom && this.highlights[this.kink.id],
subkink: this.kink.hasSubkinks,
'expanded-custom-kink': this.expandedCustom,
'expanded-custom-kink': this.expandedCustom
};
classes[`kink-id-${this.kinkId}`] = true;
classes[`kink-group-${this.kink.group}`] = true;

View File

@ -143,18 +143,16 @@
@Hook('mounted')
async mounted(): Promise<void> {
if ((this.character) && (this.character.is_self)) {
if ((this.character) && (this.character.is_self))
return;
}
await this.compareKinks();
}
@Watch('character')
async characterChanged(): Promise<void> {
if ((this.character) && (this.character.is_self)) {
if ((this.character) && (this.character.is_self))
return;
}
await this.compareKinks();
}

View File

@ -32,10 +32,15 @@
<script lang="ts">
import { Component, Prop, Watch } from '@f-list/vue-ts';
import Vue from 'vue';
import { MatchReport, MatchResult, Score, Scoring } from './matcher';
import * as _ from 'lodash';
import Vue from 'vue';
import * as Utils from '../utils';
import { MatchReport, MatchResult, Score, Scoring } from './matcher';
export interface CssClassMap {
[key: string]: boolean;
}
@Component
export default class MatchReportView extends Vue {
@ -43,22 +48,19 @@
readonly characterMatch!: MatchReport;
@Prop({required: true})
minimized = false;
readonly minimized = false;
readonly avatarUrl = Utils.avatarURL;
isMinimized = false;
@Watch('isMinimized')
onMinimizedChange(): void {
this.isMinimized = this.minimized;
}
getScoreClass(score: Score) {
const classes: any = {};
getScoreClass(score: Score): CssClassMap {
const classes: CssClassMap = {};
classes[score.getRecommendedClass()] = true;
classes['match-score'] = true;
@ -73,18 +75,15 @@
);
}
shouldShowScore(score: Score) {
shouldShowScore(score: Score): boolean {
return (score.score !== Scoring.NEUTRAL);
}
getScores(result: MatchResult): Score[] {
return _.map(result.scores, (s: Score) => (s));
}
toggleMinimize() {
toggleMinimize(): void {
this.isMinimized = !this.isMinimized;
}
}

View File

@ -133,10 +133,12 @@ enum Species {
const nonAnthroSpecies = [Species.Human, Species.Elf, Species.Orc];
const mammalSpecies = [Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine, Species.Musteline, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate, Species.Elf, Species.Orc, Species.Anthro, Species.Minotaur];
const mammalSpecies = [Species.Equine, Species.Feline, Species.Canine, Species.Vulpine, Species.Cervine, Species.Lapine,
Species.Musteline, Species.Rodent, Species.Ursine, Species.MarineMammal, Species.Primate, Species.Elf, Species.Orc,
Species.Anthro, Species.Minotaur];
interface SpeciesMap {
[key: number]: string[]
[key: number]: string[];
}
interface SpeciesStrMap {
@ -152,7 +154,8 @@ const speciesNames: SpeciesStrMap = {
const speciesMapping: SpeciesMap = {
[Species.Human]: ['human', 'humanoid', 'angel', 'android'],
[Species.Equine]: ['horse', 'stallion', 'mare', 'filly', 'equine', 'shire', 'donkey', 'mule', 'zebra', 'centaur', 'pony' ],
[Species.Feline]: ['cat', 'kitten', 'catgirl', 'neko', 'tiger', 'puma', 'lion', 'lioness', 'tigress', 'feline', 'jaguar', 'cheetah', 'lynx', 'leopard'],
[Species.Feline]: ['cat', 'kitten', 'catgirl', 'neko', 'tiger', 'puma', 'lion', 'lioness',
'tigress', 'feline', 'jaguar', 'cheetah', 'lynx', 'leopard'],
[Species.Canine]: ['dog', 'wolf', 'dingo', 'coyote', 'jackal', 'canine', 'doberman', 'husky'],
[Species.Vulpine]: ['fox', 'fennec', 'kitsune', 'vulpine', 'vixen'],
[Species.Avian]: ['bird', 'gryphon', 'phoenix', 'roc', 'chimera', 'avian'],
@ -292,7 +295,7 @@ export class Matcher {
info: {
species: Matcher.species(this.you),
gender: Matcher.getTagValueList(TagId.Gender, this.you),
orientation: Matcher.getTagValueList(TagId.Orientation, this.you),
orientation: Matcher.getTagValueList(TagId.Orientation, this.you)
}
};
}
@ -311,6 +314,7 @@ export class Matcher {
// Question: If someone identifies themselves as 'straight cuntboy', how should they be matched? like a straight female?
// CIS
// tslint:disable-next-line curly
if (Matcher.isCisGender(yourGender)) {
if (yourGender === theirGender) {
// same sex CIS
@ -359,7 +363,8 @@ export class Matcher {
return new Score(Scoring.NEUTRAL);
}
private formatKinkScore(score: KinkPreference, description: string): Score {
static formatKinkScore(score: KinkPreference, description: string): Score {
if (score === KinkPreference.No)
return new Score(Scoring.MISMATCH, `No <span>${description}</span>`);
@ -388,21 +393,21 @@ export class Matcher {
if (speciesScore !== null) {
const speciesName = speciesNames[theirSpecies] || `${Species[theirSpecies].toLowerCase()}s`;
return this.formatKinkScore(speciesScore, speciesName);
return Matcher.formatKinkScore(speciesScore, speciesName);
}
if (Matcher.isAnthro(them)) {
const anthroScore = Matcher.getKinkPreference(you, Kink.AnthroCharacters);
if (anthroScore !== null)
return this.formatKinkScore(anthroScore, 'anthros');
return Matcher.formatKinkScore(anthroScore, 'anthros');
}
if (Matcher.isMammal(them)) {
const mammalScore = Matcher.getKinkPreference(you, Kink.Mammals);
if (mammalScore !== null)
return this.formatKinkScore(mammalScore, 'mammals');
return Matcher.formatKinkScore(mammalScore, 'mammals');
}
return new Score(Scoring.NEUTRAL);
@ -444,7 +449,12 @@ export class Matcher {
: (theyAreHuman ? Matcher.humanLikeabilityScore(you) : Scoring.NEUTRAL);
if (score === Scoring.WEAK_MATCH)
return new Score(score, theyAreAnthro ? 'Would prefer <span>humans</span>, ok with anthros' : 'Would prefer <span>anthros</span>, ok with humans');
return new Score(
score,
theyAreAnthro
? 'Would prefer <span>humans</span>, ok with anthros'
: 'Would prefer <span>anthros</span>, ok with humans'
);
return this.formatScoring(score, theyAreAnthro ? 'furry pairings' : theyAreHuman ? 'human pairings' : '');
}
@ -506,13 +516,13 @@ export class Matcher {
const underageScore = Matcher.getKinkPreference(you, Kink.UnderageCharacters);
if ((theirAge < 16) && (ageplayScore !== null))
return this.formatKinkScore(ageplayScore, `ages of ${theirAge}`);
return Matcher.formatKinkScore(ageplayScore, `ages of ${theirAge}`);
if ((theirAge < 16) && (ageplayScore === null))
return this.formatKinkScore(KinkPreference.No, `ages of ${theirAge}`);
return Matcher.formatKinkScore(KinkPreference.No, `ages of ${theirAge}`);
if ((theirAge < 18) && (underageScore !== null))
return this.formatKinkScore(underageScore, `ages of ${theirAge}`);
return Matcher.formatKinkScore(underageScore, `ages of ${theirAge}`);
if ((yourAgeTag) && (yourAgeTag.string)) {
const olderCharactersScore = Matcher.getKinkPreference(you, Kink.OlderCharacters);
@ -521,10 +531,10 @@ export class Matcher {
const yourAge = parseInt(yourAgeTag.string, 10);
if ((yourAge < theirAge) && (olderCharactersScore !== null))
return this.formatKinkScore(olderCharactersScore, 'older characters');
return Matcher.formatKinkScore(olderCharactersScore, 'older characters');
if ((yourAge > theirAge) && (youngerCharactersScore !== null))
return this.formatKinkScore(youngerCharactersScore, 'younger characters');
return Matcher.formatKinkScore(youngerCharactersScore, 'younger characters');
}
return new Score(Scoring.NEUTRAL);
@ -543,7 +553,7 @@ export class Matcher {
const genderKinkScore = Matcher.getKinkGenderPreference(you, theirGender);
if (genderKinkScore !== null)
return this.formatKinkScore(genderKinkScore, genderName);
return Matcher.formatKinkScore(genderKinkScore, genderName);
return new Score(Scoring.NEUTRAL);
}
@ -635,20 +645,21 @@ export class Matcher {
const finalSpecies = mySpecies.string.toLowerCase();
_.each(
speciesMapping as any,
(keywords: string[], speciesId: Species) => {
speciesMapping,
(keywords: string[], speciesId: string) => {
_.each(
keywords,
(k: string) => {
if ((k.length > match.length) && (finalSpecies.indexOf(k) >= 0)) {
match = k;
foundSpeciesId = speciesId;
foundSpeciesId = parseInt(speciesId, 10);
}
}
);
}
);
// tslint:disable-next-line: strict-type-predicates
return (foundSpeciesId === null) ? null : parseInt(foundSpeciesId, 10);
}
}

View File

@ -12,10 +12,7 @@
"statements"
],
"comment-format": false,
"curly": [
true,
"as-needed"
],
"curly": false,
"eofline": false,
"linebreak-style": false,
"trailing-comma": [
@ -57,10 +54,7 @@
"await-promise": [true, "AxiosPromise"],
"comment-format": false,
"completed-docs": false,
"curly": [
true,
"as-needed"
],
"curly": false,
"cyclomatic-complexity": false,
"eofline": false,
"file-name-casing": false,
@ -84,6 +78,7 @@
"no-angle-bracket-type-assertion": false,
"no-bitwise": false,
"no-conditional-assignment": false,
"no-consecutive-blank-lines": [true, 2],
"no-console": false,
"no-default-export": false,
"no-default-import": false,
@ -99,6 +94,7 @@
"no-magic-numbers": false,
"no-namespace": false,
"no-non-null-assertion": false,
"no-null-keyword": false,
"no-parameter-properties": false,
"no-parameter-reassignment": false,
"no-string-literal": false,
@ -119,6 +115,7 @@
true,
"allow-declarations"
],
"ordered-imports": false,
"prefer-function-over-method": [
true,
"allow-public"
@ -138,8 +135,9 @@
true,
"never"
],
"strict-boolean-expressions": [true, "allow-boolean-or-undefined"],
"strict-boolean-expressions": false,
"switch-default": false,
"switch-final-break": false,
"trailing-comma": [
true,
{