Context Menu on IOS

2842
1
06-06-2017 04:51 PM
JamesFaron
Occasional Contributor

I have a similar question as asked previously in the forum here. I have implemented the context menu in an app and it works with long press on android, but not on ios. I tried the esri context menu sample and it too fails on ios.  I know that ios handles mouse events natively, and they don't bubble by default, but I have followed all the published advice, including adding 'pointer: cursor; to all nodes in the DOM, and created empty mouse events (click handlers) in the code, but I can only get alerts to work when inserted into the click handlers that I create, using touchstart or mousedown as the event, and even tried to use 'contextmenu' event, but that doesn't work on ios either. I can't tell how far the long press gets: It seems to be a problem with dojo menu.js, but I have not had the opportunity yet to debug an ipad on a mac (I use Windows at work, and the Chrome simulator cannot simulate native ios mouse events: the context menu works fine in the Chrome simulator).

The gist of the problem is described here and here and here.

Since the esri sample doesn't seem to work on ios either, I wonder if the esri javascript api supports ios fully or even well? An app that does not work on iPad is not going to be successful.

I hope there is a work-around. I am using the bower build, so I do have access to the menu.js, if it is necessary to adjust anything there. Any help would be greatly appreciated.

Thanks,

Jim Faron

0 Kudos
1 Reply
JamesFaron
Occasional Contributor

The problem is that iOS does not process the contextmenu mouse event, as both Android and Windows do. Unfortunately unless you are using the Bower build, there is no current fix for the problem, as it requires a significant hack to the menu.js in dojo's digit directory.

The dojo menu.js code that won't work in iOS:

      on(cn, delegatedEvent(this.leftClickToOpen ? "click" : "contextmenu"), function(evt){

The fix requires a separate section of code for ios. First bring in the dojox/gesture/tap module to menu.js. Then as follows:

//create a var for tap.hold with a long enough hold time to prevent from being activated on swipe gesture

var myTap = new dojox.gesture.tap.Tap({holdThreshold: 1000});

//separate code for ios only:

if(has("ios")){
   var hammertime = Hammer(dom.byId("mapViewDiv_root"));
   hammertime.get('press').set({
      time: 1000,
      pointers: 1,
      threshold: 9
      });

  var self = this;
   hammertime.on("press", function (e) {
   var x, y;
   x = e.center.x;
   y = e.center.y;
   self.myX = x;
   self.myY = y;
   });

   var doConnects = lang.hitch(this, function(cn){
      var selector = this.selector,
      delegatedEvent = selector ?
         function(eventType){

//the folowing is necessary to keep iOS from freezing any other click events on the map, due to using dojox/gesture
           if(cn.className == "esriMapContainer"){
               cn.dojoClick = true;}

//end add
         return on.selector(selector, eventType);
         } :
         function(eventType){
               return eventType;
            }

//self= this not needed here since it is declared above
        //  self = this; 

return [
      on(cn, delegatedEvent(this.leftClickToOpen ? "click" : myTap.hold), function(evt){
            evt.stopPropagation();
            evt.preventDefault();

//need to this to clear the element for other click events.Not sure why at this point:

         query(dom.byId("mapViewDiv_root")).on(myTap.hold, function(e){e.preventDefault()});

//need to allow other node menu events to work as usual, thus separate code for the context menu

         if(evt.target.nodeName == "svg"){
               self._scheduleOpen(this, iframe, {x: self.myX, y: self.myY}, evt.target);
                  }else{
               self._scheduleOpen(this, iframe, {x: evt.pageX, y: evt.pageY}, evt.target);
                 }

//end altered/added code: the rest can be taken as written in menu.js. 

I use an 'else' statement to move from 'has(ios)' to the original code for all other devices. Hammer.js is necessary as documented elsewhere due to dojox/gesture not returning screen coordinates.

I hope this helps someone. Took me a few days to figure everything out. Unfortunately, I'm getting used to this.

0 Kudos