package com.ericfeminella.application
{
import com.ericfeminella.collections.HashMap;
import com.ericfeminella.collections.IMap;
import flash.external.ExternalInterface;
import mx.core.Application;
/**
*
* Provides an API which allows for detailed inspection and
* modification of an application QueryString.
*
* <p>
* QueryString supports parsing of a QueryString which has been
* provided to the application via a user agent. Additionally,
* support for specific QueryStrings is provided which allows
* for detailed inspection of arbitrary query strings via the
* constructor
* </p>
*
* @see flash.external.ExternalInterface
* @see mx.core.Application
*
*/
public class QueryString implements IQueryString
{
/**
*
* Uniform Resource Identifier (URI) to which the querystring
* has been provided
*
* @example
* <listing version="3.0">
*
* var url:String = "http://localhost/test.html?version=3";
* // uri: http://localhost/test.html
*
* </listing>
*
*/
protected var uri:String;
/**
*
* The querystring which has been provided via the application
* URL or specified in the constructor, any modification to the
* querystring are reflected in this String
*
* @example
* <listing version="3.0">
*
* var url:String = "http://localhost/test.html?version=3";
* // uri: version=3
*
* </listing>
*
*/
protected var querystring:String;
/**
*
* Defines the name / value pairs which have been supplied
* to the querystring, any modification to the querystring
* are reflected in this HashMap
*
*/
protected var parameters:IMap;
/**
*
* By default the QueryString constructor will use the applications
* querystring and decode it unless specified otherwise
*
* <p>
* Additionally, support for specific QueryStrings is provided which
* allows for detailed inspection of arbitrary query strings via the
* constructor
* </p>
*
* <p>
* The QueryString constructor takes a single url as an argument.
* This argument is optional, and, if specified instructs the
* QueryString object to use the specified url for all subsequent
* operations. If the url is not specified the QueryString object
* will assume the aplication query string is to be used for all
* operations.
* </p>
*
* <p>
* Unfortunately, ActionScript 3 does not support constructor /
* method overloading so the url parameter is used to achive the
* correct functionality based on context.
* </p>
*
* @example
* <listing version="3.0">
*
* var querystring:IQueryString = new QueryString();
* //defaults to application querystring
*
* trace ( querystring.getQueryString() );
* //outputs application querystring
*
* </listing>
*
* <p>
* Optionally, you can opt to use a specific QueryString by passing
* it to the constructor:
* </p>
*
* <listing version="3.0">
*
* var url:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3";
*
* var querystring:IQueryString = new QueryString();
* //defaults to: name=Adobe Flex&version=3
*
* trace ( querystring.getQueryString() );
* //name=Adobe Flex&version=3
*
* </listing>
*
*
* @param an optional url from which the query string is to be based
* @param specifies if the query string is to be URL decoded
* @see #build
*
*/
public function QueryString(url:String = null, decode:Boolean = true)
{
this.build( url, decode );
this.createParameters();
}
/**
*
* Determines if parameters have been provided to the application
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.isProvided );
* //true
*
* </listing>
*
* @return true if supplied, false if not
*
*/
public function get isProvided() : Boolean
{
return parameters.size() > 0;
}
/**
*
* Retrieves the raw query string provided to the application
*
* @example
* <listing version="3.0>
*
* var url:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( url );
*
* trace( querystring.getQueryString() );
* //name=Adobe%20Flex&version=3.0
*
* //QueryString Object with decode set to true
*
* trace( querystring.getQueryString(true) );
* //name=Adobe Flex&version=3.0
*
* </listing>
*
* @param specifies if the querystring is to be URL decoded /encoded
* @return the raw query string which has been supplied
*
*/
public function getQueryString(decode:Boolean = true) : String
{
return decode ? decodeURIComponent( querystring ) : encodeURIComponent( querystring );
}
/**
*
* Retrieves all name / value pair provided to the application and
* returns an Array of Objects which contain each parameter name
* and value.
*
* <p>
* <code>QueryString.getParameters()</code> returns a new HashMap
* which contains all key / value pairs. A reference to the internal
* HashMap instance is preserved, the <code>IMap</code> returned is
* a copy of the key / values from the internal <code>HashMap</code>
* </p>
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
*
* var map:IMap = querystring.getParameters() );
* trace( map.getValues() );
* // Adobe Flex,3.0
*
* </listing>
*
* @return IMap containing key / values as specified in the querystring
*
*/
public function getParameters() : IMap
{
var map:IMap = new HashMap();
var keys:Array = parameters.getKeys();
var n:int = keys.length;
for (var i:int = 0; i < n; i++)
{
var key:* = keys[i];
var value:* = parameters.getValue( keys[i] );
map.put( key, value );
}
return map;
}
/**
*
* Adds a new parameter ( name / value ) pair to the querystring
*
* <p>
* If the parameter name which has been specified currently exists
* in the querystring then it is simply ignored.
* </p>
*
* <p>
* If you need to overwrite an existing parameter or modify the value
* of an existing parameter use <code>setValue</code> instead
* </p>
*
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
*
* trace( querystring.getQueryString(true) );
* //name=Adobe Flex&version=3.0
*
* //add an additional parameter to the querystring
* querystring.addParameter("year", 2008);
*
* trace( querystring.getQueryString( true ) );
* //name=Adobe Flex&version=3.0&year=2008
*
* </listing>
*
*
* @param the name of the parameter which is to be added to the QueryString
* @param the value to assigned to the specified parameter name
*
*/
public function addParameter(name:String, value:*) : void
{
if ( !parameters.containsKey(name) )
{
parameters.put( name, value.toString() );
update();
}
}
/**
*
* Removes an existing parameter from the querystring
*
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
*
* trace( querystring.getQueryString(true) );
* //name=Adobe Flex&version=3.0
*
* //remove a parameter from the querystring
* querystring.removeParameter("version");
*
* trace( querystring.getQueryString( true ) );
* //name=Adobe Flex
*
* </listing>
*
* @param the name of the parameter which is to be removed
*
*/
public function removeParameter(name:String) : void
{
parameters.remove( name );
update();
}
/**
*
* Determines if the specified parameter has been provided to
* the query string
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.containsParameter("name") );
* //true
*
* </listing>
*
* @param the paramter to determine
* @return true if supplied, false if not
*
*/
public function containsParameter(name:String) : Boolean
{
return parameters.containsKey( name );
}
/**
*
* Retrieves the parameter names provided to the application
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.getNames() );
* //name, version
*
* </listing>
*
* @return each query string parameter name
*
*/
public function getNames() : Array
{
return parameters.getKeys();
}
/**
*
* Retrieves a specific parameter name based on the parameters
* value
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.getName(3.0) );
* //version
*
* </listing>
*
* @param the value of the parameter which is to be located
* @return parameter name to which the specified value has been assigned
*
*/
public function getName(value:String) : String
{
return parameters.getKey( value );
}
/**
*
* Retrieves the parameter values provided to the application
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri, true );
* trace( querystring.getValues() );
* //Adobe Flex, 3.0
*
* </listing>
*
* @return each query string parameter value
*
*/
public function getValues() : Array
{
return parameters.getValues();
}
/**
*
* Retrieves the value of the specified parameter name. If the
* parameter does not exist a null value is returned. If the
* name has not been provided in the querystring then a null
* value is returned
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri, true );
* trace( querystring.getValue("version") );
* //3.0
*
* </listing>
*
* @param the name of the parameter
* @return the value of the specified paramter name
*
*/
public function getValue(name:String) : *
{
trace( parameters.getValue( name ) );
if ( parameters.getValue( name ) == "false" || parameters.getValue( name ) == "true")
{
return parameters.getValue( name ) == "false" ? false : true;
}
return parameters.getValue( name );
}
/**
*
* Assigns a new value to the specified querystring parameter
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri, true );
*
* trace( querystring.getValue("version") );
* //3.0
*
* querystring.setValue("version", 2.1)
*
* trace( querystring.getValue("version") );
* //2.1
*
* </listing>
*
* @param the name of the parameter
* @param the value to assigned to the specified parameter name
*
*/
public function setValue(name:String, value:*) : void
{
parameters.put( name, value.toString() );
update();
}
/**
*
* Determines if the specified value has been provided to the
* query string
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.containsValue(3.0) );
* //true
*
* </listing>
*
* @param the value in which to determine
* @return true if the value has been provided, false if not
*
*/
public function containsValue(value:*) : Boolean
{
return parameters.containsValue( value );
}
/**
*
* Appends the current state of the <code>querystring</code>
* to a URL
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri, true );
*
* var url:String = "http://127.0.0.1/apps/test.html";
* url = querystring.appendToURL( url );
*
* trace( url );
* //http://127.0.0.1/apps/test.html?name=Adobe Flex&version=3.0;
*
* </listing>
*
* @param the url to which the querystring is to be appended
* @param specifies if the querystring is to be URL decoded /encoded
* @return the specified url with the querystring appended
*
*/
public function appendToURL(url:String, decode:Boolean = true) : String
{
if ( url.indexOf("?") != -1 )
{
url += "&" + this.querystring;
}
else
{
url += "?" + this.querystring;
}
return decode ? decodeURI( url ) : encodeURI( url );;
}
/**
*
* Determines the length of the query string based on the amount
* of name value pairs which have been supplied to the QueryString
*
* @example
* <listing version="3.0>
*
* var uri:String = "http://127.0.0.1/test.html?name=Adobe Flex&version=3.0";
*
* var querystring:IQueryString = new QueryString( uri );
* trace( querystring.length() );
* // 2
*
* </listing>
*
* @return the length of the query string
*
*/
public function length() : int
{
return parameters.size();
}
/**
*
* Builds the QueryString Object and members from the specified
* URL or Application URL
*
* @param an optional url from which the query string is to be based
* @param specifies if the query string is to be URL decoded
* @see #createParameters
*
*/
protected function build(url:String = null, decode:Boolean = true) : void
{
var parts:Array;
if (url == null)
{
if ( ExternalInterface.available )
{
this.uri = ExternalInterface.call( "window.location.href.toString" );
parts = this.uri.split("?");
querystring = decode == true ? decodeURIComponent( parts[1] ) : parts[1];
}
}
else
{
parts = url.split("?");
uri = parts[0];
querystring = decode ? decodeURIComponent( parts[1] ) : parts[1];
}
}
/**
*
* Parses the <code>querystring</code> into an Array of Objects.
*
* <p>
* Each containing a specific name property and a value property
* which contains the values of each name / value pair in provided
* in the querystring
* </p>
*
*/
protected function createParameters() : void
{
parameters = new HashMap( true );
var nameValuePairs:Array = querystring.split("&");
var n:int = nameValuePairs.length;
for (var i:int = 0; i < n; i++)
{
var parts:Array = nameValuePairs[i].split("=");
var name:String = parts[0];
var value:String = parts[1];
parameters.put(name, value);
}
}
/**
*
* Updates the querystring to reflect changes made via
* <code>setValue()</code>, <code>addParameter()</code>
* and <code>removeParameter()</code>
*
* @see #setValue
* @see #addParameter
* @see #removeParameter
*
*/
protected final function update() : void
{
var qs:String = "";
for (var name:String in parameters)
{
qs += name + "=" + parameters[name] + "&";
}
this.querystring = qs.slice( 0, qs.length -1 );
}
}
}