1 /**
  2  * @fileoverview  Sourcemap.Editor: Main component to handle viewing and editing of Sourcemaps.
  3  * @version 0.8
  4  * @author sourcemap@media.mit.edu
  5  * @package sourcemap
  6  * @subpackage js
  7  */
  8 
  9 
 10 /**
 11  * Create a new Sourcemap instance.
 12  * @see  Sourcemap
 13  */
 14 
 15 if (typeof(Sourcemap) == 'undefined' ) {Sourcemap = {}; }
 16 
 17 
 18 /** 
 19 * @namespace Sourcemap Editor
 20 */
 21 Sourcemap.Editor = {
 22     init: function() {
 23 
 24 	/**
 25 	* Triggers edit mode of objects by switching fields and enabling interaction.
 26 	 */
 27 	this.processHashEvent = function(hash) {
 28 		if(hash == "#edit") {
 29 			this.initializeEditMode();
 30 			if(Sourcemap.Template.usechooser) { this.showPartChooser();}
 31 		}			
 32 		else if(hash == "#new") {
 33 			this.initializeEditMode();
 34 			if(Sourcemap.Template.usechooser) { this.showPartChooser();}
 35 			this.initializeTooltips();				    
 36 		}			
 37 	};
 38 	/**
 39 	 * Intialize all the functions
 40 	 * Make all the fields editable 
 41 	 * @see  #setupPartHandlers
 42 	 * @see  #setupEndoflifeHandlers
 43 	 * @see  #setupProcessHandlers
 44 	 */
 45  	this.initializeEditMode = function() {	
 46 	// Make Objects Editable
 47 	    $("#object-name").html('<input class="input-object-name" value="'+$("#object-name").text()+'">'); 
 48 	    $("#object-description").html('<textarea class="input-object-description">'+$("#object-description").html()+'</textarea>');
 49 	    $("#object-origin").html('<input class="input-object-origin" value="'+$("#object-origin").text()+'">');
 50 	    $("#object-destination").html('<input class="input-object-destination" value="'+$("#object-destination").text()+'">');
 51 	    $("#object-via select").removeAttr("disabled");
 52 	    
 53 	    $( "#part-list").addClass("editmode");						    
 54 	    $("div#partlist-shell").css("height","360px");	
 55 	
 56 	    // Make Parts Editable
 57 	    $(".part-name").each(function() { $(this).html('<input class="input-name" value="'+$(this).text()+'">');});
 58 	    $(".part-description").each(function() { $(this).html('<textarea class="input-description">'+$(this).html()+'</textarea>');});	
 59 	    $(".part-weight").each(function() { $(this).html('<input class="input-weight" value="'+$(this).text()+'">');});
 60 	    $(".part-via select").removeAttr("disabled");
 61 	    $(".part-origin").each(function() { $(this).html('<input class="input-origin" value="'+$(this).text()+'">');});
 62 	    $(".part-rawemissions").each(function() { $(this).html('<input class="input-rawemissions" value="'+$(this).text()+'">');});
 63 	    			    			    
 64 	    /**
 65 	     *  Make Process Editable
 66 	     */
 67 
 68 	    $(".process-text").each(function() { 
 69 					$(this).html('<input class="input-process-text" value="'+$(this).text()+'"/>');
 70 				    });
 71 
 72 	    $(".process-area").each(function() { 
 73 			if($(this).parents(".process-details").find("span.process-unit").html() != "kg") {
 74 				$(this).html('<input class="input-process-area" value="'+$(this).text()+'"/>');
 75 			}
 76 		});
 77 
 78 	    $(".process-display").each(function() { 
 79 					   $(this).html('<input class="input-process-display" value="'+$(this).text()+'"/>');
 80 				       });
 81 	    
 82 	    /**
 83 	     * Make Endoflife Editable
 84 	     */
 85 
 86 	    $(".endoflife-display").each(function() { $(this).html('<input class="input-endoflife-display" value="'+$(this).text()+'">');});
 87 	    
 88 	    $(".endoflife-emissions").each(function() { $(this).html('<input class="input-endoflife-emissions" value="'+$(this).text()+'">');});
 89 
 90 
 91 	    /** 
 92 	     * Set handlers to Sourcemap.Object
 93 	     * .change functions call their respective functions in objects.js
 94 	     */
 95 	    
 96 	    $(".input-object-name").change(function() { 
 97 		    objectConfig.setName($(this).val()); $(this).addClass("dirty");
 98 		});
 99 	    $(".input-object-description").change(function() { 
100 		    objectConfig.setDescription($(this).val()); $(this).addClass("dirty");
101 		});
102 	  
103 	    $(".input-object-origin").change(function() { 
104 		    objectConfig.setOrigin($(this).val()); $(this).addClass("dirty");
105 		});
106 	    $(".input-object-destination").change(function() { 
107 		    objectConfig.setDestination($(this).val()); $(this).addClass("dirty");
108 		});
109 	    $("#object-via-select").change(function() { 
110 		    objectConfig.setVia($("#object-via select :selected").text()); $(this).addClass("dirty");
111 		});
112 	    	        			    
113 	    Sourcemap.Editor.setupPartHandlers("");
114             Sourcemap.Editor.setupProcessHandlers("");	    
115 	    Sourcemap.Editor.setupEndoflifeHandlers("");
116 	    Sourcemap.Editor.setupPermissions();	    	    
117 
118 	    /**
119 	     * @name onbeforeunload
120 	     * @function
121 	     */
122 	    window.onbeforeunload = function() { return "You are currently editing a sourcemap and you haven't saved your changes. If you want to save your changes, click the green 'Save Sourcemap' button before you leave."; };	 
123 	    
124 	    $("#permission-button").removeClass("hidden");
125 
126 	    $("li.part-details").addClass("hover");
127 	    $(".part-details .removeaction").css("display","inline");
128 	    
129 	    $('input:checkbox').removeAttr("disabled"); 
130 	    $("#usekwh, #poweruselist, #transportlist").removeAttr("disabled"); 
131 	    $("div#summary-statistics .checkmessage, div#summary-statistics input[type='checkbox']").css("display","inline");
132 	    
133 	    $("#editsourcemapbutton").css("display","none");
134 	    $("#savesourcemapbutton").slideDown();
135 	    $("#addpartbutton, #partlist-menu").slideDown();
136 
137 	    $(".list-expand").text("-");			
138 	    
139 	    /**
140 	     * Auto Complete for part location
141 	     * keyup function sends e as the @param for filterLocate	    
142 	     */
143 	
144 	    $(".part-origin .input-origin").unbind("keyup");
145 	    $(".part-origin .input-origin").keyup(function(e) {
146 						 if(e.keyCode!=40 && e.keyCode != 13  && e.keyCode != 38)  {
147 						     Sourcemap.Editor.filterLocate(e);
148 						 }
149 	});
150 	    
151   	};
152 
153 	/**
154 	 *  Display all the locations for the part
155 	 *  Do an ajax call to get all the locations of a part
156 	 */
157 
158 	$(".list").unbind("click");
159 	$(".list").click(function(e) {
160 			     var part_locate ="";
161 			     var part_location_id = parseInt($(e.target).parents(".part-details").attr("id"));
162 			     var part_location_name = objectConfig.parts[part_location_id].name;
163 			     var saveData = { part_location: part_locate,
164 					      name: part_location_name };
165 			     
166 			     var sendData = "data=" + JSON.stringify(saveData) + "";
167 			     $.post(Sourcemap.siteurl+"parts/getPartLocations", sendData, function(response) {
168 					var part_locations = eval(response);
169 					$(".ac_results").remove();
170 					
171 					// create a div and as a child to the parent of the input field (use append)	       
172 					var locate = $("li#"+part_location_id+".part-details .part-origin");
173 					locate.append('<div class="ac_results"><ul>');
174 					$.each(part_locations, function(i,e) {
175 						   // create one <li>location</li> per location inside div
176 						   $(".ac_results ul").append('<li>'+e.displaylocation+'</li>');
177 						   
178 					       });
179 					locate.append('</ul></div>');
180 					
181 					Sourcemap.Editor.hoverLocate(locate.find("input.input-origin"));
182 					
183 				    });
184 			     
185 			 });
186 	
187 	/**
188 	 * To autocomplete the location in the input field by hover over function
189 	 * @param target. This is a classname where the location has to be display
190 	 */
191 	this.hoverLocate = function(target) {
192 	    $(target).parent().find(".ac_results ul li").hover(
193 		function(event) {
194 		    $(event.target).css('background', 'red');
195 		    $(target).val($(event.target).html());
196 		},
197 		function(event) {
198 		    $(event.target).css('background', '');
199 		});	     
200 	};
201 
202 
203 	/**
204 	 * Do the ajax call to the server to get the locations
205 	 * Display them in the part-origin input field
206 	 * With keydown/keyup, different locations can be selected
207 	 * @param e, this is the target element
208 	 * @see  #hoverLocate 
209 	 */
210  	this.filterLocate = function(e) {
211 	    
212 	    var part_locations_display = Array();
213 	    var part_location_id = parseInt($(e.target).parents(".part-details").attr("id"));
214 	    var part_location_name = objectConfig.parts[part_location_id].name;
215 	    var filterPartLocate = $(e.target).val();
216 	    var saveData = { part_location: filterPartLocate,
217 			     name: part_location_name };
218 	    
219 	    var sendData = "data=" + JSON.stringify(saveData) + "";
220 	    $.post(Sourcemap.siteurl+"parts/getPartLocations", sendData, function(response) {
221                        var part_locations = eval(response);
222 		       $(".ac_results").remove();
223 		       
224 		       // create a div and as a child to the parent of the input field (use append)	       
225 		       $(e.target).parent().append('<div class="ac_results"><ul>');
226 		       $.each(part_locations, function(i,e) {
227 				  // create one <li>location</li> per location inside div
228 				  $(".ac_results ul").append('<li>'+e.displaylocation+'</li>');
229 				  part_locations_display = e.displaylocation;
230 			      });
231 		       $(e.target).parent().append('</ul></div>');
232 		       Sourcemap.Editor.hoverLocate(e.target);
233 		   });
234 	    
235 	    var currentSelection = null;
236 	    
237 		
238 
239 		$(e.target).unbind("keydown");
240 		$(e.target).keydown(function(event) {
241 					var target = $(e.target);
242 					var ac = target.parent().find('.ac_results');
243 								
244 					if(ac.length == 0 ) { return; }
245 					if(event.keyCode==40) {
246 					    if(currentSelection==null) {
247 						currentSelection = ac.find("li")[0];
248 					    } else { 
249 						$(currentSelection).css('background', '');
250 						currentSelection = $(currentSelection).next();
251 						if(currentSelection.length == 0) {
252 						    currentSelection = ac.find("li")[0];
253 						} else {
254 						    currentSelection = currentSelection[0];
255 						}
256 					}
257 					    
258 					    $(currentSelection).css('background', 'red');  
259 					 					    
260 					} else if(event.keyCode==38) {
261 					 
262 					    if(currentSelection==null) {
263 						currentSelection = ac.find("li")[ac.find("li").length-1];
264 					    } else {
265 						$(currentSelection).css('background', '');
266 						currentSelection = $(currentSelection).prev();
267 						if(currentSelection.length == 0) {
268 						    currentSelection = ac.find("li")[ac.find("li").length-1];
269 						} else {
270 						    currentSelection = currentSelection[0];
271 						}
272 					    }
273 					    $(currentSelection).css('background', 'red');
274 					    
275 				    } else if(event.keyCode==13) {
276 					target.val($(currentSelection).html());
277 				    }
278 				    });
279 		
280 	};
281 	
282 	/**
283 	 * Enable accordion
284 	 */
285 	$("#summary-statistics").accordion();
286 
287 
288 
289         /**
290 	 * Stop all the functions which were enabled in edit mode.
291 	 * The fields are not editable and are all hidden
292 	 */	
293 	this.stopEditMode = function() {	
294 	    $(".qTip").remove();
295 	    window.location.hash = "#";
296     
297 	    $( "#ajaxnote" ).text("Saving Object..."); // TODO should become notes area.
298 	    $( "#part-list").removeClass("editmode");
299 	    
300 	    $("#permission-button").addClass("hidden");
301 	    $("#permission-panel").css("display","none");
302 	    
303 	    Sourcemap.Editor.closePartChooser();
304 	    
305 	    objectConfig.recalculateObjectValues();	
306 	    objectConfig.save();
307 	    
308 	    $(".list-expand").text("+");
309 	    $(".list-expand").parents(".part-details").removeClass("hover");
310 	    
311 	    
312 	    // Add input switch to unedit object
313 	    $(".input-object-name").each(function() { $(this).replaceWith($(this).val());});		
314 	    $(".input-object-description").each(function() { $(this).replaceWith(Sourcemap.Util.rhtmlspecialchars($(this).val()));});			
315 	    $(".input-object-permissions").each(function() { $(this).replaceWith($(this).val());});		
316 	    $(".input-object-origin").each(function() { $(this).replaceWith($(this).val());});		
317 	    $(".input-object-destination").each(function() { $(this).replaceWith($(this).val());});
318 	    
319 	    $(".input-object-via").attr("disabled", "disabled"); $(".input-object-via").removeClass("dirty");
320 	    $(".input-object-lifetime").each(function() { $(this).replaceWith($(this).val());});
321 	    
322 	    // Add input switch to unedit parts	
323 	    $(".input-name").each(function() { $(this).replaceWith($(this).val());});
324 	    $(".input-description").each(function() { $(this).replaceWith(Sourcemap.Util.rhtmlspecialchars($(this).val()));});
325 	    $(".input-weight").each(function() { $(this).replaceWith($(this).val());});
326 	    $(".input-via").attr("disabled", "disabled"); $(".input-via").removeClass("dirty");	
327 	    $(".input-origin").each(function() { $(this).replaceWith($(this).val());});
328 	    $(".input-rawemissions").each(function() { $(this).replaceWith($(this).val());});
329 	    
330 	    $(".part-details .removeaction").css("display","none");
331 	    
332 	    // Add input switch to unedit process
333 	    $(".input-process-text").each(function() { $(this).replaceWith($(this).val());
334 						     });          
335 	    $(".input-process-area").each(function() { $(this).replaceWith($(this).val());
336 						     });          
337 	    $(".input-process-display").each(function() { $(this).replaceWith($(this).val());
338 						     });          
339 
340 	    //Add input switch to unedit endoflife
341 	    $(".input-endoflife-display").each(function() { $(this).replaceWith($(this).val());
342 							  });          
343 	    $(".input-endoflife-emissions").each(function() { $(this).replaceWith($(this).val());
344 						     });          
345 	    
346 	    
347 	    // Add capability to create parts
348 	    $("#private-button").unbind("click");
349 	    $("#editsourcemapbutton").slideDown();
350 	    $("#savesourcemapbutton").css("display","none");
351 	    $("#addpartbutton, #partlist-menu").css("display","none");
352 	    $("div#summary-statistics .checkmessage, div#summary-statistics input[type='checkbox']").css("display","none");		
353 	    $("div#partlist-shell").css("height","385px");
354 	    $('#partchooser-visualization').css("display","none");
355 	    $("input:checkbox").attr("disabled","true");
356 	    $("#usekwh, #poweruselist").attr("disabled", "true"); 
357 	};
358 
359 
360 	/**
361 	 * Call a function in the objects.js to add a process
362 	 * @param target_element, it is the location where the add process
363 	 * button is located.
364 	 * @see  #getProcessesForPart
365 	 */
366 	this.addProcessPart = function(target_element){
367 
368 	    var part_id = parseInt($(target_element).parents(".part-details").attr("id"));
369 	    var process_id = parseInt($(target_element).parents(".part-details").find(".process-details").attr("id"));
370 	    Sourcemap.Editor.getProcessesForPart(part_id, process_id, target_element);
371 	    $("li#"+part_id+" .add-process").css("display","block");
372 	  };
373 
374 
375 
376 	/**
377 	 * Call a function in the objects.js to ass an endoflife for a part
378 	 * @param target_element, it is the location where add endoflife button
379 	 * is located 
380 	 * @see  #getEndoflifeForPart
381 	 */
382 
383 	this.addEndoflifePart = function(target_element) {
384             var part_id = parseInt($(target_element).parents(".part-details").attr("id"));
385 	    var endoflife_id = parseInt($(target_element).parents(".part-details").find(".endoflife-details").attr("id"));
386 	    Sourcemap.Editor.getEndoflifeForPart(part_id, endoflife_id, target_element);	    
387 	    $("li"+part_id+" .add-endoflife").css("display", "block");
388 	};
389 	
390 	
391 	/**
392 	 * Setup handlers for a part
393 	 * @param specifier, this points to "li #id"
394 	 * Call the associated function in objects.js for every change function
395 	 * @see  #intializeEditMode
396 	 */
397 	this.setupPartHandlers = function(specifier) {
398 	    // Set part handlers to Sourcemap.Object
399 	    
400 	    $(specifier + ".input-name").change(function() {
401 						    objectConfig.setPartName(parseInt($(this).parents(".part-details").attr("id")), $(this).val()); 
402 						    $(this).addClass("dirty");
403 						});
404 	    $(specifier + ".input-description").change(function() {
405 							   objectConfig.setPartDescription(parseInt($(this).parents(".part-details").attr("id")), $(this).val()); 
406 							   $(this).addClass("dirty");
407 						       });
408 	    $(specifier + ".input-weight").change(function() {
409 						      objectConfig.setPartWeight(parseInt($(this).parents(".part-details").attr("id")), $(this).val()); 
410 						      $(this).addClass("dirty");
411 						  });
412 	    $(specifier + ".input-via").change(function() {
413 						   objectConfig.setPartVia(parseInt($(this).parents(".part-details").attr("id")), $(this).val(), $(this).children(":selected").text()); 
414 						   $(this).addClass("dirty");
415 					       });
416 	    $(specifier + ".input-origin").change(function() {
417 						      objectConfig.setPartOrigin(parseInt($(this).parents(".part-details").attr("id")), $(this).val(), true); 
418 						      $(this).addClass("dirty");
419 						  });
420 	    $(specifier + ".input-rawemissions").change(function() {
421 							    objectConfig.setPartRawEmissions(parseInt($(this).parents(".part-details").attr("id")), $(this).val()); 
422 							    $(this).addClass("dirty");
423 							});
424 	    $(specifier + ".removeaction").click(function() {
425 						     objectConfig.removePart(parseInt($(this).parents(".part-details").attr("id")));
426 						 });
427 	};
428 	
429 
430 	/**
431 	 * Setup handlers for process
432 	 * @param specifier, this points to "li .part-details #id"
433 	 * Call the associated function in objects.js for every change function
434 	 * @see  #intializeEditMode
435 	 */
436 	this.setupProcessHandlers = function(specifier) {
437             
438 	    $(".add-process").unbind("click");
439 	    $(".add-process").click(function(e){
440 					Sourcemap.Editor.addProcessPart(e.target);                        							     
441 				    });
442 	    
443 	    
444 	    $(specifier + ".input-process-area").change(function(){
445 		process_id =parseInt($(this).parents(".process-details").attr("id"));	
446          		var part_id = parseInt($(this).parents(".part-details").attr("id"));
447 			objectConfig.setProcessFactor(part_id, process_id, $(this).val(), 1);
448 		});
449 
450 	    $(specifier + ".input-process-text").change(function(){
451 			process_id =parseInt($(this).parents(".process-details").attr("id"));
452 			var part_id = parseInt($(this).parents(".part-details").attr("id"));
453 			objectConfig.addProcessEmissions(part_id, process_id, $(this).val());
454 		});
455 
456 	    $(specifier + ".input-process-display").change(function(){
457 			process_id =parseInt($(this).parents(".process-details").attr("id"));
458 			var part_id = parseInt($(this).parents(".part-details").attr("id"));
459 			objectConfig.setProcessName(part_id, process_id, $(this).val());		   
460 		});
461 
462 	    $(specifier + ".process-unit").change(function(){
463 			process_id =parseInt($(this).parents(".process-details").attr("id"));
464 			var part_id = parseInt($(this).parents(".part-details").attr("id"));
465 			objectConfig.addProcessUnit(part_id, process_id, $(this).val());		   
466 		});
467 
468 	    $(specifier + "span.removeprocessaction").click(function(){
469 			process_id =parseInt($(this).parents(".process-details").attr("id"));
470 			var part_id = parseInt($(this).parents(".part-details").attr("id"));
471 			flag = true;
472 			objectConfig.removeProcess(part_id, process_id, flag);						   
473 		});	   
474 
475  
476  	    
477 	};
478 
479 
480 	/**
481 	 * Setup handlers for endoflife
482 	 * @param specifier, this points to "li .part-details #id"
483 	 * Call the associated function in objects.js for every change function
484 	 * @see  #intializeEditMode
485 	 */
486 
487 	this.setupEndoflifeHandlers = function(specifier) {
488 	    $(".add-endoflife").unbind("click");
489 	    $(".add-endoflife").click(function(e) {
490 					  Sourcemap.Editor.addEndoflifePart(e.target);
491 				      });
492 	    
493 	    
494 	    $(specifier + ".input-endoflife-emissions").change(function(){
495 			endoflife_id =parseInt($(this).parents(".endoflife-details").attr("id"));
496 			var partId = parseInt($(this).parents(".part-details").attr("id"));
497 			objectConfig.addEndoflifeEmissions(partId, endoflife_id, $(this).val());
498 		});
499 
500 	    $(specifier + ".input-endoflife-display").change(function(){
501 			endoflife_id =parseInt($(this).parents(".endoflife-details").attr("id"));
502 			var partId = parseInt($(this).parents(".part-details").attr("id"));
503 			objectConfig.setEndoflifeType(partId, endoflife_id, $(this).val());
504 		});	    
505 
506 	    $(specifier + "span.removeendoflifeaction").click(function(){						
507 		        var id = parseInt($(this).parents(".part-details").attr("id"));
508 		        var endoflife_id = parseInt($(this).parents(".endoflife-details").attr("id"));
509 	                flag = true;
510 
511 		        objectConfig.removeEndoflife(id, endoflife_id, flag);
512 	       });
513 
514 	};
515 	
516 
517 	/**
518 	 * Get the value part-punch 
519 	 * @param id, part id
520 	 * Calculate totalval
521 	 */
522 
523 	this.updatePartPunch = function(id) {		
524 	    var selectpunch = "#"+id+".part-details .part-punch-totalemissions";			    
525 	    var embodiedpunch = "#"+id+".part-details .part-punch-emissions";
526 	    var transportpunch = "#"+id+".part-details .part-punch-transportemissions";
527 	    var processpunch = "#"+id+".part-details .part-punch-processemissions";
528 	    var endoflifepunch = "#"+id+".part-details . part-punch-endoflifeemissions";
529 	    var embodiedval = $(embodiedpunch).text();
530 	    var transportval = $(transportpunch).text();
531 	    var processval = $(processpunch).text();
532 	    var endoflifeval = $(endoflifepunch).text();
533 	    if(objectConfig.showembodied == "") { embodiedval = 0;}
534 	    if(objectConfig.showtransport == "") { transportval = 0;}
535 	    var totalval = Sourcemap.Util.roundIt(Number(embodiedval) + Number(transportval) + Number(processval),2);
536 	    $(selectpunch).text("" + totalval);
537 	    if(objectConfig.showprocess == "") { processval =0;}
538 	    if(objectConfig.showendoflife == "") { endoflifeval =0;}
539 	};
540 	
541 	/**
542 	 *  Receipt Toggle function for EmbodiedDisplay
543 	 * TransportDisplay, ProcessDisplay, EndoflifeDisplay
544 	 */
545 	this.toggleEmbodiedDisplay = function() {
546 	    if(objectConfig.showembodied == "on" && Sourcemap.Template.useembodied) { $(".part-rawemissions, .part-punch-emissions").css("display", "inline");}
547 	    else { $(".part-rawemissions, .part-punch-emissions").css("display", "none");}
548 	};
549 	
550 	this.toggleTransportDisplay = function() {
551 		if(objectConfig.showtransport == "on") { $(".part-shipping, .part-transport, .part-via, .part-punch-transportemissions").css("display", "inline");}
552 		else { $(".part-shipping, .part-transport, .part-via, .part-punch-transportemissions").css("display", "none");}
553 	};
554 
555 	this.toggleProcessDisplay = function() {
556 		if(objectConfig.showprocess =="on") { $(".add-process, .process-appearance-super, processemissions-punch-value").css("display", "inline"); }
557 		else { $(".add-process, .process-appearance-super, processemissions-punch-value").css("display", "none"); }
558 	};
559               
560 	this.toggleEndoflifeDisplay = function () {
561 		if(objectConfig.showendoflife == "on") { $(".add-endoflife, .endoflife-appearance-super, endoflifeemissions-punch-value").css("display", "inline"); }
562 		else { $(".add-endoflife, .endoflife-appearance-super, endoflifeemissions-punch-value").css("display", "none"); }
563 	}; 
564 	
565 	/**
566 	 *  Currently unused
567 	 */
568 	this.initializeTooltips = function() {
569 	    $('.input-object-name').qtip({ content: '<div class="number">1</div>What is the name of your Sourcemap?', show: { when: false, ready: true }, hide: 'focus', position: { corner: { target: 'leftTop', tooltip: 'bottomLeft' } }, style: { width:540, 'font-size': 16, tip: 'bottomLeft', border: { width: 3, radius: 8, color: '#f9e98e' }, background: '#fbf7aa', 'font-weight': 'bold', color: '#000' } });
570 	    
571 	    $('.input-object-origin').qtip({ content: '<div class="number">2</div> What is the location?', show: { when: false, ready: true }, hide: 'focus', position: { corner: { target: 'rightMiddle', tooltip: 'topLeft' } }, style: { width:240, tip: 'topLeft', border: { width: 1, radius: 8, color: '#f9e98e' }, 'font-size': 12, background: '#fbf7aa', color: '#000' } });
572 	    
573 	    $('.input-object-description').qtip({ content: '<div class="number">3</div>You can add a description here, some html is ok.', show: { when: false, ready: true }, hide: 'focus', position: { corner: { target: 'bottomMiddle', tooltip: 'topMiddle' } }, style: { width:340, tip: 'topMiddle', border: { width: 1, radius: 8, color: '#f9e98e' }, 'font-size': 12, background: '#fbf7aa', color: '#000'} }); 
574 	};
575 
576 	
577 	/**
578 	 *  Partlist visualization
579 	 */
580 	this.partHighlight = function(id) {
581 	    $('#partlist-shell').scrollTo($("#"+id), 200, {offset:-10});
582 	    
583 	    $("#"+id+" .part-summary").css("background-color", "#ffffcc");
584 	    $("#"+id+" .part-summary").css("border-color", "#ffaa00");
585 	    $("#"+id).css("background-color", "#ffffcc");
586 	    $("#"+id).css("border-color", "#ffaa00");	    
587 	    $("#"+id+" .part-actions").css("background-color", "#ffaa00");
588 	    
589 	    $("#"+id+" .part-summary").animate({ backgroundColor: "#eeeeee", borderBottomColor: "#cccccc", borderTopColor: "#cccccc", borderLeftColor: "#cccccc", borderRightColor: "#cccccc"}, 3000 );
590 	    $("#"+id+" .part-summary").animate({ backgroundColor: "#eeeeee", borderBottomColor: "#cccccc", borderTopColor: "#cccccc", borderLeftColor: "#cccccc", borderRightColor: "#cccccc"}, 3000 );
591 	    $("#"+id).animate({ backgroundColor: "#eeeeee", borderBottomColor: "#cccccc", borderTopColor: "#cccccc", borderLeftColor: "#cccccc", borderRightColor: "#cccccc"}, 3000 );
592 	    $("#"+id).animate({ backgroundColor: "#f5f5f5", borderBottomColor: "#cccccc", borderTopColor: "#cccccc", borderLeftColor: "#cccccc", borderRightColor: "#cccccc"}, 3000 );
593 	    
594 	    $("#"+id+" .part-actions").animate({ backgroundColor: "#cccccc"}, 3000);	
595 	    
596 	    $("#"+id+".part-details").addClass("hover");
597 	    $("#"+id+" .list-expand").text("-"); 				
598 	};
599 	
600 	/**
601 	 * partlist visualization
602 	 */
603 	
604 	this.showPartChooser = function() {
605 	    SMap.clearPopup();
606 	    $('#partlist-shell, #partlist-menu').css("display","none");					
607 	    $("#part-shell, #part-visualization").css("width","125px");				
608 	    $('#partchooser-visualization').css("display", "block");
609 	    $("#partchooser-visualization .visualization-close-button").click(function() {Sourcemap.Editor.closePartChooser();});
610 	    $("#partlist-close-button").unbind("click");
611 	    $("#partlist-close-button").click(function() {
612 		    Sourcemap.Editor.closePartChooser();
613 		});			    			    
614 	};
615 	
616 	this.closePartChooser = function() {
617 	    $("#part-shell, #part-visualization").css("width", "540px"),
618 	    $('#partlist-menu').css("display","block");					
619 	    $('#partlist-shell').css("display","block"); 
620 	    $('#partchooser-visualization').css("display","none");	
621 	    $("#partlist-close-button").unbind("click");	
622 	    $("#partlist-close-button").click( function() { 
623 		    $("#part-visualization ").css("display", "none");
624 		});	
625 	};
626 	
627 	/**
628 	 *  protopart definition
629 	 */
630 	this.protoPart = $.template('<li class="part-details hover" id="${pid}"><div class="part-actions"><span class="removeaction" style="display:inline">x</span>  <span class="list-expand">-</span></div><div class="list-legend">${legend}</div><ul class="part-summary"><li class="part-name">${plinkstart}<input class="input-name" value="${pname}">${plinkfinish}</li><li class="part-origin"><input class="input-origin" value="${porigin}"></li><li class="part-weight"><input class="input-weight" value="0"></li><span class="unit"><span class="part-punch-totalemissions">0</span></span><div style="clear:both;"></div></ul><div style="clear:both;"></div><ul class="part-properties"><li class="part-rawemissions"><input class="input-rawemissions" value="${pemissions}"></li><li class="part-punch-emissions">0</li><div style="clear:both;"></div><li class="part-shipping">0</li><li class="part-via">${pvia}</li><li class="part-punch-transportemissions">0</li></ul><div style="clear:both;"></div><div class="part-description"><textarea class="input-description">${pdescription}</textarea></div><div class="add-process"><select name="Processes" class="process-selected"></select></div><div class="process-appearance-super" style="display:block"><div class="process-details"></div></div><div class="part-punch-processemissions"></div>  <div class="add-endoflife"><select name="Endoflife" class="endoflife-selected"><option value=""></option></select></div><div class="endoflife-appearance-super" style="display:block"><div class="part-punch-endoflifeemissions"></div></div></li></div>');
631 	
632 	/** 
633 	 *  Event callbacks
634 	 */
635 	this.receiveDescriptionChange = function(description) {
636 	    $(".input-object-description").val(description);
637 	};	
638 	
639 
640 	/**
641 	 * Display the part using protoPart definition
642 	 * @param part id, name, description, emissions, link
643 	 * Call the setup handlers for process and endoflife
644 	 */
645 	this.receiveAddedPart = function(id, name, description, emissions, link) {	
646 	    $(".qtip").remove();
647 	    Sourcemap.Editor.closePartChooser();
648 	 	var linkurl =  Sourcemap.siteurl+link;
649 		if(linkurl != Sourcemap.siteurl) { var linkstart = '<a href="'+linkurl+'">'; var linkfinish = '</a>'; }
650 		else { var linkstart = ''; var linkfinish = '';}
651 
652 	    $("#part-list").append( Sourcemap.Editor.protoPart , {
653 		    pid: id,
654 		    legend:id+1,
655 		    plinkstart:linkstart,
656 		    plinkfinish:linkfinish,
657 		    pname: name,
658 		    porigin: Sourcemap.Template.partlocationstubname,
659 		    pemissions: emissions,
660 		    pvia: $("#object-via").html(),
661 		    pdescription: description
662 		});
663 
664 	    Sourcemap.Editor.addProcessPart($("li.#"+id+" .add-process"));
665 	    Sourcemap.Editor.addEndoflifePart($("li.#"+id+" .add-endoflife"));
666 	    Sourcemap.Editor.setupProcessHandlers("li.#"+id+" ");
667 	    Sourcemap.Editor.setupEndoflifeHandlers("li.#"+id+" ");
668 	
669 	    Sourcemap.Editor.setupPartHandlers("#"+id+" ");
670 	    if(	$('#part-visualization').css("display") == "none") {
671 		$('#part-visualization').css("display", "block");
672 	    }
673 	    $('#partlist-shell').scrollTo("max");	
674 		Sourcemap.Editor.partHighlight(id);
675 		
676 		$(".list-expand").bind("click", function() { 
677 			$(this).parents(".part-details").toggleClass("hover");
678 			if($(this).text() == "+") { $(this).text("-"); } else { $(this).text("+"); }
679 		});	
680 	};
681 	
682 	/**
683 	 * remove button visualization
684 	 * @param id, part id 
685 	 */
686 	this.receiveRemovedPart = function(id) {
687 		if(id == 0) { $(".part-details:first").remove(); } else {$("#"+id+".part-details").remove();}			    
688 	};
689 	
690 
691 	/**
692 	 * TODO Actually only the receipt cares about this...
693 	 */
694 	this.receiveObjectTotals = function(emissions, embodied, transport, shipping, weight, processTotal, endoflifeTotal) {
695 	    $("#object-emissions").text(Sourcemap.Util.roundIt(Number(emissions),2));
696 	    $("#embodiedemissions-punch-value").text(Sourcemap.Util.roundIt(Number(embodied),2));
697 	    $("#transportemissions-punch-value").text(Sourcemap.Util.roundIt(Number(transport),2));
698 	    $("#object-shipping").text(Sourcemap.Util.roundIt(Number(shipping),2));
699 	    $("#object-weight").text(Sourcemap.Util.roundIt(Number(weight),2));		
700 	    $("#processemissions-punch-value").text(Sourcemap.Util.roundIt(Number(processTotal),2));		
701 	    $("#endoflifeemissions-punch-value").text(Sourcemap.Util.roundIt(Number(endoflifeTotal),2));		
702 	    
703 	    for ( var part in objectConfig.parts ) { Sourcemap.Editor.updatePartPunch(part);}
704 	};
705 	
706 
707 	/**
708 	 * Callback functions
709 	 */
710 	this.receiveGeocodeError = function(element) {
711 	    $(element).parent().qtip({ content: "We couldn't find this location...", show: { when: false, ready: true }, hide: 'click', position: { corner: { target: 'topMiddle', tooltip: 'bottomMiddle' } }, style: { width:340, 'font-size': 16, tip: 'bottomMiddle', border: { width: 3, radius: 8, color: 'red' }, background: 'red', 'font-weight': 'bold', color: 'white'} });			    
712 	    setTimeout(function(){  $(".qtip:last").fadeOut("normal", function() {$(this).remove(); }); }, 2000);
713 	};
714 	
715 	this.receiveGeocodeMessage = function(element, address) {
716 	    $(element).val(address);
717 	    $(element).parent().qtip({ content: "We think you meant " + address + ".", show: { when: false, ready: true }, hide: 'click', position: { corner: { target: 'topMiddle', tooltip: 'bottomMiddle' } }, style: { width:340, 'font-size': 16, tip: 'bottomMiddle', border: { width: 3, radius: 8, color: '#f9e98e' }, background: '#fbf7aa', 'font-weight': 'bold',
718 color: '#000'} });			    
719 	    setTimeout(function(){  $(".qtip:last").fadeOut("normal", function() {$(this).remove(); }); }, 2000);
720 	};
721 	
722 	this.receiveSaveConfirmation = function(data) {
723 	    $( "#ajaxnote" ).text("");
724 	    window.onbeforeunload = null;
725 	    
726 	    if(data == "added") { 
727 		window.location.href = Sourcemap.siteurl+objectConfig.type+'/' + objectConfig.slug+"#edit";
728 	    }
729 	
730 		SMap.clearPopup();
731 		SMap.objectsummary = objectConfig;
732 		
733 		SMap.refreshMap();
734 	};
735 	
736 	/**
737 	 * protoEndoflife definition               
738 	 */
739 	this.protoEndoflife = $.template('<div class="endoflife-details" id="${id}"><input class="input-endoflife-display" value="${endoflife_type}"> <input class="input-endoflife-emissions" value="${emissions}"> <span class="endoflife-unit">${endoflife_unit}</span> <span class="process-carbon"></span> <span class="removeendoflifeaction">x</span></div>');
740 
741 	
742 	/**
743 	 * Display the endoflife using protoEndoflife definition
744 	 * @param partId, endlifelife_id, endoflife_type, emissions, unit
745 	 *  Call the setup handlers for endoflife
746 	 */
747 	this.receiveAddedEndoflife = function(partId, endoflife_id, endoflife_type, emissions, unit) {
748             var endoflifeId = endoflife_id;
749 	    $("#"+partId+".part-details .endoflife-appearance-super").append(Sourcemap.Editor.protoEndoflife, {
750 			part_id: partId,
751 			id: endoflife_id,
752 			endoflife_type: endoflife_type,
753 			emissions: emissions,
754 			endoflife_unit: unit
755 		});
756 
757 	    if(endoflife_type == "reuse") {
758 		var children = $("#"+partId+".part-details .endoflife-appearance-super").children();
759 		$(children[children.length-1]).find(".input-endoflife-emissions").hide();
760 		$(children[children.length-2]).find(".endoflife-unit").hide();
761 		
762 	    }
763 
764 	    Sourcemap.Editor.setupEndoflifeHandlers("li.#"+partId+" ");
765 	
766 	};
767              
768 	/**
769 	 *  protoProcess definition	
770 	 */
771 
772 	this.protoProcess = $.template('<div class="process-details" id="${id}"><span class="process-display"><input class="input-process-display" value="${process_name}"></span><span class="process-text"><input class="input-process-text" value="${process_emissions}"></span> <span class="process-area"><input class="input-process-area" value="${process_factor}"></span><span class="process-unit">${process_unit}</span> <span class="process-carbon"></span> <span class="removeprocessaction">x</span></div>');
773 
774 
775         /**
776 	 * Display the endoflife using protoEndoflife definition
777 	 * @param partId, endlifelife_id, endoflife_type, emissions, unit
778 	 *  Call the setup handlers for endoflife
779 	 */    
780 	this.receiveAddedProcess = function (part_id, process_id, name, emissions, unit, flag, factor, check){
781  	    var proc_id = process_id;
782 
783 	    $("#"+part_id+".part-details .process-appearance-super").append(Sourcemap.Editor.protoProcess,  {
784 			part_id: part_id,
785 			id: process_id,
786 			process_name: name,
787 			process_emissions: emissions,
788 			process_unit: unit,
789 			process_factor: factor
790 		});
791 	   
792 	    if(unit == "kg") {
793 			var children = $("#"+part_id+".part-details .process-appearance-super").children();
794 			$(children[children.length-1]).find(".input-process-area").hide();
795 	    }
796 
797 	    Sourcemap.Editor.setupProcessHandlers("li.#"+part_id+" ");
798 	
799 	};
800 
801 	
802 	/**
803 	 * process and endoflife functions to do the visualizations
804 	 */
805 	this.receiveEndoflifeType = function(partId, id, type) {
806 		$("#"+id+".endoflife-details .input-endoflife-display").val(Sourcemap.Util.utf8decode(type));  
807 	};
808 
809 	this.receiveEndoflifeEmissions = function(partId, id, emissions) {
810 		$("#"+id+".endoflife-details .input-endoflife-emissions").val(Sourcemap.Util.utf8decode(emissions));  
811 	};
812 
813 	this.receiveRemovedEndoflife = function(id, endoflife_id) {
814 	    if(endoflife_id == 0) { $("div.endoflife-details:first").remove(); } 
815 	    else { $("#"+id+".part-details div#"+endoflife_id+".endoflife-details").remove();}			    	    
816 	};
817 
818 	this.receiveProcessNameChange = function(id, process_name) {
819 		$("#"+id+".process-details .input-process-display").val(Sourcemap.Util.utf8decode(process_name));  
820 	};
821 
822 	this.receiveProcessEmissionsChange = function(id, emissions) {
823 		$("#"+id+".process-details .input-process-text").text(Sourcemap.Util.roundIt(Number(emissions),2));  
824 	};
825 
826 	this.receiveProcessUnitChange = function(id, unit) {
827 		$("#"+id+".process-details .process-unit").val(Sourcemap.Util.utf8decode(unit));  
828 	};
829 
830 	this.receiveProcessFlagChange = function(id, flag) {
831 		$("#"+id+".flag").val(Sourcemap.Util.utf8decode(flag));  
832 	};
833 
834 	this.receiveProcessFactorChange = function(id, factor, check) {
835 		if (check ==1) {		
836 			$("#"+id+".process-details .input-process-area").val(Sourcemap.Util.utf8decode(factor));  
837 		}
838 	};
839 	
840 	this.receiveRemovedProcess = function(id, process_id) {
841 		if(process_id == 0) { $("div.process-details:first").remove(); } 
842 		else { $("#"+id+".part-details div#"+process_id+".process-details").remove();}			    	    
843 	};
844 
845     /**
846      *  part functions to do visualization
847      */
848 	this.receivePartTotalsChanged = function(id) {
849 		Sourcemap.Editor.updatePartPunch(id);
850 	};
851 	
852 	this.receivePartNameChange = function(id, name) {
853 		$("#"+id+" .input-name").val(Sourcemap.Util.utf8decode(name));
854 	};
855 	
856 	this.receivePartDescriptionChange = function(id, description) {
857 		$("#"+id+" .input-description").val(Sourcemap.Util.utf8decode(description));
858 	};
859 	
860 	this.receivePartWeightChange = function(id, weight) {
861 		$("#"+id+" .input-weight").val(Number(weight));	
862 	};
863 	this.receivePartShippingChange = function(id, shipping) {
864 		$("#"+id+" .part-shipping").text(Sourcemap.Util.roundIt(Number(shipping),2));	
865 	};		
866 	this.receivePartEmissionsChange = function(id, emissions) {
867 		$("#"+id+" .part-punch-emissions").text(Sourcemap.Util.roundIt(Number(emissions),2));		
868 	};
869 	this.receievePartRawEmissionsChange = function(id, rawemissions) {
870 		$( "#"+id+" .part-rawemissions").val(Sourcemap.Util.roundIt(Number(rawemissions),2));
871 	};
872 	this.receivePartTransportEmissionsChange = function(id, transportemissions) {	
873 		$( "#"+id+" .part-punch-transportemissions").text("" + Sourcemap.Util.roundIt(Number(objectConfig.parts[id].shipping * (objectConfig.parts[id].weight/1000) * transportemissions),2));
874 	};
875 	this.receivePartViaChange = function(id, via) {
876 		$( "#"+id+" .input-via").val(via);	
877 	};
878 	this.receivePartOriginChange = function(id, origin) {
879 		$( "#"+id+" .input-origin").val(origin);	
880 		SMap.refreshMap();
881 	};
882 
883 	var slugToEndoflifeCache = Array();
884 	var slug_end = Array(100);
885 	var defaultSelectedTextEnd = "None Selected";
886 	var endoflife_id = 0;
887 	
888 	/**
889 	 * Getting the endoflife list for the parts id
890 	 * @param partId, endoflife_id, element
891 	 * Get the slug for the part and call saveEndoflifeForPart 
892 	 */
893 	
894 	this.getEndoflifeForPart = function(partId, endoflife_id, element) {
895 		var pslug = objectConfig.parts[partId].linkid;
896 	        var slug = pslug.split("/")[1];
897 		Sourcemap.Editor.saveEndoflifeForPart(slug, partId, endoflife_id, element);	    
898 	};
899 	
900 	/**
901 	 *  Display the endoflife dropdown array for the part
902 	 * @param slug_endoflife ,element, this is the part slug and target_element
903 	 */
904 	this.populateEndoflifeOptions = function(slug_endoflife, element) {
905 		var options = "<option>"+defaultSelectedTextEnd+"</option>";
906 	  
907 		$.each(slug_endoflife, function(i,e) {
908 			options += '<option value="' + e.id + '">' + e.type + '</option>';   
909 			endoflife_id = e.id;
910 		});
911 		endoflife_id = endoflife_id+1;
912 		options += '<option value="' + endoflife_id + '">' + "reuse" + '</option>';   
913            	    // If this element is a select element use set options.  Otherwise traverse up and set children.
914         	if(element.tagName == "SELECT") {
915 		   $(element).html(options);		
916   		} else {
917 		    $( element).parents("select").html(options);		
918 		}
919 	};
920 	
921 
922 
923 	/**
924 	 *  Get the JSON requet from ObjectsModel, if it already exists then cache it.
925 	 * @param slug_endoflife, partId, endoflife_id, element
926 	 */
927 	this.saveEndoflifeForPart = function(slug_endoflife, partId, endoflife_id, element) {
928 		slug_end = slug_endoflife;
929 		if(slugToEndoflifeCache[slug_end] != null) {
930 			Sourcemap.Editor.populateEndoflifeOptions(slugToEndoflifeCache[slug_end], element);
931 		} else {
932 			var saveEndoflife = {parts_endoflife_slug: slug_endoflife};		
933 			var sendData = "data=" + JSON.stringify(saveEndoflife) + "";
934 			$.post(Sourcemap.siteurl+"objects/getEndoflife", sendData, function(response) {
935 				var objects_endoflife = eval(response); var options = "";
936 				slugToEndoflifeCache[slug_endoflife] = objects_endoflife;
937 				Sourcemap.Editor.populateEndoflifeOptions(slugToEndoflifeCache[slug_endoflife], element);
938 			});
939 		}
940 	    
941 	    /**
942 	     *  Select an endoflife from the list 
943 	     * call a fuunction is objects.js to add the endoflife for the part
944 	     */
945 		$(".endoflife-selected").unbind("change");
946 		$(".endoflife-selected").change(function() {
947 		    var endoflife_type = $(this).children("option:selected").text();
948 
949 		    if(typeof(objectConfig.parts[partId].endoflife) == 'undefined') {
950 			endoflife_id =0;
951 		    } else {
952 			endoflife_id = $(objectConfig.parts[partId].endoflife).size();
953 		    }
954 	         					    
955 
956 		    if(endoflife_type == defaultSelectedTextEnd) {return;}
957 						    
958                     var endoflifeAlreadyAdded = false;
959 		    $("li.#"+partId+" .endoflife-appearance-super .input-endoflife-display").each(function(i, element) {
960                        if(($(element).val() == endoflife_type) || (endoflife_id != 0)) {endoflifeAlreadyAdded = true; return false;}
961 			  return true;
962 			});
963 		    if(endoflifeAlreadyAdded) {return;}
964 
965 						    
966 		    
967 		    var emissions = null;
968 		    var unit = null;
969 		    var unit_flag = false;
970 		    var flag = false;
971 
972 		    $.each(slugToEndoflifeCache[slug_end], function(i, e) {
973 				if(e.type == endoflife_type) {
974 					emissions = e.emissions; unit = e.unit;
975 					if(unit != "kg") { unit_flag = true; }   
976 					return false;
977 				}
978 				return true;
979 			});
980 		   
981 
982 		    objectConfig.addEndoflife(partId, endoflife_id, endoflife_type, emissions, unit, flag);
983 		});
984 	};
985 
986 
987 	
988 
989 	var slugToProcessCache = Array();
990 	var slug = Array(100);	
991 	var defaultSelectText = "None Selected:";
992 	var process_id = 0;
993 	var flag = false;
994 	var factor = 1;
995 	var check_factor = 0;
996 	
997 	/**
998 	 * Getting the processes list for the parts id
999 	 * @param part_id, process_id, elt
1000 	 * call saveProcessForPart function 
1001 	 */
1002 		
1003 	this.getProcessesForPart = function(part_id, process_id, elt) {
1004 	        var part_slug = objectConfig.parts[part_id].linkid;
1005 	        var slug_part =part_slug.split("/")[1];
1006 		Sourcemap.Editor.saveProcessForPart(slug_part, part_id, process_id, elt);  
1007 	};
1008 	
1009 	/**
1010 	 *  Display the process dropdown array
1011 	 */
1012 	this.populateProcessOptions =function(slug_process, elt) {
1013 	    var options ="<option>"+defaultSelectText+"</option>";	    
1014 	    $.each(slug_process, function(i,e) { options +='<option value="' + e.id + '">' + e.name + '</option>';});	    
1015 	    // If this element is a select element use set options.  Otherwise traverse up and set children.
1016 	    if(elt.tagName == "SELECT") {
1017 		$(elt).html(options);		
1018 	    } else {
1019 		$(elt).parents("select").html(options);		
1020 	    }
1021 	};
1022 	
1023 
1024 	/**
1025 	 * Get the JSON request from ObjectsModel, if it already exists then cache it.
1026 	 */
1027 	
1028 	this.saveProcessForPart = function(data, part_id, process_id, elt){
1029 	    slug = data;
1030 	    if(slugToProcessCache[slug] != null) {
1031 		Sourcemap.Editor.populateProcessOptions(slugToProcessCache[slug], elt);		
1032 	    } else {		
1033 		var saveData = { parts_slug : data };
1034 		
1035 		var sendData = "data=" + JSON.stringify(saveData) + "";
1036 		$.post(Sourcemap.siteurl+"objects/getProcesses", sendData, function(response) {
1037 			   var objects = eval(response);
1038 				var options = "";
1039 			   slugToProcessCache[slug] = objects;
1040 			   Sourcemap.Editor.populateProcessOptions(slugToProcessCache[slug], elt);
1041 		       });
1042 	    }
1043 	    
1044 	    //Selecting a process from the list and if it exists in cache then 
1045 	    $(".process-selected").unbind("change");
1046 	    $(".process-selected").change(function() {
1047 					      var process_name = $(this).children("option:selected").text();						  
1048 					      if(typeof(objectConfig.parts[part_id].process) == "undefined") {
1049 						  process_id = 0;
1050 					      } else {
1051 						  process_id = $(objectConfig.parts[part_id].process).size();
1052 					      }
1053 					      
1054 					      
1055 					      if(process_name == defaultSelectText) { return;}
1056 					      
1057 					      var processAlreadyAdded = false;
1058 					      $(".process-appearance-super .input-process-display").each( function(i, element) {
1059 						   if($(element).val() == process_name) { processAlreadyAdded = true; return false;}
1060 						    return true;
1061 					     });
1062 					      if(processAlreadyAdded) {return;}
1063 		    
1064 					      // Get emissions and unit from cache
1065 					      var emissions = null;
1066 					      var unit = null;
1067 					      var unit_flag = false;
1068 					      
1069 					      $.each(slugToProcessCache[slug], function(i,e) { 
1070 							 if(e.name == process_name) {
1071 							     emissions = e.emissions;
1072 							     unit = e.unit;
1073 							     if (unit != "kg"){ unit_flag = true; }
1074 							     return false;
1075 							 }
1076 							 return true;
1077 						     });
1078 					      
1079 					      if (unit_flag == true) { check_factor = 1; factor = 1; } 
1080 					      else{ factor = 0; check_factor = 0;}
1081 					      
1082 					      
1083 					      objectConfig.addProcess(part_id, process_id, process_name, emissions, unit, flag, factor, check_factor);		   		    
1084 					  });
1085 	};
1086 	
1087 	
1088 	// Misc Functions TODO These functions should probably be moved somewhere else...	
1089 	this.calculateUsage = function() {
1090 	    var factorVal = $("#poweruselist").find(":selected").val();
1091 	    var usage = objectConfig.usageenergy * factorVal;
1092 	    $("#usepunch").text(Sourcemap.Util.roundIt(Number(usage),2));
1093 	    objectConfig.usageemissions = Sourcemap.Util.roundIt(Number(usage),2);
1094 	};
1095 		
1096 
1097 	/**
1098 	 * setting up click functions set up the permissions 
1099 	 * call save function to save the permission settings on the server
1100 	 */
1101 
1102 	this.setupPermissions = function() {
1103 		$(".permission_user").click(function() {
1104 			Sourcemap.Editor.savePermissions("useredit");
1105 			Sourcemap.Editor.removePermissions();
1106 			$(".permission_user").addClass("selected");							    
1107 		});
1108 	    $("#groupedit").change(function() {
1109 			Sourcemap.Editor.savePermissionsGroups($("#groupedit option:selected").text());
1110 			Sourcemap.Editor.removePermissions();
1111 			$(".permission_group").addClass("selected");
1112 		});
1113 	    $(".permission_group").click(function() {
1114 			Sourcemap.Editor.savePermissionsGroups($("#groupedit option:selected").text());
1115 			Sourcemap.Editor.removePermissions();
1116 			$(".permission_group").addClass("selected");
1117 		});
1118 	    
1119 	    $(".permission_everyone").click(function() {
1120 			Sourcemap.Editor.savePermissions("everyoneedit");
1121 			Sourcemap.Editor.removePermissions();
1122 			$(".permission_everyone").addClass("selected");
1123 			$(".permission_public").addClass("selected");
1124 			$(".permission_private").removeClass("selected");
1125 		});
1126 	    $(".permission_public").click(function() {
1127 			objectConfig.visibility = "public";
1128 			Sourcemap.Editor.savePermissionsObjects("public");
1129 			Sourcemap.Editor.removeVisibility();
1130 			$(".permission_public").addClass("selected");
1131 		});
1132 		$(".permission_private").click(function() {
1133 			if($(".permission_public").hasClass("selected") && $(".permission_everyone").hasClass("selected")){ }
1134 			else {
1135 				objectConfig.visibility = "private";
1136 				Sourcemap.Editor.savePermissionsObjects("private");
1137 				Sourcemap.Editor.removeVisibility();
1138 				$(".permission_private").addClass("selected");
1139 			}
1140 		});
1141 	};
1142 			
1143 	/**
1144 	 * Remove function visualizations
1145 	 */
1146 	this.removeVisibility = function() {
1147 		$(".permission_public").removeClass("selected");
1148 		$(".permission_private").removeClass("selected");			
1149 	};
1150 
1151 	this.removePermissions = function() {
1152 		$(".permission_user").removeClass("selected");
1153 		$(".permission_group").removeClass("selected");
1154 		$(".permission_everyone").removeClass("selected");
1155 	};
1156 
1157 	/**
1158 	 * call objects controller/model to save the settings
1159 	 */
1160 	this.savePermissions = function(data) {
1161 		var saveData = {
1162 		    permission_type: data,
1163 		    oid: objectConfig.oid
1164 		};
1165 	
1166 		var sendData = "data=" + JSON.stringify(saveData) + "";
1167 		$.post(Sourcemap.siteurl+"objects/setpermissions", sendData);			
1168        };
1169 
1170 	this.savePermissionsGroups = function(data) {
1171 		var saveData = {
1172 			group_name: data,
1173 			permission_type: "groupedit",
1174 		    oid: objectConfig.oid
1175 		};
1176 	
1177 		var sendData = "data=" + JSON.stringify(saveData) + "";
1178 		$.post(Sourcemap.siteurl+"objects/setpermissions", sendData);			
1179 	};
1180 	
1181 	this.savePermissionsObjects = function(permission) {
1182 		var saveData = {
1183 		    visibility: permission,
1184 		    oid: objectConfig.oid
1185 		};
1186 	
1187 		var sendData = "data=" + JSON.stringify(saveData) + "";
1188 		$.post(Sourcemap.siteurl+"objects/setvisibility", sendData);
1189 	};		
1190 
1191 	/**
1192 	 *  Listen for object events
1193 	 * bind event calls the respective recevie function for visualization
1194 	 * bind events is triggered by setDescription in objects.js
1195 	 * 
1196 	 */
1197 
1198 	$("body").bind('objectDescriptionUpdated', function(e, description) {
1199 		Sourcemap.Editor.receiveDescriptionChange(description); 
1200 	});
1201 
1202 	/**
1203 	 * bind event is triggered by setOrigin in objects.js
1204 	 */
1205 	$("body").bind('originGeoError', function(e, id) {
1206 		if(id == "object") { Sourcemap.Editor.receiveGeocodeError(".input-object-origin"); }
1207 		else { Sourcemap.Editor.receiveGeocodeError("#"+id+" .input-origin"); }
1208 	});
1209 
1210 	/**
1211 	 * bind event is triggered by setOrigin in objects.js
1212 	 */
1213 	$("body").bind('originGeoMessage', function(e, id, msg) {
1214 		if(id == "object") { Sourcemap.Editor.receiveGeocodeMessage(".input-object-origin", msg); }
1215 		else { Sourcemap.Editor.receiveGeocodeMessage("#"+id+" .input-origin", msg); }
1216 	});	
1217 
1218 
1219 	/**
1220 	  * bind event is triggered by recalculatedObjectValues in objects.js
1221 	  */
1222 	   
1223 	$("body").bind("objectTotalsCalculated", function(e, emis, embod, trans, ship, weight, processTotal, endoflifeTotal) {	
1224 		Sourcemap.Editor.receiveObjectTotals(emis,embod,trans,ship,weight, processTotal, endoflifeTotal);
1225 	});			
1226 
1227 	/**
1228 	 * bind event is triggered by saveConfirmation in objects.js
1229 	 */
1230 	$("body").bind("saveObjectConfirmation", function(e, data) { Sourcemap.Editor.receiveSaveConfirmation(data);});	
1231 
1232 	/**
1233 	 * bind event is triggered by addPart in objects.js
1234 	 */
1235 	$("body").bind("partAdded", function(e, id, name, description, emissions, link) { 
1236 		Sourcemap.Editor.receiveAddedPart(id, name, description, emissions, link);
1237 	});
1238 
1239 	/**
1240 	 * bind event is triggered by removePart in objects.js
1241 	 */
1242 	
1243 	$("body").bind("partRemoved", function(e, id) {
1244 		Sourcemap.Editor.receiveRemovedPart(id);
1245 		SMap.refreshMap();
1246 	});
1247 
1248 
1249 	
1250 			
1251 	/**
1252 	 * Listen for endoflife events
1253 	 * bind event calls the respective recieve function for visualization
1254 	 * bind event is triggered by addEndflife function in object.js
1255 	 */
1256 
1257 	$("body").bind("endoflifeAdded", function(e, partId, endoflife_id, endoflife_type, emissions, unit) {
1258 		Sourcemap.Editor.receiveAddedEndoflife(partId, endoflife_id, endoflife_type, emissions, unit); 
1259 	});
1260 	
1261 	/**
1262 	 * bind event is triggered by setEndflifeType function in object.js
1263 	 */
1264 	$("body"). bind("endoflifeType", function (e, partId, endoflife_id, type) {
1265 		Sourcemap.Editor.receiveEndoflifeEmissions(partId, endoflife_id, type); 
1266 	});
1267 
1268 	/**
1269 	 *  bind event is triggered by addEndflifeEmissions function in object.js
1270 	 */
1271 
1272 	$("body"). bind("endoflifeEmissions", function (e, partId, endoflife_id, emissions) {
1273 		Sourcemap.Editor.receiveEndoflifeEmissions(partId, endoflife_id, emissions); 
1274 	});
1275 
1276 	/**
1277 	 *  bind event is triggered by removeEndflife function in object.js
1278 	 */	
1279 
1280         $("body").bind("endoflifeRemoved", function(e, id, endoflife_id) {
1281 			   Sourcemap.Editor.receiveRemovedEndoflife(id, endoflife_id);
1282 	});	
1283 
1284 
1285 
1286 	/**
1287 	 * Listen for endoflife events
1288 	 * bind event calls the respective recieve function for visualization
1289 	 * bind event is triggered by addEndflife function in object.js
1290 	 */
1291 	$("body").bind("processAdded", function(e, part_id, process_id, name, emissions, unit, flag, factor, check) { 
1292 		Sourcemap.Editor.receiveAddedProcess(part_id, process_id, name, emissions, unit, flag, factor,check);
1293 	});
1294 
1295 
1296 	/**
1297 	 * bind event is triggered by setProcessName in objects.js
1298 	 */
1299 
1300 	$("body").bind("addingProcessName", function(e, id, process_name){
1301 		Sourcemap.Editor.receiveProcessNameChange(id, process_name);	   
1302 	});
1303 
1304 	/**
1305 	 * bind event is triggered by addProcessEmissions in objects.js
1306 	 */
1307 	$("body").bind("addingProcessEmissions", function(e, id, emissions){
1308 		Sourcemap.Editor.receiveProcessEmissionsChange(id, emissions);	   
1309 	});
1310 	
1311 	/**
1312 	 * bind event is triggered by setProcessUnit in objects.js
1313 	 */
1314 	$("body").bind("addingProcessUnit", function(e, id, unit){
1315 		Sourcemap.Editor.receiveProcessUnitChange(id, unit);	   
1316 	});
1317 
1318 	/**
1319 	 * bind event is triggered by setProcessFlag in objects.js
1320 	 */
1321 	$("body").bind("addingProcessFlag", function(e, id, flag){
1322 		Sourcemap.Editor.receiveProcessFlagChange(id, flag);	   
1323 	});
1324 
1325 	/**
1326 	 * bind event is triggered by setProcessFactor in objects.js
1327 	 */
1328 	$("body").bind("addingProcessFactor", function(e, id, factor, check){
1329 		Sourcemap.Editor.receiveProcessFactorChange(id, factor, check);	   
1330 	});
1331 
1332 	/**
1333 	 * bind event is triggered by removeProcess in objects.js
1334 	 */
1335 	$("body").bind("processRemoved", function(e, id, process_id) {
1336 		Sourcemap.Editor.receiveRemovedProcess(id, process_id);
1337 	});	
1338 
1339 
1340 	
1341 	 /**
1342 	 * bind event is triggered by setPartVia in objects.js
1343 	 */
1344 	
1345 	$("body").bind("partTotalsChanged", function(e, id) {
1346 		Sourcemap.Editor.receivePartTotalsChanged(id);
1347 	});	
1348 
1349 	/**
1350 	 * bind event is triggered by setPartName in objects.js
1351 	 */
1352 	$("body").bind("partNameUpdated", function(e, id, name) {
1353 		Sourcemap.Editor.receivePartNameChange(id, name);
1354 	});	
1355 
1356 	/**
1357 	 * bind event is triggered by setPartDescription in objects.js
1358 	 */
1359 	$("body").bind("partDescriptionUpdated", function(e, id, description) {
1360 		Sourcemap.Editor.receivePartDescriptionChange(id, description);
1361 	});
1362 
1363 
1364 	/**
1365 	 * bind event is triggered by setPartWeight in objects.js
1366 	 */
1367 	$("body").bind("partWeightUpdated", function(e, id, weight) {
1368 		Sourcemap.Editor.receivePartWeightChange(id, weight);		
1369 	});
1370 
1371 	/**
1372 	 * bind event is triggered by setPartShipping in objects.js
1373 	 */
1374 	$("body").bind("partShippingUpdated", function(e, id, shipping) {
1375 		Sourcemap.Editor.receivePartShippingChange(id, shipping);		
1376 	});	
1377 
1378 	/**
1379 	 * bind event is triggered by setPartEmissions in objects.js
1380 	 */
1381 	$("body").bind("partEmissionsUpdated", function(e, id, emissions) {
1382 		Sourcemap.Editor.receivePartEmissionsChange(id, emissions);
1383 	});	
1384 
1385 	/**
1386 	 * bind event is triggered by setPartRawEmissions in objects.js
1387 	 */
1388 	$("body").bind("partRawEmissionsUpdated", function(e, id, rawemissions) {
1389 		Sourcemap.Editor.receievePartRawEmissionsChange(id, rawemissions);
1390 	});
1391 
1392 	/**
1393 	 * bind event is triggered by setPartTransportEmissions in objects.js
1394 	 */
1395 	$("body").bind("partTransportEmissionsUpdated", function(e, id, transportemissions) {
1396 		Sourcemap.Editor.receivePartTransportEmissionsChange(id, transportemissions);
1397 	});
1398 
1399 	/**
1400 	 * bind event is triggered by setPartVia in objects.js
1401 	 */
1402 	$("body").bind("partViaUpdated", function(e, id, via) {
1403 		Sourcemap.Editor.receivePartViaChange(id, via);
1404 	});
1405 
1406 	/**
1407 	 * bind event is triggered by setPartOrigin in objects.js
1408 	 */
1409 	$("body").bind("partOriginUpdated", function(e, id, origin) {
1410 		Sourcemap.Editor.receivePartOriginChange(id, origin);
1411 	});	
1412 
1413 
1414 	$("body").bind("partSelected", function(e, id) {
1415 		Sourcemap.Editor.partHighlight(id-1);
1416 	});
1417 
1418 	$("#more-description-button").click( function() { 
1419 		$("body").scrollTo($("#object-story"), 500);
1420 	});
1421 			
1422 	/**
1423 	 * Parts Visualization Menu
1424 	 */
1425 	$("#partlist-close-button").click( function() { 
1426 		$("#part-visualization").slideToggle("normal",function(){
1427 			SMap.fitMap($("#part-visualization").css("display")=="block");
1428 		});
1429 	});
1430 	$(".visualization-close-button").click( function() { 
1431 		$(".visualization").css("display", "none");
1432 	});
1433 	$(".comment-visualization-button").click( function() { 
1434 		$(".visualization").css("display", "none");
1435 		$("#comment-visualization").slideDown();
1436 	});
1437 	$(".charting-visualization-button").click( function() { 
1438 		$(".visualization").css("display", "none");
1439 		$("#charting-visualization").slideDown();
1440 	    });
1441 	$(".partlist-visualization-button").click( function() { 
1442 		$("#part-visualization").slideToggle("normal",function(){
1443 			SMap.fitMap($("#part-visualization").css("display")=="block");
1444 		});
1445 	});
1446 
1447 	/**
1448 	 * Edit button visualization
1449 	 */
1450 					
1451 	$("#editsourcemapbutton").click( function() { 
1452 		Sourcemap.Editor.initializeEditMode();
1453 		$(".add-process").show();
1454 		$(".process-appearance-super").show();
1455 		$(".part-punch-processemissions").show();
1456 
1457 		$(".add-endoflife").show();
1458 		$(".endoflife-appearance-super").show();
1459 		$(".part-punch-endoflifeemissions").show();
1460 	});
1461 
1462 	/**
1463 	 * Save button visualization
1464 	 */
1465 	$("#savesourcemapbutton").click( function() { 
1466 		Sourcemap.Editor.stopEditMode(); 
1467 		$(".add-process").hide();
1468 		$(".process-appearance-super").hide();
1469 		$(".part-punch-processemissions").hide();
1470 
1471 		$(".add-endoflife").hide();
1472 		$(".endoflife-appearance-super").hide();
1473 		$(".part-punch-endoflifeemissions").hide();
1474 	});
1475 			
1476 	if(!(Sourcemap.Template.usechooser)) { $("#addpartbutton, #partlist-menu").click( function() { objectConfig.addPart(Sourcemap.Template.partstubname, '', '0', ''); });} 
1477 	else { $("#addpartbutton, #partlist-menu").click( function() { Sourcemap.Editor.showPartChooser(); });}
1478 	
1479 	/**
1480 	 * peermissions button, shar, lastleg button visualization
1481 	 */
1482 
1483 	$("#permission-button").click( function() { 
1484 		$("#delivered-panel").slideUp("fast"); $("#lastleg-button").removeClass("selected");				
1485 		$("#share-panel").slideUp("fast"); $("#share-button").removeClass("selected");			
1486 		$("#permission-panel").slideToggle("fast"); $("#permission-button").toggleClass("selected");
1487 	});
1488 	$("#share-button").click( function() { 
1489 		$("#delivered-panel").slideUp("fast"); $("#lastleg-button").removeClass("selected");
1490 		$("#permission-panel").slideUp("fast"); $("#permission-button").removeClass("selected");						
1491 		$("#share-panel").slideToggle("fast"); $("#share-button").toggleClass("selected");				
1492 	});
1493 	$("#lastleg-button").click( function() { 
1494 		$("#share-panel").slideUp("fast"); $("#share-button").removeClass("selected");				
1495 		$("#permission-panel").slideUp("fast"); $("#permission-button").removeClass("selected");												
1496 		$("#delivered-panel").slideToggle("fast"); $("#lastleg-button").toggleClass("selected");
1497 		
1498 	});
1499 	
1500 	var smapOptions = {};
1501 	if ($('#part-visualization').css("display") != "none")
1502 	{
1503 		var pv = $('#part-visualization');
1504 		smapOptions.constrain = pv[0].clientWidth + '_rc';
1505 	}
1506 	
1507 	smapOptions.userLocation = false;
1508 	smapOptions.navPosition = new OpenLayers.Pixel(2,15);
1509 	
1510 	// Initialize Map
1511 	SMap = new Sourcemap.OpenSourcemap( 'smap', objectConfig, smapOptions );
1512 	if(GBrowserIsCompatible()){ SMap.geoCoder = new GClientGeocoder(); }			
1513 
1514 	$(".list-expand").bind("click", function() { 
1515 		$(this).parents(".part-details").toggleClass("hover");
1516 		if($(this).text() == "+") { $(this).text("-"); } else { $(this).text("+"); }
1517 	});
1518 									
1519 
1520 	/**
1521 	 * show the footprrint only if objectConfig.showfootprint is on
1522 	 * same for showembodied, showtransport, showendoflife, showuse
1523 	 */
1524 	$("#showfootprint").click(function() {
1525 		if(objectConfig.showfootprint != "on") { objectConfig.showfootprint = "on";} else { objectConfig.showfootprint = "";}		
1526 		if(objectConfig.showfootprint == "on") { checkval = true;} else { checkval = false;}
1527 		$("#showembodied").attr('checked', checkval);
1528 		objectConfig.showembodied = objectConfig.showfootprint;
1529 		$("#showtransport").attr('checked', checkval);
1530 		objectConfig.showtransport = objectConfig.showfootprint;
1531 		$("#showprocess").attr('checked', checkval);
1532 		objectConfig.showprocess = objectConfig.showfootprint;
1533 		$("#showendoflife").attr('checked', checkval);
1534 		objectConfig.showendoflife = objectConfig.showfootprint;
1535 		
1536 		$("#showuse").attr('checked', checkval);
1537 		objectConfig.showuse = objectConfig.showfootprint;
1538 		objectConfig.recalculateObjectValues();
1539 		Sourcemap.Editor.toggleEmbodiedDisplay();
1540 		Sourcemap.Editor.toggleTransportDisplay();
1541 		Sourcemap.Editor.toggleProcessDisplay();
1542 		Sourcemap.Editor.toggleEndoflifeDisplay();
1543 	});
1544 			
1545 	$("#showembodied").click(function() { if(objectConfig.showembodied != "on") { objectConfig.showembodied = "on";} else { objectConfig.showembodied = "";} objectConfig.recalculateObjectValues(); Sourcemap.Editor.toggleEmbodiedDisplay();});
1546 	$("#showtransport").click(function() { if(objectConfig.showtransport != "on") { objectConfig.showtransport = "on";} else { objectConfig.showtransport = "";} objectConfig.recalculateObjectValues(); Sourcemap.Editor.toggleTransportDisplay();});
1547 	$("#showprocess").click(function() { if(objectConfig.showprocess != "on") { objectConfig.showprocess = "on";} else { objectConfig.showprocess = "";} objectConfig.recalculateObjectValues(); Sourcemap.Editor.toggleProcessDisplay();});
1548 	$("#showendoflife").click(function() { if(objectConfig.showendoflife != "on") { objectConfig.showendoflife = "on";} else { objectConfig.showendoflife = "";} objectConfig.recalculateObjectValues(); Sourcemap.Editor.toggleEndoflifeDisplay();});
1549 	$("#showuse").click(function() { if(objectConfig.showuse != "on") { objectConfig.showuse = "on";} else { objectConfig.showuse = "";} objectConfig.recalculateObjectValues();});
1550 	$("#showstats").click(function() { if(objectConfig.showstats != "on") { objectConfig.showstats = "on";} else { objectConfig.showstats = "";} objectConfig.recalculateObjectValues();});
1551 	
1552 	$("#usekwh").change(function() {
1553 		objectConfig.usageenergy = $(this).val();
1554 		Sourcemap.Editor.calculateUsage();
1555 	});
1556 	$("#poweruselist").change(function() {
1557 		var selectName = $(this).parent().find(":selected").text();
1558 		objectConfig.usagetype = selectName;
1559 		Sourcemap.Editor.calculateUsage();
1560 	});
1561 			
1562 	// Live events
1563 	$(".input-name").live("click", function(){ if($(this).val() == Sourcemap.Template.partstubname) { $(this).val(""); } return false;});
1564 	$(".input-origin").live("click", function(){ if($(this).val() == Sourcemap.Template.partlocationstubname) { $(this).val(""); } return false;});	
1565 
1566 	// Additional UI
1567 	$("#part-visualization, .visualization").draggable({ containment: '#map_container', revert: true, handle: "#part-shell-menu, .visualization-menu" });						    
1568     
1569 	objectConfig.recalculateObjectValues();			
1570 	Sourcemap.Editor.processHashEvent(window.location.hash);	        		
1571 
1572 	}
1573 };
1574     
1575 var SMap = null;
1576 
1577 /**
1578  *  Initial call (setup for edit mode)
1579  */
1580 $(document).ready(function() {		
1581 	Sourcemap.Editor.init();
1582 });
1583