User Tools

Site Tools


public:tellmaps_url_and_seo

This is an old revision of the document!


Tellmaps: URL, SEO

This document proposes new URL format for tellmaps to resolve these issues:

  • for the user, to have a representative URL of current situation in the location bar
  • for the user, to allow navigation using browser's back / forward buttons
  • for search engines, to serve static content to be parsed when using dynamic URL's

URL format

We propose a shebang syntax, which is backward-compatible with most browsers and uses a hash-trick to allow dynamic changes of the URL. It is also directly supported by search engines such as Google.

Shebang syntax is defined as follows:

http://server.name/#!/path/to/web/feature?param1=value&param2=value#local-hash 

which can be decomposed to three major parts:

  • a path component, /path/to/web/feature - this is the main path of given server resouce, in case of tellmaps, an address of a particular map
  • a param set, ?param1=value&param2=value - this is a GET string with dynamic parameters such as filtering, country targetting, view change
  • a local hash, #local-hash - this is used as a normal hash, i.e. to scroll to a given part of document (top / bottom etc).

[Implementation] code to retriveve params from hash part: https://gist.github.com/miohtama/1570295

URLs for Tellmaps

We propose to use the above parts this way:

Path component

Should contain a path to resource. We propose:

  • for site content: directly name of the page, such as /contact, /about us etc.
  • for tellmaps: identifier of tellmap, tellmap ID or name. Arbitrarily, edition name. Examples: /tellmap/oil-consupmtion or with edition, /tellmap/angola/human-resouce-index. The identifiers should be URL-parsable strings in lower case, or less preferably ID (numeric). The nesting of edition/map is better for SEO purposes.
  • for country/province profiles: should be very simmilar but using different prefix than tellmap such as /province/{edition_name}/{province_name}
  • …some more?

The general rule of thumb is: if we have a content we want to serve to search engine as a static document, it should have an unique path component.

Param set

Should contain all kinds of data we don't need a SEO representation of. Such as filtering, pagination, views. Due to it's nature it should be in a format of property_name=property_value. We shall have a way on how to define defaults for these values if ommited in the application.

Examples of params (names - values):

  • legend - numeric
  • date - year
  • focus - part of map to focus on, string
  • carthogram - true / false

Advantages of param set over path set (such as /tellmap/WDAWORLD01/date/1974/focus/BRA/cartogram/true):

  • params are simpler to parse / assemble, it's much harder to make a mistake as would be in the above if we remove one part of component, such as date
  • we can distinguish between what is a path to resource, and what is only a different way to display it

Params will be parsed rather simply - we won't support arrays.

local hash

Will only be used if we need to scroll to some element ID. Because we don't have a way to do this if using shebang syntax directly, we can parse the additional # at the end of a path and programatically scroll to given DOM ID element. This will enable scroll to top / certain element.

Javascript implementation

The main idea is to create a Javascript service which can be called from existing system modules to perform URL-based operations. We shall call it TellmapsURIService.

API should provide:

/**
 * Register a given path.
 * @param uri_string string with path. May contain variables in the format of '':variable'' - will be passed to callback on request.
 * @param callback - a function in the form of function(passed_vars, get_vars, path_not_changed)
 *   passed_vars is a collection of { variable_name: variable_value }
 *   get_vars is a collection of param set (GET) in form of { param_name: param_value } with automatic completion from default_params_object
 *   path_not_changed is true if path component changed from last state, false if only params / local hash changed
 *   function will be called whenever URI matches on URI change
 * @param default_params_object - contains default GET values in form of { param_name: param_def_value }
 * @return none
 **/
function registerURI( uri_string, callback, default_params_object ) {
...
 
/**
 * Register a callback to be executed on URI parse fail
 * @param callback - a function in the form of function(current_uri, error_message)
 *   current_uri is the processed shebang that failed
 *   error_message does show a messages the class outputted on fail
 *   function will be called on URI parse failed
 * @return none
 **/
function onURIFail( callback ) {
...
 
/**
 * Manual call to path change
 * @param path - string, path component part
 * @param get_params - get param collection in the form of { param_name : param_value }
 * @param local_hash - string, local hash part
 * @return true/false on success / fail
 **/
function changeURI( path, get_params, local_hash ) {
...

So, on the side of implementor into existing system, the role is to: call the TellmapsURIService.registerURI in the setup phase of the application and register a callback to provide given task, for every “static” piece of content.

Whenever somebody clicks on a link with the hashbang syntax, uses browser history or manually changes the location, callbacks should trigger.

TellmapsURIService should handle events of location change and/or parse the [variable, get, local hash] data before use.

Javascript implementation - version B (revised)

A more thought-through approach to API:

/**
 * revised version with one settings object and multiple callback definitions
 * @param settings - collection {}, specify these properties:
 *  - path - string - define a path component with possible :variable notation
 *  - onPathChange - function(variables) - pass in a callback to be called whenever a path changes
 *                    - @param variables - collection of passed :variable values 
 *                        in format { variable_name: variable_value }
 *  - onPathOut - function() - pass in a callback to as destructor function
 *              - is called whenever path components change from this path
 *  - onParamsChange - function(params) - pass in a callback to be called whenever a param string changes
 *                     - @param params - collections of passed GET params
 *                         in format { param_name: param_value }
 *  - defaultParams - collection - define an array of default GET values - they automatically pre-fill the 
 *                   params in onParamsChange callback if not provided from GET
 *  - onHashChange - function(local_hash) - pass in a callback to be called whenever a local hash part changes
 *                     - @param local_hash - provides new value of local_hash
 *     - @default if not defined, will perform a scroll to page top / element of ID #local_hash,
 *                as standard hash does
 *  - debug - boolean - provide console.log outputs on various operations of this registerURI block              
 * @return none
 **/
function registerURI( settings ) {
...
 
/**
 * Register a callback to be executed on URI parse fail
 * @param callback - a function in the form of function(current_uri, error_message)
 *   current_uri is the processed shebang that failed
 *   error_message does show a messages the class outputted on fail
 *   function will be called on URI parse failed
 * @return none
 **/
function onURIFail( callback ) {
...
 
/**
 * Manual call to path change
 * @param path - string, path component part
 * @param get_params - get param collection in the form of { param_name : param_value }
 * @param local_hash - string, local hash part
 * @return true/false on success / fail
 **/
function changeURI( path, get_params, local_hash ) {
...
 
/**
 * Manual call to path-only change, get_params and local_hash remains the same
 * @param path - string, path component part
 * @return true/false on success / fail
 **/
function changeURIPath( path ) {
...
 
/**
 * Manual call to params-only change, path and local_hash remains the same
 * @param get_params - get param collection in the form of { param_name : param_value }
 * @return true/false on success / fail
 **/
function changeURIParams( get_params ) {
...
 
/**
 * Manual call to local_hash-only change, path and params remains the same
 * @param local_hash - string, local hash part
 * @return true/false on success / fail
 **/
function changeURILocalHash( local_hash ) {
...

This solution has these advantages:

  • destructor on path component change - can be used to free memory-intensive resouces, kill dialogs etc.
  • separate GET params / path component / local hash change callbacks - better, isolated events. The event order is as follows:
(change a path component) -> trigger onPathChange -> trigger onParamChange -> trigger onHashChange
(change a params part) -> trigger onParamChange only
(change a local hash part) -> trigger onHashChange only

Server-side implementation

Old URI redirection

Should perform a redirection from old to new format using rules described above. Should be done server-side with R=301 redirects.

SEO - support

Shebang format has an advantage in that it allows search engines to crawl them. When it notices the shebang format such as http://example.com/#!/some/path, it automatically requests http://example.com?_escaped_fragment=/some/path and this can be processed using the server and serving the search engine with custom SEO-ready content version of a given resource.

This will need much more through-thinking but the URL part is a good start.

public/tellmaps_url_and_seo.1398434890.txt.gz · Last modified: 2014/04/25 14:08 by honzik