I have 2 dialogs (A and B) with closeOnEscape="true".
Both dialogs are modal and have <p:focus context="innerForm" /> inside.
The dialog A opens the dialog B. Yeah, I know, this is a bad design, but...
The problem is that when I press ESC on dialog B it closes correctly and focus return to dialog A, but ESC do not close this dialog.
This is a bug and has been reported to PrimeFaces on GitHub:
https://github.com/primefaces/primefaces/issues/6677
PR: https://github.com/primefaces/primefaces/pull/6678
Will be in PF 9.0
Add this to your JS that loads after PF to fix it right now:
if (PrimeFaces.widget.Dialog) {
PrimeFaces.widget.Dialog.prototype.bindEvents = function() {
var $this = this;
//Move dialog to top if target is not a trigger for a PrimeFaces overlay
this.jq.on("mousedown", function(e) {
if (!$(e.target).data('primefaces-overlay-target')) {
$this.moveToTop();
}
});
this.icons.on('mouseover', function() {
$(this).addClass('ui-state-hover');
}).on('mouseout', function() {
$(this).removeClass('ui-state-hover');
}).on('focus', function() {
$(this).addClass('ui-state-focus');
}).on('blur', function() {
$(this).removeClass('ui-state-focus');
});
this.closeIcon.on('click', function(e) {
$this.hide();
e.preventDefault();
});
this.maximizeIcon.on("click", function(e) {
$this.toggleMaximize();
e.preventDefault();
});
this.minimizeIcon.on("click", function(e) {
$this.toggleMinimize();
e.preventDefault();
});
if (this.cfg.closeOnEscape) {
$(document).on('keydown.dialog_' + this.id, function(e) {
var keyCode = $.ui.keyCode;
if (e.which === keyCode.ESCAPE && $this.isVisible()) {
var active = parseInt($this.jq.css('z-index')) === parseInt($('.ui-dialog:visible').last().css('z-index'));
if (active) {
$this.hide();
}
};
});
}
};
}
Related
I want to make a message box which contains yes and no buttons in a electron.js app. I tried to do it with dialog inside the electron. But it didn't work:
const electron = require('electron')
const { dialog } = electron
console.log(dialog) // undefined
const electron = require('electron')
const dialog = electron.remote.dialog
console.log(dialog) // Uncaught Error: Cannot read "dialog" of undefined (remote is undefined)
Then, I tried to do it with dialog which is a module in npm. But it didn't do the thing that I want to do. There wasn't any yes or no buttons also it returned the same responses when I clicked OK or I closed window:
const electron = require('electron')
const dialog = require('dialog')
dialog.info('Are you sure?', 'Confirmation', function(exitCode) {
if (exitCode == 0) {
// Should clicked OK (always response)
}
if (exitCode == 1) {
// Should closed window (but never works)
}
})
What did I do wrong?
You will want to use
Electron's dialog.showMessageBox();
method.
The dialog.showMessageBoxSync();
method would block your main process until a response is received, so you won't want to use that unless intended.
I have placed the creation and management of your dialog box in the main.js file. If you want to move this into its
own file, that's not a problem. All you would need to do is get() the (main) window instance if you want your dialog
box to be a child of the main window.
main.js (main process)
// Import required Electron modules
const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;
// Import required Node modules
const nodePath = require('path');
// Prevent garbage collection
let window;
function createWindow() {
const window = new electronBrowserWindow({
x: 0,
y: 0,
width: 800,
height: 600,
show: false,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: nodePath.join(__dirname, 'preload.js')
}
});
window.loadFile('index.html')
.then(() => { window.show(); });
return window;
}
electronApp.on('ready', () => {
window = createWindow();
});
electronApp.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
electronApp.quit();
}
});
electronApp.on('activate', () => {
if (electronBrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// ---
electronIpcMain.on('openDialog', () => {
electronDialog.showMessageBox(window, {
'type': 'question',
'title': 'Confirmation',
'message': "Are you sure?",
'buttons': [
'Yes',
'No'
]
})
// Dialog returns a promise so let's handle it correctly
.then((result) => {
// Bail if the user pressed "No" or escaped (ESC) from the dialog box
if (result.response !== 0) { return; }
// Testing.
if (result.response === 0) {
console.log('The "Yes" button was pressed (main process)');
}
// Reply to the render process
window.webContents.send('dialogResponse', result.response);
})
})
For proper communication between processes, we must
use Inter-Process Communication.
preload.js (main process)
// Import the necessary Electron modules
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;
// Exposed protected methods in the render process
contextBridge.exposeInMainWorld(
// Allowed 'ipcRenderer' methods
'ipcRenderer', {
// From render to main
openDialog: () => {
ipcRenderer.send('openDialog');
},
dialogResponse: (response) => {
ipcRenderer.on('dialogResponse', response);
}
}
);
Finally, your index.html file will listen for a button click. Once clicked, send a message to the main process to open
the
dialog box.
Once a valid response is received from the dialog box, the response is sent back to the render process for processing.
PS: The render
method ipcRenderer.invoke()
could be used instead of
the ipcRenderer.send() method.
But if it was, you would need to handle the "No" or escape (ESC) response in the render process.
index.html (render process)
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Electron Test</title>
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
</head>
<body>
<input type="button" id="openDialog" value="Show Dialog">
<hr>
<div id="response"></div>
</body>
<script>
// Open dialog (in main process) when "Show Dialog" button is clicked
document.getElementById('openDialog').addEventListener('click', () => {
window.ipcRenderer.openDialog('openDialog');
})
// Response from main process
window.ipcRenderer.dialogResponse((event, response) => {
if (response === 0) {
// Perform your render action here
document.getElementById('response').innerText = 'The "Yes" button was clicked';
}
});
</script>
</html>
To use more than 2 buttons in your dialog box(es), in the creation of your dialog box you may want to designate
a cancelId and check for all valid return values before actioning anything.
I chrome extention in my popup.html I have a "settings" button, for now when I click this button it opens the settings page in a new tab, and it's possible to open multiple pages, my question is how to prevent multiple settings instances, i.e I want to enable only one settings page open.
My code:
<button type="button">
<a id="settings-btn"> <i class="fa fa-cog fa-lg fa-fw" style="font-size:27px;"></i></a>
</button>
And in popup.js:
document.addEventListener('DOMContentLoaded', function () {
document.getElementById("settings-btn").addEventListener("click", openIndex);
})
function openIndex() {
chrome.tabs.create({
url: "Options.html"
});
}
Update:
#wOxxOm's answer worked after I added tabs permission in manifest file
There are two methods.
Using tabs permission and chrome.tabs.query to find the existing tab
manifest.json:
"permissions": ["tabs"]
popup.js
openOrActivate('Options.html');
function openOrActivate(url) {
if (!url.includes(':')) url = chrome.runtime.getURL(url);
chrome.tabs.query({url: url + '*'}, tabs => {
const [tab] = tabs;
if (!tab) {
chrome.tabs.create({url});
} else {
chrome.tabs.update(tab.id, {active: true});
chrome.windows.update(tab.windowId, {focused: true});
}
});
}
Send a message that will be received by an options page if it's open
In case of no response we'll open a new tab.
popup.js:
openOrActivate('Options.html');
function openOrActivate(path) {
if (!path.startsWith('/')) path = `/${path}`;
chrome.runtime.sendMessage(path, tab => {
if (chrome.runtime.lastError || !tab) {
chrome.tabs.create({ url: path });
} else {
chrome.tabs.update(tab.id, { active: true });
chrome.windows.update(tab.windowId, { focused: true });
}
});
}
Options.js (the script of Options.html):
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message === location.pathname) {
chrome.tabs.getCurrent(sendResponse);
return true;
}
});
I am tying to make single instance Electron application.
I am using app.makeSingleInstance , see my sample below.
SingleInstance issue with middle click :
Single Instance works if I click on app.exe 2nd time
It does not work if I middle click on a link inside my app
What I need:
Make electron app singleInstance and ensure it remaisn single instance even with middle click.
I dont want to compeltey disable middle click in my app as at some places, I have a use case for them on non-link items
How to reproduce:
use repo: https://github.com/electron/electron-quick-start
replace existing with my index.html and main.js , see below
npm install and then npm start
index.html:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Hello World!</title></head>
<body>
<h1>app.makeSingleInstance()</h1>
Middle Click on it
</body>
</html>
main.js
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const url = require('url')
let mainWindow
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
if (isSecondInstance) {
app.quit()
}
function createWindow () {
mainWindow = new BrowserWindow({width: 800, height: 600})
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
mainWindow.on('closed', function () {
mainWindow = null
})
}
app.on('ready', createWindow)
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (mainWindow === null) {
createWindow()
}
})
The middle click does not create a new instance of your application, but rather a new instance of a BrowserWindow. You can disable middle-clicks on a (actually all) elements using the auxclick event.
In your main window's HTML you could put the following JavaScript to disable middle-clicks on link elements if you do not want to redirect these events to your default browser:
// The following function will catch all non-left (middle and right) clicks
function handleNonLeftClick (e) {
// e.button will be 1 for the middle mouse button.
if (e.button === 1) {
// Check if it is a link (a) element; if so, prevent the execution.
if (e.target.tagName.toLowerCase() === "a") {
e.preventDefault();
}
}
}
window.onload = () => {
// Attach the listener to the whole document.
document.addEventListener("auxclick", handleNonLeftClick);
}
But you can also choose to redirect the middle-click events to your standard browser, namely via Electron's shell module:
// Require Electron's "shell" module
const { shell } = require("electron");
function handleNonLeftClick (e) {
// e.button will be 1 for the middle mouse button.
if (e.button === 1) {
// Check if it is a link (a) element; if so, prevent the execution.
if (e.target.tagName.toLowerCase() === "a") {
// Prevent the default action to fire...
e.preventDefault();
// ...and let the OS handle the URL.
shell.openExternal(e.target.href);
}
}
}
// Also attach the listener this time:
window.onload = () => { document.addEventListener("auxclick", handleNonLeftClick); }
You could remove the if (e.button === 1) if you also want to block right-clicks on a elements.
I am using Alertify js 1.6.1 to show dialog box when user leaves a page. Apart from Ok and Cancel, I need to add one extra button "continue" in alertify js confirm dialog box. Is there a way to add custom button functionality? Let me know if you have any ideas on it. Thanks
You can build your own or extend the existing confirm:
alertify.dialog('myConfirm', function() {
var settings;
return {
setup: function() {
var settings = alertify.confirm().settings;
for (var prop in settings)
this.settings[prop] = settings[prop];
var setup = alertify.confirm().setup();
setup.buttons.push({
text: '<u>C</u>ontinue',
key: 67 /*c*/ ,
scope: 'auxiliary',
});
return setup;
},
settings: {
oncontinue: null
},
callback: function(closeEvent) {
if (closeEvent.index == 2) {
if (typeof this.get('oncontinue') === 'function') {
returnValue = this.get('oncontinue').call(this, closeEvent);
if (typeof returnValue !== 'undefined') {
closeEvent.cancel = !returnValue;
}
}
} else {
alertify.confirm().callback.call(this, closeEvent);
}
}
};
}, false, 'confirm');
see example
I have created a custom rating widget in openerp using Rateit.
But the widget is always editable, How can i make it editable only when i click 'Edit' button and How do i know it is in readonly mode?
xml
<field name="rating" widget="rating"/>
js
instance.my_module.Rating = instance.web.form.FieldChar.extend({
template : "rating",
init: function(field_manager, node){
this._super.apply(this, arguments);
},
start: function() {
var self = this;
$('#rateit').rateit({
value: 0,
resetable: false
});
},
});
Finally i got it working, here is my code
start: function() {
var self = this;
this.field_manager.has_been_loaded.done(function() {
$('#rateit').rateit({
value: 0,
resetable: false
});
self.field_manager.on("change:actual_mode", self, self.check_actual_mode);
self.check_actual_mode();
});
},
check_actual_mode: function(source, options) {
var self = this;
if(self.field_manager.get("actual_mode")=='view'){
$('#rateit').rateit('readonly',true);
}
else {
$('#rateit').rateit('readonly',false);
}
}