Revive/activate existing panels - vscode-extensions

My extension have sidebar webview that can create additional webviews as panels in the active text editor. Each of these additional webviews is for an unique item and I want to revive/activate existing webview, for the specific item, if it exists.
My issues:
I can get a list of the existing tabs with window.tabGroups.all and loop through the result. But there is no way, as far as i can see, to reactivate the desired tab. I can get some properties from there but no methods. The question here is: is there a API to get a list of the tabs and be able to revive/activate it?
Because of the first point ive decided to keep list of the instances of the additional webviews and when new webview is about the be created im checking if its unique id (in the title) is in the list and if it is then just revive the tab instead of creating a new one. Dont like this approach much but its working. The problem here is when the additional webview is closed. When closed it has to be removed from the array. Ive implemented onDidDispose for the panel but somehow the filter function, inside it, is not called:
// panels: vscode.WebviewPanel[]
// create new panel
const panel = vscode.window.createWebviewPanel(...)
// add the webview instance to the panel
const newWebview = new AdditionalWebview(panel, this.context);
this.panels.push(panel);
panel.onDidDispose(() => {
console.log("Before remove the panel"); // can see this in the console
this.panels = this.panels.filter((p) => p.title != panel.title);
console.log("Before remove the panel"); // for some reason this never appears
});
Not sure why but the panel filter functionality is never triggered (and everything after it is also not ran).
extra question: at the moment the uniqueness of the additional panels is based on their label/title. In my case thats is ok but is there any other way to get unique identifier of each tab? id/guid somewhere?

On your first question about activating a given editor, you have a couple of options.
If you know the editor's index/position in its group. That can be obtained from its tabGroup.tabs position - it seems that the tab's index in that array is faithfully its index in the editor. So you could do a Array.findIndex to get the tab uri you want to set to active.
await vscode.commands.executeCommand('workbench.action.openEditorAtIndex', [indexToOpen]);
// note the [] around the index argument
The only problem with this approach is that it works within the active group only, so you may have to activate the correct group first via:
await vscode.commands.executeCommand('workbench.action.focusSecondEditorGroup');
// or whichever group the tab you want to open is in
Or second method:
// assumes you have the tab
const openOptions = { preserveFocus: true, preview: tab.isPreview, viewColumn: tab.group.viewColumn};
// check if a uri, might be viewtype, etc., instead
if (tab.input instanceof vscode.TabInputText) {
await vscode.commands.executeCommand('vscode.open', tab.input.uri, openOptions);
}
// are your editors regular text editors?
This looks like it is opening a new tab but it will focus an existing tab if one exists at that location with that same uri.

Related

Vuetify Data Table jump to page with selected item

Using Vuetify Data Tables, I'm trying to figure out if there's a way to determine what page the current selected item is on, then jump to that page. My use case for this is, I'm pulling data out of the route to determine which item was selected in a Data Table so when a user follows that URL or refreshes the page that same item is automatically selected for them. This is working just fine, however, I can't figure out how to get the Data Table to display the correct page of the selection.
For example, user visits mysite.com/11
The Data Table shows 10 items per page.
When the user enters the site, item #11 is currently auto-selected, but it is on the 2nd page of items. How can I get this to show items 11-20 on page load?
I ended up using a solution similar to what #ExcessJudgement posted. Thank you for putting that code pen together, BTW! I created this function:
jumpToSelection: function(){
this.$nextTick(() => {
let selected = this.selected[0];
let page = Math.ceil((this.products.indexOf(selected) + 1) / this.pagination.rowsPerPage);
this.pagination.sortBy = "id";
this.$nextTick(() => {
this.pagination.page = page;
});
});
}
I'm not sure why I needed to put this into a $nextTick(), but it would not work otherwise. If anybody has any insight into this, it would be useful to know why this is the case.
The second $nextTick() was needed because updating the sortBy, then the page was causing the page to not update, and since I'm finding the page based on the ID, I need to make sure it's sorted properly before jumping pages. A bit convoluted, but it's working.

Yii2 Gridview get all selected row for all pagination

I wrapped my gridview with Pjax widget like this
\yii\widgets\Pjax::begin();
gridview
\yii\widgets\Pjax::end();
in order to make the gridview make ajax request when I click on each pagination.
I also use ['class' => 'yii\grid\CheckboxColumn'], in column as well.
and I find that when I'm on first pagination I checked some rows and then go to second page and check some rows but when I go back to first page what I've checked is gone.
My question is how can I keep all checkedrow for all pagination
With current conditions (Pjax, multiple pages, yii\grid\CheckboxColumn) it's impossible because of the way it works.
When you click on the pagination links all GridView html content is replaced by new one that comes from the AJAX response.
So obviously all selected checkboxes on the previous page are gone.
Few possible ways to solve that:
1) Write custom javascript and server side logic.
As one of the options, you can send AJAX request to server with parameter meaning that user has chosen to select all data for the bulk delete operation (or use separate controller action for bulk deletion). In this case actually we don't need to get the selected data from user, because we can simply get them from database (credits - Seng).
2) Increase number of displayed rows per page.
3) Use infinite scroll extension, for example this.
4) Break desired action in several iterations:
select needed rows on first page, do action (for example, delete).
repeat this again for other pages.
You can get selected rows like that:
$('#your-grid-view').yiiGridView('getSelectedRows');
[infinite scroll] : http://kop.github.io/yii2-scroll-pager/ will work good if you do not have any pjax filters. If you have filters also in play, do not use this plugin as it does not support pjax filters with it. For rest of the applications it is perfect to use.
Update1 : it seems to be straight forward than expected, here is the how I accomplished it
Add following lines to the checkbox column
'checkboxOptions' => function($data){
return ['id' => $data->id, 'onClick' => 'selectedRow(this)'];
}
Now add following JS to the common js file you will have in your project of the page where this datagrid resides
var selectedItems=[]; //global variable
/**
* Store the value of the selected row or delete it if it is unselected
*
* #param {checkbox} ele
*/
function selectedRow(ele){
if($(ele).is(':checked')) {
//push the element
if(!selectedItems.includes($(ele).attr('id'))) {
selectedItems.push($(ele).attr('id'));
}
} else {
//pop the element
if(selectedItems.includes($(ele).attr('id'))) {
selectedItems.pop($(ele).attr('id'));
}
}
}
Above function will store the selected row ids in the global variable array
Now add following lines to pjax:end event handler
$(document).on('pjax:end', function () {
//Select the already selected items on the grid view
if(!empty(selectedItems)){
$.each(selectedItems, function (index,value) {
$("#"+value).attr('checked',true);
});
}
});
Hope it helps.
I just solved this problem and it works properly with Pjax.
You may use my CheckboxColumn. I hope this can help. The checked items are recorded with cookies.
You can read the part with //add by hezll to understand how to fix it, because I didn't provide a complete general one.
Hope it works for you.
https://owncloud.xiwangkt.com/index.php/s/dGH3fezC5MGCx4H

TableView delete column via contextual menu

It is my first time asking here, sorry if i do something wrong (also not in my mother tongue).
Recently, i moved from Swing&AWT to JavaFX.
I am discovering the new Table which is quite different from the Swing version. Better i would say, it needs less operation and do more things, but ... lord, it's way more difficult to understand !
I am currently trying to modify the TableView dynamically. While the addColumn method is not a big challenge, i need help for my deleteColumn method :/
Let's talk about my problem :
I have a scene with many components on it (panes, buttons, menus, ...) and one pane (actually an anchorpane) hosts a TableView.
I would like to dynamically delete an entire column when this operation occurs :
The user right clicks on the TableView > a contextual menu shows up > he selects the item "delete"
So, basically a contextual menu that offers the option to delete the column where the user right-clicked.
I tried this :
-> When the user right-clicks on the TableView, this method is called :
public void setTargetForContext(ContextMenuEvent event){
if(event.getTarget() instanceof Label){
ObservableList list =(((Label)event.getTarget()).getChildrenUnmodifiable());
activeColumn = ((Text)((ObservableList)list)).getText();
}...
And the goal was to set the column name in "activeColumn".
Then, when the user will select the "delete" option from the contextual menu, another method would be called to compare the name of the columns and delete the right one.
But it seems that i can't call a getChildren() method on the label, only an unmodifiable one. And it does not allow a cast and throw the exception.
Do you have a solution to allow me to get the column name ?
Or maybe i am going the wrong way and i have to find another way to delete the right-clicked column, but in this case i will need your help too.
Thanks a lot for reading, and thanks in advance for your help.
First, let me point out that if you call
table.setTableMenuButtonVisible(true);
then the table will have a built-in menu button with radio buttons allowing the user to select which columns are displayed. Maybe this is all you need.
In Swing, the renderers for table cells are just "rubber stamps" that are painted onto the table. Thus you can't register listeners for UI events with them.
By contrast, in JavaFX, the cells in a table are real UI controls with full functionality. This means there's no real need for API that gets the cell coordinates from a table. You should not register your listener with the TableView, but with the actual cells on which you want to operate. You access the cells from the table column's cell factory.
// the table:
TableView<RowDataType> table = new TableView<>();
//...
// A table column:
TableColumn<RowDataType, CellDataType> column = new TableColum<>("Header text");
// A context menu for the table column cells:
ContextMenu contextMenu = new ContextMenu();
MenuItem deleteColumnItem = new MenuItem("Remove Column");
deleteColumnItem.setOnAction(e -> table.getColumns().remove(column));
contextMenu.getItems().add(deleteColumnItem);
// Cell factory for the column
column.setCellFactory(col -> {
// basically a cell with default behavior:
TableCell<RowDataType, CellDataType> cell = new TableCell<RowDataType, CellDataType>() {
#Override
public void updateItem(CellDataType item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText(null);
} else {
setText(item.toString());
}
}
});
// add the context menu to the cell:
cell.setContextMenu(contextMenu);
return cell ;
});
If you want the context menu to appear in the table column header as well, you just need to do
column.setContextMenu(contextMenu);

Extjs4 Combo's and Stores: Remove filter when queryMode=local?

I'm getting frustrated because my store keeps getting filtered whenever I use it to back a combofield. Is there any way I can disable this?
The Scenario
I have a Store with a data field on it; an array of objects loaded when the store is instantiated. I use this store to drive a bunch of combo's in different areas of my app. Unfortunately, my combos are applying filters on the store, causing other combos using the same store to only display the filtered values later on, not the whole list.
Workarounds
My goofy workaround is to call combo.getStore().clearFilter() after I'm done with the combo, but that's going to get old very quick, and probably introduce a bug somewhere, I'm sure.
If I remove queryMode:'local' from my combo's config, all is well, except that now the handy type-ahead feature no longer works; I'm just shown a list of items in a drop-down that I can't even navigate around my typing letters of matching items. That's worse than a regular html select tag!
Any ideas?
Thanks!
You can't do that since the filtering is applied not on the combo but on the store. You could try creating multiple instances of the same store and work with that. Though I don't know if it'll work.
Ext.create('combo', {
//other config
store : Ext.create('my.store')
});
It'll work if you make the combo non-editable since no filtering can be applied then. But, as you say, you need the type ahead feature, you'll need to create multiple instances of the store.
In light of the fact that combos will add filters on the backing store, hence affecting all combos that use the store within my application, I've opted to add an override to the combo class so it will clear the filter on the store when the combo box is destroyed.
Ext.define('MAP.override.Combo', {
override : 'Ext.form.field.ComboBox',
initComponent : function()
{
this.callParent(arguments);
this.on('beforedestroy',function(combo){
if(combo.leaveFilter === true) return;
console.log('clearing filter on store');
combo.getStore().clearFilter();
});
}
});
it's a bit of a hack, but I do allow for the escape hatch of indicating not to clear the filters, too.
The simplest way I have found to handle this solution is to add the following listener to the combo:
listeners: {
beforequery: function(queryPlan){
queryPlan.query = true;
}
}
by default queryPlan.query is the text currently in the combo field which is used for filtering. Setting it to false cancels the query, but setting it to true allows the query to go through without a filter value, therefore keeping all values in the drop down list for all combo fields.
I've had similar problem with ExtJS 4.2 and combo. Store kept being filtered but I couldn't use clearFilter() because after that combo was unusable. My solution, which worked, is this listener on combo:
listeners: {
blur: function(combo) {
if (combo.queryFilter) {
combo.queryFilter.setValue('');
combo.getStore().filter();
}
}
}

Dojo dnd (drag and drop) 1.7.2 - How to maintain a separate (non-dojo-dnd) list?

I'm using Dojo dnd version 1.7.2 and it's generally working really well. I'm happy.
My app maintains many arrays of items, and as the user drags and drops items around, I need to ensure that my arrays are updated to reflect the contents the user is seeing.
In order to accomplish this, I think I need to run some code around the time of Source.onDndDrop
If I use dojo.connect to set up a handler on my Source for onDndDrop or onDrop, my code seems to get called too late. That is, the source that's passed to the handler doesn't actually have the item in it any more.
This is a problem because I want to call source.getItem(nodes[0].id) to get at the actual data that's being dragged around so I can find it in my arrays and update those arrays to reflect the change the user is making.
Perhaps I'm going about this wrong; and there's a better way?
Ok, I found a good way to do this. A hint was found in this answer to a different question:
https://stackoverflow.com/a/1635554/573110
My successful sequence of calls is basically:
var source = new dojo.dnd.Source( element, creationParams );
var dropHandler = function(source,nodes,copy){
var o = source.getItem(nodes[0].id); // 0 is cool here because singular:true.
// party on o.data ...
this.oldDrop(source,nodes,copy);
}
source.oldDrop = source.onDrop;
source.onDrop = dropHandler;
This ensures that the new implementation of onDrop (dropHandler) is called right before the previously installed one.
Kind'a shooting a blank i guess, there are a few different implementations of the dndSource. But there are a some things one needs to know about the events / checkfunctions that are called during the mouseover / dnddrop.
One approach would be to setup checkAcceptance(source, nodes) for any target you may have. Then keep a reference of the nodes currently dragged. Gets tricky though, with multiple containers that has dynamic contents.
Setup your Source, whilst overriding the checkAcceptance and use a known, (perhaps global) variable to keep track.
var lastReference = null;
var target = dojo.dnd.Source(node, {
checkAcceptance(source, nodes) : function() {
// this is called when 'nodes' are attempted dropped - on mouseover
lastReference = source.getItem(nodes[0].id)
// returning boolean here will either green-light or deny your drop
// use fallback (default) behavior like so:
return this.inhertied(arguments);
}
});
Best approach might just be like this - you get both target and source plus nodes at hand, however you need to find out which is the right stack to look for the node in. I believe it is published at same time as the event (onDrop) youre allready using:
dojo.subscribe("/dnd/drop", function(source, nodes, copy, target) {
// figure out your source container id and target dropzone id
// do stuff with nodes
var itemId = nodes[0].id
}
Available mechanics/topics through dojo.subscribe and events are listed here
http://dojotoolkit.org/reference-guide/1.7/dojo/dnd.html#manager