ultrawidify/src/csui/Popup.vue

613 lines
16 KiB
Vue
Raw Normal View History

<template>
2025-04-26 23:27:09 +02:00
<div class="popup-panel" style="height: 100vh">
2024-05-04 01:04:23 +02:00
<!--
NOTE the code that makes ultrawidify popup work in firefox regardless of whether the
extension is being displayed in a normal or a small/overflow popup breaks the popup
behaviour on Chrome (where the popup would never reach the full width of 800px)
Since I'm tired and the hour is getting late, we'll just add an extra CSS class for
non-firefox builds of this extension and be done with it. No need to complicate things
further than that.
-->
<div v-if="settingsInitialized"
2025-04-26 23:27:09 +02:00
style="height: 100vh"
class="popup flex flex-col no-overflow"
2024-05-04 01:04:23 +02:00
:class="{'popup-chrome': ! BrowserDetect?.firefox}"
>
<div class="flex flex-col w-full relative header"
2024-05-04 01:04:23 +02:00
>
<div class="flex flex-row w-full" style="height: 42px">
<h1 class="flex-grow">
<span class="smallcaps">Ultrawidify</span>: <small>Quick settings</small>
</h1>
<button
class="settings-header-button"
style="align-self: stretch"
@click="showInPlayerUi()"
>
Show settings window
</button>
</div>
<div class="flex flex-row w-full">
<div v-if="site && siteSettings" style="transform: scale(0.75) translateX(-12.5%); margin-bottom: -0.5rem; align-content: center" class="flex flex-row flex-grow items-center">
2025-01-26 22:09:32 +01:00
<div>site: {{site.host}}</div>
<SupportLevelIndicator
:siteSupportLevel="siteSupportLevel"
>
</SupportLevelIndicator>
</div>
<!-- Version info -->
<div v-if="BrowserDetect?.processEnvChannel !== 'stable'" class="absolute channel-info version-info">
<label>Version:</label> <br/>
{{ settings.getExtensionVersion() }} (non-stable)
</div>
<div v-else class="version-info">
<label>Version:</label> <br/>
{{ settings.getExtensionVersion() }}
</div>
2024-05-04 01:04:23 +02:00
</div>
</div>
2023-09-11 00:43:26 +02:00
2024-05-04 01:04:23 +02:00
<!-- CONTAINER ROOT -->
<div class="flex flex-row body no-overflow flex-grow">
<!-- TABS -->
<div class="flex flex-col tab-row" style="flex: 3 3; border-right: 1px solid #222;">
<div
v-for="tab of tabs"
:key="tab.id"
class="tab flex flex-row"
2025-01-30 02:40:04 +01:00
:class="{
'active': tab.id === selectedTab,
'highlight-tab': tab.highlight,
}"
2024-05-04 01:04:23 +02:00
@click="selectTab(tab.id)"
>
<div class="icon-container">
<mdicon
:name="tab.icon"
:size="32"
/>
</div>
<div class="label">
{{tab.label}}
</div>
2023-09-11 00:43:26 +02:00
</div>
</div>
2024-05-04 01:04:23 +02:00
<!-- CONTENT -->
2025-04-26 23:27:09 +02:00
<div class="scrollable window-content" style="flex: 7 7; padding: 1rem;">
2024-05-04 01:04:23 +02:00
<template v-if="settings && siteSettings">
<PopupVideoSettings
v-if="selectedTab === 'videoSettings'"
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
></PopupVideoSettings>
<BaseExtensionSettings
v-if="selectedTab === 'extensionSettings'"
:settings="settings"
:eventBus="eventBus"
:siteSettings="siteSettings"
:site="site.host"
>
</BaseExtensionSettings>
2025-01-30 02:40:04 +01:00
<ChangelogPanel
v-if="selectedTab === 'changelog'"
:settings="settings"
></ChangelogPanel>
2025-01-13 01:31:59 +01:00
<AboutPanel
v-if="selectedTab === 'about'"
>
</AboutPanel>
2024-05-04 01:04:23 +02:00
</template>
<template v-else>No settings or site settings found.</template>
2024-05-04 01:04:23 +02:00
</div>
2024-05-04 01:04:23 +02:00
</div>
</div>
</div>
</template>
<script>
2023-09-11 00:43:26 +02:00
import BaseExtensionSettings from './src/PlayerUiPanels/BaseExtensionSettings.vue'
import PlayerDetectionPanel from './src/PlayerUiPanels/PlayerDetectionPanel.vue'
2025-01-30 02:40:04 +01:00
import ChangelogPanel from './src/PlayerUiPanels/ChangelogPanel.vue'
import PopupVideoSettings from './src/popup/panels/PopupVideoSettings.vue'
2025-01-13 01:31:59 +01:00
import AboutPanel from '@csui/src/popup/panels/AboutPanel.vue'
import Debug from '../ext/conf/Debug';
import BrowserDetect from '../ext/conf/BrowserDetect';
import Comms from '../ext/lib/comms/Comms';
import CommsClient, {CommsOrigin} from '../ext/lib/comms/CommsClient';
import Settings from '../ext/lib/Settings';
import Logger from '../ext/lib/Logger';
import EventBus from '../ext/lib/EventBus';
import {ChromeShittinessMitigations as CSM} from '../common/js/ChromeShittinessMitigations';
2025-01-26 22:09:32 +01:00
import SupportLevelIndicator from '@csui/src/components/SupportLevelIndicator.vue'
export default {
2025-01-13 01:31:59 +01:00
components: {
Debug,
BrowserDetect,
PopupVideoSettings,
PlayerDetectionPanel,
BaseExtensionSettings,
2025-01-26 22:09:32 +01:00
SupportLevelIndicator,
2025-01-30 02:40:04 +01:00
ChangelogPanel,
2025-01-13 01:31:59 +01:00
AboutPanel
},
data () {
return {
comms: undefined,
eventBus: new EventBus(),
settings: {},
settingsInitialized: false,
narrowPopup: null,
sideMenuVisible: null,
2022-07-26 23:54:25 +02:00
logger: undefined,
site: undefined,
siteSettings: undefined,
selectedTab: 'videoSettings',
2023-09-11 00:43:26 +02:00
tabs: [
// see this for icons: https://pictogrammers.com/library/mdi/
// {id: 'playerUiCtl', label: 'In-player UI', icon: 'artboard'},
2023-09-11 00:43:26 +02:00
{id: 'videoSettings', label: 'Video settings', icon: 'crop'},
2024-05-04 01:04:23 +02:00
// {id: 'playerDetection', label: 'Player detection', icon: 'television-play'},
2023-09-11 00:43:26 +02:00
{id: 'extensionSettings', label: 'Site and Extension options', icon: 'cogs' },
2025-01-30 02:40:04 +01:00
{id: 'changelog', label: 'What\'s new', icon: 'alert-decagram' },
2025-01-13 01:31:59 +01:00
{id: 'about', label: 'About', icon: 'information-outline'},
2023-09-11 00:43:26 +02:00
],
}
},
2025-01-26 22:09:32 +01:00
computed: {
siteSupportLevel() {
return (this.site && this.siteSettings) ? this.siteSettings.data.type || 'no-support' : 'waiting';
}
},
2025-01-30 02:40:04 +01:00
mounted() {
this.tabs.find(x => x.id === 'changelog').highlight = !this.settings.active?.whatsNewChecked;
2025-01-30 02:40:04 +01:00
},
async created() {
2020-01-28 01:26:40 +01:00
this.logger = new Logger();
await this.logger.init({
2020-01-16 01:00:12 +01:00
allowLogging: true,
2019-09-17 22:18:02 +02:00
});
this.settings = new Settings({afterSettingsSaved: () => this.updateConfig(), logger: this.logger});
2019-02-13 23:58:19 +01:00
await this.settings.init();
this.settingsInitialized = true;
// const port = chrome.runtime.connect({name: 'popup-port'});
// port.onMessage.addListener( (m,p) => this.processReceivedMessage(m,p));
// CSM.setProperty('port', port);
this.eventBus = new EventBus();
this.eventBus.subscribe(
'set-current-site',
{
source: this,
function: (config, context) => {
if (this.site) {
if (!this.site.host) {
// dunno why this fix is needed, but sometimes it is
this.site.host = config.site.host;
}
}
this.site = config.site;
2023-09-11 00:43:26 +02:00
// this.selectedSite = this.selectedSite || config.site.host;
this.siteSettings = this.settings.getSiteSettings(this.site.host);
this.eventBus.setupPopupTunnelWorkaround({
origin: CommsOrigin.Popup,
comms: {
forwardTo: 'active'
}
});
this.loadFrames(this.site);
}
},
);
this.comms = new CommsClient('popup-port', this.logger, this.eventBus);
this.eventBus.setComms(this.comms);
this.eventBus.setupPopupTunnelWorkaround({
origin: CommsOrigin.Popup,
comms: {forwardTo: 'active'}
});
2020-12-21 19:29:52 +01:00
2019-01-18 00:26:15 +01:00
// ensure we'll clean player markings on popup close
window.addEventListener("unload", () => {
2020-12-21 19:29:52 +01:00
CSM.port.postMessage({
2019-01-18 00:26:15 +01:00
cmd: 'unmark-player',
2019-04-13 03:09:29 +02:00
forwardToAll: true,
2019-01-18 00:26:15 +01:00
});
2023-07-10 22:00:53 +02:00
// if (BrowserDetect.anyChromium) {
// chrome.extension.getBackgroundPage().sendUnmarkPlayer({
// cmd: 'unmark-player',
// forwardToAll: true,
// });
// }
2019-01-18 00:26:15 +01:00
});
2019-04-13 03:09:29 +02:00
// get info about current site from background script
while (true) {
2022-09-20 01:38:08 +02:00
this.requestSite();
2019-04-13 03:09:29 +02:00
await this.sleep(5000);
2021-07-05 00:49:35 +02:00
}
},
async updated() {
const body = document.getElementsByTagName('body')[0];
// ensure that narrowPopup only gets set the first time the popup renders
// if popup was rendered before, we don't do anything because otherwise
// we'll be causing an unwanted re-render
2021-07-05 00:49:35 +02:00
//
2020-12-04 00:53:51 +01:00
// another thing worth noting — the popup gets first initialized with
// offsetWidth set to 0. This means proper popup will be displayed as a
// mini popup if we don't check for that.
if (this.narrowPopup === null && body.offsetWidth > 0) {
this.narrowPopup = body.offsetWidth < 600;
}
},
2025-01-13 01:31:59 +01:00
2019-01-03 02:07:16 +01:00
methods: {
showInPlayerUi() {
this.eventBus.send('uw-set-ui-state', {globalUiVisible: true}, {comms: {forwardTo: 'active'}});
},
2019-01-18 00:26:15 +01:00
async sleep(t) {
return new Promise( (resolve,reject) => {
2019-01-18 00:26:15 +01:00
setTimeout(() => resolve(), t);
});
},
toObject(obj) {
return JSON.parse(JSON.stringify(obj));
},
requestSite() {
2019-01-18 00:26:15 +01:00
try {
this.logger.log('info','popup', '[popup::getSite] Requesting current site ...')
// CSM.port.postMessage({command: 'get-current-site'});
this.eventBus.send(
'get-current-site',
{
comms: {forwardTo: 'active'}
}
);
2019-01-18 00:26:15 +01:00
} catch (e) {
this.logger.log('error','popup','[popup::getSite] sending get-current-site failed for some reason. Reason:', e);
2019-01-18 00:26:15 +01:00
}
},
getRandomColor() {
return `rgb(${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)})`;
},
2023-09-11 00:43:26 +02:00
selectTab(tab) {
this.selectedTab = tab;
},
2019-01-03 02:07:16 +01:00
processReceivedMessage(message, port) {
this.logger.log('info', 'popup', '[popup::processReceivedMessage] received message:', message)
2019-01-03 02:07:16 +01:00
if (message.command === 'set-current-site'){
2019-01-03 02:07:16 +01:00
if (this.site) {
if (!this.site.host) {
2019-01-03 02:07:16 +01:00
// dunno why this fix is needed, but sometimes it is
this.site.host = site.tabHostname;
2019-01-03 02:07:16 +01:00
}
}
this.site = message.site;
// update activeSites
// this.activeSites = this.activeSites.filter(x => x.host !== message.site);
// add current site
// this.activeSites = unshift({
// host: message.site.host,
// isIFrame: false, // currently unused
// });
this.selectedSite = this.selectedSite || message.site.host;
2019-01-18 00:26:15 +01:00
this.loadFrames(this.site);
}
2019-05-09 21:10:26 +02:00
2019-08-25 01:52:04 +02:00
return true;
},
isDefaultFrame(frameId) {
return frameId === '__playing' || frameId === '__all';
2019-01-18 00:26:15 +01:00
},
2022-07-26 23:54:25 +02:00
loadFrames() {
this.activeSites = [{
host: this.site.host,
isIFrame: false, // not used tho. Maybe one day
}];
this.selectedSite = this.selectedSite || this.site.host;
2022-07-26 23:54:25 +02:00
// for (const frame in videoTab.frames) {
// this.activeFrames.push({
// id: `${this.site.id}-${frame}`,
// label: videoTab.frames[frame].host,
// ...this.frameStore[frame],
// })
// // only add each host once at most
// if (!this.activeSites.find(x => x.host === videoTab.frames[frame].host)) {
// this.activeSites.push({
// host: videoTab.frames[frame].host,
// isIFrame: undefined // maybe one day
// });
// }
// }
// update whether video tab can be shown
2023-09-11 00:43:26 +02:00
// this.updateCanShowVideoTab();
2019-01-03 02:07:16 +01:00
},
getRandomColor() {
2019-01-03 02:07:16 +01:00
return `rgb(${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)}, ${Math.floor(Math.random() * 128)})`;
},
updateConfig() {
this.settings.init();
this.$nextTick( () => this.$forceUpdate());
2019-01-03 02:07:16 +01:00
}
}
}
</script>
<style lang="scss">
2024-05-04 01:04:23 +02:00
// @import 'res/css/uwui-base.scss';
@import 'res/css/colors.scss';
@import 'res/css/font/overpass.css';
@import 'res/css/font/overpass-mono.css';
@import 'res/css/common.scss';
@import './src/res-common/_variables';
.header {
background-color: rgb(90, 28, 13);
background-color: rgb(0,0,0);
color: #fff;
padding: 8px;
// display: flex;
// flex-direction: row;
// justify-content: space-between;
border-bottom: 1px dotted #fa6;
h1 {
font-size: 2rem;
}
.version-info {
text-align: right;
font-size: 0.8rem;
opacity: 0.8;
label {
opacity: 0.5;
}
}
}
2024-05-04 01:04:23 +02:00
.settings-header-button {
display: flex;
flex-direction: row;
align-items: center;
padding: 0.5rem 2rem;
text-transform: lowercase;
font-variant: small-caps;
background-color: #000;
border: 1px solid #fa68;
color: #eee;
}
2024-05-04 01:04:23 +02:00
.site-support-info {
display: flex;
flex-direction: row;
align-items: center;
.site-support-site {
font-size: 1.5em;
}
.site-support {
display: inline-flex;
flex-direction: row;
align-items: center;
margin-left: 1rem;
border-radius: 8px;
padding: 0rem 1.5rem 0rem 1rem;
position: relative;
.tooltip {
padding: 1rem;
display: none;
position: absolute;
bottom: 0;
transform: translateY(110%);
width: 42em;
background-color: rgba(0,0,0,0.90);
color: #ccc;
}
&:hover {
.tooltip {
display: block;
}
}
.mdi {
margin-right: 1rem;
}
&.official {
background-color: #fa6;
color: #000;
.mdi {
fill: #000 !important;
}
}
&.community {
background-color: rgb(85, 85, 179);
color: #fff;
.mdi {
fill: #fff !important;
}
}
&.no-support {
background-color: rgb(138, 65, 126);
color: #eee;
.mdi {
fill: #eee !important;
}
}
&.user-added {
border: 1px solid #ff0;
color: #ff0;
.mdi {
fill: #ff0 !important;
}
}
}
}
.content {
flex-grow: 1;
.warning-area {
flex-grow: 0;
flex-shrink: 0;
}
.panel-content {
flex-grow: 1;
flex-shrink: 1;
overflow-y: auto;
padding: 1rem;
}
}
.warning-box {
background: rgb(255, 174, 107);
color: #000;
margin: 1rem;
padding: 1rem;
display: flex;
flex-direction: row;
align-items: center;
.icon-container {
margin-right: 1rem;
flex-shrink: 0;
flex-grow: 0;
}
a {
color: rgba(0,0,0,0.7);
cursor: pointer;
}
}
.popup-panel {
background-color: rgba(0,0,0,0.50);
color: #fff;
overflow-y: auto;
.popup-window-header {
padding: 1rem;
background-color: rgba(5,5,5, 0.75);
}
.tab-row {
background-color: rgba(11,11,11, 0.75);
.tab {
display: flex;
flex-direction: row;
align-items: center;
padding: 1rem;
font-size: 1.25rem;
// height: rem;
min-height: 3rem;
border-bottom: 1px solid rgba(128, 128, 128, 0.5);
border-top: 1px solid rgba(128, 128, 128, 0.5);
opacity: 0.5;
&:hover {
opacity: 1;
}
&.active {
opacity: 1.0;
background-color: $primaryBg;
color: rgb(255, 174, 107);
border-bottom: 1px solid rgba(116, 78, 47, 0.5);
border-top: 1px solid rgba(116, 78, 47, 0.5);
}
.icon-container {
width: 64px;
flex-grow: 0;
flex-shrink: 0;
}
.label {
flex-grow: 1;
flex-shrink: 1;
padding: 0 !important;
}
2025-01-30 02:40:04 +01:00
&.highlight-tab {
opacity: 0.9;
color: #eee;
// .label {
// color: rgb(239, 192, 152);
// }
}
2024-05-04 01:04:23 +02:00
}
}
.popup-title, .popup-title h1 {
font-size: 48px !important;
}
}
pre {
white-space: pre-wrap;
}
.button {
border: 1px solid #222 !important;
}
h1 {
margin: 0; padding: 0; font-weight: 400; font-size:24px;
}
2025-04-26 23:27:09 +02:00
.window-content {
height: 100%;
width: 100%;
overflow: auto;
}
</style>