/** * Adressvalidierung im Browser * Fragt wpsg_mod_addressvalidation::ajaxValidate() im Shop an, der API-Key bleibt auf dem Server * Die Konfiguration (ajaxurl, action, nonce, labelApply, labelProposal) setzt wpsg_mod_addressvalidation::wpsg_enqueue_scripts() */ /** Verzögerung, damit mehrere geänderte Felder nur eine Anfrage auslösen (ms) */ var wpsg_mod_addressvalidation_delay = 400; /** * Selektoren der Adressfelder je Adresse * Klassische Kasse, OnePage, Profil und Registrierung (#strasse …) sowie SmartCheckout (#wpsg_sc_strasse …) * Die Lieferanschrift (#shipping_…) ist in beiden gleich */ var wpsg_mod_addressvalidation_fields = [ { type: 'billing', strasse: '#strasse, #wpsg_sc_strasse', nr: '#nr, #wpsg_sc_nr', plz: '#plz, #wpsg_sc_plz', ort: '#ort, #wpsg_sc_ort', land: '#wpsg_land, #wpsg_sc_land' }, { type: 'shipping', strasse: '#shipping_strasse', nr: '#shipping_nr', plz: '#shipping_plz', ort: '#shipping_ort', land: '#shipping_land' } ]; /** * Liefert das erste vorhandene Feld zu einem Schlüssel (strasse, nr, plz, ort, land) * * @param oFields * @param strKey * @return jQuery */ function wpsg_mod_addressvalidation_getField(oFields, strKey) { return jQuery(oFields[strKey]).first(); } // function wpsg_mod_addressvalidation_getField(oFields, strKey) /** * Bindet die Prüfung an die Felder einer Adresse * Über document, damit auch Felder greifen, die erst später erzeugt werden (SmartCheckout baut sie mit Vue auf) * * @param oFields Selektoren der Felder (strasse, nr, plz, ort, land) und type ('billing' oder 'shipping') */ function wpsg_mod_addressvalidation_bind(oFields) { var oTimer = null; jQuery(document).on('change', [oFields.strasse, oFields.nr, oFields.plz, oFields.ort, oFields.land].join(', '), function() { window.clearTimeout(oTimer); oTimer = window.setTimeout(function() { wpsg_mod_addressvalidation_check(oFields); }, wpsg_mod_addressvalidation_delay); }); } // function wpsg_mod_addressvalidation_bind(oFields) /** * Liefert das Element für die Meldung einer Adresse und legt es bei Bedarf direkt hinter dem Land an * (ohne Land hinter Ort bzw. PLZ) * * @param oFields * @return jQuery */ function wpsg_mod_addressvalidation_getMessage(oFields) { var strClass = 'wpsg_mod_addressvalidation_message_' + oFields.type; var oMessage = jQuery('.' + strClass); if (oMessage.length) return oMessage; oMessage = jQuery('
').css({ 'margin': '0 0 1rem 0', 'padding': '3px 0 3px 8px' }).hide(); var arAnchor = ['land', 'ort', 'plz']; for (var i = 0; i < arAnchor.length; i ++) { var oField = wpsg_mod_addressvalidation_getField(oFields, arAnchor[i]); if (oField.length) { // SmartCheckout: Die Felder liegen in einem Grid, die Meldung belegt dort eine eigene Zeile über die volle Breite var oBlock = oField.closest('.sc_field'); if (oBlock.length) { oMessage.css({ 'grid-column': '1 / -1', 'margin': '0' }); } else { oBlock = oField.closest('.wpsg_checkoutblock'); } ((oBlock.length)?oBlock:oField).after(oMessage); break; } } return oMessage; } // function wpsg_mod_addressvalidation_getMessage(oFields) /** * Setzt den Wert eines Feldes und meldet die Änderung, damit auch Vue (SmartCheckout) den Wert übernimmt * * @param oField * @param strValue */ function wpsg_mod_addressvalidation_setValue(oField, strValue) { if (!oField.length) return; var el = oField[0]; el.value = strValue; el.dispatchEvent(new Event('input', { bubbles: true })); el.dispatchEvent(new Event('change', { bubbles: true })); } // function wpsg_mod_addressvalidation_setValue(oField, strValue) /** * Übernimmt den Vorschlag des Dienstes in die Felder einer Adresse * * @param oFields * @param oProposal strasse, nr, plz, ort */ function wpsg_mod_addressvalidation_apply(oFields, oProposal) { var oNr = wpsg_mod_addressvalidation_getField(oFields, 'nr'); var strStrasse = oProposal.strasse; // Ohne eigenes Feld für die Hausnummer gehört sie zur Straße if (oNr.length) { wpsg_mod_addressvalidation_setValue(oNr, oProposal.nr); } else if (oProposal.nr !== '') { strStrasse = strStrasse + ' ' + oProposal.nr; } wpsg_mod_addressvalidation_setValue(wpsg_mod_addressvalidation_getField(oFields, 'strasse'), strStrasse); wpsg_mod_addressvalidation_setValue(wpsg_mod_addressvalidation_getField(oFields, 'plz'), oProposal.plz); wpsg_mod_addressvalidation_setValue(wpsg_mod_addressvalidation_getField(oFields, 'ort'), oProposal.ort); } // function wpsg_mod_addressvalidation_apply(oFields, oProposal) /** * Baut die Zeile mit dem Vorschlag des Dienstes, Werte, die von der Eingabe abweichen, sind fett * * @param oFields * @param oData eingegebene Werte (strasse, nr, plz, ort) * @param oProposal vorgeschlagene Werte (strasse, nr, plz, ort) * @return jQuery */ function wpsg_mod_addressvalidation_renderProposal(oFields, oData, oProposal) { var oLine = jQuery('').css('margin-top', '4px'); var bNr = (wpsg_mod_addressvalidation_getField(oFields, 'nr').length > 0); var normalize = function(strValue) { return jQuery.trim(String(strValue || '')).replace(/\s+/g, ' ').toLowerCase(); }; var addValue = function(strValue, strInput) { oLine.append(jQuery((normalize(strValue) !== normalize(strInput))?'':'').text(strValue)); }; oLine.append(jQuery('').text(wpsg_mod_addressvalidation.labelProposal + ' ')); // Ohne eigenes Feld für die Hausnummer steht sie in der Eingabe mit in der Straße if (bNr) { addValue(oProposal.strasse, oData.strasse); if (oProposal.nr !== '') { oLine.append(' '); addValue(oProposal.nr, oData.nr); } } else { addValue(jQuery.trim(oProposal.strasse + ' ' + oProposal.nr), oData.strasse); } oLine.append(', '); addValue(oProposal.plz, oData.plz); oLine.append(' '); addValue(oProposal.ort, oData.ort); return oLine; } // function wpsg_mod_addressvalidation_renderProposal(oFields, oData, oProposal) /** * Prüft die Adresse über den Shop und zeigt die Meldung an * * @param oFields */ function wpsg_mod_addressvalidation_check(oFields) { var oStrasse = wpsg_mod_addressvalidation_getField(oFields, 'strasse'); var oPlz = wpsg_mod_addressvalidation_getField(oFields, 'plz'); var oOrt = wpsg_mod_addressvalidation_getField(oFields, 'ort'); if (!oStrasse.length || !oPlz.length || !oOrt.length) return; var oMessage = wpsg_mod_addressvalidation_getMessage(oFields); var oData = { action: wpsg_mod_addressvalidation.action, nonce: wpsg_mod_addressvalidation.nonce, type: oFields.type, strasse: jQuery.trim(oStrasse.val() || ''), nr: jQuery.trim(wpsg_mod_addressvalidation_getField(oFields, 'nr').val() || ''), plz: jQuery.trim(oPlz.val() || ''), ort: jQuery.trim(oOrt.val() || ''), land: wpsg_mod_addressvalidation_getField(oFields, 'land').val() || '' }; // Unvollständige Adressen nicht anfragen if (oData.strasse.length < 3 || oData.plz.length < 3 || oData.ort.length < 2) { oMessage.removeData('address').hide().empty(); return; } var strAddress = JSON.stringify([oData.strasse, oData.nr, oData.plz, oData.ort, oData.land]); if (oMessage.data('address') === strAddress) return; oMessage.data('address', strAddress); jQuery.post(wpsg_mod_addressvalidation.ajaxurl, oData).done(function(response) { // Inzwischen wurde die Adresse erneut geändert if (oMessage.data('address') !== strAddress) return; if (!response || !response.success || !response.data.message) { oMessage.hide().empty(); return; } oMessage.empty().append(jQuery('').text(response.data.message)); if (response.data.proposal) { var oProposal = response.data.proposal; oMessage.append(wpsg_mod_addressvalidation_renderProposal(oFields, oData, oProposal).append(' ', jQuery('').text(wpsg_mod_addressvalidation.labelApply).on('click', function() { wpsg_mod_addressvalidation_apply(oFields, oProposal); }))); } oMessage.css('border-left', '4px solid ' + ((response.data.blocked)?'#DD3D36':'#F0AD4E')).show(); }).fail(function() { // Ohne Antwort beim nächsten Ändern erneut versuchen, checkCheckout() prüft beim Absenden trotzdem oMessage.removeData('address').hide().empty(); }); } // function wpsg_mod_addressvalidation_check(oFields) /** * Prüft eine bereits ausgefüllte Adresse direkt nach dem Laden, z.B. nach einem abgewiesenen Absenden * Wartet, bis die Felder vorhanden sind (SmartCheckout baut sie erst mit Vue auf) * * @param oFields * @param nTry bisherige Versuche */ function wpsg_mod_addressvalidation_checkInitial(oFields, nTry) { if (!wpsg_mod_addressvalidation_getField(oFields, 'strasse').length) { if (nTry < 20) { window.setTimeout(function() { wpsg_mod_addressvalidation_checkInitial(oFields, nTry + 1); }, 250); } return; } wpsg_mod_addressvalidation_check(oFields); } // function wpsg_mod_addressvalidation_checkInitial(oFields, nTry) /** * Früherer Aufruf aus checkout.phtml, bleibt für angepasste Templates im Theme erhalten * Die Felder werden inzwischen automatisch gebunden, der übergebene API-Key wird nicht mehr verwendet * * @param data */ function validateAddressBind(data) { } // function validateAddressBind(data) jQuery(document).ready(function() { if (typeof(wpsg_mod_addressvalidation) == 'undefined') return; for (var i = 0; i < wpsg_mod_addressvalidation_fields.length; i ++) { wpsg_mod_addressvalidation_bind(wpsg_mod_addressvalidation_fields[i]); wpsg_mod_addressvalidation_checkInitial(wpsg_mod_addressvalidation_fields[i], 0); } });