sub common_shared_poc_recipient_select_code {
	
	my ($poc_or_recipient,$from_dialog,$id,$is_readonly) = @_ ; 
	
	return unless $poc_or_recipient ; 
	$side = 'aisa' unless $side ; 
	
	my $ucfirst_poc_or_recipient = ucfirst $poc_or_recipient ; 
	my $uc_poc_or_recipient = ($poc_or_recipient eq 'poc') ? uc $poc_or_recipient : $ucfirst_poc_or_recipient ; 
	
	my $table_ = "event_quotes_$poc_or_recipient" ;
	
	my $name_field = "$poc_or_recipient\_name" ;
	
	my $contact_nr = ($poc_or_recipient eq 'poc') ? "contact_nr" : "nr" ;
	
	my $nr_field = "$poc_or_recipient\_$contact_nr"  ;
	my $id_field = "$poc_or_recipient\_id" ;

	if ($is_readonly) {
		
		$readonly{$name_field} = "READONLY" ; 
		$readonly{$nr_field}   = "READONLY" ; 
		$add_form_fields .= &common_min_form_input($name_field,$db{$table_}{$db{$table}{$id}{$id_field}}{name}) ; 
		$add_form_fields .= &common_min_form_input($nr_field,$db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr}) ; 
		$add_form_fields .= qq~<input type='hidden' name='$id_field' value='$db{$table}{$id}{$id_field}'>~ ; 
		return ;
	}
	
	my %seen;
	my @unique_keys = grep {
		my $name = $db{$table_}{$_}{name};
		!$seen{$name}++
	} sort {
		$db{$table_}{$a}{name} cmp $db{$table_}{$b}{name}
	} keys %{$db{$table_}};

	$opts{$name_field} = qq~<option ~ . join(
		"</option><option ",
		map {
			my $name = $db{$table_}{$_}{name} ;
			qq~value="$name">$name~
		} @unique_keys
	) . qq~</option>~ ;
	
	my $len = scalar @unique_keys ; 
	
	$opts{$name_field} =~ s/value="\Q$db{$table_}{$db{$table}{$id}{$id_field}}{name}\E"/value="$db{$table_}{$db{$table}{$id}{$id_field}}{name}" SELECTED/g  if $db{$table}{$id}{$id_field} ;
	
	my @filtered = grep {
		$db{$table_}{$_}{name} eq $db{$table_}{$db{$table}{$id}{$id_field}}{name}
	} keys %{$db{$table_}};

	$opts{$nr_field} = qq~<option ~ . join(
		"</option><option ",
		map {
			# return () if $db{event_quotes_poc}{$_}{name} ne $db{event_quotes_poc}{$db{$table}{$id}{$id_field}}{name} ;
			my $disp_nr = $db{$table_}{$_}{contact_nr} ;
			if (length($disp_nr) == 11) {
				$disp_nr = substr($disp_nr,0,2) . ' ' .  substr($disp_nr,2,2) . ' ' .  substr($disp_nr,4,3) . ' ' .  substr($disp_nr,7,4) ;
				$disp_nr = '+' . $disp_nr if $disp_nr =~ /^27/ ;
			}
			qq~value='$db{$table_}{$_}{contact_nr}'>$disp_nr~
		} @filtered 
	) . qq~</option>~ ;

	$opts{$nr_field} =~ s/value='$db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr}'/value='$db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr}' SELECTED/g if $db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr} ;
	
	$dlg{$name_field} .= ($from_dialog) ? 
		qq~<div class="col-md-1"><a href="javascript:parent.dlgMdl('$useropts{'scripts'}/dialog/add_event_poc_or_recipient.pl?add&&$poc_or_recipient','Add New $uc_poc_or_recipient','height:240px','min-dialog');" class="btn btn-primary btn-xs" style="padding:0px 2px 0px 3px;margin-top:0px;" title='Add New $uc_poc_or_recipient' data-toggle='tooltip' data-placement='right'><i class="glyphicon glyphicon-plus" style="padding:0;margin-top:0px;top:0px;"></i></a></div>~ : 
		qq~<div class="col-md-1"><a href="javascript:parent.dlgMdl('$useropts{'scripts'}/dialog/add_event_poc_or_recipient.pl?add&&$poc_or_recipient','Add New $uc_poc_or_recipient','','medium-dialog');" class="btn btn-primary btn-xs" style="padding:0px 2px 0px 3px;margin-top:0px;" title='Add $uc_poc_or_recipient' data-toggle='tooltip' data-placement='right'><i class="glyphicon glyphicon-plus" style="padding:0;margin-top:0px;top:0px;"></i></a></div>~ ; 
	
	my $add_poc_contact_nr_style = (!$db{$table}{$id}{$id_field} || ($db{$table_}{$db{$table}{$id}{$id_field}}{name} && $db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr})) ? "style='display:none;'" : "" ;
	# my $add_poc_contact_nr_style = ($opts{$nr_field}) ? "style='display:none;'" : "" ;

	$dlg{$nr_field} .= ($from_dialog) ? 
		qq~<div class="col-md-1" id='add_$poc_or_recipient\_$contact_nr' $add_poc_contact_nr_style><a href="javascript:parent.dlgMdl('$useropts{'scripts'}/dialog/add_event_poc_or_recipient.pl?add_number_only&&$poc_or_recipient','Add New $uc_poc_or_recipient Number','height:240px','min-dialog');" class="btn btn-primary btn-xs" style="padding:0px 2px 0px 3px;margin-top:0px;" title='Add $uc_poc_or_recipient Number' data-toggle='tooltip' data-placement='right'><i class="glyphicon glyphicon-plus" style="padding:0;margin-top:0px;top:0px;"></i></a></div>~ : 
		qq~<div class="col-md-1" id='add_$poc_or_recipient\_$contact_nr' $add_poc_contact_nr_style><a href="javascript:parent.dlgMdl('$useropts{'scripts'}/dialog/add_event_poc_or_recipient.pl?add_number_only&&$poc_or_recipient','Add $uc_poc_or_recipient Number','','medium-dialog');" class="btn btn-primary btn-xs" style="padding:0px 2px 0px 3px;margin-top:0px;" title='Add $uc_poc_or_recipient Number' data-toggle='tooltip' data-placement='right'><i class="glyphicon glyphicon-plus" style="padding:0;margin-top:0px;top:0px;"></i></a></div>~  ; 
		
	$add_form_fields .= &common_min_form_select($name_field,$db{$table}{$id}{$name_field}) ; 
	$add_form_fields .= &common_min_form_select($nr_field,$db{$table}{$id}{$nr_field}) ; 
	$add_form_fields .= qq~<input type='hidden' name='$id_field' value='$db{$table}{$id}{$id_field}'>~ ; 
	
	$trigger_jquery .= qq~
		\$("#select$ucfirst_poc_or_recipient\_name_chosen,#select$ucfirst_poc_or_recipient\_$contact_nr\_chosen").css("width","100%") ; 
	~ ; 
	
	$trigger_jquery_raw .= qq~
	
		let orig_$poc_or_recipient\_id = "$db{$table}{$id}{$id_field}" ;
		let orig_$poc_or_recipient\_contact_nr = "$db{$table_}{$db{$table}{$id}{$id_field}}{contact_nr}" ;
		let orig_$poc_or_recipient\_name = "$db{$table_}{$db{$table}{$id}{$id_field}}{name}" ;
		
		\$("#select$ucfirst_poc_or_recipient\_$contact_nr").change( function () {
			
			if (orig_$poc_or_recipient\_contact_nr != \$(this).val() || orig_$poc_or_recipient\_name != \$("#select$ucfirst_poc_or_recipient\_name").val()) {
				\$("input[name='$id_field']").val("") ; 
			} else if (!\$("input[name='$id_field']").val()) {
				\$("input[name='$id_field']").val(orig_$poc_or_recipient\_id) ; 
			}
			
		}) ; 
		
	~ ;

} #-------------------------------------------------------------------------------

sub common_shared_poc_recipient_select_shared_jquery {
	
	$trigger_jquery_raw .= qq~

		\$("#selectPoc_name,#selectRecipient_name").change( async function () {
			
			console.log("selectPoc_name : "+this.id) ; 
			
			let poc_or_recip ; let ucfirst_poc_or_recip ; let contact_nr ; 
			if (this.id.includes("Poc")) {
				poc_or_recip = "poc" ; 
				ucfirst_poc_or_recip = "Poc" ; 
				contact_nr = "contact_nr" ; 
			} else if (this.id.includes("Recipient")) {
				poc_or_recip = "recipient" ; 
				ucfirst_poc_or_recip = "Recipient" ; 
				contact_nr = "nr" ; 
			}
			
			var vid = \$("#select"+ucfirst_poc_or_recip+"_"+contact_nr) ;
			
			let sel_val = \$(this).val()  ;
			
			vid.empty() ;
			vid.append("<option value=''></option>").trigger("chosen:updated") ;
			
			var url = "$useropts{scripts}/get/get_poc_or_recipient_contact_nr.pl?"+poc_or_recip+"_name="+sel_val ; 
			
			console.log("url : "+url) ; 
			
			let nrs_cnt = 0 ; let def_val = "" ; let disp_val = "" ; let poc_recip_id = 0 ;
			
			await \$.get(url, function(json) {
				\$.each(json, function(key, data) {
					disp_val = data.contact_nr ;
					disp_val = disp_val.toString() ;
					if (disp_val.length === 11 && disp_val.match(/^27/)) {
						disp_val = `+27 \${disp_val.slice(2, 4)} \${disp_val.slice(4, 7)} \${disp_val.slice(7)}`
					}
					vid.append("<option value='"+data.contact_nr+"'>"+disp_val+"</option>").trigger("chosen:updated") ;
					if (data.contact_nr) {
						nrs_cnt++ ;
					}
					def_val = data.contact_nr ;
					poc_recip_id = data.id ;
				}) ;
			},'json') ;
			
			if (nrs_cnt == 1) {
				vid.val(def_val).trigger("chosen:updated") ;
				\$("input[name='"+poc_or_recip+"_id']").val(poc_recip_id) ; 
			} else {
				\$("input[name='"+poc_or_recip+"_id']").val("") ; 
			}
			
			if (\$(this).val() && nrs_cnt == 0 && \$("#add_"+poc_or_recip+"_"+contact_nr).is(":hidden")) {
				\$("#add_"+poc_or_recip+"_"+contact_nr).show() ;
			} else if (!\$("#add_"+poc_or_recip+"_"+contact_nr).is(":hidden")) {
				\$("#add_"+poc_or_recip+"_"+contact_nr).hide() ;
			}
			
		}) ;

	~ ;
	
}  #-------------------------------------------------------------------------------

sub common_shared_load_poc_recipient_nr_json {
	
	my $poc_or_recipient = ($param{poc_name} || $param{poc_id}) ? "poc" : ($param{recipient_name} || $param{recipient_id}) ? "recipient" : "" ;
	
	return unless $poc_or_recipient ;
	
	my $name_field = "$poc_or_recipient\_name" ;
	my $id_field = "$poc_or_recipient\_id" ;
	my $table_ = "event_quotes_$poc_or_recipient" ;
	
	my $sql_where = ($param{$id_field}) ? "`id`='$param{$id_field}'" : ""  ;
	$sql_where .= ($param{$id_field} && $param{$name_field}) ? " OR " : "" ;
	$sql_where .= ($param{$name_field}) ? "`name`='$param{$name_field}'" : "" ;
	
	&db_open_ro('aisa') ;
		$db_ignore_open_close = 1 ;
			&db_min_ro($table_,"id,contact_nr","$sql_where",'','') ; 
			foreach (keys %{$db{$table_}}) {
				$json .= qq~{"id":"$_","contact_nr":"$db{$table_}{$_}{contact_nr}"},~ if $db{$table_}{$_}{contact_nr} ; 
			}
		$db_ignore_open_close = 0 ;
	&db_close_conn ;
	
	chop $json if $json && $json =~ /,/ ;
	
} #------------------------------------------------------------------------------------------  

sub common_shared_log_update_changes {
	
	my ($table_,$change_table,$change_script,$max_nr_of_rows) = @_ ; 
	
	return unless $i{id} ;

	$max_nr_of_rows = 10000 unless $max_nr_of_rows ;
	
	&db_min_ro($table_,'*',"id='$i{id}'") unless $db{$table_}{$i{id}}{id} ; 
	
	my %col_to_be_updated = () ; my %ignore_for_now = () ; 
	
	foreach (keys %i) {		
		$col_to_be_updated{$_} = 1 ;	
	}
	
	my $last_update = qq~~ ;  my $last_updated = qq~~ ; 

	foreach my $col (keys %{$db{$table_}{$i{id}}}) {	
		$last_update = $db{$table_}{$i{id}}{$col} if $col eq 'last_update' ;
		$last_updated = $db{$table_}{$i{id}}{$col} if $col eq 'last_updated' ;
		next if $ignore{$col} || $hidden{$col} == 1 || substr($col,0,3) eq 'new' || !$col_to_be_updated{$col} || $col eq 'last_updated' || $col eq 'last_update' ;
		my $before_ = $db{$table_}{$i{id}}{$col} ;
		
		$db{$table_}{$i{id}}{$col} =~ s/\|+$// ;
		$db{$table_}{$i{id}}{$col} =~ s/;+$// ;
		$db{$table_}{$i{id}}{$col} =~ s/,+$// ;
		
		$i{$col} =~ s/\|+$// ;
		$i{$col} =~ s/;+$// ;
		$i{$col} =~ s/,+$// ;
		
		my $a = $i{$col} ;
		my $b = $db{$table_}{$i{id}}{$col} ; 
		
		$a =~ s/\n/\\n/g ; $a =~ s/\r//g ; 
		$b =~ s/\n/\\n/g ; $b =~ s/\r//g ;

		if (($a or $b) and $a ne $b) {
			$line .= qq~$col='$db{$table_}{$i{id}}{$col}',~ ;
		} elsif ($before_ !~ s/;+$// && $before_ !~ s/,+$// && $before_ !~ s/\|+$// && !$ignore{$col} && ((!$a && !$b) || (($a || $b) && $a eq $b))) {
			$ignore{$col} = 1 ; $ignore_for_now{$col} = 1 ;
		}
	}
	
	if ($change_script || $change_table) {
		
		if  ($last_update && !$line) {
			$ignore{last_update} = 1 ; $ignore_for_now{last_update} = 1 ;
		}
		if  ($last_updated && !$line) {
			$ignore{last_updated} = 1 ; $ignore_for_now{last_updated} = 1 ;
		}
		$line .= qq~last_update='$db{$table_}{$i{id}}{last_update}'~ if $last_update && $line ;
		$line .= qq~last_updated='$db{$table_}{$i{id}}{last_updated}'~ if $last_updated && $line ;
		
		if ($line) {
			my $id_name = ($table_ =~ /event_quotes/) ? "event_quote" : ($table_ =~ /quotes/) ?  "quote" : $table_ ;
			chop $id_name if substr($id_name,-1,1) eq 's' ;
			$line = qq~$now_year$now_year$now_mm$now_dd$now_hour$now_min$now_sec|$now_year-$now_mm-$now_dd $now_hour:$now_min:$now_sec|$id_name\_id='$i{id}'|user_id='$userid'|changed_from|~ . $line ; 
			$line =~ s/,+$//; 

			&common_log_changes("events/$change_script.dat",$line,$max_nr_of_rows) if $change_script && !$testing ;
			
			if ($change_table) {
				my %iv = %i ; 
				%i = ()  ; 	
				&db_min_ro($change_table,"1,MAX(id)+1 AS 'max_id'",'','','') ; 
				$i{id} = $db{$change_table}{1}{max_id} ; 
				$i{id} = 1 unless $i{id} ;
				$i{changes} = "$line" ; 
				my $hidden_id = $hidden{id} ; 
				my $ignore_id = $ignore{id} ; 
				$hidden{id} = "" if $hidden{id} ;
				$ignore{id} = "" if $ignore{id} ;
				&db_min_insert($change_table) ; 
				$hidden{id} = $hidden_id ;
				$ignore{id} = $ignore_id ;
				$i{id} -= $max_nr_of_rows ; 
				&db_min_delete($change_table,"id <= '$i{id}'") if $i{id} > 0 ;
				%i = %iv ; 			
			}
		}
	}

	&db_min_upd($table_,"id='$i{id}'") ;
	
	foreach (keys %ignore_for_now) {
		$ignore{$_} = '' ; 
	}
	
} #------------------------------------------------------------------------------------------

sub common_shared_process_poc_recipients {
	
	my ($recip_or_poc) = @_ ; 

	my $contact_ = ($recip_or_poc eq "poc") ? "contact_nr" : "nr" ;
	my $name_field = "$recip_or_poc\_name" ;
	my $nr_field = "$recip_or_poc\_$contact_" ;
	my $id_field = "$recip_or_poc\_id" ;
	my $table_name = "event_quotes_$recip_or_poc" ;
	
	$ignore{$name_field} = 1 ;
	$ignore{$nr_field} = 1 ;
		
	if (!$i{$id_field} && $i{$name_field} && $i{$nr_field}) {
		&db_min_ro($table_name,'1,id',"name='$i{$name_field}' AND contact_nr = '$i{$nr_field}'",'','') ;
		$i{$id_field} = $db{$table_name}{1}{id} ;	
	}

	if (($i{id} && $i{$id_field} eq $db{event_quotes}{$i{id}}{$id_field}) || (!$i{$id_field} && !$db{event_quotes}{$i{id}}{$id_field})) {
		$ignore{$id_field} = 1 ; 
	}
	
	$i{$id_field} = ($i{$id_field}) ? $i{$id_field} : 0 ;
	
} #----------------------------------------------------------------------------------------

sub common_shared_build_select_primary_jquery {
	
	$trigger_jquery_raw .= qq~		
			
		const updateChosen = \$el => \$el.trigger("chosen:updated");
		
		const clearSelect = (\$el, includeBlank = true) => {
			\$el.empty();
			if (includeBlank) \$el.append(`<option value=""></option>`);
			updateChosen(\$el) ;
		};
		
		const fetchJSON = async url => {
			try {
				const res = await fetch(url);
				if (!res.ok) throw new Error(`Request failed: \${res.status}`);
				return await res.json();
			} catch (err) {
				console.error("Fetch error:", err);
				return [];
			}
		};
			
		const populateSelect = (\$field, json_list, getLabel, defaultSelected = () => "") => {
			
			let isSelected ;
			// Determine how to handle selected logic
			if (typeof defaultSelected === "function") {
				isSelected = defaultSelected ;
			} else if (Array.isArray(defaultSelected)) {
				isSelected = data => defaultSelected.includes(data.id) ? "selected" : "" ;
			} else {
				isSelected = data => data.id == defaultSelected ? "selected" : "" ;
			}
			// Auto-select the only item if none explicitly selected
			const autoSelectOnly = json_list.length === 1 && typeof defaultSelected === "string" && defaultSelected === "" ;
			
			let lastId = null ;
			json_list.forEach(data => {
				const selected = autoSelectOnly || isSelected(data) ? "selected" : "" ;
				\$field.append(`<option value="\${data.id}" \${selected}>\${getLabel(data)}</option>`) ;
				lastId = data.id;
			});

			updateChosen(\$field) ;
			// return json_list.length ;
			return { count: json_list.length, lastId } ;
			
		} ;
			
	~ ;
	
}  #----------------------------------------------------------------------------------------

sub common_shared_fix_poc_numbers {
	
	my ($number) = @_ ;
	
	# use utf8; Make sure this is called
	
	$number =~ s/\-//g ;
	$number =~ s/\p{Space}//g;
	$number = &common_shared_fix_cell($number) ;
	# $number = "" if !$number || length($number) <= 5 ; 
	$number = "" if !$number || length($number) < 10 ; 
	
	if ($number =~ /\//) {
		$number = join ("/",map{ &common_shared_fix_cell($_) } split(/\//,$number)) ;
	} elsif (length ($number) == 10 && substr($number,0,1) eq '7') {
		$number = '2' . $number ;
	}
	return $number ;	
	
} #-------------------------------------------------------------------------------

sub common_shared_fix_poc_name {
	
	my ($name) = @_ ;
	$name = lc $name ;
	$name = join(" ", map { ($_ eq 'v' || $_ eq 'van' || $_ eq 'der' || $_ eq 'vd') ? $_ : ucfirst $_ } split(/ /,$name)) ;
	$name = join("-", map { ucfirst $_ } split(/\-/,$name)) ;
	$name = join(":", map { ucfirst $_ } split(/\:/,$name)) ;
	$name =~ s/  / /g ;
	if ($name =~ /\b- \b/ ) {
		$name =~ s/- /-/g ;
	} elsif ($name =~ /\b -\b/) {
		$name =~ s/ -/-/g ;
	}
	
	$name =~ s/:(?=\S)/: /g;
	$name =~ s/^\s+|\s+$//g;
	
	return $name ; 
	
}  #-------------------------------------------------------------------------------

sub common_shared_fix_cell {

my ($cell) = @_ ;
 
	$cell =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
	$cell =~ s/amp;//g; 
	$cell =~ s/\(//g; 
	$cell =~ s/\)//g; 
	$cell =~ s/ //g;
	 
	if ($cell == 0) {
		return ;
	} elsif ((substr($cell,0,1) == 0) and (length($cell) == 10)) { # e.g. 0825564120
		$cell = 27 . substr($cell,1) ; # 27825564120
	} elsif (substr($cell,0,1) eq '+') {
		$cell = substr($cell,1) ; # 27825564120
	}

	return ($cell) ;

} #------------------------------------------------------------------------------------------

sub common_shared_fix_str {
	
	my ($txt) = @_ ;
	
	$txt = lc $txt ;
	$txt =~ s/\'//iog ;
	$txt =~ s/^\s+|\s+$//g; # remove whitespace before and after
	local $txt_new = '' ;
	foreach (split(/ /,$txt)) {
		if ($_ ne 'and' and $_ ne 'or' and $_ ne 'of' and $_ ne 'in') {
			$txt_new .= ucfirst $_ ;
		} else {
			$txt_new .= "$_" ;
		}
		$txt_new .= ' ' ;
	}
	chop $txt_new if $txt_new ;
	
	return ($txt_new) ;

} #-------------------------------------------------------------------------------

sub common_shared_event_quotes_column_not_to_copy {
	
	$i{event_system_calibration_ids} = '' ; 
	$i{set_up_groups_status_ids} = '' ; 		
	$i{set_up_groups_head_operator_ids} = '' ;
	$i{monitor_report_saved_data} = '' ;
	$i{logistics_shipment_operator_id} = '' ;
	$i{logistics_amounts_paid} = '' ;
	$i{logistics_dates_paid} = '' ;
	$i{logistics_dcb_comments} = '' ;
	$i{logistics_last_changed_by} = '' ;
	$i{logistics_costs} = '0.00' ;
	$i{logistics_system_location_id} = '' ;
	$i{logistics_location_other} = '' ;
	$i{logistics_received_by} = '' ;
	$i{logistics_delivery_datetime} = '' ;
	$i{logistics_dcb_waybill} = '' ;
	$i{logistics_complete} = '' ;
	$i{logistics_special_instructions} = '' ;
	$i{logistics_poc_ids} = '' ;
	$i{logistics_item_ids} = '' ;
	$i{logistics_venue_id} = '' ;
	$i{logistics_status_ids} = '' ;
	$i{logistics_address_ids} = '' ;
	$i{logistics_waybill_nrs} = '' ;
	$i{logistics_suppliers} = '' ;
	$i{calibrator_dates_paid} = '' ;
	$i{calibrator_amounts_paid} = '' ;
	$i{event_system_head_operator_ids} = '' ;
	$i{fixed_system_additional_comments} = '' ;
	$i{fixed_system_overall_status} = '' ;
	$i{fixed_system_sound_test} = '' ;
	$i{fixed_system_test_event} = '' ;
	$i{fixed_system_system_test} = '' ;
	$i{fixed_system_network_test} = '' ;
	$i{fixed_system_online_status} = '' ;
	$i{event_system_calibration_status} = '' ;
	$i{demo_id} = '0' ;
	
} #-------------------------------------------------------------------------------

sub common_shared_typeahead {

	my ($parent_id,$typeahead_names) = @_ ; #$typeahead_ids
	
	# $typeahead_ids = "" ;
	
	return unless $parent_id && ($typeahead_names || $typeahead_ids)   ;
	
	return if $common_shared_typeahead_call_count ;
	$common_shared_typeahead_call_count++ ;

	$typeahead_names = join(",", map { "[name^='$_']" }  grep { /^typeahead_/ } split(/\,/,$typeahead_names)) ; 
	
	unless ($typeahead_names) {
		$typeahead_names = join(",", map { "[id^='$_']" }  grep { /^inputTypeahead_/ } split(/\,/,$typeahead_ids)) ; 
	}	
	
	return unless $typeahead_names ;

	$extra_js .= qq~
	
<script src="$useropts{'js'}/typeahead_added_by_handre/typeahead.bundle.js"></script>
<script src="$useropts{'js'}/typeahead_added_by_handre/bloodhound.js"></script>
<script src="$useropts{'js'}/typeahead_added_by_handre/handlebars.min.js"></script>

<script>
	
	// create_typeahead("$parent_id","$typeahead_names") ;
	
	// \$('#inputTypeahead_name').on('typeahead:selected',onAutocompleted);
	\$('#$parent_id').on('typeahead:selected',"$typeahead_names",onAutocompleted) ;
	\$('#$parent_id').on('change',"$typeahead_names",async function () {

		if (\$(this).data('tt-selected')) {
			\$(this).data('tt-selected',false) ;
			return ;
		} 

		let field_name = this.name ; 
		field_name = field_name.replace(/^typeahead_/, '') ;
		\$("input[name='"+field_name+"']").val("") ;
		
		let url_teams = "$useropts{'scripts'}/get/get_sss_teams_from_typeahead.pl?query="+\$("input[name='typeahead_"+field_name+"']").val() + "&exact_name=1" ;

		let teams_ = await fetchJSON(url_teams) ;	
		
		if (teams_.length > 0 && teams_ != "[]") {
			\$("input[name='"+field_name+"']").val(teams_[0].id) ;
			\$("input[name='typeahead_"+field_name+"']").val(teams_[0].team_name) ;
		} else {
			\$("input[name='typeahead_"+field_name+"']").val("") ;
		}
		
		$on_team_change_extra_trigger_jquery_raw
		
	}) ;
	
	function onAutocompleted(\$e, datum) {
		console.log("onAutocompleted") ; 
		\$(this).data('tt-selected', true);
		goAutoComplete(datum.display,datum.key,this.name) ;
	}
	
	function create_typeahead (parent_id,typeahead_names,client_id="",min_length=3) {	
		
		const \$inputs = \$("#"+parent_id).find(typeahead_names);

		\$inputs.each(function () {
			const \$el = \$(this);
			if (\$el.data('ttTypeahead')) {
				\$el.typeahead('destroy');
			}
		});
		
		var safet = new Bloodhound({
			datumTokenizer: Bloodhound.tokenizers.whitespace,
			datumTokenizer: Bloodhound.tokenizers.obj.whitespace('display'),
			queryTokenizer: Bloodhound.tokenizers.whitespace,
			limit: 20,
			remote: {
				url: "$useropts{'scripts'}/get/get_sss_teams_from_typeahead.pl?client_id="+client_id+"&query=%QUERY",
				filter: function (safet) {
					return \$.map(safet, function (data) {
					return {
						key: data.id,
						value: data.team_name,
						display: data.team_name
					} ;
					}) ;
				}
			}
		}) ;

		safet.initialize() ;

		// \$('#inputTypeahead_name').typeahead({
		\$('#'+parent_id).find(typeahead_names).typeahead({
			hint: true,
			highlight: true,
			minLength: min_length
		},{
			displayKey: 'display',
			source: safet.ttAdapter(),
			templates: {
				suggestion: Handlebars.compile("{{display}}"),
				empty: ['<div class="tt-suggestion">', "Nothing found...", '</div>'].join('\\n')
			}
		}) ;
		
	}

</script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.11.1/jquery.validate.min.js"></script>
<link rel="stylesheet" href="$useropts{'css'}/typeahead_added_by_handre/safet.typeahead.css">

~;

	$trigger_jquery_raw .= qq~
	
		function goAutoComplete(input_value,input_id,field_name) {
			let company_name_fix = fixName(input_value);
			\$("input[name='"+field_name+"']").val(company_name_fix) ;
			
			field_name = field_name.replace(/^typeahead_/, '') ;
			
			if (typeof \$("input[name='"+field_name+"']").val() === 'undefined') {
				\$("input[name='"+field_name+"']").val("") ;
				return ;
			}
			
			\$("input[name='"+field_name+"']").val(input_id) ;
			
			$on_team_change_extra_trigger_jquery_raw_2
			
		}
		
		function fixName(txt,typ) {
			if (typ == 1) {
				txt = txt.replace(/&amp;/g,"&").trim() ;
			} else if (typ == 2) {
				const a = txt.split("\\n") ;
					txt = a.join(", ") ;
			}
			return (txt) ;
		}
	~ ;

	$useropts{'common'}{'css'} .= qq~.modal-backdrop.in { opacity: 0.02; }~ ;

} #-------------------------------------------------------------------------------

1 ;