Image preview toolbar and sticky mode
This commit is contained in:
parent
49e58b27c7
commit
093ab4e7eb
|
@ -10,6 +10,7 @@
|
|||
@mouseenter="show()"
|
||||
@mouseleave="dismiss()"
|
||||
@mouseout="dismiss()"
|
||||
@click.middle.prevent="toggleStickyness()"
|
||||
>{{text}}</a>
|
||||
<span
|
||||
class="link-domain bbcode-pseudo"
|
||||
|
@ -51,5 +52,10 @@
|
|||
show(): void {
|
||||
EventBus.$emit('imagepreview-show', {url: this.url});
|
||||
}
|
||||
|
||||
|
||||
toggleStickyness(): void {
|
||||
EventBus.$emit('imagepreview-toggle-stickyness', {url: this.url});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
<template>
|
||||
<!-- hiding elements instead of using 'v-if' is used here as an optimization -->
|
||||
<div class="image-preview-wrapper" :style="{display: visible ? 'block' : 'none'}">
|
||||
<div class="image-preview-wrapper" :class="{visible: visible, interactive: sticky}">
|
||||
<div class="image-preview-toolbar" v-if="sticky || debug">
|
||||
<a @click="toggleDevMode()" :class="{toggled: debug}" title="Debug Mode"><i class="fa fa-terminal"></i></a>
|
||||
<a @click="toggleJsMode()" :class="{toggled: runJs}" title="Expand Images"><i class="fa fa-magic"></i></a>
|
||||
<a @click="reloadUrl()" title="Reload Image"><i class="fa fa-redo-alt"></i></a>
|
||||
<a @click="toggleStickyMode()" :class="{toggled: sticky}" title="Toggle Stickyness"><i class="fa fa-thumbtack"></i></a>
|
||||
</div>
|
||||
|
||||
<webview webpreferences="allowRunningInsecureContent, autoplayPolicy=no-user-gesture-required" id="image-preview-ext" ref="imagePreviewExt" class="image-preview-external" :src="externalUrl" :style="{display: externalUrlVisible ? 'flex' : 'none'}"></webview>
|
||||
<div
|
||||
class="image-preview-local"
|
||||
|
@ -43,7 +50,9 @@
|
|||
private shouldDismiss = false;
|
||||
private visibleSince = 0;
|
||||
|
||||
private debug = false;
|
||||
sticky = false;
|
||||
runJs = true;
|
||||
debug = false;
|
||||
|
||||
|
||||
@Hook('mounted')
|
||||
|
@ -52,6 +61,7 @@
|
|||
'imagepreview-dismiss',
|
||||
(eventData: any) => {
|
||||
// console.log('Event dismiss', eventData.url);
|
||||
|
||||
this.dismiss(eventData.url);
|
||||
}
|
||||
);
|
||||
|
@ -60,31 +70,74 @@
|
|||
'imagepreview-show',
|
||||
(eventData: any) => {
|
||||
// console.log('Event show', eventData.url);
|
||||
|
||||
this.show(eventData.url);
|
||||
}
|
||||
);
|
||||
|
||||
EventBus.$on(
|
||||
'imagepreview-toggle-stickyness',
|
||||
(eventData: any) => {
|
||||
if ((this.url === eventData.url) && (this.visible))
|
||||
this.sticky = !this.sticky;
|
||||
}
|
||||
);
|
||||
|
||||
const webview = this.$refs.imagePreviewExt as any;
|
||||
|
||||
webview.addEventListener(
|
||||
'dom-ready',
|
||||
() => {
|
||||
if (this.debug)
|
||||
webview.openDevTools();
|
||||
|
||||
(event: any) => {
|
||||
const url = webview.getURL();
|
||||
|
||||
const js = this.jsMutator.getMutatorJsForSite(url);
|
||||
|
||||
if (js) {
|
||||
if (this.debug) {
|
||||
console.log('ImagePreview dom-ready', event, js);
|
||||
// webview.openDevTools();
|
||||
}
|
||||
|
||||
if ((js) && (this.runJs))
|
||||
webview.executeJavaScript(js);
|
||||
}
|
||||
);
|
||||
|
||||
webview.addEventListener(
|
||||
'did-fail-load',
|
||||
(event: any) => {
|
||||
const js = this.jsMutator.getErrorMutator(event.errorCode, event.errorDescription);
|
||||
|
||||
if (this.debug) {
|
||||
console.log('ImagePreview did-fail-load', event, js);
|
||||
}
|
||||
|
||||
if ((js) && (this.runJs) && (event.errorCode >= 400))
|
||||
webview.executeJavaScript(js);
|
||||
}
|
||||
);
|
||||
|
||||
webview.addEventListener(
|
||||
'did-navigate',
|
||||
(event: any) => {
|
||||
if (event.httpResponseCode >= 400) {
|
||||
const js = this.jsMutator.getErrorMutator(event.httpResponseCode, event.httpStatusText);
|
||||
|
||||
if (this.debug) {
|
||||
console.log('ImagePreview did-navigate', event, js);
|
||||
}
|
||||
|
||||
if ((js) && (this.runJs))
|
||||
webview.executeJavaScript(js);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
webview.getWebContents().on(
|
||||
// webview.getWebContents().on(
|
||||
webview.addEventListener(
|
||||
'did-finish-load',
|
||||
()=> {
|
||||
(event: any)=> {
|
||||
if (this.debug)
|
||||
console.log('ImagePreview did-finish-load', event);
|
||||
|
||||
webview.getWebContents().session.on(
|
||||
'will-download',
|
||||
(e: any) => {
|
||||
|
@ -94,6 +147,7 @@
|
|||
}
|
||||
);
|
||||
|
||||
|
||||
setInterval(
|
||||
() => {
|
||||
if (((this.visible) && (!this.exitInterval) && (!this.shouldDismiss)) || (this.interval))
|
||||
|
@ -107,7 +161,7 @@
|
|||
}
|
||||
|
||||
|
||||
private hide(): void {
|
||||
hide(): void {
|
||||
this.cancelExitTimer();
|
||||
|
||||
this.url = null;
|
||||
|
@ -123,6 +177,8 @@
|
|||
this.exitInterval = null;
|
||||
|
||||
this.shouldDismiss = false;
|
||||
|
||||
this.sticky = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -130,7 +186,10 @@
|
|||
if (this.url !== url)
|
||||
return; // simply ignore
|
||||
|
||||
if (this.debug)
|
||||
// if (this.debug)
|
||||
// return;
|
||||
|
||||
if (this.sticky)
|
||||
return;
|
||||
|
||||
// console.log('DISMISS');
|
||||
|
@ -167,6 +226,9 @@
|
|||
if ((this.url === url) && ((this.visible) || (this.interval)))
|
||||
return;
|
||||
|
||||
if ((this.url) && (this.sticky) && (this.visible))
|
||||
return;
|
||||
|
||||
const due = ((url === this.exitUrl) && (this.exitInterval)) ? 0 : 100;
|
||||
|
||||
this.url = url;
|
||||
|
@ -235,6 +297,7 @@
|
|||
}
|
||||
|
||||
isExternalUrl(): boolean {
|
||||
// 'f-list.net' is tested here on purpose, because keeps the character URLs from being previewed
|
||||
return !((this.domain === 'f-list.net') || (this.domain === 'static.f-list.net'));
|
||||
}
|
||||
|
||||
|
@ -242,6 +305,39 @@
|
|||
isInternalUrl(): boolean {
|
||||
return !this.isExternalUrl();
|
||||
}
|
||||
|
||||
|
||||
toggleDevMode(): void {
|
||||
this.debug = !this.debug;
|
||||
|
||||
if (this.debug) {
|
||||
const webview = this.$refs.imagePreviewExt as any;
|
||||
|
||||
webview.openDevTools();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
toggleStickyMode(): void {
|
||||
this.sticky = !this.sticky;
|
||||
|
||||
if (!this.sticky)
|
||||
this.hide();
|
||||
}
|
||||
|
||||
|
||||
toggleJsMode(): void {
|
||||
this.runJs = !this.runJs;
|
||||
}
|
||||
|
||||
|
||||
reloadUrl(): void {
|
||||
if (this.externalUrlVisible) {
|
||||
const webview = this.$refs.imagePreviewExt as any;
|
||||
|
||||
webview.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -251,30 +347,99 @@
|
|||
@import "~bootstrap/scss/variables";
|
||||
@import "~bootstrap/scss/mixins/breakpoints";
|
||||
|
||||
.image-preview-external {
|
||||
position: absolute;
|
||||
width: 50%;
|
||||
height: 70%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.image-preview-local {
|
||||
position: absolute;
|
||||
width: 50%;
|
||||
height: 70%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
background-size: contain;
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
// background-color: black;
|
||||
}
|
||||
|
||||
.image-preview-wrapper {
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 50%;
|
||||
height: 70%;
|
||||
pointer-events: none;
|
||||
|
||||
&.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.interactive {
|
||||
pointer-events: auto;
|
||||
|
||||
.image-preview-local,
|
||||
.image-preview-auto {
|
||||
// pointer-events: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.image-preview-external {
|
||||
/* position: absolute;
|
||||
width: 50%;
|
||||
height: 70%;
|
||||
top: 0;
|
||||
left: 0; */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// pointer-events: none;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.image-preview-local {
|
||||
/* position: absolute;
|
||||
width: 50%;
|
||||
height: 70%;
|
||||
top: 0;
|
||||
left: 0; */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
// pointer-events: none;
|
||||
background-size: contain;
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
// background-color: black;
|
||||
}
|
||||
|
||||
|
||||
.image-preview-toolbar {
|
||||
position: absolute;
|
||||
/* background-color: green; */
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin: 1rem;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
flex-direction: row;
|
||||
width: 15rem;
|
||||
flex-wrap: nowrap;
|
||||
background-color: rgba(77, 76, 116, 0.92);
|
||||
border-radius: 3px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
padding: 0.5rem;
|
||||
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.2);
|
||||
|
||||
a i.fa {
|
||||
font-size: 1.25rem;
|
||||
top: 50%;
|
||||
position: relative;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
a {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 3px;
|
||||
margin-right: 0.5rem;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
a:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.toggled {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 0 1px 0px rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,36 +1,77 @@
|
|||
/* tslint:disable:quotemark */
|
||||
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { domain } from '../bbcode/core';
|
||||
|
||||
export interface PreviewMutator {
|
||||
match: string|RegExp;
|
||||
injectJs: string;
|
||||
}
|
||||
|
||||
export interface ImagePreviewMutatorCollection {
|
||||
[key: string]: string;
|
||||
[key: string]: PreviewMutator;
|
||||
}
|
||||
|
||||
export class ImagePreviewMutator {
|
||||
private mutators: ImagePreviewMutatorCollection = {};
|
||||
private hostMutators: ImagePreviewMutatorCollection = {};
|
||||
private regexMutators: PreviewMutator[] = [];
|
||||
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
getMutatorJsForSite(url: string): string | undefined {
|
||||
let mutator = this.matchMutator(url);
|
||||
|
||||
if (!mutator)
|
||||
mutator = this.hostMutators['default'];
|
||||
|
||||
return this.wrapJs(mutator.injectJs);
|
||||
}
|
||||
|
||||
|
||||
matchMutator(url: string): PreviewMutator | undefined {
|
||||
const urlDomain = domain(url);
|
||||
|
||||
if (!urlDomain)
|
||||
return;
|
||||
|
||||
// console.log('Domain is', urlDomain);
|
||||
if (urlDomain in this.hostMutators)
|
||||
return this.hostMutators[urlDomain];
|
||||
|
||||
let mutatorJs = this.mutators[urlDomain];
|
||||
return _.find(
|
||||
this.regexMutators,
|
||||
(m: PreviewMutator) => {
|
||||
const match = m.match;
|
||||
|
||||
if (!mutatorJs)
|
||||
mutatorJs = this.mutators['default'];
|
||||
|
||||
return `(() => { try { ${mutatorJs} } catch (err) { console.error(err); } })()`;
|
||||
return (match instanceof RegExp) ? (urlDomain.match(match) !== null) : (match === urlDomain);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
protected add(domain: string, mutatorJs: string) {
|
||||
this.mutators[domain] = mutatorJs;
|
||||
|
||||
protected wrapJs(mutatorJs: string) {
|
||||
return `(() => { try { ${mutatorJs} } catch (err) { console.error('Mutator error', err); } })();`;
|
||||
}
|
||||
|
||||
|
||||
protected add(domain: string|RegExp, mutatorJs: string) {
|
||||
if (domain instanceof RegExp) {
|
||||
this.regexMutators.push(
|
||||
{
|
||||
match: domain,
|
||||
injectJs: mutatorJs
|
||||
}
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.hostMutators[domain] = {
|
||||
match: domain,
|
||||
injectJs: mutatorJs
|
||||
};
|
||||
}
|
||||
|
||||
protected init() {
|
||||
|
@ -42,16 +83,19 @@ export class ImagePreviewMutator {
|
|||
this.add('danbooru.donmai.us', this.getBaseJsMutatorScript('#image, video'));
|
||||
this.add('gfycat.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('gfycatporn.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('www.youtube.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('youtube.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('instantfap.com', this.getBaseJsMutatorScript('#post img, #post video'));
|
||||
this.add('www.webmshare.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('webmshare.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('pornhub.com', this.getBaseJsMutatorScript('.mainPlayerDiv video, .photoImageSection img'));
|
||||
this.add('www.sex.com', this.getBaseJsMutatorScript('.image_frame img, .image_frame video'));
|
||||
this.add('sex.com', this.getBaseJsMutatorScript('.image_frame img, .image_frame video'));
|
||||
this.add('redirect.media.tumblr.com', this.getBaseJsMutatorScript('picture img, picture video'));
|
||||
this.add('i.imgur.com', this.getBaseJsMutatorScript('video, img'));
|
||||
this.add('postimg.cc', this.getBaseJsMutatorScript('#main-image, video'));
|
||||
this.add('gifsauce.com', this.getBaseJsMutatorScript('video'));
|
||||
this.add('motherless.com', this.getBaseJsMutatorScript('.content video, .content img'));
|
||||
// this.add('beeg.com', this.getBaseJsMutatorScript('video'));
|
||||
|
||||
this.add(/^media[0-9]\.giphy\.com$/, this.getBaseJsMutatorScript('video, img[alt]'));
|
||||
|
||||
this.add(
|
||||
'imgur.com',
|
||||
|
@ -65,7 +109,6 @@ export class ImagePreviewMutator {
|
|||
`
|
||||
);
|
||||
|
||||
|
||||
this.add(
|
||||
'rule34.xxx',
|
||||
`${this.getBaseJsMutatorScript('#image, video')}
|
||||
|
@ -75,49 +118,108 @@ export class ImagePreviewMutator {
|
|||
);
|
||||
}
|
||||
|
||||
getBaseJsMutatorScript(imageSelector: string, skipElementRemove = false): string {
|
||||
getBaseJsMutatorScript(imageSelector: 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()
|
||||
|
||||
if (!img) { return; }
|
||||
|
||||
const el = document.createElement('div');
|
||||
el.id = 'flistWrapper';
|
||||
|
||||
el.style = 'width: 100% !important; height: 100% !important; position: absolute !important;'
|
||||
+ 'top: 0 !important; left: 0 !important; z-index: 100000 !important;'
|
||||
+ 'background-color: black !important; background-size: contain !important;'
|
||||
+ 'background-repeat: no-repeat !important; background-position: top left !important;'
|
||||
+ 'opacity: 1 !important; padding: 0 !important; border: 0 !important; margin: 0 !important;';
|
||||
|
||||
img.remove();
|
||||
el.append(img);
|
||||
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;';
|
||||
|
||||
img.style = 'object-position: top left !important; object-fit: contain !important;'
|
||||
+ 'width: 100% !important; height: 100% !important; opacity: 1 !important;'
|
||||
+ 'margin: 0 !imporant; border: 0 !important; padding: 0 !important;';
|
||||
|
||||
img.class = '';
|
||||
el.class = '';
|
||||
|
||||
if (img.play) { img.muted = true; img.play(); }
|
||||
|
||||
|
||||
let removeList = [];
|
||||
body.childNodes.forEach((el) => { if(el.id !== 'flistWrapper') { removeList.push(el); } });
|
||||
${skipElementRemove ? '' : 'removeList.forEach((el) => el.remove());'}
|
||||
removeList = [];
|
||||
const img = Array.from(document.querySelectorAll('${imageSelector}'))
|
||||
.filter((i) => ((i.width !== 1) && (i.height !== 1))).shift()
|
||||
|
||||
if (!img) { return; }
|
||||
|
||||
const el = document.createElement('div');
|
||||
el.id = 'flistWrapper';
|
||||
|
||||
el.style = 'width: 100% !important; height: 100% !important; position: absolute !important;'
|
||||
+ 'top: 0 !important; left: 0 !important; z-index: 100000 !important;'
|
||||
+ 'background-color: black !important; background-size: contain !important;'
|
||||
+ 'background-repeat: no-repeat !important; background-position: top left !important;'
|
||||
+ 'opacity: 1 !important; padding: 0 !important; border: 0 !important; margin: 0 !important;';
|
||||
|
||||
img.remove();
|
||||
el.append(img);
|
||||
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;';
|
||||
|
||||
img.style = 'object-position: top left !important; object-fit: contain !important;'
|
||||
+ 'width: 100% !important; height: 100% !important; opacity: 1 !important;'
|
||||
+ 'margin: 0 !imporant; border: 0 !important; padding: 0 !important;';
|
||||
|
||||
img.class = '';
|
||||
el.class = '';
|
||||
|
||||
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());'}
|
||||
removeList = [];
|
||||
`;
|
||||
}
|
||||
|
||||
getErrorMutator(code: number, description: string): string {
|
||||
const errorHtml = `
|
||||
<div id="flistError" 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: 200000 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
line-height: 100% !important;
|
||||
border: 0 !important;
|
||||
opacity: 1 !important;
|
||||
text-align: center !important;
|
||||
"><h1 style="
|
||||
color: #FF4444 !important;
|
||||
font-size: 45pt !important;
|
||||
margin: 0 !important;
|
||||
margin-top: 10pt !important;
|
||||
line-height: 100% !important;
|
||||
padding: 0 !important;
|
||||
border: 0 !important;
|
||||
background: none !important;
|
||||
font-family: Helvetica, Arial, sans-serif !important;
|
||||
font-weight: bold !important;
|
||||
">${code}</h1><p style="
|
||||
max-width: 400px !important;
|
||||
color: #ededed !important;
|
||||
display: inline-block !important;
|
||||
font-size: 15pt !important;
|
||||
font-family: Helvetica, Arial, sans-serif !important;
|
||||
font-weight: 300 !important;
|
||||
border: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
margin-top: 5pt !important;
|
||||
line-height: 130% !important;
|
||||
">${description}</p></div>
|
||||
`;
|
||||
|
||||
return this.wrapJs(`
|
||||
const range = document.createRange();
|
||||
|
||||
range.selectNode(document.body);
|
||||
|
||||
const error = range.createContextualFragment(\`${errorHtml}\`);
|
||||
|
||||
document.body.appendChild(error);
|
||||
`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
|
|||
* Rotate multiple ads on a single channel
|
||||
* Link previews
|
||||
* Hover cursor over any `[url]` to see a preview of it
|
||||
* Middle click any `[url]` to turn the preview into a sticky / interactive mode
|
||||
* Profile
|
||||
* Kinks are auto-compared when profile is loaded
|
||||
* Custom kink explanations can be expanded inline
|
||||
|
@ -23,6 +24,9 @@ This repository contains a modified version of the mainline F-Chat 3.0 client.
|
|||
* Cleaner guestbook view
|
||||
|
||||
|
||||
## Todo / Ideas
|
||||
* Preview mode should allow detaching from the main window
|
||||
|
||||
|
||||
# F-List Exported
|
||||
This repository contains the open source parts of F-list and F-Chat 3.0.
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane" :class="{active: tab === '0'}" id="overview">
|
||||
<match-report :characterMatch="characterMatch"></match-report>
|
||||
<match-report :characterMatch="characterMatch" :minimized="character.is_self"></match-report>
|
||||
<div v-bbcode="character.character.description" style="margin-bottom: 10px"></div>
|
||||
<character-kinks :character="character" :oldApi="oldApi" ref="tab0"></character-kinks>
|
||||
</div>
|
||||
|
@ -198,8 +198,6 @@
|
|||
|
||||
const guestbookState = await methods.guestbookPageGet(this.character.character.id, 1, false);
|
||||
|
||||
console.log('GUESTBOOK', guestbookState.posts);
|
||||
|
||||
this.guestbookPostCount = `${guestbookState.posts.length}${guestbookState.nextPage ? '+' : ''}`;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
@ -227,7 +225,10 @@
|
|||
|
||||
async countFriends() {
|
||||
try {
|
||||
if (!this.character) {
|
||||
if (
|
||||
(!this.character)
|
||||
|| (!this.character.is_self) && (!this.character.settings.show_friends)
|
||||
) {
|
||||
this.friendCount = null;
|
||||
return;
|
||||
}
|
||||
|
@ -274,12 +275,14 @@
|
|||
standardParser.allowInlines = true;
|
||||
standardParser.inlines = this.character.character.inlines;
|
||||
|
||||
console.log('LoadChar', this.name, this.character);
|
||||
|
||||
this.updateMatches();
|
||||
|
||||
// no awaits on these on purpose
|
||||
this.countGuestbookPosts();
|
||||
this.countGroups();
|
||||
this.countFriends();
|
||||
|
||||
this.updateMatches();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -143,11 +143,19 @@
|
|||
|
||||
@Hook('mounted')
|
||||
async mounted(): Promise<void> {
|
||||
if ((this.character) && (this.character.is_self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.compareKinks();
|
||||
}
|
||||
|
||||
@Watch('character')
|
||||
async characterChanged(): Promise<void> {
|
||||
if ((this.character) && (this.character.is_self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.compareKinks();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div id="match-report" :class="{'match-report': true, minimized: minimized}" v-if="(haveScores(characterMatch.you) || haveScores(characterMatch.them))">
|
||||
<a class="minimize-btn" @click="toggleMinimize()"><i :class="{fa: true, 'fa-plus': minimized, 'fa-minus': !minimized}"></i></a>
|
||||
<div id="match-report" :class="{'match-report': true, minimized: isMinimized}" v-if="(haveScores(characterMatch.you) || haveScores(characterMatch.them))">
|
||||
<a class="minimize-btn" @click="toggleMinimize()"><i :class="{fa: true, 'fa-plus': isMinimized, 'fa-minus': !isMinimized}"></i></a>
|
||||
|
||||
<div class="scores you">
|
||||
<h3>
|
||||
|
@ -31,7 +31,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop } from '@f-list/vue-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';
|
||||
|
@ -42,9 +42,20 @@
|
|||
@Prop({required: true})
|
||||
readonly characterMatch!: MatchReport;
|
||||
|
||||
@Prop({required: true})
|
||||
minimized = false;
|
||||
|
||||
readonly avatarUrl = Utils.avatarURL;
|
||||
|
||||
minimized = false;
|
||||
isMinimized = false;
|
||||
|
||||
|
||||
|
||||
@Watch('isMinimized')
|
||||
onMinimizedChange(): void {
|
||||
this.isMinimized = this.minimized;
|
||||
}
|
||||
|
||||
|
||||
getScoreClass(score: Score) {
|
||||
const classes: any = {};
|
||||
|
@ -74,7 +85,7 @@
|
|||
|
||||
|
||||
toggleMinimize() {
|
||||
this.minimized = !this.minimized;
|
||||
this.isMinimized = !this.isMinimized;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue