PageSourceSearch

https://www.cookshack.com/mm5/clientside.mvc?T=116f58ee&Filename=AttributeMachine.js

js cookshack.com collected 2026-09-26 02:31:54 UTC 56,633 bytes, 1,941 lines download raw bytes

1// Miva Merchant
2//
3// This file and the source codes contained herein are the property of
4// Miva, Inc.  Use of this file is restricted to the specific terms and
5// conditions in the License Agreement associated with this file.  Distribution
6// of this file or portions of this file for uses not covered by the License
7// Agreement is not allowed without a written agreement signed by an officer of
8// Miva, Inc.
9//
10// Copyright 1998-2026 Miva, Inc.  All rights reserved.
11// http://www.miva.com
12//
13
14(function( obj, eventType, fn )
15{
16	if ( obj.addEventListener )
17	{
18		obj.addEventListener( eventType, fn, false );
19	}
20	else if ( obj.attachEvent )
21	{
22		obj.attachEvent( 'on' + eventType, fn );
23	}
24})( window, 'load', function() { AttributeMachine_Initialize(); } );
25
26function AttributeMachine_Initialize()
27{
28	FireEvent( window, 'attributemachine_override' );
29	FireEvent( window, 'attributemachine_initialize' );
30}
31
32function AttributeMachine( product_code, dependency_resolution, inventory_element_id, inv_long, price_element_id, swatch_element_id, invalid_msg, missing_text_msg, missing_radio_msg, attribute_swatch_id )
33{
34	this.purchase_disabled					= false;
35
36	this.inv_div							= null;
37	this.price_div							= null;
38	this.additional_price_div				= null;
39	this.weight_div							= null;
40	this.discount_div						= null;
41	this.swatches							= null;
42	this.master_attributes					= null;
43	this.attributes							= null;
44	this.have_inventory_attributes			= false;
45	this.purchase_buttons					= null;
46	this.buttons							= new Array();
47	this.possible_req						= null;
48
49	this.form								= null;
50	this.form_action						= null;
51	this.element_product_code 				= null;
52	this.element_product_quantity			= null;
53	this.elementlist_product_attributes		= new Array();
54	this.elementlist_product_subscription	= new Array();
55
56	/*
57	 * Provide backwards compatibility with old parameters
58	 */
59
60	if ( typeof product_code === 'object' )
61	{
62		this.settings						= product_code;
63
64		if ( typeof this.settings.getElementById === 'function' )		this.getElementById			= this.settings.getElementById;
65		if ( typeof this.settings.getElementsByTagName === 'function' )	this.getElementsByTagName	= this.settings.getElementsByTagName;
66	}
67	else
68	{
69		this.settings						= new Object();
70		this.settings.product_code			= product_code;
71		this.settings.dependency_resolution	= dependency_resolution;
72		this.settings.inventory_element_id	= inventory_element_id;
73		this.settings.inv_long				= inv_long;
74		this.settings.price_element_id		= price_element_id;
75		this.settings.swatch_element_id		= swatch_element_id;
76		this.settings.attribute_swatch_id	= attribute_swatch_id;
77		this.settings.invalid_msg			= invalid_msg ? invalid_msg : '';
78		this.settings.missing_text_msg		= missing_text_msg ? missing_text_msg : '';
79		this.settings.missing_radio_msg		= missing_radio_msg ? missing_radio_msg : '';
80	}
81
82	if ( this.settings.inventory_element_id )			this.inv_div				= this.getElementById( this.settings.inventory_element_id );
83	if ( this.settings.price_element_id )				this.price_div				= this.getElementById( this.settings.price_element_id );
84	if ( this.settings.additional_price_element_id )	this.additional_price_div	= this.getElementById( this.settings.additional_price_element_id );
85	if ( this.settings.weight_element_id )				this.weight_div				= this.getElementById( this.settings.weight_element_id );
86	if ( this.settings.discount_element_id )			this.discount_div			= this.getElementById( this.settings.discount_element_id );
87	if ( this.settings.swatch_element_id )				this.swatches				= this.getElementById( this.settings.swatch_element_id );
88
89	if ( this.price_div )								this.initial_price_value			= this.price_div.innerHTML;
90	if ( this.additional_price_div )					this.initial_additional_price_value	= this.additional_price_div.innerHTML;
91	if ( this.weight_div )								this.initial_weight_value			= this.weight_div.innerHTML;
92	if ( this.discount_div )							this.initial_discount_value			= this.discount_div.innerHTML;
93}
94
95AttributeMachine.prototype.Initialize = function( attributes, possible )
96{
97	var self = this;
98
99	if ( attributes )	return this.AttributeAndOptionList_Load_Callback( attributes, possible );
100	else				Runtime_AttributeAndOptionList_Load_Product( this.settings.product_code, function( response ) { self.AttributeAndOptionList_Load_Callback( response, possible ); } );
101}
102
103AttributeMachine.prototype.Find_Purchase_Buttons = function()
104{
105	var i, i_len, type, node_name;
106
107	if ( !this.form )
108	{
109		return;
110	}
111
112	for ( i = 0, i_len = this.form.elements.length; i < i_len; i++ )
113	{
114		node_name = this.form.elements[ i ].nodeName.toLowerCase();
115
116		if ( this.form.elements[ i ].hasAttribute( 'type' ) &&
117			 typeof this.form.elements[ i ].type === 'string' )		type = this.form.elements[ i ].type.toLowerCase();
118		else if ( node_name === 'button' )							type = 'submit';	// Default type for HTMLButtonElement
119		else if ( node_name === 'input' )							type = 'text';		// Default type for HTMLInputElement
120		else														type = null;
121
122		if ( type === 'button' || type === 'submit' )
123		{
124			//
125			// Button, input, or custom element that wants to be treated as a button
126			//
127
128			this.buttons.push( this.form.elements[ i ] );
129		}
130	}
131}
132
133AttributeMachine.prototype.Disable_Purchase_Buttons = function()
134{
135	var i, i_len;
136
137	if ( this.form_action === 'ATWL' || this.form_action == 'AFWL' )
138	{
139		return;
140	}
141	else if ( this.form_action === 'ADPM' )
142	{
143		if ( this.Purchase_FormElement_CanEnableDisable( this.element_product_quantity ) )
144		{
145			this.element_product_quantity.disabled = true;
146		}
147	}
148	else if ( this.form_action === 'AUPM' )
149	{
150		for ( i = 0, i_len = this.buttons.length; i < i_len; i++ )
151		{
152			if ( this.Purchase_FormElement_CanEnableDisable( this.buttons[ i ] ) )
153			{
154				this.Purchase_FormElement_IncrementInvalidCount( this.buttons[ i ] );
155				this.buttons[ i ].disabled = true;
156			}
157		}
158	}
159	else
160	{
161		for ( i = 0, i_len = this.buttons.length; i < i_len; i++ )
162		{
163			if ( this.Purchase_FormElement_CanEnableDisable( this.buttons[ i ] ) )
164			{
165				this.buttons[ i ].disabled = true;
166			}
167		}
168	}
169
170	this.purchase_disabled	= true;
171}
172
173AttributeMachine.prototype.Enable_Purchase_Buttons = function()
174{
175	var i, i_len;
176
177	if ( this.form_action === 'ATWL' || this.form_action == 'AFWL' )
178	{
179		return;
180	}
181	else if ( this.form_action === 'ADPM' )
182	{
183		if ( this.Purchase_FormElement_CanEnableDisable( this.element_product_quantity ) )
184		{
185			this.element_product_quantity.disabled = false;
186		}
187	}
188	else if ( this.form_action === 'AUPM' )
189	{
190		for ( i = 0, i_len = this.buttons.length; i < i_len; i++ )
191		{
192			if ( this.Purchase_FormElement_CanEnableDisable( this.buttons[ i ] ) &&
193				 this.Purchase_FormElement_DecrementInvalidCount( this.buttons[ i ] ) == 0 )
194			{
195				this.buttons[ i ].disabled = false;
196			}
197		}
198	}
199	else
200	{
201		for ( i = 0, i_len = this.buttons.length; i < i_len; i++ )
202		{
203			if ( this.Purchase_FormElement_CanEnableDisable( this.buttons[ i ] ) )
204			{
205				this.buttons[ i ].disabled = false;
206			}
207		}
208	}
209
210	this.purchase_disabled = false;
211}
212
213AttributeMachine.prototype.Purchase_Button_CanEnableDisable = function( button )
214{
215	return this.Purchase_FormElement_CanEnableDisable( button );
216}
217
218AttributeMachine.prototype.Purchase_FormElement_CanEnableDisable = function( element )
219{
220	if ( element )
221	{
222		while ( ( element = element.parentNode ) != null )
223		{
224			if ( ( typeof element.getAttribute === 'function' ) &&
225				 ( element.getAttribute( 'data-mmnodisable' ) !== null ) )
226			{
227				return false;
228			}
229		}
230
231		return true;
232	}
233
234	return false;
235}
236
237AttributeMachine.prototype.Purchase_FormElement_IncrementInvalidCount = function( element )
238{
239	var invalid_count;
240
241	invalid_count = parseInt( element.getAttribute( 'data-mminvalidcount' ) ) || 0;
242
243	if ( !this.purchase_disabled )
244	{
245		invalid_count++;
246	}
247
248	element.setAttribute( 'data-mminvalidcount', invalid_count );
249	return invalid_count;
250}
251
252AttributeMachine.prototype.Purchase_FormElement_DecrementInvalidCount = function( element )
253{
254	var invalid_count;
255
256	invalid_count = parseInt( element.getAttribute( 'data-mminvalidcount' ) ) || 0;
257
258	if ( this.purchase_disabled && invalid_count > 0 )
259	{
260		invalid_count--;
261	}
262
263	element.setAttribute( 'data-mminvalidcount', invalid_count );
264	return invalid_count;
265}
266
267AttributeMachine.prototype.Gather_Form_ProductAttributeElements = function( attribute, template_attribute )
268{
269	var i, i_len, index, match, regex, elements;
270
271	elements = new Array();
272
273	if ( ( index = this.Lookup_Attribute_Form_Index( this.form, attribute.code, template_attribute ? template_attribute.code : null ) ) !== null )
274	{
275		if ( this.form_action === 'ADPM' )
276		{
277			regex = new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}' + index + '\\s{0,}\\]:value$', 'i' );
278
279			for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
280			{
281				if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
282				if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
283
284				elements.push( this.elementlist_product_attributes[ i ] );
285			}
286		}
287		else if ( this.form_action === 'AUPM' )
288		{
289			regex = new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}' + index + '\\s{0,}\\]:value$', 'i' );
290
291			for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
292			{
293				if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
294				if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
295
296				elements.push( this.elementlist_product_attributes[ i ] );
297			}
298		}
299		else
300		{
301			regex = new RegExp( '^product_attributes\\[\\s{0,}' + index + '\\s{0,}\\]:value$', 'i' );
302
303			for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
304			{
305				if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
306				if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
307
308				elements.push( this.elementlist_product_attributes[ i ] );
309			}
310		}
311	}
312
313	return elements;
314}
315
316AttributeMachine.prototype.AttributeAndOptionList_Load_Callback = function( response, possible )
317{
318	var self = this;
319	var i, j, i_len, j_len, data, input, attribute, selection, last_attr_id, last_option_id, last_attmpat_id, template_attribute;
320
321	if ( !response.success )
322	{
323		this.onerror( response.error_message );
324	}
325
326	this.master_attributes			= response.data;
327	this.attributes					= new Array();
328	this.have_inventory_attributes	= false;
329
330	if ( !this.Lookup_Attribute_Form() )
331	{
332		return;
333	}
334
335	this.Find_Purchase_Buttons();
336
337	if ( this.settings.displaydiscounts )
338	{
339		this.subscription_term			= new AttributeMachine_SubscriptionTerm( this, this.form, this.elementlist_product_subscription.slice() );
340		this.subscription_term.onchange	= function( event ) { self.ProductSubscriptionTerm_Changed(); };
341	}
342
343	for ( i = 0, i_len = this.master_attributes.length; i < i_len; i++ )
344	{
345		attribute = this.master_attributes[ i ];
346
347		if ( attribute.type != 'template' )
348		{
349			if ( attribute.inventory )
350			{
351				this.have_inventory_attributes		= true;
352			}
353
354			if ( attribute.type == 'checkbox' )				input = new AttributeMachine_Checkbox( this, attribute, null );
355			else if ( attribute.type == 'text' )			input = new AttributeMachine_Text( this, attribute, null );
356			else if ( attribute.type == 'memo' )			input = new AttributeMachine_Memo( this, attribute, null );
357			else if ( attribute.type == 'radio' )			input = new AttributeMachine_Radio( this, attribute, null );
358			else if ( attribute.type == 'select' )			input = new AttributeMachine_Select( this, attribute, null );
359			else if ( attribute.type == 'swatch-select' )	input = new AttributeMachine_Select( this, attribute, null );
360			else											continue;
361
362			if ( !input.Initialize( this.form, this.Gather_Form_ProductAttributeElements( attribute, null ) ) )
363			{
364				this.onerror( 'Unable to locate form element(s) for attribute ' + attribute.code );
365				continue;
366			}
367
368			this.attributes.push( input );
369		}
370		else
371		{
372			for ( j = 0, j_len = attribute.attributes.length; j < j_len; j++ )
373			{
374				template_attribute = attribute.attributes[ j ];
375
376				if ( template_attribute.inventory )
377				{
378					this.have_inventory_attributes	= true;
379				}
380
381				if ( template_attribute.type == 'checkbox' )			input = new AttributeMachine_Checkbox( this, attribute, template_attribute );
382				else if ( template_attribute.type == 'text' )			input = new AttributeMachine_Text( this, attribute, template_attribute );
383				else if ( template_attribute.type == 'memo' )			input = new AttributeMachine_Memo( this, attribute, template_attribute );
384				else if ( template_attribute.type == 'radio' )			input = new AttributeMachine_Radio( this, attribute, template_attribute );
385				else if ( template_attribute.type == 'select' )			input = new AttributeMachine_Select( this, attribute, template_attribute );
386				else if ( template_attribute.type == 'swatch-select' )	input = new AttributeMachine_Select( this, attribute, template_attribute );
387				else													continue;
388
389				if ( !input.Initialize( this.form, this.Gather_Form_ProductAttributeElements( attribute, template_attribute ) ) )
390				{
391					this.onerror( 'Unable to locate form element(s) for template attribute ' + attribute.code + ':' + template_attribute.code );
392					continue;
393				}
394
395				this.attributes.push( input );
396			}
397		}
398	}
399
400	if ( this.attributes.length == 0 )
401	{
402		this.oninitializeswatches( this.master_attributes, null );
403		return;
404	}
405
406	selection			= this.Build_Selection();
407
408	if ( !selection.Has_Selected() )
409	{
410		last_attr_id	= 0;
411		last_attmpat_id	= 0;
412		last_option_id	= 0;
413	}
414	else
415	{
416		last_attr_id	= selection.selected_attr_ids[ 0 ];
417		last_attmpat_id	= selection.selected_attmpat_ids[ 0 ];
418		last_option_id	= selection.selected_option_ids[ 0 ];
419	}
420
421	if ( possible )
422	{
423		this.AttributeList_Load_Possible_Callback( possible );
424	}
425	else
426	{
427		data							= new Object();
428		data.product_code				= this.settings.product_code;
429		data.dependency_resolution		= this.settings.dependency_resolution;
430		data.predictdiscounts			= this.settings.displaydiscounts;
431		data.calculate_sale_price		= this.settings.price === 'sale' ? true : false;
432		data.last_selected_attr_id		= last_attr_id;
433		data.last_selected_attmpat_id	= last_attmpat_id;
434		data.last_selected_option_id	= last_option_id;
435		data.selected_term_id			= selection.selected_term_id;
436		data.selected_attr_ids			= selection.selected_attr_ids;
437		data.selected_attmpat_ids		= selection.selected_attmpat_ids;
438		data.selected_option_ids		= selection.selected_option_ids;
439		data.selected_attr_types		= selection.selected_attr_types;
440		data.unselected_attr_ids		= selection.unselected_attr_ids;
441		data.unselected_attmpat_ids		= selection.unselected_attmpat_ids;
442
443		this.possible_req				= v96_Runtime_AttributeList_Load_ProductVariant_Possible_PredictDiscounts( data, function( possible_response ) { self.AttributeList_Load_Possible_Callback( possible_response ); } );
444	}
445}
446
447AttributeMachine.prototype.ProductSubscriptionTerm_Changed = function()
448{
449	var self = this;
450	var data, selection;
451
452	selection						= this.Build_Selection();
453
454	data							= new Object();
455	data.product_code				= this.settings.product_code;
456	data.dependency_resolution		= this.settings.dependency_resolution;
457	data.predictdiscounts			= this.settings.displaydiscounts;
458	data.calculate_sale_price		= this.settings.price === 'sale' ? true : false;
459	data.last_selected_attr_id		= 0;
460	data.last_selected_attmpat_id	= 0;
461	data.last_selected_option_id	= 0;
462	data.selected_term_id			= selection.selected_term_id;
463	data.selected_attr_ids			= selection.selected_attr_ids;
464	data.selected_attmpat_ids		= selection.selected_attmpat_ids;
465	data.selected_option_ids		= selection.selected_option_ids;
466	data.selected_attr_types		= selection.selected_attr_types;
467	data.unselected_attr_ids		= selection.unselected_attr_ids;
468	data.unselected_attmpat_ids		= selection.unselected_attmpat_ids;
469
470	this.possible_req				= v96_Runtime_AttributeList_Load_ProductVariant_Possible_PredictDiscounts( data, function( possible_response ) { self.AttributeList_Load_Possible_Callback( possible_response ); } );
471}
472
473AttributeMachine.prototype.AttributeList_Load_Possible_Callback = function( response )
474{
475	var i, i_len, variant, message, attribute, cull_failures, possible_lookup, template_attribute, possible_sublookup;
476
477	cull_failures		= new Array();
478	this.possible_req	= null;
479
480	if ( !response.success )
481	{
482		this.onerror( response.error_message );
483	}
484
485	this.oninitializeswatches( this.master_attributes, response );
486
487	possible_lookup	= ( response.data ) ? this.Build_Possible_Lookup( response.data.attributes ) : null;
488
489	// Iterate through the attributes we've created and disable any that are not possible
490	for ( i = 0, i_len = this.attributes.length; i < i_len; i++ )
491	{
492		attribute				= this.attributes[ i ].attribute;
493		template_attribute		= this.attributes[ i ].template_attribute;
494
495		if ( !attribute.inventory && ( !template_attribute || !template_attribute.inventory ) )
496		{
497			continue;
498		}
499
500		possible_sublookup		= ( possible_lookup ) ? possible_lookup[ attribute.id ] : null;
501
502		if ( possible_sublookup )
503		{
504			if ( template_attribute )	possible_sublookup = possible_sublookup[ template_attribute.id ];
505			else						possible_sublookup = possible_sublookup[ 0 ];
506		}
507
508		if ( possible_sublookup == null )	this.attributes[ i ].Disable();
509		else
510		{
511			if ( !this.attributes[ i ].Cull( possible_sublookup.options, possible_sublookup.selected_id, message ) )
512			{
513				cull_failures.push( template_attribute ? template_attribute : attribute );
514			}
515		}
516	}
517
518	variant = ( response.data ) ? response.data.variant : null;
519
520	if ( response.data && response.data.have_price )
521	{
522		this.Pricing_Update( response.data );
523		this.Weight_Update( response.data );
524	}
525	else
526	{
527		this.Pricing_Reset();
528		this.Weight_Reset();
529	}
530
531	if ( !this.have_inventory_attributes )
532	{
533		return;
534	}
535
536	// Handle the purchase buttons and inventory message
537	if ( !variant || cull_failures.length )
538	{
539		this.Disable_Purchase_Buttons();
540
541		if ( this.inv_div )
542		{
543			this.inv_div.innerHTML = this.settings.invalid_msg;
544
545			for ( i = 0, i_len = cull_failures.length; i < i_len; i++ )
546			{
547				if ( cull_failures[ i ].type == 'radio' )													message = this.settings.missing_radio_msg;
548				else if ( ( cull_failures[ i ].type == 'text' ) || ( cull_failures[ i ].type == 'memo' ) )	message = this.settings.missing_text_msg;
549				else																						message = '';
550
551				message	= message.replace( '%attribute_code%',		cull_failures[ i ].code	);
552				message	= message.replace( '%attribute_prompt%',	cull_failures[ i ].prompt );
553
554				this.inv_div.innerHTML	+= message;
555			}
556		}
557	}
558	else
559	{
560		if ( variant.inv_active &&
561			 variant.inv_level == 'out' )	this.Disable_Purchase_Buttons();
562		else								this.Enable_Purchase_Buttons();
563
564		if ( this.inv_div )					this.inv_div.innerHTML = this.settings.inv_long ? variant.inv_long : variant.inv_short;
565
566		const product_data =
567		{
568			product_code:	this.settings.product_code,
569			variant_id:		variant.variant_id
570		};
571
572		this.onVariantChanged( product_data );
573
574		if ( typeof MivaEvents !== 'undefined' )
575		{ 
576			MivaEvents.ThrowEvent( 'variant_changed', product_data );
577		}
578	}
579}
580
581AttributeMachine.prototype.Pricing_Update = function( data )
582{
583	var i, i_len, price, additional_price, formatted_price, formatted_additional_price;
584
585	if ( this.settings.price === 'retail' )
586	{
587		price			= data.retail;
588		formatted_price	= data.formatted_retail;
589	}
590	else if ( this.settings.price === 'base' )
591	{
592		price			= data.base_price;
593		formatted_price	= data.formatted_base_price;
594	}
595	else
596	{
597		price			= data.price;
598		formatted_price	= data.formatted_price;
599	}
600
601	if ( ( this.settings.additionalprice === 'retail' ) && ( price < data.retail ) )
602	{
603		additional_price			= data.retail;
604		formatted_additional_price	= data.formatted_retail;
605	}
606	else if ( ( this.settings.additionalprice === 'base' ) && ( price < data.base_price ) )
607	{
608		additional_price			= data.base_price;
609		formatted_additional_price	= data.formatted_base_price;
610	}
611	else
612	{
613		additional_price			= null;
614		formatted_additional_price	= '';
615	}
616
617	if ( this.price_div )				this.price_div.innerHTML			= formatted_price;
618	if ( this.additional_price_div )	this.additional_price_div.innerHTML	= formatted_additional_price;
619
620	if ( this.discount_div && this.settings.displaydiscounts )
621	{
622		this.discount_div.innerHTML	= '';
623
624		for ( i = 0, i_len = data.discounts.length; i < i_len; i++ )
625		{
626			this.discount_div.appendChild( this.Generate_Discount( data.discounts[ i ] ) );
627		}
628	}
629
630	const product_data =
631	{
632		product_code:				this.settings.product_code,
633		price:						price,
634		additional_price:			additional_price,
635		formatted_price:			formatted_price,
636		formatted_additional_price:	formatted_additional_price
637	};
638
639	this.onPriceChanged( product_data );
640
641	if ( typeof MivaEvents !== 'undefined' )
642	{ 
643		MivaEvents.ThrowEvent( 'price_changed', product_data );
644	}
645}
646
647AttributeMachine.prototype.Pricing_Reset = function()
648{
649	if ( this.price_div )				this.price_div.innerHTML			= this.initial_price_value;
650	if ( this.additional_price_div )	this.additional_price_div.innerHTML	= this.initial_additional_price_value;
651
652	if ( this.discount_div && this.settings.displaydiscounts )
653	{
654		this.discount_div.innerHTML = this.initial_discount_value;
655	}
656}
657
658AttributeMachine.prototype.Weight_Update = function( data )
659{
660	if ( this.weight_div )
661	{
662		this.weight_div.textContent = this.weight_div.hasAttribute( 'data-mm-formatted' ) ? data.formatted_weight : data.padded_weight;
663	}
664}
665
666AttributeMachine.prototype.Weight_Reset = function()
667{
668	if ( this.weight_div )
669	{
670		this.weight_div.innerHTML = this.initial_weight_value;
671	}
672}
673
674AttributeMachine.prototype.Attribute_Changed = function( attribute )
675{
676	var self = this;
677	var data, selection;
678
679	if ( this.possible_req )
680	{
681		this.possible_req.onreadystatechange = function() {};
682		this.possible_req.abort();
683	}
684
685	selection						= this.Build_Selection();
686
687	data							= new Object();
688	data.product_code				= this.settings.product_code;
689	data.dependency_resolution		= this.settings.dependency_resolution;
690	data.predictdiscounts			= this.settings.displaydiscounts;
691	data.calculate_sale_price		= this.settings.price === 'sale' ? true : false;
692	data.last_selected_attr_id		= attribute.attribute.id;
693	data.last_selected_attmpat_id	= attribute.template_attribute ? attribute.template_attribute.id : 0;
694	data.last_selected_option_id	= attribute.Selected_Option_ID();
695	data.selected_term_id			= selection.selected_term_id;
696	data.selected_attr_ids			= selection.selected_attr_ids;
697	data.selected_attmpat_ids		= selection.selected_attmpat_ids;
698	data.selected_option_ids		= selection.selected_option_ids;
699	data.selected_attr_types		= selection.selected_attr_types;
700	data.unselected_attr_ids		= selection.unselected_attr_ids;
701	data.unselected_attmpat_ids		= selection.unselected_attmpat_ids;
702
703	this.possible_req				= v96_Runtime_AttributeList_Load_ProductVariant_Possible_PredictDiscounts( data, function( possible_response ) { self.AttributeList_Load_Possible_Callback( possible_response ); } );
704}
705
706AttributeMachine.prototype.Build_Selection = function()
707{
708	var i, type, i_len, attr_id, selection, option_id, attmpat_id;
709
710	selection = new AttributeMachine_Selection();
711
712	if ( this.subscription_term )
713	{
714		selection.selected_term_id = this.subscription_term.GetValue();
715	}
716
717	for ( i = 0, i_len = this.attributes.length; i < i_len; i++ )
718	{
719		attr_id		= this.attributes[ i ].attribute.id;
720		attmpat_id	= this.attributes[ i ].template_attribute == null ? 0 : this.attributes[ i ].template_attribute.id;
721		option_id	= this.attributes[ i ].Selected_Option_ID();
722
723		if ( option_id === null )
724		{
725			selection.unselected_attr_ids.push( attr_id );
726			selection.unselected_attmpat_ids.push( attmpat_id );
727		}
728		else
729		{
730			type = this.attributes[ i ].template_attribute == null ? this.attributes[ i ].attribute.type : this.attributes[ i ].template_attribute.type;
731
732			selection.selected_attr_ids.push( attr_id );
733			selection.selected_attmpat_ids.push( attmpat_id );
734			selection.selected_option_ids.push( option_id );
735			selection.selected_attr_types.push( type );
736		}
737	}
738
739	return selection;
740}
741
742AttributeMachine.prototype.Build_Possible_Lookup = function( data )
743{
744	var i, j, i_len, j_len, lookup, attr_id, option_id, attmpat_id;
745
746	lookup = new Array();
747
748	for ( i = 0, i_len = data.length; i < i_len; i++ )
749	{
750		attr_id		= data[ i ].id;
751		attmpat_id	= data[ i ].attmpat_id;
752
753		if ( lookup[ attr_id ] == null )
754		{
755			lookup[ attr_id ] = new Array();
756		}
757
758		if ( lookup[ attr_id ][ attmpat_id ] == null )
759		{
760			lookup[ attr_id ][ attmpat_id ]			= new Object;
761			lookup[ attr_id ][ attmpat_id ].options	= new Array();
762		}
763
764		lookup[ attr_id ][ attmpat_id ].selected_id	= data[ i ].selected_id;
765
766		for ( j = 0, j_len = data[ i ].options.length; j < j_len; j++ )
767		{
768			option_id												= data[ i ].options[ j ];
769			lookup[ attr_id ][ attmpat_id ].options[ option_id ]	= 1;
770		}
771	}
772
773	return lookup;
774}
775
776AttributeMachine.prototype.Lookup_Form_Data = function()
777{
778	var i, j, data, forms, i_len, j_len, action, action_value;
779
780	forms = this.getElementsByTagName( 'form' );
781
782	for ( i = 0, i_len = forms.length; i < i_len; i++ )
783	{
784		for ( j = 0, j_len = forms[ i ].elements.length; j < j_len; j++ )
785		{
786			if ( !forms[ i ].elements[ j ].hasAttribute( 'name' ) )
787			{
788				continue;
789			}
790			else if ( forms[ i ].elements[ j ].name.toLowerCase() === 'action' )
791			{
792				action = forms[ i ].elements[ j ];
793				break;
794			}
795		}
796
797		if ( !action )
798		{
799			continue;
800		}
801
802		action_value = action.value.toUpperCase();
803
804		if ( action_value !== 'ADPR' &&
805			 action_value !== 'ADPM' &&
806			 action_value !== 'AUPR' &&
807			 action_value !== 'AUPM' &&
808			 action_value !== 'AFWL' )
809		{
810			continue;
811		}
812
813		if ( action_value === 'ADPM' || action_value === 'AUPM' )
814		{
815			if ( ( data = this.Lookup_Form_Data_LowLevel_MultiAddForm( forms[ i ], action_value ) ) !== null )
816			{
817				return data;
818			}
819		}
820		else
821		{
822			if ( ( data = this.Lookup_Form_Data_LowLevel_SingleAddForm( forms[ i ], action_value ) ) !== null )
823			{
824				return data;
825			}
826		}
827	}
828
829	return null;
830}
831
832AttributeMachine.prototype.Lookup_Form_Data_LowLevel_MultiAddForm = function( form, action_value )
833{
834	var i, data, i_len, name, product_id, match_code, match_quantity, match_attributes, regex_product_code, match_subscription, regex_product_quantity;
835	var elementmap_product_code, regex_product_attributes, regex_product_subscription, elementmap_product_quantity, elementmap_product_attributes, elementmap_product_subscription;
836
837	product_id							= -1;
838	elementmap_product_code				= new Object();
839	elementmap_product_quantity			= new Object();
840	elementmap_product_attributes		= new Object();
841	elementmap_product_subscription		= new Object();
842
843	if ( action_value === 'AUPM' )
844	{
845		regex_product_code				= new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:code', 'i' );
846		regex_product_quantity			= null;
847		regex_product_attributes		= new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[', 'i' );
848		regex_product_subscription		= new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:subterm_id', 'i' );
849	}
850	else
851	{
852		regex_product_code				= new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:code', 'i' );
853		regex_product_quantity			= new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:quantity', 'i' );
854		regex_product_attributes		= new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[', 'i' );
855		regex_product_subscription		= new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:subterm_id', 'i' );
856	}
857
858	for ( i = 0, i_len = form.elements.length; i < i_len; i++ )
859	{
860		if ( !form.elements[ i ].hasAttribute( 'name' ) )
861		{
862			continue;
863		}
864
865		name = form.elements[ i ].name.toLowerCase();
866
867		if ( ( ( match_code = name.match( regex_product_code ) ) !== null ) && ( typeof match_code[ 1 ] === 'string' ) && ( match_code[ 1 ].length ) )
868		{
869			if ( form.elements[ i ].value.toLowerCase() === this.settings.product_code.toLowerCase() )
870			{
871				product_id = match_code[ 1 ];
872			}
873
874			elementmap_product_code[ match_code[ 1 ] ] = form.elements[ i ];
875		}
876		else if ( regex_product_quantity && ( ( match_quantity = name.match( regex_product_quantity ) ) !== null ) && ( typeof match_quantity[ 1 ] === 'string' ) && ( match_quantity[ 1 ].length ) )
877		{
878			elementmap_product_quantity[ match_quantity[ 1 ] ] = form.elements[ i ];
879		}
880		else if ( ( ( match_attributes = name.match( regex_product_attributes ) ) !== null ) && ( typeof match_attributes[ 1 ] === 'string' ) && ( match_attributes[ 1 ].length ) )
881		{
882			if ( !Array.isArray( elementmap_product_attributes[ match_attributes[ 1 ] ] ) )
883			{
884				elementmap_product_attributes[ match_attributes[ 1 ] ] = new Array();
885			}
886
887			elementmap_product_attributes[ match_attributes[ 1 ] ].push( form.elements[ i ] );
888		}
889		else if ( ( ( match_subscription = name.match( regex_product_subscription ) ) !== null ) && ( typeof match_subscription[ 1 ] === 'string' ) && ( match_subscription[ 1 ].length ) )
890		{
891			if ( !Array.isArray( elementmap_product_subscription[ match_subscription[ 1 ] ] ) )
892			{
893				elementmap_product_subscription[ match_subscription[ 1 ] ] = new Array();
894			}
895
896			elementmap_product_subscription[ match_subscription[ 1 ] ].push( form.elements[ i ] );
897		}
898	}
899
900	if ( product_id === -1 )																												return null;
901	if ( !elementmap_product_code.hasOwnProperty( product_id ) )																			return null;
902	if ( action_value === 'ADPM' && !elementmap_product_quantity.hasOwnProperty( product_id ) )												return null;
903	if ( ( !elementmap_product_attributes.hasOwnProperty( product_id ) || elementmap_product_attributes[ product_id ].length === 0 ) &&
904		 ( !elementmap_product_subscription.hasOwnProperty( product_id ) || elementmap_product_subscription[ product_id ].length === 0 ) )	return null;
905
906	data									= new Object();
907	data.form								= form;
908	data.form_action						= action_value;
909	data.element_product_code				= elementmap_product_code[ product_id ];
910	data.element_product_quantity			= elementmap_product_quantity.hasOwnProperty( product_id ) ? elementmap_product_quantity[ product_id ] : null;
911	data.elementlist_product_attributes		= elementmap_product_attributes[ product_id ];
912	data.elementlist_product_subscription	= elementmap_product_subscription.hasOwnProperty( product_id ) ? elementmap_product_subscription[ product_id ] : [];
913
914	return data;
915}
916
917AttributeMachine.prototype.Lookup_Form_Data_LowLevel_SingleAddForm = function( form, action_value )
918{
919	var i, name, data, i_len, element_product_code, element_product_quantity, elementlist_product_attributes, elementlist_product_subscription;
920
921	element_product_code				= null;
922	element_product_quantity			= null;
923	elementlist_product_attributes		= new Array();
924	elementlist_product_subscription	= new Array();
925
926	for ( i = 0, i_len = form.elements.length; i < i_len; i++ )
927	{
928		if ( !form.elements[ i ].hasAttribute( 'name' ) )
929		{
930			continue;
931		}
932
933		name = form.elements[ i ].name.toLowerCase();
934
935		if ( name === 'product_code' )							element_product_code		= form.elements[ i ];
936		else if ( name === 'quantity' )							element_product_quantity	= form.elements[ i ];
937		else if ( name === 'product_subscription_term_id' )		elementlist_product_subscription.push( form.elements[ i ] );
938		else if ( name.indexOf( 'product_attributes[' ) === 0 )	elementlist_product_attributes.push( form.elements[ i ] );
939	}
940
941	if ( !element_product_code )																		return null;
942	if ( action_value === 'ADPM' && !element_product_quantity )											return null;
943	if ( element_product_code.value.toLowerCase() != this.settings.product_code.toLowerCase() )			return null;
944	if ( elementlist_product_attributes.length === 0 && elementlist_product_subscription.length === 0 )	return null;
945
946	data									= new Object();
947	data.form								= form;
948	data.form_action						= action_value;
949	data.element_product_code				= element_product_code;
950	data.element_product_quantity			= element_product_quantity;
951	data.elementlist_product_attributes		= elementlist_product_attributes;
952	data.elementlist_product_subscription	= elementlist_product_subscription;
953
954	return data;
955}
956
957AttributeMachine.prototype.Lookup_Attribute_Form = function()
958{
959	var i, j, forms, i_len, j_len, action, form_data, ignore_error;
960
961	if ( ( form_data = this.Lookup_Form_Data() ) !== null )
962	{
963		this.form								= form_data.form;
964		this.form_action						= form_data.form_action;
965		this.element_product_code				= form_data.element_product_code;
966		this.element_product_quantity			= form_data.element_product_quantity;
967		this.elementlist_product_attributes		= form_data.elementlist_product_attributes;
968		this.elementlist_product_subscription	= form_data.elementlist_product_subscription;
969
970		return form_data.form;
971	}
972
973	//
974	// Iterate over each of the forms on screen. If the ATWL
975	// form exists, then we ignore the error alert
976	//
977
978	forms = this.getElementsByTagName( 'form' );
979
980	for ( i = 0, i_len = forms.length; i < i_len; i++ )
981	{
982		for ( j = 0, j_len = forms[ i ].elements.length; j < j_len; j++ )
983		{
984			if ( !forms[ i ].elements[ j ].hasAttribute( 'name' ) )
985			{
986				continue;
987			}
988			else if ( forms[ i ].elements[ j ].name.toLowerCase() === 'action' )
989			{
990				action = forms[ i ].elements[ j ];
991				break;
992			}
993		}
994
995		if ( !action )
996		{
997			continue;
998		}
999		else if ( action.value.toUpperCase() === 'ATWL' )
1000		{
1001			ignore_error = true;
1002			break;
1003		}
1004	}
1005
1006	if ( !ignore_error )
1007	{
1008		this.onerror( 'Unable to locate form for inventory attributes' );
1009	}
1010
1011	return null;
1012}
1013
1014AttributeMachine.prototype.Lookup_Attribute_Form_Index = function( form, attribute_code, template_code )
1015{
1016	var i, j, i_len, j_len, regex, match, index, regex_template, match_template;
1017
1018	if ( form !== this.form )
1019	{
1020		return null;
1021	}
1022
1023	if ( this.form_action === 'ADPM' )
1024	{
1025		regex = new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:code$', 'i' );
1026
1027		for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
1028		{
1029			if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
1030			if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
1031			if ( this.elementlist_product_attributes[ i ].value !== attribute_code )					continue;
1032
1033			index = parseInt( match[ 2 ], 10 );
1034
1035			if ( template_code === null )
1036			{
1037				return index;
1038			}
1039
1040			regex_template = new RegExp( '^products\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:template_code$', 'i' );
1041
1042			for ( j = 0, j_len = this.elementlist_product_attributes.length; j < j_len; j++ )
1043			{
1044				if ( !this.elementlist_product_attributes[ j ].hasAttribute( 'name' ) )										continue;
1045				if ( ( match_template = this.elementlist_product_attributes[ j ].name.match( regex_template ) ) === null )	continue;
1046				if ( this.elementlist_product_attributes[ j ].value !== template_code )										continue;
1047
1048				if ( parseInt( match_template[ 2 ], 10 ) === index )
1049				{
1050					return index;
1051				}
1052			}
1053		}
1054	}
1055	else if ( this.form_action == 'AUPM' )
1056	{
1057		regex = new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:code$', 'i' );
1058
1059		for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
1060		{
1061			if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
1062			if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
1063			if ( this.elementlist_product_attributes[ i ].value !== attribute_code )					continue;
1064
1065			index = parseInt( match[ 2 ], 10 );
1066
1067			if ( template_code === null )
1068			{
1069				return index;
1070			}
1071
1072			regex_template = new RegExp( '^product\\[\\s{0,}(\\d{1,})\\s{0,}\\]:attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:template_code$', 'i' );
1073
1074			for ( j = 0, j_len = this.elementlist_product_attributes.length; j < j_len; j++ )
1075			{
1076				if ( !this.elementlist_product_attributes[ j ].hasAttribute( 'name' ) )										continue;
1077				if ( ( match_template = this.elementlist_product_attributes[ j ].name.match( regex_template ) ) === null )	continue;
1078				if ( this.elementlist_product_attributes[ j ].value !== template_code )										continue;
1079
1080				if ( parseInt( match_template[ 2 ], 10 ) === index )
1081				{
1082					return index;
1083				}
1084			}
1085		}
1086	}
1087	else
1088	{
1089		regex = new RegExp( '^product_attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:code$', 'i' );
1090
1091		for ( i = 0, i_len = this.elementlist_product_attributes.length; i < i_len; i++ )
1092		{
1093			if ( !this.elementlist_product_attributes[ i ].hasAttribute( 'name' ) )						continue;
1094			if ( ( match = this.elementlist_product_attributes[ i ].name.match( regex ) ) === null )	continue;
1095			if ( this.elementlist_product_attributes[ i ].value !== attribute_code )					continue;
1096
1097			index = parseInt( match[ 1 ], 10 );
1098
1099			if ( template_code === null )
1100			{
1101				return index;
1102			}
1103
1104			regex_template = new RegExp( '^product_attributes\\[\\s{0,}(\\d{1,})\\s{0,}\\]:template_code$', 'i' );
1105
1106			for ( j = 0, j_len = this.elementlist_product_attributes.length; j < j_len; j++ )
1107			{
1108				if ( !this.elementlist_product_attributes[ j ].hasAttribute( 'name' ) )										continue;
1109				if ( ( match_template = this.elementlist_product_attributes[ j ].name.match( regex_template ) ) === null )	continue;
1110				if ( this.elementlist_product_attributes[ j ].value !== template_code )										continue;
1111
1112				if ( parseInt( match_template[ 1 ], 10 ) === index )
1113				{
1114					return index;
1115				}
1116			}
1117		}
1118	}
1119
1120	return null;
1121}
1122
1123AttributeMachine.prototype.onerror				= function( error_message ) { console.log( error_message ); }
1124AttributeMachine.prototype.getElementById		= function( id ) { return document.getElementById( id ); }
1125AttributeMachine.prototype.getElementsByTagName	= function( tagName ) { return document.getElementsByTagName( tagName ); }
1126AttributeMachine.prototype.onPriceChanged		= function( product_data ) { ; }
1127AttributeMachine.prototype.onVariantChanged		= function( product_data ) { ; }
1128
1129// AttributeMachine_SubscriptionTerm
1130///////////////////////////////////////////////////////////////////
1131
1132function AttributeMachine_SubscriptionTerm( machine, form, elements )
1133{
1134	var self = this;
1135	var i, i_len;
1136
1137	this.machine	= machine;
1138	this.elements	= new Array();
1139
1140	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1141	{
1142		if ( elements[ i ].nodeName.toLowerCase() === 'input' &&
1143			 elements[ i ].type.toLowerCase() === 'radio' )
1144		{
1145			this.elements.push( elements[ i ] );
1146			AddEvent( elements[ i ], 'click', function( event ) { self.onchange( event ); } );
1147		}
1148		else
1149		{
1150			this.elements.push( elements[ i ] );
1151			AddEvent( elements[ i ], 'change', function( event ) { self.onchange( event ); } );
1152		}
1153	}
1154}
1155
1156AttributeMachine_SubscriptionTerm.prototype.GetValue = function()
1157{
1158	var i, i_len;
1159
1160	if ( this.elements.length == 0 )
1161	{
1162		return 0;
1163	}
1164
1165	for ( i = 0, i_len = this.elements.length; i < i_len; i++ )
1166	{
1167		if ( ( this.elements[ i ].nodeName.toLowerCase() == 'input' ) &&
1168			 ( this.elements[ i ].type.toLowerCase() == 'radio' ) )
1169		{
1170			if ( this.elements[ i ].checked )
1171			{
1172				return this.elements[ i ].value;
1173			}
1174		}
1175		else
1176		{
1177			return this.elements[ i ].value;
1178		}
1179	}
1180}
1181
1182AttributeMachine_SubscriptionTerm.prototype.onchange = function( event ) { ; }
1183
1184// AttributeMachine_Selection
1185///////////////////////////////////////////////////////////////////
1186
1187function AttributeMachine_Selection()
1188{
1189	this.selected_term_id		= 0;
1190	this.selected_attr_ids		= new Array();
1191	this.selected_attmpat_ids	= new Array();
1192	this.selected_option_ids	= new Array();
1193	this.selected_attr_types	= new Array();
1194
1195	this.unselected_attr_ids	= new Array();
1196	this.unselected_attmpat_ids	= new Array();
1197}
1198
1199AttributeMachine_Selection.prototype.Has_Selected = function()
1200{
1201	return this.selected_attr_ids.length ? true : false;
1202}
1203
1204// AttributeMachine_Checkbox
1205///////////////////////////////////////////////////////////////////
1206
1207function AttributeMachine_Checkbox( machine, attribute, template_attribute )
1208{
1209	this.machine			= machine;
1210	this.attribute			= attribute;
1211	this.template_attribute	= template_attribute;
1212	this.checkbox			= null;
1213	this.hidden				= null;
1214}
1215
1216AttributeMachine_Checkbox.prototype.Initialize = function( form, elements )
1217{
1218	var self = this;
1219	var i, i_len;
1220
1221	this.checkbox = null;
1222
1223	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1224	{
1225		if ( !elements[ i ].hasAttribute( 'type' ) )			continue;
1226		if ( elements[ i ].type.toLowerCase() !== 'checkbox' )	continue;
1227
1228		this.checkbox = elements[ i ];
1229		break;
1230	}
1231
1232	if ( this.checkbox == null )
1233	{
1234		return false;
1235	}
1236
1237	this.hidden				= document.createElement( 'input' );
1238	this.hidden.type		= 'hidden';
1239	this.hidden.name		= this.checkbox.name;
1240	this.hidden.value		= this.checkbox.checked ? 'Yes' : '';
1241	this.hidden.disabled	= this.checkbox.disabled ? false : true;
1242
1243	this.checkbox.form.appendChild( this.hidden );
1244
1245	AddEvent( this.checkbox, 'click', function()
1246	{
1247		self.machine.Attribute_Changed( self );
1248		return true;
1249	} );
1250
1251	return true;
1252}
1253
1254AttributeMachine_Checkbox.prototype.Disable = function()
1255{
1256	this.checkbox.disabled	= true;
1257	this.hidden.disabled	= false;
1258}
1259
1260AttributeMachine_Checkbox.prototype.Enable = function()
1261{
1262	this.checkbox.disabled	= false;
1263	this.hidden.disabled	= true;
1264}
1265
1266AttributeMachine_Checkbox.prototype.Cull = function( possible_option_lookup, selected_id )
1267{
1268	if ( selected_id == 0 )
1269	{
1270		this.checkbox.checked	= false;
1271		this.hidden.value		= '';
1272	}
1273	else if ( selected_id == 1 )
1274	{
1275		this.checkbox.checked	= true;
1276		this.hidden.value		= 'Yes';
1277	}
1278
1279	if ( possible_option_lookup[ 0 ] == null ||
1280		 possible_option_lookup[ 1 ] == null )	this.Disable();
1281	else										this.Enable();
1282
1283	return true;
1284}
1285
1286AttributeMachine_Checkbox.prototype.Selected_Option_ID = function()
1287{
1288	if ( this.checkbox.checked )	return 1;
1289	else							return 0;
1290}
1291
1292// AttributeMachine_Text
1293///////////////////////////////////////////////////////////////////
1294
1295function AttributeMachine_Text( machine, attribute, template_attribute )
1296{
1297	this.machine			= machine;
1298	this.attribute			= attribute;
1299	this.template_attribute	= template_attribute;
1300	this.input				= null;
1301	this.last_value			= null;
1302}
1303
1304AttributeMachine_Text.prototype.Initialize = function( form, elements )
1305{
1306	var self = this;
1307	var i, i_len;
1308
1309	this.input = null;
1310
1311	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1312	{
1313		if ( !elements[ i ].hasAttribute( 'type' ) )		continue;
1314		if ( elements[ i ].type.toLowerCase() !== 'text' )	continue;
1315
1316		this.input = elements[ i ];
1317		break;
1318	}
1319
1320	if ( this.input == null )
1321	{
1322		return false;
1323	}
1324
1325	this.last_value = this.input.value;
1326
1327	AddEvent( this.input, 'change',	function( event ) { return self.Event_OnChange( event ? event : window.event ); } );
1328	AddEvent( this.input, 'keyup',	function( event ) { return self.Event_OnChange( event ? event : window.event ); } );
1329
1330	return true;
1331}
1332
1333AttributeMachine_Text.prototype.Event_OnChange = function( e )
1334{
1335	if ( ( this.last_value.length == 0 ) != ( this.input.value.length == 0 ) )
1336	{
1337		this.machine.Attribute_Changed( this );
1338	}
1339
1340	this.last_value = this.input.value;
1341
1342	return true;
1343}
1344
1345AttributeMachine_Text.prototype.Disable = function()
1346{
1347	this.input.disabled	= true;
1348}
1349
1350AttributeMachine_Text.prototype.Enable = function()
1351{
1352	this.input.disabled	= false;
1353}
1354
1355AttributeMachine_Text.prototype.Cull = function( possible_option_lookup, selected_id )
1356{
1357	if ( possible_option_lookup[ 1 ] == null )
1358	{
1359		this.Disable();
1360		return true;
1361	}
1362
1363	this.Enable();
1364
1365	switch ( selected_id )
1366	{
1367		case 0 :
1368		{
1369			this.last_value		= '';
1370			this.input.value	= '';
1371
1372			break;
1373		}
1374		case 1 :
1375		{
1376			if ( this.input.value.length == 0 )
1377			{
1378				return false;
1379			}
1380
1381			break;
1382		}
1383	}
1384
1385	return true;
1386}
1387
1388AttributeMachine_Text.prototype.Selected_Option_ID = function()
1389{
1390	if ( this.input.disabled )		return 0;
1391	if ( this.input.value.length )	return 1;
1392	else							return 0;
1393}
1394
1395// AttributeMachine_Memo
1396///////////////////////////////////////////////////////////////////
1397
1398function AttributeMachine_Memo( machine, attribute, template_attribute )
1399{
1400	this.machine			= machine;
1401	this.attribute			= attribute;
1402	this.template_attribute	= template_attribute;
1403	this.textarea			= null;
1404	this.last_value			= null;
1405}
1406
1407AttributeMachine_Memo.prototype.Initialize = function( form, elements )
1408{
1409	var self = this;
1410	var i, i_len;
1411
1412	this.textarea = null;
1413
1414	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1415	{
1416		if ( elements[ i ].nodeName.toLowerCase() !== 'textarea' )
1417		{
1418			continue;
1419		}
1420
1421		this.textarea = elements[ i ];
1422		break;
1423	}
1424
1425	if ( this.textarea == null )
1426	{
1427		return false;
1428	}
1429
1430	this.last_value = this.textarea.value;
1431
1432	AddEvent( this.textarea, 'change',	function( event ) { return self.Event_OnChange( event ? event : window.event ); } );
1433	AddEvent( this.textarea, 'keyup',	function( event ) { return self.Event_OnChange( event ? event : window.event ); } );
1434
1435	return true;
1436}
1437
1438AttributeMachine_Memo.prototype.Event_OnChange = function( e )
1439{
1440	if ( ( this.last_value.length == 0 ) != ( this.textarea.value.length == 0 ) )
1441	{
1442		this.machine.Attribute_Changed( this );
1443	}
1444
1445	this.last_value = this.textarea.value;
1446
1447	return true;
1448}
1449
1450AttributeMachine_Memo.prototype.Disable = function()
1451{
1452	this.textarea.disabled = true;
1453}
1454
1455AttributeMachine_Memo.prototype.Enable = function()
1456{
1457	this.textarea.disabled = false;
1458}
1459
1460AttributeMachine_Memo.prototype.Cull = function( possible_option_lookup, selected_id )
1461{
1462	if ( possible_option_lookup[ 1 ] == null )
1463	{
1464		this.Disable();
1465		return true;
1466	}
1467
1468	this.Enable();
1469
1470	switch ( selected_id )
1471	{
1472		case 0 :
1473		{
1474			this.last_value		= '';
1475			this.textarea.value	= '';
1476
1477			break;
1478		}
1479		case 1 :
1480		{
1481			if ( this.textarea.value.length == 0 )
1482			{
1483				return false;
1484			}
1485
1486			break;
1487		}
1488	}
1489
1490	return true;
1491}
1492
1493AttributeMachine_Memo.prototype.Selected_Option_ID = function()
1494{
1495	if ( this.textarea.disabled )		return 0;
1496	if ( this.textarea.value.length )	return 1;
1497	else								return 0;
1498}
1499
1500// AttributeMachine_Radio
1501///////////////////////////////////////////////////////////////////
1502
1503function AttributeMachine_Radio( machine, attribute, template_attribute )
1504{
1505	this.machine			= machine;
1506	this.attribute			= attribute;
1507	this.template_attribute	= template_attribute;
1508	this.options			= template_attribute ? template_attribute.options : attribute.options;
1509	this.radios				= new Array();
1510	this.empty_radio		= null;
1511	this.option_lookup		= null;
1512}
1513
1514AttributeMachine_Radio.prototype.Initialize = function( form, elements )
1515{
1516	var self = this;
1517	var i, i_len, j, j_len;
1518
1519	this.radios = new Array();
1520
1521	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1522	{
1523		if ( !elements[ i ].hasAttribute( 'type' ) )		continue;
1524		if ( elements[ i ].type.toLowerCase() !== 'radio' )	continue;
1525
1526		this.radios.push( elements[ i ] );
1527	}
1528
1529	if ( this.radios.length === 0 )
1530	{
1531		return false;
1532	}
1533
1534	// Build an option lookup by ID that correlates to the specific radio <input> element for that option
1535	this.option_lookup = new Array();
1536
1537	for ( i = 0, i_len = this.radios.length; i < i_len; i++ )
1538	{
1539		if ( ( this.radios[ i ].value.length === 0 ) && ( this.empty_radio === null ) )
1540		{
1541			this.empty_radio = this.radios[ i ];
1542		}
1543		else
1544		{
1545			for ( j = 0, j_len = this.options.length; j < j_len; j++ )
1546			{
1547				if ( this.radios[ i ].value == this.options[ j ].code )
1548				{
1549					this.option_lookup[ this.options[ j ].id ] = this.radios[ i ];
1550				}
1551			}
1552		}
1553	}
1554
1555	for ( i = 0, i_len = this.radios.length; i < i_len; i++ )
1556	{
1557		AddEvent( this.radios[ i ], 'click', function()
1558		{
1559			self.machine.Attribute_Changed( self );
1560			return true;
1561		} );
1562	}
1563
1564	return true;
1565}
1566
1567AttributeMachine_Radio.prototype.Disable = function()
1568{
1569	var i;
1570
1571	for ( i = 0; i < this.radios.length; i++ )
1572	{
1573		this.radios[ i ].disabled	= true;
1574		this.radios[ i ].checked	= false;
1575	}
1576
1577	if ( this.empty_radio )
1578	{
1579		this.empty_radio.disabled	= false;
1580		this.empty_radio.checked	= true;
1581	}
1582}
1583
1584AttributeMachine_Radio.prototype.Enable = function()
1585{
1586	var i;
1587
1588	for ( i = 0; i < this.radios.length; i++ )
1589	{
1590		this.radios[ i ].disabled	= false;
1591	}
1592}
1593
1594AttributeMachine_Radio.prototype.Cull = function( possible_option_lookup, selected_id )
1595{
1596	var i;
1597
1598	this.Enable();
1599
1600	for ( i = 0; i < this.options.length; i++ )
1601	{
1602		if ( !possible_option_lookup[ this.options[ i ].id ] )
1603		{
1604			this.option_lookup[ this.options[ i ].id ].disabled	= true;
1605		}
1606	}
1607
1608	if ( selected_id )				this.option_lookup[ selected_id ].checked	= true;
1609	else if ( this.empty_radio )	this.empty_radio.checked					= true;
1610	else
1611	{
1612		for ( i in this.option_lookup )
1613		{
1614			this.option_lookup[ i ].checked	= false;
1615		}
1616
1617		if ( this.template_attribute )
1618		{
1619			if ( this.template_attribute.required )	return false;
1620		}
1621		else if ( this.attribute.required )			return false;
1622	}
1623
1624	return true;
1625}
1626
1627AttributeMachine_Radio.prototype.Selected_Option_ID = function()
1628{
1629	var i, j;
1630
1631	for ( i = 0; i < this.radios.length; i++ )
1632	{
1633		if ( this.radios[ i ].checked && !this.radios[ i ].disabled )
1634		{
1635			for ( j = 0; j < this.options.length; j++ )
1636			{
1637				if ( this.options[ j ].code == this.radios[ i ].value )
1638				{
1639					return this.options[ j ].id;
1640				}
1641			}
1642		}
1643	}
1644
1645	return null;
1646}
1647
1648// AttributeMachine_Select
1649///////////////////////////////////////////////////////////////////
1650
1651function AttributeMachine_Select( machine, attribute, template_attribute )
1652{
1653	this.machine			= machine;
1654	this.attribute			= attribute;
1655	this.template_attribute	= template_attribute;
1656	this.options			= template_attribute ? template_attribute.options : attribute.options;
1657	this.select				= null;
1658	this.option_lookup		= null;
1659	this.empty_option		= null;
1660}
1661
1662AttributeMachine_Select.prototype.Initialize = function( form, elements )
1663{
1664	var self = this;
1665	var i, j, i_len, j_len;
1666
1667	this.select = null;
1668
1669	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1670	{
1671		if ( elements[ i ].nodeName.toLowerCase() !== 'select' )	continue;
1672		if ( elements[ i ].type.toLowerCase() !== 'select-one' )	continue;
1673
1674		this.select = elements[ i ];
1675		break;
1676	}
1677
1678	if ( this.select == null )
1679	{
1680		return false;
1681	}
1682
1683	// Build an option lookup by ID that correlates to the specific <option> element for that option
1684	this.option_lookup = new Array();
1685
1686	for ( i = 0, i_len = this.select.options.length; i < i_len; i++ )
1687	{
1688		if ( this.select.options[ i ].value == '' )
1689		{
1690			this.empty_option = this.select.options[ i ];
1691			continue;
1692		}
1693
1694		for ( j = 0, j_len = this.options.length; j < j_len; j++ )
1695		{
1696			if ( this.select.options[ i ].value == this.options[ j ].code )
1697			{
1698				this.option_lookup[ this.options[ j ].id ] = this.select.options[ i ];
1699			}
1700		}
1701	}
1702
1703	AddEvent( this.select, 'change', function()
1704	{
1705		self.machine.Attribute_Changed( self );
1706		return true;
1707	} );
1708
1709	return true;
1710}
1711
1712AttributeMachine_Select.prototype.Initialize_NonInventory = function( form, elements )
1713{
1714	var i, i_len;
1715
1716	for ( i = 0, i_len = elements.length; i < i_len; i++ )
1717	{
1718		if ( elements[ i ].nodeName.toLowerCase() !== 'select' )	continue;
1719		if ( elements[ i ].type.toLowerCase() !== 'select-one' )	continue;
1720
1721		this.select = elements[ i ];
1722		break;
1723	}
1724}
1725
1726AttributeMachine_Select.prototype.Disable = function()
1727{
1728	this.select.disabled	= true;
1729}
1730
1731AttributeMachine_Select.prototype.Enable = function()
1732{
1733	this.select.disabled	= false;
1734}
1735
1736AttributeMachine_Select.prototype.Cull = function( possible_option_lookup, selected_id )
1737{
1738	var i, option_count, selected_index;
1739
1740	this.select.options.length	= 0;
1741	option_count				= 0;
1742	selected_index				= 0;
1743
1744	if ( this.empty_option )
1745	{
1746		this.select.options[ option_count++ ]		= this.empty_option;
1747	}
1748
1749	for ( i = 0; i < this.options.length; i++ )
1750	{
1751		if ( possible_option_lookup[ this.options[ i ].id ] )
1752		{
1753			if ( this.options[ i ].id == selected_id )
1754			{
1755				selected_index						= option_count;
1756			}
1757
1758			this.select.options[ option_count++ ]	= this.option_lookup[ this.options[ i ].id ];
1759		}
1760	}
1761
1762	this.select.selectedIndex	= selected_index;
1763
1764	if ( this.select.options.length )	this.Enable();
1765	else								this.Disable();
1766
1767	return true;
1768}
1769
1770AttributeMachine_Select.prototype.Selected_Option_ID = function()
1771{
1772	var i;
1773	var selected_code;
1774
1775	if ( this.select.disabled ||
1776		 this.select.selectedIndex < 0 )
1777	{
1778		return null;
1779	}
1780
1781	selected_code = this.select.options[ this.select.selectedIndex ].value;
1782
1783	for ( i = 0; i < this.options.length; i++ )
1784	{
1785		if ( this.options[ i ].code == selected_code )
1786		{
1787			return this.options[ i ].id;
1788		}
1789	}
1790
1791	return null;
1792}
1793
1794// AttributeMachine Swatches
1795///////////////////////////////////////////////////////////////////
1796
1797AttributeMachine.prototype.oninitializeswatches = function( attributes, possible )
1798{
1799	this.Initialize_Swatches( attributes, possible );
1800}
1801
1802AttributeMachine.prototype.onswatchclick = function( input, attribute, option )
1803{
1804	this.Swatch_Click( input, attribute, option );
1805}
1806
1807AttributeMachine.prototype.Initialize_Swatches = function( attributes, possible )
1808{
1809	var self = this;
1810	var i, j;
1811	var possible_lookup;
1812	var attribute, template_attribute, current, swatch, attr_ul, attr_swatch;
1813
1814	if ( !this.Lookup_Attribute_Form() )
1815	{
1816		return;
1817	}
1818
1819	this.swatch_attributes = []
1820
1821	for ( i = 0; i < attributes.length; i++ )
1822	{
1823		if ( attributes[ i ].type === 'template' )
1824		{
1825			for ( j = 0; j < attributes[ i ].attributes.length; j++ )
1826			{
1827				if ( attributes[ i ].attributes[ j ].type === 'swatch-select' )
1828				{
1829					this.swatch_attributes.push( new AttributeMachine_Select( this, attributes[ i ], attributes[ i ].attributes[ j ] ) );
1830					this.swatch_attributes[ this.swatch_attributes.length - 1 ].Initialize_NonInventory( this.form, this.Gather_Form_ProductAttributeElements( attributes[ i ], attributes[ i ].attributes[ j ] ) );
1831				}
1832			}
1833		}
1834		else if ( attributes[ i ].type === 'swatch-select' )
1835		{
1836			this.swatch_attributes.push( new AttributeMachine_Select( this, attributes[ i ], null ) );
1837			this.swatch_attributes[ this.swatch_attributes.length - 1 ].Initialize_NonInventory( this.form, this.Gather_Form_ProductAttributeElements( attributes[ i ], null ) );
1838		}
1839	}
1840
1841	if ( this.swatch_attributes.length === 0 ) return;
1842
1843	if ( this.swatches ) this.Empty_Element( this.swatches );
1844
1845	possible_lookup = ( possible ) ? this.Build_Possible_Lookup( possible.data.attributes ) : null;
1846
1847	for ( i = 0; i < this.swatch_attributes.length; i++ )
1848	{
1849		attribute				= this.swatch_attributes[ i ].attribute;
1850		template_attribute		= this.swatch_attributes[ i ].template_attribute;
1851
1852		current = template_attribute ? template_attribute : attribute;
1853
1854		attr_swatch = this.Find_Attribute_Swatch( current );
1855		if ( attr_swatch ) this.Empty_Element( attr_swatch );
1856
1857		possible_sublookup		= ( possible_lookup ) ? possible_lookup[ attribute.id ] : null;
1858
1859		if ( possible_sublookup )
1860		{
1861			if ( template_attribute )	possible_sublookup	= possible_sublookup[ template_attribute.id ];
1862			else						possible_sublookup	= possible_sublookup[ 0 ];
1863		}
1864
1865		attr_ul					= document.createElement( 'ul' );
1866		attr_ul.style.clear		= 'both';
1867
1868		for ( j = 0; j < current.options.length; j++ )
1869		{
1870			if ( current.inventory && possible_sublookup )
1871			{
1872				if ( !possible_sublookup.options[ current.options[ j ].id ] ) continue;
1873			}
1874
1875			swatch = this.Generate_Swatch( this.settings.product_code, current, current.options[ j ] );
1876
1877			swatch.mm5_input		= this.swatch_attributes[ i ];
1878			swatch.mm5_attribute	= current;
1879			swatch.mm5_option		= current.options[ j ];
1880
1881			AddEvent( swatch, 'click', function()
1882			{ 
1883				var node;
1884
1885				if ( this.mm5_input )		node = this;
1886				else if ( window.event )	node = window.event.srcElement;
1887				else						node = null;
1888
1889				while ( node && !node.mm5_input )
1890				{
1891					node = node.parentNode;
1892				}
1893
1894				if ( node ) self.onswatchclick( node.mm5_input, node.mm5_attribute, node.mm5_option );
1895			} );
1896
1897			if ( attr_swatch )	attr_ul.appendChild( swatch );
1898			else if ( this.swatches )	attr_ul.appendChild( swatch );
1899		}
1900
1901		if ( attr_swatch )	attr_swatch.appendChild( attr_ul );
1902		else if ( this.swatches )	this.swatches.appendChild( attr_ul );
1903	}
1904}
1905
1906AttributeMachine.prototype.Swatch_Click = function( input, attribute, option )
1907{
1908	var i
1909
1910	for ( i = 0; i < input.select.options.length; i++ )
1911	{
1912		if ( input.select.options[ i ].value == option.code )
1913		{
1914			input.select.selectedIndex = i;
1915		}
1916	}					
1917
1918	this.Attribute_Changed( input );
1919}
1920
1921AttributeMachine.prototype.Empty_Element = function( container )
1922{
1923	while( container.hasChildNodes() )
1924	{
1925		container.removeChild( container.lastChild );
1926	}
1927}
1928
1929AttributeMachine.prototype.Find_Attribute_Swatch = function( attribute )
1930{
1931	var selector = this.settings.attribute_swatch_id;
1932
1933	if ( !selector )
1934	{
1935		return null;
1936	}
1937
1938	selector = selector.replace( '%attribute_id%', attribute.id );
1939
1940	return this.getElementById( selector );
1941}

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.