12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function focus(element) { 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Focus the target element in order to send keys to it. 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // First, the currently active element is blurred, if it is different from 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the target element. We do not want to blur an element unnecessarily, 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // because this may cause us to lose the current cursor position in the 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // element. 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Secondly, we focus the target element. 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Thirdly, if the target element is newly focused and is a text input, we 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // set the cursor position at the end. 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Fourthly, we check if the new active element is the target element. If not, 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // we throw an error. 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Additional notes: 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - |document.activeElement| is the currently focused element, or body if 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // no element is focused 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - Even if |document.hasFocus()| returns true and the active element is 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the body, sometimes we still need to focus the body element for send 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // keys to work. Not sure why 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - You cannot focus a descendant of a content editable node 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // - V8 throws a TypeError when calling setSelectionRange for a non-text 24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // input, which still have setSelectionRange defined. For chrome 29+, V8 25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) // throws a DOMException with code InvalidStateError. 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var doc = element.ownerDocument || element; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) var prevActiveElement = doc.activeElement; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (element != prevActiveElement && prevActiveElement) 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) prevActiveElement.blur(); 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) element.focus(); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (element != prevActiveElement && element.value && 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) element.value.length && element.setSelectionRange) { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try { 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) element.setSelectionRange(element.value.length, element.value.length); 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } catch (error) { 36a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!(error instanceof TypeError) && !(error instanceof DOMException && 37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) error.code == DOMException.INVALID_STATE_ERR)) 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw error; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (element != doc.activeElement) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) throw new Error('cannot focus element'); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 44