001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui.impl;
017:
018: import com.google.gwt.core.client.JavaScriptObject;
019: import com.google.gwt.user.client.Element;
020:
021: /**
022: * Crazy implementation of {@link com.google.gwt.user.client.ui.impl.FocusImpl}
023: * that uses a hidden anchor to serve as a 'proxy' for focus.
024: */
025: public class FocusImplOld extends FocusImpl {
026:
027: /*
028: * Use isolated method calls to create all of the handlers to avoid creating
029: * memory leaks via handler-closures-element.
030: */
031: JavaScriptObject blurHandler = createBlurHandler();
032: JavaScriptObject focusHandler = createFocusHandler();
033: JavaScriptObject mouseHandler = createMouseHandler();
034:
035: @Override
036: public native void blur(Element elem) /*-{
037: elem.firstChild.blur();
038: }-*/;
039:
040: @Override
041: public native Element createFocusable() /*-{
042: // Use the infamous 'hidden input' trick to make a div effectively
043: // focusable.
044: var div = $doc.createElement('div');
045: var input = this.@com.google.gwt.user.client.ui.impl.FocusImplOld::createHiddenInput()();
046:
047: // Add a mousedown listener to the div to focuses the input (to mimic the
048: // behavior of focusable elements on other browsers), and focus listeners
049: // on the input to propagate focus events back to the div.
050:
051: // Note that we're using isolated lambda methods as the event listeners
052: // to avoid creating a memory leaks. (Lambdas here would create cycles
053: // involving the div and input). This also allows us to share a single
054: // set of handlers among every focusable item.
055:
056: input.addEventListener(
057: 'blur',
058: this.@com.google.gwt.user.client.ui.impl.FocusImplOld::blurHandler,
059: false);
060:
061: input.addEventListener(
062: 'focus',
063: this.@com.google.gwt.user.client.ui.impl.FocusImplOld::focusHandler,
064: false);
065:
066: div.addEventListener(
067: 'mousedown',
068: this.@com.google.gwt.user.client.ui.impl.FocusImplOld::mouseHandler,
069: false);
070:
071: div.appendChild(input);
072: return div;
073: }-*/;
074:
075: @Override
076: public native void focus(Element elem) /*-{
077: elem.firstChild.focus();
078: }-*/;
079:
080: @Override
081: public native int getTabIndex(Element elem) /*-{
082: return elem.firstChild.tabIndex;
083: }-*/;
084:
085: @Override
086: public native void setAccessKey(Element elem, char key) /*-{
087: elem.firstChild.accessKey = key;
088: }-*/;
089:
090: @Override
091: public native void setTabIndex(Element elem, int index) /*-{
092: elem.firstChild.tabIndex = index;
093: }-*/;
094:
095: protected native JavaScriptObject createBlurHandler() /*-{
096: return function(evt) {
097: // This function is called directly as an event handler, so 'this' is
098: // set up by the browser to be the input on which the event is fired.
099: if (this.parentNode.onblur) {
100: this.parentNode.onblur(evt);
101: }
102: };
103: }-*/;
104:
105: protected native JavaScriptObject createFocusHandler() /*-{
106: return function(evt) {
107: // This function is called directly as an event handler, so 'this' is
108: // set up by the browser to be the input on which the event is fired.
109: if (this.parentNode.onfocus) {
110: this.parentNode.onfocus(evt);
111: }
112: };
113: }-*/;
114:
115: protected native Element createHiddenInput() /*-{
116: var input = $doc.createElement('input');
117: input.type = 'text';
118: input.style.width = input.style.height = 0;
119: input.style.zIndex = -1;
120: input.style.position = 'absolute';
121: return input;
122: }-*/;
123:
124: protected native JavaScriptObject createMouseHandler() /*-{
125: return function() {
126: // This function is called directly as an event handler, so 'this' is
127: // set up by the browser to be the div on which the event is fired.
128: this.firstChild.focus();
129: };
130: }-*/;
131: }
|