Last active
October 20, 2016 15:10
-
-
Save bowheart/4c66607ab1a6ff8de9fb to your computer and use it in GitHub Desktop.
Filling out forms can be tedious stuff. This library will autofill city and state fields in a form when the user enters their zipcode. Makes use of the Google Maps API.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Another library by Joshua Claunch | |
* https://github.com/bowheart | |
* https://gist.github.com/bowheart | |
* | |
* A jQuery-dependent secret intelligence library. :O | |
*/ | |
(function() { | |
var Autofiller = function(zipInput, cityInput, stateInput, phoneInput) { | |
this.zipInput = zipInput; | |
this.cityInput = cityInput; | |
this.stateInput = stateInput; | |
this.phoneInput = phoneInput; | |
this.geocoder = new google.maps.Geocoder(); | |
this.bindInput(); | |
}; | |
Autofiller.prototype = { | |
autofill: function(cityVal, stateVal) { | |
this.autofillCity(cityVal); | |
this.autofillState(stateVal); | |
this.autoFocus(); | |
}, | |
autofillCity: function(cityVal) { | |
this.cityInput | |
.val(cityVal) | |
.trigger('validate'); | |
}, | |
autofillState: function(stateVal) { | |
this.stateInput | |
.val(this.statePrefix + stateVal) | |
.trigger('validate'); | |
}, | |
autoFocus: function() { | |
if (!this.jumpFocus) return; | |
this.focusInput.focus(); | |
}, | |
bindInput: function() { | |
this.zipInput[0].addEventListener('input', this.handleInput.bind(this)); | |
}, | |
fetchZipInfo: function() { | |
var self = this; | |
self.geocoder.geocode({address: self.val}, function(results, status) { | |
if (!results || status.toLowerCase() !== 'ok') return; // It didn't work. Don't try to do anything. | |
var result = self.parseResults(results); // reduce to a single result | |
if (!result) return; // No correct-country result. Stop execution. | |
self.validateZipInfo(result); | |
}); | |
}, | |
handleInput: function() { | |
if (!this.zipIsValid()) return; | |
this.fetchZipInfo(); | |
}, | |
parseResults: function(results) { | |
var self = this; | |
return results.filter(function(nextResult) { | |
return nextResult.address_components.pop().short_name === self.country; // filter out non-correct-country results | |
})[0]; // assume we want the first correct-country result (a pretty safe assumption, I think?) | |
}, | |
parseCityVal: function(zipInfo) { | |
return zipInfo.address_components[1].short_name; | |
}, | |
parseStateVal: function(zipInfo) { | |
return zipInfo.address_components.pop().short_name; | |
}, | |
validCondition: function(cityVal, stateVal) { | |
return cityVal && stateVal; | |
}, | |
validateZipInfo: function(zipInfo) { | |
var cityVal = this.parseCityVal(zipInfo), | |
stateVal = this.parseStateVal(zipInfo); | |
if (!this.validCondition(cityVal, stateVal)) return; // The result isn't what's expected. Stop execution. | |
this.autofill(cityVal, stateVal); | |
}, | |
zipIsValid: function() { | |
return this.val.length >= this.length; | |
}, | |
get focusInput() { | |
return this.newFocusInput || this.phoneInput; | |
}, | |
get val() { | |
return this.zipInput.val(); | |
}, | |
jumpFocus: true, | |
length: 5, | |
statePrefix: '' | |
}; | |
var USAutofiller = function() { Autofiller.apply(this, arguments); }; | |
USAutofiller.prototype = Object.create(Autofiller.prototype, { | |
country: { value: 'US' } | |
}); | |
var CAAutofiller = function() { Autofiller.apply(this, arguments); }; | |
CAAutofiller.prototype = Object.create(Autofiller.prototype, { | |
country: { value: 'CA' }, | |
length: { value: 7 } | |
}); | |
var GBAutofiller = function() { Autofiller.apply(this, arguments); }; | |
GBAutofiller.prototype = Object.create(Autofiller.prototype, { | |
country: { value: 'GB' }, | |
jumpFocus: { value: false }, | |
length: { value: 6 }, | |
parseStateVal: { value: function(zipInfo) { | |
var optionText = zipInfo.address_components.pop().short_name.trim().toLowerCase(), | |
stateOption = this.stateInput.find('option').filter(function() { | |
return this.innerHTML.trim().toLowerCase() === optionText; | |
}); | |
if (!stateOption.length) { | |
this.validCondition = function(cityVal) { | |
return !!cityVal; | |
}; | |
this.autofillState = function() {}; // do nothing | |
return ''; | |
} | |
return stateOption[0].value; | |
} }, | |
}); | |
var AUAutofiller = function() { Autofiller.apply(this, arguments); }; | |
AUAutofiller.prototype = Object.create(Autofiller.prototype, { | |
country: { value: 'AU' }, | |
length: { value: 4 }, | |
statePrefix: { value: 'AU-' }, | |
autofillCity: { value: function(cityVal) { | |
// do nothing. | |
} }, | |
focusInput: { get: function() { | |
return this.cityInput; | |
} } | |
}); | |
var autofillersMap = { | |
USAutofiller: USAutofiller, | |
CAAutofiller: CAAutofiller, | |
GBAutofiller: GBAutofiller, | |
AUAutofiller: AUAutofiller | |
}; | |
var factory = function() { | |
// create the correct Autofiller descendant (one for each form on the page) based on the site's country. | |
var zipInputs = $('input').filter(function() { return /zip/i.test(this.name); }), | |
tempStateInput = zipInputs.first().parents('form').find('select').filter(function() { return /state/i.test(this.name); }), | |
country = tempStateInput.find('option')[1].value.slice(0, 2).toUpperCase() | |
if (country === 'AB') country = 'CA'; // A hack... AB == Alberta ... Canada | |
else if (country === 'AL') country = 'US'; // A hack... AL == Alabama ... US | |
var countryAutofiller = autofillersMap[country + 'Autofiller']; | |
zipInputs.each(function() { | |
var zipInput = $(this), | |
cityInput = zipInput.parents('form').find('input').filter(function() { return /city/i.test(this.name); }), | |
stateInput = zipInput.parents('form').find('select').filter(function() { return /state/i.test(this.name); }), | |
phoneInput = zipInput.parents('form').find('input[name="phone"]').add(zipInput.parents('form').find('input[name="card"]')); | |
new countryAutofiller(zipInput, cityInput, stateInput, phoneInput); | |
}); | |
}; | |
var loadGoogleMaps = function(onload) { | |
var script = document.createElement('script'); | |
$('head').append(script); | |
script.onload = onload; | |
script.src = 'https://maps.google.com/maps/api/js?key=AIzaSyCKz4Jc4FO96-0oLCWxLM5_aQhWhWayg3o'; | |
}; | |
$(function() { | |
if ($('script').filter(function() { return this.src.match(/google\.com\/maps\/api\/js/); }).length) { | |
return factory(); | |
} | |
loadGoogleMaps(factory.bind(factory)); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment