Limit when in-player UI shows. Add self-expiring menu options that takes you to the proposed, not-yet-implemented UI settings screen
This commit is contained in:
parent
0d098815a2
commit
ca1a375f2d
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ultrawidify",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ultrawidify",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.2",
|
||||
"description": "Aspect ratio fixer for youtube and other sites, with automatic aspect ratio detection. Supports ultrawide and other ratios.",
|
||||
"author": "Tamius Han <tamius.han@gmail.com>",
|
||||
"scripts": {
|
||||
|
@ -213,7 +213,15 @@ interface SettingsInterface {
|
||||
|
||||
ui: {
|
||||
inPlayer: {
|
||||
enabled: boolean
|
||||
enabled: boolean,
|
||||
minEnabledWidth: number, // don't show UI if player is narrower than % of screen width
|
||||
activation: 'trigger-zone' | 'player', // what needs to be hovered in order for UI to be visible
|
||||
triggerZoneDimensions: { // how large the trigger zone is (relative to player size)
|
||||
width: number
|
||||
height: number,
|
||||
offsetX: number, // fed to translateX(offsetX + '%'). Valid range [-100, 0]
|
||||
offsetY: number // fed to translateY(offsetY + '%'). Valid range [-100, 100]
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -311,6 +319,7 @@ interface SettingsInterface {
|
||||
internal?: CommandInterface[],
|
||||
},
|
||||
whatsNewChecked: boolean,
|
||||
newFeatureTracker: any,
|
||||
// -----------------------------------------
|
||||
// ::: SITE CONFIGURATION :::
|
||||
// -----------------------------------------
|
||||
|
@ -1,12 +1,29 @@
|
||||
<template>
|
||||
<div
|
||||
class="context-spawn uw-ui-trigger"
|
||||
style="z-index: 1000"
|
||||
@mouseenter="(ev) => setTriggerZoneActive(true, ev)"
|
||||
@mouseleave="(ev) => setTriggerZoneActive(false, ev)"
|
||||
>
|
||||
<div
|
||||
class="spawn-container uw-trigger"
|
||||
:style="triggerZoneStyles"
|
||||
>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="contextMenuActive || settingsInitialized && uwTriggerZoneVisible && !isGlobal"
|
||||
class="context-spawn uw-clickable"
|
||||
style="z-index: 1001"
|
||||
@mouseenter="preventContextMenuHide()"
|
||||
@mouseleave="allowContextMenuHide()"
|
||||
>
|
||||
|
||||
<GhettoContextMenu alignment="right">
|
||||
<GhettoContextMenu
|
||||
alignment="right" class="uw-menu"
|
||||
@mouseenter="newFeatureViewUpdate('uw6.ui-popup')"
|
||||
>
|
||||
<template v-slot:activator>
|
||||
<div class="context-item">
|
||||
Ultrawidify
|
||||
@ -68,12 +85,38 @@
|
||||
</GhettoContextMenuItem>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
|
||||
<!-- shortcut for configuring UI -->
|
||||
<GhettoContextMenuOption
|
||||
v-if="settings.active.newFeatureTracker?.['uw6.ui-popup']?.show > 0"
|
||||
@click="showUwWindow('ui-config')"
|
||||
>
|
||||
<span style="color: #fa6;">I hate this popup<br/></span>
|
||||
<span style="font-size: 0.8em">
|
||||
<span style="text-transform: uppercase; font-size: 0.8em">
|
||||
<a @click="showUwWindow('ui-config')">
|
||||
Do something about it
|
||||
</a> × <a @click="acknowledgeNewFeature('uw6.ui-popup')">keep the popup</a>
|
||||
</span>
|
||||
<br/>
|
||||
<span style="opacity: 0.5">This menu option will show {{settings.active.newFeatureTracker?.['uw6.ui-popup']?.show}} more<br/> times; or until clicked or dismissed.<br/>
|
||||
Also accessible via <span style="font-variant: small-caps">extension settings</span>.
|
||||
</span>
|
||||
</span>
|
||||
</GhettoContextMenuOption>
|
||||
|
||||
<!-- -->
|
||||
|
||||
<GhettoContextMenuOption
|
||||
@click="showUwWindow()"
|
||||
label="Extension settings"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
<button @click="showUwWindow()">Not working?</button>
|
||||
<GhettoContextMenuOption
|
||||
@click="showUwWindow('about')"
|
||||
label="Not working?"
|
||||
>
|
||||
</GhettoContextMenuOption>
|
||||
</div>
|
||||
</slot>
|
||||
</GhettoContextMenu>
|
||||
@ -160,6 +203,7 @@ export default {
|
||||
disabled: false,
|
||||
|
||||
contextMenuActive: false,
|
||||
triggerZoneActive: false,
|
||||
|
||||
uiVisible: true,
|
||||
debugData: {
|
||||
@ -311,6 +355,34 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles trigger zone
|
||||
*/
|
||||
handleTriggerZone(mouseInside) {
|
||||
console.log('handing trigger zone!', mouseInside);
|
||||
// this.triggerZoneActive = mouseInside;
|
||||
},
|
||||
|
||||
acknowledgeNewFeature(featureKey) {
|
||||
delete this.settings.active.newFeatureTracker[featureKey];
|
||||
this.settings.saveWithoutReload();
|
||||
},
|
||||
newFeatureViewUpdate(featureKey) {
|
||||
if (!this.settings.active.newFeatureTracker[featureKey]) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.settings.active.newFeatureTracker[featureKey].show--;
|
||||
this.settings.saveWithoutReload();
|
||||
|
||||
if (this.settings.active.newFeatureTracker[featureKey]?.show < 0) {
|
||||
this.acknowledgeNewFeature(featureKey);
|
||||
}
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sends message to parent _without_ using event bus.
|
||||
*/
|
||||
@ -324,14 +396,16 @@ export default {
|
||||
},
|
||||
|
||||
preventContextMenuHide() {
|
||||
console.log('entered context menu ...');
|
||||
this.contextMenuActive = true;
|
||||
},
|
||||
allowContextMenuHide() {
|
||||
console.log('exited context menu ...');
|
||||
this.contextMenuActive = false;
|
||||
},
|
||||
|
||||
setTriggerZoneActive(active, event) {
|
||||
this.triggerZoneActive = active;
|
||||
},
|
||||
|
||||
showUwWindow() {
|
||||
this.uwWindowFadeOut = false;
|
||||
this.uwWindowVisible = true;
|
||||
@ -473,6 +547,10 @@ export default {
|
||||
|
||||
// white-space: nowrap;
|
||||
// }
|
||||
|
||||
// .spawn-container {
|
||||
// border: 1px solid white;
|
||||
// }
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -43,26 +43,8 @@
|
||||
<p class="text-center">
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius" target="_blank">Donate on Paypal</a>
|
||||
</p>
|
||||
<h2>Fun stuff</h2>
|
||||
<p>
|
||||
This is probably a bad idea but—
|
||||
</p>
|
||||
<p>
|
||||
Are you attending Isle of Wonders on Cres, Croatia, between 28. 6. and 30. 6.? So am I, by official duty.
|
||||
</p>
|
||||
<p>
|
||||
Club Amulet D20 is forecasted to have a stand there, and I am forecasted to be in the general vicinity of it (barring any unexpected circumstances). I'll be either taking photos, painting minis, or doing heatstroke any% in rather rudamentary costume.
|
||||
</p>
|
||||
<p>
|
||||
If you're there, you can swing around to say 'hi' or provide some validation, or paint some minis. Rumor has it Conquest will have paint&take event.
|
||||
</p>
|
||||
<p>
|
||||
— Tamius
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<small>I am not paid to shill this.</small>
|
||||
I also have <a href="https://instagram.com/shaman_urkog" target="_blank">instagram with nerdy shit</a> <small>(mini painting + various fantasy events)</small>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -77,27 +77,7 @@
|
||||
<p class="text-center">
|
||||
<a class="donate" href="https://www.paypal.com/paypalme/tamius" target="_blank">Donate on Paypal</a>
|
||||
</p>
|
||||
<h2>Fun stuff</h2>
|
||||
<p>
|
||||
This is probably a bad idea but—
|
||||
</p>
|
||||
<p>
|
||||
Are you attending Isle of Wonders on Cres, Croatia, between 28. 6. and 30. 6.? So am I, by official duty.
|
||||
</p>
|
||||
<p>
|
||||
Club Amulet D20 is forecasted to have a stand there, and I am forecasted to be in the general vicinity of it (barring any unexpected circumstances). I'll be either taking photos, painting minis, or doing heatstroke any% in rather rudamentary costume.
|
||||
</p>
|
||||
<p>
|
||||
If you're there, you can swing around to say 'hi' or provide some validation, or paint some minis. Rumor has it Conquest will have paint&take event.
|
||||
</p>
|
||||
<p>
|
||||
— Tamius
|
||||
</p>
|
||||
<p>
|
||||
</p>
|
||||
<p>
|
||||
<small>I am not paid to shill this.</small>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="context-container" @mouseleave="hideContextMenu()">
|
||||
<GhettoContextMenuItem
|
||||
class="activator"
|
||||
class="activator uw-clickable"
|
||||
:css="{
|
||||
'expand-left': alignment === 'left',
|
||||
'expand-right': alignment === 'right',
|
||||
@ -13,7 +13,7 @@
|
||||
</GhettoContextMenuItem>
|
||||
<div
|
||||
v-if="contextMenuVisible"
|
||||
class="context-menu"
|
||||
class="context-menu uw-clickable"
|
||||
:class="{
|
||||
'menu-left': alignment === 'left',
|
||||
'menu-right': alignment === 'right'
|
||||
|
@ -1,7 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<GhettoContextMenuItem>
|
||||
{{label}} {{shortcut ? `(${shortcut})` : ''}}
|
||||
<template v-if="label">
|
||||
{{label}} {{shortcut ? `(${shortcut})` : ''}}
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot></slot>
|
||||
</template>
|
||||
</GhettoContextMenuItem>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -14,7 +14,29 @@ export default {
|
||||
}, this.origin);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
playerDimensions: undefined,
|
||||
triggerZoneStyles: {
|
||||
height: '50dvh',
|
||||
width: '50dvw',
|
||||
transform: 'translateX(-50%)'
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
playerDimensionsUpdate(dimensions) {
|
||||
if (dimensions?.width !== this.playerDimensions?.width || dimensions?.height !== this.playerDimensions?.height) {
|
||||
this.playerDimensions = dimensions;
|
||||
|
||||
this.triggerZoneStyles = {
|
||||
height: `${this.playerDimensions.height * 0.5}px`,
|
||||
width: `${this.playerDimensions.width * 0.5}px`,
|
||||
transform: `translate(${(this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetX)}%, ${this.settings.active.ui.inPlayer.triggerZoneDimensions.offsetY}%)`,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles 'uwui-probe' events. It checks whether there's a clickable element under
|
||||
* cursor, and sends a reply to the content scripts that indicates whether pointer-events
|
||||
@ -26,16 +48,6 @@ export default {
|
||||
}
|
||||
this.lastProbeTs = eventData.ts;
|
||||
|
||||
// show ultrawidify trigger zone and set it to vanish after 250ms
|
||||
// but don't show the trigger zone behind an active popup
|
||||
if (! this.uwWindowVisible) {
|
||||
this.uwTriggerZoneVisible = true;
|
||||
clearTimeout(this.uwTriggerZoneTimeout);
|
||||
this.uwTriggerZoneTimeout = setTimeout(
|
||||
() => this.uwTriggerZoneVisible = false,
|
||||
250
|
||||
);
|
||||
}
|
||||
|
||||
/* we check if our mouse is hovering over an element.
|
||||
*
|
||||
@ -47,16 +59,36 @@ export default {
|
||||
* our top-level element.
|
||||
*/
|
||||
let isClickable = false;
|
||||
let element = document.elementFromPoint(eventData.coords.x, eventData.coords.y);
|
||||
let isOverTriggerZone = false;
|
||||
const elements = document.elementsFromPoint(eventData.coords.x, eventData.coords.y);
|
||||
|
||||
while (element) {
|
||||
if (element?.classList.contains('uw-clickable')) {
|
||||
// we could set 'pointerEvents' here and now & simply use return, but that
|
||||
// might cause us a problem if we ever try to add more shit to this function
|
||||
for (const element of elements) {
|
||||
if (element.classList?.contains('uw-clickable')) {
|
||||
isClickable = true;
|
||||
break;
|
||||
}
|
||||
element = element.parentElement;
|
||||
if (element.classList?.contains('uw-ui-trigger')) {
|
||||
isOverTriggerZone = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.triggerZoneActive = isOverTriggerZone;
|
||||
|
||||
// show ultrawidify trigger zone and set it to vanish after 250ms
|
||||
// but don't show the trigger zone behind an active popup
|
||||
if (
|
||||
eventData.canShowUI
|
||||
&& (this.settings.active.ui.inPlayer.activation !== 'player' || isOverTriggerZone)
|
||||
) {
|
||||
if (! this.uwWindowVisible) {
|
||||
this.uwTriggerZoneVisible = true;
|
||||
clearTimeout(this.uwTriggerZoneTimeout);
|
||||
this.uwTriggerZoneTimeout = setTimeout(
|
||||
() => this.uwTriggerZoneVisible = false,
|
||||
250
|
||||
);
|
||||
}
|
||||
} else {
|
||||
this.uwTriggerZoneVisible = false;
|
||||
}
|
||||
|
||||
window.parent.postMessage(
|
||||
|
@ -159,7 +159,7 @@ const ExtensionConfPatch = [
|
||||
userOptions.sites['@empty'].defaultType = 'modified';
|
||||
}
|
||||
}, {
|
||||
forVersion: '6.0.1-7',
|
||||
forVersion: '6.0.2-0',
|
||||
updateFn: (userOptions: SettingsInterface, defaultOptions) => {
|
||||
// remove custom CSS, as it is no longer needed
|
||||
for (const site in userOptions.sites) {
|
||||
@ -168,9 +168,18 @@ const ExtensionConfPatch = [
|
||||
}
|
||||
userOptions.ui = {
|
||||
inPlayer: {
|
||||
enabled: false, // keep disabled for existing users
|
||||
enabled: true, // enable by default on new installs
|
||||
minEnabledWidth: 0.75,
|
||||
activation: 'player',
|
||||
triggerZoneDimensions: {
|
||||
width: 0.5,
|
||||
height: 0.5,
|
||||
offsetX: -50,
|
||||
offsetY: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
userOptions.newFeatureTracker['uw6.ui-popup'] = {show: 10};
|
||||
}
|
||||
}
|
||||
];
|
||||
|
@ -160,6 +160,14 @@ const ExtensionConf: SettingsInterface = {
|
||||
ui: {
|
||||
inPlayer: {
|
||||
enabled: true, // enable by default on new installs
|
||||
minEnabledWidth: 0.75,
|
||||
activation: 'player',
|
||||
triggerZoneDimensions: {
|
||||
width: 0.5,
|
||||
height: 0.5,
|
||||
offsetX: -50,
|
||||
offsetY: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1415,6 +1423,9 @@ const ExtensionConf: SettingsInterface = {
|
||||
}
|
||||
},
|
||||
whatsNewChecked: true,
|
||||
newFeatureTracker: {
|
||||
'uw6.ui-popup': {show: 10}
|
||||
},
|
||||
// -----------------------------------------
|
||||
// ::: SITE CONFIGURATION :::
|
||||
// -----------------------------------------
|
||||
|
@ -13,7 +13,7 @@ const csuiVersions = {
|
||||
class UI {
|
||||
constructor(
|
||||
interfaceId,
|
||||
uiConfig, // {parentElement?, eventBus?}
|
||||
uiConfig, // {parentElement?, eventBus?, isGlobal?, playerData}
|
||||
) {
|
||||
this.interfaceId = interfaceId;
|
||||
this.uiConfig = uiConfig;
|
||||
@ -31,6 +31,9 @@ class UI {
|
||||
this.disablePointerEvents = false;
|
||||
|
||||
this.saveState = undefined;
|
||||
this.playerData = uiConfig.playerData;
|
||||
this.uiSettings = uiConfig.uiSettings;
|
||||
|
||||
}
|
||||
|
||||
async init() {
|
||||
@ -108,12 +111,16 @@ class UI {
|
||||
y: event.pageY - this.uiIframe.offsetTop
|
||||
};
|
||||
|
||||
const playerData = this.canShowUI(coords);
|
||||
|
||||
// ask the iframe to check whether there's a clickable element
|
||||
this.uiIframe.contentWindow.postMessage(
|
||||
{
|
||||
action: 'uwui-probe',
|
||||
coords,
|
||||
ts: +new Date() // this should be accurate enough for our purposes
|
||||
playerDimensions: playerData.playerDimensions,
|
||||
canShowUI: playerData.canShowUI,
|
||||
ts: +new Date() // this should be accurate enough for our purposes,
|
||||
},
|
||||
uiURI
|
||||
);
|
||||
@ -130,6 +137,7 @@ class UI {
|
||||
|
||||
rootDiv.appendChild(iframe);
|
||||
}
|
||||
|
||||
initMessaging() {
|
||||
// subscribe to events coming back to us. Unsubscribe if iframe vanishes.
|
||||
const messageHandlerFn = (message) => {
|
||||
@ -209,6 +217,51 @@ class UI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether mouse is moving over either:
|
||||
* * <video> element
|
||||
* * player element ()
|
||||
* * uwui-clickable element
|
||||
*/
|
||||
canShowUI(coords) {
|
||||
const playerCssClass = 'uw-ultrawidify-player-css';
|
||||
|
||||
const result = {
|
||||
playerDimensions: undefined,
|
||||
canShowUI: false
|
||||
}
|
||||
|
||||
if (this.playerData?.dimensions) {
|
||||
result.playerDimensions = this.playerData.dimensions;
|
||||
}
|
||||
|
||||
// if player is not wide enough, we do nothing
|
||||
if (
|
||||
!this.isGlobal && // this.isGlobal is basically 'yes, do as I say'
|
||||
!document.fullscreenElement && // if we are in full screen, we allow it in every case as player detection is not 100% reliable,
|
||||
result.playerDimensions?.width && // which makes playerDimensions.width unreliable as well (we assume nobody uses browser in
|
||||
// fullscreen mode unless watching videos)
|
||||
result.playerDimensions.width < window.screen.width * (this.uiSettings.inPlayer.minEnabledWidth ?? 0)
|
||||
) {
|
||||
result.canShowUI = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
const elements = document.elementsFromPoint(coords.x, coords.y);
|
||||
|
||||
for (const element of elements) {
|
||||
if (
|
||||
element instanceof HTMLVideoElement
|
||||
|| element.classList.contains(playerCssClass)
|
||||
) {
|
||||
result.canShowUI = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles events received from the iframe.
|
||||
* @param {*} event
|
||||
|
@ -157,7 +157,9 @@ class PlayerData {
|
||||
'ultrawidifyUi',
|
||||
{
|
||||
parentElement: this.element,
|
||||
eventBus: this.eventBus
|
||||
eventBus: this.eventBus,
|
||||
playerData: this,
|
||||
uiSettings: this.videoData.settings.active.ui
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "Ultrawidify",
|
||||
"description": "Removes black bars on ultrawide videos and offers advanced options to fix aspect ratio.",
|
||||
"version": "6.0.1",
|
||||
"version": "6.0.2",
|
||||
"icons": {
|
||||
"32":"res/icons/uw-32.png",
|
||||
"64":"res/icons/uw-64.png"
|
||||
|
Loading…
Reference in New Issue
Block a user