kogmbh/WebODF — pull request #372 by adityab (2014-02-06 23:51:40+00:00)
Title: [WIP] iOS Safari Keyboard Support

# Editing with the virtual keyboard on iOS Safari

This is a working preview of keyboard support on iOS. It is not ready for merging and if you review this code kittens *will* die, so proceed at your own risk. :crying_cat_face:

## What works so far:
- [x] Toolbar should not slide out of the window
- [x] Event Trap overlay
- [ ] Show IME compositions inside the cursor
- [x] Sustained typing without collapsing keyboard
- [x] Clicking somewhere in the text should open the keyboard
- [ ] Show an overlay button to pop up the keyboard

There were several issues blocking keyboard control on iOS (all more or less fixed/worked-around now :v: ):
- **The window is shrunk and the entire body is scrolled upwards.**
This means that the toolbar slides upwards and out of the visible part of the viewport. To fix this, I had to resort to a hack in which when the keyboard slides in, save the `body.scrollTop` in a `y`, reset the scroll to `0`, add `y` to the canvas container's `padding-bottom`, and scroll the container downwards by `y`. This means that:
1. The toolbar is back in the expected top position after a brief flicker.
2. The intended position that was clicked for editing will roughly remain in the visible part of the shrunk viewport, unobscured behind the keyboard, and more or less in the same general position as safari intended it to be after the keyboard's appearance.

Additionally, I undo the extra padding and scrolling of the canvas container, and reset the `body.scrollTop` to `0` on `focusout`, which is when the keyboard slides out of the screen.

- **There were frequent `blur()` and `focus()` calls after every movement and operation.**
This made it impossible to keep the keyboard open to do sustained typing, because it would lose focus and slide out after each keypress. The workaround was to move the event trap out of the cursor, so that it would not be frequently reparented (thus losing focus), and to position it as an overlay above the cursor -- this positioning was important to do because:
1. Some IMEs show suggestions over the cursor position (like in OS X)
2. A mobile browser like Safari, which frequently resizes the window to accomodate a virtual keyboard, will automatically scroll to the element which holds the focus so that the input-eating area lies in the visible part of the viewport; therefore the event trap obviously needs to be in the right position so the browser knows where to scroll.

- **It is possible to assign focus only under very special conditions.**
1. In iOS Safari, focus will only be granted if the call to `eventTrap.focus()` is done within certain mouse and touch event listeners. For this, calls to `blur()` must be avoided at all costs outside such event handlers, unless, of course, the intent is indeed to lose focus.
2. Most desktop browsers do not update the selection if you click within an existing selection immediately - the updated selection is available only after the event is completely processed - for this reason, the existing code reads the new selection and assigns the focus in a 0-timeout. This is impossible on iOS because you cannot grant focus within a timeout. The least painful solution was to just check for `navigator.platform` being an iOS device. I will write a little function to test for this quirk so we don't have to rely on this...

So that's how the state is. There are still a few things remaining, and I'm not too happy with it, but as of now editing on iOS7 Safari is working.