//v=3& var atdcraAutoComplete = false; var atdcraAutoCompleteId = 'atdcraAutoComplete'; var atdcraDefaultString = 'NA'; function atdcraLoadGoogleApi() { $.getScript("https://maps.googleapis.com/maps/api/js?key=AIzaSyD5LLbBU1OwlsMMX18FPNqJC6B6JA8UpYk&libraries=places&v=3&callback=atdcraInitAutoComplete") .done(function( script, textStatus ) {console.info('Loaded google maps API.');}) .fail(function(jqxhr, settings, exception) {console.error('Failed to load google maps API, address auto completion disabled.');}); } function atdcraInitAutoComplete() { //----add auto complete field, hide others... atdcraPrepForm(); //atdcraUpdateAddressDisplaySpans(); // Create the autocomplete object, restricting the search to geographical location types // Thanks: https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform atdcraAutoComplete = new google.maps.places.Autocomplete( /** @type {!HTMLInputElement} */(document.getElementById(atdcraAutoCompleteId)), {types: ['geocode']}); // When the user selects an address from the dropdown, populate the address fields in the form. atdcraAutoComplete.addListener('place_changed', atdcraAutoCompleteFields); } function atdcraGetUnixTimestamp() { var u; if (!Date.now) { Date.now = function() { return new Date().getTime(); } } u = Math.floor(Date.now() / 1000); return u; } function atdcraCreateAutoCompleteElement() { var d = document.createElement('div'); var l = document.createElement('label'); var i = document.createElement('input'); var n = atdcraAutoCompleteId; $(d).addClass('form-group'); $(l).attr('for', n); $(l).addClass('control-label'); $(l).addClass('required'); $(l).html('Start Typing Your Address'); $(d).append(l); $(i).attr('id', n); $(i).attr('name', n); $(i).attr('required', true); $(i).attr('type', 'text'); $(i).attr('data-atdcra-valid-place', 0); $(i).attr('placeholder', 'Enter your address'); $(i).attr('autocomplete', 'off'); $(i).addClass('form-control'); $(i).attr('data-atdcra-last-focus-in', 0); //$(i).attr('data-atdcra-last-focus-out', 0); $(i).attr('data-atdcra-last-valid-api-call', 0); $(i).on('focus', function(e) { var u = atdcraGetUnixTimestamp(); $(this).attr('data-atdcra-last-focus-in', u); atdcraGeoLocate(); }); $(i).on('focusout', function() { //var u = atdcraGetUnixTimestamp(); //$(this).attr('data-atdcra-last-focus-out', u); //-----if no valid place is selected after focus out (plus a slight delay)... clear evreything out to prevent null input //-----unfortunatley, place_changed is the only event the auto complete api uses atdcraValidateAutoCompleteField(); }); $(d).append(i); return d; } function atdcraBuildAddressDisplaySpan(l) { var s = false; var i = $('#'+l); var v; s = document.createElement('span'); $(s).addClass('static-address-item'); $(s).attr('data-atdcra-static-address-id', l); //$(s).css('display', 'block'); $(s).html(' '); $(i).on('change', function() { atdcraUpdateAddressDisplaySpans(); }); return s; } function atdcraUpdateAddressDisplaySpans() { var f = atdcraFieldMappings(); var u; var n; var s; var v; var m = $('span.static-address-item[data-atdcra-static-address-id="instruction"]'); var x = false; f['address_2'] = {}; $.each(f, function(i, n) { if (i == 'country') { //===================== n = atdcraUpdateAddressSpanViaSelectOption(i); //console.log('fix me atdcraUpdateAddressDisplaySpans()'); } else { n = atdcraUpdateAddressSpanViaTextInput(i); } if (n == true) { x = true; } }); if (x == true) { $(m).css('display', 'none'); } else { $(m).css('display', 'block'); } } function atdcraUpdateAddressSpanViaSelectOption(i) { var s = $('span.static-address-item[data-atdcra-static-address-id="' + i + '"]'); var u = $('#'+i); var n; var v; var x = false; if (!$(s).length) { return false; } n = $(u).find('option:selected').first(); v = $(u).val(); if (!v.trim()) { // is empty or whitespace v = ""; } else { v = $(n).text(); } if (!v.trim()) { // is empty or whitespace $(s).css('display', 'none'); } else { $(s).css('display', 'block'); x = true; } $(s).html(v); return x; } function atdcraUpdateAddressSpanViaTextInput(i) { var s = $('span.static-address-item[data-atdcra-static-address-id="' + i + '"]'); var u = $('#'+i); var v = $(u).val(); var x = false; if (!$(s).length) { return false; } if (!v.trim()) { // is empty or whitespace $(s).css('display', 'none'); } else { $(s).css('display', 'block'); x = true; } $(s).html(v); return x; } function atdcraBuildAddressDisplay() { var d = document.createElement('div'); var l = document.createElement('label'); var f = atdcraFieldMappings(); var s; $(d).addClass('form-group'); $(d).addClass('static-address-group'); $(l).addClass('control-label'); $(l).html('Address'); $(d).append(l); s = false; s = atdcraBuildAddressDisplaySpan('instruction'); $(s).html('Please search for your address using the input above and select one of the suggested options.'); $(s).css('font-weight', 'bold'); /* $(s).css('color', 'red'); */ $(s).css('display', 'block'); $(d).append(s); $.each(f, function(i, n) { s = false; s = atdcraBuildAddressDisplaySpan(i); $(s).css('display', 'none'); $(d).append(s); if (i == 'address') { s = false; s = atdcraBuildAddressDisplaySpan('address_2'); $(s).css('display', 'none'); $(d).append(s); } }); s = false; s = atdcraBuildAddressDisplaySpan('fallback'); $(s).html('(Address incorrect or not listed in the suggested options? Click here to input it manually.)'); $(s).css('display', 'block'); $(s).css('color', '#9b7f41'); $(s).css('cursor', 'pointer'); $(s).css('font-size', '80%'); $(s).on('touchstart mousedown', function () { atdcraEnableManualAddressInput(); }); $(d).append(s); atdcraUpdateAddressDisplaySpans(); return d; } function atdcraEnableManualAddressInput() { var f = atdcraFieldMappings(); var n = '#' + atdcraAutoCompleteId; //-----lets *not* purge incase the form had errors?.. else user has to re fill fields //atdcraPurgeAddressFieldValues(); $.each(f, function(i, n) { l = $('#'+i); //-----remember; required was removed for usabality $(l).attr('required', 'true'); w = $(l).closest('div.form-group'); $(w).css('display', 'block'); }); $(n).closest('div.form-group').remove(); $('.static-address-group').remove(); } function atdcraValidateAutoCompleteField() { var m = $('#'+atdcraAutoCompleteId); var n; var o; var p; var q; var t = 10; //-----if googles dropdown ia visible, delay this action to allow time for api call... //-----since the dropdown list of suggesteed addresses is a div outside of the form input... //-------selecting a place causes the form input to lose focus which triggers this function if ($('body .pac-container').first().is(":visible")) { //-----if menu is visible at time of focus out... //-------there is a chance that the user caused focus to be lost by selecting one of the suggested places in the dropdown //-------to allow for this, add a delay before checking if a valid address was selected //-------this run arround is required as there are no events fired by googles api that signify a change of the address search value with an invalid input //console.log('menu visible'); t = 250; } function checkValidity() { n = parseInt($(m).attr('data-atdcra-last-focus-in')); //o = parseInt($(m).attr('data-atdcra-last-focus-out')); p = parseInt($(m).attr('data-atdcra-last-valid-api-call')); q = p - n; if (q > 0) { //console.log('valid place found'); } else { //console.log('invalid, no place selected'); atdcraPurgeAddressFieldValues(); } } setTimeout(checkValidity, t); } function atdcraFieldMappings() { //-----map laravel form fields to google api json output //-----primary key = field id in laravel //-----value = object enumerating google api fields and targe value node //-------multiple google api fields can be concatnated var f = {}; f['address'] = {}; f['address'][0] = {}; f['address'][0]['street_number'] = {}; f['address'][0]['street_number'] = 'short_name'; f['address'][1] = {}; f['address'][1]['route'] = {}; f['address'][1]['route'] = 'long_name'; f['city'] = {}; f['city'][0] = {}; f['city'][0]['locality'] = {}; f['city'][0]['locality'] = 'long_name'; f['state_province'] = {}; f['state_province'][0] = {}; f['state_province'][0]['administrative_area_level_1'] = {}; f['state_province'][0]['administrative_area_level_1'] = 'short_name'; f['postal_code'] = {}; f['postal_code'][0] = {}; f['postal_code'][0]['postal_code'] = {}; f['postal_code'][0]['postal_code'] = 'short_name'; f['country'] = {}; f['country'][0] = {}; f['country'][0]['country'] = {}; f['country'][0]['country'] = 'short_name'; return f; } function atdcraGetRequiredNodes() { var f = atdcraFieldMappings(); var y = {}; $.each(f, function(i, n) { $.each(n, function(ni, nn) { $.each(nn, function(nni, nnn) { y[nni] = i; }); }); }); return y; } function atdcraGetRequiredNodeValueTypes() { var f = atdcraFieldMappings(); var y = {}; $.each(f, function(i, n) { $.each(n, function(ni, nn) { $.each(nn, function(nni, nnn) { y[nni] = nnn; }); }); }); return y; } function atdcraPrepForm() { //-----hide fields that the autocomplete field will manage //-----also, add the auto complete field var d = atdcraCreateAutoCompleteElement(); var s = atdcraBuildAddressDisplay(); var f = atdcraFieldMappings(); var r = false; var u; var x = 0; var l; var w; $.each(f, function(i, n) { l = $('#'+i); //u = $(l).attr('rules'); //$(l).attr('data-atdcra-rules'); $(l).removeAttr("required"); w = $(l).closest('div.form-group'); //-----disable this for debugging $(w).css('display', 'none'); if (r == false) { r = w; } }); $('#address_2').on('keyup', function() { atdcraUpdateAddressSpanViaTextInput('address_2') }); $(d).insertBefore(r); l = $(l).closest('.form-group'); $(s).insertAfter(l); } function atdcraPurgeAddressFieldValues() { var f = atdcraFieldMappings(); var l; var p; var q; $.each(f, function(i, n) { l = $('#'+i); if (i == 'country') { //===================== //-----best way to unselect? //-------locate empty 'Country' option... select that q = $(l).find('option'); $.each(q, function(qi, qn) { $(qn).removeAttr('selected'); }); } else { $(l).val(""); } }); l = $('#'+atdcraAutoCompleteId); $(l).val(""); atdcraUpdateAddressDisplaySpans(); } function atdcraFilterAddressValuesFromApi() { // Get the place details from the autocomplete object. var p = atdcraAutoComplete.getPlace(); var n = atdcraGetRequiredNodes(); var t = atdcraGetUnixTimestamp(); var u; var v = atdcraGetRequiredNodeValueTypes(); var w = {}; var x; var y; var z; var l; var m = $('#'+atdcraAutoCompleteId); if(typeof p.address_components === "undefined") { //-----if you input some data then hit enter without selecting one of googles suggestions, shit hits the fan //-----this helps prevent that issue $(m).attr('data-atdcra-last-valid-api-call', 0); return false; } else { //console.log('set'); //console.log(p.address_components); $(m).attr('data-atdcra-last-valid-api-call', t); } for (var i = 0; i < p.address_components.length; i++) { y = p.address_components[i].types[0]; w[y] = ""; if (typeof y !== 'undefined' && typeof n[y] !== 'undefined') { z = v[y]; u = p.address_components[i][z]; if (typeof u !== 'undefined') { w[y] = u; } } } return w; } function atdcraParseAddressValues() { var f = atdcraFieldMappings(); var w = atdcraFilterAddressValuesFromApi(); var v = {}; var t = 0; var o = {}; if (w === false) { return false; } $.each(f, function(i, n) { t = 0; $.each(n, function(ni, nn) { $.each(nn, function(nni, nnn) { v = w[nni]; }); if (typeof v === 'undefined') { v = ''; } if (t == 0) { o[i] = v; } else { o[i] = o[i] + ' ' + v; } t++; }); }); //-----check for empty strings $.each(o, function(i, n) { if (typeof n === 'undefined' || n == 'undefined' || !n.trim()) { // is empty or whitespace o[i] = atdcraDefaultString; if (i == 'countrty') { //-----default string of NA would equate to nambia... override... o[i] = 'XX'; } } }); return o; } function atdcraAutoCompleteFields() { var o = atdcraParseAddressValues(); var l; var p; var q; $.each(o, function(i, n) { l = $('#'+i); if (i == 'country') { //===================== $(l).val(n); //console.log('fix me atdcraAutoCompleteFields()'); } else { $(l).val(n); } //console.log(l); //console.log('updated ' + i + ' : ' + n); }); atdcraUpdateAddressDisplaySpans(); } function atdcraGetProtocol() { var u = window.location.href; var a = u.split(":"); var p = a[0]; return p; } function atdcraGeoLocate() { // Bias the autocomplete object to the user's geographical location, // as supplied by the browser's 'navigator.geolocation' object. // Thanks: https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform var h = atdcraGetProtocol(); if (navigator.geolocation && atdcraAutoComplete !== false && h == 'https') { navigator.geolocation.getCurrentPosition(function(position) { var geolocation = { lat: position.coords.latitude, lng: position.coords.longitude }; var circle = new google.maps.Circle({ center: geolocation, radius: position.coords.accuracy }); atdcraAutoComplete.setBounds(circle.getBounds()); }); } } $(document).ready(function(){ var i = 'address' var s = $('span.static-address-item[data-atdcra-static-address-id="' + i + '"]'); var u = $('#'+i); var v = $(u).val(); if (!v.trim()) { //-----is empty or whitespace //-----address fields are not populated, attempt load of google api atdcraLoadGoogleApi(); } else { //-----address input is not empty, form may have reloaded on account of an error //-----lets avert loading google api and just show them their pre selected values console.log('Averted Loading of google maps API.'); } });