Port to libwrapper
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"esmodules": [
|
"esmodules": [
|
||||||
|
"src/libwrapper_shim.js",
|
||||||
"src/main.js",
|
"src/main.js",
|
||||||
"src/socket.js"
|
"src/socket.js"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
// Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro
|
||||||
|
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// A shim for the libWrapper library
|
||||||
|
export let libWrapper = undefined;
|
||||||
|
|
||||||
|
export const VERSIONS = [1,11,0];
|
||||||
|
export const TGT_SPLIT_RE = new RegExp("([^.[]+|\\[('([^'\\\\]|\\\\.)+?'|\"([^\"\\\\]|\\\\.)+?\")\\])", 'g');
|
||||||
|
export const TGT_CLEANUP_RE = new RegExp("(^\\['|'\\]$|^\\[\"|\"\\]$)", 'g');
|
||||||
|
|
||||||
|
// Main shim code
|
||||||
|
Hooks.once('init', () => {
|
||||||
|
// Check if the real module is already loaded - if so, use it
|
||||||
|
if(globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
|
||||||
|
libWrapper = globalThis.libWrapper;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback implementation
|
||||||
|
libWrapper = class {
|
||||||
|
static get is_fallback() { return true };
|
||||||
|
|
||||||
|
static get WRAPPER() { return 'WRAPPER' };
|
||||||
|
static get MIXED() { return 'MIXED' };
|
||||||
|
static get OVERRIDE() { return 'OVERRIDE' };
|
||||||
|
|
||||||
|
static register(package_id, target, fn, type="MIXED", {chain=undefined}={}) {
|
||||||
|
const is_setter = target.endsWith('#set');
|
||||||
|
target = !is_setter ? target : target.slice(0, -4);
|
||||||
|
const split = target.match(TGT_SPLIT_RE).map((x)=>x.replace(/\\(.)/g, '$1').replace(TGT_CLEANUP_RE,''));
|
||||||
|
const root_nm = split.splice(0,1)[0];
|
||||||
|
|
||||||
|
let obj, fn_name;
|
||||||
|
if(split.length == 0) {
|
||||||
|
obj = globalThis;
|
||||||
|
fn_name = root_nm;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const _eval = eval;
|
||||||
|
fn_name = split.pop();
|
||||||
|
obj = split.reduce((x,y)=>x[y], globalThis[root_nm] ?? _eval(root_nm));
|
||||||
|
}
|
||||||
|
|
||||||
|
let iObj = obj;
|
||||||
|
let descriptor = null;
|
||||||
|
while(iObj) {
|
||||||
|
descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
|
||||||
|
if(descriptor) break;
|
||||||
|
iObj = Object.getPrototypeOf(iObj);
|
||||||
|
}
|
||||||
|
if(!descriptor || descriptor?.configurable === false) throw `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`;
|
||||||
|
|
||||||
|
let original = null;
|
||||||
|
const wrapper = (chain ?? (type.toUpperCase?.() != 'OVERRIDE' && type != 3)) ? function() { return fn.call(this, original.bind(this), ...arguments); } : function() { return fn.apply(this, arguments); };
|
||||||
|
|
||||||
|
if(!is_setter) {
|
||||||
|
if(descriptor.value) {
|
||||||
|
original = descriptor.value;
|
||||||
|
descriptor.value = wrapper;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
original = descriptor.get;
|
||||||
|
descriptor.get = wrapper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!descriptor.set) throw `libWrapper Shim: '${target}' does not have a setter`;
|
||||||
|
original = descriptor.set;
|
||||||
|
descriptor.set = wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.configurable = true;
|
||||||
|
Object.defineProperty(obj, fn_name, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
+29
-45
@@ -3,6 +3,7 @@
|
|||||||
import {currentSpeedProvider, getColorForDistanceAndToken, getMovedDistanceFromToken, getRangesFromSpeedProvider, initApi, registerModule, registerSystem} from "./api.js";
|
import {currentSpeedProvider, getColorForDistanceAndToken, getMovedDistanceFromToken, getRangesFromSpeedProvider, initApi, registerModule, registerSystem} from "./api.js";
|
||||||
import {checkDependencies, getHexSizeSupportTokenGridCenter, highlightMeasurementTerrainRuler} from "./compatibility.js";
|
import {checkDependencies, getHexSizeSupportTokenGridCenter, highlightMeasurementTerrainRuler} from "./compatibility.js";
|
||||||
import {moveEntities, onMouseMove} from "./foundry_imports.js"
|
import {moveEntities, onMouseMove} from "./foundry_imports.js"
|
||||||
|
import {libWrapper} from "./libwrapper_shim.js";
|
||||||
import {performMigrations} from "./migration.js"
|
import {performMigrations} from "./migration.js"
|
||||||
import {getMovementHistory, removeLastHistoryEntryIfAt, resetMovementHistory} from "./movement_tracking.js";
|
import {getMovementHistory, removeLastHistoryEntryIfAt, resetMovementHistory} from "./movement_tracking.js";
|
||||||
import {extendRuler} from "./ruler.js";
|
import {extendRuler} from "./ruler.js";
|
||||||
@@ -16,8 +17,8 @@ Hooks.once("init", () => {
|
|||||||
initApi()
|
initApi()
|
||||||
hookDragHandlers(Token);
|
hookDragHandlers(Token);
|
||||||
hookDragHandlers(MeasuredTemplate);
|
hookDragHandlers(MeasuredTemplate);
|
||||||
hookKeyboardManagerFunctions()
|
libWrapper.register("drag-ruler", "KeyboardManager.prototype._handleKeys", forwardIfUnahndled(handleKeys), "MIXED");
|
||||||
hookLayerFunctions();
|
libWrapper.register("drag-ruler", "TokenLayer.prototype.undoHistory", tokenLayerUndoHistory, "WRAPPER");
|
||||||
|
|
||||||
extendRuler();
|
extendRuler();
|
||||||
|
|
||||||
@@ -57,50 +58,28 @@ Hooks.on("getCombatTrackerEntryContext", function (html, menu) {
|
|||||||
menu.splice(1, 0, entry);
|
menu.splice(1, 0, entry);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function forwardIfUnahndled(newFn) {
|
||||||
|
return function(oldFn, ...args) {
|
||||||
|
const eventHandled = newFn(...args);
|
||||||
|
if (!eventHandled)
|
||||||
|
oldFn(...args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function hookDragHandlers(entityType) {
|
function hookDragHandlers(entityType) {
|
||||||
const originalDragLeftStartHandler = entityType.prototype._onDragLeftStart
|
const entityName = entityType.name
|
||||||
entityType.prototype._onDragLeftStart = function(event) {
|
libWrapper.register("drag-ruler", `${entityName}.prototype._onDragLeftStart`, onEntityLeftDragStart, "WRAPPER");
|
||||||
originalDragLeftStartHandler.call(this, event)
|
|
||||||
onEntityLeftDragStart.call(this, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalDragLeftMoveHandler = entityType.prototype._onDragLeftMove
|
|
||||||
entityType.prototype._onDragLeftMove = function (event) {
|
|
||||||
if (entityType === Token)
|
if (entityType === Token)
|
||||||
applyGridlessSnapping.call(this, event);
|
libWrapper.register("drag-ruler", `${entityName}.prototype._onDragLeftMove`, onEntityLeftDragMoveSnap, "WRAPPER");
|
||||||
originalDragLeftMoveHandler.call(this, event)
|
else
|
||||||
onEntityLeftDragMove.call(this, event)
|
libWrapper.register("drag-ruler", `${entityName}.prototype._onDragLeftMove`, onEntityLeftDragMove, "WRAPPER");
|
||||||
}
|
libWrapper.register("drag-ruler", `${entityName}.prototype._onDragLeftDrop`, forwardIfUnahndled(onEntityDragLeftDrop), "MIXED");
|
||||||
|
libWrapper.register("drag-ruler", `${entityName}.prototype._onDragLeftCancel`, forwardIfUnahndled(onEntityDragLeftCancel), "MIXED");
|
||||||
const originalDragLeftDropHandler = entityType.prototype._onDragLeftDrop
|
|
||||||
entityType.prototype._onDragLeftDrop = function (event) {
|
|
||||||
const eventHandled = onEntityDragLeftDrop.call(this, event)
|
|
||||||
if (!eventHandled)
|
|
||||||
originalDragLeftDropHandler.call(this, event)
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalDragLeftCancelHandler = entityType.prototype._onDragLeftCancel
|
|
||||||
entityType.prototype._onDragLeftCancel = function (event) {
|
|
||||||
const eventHandled = onEntityDragLeftCancel.call(this, event)
|
|
||||||
if (!eventHandled)
|
|
||||||
originalDragLeftCancelHandler.call(this, event)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hookKeyboardManagerFunctions() {
|
async function tokenLayerUndoHistory(wrapped) {
|
||||||
const originalHandleKeys = KeyboardManager.prototype._handleKeys
|
|
||||||
KeyboardManager.prototype._handleKeys = function (event, key, up) {
|
|
||||||
const eventHandled = handleKeys.call(this, event, key, up)
|
|
||||||
if (!eventHandled)
|
|
||||||
originalHandleKeys.call(this, event, key, up)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hookLayerFunctions() {
|
|
||||||
const originalTokenLayerUndoHistory = TokenLayer.prototype.undoHistory;
|
|
||||||
TokenLayer.prototype.undoHistory = function () {
|
|
||||||
const historyEntry = this.history[this.history.length - 1];
|
const historyEntry = this.history[this.history.length - 1];
|
||||||
return originalTokenLayerUndoHistory.call(this).then((returnValue) => {
|
const returnValue = await wrapped();
|
||||||
if (historyEntry.type === "update") {
|
if (historyEntry.type === "update") {
|
||||||
for (const entry of historyEntry.data) {
|
for (const entry of historyEntry.data) {
|
||||||
const token = canvas.tokens.get(entry._id);
|
const token = canvas.tokens.get(entry._id);
|
||||||
@@ -108,8 +87,6 @@ function hookLayerFunctions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return returnValue;
|
return returnValue;
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleKeys(event, key, up) {
|
function handleKeys(event, key, up) {
|
||||||
@@ -180,7 +157,8 @@ function onKeyEscape(up) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEntityLeftDragStart(event) {
|
function onEntityLeftDragStart(wrapped, event) {
|
||||||
|
wrapped(event);
|
||||||
const isToken = this instanceof Token;
|
const isToken = this instanceof Token;
|
||||||
const ruler = canvas.controls.ruler
|
const ruler = canvas.controls.ruler
|
||||||
ruler.draggedEntity = this;
|
ruler.draggedEntity = this;
|
||||||
@@ -218,7 +196,13 @@ function startDragRuler(options, measureImmediately=true) {
|
|||||||
ruler.measure(destination, options);
|
ruler.measure(destination, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEntityLeftDragMove(event) {
|
function onEntityLeftDragMoveSnap(wrapped, event) {
|
||||||
|
applyGridlessSnapping.call(this, event);
|
||||||
|
onEntityLeftDragMove.call(this, wrapped, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEntityLeftDragMove(wrapped, event) {
|
||||||
|
wrapped(event);
|
||||||
const ruler = canvas.controls.ruler
|
const ruler = canvas.controls.ruler
|
||||||
if (ruler.isDragRuler)
|
if (ruler.isDragRuler)
|
||||||
onMouseMove.call(ruler, event)
|
onMouseMove.call(ruler, event)
|
||||||
|
|||||||
Reference in New Issue
Block a user