Electron modify a single menu item? - javascript

So, I'm building a softare using electron. Now I can add menu in the software from a template
var menu = Menu.buildFromTemplate([
{
label: 'Menu',
submenu: [
{label:'open'},
{label:'save'},
{label:'Exit'}
]
}
])
Menu.setApplicationMenu(menu);
But how do I modify a single menu item. For example, say, the save menu is disabled by default and activated after the open is clicked. Also say after clicking open a new menu edit appears. I can create the complete new template in full and just change the previous template with the new. But thats a bad way and can't be a practical solution when I'm using several menus with several submenus. So can I modify just one single menu item of my choice?

You can get the menu items using:
import { Menu } from 'electron';
Menu.getApplicationMenu().items // all the items
Menu.getApplicationMenu().getMenuItemById('MENU_ITEM_ID') // get a single item by its id
After that you have several properties on the single menu item as:
- checked
- enabled
- visible
- label
- click
And you can customize your behavior as you want to.
Tested with electron 3.0.5, before the 27 Sep 2017 the method getMenuItemById was not there and you had to loop over all the items.

Related

Cypress unable to select multiselect with loop

I am writing a React application that I'm testing with Cypress. In my integration tests I've written a cypress command that takes an array of strings, in order to select items in a multi-value select box.
The code I'm using looks roughly like this:
Cypress.Commands.add("command", (options) => {
options.forEach((option) => {
cy.get("div[data-g-portal-id='1']") // this is the container for the select box dropdown
.find("div[role='menubar']")
.contains(option)
.click({ force: true });
});
}
I've tried various iterations of this, including things like cy.wrap and .each. Whatever I do, when the array contains more than one item, it clicks one item, the item is marked as selected successfully, then it clicks the other item, marks it as selected, but the first item loses its selection state. Its as if the internal state of the component never really got the initial change.
I've confirmed this is not a bug in my application; when testing it manually, the multi-select works fine. But Cypress just doesn't want to know. Any help would be much appreciated.
The v2.grommet.io/select uses a "portal" to display the dropdown options.
The portal is just a div that's appended to body when the dropdown opened and removed again when an option is clicked.
Problem is, there isn't a property to connect the dropdown and portal containing the options. There may be other portals present e.g the Layer component uses a portal.
The options portal we need to target will always be the last portal on the page (since we just opened the dropdown). In the custom command, applying the .last() command will select the options portal.
Cypress.Commands.add("multiselect", (options) => {
options.forEach((option) => {
cy.get(`[data-g-portal-id]`)
.last() // just opened the dropdown so option are in the last portal
.find("div[role='menubar']")
.contains(option)
.click();
});
});
cy.get('input[name="my-select"]')
.click(); // open dropdown
.multiselect(['First', 'Third']);
cy.get('input[name="my-select"]')
.click(); // close dropdown
cy.get('input[name="my-select"]')
.should('have.value', 'multiple')
The test ends with dropdown displaying the text "multiple".
Configuration of the Select,
<Select
multiple // allow multiple selected options
closeOnChange={false} // do not close the dropdown between selections
name="my-select"
options={myOptions}
...
/>

Tabulator context menu won't show

I have a problem with Tabulator.js library. I am usig version 4.8, I would like to use context menu feature, but I am unable to make it work. When I use code from documentation (see bellow) browser default context menu is replaced by nothing (nothing shows up). I was not able to find answer to this. Is here someone with similar experience? I have tried three different browsers,but behavior appears to be same in every one of them.
rowContextMenu: [
{
label:"Hide Column",
action:function(e, column){
column.hide();
}
},
{
separator:true,
},
{
disabled:true,
label:"Move Column",
action:function(e, column){
column.move("col");
}
}
]
Unfortunately the example is in error. The rowContextMenu action function does not provide a Column component. It provides a Row component.
If you want to manipulate a column you will need to setup Column Menus. Start by looking here and scroll down to see the other options - http://tabulator.info/docs/4.8/menu#header-menu.
For Rows look at Row Context Menus - http://tabulator.info/docs/4.8/menu#row-context
Unfourtunately, it was all my mistake, I surely did update tabulator js version but forgot to change CSS file, so menu was working right but was shown as div without styling on the bottom.

Dashcode mobile web app dynamic list row labeling

I'm trying to put together a mobile web app using Apple's Dashcode.
I would like to use a Rounded Rectangle List as a menu interface for my users, however, I cannot seem to change the various rows' labels in a dynamic list.
Here is the javascript for my list:
var dayController = {
/* categoryList will display these items */
_rowData: ["iPods", "Macs", "Applications"],
/* categoryListController must implement the numberOfRows and prepareRow functions */
/* This method is used to find out how many rows should be in the list */
numberOfRows: function() {
return this._rowData.length;
},
/* categoryList calls this method once for every row. */
prepareRow: function(rowElement, rowIndex, templateElements) {
/*
templateElements contains references to all elements that have an id in the category template row.
We use the lines below to update the list with each category item in _rowData.
*/
if (templateElements.categoryLabel) {
templateElements.categoryLabel.innerText = this._rowData[rowIndex];
}
/* Assign an onclick handler that will cause the browser to go a page
showing all products related to this category item, when clicked
*/
var self = this;
var handler = function() {
/* Get the category item associated with this row */
var category = self._rowData[rowIndex];
};
rowElement.onclick = handler;
}
};
I want to be able to assign the rowData[] as the labels for the rows in the lists, but I can't seem to get it to work.
I'm guessing I need to change something with the prepareRow function, right?
Has anyone successfully used JQuery with Dashcode to build a web app? Perhaps that would be a better approach.
Erm wouldn't you set the rounded rectangle in the css and not the javascript?
You can use Dashcode to make the web app but there other alternatives, rather a lot these days actually. However there was a JS framework called JQTouch, built on top of JQuery for doing this. JQTouch has now beed subsumed into Extjs and all of it rename Sechcha Touch. I would suggestyou go an look at that as a more flexible alternative.
I found Dashcode excellent for building Mac Widgets but much more limited for web based iPxx apps.

Ext JS removeAll(false) behaviour

I have been using the following snippet of code in my app to drive a menu that contains different trees depending upon what is selected. It tries to create tree panels only once and to then reuse them if they are selected again, i.e. to keep the trees expanded state.
var west = Ext.getCmp("west-panel");
west.removeAll(false);
west.doLayout();
var existingPanel = Ext.getCmp('component-tree-project-' + systemId);
if (existingPanel) {
west.add(existingPanel);
west.doLayout();
return;
}
//... code to add create and add a new tree panel
The problem is with west.removeAll(false), the false stops the nodes getting destroyed but they do not appear back in the panel. The panel sticks to showing what it last had in it.
Using west.removeAll(true) works fine except for the fact that new panels are always created.
Should not statement be west.removeAll(true);

Javascript syntax for objects in jquery

I am trying to enhance my page with a jquery right mouse menu, but am having trouble building the correct structures to populate it easily.
Currently my page contains (among other things) a list of items for the user to review. (an html table) Based on the users role, and the current state and context of the row, the user may take one of various actions on each row of data. (approve, reject, refer it to someone else, ect.) My ASP.Net page handles this by setting the visibility of an imagebutton within the row to true, if the option is available. I can control the Cssclass of each button, and am setting the class of for example the "approve" button to “approvebtn”.
Now I want to enhance my site with a right menu.
I am extending my site with Cory S.N. LaViska’s jQuery Context Menu Plugin -
http://abeautifulsite.net/notebook/80
This plugin allows the default right mouse behavior for any elelement to be overridden with a user controlled context menu. The menu is inserted into your page as an unordered list and becomes visible when it is needed.
<ul id="rightMenu" class="contextMenu">
<li class="details">Details </li>
<li class="addnote">AddNote </li>
<li class="listnote">ShowNotes </li>
<li class="approve">Approve </li>
<li class="reject">Reject </li>
<li class="release">Release </li>
<li class="takeover">Takeover </li>
</ul>
Your app gets a callback when something on the right menu is clicked, and you can interrogate the action (the bogus href element) to see which item it was.
I really like this menu because it is simple to use and is completely CSS styled.
However, I need to do something that this plugin does not nativly seem to support. I need to change which items are available on the menu from row to row. Basically if an Imagebutton (for say approve) is avaiable in the row, then its corrisponding menu item should exist as well.
I was able to gain access to the menu just before it is displayed by altering the plugin slightly, to call my function right before the menu is displayed.
This works, but the logic I had to write seems so brute force, that there must be a better way….
In my callback:
function jimsbuggeredfunction(menu,el)
"el" is the element that was right clicked on (usually a table cell), and "menu" is the menu that this right click is bound to. (so I should be using that name and not hardcoding to #rightMenu')
So, the “if” line finds out if the table row containing the element that was “right clicked” contains a specific button (by its class name) if it does the menu item is enabled, otherwise it is disabled. This process continues for every menu item that I want to be flexable row-to-row.
function jimsbuggeredfunction(menu,el) {
if($(el).parents("tr:eq(0)").find('.approvebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#approve');
else
$('#rightMenu').disableContextMenuItems('#approve');
if($(el).parents("tr:eq(0)").find('.rejectbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#reject');
else
$('#rightMenu').disableContextMenuItems('#reject');
if($(el).parents("tr:eq(0)").find('.releasebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#release');
else
$('#rightMenu').disableContextMenuItems('#release');
if($(el).parents("tr:eq(0)").find('.takeoverbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#takeover');
else
$('#rightMenu').disableContextMenuItems('#takeover');
if($(el).parents("tr:eq(0)").find('.revertbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#revert');
else
$('#rightMenu').disableContextMenuItems('#revert');
if($(el).parents("tr:eq(0)").find('.removebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#remove');
else
$('#rightMenu').disableContextMenuItems('#remove');
if($(el).parents("tr:eq(0)").find('.addnotebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#addnote');
else
$('#rightMenu').disableContextMenuItems('#addnote');
if($(el).parents("tr:eq(0)").find('.listnotebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#listnote');
else
$('#rightMenu').disableContextMenuItems('#listnote');
};
There must be a better way to set this up, so that it also just ignores menu items that I want to display all of the time) but it is escaping me at the moment. Is there a better way to accomplish this?
Thanks,
Jim
I would find some way to create a mapping between the two IDs and some more systematic way of finding the relevant button. For example, if the button always belongs inside a certain cell that has a class, let's say "buttonclass", then something like this should work:
var mapping = {
takeoverbtn: '#takeover',
listnotebtn: '#listnote'
// ...
};
function jimsbuggeredfunction(menu,el) {
var buttontype = $(el).parents("tr:eq(0)").find('.buttonclass').children().attr("class");
$('#rightMenu').disableContextMenuItems(mapping[buttontype]);
}
My jQuery is a little rusty, there's probably a cleaner way of retrieving the buttontype, but that general idea ought to work.

Categories

Resources