mirror of
https://github.com/Ximi1970/systray-x.git
synced 2026-05-06 20:57:25 +02:00
WIP
This commit is contained in:
@@ -41,10 +41,10 @@ PreferencesDialog::PreferencesDialog( SysTrayXLink *link, Preferences *pref, QWi
|
||||
* Set close type button Ids
|
||||
*/
|
||||
m_ui->closeTypeGroup->setId( m_ui->defaultCloseWindowsRadioButton, Preferences::PREF_DEFAULT_CLOSE_WINDOWS);
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeMainCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_CLOSE_CHILDREN_WINDOWS );
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeAllWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS );
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeMainTrayCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_TRAY_CLOSE_CHILDREN_WINDOWS );
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeAllTrayWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS_TRAY );
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeMainCloseChildrenWindowsRadioButton, Preferences::PREF_MINIMIZE_MAIN_CLOSE_CHILDREN_WINDOWS );
|
||||
m_ui->closeTypeGroup->setId( m_ui->minimizeAllWindowsRadioButton, Preferences::PREF_MINIMIZE_ALL_WINDOWS );
|
||||
|
||||
/*
|
||||
* Set minimize type button Ids
|
||||
|
||||
@@ -231,7 +231,7 @@ void WindowCtrl::slotWindowState( Preferences::WindowState state )
|
||||
}
|
||||
else
|
||||
{
|
||||
if( state == Preferences::STATE_MINIMIZED )
|
||||
if( state == Preferences::STATE_MINIMIZED || state == Preferences::STATE_DOCKED )
|
||||
{
|
||||
Preferences::MinimizeType minimizeType = getMinimizeType();
|
||||
if( minimizeType != Preferences::PREF_DEFAULT_MINIMIZE )
|
||||
|
||||
@@ -364,6 +364,34 @@ SysTrayX.Messaging = {
|
||||
|
||||
console.debug("onCloseButton Window: " + JSON.stringify( window ) );
|
||||
|
||||
// SysTrayX.Link.postSysTrayXMessage({ window: "minimized_all" });
|
||||
|
||||
let state = undefined;
|
||||
if (SysTrayX.Messaging.closeType === "1" || SysTrayX.Messaging.closeType === "2") {
|
||||
// Minimize to tray
|
||||
state = "docked";
|
||||
|
||||
console.debug("onCloseButton: " + state);
|
||||
|
||||
} else if (SysTrayX.Messaging.closeType === "3" || SysTrayX.Messaging.closeType === "4") {
|
||||
// Minimize
|
||||
state = "minimized";
|
||||
|
||||
console.debug("onCloseButton: " + state);
|
||||
|
||||
}
|
||||
|
||||
if (state !== undefined) {
|
||||
browser.windows.update( window.id, {
|
||||
state: state,
|
||||
});
|
||||
|
||||
SysTrayX.Link.postSysTrayXMessage({ window: state });
|
||||
|
||||
console.debug("onCloseButton Send state: " + state);
|
||||
}
|
||||
|
||||
/*
|
||||
if( window.id === SysTrayX.mainWindowId ) {
|
||||
SysTrayX.Link.postSysTrayXMessage({ window: "minimized_all" });
|
||||
} else {
|
||||
@@ -374,7 +402,7 @@ SysTrayX.Messaging = {
|
||||
// state: "minimized",
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
||||
/*
|
||||
browser.windows.update(browser.windows.WINDOW_ID_CURRENT, {
|
||||
state: "minimized",
|
||||
@@ -953,7 +981,14 @@ SysTrayX.Link = {
|
||||
|
||||
SysTrayX.Window = {
|
||||
focusChanged: function (windowId) {
|
||||
// no focus change when docked
|
||||
|
||||
// windowId sometimes not defined
|
||||
console.debug("focusChanged Id: " + windowId);
|
||||
|
||||
browser.windows.getCurrent().then((win) => {
|
||||
console.debug("focusChanged Id: " + win.id);
|
||||
console.debug("focusChanged state: " + win.state);
|
||||
SysTrayX.Link.postSysTrayXMessage({ window: win.state });
|
||||
});
|
||||
},
|
||||
@@ -1088,17 +1123,17 @@ async function start() {
|
||||
|
||||
|
||||
// Set the close type
|
||||
browser.windowEvent2.setCloseType( Number( SysTrayX.Messaging.closeType ) );
|
||||
browser.windowEvent.setCloseType( Number( SysTrayX.Messaging.closeType ) );
|
||||
|
||||
// Set the main window id
|
||||
browser.windowEvent2.setMainWindowId( Number( SysTrayX.mainWindowId ) );
|
||||
browser.windowEvent.setMainWindowId( Number( SysTrayX.mainWindowId ) );
|
||||
|
||||
// Intercept close button?
|
||||
if (SysTrayX.Messaging.closeType !== "0") {
|
||||
// Intercept new window
|
||||
browser.windowEvent2.onNewWindow.addListener( SysTrayX.Messaging.onNewWindow );
|
||||
browser.windowEvent.onNewWindow.addListener( SysTrayX.Messaging.onNewWindow );
|
||||
|
||||
browser.windowEvent2.onCloseButtonClick.addListener(
|
||||
browser.windowEvent.onCloseButtonClick.addListener(
|
||||
SysTrayX.Messaging.onCloseButton
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
/* eslint-disable object-shorthand */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Using a closure to not leak anything but the API to the outside world.
|
||||
(function (exports) {
|
||||
|
||||
// Get various parts of the WebExtension framework that we need.
|
||||
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
|
||||
// You probably already know what this does.
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// A helpful class for listening to windows opening and closing.
|
||||
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
|
||||
|
||||
/**
|
||||
* This object is just what we're using to listen for toolbar clicks. The implementation
|
||||
* isn't what this example is about, but you might be interested as it's a common pattern.
|
||||
* We count the number of callbacks waiting for events so that we're only listening if we
|
||||
* need to be.
|
||||
*
|
||||
* An EventEmitter has the following basic functions:
|
||||
*
|
||||
* EventEmitter.on(emitterName, callback)
|
||||
* Registers a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.off(emitterName, callback)
|
||||
* Unregisters a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.emit(emitterName)
|
||||
* Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks.
|
||||
*/
|
||||
|
||||
let windowListener;
|
||||
|
||||
class WindowListener extends ExtensionCommon.EventEmitter {
|
||||
constructor(extension) {
|
||||
super();
|
||||
this.extension = extension;
|
||||
this.callbackCount = 0;
|
||||
}
|
||||
|
||||
get listenerId() {
|
||||
return `experiment_listener_${this.extension.uuid}_${this.extension.instanceId}`;
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
// Only react to the secondary mouse button.
|
||||
if (event.button == 0) {
|
||||
let toolbar = event.target.closest("toolbar");
|
||||
// Emit "toolbar-clicked" and send toolbar.id, event.clientX, event.clientY to
|
||||
// the registered callbacks.
|
||||
windowListener.emit("toolbar-clicked", toolbar.id, event.clientX, event.clientY);
|
||||
}
|
||||
}
|
||||
|
||||
add(callback) {
|
||||
// Registering the callback for "toolbar-clicked".
|
||||
this.on("toolbar-clicked", callback);
|
||||
this.callbackCount++;
|
||||
|
||||
if (this.callbackCount == 1) {
|
||||
ExtensionSupport.registerWindowListener(this.listenerId, {
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
],
|
||||
onLoadWindow: function (window) {
|
||||
let toolbox = window.document.getElementById("mail-toolbox");
|
||||
toolbox.addEventListener("click", windowListener.handleEvent);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
remove(callback) {
|
||||
// Un-Registering the callback for "toolbar-clicked".
|
||||
this.off("toolbar-clicked", callback);
|
||||
this.callbackCount--;
|
||||
|
||||
if (this.callbackCount == 0) {
|
||||
for (let window of ExtensionSupport.openWindows) {
|
||||
if ([
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes(window.location.href)) {
|
||||
let toolbox = window.document.getElementById("mail-toolbox");
|
||||
toolbox.removeEventListener("click", this.handleEvent);
|
||||
}
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener(this.listenerId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// This is the important part. It implements the functions and events defined
|
||||
// in the schema.json. The name must match what you've been using so far,
|
||||
// "ExampleAPI" in this case.
|
||||
class ExampleAPI extends ExtensionCommon.ExtensionAPI {
|
||||
// An alternative to defining a constructor here, is to use the onStartup
|
||||
// event. However, this causes the API to be instantiated directly after the
|
||||
// add-on has been loaded, not when the API is first used. Depends on what is
|
||||
// desired.
|
||||
constructor(extension) {
|
||||
super(extension);
|
||||
windowListener = new WindowListener(extension);
|
||||
}
|
||||
|
||||
getAPI(context) {
|
||||
return {
|
||||
// This key must match the class name.
|
||||
ExampleAPI: {
|
||||
|
||||
// A function.
|
||||
sayHello: async function (name) {
|
||||
Services.wm.getMostRecentWindow("mail:3pane").alert(name);
|
||||
},
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onToolbarClick: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "ExampleAPI.onToolbarClick",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event, id, x, y) {
|
||||
return fire.async(id, x, y);
|
||||
}
|
||||
|
||||
windowListener.add(callback);
|
||||
return function () {
|
||||
windowListener.remove(callback);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
onShutdown(isAppShutdown) {
|
||||
// This function is called if the extension is disabled or removed, or Thunderbird closes.
|
||||
// We usually do not have to do any cleanup, if Thunderbird is shutting down entirely
|
||||
if (isAppShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("Goodbye world!");
|
||||
}
|
||||
};
|
||||
|
||||
// Export the api by assigning in to the exports parameter of the anonymous closure
|
||||
// function, which is the global this.
|
||||
exports.ExampleAPI = ExampleAPI;
|
||||
|
||||
})(this)
|
||||
@@ -1,206 +1,312 @@
|
||||
// This is the important part. It implements the functions and events defined in schema.json.
|
||||
// The variable must have the same name you've been using so far, "myapi" in this case.
|
||||
var windowEvent = class extends ExtensionCommon.ExtensionAPI {
|
||||
getAPI(context) {
|
||||
console.log("windowEvent API started");
|
||||
/* eslint-disable object-shorthand */
|
||||
|
||||
// To be notified of the extension going away, call callOnClose with any object that has a
|
||||
// close function, such as this one.
|
||||
context.callOnClose(this);
|
||||
"use strict";
|
||||
|
||||
return {
|
||||
// Again, this key must have the same name.
|
||||
windowEvent: {
|
||||
setCloseType: async function (type) {
|
||||
windowListener.setCloseType(type);
|
||||
},
|
||||
// Using a closure to not leak anything but the API to the outside world.
|
||||
(function (exports) {
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onCloseButtonClick: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "windowEvent.onCloseButtonClick",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event) {
|
||||
return fire.async();
|
||||
}
|
||||
// Get various parts of the WebExtension framework that we need.
|
||||
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
|
||||
windowListener.addOnCloseButton(callback);
|
||||
return function () {
|
||||
windowListener.removeOnCloseButton(callback);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
},
|
||||
};
|
||||
}
|
||||
// You probably already know what this does.
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
close() {
|
||||
// This function is called if the extension is disabled or removed, or Thunderbird closes.
|
||||
// We registered it with callOnClose, above.
|
||||
console.log("windowEvent API closed");
|
||||
}
|
||||
};
|
||||
// A helpful class for listening to windows opening and closing.
|
||||
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
|
||||
|
||||
// A helpful class for listening to windows opening and closing.
|
||||
// (This file had a lowercase E in Thunderbird 65 and earlier.)
|
||||
var { ExtensionSupport } = ChromeUtils.import(
|
||||
"resource:///modules/ExtensionSupport.jsm"
|
||||
);
|
||||
/**
|
||||
* This object is just what we're using to listen for toolbar clicks. The implementation
|
||||
* isn't what this example is about, but you might be interested as it's a common pattern.
|
||||
* We count the number of callbacks waiting for events so that we're only listening if we
|
||||
* need to be.
|
||||
*
|
||||
* An EventEmitter has the following basic functions:
|
||||
*
|
||||
* EventEmitter.on(emitterName, callback)
|
||||
* Registers a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.off(emitterName, callback)
|
||||
* Unregisters a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.emit(emitterName)
|
||||
* Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks.
|
||||
*/
|
||||
|
||||
// This object is just what we're using to listen for toolbar clicks. The implementation isn't
|
||||
// what this example is about, but you might be interested as it's a common pattern. We count the
|
||||
// number of callbacks waiting for events so that we're only listening if we need to be.
|
||||
var windowListener = new (class extends ExtensionCommon.EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.callbackOnCloseButtonCount = 0;
|
||||
this.callbackOnLoadWindowCount = 0;
|
||||
let windowListener;
|
||||
|
||||
this.MESSAGE_CLOSE_TYPE_DEFAULT = 0;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN = 1;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY = 2;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN = 3;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_ALL = 4;
|
||||
class WindowListener extends ExtensionCommon.EventEmitter {
|
||||
constructor(extension) {
|
||||
super();
|
||||
this.extension = extension;
|
||||
this.onNewWindowCallbackCount = 0;
|
||||
this.onCloseButtonClickCallbackCount = 0;
|
||||
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN;
|
||||
}
|
||||
|
||||
setCloseType(closeType) {
|
||||
if (closeType === 0) {
|
||||
this.MESSAGE_CLOSE_TYPE_DEFAULT = 0;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN = 1;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY = 2;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN = 3;
|
||||
this.MESSAGE_CLOSE_TYPE_MIN_ALL = 4;
|
||||
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
|
||||
} else if (closeType === 1) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN;
|
||||
} else if (closeType === 2) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY;
|
||||
} else if (closeType === 3) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN;
|
||||
} else if (closeType === 4) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL;
|
||||
} else console.log("Unknown close type: " + closeType);
|
||||
}
|
||||
|
||||
addOnCloseButton(callback) {
|
||||
if (this.callbackOnCloseButtonCount == 0) {
|
||||
this.on("close-clicked", callback);
|
||||
this.callbackOnCloseButtonCount++;
|
||||
|
||||
ExtensionSupport.registerWindowListener("closeButtonListener", {
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
],
|
||||
onLoadWindow: function (window) {
|
||||
windowListener.callbackOnLoadWindowCount++;
|
||||
if (
|
||||
windowListener.callbackOnLoadWindowCount === 1 ||
|
||||
windowListener.closeType ===
|
||||
windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL ||
|
||||
windowListener.closeType ===
|
||||
windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY
|
||||
) {
|
||||
window.addEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
windowListener.hijackTitlebarCloseButton(window);
|
||||
|
||||
windowListener.oldClose = window.close;
|
||||
window.close = () => windowListener.onCloseButton(null);
|
||||
|
||||
console.log("Close listener added");
|
||||
}
|
||||
},
|
||||
});
|
||||
this.oldClose = undefined;
|
||||
this.mainWindowId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
removeOnCloseButton(callback) {
|
||||
if (this.callbackOnCloseButtonCount == 1) {
|
||||
this.off("close-clicked", callback);
|
||||
this.callbackOnCloseButtonCount--;
|
||||
get listenerIdNewWindow() {
|
||||
return `window_event_listener_new_window_${this.extension.uuid}_${this.extension.instanceId}`;
|
||||
}
|
||||
|
||||
for (let window of ExtensionSupport.openWindows) {
|
||||
if (
|
||||
[
|
||||
get listenerIdCloseButton() {
|
||||
return `window_event_listener_close_button_${this.extension.uuid}_${this.extension.instanceId}`;
|
||||
}
|
||||
|
||||
setCloseType(closeType) {
|
||||
if (closeType === 0) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
|
||||
} else if (closeType === 1) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN;
|
||||
} else if (closeType === 2) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY;
|
||||
} else if (closeType === 3) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN;
|
||||
} else if (closeType === 4) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL;
|
||||
} else console.log("Unknown close type: " + closeType);
|
||||
}
|
||||
|
||||
setMainWindowId(id) {
|
||||
this.mainWindowId = id;
|
||||
}
|
||||
|
||||
addOnNewWindow( callback ) {
|
||||
// Registering the callback for "new-window".
|
||||
this.on("new-window", callback);
|
||||
this.onNewWindowCallbackCount++;
|
||||
|
||||
if (this.onNewWindowCallbackCount === 1) {
|
||||
ExtensionSupport.registerWindowListener( this.listenerIdNewWindow, {
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes(window.location.href)
|
||||
) {
|
||||
window.removeEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
window.close = windowListener.oldClose;
|
||||
],
|
||||
onLoadWindow: function ( window ) {
|
||||
|
||||
console.log("Close listener removed");
|
||||
windowListener.emit( "new-window" );
|
||||
|
||||
console.log("New window added");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeOnNewWindow( callback ) {
|
||||
// Un-Registering the callback for "new-window".
|
||||
this.off("new-window", callback);
|
||||
this.onNewWindowCallbackCount--;
|
||||
|
||||
if (this.onNewWindowCallbackCount === 0) {
|
||||
for (let window of ExtensionSupport.openWindows) {
|
||||
if ( [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes( window.location.href ) ) {
|
||||
console.log( "New window listener removed" );
|
||||
}
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener( this.listenerIdNewWindow );
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener("closeButtonListener");
|
||||
}
|
||||
}
|
||||
|
||||
onCloseButton(event) {
|
||||
if (event) event.preventDefault();
|
||||
windowListener.emit("close-clicked");
|
||||
return true;
|
||||
}
|
||||
|
||||
hijackTitlebarCloseButton(window) {
|
||||
if (
|
||||
windowListener.replaceCommand(window, "titlebar-close", function () {
|
||||
return windowListener.onCloseButton(null);
|
||||
})
|
||||
) {
|
||||
console.log("replaced command= " + "titlebar-close");
|
||||
}
|
||||
}
|
||||
|
||||
replaceCommand(window, eltId, gotHidden) {
|
||||
let elt = window.document.getElementById(eltId);
|
||||
if (!elt) {
|
||||
console.log("Element '" + eltId + "' not found. Command not replaced.");
|
||||
return false;
|
||||
}
|
||||
|
||||
let prevent = null;
|
||||
if (elt.command) {
|
||||
prevent = {
|
||||
event: "click",
|
||||
func: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
onCloseButton( event ) {
|
||||
if ( event ) event.preventDefault();
|
||||
windowListener.emit( "close-clicked" );
|
||||
|
||||
console.log("Close clicked");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
onCloseMenu( event ) {
|
||||
if ( event ) event.preventDefault();
|
||||
windowListener.emit( "close-clicked" );
|
||||
|
||||
console.log("Close menu");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addOnCloseButtonClick( callback, context ) {
|
||||
// Registering the callback for "close-clicked".
|
||||
this.on( "close-clicked", callback );
|
||||
this.onCloseButtonClickCallbackCount++;
|
||||
|
||||
if (this.onCloseButtonClickCallbackCount === 1) {
|
||||
ExtensionSupport.registerWindowListener( this.listenerIdCloseButton, {
|
||||
context,
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
],
|
||||
onLoadWindow: function ( window ) {
|
||||
if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) {
|
||||
if ((windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN) &&
|
||||
(context.extension.windowManager.getWrapper(window).id === windowListener.mainWindowId) ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL) {
|
||||
|
||||
// Intercept the close event (triggered when clicking the close button)
|
||||
window.addEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get a window ID from a real window:
|
||||
let id = context.extension.windowManager.getWrapper(window).id;
|
||||
|
||||
if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) {
|
||||
console.log( "Close listener trigger");
|
||||
}
|
||||
|
||||
// Intercept the close by menu
|
||||
// windowListener.oldClose = window.close;
|
||||
// window.close = () => windowListener.onCloseMenu();
|
||||
|
||||
console.log( "Close listener mid:" + windowListener.mainWindowId);
|
||||
console.log( "Close listener id:" + id);
|
||||
console.log( "Close listener typeof mid:" + typeof windowListener.mainWindowId);
|
||||
console.log( "Close listener typeof id:" + typeof id);
|
||||
|
||||
console.log( "Close listener added" );
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeOnCloseButtonClick( callback, context ) {
|
||||
// Un-Registering the callback for "close-clicked".
|
||||
this.off( "close-clicked", callback );
|
||||
this.onCloseButtonClickCallbackCount--;
|
||||
|
||||
if ( this.onCloseButtonClickCallbackCount === 0 ) {
|
||||
for ( let window of ExtensionSupport.openWindows ) {
|
||||
if ( [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes( window.location.href ) ) {
|
||||
if (windowListener.closeType !== windowListener.MESSAGE_CLOSE_TYPE_DEFAULT) {
|
||||
if ((windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN) &&
|
||||
(context.extension.windowManager.getWrapper(window).id === windowListener.mainWindowId) ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY ||
|
||||
windowListener.closeType === windowListener.MESSAGE_CLOSE_TYPE_MIN_ALL) {
|
||||
// Release the close event (triggered when clicking the close button)
|
||||
window.removeEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( windowListener.oldClose != undefined ) {
|
||||
window.close = windowListener.oldClose;
|
||||
}
|
||||
|
||||
console.log( "Close listener removed" );
|
||||
}
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener( this.listenerIdCloseButton );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This is the important part. It implements the functions and events defined
|
||||
// in the schema.json. The name must match what you've been using so far,
|
||||
// "windowEvent" in this case.
|
||||
class windowEvent extends ExtensionCommon.ExtensionAPI {
|
||||
// An alternative to defining a constructor here, is to use the onStartup
|
||||
// event. However, this causes the API to be instantiated directly after the
|
||||
// add-on has been loaded, not when the API is first used. Depends on what is
|
||||
// desired.
|
||||
constructor(extension) {
|
||||
super(extension);
|
||||
windowListener = new WindowListener(extension);
|
||||
}
|
||||
|
||||
getAPI(context) {
|
||||
console.log("windowEvent API started");
|
||||
|
||||
return {
|
||||
// This key must match the class name.
|
||||
windowEvent: {
|
||||
setCloseType: async function (type) {
|
||||
windowListener.setCloseType(type);
|
||||
},
|
||||
|
||||
setMainWindowId: async function (id) {
|
||||
windowListener.setMainWindowId(id);
|
||||
},
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onNewWindow: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "windowEvent.onNewWindow",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event) {
|
||||
return fire.async();
|
||||
}
|
||||
|
||||
windowListener.addOnNewWindow(callback);
|
||||
return function () {
|
||||
windowListener.removeOnNewWindow(callback);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onCloseButtonClick: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "windowEvent.onCloseButtonClick",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event) {
|
||||
return fire.async();
|
||||
}
|
||||
|
||||
windowListener.addOnCloseButtonClick(callback,context);
|
||||
return function () {
|
||||
windowListener.removeOnCloseButtonClick(callback,context);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
},
|
||||
};
|
||||
} else if (elt.getAttribute("oncommand")) {
|
||||
prevent = {
|
||||
event: "command",
|
||||
func: function (e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
};
|
||||
} else {
|
||||
console.warn("Could not replace oncommand on " + eltId);
|
||||
return false;
|
||||
}
|
||||
|
||||
let callback = function (event) {
|
||||
if (event.target.id === eltId) {
|
||||
console.debug(prevent.event + " on " + eltId);
|
||||
if (gotHidden()) prevent.func(event);
|
||||
onShutdown(isAppShutdown) {
|
||||
// This function is called if the extension is disabled or removed, or Thunderbird closes.
|
||||
// We usually do not have to do any cleanup, if Thunderbird is shutting down entirely
|
||||
if (isAppShutdown) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/* We put listeners on the "titlebar" parent node, because:
|
||||
- we can hardly short-circuit command/oncommand (probably because they are
|
||||
registered first)
|
||||
- we'd have otherwise to alter "oncommand"/"command" attribute and use
|
||||
Function(), which do not pass review nowadays. */
|
||||
elt.parentNode.addEventListener(prevent.event, callback, true);
|
||||
console.log("windowEvent API closed");
|
||||
}
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
})();
|
||||
// Export the api by assigning in to the exports parameter of the anonymous closure
|
||||
// function, which is the global this.
|
||||
exports.windowEvent = windowEvent;
|
||||
|
||||
})(this)
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
/* eslint-disable object-shorthand */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Using a closure to not leak anything but the API to the outside world.
|
||||
(function (exports) {
|
||||
|
||||
// Get various parts of the WebExtension framework that we need.
|
||||
var { ExtensionCommon } = ChromeUtils.import("resource://gre/modules/ExtensionCommon.jsm");
|
||||
|
||||
// You probably already know what this does.
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// A helpful class for listening to windows opening and closing.
|
||||
var { ExtensionSupport } = ChromeUtils.import("resource:///modules/ExtensionSupport.jsm");
|
||||
|
||||
/**
|
||||
* This object is just what we're using to listen for toolbar clicks. The implementation
|
||||
* isn't what this example is about, but you might be interested as it's a common pattern.
|
||||
* We count the number of callbacks waiting for events so that we're only listening if we
|
||||
* need to be.
|
||||
*
|
||||
* An EventEmitter has the following basic functions:
|
||||
*
|
||||
* EventEmitter.on(emitterName, callback)
|
||||
* Registers a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.off(emitterName, callback)
|
||||
* Unregisters a callback for a custom emitter.
|
||||
*
|
||||
* EventEmitter.emit(emitterName)
|
||||
* Emit a custom emitter, all provided parameters will be forwarded to the registered callbacks.
|
||||
*/
|
||||
|
||||
let windowListener;
|
||||
|
||||
class WindowListener extends ExtensionCommon.EventEmitter {
|
||||
constructor(extension) {
|
||||
super();
|
||||
this.extension = extension;
|
||||
this.onNewWindowCallbackCount = 0;
|
||||
this.onCloseButtonClickCallbackCount = 0;
|
||||
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
|
||||
this.oldClose = undefined;
|
||||
this.mainWindowId = 0;
|
||||
}
|
||||
|
||||
get listenerIdNewWindow() {
|
||||
return `window_event_listener_new_window_${this.extension.uuid}_${this.extension.instanceId}`;
|
||||
}
|
||||
|
||||
get listenerIdCloseButton() {
|
||||
return `window_event_listener_close_button_${this.extension.uuid}_${this.extension.instanceId}`;
|
||||
}
|
||||
|
||||
setCloseType(closeType) {
|
||||
if (closeType === 0) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_DEFAULT;
|
||||
} else if (closeType === 1) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_TRAY_CLOSE_CHILDREN;
|
||||
} else if (closeType === 2) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL_TRAY;
|
||||
} else if (closeType === 3) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_MAIN_CLOSE_CHILDREN;
|
||||
} else if (closeType === 4) {
|
||||
this.closeType = this.MESSAGE_CLOSE_TYPE_MIN_ALL;
|
||||
} else console.log("Unknown close type: " + closeType);
|
||||
}
|
||||
|
||||
setMainWindowId(id) {
|
||||
this.mainWindowId = id;
|
||||
}
|
||||
|
||||
addOnNewWindow( callback ) {
|
||||
// Registering the callback for "new-window".
|
||||
this.on("new-window", callback);
|
||||
this.onNewWindowCallbackCount++;
|
||||
|
||||
if (this.onNewWindowCallbackCount == 1) {
|
||||
ExtensionSupport.registerWindowListener( this.listenerIdNewWindow, {
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
],
|
||||
onLoadWindow: function ( window ) {
|
||||
|
||||
windowListener.emit( "new-window" );
|
||||
|
||||
console.log("New window added");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeOnNewWindow( callback ) {
|
||||
// Un-Registering the callback for "new-window".
|
||||
this.off("new-window", callback);
|
||||
this.onNewWindowCallbackCount--;
|
||||
|
||||
if (this.onNewWindowCallbackCount == 0) {
|
||||
for (let window of ExtensionSupport.openWindows) {
|
||||
if ( [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes( window.location.href ) ) {
|
||||
console.log( "New window listener removed" );
|
||||
}
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener( this.listenerIdNewWindow );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onCloseButton( event ) {
|
||||
if ( event ) event.preventDefault();
|
||||
windowListener.emit( "close-clicked" );
|
||||
|
||||
console.log("Close clicked");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
onCloseMenu( event ) {
|
||||
if ( event ) event.preventDefault();
|
||||
windowListener.emit( "close-clicked" );
|
||||
|
||||
console.log("Close menu");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
addOnCloseButtonClick( callback, context, window ) {
|
||||
// Registering the callback for "close-clicked".
|
||||
this.on( "close-clicked", callback );
|
||||
this.onCloseButtonClickCallbackCount++;
|
||||
|
||||
if (this.onCloseButtonClickCallbackCount == 1) {
|
||||
ExtensionSupport.registerWindowListener( this.listenerIdCloseButton, {
|
||||
chromeURLs: [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
],
|
||||
onLoadWindow: function ( window ) {
|
||||
if( this.closeType !== )
|
||||
|
||||
|
||||
window.addEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
|
||||
// windowListener.oldClose = window.close;
|
||||
// window.close = () => windowListener.onCloseMenu();
|
||||
|
||||
// Get a window ID from a real window:
|
||||
let id = context.extension.windowManager.getWrapper(window).id;
|
||||
|
||||
console.log( "Close listener mid:" + windowListener.mainWindowId);
|
||||
console.log( "Close listener id:" + id);
|
||||
|
||||
|
||||
console.log( "Close listener added" );
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
removeOnCloseButtonClick( callback ) {
|
||||
// Un-Registering the callback for "close-clicked".
|
||||
this.off( "close-clicked", callback );
|
||||
this.onCloseButtonClickCallbackCount--;
|
||||
|
||||
if ( this.onCloseButtonClickCallbackCount == 0 ) {
|
||||
for ( let window of ExtensionSupport.openWindows ) {
|
||||
if ( [
|
||||
"chrome://messenger/content/messenger.xhtml",
|
||||
"chrome://messenger/content/messenger.xul",
|
||||
].includes( window.location.href ) ) {
|
||||
window.removeEventListener(
|
||||
"close",
|
||||
windowListener.onCloseButton,
|
||||
true
|
||||
);
|
||||
|
||||
if ( windowListener.oldClose != undefined ) {
|
||||
window.close = windowListener.oldClose;
|
||||
}
|
||||
|
||||
console.log( "Close listener removed" );
|
||||
}
|
||||
}
|
||||
ExtensionSupport.unregisterWindowListener( this.listenerIdCloseButton );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// This is the important part. It implements the functions and events defined
|
||||
// in the schema.json. The name must match what you've been using so far,
|
||||
// "windowEvent2" in this case.
|
||||
class windowEvent2 extends ExtensionCommon.ExtensionAPI {
|
||||
// An alternative to defining a constructor here, is to use the onStartup
|
||||
// event. However, this causes the API to be instantiated directly after the
|
||||
// add-on has been loaded, not when the API is first used. Depends on what is
|
||||
// desired.
|
||||
constructor(extension) {
|
||||
super(extension);
|
||||
windowListener = new WindowListener(extension);
|
||||
}
|
||||
|
||||
getAPI(context) {
|
||||
console.log("windowEvent API started");
|
||||
|
||||
return {
|
||||
// This key must match the class name.
|
||||
windowEvent2: {
|
||||
setCloseType: async function (type) {
|
||||
windowListener.setCloseType(type);
|
||||
},
|
||||
|
||||
setMainWindowId: async function (id) {
|
||||
windowListener.setMainWindowId(id);
|
||||
},
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onNewWindow: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "windowEvent2.onNewWindow",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event) {
|
||||
return fire.async();
|
||||
}
|
||||
|
||||
windowListener.addOnNewWindow(callback);
|
||||
return function () {
|
||||
windowListener.removeOnNewWindow(callback);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
// An event. Most of this is boilerplate you don't need to worry about, just copy it.
|
||||
onCloseButtonClick: new ExtensionCommon.EventManager({
|
||||
context,
|
||||
name: "windowEvent2.onCloseButtonClick",
|
||||
// In this function we add listeners for any events we want to listen to, and return a
|
||||
// function that removes those listeners. To have the event fire in your extension,
|
||||
// call fire.async.
|
||||
register(fire) {
|
||||
function callback(event) {
|
||||
return fire.async();
|
||||
}
|
||||
|
||||
windowListener.addOnCloseButtonClick(callback,context);
|
||||
return function () {
|
||||
windowListener.removeOnCloseButtonClick(callback);
|
||||
};
|
||||
},
|
||||
}).api(),
|
||||
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
onShutdown(isAppShutdown) {
|
||||
// This function is called if the extension is disabled or removed, or Thunderbird closes.
|
||||
// We usually do not have to do any cleanup, if Thunderbird is shutting down entirely
|
||||
if (isAppShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("windowEvent API closed");
|
||||
}
|
||||
};
|
||||
|
||||
// Export the api by assigning in to the exports parameter of the anonymous closure
|
||||
// function, which is the global this.
|
||||
exports.windowEvent2 = windowEvent2;
|
||||
|
||||
})(this)
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
// This is the important part. It implements the functions and events defined
|
||||
// in the schema.json. The name must match what you've been using so far,
|
||||
// "windowEvent2" in this case.
|
||||
// "windowHandler" in this case.
|
||||
class windowHandler extends ExtensionCommon.ExtensionAPI {
|
||||
// An alternative to defining a constructor here, is to use the onStartup
|
||||
// event. However, this causes the API to be instantiated directly after the
|
||||
|
||||
@@ -40,14 +40,6 @@
|
||||
"script": "js/windowEvent.js"
|
||||
}
|
||||
},
|
||||
"windowEvent2": {
|
||||
"schema": "schema_windowEvent2.json",
|
||||
"parent": {
|
||||
"scopes": ["addon_parent"],
|
||||
"paths": [["windowEvent2"]],
|
||||
"script": "js/windowEvent2.js"
|
||||
}
|
||||
},
|
||||
"windowHandler": {
|
||||
"schema": "schema_windowHandler.json",
|
||||
"parent": {
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
[
|
||||
{
|
||||
"namespace": "ExampleAPI",
|
||||
"functions": [
|
||||
{
|
||||
"name": "sayHello",
|
||||
"type": "function",
|
||||
"description": "Says hello to the user.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"description": "Who to say hello to."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onToolbarClick",
|
||||
"type": "function",
|
||||
"description": "Fires when the user clicks the secondary mouse button anywhere on the toolbar in the main window.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "toolbarId",
|
||||
"type": "string",
|
||||
"description": "The ID of the toolbar the user clicked."
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "x",
|
||||
"minimum": 0,
|
||||
"description": "The X position of the mouse when the user clicked."
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "y",
|
||||
"minimum": 0,
|
||||
"description": "The Y position of the mouse when the user clicked."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -15,13 +15,31 @@
|
||||
"maximum": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "setMainWindowId",
|
||||
"type": "function",
|
||||
"description": "Set the main window id.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "type"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onNewWindow",
|
||||
"type": "function",
|
||||
"description": "Fires when the user opens a new window.",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "onCloseButtonClick",
|
||||
"type": "function",
|
||||
"description": "Fires when the user clicks on the close button of the main window.",
|
||||
"description": "Fires when the user clicks on the close button of a window.",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
[
|
||||
{
|
||||
"namespace": "windowEvent2",
|
||||
"functions": [
|
||||
{
|
||||
"name": "setCloseType",
|
||||
"type": "function",
|
||||
"description": "Set the close type.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "type",
|
||||
"minimum": 0,
|
||||
"maximum": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "setMainWindowId",
|
||||
"type": "function",
|
||||
"description": "Set the main window id.",
|
||||
"async": true,
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "type"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"name": "onNewWindow",
|
||||
"type": "function",
|
||||
"description": "Fires when the user opens a new window.",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"name": "onCloseButtonClick",
|
||||
"type": "function",
|
||||
"description": "Fires when the user clicks on the close button of a window.",
|
||||
"parameters": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user