UploadWizard/Geolocation

= Locator Widget =

Problem
It is difficult to geocode uploaded media on Wikimedia Commons. The existing advice is for the user to go elsewhere to figure out the latitude and longitude appropriate to their photo, then to figure out which representation of latitude and longitude to use (degrees minutes seconds, decimal degrees, or some other format) and finally to encode the latitude and longitude in appropriate wikiText, such as a Location template.

We would like to greatly lower the bar to geocode media on Commons:
 * use EXIF data contained in the media file to suggest an appropriate location
 * eliminate the need for the uploader to go outside the upload interface to search a map.
 * eliminate the need for the uploader to manually edit, or even know about, latitude and longitude.
 * eliminate the need for the uploader to create, edit, or even know about the location-related wikitext that will be entered onto the File: page for the media file.

This should also:
 * help regularize the format of the wikitext that is used on Commons to geocode media files.

Requirements
The desired solution is a JavaScript jQuery plugin which presents a map interface, which can be manipulated to select a particular location, and which can then report that location in code, preferably as wikiText containing a Location template.

The map plugin should not be dependent on any particular maps provider. It should be able to show tiles and interface from Google Maps, Yahoo Maps, and OpenStreetMaps. (This will probably reuse existing work such as the MediaWiki Maps extension.)

This plugin should be able to be integrated directly into the MediaWiki UploadWizard extension. For the most part, as long as it conforms to the Javascript API below, that should happen automatically.

This plugin should be able to show an interface centered at a pre-selected location.

The plugin will be delivered with documentation that describes the interface for creating the widget, how to manipulate the map to change a location, and how to obtain location wikiText.

The plugin should not have any effects on the HTML page or the window's DOM structure, other than within the element selected for it at creation. The plugin should not create any global variables. It should be possible to have multiple widgets on the page (although it is acceptable if we can only have one in "open, editing" state at a time).

The plugin should work on the following browsers, at a minimum: Microsoft Internet Explorer 6 or greater, Mozilla Firefox 3.1 or greater, Apple Safari 3.0 or greater, and Google Chrome 4.0 or greater. Compatibility with Opera 9 or greater is preferred. Some degraded functionality is acceptable for older browsers such as Microsoft Internet Explorer 6.

The plugin should be internationalizable, at least in all messages presented to the user.

The code and other assets for this plugin will be licensed under the same terms as MediaWiki. (The code will be GPL-compatible, the images and other assets will be compatible with a Creative Commons Attribution-ShareAlike Unported 3.0 license.)

What's out of scope
Details of decoding EXIF data are dealt with elsewhere; on MediaWiki 1.18 and later properly decoded 'gpslatitude' and 'gpslongitude' entries are made available in the image's metadata dictionary. The calling code elsewhere in UploadWizard will extract these and hand them to the widget. (See the stub prefillLocation and the already-extant similar prefillDate in mw.UploadWizardDetails.js for where to start plugging.)

All the map widget has to do is be able to select a location based on the provided latitude and longitude.

Use cases
Here are some rough docs on Location widget use cases. They help explain why it isn't just a simple map. We also need to recover from mistakes, confirm that the prefilled EXIF data is good, or remove location data.

Existing tools
As usual, for any annoying task Wikipedians have developed lots of tools to make them easier. Here are a few that we know of.


 * MultiChil's coordinates tool - This is a great tool and does almost everything we want already. The flaws from my (NeilK's) persepctive:
 * On another page on the toolserver -- we want something that can be integrated into the upload process, or even used as a widget on the File: page itself for all images.
 * Still shows you wikitext. Way too many options; it's more of a wikitext generator for those who know what they are doing.
 * Tied to Google Maps API. Ideally we want something that we could use with OpenLayers, etc.
 * When searching for points, displays many candidates. But it is not obvious how to select one of them and make it "yours"; they just disappear?


 * Freeside.sk Geolocator - Again, an all-singing all-dancing geolocator
 * Primarily for Wikipedians, but also has lots of other formats (which is nice, but makes the page awfully complicated). We don't care about Dublin Core, we don't even care about Wikipedia's Coord template. We just want something for Wikimedia Commons.
 * Still on another page, not integrated with Commons upload or File: pages.
 * Usability is poor -- again, way too many options for almost all photos, impossible for a naive user to guess what's going on
 * Bad - you need to control-click to set the point. Otherwise 0,0 is preselected. We want a tool that can also record "no geocode for this photo".
 * Good point - does headings, radius, etc, although this functionality achieved with special Alt-click, shift-click, etc. Not obvious or intuitive
 * Good - you can drag the marker around, which is intuitive, although I think clicking is still more likely to be guessed at.

Javascript API and interface specification
In the spirit of NORULES, feel free to abandon any aspect of this specification that does not make sense, or seems like it will take a very long time to implement. It just has to satisfy the broad goals listed above.

That said, it is expected that the following behaviour should be pretty easy to achieve with modern mapping libraries and jQuery.

It may be difficult to achieve all the behaviour in a cross-library manner, where it works on OpenLayers as well as Google Maps, for instance. Small differences can be ignored.

The names of methods and parameters are just suggestions. If they need to be changed to conform to existing conventions, please do so.

In the following examples, $ is a jQuery object.

Although the mockups are crude, it is expected that all the buttons and so on are generated with jQuery.UI, and thus are themed by default. When colors have to be chosen (like the greys or light blue in the mockups) please use the palette of [[Toolserver:
 * File:Vector-Colors.png|Vector colors]]. If there's a conflict between what I sketched and the Vector guidelines, Vector should win if at all possible.

Creation of widget
The widget can be created with or without a pre-defined location.

The following code would create a map widget on the page, pre-centered and pre-zoomed to a point in San Francisco, CA.

// at present, these are the only defined options, but add more if they make sense to control the map display var options = { latitude: 37.775, longitude: -122.4183 };

// create widget on page, at HTML element located at #foo var locator = $('#foo').locator( options );

If either of the latitude and longitude options are insane, the map should behave as if neither were present.

Insane parameters include:
 * null values for latitude or longitude
 * object does not contain both latitude and longitude properties
 * latitude < -90.0 or latitude > 90.0
 * longitude > 180.0 or longitude < -180.0

Interacting with the map widget
The map widget can be "open" or "closed".

When "closed" it takes up a minimal amount of space on the web page, and merely indicates what location it is set to. If it is not set to any location, an invitation to set a location is shown.

When "open" it takes up much more room (possibly as an overlay) and shows an interactive map widget.

Some of this design is inspired by Flickr's mapping widget, although it is somewhat simpler. Try that to get a feel for what we're going for.

States that the map widget can be in:

"Closed", not editing, no stored location
Here the map widget has no associated data. A zoomed-out map of the world is used as backdrop with an invitation to edit. Clicking on anywhere in the map widget will give us the "open" editing view.

"Open", editing, no stored location yet
We begin zoomed out very far. The map widget will show a standard "slippy" map with minimal controls.

A user can pan the map around by grabbing the map and dragging it in any direction. They can zoom in or out. The programmer can choose whether to allow changing to different modes (such as between satellite or street maps). Photographic views like Google Street View or Bing's bird's eye view are left as a choice to the programmer.

Here we have zoomed in closer to a particular location.

"Open", editing, location stored
Clicking once on the map (not clicking and dragging) will set a marker. This marker's location is now stored in the widget.

(Question: Will users understand they are supposed to click once on the map to set a location? Do they need a prompt of some kind?)

Clicking elsewhere on the map moves the marker to a new location.

Once the map has a location stored a "Remove this from the map" link appears.

Once the location has been chosen, the user can press "Done" to accept this location. The widget reverts to "closed" state.

If the user selects the "Remove this from the map", the stored location is deleted, and the marker is deleted. The widget reverts to "closed" state.

Using the text field to find a location
A text field appears below the map. This is used to find locations with geocodable strings, such as addresses, landmark names, and so on. The geocoding API will of course vary depending on the maps provider used. If there are any providers for whom this service is not available then the field should not be shown.

The field will have grey "hint" text such as shown in the mockup. This text disappears if the text field contains any content or has the mouse focus. The help text reappears if text field does not have focus and contains only the empty string or whitespace.

If the user enters a location in that field and presses return, a call to a geocoding service will be made, to obtain coordinates.

If the location is found:
 * If one location is found, this will drop a marker onto the map, and also store this as the widget's current location.
 * If a number of locations are found, this should be made visible with noticeably different markers (both in color and icon). Clicking on one of these icons should cause that to become the selected marker (or, erase all such search markers and drop a new one where that was, same thing).
 * See Multichil's tool (linked above) for ideas about how to display multiple search results... uncertain about how this should be done, please experiment. Just make it easy to "convert" one of the found points into our marker point, ideally with a single click.

The text field will be blanked if the user subsequently changes the marker location by clicking elsewhere on the map.

If the location is not found, an error message is shown in red near the text field (probably below it, or perhaps right on the map itself with appropriately opaque background). The error message will be somethng like "That location could not be found." The unfindable location remains visible in the text box. If the user makes any change to the text in that box, the error message disappears.

N.B. There are various jQuery plugins which make a lot of the above behavior easy, particularly the "validator" plugin. Also see: http://www.pluginquery.com/?q=hint

"Closed", location stored
Here we see the widget in its "closed" state while storing a location. The map shown is not interactive; clicking anywhere on it just opens up the widget again, which will show an interactive map with the location marker pre-set, similar to how it appeared in the "Open", location set state.

Obtaining wikitext
The user does not take any special action to show wikitext. Instead, this will be handled by other scripts on the page (which initialized the map widget in the first place). The widget will define a getWikiText method, such that this sample scenario works.

upload.locator = $('div.loc').locator( options );

// Sometime later, get location information var wikiText = upload.locator.getWikiText;

If no location has been chosen in the widget, the returned wikitext is the empty string.

The wikitext that is generated will follow the guidelines for Commons geocoding.

We will also obey these further restrictions:


 * We always use "Location dec", i.e. Location specified with decimal latitude and longitude.
 * We always use "camera location" as this is compatible with typical EXIF metadata, which is measured at the camera.
 * For this iteration of the widget, we will not add any meta information such as region, scale, type, or heading. (For most Commons images the defaults will be just fine.)

In other words, here is a sample of the typical output:

It is not required to put newlines before or after the returned wikitext.