1// LIVEOPENCART: Related Options 2 3(function ($) { $.fn.liveopencart_RelatedOptions = function(p_params){ 4 5 $this = this; 6 7 var inst = { 8 9 each : function(collection, fn){ 10 for ( var i_item in collection ) { 11 if ( !collection.hasOwnProperty(i_item) ) continue; 12 if ( fn(collection[i_item], i_item) === false ) { 13 return; 14 } 15 } 16 }, 17 18 getSetting : function(p_setting_name, p_default) { 19 if ( typeof(inst.ro_settings[p_setting_name]) != 'undefined' ) { 20 if ( inst.ro_settings[p_setting_name] !== '0' ) { 21 return inst.ro_settings[p_setting_name]; 22 } else { 23 return 0; 24 } 25 } else { 26 return p_default; 27 } 28 }, 29 30 bind : function(trigger_name, event_function) { 31 inst.parentBlock.on(trigger_name, event_function); 32 }, 33 trigger : function(trigger_name, values) { 34 inst.getBlockOfOptions().trigger(trigger_name, values); 35 }, 36 37 initRO : function(ro_init_cnt) { 38 39 if ( !inst.ro_data || inst.ro_data == {} || inst.ro_data == [] ) { 40 return; // no related options 41 } 42 43 // add specifically displayed options (quantity input/select per option value) 44 inst.getOptionElement('[data-quantity-per-option][data-product-option-id]').each(function(){ 45 var product_option_id = $(this).attr('data-product-option-id'); 46 if ( $.inArray(product_option_id, inst.ro_product_options) !=-1 ) { 47 inst.input_quantity_per_options.push( product_option_id ); 48 } 49 }); 50 51 // assign for global variable 52 inst.options_step_by_step = inst.getOptionsAsStepsFromHTML(); 53 54 if ( !inst.options_step_by_step.length && !ro_init_cnt ) { 55 // in some themes page options may be not available on this stage, so recall init on document.ready 56 $().ready( function() { 57 inst.initRO(1); 58 }); 59 return; 60 } 61 62 63 inst.each(inst.options_step_by_step, function(option_step){ // we need all options, even not visible on this action 64 inst.all_values_of_options[option_step] = inst.getAllValuesOfProductOption(option_step); 65 }); 66 67 inst.getOptionElement('select[name^="'+inst.option_prefix+'"]').change(function(){ 68 inst.controlAccessToValuesOfAllOptions(); 69 }); 70 71 inst.getOptionElement('input[type=radio][name^="'+inst.option_prefix+'"]').change(function(){ 72 inst.controlAccessToValuesOfAllOptions(); 73 }); 74 75 inst.controlAccessToValuesOfAllOptions(); 76 77 $().ready( function() { 78 79 if ( typeof(inst.ros_to_select) != 'undefined' && inst.ros_to_select && inst.ros_to_select.length) { 80 let ro_id_last = false; 81 if ( !inst.poip_ov ) { 82 83 inst.each(inst.ros_to_select, function(ro_id){ 84 ro_id_last = ro_id; 85 inst.setSelectedCombination(ro_id, true); // without limitaions 86 }); 87 if (ro_id_last) { 88 inst.setSelectedCombination(ro_id_last); /// with limitations 89 } 90 } 91 92 } else { 93 94 // if there's filter and it's equal to related options model - this related options combination should be selected 95 if (!inst.setSelectedCombinationByModel(inst.filter_name)) { // if there's not filter relevant to related options 96 // if any value is selected - all values should be reselected (to be relevant to available related options) 97 // commented out (should not be used?) 98 //if ( inst.poip_ov ) { 99 // setTimeout(function () { 100 // ro_use_first_values(); 101 // }, 1); // if any combination is selected (may be other extension), check it and change if it's not relevant to available related options 102 //} 103 } 104 inst.controlAccessToValuesOfAllOptions(); 105 106 inst.initialAutoSelect(); 107 108 } 109 110 }); 111 112 inst.trigger('init_after.ro'); 113 114 }, 115 116 getOptionsAsSteps : function() { 117 118 let steps = []; 119 inst.each(inst.options_step_by_step, function(product_option_id){ 120 // skip options hidden by pcop 121 if ( typeof(pcop_front) != 'undefined' && typeof(pcop_front.getHiddenOptions) == 'function' ) { 122 if ( $.inArray(product_option_id, pcop_front.getHiddenOptions()) == -1 ) { 123 steps.push(product_option_id); 124 } 125 } else { 126 steps.push(product_option_id); 127 } 128 129 }); 130 131 return steps; 132 }, 133 134 getQuantityInput : function() { 135 return inst.getElement('#input-quantity, input[name="quantity"]'); 136 }, 137 138 setOptionValue : function(product_option_id, product_option_value_id) { 139 140 var $touched_elems = ''; 141 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]').length > 0) { 142 143 $touched_elems = inst.getOptionElement('[name="'+inst.option_prefix+'['+product_option_id+']"]').val(product_option_value_id); 144 145 } else if ( inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]').length > 0) { 146 var radio_elems = inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]'); 147 radio_elems.prop('checked', false); 148 149 if ( product_option_value_id ) { 150 var radio_elem = inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"][value='+product_option_value_id+']'); 151 152 // mod, baracsi, 2023.01.17, a kiválasztás váltson ki click eseményt 153 //radio_elem.prop('checked', true); 154 radio_elem.prop('checked', true).trigger('click'); 155 } 156 157 $touched_elems = radio_elems; 158 } 159 160 inst.trigger('setOptionValue_after.ro', [product_option_id, product_option_value_id, $touched_elems]); 161
162 // Product Option Image PRO compatibility 163 if ( typeof(poipExternalOptionChange)=='function' ) { 164 poipExternalOptionChange(); 165 } 166 if ( typeof(poip_product)!='undefined' && typeof(poip_product.externalOptionChange) == 'function' ) { 167 poip_product.externalOptionChange(); 168 } 169 170 }, 171 172 getBlockOfOptions : function() { 173 return inst.parentBlock; 174 }, 175 176 getOptionElement : function(selector) { 177 return inst.getBlockOfOptions().find(selector); 178 }, 179 180 getProductOptionIdFromName : function(name) { 181 return name.substr(inst.option_prefix_length+1, name.indexOf(']')-(inst.option_prefix_length+1) ); 182 }, 183 184 getElement : function(selector) { 185 return inst.parentBlock.find(selector); 186 }, 187 188 getValuesOfSelectOption : function(param_product_option_id) { 189 if ( $.isEmptyObject(inst.all_select_ov) ) { 190 inst.getOptionElement('select[name^="'+inst.option_prefix+'["]').each( function (si, sel_elem) { 191 var product_option_id = inst.getProductOptionIdFromName(sel_elem.name); 192 193 inst.all_select_ov[product_option_id] = []; 194 195 $.each(sel_elem.options, function (oi, op_elem) { 196 inst.all_select_ov[product_option_id].push(op_elem.value); 197 }); 198 199 } ); 200 } 201 return inst.all_select_ov[param_product_option_id]; 202 }, 203 204 getSelectedROCombsByOptions : function(options_values){ 205 return inst.getROIdsByOptions(options_values, true); 206 }, 207 208 getROIdsByOptions : function(options_values, strict) { 209 let ro_ids = []; 210 let ro_combs = inst.getROCombsByOptions(options_values, strict); 211 inst.each(ro_combs, function(ro_comb){ 212 ro_ids.push(ro_comb.relatedoptions_id); 213 }); 214 return ro_ids; 215 //var ro_ids = []; 216 //inst.each(inst.ro_data, function(ro_dt){ 217 // 218 // var all_ok; 219 // inst.each(ro_dt.ro, function(ro_comb){ 220 // let ro_id = ro_comb.relatedoptions_id; 221 // 222 // all_ok = true; 223 // inst.each(ro_comb.options, function(ro_option, product_option_id){ 224 // 225 // if (!(product_option_id in options_values && options_values[product_option_id]==ro_option)) { 226 // all_ok = false; 227 // } 228 // }); 229 // if (all_ok) ro_ids.push(ro_id); 230 // }); 231 //}); 232 //return ro_ids; 233 }, 234 235 getCurrentROCombs : function(strict){ 236 let selected_option_values = inst.getOptionValues([]); 237 return inst.getROCombsByOptions(selected_option_values, strict); 238 }, 239 240 getROCombsByOptions : function(options_values, strict) { 241 let ro_combs = []; 242 inst.each(inst.ro_data, function(ro_dt){ 243 244 let all_ok; 245 inst.each(ro_dt.ro, function(ro_comb){ 246 247 all_ok = true; 248 inst.each(ro_comb.options, function(pov_id, product_option_id){ 249 250 all_ok = all_ok && ((product_option_id in options_values && options_values[product_option_id]==pov_id) || (!strict && !options_values[product_option_id] ) ); 251 }); 252 if (all_ok) ro_combs.push(ro_comb); 253 }); 254 }); 255 return ro_combs; 256 }, 257 258 arrayIntersection : function(arr1, arr2) { 259 var new_arr = []; 260 for (let i in arr1) { 261 if ( arr1.hasOwnProperty(i) ) { 262 if ($.inArray(arr1[i], arr2) != -1) { 263 new_arr.push(arr1[i]); 264 } 265 } 266 } 267 return new_arr; 268 }, 269 270 arrayCopy : function(arr) { 271 var new_arr = []; 272 for (let i in arr) { 273 if ( arr.hasOwnProperty(i) ) { 274 if ( $.isArray(arr[i]) ) { 275 new_arr[i] = inst.arrayCopy(arr[i]); 276 } else { 277 new_arr[i] = arr[i]; 278 } 279 } 280 } 281 return new_arr; 282 }, 283 284 getAllValuesOfProductOption : function(product_option_id) { 285 var values = []; 286 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]').length) { 287 var select_options = inst.getValuesOfSelectOption(product_option_id); 288 inst.each(select_options, function(select_option){ 289 //for (var i=0;i<select_options.length;i++) { 290 if (select_option) { 291 values.push(select_option); 292 } 293 }); 294 } else if ( inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+product_option_id+']"]').length) { 295 inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+product_option_id+']"]').each(function(){ 296 values.push($(this).val()); 297 }); 298 } 299 // add specifically displayed options (quantity input/select per option value) 300 if ( $.inArray(product_option_id, inst.input_quantity_per_options) != -1 ) { 301 $('[name^="quantity_per_option['+product_option_id+']["]').each(function(){ 302 var product_option_value_id = $(this).attr('data-value'); 303 if ( product_option_value_id ) { 304 values.push(product_option_value_id); 305 } 306 }); 307 } 308 return values; 309 }, 310 311 getOptionsWithDirectRelations : function(prodict_option_id) { 312 313 if ( inst.linked_options_cache[prodict_option_id] ) { 314 return inst.linked_options_cache[prodict_option_id]; 315 } else { 316 317 var linked_options = []; 318 inst.each(inst.ro_data, function(ro_dt){ 319 //for (var i in inst.ro_data) { 320 if ( $.inArray(prodict_option_id, ro_dt.options_ids)!=-1 ) { 321 inst.each(ro_dt.options_ids, function(current_option_id){ 322 //for ( var j in inst.ro_data[i].options_ids ) { 323 // current_option_id = inst.ro_data[i].options_ids[j]; 324 if ( current_option_id != prodict_option_id && $.inArray(current_option_id, linked_options) ) { 325 linked_options.push(current_option_id); 326 } 327 }); 328 } 329 }); 330 inst.linked_options_cache[prodict_option_id] = linked_options; 331 return linked_options; 332 } 333 }, 334 335 // get available options values 336 // option_id - (product_option_id) 337 // param_options_values - current options values (selected) - only for related options 338 // param_skip_ropv_ids - don't make values addition for this related options combinations 339 getAccessibleOptionValues : function(option_id, param_options_values, param_skip_options) { 340 341 // make copies od arrays 342 let options_values = inst.arrayCopy(param_options_values); 343 let skip_options = inst.arrayCopy(param_skip_options); 344 skip_options.push(option_id); 345 346 let linked_options = inst.getOptionsWithDirectRelations(option_id); 347 348 inst.each(linked_options, function(current_option_id){ 349 //for ( var i in linked_options ) { 350 // current_option_id = linked_options[i]; 351 //for (var current_option_id in options_values) { 352 if ( options_values[current_option_id] && !options_values[current_option_id].length && current_option_id != option_id) { 353 if ( $.inArray(current_option_id, skip_options) == -1 ) { 354 options_values[current_option_id] = inst.getAccessibleOptionValues(current_option_id, options_values, skip_options); 355 } 356 } 357 }); 358 359 let common_accessible_values = false;
360 361 let possible_current_option_values = inst.all_values_of_options[option_id]; 362 363 inst.each(inst.ro_data, function(ro_dt){ 364 365 if ($.inArray(option_id, ro_dt.options_ids)==-1) { 366 return; 367 } 368 369 let accessible_values = []; 370 let ro_combs = ro_dt.ro; 371 372 let options_for_check = []; // optimization 373 inst.each(options_values, function(values, current_option_id){ 374 //for(var current_option_id in options_values) { 375 if (current_option_id != option_id && values.length && $.inArray(current_option_id, skip_options) == -1 && $.inArray(current_option_id, ro_dt.options_ids)!=-1) { 376 options_for_check.push(current_option_id); 377 } 378 }); 379 380 if (!options_for_check.length) { 381 if (ro_dt.options_ids.length == 1) { // combination contains only one option (this option) 382 inst.each(ro_combs, function(ro_comb){ 383 //for(var ro_id in ro_combs) { 384 // if( !ro_combs.hasOwnProperty(ro_id) ) continue; 385 if ( ro_comb.options[option_id] && $.inArray(ro_comb.options[option_id], accessible_values) == -1 ) { 386 accessible_values.push(ro_comb.options[option_id]); 387 } 388 }); 389 } else { 390 accessible_values = inst.arrayCopy(possible_current_option_values); 391 } 392 } else { 393 inst.each(ro_combs, function(ro_comb){ 394 395 all_ok = true; 396 inst.each(options_for_check, function(current_option_id){ 397 if ( $.inArray(ro_comb.options[current_option_id], options_values[current_option_id]) == -1 ) { 398 all_ok = false; 399 } 400 if (!all_ok) { 401 return false; 402 } 403 }); 404 405 if (all_ok && ($.inArray(ro_comb.options[option_id], accessible_values) == -1 )) { 406 accessible_values.push(ro_comb.options[option_id]); 407 if (possible_current_option_values.length == accessible_values.length) { // optimization 408 return false; 409 } 410 } 411 }); 412 } 413 414 if (common_accessible_values === false) { 415 common_accessible_values = accessible_values; 416 } else { 417 common_accessible_values = inst.arrayIntersection(common_accessible_values, accessible_values); 418 } 419 }); 420 421 return common_accessible_values; 422 }, 423 424 // only for options with values 425 // returns array of accessible values 426 controlAccessToValuesOfOption : function(param_options_values, option_id) { 427 428 var options_values = []; 429 inst.each(param_options_values, function(product_option_value_id, product_option_id){ 430 //for (var product_option_id in param_options_values) { 431 options_values[product_option_id] = []; 432 if (param_options_values[product_option_id]) { 433 options_values[product_option_id].push(product_option_value_id); 434 } 435 }); 436 var skip_ropv_ids = []; 437 var accessible_values = inst.getAccessibleOptionValues(option_id, options_values, skip_ropv_ids); 438 439 inst.setAccessibleOptionValues(option_id, accessible_values); 440 441 return accessible_values; 442 }, 443 444 toggleOptionElement : function(option_id, toggle_flag) { 445 inst.getOptionElement('#input-option'+option_id).parent().toggle(toggle_flag); 446 if ( inst.getOptionElement('#input-option'+option_id).parent().is('div.select') && inst.getOptionElement('#input-option'+option_id).parent().parent().is('div.form-group') ) { // additional compatibility (fastor theme or custom modification) 447 inst.getOptionElement('#input-option'+option_id).parent().parent().toggle(toggle_flag); 448 } 449 inst.getOptionElement('label[for="input-option'+option_id+'"]').toggle(toggle_flag); 450 }, 451 452 optionIsAccessible : function(option_id) { 453 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]').length) { 454 return inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"] option[value][value!=""]:not(:disabled)').length ? true : false; 455 } else if ( inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]').length) { 456 return inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]:not(:disabled)').length ? true : false; 457 } else if ( inst.getOptionElement('input[name^="quantity_per_option['+option_id+']["]').length) { 458 return inst.getOptionElement('input[name^="quantity_per_option['+option_id+']["]:not(:disabled)').length ? true : false;
459 } 460 }, 461 462 hideInaccessibleOptionIfNeeded : function(option_id) { 463 if (inst.ro_settings && inst.ro_settings.hide_option) { 464 inst.toggleOptionElement(option_id, inst.optionIsAccessible(option_id)); 465 } 466 }, 467 468 makeInaccessibleOptionsNotRequired : function(option_id) { 469 if (inst.ro_settings && inst.ro_settings.unavailable_not_required) { 470 var current_ids = []; 471 if ($('#ro_not_required').length) { 472 current_ids = $('#ro_not_required').val().split(','); 473 } else { 474 $('#product').append('<input type="hidden" name="ro_not_required" id="ro_not_required" value="">'); 475 } 476 var new_ids = []; 477 inst.each(current_ids, function(current_id){ 478 //for (var i in current_ids) { 479 if (current_id != option_id) { 480 new_ids.push(current_id); 481 } 482 }); 483 if (!inst.optionIsAccessible(option_id)) { 484 new_ids.push(option_id); 485 } 486 $('#ro_not_required').val( new_ids.toString()); 487 } 488 }, 489 490 setAccessibleOptionValues : function(option_id, accessible_values) { 491 492 var current_value = ( inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]:checked').val() || inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]').val()); 493 494 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]').length) { 495 496 if (current_value && $.inArray(current_value, accessible_values)==-1) { 497 inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]').val(""); 498 } 499 500 if (inst.hide_inaccessible) { 501 502 let select_options = inst.getValuesOfSelectOption(option_id); 503 //select_options = inst.all_select_ov[inst.option_prefix+"["+option_id+"]"]; 504 inst.each(select_options, function(select_option){ 505 //for (let i=0;i<select_options.length;i++) { 506 if (select_option) { 507 option_value_disabled = ($.inArray(select_option,accessible_values) == -1); 508 // hiding options for IE 509 inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]').toggleOption(select_option, !option_value_disabled); 510 inst.trigger( 'setAccessibleOptionValues_selectToggle_after.ro', [option_id, select_option, option_value_disabled] ); 511 } 512 }); 513 514 } else { 515 516 let select_options = inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_id+']"]')[0].options; 517 inst.each(select_options, function(select_option){ 518 //for (let i=0;i<select_options.length;i++) { 519 if (select_option.value) { 520 option_value_disabled = ($.inArray(select_option.value,accessible_values) == -1); 521 select_option.disabled = option_value_disabled; 522 if (option_value_disabled) { 523 $(select_option).addClass('ro_option_disabled'); 524 } else { 525 $(select_option).removeClass('ro_option_disabled'); 526 } 527 inst.trigger( 'setAccessibleOptionValues_selectEnableDisable_after.ro', [option_id, select_option.value, option_value_disabled] ); 528 } 529 }); 530 } 531 532 inst.trigger( 'setAccessibleOptionValues_select_after.ro', [option_id, accessible_values] ); 533 534 } else if ( inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]').length) { 535 536 if (current_value && $.inArray(current_value, accessible_values)==-1) { 537 538 var elem_to_uncheck = inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]:checked'); 539 540 if ( elem_to_uncheck.length ) { 541 elem_to_uncheck.prop('checked', false); 542 } 543 544 inst.trigger( 'setAccessibleOptionValues_radioUncheck_after.ro', [elem_to_uncheck] ); 545 } 546 547 $radio_options = inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_id+']"]'); 548 $radio_options.each(function(){ 549 //for (var i=0;i<radio_options.length;i++) { 550 let $radio_option = $(this); 551 552 option_value_disabled = ($.inArray($radio_option.val(), accessible_values) == -1); 553 554 $radio_option.prop('disabled', option_value_disabled); // hidden should be disabled too 555 556 if (inst.hide_inaccessible) { 557 558 if ( typeof(inst.custom_radioToggle) != 'undefined' && inst.custom_radioToggle( $radio_option, option_value_disabled ) ) { 559 // do nothing 560 } else { 561 $radio_option.parent().parent().toggle(!option_value_disabled); 562 $radio_option.toggle(!option_value_disabled); 563 } 564 565 // style change for padding change 566 if (option_value_disabled) { 567 if ($radio_option.parent().parent().hasClass('radio')) { 568 $radio_option.parent().parent().removeClass('radio'); 569 $radio_option.parent().parent().addClass('_radio_ro'); 570 } 571 } else { 572 if ($radio_option.parent().parent().hasClass('_radio_ro')) { 573 $radio_option.parent().parent().removeClass('_radio_ro'); 574 $radio_option.parent().parent().addClass('radio'); 575 } 576 } 577 578 inst.trigger( 'setAccessibleOptionValues_radioToggle_after.ro', [ option_id, $radio_option, option_value_disabled ] ); 579 580 } else { 581 582 if ( typeof(inst.custom_radioEnableDisable) != 'undefined' && inst.custom_radioEnableDisable( $radio_option, option_value_disabled ) ) { 583 // do nothing 584 } else { 585 586 if (option_value_disabled) { 587 inst.fadeToOptionRadio($radio_option, 0.1); 588 //$radio_option.parent().fadeTo("fast", 0.1); 589 } else { 590 inst.fadeToOptionRadio($radio_option, 1); 591 //$radio_option.parent().fadeTo("fast", 1); 592 } 593 594 } 595 596 inst.trigger( 'setAccessibleOptionValues_radioEnableDisable_after.ro', [ option_id, $radio_option, option_value_disabled ] ); 597 598 } 599 //} 600 }); 601 602 } else if ( $.inArray(option_id, inst.input_quantity_per_options) != -1 ) { // for specifically displayed options (quantity input/select per option value) 603 604 inst.getOptionElement('[name^="quantity_per_option['+option_id+']["]').each(function(){ 605 var $qpo_input = $(this); 606 var product_option_value_id = qpo_getPOVIdByName( $qpo_input.attr('name') ); 607 //var product_option_value_id = $qpo_input.attr('data-value'); 608 if ( product_option_value_id ) { 609 option_value_disabled = ( $.inArray(product_option_value_id, accessible_values) == -1 ); 610 if ( option_value_disabled ) { 611 $qpo_input.val(''); 612 } else if ( $qpo_input.prop('disabled') ) { // re-enable the input - place default values 613 $qpo_input.val( $qpo_input.attr('data-default-value' || '0') ); 614 } 615 $qpo_input.prop('disabled', option_value_disabled); 616 var $option_value_container = $qpo_input.closest('tr'); 617 if ( !$option_value_container.length ) { 618 $option_value_container = $qpo_input.closest('div'); 619 } 620 if (inst.hide_inaccessible) { 621 $option_value_container.toggle(!option_value_disabled); 622 } else { 623 if ( option_value_disabled ) { 624 inst.fadeToForElement($option_value_container, 0.1); 625 //$option_value_container.fadeTo("fast", 0.1); 626 } else { 627 inst.fadeToForElement($option_value_container, 1); 628 //$option_value_container.fadeTo("fast", 1); 629 } 630 } 631 } 632 }); 633 634 } 635 636 inst.hideInaccessibleOptionIfNeeded(option_id); 637 inst.makeInaccessibleOptionsNotRequired(option_id); 638 }, 639 640 getOptionValues : function() { 641 642 var options_values = {}; 643 644 inst.getOptionElement('select[name^="'+inst.option_prefix+'["], input[type=radio][name^="'+inst.option_prefix+'["]').each(function(){ 645 option_id = inst.getProductOptionIdFromName( $(this).attr('name') ); 646 647 if ($.inArray(option_id,inst.ro_product_options) != -1) { 648 649 if ( typeof(options_values[option_id]) == 'undefined' ) { 650 options_values[option_id] = 0; 651 } 652 653 if ( $(this).find('option[value]').length ) { // select 654 options_values[option_id] = $(this).val(); 655 } else { // radio 656 if ( $(this).is(':checked') ) { 657 options_values[option_id] = $(this).val(); 658 } 659 } 660 661 } 662 }); 663 664 // add specifically displayed options (quantity input/select per option value) 665 inst.each(inst.input_quantity_per_options, function(product_option_id){ 666 //for (var i_input_quantity_per_options in inst.input_quantity_per_options) { 667 // if ( !inst.input_quantity_per_options.hasOwnProperty(i_input_quantity_per_options) ) continue; 668 // var product_option_id = inst.input_quantity_per_options[i_input_quantity_per_options]; 669 670 options_values[product_option_id] = 0; 671 }); 672 673 return options_values; 674 }, 675 676 getSelectedRelatedOptions : function(){ 677 let related_options = inst.getOptionValues(); 678 let selected_related_options = {}; 679 inst.each(related_options, function(pov_id, po_id){ 680 if (pov_id) { 681 selected_related_options[po_id] = pov_id; 682 } 683 }); 684 return selected_related_options; 685 }, 686 687 setSelectedCombination : function(ro_id, skip_access) { 688 689 let options_to_set = {}; 690 //var selected_povs = []; 691 if (inst.ro_data) { 692 inst.each(inst.ro_data, function(ro_dt){ 693 //for (var i in inst.ro_data) { 694 if (ro_dt.ro[ro_id]) { 695 696 inst.each(ro_dt.ro[ro_id].options, function(pov_id, po_id){ 697 options_to_set[po_id] = pov_id; 698 //for (var product_option_id in ro_dt.ro[ro_id].options) { 699 //inst.setOptionValue(po_id, pov_id); 700 //selected_povs.push(ro_dt.ro[ro_id].options[po_id]); 701 }); 702 703 return false;
704 } 705 }); 706 } 707 708 if ( !$.isEmptyObject(options_to_set) ) { // we should set option values in the order of options on the page (to make it working with the step-by-step mode) 709 inst.each(inst.getOptionsAsSteps(), function(po_id){ 710 //inst.each(inst.options_step_by_step, function(po_id){ 711 if ( options_to_set[po_id] ) { 712 inst.setOptionValue(po_id, options_to_set[po_id]); 713 if ( inst.step_by_step && inst.hide_inaccessible ) { // control access, otherwise next option may do not have values to make selected at all 714 inst.controlAccessToValuesOfAllOptions(); 715 } 716 } 717 }); 718 } 719 720 // access should be checked also for step by step because there may be selects with removed options 721 if ( typeof(skip_access) == 'undefined' || !skip_access || (inst.step_by_step && inst.hide_inaccessible) ) { 722 723 inst.controlAccessToValuesOfAllOptions(); 724 725 inst.trigger('setSelectedCombination_withAccessControl_after.ro'); 726 727 } 728 729 inst.executeFunctionsFromOtherExtensionsOnOptionChange(); 730 }, 731 732 executeFunctionsFromOtherExtensionsOnOptionChange : function() { 733 734 // Parent-child options - compatibility 735 if ( typeof(pcop_front) != 'undefined' && typeof(pcop_front.checkVisibility) == 'function' ) { 736 pcop_front.checkVisibility(); 737 } 738 739 // very old Product Option Image PRO compatibility 740 if ( typeof(poipExternalOptionChange)=='function' ) { 741 poipExternalOptionChange(); 742 } 743 // old Product Option Image PRO compatibility 744 if ( typeof(poip_product)!='undefined' && typeof(poip_product.externalOptionChange) == 'function' ) { 745 poip_product.externalOptionChange(); 746 } 747 748 if ( typeof(poip_common)!='undefined' && poip_common && typeof(poip_common.externalOptionChangeEvent) == 'function' ) { 749 poip_common.externalOptionChangeEvent( inst.getBlockOfOptions() ); 750 } 751 752 // Live Price OLD 753 if ( typeof(liveprice_recalc) == 'function' ) { 754 liveprice_recalc(100); 755 } 756 757 // Live Price NEW 758 if ( window.liveopencart && window.liveopencart.live_price_instances ) { 759 var lp_instances = window.liveopencart.live_price_instances; 760 if ( Array.isArray(lp_instances) && lp_instances.length ) { 761 inst.each(lp_instances, function(lp_instance){ 762 //for ( var i_lp_instances in lp_instances ) { 763 // if ( !lp_instances.hasOwnProperty(i_lp_instances) ) continue; 764 // var lp_instance = lp_instances[i_lp_instances]; 765 lp_instance.updatePrice(100); 766 }); 767 } 768 } 769 770 $(document).trigger('external_option_change'); // io supported 771 }, 772 773 setSelectedCombinationByModel : function(model) { 774 if (model && inst.ro_data) { 775 inst.each(inst.ro_data, function(ro_dt){ 776 inst.each(ro_dt.ro, function(ro_comb, ro_id){ 777 //for (var ro_id in ro_dt.ro) { 778 if (ro_comb.model && ro_comb.model.toLowerCase() == model.toLowerCase()) { 779 ro_set_selected_combination(ro_id); 780 return true; 781 } 782 }); 783 }); 784 } 785 return false; 786 }, 787 788 // for step-by-step way 789 getOptionsAsStepsFromHTML : function() { 790 var options_steps = []; 791 792 inst.getOptionElement('input[name^="'+inst.option_prefix+'["], select[name^="'+inst.option_prefix+'["]').each(function(){ 793 794 let product_option_id = inst.getProductOptionIdFromName( inst.getOptionElement(this).attr('name')); 795 796 if ($.inArray(product_option_id, inst.ro_product_options) != -1) { 797 if ($.inArray(product_option_id, options_steps) == -1) { 798 options_steps.push(product_option_id); 799 } 800 } 801 802 }); 803 804 // add specifically displayed options (quantity input/select per option value) 805 inst.each(inst.input_quantity_per_options, function(product_option_id){ 806 options_steps.push(product_option_id); 807 }); 808 809 return options_steps; 810 }, 811 812 controlAccessToValuesOfAllOptions : function() { 813 814 if (!inst.ro_data || !Object.keys(inst.ro_data).length) return; 815 816 if (inst.step_by_step) { 817 818 var prev_options_values = {}; 819 var prev_options = []; 820 var option_accessible_values = []; 821 var one_prev_value_is_not_set = false; 822 823 824 inst.each(inst.getOptionsAsSteps(), function(option_step, i){ 825 826 if (i>0) { 827 // if previous option value is selected or if previous option has no available values 828 if (!one_prev_value_is_not_set) { 829 // limitaion on previous 830 option_accessible_values = inst.controlAccessToValuesOfOption(prev_options_values, option_step); 831 832 } else { 833 // disable all 834 inst.setAccessibleOptionValues(option_step, []); 835 option_accessible_values = []; 836 } 837 } 838 839 prev_options.push( ( inst.getOptionElement('input[type=radio][name="'+inst.option_prefix+'['+option_step+']"]:checked').val() || inst.getOptionElement('select[name="'+inst.option_prefix+'['+option_step+']"]').val()) ); 840 prev_options_values[option_step] = prev_options[prev_options.length-1]; 841 842 if ((option_accessible_values.length || i==0) && !prev_options[i] ) { // option has available values, but none of them is selected 843 one_prev_value_is_not_set = true; 844 } 845 846 }); 847 848 } else { 849 850 //var options_keys = []; 851 var options_values = inst.getOptionValues(); 852 var options_keys = Object.keys(options_values); 853 854 inst.each(options_keys, function(option_key){ 855 //for (let i=0;i<options_keys.length;i++) { 856 inst.controlAccessToValuesOfOption(options_values, option_key); 857 }); 858 859 } 860 861 inst.controlOutOfStockOptionViewAll(); 862 863 inst.checkAutoSelect(); 864 865 inst.trigger('controlAccessToValuesOfAllOptions_after.ro'); 866 867 }, 868 869 controlOutOfStockOptionViewAll : function() { 870 if ( inst.ro_settings.allow_zero_select && inst.ro_settings.fade_out_of_stock_option_values ) { 871 872 let po_ids = inst.getOptionsAsSteps(); 873 let selected_option_values = inst.getOptionValues([]); 874 875 if ( inst.ro_settings.fade_out_of_stock_option_values == 1 ) { 876 877 inst.each(po_ids, function(po_id){ 878 879 inst.controlOutOfStockOptionViewOneOption(po_id, selected_option_values); 880 881 }); 882 } else if ( inst.ro_settings.fade_out_of_stock_option_values == 2 ) { 883 if ( po_ids.length ) { 884 inst.controlOutOfStockOptionViewOneOption(po_ids[po_ids.length-1], selected_option_values); 885 } 886 } 887 } 888 }, 889 890 controlOutOfStockOptionViewOneOption : function(po_id, selected_option_values) { 891 892 if ( inst.ro_settings.allow_zero_select && inst.ro_settings.fade_out_of_stock_option_values ) { 893 894 let current_option_values = $.extend(true, {}, selected_option_values); 895 delete current_option_values[po_id]; 896 897 let ro_combs = inst.getROCombsByOptions(current_option_values); 898 let pov_ids_stock = inst.getPOVStockByROCombs(po_id, ro_combs); 899 900 let $ov_elements = inst.getOptionElement('select[name="'+inst.option_prefix+'['+po_id+']"]').find('option[value]'); 901 if ( !$ov_elements.length ) { 902 $ov_elements = inst.getOptionElement(':radio[name="'+inst.option_prefix+'['+po_id+']"]'); 903 } 904 905 if ( $ov_elements.length ) { 906 $ov_elements.each(function(){ 907 let $ov_element = $(this); 908 909 if ( $ov_element.is(':disabled') ) { 910 inst.controlOutOfStockOptionViewOneOptionIsDisabled($ov_element); 911 //inst.setOriginalTitleForRadio($radio); 912 } else { 913 let pov_id = $ov_element.val(); 914 if ( typeof(pov_ids_stock[pov_id]) != 'undefined' ) { 915 let pov_stock_data = pov_ids_stock[pov_id]; 916 if ( pov_stock_data.in_stock ) { // in stock 917 inst.controlOutOfStockOptionViewOneOptionIsInStock($ov_element); 918 //inst.fadeToOptionRadio($radio, 1); 919 //if ( inst.ro_settings.spec_ofs ) { 920 // inst.setOriginalTitleForRadio($radio); 921 //} 922 } else { 923 inst.controlOutOfStockOptionViewOneOptionIsOutOfStock($ov_element, (pov_ids_stock[pov_id].last_ro_comb ? pov_stock_data.last_ro_comb.stock_status || pov_stock_data.last_ro_comb.product_stock_status : '')); 924 //inst.fadeToOptionRadio($radio, 0.2); 925 //if ( inst.ro_settings.spec_ofs ) { 926 // if ( pov_ids_stock[pov_id].last_ro_comb ) { 927 // inst.appendToTitleForRadio($radio, pov_stock_data.last_ro_comb.stock_status || pov_stock_data.last_ro_comb.product_stock_status ); 928 // } 929 // //inst.setOriginalTitleForRadio($radio, ); 930 //} 931 } 932 } 933 } 934 }); 935 } 936 937 938 //let $select = inst.getOptionElement('select[name="'+inst.option_prefix+'['+po_id+']"]'); 939 //if ( $select.length ) { 940 // 941 // let $select_options = $select.find('option[value]');
942 // $select_options.each(function(){ 943 // let $select_option = $(this); 944 // if ( $select_option.is(':disabled') ) { 945 // $select_option.removeClass('ro_option_faded'); 946 // } else { 947 // 948 // } 949 // }); 950 //} 951 952 //let $radios = inst.getOptionElement(':radio[name="'+inst.option_prefix+'['+po_id+']"]'); 953 //if ( $radios.length ) { 954 // $radios.each(function(){ 955 // let $radio = $(this); 956 // 957 // if ( $radio.is(':disabled') ) { 958 // inst.setOriginalTitleForRadio($radio); 959 // } else { 960 // let pov_id = $radio.val(); 961 // if ( typeof(pov_ids_stock[pov_id]) != 'undefined' ) { 962 // let pov_stock_data = pov_ids_stock[pov_id]; 963 // if ( pov_stock_data.in_stock ) { // in stock 964 // inst.fadeToOptionRadio($radio, 1); 965 // if ( inst.ro_settings.spec_ofs ) { 966 // inst.setOriginalTitleForRadio($radio); 967 // } 968 // } else { 969 // inst.fadeToOptionRadio($radio, 0.2); 970 // if ( inst.ro_settings.spec_ofs ) { 971 // if ( pov_ids_stock[pov_id].last_ro_comb ) { 972 // inst.appendToTitleForRadio($radio, pov_stock_data.last_ro_comb.stock_status || pov_stock_data.last_ro_comb.product_stock_status ); 973 // } 974 // //inst.setOriginalTitleForRadio($radio, ); 975 // } 976 // } 977 // } 978 // } 979 // }); 980 //} 981 } 982 }, 983 984 controlOutOfStockOptionViewOneOptionIsDisabled : function($ov_element){ 985 if ( $ov_element.is('option') ) { 986 $ov_element.removeClass('ro_option_faded'); 987 } else { // radio 988 inst.setOriginalTitleForRadio($ov_element); 989 } 990 }, 991 992 controlOutOfStockOptionViewOneOptionIsOutOfStock : function($ov_element, title){ 993 if ( $ov_element.is('option') ) { 994 $ov_element.addClass('ro_option_faded'); 995 } else { // radio 996 inst.fadeToOptionRadio($ov_element, 0.3); 997 if ( inst.ro_settings.spec_ofs ) { 998 if ( title ) { 999 inst.appendToTitleForRadio($ov_element, title ); 1000 } 1001 //inst.setOriginalTitleForRadio($radio, ); 1002 } 1003 } 1004 }, 1005 1006 controlOutOfStockOptionViewOneOptionIsInStock : function($ov_element){ 1007 if ( $ov_element.is('option') ) { 1008 $ov_element.removeClass('ro_option_faded'); 1009 } else { // radio 1010 inst.fadeToOptionRadio($ov_element, 1); 1011 if ( inst.ro_settings.spec_ofs ) { 1012 inst.setOriginalTitleForRadio($ov_element); 1013 } 1014 } 1015 }, 1016 1017 getPOVStockByROCombs(po_id_current, ro_combs) { 1018 let pov_ids_stock = {}; 1019 1020 inst.each(ro_combs, function(ro_comb){ 1021 inst.each(ro_comb.options, function(pov_id, po_id){ 1022 if ( po_id == po_id_current ) { 1023 if ( !pov_ids_stock[pov_id] ) { 1024 pov_ids_stock[pov_id] = { 1025 in_stock : false, 1026 last_ro_comb : '', 1027 }; 1028 } 1029 pov_ids_stock[pov_id].in_stock = pov_ids_stock[pov_id].in_stock || ro_comb.in_stock; 1030 pov_ids_stock[pov_id].last_ro_comb = ro_comb; 1031 } 1032 }); 1033 }); 1034 return pov_ids_stock; 1035 }, 1036 1037 fadeToOptionRadio : function($radio, fade_to){ 1038 inst.fadeToForElement($radio.parent(), fade_to); 1039 }, 1040 fadeToForElement : function($elem, fade_to) { 1041 $elem.stop().fadeTo('fast', fade_to); 1042 }, 1043 1044 setOriginalTitleForRadio : function($radio){ 1045 let $elem = $radio.parent(); 1046 if ( typeof($elem.attr('data-ro-original-title')) != 'undefined' ) { 1047 $elem.attr('title', $elem.attr('data-ro-original-title')); 1048 } 1049 }, 1050 appendToTitleForRadio : function($radio, title_append) { 1051 let $elem = $radio.parent(); 1052 if ( typeof($elem.attr('data-ro-original-title')) == 'undefined' ) { 1053 $elem.attr('data-ro-original-title', $elem.attr('title')||''); 1054 } 1055 $elem.attr('title', ($elem.attr('data-ro-original-title')+' '+title_append).trim() ); 1056 }, 1057 1058 // autoselection for last available option value & first available always 1059 checkAutoSelect : function() { 1060 1061 if (inst.auto_select_last || inst.auto_select_first_always) { 1062 1063 inst.each(inst.getOptionsAsSteps(), function(product_option_id){ 1064 1065 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]').length ) { 1066 1067 var options_elems = inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]').find('option[value][value!=""]:not(:disabled)'); 1068 1069 if ( inst.auto_select_last && options_elems.length == 1 && !$(options_elems[0]).is(':selected') || ( inst.auto_select_first_always && options_elems.length && !options_elems.filter(':selected').length ) ) { 1070 1071 let product_option_value_id = $(options_elems[0]).val(); 1072 1073 inst.setOptionValue(product_option_id, product_option_value_id); 1074 $(options_elems[0]).parent().change(); 1075 return; 1076 } 1077 1078 } else if ( inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]').length ) { 1079 1080 var radio_elems = inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]:not(:disabled)'); 1081 1082 if ( inst.auto_select_last && radio_elems.length == 1 && !$(radio_elems[0]).is(':checked') || ( inst.auto_select_first_always && radio_elems.length && !radio_elems.filter(':checked').length ) ) { 1083 1084 let product_option_value_id = $(radio_elems[0]).val(); 1085 1086 inst.setOptionValue(product_option_id, product_option_value_id); 1087 1088 $(radio_elems[0]).change(); 1089 return; 1090 1091 } 1092 } 1093 }); 1094 } 1095 }, 1096 1097 // autorelection for first values (initial) 1098 initialAutoSelect : function() { 1099 1100 if (inst.ro_settings && inst.ro_settings.select_first && inst.ro_settings.select_first == 1) { 1101 inst.each(inst.getOptionsAsSteps(), function(product_option_id){ 1102 1103 if ( inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]').length ) { 1104 1105 let elem = inst.getOptionElement('select[name="'+inst.option_prefix+'['+product_option_id+']"]'); 1106 if ( !elem.val() ) { 1107 1108 let elem_option = elem.find('option[value][value!=""]:not(:disabled)'); 1109 if (elem_option.length) { 1110 1111 inst.setOptionValue(product_option_id, elem_option.val() ); 1112 1113 elem.change(); 1114 } 1115 1116 } 1117 1118 } else if ( inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]').length ) { 1119 1120 if ( !inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]:checked').length ) { 1121 let elem = inst.getOptionElement('input:radio[name="'+inst.option_prefix+'['+product_option_id+']"]:not(:disabled):first'); 1122 if (elem.length) { 1123 1124 inst.setOptionValue(product_option_id, elem.attr('value') ); 1125 1126 elem.change(); 1127 1128 } 1129 } 1130 } 1131 1132 1133 }); 1134 } 1135 }, 1136 1137 1138 }; 1139 1140 if ( typeof(getROProductThemeMethods) == 'function' ) { 1141 let ro_theme_methods = getROProductThemeMethods(inst); 1142 let debug = false;
1143 ro_common.proxyObjectMethods(inst, debug, ro_theme_methods); 1144 } 1145 1146 inst.parentBlock = this; 1147 1148 var params = $.extend( { 1149 'ro_settings' : {}, 1150 'ro_texts' : {}, 1151 'ro_data' : false, 1152 'ro_theme_name' : '', 1153 'ros_to_select' : '', 1154 'poip_ov' : '', 1155 'filter_name' : '', 1156 'product_id' : 0, 1157 }, p_params); 1158 inst.ro_settings = params.ro_settings; 1159 inst.ro_theme_name = params.ro_theme_name; 1160 inst.ro_texts = params.ro_texts; 1161 inst.ro_data = params.ro_data; 1162 inst.ros_to_select = params.ros_to_select; 1163 inst.poip_ov = params.poip_ov; 1164 inst.filter_name = params.filter_name; 1165 inst.product_id = params.product_id; 1166 1167 // settings 1168 inst.hide_inaccessible = inst.getSetting('hide_inaccessible'); 1169 inst.step_by_step = inst.getSetting('step_by_step'); 1170 1171 inst.auto_select_last = inst.getSetting('select_first') == 2; 1172 inst.auto_select_first_always = inst.getSetting('select_first') == 3; 1173 1174 inst.option_prefix = "option"; 1175 if ( !$('[name^="option["]').length ) { 1176 if ( $('[name^="option_oc["]').length ) { // mijoshop 1177 inst.option_prefix = "option_oc"; 1178 } 1179 } 1180 inst.option_prefix_length = inst.option_prefix.length; 1181 1182 // data 1183 inst.ro_product_options = []; 1184 if ( inst.ro_data ) { 1185 inst.each(inst.ro_data, function(ro_dt){ 1186 //for ( var i_ro_data in inst.ro_data ) { 1187 // if ( !inst.ro_data.hasOwnProperty(i_ro_data) ) continue; 1188 var option_ids = ro_dt.options_ids; 1189 inst.each(option_ids, function(product_option_id){ 1190 //for ( var i_option_ids in option_ids ) { 1191 // if ( !option_ids.hasOwnProperty(i_option_ids) ) continue; 1192 // var product_option_id = option_ids[i_option_ids]; 1193 if ( $.inArray(product_option_id, inst.ro_product_options) == -1 ) { 1194 inst.ro_product_options.push(product_option_id); 1195 } 1196 }); 1197 }); 1198 } 1199 //var ro_exists = false; 1200 1201 // variables 1202 inst.linked_options_cache = {}; // cache 1203 inst.all_select_ov = {}; // selects cache 1204 inst.input_quantity_per_options = []; 1205 inst.ro_stock_control_last_call = ''; 1206 inst.options_types = []; 1207 inst.options_step_by_step = []; 1208 inst.all_values_of_options = []; 1209 1210 //inst.initRO(); // init should be started from outside, after assigning all additional functions/triggers 1211 1212 $this.data('liveopencart_relatedOptions', inst); 1213 1214 if ( !window.liveopencart ) { 1215 window.liveopencart = {}; 1216 } 1217 if ( !window.liveopencart.related_options_instances ) { 1218 window.liveopencart.related_options_instances = []; 1219 } 1220 window.liveopencart.related_options_instances.push(inst); 1221 1222 return inst; 1223 1224}; })(jQuery); 1225 1226 1227 1228 1229
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.