How to Prevent Widgets from Drag and Drop

Hi, Contributors

I’m a very interested user of theia.

I am currently looking for a way to prevent drag and drop movement of widgets.

The method I’m currently trying is to create a class in my contribution that extends ApplicationShell

handleEvent to return an event if the id of the currently active widget has the id of the widget I want to prevent,

event to be returned if the currently active widget has the id of the widget I want to block.

In module.ts, I bind my Contribution with Bind(MyContribution).toSelf().inSingletonScope() and then call

bind(ApplicationShell).toService(MyContribution).

But when I run it, I get infinite loading.

I would appreciate any feedback on where I am thinking wrong.

@VICTUS thank you for the discussion, if you open your devtools you should see errors as to why you’re infinitely loading. My guess is something is wrong with your binding.

My guess is that the binding is incorrect, because commenting out the bind implementation makes it run correctly.

Below is my implementation of the Contribution, module file:

Contribution File =================================================

import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
import { injectable } from '@theia/core/shared/inversify';

@injectable()
export class MyContribution extends ApplicationShell {
  handleEvent(event: Event): void {
    const activeWidget = this.activeWidget;

    if (activeWidget && activeWidget.id === 'my-widget-id') {
      return;
    }

    super.handleEvent(event);
  }
}

Module File =====================================================

import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell';
import { MyContribution } from './my-contribution';
import { ContainerModule } from '@theia/core/shared/inversify';

export default new ContainerModule((bind) => {
  bind(MyContribution).toSelf().inSingletonScope();
  bind(ApplicationShell).toService(MyContribution);
});

@VICTUS what specific error do you see on startup, it should tell you what you should look for.

My console doesn’t show anything that looks like an error.

But, just says that the BackendApplication has finished loading, and I don’t see any logs of the FrontendApplication starting.

My guess is that the backend service has finished loading normally, but the frontend service cannot be started.

@VICTUS you mentioned that your frontend is infinitely loading, so you should check the devtools console as I mentioned to see errors, not the backend terminal from which you started the application. I suspect you should see errors regarding your bindings.

devtools console means this capture?

@VICTUS that’s right, now you can see that you have issues with your ApplicationShell binding and it is causing an infinite loading.

You’ll instead want to rebind the ApplicationShell to your custom implementation:

export default new ContainerModule((bind, unbind, isBound, rebind) => {
    rebind(ApplicationShell).to(MyContribution).inSingletonScope();
});

Keeping an eye on devtools when I get an error in Theia can give me a big hint!
I fixed the bind error in ApplicationShell with the rebind you mentioned, thank you.

Also, if you have extended the ApplicationShell in your contribution, you can use the

Is it possible to use this.activeWidget to get the id of the currently clicked widget?

Also, if you have extended the ApplicationShell in your contribution, you can use the
Is it possible to use this.activeWidget to get the id of the currently clicked widget?

I assume you mean if you extend ApplicationShell can you still use activeWidget?
Given you did not override the implementation for activeWidget it should work as before, and if a widget is active you should be able to obtain it’s id.

Yes, that’s exactly what I meant.

The reason i used this.activeWidget because I want to prevent that when the user try to drag and drop,

So i try it like my Contribution code I provided above, it would prevent drag and drop as I expected, but it fails because this.activeWidget returns undefined.

I’d like to know what I’m thinking wrong.

@VICTUS to actually disable drag-and-drop it may be a little more difficult, the behavior as far as I am aware comes from phosphorjs, more notably the DockPanel.

There are the following options which enable the feature:

If you were to override these properties in theia-dock-panel.ts then you could disable dnd, but you’ll need to find a way to only do so for your widget (which may be difficult as this disables dnd in the panel itself).

The 3 features of DockPanel you mentioned are declared as private in the class, so I can’t override them.

In theia-dock-panel.ts, I don’t see any methods related to the three drag features you mentioned. Can you tell me which methods you are asking me to override?

@VICTUS they are private but still overridable using bracket notation, like other examples in TheiaDockPanel:

You can do the same:

this['_evtDragEnter'] = () => {};
this['_evtDragLeave'] = () => {};
this['_evtDragOver'] = () => {};

Oh, so there’s a way to override private by using a bracket notation. That’s new to me.

I used your method to prevent the Widget from dnd event anymore.

Now I need to think of a way to apply this method to prevent it only in certain areas of the ApplicationShell or if the widget has a specific id.

Thanks for your help