001package votorola.a.web.gwt; // Copyright 2010-2013, 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.dom.client.*; 004import com.google.gwt.http.client.URL; 005import com.google.gwt.regexp.shared.RegExp; 006import java.util.regex.MatchResult; 007import votorola.a.*; 008import votorola.a.position.*; 009import votorola.a.voter.*; 010import votorola.g.*; 011import votorola.g.web.gwt.*; 012 013 014/** A pollwiki from the viewpoint of a GWT client. 015 * 016 * @see App#pollwiki() 017 */ 018public final class PollwikiG implements Pollwiki 019{ 020 021 022 /** Does nothing itself but the call forces static initialization of this class. 023 */ 024 static void forceInitClass() {} 025 026 027 028 // ------------------------------------------------------------------------------------ 029 030 031 /** Encodes a page name and appends it to the wiki {@linkplain #getLocation() base 032 * URL}. Usage example:<pre> 033 * 034 * String href = voteServer.pollwiki().encodePageSpecifier( 035 * "Main page" ).build().toASCIIString();</pre> 036 * 037 * @see #appendPageSpecifier(String) 038 */ 039 public StringBuilder encodePageSpecifier( String pageName ) 040 { 041 // cf. MediaWiki.encodePageSpecifier 042 043 final StringBuilder b = new StringBuilder( wikiLocation ); 044 pageName = MediaWiki.demiEncodedPageName( pageName, maybeUgly ); // fully encoded here: 045 if( maybeUgly ) 046 { 047 b.append( "?title=" ); 048 b.append( URL.encodeQueryString( pageName )); 049 } 050 else 051 { 052 b.append( '/' ); 053 b.append( URLX.encodePath( pageName )); 054 } 055 return b; 056 } 057 058 059 060 /** The base URL for requesting pages from the pollwiki, without a trailing slash (/). 061 * This is either the standard access URL ending in "index.php" for example, or a 062 * pretty alias per <code>$wgUsePathInfo</code>. 063 * 064 * @see #appendPageSpecifier(String) 065 * @see #maybeUgly() 066 * @see #setLocation(String) 067 */ 068 public static @GWTConfigCallback String getLocation() { return wikiLocation; } 069 // cf. votorola.a.PollwikiVS.uri() 070 071 072 private static String wikiLocation; 073 074 075 private static native void exposeLocation() 076 /*-{ 077 $wnd.a_web_gwt_PollwikiG_getLocation = $entry( 078 @votorola.a.web.gwt.PollwikiG::getLocation() ); 079 $wnd.a_web_gwt_PollwikiG_setLocation = $entry( 080 @votorola.a.web.gwt.PollwikiG::setLocation(Ljava/lang/String;) ); 081 }-*/; 082 083 static 084 { 085 assert AMod.isForcedInit(): "forced init " + PollwikiG.class.getName(); 086 exposeLocation(); 087 } 088 089 090 /** Sets the base URL for requesting pages from the pollwiki. Call it from the 091 * global configuration function {@linkplain AMod voGWTConfig.a} in this 092 * manner:<pre 093 * 094 *> a_web_gwt_PollwikiG_setLocation( 'http://<var>YOUR.DOM</var>/wiki' ); 095 * // defaults to http://SCRIPT-LOCATION/index.php</pre> 096 * 097 * @throws IllegalArgumentException if the location ends with a slash '/' 098 * character. 099 * @see #getLocation() 100 * @see #setScriptLocation(String) 101 */ 102 public static @GWTConfigCallback void setLocation( final String s ) 103 { 104 if( s.endsWith( "/" )) throw new IllegalArgumentException( "location ends with '/'" ); 105 106 wikiLocation = s; 107 maybeUgly = MAYBE_UGLY_URL_PATTERN.exec(s) != null; 108 } 109 110 111 112 /** The base URL for script execution in the pollwiki, without a trailing slash (/). 113 * For example <code>http://reluk.ca/mediawiki</code>. Script requests may be 114 * constructed by appending the script path and parameters:<pre 115 * 116 *> getScriptLocation() + "/index.php?oldid=1138"</pre> 117 * 118 * @see #setScriptLocation(String) 119 */ 120 public static @GWTConfigCallback String getScriptLocation() { return wikiScriptLocation; } 121 // cf. votorola.a.PollwikiVS.wikiScriptURI() 122 123 124 private static String wikiScriptLocation; 125 126 127 private static native void exposeScriptLocation() 128 /*-{ 129 $wnd.a_web_gwt_PollwikiG_getScriptLocation = $entry( 130 @votorola.a.web.gwt.PollwikiG::getScriptLocation() ); 131 $wnd.a_web_gwt_PollwikiG_setScriptLocation = $entry( 132 @votorola.a.web.gwt.PollwikiG::setScriptLocation(Ljava/lang/String;) ); 133 }-*/; 134 135 static 136 { 137 assert AMod.isForcedInit(): "forced init " + PollwikiG.class.getName(); 138 exposeScriptLocation(); 139 } 140 141 142 /** Sets base URL for for script execution in the pollwiki. Call it from the 143 * global configuration function {@linkplain AMod voGWTConfig.a} in this 144 * manner:<pre 145 * 146 *> a_web_gwt_PollwikiG_setScriptLocation( 'http://<var>YOUR.DOM</var>/mediawiki' ); 147 * // defaults to the standard location http://SERVER.DOM/mediawiki 148 * // where SERVER.DOM is a calculated guess at the web server name</pre> 149 * 150 * @throws IllegalArgumentException if the location ends with a slash '/' 151 * character. 152 * @see #getScriptLocation() 153 */ 154 public static @GWTConfigCallback void setScriptLocation( final String s ) 155 { 156 if( s.endsWith( "/" )) throw new IllegalArgumentException( "location ends with '/'" ); 157 158 wikiScriptLocation = s; 159 } 160 161 162 163 /** Returns the position identifier of the loaded page, or null if the page is not a 164 * position page. 165 */ 166 public PositionID identifyAsPosition( final Document page ) 167 { 168 final String pageName = WindowX.js()._get( "wgPageName" ); 169 if( pageName == null ) return null; // not a MediaWiki page 170 171 return identifyAsPosition( pageName ); 172 } 173 174 175 176 /** Returns the position identifier of the loaded page, or null if the page is not a 177 * position page. 178 */ 179 public PositionID identifyAsPosition( final String pageName ) 180 { 181 final MatchResult m = MediaWiki.parsePageNameS( pageName ); 182 if( m == null ) return null; // not a MediaWiki page 183 184 final String personName = IDPair.normalUsername( m.group( 2 )); 185 final String pollName; 186 if( pipeRecognizer.isPipeName( personName )) 187 { 188 pollName = datumValue( "pipePoll", Document.get() ); 189 // per http://havoc.zelea.com/w/Category:Pipe 190 } 191 else pollName = m.group( 3 ); // subpage path if any 192 if( pollName == null ) return null; 193 194 return new PositionID( personName, pollName ); 195 } 196 197 198 199 // - P o l l w i k i ------------------------------------------------------------------ 200 201 202 /** @see #getLocation() 203 * @see #encodePageSpecifier(String) 204 */ 205 public StringBuilder appendPageSpecifier( final String encodedPageName ) 206 { 207 return MediaWiki.appendPageSpecifier( new StringBuilder(wikiLocation), maybeUgly, 208 encodedPageName ); 209 } 210 211 212 213 /** @see #getLocation() 214 */ 215 public boolean maybeUgly() { return maybeUgly; } 216 217 218 private static boolean maybeUgly; 219 220 221 222 /** @see #setPipeRecognizer(String,String) 223 */ 224 public PipeRecognizer pipeRecognizer() { return pipeRecognizer; } 225 226 227 private static PipeRecognizer pipeRecognizer = new PipeRecognizer0(); // by default 228 229 230 private static native void exposePipeRecognizer() 231 /*-{ 232 $wnd.a_web_gwt_PollwikiG_setPipeRecognizer = $entry( 233 @votorola.a.web.gwt.PollwikiG::setPipeRecognizer(Ljava/lang/String;Ljava/lang/String;) ); 234 }-*/; 235 236 static 237 { 238 assert AMod.isForcedInit(): "forced init " + PollwikiG.class.getName(); 239 exposePipeRecognizer(); 240 } 241 242 243 /** Configures the pipe recognizer. Call this method from the global 244 * configuration function {@linkplain AMod voGWTConfig.a} in this manner:<pre 245 * 246 *> a_web_gwt_PollwikiG_setPipeRecognizer( 'PREFIX', 'SUFFIX' ); 247 * // there are no dependable defaults, you should set values if pipes are enabled</pre> 248 * 249 * @see #pipeRecognizer() 250 * @see <a href='http://havoc.zelea.com/w/Category:Pipe#Enabling_pipes_in_the_wiki' 251 * target='_top'>Category:Pipe#Enabling pipes in the wiki</a> 252 */ 253 public static @GWTConfigCallback void setPipeRecognizer( final String pipePrefix, 254 final String pipeSuffix ) 255 { 256 pipeRecognizer = new PipeRecognizer1( pipePrefix, pipeSuffix ); 257 } 258 259 260 261 public String positionPageName( final String personName, final String pollName ) 262 { 263 return PositionID.pageName( personName, pollName, pipeRecognizer() ); 264 } 265 266 267 268//// P r i v a t e /////////////////////////////////////////////////////////////////////// 269 270 271 /** Returns the value of a datum encoded in the loaded pollwiki page, or null if none 272 * is encoded. 273 * 274 * @see <a href='http://havoc.zelea.com/w/Template:Data_encoded' 275 * target='_top'>Template:Data encoded</a> 276 */// per INLDOC 277 private String datumValue( final String name, final Document page ) 278 { 279 final Element span = page.getElementById( name ); 280 return span == null? null: span.getTitle(); 281 } 282 283 284 285 private static final RegExp MAYBE_UGLY_URL_PATTERN = RegExp.compile( 286 ".+/index\\.php[0-9]*.*" ); // changing? change also in g.MediaWiki 287 288 289}