Adds info tiddlers for viewport dimensions (#9260)

* feat: added info tiddlers for viewport dimensions

* feat: multi window support for dimensions info tiddlers

* refactor: introduce standalone eventbus and refactor for ES2017

* docs: extended docs for InfoMechanism to cover new additions
This commit is contained in:
Saq Imtiaz
2025-10-06 18:00:13 +02:00
committed by GitHub
parent ee23097816
commit a36356a07d
5 changed files with 170 additions and 5 deletions

View File

@@ -0,0 +1,86 @@
/*\
title: $:/core/modules/info/windowdimensions.js
type: application/javascript
module-type: info
\*/
exports.getInfoTiddlerFields = function(updateInfoTiddlersCallback) {
if(!$tw.browser) {
return [];
}
class WindowDimensionsTracker {
constructor(updateCallback) {
this.updateCallback = updateCallback;
this.resizeHandlers = new Map();
this.dimensionsInfo = [
["outer/width", win => win.outerWidth],
["outer/height", win => win.outerHeight],
["inner/width", win => win.innerWidth],
["inner/height", win => win.innerHeight],
["client/width", win => win.document.documentElement.clientWidth],
["client/height", win => win.document.documentElement.clientHeight]
];
}
buildTiddlers(win,windowId) {
const prefix = `$:/info/browser/window/${windowId}/`;
return this.dimensionsInfo.map(([suffix, getter]) => ({
title: prefix + suffix,
text: String(getter(win))
}));
}
clearTiddlers(windowId) {
const prefix = `$:/info/browser/window/${windowId}/`,
deletions = this.dimensionsInfo.map(([suffix]) => prefix + suffix);
this.updateCallback([], deletions);
}
getUpdateHandler(win,windowId) {
let scheduled = false;
return () => {
if(!scheduled) {
scheduled = true;
requestAnimationFrame(() => {
this.updateCallback(this.buildTiddlers(win,windowId), []);
scheduled = false;
});
}
};
}
trackWindow(win,windowId) {
const handler = this.getUpdateHandler(win, windowId);
handler(); // initial update
win.addEventListener("resize",handler,{passive:true});
this.resizeHandlers.set(windowId,{win, handler});
}
untrackWindow(windowId) {
const entry = this.resizeHandlers.get(windowId);
if(entry) {
entry.win.removeEventListener("resize", entry.handler);
this.resizeHandlers.delete(windowId);
}
this.clearTiddlers(windowId);
}
}
const tracker = new WindowDimensionsTracker(updateInfoTiddlersCallback);
// Track main window
tracker.trackWindow(window,"system/main");
// Hook into event bus for user windows
if($tw.eventBus) {
$tw.eventBus.on("window:opened", ({window: win, windowID}) => {
tracker.trackWindow(win, "user/" + windowID);
});
$tw.eventBus.on("window:closed", ({windowID}) => {
tracker.untrackWindow("user/" + windowID);
});
}
return [];
};

View File

@@ -0,0 +1,46 @@
/*\
title: $:/core/modules/startup/eventbus.js
type: application/javascript
module-type: startup
Event bus for cross module communication
\*/
exports.name = "eventbus";
exports.platforms = ["browser"];
exports.before = ["windows"];
exports.synchronous = true;
$tw.eventBus = {
listenersMap: new Map(),
on(event,handler) {
if(!this.listenersMap.has(event)) {
this.listenersMap.set(event,new Set());
}
const listeners = this.listenersMap.get(event);
listeners.add(handler);
},
off(event,handler) {
const listeners = this.listenersMap.get(event);
if(listeners) {
listeners.delete(handler);
}
},
once(event,handler) {
const wrapper = (...args) => {
handler(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
},
emit(event,data) {
const listeners = this.listenersMap.get(event);
if(listeners) {
listeners.forEach(fn => fn(data));
}
}
};

View File

@@ -19,11 +19,17 @@ var TITLE_INFO_PLUGIN = "$:/temp/info-plugin";
exports.startup = function() {
// Function to bake the info plugin with new tiddlers
var updateInfoPlugin = function(tiddlerFieldsArray) {
// additions: array of tiddler field objects
// removals: array of titles to remove
var updateInfoPlugin = function(additions = [], removals = []) {
// Get the existing tiddlers
var json = $tw.wiki.getTiddlerData(TITLE_INFO_PLUGIN,{tiddlers: {}});
// Add the new ones
$tw.utils.each(tiddlerFieldsArray,function(fields) {
$tw.utils.each(removals,function(title) {
if(json.tiddlers[title]) {
delete json.tiddlers[title];
}
});
$tw.utils.each(additions,function(fields) {
if(fields && fields.title) {
json.tiddlers[fields.title] = fields;
}
@@ -47,7 +53,7 @@ exports.startup = function() {
}
});
updateInfoPlugin(tiddlerFieldsArray);
var changes = $tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
$tw.wiki.readPluginInfo([TITLE_INFO_PLUGIN]);
$tw.wiki.registerPluginTiddlers("info",[TITLE_INFO_PLUGIN]);
$tw.wiki.unpackPluginTiddlers();
};

View File

@@ -56,9 +56,11 @@ exports.startup = function() {
srcDocument.write("<!DOCTYPE html><head></head><body class='tc-body tc-single-tiddler-window'></body></html>");
srcDocument.close();
srcDocument.title = windowTitle;
$tw.eventBus.emit("window:opened",{windowID, window: srcWindow});
srcWindow.addEventListener("beforeunload",function(event) {
delete $tw.windows[windowID];
$tw.wiki.removeEventListener("change",refreshHandler);
$tw.eventBus.emit("window:closed",{windowID});
},false);
// Set up the styles
var styleWidgetNode = $tw.wiki.makeTranscludeWidget("$:/core/ui/PageStylesheet",{

View File

@@ -1,5 +1,5 @@
created: 20140720164948099
modified: 20201124185829706
modified: 20250819181815032
tags: Mechanisms
title: InfoMechanism
type: text/vnd.tiddlywiki
@@ -19,6 +19,7 @@ System tiddlers in the namespace `$:/info/` are used to expose information about
|[[$:/info/browser/language]] |<<.from-version "5.1.20">> Language as reported by browser (note that some browsers report two character codes such as `en` while others report full codes such as `en-GB`) |
|[[$:/info/browser/screen/width]] |Screen width in pixels |
|[[$:/info/browser/screen/height]] |Screen height in pixels |
|`$:/info/browser/window/*` |<<.from-version "5.4.0">> Tiddlers reporting window dimensions, updated when the windows are resized |
|[[$:/info/node]] |Running under [[Node.js]]? ("yes" or "no") |
|[[$:/info/url/full]] |<<.from-version "5.1.14">> Full URL of wiki (eg, ''<<example full>>'') |
|[[$:/info/url/host]] |<<.from-version "5.1.14">> Host portion of URL of wiki (eg, ''<<example host>>'') |
@@ -29,3 +30,27 @@ System tiddlers in the namespace `$:/info/` are used to expose information about
|[[$:/info/url/protocol]] |<<.from-version "5.1.14">> Protocol portion of URL of wiki (eg, ''<<example protocol>>'') |
|[[$:/info/url/search]] |<<.from-version "5.1.14">> Search portion of URL of wiki (eg, ''<<example search>>'') |
|[[$:/info/darkmode]] |<<.from-version "5.1.23">> Is dark mode enabled? ("yes" or "no") |
! Main Window Dimension Tiddlers
<<.from-version "5.4.0">> These tiddlers reports the dimensions of the main ~TiddlyWiki window and are updated automatically whenever the main window is resized.
|!Title |!Description |
|[[$:/info/browser/window/system/main/outer/width]] |Full browser window including chrome, tabs, toolbars |
|[[$:/info/browser/window/system/main/outer/height]] |Full browser window including chrome, tabs, toolbars |
|[[$:/info/browser/window/system/main/inner/width]] |Viewport width including scrollbars |
|[[$:/info/browser/window/system/main/inner/height]] |Viewport height including scrollbars |
|[[$:/info/browser/window/system/main/client/width]] |Content width excluding scrollbars |
|[[$:/info/browser/window/system/main/client/height]] |Content height excluding scrollbars |
! User-Created Window Dimension Tiddlers
<<.from-version "5.4.0">> These tiddler reports the dimensions of additional windows opened via [[tm-open-window|WidgetMessage: tm-open-window]]. The windowID used when opening the window is used to identify the corresponding info tiddlers. These tiddlers are updated automatically whenever the main window is resized.
|!Title |!Description |
|`$:/info/browser/window/user/<windowID>/outer/width` | Full browser window including chrome, tabs, toolbars |
|`$:/info/browser/window/user/<windowID>/outer/height` | Full browser window including chrome, tabs, toolbars |
|`$:/info/browser/window/user/<windowID>/inner/width` |Viewport width including scrollbars |
|`$:/info/browser/window/user/<windowID>/inner/height` |Viewport height including scrollbars |
|`$:/info/browser/window/user/<windowID>/client/width` |Content width excluding scrollbars |
|`$:/info/browser/window/user/<windowID>/client/height` |Content height excluding scrollbars |