PageSourceSearch

https://puregreenlawn.net/wp-content/plugins/tmb-site-manager-clie…exus-address-session-prefill.js?ver=1.149.0

js puregreenlawn.net collected 2026-10-08 16:52:15 UTC 5,559 bytes, 134 lines download raw bytes

1/**
2 * Nexus Address Session Prefill.
3 *
4 * The site-wide "See if we service you" address lookup (nexus-zip-enrichment.js)
5 * stores whatever address the visitor picked into sessionStorage under
6 * `nexus_selected_address` before redirecting to the matched location's quote
7 * page. This script reads that value on every subsequent page in the same tab
8 * and prefills any Fluent Forms address-shaped fields it finds — so a visitor
9 * who already told us their address on the homepage never has to retype it on
10 * a lead form later in the same visit.
11 *
12 * Never overwrites a field the visitor (or another script) already filled in,
13 * and never touches line2/suite (geocoders don't know the unit).
14 *
15 * Field matching reuses the same name-based classification heuristic as
16 * assets/js/address-autocomplete/autocomplete.js, kept as an independent
17 * (small, load-once) copy here rather than a shared dependency.
18 */
19( function () {
20	'use strict';
21
22	// QA-04: a postal code is written into the form the way the post office
23	// writes it ("12345", "12345-6789", "M5H 2N2"), because the /quote/ page
24	// shows the field back as "Quoting for …". Mirrors
25	// TMB_Client_Postal_Code::display(); anything else is left as given.
26	function displayPostal( v ) {
27		var raw = String( v == null ? '' : v ).trim();
28		var c = raw.toUpperCase().replace( /[\s-]+/g, '' );
29		var m = /^(\d{5})(\d{4})?$/.exec( c );
30		if ( m ) { return m[ 2 ] ? m[ 1 ] + '-' + m[ 2 ] : m[ 1 ]; }
31		m = /^([ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ])(\d[ABCEGHJKLMNPRSTVWXYZ]\d)$/.exec( c );
32		return m ? m[ 1 ] + ' ' + m[ 2 ] : raw;
33	}
34
35	if ( window.__tmbAddressSessionPrefillLoaded ) { return; }
36	window.__tmbAddressSessionPrefillLoaded = true;
37
38	function readStoredAddress() {
39		try {
40			var raw = window.sessionStorage.getItem( 'nexus_selected_address' );
41			if ( ! raw ) { return null; }
42			var data = JSON.parse( raw );
43			return ( data && typeof data === 'object' ) ? data : null;
44		} catch ( e ) {
45			return null;
46		}
47	}
48
49	function leaf( name ) {
50		if ( ! name ) { return ''; }
51		var m = name.match( /\[([^\]]+)\]\s*$/ );
52		var l = m ? m[ 1 ] : name;
53		return l.toLowerCase().replace( /[^a-z0-9]+/g, '_' ).replace( /^_+|_+$/g, '' );
54	}
55
56	function classify( el ) {
57		if ( ! el || ( el.tagName !== 'INPUT' && el.tagName !== 'SELECT' && el.tagName !== 'TEXTAREA' ) ) { return null; }
58		var type = ( el.getAttribute( 'type' ) || 'text' ).toLowerCase();
59		if ( [ 'hidden', 'checkbox', 'radio', 'file', 'submit', 'button', 'password' ].indexOf( type ) !== -1 ) { return null; }
60		var key = ( el.getAttribute( 'data-key_name' ) || '' ).toLowerCase();
61		var k = key || leaf( el.getAttribute( 'name' ) || '' );
62		if ( ! k ) { return null; }
63		if ( /email/.test( k ) ) { return null; }
64		if ( /address_line_2|address_2|^line_?2$|\bsuite\b|^ste$|_ste$|\bapt\b|apartment|\bunit\b/.test( k ) ) { return null; } // never prefill line2
65		if ( /^city$|_city$|\btown\b|municipal/.test( k ) ) { return 'city'; }
66		if ( /^state$|_state$|province|region/.test( k ) ) { return 'state'; }
67		if ( /zip|postal|postcode/.test( k ) ) { return 'zip'; }
68		if ( /address_line_1|address_1|street_address|^street$|_street$|^address$|_address$|\baddress\b/.test( k ) ) { return 'line1'; }
69		return null;
70	}
71
72	function matchOption( select, val ) {
73		var want = String( val || '' ).toLowerCase();
74		for ( var i = 0; i < select.options.length; i++ ) {
75			var o = select.options[ i ];
76			if ( ( o.value || '' ).toLowerCase() === want || ( o.text || '' ).trim().toLowerCase() === want ) { return o; }
77		}
78		return null;
79	}
80
81	function setVal( el, val ) {
82		if ( el == null || val == null || val === '' ) { return; }
83		// Never overwrite a value the visitor (or another script) already put there.
84		if ( ( el.value || '' ).trim() !== '' ) { return; }
85		if ( el.tagName === 'SELECT' ) {
86			var opt = matchOption( el, val );
87			if ( ! opt ) { return; }
88			el.value = opt.value;
89		} else {
90			el.value = String( val );
91		}
92		el.dispatchEvent( new Event( 'input', { bubbles: true } ) );
93		el.dispatchEvent( new Event( 'change', { bubbles: true } ) );
94	}
95
96	function prefillForm( form, addr ) {
97		var nodes = form.querySelectorAll( 'input, select, textarea' );
98		for ( var i = 0; i < nodes.length; i++ ) {
99			var role = classify( nodes[ i ] );
100			if ( role === 'line1' ) { setVal( nodes[ i ], addr.line1 || addr.label ); }
101			else if ( role === 'city' ) { setVal( nodes[ i ], addr.city ); }
102			else if ( role === 'state' ) {
103				if ( nodes[ i ].tagName === 'SELECT' ) {
104					setVal( nodes[ i ], addr.state_code && matchOption( nodes[ i ], addr.state_code ) ? addr.state_code : addr.state );
105				} else {
106					setVal( nodes[ i ], addr.state_code || addr.state );
107				}
108			}
109			else if ( role === 'zip' ) { setVal( nodes[ i ], displayPostal( addr.zip ) ); }
110		}
111	}
112
113	function run() {
114		var addr = readStoredAddress();
115		if ( ! addr || ( ! addr.zip && ! addr.line1 ) ) { return; }
116		var forms = document.querySelectorAll( 'form.frm-fluent-form, form.fluentform, form[data-form_id]' );
117		for ( var i = 0; i < forms.length; i++ ) { prefillForm( forms[ i ], addr ); }
118	}
119
120	if ( document.readyState === 'loading' ) {
121		document.addEventListener( 'DOMContentLoaded', run );
122	} else {
123		run();
124	}
125
126	// Fluent Forms can render/re-render after load (AJAX step forms, conversational forms).
127	if ( window.MutationObserver ) {
128		var timer = null;
129		new MutationObserver( function () {
130			if ( timer ) { clearTimeout( timer ); }
131			timer = setTimeout( run, 250 );
132		} ).observe( document.body, { childList: true, subtree: true } );
133	}
134} )();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.