)]}'
{
  "commit": "3de91d8f5a2f96f3a805dfd341010fcb4bba3ca9",
  "tree": "feeaf2494f17423370488358cf31e02dd1526117",
  "parents": [
    "3472eb8452643d85ab84fca7f7be583ba8b1f0d7",
    "a9a915ee19dbc1d316fa0f001da21d2c1656884d"
  ],
  "author": {
    "name": "Han Seoul-Oh",
    "email": "laughinghan@gmail.com",
    "time": "Fri Apr 22 12:30:56 2016 -0700"
  },
  "committer": {
    "name": "Han Seoul-Oh",
    "email": "laughinghan@gmail.com",
    "time": "Fri Apr 22 12:30:56 2016 -0700"
  },
  "message": "Merge pull request #622 from mathquill/feature.fastClick-rebase\n\nAPI to enable \"fast clicks\" on touch devices\r\n\r\nArgghhhhh. Want touch swipes to scroll the page, even if they start in\r\nMathQuill (so that it\u0027s possible to scroll an expression list filled to\r\nthe brim with nothing but MathQuills), but touch taps to place the\r\ncursor. Now, with mouse events, if all you care about is a logical\r\n\"click\" on the current platform, you just listen for the click event and\r\nthe browser will take care of whether a particular sequence of\r\nmousedown-mousemoves-mouseup is a click or not. With touch events,\r\nthere\u0027s no equivalent logical \"tap\" event, and while legacy mouse events\r\ndo fire if you don\u0027t .preventDefault() on touchstart, Safari on iOS waits\r\na glacial ~360ms [1] after a tap in case you\u0027re actually doing the\r\ndouble-tap gesture to zoom in.\r\n\r\n[1]: Videos: http://developer.telerik.com/featured/300-ms-click-delay-ios-8/\r\n\r\nIt gets better. Not only are the legacy mouse events unhelpful, they\u0027re\r\nmisleading, because there is no way to directly tell them apart from\r\nreal mouse events and no way to get them not to fire except calling\r\n.preventDefault(), which breaks touch-swipe-to-scroll.\r\n\r\nAs a result, across the Web there are dozens of blog posts about, and\r\nshitty JS libraries for, \"fast clicks\", that all disagree on what counts\r\nas a \"tap\", and also when to ignore a mouse event because it\u0027s probably\r\na legacy one 300ms after a touch event that\u0027s already been dealt with.\r\nBy far the 2 most-cited \"fast click\" solutions are Google Developer\u0027s\r\n\"Fast Buttons\" article [2] and FT Labs\u0027 FastClick library [3]; only the\r\nlatter ignores taps that are to stop scrolling after a fling, taps where\r\ntouchend is \u003e700ms after touchstart, or taps with more than one finger,\r\nbut only the former appears to put a time and distance limit on mouse\r\nevents to ignore (FastClick just ignores the next one).\r\n\r\n[2]: https://web.archive.org/web/20150406091222/https://developers.google.com/mobile/articles/fast_buttons\r\n[3]: https://github.com/ftlabs/fastclick\r\n\r\n(Google seems to have lost the original widely-cited \"Fast Buttons\" article: https://developers.google.com/mobile/articles/fast_buttons )\r\n\r\nMathQuill\u0027s sponsor, Desmos, has a custom touch events library whose\r\ndefinition of \"tap\", and whose strategy for ignoring delayed mouse\r\nevents, is different from either of the above. Clearly, this stuff needs\r\nto be decided by the parent application using MathQuill.\r\n\r\nSo, with heart-wrenching despair, here are 2 new API calls:\r\n\r\n- .clickAt(clientX, clientY, target) takes in the touch event info\r\n  and places the cursor like there was a click there (also useful for\r\n  e.g. obviating .dropEmbedded())\r\n    + `target` is optional but optimizes-away one DOM call for free\r\n\r\n- .ignoreNextMousedown(fn) takes a function that is called on subsequent\r\n  mousedown events, which MathQuill will ignore if true is returned.\r\n  MathQuill stops calling the function once it returns false.\r\n  You should call this whenever there might be a legacy mousedown, even\r\n  if it doesn\u0027t \"count\" as a tap to you, else MathQuill will get clicked\r\n  fast sometimes and slow others, that\u0027d be weird.\r\n\r\n--\r\n\r\nWhy clientX/Y even though .seek() takes in pageX/Y? Well,\r\ndocument.elementFromPoint() *has* to take in clientX/Y, whereas .seek()\r\nmerely *happens* to take in pageX/Y because it\u0027s slightly easier to work\r\nwith jQuery::offset(), and that\u0027s likely to change because jQuery::offset()\r\nhas poor performance so MathQuill may want to start working with\r\n.getBoundingClientRects() directly, which would make it actually easier to\r\nwork with clientX/Y than pageX/Y in the first place.\r\n\r\nFor now, though, I\u0027m not gonna port everything over the whole .seek() system\r\nto clientX/Y yet, instead .clickAt() just converts clientX/Y to pageX/Y by\r\nway of window.pageXOffset and window.pageYOffset, which according to\r\nQuirksMode [4] is the difference between them and has very good support.\r\n(It\u0027s also used by jQuery to convert from clientX/Y to what jQuery::offset()\r\nreturns [5].)\r\n\r\n[4]: http://www.quirksmode.org/mobile/tableViewport.html#t10\r\n[5]: https://github.com/jquery/jquery/blob/1.12.3/src/offset.js#L113-L114\r\n\r\n--\r\n\r\nThe test case has a trivial notion of logical \"tap\", which is if no\r\ntouchmoves happen between the touchstart and touchend. Note that it\r\ncalls .ignoreNextMousedown() after every touchend, or else sometimes if\r\nyou wiggle your finger a little but not much, the logical \"tap\" won\u0027t\r\nhappen but Safari on iOS will still fire a legacy mousedown event.\r\n\r\nTest case also gained -webkit-tap-highlight-color to to hide the gray\r\ntap highlight box.",
  "tree_diff": []
}
