Get the non-framed popover working initially
This commit is contained in:
parent
8e8202f8a6
commit
77abcb11a9
5 changed files with 132 additions and 165 deletions
|
|
@ -193,8 +193,9 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin
|
|||
* @param {PointerEvent} event
|
||||
*/
|
||||
async #ammoInfoPointerEnter(event) {
|
||||
console.log(event.x, event.y);
|
||||
const { x, y } = event;
|
||||
const pos = event.target.getBoundingClientRect();
|
||||
const x = pos.x + Math.floor(pos.width / 2);
|
||||
const y = pos.y;
|
||||
|
||||
this.#ammoTrackerHoverTimeout = setTimeout(
|
||||
() => {
|
||||
|
|
@ -214,7 +215,7 @@ export class HeroSkillsCardV1 extends GenericAppMixin(HandlebarsApplicationMixin
|
|||
|
||||
async #ammoInfoPointerOut() {
|
||||
if (this.#ammoTracker) {
|
||||
// this.#ammoTracker.close();
|
||||
this.#ammoTracker.close();
|
||||
};
|
||||
|
||||
if (this.#ammoTrackerHoverTimeout !== null) {
|
||||
|
|
|
|||
|
|
@ -7,14 +7,9 @@ export class AmmoTracker extends GenericPopoverMixin(HandlebarsApplicationMixin(
|
|||
// #region Options
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: [
|
||||
`ripcrypt`,
|
||||
`ripcrypt--AmmoTracker`,
|
||||
],
|
||||
window: {
|
||||
frame: false,
|
||||
positioned: true,
|
||||
resizable: false,
|
||||
minimizable: false,
|
||||
},
|
||||
position: {
|
||||
width: 100,
|
||||
height: 30,
|
||||
|
|
@ -30,164 +25,9 @@ export class AmmoTracker extends GenericPopoverMixin(HandlebarsApplicationMixin(
|
|||
// #endregion
|
||||
|
||||
// #region Instance Data
|
||||
popover = {};
|
||||
constructor({ popover, ...options}) {
|
||||
|
||||
// For when the caller doesn't provide anything, we want this to behave
|
||||
// like a normal Application.
|
||||
popover.framed ??= true;
|
||||
popover.locked ??= true;
|
||||
|
||||
if (popover.framed) {
|
||||
options.window.frame = true;
|
||||
options.window.minimizable = true;
|
||||
}
|
||||
|
||||
super(options);
|
||||
|
||||
this.popover = popover;
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Lifecycle
|
||||
_insertElement(element) {
|
||||
// console.log(this.popover);
|
||||
const existing = document.getElementById(element.id);
|
||||
if (existing) {
|
||||
existing.replaceWith(element);
|
||||
return;
|
||||
};
|
||||
// const pos = element.getBoundingClientRect();
|
||||
|
||||
// const horizontalOffset = Math.floor(pos.width / 2);
|
||||
// console.log({ x: this.popover.x, y: this.popover.y, height: pos.height, xOffset: horizontalOffset });
|
||||
|
||||
element.style.position = `absolute`;
|
||||
element.style.color = `black`;
|
||||
element.style.background = `greenyellow`;
|
||||
element.style[`z-index`] = 10000;
|
||||
// element.style.left = `${this.popover.x - horizontalOffset}px`;
|
||||
// element.style.top = `${this.popover.y - pos.height}px`;
|
||||
// this.position = {
|
||||
// left: this.popover.x - horizontalOffset,
|
||||
// top: this.popover.y - pos.height,
|
||||
// };
|
||||
|
||||
// standard addition
|
||||
document.body.append(element);
|
||||
};
|
||||
|
||||
// _updatePosition(position) {
|
||||
// const pos = super._updatePosition(position);
|
||||
// if (this.popover.framed) { return pos };
|
||||
|
||||
// delete pos.left;
|
||||
// delete pos.top;
|
||||
|
||||
// const el = this.element;
|
||||
// let bounds;
|
||||
// let width, height;
|
||||
|
||||
// // Implicit height
|
||||
// if ( true ) {
|
||||
// Object.assign(el.style, {width: `${width}px`, height: ""});
|
||||
// bounds = el.getBoundingClientRect();
|
||||
// height = bounds.height;
|
||||
// }
|
||||
|
||||
// // Implicit width
|
||||
// if ( true ) {
|
||||
// Object.assign(el.style, {height: `${height}px`, width: ""});
|
||||
// bounds = el.getBoundingClientRect();
|
||||
// width = bounds.width;
|
||||
// }
|
||||
|
||||
// // const { width, height } = this.element.getBoundingClientRect();
|
||||
// const horizontalOffset = Math.floor(width / 2);
|
||||
// pos.left = this.popover.x - horizontalOffset;
|
||||
// pos.top = this.popover.y - height;
|
||||
|
||||
// console.log({ x: this.popover.x, y: this.popover.y, height, xOffset: horizontalOffset, width });
|
||||
|
||||
// return pos;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @override
|
||||
* Custom implementation in order to make it show up approximately where I
|
||||
* want it to when being created.
|
||||
*/
|
||||
_updatePosition(position) {
|
||||
if ( !this.element ) { return position };
|
||||
const el = this.element;
|
||||
let {width, height, left, top, scale} = position;
|
||||
scale ??= 1.0;
|
||||
const computedStyle = getComputedStyle(el);
|
||||
let minWidth = ApplicationV2.parseCSSDimension(computedStyle.minWidth, el.parentElement.offsetWidth) || 0;
|
||||
let maxWidth = ApplicationV2.parseCSSDimension(computedStyle.maxWidth, el.parentElement.offsetWidth) || Infinity;
|
||||
let minHeight = ApplicationV2.parseCSSDimension(computedStyle.minHeight, el.parentElement.offsetHeight) || 0;
|
||||
let maxHeight = ApplicationV2.parseCSSDimension(computedStyle.maxHeight, el.parentElement.offsetHeight) || Infinity;
|
||||
let bounds = el.getBoundingClientRect();
|
||||
const {clientWidth, clientHeight} = document.documentElement;
|
||||
|
||||
// Explicit width
|
||||
const autoWidth = width === `auto`;
|
||||
if ( !autoWidth ) {
|
||||
const targetWidth = Number(width || bounds.width);
|
||||
minWidth = parseInt(minWidth) || 0;
|
||||
maxWidth = parseInt(maxWidth) || (clientWidth / scale);
|
||||
width = Math.clamp(targetWidth, minWidth, maxWidth);
|
||||
}
|
||||
|
||||
// Explicit height
|
||||
const autoHeight = height === `auto`;
|
||||
if ( !autoHeight ) {
|
||||
const targetHeight = Number(height || bounds.height);
|
||||
minHeight = parseInt(minHeight) || 0;
|
||||
maxHeight = parseInt(maxHeight) || (clientHeight / scale);
|
||||
height = Math.clamp(targetHeight, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
// Implicit height
|
||||
if ( autoHeight ) {
|
||||
Object.assign(el.style, {width: `${width}px`, height: ``});
|
||||
bounds = el.getBoundingClientRect();
|
||||
height = bounds.height;
|
||||
}
|
||||
|
||||
// Implicit width
|
||||
if ( autoWidth ) {
|
||||
Object.assign(el.style, {height: `${height}px`, width: ``});
|
||||
bounds = el.getBoundingClientRect();
|
||||
width = bounds.width;
|
||||
}
|
||||
|
||||
// Left Offset
|
||||
const scaledWidth = width * scale;
|
||||
const targetLeft = left ?? (this.popover.x - Math.floor( scaledWidth / 2 ));
|
||||
const maxLeft = Math.max(clientWidth - scaledWidth, 0);
|
||||
left = Math.clamp(targetLeft, 0, maxLeft);
|
||||
|
||||
// Top Offset
|
||||
const scaledHeight = height * scale;
|
||||
const targetTop = top ?? (this.popover.y - scaledHeight);
|
||||
const maxTop = Math.max(clientHeight - scaledHeight, 0);
|
||||
top = Math.clamp(targetTop, 0, maxTop);
|
||||
|
||||
// Scale
|
||||
scale ??= 1.0;
|
||||
return {
|
||||
width: autoWidth ? `auto` : width,
|
||||
height: autoHeight ? `auto` : height,
|
||||
left,
|
||||
top,
|
||||
scale,
|
||||
};
|
||||
}
|
||||
|
||||
async _onFirstRender(context, options) {
|
||||
await super._onFirstRender(context, options);
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
|
|
|
|||
|
|
@ -1,4 +1,123 @@
|
|||
const { ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export function GenericPopoverMixin(HandlebarsApp) {
|
||||
class GenericRipCryptPopover extends HandlebarsApp {};
|
||||
class GenericRipCryptPopover extends HandlebarsApp {
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: [
|
||||
`popover`,
|
||||
],
|
||||
window: {
|
||||
frame: false,
|
||||
positioned: true,
|
||||
resizable: false,
|
||||
minimizable: false,
|
||||
},
|
||||
actions: {},
|
||||
};
|
||||
|
||||
popover = {};
|
||||
constructor({ popover, ...options}) {
|
||||
|
||||
// For when the caller doesn't provide anything, we want this to behave
|
||||
// like a normal Application instance.
|
||||
popover.framed ??= true;
|
||||
popover.locked ??= true;
|
||||
|
||||
if (popover.framed) {
|
||||
options.window.frame = true;
|
||||
options.window.minimizable = true;
|
||||
};
|
||||
|
||||
super(options);
|
||||
|
||||
this.popover = popover;
|
||||
};
|
||||
|
||||
async close(options = {}) {
|
||||
if (!this.popover.framed) {
|
||||
options.animate ??= false;
|
||||
};
|
||||
return super.close(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
* Custom implementation in order to make it show up approximately where I
|
||||
* want it to when being created.
|
||||
*
|
||||
* Most of this implementation is identical to the ApplicationV2
|
||||
* implementation, the biggest difference is how targetLeft and targetRight
|
||||
* are calculated.
|
||||
*/
|
||||
_updatePosition(position) {
|
||||
if (!this.element) { return position };
|
||||
if (this.popover.framed) { return position }
|
||||
|
||||
const el = this.element;
|
||||
let {width, height, left, top, scale} = position;
|
||||
scale ??= 1.0;
|
||||
const computedStyle = getComputedStyle(el);
|
||||
let minWidth = ApplicationV2.parseCSSDimension(computedStyle.minWidth, el.parentElement.offsetWidth) || 0;
|
||||
let maxWidth = ApplicationV2.parseCSSDimension(computedStyle.maxWidth, el.parentElement.offsetWidth) || Infinity;
|
||||
let minHeight = ApplicationV2.parseCSSDimension(computedStyle.minHeight, el.parentElement.offsetHeight) || 0;
|
||||
let maxHeight = ApplicationV2.parseCSSDimension(computedStyle.maxHeight, el.parentElement.offsetHeight) || Infinity;
|
||||
let bounds = el.getBoundingClientRect();
|
||||
const {clientWidth, clientHeight} = document.documentElement;
|
||||
|
||||
// Explicit width
|
||||
const autoWidth = width === `auto`;
|
||||
if ( !autoWidth ) {
|
||||
const targetWidth = Number(width || bounds.width);
|
||||
minWidth = parseInt(minWidth) || 0;
|
||||
maxWidth = parseInt(maxWidth) || (clientWidth / scale);
|
||||
width = Math.clamp(targetWidth, minWidth, maxWidth);
|
||||
}
|
||||
|
||||
// Explicit height
|
||||
const autoHeight = height === `auto`;
|
||||
if ( !autoHeight ) {
|
||||
const targetHeight = Number(height || bounds.height);
|
||||
minHeight = parseInt(minHeight) || 0;
|
||||
maxHeight = parseInt(maxHeight) || (clientHeight / scale);
|
||||
height = Math.clamp(targetHeight, minHeight, maxHeight);
|
||||
}
|
||||
|
||||
// Implicit height
|
||||
if ( autoHeight ) {
|
||||
Object.assign(el.style, {width: `${width}px`, height: ``});
|
||||
bounds = el.getBoundingClientRect();
|
||||
height = bounds.height;
|
||||
}
|
||||
|
||||
// Implicit width
|
||||
if ( autoWidth ) {
|
||||
Object.assign(el.style, {height: `${height}px`, width: ``});
|
||||
bounds = el.getBoundingClientRect();
|
||||
width = bounds.width;
|
||||
}
|
||||
|
||||
// Left Offset
|
||||
const scaledWidth = width * scale;
|
||||
const targetLeft = left ?? (this.popover.x - Math.floor( scaledWidth / 2 ));
|
||||
const maxLeft = Math.max(clientWidth - scaledWidth, 0);
|
||||
left = Math.clamp(targetLeft, 0, maxLeft);
|
||||
|
||||
// Top Offset
|
||||
const scaledHeight = height * scale;
|
||||
const targetTop = top ?? (this.popover.y - scaledHeight);
|
||||
const maxTop = Math.max(clientHeight - scaledHeight, 0);
|
||||
top = Math.clamp(targetTop, 0, maxTop);
|
||||
|
||||
// Scale
|
||||
scale ??= 1.0;
|
||||
return {
|
||||
width: autoWidth ? `auto` : width,
|
||||
height: autoHeight ? `auto` : height,
|
||||
left,
|
||||
top,
|
||||
scale,
|
||||
};
|
||||
};
|
||||
};
|
||||
return GenericRipCryptPopover;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue