PageSourceSearch

https://blb.uz/catalog/view/theme/extension_liveopencart/related_options/js/liveopencart.related_options.js

js blb.uz collected 2026-10-07 15:17:46 UTC 49,253 bytes, 1,373 lines download raw bytes

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

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.