/**
* Mapstraction implementation for Geo Mashup maps.
* @fileOverview
*/
/**
* @name AjaxRequestOptions
* @class This type represents options used for an AJAX request.
* It has no constructor, but is instantiated as an object literal.
*
* @property {String} url The AJAX request URL.
*/
/**
* @name ContentFilter
* @class This type represents objects used to filter content.
* It has no constructor, but is instantiated as an object literal.
*
* @name ContentFilter#content
* @property {String} content HTML content to filter.
*/
/*global GeoMashup */
/*global customizeGeoMashup, customizeGeoMashupMap, customGeoMashupColorIcon, customGeoMashupCategoryIcon */
/*global customGeoMashupSinglePostIcon, customGeoMashupMultiplePostImage */
/*global jQuery, mxn */
/*jslint browser: true, white: true, sloppy: true */
GeoMashup.loadFullPost = function( point ) {
var i, request, cache, objects, object_ids;
objects = this.getObjectsAtLocation( point );
object_ids = this.getOnObjectIDs( objects );
cache = this.locationCache( point, 'full-post-' + object_ids.join(',') );
if ( cache.html ) {
this.getShowPostElement().innerHTML = cache.html;
} else {
this.getShowPostElement().innerHTML = '

';
request = {
url: this.geo_query_url + '&object_name=' + this.opts.object_name +
'&object_ids=' + object_ids.join( ',' ) + '&template=full-post'
};
/**
* Requesting full post content.
* @name GeoMashup#fullPostRequest
* @event
* @param {Array} objects Objects included in the request
* @param {AjaxRequestOptions} options
*/
this.doAction( 'fullPostRequest', objects, request );
jQuery.get( request.url, function( content ) {
var filter = {content: content};
/**
* Loading full post content.
* @name GeoMashup#fullPostLoad
* @event
* @param {Array} objects Objects included in the request
* @param {ContentFilter} filter
*/
GeoMashup.doAction( 'fullPostLoad', objects, filter );
cache.html = filter.content;
jQuery( GeoMashup.getShowPostElement() ).html( filter.content );
/**
* The full post display has changed.
* @name GeoMashup#fullPostChanged
* @event
*/
GeoMashup.doAction( 'fullPostChanged' );
} );
}
};
GeoMashup.createTermLine = function ( taxonomy, term_id, term_data ) {
// Polylines are close, but the openlayers implementation at least cannot hide or remove a polyline
var options = {color: term_data.color, width: 5, opacity: 0.5, visible: true, taxonomy: taxonomy, term_id: term_id};
term_data.line = new mxn.Polyline(term_data.points);
/**
* A term line was created.
* @name GeoMashup#termLine
* @event
* @param {Polyline} line
* @param {String} taxonomy
* @param {String} term_id
* @param {Object} term_data Other properties of the term
*/
this.doAction( 'termLine', term_data.line, taxonomy, term_id, term_data );
/**
* A category line was created.
* @name GeoMashup#categoryLine
* @event
* @deprecated Use GeoMashup#termLine
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Polyline} line
*/
this.doAction( 'categoryLine', this.opts, term_data.line );
/**
* A term line will be added with the given options.
* @name GeoMashup#termLineOptions
* @event
* @param {Object} options Modifiable Mapstraction
* or Google Polyline options
* @param {String} taxonomy
* @param {String} term_id
* @param {Object} term_data Other properties of the term
*/
this.doAction( 'termLineOptions', options, taxonomy, term_id, term_data );
/**
* A term line will be added with the given options.
* @name GeoMashup#categoryLineOptions
* @event
* @deprecated Use GeoMashup#termLineOptions
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} options Modifiable Mapstraction
* or Google Polyline options
*/
this.doAction( 'categoryLineOptions', this.opts, options );
this.map.addPolylineWithData( term_data.line, options );
if (this.map.getZoom() > term_data.max_line_zoom) {
this.hideLine( term_data.line );
}
};
GeoMashup.openInfoWindow = function( marker ) {
var request, cache, object_ids, i, object_element, point = marker.location;
if ( this.open_window_marker && !this.opts.multiple_info_windows ) {
this.open_window_marker.closeBubble();
}
object_ids = this.getOnObjectIDs( this.getObjectsAtLocation( point ) );
cache = this.locationCache( point, 'info-window-' + object_ids.join(',') );
if ( cache.html ) {
marker.setInfoBubble( cache.html );
marker.openBubble();
} else {
marker.setInfoBubble( '' );
marker.openBubble();
this.open_window_marker = marker;
// Collect object ids
// Do an AJAX query to get content for these objects
request = {
url: this.geo_query_url + '&object_name=' + this.opts.object_name +
'&object_ids=' + object_ids.join( ',' )
};
/**
* A marker's info window content is being requested.
* @name GeoMashup#markerInfoWindowRequest
* @event
* @param {Marker} marker
* @param {AjaxRequestOptions} request Modifiable property: url
*/
this.doAction( 'markerInfoWindowRequest', marker, request );
jQuery.get(
request.url,
function( content ) {
var filter = {content: content};
marker.closeBubble();
/**
* A marker info window content is being loaded.
* @name GeoMashup#markerInfoWindowLoad
* @event
* @param {Marker} marker
* @param {ContentFilter} filter Modifiable property: content
*/
GeoMashup.doAction( 'markerInfoWindowLoad', marker, filter );
cache.html = GeoMashup.parentizeLinksMarkup( filter.content );
marker.setInfoBubble( cache.html );
marker.openBubble();
}
);
}
};
GeoMashup.closeInfoWindow = function( marker ) {
marker.closeBubble();
};
GeoMashup.addGlowMarker = function( marker ) {
var point = marker.location,
glow_options = {
clickable : true,
icon : this.opts.url_path + '/images/mm_36_glow.png',
iconSize : [ 30, 36 ],
iconAnchor : [ 15, 36 ]
};
if ( this.glow_marker ) {
this.removeGlowMarker();
}
/**
* A highlight "glow" marker is being created.
* @name GeoMashup#glowMarkerIcon
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} glow_options Modifiable Mapstraction
* or Google marker options
*/
this.doAction( 'glowMarkerIcon', this.opts, glow_options );
this.glow_marker = new mxn.Marker( point );
this.glow_marker.addData( glow_options );
this.glow_marker.click.addHandler( function() {
GeoMashup.deselectMarker();
} );
this.map.addMarker( this.glow_marker );
};
GeoMashup.removeGlowMarker = function() {
if ( this.glow_marker ) {
this.glow_marker.hide();
this.map.removeMarker( this.glow_marker );
this.glow_marker = null;
}
};
GeoMashup.hideAttachments = function() {
var i, j, obj;
/* No removeOverlay (yet)
for ( i = 0; i < this.open_attachments.length; i += 1 ) {
this.map.removeOverlay( this.open_attachments[i] );
}
this.open_attachments = [];
*/
};
GeoMashup.showMarkerAttachments = function( marker ) {
var object_ids, uncached_ids = [];
this.hideAttachments(); // check support
object_ids = this.getOnObjectIDs( this.getMarkerObjects( marker ) );
jQuery.each( object_ids, function( i, id ) {
var cached_attachments = GeoMashup.locationCache( marker.location, 'attachments-' + id );
if ( cached_attachments.urls ) {
jQuery.each( cached_attachments.urls, function( j, url ) {
GeoMashup.open_attachments.push( url );
GeoMashup.map.addOverlay( url );
} );
} else {
uncached_ids.push( id );
}
} );
// Request any uncached attachments
jQuery.each( uncached_ids, function( i, id ) {
var ajax_params = {action: 'geo_mashup_kml_attachments'};
ajax_params.post_ids = id;
jQuery.getJSON( GeoMashup.opts.ajaxurl + '?callback=?', ajax_params, function( data ) {
var cached_attachments = GeoMashup.locationCache( marker.location, 'attachments-' + id );
if ( !cached_attachments.urls ) {
cached_attachments.urls = [];
}
jQuery.each( data, function( j, url ) {
cached_attachments.urls.push( url );
GeoMashup.open_attachments.push( url );
GeoMashup.map.addOverlay( url );
} );
} );
} );
};
GeoMashup.addObjectIcon = function( obj ) {
// Back compat
if ( typeof customGeoMashupCategoryIcon === 'function' && obj.terms && obj.terms.hasOwnProperty( 'category' ) ) {
obj.icon = customGeoMashupCategoryIcon( GeoMashup.opts, obj.terms.category );
}
if ( !obj.icon ) {
jQuery.each( obj.terms, function( taxonomy, terms ) {
var single_icon;
if ( terms.length > 1) {
obj.icon = GeoMashup.clone( GeoMashup.multiple_term_icon );
return false;
} else if ( terms.length === 1 ) {
single_icon = GeoMashup.term_manager.getTermData( taxonomy, terms[0], 'icon' );
if ( obj.icon && obj.icon.image !== single_icon.image ) {
// We have two different icons in different taxonomies
obj.icon = GeoMashup.clone( GeoMashup.multiple_term_icon );
return false;
} else {
obj.icon = GeoMashup.clone( single_icon );
}
}
} );
if ( !obj.icon ) {
obj.icon = GeoMashup.colorIcon( 'red' );
}
/**
* An icon is being assigned to an object.
* @name GeoMashup#objectIcon
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {GeoMashupObject} object Object whose icon property was set.
*/
this.doAction( 'objectIcon', GeoMashup.opts, obj );
}
};
GeoMashup.createMarker = function(point,obj) {
var marker, marker_opts;
if ( !obj.icon ) {
this.addObjectIcon( obj );
}
marker_opts = {
label: obj.title,
icon: obj.icon.image,
iconSize: obj.icon.iconSize,
iconShadow: obj.icon.iconShadow,
iconAnchor: obj.icon.iconAnchor,
iconShadowSize: obj.icon.shadowSize,
visible: true
};
/**
* A marker is being created for an object. Use this to change marker
* options, but if you just want to assign an icon to an object, use the
* objectIcon action.
*
* @name GeoMashup#objectMarkerOptions
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} glow_options Modifiable Mapstraction
* or Google marker options
* @param {GeoMashupObject} object
*/
this.doAction( 'objectMarkerOptions', this.opts, marker_opts, obj );
marker = new mxn.Marker( point );
marker.addData( marker_opts );
marker.click.addHandler( function() {
// Toggle marker selection
if ( marker === GeoMashup.selected_marker ) {
GeoMashup.deselectMarker();
} else {
GeoMashup.selectMarker( marker );
}
} );
/**
* A marker was created.
* @name GeoMashup#marker
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Marker} marker
*/
this.doAction( 'marker', this.opts, marker );
return marker;
};
GeoMashup.clickObjectMarker = function( object_id, try_count ) {
var obj = this.objects[object_id];
if ( !GeoMashup.isObjectOn( obj ) ) {
return false;
}
if (typeof try_count === 'undefined') {
try_count = 1;
}
if ( obj && obj.marker && try_count < 4 ) {
// openlayers/mxn seems to have trouble displaying an infobubble right away
if ( try_count < 2 ) {
try_count += 1;
setTimeout(function () {GeoMashup.clickObjectMarker(object_id, try_count);}, 1000);
} else {
obj.marker.click.fire();
}
}
};
GeoMashup.colorIcon = function( color_name ) {
var icon = this.clone( this.base_color_icon );
icon.image = this.opts.url_path + '/images/mm_36_' + color_name + '.png';
return icon;
};
GeoMashup.getMarkerLatLng = function( marker ) {
return marker.location;
};
GeoMashup.hideMarker = function( marker ) {
if ( marker === this.selected_marker ) {
this.deselectMarker();
}
marker.hide();
};
GeoMashup.showMarker = function( marker ) {
marker.show();
};
GeoMashup.hideLine = function( line ) {
try {
line.hide();
} catch( e ) {
this.map.removePolyline( line );
}
line.setAttribute( 'visible', false );
};
GeoMashup.showLine = function( line ) {
try {
line.show();
} catch( e ) {
this.map.addPolyline( line );
}
line.setAttribute( 'visible', true );
};
GeoMashup.isLineVisible = function( line ) {
return line.getAttribute( 'visible' );
};
GeoMashup.newLatLng = function( lat, lng ) {
return new mxn.LatLonPoint( lat, lng );
};
GeoMashup.extendLocationBounds = function( latlng ) {
if ( this.location_bounds ) {
this.location_bounds.extend( latlng );
} else {
this.location_bounds = new mxn.BoundingBox( latlng, latlng );
}
};
GeoMashup.addMarkers = function( markers ) {
this.forEach( markers, function( i, marker ) {
this.map.addMarker( marker );
} );
};
GeoMashup.makeMarkerMultiple = function( marker ) {
var plus_image, original_image;
if (typeof customGeoMashupMultiplePostImage === 'function') {
plus_image = customGeoMashupMultiplePostImage(this.opts, marker);
}
if (!plus_image) {
plus_image = this.opts.url_path + '/images/mm_36_plus.png';
}
original_image = marker.iconUrl;
marker.setIcon( plus_image );
/**
* A marker representing multiple objects was created.
* @name GeoMashup#multiObjectMarker
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Marker} marker
*/
this.doAction( 'multiObjectMarker', this.opts, marker );
/**
* A marker representing multiple objects was created with this icon.
* @name GeoMashup#multiObjectIcon
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {String} plus_image Icon URL
*/
this.doAction( 'multiObjectIcon', this.opts, plus_image );
if ( marker.onmap && marker.iconUrl !== original_image ) {
this.map.removeMarker( marker );
this.map.addMarker( marker );
}
};
GeoMashup.setMarkerImage = function( marker, image_url ) {
if ( marker.iconUrl !== image_url ) {
marker.setIcon( image_url );
if ( marker.onmap ) {
this.map.removeMarker( marker );
this.map.addMarker( marker );
}
}
};
GeoMashup.autoZoom = function() {
var map = this.map;
var limitZoom = function() {
var max_zoom = parseInt( GeoMashup.opts.auto_zoom_max, 10 );
if ( map.getZoom() > max_zoom ) {
map.setZoom( max_zoom );
}
map.changeZoom.removeHandler( limitZoom );
};
if ( typeof this.opts.auto_zoom_max !== 'undefined' ) {
this.map.changeZoom.addHandler( limitZoom );
}
this.map.autoCenterAndZoom();
};
GeoMashup.isMarkerVisible = function( marker ) {
var map_bounds;
try {
map_bounds = this.map.getBounds();
} catch( e ) {
// No bounds available yet, no markers are visible
return false;
}
return ( marker.getAttribute( 'visible' ) && map_bounds && map_bounds.contains( marker.location ) );
};
GeoMashup.centerMarker = function( marker, zoom ) {
if ( typeof zoom === 'number' ) {
this.map.setCenterAndZoom( marker.location, zoom );
} else {
this.map.setCenter( marker.location, {}, true );
}
};
GeoMashup.createMap = function(container, opts) {
var i, type_num, center_latlng, map_opts, map_types, request, url, objects, point, marker_opts,
clusterer_opts, single_marker, ov, credit_div, initial_zoom = 1, controls = {}, filter = {};
this.container = container;
this.base_color_icon = {};
this.base_color_icon.image = opts.url_path + '/images/mm_36_black.png';
this.base_color_icon.iconShadow = '';
this.base_color_icon.iconSize = [30, 36];
this.base_color_icon.shadowSize = [0,0];
this.base_color_icon.iconAnchor = [15, 36];
this.base_color_icon.infoWindowAnchor = [15, 2];
this.multiple_term_icon = this.clone( this.base_color_icon );
this.multiple_term_icon.image = opts.url_path + '/images/mm_36_mixed.png';
// Falsify options to make tests simpler
this.forEach( opts, function( key, value ) {
if ( 'false' === value || 'FALSE' === value ) {
opts[key] = false;
}
} );
// See if we have access to a parent frame
this.have_parent_access = false;
try {
if ( typeof parent === 'object' ) {
// Try access, throws an exception if prohibited
parent.document.getElementById( 'bogus-test' );
// Access worked
this.have_parent_access = true;
}
} catch ( parent_exception ) { }
// For now, siteurl is the home url
opts.home_url = opts.siteurl;
map_types = {
'G_NORMAL_MAP' : mxn.Mapstraction.ROAD,
'G_SATELLITE_MAP' : mxn.Mapstraction.SATELLITE,
'G_HYBRID_MAP' : mxn.Mapstraction.HYBRID,
'G_PHYSICAL_MAP' : mxn.Mapstraction.PHYSICAL
};
if (typeof opts.map_type === 'string') {
if ( map_types[opts.map_type] ) {
opts.map_type = map_types[opts.map_type] ;
} else {
type_num = parseInt(opts.map_type, 10);
if ( isNaN(type_num) || type_num > 2 ) {
opts.map_type = map_types.G_NORMAL_MAP;
} else {
opts.map_type = type_num;
}
}
} else if (typeof opts.map_type === 'undefined') {
opts.map_type = map_types.G_NORMAL_MAP;
}
this.map = new mxn.Mapstraction( this.container, opts.map_api );
map_opts = {enableDragging: true};
map_opts.enableScrollWheelZoom = ( opts.enable_scroll_wheel_zoom ? true : false );
if ( typeof this.map.enableGeoMashupExtras === 'function' ) {
this.map.enableGeoMashupExtras();
}
/**
* The map options are being set.
* @name GeoMashup#mapOptions
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} map_opts Modifiable Mapstraction
* or Google map options
*/
this.doAction( 'mapOptions', opts, map_opts );
this.map.setOptions( map_opts );
this.map.setCenterAndZoom(new mxn.LatLonPoint(0,0), 0);
/**
* The map was created.
* @name GeoMashup#newMap
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Map} map
*/
this.doAction( 'newMap', opts, this.map );
// Create the loading spinner icon and show it
this.spinner_div = document.createElement( 'div' );
this.spinner_div.innerHTML = '' +
'

';
this.showLoadingIcon();
this.map.load.addHandler( function() {GeoMashup.hideLoadingIcon();} );
if (!opts.object_name) {
opts.object_name = 'post';
}
this.opts = opts;
filter.url = opts.siteurl +
( opts.siteurl.indexOf( '?' ) > 0 ? '&' : '?' ) +
'geo_mashup_content=geo-query&map_name=' + encodeURIComponent( opts.name );
if ( opts.lang && filter.url.indexOf( 'lang=' ) === -1 ) {
filter.url += '&lang=' + encodeURIComponent( opts.lang );
}
/**
* The base URL used for geo queries is being set.
* @name GeoMashup#geoQueryUrl
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} filter Mofiable property: url
*/
this.doAction( 'geoQueryUrl', this.opts, filter );
this.geo_query_url = filter.url;
this.map.changeZoom.addHandler( function() {
GeoMashup.adjustZoom();
GeoMashup.adjustViewport();
}, this );
this.map.endPan.addHandler( function() {GeoMashup.adjustViewport();}, this );
// No clustering available
if ( opts.zoom !== 'auto' && typeof opts.zoom === 'string' ) {
initial_zoom = parseInt(opts.zoom, 10);
}else {
initial_zoom = opts.zoom;
}
if (opts.load_kml) {
try {
// Some servers (Google) don't like HTML entities in URLs
opts.load_kml = jQuery( '').html( opts.load_kml ).text();
if ( initial_zoom === 'auto' ) {
this.map.addOverlay( opts.load_kml, true );
} else {
this.map.addOverlay( opts.load_kml );
}
} catch (e) {
// Probably not implemented
}
}
if ( this.term_manager ) {
this.term_manager.load();
}
try {
this.map.setMapType( opts.map_type );
} catch ( map_type_ex) {
// Probably not implemented
}
if ( initial_zoom !== 'auto' ) {
if (opts.center_lat && opts.center_lng) {
// Use the center from options
this.map.setCenterAndZoom(new mxn.LatLonPoint( parseFloat( opts.center_lat ), parseFloat( opts.center_lng ) ), initial_zoom );
} else if (opts.object_data && opts.object_data.objects[0]) {
center_latlng = new mxn.LatLonPoint( parseFloat( opts.object_data.objects[0].lat ), parseFloat( opts.object_data.objects[0].lng ) );
this.map.setCenterAndZoom( center_latlng, initial_zoom );
} else {
// Center on the most recent located object
url = this.geo_query_url + '&limit=1';
if (opts.map_cat) {
url += '&map_cat='+opts.map_cat;
}
jQuery.getJSON( url, function( objects ) {
if (objects.length>0) {
center_latlng = new mxn.LatLonPoint( parseFloat( objects[0].lat ), parseFloat( objects[0].lng ) );
this.map.setCenterAndZoom( center_latlng, initial_zoom );
}
} );
}
}
this.location_bounds = null;
if (opts.map_content === 'single')
{
if (opts.object_data && opts.object_data.objects.length && !opts.load_kml)
{
marker_opts = {visible: true};
if (typeof customGeoMashupSinglePostIcon === 'function') {
marker_opts = customGeoMashupSinglePostIcon(this.opts);
}
if ( !marker_opts.image ) {
marker_opts = this.colorIcon( 'red' );
marker_opts.icon = marker_opts.image;
}
/**
* A single map marker is being created with these options
* @name GeoMashup#singleMarkerOptions
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Object} marker_opts Mofifiable Mapstraction or Google marker options
*/
this.doAction( 'singleMarkerOptions', this.opts, marker_opts );
single_marker = new mxn.Marker(
new mxn.LatLonPoint( parseFloat( opts.object_data.objects[0].lat ), parseFloat( opts.object_data.objects[0].lng ) )
);
this.map.addMarkerWithData( single_marker, marker_opts );
/**
* A single map marker was added to the map.
* @name GeoMashup#singleMarker
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Marker} single_marker
*/
this.doAction( 'singleMarker', this.opts, single_marker );
}
} else if (opts.object_data) {
this.addObjects(opts.object_data.objects,true);
} else {
// Request objects near visible range first
this.requestObjects(true);
// Request all objects
this.requestObjects(false);
}
if ('GSmallZoomControl' === opts.map_control || 'GSmallZoomControl3D' === opts.map_control) {
controls.zoom = 'small';
} else if ('GSmallMapControl' === opts.map_control) {
controls.zoom = 'small';
controls.pan = true;
} else if ('GLargeMapControl' === opts.map_control || 'GLargeMapControl3D' === opts.map_control) {
controls.zoom = 'large';
controls.pan = true;
}
if (opts.add_map_type_control ) {
controls.map_type = true;
}
if (opts.add_overview_control) {
controls.overview = true;
}
this.map.addControls( controls );
if (opts.add_map_type_control && typeof this.map.setMapTypes === 'function' ) {
if ( typeof opts.add_map_type_control === 'string' ) {
opts.add_map_type_control = opts.add_map_type_control.split(/\s*,\s*/);
if ( typeof map_types[opts.add_map_type_control[0]] === 'undefined' ) {
// Convert the old boolean value to a default array
opts.add_map_type_control = [ 'G_NORMAL_MAP', 'G_SATELLITE_MAP', 'G_PHYSICAL_MAP' ];
}
}
// Convert to mapstraction types
opts.mxn_map_type_control = [];
for ( i = 0; i < opts.add_map_type_control.length; i += 1 ) {
opts.mxn_map_type_control.push( map_types[ opts.add_map_type_control[i] ] );
}
this.map.setMapTypes( opts.mxn_map_type_control );
}
this.map.load.addHandler( function() {GeoMashup.updateVisibleList();} );
if (typeof customizeGeoMashupMap === 'function') {
customizeGeoMashupMap(this.opts, this.map);
}
if (typeof customizeGeoMashup === 'function') {
customizeGeoMashup(this);
}
this.hideLoadingIcon();
/**
* The map has loaded.
* @name GeoMashup#loadedMap
* @event
* @param {GeoMashupOptions} properties Geo Mashup configuration data
* @param {Map} map
*/
this.doAction( 'loadedMap', this.opts, this.map );
};