swisnl / jQuery-contextMenu

jQuery contextMenu plugin & polyfill
https://swisnl.github.io/jQuery-contextMenu/
MIT License
2.25k stars 744 forks source link

Not usable with webcomponents (because of ShadowDom?) #325

Open jogibear9988 opened 8 years ago

jogibear9988 commented 8 years ago

I will use the Menu in a web-component (Polymer), but that does not work!

I think it's because of the Dom encapsulation (I can give only a selector, not a list of elements to wich the menu should apply, and the selector does not work cause of shadow dom)

bbrala commented 8 years ago

Hmm, i dont really have much handon experience with polymer, so i can't really help you right now. I might be able to help you if you have a page somewhere where i can look.

jogibear9988 commented 8 years ago

The problem is Polymer (or Webcomponents) uses ShadowDom to encapsulate Elements, so you can't access it's children via jquery and a selector. So it would be cool, if you have a Extra Method to wich I can supply my selected Elements to wich the Context Menu should be applied!

jogibear9988 commented 8 years ago

Maybe we can also enhance your Polyfill, so that already when I add the Script to the Page "menu" elements are polyfilled (so work the most polyfills), without calling a method! And also Menu Elemnts in ShadowDom should be polyfilled (don't know how this will be possible)

bbrala commented 8 years ago

The menu elements can be polyfilled automaticly, (see http://swisnl.github.io/jQuery-contextMenu/docs/html5-polyfill.html). But this might indeed nog be the case for the ShadowDom elements.

Again tho, would you be able to put of a small test page where i can check and test?

jogibear9988 commented 8 years ago

yes they can, but they were not if i I use "

" in a webcomponent! And also many other polyfills require only to include the javascript and will then work, yours need to be called after the page with "" was loaded (if I'm correct..)

I'd look to create a Example in JSFiddle

jogibear9988 commented 8 years ago

look at https://jsfiddle.net/tpw7to3b/3/ - when you change from "shady" to "shadow" the menu does not work any more (you need to test in chrome, the other browsers will ship shadowDom in the next releases)

jogibear9988 commented 8 years ago

And one with the HTML5 Polyfill https://jsfiddle.net/qok36dab/1/ (also, use Chrome)

bbrala commented 8 years ago

I've been looking into this, and adding support for shadow DOM is kind of hard at the moment. The plugin is made to be as fast as possible because it doesn't bind on single elements. This created the problem is listens to the root document and opens on the elements that fit the selector.

The problem with the shadow root is since it is isolated the plugin would need to bind to the first html element in the shadowdom, in order to do this there is quite a lot of code that needs rewriting.

Another problem is that jQuery positioning currently doesn't really support the shadowdom that well, which is a problem if you try to position the menu on the proper clicked element.

Conclusion is that i currently dont see how i can implement this in a reasonable amount of time.

jogibear9988 commented 8 years ago

I'm looking into this in the first weeks of next year, cause we need it for a customer site! Maybe I get a good idea and then I will write here again!

jogibear9988 commented 8 years ago

I've found this: http://stackoverflow.com/a/28028150/579623 maybe this helps?

jogibear9988 commented 8 years ago

But of cause this should not only be fixed for polymer this should be fixed for all libraries wich are using webcomponents

jogibear9988 commented 8 years ago

I've don a few changes:

line 1414 from

    if (!o.context || !o.context.length) {
        o.context = document;
    } else {

to

    if (!o.context) {
        o.context = document;
    } else {

line 1450 from

                $document
                    .on({

to

                $context
                    .on({

and line 1473 from

            $context
                .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu);

to

            $context
                .on('contextmenu', o.selector, o, handle.contextmenu);

but it does not work ;-(

the context menu now is added correctly to the dom of my component when I use it like this:

        $.contextMenu({
            selector: '.mfc-place-context-menu',
            callback: function (key, options) {
                var m = "clicked: " + key;
                window.console && console.log(m) || alert(m);
            },
            appendTo: self.$.rpdiv,
            context: self.shadowRoot,
            items: {
                "edit": { name: "Edit", icon: "edit" },
                "cut": { name: "Cut", icon: "cut" },
                copy: { name: "Copy", icon: "copy" },
                "paste": { name: "Paste", icon: "paste" },
                "delete": { name: "Delete", icon: "delete" },
                "sep1": "---------",
                "quit": {
                    name: "Quit", icon: function () {
                        return 'context-menu-icon context-menu-icon-quit';
                    }
                }
            }
        });

as you see, i set the context to self.shadowroot, but the menu is not opened... any help?

bbrala commented 8 years ago

Yeah i tried the same, there is also a few places where $(document) is called. These would need to change also.

Another thing i read is that the positioning of an element in a shadow root can't be calculated correctly, but i didnt double check that so that might not be an issue.

jogibear9988 commented 8 years ago

But do you have an Idea why it would not open?

jogibear9988 commented 8 years ago

I've also created a fiddle with my changes: https://jsfiddle.net/bz6774nj/4/

bbrala commented 8 years ago

Not sure, but i would guess it would be the click handler is on the parent document, and not somewhere in the shadowroot.

EliteScientist commented 4 years ago

I'm currently trying to do the same thing. the shadowRoot does not have the "contextmenu" event. I've had success using the element itself as the context to put the event on. The issue that I'm running into right now is that the "currentTarget" property of the MouseEvent is always null. This library attempts to get the current target and set it as the trigger.

My next test will be to iterate through the event's "path" array until' I find an item that matches the selector then use that as the trigger

rafalsk commented 2 years ago

Hey folks! Great stuff the component... we've been using it heavily in GRIDNET OS (https://gridnet.org) still.. we just ran into a serious problem... it does not handle Shadow DOM.. which is of extreme importance in UI dApps.... It would die right here when doing initialization.. during the 'create' event.... effectively no contextmenu events are bound.. preventing the menu from being opened... also.. seems like the 'appendTo' option is broken when in ShadowDom.. as under the hood the plugin seemingly attempts to convert passed object to an identifier... which doesn't exist. anyway it dies right here

// engage native contextmenu event $context.on('contextmenu' + o.ns, o.selector, o, handle.contextmenu);