Skip to content

Instantly share code, notes, and snippets.

@tistre
Last active February 16, 2017 14:16
Show Gist options
  • Save tistre/9092438 to your computer and use it in GitHub Desktop.
Save tistre/9092438 to your computer and use it in GitHub Desktop.
Google Maps demo for Tim’s simple JavaScript component test, see https://www.strehle.de/tim/weblog/archives/2014/02/19/1694
/* Namespace */
var DCX = DCX || { };
DCX.Ui = DCX.Ui || { };
DCX.Ui.Model = DCX.Ui.Model || { };
DCX.Ui.View = DCX.Ui.View || { };
DCX.Ui.Controller = DCX.Ui.Controller || { };
DCX.Ui.Service = DCX.Ui.Service || { };
/* Demo page component */
DCX.Ui.DemoPage = function(config)
{
var _private = { };
_private.config = config;
_private.$element = $(document);
_private.$model = $(_private.config.model).first();
// Update page title when the address changes
_private.$model.on('data_changed.dcx_ui_model', function(e)
{
if (e.data_key === 'address')
{
document.title = e.data_value;
}
});
};
/* Contact info model */
DCX.Ui.Model.ContactInfo = function(config)
{
var _private = { };
_private.config = config;
_private.data = { };
_private.$element = $(_private.config.selector).first();
// Update model data when components send new data
_private.$element.on('data_changed.dcx_ui_model', function(e)
{
_private.data[ e.data_key ] = e.data_value;
});
};
/* Contact info controller */
DCX.Ui.Controller.ContactInfo = function(config)
{
var _private = { };
_private.config = config;
_private.$element = $(_private.config.selector).first();
_private.$model = $(_private.config.model).first();
_private.$address_input = $(_private.config.address_input).first();
_private.$map = $(_private.config.map).first();
_private.$geocoder_service = $(_private.config.geocoder_service).first();
// When the address changes in the model, update the input field value and map
_private.$model.on('data_changed.dcx_ui_model', function(e)
{
if (e.data_key === 'address')
{
if (e.data_origin !== 'address_input')
{
_private.$address_input.trigger($.Event
(
'set_value.dcx_ui_textinput',
{ data_value: e.data_value }
));
}
if (e.data_origin !== 'map')
{
var result = DCX.Ui.getEventResult
(
_private.$geocoder_service,
'geocode.google_maps_geocoder',
{ address: e.data_value }
);
$.when(result).done(function()
{
_private.$map.trigger($.Event
(
'pan_to.google_maps_map',
{
location: result.gcr[ 0 ].geometry.location
}
));
});
}
}
});
// When the user enters an address in the input field, change the model
_private.$address_input.on('value_changed.dcx_ui_textinput', function(e)
{
_private.$model.trigger($.Event
(
'data_changed.dcx_ui_model',
{
data_key: 'address',
data_value: e.data_value,
data_origin: 'address_input'
}
));
});
// When the map center changes, do a geocoder address lookup
// and publish its result as a model event
_private.$map.on('center_changed.google_maps_map', function(e)
{
var result = DCX.Ui.getEventResult
(
_private.$geocoder_service,
'reverse_geocode.google_maps_geocoder',
{ location: e.center_location }
);
$.when(result).done(function()
{
_private.$model.trigger($.Event
(
'data_changed.dcx_ui_model',
{
data_key: 'address',
data_value: result.gcr[ 0 ].formatted_address,
data_origin: 'map'
}
));
});
});
};
/* Address text input component */
DCX.Ui.View.AddressInput = function(config)
{
var _private = { };
_private.config = config;
_private.$element = $(_private.config.selector).first();
_private.$button = $(_private.config.button).first();
// Update the input value when requested
_private.$element.on('set_value.dcx_ui_textinput', function(e)
{
if (_private.$element.val() === e.data_value)
{
return;
}
_private.$element.val(e.data_value);
_private.$button.attr('disabled', 'disabled');
});
// When the user starts to type in the address input field, enable the "Jump to" button
_private.$element.on('keyup', function(e)
{
_private.$button.removeAttr('disabled');
});
// When the user clicks the "Jump to" button, trigger a "value_changed" event
_private.$button.on('click', function(e)
{
_private.$element.trigger($.Event
(
'value_changed.dcx_ui_textinput',
{
data_value: _private.$element.val()
}
));
});
};
/* Google Maps map component */
DCX.Ui.View.GoogleMaps_Map = function(config)
{
var _private = { };
_private.config = config;
_private.$element = $(_private.config.selector).first();
// Create Google Maps map
_private.map = new google.maps.Map
(
_private.$element[ 0 ],
_private.config.map_options
);
// Pan to coordinates if requested
_private.$element.on('pan_to.google_maps_map', function(e)
{
_private.map.panTo(e.location);
});
// Translate Google Maps events into jQuery custom events
google.maps.event.addListener(_private.map, 'center_changed', function()
{
_private.$element.trigger($.Event
(
'center_changed.google_maps_map',
{ center_location: _private.map.getCenter() }
));
});
};
/* Google Maps geocoder component */
DCX.Ui.Service.GoogleMaps_Geocoder = function(config)
{
var _private = { };
_private.config = config;
_private.$element = $(_private.config.selector).first();
// Create Google Maps geocoder
_private.geocoder = new google.maps.Geocoder();
// Get location by address
_private.$element.on('geocode.google_maps_geocoder', function(e)
{
var request = { address: e.address };
var deferred = $.Deferred();
_private.geocoder.geocode(request, function(results, status)
{
if ((status === google.maps.GeocoderStatus.OK) && results[ 1 ])
{
// XXX is it okay to write custom data into the promise?
$.extend(true, deferred.promise(), { gcr: results });
deferred.resolve();
}
else
{
deferred.reject();
}
});
return deferred.promise();
});
// Get address by location
_private.$element.on('reverse_geocode.google_maps_geocoder', function(e)
{
var request = { location: e.location };
var deferred = $.Deferred();
_private.geocoder.geocode(request, function(results, status)
{
if ((status === google.maps.GeocoderStatus.OK) && results[ 1 ])
{
// XXX is it okay to write custom data into the promise?
$.extend(true, deferred.promise(), { gcr: results });
deferred.resolve();
}
else
{
deferred.reject();
}
});
return deferred.promise();
});
};
/* Generic framework */
DCX.Ui.component_selectors = [ ];
DCX.Ui.createComponent = function(config)
{
config = config || { };
config.factory_function.call({ }, config);
if ($.inArray(config.selector, DCX.Ui.component_selectors) < 0)
{
DCX.Ui.component_selectors.push(config.selector);
}
};
DCX.Ui.createComponents = function(configs)
{
if (! $.isArray(configs))
{
return;
}
$.each(configs, function(i, config)
{
DCX.Ui.createComponent(config);
});
$.each(DCX.Ui.component_selectors, function(i, selector)
{
$(selector).first().trigger('initialize.dcx_ui_component');
});
};
DCX.Ui.getEventResult = function($element, event_type, event_properties)
{
var all_results = DCX.Ui.getAllEventResults($element, event_type, event_properties);
return all_results[ 0 ];
};
DCX.Ui.getAllEventResults = function($element, event_type, event_properties)
{
var e = $.Event(event_type, event_properties);
$element.trigger(e);
if (e.result === undefined)
{
return [ { } ];
}
if (! $.isArray(e.result))
{
e.result = [ e.result ];
}
return e.result;
};
/* Generic framework - "loader" that initializes components */
$(document).ready(function()
{
DCX.Ui.createComponents(DCX.Ui.initialComponentConfig);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment