Advanced Sitecore Google Maps (WCAG Edition)

Advanced Sitecore Google Maps (WCAG Edition) is a new module for Sitecore. The module provides maps, that are accessible and meet the Section 508 requirements. The module is very easy to use for your Sitecore editors.

Google Maps from Google is a great tool, that you can make to your tool with this module. Users are familiar with Google Maps, from many other sites. They know how to zoom in and out and switch between various map types. There is a possibility to show the geodesic maps, terrain maps, satellite maps and combinations.

It is becoming increasingly more important that websites are accessible. The Advanced Sitecore Google Maps module expands Google Maps features to also be accessible and meet the requirements of WCAG 2.0 level AA and Section 508. This module is the only map solution for Sitecore, that meets the WCAG 2.0 Level AA.

The module provides multiple ways of viewing a Google Map, including several filters and accessibility lists. As a developer, you can develop your own views:

Google Maps view including 3-level filter and accessibility list

Google Maps view including 3-level filter and accessibility list

The module is configured from Sitecore using custom Sitecore editors directly on the item that show the map. You can enter an address, or move the map marker to find the map center:

Create a map in Sitecore

Create a map in Sitecore

When creating a map you have full control over the zoom control, the map types to include (including moon, mars and sky views) and how the map should be displayed. You can even add the overview map and the Google search box to your map.

Markers, polygons and polylines are called “overlays”. These overlays can be grouped, and these groups can be used to filter overlays from the map, or to inherit marker icons. All overlays contain titles, text, alternative text and address information that can be used when presenting the overlay.

Markers are created similar to creating a map, by entering an address or moving a marker to the designated position.

Creating a marker in Sitecore

Creating a marker in Sitecore

Polygons and polylines are created in a similar fashion, simply by clicking on the map untill the polygon or polyline is drawn. The polygon and polyline colors, line thickness and transparency are fully controllable:

Adding a polygon to the overlays collection

Adding a polygon to the overlays collection

In order to use Google Maps, you need to register your URL at Google. If your website has many URL’s, you need to register each of them, including sub-domains (www.mysite.com and mysite.com for example). The module contains a key manager where you add all of your Google Maps keys, and the module automatically finds the correct key:

Multiple Google Maps key management

Multiple Google Maps key management

Click here to read more about the module, or Click here to see a demo of the module.

Google Maps polyline encoding in C#

One of the new features in the Advanced Sitecore Google Maps (WCAG edition) is the ability to draw polylines. Polylines in Google Maps can be drawn using 2 methods: By creating a new GPolyline with the array of coordinates to draw, or by using the GPolyline.fromEncoded function which takes an encoded string of coordinates and renders this as a line.

The encoded polyline function has the advantage of being faster and more compressed compared with feeding the GPolyline with an array of coordinates. However, some of the precision is lost, as the encoding algorithm only uses 5 digit coordinates. 5 digits is still a pretty good precision, so I decided to go with the encoded string.

I was looking for a method of encoded my coordinates in C# when i stumbled upon a solution on the SoulSolutions webpage, where the developer demonstrates a Javascript and C# method to encode and decode polyline coordinates.

This is the C# method re-written. SoulSolutions should be credited for the code. However, his code examples are incomplete, so I rewrote them. First I need a Coordinate class, which contains the latitude and longitude of a coordinate set (I have removed comments and other stuff to compress the code):

public class Coordinate
{
  public double Latitude { get; set; }
  public double Longitude { get; set; }
}

The following function EncodeCoordinates encodes a list of coordinates into an encoded string:

/// <summary>
/// Encodes the list of coordinates to a Google Maps encoded coordinate string.
/// </summary>
/// <param name="coordinates">The coordinates.</param>
/// <returns>Encoded coordinate string</returns>
public static string EncodeCoordinates(List<Coordinate> coordinates)
{
  int plat = 0;
  int plng = 0;
  StringBuilder encodedCoordinates = new StringBuilder();
  foreach (Coordinate coordinate in coordinates)
  {
    // Round to 5 decimal places and drop the decimal
    int late5 = (int)(coordinate.Latitude * 1e5);
    int lnge5 = (int)(coordinate.Longitude * 1e5);
    // Encode the differences between the coordinates
    encodedCoordinates.Append(EncodeSignedNumber(late5 - plat));
    encodedCoordinates.Append(EncodeSignedNumber(lnge5 - plng));
    // Store the current coordinates
    plat = late5;
    plng = lnge5;
  }
  return encodedCoordinates.ToString();
}
/// <summary>
/// Encode a signed number in the encode format.
/// </summary>
/// <param name="num">The signed number</param>
/// <returns>The encoded string</returns>
private static string EncodeSignedNumber(int num)
{
  int sgn_num = num << 1; //shift the binary value
  if (num < 0) //if negative invert
  {
    sgn_num = ~(sgn_num);
  }
  return (EncodeNumber(sgn_num));
}

/// <summary>
/// Encode an unsigned number in the encode format.
/// </summary>
/// <param name="num">The unsigned number</param>
/// <returns>The encoded string</returns>
private static string EncodeNumber(int num)
{
  StringBuilder encodeString = new StringBuilder();
  while (num >= 0x20)
  {
    encodeString.Append((char)((0x20 | (num & 0x1f)) + 63));
    num >>= 5;
  }
  encodeString.Append((char)(num + 63));
  // All backslashes needs to be replaced with double backslashes
  // before being used in a Javascript string.
  return encodeString.ToString().Replace(@"\", @"\\");
}

Using the encoded string, I can draw a line surrounding Denmark like this:

var line = new GPolyline.fromEncoded({
               color: "#0000FF",
               weight: 5,
               opacity: 0.5,
               points: "kpgiI}{wt@{xeDfxv@ylqC|flAyfyDidPiioBoabD_fkAyjfDooZ{nyCtw_BihCnzlBzbyAl}XehjBfp`B_se@vdgAhdPya_BoabDipHoabDngiAsen@jz}@htcAzqt@itcAnha@|~eBdzh@qqnBf~w@zrlCjkx@fppAy{u@zflA{zRpeuC`zWh`]bmx@}byAlwn@ny{DncNn}nDsxd@uqG",
               levels: "BBBBBBBBBBBBBBBBBBBBBBBBBBBB",
               zoomFactor: 32,
               numLevels: 4 });

The line looks like this using 28 coordinates:

Line drawing using GPolyline.fromEncoded

Line drawing using GPolyline.fromEncoded

Assigning Security to items in Sitecore 6 programatically

When Sitecore 6 came out, Sitecore changed the Security model dramatically. Sitecore now uses the .net security model, and on top of this they have built a set of classes to help with the assigning of roles and members.

You will find the helper classes in the Sitecore.Security namespace:

using Sitecore.Security.Accounts;
using Sitecore.Security.AccessControl;

Access rights to items can be added programatically to any item using the AccessRuleCollection class. The following example demonstates how to apply read access to a role (group) using the AccessRuleCollection:

public void SetAccess(Item item)
{
  Role myRole = Role.FromName("sitecore\\myRole");

  // Get the current accessrules
  AccessRuleCollection accessRules = item.Security.GetAccessRules();

  // Apply read access for the "myRole" to the current item
  // and all it's children
  accessRules.Helper.AddAccessPermission(myRole,
     AccessRight.ItemRead,
     PropagationType.Any,
     AccessPermission.Allow);

  // Write the rules back to the item
  item.Editing.BeginEdit();
  item.Security.SetAccessRules(accessRules);
  item.Editing.EndEdit(); 
}

As you already know, the Item in the function’s parameter must come from the “master” database.

The AddAccessPermission is pretty straight forward. In my example I grant access to a role, but the function will also take a user. Please also note that when retrieving a role or user from the user database, you must prefix the user or role name with the domain name.

The AccessRight class defines which right to apply to the item. If you need to grant more than one right, you will need to add them one by one. Like in this example:

PropagationType pt = PropagationType.Any;
AccessPermission ap = AccessPermission.Allow;
accessRules.Helper.AddAccessPermission(myRole, AccessRight.ItemRead, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.ItemWrite, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.ItemRename, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.ItemCreate, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.ItemDelete, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.WorkflowStateDelete, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.WorkflowStateWrite, pt, ap);
accessRules.Helper.AddAccessPermission(myRole, AccessRight.WorkflowCommandExecute, pt, ap);

The PropagationType enumeration determines which items will be granted the access right. Any means the item and all items inheriting. Descendants applies rights to inheriting children only, and Entity applies right to the item only.

Finally, the AccessPermission enumeration determines whether to grant (allow) or deny the access right.

If you wish to know more about the Sitecore security model, you should read the Sitecore Security API Cookbook (available for members of the Sitecore Developer Network only).