1// Miva Merchant 2// 3// This file and the source codes contained herein are the property of 4// Miva, Inc. Use of this file is restricted to the specific terms and 5// conditions in the License Agreement associated with this file. Distribution 6// of this file or portions of this file for uses not covered by the License 7// Agreement is not allowed without a written agreement signed by an officer of 8// Miva, Inc. 9// 10// Copyright 1998-2019 Miva, Inc. All rights reserved. 11// http://www.miva.com 12// 13// $Id: runtime.js 74489 2019-04-08 15:49:50Z rguisewite $ 14// 15 16/* 17 Required elements: 18 $unique_id = some_unique_to_DOM_value; 19 20 <input type="[any text supported input]" class="any" data-mm_searchfield="Yes" data-mm_searchfield_id="$unique_id" value="&mvte:global:Search;" /> 21 <[HTMLElement] data-mm_searchfield_menu="Yes" data-mm_searchfield_id="$unique_id"></[HTMLElement]> 22*/ 23 24(function( obj, eventType, fn ) 25{ 26 if ( obj.addEventListener ) 27 { 28 obj.addEventListener( eventType, fn, false ); 29 } 30 else if ( obj.attachEvent ) 31 { 32 obj.attachEvent( 'on' + eventType, fn ); 33 } 34})( window, 'load', function() { MMSearchField_Initialize(); } ); 35 36var mm_searchfields = new Object(); 37 38function MMSearchField_Initialize() 39{ 40 var e, i, id, i_len, lookup, elements; 41 42 FireEvent( window, 'mmsearchfield_override' ); 43 44 lookup = new Object(); 45 elements = document.getElementsByTagName( '*' ); 46 47 for ( i = 0, i_len = elements.length; i < i_len; i++ ) 48 { 49 if ( id = elements[ i ].getAttribute( 'data-mm_searchfield_id' ) ) 50 { 51 if ( !lookup[ id ] ) 52 { 53 lookup[ id ] = new Object(); 54 } 55 56 if ( elements[ i ].getAttribute( 'data-mm_searchfield' ) ) lookup[ id ].element_search = elements[ i ]; 57 else if ( elements[ i ].getAttribute( 'data-mm_searchfield_menu' ) ) lookup[ id ].element_menu = elements[ i ]; 58 } 59 } 60 61 for ( id in lookup ) 62 { 63 if ( !lookup.hasOwnProperty( id ) || 64 !lookup[ id ].element_search || 65 !lookup[ id ].element_menu || 66 ( lookup[ id ].element_search.nodeType !== 1 ) || 67 ( lookup[ id ].element_menu.nodeType !== 1 ) || 68 ( lookup[ id ].element_search.nodeName.toLowerCase() !== 'input' ) ) 69 { 70 continue; 71 } 72 73 mm_searchfields[ id ] = new MMSearchField( lookup[ id ].element_search, lookup[ id ].element_menu ); 74 } 75 76 FireEvent( window, 'mmsearchfield_initialized' ); 77} 78 79function MMSearchField( element_search, element_menu ) 80{ 81 var self = this; 82 83 // Elements 84 this.element_search = element_search; 85 this.element_menu = element_menu; 86 87 // Values 88 this.current_search = ''; 89 this.search_timeout = null; 90 this.search_delay = 400; 91 this.menu_visible = false; 92 this.menu_items = new Array(); 93 this.selected_item = null; 94 this.product_count = 5; 95 this.has_focus = false; 96 this.delegator = new AJAX_ThreadPool( 1 ); 97 this.last_displayed_search_value = null; 98 99 // Events 100 this.event_search_focus = function( event ) { return self.Event_Focus( event ? event : window.event ); }; 101 this.event_search_keydown = function( event ) { return self.Event_Keydown( event ? event : window.event ); }; 102 this.event_search_keyup = function( event ) { return self.Event_Keyup( event ? event : window.event ); }; 103 this.event_search_blur = function( event ) { return self.Event_Blur( event ? event : window.event ); }; 104 this.event_search_paste = function( event ) { setTimeout( function() { self.Search( self.element_search.value ); }, 0 ); }; 105 this.event_search_click = function( event ) { eventStopPropagation( event ? event : window.event ); }; 106 this.event_document_mousedown = function( event ) { return self.Event_Document_MouseDown( event ? event : window.event ); }; 107 this.event_document_mousemove = function( event ) { return self.Event_Document_MouseMove( event ? event : window.event ); }; 108 109 AddEvent( this.element_search, 'focus', this.event_search_focus ); 110 AddEvent( this.element_search, 'keydown', this.event_search_keydown ); 111 AddEvent( this.element_search, 'keyup', this.event_search_keyup ); 112 AddEvent( this.element_search, 'blur', this.event_search_blur ); 113 AddEvent( this.element_search, 'paste', this.event_search_paste ); 114 AddEvent( this.element_search, 'click', this.event_search_click ); 115 116 // Initial Setup 117 118 this.Menu_Empty(); 119 this.Menu_Hide(); 120} 121 122MMSearchField.prototype.GetSearchURL = function() 123{ 124 return MMSearchField_Search_URL_sep; 125} 126 127MMSearchField.prototype.SetLoadCount = function( count ) 128{ 129 this.product_count = count; 130} 131 132MMSearchField.prototype.SetSearchDelay = function( delay ) 133{ 134 this.search_delay = delay; 135} 136 137MMSearchField.prototype.Menu_Empty = function() 138{ 139 this.menu_items = new Array(); 140 this.element_menu.innerHTML = ''; 141 this.last_displayed_search_value = null; 142 143 this.Menu_Item_Select( null ); 144} 145 146MMSearchField.prototype.Menu_Show = function() 147{ 148 if ( this.menu_visible ) 149 { 150 return; 151 } 152 153 this.menu_visible = true; 154 this.element_menu.style.display = 'block'; 155} 156 157MMSearchField.prototype.Menu_Hide = function() 158{ 159 if ( !this.menu_visible ) 160 { 161 return; 162 } 163 164 this.menu_visible = false;
165 this.element_menu.style.display = 'none'; 166} 167 168MMSearchField.prototype.Menu_Append_Header = function() 169{ 170 var item; 171 172 if ( item = this.onMenuAppendHeader() ) 173 { 174 this.element_menu.appendChild( item ); 175 } 176} 177 178MMSearchField.prototype.Menu_Append_Item = function( data ) 179{ 180 var self = this; 181 var item; 182 183 if ( item = this.onMenuAppendItem( data.menuitem ) ) 184 { 185 item.mm_data = data; 186 item.action = data.product_link; 187 item.onclick = function( event ) { self.Menu_Item_OnClick( event ? event : window.event, this.action ); }; 188 item.onmousemove = function( event ) { self.Event_MenuItem_MouseMove( event ? event : window.event, item ); }; 189 this.element_menu.appendChild( item ); 190 this.menu_items.push( item ); 191 } 192} 193 194MMSearchField.prototype.Menu_Append_StoreSearch = function() 195{ 196 var self = this; 197 var item; 198 199 if ( item = this.onMenuAppendStoreSearch( this.element_search.value ) ) 200 { 201 item.action = this.GetSearchURL() + encodeURIComponent( this.element_search.value ); 202 item.onclick = function( event ) { self.Menu_Item_OnClick( event ? event : window.event, this.action ); }; 203 item.onmousemove = function( event ) { self.Event_MenuItem_MouseMove( event ? event : window.event, item ); }; 204 205 this.element_menu.appendChild( item ); 206 207 this.menu_item_storesearch = item; 208 this.menu_items.push( item ); 209 } 210} 211 212MMSearchField.prototype.Menu_Replace_StoreSearch = function() 213{ 214 var self = this; 215 var item; 216 217 if ( item = this.onMenuAppendStoreSearch( this.element_search.value ) ) 218 { 219 item.action = this.GetSearchURL() + encodeURIComponent( this.element_search.value ); 220 item.onclick = function( event ) { self.Menu_Item_OnClick( event ? event : window.event, this.action ); }; 221 item.onmousemove = function( event ) { self.Event_MenuItem_MouseMove( event ? event : window.event, item ); }; 222 223 this.element_menu.appendChild( item ); 224 225 if ( this.menu_item_storesearch && ( ( index = this.menu_items.indexOf( this.menu_item_storesearch ) ) != -1 ) ) 226 { 227 this.menu_item_storesearch.parentNode.removeChild( this.menu_item_storesearch ); 228 this.menu_items.splice( index, 1 ); 229 } 230 231 if ( this.selected_item === this.menu_item_storesearch ) 232 { 233 this.Menu_Item_Select( item ); 234 } 235 236 this.menu_item_storesearch = item; 237 this.menu_items.push( item ); 238 } 239} 240 241MMSearchField.prototype.Menu_Item_Select = function( item ) 242{ 243 this.selected_item = item; 244 245 if ( item !== null ) 246 { 247 this.selected_item.className = classNameAdd( this.selected_item, 'mm_searchfield_menuitem_selected' ); 248 } 249} 250 251MMSearchField.prototype.Menu_Item_OnClick = function( e, url ) 252{ 253 window.location.href = url; 254} 255 256MMSearchField.prototype.SetFocus = function() 257{ 258 this.element_search.focus(); 259} 260 261MMSearchField.prototype.Search = function( value ) 262{ 263 var self = this; 264 265 if ( ( typeof value !== 'string' ) || ( value.length == 0 ) ) 266 { 267 this.Menu_Empty(); 268 this.Menu_Hide(); 269 270 return; 271 } 272 else if ( value.length < 3 ) 273 { 274 this.Menu_Empty(); 275 this.Menu_Show(); 276 this.Menu_Replace_StoreSearch(); 277 278 return; 279 } 280 281 AJAX_Call_Module( function( response ) { self.Search_Callback( response, value ); }, 'runtime', 282 'cmp-cssui-searchfield', 283 'Search', 284 'Search=' + encodeURIComponent( value ) + 285 '&Count=' + this.product_count, 286 this.delegator ); 287 288 this.delegator.LimitQueueToCount( 1 ); 289 this.delegator.Run(); 290} 291 292MMSearchField.prototype.Search_Callback = function( response, original_search_value ) 293{ 294 var i, i_len, last_selected; 295 296 last_selected = this.selected_item; 297 298 this.Menu_Empty(); 299 300 if ( !this.has_focus || this.element_search.value.length == 0 ) 301 { 302 this.Menu_Empty(); 303 this.Menu_Hide(); 304 305 return; 306 } 307 308 this.Menu_Show(); 309 310 if ( !response.success || ( response.data.length == 0 ) || ( this.element_search.value != original_search_value ) ) 311 { 312 return this.Menu_Append_StoreSearch(); 313 } 314 315 this.last_displayed_search_value = this.element_search.value; 316 317 this.Menu_Append_Header(); 318 319 for ( i = 0, i_len = response.data.length; i < i_len; i++ ) 320 { 321 this.Menu_Append_Item( response.data[ i ] ); 322 } 323 324 this.Menu_Append_StoreSearch(); 325 326 if ( last_selected ) 327 { 328 for ( i = 0, i_len = this.menu_items.length; i < i_len; i++ ) 329 { 330 if ( this.menu_items[ i ].action == last_selected.action ) 331 { 332 this.Menu_Item_Select( this.menu_items[ i ] ); 333 break; 334 } 335 } 336 } 337} 338 339MMSearchField.prototype.Event_Keydown = function( e ) 340{ 341 var keycode, modifier; 342 343 keycode = e.keyCode || e.which; 344 modifier = e.metaKey || e.ctrlKey || e.shiftKey || e.altKey; 345 this.current_search = this.element_search.value; 346 347 if ( keycode == 9 && !modifier ) return this.Menu_Hide(); 348 else if ( keycode == 13 && !modifier ) return this.Event_Enter( e ); 349 else if ( keycode == 27 && !modifier ) return this.Event_ESC( e ); 350 else if ( keycode == 38 && !modifier ) return this.Event_ArrowUp( e ); 351 else if ( keycode == 40 && !modifier ) return this.Event_ArrowDown( e ); 352 353 if ( keycode == 85 && keySupportsMultiSelect( e ) ) 354 { 355 this.element_search.value = ''; 356 this.current_search = ''; 357 358 cursorToEnd( this.element_search ); 359 this.Menu_Empty(); 360 this.Menu_Hide(); 361 362 return eventPreventDefault( e ); 363 } 364 365 if ( this.element_search.value.length == 0 ) 366 { 367 this.Menu_Empty(); 368 this.Menu_Hide(); 369 } 370 else 371 { 372 this.Menu_Show(); 373 this.Menu_Replace_StoreSearch(); 374 } 375 376 return true; 377} 378 379MMSearchField.prototype.Event_Keyup = function( e ) 380{ 381 var self = this; 382 var keycode = e.keyCode || e.which; 383 384 if ( keycode == 13 ) return; /* Enter Key */ 385 else if ( keycode == 27 ) return; /* Esc Key */ 386 else if ( keycode == 38 ) return; /* Up Arrow */ 387 else if ( keycode == 40 ) return; /* Down Arrow */ 388 389 if ( this.element_search.value.length == 0 ) 390 { 391 this.Menu_Empty(); 392 this.Menu_Hide(); 393 } 394 else 395 { 396 this.Menu_Show(); 397 this.Menu_Replace_StoreSearch(); 398 } 399 400 if ( this.current_search == this.element_search.value ) 401 { 402 return; 403 } 404 405 if ( this.search_timeout ) 406 { 407 clearTimeout( this.search_timeout ); 408 } 409 410 this.search_timeout = setTimeout( function() 411 { 412 self.Search( self.element_search.value ); 413 self.search_timeout = null; 414 }, this.search_delay ); 415} 416 417MMSearchField.prototype.Event_Focus = function( e ) 418{ 419 if ( this.has_focus ) 420 { 421 return; 422 } 423 424 this.has_focus = true; 425 this.element_search.className = classNameAdd( this.element_search, 'focu
425s' ); 426 427 this.onFocus( e ); 428 429 if ( this.element_search.value === this.last_displayed_search_value ) 430 { 431 this.Menu_Show(); 432 } 433 else if ( this.element_search.value.length ) 434 { 435 this.Menu_Empty(); 436 this.Menu_Show(); 437 this.Menu_Replace_StoreSearch(); 438 this.Search( this.element_search.value ); 439 } 440 441 AddEvent( document, 'mousedown', this.event_document_mousedown ); 442} 443 444MMSearchField.prototype.Event_Blur = function( e ) 445{ 446 if ( !this.has_focus ) 447 { 448 return; 449 } 450 451 this.has_focus = false; 452 this.element_search.className = classNameRemove( this.element_search, 'focus' ); 453 454 this.Menu_Hide(); 455 this.onBlur( e ); 456 457 RemoveEvent( document, 'mousedown', this.event_document_mousedown ); 458} 459 460MMSearchField.prototype.Event_Enter = function( e ) 461{ 462 if ( this.selected_item && this.selected_item.action ) this.Menu_Item_OnClick( e, this.selected_item.action ); 463 else this.Menu_Item_OnClick( e, this.GetSearchURL() + encodeURIComponent( this.element_search.value ) ); 464 465 eventStopPropagation( e ); 466 return eventPreventDefault( e ); 467} 468 469MMSearchField.prototype.Event_ESC = function( e ) 470{ 471 if ( this.menu_visible ) 472 { 473 this.Menu_Hide(); 474 } 475 else 476 { 477 this.element_search.value = ''; 478 this.current_search = ''; 479 480 this.Menu_Empty(); 481 this.Menu_Hide(); 482 } 483 484 eventStopPropagation( e ); 485 return eventPreventDefault( e ); 486} 487 488MMSearchField.prototype.Event_ArrowUp = function( e ) 489{ 490 var i, i_len, index, next_index; 491 492 if ( !this.menu_visible ) 493 { 494 this.Search( this.element_search.value ); 495 496 return eventPreventDefault( e ); 497 } 498 499 for ( i = 0, i_len = this.menu_items.length; i < i_len; i++ ) 500 { 501 this.menu_items[ i ].className = classNameRemove( this.menu_items[ i ], 'mm_searchfield_menuitem_selected' ); 502 } 503 504 if ( this.menu_items.length == 0 ) 505 { 506 this.Menu_Item_Select( null ); 507 } 508 509 if ( ( index = this.menu_items.indexOf( this.selected_item ) ) != -1 ) 510 { 511 next_index = ( index - 1 < 0 ) ? ( this.menu_items.length - 1 ) : ( index - 1 ); 512 } 513 else 514 { 515 next_index = ( this.menu_items.length - 1 ); 516 } 517 518 this.Menu_Item_Select( this.menu_items[ next_index ] ); 519 520 return eventPreventDefault( e ); 521} 522 523MMSearchField.prototype.Event_ArrowDown = function( e ) 524{ 525 var i, i_len, index, next_index; 526 527 if ( !this.menu_visible ) 528 { 529 this.Search( this.element_search.value ); 530 531 return eventPreventDefault( e ); 532 } 533 534 for ( i = 0, i_len = this.menu_items.length; i < i_len; i++ ) 535 { 536 this.menu_items[ i ].className = classNameRemove( this.menu_items[ i ], 'mm_searchfield_menuitem_selected' ); 537 } 538 539 if ( this.menu_items.length == 0 ) 540 { 541 this.Menu_Item_Select( null ); 542 } 543 544 if ( ( index = this.menu_items.indexOf( this.selected_item ) ) != -1 ) 545 { 546 next_index = ( index + 1 > this.menu_items.length - 1 ) ? 0 : ( index + 1 ); 547 } 548 else 549 { 550 next_index = 0; 551 } 552 553 this.Menu_Item_Select( this.menu_items[ next_index ] ); 554 555 return eventPreventDefault( e ); 556} 557 558MMSearchField.prototype.Event_Document_MouseDown = function( e ) 559{ 560 var target = e.target || e.srcElement; 561 562 if ( target === this.element_menu || containsChild( this.element_menu, target ) ) 563 { 564 eventStopPropagation( e ); 565 return eventPreventDefault( e ); 566 } 567} 568 569MMSearchField.prototype.Event_MenuItem_MouseMove = function( e, item ) 570{ 571 var i, i_len; 572 573 for ( i = 0, i_len = this.menu_items.length; i < i_len; i++ ) 574 { 575 this.menu_items[ i ].className = classNameRemove( this.menu_items[ i ], 'mm_searchfield_menuitem_selected' ); 576 } 577 578 this.Menu_Item_Select( item ); 579}
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.