Post by Jeens » Thu Oct 15, 2020 10:41 pm

After 4 years of perfect work the AJAX search on my opencart 2.3.0.2 instalation started acting weird over night.



The search field is in the top left part of the header. If you type in the article number of the product from the link "x103997" by hand, the quick search dropdown field will correctly suggest the product i am looking for. Everything works.

If you copy and paste "x103997" into the search field nothing happens. It used to show the quick search dropdown field though. Now it does not for some reason. It will show it though if you click somewhere outside the search field and then click inside the search field again. It will show it too when you minimize and maximize your browser window.

Just as if it needs some sort of re-trigger. It wont take anythin you ctrl+v inside it though.

I know this is a very general question but i cannot find who the developer is and i have no idea if this is a php or css error or whatever, so i am thankfull for any ideas.

Here is the openart controller file of that search module:

Code: Select all

<?php
class ControllerExtensionModuleDAjaxSearch extends Controller {
	public function index() {
		if ($this->config->get('d_ajax_search')) {
		
		$d_ajax_search = $this->config->get('d_ajax_search');
		if ($d_ajax_search['search_on_off']) {
			
			$this->document->addStyle('catalog/view/theme/cosyone/stylesheet/d_ajax_search.css');
			
			
			$data['search_width'] = $d_ajax_search['search_width'];
					
			return $this->load->view('extension/module/d_ajax_search', $data);
			
			$this->response->setOutput($this->index());
		 }
		}
	}
	
	public function ajaxsearch() {
		
		$customer_group_id = $this->config->get('config_customer_group_id');
		
		$d_ajax_search = $this->config->get('d_ajax_search');
		
		$data = array(); $data_i=0;
		if( isset($this->request->get['keyword']) ) {
			$keywords = strtolower( $this->request->get['keyword'] );
			if( strlen($keywords) >= 1 ) {
				$parts = explode( ' ', $keywords );
				$procent="%"; if (isset($d_ajax_search['search_first_symbols'])) $procent="";
				
				for($i=0;$i<5;$i++) {
				/*  Products  */
				if (isset($d_ajax_search['search_product_on']) && (int)$d_ajax_search['search_product_sort']==$i) {
				if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
				$add = '';
				foreach( $parts as $part ) {
					$add .= ' AND (LOWER(pd.name) LIKE "' . $procent . $this->db->escape($part) . '%"';
					$add .= ' OR LOWER(p.model) LIKE "' . $procent . $this->db->escape($part) . '%"';
					$add .= ' OR LOWER(pd.description) LIKE "' . $procent . $this->db->escape($part) . '%"';
					$add .= ' OR LOWER(pd.tag) LIKE "' . $procent . $this->db->escape($part) . '%")';
				}
				$add = substr( $add, 4 );
				$sql  = "SELECT pd.product_id, pd.name, p.model, p.image, pd.tag, pd.description, p.price, 
						(SELECT price FROM " . DB_PREFIX . "product_special ps 
						WHERE ps.product_id = p.product_id 
							AND ps.customer_group_id = '" . (int)$customer_group_id . "' 
							AND ((ps.date_start = '0000-00-00' OR ps.date_start < NOW()) 
							AND (ps.date_end = '0000-00-00' OR ps.date_end > NOW())) 
						ORDER BY ps.priority ASC, ps.price ASC LIMIT 1) AS special 

						FROM " . DB_PREFIX . "product_description AS pd ";

				$sql .= "LEFT JOIN " . DB_PREFIX . "product AS p ON p.product_id = pd.product_id ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "product_to_store AS p2s ON p2s.product_id = pd.product_id ";
				$sql .= "WHERE " . $add . " AND p.status = 1 ";
				$sql .= "AND pd.language_id = " . (int)$this->config->get('config_language_id');
				$sql .= " AND p2s.store_id =  " . (int)$this->config->get('config_store_id'); 
				$sql .= " ORDER BY p.date_added DESC, LOWER(pd.name) DESC";
				if ((int)$d_ajax_search['search_max_results']>0) $sql .= " LIMIT " . ((int)$d_ajax_search['search_max_results']-$data_i);
				
				$res = $this->db->query( $sql );
				if( $res ) {
					$res = ( isset($res->rows) ) ? $res->rows : $res->row;
					
                    $this->load->model('tool/image');
					$this->load->model('catalog/product');
                    
					foreach( $res as $key => $values ) {
						if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
						$product_info = $this->model_catalog_product->getProduct($values['product_id']);
						if ($values['image']) {
							$image = $this->model_tool_image->resize($values['image'],  40,  40);
						} else {
							$image = false;
						}
                        if (isset($d_ajax_search['search_price'])) {
                        if ($values['price']) {
							if (isset($d_ajax_search['search_tax'])) $price = $this->currency->format($this->tax->calculate($product_info['price'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
							else $price = $this->currency->format($values['price'], $this->session->data['currency']);
						} else {
							$price = false;
						}

						if (isset($d_ajax_search['search_special'])) {
						 if ($values['special']) {
							if (isset($d_ajax_search['search_tax'])) $special = $this->currency->format($this->tax->calculate($product_info['special'], $product_info['tax_class_id'], $this->config->get('config_tax')), $this->session->data['currency']);
							else $special = $this->currency->format($values['special'], $this->session->data['currency']);
						} else {
							$special = false;
						}
						}
						else {$special = false;}
						}
						else {$special=false; $price=false;}
						
						$name=strip_tags(html_entity_decode($values['name'], ENT_QUOTES, 'UTF-8')); $name2=$name;
						if ((int)$d_ajax_search['search_max_symbols']>0) $name=utf8_substr($name, 0, (int)$d_ajax_search['search_max_symbols']) . '';
						if (strrpos($name, " ")!==false && $name!=$name2) $name=utf8_substr($name, 0, strrpos($name, " "));
						
						$model=$values['model'];
						
						$data[$data_i] = array(
							'thumb' => $image,
                            'price' => $price,
							'special' => $special,
                            'name' => $name,
							'model' => $model,
							'href'  => $this->url->link('product/product', 'product_id=' . $values['product_id'])
						);
						}
						$data_i++;
					}
					
				}
				}
				}
				
				/*  Categories  */
				if (isset($d_ajax_search['search_category_on']) && (int)$d_ajax_search['search_category_sort']==$i) {
				if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
				$add = '';
				foreach( $parts as $part ) {
					$add .= ' AND (LOWER(cd.name) LIKE "' . $procent . $this->db->escape($part) . '%")';
				}
				$add = substr( $add, 4 );
				$sql  = "SELECT cd.category_id, cd.name, c.image FROM " . DB_PREFIX . "category_description AS cd ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "category AS c ON c.category_id = cd.category_id ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "category_to_store AS cs ON cs.category_id = cd.category_id ";
				$sql .= "WHERE " . $add . " AND c.status = 1 ";
				$sql .= "AND cd.language_id = " . (int)$this->config->get('config_language_id');
				$sql .= " AND cs.store_id =  " . (int)$this->config->get('config_store_id'); 
				$sql .= " ORDER BY c.sort_order ASC, LOWER(cd.name) ASC";
				if ((int)$d_ajax_search['search_max_results']>0) $sql .= " LIMIT " . ((int)$d_ajax_search['search_max_results']-$data_i);
				
				$res = $this->db->query( $sql );
				if( $res ) {
					$res = ( isset($res->rows) ) ? $res->rows : $res->row;
					                    
                    $this->load->model('tool/image');
                    
					foreach( $res as $key => $values ) {
						if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
						if ($values['image']) {
							$image = $this->model_tool_image->resize($values['image'],  40,  40);
						} else {
							$image = false;
						}
						
                        $special=false; $price=false;	
						
						$name=strip_tags(html_entity_decode($values['name'], ENT_QUOTES, 'UTF-8')); $name2=$name;
						if ((int)$d_ajax_search['search_max_symbols']>0) $name=utf8_substr($name, 0, (int)$d_ajax_search['search_max_symbols']) . '';
						if (strrpos($name, " ")!==false && $name!=$name2) $name=utf8_substr($name, 0, strrpos($name, " "));
						$data[$data_i] = array(
							'thumb' => $image,
                            'price' => $price,
							'special' => $special,
                            'name' => $name,
							'model' => false,
							'href'  => $this->url->link('product/category', 'path=' . $values['category_id'])
						);
						}
						$data_i++;
					}
				}
				}
				}
				/*  Manufacture  */
				if (isset($d_ajax_search['search_manufacturer_on']) && (int)$d_ajax_search['search_manufacturer_sort']==$i) {
				if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
				$add = '';
				foreach( $parts as $part ) {
					$add .= ' AND (LOWER(m.name) LIKE "' . $procent . $this->db->escape($part) . '%")';
				}
				$add = substr( $add, 4 );
				$sql  = "SELECT m.manufacturer_id, m.name, m.image FROM " . DB_PREFIX . "manufacturer AS m ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "manufacturer_to_store AS ms ON ms.manufacturer_id = m.manufacturer_id ";
				$sql .= "WHERE " . $add . " ";
				$sql .= " AND ms.store_id =  " . (int)$this->config->get('config_store_id'); 
				$sql .= " ORDER BY m.sort_order ASC, LOWER(m.name) ASC";
				if ((int)$d_ajax_search['search_max_results']>0) $sql .= " LIMIT " . ((int)$d_ajax_search['search_max_results']-$data_i);
				
				$res = $this->db->query( $sql );
				if( $res ) {
					$res = ( isset($res->rows) ) ? $res->rows : $res->row;
					                    
                    $this->load->model('tool/image');
                    
					foreach( $res as $key => $values ) {
						if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
						if ($values['image']) {
							$image = $this->model_tool_image->resize($values['image'],  40,  40);
						} else {
							$image = false;
						}
						
                        $special=false; $price=false;	
						
						$name=strip_tags(html_entity_decode($values['name'], ENT_QUOTES, 'UTF-8')); $name2=$name;
						if ((int)$d_ajax_search['search_max_symbols']>0) $name=utf8_substr($name, 0, (int)$d_ajax_search['search_max_symbols']) . '';
						if (strrpos($name, " ")!==false && $name!=$name2) $name=utf8_substr($name, 0, strrpos($name, " "));
						$data[$data_i] = array(
							'thumb' => $image,
                            'price' => $price,
							'special' => $special,
                            'name' => $name,
							'model' => false,
							'href'  => $this->url->link('product/manufacturer/info', 'manufacturer_id=' . $values['manufacturer_id'])
						);
						}
						$data_i++;
					}
				}
				}
				}

				/*  Information  */
				if (isset($d_ajax_search['search_information_on']) && (int)$d_ajax_search['search_information_sort']==$i) {
				if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
				$add = '';
				foreach( $parts as $part ) {
					$add .= ' AND (LOWER(ind.title) LIKE "' . $procent . $this->db->escape($part) . '%")';
				}
				$add = substr( $add, 4 );
				$sql  = "SELECT ind.information_id, ind.title FROM " . DB_PREFIX . "information_description AS ind ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "information AS i ON i.information_id = ind.information_id ";
				$sql .= "LEFT JOIN " . DB_PREFIX . "information_to_store AS ins ON ins.information_id = ind.information_id ";
				$sql .= "WHERE " . $add . " AND i.status = 1 ";
				$sql .= "AND ind.language_id = " . (int)$this->config->get('config_language_id');
				$sql .= " AND ins.store_id =  " . (int)$this->config->get('config_store_id'); 
				$sql .= " ORDER BY i.sort_order ASC, LOWER(ind.title) ASC";
				if ((int)$d_ajax_search['search_max_results']>0) $sql .= " LIMIT " . ((int)$d_ajax_search['search_max_results']-$data_i);
				
				$res = $this->db->query( $sql );
				if( $res ) {
					$res = ( isset($res->rows) ) ? $res->rows : $res->row;
					                    

					foreach( $res as $key => $values ) {
						if ($data_i<(int)$d_ajax_search['search_max_results'] || (int)$d_ajax_search['search_max_results']==0) {
						
                        $special=false; $price=false;	
						
						$name=strip_tags(html_entity_decode($values['title'], ENT_QUOTES, 'UTF-8')); $name2=$name;
						if ((int)$d_ajax_search['search_max_symbols']>0) $name=utf8_substr($name, 0, (int)$d_ajax_search['search_max_symbols']) . '';
						if (strrpos($name, " ")!==false && $name!=$name2) $name=utf8_substr($name, 0, strrpos($name, " "));
						$data[$data_i] = array(
							'thumb' => false,
                            'price' => $price,
							'special' => $special,
                            'name' => $name,
							'model' => false,
							'href'  => $this->url->link('information/information', 'information_id=' . $values['information_id'])
						);
						}
						$data_i++;
					}
				}
				}
				}
			
				
				}
			}
			$this->load->language('extension/module/d_ajax_search');
			if( $data_i > 0 ){
				$d_search_result = $this->language->get('text_view_all');
				$d_href_result = $this->url->link('product/search', '' . $this->request->get['keyword']);
			}else{
				$d_search_result = $this->language->get('text_no_result');
				$d_href_result = '#';
			}
			$data[$data_i] = array(
							'thumb' => false,
                            'price' => '',
							'special' => '',
                            'name' => $d_search_result,
							'model' => '',
							'href'  => $d_href_result
						);
		}
		echo json_encode( $data ); 
	}
	
	
}
Last edited by Jeens on Fri Oct 16, 2020 2:02 am, edited 2 times in total.

New member

Posts

Joined
Sat Jul 11, 2020 5:16 pm

Post by Jeens » Thu Oct 15, 2020 10:43 pm

Here is the tpl template code:

Code: Select all

<script>
function doquick_search( ev, keywords ) {
	if( ev.keyCode == 38 || ev.keyCode == 40 ) {
		return false;
	}	
	$('#ajax_search_results').remove();
	 updown = -1;
	if( keywords == '' || keywords.length < 1 ) {
		return false;
	}
	keywords = encodeURI(keywords);
	$.ajax({url: $('base').attr('href') + 'index.php?route=extension/module/d_ajax_search/ajaxsearch&keyword=' + keywords, dataType: 'json', success: function(result) {
            console.log(result);
		if( result.length > 0 ) {
			var html, i;
			html = '<table id="ajax_search_results" <?php if($search_width) { ?>style="width: <?php echo $search_width; ?>"<?php } ?> border="0" cellspacing="0" cellpadding="0"><tbody id="ajax_search_results_body">';
			for(i=0;i<result.length;i++) {
				html += '<tr>';
				if(result[i].thumb){
					html += '<td class="live_image"><a href="' + result[i].href + '"><img src="' + result[i].thumb + '" /></a></td>';
				}else{
						html += '<td></td>';
				}
				html += '<td><a href="' + result[i].href + '"><span class="name">' + result[i].name + '</span>';
				html += '</a></td>';
				
				if(result[i].special.length > 0){
					html += '<td class="live_price"><a href="' + result[i].href + '"><p class="old-price">' + result[i].price + '</p>';
					html += '<p class="special price">' + result[i].special + '</p></a></td>';
				}else{
					if(result[i].price.length > 0){
						html += '<td class="live_price"><a href="' + result[i].href + '"><p class="price">' + result[i].price + '</p></a></td>';	
					}else{
						html += '<td></td>';
					}
				}
				html += '</tr>';
			}
			html += '</tbody></table>';
			if( $('#ajax_search_results').length > 0 ) {
				$('#ajax_search_results').remove();
			}
			$('#search').append(html);
		}
	}});
	return true;
}

function upDownEvent( ev ) {
	var elem = document.getElementById('ajax_search_results_body');
	var fkey = $('#search').find('[name=search]').first();
	if( elem ) {
		var length = elem.childNodes.length - 1;
		if( updown != -1 && typeof(elem.childNodes[updown]) != 'undefined' ) {
			$(elem.childNodes[updown]).removeClass('selected');
		}
		if( ev.keyCode == 38 ) {
			updown = ( updown > 0 ) ? --updown : updown;	
		}
		else if( ev.keyCode == 40 ) {
			updown = ( updown < length ) ? ++updown : updown;
		}
		if( updown >= 0 && updown <= length ) {
			$(elem.childNodes[updown]).addClass('selected');
			var text = $(elem.childNodes[updown]).find('.name').html();
			$('#search').find('[name=search]').first().val(text);
		}
	}
	return false;
}
var updown = -1;
$(document).ready(function(){
	$('[name=search]').keyup(function(ev){
		doquick_search(ev, this.value);
	}).focus(function(ev){
		doquick_search(ev, this.value);
	}).keydown(function(ev){
		upDownEvent( ev );
	}).blur(function(){
		window.setTimeout("$('#ajax_search_results').remove();updown=0;", 15000);
	});
	$(document).bind('keydown', function(ev) {
		try {
			if( ev.keyCode == 13 && $('.selected').length > 0 ) {
				if($('.selected').find('a').first().attr('href')){
					document.location.href = $('.selected').find('a').first().attr('href');
				}
			}
		}
		catch(e) {}
	});
});
</script>

New member

Posts

Joined
Sat Jul 11, 2020 5:16 pm

Post by Jeens » Thu Oct 15, 2020 10:44 pm

here is its css:

Code: Select all

#ajax_search_results {
    margin: 0;
    text-align: left !important;
    position: absolute;
    left: 1px;
    list-style-type: none;
    z-index: 1005;
    width: 237px;
    font-size: 13px;
    background-color: #fff;
    border: 1px solid #e5e5e5;
    display: table;
}
#ajax_search_results .s_row {
    position: relative;
    display: block;
    z-index: 13005;
    width: 237px;
    padding: 8px 0;
}
#ajax_search_results .link {
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 237px;
    height: 100%;
    display: inline-block;
    position: absolute;
}
#ajax_search_results .s_row:hover {
    background: #f9f9fa;
}
#ajax_search_results a {
    display: block;
}
#ajax_search_results .selected {
    color: #af2645;
    background-color: #ebebeb;
}
#ajax_search_results .s_cell {
    display: table-cell;
    vertical-align: middle;
    padding: 0 6px;
}
#ajax_search_results .live_image {
    min-width: 55px;
    text-align: center;
}
#ajax_search_results .live_image img {
    display: inline-block;
    min-width: 40px;
}
#ajax_search_results .live_name {
    width: 100%;
    padding: 0 5px;
}
#ajax_search_results .live_price {
    text-align: right;
}
#ajax_search_results .live_price p {
    white-space: nowrap;
    min-width: 40px;
    margin: 0;
}
#ajax_search_results .special {
    margin-top: 0;
    margin-bottom: 0;
    white-space: nowrap;
    min-width: 40px;
}
#ajax_search_results .old-price {
    color: #8c8c8c;
    font-size: 11px;
    text-decoration: line-through;
    white-space: nowrap;
    min-width: 40px;
}

New member

Posts

Joined
Sat Jul 11, 2020 5:16 pm

Post by JNeuhoff » Thu Oct 15, 2020 11:20 pm

Works fine here, using FireFox 81.0 (64-bit) or Google Chrome 86.0.4240.75 (Official Build) (64-bit)

Export/Import Tool * SpamBot Buster * Unused Images Manager * Instant Option Price Calculator * Number Option * Google Tag Manager * Survey Plus * OpenTwig


User avatar
Guru Member

Posts

Joined
Wed Dec 05, 2007 3:38 am


Post by Jeens » Fri Oct 16, 2020 2:02 am

Thanks! I was able to sort out the problem by calling the css file earlier in the header.

New member

Posts

Joined
Sat Jul 11, 2020 5:16 pm

Post by ADD Creative » Fri Oct 16, 2020 2:17 am

It doesn't work for me in Chrome 86.0.4240.75 (Official Build) (64-bit) when pasting just using a mouse. It would depend on how you are pasting. With keyboard would probably trigger your events, with a mouse wouldn't.

www.add-creative.co.uk


Expert Member

Posts

Joined
Sat Jan 14, 2012 1:02 am
Location - United Kingdom
Who is online

Users browsing this forum: No registered users and 39 guests