001package votorola.s.gwt.wic; // Copyright 2012, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. 002 003import com.google.gwt.core.client.*; 004import com.google.gwt.dom.client.*; 005import votorola.g.web.gwt.*; 006import votorola.g.web.gwt.event.*; 007import votorola.s.gwt.stage.*; 008 009 010/** A controller that corrects links in the Wicket scene when the actor changes on stage. 011 * Currently it corrects position-like URLs in 'href' and 'onclick' attributes of the 012 * navigations tabs, which are expected to have an 'id' of 'navPile'. 013 */ 014final class ActorLinker implements PropertyChangeHandler 015{ 016 017 018 /** Creates the {@linkplain #i() single instance} of ActorLinker. 019 */ 020 ActorLinker( final Stage stage ) // called by CountIn 021 { 022 navPile = Document.get().getElementById( "navPile" ); 023 if( navPile == null ) assert false; 024 else 025 { 026 GWTX.i().bus().addHandlerToSource( PropertyChange.TYPE, /*source*/stage, 027 ActorLinker.this ); // no need to unregister, registry does not outlive this handler 028 relink( stage.getActorName() ); // init 029 } 030 } 031 032 033 034 /** The single instance of ActorLinker. 035 */ 036 static ActorLinker i() { return instance; } 037 038 039 private static ActorLinker instance; 040 041 { 042 if( instance != null ) throw new IllegalStateException(); 043 044 instance = ActorLinker.this; 045 } 046 047 048 049 // - P r o p e r t y - C h a n g e - H a n d l e r ------------------------------------ 050 051 052 public void onPropertyChange( final PropertyChange e ) 053 { 054 if( !e.propertyName().startsWith( "actorName" )) return; 055 056 relink( Stage.i().getActorName() ); 057 } 058 059 060 061//// P r i v a t e /////////////////////////////////////////////////////////////////////// 062 063 064 private static final JavaScriptObject JS = newJS(); // constant JavaScript constructions 065 066 067 private static native JavaScriptObject newJS() 068 /*-{ 069 var JS = {}; 070 JS.LINK_PATTERN = new RegExp( "^(.*[A-Z][a-z]*\\?)(.*p=[^']+)(.*)$" ); 071 // page name ? params trailer 072 // in 'onclick', params end in single quote (') 073 JS.U_PARAMS_PATTERN = new RegExp( "^(.*)(&u=[^&]+)(.*)$" ); 074 // leader &u=value trailer 075 // requires '&' first prepended 076 return JS; 077 }-*/; 078 079 080 081 private final Element navPile; 082 083 084 085 private native void relink( final String actorName ) // native to use _hvvww_dom.nextElement 086 /*-{ 087 var dom = $wnd._hvvww_dom; 088 var JS = @votorola.s.gwt.wic.ActorLinker::JS; 089 var e = this.@votorola.s.gwt.wic.ActorLinker::navPile; 090 var eBound = dom.nextElement( e, null, false ); // shallow 091 for( ;; ) // each descendant of navPile 092 { 093 e = dom.nextElement( e, null, true ); // deep 094 if( e == eBound ) break; 095 096 var aName = 'href'; 097 var aValue = e.getAttribute( aName ); 098 if( !aValue ) 099 { 100 aName = 'onclick'; 101 aValue = e.getAttribute( aName ); 102 } 103 if( !aValue ) continue; 104 105 var linkMatch = JS.LINK_PATTERN.exec( aValue ); 106 if( !linkMatch ) continue; 107 108 var params = '&' + linkMatch[2]; // prepend '&' per U_PARAMS_PATTERN 109 var uMatch = JS.U_PARAMS_PATTERN.exec( params ); 110 if( uMatch ) params = uMatch[1] + uMatch[3]; // without old u 111 112 if( actorName ) params += '&u=' + actorName; // add new u 113 params = params.slice( 1 ); // undo prepend of '&' 114 e.setAttribute( aName, linkMatch[1] + params + linkMatch[3] ); 115 } 116 }-*/; 117 118 119}