| /******************************************************************************* |
| * Copyright (c) 2009, 2012 EclipseSource and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * EclipseSource - initial API and implementation |
| ******************************************************************************/ |
| |
| /** |
| * This class provides the client-side implementation for |
| * rwt.widgets.Link |
| */ |
| qx.Class.define( "rwt.widgets.Link", { |
| extend : rwt.widgets.base.Parent, |
| |
| construct : function() { |
| this.base( arguments ); |
| this.setAppearance( "link" ); |
| this._text = ""; |
| this._hasSelectionListener = false; |
| this._hyperlinksHaveListeners = false; |
| this._readyToSendChanges = true; |
| this._focusedLinkIndex = -1; |
| this._linksCount = 0; |
| this._link = new rwt.widgets.base.HtmlEmbed(); |
| this._link.setAppearance( "link-text" ); |
| this.add( this._link ); |
| this.setSelectable( false ); |
| this.setHideFocus( true ); |
| this.__onMouseDown = rwt.util.Function.bindEvent( this._onMouseDown, this ); |
| this.__onMouseOver = rwt.util.Function.bindEvent( this._onMouseOver, this ); |
| this.__onMouseOut = rwt.util.Function.bindEvent( this._onMouseOut, this ); |
| this.__onKeyDown = rwt.util.Function.bindEvent( this._onKeyDown, this ); |
| this.addEventListener( "appear", this._onAppear, this ); |
| this.addEventListener( "changeEnabled", this._onChangeEnabled, this ); |
| this.addEventListener( "keypress", this._onKeyPress ); |
| this.addEventListener( "focusout", this._onFocusOut ); |
| this._link.addEventListener( "changeHtml", this._onChangeHtml, this ); |
| }, |
| |
| destruct : function() { |
| this._removeEventListeners(); |
| delete this.__onMouseDown; |
| delete this.__onMouseOver; |
| delete this.__onMouseOut; |
| delete this.__onKeyDown; |
| this.removeEventListener( "appear", this._onAppear, this ); |
| this.removeEventListener( "changeEnabled", this._onChangeEnabled, this ); |
| this.removeEventListener( "keypress", this._onKeyPress ); |
| this.removeEventListener( "focusout", this._onFocusOut ); |
| this._link.removeEventListener( "changeHtml", this._onChangeHtml, this ); |
| this._link.dispose(); |
| }, |
| |
| members : { |
| |
| _onAppear : function( evt ) { |
| this._link.setTabIndex( null ); |
| this._link.setHideFocus( true ); |
| this._applyHyperlinksStyleProperties(); |
| this._addEventListeners(); |
| }, |
| |
| _onChangeHtml : function( evt ) { |
| this._applyHyperlinksStyleProperties(); |
| this._addEventListeners(); |
| }, |
| |
| _applyTextColor : function( value, old ) { |
| this.base( arguments, value, old ); |
| this._applyHyperlinksStyleProperties(); |
| }, |
| |
| _onChangeEnabled : function( evt ) { |
| this._applyHyperlinksStyleProperties(); |
| this._changeHyperlinksTabIndexProperty(); |
| }, |
| |
| _getStates : function() { |
| if( !this.__states ) { |
| this.__states = {}; |
| } |
| return this.__states; |
| }, |
| |
| addState : function( state ) { |
| this.base( arguments, state ); |
| this._link.addState( state ); |
| }, |
| |
| removeState : function( state ) { |
| this.base( arguments, state ); |
| this._link.removeState( state ); |
| }, |
| |
| setHasSelectionListener : function( value ) { |
| this._hasSelectionListener = value; |
| }, |
| |
| addText : function( text ) { |
| this._text += text; |
| }, |
| |
| addLink : function( text, index ) { |
| var style = this._getHyperlinkStyle( false ); |
| var widgetManager = org.eclipse.swt.WidgetManager.getInstance(); |
| var id = widgetManager.findIdByWidget( this ) + "#" + index; |
| this._text += "<span tabIndex=\"1\" "; |
| this._text += "style=\""; |
| this._text += "text-decoration:" + style.textDecoration + "; "; |
| this._text += "\" "; |
| this._text += "id=\"" + id + "\""; |
| this._text += ">"; |
| this._text += text; |
| this._text += "</span>"; |
| this._linksCount++; |
| }, |
| |
| applyText : function() { |
| this._link.setHtml( this._text ); |
| if( this._linksCount === 0 ) { |
| this.setTabIndex( null ); |
| } else { |
| this.setTabIndex( 1 ); |
| } |
| }, |
| |
| clear : function() { |
| this._removeEventListeners(); |
| this._text = ""; |
| this._linksCount = 0; |
| this._focusedLinkIndex = -1; |
| }, |
| |
| _applyHyperlinksStyleProperties : function() { |
| var style = this._getHyperlinkStyle( false ); |
| var hyperlinks = this._getHyperlinkElements(); |
| for( var i = 0; i < hyperlinks.length; i++ ) { |
| org.eclipse.rwt.HtmlUtil.setStyleProperty( hyperlinks[ i ], "color", style.textColor ); |
| org.eclipse.rwt.HtmlUtil.setTextShadow( hyperlinks[ i ], style.textShadow ); |
| org.eclipse.rwt.HtmlUtil.setStyleProperty( hyperlinks[ i ], "cursor", style.cursor ); |
| } |
| }, |
| |
| _changeHyperlinksTabIndexProperty : function() { |
| var hyperlinks = this._getHyperlinkElements(); |
| for( var i = 0; i < hyperlinks.length; i++ ) { |
| if( this.isEnabled() ) { |
| hyperlinks[ i ].tabIndex = "1"; |
| } else { |
| hyperlinks[ i ].tabIndex = "-1"; |
| } |
| } |
| }, |
| |
| // TODO [tb] : This is way more complicated than it needs to be. |
| // There is no need to work on DOM-level except when handling the event. |
| _addEventListeners : function() { |
| var hyperlinks = this._getHyperlinkElements(); |
| if( hyperlinks.length > 0 && !this._hyperlinksHaveListeners ) { |
| for( var i = 0; i < hyperlinks.length; i++ ) { |
| qx.html.EventRegistration.addEventListener( hyperlinks[ i ], |
| "mousedown", |
| this.__onMouseDown ); |
| qx.html.EventRegistration.addEventListener( hyperlinks[ i ], |
| "mouseover", |
| this.__onMouseOver ); |
| qx.html.EventRegistration.addEventListener( hyperlinks[ i ], |
| "mouseout", |
| this.__onMouseOut ); |
| qx.html.EventRegistration.addEventListener( hyperlinks[ i ], |
| "keydown", |
| this.__onKeyDown ); |
| } |
| this._hyperlinksHaveListeners = true; |
| } |
| }, |
| |
| _removeEventListeners : function() { |
| var hyperlinks = this._getHyperlinkElements(); |
| if( hyperlinks.length > 0 && this._hyperlinksHaveListeners ) { |
| for( var i = 0; i < hyperlinks.length; i++ ) { |
| qx.html.EventRegistration.removeEventListener( hyperlinks[ i ], |
| "mousedown", |
| this.__onMouseDown ); |
| qx.html.EventRegistration.removeEventListener( hyperlinks[ i ], |
| "mouseover", |
| this.__onMouseOver ); |
| qx.html.EventRegistration.removeEventListener( hyperlinks[ i ], |
| "mouseout", |
| this.__onMouseOut ); |
| qx.html.EventRegistration.removeEventListener( hyperlinks[ i ], |
| "keydown", |
| this.__onKeyDown ); |
| } |
| this._hyperlinksHaveListeners = false; |
| } |
| }, |
| |
| _onMouseDown : function( evt ) { |
| if( this.isEnabled() && this._isLeftMouseButtonPressed( evt ) ) { |
| var target = this._getEventTarget( evt ); |
| var index = this._getLinkIndex( target ); |
| this._setFocusedLink( index ); |
| if( this._readyToSendChanges ) { |
| // [if] Fix for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=252559 |
| this._readyToSendChanges = false; |
| rwt.client.Timer.once( function() { |
| this._sendChanges( index ); |
| }, this, org.eclipse.swt.EventUtil.DOUBLE_CLICK_TIME ); |
| } |
| } |
| }, |
| |
| _onMouseOver : function( evt ) { |
| var target = this._getEventTarget( evt ); |
| var style = this._getHyperlinkStyle( true ); |
| org.eclipse.rwt.HtmlUtil.setStyleProperty( target, "textDecoration", style.textDecoration ); |
| }, |
| |
| _onMouseOut : function( evt ) { |
| var target = this._getEventTarget( evt ); |
| var style = this._getHyperlinkStyle( false ); |
| org.eclipse.rwt.HtmlUtil.setStyleProperty( target, "textDecoration", style.textDecoration ); |
| }, |
| |
| _isLeftMouseButtonPressed : function( evt ) { |
| var result = false; |
| if( evt.which ) { |
| result = ( evt.which === 1 ); |
| } else if( evt.button ) { |
| if( rwt.client.Client.isMshtml() ) { |
| result = ( evt.button === 1 ); |
| } else { |
| result = ( evt.button === 0 ); |
| } |
| } |
| return result; |
| }, |
| |
| _onKeyDown : function( evt ) { |
| if( this.isEnabled() && evt.keyCode === 13 ) { |
| var target = this._getEventTarget( evt ); |
| var index = this._getLinkIndex( target ); |
| this._sendChanges( index ); |
| } |
| }, |
| |
| _getLinkIndex : function( element ) { |
| var id = element.id; |
| var index = id.substr( id.lastIndexOf( "#" ) + 1 ); |
| return parseInt( index, 10 ); |
| }, |
| |
| _getHyperlinkStyle : function( hover ) { |
| var states = this._getStates(); |
| if( hover ) { |
| states[ "over" ] = true; |
| } else { |
| delete states[ "over" ]; |
| } |
| var manager = rwt.theme.AppearanceManager.getInstance(); |
| return manager.styleFrom( "link-hyperlink", states ); |
| }, |
| |
| _getEventTarget : function( evt ) { |
| var target; |
| if( rwt.client.Client.isMshtml() ) { |
| target = window.event.srcElement; |
| } else { |
| target = evt.target; |
| } |
| return target; |
| }, |
| |
| // Override of the _ontabfocus method from rwt.widgets.base.Widget |
| _ontabfocus : function() { |
| if( this._focusedLinkIndex === -1 && this._linksCount > 0 ) { |
| this._setFocusedLink( 0 ); |
| } |
| }, |
| |
| _onKeyPress : function( evt ) { |
| if( this.isFocused() && evt.getKeyIdentifier() === "Tab" && this._linksCount > 0 ) { |
| var index = this._focusedLinkIndex; |
| if( !evt.isShiftPressed() && index >= 0 && index < this._linksCount - 1 ) { |
| evt.stopPropagation(); |
| evt.preventDefault(); |
| this._setFocusedLink( index + 1 ); |
| } else if( !evt.isShiftPressed() && index === -1 ) { |
| evt.stopPropagation(); |
| evt.preventDefault(); |
| this._setFocusedLink( 0 ); |
| } else if( evt.isShiftPressed() && index > 0 && index <= this._linksCount - 1 ) { |
| evt.stopPropagation(); |
| evt.preventDefault(); |
| this._setFocusedLink( index - 1 ); |
| } |
| } |
| }, |
| |
| _onFocusOut : function( evt ) { |
| this._setFocusedLink( -1 ); |
| }, |
| |
| _setFocusedLink : function( index ) { |
| var hyperlink = this._getFocusedHyperlinkElement(); |
| if( hyperlink !== null ) { |
| hyperlink.blur(); |
| hyperlink.style.outline = "none"; |
| } |
| this._focusedLinkIndex = index; |
| hyperlink = this._getFocusedHyperlinkElement(); |
| if( hyperlink !== null ) { |
| hyperlink.focus(); |
| hyperlink.style.outline = "1px dotted"; |
| } |
| }, |
| |
| _getFocusedHyperlinkElement : function() { |
| var result = null; |
| var hyperlinks = this._getHyperlinkElements(); |
| var index = this._focusedLinkIndex; |
| if( index >= 0 && index < hyperlinks.length ) { |
| result = hyperlinks[ index ]; |
| } |
| return result; |
| }, |
| |
| _getHyperlinkElements : function() { |
| var result; |
| var linkElement = this.getElement(); |
| if( linkElement ) { |
| result = linkElement.getElementsByTagName( "span" ); |
| } else { |
| result = []; |
| } |
| return result; |
| }, |
| |
| _sendChanges : function( index ) { |
| if( this._hasSelectionListener ) { |
| org.eclipse.swt.EventUtil.notifySelected( this, { "index" : index } ); |
| } |
| this._readyToSendChanges = true; |
| } |
| |
| } |
| |
| } ); |