How to mix your own undo and webContents.undo() in Electron? - menu

I want to handle my own undo/redo menu commands and at the same time still support the Electron built-in undo/redo of the webContents object when it is relevant, for example when the user is focused on a text input element.
This answer seems like a good start, but it is incomplete as it does not address the root question, which is how to mix the two things.
Here is how the ideal code would look like when defining the menu item:
{
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
click: function(menuItem, focusedWin) {
if (*** focusedWin.webContents thinks it can handle it ***) {
focusedWin.webContents.undo();
} else {
// Run my own code
}
}
}
The one dollar question is: how do I code the "if focusedWin.webContents thinks it can handle it" test?

I found a solution to my problem. It's not elegant, but it works. The idea is that the built-in Edit menus such as undo/redo/cut/copy/paste/delete/etc. should be managed by the webContents object only when the user is focused on an input or textarea element.
So in my index.html file, I send a message to the Main process when there is a focus or a blur event on input elements. This sets a global variable (yuck!) on the main process side which is used to make the decision between letting webContents do its job or doing it ourselves.
In index.html (I use jQuery and the great messaging system described in this other thread):
//-- Tell the main process if the preset Edit menus should be activated or not.
// Typically we active it only when the active item has text input
$('input').focus(() => window.api.send("menus:edit-buildin", { turnItOn: true }));
$('input').blur(() => window.api.send("menus:edit-buildin", { turnItOn: false }));
In main.js:
// This is a global :-( to track if we should enable and use
// the preset Edit menus: undo/redo/cut/copy/paste/delete
var menusEditPreset = false;
// Listen to the renderer
ipcMain.on("menus:edit-buildin", (event, { turnItOn }) => {
menusEditPreset = turnItOn;
});
// ... and in the menu definition:
{
id: 'undo',
label: 'Undo',
accelerator: 'CmdOrCtrl+Z',
click: (event, focusedWindow, focusedWebContents) => {
if (menusEditPreset) {
focusedWindow.webContents.undo();
} else {
console.log("My own undo !");
}
}
},

Related

Cypress: How to know if element is visible or not in using If condition?

I want to know if an element is visible or not. I am not sure how to do that.
I know that we can run this:
cy.get('selector').should('be.visible')
But if element is invisible then test is failed. So I just want a boolean value if element is not visible so I can decide through if condition.
Use case:
I want to open a side menu by clicking on the button only if sidebar is invisible.
if(sidebarIsInvisible){
cy.get('#sideMenuToggleButton').click();
}
Is this possible?
I really appreciate for any contribution.
Thanks in advance
Cypress allows jQuery to work with DOM elements so this will work for you:
cy.get("selector_for_your_button").then($button => {
if ($button.is(':visible')){
//you get here only if button is visible
}
})
UPDATE: You need to differentiate between button existing and button being visible. The code below differentiates between 3 various scenarios (exists & visible, exists & not visible, not exists). If you want to pass the test if the button doesn't exist, you can just do assert.isOk('everything','everything is OK')
cy.get("body").then($body => {
if ($body.find("selector_for_your_button").length > 0) {
//evaluates as true if button exists at all
cy.get("selector_for_your_button']").then($header => {
if ($header.is(':visible')){
//you get here only if button EXISTS and is VISIBLE
} else {
//you get here only if button EXISTS but is INVISIBLE
}
});
} else {
//you get here if the button DOESN'T EXIST
assert.isOk('everything','everything is OK');
}
});
You can also use my plugin cypress-if to write conditional command chains
cy.get('...').if('visible').click()
Read https://glebbahmutov.com/blog/cypress-if/
try this code:
isElementVisible(xpathLocater) {
this.xpath(xpathLocater).should('be.visible');
};
isElementNotVisible(xpathLocater) {
this.xpath(xpathLocater).should('not.exist');
};
then use these two methods with if statement like shown below:
if(isElementNotVisible) {
}
or
if(isElementVisible) {
}

Microsoft Bot framework session.endDialog() use

I read the Bot document somewhere people posted if you replace dialog then previous dialog store in stack and stored somewhere.
Now I tried to follow the way to endDialog() then replaceDialog();
callRequest.GetWebAPICall(session, urlData, function (body) {
if(body.statusCode == 200) {
if(body.data == undefined) {
builder.Prompts.choice(session,Want to Select List?", "Yes|No",{listStyle: builder.ListStyle.button});
} else {
session.endDialog();
session.replaceDialog('/Show List');
}
} else {
session.send('Something went wrong. You can use the back or top command.');
session.replaceDialog('/menu');
}
});
For need to know if I replace below lines
session.endDialog();
session.replaceDialog('/Show List');
by
session.endDialog('/Show List');
No. endDialog() doesn't have the functionality to start a new dialog. You can refer to the function definition interface endDialog(message?: TextOrMessageType, ...args: any\[\]): Session;.
In your case, '/Show List' would be sent to the user as a message.
And there is also a misunderstanding about replaceDialog().
Ends the current dialog and starts a new one its place. The parent dialog will not be resumed until the new dialog completes.
If you need to store the previous dialog, you can use beginDialog()

Ember Save a change to an attribute

Very new to Ember, quick question please: How do I save/persist a change to an attribute? Have the following action in the controller:
actions: {
togOnField: function(){
if (this.get('onField')){
this.set('onField', false);
} else {
this.set('onField', true);
}
}
}
Looking around I've found
this.get('model').save
At the moment, using this, the attribute is immediately reverting back to its previous state. Does this mean the save is unsuccessful? Working with a Sails API and Postgres DB, both seem to be working fine.
And what are the different options for how I might save from this action? Thanks a lot.
this in that controller refers to the controller, probably not the model as you expect. One thing you can do is pass in the model to the action.
In your template,
<button {{action 'toggleOnField' user}}>Toggle on field</button>
Then the action becomes
actions: {
toggleOnField: function(user) {
user.toggleProperty('onField').save().then(function() {
// do something
}, function(reason) {
// handle error
});
}
}

How do I track whether a context menu item is already created by my Chrome Extension?

There are only four methods for chrome.contextMenus:
create
update
remove
removeAll
I am wondering how do I check whether one menu is already created?
I tried this:
try {
chrome.contextMenus.update("byname", {});
} catch (e) {
// doesn't exist
}
But it seems the error cannot be caught (but shown in the console).
Thanks for any kind of tips!
Each chrome.contextMenus.create call returns an unique identifier. Store these identifiers in an array or hash to keep track of them.
This is a direct solution to anyone having the op's problem, based on the suggestion by Rob W. The idea is to maintain your own list of existing context menu id's.
By using these wrapper functions to maintain context menu entries, also the removal and updates are being kept track of (addressing Fuzzyma's comment).
Usage works like Chrome's own methods, eg. createContextMenu({id: "something"}, onclick). It works for me.
let contextMenus = {}
// method to create context menu and keep track of its existence
function createContextMenu() {
if (arguments[0] && arguments[0].id) {
// TODO: not sure if this will work properly, is creation synchronous or asynchrounous?
// take in to account calll back and the runtime error?
chrome.contextMenus[arguments[0].id] = chrome.contextMenus.create.apply(null, arguments);
}
}
function updateContextMenu() {
if (arguments[0] && contextMenus[arguments[0]]) {
chrome.contextMenus.update.apply(mull, arguments);
}
}
function removeContextMenu() {
if (arguments[0] && contextMenus[arguments[0]]) {
chrome.contextMenus.remove.apply(null, arguments);
contextMenus[arguments[0]] = undefined;
}
}
function contextMenuExists(id) {
return !!contextMenus[id];
}

CKEditor 3 Dialog Positioning

I have checked and tried the method posted here to set where CKEditor dialogs pop up:
Programatically set the position of CKEditor's dialogs
This seems to either be deprecated or incomplete. When attempting this for the 'link' dialog, the dialog box does not format correctly, as if this onShow definition replaces the default action rather than adding to it. Any suggestions to alter this code or a new method to position the link dialog closer to the menu bar?
CKEDITOR.on('dialogDefinition', function(e) {
var dialogDefinition = e.data.definition;
dialogDefinition.onShow = function() {
this.move(200, 100);
}
})
You're right. Your code is overwriting the basic onShow definition.
What you have to do is simply to save a default (generic) onShow, then overwrite it so it calls the saved one and eventually executes your code:
CKEDITOR.on( 'dialogDefinition', function( event ) {
var dialogDefinition = event.data.definition,
genericOnShow = dialogDefinition.onShow;
dialogDefinition.onShow = function() {
genericOnShow.apply( this );
this.move( 10, 10 );
// ...or anything you want ;)
}
});
VoilĂ !
PS. Remember to always pass the context with apply or call.

Resources