infor-design / enterprise

Enterprise-grade component library for the Infor Design System
https://design.infor.com
Apache License 2.0
134 stars 81 forks source link

PopupMenu: Custom menu in response to OnContextMenu event no longer works on table since IDS 4.23 #3435

Closed sanx72 closed 4 years ago

sanx72 commented 4 years ago

In our code we have a oncontextmenu event on the body of the page so that when the user right-clicks anywhere on the page, we can then show our own menu using the PopupMenu control with the "immediate" option.

This used to work OK on all IDS controls until we upgraded to IDS 4.23. Now, it no longer works on the DataGrid. Right Click on the DataGrid causes a JQuery Event instead of a MouseClick Event which then breaks the PopupMenu call which expects a MouseEvent (I think).

Tested in Chrome and Firefox (latest versions) on Windows 8.1

Here is an example code fragment you can plug into your standard IDS template (full page test included as ZIP attachment)...

<section id="maincontent" class="page-container scrollable" role="main">
      <div class="row top-padding">
        <div class="six columns">
          <h2>Popupmenu configured to trigger immediately on right-click</h2>
        </div>
      </div>
    <div class="row">
        <div class="twelve columns">
          <div id="datagrid" class="datagrid">
          </div>
        </div>
      </div>
      <ul id="menu" class="hidden" style="min-width: 250px;">
        <li>
          <a href="#">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use xlink:href="#icon-filter"></use>
            </svg>
            <span>Filtering...</span>
          </a>
        </li>
        <li class="separator"></li>
        <li>
          <a href="#">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use xlink:href="#icon-like"></use>
            </svg>
            <span>Like</span>
          </a>
        </li>
        <li>
          <a href="#">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use xlink:href="#icon-like"></use>
            </svg>
            <span>Dislike</span>
          </a>
        </li>
        <li>
          <a href="#">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use xlink:href="#icon-new"></use>
            </svg>
            <span>Favorite</span>
          </a>
        </li>
        <li class="separator"></li>
        <li>
          <a href="#">
            <svg class="icon" focusable="false" aria-hidden="true" role="presentation">
              <use xlink:href="#icon-settings"></use>
            </svg>
            <span>Settings</span>
          </a>
        </li>
      </ul>

      <script nonce="09371041">
        document.body.oncontextmenu = function(evt) {
            window.console.log(evt);
            $("body").popupmenu({ 
                    menu: $('#menu'), 
                    trigger: "immediate", 
                    useCoordsForClick: true,
                    eventObj: evt
                });
            return false;
        }

        $('body').one('initialized', function () {

            var columns = [];

            $.getJSON('//latest-enterprise.demo.design.infor.com/api/datagrid-sample-data', function(res) {

              //Define Columns for the Grid.
              columns.push({ id: 'productId', hideable: false, name: 'Id', field: 'productId', reorderable: true, formatter: Formatters.Text, width: 100});
              columns.push({ id: 'productName', name: 'Product Name', field: 'productName', reorderable: true, formatter: Formatters.Hyperlink, width: 300, minWidth: 100});
              columns.push({ id: 'activity', name: 'Activity', field: 'activity', reorderable: true});
              columns.push({ id: 'hidden', hidden: true, name: 'Hidden', field: 'hidden'});
              columns.push({ id: 'price', align: 'right', name: 'Actual Price', field: 'price', reorderable: true, formatter: Formatters.Decimal, numberFormat: {minimumFractionDigits: 0, maximumFractionDigits: 0, style: 'currency', currencySign: '$'}});
              columns.push({ id: 'percent', align: 'right', name: 'Actual %', field: 'percent', reorderable: true, formatter: Formatters.Decimal, numberFormat: {minimumFractionDigits: 0, maximumFractionDigits: 0, style: 'percent'}});
              columns.push({ id: 'orderDate', name: 'Order Date', field: 'orderDate', reorderable: true, formatter: Formatters.Date, dateFormat: 'M/d/yyyy'});
              columns.push({ id: 'phone', name: 'Phone', field: 'phone', reorderable: true, formatter: Formatters.Text});

              //Init and get the api for the grid
              $('#datagrid').datagrid({
                columns: columns,
                dataset: res,
                saveColumns: false,
                toolbar: {title: 'Compressors', results: true, actions: true, rowHeight: true, personalize: true}
              });
            });
       });        
      </script>
    </section>

In the console, right-click on the page shows a MouseEvent and right-click on the table shows a JQuery Event...

image

testPage.zip

How do work around this so that oncontextmenu can be used for datagrid and all other controls?

tmcconechy commented 4 years ago

The problem with your code is that the datagrid has its own context menu events so presumably its firing that one rather than the body context menu event. All you need to do is switch to using the event on the datagrid rather than the body.

We have several examples of context menus on the datagrid: http://latest-enterprise.demo.design.infor.com/components/datagrid/test-contextmenu.html http://latest-enterprise.demo.design.infor.com/components/datagrid/test-contextmenu-on-specific-columns.html http://latest-enterprise.demo.design.infor.com/components/datagrid/test-contextmenu-in-events.html http://latest-enterprise.demo.design.infor.com/components/datagrid/test-contextmenu-firstclick.html http://latest-enterprise.demo.design.infor.com/components/datagrid/test-contextmenu-dynamic.html

Best way thats closest would be..

 $('#datagrid').datagrid({
      columns: columns,
      dataset: data
    }).on('contextmenu', function (e, args) {
      console.log('contextmenu fired do your popupmenu', args);
    });

https://github.com/infor-design/enterprise/blob/master/app/views/components/datagrid/test-contextmenu-dynamic.html#L68

Possibly this is due to being able to now veto the contextmenu event manually but this is the opposite of what your doing.... Potentially this line https://github.com/infor-design/enterprise/blob/master/src/components/datagrid/datagrid.js#L6015

Other workarounds... Turn off ours..

 $('#datagrid').off('contextmenu.datagrid');

Or attach to both

$('body, #datagrid').on('contextmenu', function () {
   window.console.log(evt);
  $("body").popupmenu({...});
   return false;
});
sanx72 commented 4 years ago

@tmcconechy $('#datagrid').off('contextmenu.datagrid'); works in the testPage example so I'll try that in our production code, thanks

tmcconechy commented 4 years ago

Considering this done as long as you can make that work

sanx72 commented 4 years ago

Switching the event off immediately after we create data grids in our application restores the original behaviour so happy to go with that.