Ver código fonte

Merge branch '1.9.x' of github.com:chamilo/chamilo-lms into 1.9.x

Yannick Warnier 11 anos atrás
pai
commit
8e4bc226c9
100 arquivos alterados com 7383 adições e 3131 exclusões
  1. 7 15
      main/admin/access_url_edit_courses_to_url.php
  2. 3 9
      main/admin/access_url_edit_users_to_url.php
  3. 3 4
      main/course_home/course_home.php
  4. 58 59
      main/course_progress/index.php
  5. 17 19
      main/document/create_draw.php
  6. 37 12
      main/document/downloadfolder.inc.php
  7. 1 1
      main/forum/forumfunction.inc.php
  8. 60 62
      main/inc/ajax/thematic.ajax.php
  9. 1 3
      main/inc/introductionSection.inc.php
  10. 1 0
      main/inc/lib/autoload.class.php
  11. 2 2
      main/inc/lib/banner.lib.php
  12. 1 1
      main/inc/lib/course.lib.php
  13. 0 1
      main/inc/lib/course_home.lib.php
  14. 25 4
      main/inc/lib/document.lib.php
  15. 15 0
      main/inc/lib/link.lib.php
  16. 177 153
      main/inc/lib/main_api.lib.php
  17. 0 22
      main/inc/lib/svg-edit/AUTHORS
  18. 0 19
      main/inc/lib/svg-edit/LICENSE
  19. 0 21
      main/inc/lib/svg-edit/README
  20. 10 6
      main/inc/lib/svg-edit/browser-not-supported.html
  21. 75 71
      main/inc/lib/svg-edit/browser.js
  22. 248 186
      main/inc/lib/svg-edit/canvg/canvg.js
  23. 0 6
      main/inc/lib/svg-edit/canvg/index.html
  24. 31 24
      main/inc/lib/svg-edit/canvg/rgbcolor.js
  25. 145 0
      main/inc/lib/svg-edit/config-sample.js
  26. 17 0
      main/inc/lib/svg-edit/config.js
  27. 17 18
      main/inc/lib/svg-edit/contextmenu.js
  28. 0 6
      main/inc/lib/svg-edit/contextmenu/index.html
  29. 2 3
      main/inc/lib/svg-edit/contextmenu/jquery.contextMenu.js
  30. 0 22
      main/inc/lib/svg-edit/contextmenu/jquery.contextMenu.min.js
  31. 316 0
      main/inc/lib/svg-edit/coords.js
  32. 6 0
      main/inc/lib/svg-edit/custom.css
  33. 188 179
      main/inc/lib/svg-edit/draw.js
  34. 59 0
      main/inc/lib/svg-edit/embedapi.html
  35. 0 56
      main/inc/lib/svg-edit/embedapi.html_disabled
  36. 101 148
      main/inc/lib/svg-edit/embedapi.js
  37. 11 0
      main/inc/lib/svg-edit/extensions/allowedMimeTypes.php
  38. 9 0
      main/inc/lib/svg-edit/extensions/closepath_icons.svg
  39. 260 265
      main/inc/lib/svg-edit/extensions/ext-arrows.js
  40. 71 72
      main/inc/lib/svg-edit/extensions/ext-closepath.js
  41. 155 149
      main/inc/lib/svg-edit/extensions/ext-connector.js
  42. 67 0
      main/inc/lib/svg-edit/extensions/ext-executablebuilder.js
  43. 91 88
      main/inc/lib/svg-edit/extensions/ext-eyedropper.js
  44. 229 238
      main/inc/lib/svg-edit/extensions/ext-foreignobject.js
  45. 101 130
      main/inc/lib/svg-edit/extensions/ext-grid.js
  46. 6 4
      main/inc/lib/svg-edit/extensions/ext-helloworld.js
  47. 134 120
      main/inc/lib/svg-edit/extensions/ext-imagelib.js
  48. 147 140
      main/inc/lib/svg-edit/extensions/ext-imagelib.xml
  49. 273 0
      main/inc/lib/svg-edit/extensions/ext-mathjax.js
  50. 142 0
      main/inc/lib/svg-edit/extensions/ext-overview_window.js
  51. 46 0
      main/inc/lib/svg-edit/extensions/ext-panning.js
  52. 7 0
      main/inc/lib/svg-edit/extensions/ext-panning.xml
  53. 23 0
      main/inc/lib/svg-edit/extensions/ext-php_savefile.js
  54. 34 0
      main/inc/lib/svg-edit/extensions/ext-php_savefile_chamilo.js
  55. 295 0
      main/inc/lib/svg-edit/extensions/ext-polygon.js
  56. 23 19
      main/inc/lib/svg-edit/extensions/ext-server_moinsave.js
  57. 80 51
      main/inc/lib/svg-edit/extensions/ext-server_opensave.js
  58. 357 387
      main/inc/lib/svg-edit/extensions/ext-shapes.js
  59. 236 0
      main/inc/lib/svg-edit/extensions/ext-shapes.xml
  60. 230 0
      main/inc/lib/svg-edit/extensions/ext-storage - Copy.js
  61. 293 0
      main/inc/lib/svg-edit/extensions/ext-storage.js
  62. 67 0
      main/inc/lib/svg-edit/extensions/ext-webappfind.js
  63. 42 0
      main/inc/lib/svg-edit/extensions/ext-xdomain-messaging.js
  64. 30 50
      main/inc/lib/svg-edit/extensions/eyedropper-icon.xml
  65. 34 127
      main/inc/lib/svg-edit/extensions/filesave.php
  66. 27 0
      main/inc/lib/svg-edit/extensions/foreignobject-icons.xml
  67. 70 0
      main/inc/lib/svg-edit/extensions/grid-icon.xml
  68. 0 6
      main/inc/lib/svg-edit/extensions/imagelib/smiley.svg
  69. 11 0
      main/inc/lib/svg-edit/extensions/markers-icons.xml
  70. 14 0
      main/inc/lib/svg-edit/extensions/polygon-icons.svg
  71. 5 0
      main/inc/lib/svg-edit/extensions/saved.svg
  72. 16 0
      main/inc/lib/svg-edit/extensions/savefile.php
  73. 166 0
      main/inc/lib/svg-edit/extensions/savefile_config.php
  74. 0 6
      main/inc/lib/svg-edit/extensions/shapelib/animal.json
  75. 0 1
      main/inc/lib/svg-edit/extensions/shapelib/math.json
  76. 0 0
      main/inc/lib/svg-edit/extensions/shapelib/raphael.txt
  77. 14 0
      main/inc/lib/svg-edit/extensions/shapelib/raphael_2.json
  78. 23 0
      main/inc/lib/svg-edit/extensions/webappfind-icon.svg
  79. 92 80
      main/inc/lib/svg-edit/history.js
  80. 1 1
      main/inc/lib/svg-edit/images/README.txt
  81. 0 6
      main/inc/lib/svg-edit/images/align-bottom.png
  82. BIN
      main/inc/lib/svg-edit/images/italic.png
  83. 0 0
      main/inc/lib/svg-edit/images/move_bottom.png
  84. 1 3
      main/inc/lib/svg-edit/images/shape_ungroup.png
  85. 0 6
      main/inc/lib/svg-edit/images/svg_edit_icons.svgz
  86. 1 1
      main/inc/lib/svg-edit/jgraduate/css/jPicker.css
  87. 0 6
      main/inc/lib/svg-edit/jgraduate/images/AlphaBar.png
  88. 0 6
      main/inc/lib/svg-edit/jgraduate/images/map-opacity.png
  89. 1673 0
      main/inc/lib/svg-edit/jgraduate/jpicker.js
  90. 4 4
      main/inc/lib/svg-edit/jgraduate/jpicker.min.js
  91. 74 0
      main/inc/lib/svg-edit/jgraduate/jquery.jgraduate.min.js
  92. 0 6
      main/inc/lib/svg-edit/jquery-ui/index.html
  93. 17 0
      main/inc/lib/svg-edit/jquery-ui/jquery-ui-1.8.17.custom.min.js
  94. 0 6
      main/inc/lib/svg-edit/jquery.js
  95. 0 6
      main/inc/lib/svg-edit/jquerybbq/jquery.bbq.min.js
  96. 1 0
      main/inc/lib/svg-edit/js-hotkeys/jquery.hotkeys.min.js
  97. 0 6
      main/inc/lib/svg-edit/locale/index.html
  98. 19 3
      main/inc/lib/svg-edit/locale/lang.af.js
  99. 19 3
      main/inc/lib/svg-edit/locale/lang.ar.js
  100. 19 3
      main/inc/lib/svg-edit/locale/lang.az.js

+ 7 - 15
main/admin/access_url_edit_courses_to_url.php

@@ -41,9 +41,8 @@ $interbreadcrumb[] = array ('url' => 'index.php', 'name' => get_lang('PlatformAd
 $interbreadcrumb[] = array ('url' => 'access_urls.php', 'name' => get_lang('MultipleAccessURLs'));
 $interbreadcrumb[] = array ('url' => 'access_urls.php', 'name' => get_lang('MultipleAccessURLs'));
 
 
 $add_type = 'multiple';
 $add_type = 'multiple';
-if(isset($_REQUEST['add_type']) && $_REQUEST['add_type']!=''){
+if(isset($_REQUEST['add_type']) && $_REQUEST['add_type']!='') {
 	$add_type = Security::remove_XSS($_REQUEST['add_type']);
 	$add_type = Security::remove_XSS($_REQUEST['add_type']);
-
 }
 }
 
 
 $access_url_id=1;
 $access_url_id=1;
@@ -68,7 +67,6 @@ function add_user_to_url(code, content) {
 }
 }
 
 
 function send() {
 function send() {
-
 	if (document.formulaire.access_url_id.value!=0) {
 	if (document.formulaire.access_url_id.value!=0) {
 		document.formulaire.form_sent.value=0;
 		document.formulaire.form_sent.value=0;
 		document.formulaire.add_type.value=\''.$add_type.'\';
 		document.formulaire.add_type.value=\''.$add_type.'\';
@@ -76,8 +74,7 @@ function send() {
 	}
 	}
 }
 }
 
 
-function remove_item(origin)
-{
+function remove_item(origin) {
 	for(var i = 0 ; i<origin.options.length ; i++) {
 	for(var i = 0 ; i<origin.options.length ; i++) {
 		if(origin.options[i].selected) {
 		if(origin.options[i].selected) {
 			origin.options[i]=null;
 			origin.options[i]=null;
@@ -87,10 +84,10 @@ function remove_item(origin)
 }
 }
 </script>';
 </script>';
 
 
-$form_sent=0;
-$errorMsg='';
-$UserList=$SessionList=array();
-$users=$sessions=array();
+$form_sent = 0;
+$errorMsg = '';
+$UserList = $SessionList = array();
+$users = $sessions = array();
 
 
 if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 if (isset($_POST['form_sent']) && $_POST['form_sent']) {
 	$form_sent=$_POST['form_sent'];
 	$form_sent=$_POST['form_sent'];
@@ -341,12 +338,8 @@ function loadUsersInSelect(select){
 	else  // XMLHttpRequest non supporté par le navigateur
 	else  // XMLHttpRequest non supporté par le navigateur
 	alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
 	alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
 
 
-	//xhr_object.open("GET", "loadUsersInSelect.ajax.php?id_session=<?php echo $id_session ?>&letter="+select.options[select.selectedIndex].text, false);
 	xhr_object.open("POST", "loadUsersInSelect.ajax.php");
 	xhr_object.open("POST", "loadUsersInSelect.ajax.php");
-
 	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-
-
 	nosessionUsers = makepost(document.getElementById('origin_users'));
 	nosessionUsers = makepost(document.getElementById('origin_users'));
 	sessionUsers = makepost(document.getElementById('destination_users'));
 	sessionUsers = makepost(document.getElementById('destination_users'));
 	nosessionClasses = makepost(document.getElementById('origin_classes'));
 	nosessionClasses = makepost(document.getElementById('origin_classes'));
@@ -368,9 +361,8 @@ function makepost(select){
 		ret = ret + options[i].value +'::'+options[i].text+";;";
 		ret = ret + options[i].value +'::'+options[i].text+";;";
 
 
 	return ret;
 	return ret;
-
 }
 }
 -->
 -->
 </script>
 </script>
 <?php
 <?php
-Display::display_footer();
+Display::display_footer();

+ 3 - 9
main/admin/access_url_edit_users_to_url.php

@@ -55,7 +55,6 @@ $htmlHeadXtra[] = $xajax->getJavascript('../inc/lib/xajax/');
 $htmlHeadXtra[] = '
 $htmlHeadXtra[] = '
 <script type="text/javascript">
 <script type="text/javascript">
 function add_user_to_url(code, content) {
 function add_user_to_url(code, content) {
-
 	document.getElementById("user_to_add").value = "";
 	document.getElementById("user_to_add").value = "";
 	document.getElementById("ajax_list_users").innerHTML = "";
 	document.getElementById("ajax_list_users").innerHTML = "";
 
 
@@ -67,7 +66,6 @@ function add_user_to_url(code, content) {
 }
 }
 
 
 function send() {
 function send() {
-
 	if (document.formulaire.access_url_id.value!=0) {
 	if (document.formulaire.access_url_id.value!=0) {
 		document.formulaire.form_sent.value=0;
 		document.formulaire.form_sent.value=0;
 		document.formulaire.add_type.value=\'' . $add_type . '\';
 		document.formulaire.add_type.value=\'' . $add_type . '\';
@@ -75,8 +73,7 @@ function send() {
 	}
 	}
 }
 }
 
 
-function remove_item(origin)
-{
+function remove_item(origin) {
 	for(var i = 0 ; i<origin.options.length ; i++) {
 	for(var i = 0 ; i<origin.options.length ; i++) {
 		if(origin.options[i].selected) {
 		if(origin.options[i].selected) {
 			origin.options[i]=null;
 			origin.options[i]=null;
@@ -366,7 +363,6 @@ function loadUsersInSelect(select) {
 	else  // XMLHttpRequest non supporté par le navigateur
 	else  // XMLHttpRequest non supporté par le navigateur
 	alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
 	alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
 
 
-	//xhr_object.open("GET", "loadUsersInSelect.ajax.php?id_session=<?php echo $id_session ?>&letter="+select.options[select.selectedIndex].text, false);
 	xhr_object.open("POST", "loadUsersInSelect.ajax.php");
 	xhr_object.open("POST", "loadUsersInSelect.ajax.php");
 	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 	xhr_object.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
 	nosessionUsers = makepost(document.getElementById('origin_users'));
 	nosessionUsers = makepost(document.getElementById('origin_users'));
@@ -374,11 +370,9 @@ function loadUsersInSelect(select) {
 	nosessionClasses = makepost(document.getElementById('origin_classes'));
 	nosessionClasses = makepost(document.getElementById('origin_classes'));
 	sessionClasses = makepost(document.getElementById('destination_classes'));
 	sessionClasses = makepost(document.getElementById('destination_classes'));
 	xhr_object.send("nosessionusers="+nosessionUsers+"&sessionusers="+sessionUsers+"&nosessionclasses="+nosessionClasses+"&sessionclasses="+sessionClasses);
 	xhr_object.send("nosessionusers="+nosessionUsers+"&sessionusers="+sessionUsers+"&nosessionclasses="+nosessionClasses+"&sessionclasses="+sessionClasses);
-
 	xhr_object.onreadystatechange = function() {
 	xhr_object.onreadystatechange = function() {
-		if(xhr_object.readyState == 4) {
+		if (xhr_object.readyState == 4) {
 			document.getElementById('content_source').innerHTML = result = xhr_object.responseText;
 			document.getElementById('content_source').innerHTML = result = xhr_object.responseText;
-			//alert(xhr_object.responseText);
 		}
 		}
 	}
 	}
 }
 }
@@ -392,4 +386,4 @@ function makepost(select){
 }
 }
 </script>
 </script>
 <?php
 <?php
-Display::display_footer();
+Display::display_footer();

+ 3 - 4
main/course_home/course_home.php

@@ -38,7 +38,7 @@ $language_file = array('course_home','courses');
 $use_anonymous = true;
 $use_anonymous = true;
 
 
 // Inlcuding the global initialization file.
 // Inlcuding the global initialization file.
-require dirname(__FILE__).'/../inc/global.inc.php';
+require_once dirname(__FILE__).'/../inc/global.inc.php';
 
 
 // Delete LP sessions - commented out after seeing that normal
 // Delete LP sessions - commented out after seeing that normal
 // users in their first learnpath step (1st SCO of a SCORM)
 // users in their first learnpath step (1st SCO of a SCORM)
@@ -233,7 +233,6 @@ $reqdate = "&reqdate=$temps";
 /*	MAIN CODE */
 /*	MAIN CODE */
 
 
 /*	Introduction section (editable by course admins) */
 /*	Introduction section (editable by course admins) */
-
 $content = Display::return_introduction_section(TOOL_COURSE_HOMEPAGE, array(
 $content = Display::return_introduction_section(TOOL_COURSE_HOMEPAGE, array(
 		'CreateDocumentWebDir' => api_get_path(WEB_COURSE_PATH).api_get_course_path().'/document/',
 		'CreateDocumentWebDir' => api_get_path(WEB_COURSE_PATH).api_get_course_path().'/document/',
 		'CreateDocumentDir'    => 'document/',
 		'CreateDocumentDir'    => 'document/',
@@ -245,7 +244,7 @@ $content = Display::return_introduction_section(TOOL_COURSE_HOMEPAGE, array(
 	the setting homepage_view is adjustable through
 	the setting homepage_view is adjustable through
 	the platform administration section */
 	the platform administration section */
 
 
-require_once api_get_path(LIBRARY_PATH).'course_home.lib.php';
+//require_once api_get_path(LIBRARY_PATH).'course_home.lib.php';
 
 
 if ($show_autolunch_lp_warning) {
 if ($show_autolunch_lp_warning) {
     $show_message .= Display::return_message(get_lang('TheLPAutoLaunchSettingIsONStudentsWillBeRedirectToAnSpecificLP'),'warning');
     $show_message .= Display::return_message(get_lang('TheLPAutoLaunchSettingIsONStudentsWillBeRedirectToAnSpecificLP'),'warning');
@@ -268,4 +267,4 @@ $tpl->assign('content', $content);
 $tpl->assign('course_code', $course_code);
 $tpl->assign('course_code', $course_code);
 
 
 $tpl->display_one_col_template();
 $tpl->display_one_col_template();
-Session::erase('_gid');
+Session::erase('_gid');

+ 58 - 59
main/course_progress/index.php

@@ -15,7 +15,6 @@ $language_file = array ('course_description', 'userInfo', 'admin');
 // including files
 // including files
 require_once '../inc/global.inc.php';
 require_once '../inc/global.inc.php';
 require_once api_get_path(LIBRARY_PATH).'attendance.lib.php';
 require_once api_get_path(LIBRARY_PATH).'attendance.lib.php';
-require_once api_get_path(LIBRARY_PATH).'thematic.lib.php';
 require_once api_get_path(LIBRARY_PATH).'app_view.php';
 require_once api_get_path(LIBRARY_PATH).'app_view.php';
 require_once 'thematic_controller.php';
 require_once 'thematic_controller.php';
 
 
@@ -80,19 +79,19 @@ if (!empty($thematic_id)) {
 // get default thematic plan title
 // get default thematic plan title
 $default_thematic_plan_title = $thematic->get_default_thematic_plan_title();
 $default_thematic_plan_title = $thematic->get_default_thematic_plan_title();
 
 
-// Only when I see the 3 columns. Avoids double or triple click binding for onclick event 
- 
+// Only when I see the 3 columns. Avoids double or triple click binding for onclick event
+
 $htmlHeadXtra[] = '<script type="text/javascript">
 $htmlHeadXtra[] = '<script type="text/javascript">
-	
+
 $(document).ready(function() {
 $(document).ready(function() {
 
 
-	//Second col	
+	//Second col
      /*
      /*
     $("#thematic_plan_add").live("submit", function() {
     $("#thematic_plan_add").live("submit", function() {
-   
+
 		var serialize_form_content = $(this).serialize();
 		var serialize_form_content = $(this).serialize();
 
 
-		//Getting FCK content								
+		//Getting FCK content
 		var oEditor = FCKeditorAPI.GetInstance("description[1]");
 		var oEditor = FCKeditorAPI.GetInstance("description[1]");
 		content_1=  oEditor.GetXHTML(true) ;
 		content_1=  oEditor.GetXHTML(true) ;
 		var oEditor = FCKeditorAPI.GetInstance("description[2]");
 		var oEditor = FCKeditorAPI.GetInstance("description[2]");
@@ -104,93 +103,93 @@ $(document).ready(function() {
 		var oEditor = FCKeditorAPI.GetInstance("description[5]");
 		var oEditor = FCKeditorAPI.GetInstance("description[5]");
 		content_5=  oEditor.GetXHTML(true) ;
 		content_5=  oEditor.GetXHTML(true) ;
 		var oEditor = FCKeditorAPI.GetInstance("description[6]");
 		var oEditor = FCKeditorAPI.GetInstance("description[6]");
-		content_6=  oEditor.GetXHTML(true) ;	
-		
+		content_6=  oEditor.GetXHTML(true) ;
+
 		$.ajax({
 		$.ajax({
 			type: "POST",
 			type: "POST",
 			url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=save_thematic_plan",
 			url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=save_thematic_plan",
 			data: "desc[1]="+content_1+"&"+"desc[2]="+content_2+"&"+"desc[3]="+content_3+"&"+"desc[4]="+content_4+"&"+"desc[5]="+content_5+"&"+"desc[6]="+content_6+"&"+serialize_form_content,
 			data: "desc[1]="+content_1+"&"+"desc[2]="+content_2+"&"+"desc[3]="+content_3+"&"+"desc[4]="+content_4+"&"+"desc[5]="+content_5+"&"+"desc[6]="+content_6+"&"+serialize_form_content,
-			success: function(data) {										
+			success: function(data) {
 				var thematic_id = $("input[name=\"thematic_id\"]").val();
 				var thematic_id = $("input[name=\"thematic_id\"]").val();
-				$("#thematic_plan_"+thematic_id).html(data);				
-				$("#thematic_plan_add").html("<div class=\"confirmation-message\">'.addslashes(get_lang('Saved')).'</div>");																	
-                //location.reload(true);					
+				$("#thematic_plan_"+thematic_id).html(data);
+				$("#thematic_plan_add").html("<div class=\"confirmation-message\">'.addslashes(get_lang('Saved')).'</div>");
+                //location.reload(true);
 			}
 			}
 		});
 		});
 		//prevent the browser to follow the link
 		//prevent the browser to follow the link
-        return false;				
+        return false;
 	});*/
 	});*/
-    
+
    // Third col
    // Third col
    /*
    /*
 	$("#thematic_advance").live("submit", function() {
 	$("#thematic_advance").live("submit", function() {
-	   	var url = this.href;        
+	   	var url = this.href;
         var my_id = this.id;
         var my_id = this.id;
 		var serialize_form_content = $(this).serialize();
 		var serialize_form_content = $(this).serialize();
-		
-		//Getting FCK content								
+
+		//Getting FCK content
 		var oEditor = FCKeditorAPI.GetInstance("content");
 		var oEditor = FCKeditorAPI.GetInstance("content");
-		content =  oEditor.GetXHTML(true) ;							
+		content =  oEditor.GetXHTML(true) ;
 		$.ajax({
 		$.ajax({
 				type: "POST",
 				type: "POST",
 				url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=save_thematic_advance",
 				url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=save_thematic_advance",
 				data: "real_content=" + content + "&" +serialize_form_content,
 				data: "real_content=" + content + "&" +serialize_form_content,
-				success: function(data) {										
+				success: function(data) {
 					var thematic_advance_id = $("input[name=\"thematic_advance_id\"]").val();
 					var thematic_advance_id = $("input[name=\"thematic_advance_id\"]").val();
-					$("#thematic_advance_"+thematic_advance_id).html(data);					
-					$("#thematic_advance").html("<div class=\"confirmation-message\">'.addslashes(get_lang('Saved')).'</div>");																	
-					
+					$("#thematic_advance_"+thematic_advance_id).html(data);
+					$("#thematic_advance").html("<div class=\"confirmation-message\">'.addslashes(get_lang('Saved')).'</div>");
+
 					//Only refresh if the parent is to add
 					//Only refresh if the parent is to add
 					if (my_id == "add_button") {
 					if (my_id == "add_button") {
 						//location.reload(true);
 						//location.reload(true);
 					}
 					}
 				}
 				}
-		});								
+		});
 		//prevent the browser to follow the link
 		//prevent the browser to follow the link
-        return false;	
+        return false;
 	});*/
 	});*/
-    
 
 
-    $(".thematic_advance_actions, .thematic_tools ").hide();	
-	
+
+    $(".thematic_advance_actions, .thematic_tools ").hide();
+
 	$(".thematic_content").mouseover(function() {
 	$(".thematic_content").mouseover(function() {
 		var id = parseInt(this.id.split("_")[3]);
 		var id = parseInt(this.id.split("_")[3]);
 		$("#thematic_id_content_"+id ).show();
 		$("#thematic_id_content_"+id ).show();
 	});
 	});
-	
+
 	$(".thematic_content").mouseleave(function() {
 	$(".thematic_content").mouseleave(function() {
 		var id = parseInt(this.id.split("_")[3]);
 		var id = parseInt(this.id.split("_")[3]);
 		$("#thematic_id_content_"+id ).hide();
 		$("#thematic_id_content_"+id ).hide();
-	});	
-	
+	});
+
 	$(".thematic_advance_content").mouseover(function() {
 	$(".thematic_advance_content").mouseover(function() {
 		var id = parseInt(this.id.split("_")[4]);
 		var id = parseInt(this.id.split("_")[4]);
 		$("#thematic_advance_tools_"+id ).show();
 		$("#thematic_advance_tools_"+id ).show();
 	});
 	});
-	
+
 	$(".thematic_advance_content").mouseleave(function() {
 	$(".thematic_advance_content").mouseleave(function() {
 		var id = parseInt(this.id.split("_")[4]);
 		var id = parseInt(this.id.split("_")[4]);
 		$("#thematic_advance_tools_"+id ).hide();
 		$("#thematic_advance_tools_"+id ).hide();
-	});    
+	});
     /*
     /*
-    $("#custom_date").live("click", function() {         
+    $("#custom_date").live("click", function() {
         $("#div_custom_datetime").css("display", "none");
         $("#div_custom_datetime").css("display", "none");
-        $("#div_datetime_by_attendance").hide();		
+        $("#div_datetime_by_attendance").hide();
     });
     });
-    
-    $("#from_attendance").live("click", function() {         
+
+    $("#from_attendance").live("click", function() {
         $("#div_custom_datetime").css("display", "block");
         $("#div_custom_datetime").css("display", "block");
         $("#div_custom_datetime").show();
         $("#div_custom_datetime").show();
-        $("#div_datetime_by_attendance").show();		
+        $("#div_datetime_by_attendance").show();
     });*/
     });*/
-});   	
+});
 </script>';
 </script>';
 
 
- 
+
 $htmlHeadXtra[] = '<script type="text/javascript">
 $htmlHeadXtra[] = '<script type="text/javascript">
 
 
 function datetime_by_attendance(attendance_id, thematic_advance_id) {
 function datetime_by_attendance(attendance_id, thematic_advance_id) {
-    
+
 	$.ajax({
 	$.ajax({
 		contentType: "application/x-www-form-urlencoded",
 		contentType: "application/x-www-form-urlencoded",
 		beforeSend: function(objeto) {},
 		beforeSend: function(objeto) {},
@@ -198,10 +197,10 @@ function datetime_by_attendance(attendance_id, thematic_advance_id) {
 		url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=get_datetime_by_attendance",
 		url: "'.api_get_path(WEB_AJAX_PATH).'thematic.ajax.php?a=get_datetime_by_attendance",
 		data: "attendance_id="+attendance_id+"&thematic_advance_id="+thematic_advance_id,
 		data: "attendance_id="+attendance_id+"&thematic_advance_id="+thematic_advance_id,
 		success: function(data) {
 		success: function(data) {
-			$("#div_datetime_attendance").html(data);            
+			$("#div_datetime_attendance").html(data);
             if (thematic_advance_id == 0) {
             if (thematic_advance_id == 0) {
                 $("#start_date_select_calendar").val($("#start_date_select_calendar option:first").val());
                 $("#start_date_select_calendar").val($("#start_date_select_calendar option:first").val());
-            }            
+            }
 		}
 		}
 	});
 	});
 }
 }
@@ -219,9 +218,9 @@ function update_done_thematic_advance(selected_value) {
 	});
 	});
 
 
 	// clean all radios
 	// clean all radios
-	
+
 	for (var i=0; i< $(".done_thematic").length;i++) {
 	for (var i=0; i< $(".done_thematic").length;i++) {
-		var id_radio_thematic = $(".done_thematic").get(i).id;		
+		var id_radio_thematic = $(".done_thematic").get(i).id;
 		$("#td_"+id_radio_thematic).css({"background-color":"#FFF"});
 		$("#td_"+id_radio_thematic).css({"background-color":"#FFF"});
 	}
 	}
 
 
@@ -237,21 +236,21 @@ function update_done_thematic_advance(selected_value) {
 
 
 function check_per_attendance(obj) {
 function check_per_attendance(obj) {
 	if (obj.checked) {
 	if (obj.checked) {
-        $("#div_datetime_by_attendance").show();        
+        $("#div_datetime_by_attendance").show();
         $("#div_custom_datetime").hide();
         $("#div_custom_datetime").hide();
 	} else {
 	} else {
         $("#div_datetime_by_attendance").hide();
         $("#div_datetime_by_attendance").hide();
-        $("#div_custom_datetime").show();        
+        $("#div_custom_datetime").show();
 	}
 	}
 }
 }
 
 
 function check_per_custom_date(obj) {
 function check_per_custom_date(obj) {
 	if (obj.checked) {
 	if (obj.checked) {
         $("#div_custom_datetime").show();
         $("#div_custom_datetime").show();
-        $("#div_datetime_by_attendance").hide();		        
+        $("#div_datetime_by_attendance").hide();
 	} else {
 	} else {
         $("#div_custom_datetime").hide();
         $("#div_custom_datetime").hide();
-        $("#div_datetime_by_attendance").show();		
+        $("#div_datetime_by_attendance").show();
 	}
 	}
 }
 }
 
 
@@ -273,7 +272,7 @@ if ($action == 'thematic_details') {
 }
 }
 if ($action == 'thematic_plan_list' || $action == 'thematic_plan_delete') {
 if ($action == 'thematic_plan_list' || $action == 'thematic_plan_delete') {
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
-	$interbreadcrumb[] = array ('url' => '#', 'name' => get_lang('ThematicPlan').' ('.$thematic_data['title'].') ');	
+	$interbreadcrumb[] = array ('url' => '#', 'name' => get_lang('ThematicPlan').' ('.$thematic_data['title'].') ');
 }
 }
 if ($action == 'thematic_plan_add' || $action == 'thematic_plan_edit') {
 if ($action == 'thematic_plan_add' || $action == 'thematic_plan_edit') {
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
@@ -287,7 +286,7 @@ if ($action == 'thematic_plan_add' || $action == 'thematic_plan_edit') {
 if ($action == 'thematic_advance_list' || $action == 'thematic_advance_delete') {
 if ($action == 'thematic_advance_list' || $action == 'thematic_advance_delete') {
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
 	$interbreadcrumb[] = array ('url' => '#', 'name' => get_lang('ThematicAdvance').' ('.$thematic_data['title'].')');
 	$interbreadcrumb[] = array ('url' => '#', 'name' => get_lang('ThematicAdvance').' ('.$thematic_data['title'].')');
-	
+
 }
 }
 if ($action == 'thematic_advance_add' || $action == 'thematic_advance_edit') {
 if ($action == 'thematic_advance_add' || $action == 'thematic_advance_edit') {
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
 	$interbreadcrumb[] = array ('url' => 'index.php?'.api_get_cidreq().'&action='.$_SESSION['thematic_control'], 'name' => get_lang('ThematicControl'));
@@ -305,32 +304,32 @@ switch ($action) {
     case 'thematic_import_select'   :
     case 'thematic_import_select'   :
     case 'thematic_import'          :
     case 'thematic_import'          :
 	case 'moveup'					:
 	case 'moveup'					:
-	case 'movedown'					:    
+	case 'movedown'					:
         if (!api_is_allowed_to_edit(null,true)) {
         if (!api_is_allowed_to_edit(null,true)) {
         	api_not_allowed();
         	api_not_allowed();
         }
         }
 	case 'thematic_list'			:
 	case 'thematic_list'			:
     case 'thematic_export'          :
     case 'thematic_export'          :
     case 'thematic_export_pdf'      :
     case 'thematic_export_pdf'      :
-    case 'thematic_details'         :	
+    case 'thematic_details'         :
         $thematic_controller->thematic($action);
         $thematic_controller->thematic($action);
-		break;	
+		break;
 	case 'thematic_plan_add'		:
 	case 'thematic_plan_add'		:
 	case 'thematic_plan_edit'		:
 	case 'thematic_plan_edit'		:
-	case 'thematic_plan_delete'		:	
+	case 'thematic_plan_delete'		:
         if (!api_is_allowed_to_edit(null,true)) {
         if (!api_is_allowed_to_edit(null,true)) {
             api_not_allowed();
             api_not_allowed();
-        }	
+        }
     case 'thematic_plan_list'       :
     case 'thematic_plan_list'       :
         $thematic_controller->thematic_plan($action);
         $thematic_controller->thematic_plan($action);
-        break;	
+        break;
 	case 'thematic_advance_add'		:
 	case 'thematic_advance_add'		:
 	case 'thematic_advance_edit'	:
 	case 'thematic_advance_edit'	:
 	case 'thematic_advance_delete'	:
 	case 'thematic_advance_delete'	:
         if (!api_is_allowed_to_edit(null,true)) {
         if (!api_is_allowed_to_edit(null,true)) {
-            api_not_allowed();            
+            api_not_allowed();
         }
         }
-    case 'thematic_advance_list'    : 
+    case 'thematic_advance_list'    :
         $thematic_controller->thematic_advance($action);
         $thematic_controller->thematic_advance($action);
         break;
         break;
 }
 }

+ 17 - 19
main/document/create_draw.php

@@ -34,7 +34,7 @@ api_block_anonymous_users();
 $document_data = DocumentManager::get_document_data_by_id($_GET['id'], api_get_course_id(), true);
 $document_data = DocumentManager::get_document_data_by_id($_GET['id'], api_get_course_id(), true);
 if (empty($document_data)) {
 if (empty($document_data)) {
     if (api_is_in_group()) {
     if (api_is_in_group()) {
-        $group_properties   = GroupManager::get_group_properties(api_get_group_id());        
+        $group_properties   = GroupManager::get_group_properties(api_get_group_id());
         $document_id        = DocumentManager::get_document_id(api_get_course_info(), $group_properties['directory']);
         $document_id        = DocumentManager::get_document_id(api_get_course_info(), $group_properties['directory']);
         $document_data      = DocumentManager::get_document_data_by_id($document_id, api_get_course_id());
         $document_data      = DocumentManager::get_document_data_by_id($document_id, api_get_course_id());
     }
     }
@@ -117,7 +117,7 @@ if (isset ($group)) {
 	// Copied from document.php
 	// Copied from document.php
 	$dir_array = explode('/', $dir);
 	$dir_array = explode('/', $dir);
 	$array_len = count($dir_array);
 	$array_len = count($dir_array);
-	
+
 	/*
 	/*
 	TODO:check and delete this code
 	TODO:check and delete this code
 	if (!$is_certificate_mode) {
 	if (!$is_certificate_mode) {
@@ -143,37 +143,35 @@ echo '<div class="actions">';
 		echo '<a href="document.php?id='.$document_id.'">'.Display::return_icon('back.png',get_lang('BackTo').' '.get_lang('DocumentsOverview'),'',ICON_SIZE_MEDIUM).'</a>';
 		echo '<a href="document.php?id='.$document_id.'">'.Display::return_icon('back.png',get_lang('BackTo').' '.get_lang('DocumentsOverview'),'',ICON_SIZE_MEDIUM).'</a>';
 echo '</div>';
 echo '</div>';
 
 
-if (api_browser_support('svg')){
-	
+if (api_browser_support('svg')) {
+
 	//automatic loading the course language
 	//automatic loading the course language
 	$svgedit_code_translation_table = array('' => 'en', 'pt' => 'pt-Pt', 'sr' => 'sr_latn');
 	$svgedit_code_translation_table = array('' => 'en', 'pt' => 'pt-Pt', 'sr' => 'sr_latn');
 	$langsvgedit  = api_get_language_isocode();
 	$langsvgedit  = api_get_language_isocode();
 	$langsvgedit = isset($svgedit_code_translation_table[$langsvgedit]) ? $svgedit_code_translation_table[$langsvgedit] : $langsvgedit;
 	$langsvgedit = isset($svgedit_code_translation_table[$langsvgedit]) ? $svgedit_code_translation_table[$langsvgedit] : $langsvgedit;
 	$langsvgedit = file_exists(api_get_path(LIBRARY_PATH).'svg-edit/locale/lang.'.$langsvgedit.'.js') ? $langsvgedit : 'en';
 	$langsvgedit = file_exists(api_get_path(LIBRARY_PATH).'svg-edit/locale/lang.'.$langsvgedit.'.js') ? $langsvgedit : 'en';
-	$svg_url= api_get_path(WEB_LIBRARY_PATH).'svg-edit/svg-editor.php?lang='.$langsvgedit ;
+	$svg_url= api_get_path(WEB_LIBRARY_PATH).'svg-edit/svg-editor.php?lang='.$langsvgedit;
 	?>
 	?>
-    
-	<script type="text/javascript">
-	
+	<script>
 		document.write ('<iframe id="frame" frameborder="0" scrolling="no" src="<?php echo  $svg_url; ?>" width="100%" height="100%"><noframes><p>Sorry, your browser does not handle frames</p></noframes></iframe>');
 		document.write ('<iframe id="frame" frameborder="0" scrolling="no" src="<?php echo  $svg_url; ?>" width="100%" height="100%"><noframes><p>Sorry, your browser does not handle frames</p></noframes></iframe>');
-	function resizeIframe() {
-    	var height = window.innerHeight -50;
-		//max lower size
-		if (height<550) {
-			height=550;
-		}
-    	document.getElementById('frame').style.height = height +"px";
-	};
+        function resizeIframe() {
+            var height = window.innerHeight -50;
+            //max lower size
+            if (height<550) {
+                height=550;
+            }
+            document.getElementById('frame').style.height = height +"px";
+        }
 	document.getElementById('frame').onload = resizeIframe;
 	document.getElementById('frame').onload = resizeIframe;
 	window.onresize = resizeIframe;
 	window.onresize = resizeIframe;
-	
+
 	</script>
 	</script>
-    
+
     <?php
     <?php
     echo '<noscript>';
     echo '<noscript>';
 	echo '<iframe style="height: 550px; width: 100%;" scrolling="no" frameborder="0" src="'.$svg_url.'"><noframes><p>Sorry, your browser does not handle frames</p></noframes></iframe>';
 	echo '<iframe style="height: 550px; width: 100%;" scrolling="no" frameborder="0" src="'.$svg_url.'"><noframes><p>Sorry, your browser does not handle frames</p></noframes></iframe>';
 	echo '</noscript>';
 	echo '</noscript>';
-} else {	
+} else {
 	Display::display_error_message(get_lang('BrowserDontSupportsSVG'));
 	Display::display_error_message(get_lang('BrowserDontSupportsSVG'));
 }
 }
 
 

+ 37 - 12
main/document/downloadfolder.inc.php

@@ -26,10 +26,11 @@ if (empty($document_data)) {
 }
 }
 
 
 //a student should not be able to download a root shared directory
 //a student should not be able to download a root shared directory
-if (($path == '/shared_folder' || $path=='/shared_folder_session_'.api_get_session_id()) && (!api_is_allowed_to_edit() || !api_is_platform_admin())){
-	echo '<div align="center">';
-	Display::display_error_message(get_lang('NotAllowedClickBack'));
-	echo '</div>';
+if (($path == '/shared_folder' ||
+    $path == '/shared_folder_session_' . api_get_session_id()) &&
+    (!api_is_allowed_to_edit() || !api_is_platform_admin())
+) {
+	api_not_allowed();
 	exit;
 	exit;
 }
 }
 
 
@@ -39,12 +40,12 @@ require api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php';
 //Creating a ZIP file
 //Creating a ZIP file
 $temp_zip_file = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
 $temp_zip_file = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().".zip";
 
 
-$zip_folder     = new PclZip($temp_zip_file);
-$doc_table      = Database::get_course_table(TABLE_DOCUMENT);
-$prop_table     = Database::get_course_table(TABLE_ITEM_PROPERTY);
+$zip_folder = new PclZip($temp_zip_file);
+$doc_table = Database::get_course_table(TABLE_DOCUMENT);
+$prop_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
 
 
-$course_id      = api_get_course_int_id();
-$session_id     = api_get_session_id();
+$course_id = api_get_course_int_id();
+$session_id = api_get_session_id();
 $groupId = api_get_group_id();
 $groupId = api_get_group_id();
 
 
 // We need this path to clean it out of the zip file
 // We need this path to clean it out of the zip file
@@ -65,7 +66,7 @@ if (api_is_allowed_to_edit()) {
 	}
 	}
 	$querypath = Database::escape_string($querypath);
 	$querypath = Database::escape_string($querypath);
 	// Search for all files that are not deleted => visibility != 2
 	// Search for all files that are not deleted => visibility != 2
-	$sql = "SELECT path
+	$sql = "SELECT path, id_session
 	        FROM $doc_table AS docs, $prop_table AS props
 	        FROM $doc_table AS docs, $prop_table AS props
 			WHERE
 			WHERE
 			    props.tool          ='".TOOL_DOCUMENT."' AND
 			    props.tool          ='".TOOL_DOCUMENT."' AND
@@ -76,9 +77,21 @@ if (api_is_allowed_to_edit()) {
                 props.c_id          = ".$course_id." AND
                 props.c_id          = ".$course_id." AND
                 props.id_session    IN ('0', '$session_id') AND
                 props.id_session    IN ('0', '$session_id') AND
                 docs.c_id 			= ".$course_id." ";
                 docs.c_id 			= ".$course_id." ";
+
+    $sql.= DocumentManager::getSessionFolderFilters($querypath, $session_id);
 	$query = Database::query($sql);
 	$query = Database::query($sql);
 	// Add tem to the zip file
 	// Add tem to the zip file
 	while ($not_deleted_file = Database::fetch_assoc($query)) {
 	while ($not_deleted_file = Database::fetch_assoc($query)) {
+        // Filtering folders and
+        if (strpos($not_deleted_file['path'], 'chat_files') > 0 ||
+            strpos($not_deleted_file['path'], 'shared_folder') > 0
+        ) {
+            if (!empty($session_id)) {
+               if ($not_deleted_file['id_session'] != $session_id) {
+                   continue;
+               }
+            }
+        }
 		$zip_folder->add(
 		$zip_folder->add(
             $sys_course_path.$_course['path'].'/document'.$not_deleted_file['path'],
             $sys_course_path.$_course['path'].'/document'.$not_deleted_file['path'],
             PCLZIP_OPT_REMOVE_PATH,
             PCLZIP_OPT_REMOVE_PATH,
@@ -97,7 +110,7 @@ if (api_is_allowed_to_edit()) {
 	// So... I do it in a couple of steps:
 	// So... I do it in a couple of steps:
 	// 1st: Get all files that are visible in the given path
 	// 1st: Get all files that are visible in the given path
 	$querypath = Database::escape_string($querypath);
 	$querypath = Database::escape_string($querypath);
-    $sql = "SELECT path
+    $sql = "SELECT path, id_session
             FROM $doc_table AS docs, $prop_table AS props
             FROM $doc_table AS docs, $prop_table AS props
             WHERE
             WHERE
                 docs.c_id               = $course_id AND
                 docs.c_id               = $course_id AND
@@ -109,9 +122,21 @@ if (api_is_allowed_to_edit()) {
                 docs.filetype           = 'file' AND
                 docs.filetype           = 'file' AND
                 props.id_session        IN ('0', '$session_id') AND
                 props.id_session        IN ('0', '$session_id') AND
                 props.to_group_id       = ".$groupId;
                 props.to_group_id       = ".$groupId;
-	$query = Database::query($sql);
+
+    $sql.= DocumentManager::getSessionFolderFilters($querypath, $session_id);
+
+    $query = Database::query($sql);
 	// Add them to an array
 	// Add them to an array
 	while ($all_visible_files = Database::fetch_assoc($query)) {
 	while ($all_visible_files = Database::fetch_assoc($query)) {
+        if (strpos($all_visible_files['path'], 'chat_files') > 0 ||
+            strpos($all_visible_files['path'], 'shared_folder') > 0
+        ) {
+            if (!empty($session_id)) {
+                if ($all_visible_files['id_session'] != $session_id) {
+                    continue;
+                }
+            }
+        }
 		$all_visible_files_path[] = $all_visible_files['path'];
 		$all_visible_files_path[] = $all_visible_files['path'];
 	}
 	}
 
 

+ 1 - 1
main/forum/forumfunction.inc.php

@@ -3691,7 +3691,7 @@ function display_forum_search_results($search_term)
           4. post is visible
           4. post is visible
          */
          */
         if (!api_is_allowed_to_edit(null, true)) {
         if (!api_is_allowed_to_edit(null, true)) {
-            if ($forum_categories_list[$row['forum_id']['forum_category']]['visibility'] == '1' AND
+            if ($forum_categories_list[$forum_list[$row['forum_id']]['forum_category']]['visibility'] == '1' AND
                 $forum_list[$row['forum_id']]['visibility'] == '1' AND $row['visible'] == '1'
                 $forum_list[$row['forum_id']]['visibility'] == '1' AND $row['visible'] == '1'
             ) {
             ) {
                 $display_result = true;
                 $display_result = true;

+ 60 - 62
main/inc/ajax/thematic.ajax.php

@@ -1,19 +1,17 @@
 <?php
 <?php
 /* For licensing terms, see /chamilo_license.txt */
 /* For licensing terms, see /chamilo_license.txt */
 /**
 /**
- * Responses to AJAX calls for thematic 
+ * Responses to AJAX calls for thematic
  */
  */
- 
+
 require_once '../global.inc.php';
 require_once '../global.inc.php';
 require_once api_get_path(LIBRARY_PATH).'attendance.lib.php';
 require_once api_get_path(LIBRARY_PATH).'attendance.lib.php';
-require_once api_get_path(LIBRARY_PATH).'thematic.lib.php';
-
 api_protect_course_script(true);
 api_protect_course_script(true);
 
 
 $action = $_GET['a'];
 $action = $_GET['a'];
 $thematic = new Thematic();
 $thematic = new Thematic();
 
 
-switch ($action) {		
+switch ($action) {
 	case 'save_thematic_plan':
 	case 'save_thematic_plan':
 		/*$title_list         = $_REQUEST['title'];
 		/*$title_list         = $_REQUEST['title'];
 		$description_list   = $_REQUEST['desc'];
 		$description_list   = $_REQUEST['desc'];
@@ -24,51 +22,51 @@ switch ($action) {
 				$thematic->set_thematic_plan_attributes($_REQUEST['thematic_id'], $title_list[$i], $description_list[$i], $description_type[$i]);
 				$thematic->set_thematic_plan_attributes($_REQUEST['thematic_id'], $title_list[$i], $description_list[$i], $description_type[$i]);
 				$affected_rows = $thematic->thematic_plan_save();
 				$affected_rows = $thematic->thematic_plan_save();
 			}
 			}
-		}	
+		}
 		$thematic_plan_data = $thematic->get_thematic_plan_data();
 		$thematic_plan_data = $thematic->get_thematic_plan_data();
 		$return = $thematic->get_thematic_plan_div($thematic_plan_data);
 		$return = $thematic->get_thematic_plan_div($thematic_plan_data);
 		echo $return[$_REQUEST['thematic_id']];*/
 		echo $return[$_REQUEST['thematic_id']];*/
-		break;        
-	case 'save_thematic_advance':		
+		break;
+	case 'save_thematic_advance':
 		if (!api_is_allowed_to_edit(null, true)) {
 		if (!api_is_allowed_to_edit(null, true)) {
 			echo '';
 			echo '';
 			exit;
 			exit;
         }
         }
         /*
         /*
-		if (($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) || (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) ) {	    			
+		if (($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) || (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) ) {
 			if ($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) {
 			if ($_REQUEST['start_date_type'] == 1 && empty($_REQUEST['start_date_by_attendance'])) {
         		$start_date_error = true;
         		$start_date_error = true;
-    			$data['start_date_error'] = $start_date_error;	
-			} 
-        			
+    			$data['start_date_error'] = $start_date_error;
+			}
+
         	if (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) {
         	if (!empty($_REQUEST['duration_in_hours']) && !is_numeric($_REQUEST['duration_in_hours'])) {
         		$duration_error = true;
         		$duration_error = true;
-    			$data['duration_error'] = $duration_error;	
+    			$data['duration_error'] = $duration_error;
         	}
         	}
-    
-    		$data['action'] = $_REQUEST['action'];	
-    		$data['thematic_id'] = $_REQUEST['thematic_id'];				
-    		$data['attendance_select'] = $attendance_select;					
+
+    		$data['action'] = $_REQUEST['action'];
+    		$data['thematic_id'] = $_REQUEST['thematic_id'];
+    		$data['attendance_select'] = $attendance_select;
     		if (isset($_REQUEST['thematic_advance_id'])) {
     		if (isset($_REQUEST['thematic_advance_id'])) {
     			$data['thematic_advance_id'] = $_REQUEST['thematic_advance_id'];
     			$data['thematic_advance_id'] = $_REQUEST['thematic_advance_id'];
     			$thematic_advance_data = $thematic->get_thematic_advance_list($_REQUEST['thematic_advance_id']);
     			$thematic_advance_data = $thematic->get_thematic_advance_list($_REQUEST['thematic_advance_id']);
-    			$data['thematic_advance_data'] = $thematic_advance_data;		
-    		}	    			
-		} else {   				
-			if ($_REQUEST['thematic_advance_token'] == $_SESSION['thematic_advance_token'] && api_is_allowed_to_edit(null, true)) {    	    			
+    			$data['thematic_advance_data'] = $thematic_advance_data;
+    		}
+		} else {
+			if ($_REQUEST['thematic_advance_token'] == $_SESSION['thematic_advance_token'] && api_is_allowed_to_edit(null, true)) {
     	    	$thematic_advance_id 	= $_REQUEST['thematic_advance_id'];
     	    	$thematic_advance_id 	= $_REQUEST['thematic_advance_id'];
-    	    	$thematic_id 			= $_REQUEST['thematic_id'];	    			
+    	    	$thematic_id 			= $_REQUEST['thematic_id'];
     	    	$content 				= $_REQUEST['real_content'];
     	    	$content 				= $_REQUEST['real_content'];
     	    	$duration				= $_REQUEST['duration_in_hours'];
     	    	$duration				= $_REQUEST['duration_in_hours'];
     	    	if (isset($_REQUEST['start_date_type']) && $_REQUEST['start_date_type'] == 2) {
     	    	if (isset($_REQUEST['start_date_type']) && $_REQUEST['start_date_type'] == 2) {
     	    		$start_date 	= $thematic->build_datetime_from_array($_REQUEST['custom_start_date']);
     	    		$start_date 	= $thematic->build_datetime_from_array($_REQUEST['custom_start_date']);
-    	    		$attendance_id 	= 0;	
+    	    		$attendance_id 	= 0;
     	    	} else {
     	    	} else {
     	    		$start_date 	= $_REQUEST['start_date_by_attendance'];
     	    		$start_date 	= $_REQUEST['start_date_by_attendance'];
     	    		$attendance_id 	= $_REQUEST['attendance_select'];
     	    		$attendance_id 	= $_REQUEST['attendance_select'];
-    	    	}		    			
-    	    	$thematic->set_thematic_advance_attributes($thematic_advance_id, $thematic_id,  $attendance_id, $content, $start_date, $duration);	    				    								
-				$affected_rows = $thematic->thematic_advance_save();			        	
+    	    	}
+    	    	$thematic->set_thematic_advance_attributes($thematic_advance_id, $thematic_id,  $attendance_id, $content, $start_date, $duration);
+				$affected_rows = $thematic->thematic_advance_save();
     		    if ($affected_rows) {
     		    if ($affected_rows) {
     		    	// get last done thematic advance before move thematic list
     		    	// get last done thematic advance before move thematic list
     				$last_done_thematic_advance = $thematic->get_last_done_thematic_advance();
     				$last_done_thematic_advance = $thematic->get_last_done_thematic_advance();
@@ -79,53 +77,53 @@ switch ($action) {
 				}
 				}
 			}
 			}
 		}
 		}
-		$thematic_advance_data = $thematic->get_thematic_advance_list(null, null, true);        
-		$return = $thematic->get_thematic_advance_div($thematic_advance_data);		
+		$thematic_advance_data = $thematic->get_thematic_advance_list(null, null, true);
+		$return = $thematic->get_thematic_advance_div($thematic_advance_data);
 		echo $return[$_REQUEST['thematic_id']][$_REQUEST['thematic_advance_id']];*/
 		echo $return[$_REQUEST['thematic_id']][$_REQUEST['thematic_advance_id']];*/
-        break;		
-	case 'get_datetime_by_attendance':							
-		$attendance_id       = intval($_REQUEST['attendance_id']);        
+        break;
+	case 'get_datetime_by_attendance':
+		$attendance_id       = intval($_REQUEST['attendance_id']);
 		$thematic_advance_id = intval($_REQUEST['thematic_advance_id']);
 		$thematic_advance_id = intval($_REQUEST['thematic_advance_id']);
-		
+
 		$label = '';
 		$label = '';
-		$input_select = '';			
+		$input_select = '';
 		if (!empty($attendance_id)) {
 		if (!empty($attendance_id)) {
-			$attendance = new Attendance();										
-			$thematic   = new Thematic();                
+			$attendance = new Attendance();
+			$thematic   = new Thematic();
             $thematic_list = $thematic->get_thematic_list();
             $thematic_list = $thematic->get_thematic_list();
-            
+
             $my_list = $thematic_list_temp = array();
             $my_list = $thematic_list_temp = array();
-            foreach ($thematic_list as $item) {                    	
-                $my_list = $thematic->get_thematic_advance_by_thematic_id($item['id']);                    
+            foreach ($thematic_list as $item) {
+                $my_list = $thematic->get_thematic_advance_by_thematic_id($item['id']);
                 $thematic_list_temp = array_merge($my_list, $thematic_list_temp);
                 $thematic_list_temp = array_merge($my_list, $thematic_list_temp);
-            }     
+            }
 			$new_thematic_list = array();
 			$new_thematic_list = array();
-		
+
 			foreach($thematic_list_temp as $item) {
 			foreach($thematic_list_temp as $item) {
 				if (!empty($item['attendance_id']) ) {
 				if (!empty($item['attendance_id']) ) {
 					$new_thematic_list[$item['id']] = array('attendance_id' =>$item['attendance_id'], 'start_date'=>$item['start_date']);
 					$new_thematic_list[$item['id']] = array('attendance_id' =>$item['attendance_id'], 'start_date'=>$item['start_date']);
 				}
 				}
-			}            
-			          
-			$attendance_calendar = $attendance->get_attendance_calendar($attendance_id);	
-            
+			}
+
+			$attendance_calendar = $attendance->get_attendance_calendar($attendance_id);
+
 			$label = get_lang('StartDate');
 			$label = get_lang('StartDate');
 			if (!empty($attendance_calendar)) {
 			if (!empty($attendance_calendar)) {
-				$input_select .= '<select id="start_date_select_calendar" name="start_date_by_attendance" UNIQUE size="5">';				
+				$input_select .= '<select id="start_date_select_calendar" name="start_date_by_attendance" UNIQUE size="5">';
 				foreach ($attendance_calendar as $calendar) {
 				foreach ($attendance_calendar as $calendar) {
                     $selected = null;
                     $selected = null;
 					$insert = true;
 					$insert = true;
-					//checking if was already taken						
+					//checking if was already taken
 					foreach ($new_thematic_list as $key => $thematic_item) {
 					foreach ($new_thematic_list as $key => $thematic_item) {
 						//if ($calendar['db_date_time'] == $thematic_item['start_date'] && $calendar['attendance_id'] == $thematic_item['attendance_id'] ) {
 						//if ($calendar['db_date_time'] == $thematic_item['start_date'] && $calendar['attendance_id'] == $thematic_item['attendance_id'] ) {
                         if ($calendar['db_date_time'] == $thematic_item['start_date'] ) {
                         if ($calendar['db_date_time'] == $thematic_item['start_date'] ) {
-							$insert = false;                            
+							$insert = false;
                             if ($thematic_advance_id == $key) {
                             if ($thematic_advance_id == $key) {
-                                $insert = true; 
+                                $insert = true;
                                 $selected = 'selected';
                                 $selected = 'selected';
                             }
                             }
-							break;	
-						}						
+							break;
+						}
 					}
 					}
 					if ($insert == true) {
 					if ($insert == true) {
 						$input_select .= '<option '.$selected.' value="'.$calendar['date_time'].'">'.$calendar['date_time'].'</option>';
 						$input_select .= '<option '.$selected.' value="'.$calendar['date_time'].'">'.$calendar['date_time'].'</option>';
@@ -135,27 +133,27 @@ switch ($action) {
 			} else {
 			} else {
 				$input_select .= '<em>'.get_lang('ThereAreNoRegisteredDatetimeYet').'</em>';
 				$input_select .= '<em>'.get_lang('ThereAreNoRegisteredDatetimeYet').'</em>';
 			}
 			}
-		} 
-		?>			
+		}
+		?>
 		<div class="control-group">
 		<div class="control-group">
 			<label class="control-label"><?php echo $label ?></label>
 			<label class="control-label"><?php echo $label ?></label>
 			<div class="controls"><?php echo $input_select ?></div>
 			<div class="controls"><?php echo $input_select ?></div>
-		</div>			
-		<?php				
-	    break;	    
-	case 'update_done_thematic_advance':	
+		</div>
+		<?php
+	    break;
+	case 'update_done_thematic_advance':
 		$thematic_advance_id = intval($_GET['thematic_advance_id']);
 		$thematic_advance_id = intval($_GET['thematic_advance_id']);
-		$total_average = 0;			
-		if (!empty($thematic_advance_id)) {				
-			$thematic = new Thematic();				
-			$affected_rows  = $thematic->update_done_thematic_advances($thematic_advance_id);			
+		$total_average = 0;
+		if (!empty($thematic_advance_id)) {
+			$thematic = new Thematic();
+			$affected_rows  = $thematic->update_done_thematic_advances($thematic_advance_id);
 			//if ($affected_rows) {
 			//if ($affected_rows) {
 			$total_average  = $thematic->get_total_average_of_thematic_advances(api_get_course_id(), api_get_session_id());
 			$total_average  = $thematic->get_total_average_of_thematic_advances(api_get_course_id(), api_get_session_id());
-			//}			
+			//}
 		}
 		}
 		echo $total_average;
 		echo $total_average;
 		break;
 		break;
 	default:
 	default:
 		echo '';
 		echo '';
 }
 }
-exit;
+exit;

+ 1 - 3
main/inc/introductionSection.inc.php

@@ -22,8 +22,6 @@
  *	@package chamilo.include
  *	@package chamilo.include
  */
  */
 
 
-require_once api_get_path(LIBRARY_PATH).'thematic.lib.php';
-
 /*	Constants and variables */
 /*	Constants and variables */
 
 
 $TBL_INTRODUCTION = Database::get_course_table(TABLE_TOOL_INTRO);
 $TBL_INTRODUCTION = Database::get_course_table(TABLE_TOOL_INTRO);
@@ -237,7 +235,7 @@ $introduction_section .=  '</div>';
 
 
 $introduction_section .=  '<div class="home-course-intro span12"><div class="page-course">';
 $introduction_section .=  '<div class="home-course-intro span12"><div class="page-course">';
 if ($intro_dispDefault) {
 if ($intro_dispDefault) {
-	
+
 	$intro_content = $intro_content;
 	$intro_content = $intro_content;
 
 
 	if (!empty($intro_content))	{
 	if (!empty($intro_content))	{

+ 1 - 0
main/inc/lib/autoload.class.php

@@ -97,6 +97,7 @@ class Autoload
         $result['AssetWikiRenderer'] = '/main/inc/lib/system/media/renderer/lab/asset_wiki_renderer.class.php';
         $result['AssetWikiRenderer'] = '/main/inc/lib/system/media/renderer/lab/asset_wiki_renderer.class.php';
         $result['AttendanceLink'] = '/main/gradebook/lib/be/attendancelink.class.php';
         $result['AttendanceLink'] = '/main/gradebook/lib/be/attendancelink.class.php';
         $result['Auth'] = '/main/inc/lib/auth.lib.php';
         $result['Auth'] = '/main/inc/lib/auth.lib.php';
+        $result['Thematic'] = '/main/inc/lib/thematic.lib.php';
         $result['Block'] = '/main/dashboard/block.class.php';
         $result['Block'] = '/main/dashboard/block.class.php';
         $result['Blog'] = '/main/inc/lib/blog.lib.php';
         $result['Blog'] = '/main/inc/lib/blog.lib.php';
         $result['Cache'] = '/main/inc/lib/cache.class.php';
         $result['Cache'] = '/main/inc/lib/cache.class.php';

+ 2 - 2
main/inc/lib/banner.lib.php

@@ -293,10 +293,10 @@ function return_navigation_array() {
         // Social Networking
         // Social Networking
         if (api_get_setting('show_tabs', 'social') == 'true') {
         if (api_get_setting('show_tabs', 'social') == 'true') {
             if (api_get_setting('allow_social_tool') == 'true') {
             if (api_get_setting('allow_social_tool') == 'true') {
-                $navigation['social'] = $possible_tabs['social'];
+                $navigation['social'] = isset($possible_tabs['social']) ? $possible_tabs['social'] : null;
             }
             }
         } else{
         } else{
-            $menu_navigation['social'] = $possible_tabs['social'];
+            $menu_navigation['social'] = isset($possible_tabs['social']) ? $possible_tabs['social'] : null;
         }
         }
 
 
         // Dashboard
         // Dashboard

+ 1 - 1
main/inc/lib/course.lib.php

@@ -4421,7 +4421,7 @@ class CourseManager
             $options[]=  'enter';
             $options[]=  'enter';
         }
         }
 
 
-         if ($course['visibility'] != HIDDEN && empty($course['registration_code']) && $course['unsubscribe'] == UNSUBSCRIBE_ALLOWED && api_user_is_login($uid) && (in_array($course['real_id'], $user_courses))) {
+         if ($course['visibility'] != COURSE_VISIBILITY_HIDDEN && empty($course['registration_code']) && $course['unsubscribe'] == UNSUBSCRIBE_ALLOWED && api_user_is_login($uid) && (in_array($course['real_id'], $user_courses))) {
             $options[]=  'unsubscribe';
             $options[]=  'unsubscribe';
         }
         }
 
 

+ 0 - 1
main/inc/lib/course_home.lib.php

@@ -6,7 +6,6 @@ define('SHORTCUTS_VERTICAL', 1);
 
 
 class CourseHome
 class CourseHome
 {
 {
-
     /**
     /**
      * Gets the html content to show in the 3 column view
      * Gets the html content to show in the 3 column view
      */
      */

+ 25 - 4
main/inc/lib/document.lib.php

@@ -337,7 +337,7 @@ class DocumentManager
                 header('Cache-Control: public'); // IE cannot download from sessions without a cache
                 header('Cache-Control: public'); // IE cannot download from sessions without a cache
             }
             }
             header('Content-Description: ' . $filename);
             header('Content-Description: ' . $filename);
-            header('Content-transfer-encoding: binary');
+            header('Content-Transfer-Encoding: binary');
 
 
             $res = fopen($full_file_name, 'r');
             $res = fopen($full_file_name, 'r');
             fpassthru($res);
             fpassthru($res);
@@ -463,6 +463,28 @@ class DocumentManager
         }
         }
     }
     }
 
 
+    /**
+     * Session folder filters
+     * @param string $path
+     * @param int $sessionId
+     * @return null|string
+     */
+    public static function getSessionFolderFilters($path, $sessionId)
+    {
+        $sessionId = intval($sessionId);
+        $condition = null;
+
+        if (!empty($sessionId)) {
+            // Chat folder filter
+            if ($path == '/chat_files') {
+                $condition .= " AND (id_session = '$sessionId') ";
+            }
+            // share_folder filter
+            $condition .= " AND docs.path != '/shared_folder' ";
+        }
+        return $condition;
+    }
+
     /**
     /**
      * Fetches all document data for the given user/group
      * Fetches all document data for the given user/group
      *
      *
@@ -494,8 +516,8 @@ class DocumentManager
         }
         }
 
 
         // Escape underscores in the path so they don't act as a wildcard
         // Escape underscores in the path so they don't act as a wildcard
+        $originalPath = $path;
         $path = Database::escape_string(str_replace('_', '\_', $path));
         $path = Database::escape_string(str_replace('_', '\_', $path));
-        $to_user_id = Database::escape_string($to_user_id);
         $to_value = Database::escape_string($to_value);
         $to_value = Database::escape_string($to_value);
 
 
         $visibility_bit = ' <> 2';
         $visibility_bit = ' <> 2';
@@ -508,7 +530,7 @@ class DocumentManager
         $current_session_id = api_get_session_id();
         $current_session_id = api_get_session_id();
         $condition_session = " AND (id_session = '$current_session_id' OR (id_session = '0') )";
         $condition_session = " AND (id_session = '$current_session_id' OR (id_session = '0') )";
 
 
-        // Condition for search (get ALL folders and documents)
+        $condition_session .= self::getSessionFolderFilters($originalPath, $current_session_id);
 
 
         $sql = "SELECT
         $sql = "SELECT
                     docs.id,
                     docs.id,
@@ -538,7 +560,6 @@ class DocumentManager
                     $visibility_bit
                     $visibility_bit
                     $condition_session
                     $condition_session
                 ";
                 ";
-
         $result = Database::query($sql);
         $result = Database::query($sql);
 
 
         $doc_list = array();
         $doc_list = array();

+ 15 - 0
main/inc/lib/link.lib.php

@@ -44,6 +44,21 @@ class Link extends Model
    		}
    		}
    		return $id;
    		return $id;
     }
     }
+    
+    function updateLink($linkId, $linkUrl)
+    {   
+        $tblLink = Database :: get_course_table(TABLE_LINK);
+        $linkUrl = Database::escape_string($linkUrl);
+        $linkId = intval($linkId);
+        $courseId = api_get_course_int_id();
+        $session_id = api_get_session_id();
+        if ($linkUrl != '') {
+            $query = "UPDATE $tblLink SET url = '$linkUrl' WHERE id = $linkId AND c_id = $courseId AND session_id = $session_id";
+            $resLink = Database::query($query);
+        } else {
+            return false;
+        }
+    }
 }
 }
 
 
 
 

+ 177 - 153
main/inc/lib/main_api.lib.php

@@ -1062,15 +1062,13 @@ function api_get_user_id() {
  * @param boolean   Whether to get session courses or not - NOT YET IMPLEMENTED
  * @param boolean   Whether to get session courses or not - NOT YET IMPLEMENTED
  * @return array    Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
  * @return array    Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
  */
  */
-function api_get_user_courses($userid, $fetch_session = true) {
+function api_get_user_courses($userid, $fetch_session = true)
+{
     if ($userid != strval(intval($userid))) {
     if ($userid != strval(intval($userid))) {
         return array();
         return array();
     } //get out if not integer
     } //get out if not integer
     $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
     $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
     $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
     $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
-    $t_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
-    $t_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
-    $t_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
 
 
     $sql = "SELECT cc.code code, cc.db_name db, cc.directory dir, cu.status status
     $sql = "SELECT cc.code code, cc.db_name db, cc.directory dir, cu.status status
             FROM    $t_course       cc,
             FROM    $t_course       cc,
@@ -1097,23 +1095,24 @@ function api_get_user_courses($userid, $fetch_session = true) {
  * @param array Non-standard user array
  * @param array Non-standard user array
  * @return array Standard user array
  * @return array Standard user array
  */
  */
-function _api_format_user($user, $add_password = false) {
+function _api_format_user($user, $add_password = false)
+{
     $result = array();
     $result = array();
 
 
     $firstname = null;
     $firstname = null;
     $lastname = null;
     $lastname = null;
+
     if (isset($user['firstname']) && isset($user['lastname'])) {
     if (isset($user['firstname']) && isset($user['lastname'])) {
         $firstname = $user['firstname'];
         $firstname = $user['firstname'];
         $lastname = $user['lastname'];
         $lastname = $user['lastname'];
     } elseif (isset($user['firstName']) && isset($user['lastName'])) {
     } elseif (isset($user['firstName']) && isset($user['lastName'])) {
-        $firstname = $user['firstName'];
-        $lastname = $user['lastName'];
+        $firstname = isset($user['firstName']) ? $user['firstName'] : null;
+        $lastname = isset($user['lastName']) ? $user['lastName'] : null;
     }
     }
-    $result['phone'] = $user['phone'];
 
 
     $result['complete_name'] = api_get_person_name($firstname, $lastname);
     $result['complete_name'] = api_get_person_name($firstname, $lastname);
-
     $result['complete_name_with_username'] = $result['complete_name'];
     $result['complete_name_with_username'] = $result['complete_name'];
+
     if (!empty($user['username'])) {
     if (!empty($user['username'])) {
         $result['complete_name_with_username'] 	= $result['complete_name'].' ('.$user['username'].')';
         $result['complete_name_with_username'] 	= $result['complete_name'].' ('.$user['username'].')';
     }
     }
@@ -1125,27 +1124,33 @@ function _api_format_user($user, $add_password = false) {
     $result['firstName'] 		= $firstname;
     $result['firstName'] 		= $firstname;
     $result['lastName'] 		= $lastname;
     $result['lastName'] 		= $lastname;
 
 
-    if (isset($user['email'])) {
-        $result['mail']          = $user['email'];
-        $result['email']         = $user['email'];
-    } else {
-        $result['mail']          = $user['mail'];
-        $result['email']         = $user['mail'];
-    }
-    $user_id                    = intval($user['user_id']);
-    $result['picture_uri']      = $user['picture_uri'];
-    $result['user_id']          = $user_id;
-    $result['official_code']    = $user['official_code'];
-    $result['status']           = $user['status'];
-    $result['active']           = $user['active'];
-    $result['auth_source']      = $user['auth_source'];
+    $attributes = array(
+        'phone',
+        'picture_uri',
+        'official_code',
+        'status',
+        'active',
+        'auth_source',
+        'username',
+        'theme',
+        'language',
+        'creator_id',
+        'registration_date'
+    );
 
 
-    if (isset($user['username'])) {
-        $result['username']         = $user['username'];
+    foreach ($attributes as $attribute) {
+        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
     }
     }
 
 
-    $result['theme']            = $user['theme'];
-    $result['language']         = $user['language'];
+    if (isset($user['email'])) {
+        $result['mail'] = isset($user['email']) ? $user['email'] : null;
+        $result['email'] = isset($user['email'])? $user['email'] : null;
+    } else {
+        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
+        $result['email'] = isset($user['mail'])? $user['mail'] : null;
+    }
+    $user_id = intval($user['user_id']);
+    $result['user_id'] = $user_id;
 
 
     if (isset($_configuration['save_user_last_login']) &&
     if (isset($_configuration['save_user_last_login']) &&
         $_configuration['save_user_last_login']
         $_configuration['save_user_last_login']
@@ -1173,7 +1178,7 @@ function _api_format_user($user, $add_password = false) {
 
 
     // Getting user avatar.
     // Getting user avatar.
 
 
-	$picture_filename   = trim($user['picture_uri']);
+	$picture_filename   = trim($result['picture_uri']);
 	$avatar             = api_get_path(WEB_CODE_PATH).'img/unknown.jpg';
 	$avatar             = api_get_path(WEB_CODE_PATH).'img/unknown.jpg';
 	$avatar_small       = api_get_path(WEB_CODE_PATH).'img/unknown_22.jpg';
 	$avatar_small       = api_get_path(WEB_CODE_PATH).'img/unknown_22.jpg';
     $avatar_sys_path    = api_get_path(SYS_CODE_PATH).'img/unknown.jpg';
     $avatar_sys_path    = api_get_path(SYS_CODE_PATH).'img/unknown.jpg';
@@ -1208,9 +1213,6 @@ function _api_format_user($user, $add_password = false) {
         $result['password'] = $user['password'];
         $result['password'] = $user['password'];
     }
     }
 
 
-    $result['creator_id'] = $user['creator_id'];
-    $result['registration_date'] = $user['registration_date'];
-
     return $result;
     return $result;
 }
 }
 
 
@@ -5875,7 +5877,7 @@ function api_protect_global_admin_script() {
 }
 }
 
 
 /**
 /**
- * Get actived template
+ * Get active template
  * @param string    theme type (optional: default)
  * @param string    theme type (optional: default)
  * @param string    path absolute(abs) or relative(rel) (optional:rel)
  * @param string    path absolute(abs) or relative(rel) (optional:rel)
  * @return string   actived template path
  * @return string   actived template path
@@ -5900,136 +5902,158 @@ function api_get_template($path_type = 'rel') {
 
 
 /**
 /**
  * Check browser support for type files
  * Check browser support for type files
- ** This function check if the users browser support a file format or return the current browser and major ver when $format=check_browser
+ * This function check if the users browser support a file format or
+ * return the current browser and major ver when $format=check_browser
  * @param string $format
  * @param string $format
  *
  *
  * @return bool, or return text array if $format=check_browser
  * @return bool, or return text array if $format=check_browser
  * @author Juan Carlos Raña Trabado
  * @author Juan Carlos Raña Trabado
  */
  */
 
 
-function api_browser_support($format="") {
-    require_once api_get_path(LIBRARY_PATH).'browser/Browser.php';
+function api_browser_support($format = "")
+{
+    require_once api_get_path(LIBRARY_PATH) . 'browser/Browser.php';
     $browser = new Browser();
     $browser = new Browser();
     $current_browser = $browser->getBrowser();
     $current_browser = $browser->getBrowser();
     $a_versiontemp = explode('.', $browser->getVersion());
     $a_versiontemp = explode('.', $browser->getVersion());
-    $current_majorver= $a_versiontemp[0];
-
-	//native svg support
-	if ($format=='svg'){
-		if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) || ($current_browser == 'Firefox' && $current_majorver > 1) || ($current_browser == 'Safari' && $current_majorver >= 4) || ($current_browser == 'Chrome' && $current_majorver >= 1) || ($current_browser == 'Opera' && $current_majorver >= 9)) {
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='pdf') {
-		//native pdf support
-		if($current_browser == 'Chrome' && $current_majorver >= 6){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='tif' || $format=='tiff'){
-		//native tif support
-		if($current_browser == 'Safari' && $current_majorver >= 5){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='ogg' || $format=='ogx'|| $format=='ogv' || $format=='oga'){
-	//native ogg, ogv,oga support
-		if (($current_browser == 'Firefox' && $current_majorver >= 3)  || ($current_browser == 'Chrome' && $current_majorver >= 3) || ($current_browser == 'Opera' && $current_majorver >= 9)) {
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='mpg' || $format=='mpeg'){
-		//native mpg support
-		if(($current_browser == 'Safari' && $current_majorver >= 5)){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='mp4') {
-		//native mp4 support (TODO: Android, iPhone)
-		if($current_browser == 'Android' || $current_browser == 'iPhone') {
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='mov') {
-		//native mov support( TODO:check iPhone)
-		if($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone'){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='avi') {
-		//native avi support
-		if($current_browser == 'Safari' && $current_majorver >= 5){
-			return true;
-		}
-		else{
-			return false;
-		}
-	} elseif($format=='wmv') {
-		//native wmv support
-		if ($current_browser == 'Firefox' && $current_majorver >= 4){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='webm') {
-		//native webm support (TODO:check IE9, Chrome9, Android)
-		if(($current_browser == 'Firefox' && $current_majorver >= 4) || ($current_browser == 'Opera' && $current_majorver >= 9) || ($current_browser == 'Internet Explorer' && $current_majorver >= 9)|| ($current_browser == 'Chrome' && $current_majorver >=9)|| $current_browser == 'Android'){
-			return true;
-		}
-		else{
-			return false;
-		}
-	} elseif($format=='wav') {
-		//native wav support (only some codecs !)
-		if (($current_browser == 'Firefox' && $current_majorver >= 4) || ($current_browser == 'Safari' && $current_majorver >= 5) || ($current_browser == 'Opera' && $current_majorver >= 9) || ($current_browser == 'Internet Explorer' && $current_majorver >= 9)|| ($current_browser == 'Chrome' && $current_majorver > 9)|| $current_browser == 'Android' || $current_browser == 'iPhone'){
-			return true;
-		}
-		else{
-			return false;
-		}
-	} elseif($format=='mid' || $format=='kar') {
-		//native midi support (TODO:check Android)
-		if($current_browser == 'Opera'&& $current_majorver >= 9 || $current_browser == 'Android'){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=='wma') {
-		//native wma support
-		if($current_browser == 'Firefox' && $current_majorver >= 4){
-			return true;
-		}
-		else{
-			return false;
-		}
-	} elseif($format=='au') {
-		//native au support
-		if($current_browser == 'Safari' && $current_majorver >= 5){
-			return true;
-		}
-		else{
-			return false;
-		}
-	} elseif($format=='mp3') {
-		//native mp3 support (TODO:check Android, iPhone)
-		if(($current_browser == 'Safari' && $current_majorver >= 5) || ($current_browser == 'Chrome' && $current_majorver >=6)|| ($current_browser == 'Internet Explorer' && $current_majorver >= 9)|| $current_browser == 'Android' || $current_browser == 'iPhone'){
-			return true;
-		} else {
-			return false;
-		}
-	} elseif($format=="check_browser") {
-		$array_check_browser=array($current_browser, $current_majorver);
-		return $array_check_browser;
-	} else {
-		return false;
-	}
+    $current_majorver = $a_versiontemp[0];
+
+    // Native svg support
+    if ($format == 'svg') {
+
+        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
+            ($current_browser == 'Firefox' && $current_majorver > 1) ||
+            ($current_browser == 'Safari' && $current_majorver >= 4) ||
+            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
+            ($current_browser == 'Opera' && $current_majorver >= 9)
+        ) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'pdf') {
+        //native pdf support
+        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'tif' || $format == 'tiff') {
+        //native tif support
+        if ($current_browser == 'Safari' && $current_majorver >= 5) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
+        //native ogg, ogv,oga support
+        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
+            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
+            ($current_browser == 'Opera' && $current_majorver >= 9)) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'mpg' || $format == 'mpeg') {
+        //native mpg support
+        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'mp4') {
+        //native mp4 support (TODO: Android, iPhone)
+        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'mov') {
+        //native mov support( TODO:check iPhone)
+        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'avi') {
+        //native avi support
+        if ($current_browser == 'Safari' && $current_majorver >= 5) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'wmv') {
+        //native wmv support
+        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'webm') {
+        //native webm support (TODO:check IE9, Chrome9, Android)
+        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
+            ($current_browser == 'Opera' && $current_majorver >= 9) ||
+            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
+            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
+            $current_browser == 'Android'
+        ) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'wav') {
+        //native wav support (only some codecs !)
+        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
+            ($current_browser == 'Safari' && $current_majorver >= 5) ||
+            ($current_browser == 'Opera' && $current_majorver >= 9) ||
+            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
+            ($current_browser == 'Chrome' && $current_majorver > 9) ||
+            $current_browser == 'Android' ||
+            $current_browser == 'iPhone'
+        ) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'mid' || $format == 'kar') {
+        //native midi support (TODO:check Android)
+        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'wma') {
+        //native wma support
+        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'au') {
+        //native au support
+        if ($current_browser == 'Safari' && $current_majorver >= 5) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == 'mp3') {
+        //native mp3 support (TODO:check Android, iPhone)
+        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
+            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
+            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
+            $current_browser == 'Android' ||
+            $current_browser == 'iPhone'
+        ) {
+            return true;
+        } else {
+            return false;
+        }
+    } elseif ($format == "check_browser") {
+        $array_check_browser = array($current_browser, $current_majorver);
+        return $array_check_browser;
+    } else {
+        return false;
+    }
 }
 }
 
 
 /**
 /**

+ 0 - 22
main/inc/lib/svg-edit/AUTHORS

@@ -1,22 +0,0 @@
-Narendra Sisodiya <narendra.sisodiya@gmail.com>
-Pavol Rusnak <rusnakp@gmail.com>
-Jeff Schiller <codedread@gmail.com>
-Vidar Hokstad <vidar.hokstad@gmail.com>
-Alexis Deveria <adeveria@gmail.com>
-
-Translation credits:
-
-ar: Tarik Belaam <dubraise@gmail.com> (العربية)
-cs: Jan Ptacek <jan.ptacek@gmail.com> (Čeština)
-de: Reimar Bauer <rb.proj@googlemail.com> (Deutsch)
-es: Alicia Puerto <alicia.puerto.g@gmail.com> (Español)
-fa: Payman Delshad <payman@opera.com> (فارسی)
-fr: wormsxulla <wormsxulla@yahoo.com> (Français)
-fy: Wander Nauta <info@wandernauta.nl> (Frysk)
-hi: Tavish Naruka <tavishnaruka@gmail.com> (हिन्दी)
-ja: Dong <iwadon@yarhalla.jpn.org> (日本語)
-nl: Jaap Blom <jaap.blom@gmail.com> (Nederlands)
-ro: Christian Tzurcanu <christian.tzurcanu@gmail.com> (Româneşte)
-ru: Laurent Dufloux <laurent.dufloux@etu.upmc.fr> (Русский)
-sk: Pavol Rusnak <rusnakp@gmail.com> (Slovenčina)
-zh-TW: 黃瀚生 (Han Sheng Huang) <zenixls2@gmail.com> (台灣正體) 

+ 0 - 19
main/inc/lib/svg-edit/LICENSE

@@ -1,19 +0,0 @@
-Copyright (c) 2009-2011 by SVG-edit authors (see AUTHORS file)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.

+ 0 - 21
main/inc/lib/svg-edit/README

@@ -1,21 +0,0 @@
-SVG-edit, a web based SVG editor
-
-http://code.google.com/p/svg-edit/
-
-see AUTHORS file for authors
-
------
-
-SVG-edit contains code from these projects:
-
-jQuery JavaScript Library v1.3.2
-http://jquery.com/
-Copyright (c) 2009 John Resig
-
-jQuery js-Hotkeys
-http://code.google.com/p/js-hotkeys/
-Copyright (c) 2008 Tzury Bar Yochay
-
-jPicker
-http://www.digitalmagicpro.com/jPicker/
-Copyright (c) 2009 Christopher T. Tillman

+ 10 - 6
main/inc/lib/svg-edit/browser-not-supported.html

@@ -5,7 +5,7 @@
 <meta http-equiv="X-UA-Compatible" content="chrome=1"/>
 <meta http-equiv="X-UA-Compatible" content="chrome=1"/>
 <link rel="icon" type="image/png" href="images/logo.png"/>
 <link rel="icon" type="image/png" href="images/logo.png"/>
 <link rel="stylesheet" href="svg-editor.css" type="text/css"/>
 <link rel="stylesheet" href="svg-editor.css" type="text/css"/>
-<script type="text/javascript" src="jquery.js"></script>
+<script src="jquery.js"></script>
 <title>Browser does not support SVG | SVG-edit</title>
 <title>Browser does not support SVG | SVG-edit</title>
 </head>
 </head>
 <body>
 <body>
@@ -16,12 +16,16 @@
 <p>Try the latest version of <a href="http://www.getfirefox.com">Firefox</a>, <a href="http://www.google.com/chrome/">Google Chrome</a>, <a href="http://www.apple.com/safari/download/">Safari</a>, <a href="http://www.opera.com/download/">Opera</a> or <a href="http://windows.microsoft.com/ie9">Internet Explorer</a>.</p>
 <p>Try the latest version of <a href="http://www.getfirefox.com">Firefox</a>, <a href="http://www.google.com/chrome/">Google Chrome</a>, <a href="http://www.apple.com/safari/download/">Safari</a>, <a href="http://www.opera.com/download/">Opera</a> or <a href="http://windows.microsoft.com/ie9">Internet Explorer</a>.</p>
 <p>If you are unable to install one of these and must use an old version of Internet Explorer, you can install the <a href="http://code.google.com/chrome/chromeframe/">Google Chrome Frame plugin</a>.</p>
 <p>If you are unable to install one of these and must use an old version of Internet Explorer, you can install the <a href="http://code.google.com/chrome/chromeframe/">Google Chrome Frame plugin</a>.</p>
 
 
-<script type="text/javascript">
-var viewportHeight =(window.innerHeight ? window.innerHeight : $(window).height()) - 140;
-document.write('<iframe width="100%" height="'+viewportHeight+'" src="http://caniuse.com/#cats=SVG"></iframe>');
-</script>
-
 </div>
 </div>
 
 
+<script>
+/*globals $*/
+var viewportHeight = window.innerHeight || ($(window).height() - 140);
+var iframe = document.createElement('iframe');
+iframe.style.width = '100%';
+iframe.style.height = viewportHeight + 'px';
+iframe.src = 'http://caniuse.com/#cats=SVG';
+document.body.appendChild(iframe);
+</script>
 </body>
 </body>
 </html>
 </html>

+ 75 - 71
main/inc/lib/svg-edit/browser.js

@@ -1,7 +1,9 @@
+/*globals $, svgedit*/
+/*jslint vars: true, eqeq: true*/
 /**
 /**
  * Package: svgedit.browser
  * Package: svgedit.browser
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Jeff Schiller
  * Copyright(c) 2010 Jeff Schiller
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
@@ -10,46 +12,50 @@
 // Dependencies:
 // Dependencies:
 // 1) jQuery (for $.alert())
 // 1) jQuery (for $.alert())
 
 
-var svgedit = svgedit || {};
-
-(function() {
+(function() {'use strict';
 
 
 if (!svgedit.browser) {
 if (!svgedit.browser) {
 	svgedit.browser = {};
 	svgedit.browser = {};
 }
 }
+
+// alias
+var NS = svgedit.NS;
+
 var supportsSvg_ = (function() {
 var supportsSvg_ = (function() {
-        return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect;
-})();
-svgedit.browser.supportsSvg = function() { return supportsSvg_; }
+	return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
+}());
+
+svgedit.browser.supportsSvg = function() { return supportsSvg_; };
 if(!svgedit.browser.supportsSvg()) {
 if(!svgedit.browser.supportsSvg()) {
-	window.location = "browser-not-supported.html";
+	window.location = 'browser-not-supported.html';
+	return;
 }
 }
-else{
 
 
-var svgns = 'http://www.w3.org/2000/svg';
 var userAgent = navigator.userAgent;
 var userAgent = navigator.userAgent;
-var svg = document.createElementNS(svgns, 'svg');
+var svg = document.createElementNS(NS.SVG, 'svg');
 
 
 // Note: Browser sniffing should only be used if no other detection method is possible
 // Note: Browser sniffing should only be used if no other detection method is possible
 var isOpera_ = !!window.opera;
 var isOpera_ = !!window.opera;
-var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0;
+var isWebkit_ = userAgent.indexOf('AppleWebKit') >= 0;
 var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
 var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
 var isIE_ = userAgent.indexOf('MSIE') >= 0;
 var isIE_ = userAgent.indexOf('MSIE') >= 0;
 var isChrome_ = userAgent.indexOf('Chrome/') >= 0;
 var isChrome_ = userAgent.indexOf('Chrome/') >= 0;
 var isWindows_ = userAgent.indexOf('Windows') >= 0;
 var isWindows_ = userAgent.indexOf('Windows') >= 0;
+var isMac_ = userAgent.indexOf('Macintosh') >= 0;
+var isTouch_ = 'ontouchstart' in window;
 
 
 var supportsSelectors_ = (function() {
 var supportsSelectors_ = (function() {
 	return !!svg.querySelector;
 	return !!svg.querySelector;
-})();
+}());
 
 
 var supportsXpath_ = (function() {
 var supportsXpath_ = (function() {
 	return !!document.evaluate;
 	return !!document.evaluate;
-})();
+}());
 
 
 // segList functions (for FF1.5 and 2.0)
 // segList functions (for FF1.5 and 2.0)
 var supportsPathReplaceItem_ = (function() {
 var supportsPathReplaceItem_ = (function() {
-	var path = document.createElementNS(svgns, 'path');
-	path.setAttribute('d','M0,0 10,10');
+	var path = document.createElementNS(NS.SVG, 'path');
+	path.setAttribute('d', 'M0,0 10,10');
 	var seglist = path.pathSegList;
 	var seglist = path.pathSegList;
 	var seg = path.createSVGPathSegLinetoAbs(5,5);
 	var seg = path.createSVGPathSegLinetoAbs(5,5);
 	try {
 	try {
@@ -57,11 +63,11 @@ var supportsPathReplaceItem_ = (function() {
 		return true;
 		return true;
 	} catch(err) {}
 	} catch(err) {}
 	return false;
 	return false;
-})();
+}());
 
 
 var supportsPathInsertItemBefore_ = (function() {
 var supportsPathInsertItemBefore_ = (function() {
-	var path = document.createElementNS(svgns,'path');
-	path.setAttribute('d','M0,0 10,10');
+	var path = document.createElementNS(NS.SVG, 'path');
+	path.setAttribute('d', 'M0,0 10,10');
 	var seglist = path.pathSegList;
 	var seglist = path.pathSegList;
 	var seg = path.createSVGPathSegLinetoAbs(5,5);
 	var seg = path.createSVGPathSegLinetoAbs(5,5);
 	try {
 	try {
@@ -69,44 +75,43 @@ var supportsPathInsertItemBefore_ = (function() {
 		return true;
 		return true;
 	} catch(err) {}
 	} catch(err) {}
 	return false;
 	return false;
-})();
+}());
 
 
 // text character positioning (for IE9)
 // text character positioning (for IE9)
 var supportsGoodTextCharPos_ = (function() {
 var supportsGoodTextCharPos_ = (function() {
-	var retValue = false;
-	var svgroot = document.createElementNS(svgns, 'svg');
-	var svgcontent = document.createElementNS(svgns, 'svg');
+	var svgroot = document.createElementNS(NS.SVG, 'svg');
+	var svgcontent = document.createElementNS(NS.SVG, 'svg');
 	document.documentElement.appendChild(svgroot);
 	document.documentElement.appendChild(svgroot);
 	svgcontent.setAttribute('x', 5);
 	svgcontent.setAttribute('x', 5);
 	svgroot.appendChild(svgcontent);
 	svgroot.appendChild(svgcontent);
-	var text = document.createElementNS(svgns,'text');
+	var text = document.createElementNS(NS.SVG, 'text');
 	text.textContent = 'a';
 	text.textContent = 'a';
 	svgcontent.appendChild(text);
 	svgcontent.appendChild(text);
 	var pos = text.getStartPositionOfChar(0).x;
 	var pos = text.getStartPositionOfChar(0).x;
 	document.documentElement.removeChild(svgroot);
 	document.documentElement.removeChild(svgroot);
 	return (pos === 0);
 	return (pos === 0);
-})();
+}());
 
 
 var supportsPathBBox_ = (function() {
 var supportsPathBBox_ = (function() {
-	var svgcontent = document.createElementNS(svgns, 'svg');
+	var svgcontent = document.createElementNS(NS.SVG, 'svg');
 	document.documentElement.appendChild(svgcontent);
 	document.documentElement.appendChild(svgcontent);
-	var path = document.createElementNS(svgns, 'path');
-	path.setAttribute('d','M0,0 C0,0 10,10 10,0');
+	var path = document.createElementNS(NS.SVG, 'path');
+	path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
 	svgcontent.appendChild(path);
 	svgcontent.appendChild(path);
 	var bbox = path.getBBox();
 	var bbox = path.getBBox();
 	document.documentElement.removeChild(svgcontent);
 	document.documentElement.removeChild(svgcontent);
 	return (bbox.height > 4 && bbox.height < 5);
 	return (bbox.height > 4 && bbox.height < 5);
-})();
+}());
 
 
 // Support for correct bbox sizing on groups with horizontal/vertical lines
 // Support for correct bbox sizing on groups with horizontal/vertical lines
 var supportsHVLineContainerBBox_ = (function() {
 var supportsHVLineContainerBBox_ = (function() {
-	var svgcontent = document.createElementNS(svgns, 'svg');
+	var svgcontent = document.createElementNS(NS.SVG, 'svg');
 	document.documentElement.appendChild(svgcontent);
 	document.documentElement.appendChild(svgcontent);
-	var path = document.createElementNS(svgns, 'path');
-	path.setAttribute('d','M0,0 10,0');
-	var path2 = document.createElementNS(svgns, 'path');
-	path2.setAttribute('d','M5,0 15,0');
-	var g = document.createElementNS(svgns, 'g');
+	var path = document.createElementNS(NS.SVG, 'path');
+	path.setAttribute('d', 'M0,0 10,0');
+	var path2 = document.createElementNS(NS.SVG, 'path');
+	path2.setAttribute('d', 'M5,0 15,0');
+	var g = document.createElementNS(NS.SVG, 'g');
 	g.appendChild(path);
 	g.appendChild(path);
 	g.appendChild(path2);
 	g.appendChild(path2);
 	svgcontent.appendChild(g);
 	svgcontent.appendChild(g);
@@ -114,63 +119,62 @@ var supportsHVLineContainerBBox_ = (function() {
 	document.documentElement.removeChild(svgcontent);
 	document.documentElement.removeChild(svgcontent);
 	// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
 	// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
 	return (bbox.width == 15);
 	return (bbox.width == 15);
-})();
+}());
 
 
 var supportsEditableText_ = (function() {
 var supportsEditableText_ = (function() {
 	// TODO: Find better way to check support for this
 	// TODO: Find better way to check support for this
 	return isOpera_;
 	return isOpera_;
-})();
+}());
 
 
 var supportsGoodDecimals_ = (function() {
 var supportsGoodDecimals_ = (function() {
 	// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
 	// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
-	var rect = document.createElementNS(svgns, 'rect');
-	rect.setAttribute('x',.1);
+	var rect = document.createElementNS(NS.SVG, 'rect');
+	rect.setAttribute('x', 0.1);
 	var crect = rect.cloneNode(false);
 	var crect = rect.cloneNode(false);
 	var retValue = (crect.getAttribute('x').indexOf(',') == -1);
 	var retValue = (crect.getAttribute('x').indexOf(',') == -1);
 	if(!retValue) {
 	if(!retValue) {
-		$.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\
-		Please upgrade to the <a href='http://opera.com'>latest version</a> in which the problems have been fixed.");
+		$.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n'+
+		'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.');
 	}
 	}
 	return retValue;
 	return retValue;
-})();
+}());
 
 
 var supportsNonScalingStroke_ = (function() {
 var supportsNonScalingStroke_ = (function() {
-	var rect = document.createElementNS(svgns, 'rect');
-	rect.setAttribute('style','vector-effect:non-scaling-stroke');
+	var rect = document.createElementNS(NS.SVG, 'rect');
+	rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
 	return rect.style.vectorEffect === 'non-scaling-stroke';
 	return rect.style.vectorEffect === 'non-scaling-stroke';
-})();
+}());
 
 
 var supportsNativeSVGTransformLists_ = (function() {
 var supportsNativeSVGTransformLists_ = (function() {
-	var rect = document.createElementNS(svgns, 'rect');
+	var rect = document.createElementNS(NS.SVG, 'rect');
 	var rxform = rect.transform.baseVal;
 	var rxform = rect.transform.baseVal;
-	
 	var t1 = svg.createSVGTransform();
 	var t1 = svg.createSVGTransform();
 	rxform.appendItem(t1);
 	rxform.appendItem(t1);
 	return rxform.getItem(0) == t1;
 	return rxform.getItem(0) == t1;
-})();
+}());
 
 
 // Public API
 // Public API
 
 
-svgedit.browser.isOpera = function() { return isOpera_; }
-svgedit.browser.isWebkit = function() { return isWebkit_; }
-svgedit.browser.isGecko = function() { return isGecko_; }
-svgedit.browser.isIE = function() { return isIE_; }
-svgedit.browser.isChrome = function() { return isChrome_; }
-svgedit.browser.isWindows = function() { return isWindows_; }
-
-svgedit.browser.supportsSelectors = function() { return supportsSelectors_; }
-svgedit.browser.supportsXpath = function() { return supportsXpath_; }
-
-svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; }
-svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; }
-svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; }
-svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; }
-svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; }
-svgedit.browser.supportsEditableText = function() { return supportsEditableText_; }
-svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; }
-svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; }
-svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; }
-
-}
-
-})();
+svgedit.browser.isOpera = function() { return isOpera_; };
+svgedit.browser.isWebkit = function() { return isWebkit_; };
+svgedit.browser.isGecko = function() { return isGecko_; };
+svgedit.browser.isIE = function() { return isIE_; };
+svgedit.browser.isChrome = function() { return isChrome_; };
+svgedit.browser.isWindows = function() { return isWindows_; };
+svgedit.browser.isMac = function() { return isMac_; };
+svgedit.browser.isTouch = function() { return isTouch_; };
+
+svgedit.browser.supportsSelectors = function() { return supportsSelectors_; };
+svgedit.browser.supportsXpath = function() { return supportsXpath_; };
+
+svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; };
+svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; };
+svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; };
+svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; };
+svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; };
+svgedit.browser.supportsEditableText = function() { return supportsEditableText_; };
+svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; };
+svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; };
+svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; };
+
+}());

Diferenças do arquivo suprimidas por serem muito extensas
+ 248 - 186
main/inc/lib/svg-edit/canvg/canvg.js


+ 0 - 6
main/inc/lib/svg-edit/canvg/index.html

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 31 - 24
main/inc/lib/svg-edit/canvg/rgbcolor.js

@@ -1,15 +1,15 @@
+/*jslint vars: true*/
 /**
 /**
  * A class to parse color values
  * A class to parse color values
  * @author Stoyan Stefanov <sstoo@gmail.com>
  * @author Stoyan Stefanov <sstoo@gmail.com>
  * @link   http://www.phpied.com/rgb-color-parser-in-javascript/
  * @link   http://www.phpied.com/rgb-color-parser-in-javascript/
  * @license Use it if you like it
  * @license Use it if you like it
  */
  */
-function RGBColor(color_string)
-{
+function RGBColor(color_string) { 'use strict';
     this.ok = false;
     this.ok = false;
 
 
     // strip any leading #
     // strip any leading #
-    if (color_string.charAt(0) == '#') { // remove # if any
+    if (color_string.charAt(0) === '#') { // remove # if any
         color_string = color_string.substr(1,6);
         color_string = color_string.substr(1,6);
     }
     }
 
 
@@ -163,9 +163,12 @@ function RGBColor(color_string)
         yellow: 'ffff00',
         yellow: 'ffff00',
         yellowgreen: '9acd32'
         yellowgreen: '9acd32'
     };
     };
-    for (var key in simple_colors) {
-        if (color_string == key) {
-            color_string = simple_colors[key];
+    var key;
+    for (key in simple_colors) {
+        if (simple_colors.hasOwnProperty(key)) {
+            if (color_string == key) {
+                color_string = simple_colors[key];
+            }
         }
         }
     }
     }
     // emd of simple type-in colors
     // emd of simple type-in colors
@@ -177,9 +180,9 @@ function RGBColor(color_string)
             example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
             example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
             process: function (bits){
             process: function (bits){
                 return [
                 return [
-                    parseInt(bits[1]),
-                    parseInt(bits[2]),
-                    parseInt(bits[3])
+                    parseInt(bits[1], 10),
+                    parseInt(bits[2], 10),
+                    parseInt(bits[3], 10)
                 ];
                 ];
             }
             }
         },
         },
@@ -207,13 +210,14 @@ function RGBColor(color_string)
         }
         }
     ];
     ];
 
 
+    var i;
     // search through the definitions to find a match
     // search through the definitions to find a match
-    for (var i = 0; i < color_defs.length; i++) {
+    for (i = 0; i < color_defs.length; i++) {
         var re = color_defs[i].re;
         var re = color_defs[i].re;
         var processor = color_defs[i].process;
         var processor = color_defs[i].process;
         var bits = re.exec(color_string);
         var bits = re.exec(color_string);
         if (bits) {
         if (bits) {
-            channels = processor(bits);
+            var channels = processor(bits);
             this.r = channels[0];
             this.r = channels[0];
             this.g = channels[1];
             this.g = channels[1];
             this.b = channels[2];
             this.b = channels[2];
@@ -230,36 +234,39 @@ function RGBColor(color_string)
     // some getters
     // some getters
     this.toRGB = function () {
     this.toRGB = function () {
         return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
         return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
-    }
+    };
     this.toHex = function () {
     this.toHex = function () {
         var r = this.r.toString(16);
         var r = this.r.toString(16);
         var g = this.g.toString(16);
         var g = this.g.toString(16);
         var b = this.b.toString(16);
         var b = this.b.toString(16);
-        if (r.length == 1) r = '0' + r;
-        if (g.length == 1) g = '0' + g;
-        if (b.length == 1) b = '0' + b;
+        if (r.length === 1) {r = '0' + r;}
+        if (g.length === 1) {g = '0' + g;}
+        if (b.length === 1) {b = '0' + b;}
         return '#' + r + g + b;
         return '#' + r + g + b;
-    }
+    };
 
 
     // help
     // help
     this.getHelpXML = function () {
     this.getHelpXML = function () {
-
-        var examples = new Array();
+        var i, j;
+        var examples = [];
         // add regexps
         // add regexps
-        for (var i = 0; i < color_defs.length; i++) {
+        for (i = 0; i < color_defs.length; i++) {
             var example = color_defs[i].example;
             var example = color_defs[i].example;
-            for (var j = 0; j < example.length; j++) {
+            for (j = 0; j < example.length; j++) {
                 examples[examples.length] = example[j];
                 examples[examples.length] = example[j];
             }
             }
         }
         }
         // add type-in colors
         // add type-in colors
-        for (var sc in simple_colors) {
-            examples[examples.length] = sc;
+        var sc;
+        for (sc in simple_colors) {
+            if (simple_colors.hasOwnProperty(sc)) {
+                examples[examples.length] = sc;
+            }
         }
         }
 
 
         var xml = document.createElement('ul');
         var xml = document.createElement('ul');
         xml.setAttribute('id', 'rgbcolor-examples');
         xml.setAttribute('id', 'rgbcolor-examples');
-        for (var i = 0; i < examples.length; i++) {
+        for (i = 0; i < examples.length; i++) {
             try {
             try {
                 var list_item = document.createElement('li');
                 var list_item = document.createElement('li');
                 var list_color = new RGBColor(examples[i]);
                 var list_color = new RGBColor(examples[i]);
@@ -282,6 +289,6 @@ function RGBColor(color_string)
         }
         }
         return xml;
         return xml;
 
 
-    }
+    };
 
 
 }
 }

+ 145 - 0
main/inc/lib/svg-edit/config-sample.js

@@ -0,0 +1,145 @@
+// DO NOT EDIT THIS FILE!
+// THIS FILE IS JUST A SAMPLE; TO APPLY, YOU MUST
+//   CREATE A NEW FILE config.js AND ADD CONTENTS
+//   SUCH AS SHOWN BELOW INTO THAT FILE.
+
+/*globals svgEditor*/
+/*
+The config.js file is intended for the setting of configuration or
+  preferences which must run early on; if this is not needed, it is
+  recommended that you create an extension instead (for greater
+  reusability and modularity).
+*/
+
+// CONFIG AND EXTENSION SETTING
+/*
+See defaultConfig and defaultExtensions in svg-editor.js for a list
+  of possible configuration settings.
+
+See svg-editor.js for documentation on using setConfig().
+*/
+
+// URL OVERRIDE CONFIG
+svgEditor.setConfig({
+	/**
+	To override the ability for URLs to set URL-based SVG content,
+	    uncomment the following:
+	*/
+	// preventURLContentLoading: true,
+	/**
+	To override the ability for URLs to set other configuration (including
+	    extensions), uncomment the following:
+	*/
+	// preventAllURLConfig: true,
+	/**
+	To override the ability for URLs to set their own extensions,
+	  uncomment the following (note that if setConfig() is used in
+	  extension code, it will still be additive to extensions,
+	  however):
+	*/
+	// lockExtensions: true,
+});
+
+svgEditor.setConfig({
+	/*
+	Provide default values here which differ from that of the editor but
+		which the URL can override
+	*/
+}, {allowInitialUserOverride: true});
+
+// EXTENSION CONFIG
+svgEditor.setConfig({
+	extensions: [
+		// 'ext-overview_window.js', 'ext-markers.js', 'ext-connector.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-imagelib.js', 'ext-grid.js', 'ext-polygon.js', 'ext-star.js', 'ext-panning.js', 'ext-storage.js'
+	]
+	// , noDefaultExtensions: false, // noDefaultExtensions can only be meaningfully used in config.js or in the URL
+});
+
+// OTHER CONFIG
+svgEditor.setConfig({	
+	// canvasName: 'default',
+	// canvas_expansion: 3,
+	// initFill: {
+		// color: 'FF0000', // solid red
+		// opacity: 1
+	// },
+	// initStroke: {
+		// width: 5,
+		// color: '000000', // solid black
+		// opacity: 1
+	// },
+	// initOpacity: 1,
+	// colorPickerCSS: null,
+	// initTool: 'select',
+	// wireframe: false,
+	// showlayers: false,
+	// no_save_warning: false,
+	// PATH CONFIGURATION
+	// imgPath: 'images/',
+	// langPath: 'locale/',
+	// extPath: 'extensions/',
+	// jGraduatePath: 'jgraduate/images/',
+	/*
+	Uncomment the following to allow at least same domain (embedded) access,
+	including file:// access.
+	Setting as `['*']` would allow any domain to access but would be unsafe to
+	data privacy and integrity.
+	*/
+	// allowedOrigins: [window.location.origin || 'null'], // May be 'null' (as a string) when used as a file:// URL
+	// DOCUMENT PROPERTIES
+	// dimensions: [640, 480],
+	// EDITOR OPTIONS
+	// gridSnapping: false,
+	// gridColor: '#000',
+	// baseUnit: 'px',
+	// snappingStep: 10,
+	// showRulers: true,
+	// EXTENSION-RELATED (GRID)
+	// showGrid: false, // Set by ext-grid.js
+	// EXTENSION-RELATED (STORAGE)
+	// noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
+	// forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
+	// emptyStorageOnDecline: true, // Used by ext-storage.js; empty any prior storage if the user declines to store
+});
+
+// PREF CHANGES
+/**
+setConfig() can also be used to set preferences in addition to
+  configuration (see defaultPrefs in svg-editor.js for a list of
+  possible settings), but at least if you are using ext-storage.js
+  to store preferences, it will probably be better to let your
+  users control these.
+As with configuration, one may use allowInitialUserOverride, but
+  in the case of preferences, any previously stored preferences
+  will also thereby be enabled to override this setting (and at a
+  higher priority than any URL preference setting overrides).
+  Failing to use allowInitialUserOverride will ensure preferences
+  are hard-coded here regardless of URL or prior user storage setting.
+*/
+svgEditor.setConfig(
+	{
+		// lang: '', // Set dynamically within locale.js if not previously set
+		// iconsize: '', // Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise
+		/**
+		* When showing the preferences dialog, svg-editor.js currently relies
+		* on curPrefs instead of $.pref, so allowing an override for bkgd_color
+		* means that this value won't have priority over block auto-detection as
+		* far as determining which color shows initially in the preferences
+		* dialog (though it can be changed and saved).
+		*/
+		// bkgd_color: '#FFF',
+		// bkgd_url: '',
+		// img_save: 'embed',
+		// Only shows in UI as far as alert notices
+		// save_notice_done: false,
+		// export_notice_done: false
+	}
+);
+svgEditor.setConfig(
+	{
+		// Indicate pref settings here if you wish to allow user storage or URL settings
+		//   to be able to override your default preferences (unless other config options
+		//   have already explicitly prevented one or the other)
+	},
+	{allowInitialUserOverride: true}
+);

+ 17 - 0
main/inc/lib/svg-edit/config.js

@@ -0,0 +1,17 @@
+/*globals svgEditor*/
+/* see https://code.google.com/p/svg-edit/wiki/ConfigOptions */
+svgEditor.setConfig({
+extensions: [
+    'ext-php_savefile_chamilo.js',
+	'ext-eyedropper.js',
+	'ext-shapes.js',
+	'ext-polygon.js',
+	'ext-star.js'
+],
+    noStorageOnLoad: 'true',
+    selectNew: true,
+    no_save_warning: true,
+    emptyStorageOnDecline: true,
+    iconsize: 'm',
+	allowedOrigins: [window.location.origin] // May be 'null' (as a string) when used as a file:// URL
+});

+ 17 - 18
main/inc/lib/svg-edit/contextmenu.js

@@ -1,3 +1,5 @@
+/*globals $, svgEditor*/
+/*jslint vars: true, eqeq: true*/
 /**
 /**
  * Package: svgedit.contextmenu
  * Package: svgedit.contextmenu
  * 
  * 
@@ -13,55 +15,52 @@ var svgedit = svgedit || {};
 	if (!svgedit.contextmenu) {
 	if (!svgedit.contextmenu) {
 		svgedit.contextmenu = {};
 		svgedit.contextmenu = {};
 	}
 	}
-	self.contextMenuExtensions = {}
+	self.contextMenuExtensions = {};
+	var menuItemIsValid = function(menuItem) {
+		return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function';
+	};
 	var addContextMenuItem = function(menuItem) {
 	var addContextMenuItem = function(menuItem) {
 		// menuItem: {id, label, shortcut, action}
 		// menuItem: {id, label, shortcut, action}
 		if (!menuItemIsValid(menuItem)) {
 		if (!menuItemIsValid(menuItem)) {
-			console
-					.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function");
+			console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function");
 			return;
 			return;
 		}
 		}
 		if (menuItem.id in self.contextMenuExtensions) {
 		if (menuItem.id in self.contextMenuExtensions) {
-			console.error('Cannot add extension "' + menuItem.id
-					+ '", an extension by that name already exists"');
+			console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
 			return;
 			return;
 		}
 		}
 		// Register menuItem action, see below for deferred menu dom injection
 		// Register menuItem action, see below for deferred menu dom injection
 		console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}");
 		console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}");
 		self.contextMenuExtensions[menuItem.id] = menuItem;
 		self.contextMenuExtensions[menuItem.id] = menuItem;
 		//TODO: Need to consider how to handle custom enable/disable behavior
 		//TODO: Need to consider how to handle custom enable/disable behavior
-	}
+	};
 	var hasCustomHandler = function(handlerKey) {
 	var hasCustomHandler = function(handlerKey) {
 		return self.contextMenuExtensions[handlerKey] && true;
 		return self.contextMenuExtensions[handlerKey] && true;
-	}
+	};
 	var getCustomHandler = function(handlerKey) {
 	var getCustomHandler = function(handlerKey) {
 		return self.contextMenuExtensions[handlerKey].action;
 		return self.contextMenuExtensions[handlerKey].action;
-	}
+	};
 	var injectExtendedContextMenuItemIntoDom = function(menuItem) {
 	var injectExtendedContextMenuItemIntoDom = function(menuItem) {
-		if (Object.keys(self.contextMenuExtensions).length == 0) {
+		if (Object.keys(self.contextMenuExtensions).length === 0) {
 			// all menuItems appear at the bottom of the menu in their own container.
 			// all menuItems appear at the bottom of the menu in their own container.
 			// if this is the first extension menu we need to add the separator.
 			// if this is the first extension menu we need to add the separator.
 			$("#cmenu_canvas").append("<li class='separator'>");
 			$("#cmenu_canvas").append("<li class='separator'>");
 		}
 		}
 		var shortcut = menuItem.shortcut || "";
 		var shortcut = menuItem.shortcut || "";
-		$("#cmenu_canvas").append("<li class='disabled'><a href='#" + menuItem.id + "'>"                   
+		$("#cmenu_canvas").append("<li class='disabled'><a href='#" + menuItem.id + "'>"
 									+ menuItem.label + "<span class='shortcut'>"
 									+ menuItem.label + "<span class='shortcut'>"
 									+ shortcut + "</span></a></li>");
 									+ shortcut + "</span></a></li>");
-	}
-
-	var menuItemIsValid = function(menuItem) {
-		return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function';
-	}
-	
+	};
 	// Defer injection to wait out initial menu processing. This probably goes away once all context
 	// Defer injection to wait out initial menu processing. This probably goes away once all context
 	// menu behavior is brought here.
 	// menu behavior is brought here.
 	svgEditor.ready(function() {
 	svgEditor.ready(function() {
+		var menuItem;
 		for (menuItem in contextMenuExtensions) {
 		for (menuItem in contextMenuExtensions) {
 			injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]);
 			injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]);
 		}
 		}
 	});
 	});
-	svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}}
+	svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {};};
 	svgedit.contextmenu.add = addContextMenuItem;
 	svgedit.contextmenu.add = addContextMenuItem;
 	svgedit.contextmenu.hasCustomHandler = hasCustomHandler;
 	svgedit.contextmenu.hasCustomHandler = hasCustomHandler;
 	svgedit.contextmenu.getCustomHandler = getCustomHandler;
 	svgedit.contextmenu.getCustomHandler = getCustomHandler;
-})();
+}());

+ 0 - 6
main/inc/lib/svg-edit/contextmenu/index.html

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 2 - 3
main/inc/lib/svg-edit/contextmenu/jquery.contextMenu.js

@@ -36,14 +36,13 @@ if(jQuery)( function() {
 
 
 				// Add contextMenu class
 				// Add contextMenu class
 				menu.addClass('contextMenu');
 				menu.addClass('contextMenu');
-				
 				// Simulate a true right click
 				// Simulate a true right click
-				$(this).mousedown( function(e) {
+				$(this).bind( "mousedown", function(e) {
 					var evt = e;
 					var evt = e;
 					$(this).mouseup( function(e) {
 					$(this).mouseup( function(e) {
 						var srcElement = $(this);
 						var srcElement = $(this);
 						srcElement.unbind('mouseup');
 						srcElement.unbind('mouseup');
-						if( evt.button === 2 || o.allowLeft) {
+						if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) {
 							e.stopPropagation();
 							e.stopPropagation();
 							// Hide context menus that may be showing
 							// Hide context menus that may be showing
 							$(".contextMenu").hide();
 							$(".contextMenu").hide();

+ 0 - 22
main/inc/lib/svg-edit/contextmenu/jquery.contextMenu.min.js

@@ -1,22 +0,0 @@
-// jQuery Context Menu Plugin
-//
-// Version 1.01
-//
-// Cory S.N. LaViska
-// A Beautiful Site (http://abeautifulsite.net/)
-//
-// Modifications by Alexis Deveria
-//
-// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
-//
-// Terms of Use
-//
-// This plugin is dual-licensed under the GNU General Public License
-//   and the MIT License and is copyright A Beautiful Site, LLC.
-//
-jQuery&&function(){var i=$(window),e=$(document);$.extend($.fn,{contextMenu:function(a,d){if(a.menu==undefined)return false;if(a.inSpeed==undefined)a.inSpeed=150;if(a.outSpeed==undefined)a.outSpeed=75;if(a.inSpeed==0)a.inSpeed=-1;if(a.outSpeed==0)a.outSpeed=-1;$(this).each(function(){var c=$(this),j=$(c).offset(),b=$("#"+a.menu);b.addClass("contextMenu");$(this).mousedown(function(m){$(this).mouseup(function(f){var k=$(this);k.unbind("mouseup");if(m.button===2||a.allowLeft){f.stopPropagation();$(".contextMenu").hide();
-if(c.hasClass("disabled"))return false;var g=f.pageX,h=f.pageY;f=i.width()-b.width();var l=i.height()-b.height();if(g>f-15)g=f-15;if(h>l-30)h=l-30;e.unbind("click");b.css({top:h,left:g}).fadeIn(a.inSpeed);b.find("A").mouseover(function(){b.find("LI.hover").removeClass("hover");$(this).parent().addClass("hover")}).mouseout(function(){b.find("LI.hover").removeClass("hover")});e.keypress(function(n){switch(n.keyCode){case 38:if(b.find("LI.hover").length){b.find("LI.hover").removeClass("hover").prevAll("LI:not(.disabled)").eq(0).addClass("hover");
-b.find("LI.hover").length||b.find("LI:last").addClass("hover")}else b.find("LI:last").addClass("hover");break;case 40:if(b.find("LI.hover").length==0)b.find("LI:first").addClass("hover");else{b.find("LI.hover").removeClass("hover").nextAll("LI:not(.disabled)").eq(0).addClass("hover");b.find("LI.hover").length||b.find("LI:first").addClass("hover")}break;case 13:b.find("LI.hover A").trigger("click");break;case 27:e.trigger("click")}});b.find("A").unbind("mouseup");b.find("LI:not(.disabled) A").mouseup(function(){e.unbind("click").unbind("keypress");
-$(".contextMenu").hide();d&&d($(this).attr("href").substr(1),$(k),{x:g-j.left,y:h-j.top,docX:g,docY:h});return false});setTimeout(function(){e.click(function(){e.unbind("click").unbind("keypress");b.fadeOut(a.outSpeed);return false})},0)}})});if($.browser.mozilla)$("#"+a.menu).each(function(){$(this).css({MozUserSelect:"none"})});else $.browser.msie?$("#"+a.menu).each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})}):$("#"+a.menu).each(function(){$(this).bind("mousedown.disableTextSelect",
-function(){return false})});$(c).add($("UL.contextMenu")).bind("contextmenu",function(){return false})});return $(this)},disableContextMenuItems:function(a){if(a==undefined){$(this).find("LI").addClass("disabled");return $(this)}$(this).each(function(){if(a!=undefined)for(var d=a.split(","),c=0;c<d.length;c++)$(this).find('A[href="'+d[c]+'"]').parent().addClass("disabled")});return $(this)},enableContextMenuItems:function(a){if(a==undefined){$(this).find("LI.disabled").removeClass("disabled");return $(this)}$(this).each(function(){if(a!=
-undefined)for(var d=a.split(","),c=0;c<d.length;c++)$(this).find('A[href="'+d[c]+'"]').parent().removeClass("disabled")});return $(this)},disableContextMenu:function(){$(this).each(function(){$(this).addClass("disabled")});return $(this)},enableContextMenu:function(){$(this).each(function(){$(this).removeClass("disabled")});return $(this)},destroyContextMenu:function(){$(this).each(function(){$(this).unbind("mousedown").unbind("mouseup")});return $(this)}})}(jQuery);

+ 316 - 0
main/inc/lib/svg-edit/coords.js

@@ -0,0 +1,316 @@
+/*globals $, svgroot */
+/*jslint vars: true, eqeq: true, forin: true*/
+/**
+ * Coords.
+ *
+ * Licensed under the MIT License
+ *
+ */
+
+// Dependencies:
+// 1) jquery.js
+// 2) math.js
+// 3) browser.js
+// 4) svgutils.js
+// 5) units.js
+// 6) svgtransformlist.js
+
+var svgedit = svgedit || {};
+
+(function() {'use strict';
+
+if (!svgedit.coords) {
+  svgedit.coords = {};
+}
+
+// this is how we map paths to our preferred relative segment types
+var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 
+    'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
+
+/**
+ * @typedef editorContext
+ * @type {?object}
+ * @property {function} getGridSnapping
+ * @property {function} getDrawing
+*/
+var editorContext_ = null;
+
+/**
+* @param {editorContext} editorContext
+*/
+svgedit.coords.init = function(editorContext) {
+  editorContext_ = editorContext;
+};
+
+/**
+ * Applies coordinate changes to an element based on the given matrix
+ * @param {Element} selected - DOM element to be changed
+ * @param {object} changes - Object with changes to be remapped
+ * @param {SVGMatrix} m - Matrix object to use for remapping coordinates
+*/
+svgedit.coords.remapElement = function(selected, changes, m) {
+  var i, type,
+    remap = function(x, y) { return svgedit.math.transformPoint(x, y, m); },
+    scalew = function(w) { return m.a * w; },
+    scaleh = function(h) { return m.d * h; },
+    doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
+    finishUp = function() {
+      var o;
+      if (doSnapping) {
+        for (o in changes) {
+          changes[o] = svgedit.utilities.snapToGrid(changes[o]);
+        }
+      }
+      svgedit.utilities.assignAttributes(selected, changes, 1000, true);
+    },
+    box = svgedit.utilities.getBBox(selected);
+
+  for (i = 0; i < 2; i++) {
+    type = i === 0 ? 'fill' : 'stroke';
+    var attrVal = selected.getAttribute(type);
+    if (attrVal && attrVal.indexOf('url(') === 0) {
+      if (m.a < 0 || m.d < 0) {
+        var grad = svgedit.utilities.getRefElem(attrVal);
+        var newgrad = grad.cloneNode(true);
+        if (m.a < 0) {
+          // flip x
+          var x1 = newgrad.getAttribute('x1');
+          var x2 = newgrad.getAttribute('x2');
+          newgrad.setAttribute('x1', -(x1 - 1));
+          newgrad.setAttribute('x2', -(x2 - 1));
+        } 
+
+        if (m.d < 0) {
+          // flip y
+          var y1 = newgrad.getAttribute('y1');
+          var y2 = newgrad.getAttribute('y2');
+          newgrad.setAttribute('y1', -(y1 - 1));
+          newgrad.setAttribute('y2', -(y2 - 1));
+        }
+        newgrad.id = editorContext_.getDrawing().getNextId();
+        svgedit.utilities.findDefs().appendChild(newgrad);
+        selected.setAttribute(type, 'url(#' + newgrad.id + ')');
+      }
+
+      // Not really working :(
+//      if (selected.tagName === 'path') {
+//        reorientGrads(selected, m);
+//      }
+    }
+  }
+
+  var elName = selected.tagName;
+  var chlist, mt;
+  if (elName === 'g' || elName === 'text' || elName == 'tspan' || elName === 'use') {
+    // if it was a translate, then just update x,y
+    if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && (m.e != 0 || m.f != 0) ) {
+      // [T][M] = [M][T']
+      // therefore [T'] = [M_inv][T][M]
+      var existing = svgedit.math.transformListToTransform(selected).matrix,
+          t_new = svgedit.math.matrixMultiply(existing.inverse(), m, existing);
+      changes.x = parseFloat(changes.x) + t_new.e;
+      changes.y = parseFloat(changes.y) + t_new.f;
+    } else {
+      // we just absorb all matrices into the element and don't do any remapping
+      chlist = svgedit.transformlist.getTransformList(selected);
+      mt = svgroot.createSVGTransform();
+      mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
+      chlist.clear();
+      chlist.appendItem(mt);
+    }
+  }
+  var c, pt, pt1, pt2, len;
+  // now we have a set of changes and an applied reduced transform list
+  // we apply the changes directly to the DOM
+  switch (elName) {
+    case 'foreignObject':
+    case 'rect':
+    case 'image':
+      // Allow images to be inverted (give them matrix when flipped)
+      if (elName === 'image' && (m.a < 0 || m.d < 0)) {
+        // Convert to matrix
+        chlist = svgedit.transformlist.getTransformList(selected);
+        mt = svgroot.createSVGTransform();
+        mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
+        chlist.clear();
+        chlist.appendItem(mt);
+      } else {
+        pt1 = remap(changes.x, changes.y);
+        changes.width = scalew(changes.width);
+        changes.height = scaleh(changes.height);
+        changes.x = pt1.x + Math.min(0, changes.width);
+        changes.y = pt1.y + Math.min(0, changes.height);
+        changes.width = Math.abs(changes.width);
+        changes.height = Math.abs(changes.height);
+      }
+      finishUp();
+      break;
+    case 'ellipse':
+      c = remap(changes.cx, changes.cy);
+      changes.cx = c.x;
+      changes.cy = c.y;
+      changes.rx = scalew(changes.rx);
+      changes.ry = scaleh(changes.ry);
+      changes.rx = Math.abs(changes.rx);
+      changes.ry = Math.abs(changes.ry);
+      finishUp();
+      break;
+    case 'circle':
+      c = remap(changes.cx,changes.cy);
+      changes.cx = c.x;
+      changes.cy = c.y;
+      // take the minimum of the new selected box's dimensions for the new circle radius
+      var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m);
+      var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
+      changes.r = Math.min(w/2, h/2);
+
+      if (changes.r) {changes.r = Math.abs(changes.r);}
+      finishUp();
+      break;
+    case 'line':
+      pt1 = remap(changes.x1, changes.y1);
+      pt2 = remap(changes.x2, changes.y2);
+      changes.x1 = pt1.x;
+      changes.y1 = pt1.y;
+      changes.x2 = pt2.x;
+      changes.y2 = pt2.y;
+      // deliberately fall through here
+    case 'text':
+    case 'tspan':
+    case 'use':
+      finishUp();
+      break;
+    case 'g':
+      var gsvg = $(selected).data('gsvg');
+      if (gsvg) {
+          svgedit.utilities.assignAttributes(gsvg, changes, 1000, true);
+      }
+      break;
+    case 'polyline':
+    case 'polygon':
+      len = changes.points.length;
+      for (i = 0; i < len; ++i) {
+        pt = changes.points[i];
+        pt = remap(pt.x, pt.y);
+        changes.points[i].x = pt.x;
+        changes.points[i].y = pt.y;
+      }
+
+      len = changes.points.length;
+      var pstr = '';
+      for (i = 0; i < len; ++i) {
+        pt = changes.points[i];
+        pstr += pt.x + ',' + pt.y + ' ';
+      }
+      selected.setAttribute('points', pstr);
+      break;
+    case 'path':
+      var seg;
+      var segList = selected.pathSegList;
+      len = segList.numberOfItems;
+      changes.d = [];
+      for (i = 0; i < len; ++i) {
+          seg = segList.getItem(i);
+          changes.d[i] = {
+              type: seg.pathSegType,
+              x: seg.x,
+              y: seg.y,
+              x1: seg.x1,
+              y1: seg.y1,
+              x2: seg.x2,
+              y2: seg.y2,
+              r1: seg.r1,
+              r2: seg.r2,
+              angle: seg.angle,
+              largeArcFlag: seg.largeArcFlag,
+              sweepFlag: seg.sweepFlag
+          };
+      }
+
+      len = changes.d.length;
+      var firstseg = changes.d[0],
+          currentpt = remap(firstseg.x, firstseg.y);
+      changes.d[0].x = currentpt.x;
+      changes.d[0].y = currentpt.y;
+      for (i = 1; i < len; ++i) {
+        seg = changes.d[i];
+        type = seg.type;
+        // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
+        // if relative, we want to scalew, scaleh
+        if (type % 2 == 0) { // absolute
+          var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands
+              thisy = (seg.y != undefined) ? seg.y : currentpt.y; // for H commands
+          pt = remap(thisx,thisy);
+          pt1 = remap(seg.x1, seg.y1);
+          pt2 = remap(seg.x2, seg.y2);
+          seg.x = pt.x;
+          seg.y = pt.y;
+          seg.x1 = pt1.x;
+          seg.y1 = pt1.y;
+          seg.x2 = pt2.x;
+          seg.y2 = pt2.y;
+          seg.r1 = scalew(seg.r1);
+          seg.r2 = scaleh(seg.r2);
+        }
+        else { // relative
+          seg.x = scalew(seg.x);
+          seg.y = scaleh(seg.y);
+          seg.x1 = scalew(seg.x1);
+          seg.y1 = scaleh(seg.y1);
+          seg.x2 = scalew(seg.x2);
+          seg.y2 = scaleh(seg.y2);
+          seg.r1 = scalew(seg.r1);
+          seg.r2 = scaleh(seg.r2);
+        }
+      } // for each segment
+
+      var dstr = '';
+      len = changes.d.length;
+      for (i = 0; i < len; ++i) {
+        seg = changes.d[i];
+        type = seg.type;
+        dstr += pathMap[type];
+        switch (type) {
+            case 13: // relative horizontal line (h)
+            case 12: // absolute horizontal line (H)
+                dstr += seg.x + ' ';
+                break;
+            case 15: // relative vertical line (v)
+            case 14: // absolute vertical line (V)
+                dstr += seg.y + ' ';
+                break;
+            case 3: // relative move (m)
+            case 5: // relative line (l)
+            case 19: // relative smooth quad (t)
+            case 2: // absolute move (M)
+            case 4: // absolute line (L)
+            case 18: // absolute smooth quad (T)
+                dstr += seg.x + ',' + seg.y + ' ';
+                break;
+            case 7: // relative cubic (c)
+            case 6: // absolute cubic (C)
+                dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' +
+                     seg.x + ',' + seg.y + ' ';
+                break;
+            case 9: // relative quad (q) 
+            case 8: // absolute quad (Q)
+                dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' ';
+                break;
+            case 11: // relative elliptical arc (a)
+            case 10: // absolute elliptical arc (A)
+                dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + (+seg.largeArcFlag) +
+                    ' ' + (+seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' ';
+                break;
+            case 17: // relative smooth cubic (s)
+            case 16: // absolute smooth cubic (S)
+                dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' ';
+                break;
+          }
+      }
+
+      selected.setAttribute('d', dstr);
+      break;
+    }
+};
+
+}());

+ 6 - 0
main/inc/lib/svg-edit/custom.css

@@ -0,0 +1,6 @@
+#main_icon {
+    width:38px !important;
+}
+#tools_top {
+    left: 55px !important;
+}

+ 188 - 179
main/inc/lib/svg-edit/draw.js

@@ -1,7 +1,9 @@
+/*globals $, svgedit*/
+/*jslint vars: true, eqeq: true, todo: true*/
 /**
 /**
  * Package: svgedit.draw
  * Package: svgedit.draw
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2011 Jeff Schiller
  * Copyright(c) 2011 Jeff Schiller
  */
  */
@@ -11,20 +13,15 @@
 // 2) browser.js
 // 2) browser.js
 // 3) svgutils.js
 // 3) svgutils.js
 
 
-var svgedit = svgedit || {};
-
-(function() {
+(function() {'use strict';
 
 
 if (!svgedit.draw) {
 if (!svgedit.draw) {
 	svgedit.draw = {};
 	svgedit.draw = {};
 }
 }
+// alias
+var NS = svgedit.NS;
 
 
-var svg_ns = "http://www.w3.org/2000/svg";
-var se_ns = "http://svg-edit.googlecode.com";
-var xmlns_ns = "http://www.w3.org/2000/xmlns/";
-
-var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use';
-var visElems_arr = visElems.split(',');
+var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(',');
 
 
 var RandomizeModes = {
 var RandomizeModes = {
 	LET_DOCUMENT_DECIDE: 0,
 	LET_DOCUMENT_DECIDE: 0,
@@ -35,52 +32,57 @@ var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE;
 
 
 /**
 /**
  * This class encapsulates the concept of a layer in the drawing
  * This class encapsulates the concept of a layer in the drawing
- * @param name {String} Layer name
- * @param child {SVGGElement} Layer SVG group.
+ * @param {String} name - Layer name
+ * @param {SVGGElement} child - Layer SVG group.
  */
  */
 svgedit.draw.Layer = function(name, group) {
 svgedit.draw.Layer = function(name, group) {
 	this.name_ = name;
 	this.name_ = name;
 	this.group_ = group;
 	this.group_ = group;
 };
 };
 
 
+/**
+ * @returns {string} The layer name
+ */
 svgedit.draw.Layer.prototype.getName = function() {
 svgedit.draw.Layer.prototype.getName = function() {
 	return this.name_;
 	return this.name_;
 };
 };
 
 
+/**
+ * @returns {SVGGElement} The layer SVG group
+ */
 svgedit.draw.Layer.prototype.getGroup = function() {
 svgedit.draw.Layer.prototype.getGroup = function() {
 	return this.group_;
 	return this.group_;
 };
 };
 
 
 
 
-// Called to ensure that drawings will or will not have randomized ids.
-// The current_drawing will have its nonce set if it doesn't already.
-// 
-// Params:
-// enableRandomization - flag indicating if documents should have randomized ids
-svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) {
-	randomize_ids = enableRandomization == false ?
+/**
+ * Called to ensure that drawings will or will not have randomized ids.
+ * The currentDrawing will have its nonce set if it doesn't already.
+ * @param {boolean} enableRandomization - flag indicating if documents should have randomized ids
+ * @param {svgedit.draw.Drawing} currentDrawing
+ */
+svgedit.draw.randomizeIds = function(enableRandomization, currentDrawing) {
+	randomize_ids = enableRandomization === false ?
 		RandomizeModes.NEVER_RANDOMIZE :
 		RandomizeModes.NEVER_RANDOMIZE :
 		RandomizeModes.ALWAYS_RANDOMIZE;
 		RandomizeModes.ALWAYS_RANDOMIZE;
 
 
-	if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) {
-		current_drawing.setNonce(Math.floor(Math.random() * 100001));
-	} else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) {
-		current_drawing.clearNonce();
+	if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) {
+		currentDrawing.setNonce(Math.floor(Math.random() * 100001));
+	} else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
+		currentDrawing.clearNonce();
 	}
 	}
 };
 };
 
 
 /**
 /**
  * This class encapsulates the concept of a SVG-edit drawing
  * This class encapsulates the concept of a SVG-edit drawing
- *
- * @param svgElem {SVGSVGElement} The SVG DOM Element that this JS object
+ * @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object
  *     encapsulates.  If the svgElem has a se:nonce attribute on it, then
  *     encapsulates.  If the svgElem has a se:nonce attribute on it, then
  *     IDs will use the nonce as they are generated.
  *     IDs will use the nonce as they are generated.
- * @param opt_idPrefix {String} The ID prefix to use.  Defaults to "svg_"
- *     if not specified.
+ * @param {String=svg_} [opt_idPrefix] - The ID prefix to use.
  */
  */
 svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
 svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
 	if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
 	if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
-		svgElem.tagName != 'svg' || svgElem.namespaceURI != svg_ns) {
+		svgElem.tagName != 'svg' || svgElem.namespaceURI != NS.SVG) {
 		throw "Error: svgedit.draw.Drawing instance initialized without a <svg> element";
 		throw "Error: svgedit.draw.Drawing instance initialized without a <svg> element";
 	}
 	}
 
 
@@ -127,8 +129,8 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
 	 * The nonce to use to uniquely identify elements across drawings.
 	 * The nonce to use to uniquely identify elements across drawings.
 	 * @type {!String}
 	 * @type {!String}
 	 */
 	 */
-	this.nonce_ = "";
-	var n = this.svgElem_.getAttributeNS(se_ns, 'nonce');
+	this.nonce_ = '';
+	var n = this.svgElem_.getAttributeNS(NS.SE, 'nonce');
 	// If already set in the DOM, use the nonce throughout the document
 	// If already set in the DOM, use the nonce throughout the document
 	// else, if randomizeIds(true) has been called, create and set the nonce.
 	// else, if randomizeIds(true) has been called, create and set the nonce.
 	if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) {
 	if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) {
@@ -138,51 +140,66 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
 	}
 	}
 };
 };
 
 
-svgedit.draw.Drawing.prototype.getElem_ = function(id) {
-	if(this.svgElem_.querySelector) {
+/**
+ * @param {string} id Element ID to retrieve
+ * @returns {Element} SVG element within the root SVGSVGElement
+*/
+svgedit.draw.Drawing.prototype.getElem_ = function (id) {
+	if (this.svgElem_.querySelector) {
 		// querySelector lookup
 		// querySelector lookup
-		return this.svgElem_.querySelector('#'+id);
-	} else {
-		// jQuery lookup: twice as slow as xpath in FF
-		return $(this.svgElem_).find('[id=' + id + ']')[0];
+		return this.svgElem_.querySelector('#' + id);
 	}
 	}
+	// jQuery lookup: twice as slow as xpath in FF
+	return $(this.svgElem_).find('[id=' + id + ']')[0];
 };
 };
 
 
-svgedit.draw.Drawing.prototype.getSvgElem = function() {
+/**
+ * @returns {SVGSVGElement}
+ */
+svgedit.draw.Drawing.prototype.getSvgElem = function () {
 	return this.svgElem_;
 	return this.svgElem_;
 };
 };
 
 
+/**
+ * @returns {!string|number} The previously set nonce
+ */
 svgedit.draw.Drawing.prototype.getNonce = function() {
 svgedit.draw.Drawing.prototype.getNonce = function() {
 	return this.nonce_;
 	return this.nonce_;
 };
 };
 
 
+/**
+ * @param {!string|number} n The nonce to set
+ */
 svgedit.draw.Drawing.prototype.setNonce = function(n) {
 svgedit.draw.Drawing.prototype.setNonce = function(n) {
-	this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns);
-	this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n);
+	this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
+	this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n);
 	this.nonce_ = n;
 	this.nonce_ = n;
 };
 };
 
 
-svgedit.draw.Drawing.prototype.clearNonce = function() {
+/**
+ * Clears any previously set nonce
+ */
+svgedit.draw.Drawing.prototype.clearNonce = function () {
 	// We deliberately leave any se:nonce attributes alone,
 	// We deliberately leave any se:nonce attributes alone,
 	// we just don't use it to randomize ids.
 	// we just don't use it to randomize ids.
-	this.nonce_ = "";
+	this.nonce_ = '';
 };
 };
 
 
 /**
 /**
  * Returns the latest object id as a string.
  * Returns the latest object id as a string.
  * @return {String} The latest object Id.
  * @return {String} The latest object Id.
  */
  */
-svgedit.draw.Drawing.prototype.getId = function() {
+svgedit.draw.Drawing.prototype.getId = function () {
 	return this.nonce_ ?
 	return this.nonce_ ?
-		this.idPrefix + this.nonce_ +'_' + this.obj_num :
- 		this.idPrefix + this.obj_num;
+		this.idPrefix + this.nonce_ + '_' + this.obj_num :
+		this.idPrefix + this.obj_num;
 };
 };
 
 
 /**
 /**
  * Returns the next object Id as a string.
  * Returns the next object Id as a string.
  * @return {String} The next object Id to use.
  * @return {String} The next object Id to use.
  */
  */
-svgedit.draw.Drawing.prototype.getNextId = function() {
+svgedit.draw.Drawing.prototype.getNextId = function () {
 	var oldObjNum = this.obj_num;
 	var oldObjNum = this.obj_num;
 	var restoreOldObjNum = false;
 	var restoreOldObjNum = false;
 
 
@@ -214,28 +231,25 @@ svgedit.draw.Drawing.prototype.getNextId = function() {
 	return id;
 	return id;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.releaseId
-// Releases the object Id, letting it be used as the next id in getNextId().
-// This method DOES NOT remove any elements from the DOM, it is expected
-// that client code will do this.
-//
-// Parameters:
-// id - The id to release.
-//
-// Returns:
-// True if the id was valid to be released, false otherwise.
-svgedit.draw.Drawing.prototype.releaseId = function(id) {
+/**
+ * Releases the object Id, letting it be used as the next id in getNextId().
+ * This method DOES NOT remove any elements from the DOM, it is expected
+ * that client code will do this.
+ * @param {string} id - The id to release.
+ * @returns {boolean} True if the id was valid to be released, false otherwise.
+*/
+svgedit.draw.Drawing.prototype.releaseId = function (id) {
 	// confirm if this is a valid id for this Document, else return false
 	// confirm if this is a valid id for this Document, else return false
-	var front = this.idPrefix + (this.nonce_ ? this.nonce_ +'_' : '');
-	if (typeof id != typeof '' || id.indexOf(front) != 0) {
+	var front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : '');
+	if (typeof id !== 'string' || id.indexOf(front) !== 0) {
 		return false;
 		return false;
 	}
 	}
 	// extract the obj_num of this id
 	// extract the obj_num of this id
-	var num = parseInt(id.substr(front.length));
+	var num = parseInt(id.substr(front.length), 10);
 
 
 	// if we didn't get a positive number or we already released this number
 	// if we didn't get a positive number or we already released this number
 	// then return false.
 	// then return false.
-	if (typeof num != typeof 1 || num <= 0 || this.releasedNums.indexOf(num) != -1) {
+	if (typeof num !== 'number' || num <= 0 || this.releasedNums.indexOf(num) != -1) {
 		return false;
 		return false;
 	}
 	}
 	
 	
@@ -245,73 +259,71 @@ svgedit.draw.Drawing.prototype.releaseId = function(id) {
 	return true;
 	return true;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.getNumLayers
-// Returns the number of layers in the current drawing.
-// 
-// Returns:
-// The number of layers in the current drawing.
+/**
+ * Returns the number of layers in the current drawing.
+ * @returns {integer} The number of layers in the current drawing.
+*/
 svgedit.draw.Drawing.prototype.getNumLayers = function() {
 svgedit.draw.Drawing.prototype.getNumLayers = function() {
 	return this.all_layers.length;
 	return this.all_layers.length;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.hasLayer
-// Check if layer with given name already exists
-svgedit.draw.Drawing.prototype.hasLayer = function(name) {
-	for(var i = 0; i < this.getNumLayers(); i++) {
-		if(this.all_layers[i][0] == name) return true;
+/**
+ * Check if layer with given name already exists
+ * @param {string} name - The layer name to check
+*/
+svgedit.draw.Drawing.prototype.hasLayer = function (name) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); i++) {
+		if(this.all_layers[i][0] == name) {return true;}
 	}
 	}
 	return false;
 	return false;
 };
 };
 
 
 
 
-// Function: svgedit.draw.Drawing.getLayerName
-// Returns the name of the ith layer. If the index is out of range, an empty string is returned.
-//
-// Parameters:
-// i - the zero-based index of the layer you are querying.
-// 
-// Returns:
-// The name of the ith layer
-svgedit.draw.Drawing.prototype.getLayerName = function(i) {
+/**
+ * Returns the name of the ith layer. If the index is out of range, an empty string is returned.
+ * @param {integer} i - The zero-based index of the layer you are querying.
+ * @returns {string} The name of the ith layer (or the empty string if none found)
+*/
+svgedit.draw.Drawing.prototype.getLayerName = function (i) {
 	if (i >= 0 && i < this.getNumLayers()) {
 	if (i >= 0 && i < this.getNumLayers()) {
 		return this.all_layers[i][0];
 		return this.all_layers[i][0];
 	}
 	}
-	return "";
+	return '';
 };
 };
 
 
-// Function: svgedit.draw.Drawing.getCurrentLayer
-// Returns:
-// The SVGGElement representing the current layer.
+/**
+ * @returns {SVGGElement} The SVGGElement representing the current layer.
+ */
 svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
 svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
 	return this.current_layer;
 	return this.current_layer;
 };
 };
 
 
-// Function: getCurrentLayerName
-// Returns the name of the currently selected layer. If an error occurs, an empty string 
-// is returned.
-//
-// Returns:
-// The name of the currently active layer.
-svgedit.draw.Drawing.prototype.getCurrentLayerName = function() {
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+/**
+ * Returns the name of the currently selected layer. If an error occurs, an empty string 
+ * is returned.
+ * @returns The name of the currently active layer (or the empty string if none found).
+*/
+svgedit.draw.Drawing.prototype.getCurrentLayerName = function () {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (this.all_layers[i][1] == this.current_layer) {
 		if (this.all_layers[i][1] == this.current_layer) {
 			return this.getLayerName(i);
 			return this.getLayerName(i);
 		}
 		}
 	}
 	}
-	return "";
+	return '';
 };
 };
 
 
-// Function: setCurrentLayer
-// Sets the current layer. If the name is not a valid layer name, then this function returns
-// false. Otherwise it returns true. This is not an undo-able action.
-//
-// Parameters:
-// name - the name of the layer you want to switch to.
-//
-// Returns:
-// true if the current layer was switched, otherwise false
+/**
+ * Sets the current layer. If the name is not a valid layer name, then this
+ * function returns false. Otherwise it returns true. This is not an
+ * undo-able action.
+ * @param {string} name - The name of the layer you want to switch to.
+ * @returns {boolean} true if the current layer was switched, otherwise false
+ */
 svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) {
 svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) {
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (name == this.getLayerName(i)) {
 		if (name == this.getLayerName(i)) {
 			if (this.current_layer != this.all_layers[i][1]) {
 			if (this.current_layer != this.all_layers[i][1]) {
 				this.current_layer.setAttribute("style", "pointer-events:none");
 				this.current_layer.setAttribute("style", "pointer-events:none");
@@ -325,11 +337,11 @@ svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) {
 };
 };
 
 
 
 
-// Function: svgedit.draw.Drawing.deleteCurrentLayer
-// Deletes the current layer from the drawing and then clears the selection. This function 
-// then calls the 'changed' handler.  This is an undoable action.
-// Returns:
-// The SVGGElement of the layer removed or null.
+/**
+ * Deletes the current layer from the drawing and then clears the selection.
+ * This function then calls the 'changed' handler.  This is an undoable action.
+ * @returns {SVGGElement} The SVGGElement of the layer removed or null.
+ */
 svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() {
 svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() {
 	if (this.current_layer && this.getNumLayers() > 1) {
 	if (this.current_layer && this.getNumLayers() > 1) {
 		// actually delete from the DOM and return it
 		// actually delete from the DOM and return it
@@ -342,9 +354,10 @@ svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() {
 	return null;
 	return null;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.identifyLayers
-// Updates layer system and sets the current layer to the
-// top-most layer (last <g> child of this drawing).
+/**
+ * Updates layer system and sets the current layer to the
+ * top-most layer (last <g> child of this drawing).
+*/
 svgedit.draw.Drawing.prototype.identifyLayers = function() {
 svgedit.draw.Drawing.prototype.identifyLayers = function() {
 	this.all_layers = [];
 	this.all_layers = [];
 	var numchildren = this.svgElem_.childNodes.length;
 	var numchildren = this.svgElem_.childNodes.length;
@@ -352,14 +365,15 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
 	var orphans = [], layernames = [];
 	var orphans = [], layernames = [];
 	var a_layer = null;
 	var a_layer = null;
 	var childgroups = false;
 	var childgroups = false;
-	for (var i = 0; i < numchildren; ++i) {
+	var i;
+	for (i = 0; i < numchildren; ++i) {
 		var child = this.svgElem_.childNodes.item(i);
 		var child = this.svgElem_.childNodes.item(i);
 		// for each g, find its layer name
 		// for each g, find its layer name
 		if (child && child.nodeType == 1) {
 		if (child && child.nodeType == 1) {
 			if (child.tagName == "g") {
 			if (child.tagName == "g") {
 				childgroups = true;
 				childgroups = true;
-				var name = $("title",child).text();
-				
+				var name = $("title", child).text();
+
 				// Hack for Opera 10.60
 				// Hack for Opera 10.60
 				if(!name && svgedit.browser.isOpera() && child.querySelectorAll) {
 				if(!name && svgedit.browser.isOpera() && child.querySelectorAll) {
 					name = $(child.querySelectorAll('title')).text();
 					name = $(child.querySelectorAll('title')).text();
@@ -368,7 +382,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
 				// store layer and name in global variable
 				// store layer and name in global variable
 				if (name) {
 				if (name) {
 					layernames.push(name);
 					layernames.push(name);
-					this.all_layers.push( [name,child] );
+					this.all_layers.push( [name, child] );
 					a_layer = child;
 					a_layer = child;
 					svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");});
 					svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");});
 					a_layer.setAttribute("style", "pointer-events:none");
 					a_layer.setAttribute("style", "pointer-events:none");
@@ -379,7 +393,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
 				}
 				}
 			}
 			}
 			// if child has is "visible" (i.e. not a <title> or <defs> element), then it is an orphan
 			// if child has is "visible" (i.e. not a <title> or <defs> element), then it is an orphan
-			else if(~visElems_arr.indexOf(child.nodeName)) {
+			else if(~visElems.indexOf(child.nodeName)) {
 				var bb = svgedit.utilities.getBBox(child);
 				var bb = svgedit.utilities.getBBox(child);
 				orphans.push(child);
 				orphans.push(child);
 			}
 			}
@@ -389,39 +403,37 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
 	// create a new layer and add all the orphans to it
 	// create a new layer and add all the orphans to it
 	var svgdoc = this.svgElem_.ownerDocument;
 	var svgdoc = this.svgElem_.ownerDocument;
 	if (orphans.length > 0 || !childgroups) {
 	if (orphans.length > 0 || !childgroups) {
-		var i = 1;
+		i = 1;
 		// TODO(codedread): What about internationalization of "Layer"?
 		// TODO(codedread): What about internationalization of "Layer"?
 		while (layernames.indexOf(("Layer " + i)) >= 0) { i++; }
 		while (layernames.indexOf(("Layer " + i)) >= 0) { i++; }
 		var newname = "Layer " + i;
 		var newname = "Layer " + i;
-		a_layer = svgdoc.createElementNS(svg_ns, "g");
-		var layer_title = svgdoc.createElementNS(svg_ns, "title");
+		a_layer = svgdoc.createElementNS(NS.SVG, "g");
+		var layer_title = svgdoc.createElementNS(NS.SVG, "title");
 		layer_title.textContent = newname;
 		layer_title.textContent = newname;
 		a_layer.appendChild(layer_title);
 		a_layer.appendChild(layer_title);
-		for (var j = 0; j < orphans.length; ++j) {
+		var j;
+		for (j = 0; j < orphans.length; ++j) {
 			a_layer.appendChild(orphans[j]);
 			a_layer.appendChild(orphans[j]);
 		}
 		}
 		this.svgElem_.appendChild(a_layer);
 		this.svgElem_.appendChild(a_layer);
 		this.all_layers.push( [newname, a_layer] );
 		this.all_layers.push( [newname, a_layer] );
 	}
 	}
-	svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style","pointer-events:inherit");});
+	svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style", "pointer-events:inherit");});
 	this.current_layer = a_layer;
 	this.current_layer = a_layer;
-	this.current_layer.setAttribute("style","pointer-events:all");
+	this.current_layer.setAttribute("style", "pointer-events:all");
 };
 };
 
 
-// Function: svgedit.draw.Drawing.createLayer
-// Creates a new top-level layer in the drawing with the given name and 
-// sets the current layer to it.
-//
-// Parameters:
-// name - The given name
-//
-// Returns:
-// The SVGGElement of the new layer, which is also the current layer
-// of this drawing.
+/**
+ * Creates a new top-level layer in the drawing with the given name and 
+ * sets the current layer to it.
+ * @param {string} name - The given name
+ * @returns {SVGGElement} The SVGGElement of the new layer, which is
+ * also the current layer of this drawing.
+*/
 svgedit.draw.Drawing.prototype.createLayer = function(name) {
 svgedit.draw.Drawing.prototype.createLayer = function(name) {
 	var svgdoc = this.svgElem_.ownerDocument;
 	var svgdoc = this.svgElem_.ownerDocument;
-	var new_layer = svgdoc.createElementNS(svg_ns, "g");
-	var layer_title = svgdoc.createElementNS(svg_ns, "title");
+	var new_layer = svgdoc.createElementNS(NS.SVG, "g");
+	var layer_title = svgdoc.createElementNS(NS.SVG, "title");
 	layer_title.textContent = name;
 	layer_title.textContent = name;
 	new_layer.appendChild(layer_title);
 	new_layer.appendChild(layer_title);
 	this.svgElem_.appendChild(new_layer);
 	this.svgElem_.appendChild(new_layer);
@@ -429,70 +441,66 @@ svgedit.draw.Drawing.prototype.createLayer = function(name) {
 	return new_layer;
 	return new_layer;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.getLayerVisibility
-// Returns whether the layer is visible.  If the layer name is not valid, then this function
-// returns false.
-//
-// Parameters:
-// layername - the name of the layer which you want to query.
-//
-// Returns:
-// The visibility state of the layer, or false if the layer name was invalid.
+/**
+ * Returns whether the layer is visible.  If the layer name is not valid,
+ * then this function returns false.
+ * @param {string} layername - The name of the layer which you want to query.
+ * @returns {boolean} The visibility state of the layer, or false if the layer name was invalid.
+*/
 svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) {
 svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) {
 	// find the layer
 	// find the layer
 	var layer = null;
 	var layer = null;
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (this.getLayerName(i) == layername) {
 		if (this.getLayerName(i) == layername) {
 			layer = this.all_layers[i][1];
 			layer = this.all_layers[i][1];
 			break;
 			break;
 		}
 		}
 	}
 	}
-	if (!layer) return false;
-	return (layer.getAttribute('display') != 'none');
+	if (!layer) {return false;}
+	return (layer.getAttribute('display') !== 'none');
 };
 };
 
 
-// Function: svgedit.draw.Drawing.setLayerVisibility
-// Sets the visibility of the layer. If the layer name is not valid, this function return 
-// false, otherwise it returns true. This is an undo-able action.
-//
-// Parameters:
-// layername - the name of the layer to change the visibility
-// bVisible - true/false, whether the layer should be visible
-//
-// Returns:
-// The SVGGElement representing the layer if the layername was valid, otherwise null.
+/**
+ * Sets the visibility of the layer. If the layer name is not valid, this
+ * function returns false, otherwise it returns true. This is an
+ * undo-able action.
+ * @param {string} layername - The name of the layer to change the visibility
+ * @param {boolean} bVisible - Whether the layer should be visible
+ * @returns {?SVGGElement} The SVGGElement representing the layer if the
+ *   layername was valid, otherwise null.
+*/
 svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) {
 svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) {
-	if (typeof bVisible != typeof true) {
+	if (typeof bVisible !== 'boolean') {
 		return null;
 		return null;
 	}
 	}
 	// find the layer
 	// find the layer
 	var layer = null;
 	var layer = null;
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (this.getLayerName(i) == layername) {
 		if (this.getLayerName(i) == layername) {
 			layer = this.all_layers[i][1];
 			layer = this.all_layers[i][1];
 			break;
 			break;
 		}
 		}
 	}
 	}
-	if (!layer) return null;
+	if (!layer) {return null;}
 	
 	
 	var oldDisplay = layer.getAttribute("display");
 	var oldDisplay = layer.getAttribute("display");
-	if (!oldDisplay) oldDisplay = "inline";
+	if (!oldDisplay) {oldDisplay = "inline";}
 	layer.setAttribute("display", bVisible ? "inline" : "none");
 	layer.setAttribute("display", bVisible ? "inline" : "none");
 	return layer;
 	return layer;
 };
 };
 
 
 
 
-// Function: svgedit.draw.Drawing.getLayerOpacity
-// Returns the opacity of the given layer.  If the input name is not a layer, null is returned.
-//
-// Parameters: 
-// layername - name of the layer on which to get the opacity
-//
-// Returns:
-// The opacity value of the given layer.  This will be a value between 0.0 and 1.0, or null
-// if layername is not a valid layer
+/**
+ * Returns the opacity of the given layer.  If the input name is not a layer, null is returned.
+ * @param {string} layername - name of the layer on which to get the opacity
+ * @returns {?number} The opacity value of the given layer.  This will be a value between 0.0 and 1.0, or null
+ * if layername is not a valid layer
+*/
 svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) {
 svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) {
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (this.getLayerName(i) == layername) {
 		if (this.getLayerName(i) == layername) {
 			var g = this.all_layers[i][1];
 			var g = this.all_layers[i][1];
 			var opacity = g.getAttribute('opacity');
 			var opacity = g.getAttribute('opacity');
@@ -505,18 +513,19 @@ svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) {
 	return null;
 	return null;
 };
 };
 
 
-// Function: svgedit.draw.Drawing.setLayerOpacity
-// Sets the opacity of the given layer.  If the input name is not a layer, nothing happens.
-// If opacity is not a value between 0.0 and 1.0, then nothing happens.
-//
-// Parameters:
-// layername - name of the layer on which to set the opacity
-// opacity - a float value in the range 0.0-1.0
+/**
+ * Sets the opacity of the given layer.  If the input name is not a layer,
+ * nothing happens. If opacity is not a value between 0.0 and 1.0, then
+ * nothing happens.
+ * @param {string} layername - Name of the layer on which to set the opacity
+ * @param {number} opacity - A float value in the range 0.0-1.0
+*/
 svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
 svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
-	if (typeof opacity != typeof 1.0 || opacity < 0.0 || opacity > 1.0) {
+	if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) {
 		return;
 		return;
 	}
 	}
-	for (var i = 0; i < this.getNumLayers(); ++i) {
+	var i;
+	for (i = 0; i < this.getNumLayers(); ++i) {
 		if (this.getLayerName(i) == layername) {
 		if (this.getLayerName(i) == layername) {
 			var g = this.all_layers[i][1];
 			var g = this.all_layers[i][1];
 			g.setAttribute("opacity", opacity);
 			g.setAttribute("opacity", opacity);
@@ -525,4 +534,4 @@ svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
 	}
 	}
 };
 };
 
 
-})();
+}());

+ 59 - 0
main/inc/lib/svg-edit/embedapi.html

@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <meta charset="utf-8" />
+    <title>Embed API</title>
+    <script src="jquery.js"></script>
+    <script src="embedapi.js"></script>
+    <script>
+    /*globals $, EmbeddedSVGEdit*/
+	var initEmbed;
+    $(function () {'use strict';
+        
+        var svgCanvas = null;
+
+        initEmbed = function () {
+            var doc, mainButton,
+                frame = document.getElementById('svgedit');
+            svgCanvas = new EmbeddedSVGEdit(frame);
+            // Hide main button, as we will be controlling new, load, save, etc. from the host document
+            doc = frame.contentDocument || frame.contentWindow.document;
+            mainButton = doc.getElementById('main_button');
+            mainButton.style.display = 'none';
+        };
+
+        function handleSvgData(data, error) {
+            if (error) {
+                alert('error ' + error);
+            } else {
+                alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
+            }
+        }
+
+        function loadSvg() {
+            var svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1<\/title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/><\/g><\/svg>';
+            svgCanvas.setSvgString(svgexample);
+        }
+
+        function saveSvg() {
+            svgCanvas.getSvgString()(handleSvgData);
+        }
+        
+        // Add event handlers
+        $('#load').click(loadSvg);
+        $('#save').click(saveSvg);
+		$('body').append(
+			$('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' +
+				window.location.href.replace(/\?(.*)$/, '&$1') + // Append arguments to this file onto the iframe
+				'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
+			)
+		);
+	});
+    </script>
+</head>
+<body>
+    <button id="load">Load example</button>
+    <button id="save">Save data</button>
+    <br/>
+</body>
+</html>

+ 0 - 56
main/inc/lib/svg-edit/embedapi.html_disabled

@@ -1,56 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" >
-<head>
-    <title></title>
-</head>
-<body>
-
-    <script type="text/javascript" src="embedapi.js"></script>
-    <script type="text/javascript">
-        var svgCanvas = null;
-
-        function init_embed() {
-            var frame = document.getElementById('svgedit');
-			svgCanvas = new embedded_svg_edit(frame);
-			
-			// Hide main button, as we will be controlling new/load/save etc from the host document
-			var doc;
-			doc = frame.contentDocument;
-			if (!doc)
-			{
-				doc = frame.contentWindow.document;
-			}
-			
-			var mainButton = doc.getElementById('main_button');
-			mainButton.style.display = 'none';            
-        }
-        
-        function handleSvgData(data, error) {
-			if (error)
-			{
-				alert('error ' + error);
-			}
-            else
-			{
-				alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
-			}			
-        }
-        
-        function loadSvg() {
-            var svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/></g></svg>';
-            svgCanvas.setSvgString(svgexample);
-        }
-		
-		function saveSvg() {			
-			svgCanvas.getSvgString()(handleSvgData);
-		}
-    </script>
-
-
-    <button onclick="loadSvg();">Load example</button>
-    <button onclick="saveSvg();">Save data</button>
-    <br/>
-
-    <iframe src="svg-editor.html" width="900px" height="600px" id="svgedit" onload="init_embed()"></iframe>    
-</body>
-</html>

Diferenças do arquivo suprimidas por serem muito extensas
+ 101 - 148
main/inc/lib/svg-edit/embedapi.js


+ 11 - 0
main/inc/lib/svg-edit/extensions/allowedMimeTypes.php

@@ -0,0 +1,11 @@
+<?php
+
+$allowedMimeTypesBySuffix = array(
+    'svg' => 'image/svg+xml;charset=utf-8',
+    'png' => 'image/png',
+    'jpeg' => 'image/jpeg',
+    'bmp' => 'image/bmp',
+    'webp' => 'image/webp'
+);
+
+?>

+ 9 - 0
main/inc/lib/svg-edit/extensions/closepath_icons.svg

@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<svg width="1000" height="1000" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
+ <g>
+  <title>Layer 1</title>
+  <rect id="svg_2" height="717.432104" width="862.814821" y="87.209869" x="63.851915" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="null" fill="#00ffff"/>
+  <text font-style="italic" font-weight="normal" transform="matrix(14.5579, 0, 0, 19.1025, -3784.43, -4491.74)" xml:space="preserve" text-anchor="middle" font-family="Cursive" font-size="24" id="svg_1" y="267.244915" x="291.750555" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="0" fill="#000000">ICO</text>
+ </g>
+
+</svg>

+ 260 - 265
main/inc/lib/svg-edit/extensions/ext-arrows.js

@@ -1,298 +1,293 @@
+/*globals svgEditor, svgCanvas, $*/
+/*jslint vars: true, eqeq: true*/
 /*
 /*
  * ext-arrows.js
  * ext-arrows.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
  */
  */
 
 
- 
-svgEditor.addExtension("Arrows", function(S) {
-		var svgcontent = S.svgcontent,
-			addElem = S.addSvgElementFromJson,
-			nonce = S.nonce,
-			randomize_ids = S.randomize_ids,
-			selElems;
-
-		svgCanvas.bind('setnonce', setArrowNonce);
-		svgCanvas.bind('unsetnonce', unsetArrowNonce);
-			
-		var lang_list = {
-			"en":[
-				{"id": "arrow_none", "textContent": "No arrow" }
+svgEditor.addExtension('Arrows', function(S) {
+	var svgcontent = S.svgcontent,
+		addElem = S.addSvgElementFromJson,
+		nonce = S.nonce,
+		randomize_ids = S.randomize_ids,
+		selElems, pathdata,
+		lang_list = {
+			'en':[
+				{'id': 'arrow_none', 'textContent': 'No arrow' }
 			],
 			],
-			"fr":[
-				{"id": "arrow_none", "textContent": "Sans flèche" }
+			'fr':[
+				{'id': 'arrow_none', 'textContent': 'Sans flèche' }
 			]
 			]
-		};
-		
-		var prefix = 'se_arrow_';
-		if (randomize_ids) {
-		  var arrowprefix = prefix + nonce + '_';
-		} else {
-		  var arrowprefix = prefix;
-		}
+		},
+		arrowprefix,
+		prefix = 'se_arrow_';
 
 
-		var pathdata = {
-			fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8,  id: arrowprefix + 'fw'},
-			bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'}
-		}
-		
-		function setArrowNonce(window, n) {
-		    randomize_ids = true;
-		    arrowprefix = prefix + n + '_';
- 			pathdata.fw.id = arrowprefix + 'fw';
-			pathdata.bk.id = arrowprefix + 'bk';
-		}
+	function setArrowNonce(window, n) {
+		randomize_ids = true;
+		arrowprefix = prefix + n + '_';
+		pathdata.fw.id = arrowprefix + 'fw';
+		pathdata.bk.id = arrowprefix + 'bk';
+	}
+
+	function unsetArrowNonce(window) {
+		randomize_ids = false;
+		arrowprefix = prefix;
+		pathdata.fw.id = arrowprefix + 'fw';
+		pathdata.bk.id = arrowprefix + 'bk';
+	}
+
+
+	svgCanvas.bind('setnonce', setArrowNonce);
+	svgCanvas.bind('unsetnonce', unsetArrowNonce);
+
+	if (randomize_ids) {
+		arrowprefix = prefix + nonce + '_';
+	} else {
+		arrowprefix = prefix;
+	}
+
+	pathdata = {
+		fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8,  id: arrowprefix + 'fw'},
+		bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
+	};
 
 
-		function unsetArrowNonce(window) {
-		    randomize_ids = false;
-		    arrowprefix = prefix;
- 			pathdata.fw.id = arrowprefix + 'fw';
-			pathdata.bk.id = arrowprefix + 'bk';
+	function getLinked(elem, attr) {
+		var str = elem.getAttribute(attr);
+		if(!str) {return null;}
+		var m = str.match(/\(\#(.*)\)/);
+		if(!m || m.length !== 2) {
+			return null;
 		}
 		}
+		return S.getElem(m[1]);
+	}
 
 
-		function getLinked(elem, attr) {
-			var str = elem.getAttribute(attr);
-			if(!str) return null;
-			var m = str.match(/\(\#(.*)\)/);
-			if(!m || m.length !== 2) {
-				return null;
+	function showPanel(on) {
+		$('#arrow_panel').toggle(on);
+		if(on) {
+			var el = selElems[0];
+			var end = el.getAttribute('marker-end');
+			var start = el.getAttribute('marker-start');
+			var mid = el.getAttribute('marker-mid');
+			var val;
+
+			if (end && start) {
+				val = 'both';
+			} else if (end) {
+				val = 'end';
+			} else if (start) {
+				val = 'start';
+			} else if (mid) {
+				val = 'mid';
+				if (mid.indexOf('bk') !== -1) {
+					val = 'mid_bk';
+				}
+			}
+
+			if (!start && !mid && !end) {
+				val = 'none';
 			}
 			}
-			return S.getElem(m[1]);
+
+			$('#arrow_list').val(val);
 		}
 		}
-		
-		function showPanel(on) {
-			$('#arrow_panel').toggle(on);
-			
-			if(on) {
-				var el = selElems[0];
-				var end = el.getAttribute("marker-end");
-				var start = el.getAttribute("marker-start");
-				var mid = el.getAttribute("marker-mid");
-				var val;
-				
-				if(end && start) {
-					val = "both";
-				} else if(end) {
-					val = "end";
-				} else if(start) {
-					val = "start";
-				} else if(mid) {
-					val = "mid";
-					if(mid.indexOf("bk") != -1) {
-						val = "mid_bk";
-					}
+	}
+
+	function resetMarker() {
+		var el = selElems[0];
+		el.removeAttribute('marker-start');
+		el.removeAttribute('marker-mid');
+		el.removeAttribute('marker-end');
+	}
+
+	function addMarker(dir, type, id) {
+		// TODO: Make marker (or use?) per arrow type, since refX can be different
+		id = id || arrowprefix + dir;
+
+		var marker = S.getElem(id);
+		var data = pathdata[dir];
+
+		if (type == 'mid') {
+			data.refx = 5;
+		}
+
+		if (!marker) {
+			marker = addElem({
+				'element': 'marker',
+				'attr': {
+					'viewBox': '0 0 10 10',
+					'id': id,
+					'refY': 5,
+					'markerUnits': 'strokeWidth',
+					'markerWidth': 5,
+					'markerHeight': 5,
+					'orient': 'auto',
+					'style': 'pointer-events:none' // Currently needed for Opera
 				}
 				}
-				
-				if(!start && !mid && !end) {
-					val = "none";
+			});
+			var arrow = addElem({
+				'element': 'path',
+				'attr': {
+					'd': data.d,
+					'fill': '#000000'
 				}
 				}
-				
-				$("#arrow_list").val(val);
-			}
+			});
+			marker.appendChild(arrow);
+			S.findDefs().appendChild(marker);
 		}
 		}
-		
-		function resetMarker() {
-			var el = selElems[0];
-			el.removeAttribute("marker-start");
-			el.removeAttribute("marker-mid");
-			el.removeAttribute("marker-end");
+
+		marker.setAttribute('refX', data.refx);
+
+		return marker;
+	}
+
+	function setArrow() {
+		var type = this.value;
+		resetMarker();
+
+		if (type == 'none') {
+			return;
 		}
 		}
-		
-		function addMarker(dir, type, id) {
-			// TODO: Make marker (or use?) per arrow type, since refX can be different
-			id = id || arrowprefix + dir;
-			
-			var marker = S.getElem(id);
-
-			var data = pathdata[dir];
-			
-			if(type == "mid") {
-				data.refx = 5;
-			}
 
 
-			if(!marker) {
-				marker = addElem({
-					"element": "marker",
-					"attr": {
-						"viewBox": "0 0 10 10",
-						"id": id,
-						"refY": 5,
-						"markerUnits": "strokeWidth",
-						"markerWidth": 5,
-						"markerHeight": 5,
-						"orient": "auto",
-						"style": "pointer-events:none" // Currently needed for Opera
-					}
-				});
-				var arrow = addElem({
-					"element": "path",
-					"attr": {
-						"d": data.d,
-						"fill": "#000000"
-					}
-				});
-				marker.appendChild(arrow);
-				S.findDefs().appendChild(marker);
-			} 
-			
-			marker.setAttribute('refX', data.refx);
-			
-			return marker;
+		// Set marker on element
+		var dir = 'fw';
+		if (type == 'mid_bk') {
+			type = 'mid';
+			dir = 'bk';
+		} else if (type == 'both') {
+			addMarker('bk', type);
+			svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')');
+			type = 'end';
+			dir = 'fw';
+		} else if (type == 'start') {
+			dir = 'bk';
 		}
 		}
-		
-		function setArrow() {
-			var type = this.value;
-			resetMarker();
-		
-			if(type == "none") {
-				return;
-			}
-		
-			// Set marker on element
-			var dir = "fw";
-			if(type == "mid_bk") {
-				type = "mid";
-				dir = "bk";
-			} else if(type == "both") {
-				addMarker("bk", type);
-				svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")");
-				type = "end";
-				dir = "fw";
-			} else if (type == "start") {
-				dir = "bk";
+
+		addMarker(dir, type);
+		svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')');
+		S.call('changed', selElems);
+	}
+
+	function colorChanged(elem) {
+		var color = elem.getAttribute('stroke');
+		var mtypes = ['start', 'mid', 'end'];
+		var defs = S.findDefs();
+
+		$.each(mtypes, function(i, type) {
+			var marker = getLinked(elem, 'marker-'+type);
+			if(!marker) {return;}
+
+			var cur_color = $(marker).children().attr('fill');
+			var cur_d = $(marker).children().attr('d');
+			var new_marker = null;
+			if(cur_color === color) {return;}
+
+			var all_markers = $(defs).find('marker');
+			// Different color, check if already made
+			all_markers.each(function() {
+				var attrs = $(this).children().attr(['fill', 'd']);
+				if(attrs.fill === color && attrs.d === cur_d) {
+					// Found another marker with this color and this path
+					new_marker = this;
+				}
+			});
+
+			if(!new_marker) {
+				// Create a new marker with this color
+				var last_id = marker.id;
+				var dir = last_id.indexOf('_fw') !== -1?'fw':'bk';
+
+				new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length);
+
+				$(new_marker).children().attr('fill', color);
 			}
 			}
-			
-			addMarker(dir, type);
-			svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")");
-			S.call("changed", selElems);
-		}
-		
-		function colorChanged(elem) {
-			var color = elem.getAttribute('stroke');
-			
-			var mtypes = ['start','mid','end'];
-			var defs = S.findDefs();
-			
-			$.each(mtypes, function(i, type) {
-				var marker = getLinked(elem, 'marker-'+type);
-				if(!marker) return;
-				
-				var cur_color = $(marker).children().attr('fill');
-				var cur_d = $(marker).children().attr('d');
-				var new_marker = null;
-				if(cur_color === color) return;
-				
-				var all_markers = $(defs).find('marker');
-				// Different color, check if already made
-				all_markers.each(function() {
-					var attrs = $(this).children().attr(['fill', 'd']);
-					if(attrs.fill === color && attrs.d === cur_d) {
-						// Found another marker with this color and this path
-						new_marker = this;
+
+			$(elem).attr('marker-'+type, 'url(#' + new_marker.id + ')');
+
+			// Check if last marker can be removed
+			var remove = true;
+			$(S.svgcontent).find('line, polyline, path, polygon').each(function() {
+				var elem = this;
+				$.each(mtypes, function(j, mtype) {
+					if($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
+						remove = false;
+						return remove;
 					}
 					}
 				});
 				});
-				
-				if(!new_marker) {
-					// Create a new marker with this color
-					var last_id = marker.id;
-					var dir = last_id.indexOf('_fw') !== -1?'fw':'bk';
-					
-					new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length);
-
-					$(new_marker).children().attr('fill', color);
-				}
-				
-				$(elem).attr('marker-'+type, "url(#" + new_marker.id + ")");
-				
-				// Check if last marker can be removed
-				var remove = true;
-				$(S.svgcontent).find('line, polyline, path, polygon').each(function() {
-					var elem = this;
-					$.each(mtypes, function(j, mtype) {
-						if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") {
-							return remove = false;
-						}
-					});
-					if(!remove) return false;
-				});
-				
-				// Not found, so can safely remove
-				if(remove) {
-					$(marker).remove();
-				}
-
+				if(!remove) {return false;}
 			});
 			});
-			
-		}
-		
-		return {
-			name: "Arrows",
-			context_tools: [{
-				type: "select",
-				panel: "arrow_panel",
-				title: "Select arrow type",
-				id: "arrow_list",
-				options: {
-					none: "No arrow",
-					end: "----&gt;",
-					start: "&lt;----",
-					both: "&lt;---&gt;",
-					mid: "--&gt;--",
-					mid_bk: "--&lt;--"
-				},
-				defval: "none",
-				events: {
-					change: setArrow
-				}
-			}],
-			callback: function() {
-				$('#arrow_panel').hide();
-				// Set ID so it can be translated in locale file
-				$('#arrow_list option')[0].id = 'connector_no_arrow';
-			},
-			addLangData: function(lang) {
-				return {
-					data: lang_list[lang]
-				};
+
+			// Not found, so can safely remove
+			if(remove) {
+				$(marker).remove();
+			}
+		});
+	}
+
+	return {
+		name: 'Arrows',
+		context_tools: [{
+			type: 'select',
+			panel: 'arrow_panel',
+			title: 'Select arrow type',
+			id: 'arrow_list',
+			options: {
+				none: 'No arrow',
+				end: '----&gt;',
+				start: '&lt;----',
+				both: '&lt;---&gt;',
+				mid: '--&gt;--',
+				mid_bk: '--&lt;--'
 			},
 			},
-			selectedChanged: function(opts) {
-				
-				// Use this to update the current selected elements
-				selElems = opts.elems;
-				
-				var i = selElems.length;
-				var marker_elems = ['line','path','polyline','polygon'];
-				
-				while(i--) {
-					var elem = selElems[i];
-					if(elem && $.inArray(elem.tagName, marker_elems) != -1) {
-						if(opts.selectedElement && !opts.multiselected) {
-							showPanel(true);
-						} else {
-							showPanel(false);
-						}
+			defval: 'none',
+			events: {
+				change: setArrow
+			}
+		}],
+		callback: function() {
+			$('#arrow_panel').hide();
+			// Set ID so it can be translated in locale file
+			$('#arrow_list option')[0].id = 'connector_no_arrow';
+		},
+		addLangData: function(lang) {
+			return {
+				data: lang_list[lang]
+			};
+		},
+		selectedChanged: function(opts) {
+			// Use this to update the current selected elements
+			selElems = opts.elems;
+
+			var i = selElems.length;
+			var marker_elems = ['line', 'path', 'polyline', 'polygon'];
+			while(i--) {
+				var elem = selElems[i];
+				if(elem && $.inArray(elem.tagName, marker_elems) !== -1) {
+					if(opts.selectedElement && !opts.multiselected) {
+						showPanel(true);
 					} else {
 					} else {
 						showPanel(false);
 						showPanel(false);
 					}
 					}
+				} else {
+					showPanel(false);
 				}
 				}
-			},
-			elementChanged: function(opts) {
-				var elem = opts.elems[0];
-				if(elem && (
-					elem.getAttribute("marker-start") ||
-					elem.getAttribute("marker-mid") ||
-					elem.getAttribute("marker-end")
-				)) {
-	// 								var start = elem.getAttribute("marker-start");
-	// 								var mid = elem.getAttribute("marker-mid");
-	// 								var end = elem.getAttribute("marker-end");
-					// Has marker, so see if it should match color
-					colorChanged(elem);
-				}
-				
 			}
 			}
-		};
+		},
+		elementChanged: function(opts) {
+			var elem = opts.elems[0];
+			if(elem && (
+				elem.getAttribute('marker-start') ||
+				elem.getAttribute('marker-mid') ||
+				elem.getAttribute('marker-end')
+			)) {
+//								var start = elem.getAttribute('marker-start');
+//								var mid = elem.getAttribute('marker-mid');
+//								var end = elem.getAttribute('marker-end');
+				// Has marker, so see if it should match color
+				colorChanged(elem);
+			}
+		}
+	};
 });
 });

+ 71 - 72
main/inc/lib/svg-edit/extensions/ext-closepath.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, $*/
+/*jslint vars: true, eqeq: true*/
 /*
 /*
  * ext-closepath.js
  * ext-closepath.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Jeff Schiller
  * Copyright(c) 2010 Jeff Schiller
  *
  *
@@ -9,84 +11,81 @@
 
 
 // This extension adds a simple button to the contextual panel for paths
 // This extension adds a simple button to the contextual panel for paths
 // The button toggles whether the path is open or closed
 // The button toggles whether the path is open or closed
-svgEditor.addExtension("ClosePath", function(S) {
-		var selElems,
-			updateButton = function(path) {
-				var seglist = path.pathSegList,
-					closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1,
-					showbutton = closed ? '#tool_openpath' : '#tool_closepath',
-					hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
-					$(hidebutton).hide();
-					$(showbutton).show();
-			},
-			showPanel = function(on) {
-				$('#closepath_panel').toggle(on);
-				if (on) {
-					var path = selElems[0];
-					if (path) updateButton(path);
-				}
-			},
-		
-			toggleClosed = function() {
+svgEditor.addExtension('ClosePath', function() {'use strict';
+	var selElems,
+		updateButton = function(path) {
+			var seglist = path.pathSegList,
+				closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType == 1,
+				showbutton = closed ? '#tool_openpath' : '#tool_closepath',
+				hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
+				$(hidebutton).hide();
+				$(showbutton).show();
+		},
+		showPanel = function(on) {
+			$('#closepath_panel').toggle(on);
+			if (on) {
 				var path = selElems[0];
 				var path = selElems[0];
-				if (path) {
-					var seglist = path.pathSegList,
-						last = seglist.numberOfItems - 1;					
-					// is closed
-					if(seglist.getItem(last).pathSegType == 1) {
-						seglist.removeItem(last);
-					}
-					else {
-						seglist.appendItem(path.createSVGPathSegClosePath());
-					}
-					updateButton(path);
+				if (path) {updateButton(path);}
+			}
+		},
+		toggleClosed = function() {
+			var path = selElems[0];
+			if (path) {
+				var seglist = path.pathSegList,
+					last = seglist.numberOfItems - 1;
+				// is closed
+				if (seglist.getItem(last).pathSegType == 1) {
+					seglist.removeItem(last);
+				} else {
+					seglist.appendItem(path.createSVGPathSegClosePath());
 				}
 				}
-			};
-		
-		return {
-			name: "ClosePath",
-			svgicons: "extensions/closepath_icons.svg",
-			buttons: [{
-				id: "tool_openpath",
-				type: "context",
-				panel: "closepath_panel",
-				title: "Open path",
-				events: {
-					'click': function() {
-						toggleClosed();
-					}
+				updateButton(path);
+			}
+		};
+
+	return {
+		name: 'ClosePath',
+		svgicons: svgEditor.curConfig.extPath + 'closepath_icons.svg',
+		buttons: [{
+			id: 'tool_openpath',
+			type: 'context',
+			panel: 'closepath_panel',
+			title: 'Open path',
+			events: {
+				click: function() {
+					toggleClosed();
 				}
 				}
-			},
-			{
-				id: "tool_closepath",
-				type: "context",
-				panel: "closepath_panel",
-				title: "Close path",
-				events: {
-					'click': function() {
-						toggleClosed();
-					}
+			}
+		},
+		{
+			id: 'tool_closepath',
+			type: 'context',
+			panel: 'closepath_panel',
+			title: 'Close path',
+			events: {
+				click: function() {
+					toggleClosed();
 				}
 				}
-			}],
-			callback: function() {
-				$('#closepath_panel').hide();
-			},
-			selectedChanged: function(opts) {
-				selElems = opts.elems;
-				var i = selElems.length;
-				
-				while(i--) {
-					var elem = selElems[i];
-					if(elem && elem.tagName == 'path') {
-						if(opts.selectedElement && !opts.multiselected) {
-							showPanel(true);
-						} else {
-							showPanel(false);
-						}
+			}
+		}],
+		callback: function() {
+			$('#closepath_panel').hide();
+		},
+		selectedChanged: function(opts) {
+			selElems = opts.elems;
+			var i = selElems.length;
+			while (i--) {
+				var elem = selElems[i];
+				if (elem && elem.tagName == 'path') {
+					if (opts.selectedElement && !opts.multiselected) {
+						showPanel(true);
 					} else {
 					} else {
 						showPanel(false);
 						showPanel(false);
 					}
 					}
+				} else {
+					showPanel(false);
 				}
 				}
 			}
 			}
-		};
+		}
+	};
 });
 });

+ 155 - 149
main/inc/lib/svg-edit/extensions/ext-connector.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, svgCanvas, $*/
+/*jslint vars: true, continue: true, eqeq: true, todo: true*/
 /*
 /*
  * ext-connector.js
  * ext-connector.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
@@ -24,10 +26,9 @@ svgEditor.addExtension("Connector", function(S) {
 		connections = [],
 		connections = [],
 		conn_sel = ".se_connector",
 		conn_sel = ".se_connector",
 		se_ns,
 		se_ns,
-// 			connect_str = "-SE_CONNECT-",
-		selElems = [];
-		
-	elData = $.data;
+//		connect_str = "-SE_CONNECT-",
+		selElems = [],
+		elData = $.data;
 		
 		
 	var lang_list = {
 	var lang_list = {
 		"en":[
 		"en":[
@@ -37,10 +38,42 @@ svgEditor.addExtension("Connector", function(S) {
 			{"id": "mode_connect", "title": "Connecter deux objets"}
 			{"id": "mode_connect", "title": "Connecter deux objets"}
 		]
 		]
 	};
 	};
+
+	function getBBintersect(x, y, bb, offset) {
+		if(offset) {
+			offset -= 0;
+			bb = $.extend({}, bb);
+			bb.width += offset;
+			bb.height += offset;
+			bb.x -= offset/2;
+			bb.y -= offset/2;
+		}
 	
 	
+		var mid_x = bb.x + bb.width/2;
+		var mid_y = bb.y + bb.height/2;
+		var len_x = x - mid_x;
+		var len_y = y - mid_y;
+		
+		var slope = Math.abs(len_y/len_x);
+		
+		var ratio;
+		
+		if(slope < bb.height/bb.width) {
+			ratio = (bb.width/2) / Math.abs(len_x);
+		} else {
+			ratio = (bb.height/2) / Math.abs(len_y);
+		}
+		
+		
+		return {
+			x: mid_x + len_x * ratio,
+			y: mid_y + len_y * ratio
+		};
+	}
+
 	function getOffset(side, line) {
 	function getOffset(side, line) {
 		var give_offset = !!line.getAttribute('marker-' + side);
 		var give_offset = !!line.getAttribute('marker-' + side);
-// 		var give_offset = $(line).data(side+'_off');
+//		var give_offset = $(line).data(side+'_off');
 
 
 		// TODO: Make this number (5) be based on marker width/height
 		// TODO: Make this number (5) be based on marker width/height
 		var size = line.getAttribute('stroke-width') * 5;
 		var size = line.getAttribute('stroke-width') * 5;
@@ -57,19 +90,19 @@ svgEditor.addExtension("Connector", function(S) {
 	}
 	}
 	
 	
 	function setPoint(elem, pos, x, y, setMid) {
 	function setPoint(elem, pos, x, y, setMid) {
-		var pts = elem.points;
+		var i, pts = elem.points;
 		var pt = svgroot.createSVGPoint();
 		var pt = svgroot.createSVGPoint();
 		pt.x = x;
 		pt.x = x;
 		pt.y = y;
 		pt.y = y;
-		if(pos === 'end') pos = pts.numberOfItems-1;
+		if (pos === 'end') {pos = pts.numberOfItems - 1;}
 		// TODO: Test for this on init, then use alt only if needed
 		// TODO: Test for this on init, then use alt only if needed
 		try {
 		try {
 			pts.replaceItem(pt, pos);
 			pts.replaceItem(pt, pos);
 		} catch(err) {
 		} catch(err) {
 			// Should only occur in FF which formats points attr as "n,n n,n", so just split
 			// Should only occur in FF which formats points attr as "n,n n,n", so just split
 			var pt_arr = elem.getAttribute("points").split(" ");
 			var pt_arr = elem.getAttribute("points").split(" ");
-			for(var i=0; i< pt_arr.length; i++) {
-				if(i == pos) {
+			for (i = 0; i < pt_arr.length; i++) {
+				if (i === pos) {
 					pt_arr[i] = x + ',' + y;
 					pt_arr[i] = x + ',' + y;
 				}
 				}
 			}
 			}
@@ -93,7 +126,7 @@ svgEditor.addExtension("Connector", function(S) {
 			var elem = conn.elem;
 			var elem = conn.elem;
 			
 			
 			var pre = conn.is_start?'start':'end';
 			var pre = conn.is_start?'start':'end';
-// 						var sw = line.getAttribute('stroke-width') * 5;
+//						var sw = line.getAttribute('stroke-width') * 5;
 			
 			
 			// Update bbox for this element
 			// Update bbox for this element
 			var bb = elData(line, pre+'_bb');
 			var bb = elData(line, pre+'_bb');
@@ -110,36 +143,39 @@ svgEditor.addExtension("Connector", function(S) {
 			
 			
 			// Set point of element being moved
 			// Set point of element being moved
 			var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
 			var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
-			setPoint(line, conn.is_start?0:'end', pt.x, pt.y, true);
+			setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
 			
 			
 			// Set point of connected element
 			// Set point of connected element
 			var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line));
 			var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line));
-			setPoint(line, conn.is_start?'end':0, pt2.x, pt2.y, true);
+			setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
 
 
 		}
 		}
 	}
 	}
 	
 	
 	function findConnectors(elems) {
 	function findConnectors(elems) {
-		if(!elems) elems = selElems;
+		var i;
+		if (!elems) {elems = selElems;}
 		var connectors = $(svgcontent).find(conn_sel);
 		var connectors = $(svgcontent).find(conn_sel);
 		connections = [];
 		connections = [];
 
 
 		// Loop through connectors to see if one is connected to the element
 		// Loop through connectors to see if one is connected to the element
 		connectors.each(function() {
 		connectors.each(function() {
+			var add_this;
+			function add () {
+				if ($.inArray(this, elems) !== -1) {
+					// Pretend this element is selected
+					add_this = true;
+				}
+			}
 			var start = elData(this, "c_start");
 			var start = elData(this, "c_start");
 			var end = elData(this, "c_end");
 			var end = elData(this, "c_end");
 			
 			
 			var parts = [getElem(start), getElem(end)];
 			var parts = [getElem(start), getElem(end)];
-			for(var i=0; i<2; i++) {
+			for (i = 0; i < 2; i++) {
 				var c_elem = parts[i];
 				var c_elem = parts[i];
-				var add_this = false;
+				add_this = false;
 				// The connected element might be part of a selected group
 				// The connected element might be part of a selected group
-				$(c_elem).parents().each(function() {
-					if($.inArray(this, elems) !== -1) {
-						// Pretend this element is selected
-						add_this = true;
-					}
-				});
+				$(c_elem).parents().each(add);
 				
 				
 				if(!c_elem || !c_elem.parentNode) {
 				if(!c_elem || !c_elem.parentNode) {
 					$(this).remove();
 					$(this).remove();
@@ -163,11 +199,12 @@ svgEditor.addExtension("Connector", function(S) {
 		// Updates connector lines based on selected elements
 		// Updates connector lines based on selected elements
 		// Is not used on mousemove, as it runs getStrokedBBox every time,
 		// Is not used on mousemove, as it runs getStrokedBBox every time,
 		// which isn't necessary there.
 		// which isn't necessary there.
+		var i, j;
 		findConnectors(elems);
 		findConnectors(elems);
-		if(connections.length) {
+		if (connections.length) {
 			// Update line with element
 			// Update line with element
-			var i = connections.length;
-			while(i--) {
+			i = connections.length;
+			while (i--) {
 				var conn = connections[i];
 				var conn = connections[i];
 				var line = conn.connector;
 				var line = conn.connector;
 				var elem = conn.elem;
 				var elem = conn.elem;
@@ -191,60 +228,27 @@ svgEditor.addExtension("Connector", function(S) {
 				
 				
 				// Set point of element being moved
 				// Set point of element being moved
 				var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line));
 				var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line));
-				setPoint(line, conn.is_start?0:'end', pt.x, pt.y, true);
+				setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
 				
 				
 				// Set point of connected element
 				// Set point of connected element
 				var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line));
 				var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line));
-				setPoint(line, conn.is_start?'end':0, pt2.x, pt2.y, true);
+				setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
 				
 				
 				// Update points attribute manually for webkit
 				// Update points attribute manually for webkit
-				if(navigator.userAgent.indexOf('AppleWebKit') != -1) {
+				if (navigator.userAgent.indexOf('AppleWebKit') !== -1) {
 					var pts = line.points;
 					var pts = line.points;
 					var len = pts.numberOfItems;
 					var len = pts.numberOfItems;
-					var pt_arr = Array(len);
-					for(var j=0; j< len; j++) {
-						var pt = pts.getItem(j);
+					var pt_arr = [];
+					for (j = 0; j < len; j++) {
+						pt = pts.getItem(j);
 						pt_arr[j] = pt.x + ',' + pt.y;
 						pt_arr[j] = pt.x + ',' + pt.y;
-					}	
-					line.setAttribute("points",pt_arr.join(" ")); 
+					}
+					line.setAttribute('points', pt_arr.join(' ')); 
 				}
 				}
-
 			}
 			}
 		}
 		}
 	}
 	}
 	
 	
-	function getBBintersect(x, y, bb, offset) {
-		if(offset) {
-			offset -= 0;
-			bb = $.extend({}, bb);
-			bb.width += offset;
-			bb.height += offset;
-			bb.x -= offset/2;
-			bb.y -= offset/2;
-		}
-	
-		var mid_x = bb.x + bb.width/2;
-		var mid_y = bb.y + bb.height/2;
-		var len_x = x - mid_x;
-		var len_y = y - mid_y;
-		
-		var slope = Math.abs(len_y/len_x);
-		
-		var ratio;
-		
-		if(slope < bb.height/bb.width) {
-			ratio = (bb.width/2) / Math.abs(len_x);
-		} else {
-			ratio = (bb.height/2) / Math.abs(len_y);
-		}
-		
-		
-		return {
-			x: mid_x + len_x * ratio,
-			y: mid_y + len_y * ratio
-		}
-	}
-	
 	// Do once
 	// Do once
 	(function() {
 	(function() {
 		var gse = svgCanvas.groupSelectedElements;
 		var gse = svgCanvas.groupSelectedElements;
@@ -252,7 +256,7 @@ svgEditor.addExtension("Connector", function(S) {
 		svgCanvas.groupSelectedElements = function() {
 		svgCanvas.groupSelectedElements = function() {
 			svgCanvas.removeFromSelection($(conn_sel).toArray());
 			svgCanvas.removeFromSelection($(conn_sel).toArray());
 			return gse.apply(this, arguments);
 			return gse.apply(this, arguments);
-		}
+		};
 		
 		
 		var mse = svgCanvas.moveSelectedElements;
 		var mse = svgCanvas.moveSelectedElements;
 		
 		
@@ -261,7 +265,7 @@ svgEditor.addExtension("Connector", function(S) {
 			var cmd = mse.apply(this, arguments);
 			var cmd = mse.apply(this, arguments);
 			updateConnectors();
 			updateConnectors();
 			return cmd;
 			return cmd;
-		}
+		};
 		
 		
 		se_ns = svgCanvas.getEditorNS();
 		se_ns = svgCanvas.getEditorNS();
 	}());
 	}());
@@ -283,27 +287,27 @@ svgEditor.addExtension("Connector", function(S) {
 				svgCanvas.getEditorNS(true);
 				svgCanvas.getEditorNS(true);
 			}
 			}
 		});
 		});
-// 			updateConnectors();
+//		updateConnectors();
 	}
 	}
-	
-// 		$(svgroot).parent().mousemove(function(e) {
-// // 			if(started 
-// // 				|| svgCanvas.getMode() != "connector"
-// // 				|| e.target.parentNode.parentNode != svgcontent) return;
-// 			
-// 			console.log('y')
-// // 			if(e.target.parentNode.parentNode === svgcontent) {
-// // 					
-// // 			}
-// 		});
-	
+
+//		$(svgroot).parent().mousemove(function(e) {
+// //			if(started 
+// //				|| svgCanvas.getMode() != "connector"
+// //				|| e.target.parentNode.parentNode != svgcontent) return;
+//
+//			console.log('y')
+// //			if(e.target.parentNode.parentNode === svgcontent) {
+// //					
+// //			}
+//		});
+
 	return {
 	return {
 		name: "Connector",
 		name: "Connector",
-		svgicons: "images/conn.svg",
+		svgicons: svgEditor.curConfig.imgPath + "conn.svg",
 		buttons: [{
 		buttons: [{
 			id: "mode_connect",
 			id: "mode_connect",
 			type: "mode",
 			type: "mode",
-			icon: "images/cut.png",
+			icon: svgEditor.curConfig.imgPath + "cut.png",
 			title: "Connect two objects",
 			title: "Connect two objects",
 			includeWith: {
 			includeWith: {
 				button: '#tool_line',
 				button: '#tool_line',
@@ -323,19 +327,19 @@ svgEditor.addExtension("Connector", function(S) {
 		},
 		},
 		mouseDown: function(opts) {
 		mouseDown: function(opts) {
 			var e = opts.event;
 			var e = opts.event;
-			start_x = opts.start_x,
+			start_x = opts.start_x;
 			start_y = opts.start_y;
 			start_y = opts.start_y;
 			var mode = svgCanvas.getMode();
 			var mode = svgCanvas.getMode();
 			
 			
-			if(mode == "connector") {
-				
-				if(started) return;
+			if (mode == "connector") {
 				
 				
+				if (started) {return;}
+
 				var mouse_target = e.target;
 				var mouse_target = e.target;
 				
 				
 				var parents = $(mouse_target).parents();
 				var parents = $(mouse_target).parents();
 				
 				
-				if($.inArray(svgcontent, parents) != -1) {
+				if($.inArray(svgcontent, parents) !== -1) {
 					// Connectable element
 					// Connectable element
 					
 					
 					// If child of foreignObject, use parent
 					// If child of foreignObject, use parent
@@ -365,7 +369,8 @@ svgEditor.addExtension("Connector", function(S) {
 				return {
 				return {
 					started: true
 					started: true
 				};
 				};
-			} else if(mode == "select") {
+			}
+			if (mode == "select") {
 				findConnectors();
 				findConnectors();
 			}
 			}
 		},
 		},
@@ -380,7 +385,7 @@ svgEditor.addExtension("Connector", function(S) {
 								
 								
 			var mode = svgCanvas.getMode();
 			var mode = svgCanvas.getMode();
 			
 			
-			if(mode == "connector" && started) {
+			if (mode == "connector" && started) {
 				
 				
 				var sw = cur_line.getAttribute('stroke-width') * 3;
 				var sw = cur_line.getAttribute('stroke-width') * 3;
 				// Set start point (adjusts based on bb)
 				// Set start point (adjusts based on bb)
@@ -392,7 +397,7 @@ svgEditor.addExtension("Connector", function(S) {
 				
 				
 				// Set end point
 				// Set end point
 				setPoint(cur_line, 'end', x, y, true);
 				setPoint(cur_line, 'end', x, y, true);
-			} else if(mode == "select") {
+			} else if (mode == "select") {
 				var slen = selElems.length;
 				var slen = selElems.length;
 				
 				
 				while(slen--) {
 				while(slen--) {
@@ -421,19 +426,20 @@ svgEditor.addExtension("Connector", function(S) {
 			
 			
 			if(svgCanvas.getMode() == "connector") {
 			if(svgCanvas.getMode() == "connector") {
 				var fo = $(mouse_target).closest("foreignObject");
 				var fo = $(mouse_target).closest("foreignObject");
-				if(fo.length) mouse_target = fo[0];
+				if (fo.length) {mouse_target = fo[0];}
 				
 				
 				var parents = $(mouse_target).parents();
 				var parents = $(mouse_target).parents();
 
 
-				if(mouse_target == start_elem) {
+				if (mouse_target == start_elem) {
 					// Start line through click
 					// Start line through click
 					started = true;
 					started = true;
 					return {
 					return {
 						keep: true,
 						keep: true,
 						element: null,
 						element: null,
 						started: started
 						started: started
-					}						
-				} else if($.inArray(svgcontent, parents) === -1) {
+					};
+				}
+				if ($.inArray(svgcontent, parents) === -1) {
 					// Not a valid target element, so remove line
 					// Not a valid target element, so remove line
 					$(cur_line).remove();
 					$(cur_line).remove();
 					started = false;
 					started = false;
@@ -441,55 +447,54 @@ svgEditor.addExtension("Connector", function(S) {
 						keep: false,
 						keep: false,
 						element: null,
 						element: null,
 						started: started
 						started: started
-					}
-				} else {
-					// Valid end element
-					end_elem = mouse_target;
-					
-					var start_id = start_elem.id, end_id = end_elem.id;
-					var conn_str = start_id + " " + end_id;
-					var alt_str = end_id + " " + start_id;
-					// Don't create connector if one already exists
-					var dupe = $(svgcontent).find(conn_sel).filter(function() {
-						var conn = this.getAttributeNS(se_ns, "connector");
-						if(conn == conn_str || conn == alt_str) return true;
-					});
-					if(dupe.length) {
-						$(cur_line).remove();
-						return {
-							keep: false,
-							element: null,
-							started: false
-						}
-					}
-					
-					var bb = svgCanvas.getStrokedBBox([end_elem]);
+					};
+				}
+				// Valid end element
+				end_elem = mouse_target;
 					
 					
-					var pt = getBBintersect(start_x, start_y, bb, getOffset('start', cur_line));
-					setPoint(cur_line, 'end', pt.x, pt.y, true);
-					$(cur_line)
-						.data("c_start", start_id)
-						.data("c_end", end_id)
-						.data("end_bb", bb);
-					se_ns = svgCanvas.getEditorNS(true);
-					cur_line.setAttributeNS(se_ns, "se:connector", conn_str);
-					cur_line.setAttribute('class', conn_sel.substr(1));
-					cur_line.setAttribute('opacity', 1);
-					svgCanvas.addToSelection([cur_line]);
-					svgCanvas.moveToBottomSelectedElement();
-					selManager.requestSelector(cur_line).showGrips(false);
-					started = false;
+				var start_id = start_elem.id, end_id = end_elem.id;
+				var conn_str = start_id + " " + end_id;
+				var alt_str = end_id + " " + start_id;
+				// Don't create connector if one already exists
+				var dupe = $(svgcontent).find(conn_sel).filter(function() {
+					var conn = this.getAttributeNS(se_ns, "connector");
+					if (conn == conn_str || conn == alt_str) {return true;}
+				});
+				if(dupe.length) {
+					$(cur_line).remove();
 					return {
 					return {
-						keep: true,
-						element: cur_line,
-						started: started
-					}
+						keep: false,
+						element: null,
+						started: false
+					};
 				}
 				}
+				
+				var bb = svgCanvas.getStrokedBBox([end_elem]);
+				
+				var pt = getBBintersect(start_x, start_y, bb, getOffset('start', cur_line));
+				setPoint(cur_line, 'end', pt.x, pt.y, true);
+				$(cur_line)
+					.data("c_start", start_id)
+					.data("c_end", end_id)
+					.data("end_bb", bb);
+				se_ns = svgCanvas.getEditorNS(true);
+				cur_line.setAttributeNS(se_ns, "se:connector", conn_str);
+				cur_line.setAttribute('class', conn_sel.substr(1));
+				cur_line.setAttribute('opacity', 1);
+				svgCanvas.addToSelection([cur_line]);
+				svgCanvas.moveToBottomSelectedElement();
+				selManager.requestSelector(cur_line).showGrips(false);
+				started = false;
+				return {
+					keep: true,
+					element: cur_line,
+					started: started
+				};
 			}
 			}
 		},
 		},
 		selectedChanged: function(opts) {
 		selectedChanged: function(opts) {
 			// TODO: Find better way to skip operations if no connectors are in use
 			// TODO: Find better way to skip operations if no connectors are in use
-			if(!$(svgcontent).find(conn_sel).length) return;
+			if(!$(svgcontent).find(conn_sel).length) {return;}
 			
 			
 			if(svgCanvas.getMode() == 'connector') {
 			if(svgCanvas.getMode() == 'connector') {
 				svgCanvas.setMode('select');
 				svgCanvas.setMode('select');
@@ -518,19 +523,20 @@ svgEditor.addExtension("Connector", function(S) {
 		},
 		},
 		elementChanged: function(opts) {
 		elementChanged: function(opts) {
 			var elem = opts.elems[0];
 			var elem = opts.elems[0];
-			if (elem && elem.tagName == 'svg' && elem.id == "svgcontent") {
+			if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') {
 				// Update svgcontent (can change on import)
 				// Update svgcontent (can change on import)
 				svgcontent = elem;
 				svgcontent = elem;
 				init();
 				init();
 			}
 			}
 			
 			
 			// Has marker, so change offset
 			// Has marker, so change offset
-			if(elem && (
+			var start;
+			if (elem && (
 				elem.getAttribute("marker-start") ||
 				elem.getAttribute("marker-start") ||
 				elem.getAttribute("marker-mid") ||
 				elem.getAttribute("marker-mid") ||
 				elem.getAttribute("marker-end")
 				elem.getAttribute("marker-end")
 			)) {
 			)) {
-				var start = elem.getAttribute("marker-start");
+				start = elem.getAttribute("marker-start");
 				var mid = elem.getAttribute("marker-mid");
 				var mid = elem.getAttribute("marker-mid");
 				var end = elem.getAttribute("marker-end");
 				var end = elem.getAttribute("marker-end");
 				cur_line = elem;
 				cur_line = elem;
@@ -538,13 +544,13 @@ svgEditor.addExtension("Connector", function(S) {
 					.data("start_off", !!start)
 					.data("start_off", !!start)
 					.data("end_off", !!end);
 					.data("end_off", !!end);
 				
 				
-				if(elem.tagName == "line" && mid) {
+				if (elem.tagName === 'line' && mid) {
 					// Convert to polyline to accept mid-arrow
 					// Convert to polyline to accept mid-arrow
 					
 					
-					var x1 = elem.getAttribute('x1')-0;
-					var x2 = elem.getAttribute('x2')-0;
-					var y1 = elem.getAttribute('y1')-0;
-					var y2 = elem.getAttribute('y2')-0;
+					var x1 = Number(elem.getAttribute('x1'));
+					var x2 = Number(elem.getAttribute('x2'));
+					var y1 = Number(elem.getAttribute('y1'));
+					var y2 = Number(elem.getAttribute('y2'));
 					var id = elem.id;
 					var id = elem.id;
 					
 					
 					var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' ');
 					var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' ');
@@ -567,17 +573,17 @@ svgEditor.addExtension("Connector", function(S) {
 				}
 				}
 			}
 			}
 			// Update line if it's a connector
 			// Update line if it's a connector
-			if(elem.getAttribute('class') == conn_sel.substr(1)) {
-				var start = getElem(elData(elem, 'c_start'));
+			if (elem.getAttribute('class') == conn_sel.substr(1)) {
+				start = getElem(elData(elem, 'c_start'));
 				updateConnectors([start]);
 				updateConnectors([start]);
 			} else {
 			} else {
 				updateConnectors();
 				updateConnectors();
 			}
 			}
 		},
 		},
 		toolButtonStateUpdate: function(opts) {
 		toolButtonStateUpdate: function(opts) {
-			if(opts.nostroke) {
+			if (opts.nostroke) {
 				if ($('#mode_connect').hasClass('tool_button_current')) {
 				if ($('#mode_connect').hasClass('tool_button_current')) {
-					clickSelect();
+					svgEditor.clickSelect();
 				}
 				}
 			}
 			}
 			$('#mode_connect')
 			$('#mode_connect')

+ 67 - 0
main/inc/lib/svg-edit/extensions/ext-executablebuilder.js

@@ -0,0 +1,67 @@
+/*globals svgEditor*/
+/*
+Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind
+
+Todos:
+1. See WebAppFind Readme for SVG-related todos
+*/
+(function () {'use strict';
+
+var pathID,
+    saveMessage = 'webapp-save',
+    readMessage = 'webapp-read',
+    excludedMessages = [readMessage, saveMessage];
+
+window.addEventListener('message', function(e) {
+    if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively)
+        (!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below
+    ) {
+        return;
+    }
+    var svgString,
+        messageType = e.data[0];
+    switch (messageType) {
+        case 'webapp-view':
+            // Populate the contents
+            pathID = e.data[1];
+            
+            svgString = e.data[2];
+            svgEditor.loadFromString(svgString);
+            
+            /*if ($('#tool_save_file')) {
+                $('#tool_save_file').disabled = false;
+            }*/
+            break;
+        case 'webapp-save-end':
+            alert('save complete for pathID ' + e.data[1] + '!');
+            break;
+        default:
+            throw 'Unexpected mode';
+    }
+}, false);
+
+window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on)
+
+svgEditor.addExtension('WebAppFind', function() {
+
+    return {
+        name: 'WebAppFind',
+        svgicons: svgEditor.curConfig.extPath + 'executablebuilder-icocreator.svg',
+        buttons: [{
+            id: 'webappfind_ico_export', // 
+            type: 'app_menu',
+            title: 'Export ICO Image back to Disk',
+            position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
+            events: {
+                click: function () {
+                    if (!pathID) { // Not ready yet as haven't received first payload
+                        return;
+                    }
+                    window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin);
+                }
+            }
+        }]
+    };
+});
+
+}());

+ 91 - 88
main/inc/lib/svg-edit/extensions/ext-eyedropper.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, svgedit, $*/
+/*jslint vars: true, eqeq: true*/
 /*
 /*
  * ext-eyedropper.js
  * ext-eyedropper.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Jeff Schiller
  * Copyright(c) 2010 Jeff Schiller
  *
  *
@@ -13,97 +15,98 @@
 // 3) svg_editor.js
 // 3) svg_editor.js
 // 4) svgcanvas.js
 // 4) svgcanvas.js
 
 
-svgEditor.addExtension("eyedropper", function(S) {
-		var svgcontent = S.svgcontent,
-			svgns = "http://www.w3.org/2000/svg",
-			svgdoc = S.svgroot.parentNode.ownerDocument,
-			svgCanvas = svgEditor.canvas,
-			ChangeElementCommand = svgedit.history.ChangeElementCommand,
-			addToHistory = function(cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
-			currentStyle = {fillPaint: "red", fillOpacity: 1.0,
-							strokePaint: "black", strokeOpacity: 1.0, 
-							strokeWidth: 5, strokeDashArray: null,
-							opacity: 1.0,
-							strokeLinecap: 'butt',
-							strokeLinejoin: 'miter',
-							};
-							
-		function getStyle(opts) {
-			// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
-			var mode = svgCanvas.getMode();
-			if (mode == "eyedropper") return;
+svgEditor.addExtension("eyedropper", function(S) {'use strict';
+	var // NS = svgedit.NS,
+		// svgcontent = S.svgcontent,
+		// svgdoc = S.svgroot.parentNode.ownerDocument,
+		svgCanvas = svgEditor.canvas,
+		ChangeElementCommand = svgedit.history.ChangeElementCommand,
+		addToHistory = function(cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
+		currentStyle = {
+			fillPaint: "red", fillOpacity: 1.0,
+			strokePaint: "black", strokeOpacity: 1.0, 
+			strokeWidth: 5, strokeDashArray: null,
+			opacity: 1.0,
+			strokeLinecap: 'butt',
+			strokeLinejoin: 'miter'
+		};
 
 
-			var elem = null;
-			var tool = $('#tool_eyedropper');
-			// enable-eye-dropper if one element is selected
-			if (!opts.multiselected && opts.elems[0] &&
-				$.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) == -1) 
-			{
-				elem = opts.elems[0];
-				tool.removeClass('disabled');
-				// grab the current style
-				currentStyle.fillPaint = elem.getAttribute("fill") || "black";
-				currentStyle.fillOpacity = elem.getAttribute("fill-opacity") || 1.0;
-				currentStyle.strokePaint = elem.getAttribute("stroke");
-				currentStyle.strokeOpacity = elem.getAttribute("stroke-opacity") || 1.0;
-				currentStyle.strokeWidth = elem.getAttribute("stroke-width");
-				currentStyle.strokeDashArray = elem.getAttribute("stroke-dasharray");
-				currentStyle.strokeLinecap = elem.getAttribute("stroke-linecap");
-				currentStyle.strokeLinejoin = elem.getAttribute("stroke-linejoin");
-				currentStyle.opacity = elem.getAttribute("opacity") || 1.0;
-			}
-			// disable eye-dropper tool
-			else {
-				tool.addClass('disabled');
-			}
+	function getStyle(opts) {
+		// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
+		var mode = svgCanvas.getMode();
+		if (mode == "eyedropper") {return;}
 
 
+		var elem = null;
+		var tool = $('#tool_eyedropper');
+		// enable-eye-dropper if one element is selected
+		if (!opts.multiselected && opts.elems[0] &&
+			$.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1
+		) {
+			elem = opts.elems[0];
+			tool.removeClass('disabled');
+			// grab the current style
+			currentStyle.fillPaint = elem.getAttribute("fill") || "black";
+			currentStyle.fillOpacity = elem.getAttribute("fill-opacity") || 1.0;
+			currentStyle.strokePaint = elem.getAttribute("stroke");
+			currentStyle.strokeOpacity = elem.getAttribute("stroke-opacity") || 1.0;
+			currentStyle.strokeWidth = elem.getAttribute("stroke-width");
+			currentStyle.strokeDashArray = elem.getAttribute("stroke-dasharray");
+			currentStyle.strokeLinecap = elem.getAttribute("stroke-linecap");
+			currentStyle.strokeLinejoin = elem.getAttribute("stroke-linejoin");
+			currentStyle.opacity = elem.getAttribute("opacity") || 1.0;
 		}
 		}
-		
-		return {
-			name: "eyedropper",
-			svgicons: "extensions/eyedropper-icon.xml",
-			buttons: [{
-				id: "tool_eyedropper",
-				type: "mode",
-				title: "Eye Dropper Tool",
-				key: "I",
-				events: {
-					"click": function() {
-						svgCanvas.setMode("eyedropper");
-					}
+		// disable eye-dropper tool
+		else {
+			tool.addClass('disabled');
+		}
+
+	}
+	
+	return {
+		name: "eyedropper",
+		svgicons: svgEditor.curConfig.extPath + "eyedropper-icon.xml",
+		buttons: [{
+			id: "tool_eyedropper",
+			type: "mode",
+			title: "Eye Dropper Tool",
+			key: "I",
+			events: {
+				"click": function() {
+					svgCanvas.setMode("eyedropper");
 				}
 				}
-			}],
-			
-			// if we have selected an element, grab its paint and enable the eye dropper button
-			selectedChanged: getStyle,
-			elementChanged: getStyle,
-			
-			mouseDown: function(opts) {
-				var mode = svgCanvas.getMode();
-				if (mode == "eyedropper") {
-					var e = opts.event;
-					var target = e.target;
-					if ($.inArray(target.nodeName, ['svg', 'g', 'use']) == -1) {
-						var changes = {};
+			}
+		}],
+		
+		// if we have selected an element, grab its paint and enable the eye dropper button
+		selectedChanged: getStyle,
+		elementChanged: getStyle,
+		
+		mouseDown: function(opts) {
+			var mode = svgCanvas.getMode();
+			if (mode == "eyedropper") {
+				var e = opts.event;
+				var target = e.target;
+				if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) {
+					var changes = {};
 
 
-						var change = function(elem, attrname, newvalue) {
-							changes[attrname] = elem.getAttribute(attrname);
-							elem.setAttribute(attrname, newvalue);
-						};
-						
-						if (currentStyle.fillPaint) 		change(target, "fill", currentStyle.fillPaint);
-						if (currentStyle.fillOpacity) 		change(target, "fill-opacity", currentStyle.fillOpacity);
-						if (currentStyle.strokePaint) 		change(target, "stroke", currentStyle.strokePaint);
-						if (currentStyle.strokeOpacity) 	change(target, "stroke-opacity", currentStyle.strokeOpacity);
-						if (currentStyle.strokeWidth) 		change(target, "stroke-width", currentStyle.strokeWidth);
-						if (currentStyle.strokeDashArray) 	change(target, "stroke-dasharray", currentStyle.strokeDashArray);
-						if (currentStyle.opacity) 			change(target, "opacity", currentStyle.opacity);
-						if (currentStyle.strokeLinecap) 	change(target, "stroke-linecap", currentStyle.strokeLinecap);
-						if (currentStyle.strokeLinejoin) 	change(target, "stroke-linejoin", currentStyle.strokeLinejoin);
-						
-						addToHistory(new ChangeElementCommand(target, changes));
-					}
+					var change = function(elem, attrname, newvalue) {
+						changes[attrname] = elem.getAttribute(attrname);
+						elem.setAttribute(attrname, newvalue);
+					};
+					
+					if (currentStyle.fillPaint) {change(target, "fill", currentStyle.fillPaint);}
+					if (currentStyle.fillOpacity) {change(target, "fill-opacity", currentStyle.fillOpacity);}
+					if (currentStyle.strokePaint) {change(target, "stroke", currentStyle.strokePaint);}
+					if (currentStyle.strokeOpacity) {change(target, "stroke-opacity", currentStyle.strokeOpacity);}
+					if (currentStyle.strokeWidth) {change(target, "stroke-width", currentStyle.strokeWidth);}
+					if (currentStyle.strokeDashArray) {change(target, "stroke-dasharray", currentStyle.strokeDashArray);}
+					if (currentStyle.opacity) {change(target, "opacity", currentStyle.opacity);}
+					if (currentStyle.strokeLinecap) {change(target, "stroke-linecap", currentStyle.strokeLinecap);}
+					if (currentStyle.strokeLinejoin) {change(target, "stroke-linejoin", currentStyle.strokeLinejoin);}
+					
+					addToHistory(new ChangeElementCommand(target, changes));
 				}
 				}
-			},
-		};
+			}
+		}
+	};
 });
 });

+ 229 - 238
main/inc/lib/svg-edit/extensions/ext-foreignobject.js

@@ -1,3 +1,5 @@
+/*globals svgEditor, svgedit, svgCanvas, $*/
+/*jslint vars: true, eqeq: true, todo: true*/
 /*
 /*
  * ext-foreignobject.js
  * ext-foreignobject.js
  *
  *
@@ -9,269 +11,258 @@
  */
  */
 
 
 svgEditor.addExtension("foreignObject", function(S) {
 svgEditor.addExtension("foreignObject", function(S) {
-		var svgcontent = S.svgcontent,
-			addElem = S.addSvgElementFromJson,
-			selElems,
-			svgns = "http://www.w3.org/2000/svg",
-			xlinkns = "http://www.w3.org/1999/xlink",
-			xmlns = "http://www.w3.org/XML/1998/namespace",
-			xmlnsns = "http://www.w3.org/2000/xmlns/",
-			se_ns = "http://svg-edit.googlecode.com",
-			htmlns = "http://www.w3.org/1999/xhtml",
-			mathns = "http://www.w3.org/1998/Math/MathML",
-			editingforeign = false,
-			svgdoc = S.svgroot.parentNode.ownerDocument,
-			started,
-			newFO;
-			
-			
-		var properlySourceSizeTextArea = function(){
-			// TODO: remove magic numbers here and get values from CSS
-			var height = $('#svg_source_container').height() - 80;
-			$('#svg_source_textarea').css('height', height);
-		};
+	var NS = svgedit.NS,
+		Utils = svgedit.utilities,
+		svgcontent = S.svgcontent,
+		addElem = S.addSvgElementFromJson,
+		selElems,
+		editingforeign = false,
+		svgdoc = S.svgroot.parentNode.ownerDocument,
+		started,
+		newFO;
 
 
-		function showPanel(on) {
-			var fc_rules = $('#fc_rules');
-			if(!fc_rules.length) {
-				fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
-			} 
-			fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
-			$('#foreignObject_panel').toggle(on);
-		}
+	var properlySourceSizeTextArea = function () {
+		// TODO: remove magic numbers here and get values from CSS
+		var height = $('#svg_source_container').height() - 80;
+		$('#svg_source_textarea').css('height', height);
+	};
 
 
-		function toggleSourceButtons(on) {
-			$('#tool_source_save, #tool_source_cancel').toggle(!on);
-			$('#foreign_save, #foreign_cancel').toggle(on);
+	function showPanel(on) {
+		var fc_rules = $('#fc_rules');
+		if(!fc_rules.length) {
+			fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
 		}
 		}
-		
-			
-		// Function: setForeignString(xmlString, elt)
-		// This function sets the content of element elt to the input XML.
-		//
-		// Parameters:
-		// xmlString - The XML text.
-		// elt - the parent element to append to
-		//
-		// Returns:
-		// This function returns false if the set was unsuccessful, true otherwise.
-		function setForeignString(xmlString) {
-			var elt = selElems[0];
-			try {
-				// convert string into XML document
-				var newDoc = Utils.text2xml('<svg xmlns="'+svgns+'" xmlns:xlink="'+xlinkns+'">'+xmlString+'</svg>');
-				// run it through our sanitizer to remove anything we do not support
-				S.sanitizeSvg(newDoc.documentElement);
-				elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
-				S.call("changed", [elt]);
-				svgCanvas.clearSelection();
-			} catch(e) {
-				console.log(e);
-				return false;
-			}
-	
-			return true;
-		};
+		fc_rules.text(!on?"":" #tool_topath { display: none !important; }");
+		$('#foreignObject_panel').toggle(on);
+	}
 
 
-		function showForeignEditor() {
-			var elt = selElems[0];
-			if (!elt || editingforeign) return;
-			editingforeign = true;
-			toggleSourceButtons(true);
-			elt.removeAttribute('fill');
+	function toggleSourceButtons(on) {
+		$('#tool_source_save, #tool_source_cancel').toggle(!on);
+		$('#foreign_save, #foreign_cancel').toggle(on);
+	}
 
 
-			var str = S.svgToString(elt, 0);
-			$('#svg_source_textarea').val(str);
-			$('#svg_source_editor').fadeIn();
-			properlySourceSizeTextArea();
-			$('#svg_source_textarea').focus();
-		}
-		
-		function setAttr(attr, val) {
-			svgCanvas.changeSelectedAttribute(attr, val);
-			S.call("changed", selElems);
+	// Function: setForeignString(xmlString, elt)
+	// This function sets the content of element elt to the input XML.
+	//
+	// Parameters:
+	// xmlString - The XML text.
+	// elt - the parent element to append to
+	//
+	// Returns:
+	// This function returns false if the set was unsuccessful, true otherwise.
+	function setForeignString(xmlString) {
+		var elt = selElems[0];
+		try {
+			// convert string into XML document
+			var newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
+			// run it through our sanitizer to remove anything we do not support
+			S.sanitizeSvg(newDoc.documentElement);
+			elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
+			S.call("changed", [elt]);
+			svgCanvas.clearSelection();
+		} catch(e) {
+			console.log(e);
+			return false;
 		}
 		}
-		
-		
-		return {
-			name: "foreignObject",
-			svgicons: "extensions/foreignobject-icons.xml",
-			buttons: [{
-				id: "tool_foreign",
-				type: "mode",
-				title: "Foreign Object Tool",
-				events: {
-					'click': function() {
-						svgCanvas.setMode('foreign')
-					}
+
+		return true;
+	}
+
+	function showForeignEditor() {
+		var elt = selElems[0];
+		if (!elt || editingforeign) {return;}
+		editingforeign = true;
+		toggleSourceButtons(true);
+		elt.removeAttribute('fill');
+
+		var str = S.svgToString(elt, 0);
+		$('#svg_source_textarea').val(str);
+		$('#svg_source_editor').fadeIn();
+		properlySourceSizeTextArea();
+		$('#svg_source_textarea').focus();
+	}
+
+	function setAttr(attr, val) {
+		svgCanvas.changeSelectedAttribute(attr, val);
+		S.call("changed", selElems);
+	}
+
+	return {
+		name: "foreignObject",
+		svgicons: svgEditor.curConfig.extPath + "foreignobject-icons.xml",
+		buttons: [{
+			id: "tool_foreign",
+			type: "mode",
+			title: "Foreign Object Tool",
+			events: {
+				'click': function() {
+					svgCanvas.setMode('foreign');
 				}
 				}
-			},{
-				id: "edit_foreign",
-				type: "context",
-				panel: "foreignObject_panel",
-				title: "Edit ForeignObject Content",
-				events: {
-					'click': function() {
-						showForeignEditor();
-					}
+			}
+		},{
+			id: "edit_foreign",
+			type: "context",
+			panel: "foreignObject_panel",
+			title: "Edit ForeignObject Content",
+			events: {
+				'click': function() {
+					showForeignEditor();
 				}
 				}
-			}],
-			
-			context_tools: [{
-				type: "input",
-				panel: "foreignObject_panel",
-				title: "Change foreignObject's width",
-				id: "foreign_width",
-				label: "w",
-				size: 3,
-				events: {
-					change: function() {
-						setAttr('width', this.value);
-					}
+			}
+		}],
+
+		context_tools: [{
+			type: "input",
+			panel: "foreignObject_panel",
+			title: "Change foreignObject's width",
+			id: "foreign_width",
+			label: "w",
+			size: 3,
+			events: {
+				change: function() {
+					setAttr('width', this.value);
 				}
 				}
-			},{
-				type: "input",
-				panel: "foreignObject_panel",
-				title: "Change foreignObject's height",
-				id: "foreign_height",
-				label: "h",
-				events: {
-					change: function() {
-						setAttr('height', this.value);
-					}
+			}
+		},{
+			type: "input",
+			panel: "foreignObject_panel",
+			title: "Change foreignObject's height",
+			id: "foreign_height",
+			label: "h",
+			events: {
+				change: function() {
+					setAttr('height', this.value);
 				}
 				}
-			}, {
-				type: "input",
-				panel: "foreignObject_panel",
-				title: "Change foreignObject's font size",
-				id: "foreign_font_size",
-				label: "font-size",
-				size: 2,
-				defval: 16,
-				events: {
-					change: function() {
-						setAttr('font-size', this.value);
-					}
+			}
+		}, {
+			type: "input",
+			panel: "foreignObject_panel",
+			title: "Change foreignObject's font size",
+			id: "foreign_font_size",
+			label: "font-size",
+			size: 2,
+			defval: 16,
+			events: {
+				change: function() {
+					setAttr('font-size', this.value);
 				}
 				}
 			}
 			}
-			
-			
-			],
-			callback: function() {
-				$('#foreignObject_panel').hide();
+		}
 
 
-				var endChanges = function() {
-					$('#svg_source_editor').hide();
-					editingforeign = false;
-					$('#svg_source_textarea').blur();
-					toggleSourceButtons(false);
-				}
+		],
+		callback: function() {
+			$('#foreignObject_panel').hide();
 
 
-				// TODO: Needs to be done after orig icon loads
-				setTimeout(function() {				
-					// Create source save/cancel buttons
-					var save = $('#tool_source_save').clone()
-						.hide().attr('id', 'foreign_save').unbind()
-						.appendTo("#tool_source_back").click(function() {
-							
-							if (!editingforeign) return;
+			var endChanges = function() {
+				$('#svg_source_editor').hide();
+				editingforeign = false;
+				$('#svg_source_textarea').blur();
+				toggleSourceButtons(false);
+			};
 
 
-							if (!setForeignString($('#svg_source_textarea').val())) {
-								$.confirm("Errors found. Revert to original?", function(ok) {
-									if(!ok) return false;
-									endChanges();
-								});
-							} else {
+			// TODO: Needs to be done after orig icon loads
+			setTimeout(function() {
+				// Create source save/cancel buttons
+				var save = $('#tool_source_save').clone()
+					.hide().attr('id', 'foreign_save').unbind()
+					.appendTo("#tool_source_back").click(function() {
+
+						if (!editingforeign) {return;}
+
+						if (!setForeignString($('#svg_source_textarea').val())) {
+							$.confirm("Errors found. Revert to original?", function(ok) {
+								if(!ok) {return false;}
 								endChanges();
 								endChanges();
-							}
-							// setSelectMode();	
-						});
-						
-					var cancel = $('#tool_source_cancel').clone()
-						.hide().attr('id', 'foreign_cancel').unbind()
-						.appendTo("#tool_source_back").click(function() {
+							});
+						} else {
 							endChanges();
 							endChanges();
-						});
-					
-				}, 3000);
-			},
-			mouseDown: function(opts) {
-				var e = opts.event;
-				
-				if(svgCanvas.getMode() == "foreign") {
-
-					started = true;
-					newFO = S.addSvgElementFromJson({
-						"element": "foreignObject",
-						"attr": {
-							"x": opts.start_x,
-							"y": opts.start_y,
-							"id": S.getNextId(),
-							"font-size": 16, //cur_text.font_size,
-							"width": "48",
-							"height": "20",
-							"style": "pointer-events:inherit"
 						}
 						}
+						// setSelectMode();	
 					});
 					});
-					var m = svgdoc.createElementNS(mathns, 'math');
-					m.setAttributeNS(xmlnsns, 'xmlns', mathns);
-					m.setAttribute('display', 'inline');
-					var mi = svgdoc.createElementNS(mathns, 'mi');
-					mi.setAttribute('mathvariant', 'normal');
-					mi.textContent = "\u03A6";
-					var mo = svgdoc.createElementNS(mathns, 'mo');
-					mo.textContent = "\u222A";
-					var mi2 = svgdoc.createElementNS(mathns, 'mi');
-					mi2.textContent = "\u2133";
-					m.appendChild(mi);
-					m.appendChild(mo);
-					m.appendChild(mi2);
-					newFO.appendChild(m);
-					return {
-						started: true
-					}
-				}
-			},
-			mouseUp: function(opts) {
-				var e = opts.event;
-				if(svgCanvas.getMode() == "foreign" && started) {
-					var attrs = $(newFO).attr(["width", "height"]);
-					keep = (attrs.width != 0 || attrs.height != 0);
-					svgCanvas.addToSelection([newFO], true);
 
 
-					return {
-						keep: keep,
-						element: newFO
+				var cancel = $('#tool_source_cancel').clone()
+					.hide().attr('id', 'foreign_cancel').unbind()
+					.appendTo("#tool_source_back").click(function() {
+						endChanges();
+					});
+			}, 3000);
+		},
+		mouseDown: function(opts) {
+			var e = opts.event;
+
+			if(svgCanvas.getMode() == "foreign") {
+
+				started = true;
+				newFO = S.addSvgElementFromJson({
+					"element": "foreignObject",
+					"attr": {
+						"x": opts.start_x,
+						"y": opts.start_y,
+						"id": S.getNextId(),
+						"font-size": 16, //cur_text.font_size,
+						"width": "48",
+						"height": "20",
+						"style": "pointer-events:inherit"
 					}
 					}
+				});
+				var m = svgdoc.createElementNS(NS.MATH, 'math');
+				m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
+				m.setAttribute('display', 'inline');
+				var mi = svgdoc.createElementNS(NS.MATH, 'mi');
+				mi.setAttribute('mathvariant', 'normal');
+				mi.textContent = "\u03A6";
+				var mo = svgdoc.createElementNS(NS.MATH, 'mo');
+				mo.textContent = "\u222A";
+				var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
+				mi2.textContent = "\u2133";
+				m.appendChild(mi);
+				m.appendChild(mo);
+				m.appendChild(mi2);
+				newFO.appendChild(m);
+				return {
+					started: true
+				};
+			}
+		},
+		mouseUp: function(opts) {
+			var e = opts.event;
+			if(svgCanvas.getMode() == "foreign" && started) {
+				var attrs = $(newFO).attr(["width", "height"]);
+				var keep = (attrs.width != 0 || attrs.height != 0);
+				svgCanvas.addToSelection([newFO], true);
 
 
-				}
-				
-			},
-			selectedChanged: function(opts) {
-				// Use this to update the current selected elements
-				selElems = opts.elems;
-				
-				var i = selElems.length;
-				
-				while(i--) {
-					var elem = selElems[i];
-					if(elem && elem.tagName == "foreignObject") {
-						if(opts.selectedElement && !opts.multiselected) {
-							$('#foreign_font_size').val(elem.getAttribute("font-size"));
-							$('#foreign_width').val(elem.getAttribute("width"));
-							$('#foreign_height').val(elem.getAttribute("height"));
-						
-							showPanel(true);
-						} else {
-							showPanel(false);
-						}
+				return {
+					keep: keep,
+					element: newFO
+				};
+
+			}
+
+		},
+		selectedChanged: function(opts) {
+			// Use this to update the current selected elements
+			selElems = opts.elems;
+
+			var i = selElems.length;
+
+			while(i--) {
+				var elem = selElems[i];
+				if(elem && elem.tagName === 'foreignObject') {
+					if(opts.selectedElement && !opts.multiselected) {
+						$('#foreign_font_size').val(elem.getAttribute("font-size"));
+						$('#foreign_width').val(elem.getAttribute("width"));
+						$('#foreign_height').val(elem.getAttribute("height"));
+						showPanel(true);
 					} else {
 					} else {
 						showPanel(false);
 						showPanel(false);
 					}
 					}
+				} else {
+					showPanel(false);
 				}
 				}
-			},
-			elementChanged: function(opts) {
-				var elem = opts.elems[0];
 			}
 			}
-		};
+		},
+		elementChanged: function(opts) {
+			var elem = opts.elems[0];
+		}
+	};
 });
 });

+ 101 - 130
main/inc/lib/svg-edit/extensions/ext-grid.js

@@ -1,3 +1,5 @@
+/*globals svgEditor, svgedit, svgCanvas, $*/
+/*jslint vars: true*/
 /*
 /*
  * ext-grid.js
  * ext-grid.js
  *
  *
@@ -12,119 +14,95 @@
 // 1) units.js
 // 1) units.js
 // 2) everything else
 // 2) everything else
 
 
-svgEditor.addExtension("view_grid", function(s) {
-
-    var svgdoc = document.getElementById("svgcanvas").ownerDocument,
-			svgns = "http://www.w3.org/2000/svg",
-			dims = svgEditor.curConfig.dimensions,
-			svgroot = s.svgroot;
-
-	var showGrid = false;
-    var assignAttributes = svgCanvas.assignAttributes;
-    
-    var hcanvas = document.createElement('canvas');
-    $(hcanvas).hide().appendTo('body');
-
-    var canvasgrid = svgdoc.createElementNS(svgns, "svg");
-    assignAttributes(canvasgrid, {
-        'id': 'canvasGrid',
-        'width': '100%',
-        'height': '100%',
-        'x': 0,
-        'y': 0,
-        'overflow': 'visible',
-        'display': 'none'
-    });
-    
-    var canvBG = $('#canvasBackground');
-    canvBG.append(canvasgrid);
-
-        // grid-pattern
-        var gridPattern = svgdoc.createElementNS(svgns, "pattern");
-        assignAttributes(gridPattern, {
-            'id': 'gridpattern',
-            'patternUnits': 'userSpaceOnUse',
-            'x': 0, //-(value.strokeWidth / 2), // position for strokewidth
-            'y': 0, //-(value.strokeWidth / 2), // position for strokewidth
-            'width': 100,
-            'height': 100
-        });
-        
-        var gridimg = svgdoc.createElementNS(svgns, "image");
-        assignAttributes(gridimg, {
-            'x': 0,
-            'y': 0,
-            'width': 100,
-            'height': 100
-        });
-        
-        gridPattern.appendChild(gridimg);
-        $('#svgroot defs').append(gridPattern);
-
-        // grid-box
-        var gridBox = svgdoc.createElementNS(svgns, "rect");
-        assignAttributes(gridBox, {
-            'width': '100%',
-            'height': '100%',
-            'x': 0,
-            'y': 0,
-            'stroke-width': 0,
-            'stroke': 'none',
-            'fill': 'url(#gridpattern)',
-            'style': 'pointer-events: none; display:visible;'
-        });
-        $('#canvasGrid').append(gridBox);
-//     });
+svgEditor.addExtension('view_grid', function() { 'use strict';
+
+	var NS = svgedit.NS,
+		svgdoc = document.getElementById('svgcanvas').ownerDocument,
+		showGrid = false,
+		assignAttributes = svgCanvas.assignAttributes,
+		hcanvas = document.createElement('canvas'),
+		canvBG = $('#canvasBackground'),
+		units = svgedit.units.getTypeMap(),
+		intervals = [0.01, 0.1, 1, 10, 100, 1000];
+
+	$(hcanvas).hide().appendTo('body');
+
+	var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
+	assignAttributes(canvasGrid, {
+		'id': 'canvasGrid',
+		'width': '100%',
+		'height': '100%',
+		'x': 0,
+		'y': 0,
+		'overflow': 'visible',
+		'display': 'none'
+	});
+	canvBG.append(canvasGrid);
+
+	// grid-pattern
+	var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
+	assignAttributes(gridPattern, {
+		'id': 'gridpattern',
+		'patternUnits': 'userSpaceOnUse',
+		'x': 0, //-(value.strokeWidth / 2), // position for strokewidth
+		'y': 0, //-(value.strokeWidth / 2), // position for strokewidth
+		'width': 100,
+		'height': 100
+	});
+
+	var gridimg = svgdoc.createElementNS(NS.SVG, 'image');
+	assignAttributes(gridimg, {
+		'x': 0,
+		'y': 0,
+		'width': 100,
+		'height': 100
+	});
+	gridPattern.appendChild(gridimg);
+	$('#svgroot defs').append(gridPattern);
+
+	// grid-box
+	var gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
+	assignAttributes(gridBox, {
+		'width': '100%',
+		'height': '100%',
+		'x': 0,
+		'y': 0,
+		'stroke-width': 0,
+		'stroke': 'none',
+		'fill': 'url(#gridpattern)',
+		'style': 'pointer-events: none; display:visible;'
+	});
+	$('#canvasGrid').append(gridBox);
 
 
 	function updateGrid(zoom) {
 	function updateGrid(zoom) {
+		var i;
 		// TODO: Try this with <line> elements, then compare performance difference
 		// TODO: Try this with <line> elements, then compare performance difference
-	
-		var bgwidth = +canvBG.attr('width');
-		var bgheight = +canvBG.attr('height');
-		
-		var units = svgedit.units.getTypeMap();
 		var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
 		var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
-		var r_intervals = [.01, .1, 1, 10, 100, 1000];
-	
-		var d = 0;
-		var is_x = (d === 0);
-		var dim = is_x ? 'x' : 'y';
-		var lentype = is_x?'width':'height';
-		var c_elem = svgCanvas.getContentElem();
-		var content_d = c_elem.getAttribute(dim)-0;
-		
-		var hcanv = hcanvas;
-		
 		var u_multi = unit * zoom;
 		var u_multi = unit * zoom;
-		
 		// Calculate the main number interval
 		// Calculate the main number interval
 		var raw_m = 100 / u_multi;
 		var raw_m = 100 / u_multi;
 		var multi = 1;
 		var multi = 1;
-		for(var i = 0; i < r_intervals.length; i++) {
-			var num = r_intervals[i];
+		for (i = 0; i < intervals.length; i++) {
+			var num = intervals[i];
 			multi = num;
 			multi = num;
-			if(raw_m <= num) {
+			if (raw_m <= num) {
 				break;
 				break;
 			}
 			}
 		}
 		}
-		
 		var big_int = multi * u_multi;
 		var big_int = multi * u_multi;
 
 
 		// Set the canvas size to the width of the container
 		// Set the canvas size to the width of the container
-		hcanv.width = big_int;
-		hcanv.height = big_int;
-		var ctx = hcanv.getContext("2d");
-
-		var ruler_d = 0; 
-		var cur_d = .5;
-		
+		hcanvas.width = big_int;
+		hcanvas.height = big_int;
+		var ctx = hcanvas.getContext('2d');
+		var cur_d = 0.5;
 		var part = big_int / 10;
 		var part = big_int / 10;
 
 
 		ctx.globalAlpha = 0.2;
 		ctx.globalAlpha = 0.2;
-		ctx.strokeStyle = "#000";
-		for(var i = 1; i < 10; i++) {
-			var sub_d = Math.round(part * i) + .5;
-// 					var line_num = (i % 2)?12:10;
+		ctx.strokeStyle = svgEditor.curConfig.gridColor;
+		for (i = 1; i < 10; i++) {
+			var sub_d = Math.round(part * i) + 0.5;
+			// var line_num = (i % 2)?12:10;
 			var line_num = 0;
 			var line_num = 0;
 			ctx.moveTo(sub_d, big_int);
 			ctx.moveTo(sub_d, big_int);
 			ctx.lineTo(sub_d, line_num);
 			ctx.lineTo(sub_d, line_num);
@@ -132,7 +110,7 @@ svgEditor.addExtension("view_grid", function(s) {
 			ctx.lineTo(line_num ,sub_d);
 			ctx.lineTo(line_num ,sub_d);
 		}
 		}
 		ctx.stroke();
 		ctx.stroke();
-		ctx.beginPath();  
+		ctx.beginPath();
 		ctx.globalAlpha = 0.5;
 		ctx.globalAlpha = 0.5;
 		ctx.moveTo(cur_d, big_int);
 		ctx.moveTo(cur_d, big_int);
 		ctx.lineTo(cur_d, 0);
 		ctx.lineTo(cur_d, 0);
@@ -141,7 +119,7 @@ svgEditor.addExtension("view_grid", function(s) {
 		ctx.lineTo(0, cur_d);
 		ctx.lineTo(0, cur_d);
 		ctx.stroke();
 		ctx.stroke();
 
 
-		var datauri = hcanv.toDataURL('image/png');
+		var datauri = hcanvas.toDataURL('image/png');
 		gridimg.setAttribute('width', big_int);
 		gridimg.setAttribute('width', big_int);
 		gridimg.setAttribute('height', big_int);
 		gridimg.setAttribute('height', big_int);
 		gridimg.parentNode.setAttribute('width', big_int);
 		gridimg.parentNode.setAttribute('width', big_int);
@@ -149,36 +127,29 @@ svgEditor.addExtension("view_grid", function(s) {
 		svgCanvas.setHref(gridimg, datauri);
 		svgCanvas.setHref(gridimg, datauri);
 	}
 	}
 
 
-    return {
-        name: "view_grid",
-        svgicons: "extensions/grid-icon.xml",
-
-        zoomChanged: function(zoom) {
-            // update size
-            if(showGrid) updateGrid(zoom);
-        },
-
-        buttons: [{
-            id: "view_grid",
-            type: "context",
-            panel: "editor_panel",
-            title: "Show/Hide Grid",
-            events: {
-                'click': function() {
-                    var gr = !$('#view_grid').hasClass('push_button_pressed');
-                    if (gr) {
-                        svgEditor.curConfig.showGrid = showGrid = true;
-                        $('#view_grid').addClass('push_button_pressed').removeClass('tool_button');
-                        $('#canvasGrid').attr('display', 'normal');
-                        updateGrid(svgCanvas.getZoom());
-                    }
-                    else {
-                        svgEditor.curConfig.showGrid = showGrid = false;
-                        $('#view_grid').removeClass('push_button_pressed').addClass('tool_button');
-                        $('#canvasGrid').attr('display', 'none');
-                    }
-                }
-            }
-}]
-        };
-    });
+	return {
+		name: 'view_grid',
+		svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
+
+		zoomChanged: function(zoom) {
+			if (showGrid) {updateGrid(zoom);}
+		},
+
+		buttons: [{
+			id: 'view_grid',
+			type: 'context',
+			panel: 'editor_panel',
+			title: 'Show/Hide Grid',
+			events: {
+				click: function() {
+					svgEditor.curConfig.showGrid = showGrid = !showGrid;
+					if (showGrid) {
+						updateGrid(svgCanvas.getZoom());
+					}
+					$('#canvasGrid').toggle(showGrid);
+					$('#view_grid').toggleClass('push_button_pressed tool_button');
+				}
+			}
+		}]
+	};
+});

+ 6 - 4
main/inc/lib/svg-edit/extensions/ext-helloworld.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, svgCanvas, $*/
+/*jslint vars: true, eqeq: true*/
 /*
 /*
  * ext-helloworld.js
  * ext-helloworld.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
@@ -10,16 +12,16 @@
 /* 
 /* 
 	This is a very basic SVG-Edit extension. It adds a "Hello World" button in
 	This is a very basic SVG-Edit extension. It adds a "Hello World" button in
 	the left panel. Clicking on the button, and then the canvas will show the
 	the left panel. Clicking on the button, and then the canvas will show the
- 	user the point on the canvas that was clicked on.
+	user the point on the canvas that was clicked on.
 */
 */
  
  
-svgEditor.addExtension("Hello World", function() {
+svgEditor.addExtension("Hello World", function() {'use strict';
 
 
 		return {
 		return {
 			name: "Hello World",
 			name: "Hello World",
 			// For more notes on how to make an icon file, see the source of
 			// For more notes on how to make an icon file, see the source of
 			// the hellorworld-icon.xml
 			// the hellorworld-icon.xml
-			svgicons: "extensions/helloworld-icon.xml",
+			svgicons: svgEditor.curConfig.extPath + "helloworld-icon.xml",
 			
 			
 			// Multiple buttons can be added in this array
 			// Multiple buttons can be added in this array
 			buttons: [{
 			buttons: [{

+ 134 - 120
main/inc/lib/svg-edit/extensions/ext-imagelib.js

@@ -1,17 +1,18 @@
+/*globals $, svgEditor, svgedit, svgCanvas, DOMParser*/
+/*jslint vars: true, eqeq: true, es5: true, todo: true */
 /*
 /*
  * ext-imagelib.js
  * ext-imagelib.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
  */
  */
 
 
-svgEditor.addExtension("imagelib", function() {
-	//Chamilo change library title and index.html by index.php
-	
+svgEditor.addExtension("imagelib", function() {'use strict';
+
 	var uiStrings = svgEditor.uiStrings;
 	var uiStrings = svgEditor.uiStrings;
-	
+
 	$.extend(uiStrings, {
 	$.extend(uiStrings, {
 		imagelib: {
 		imagelib: {
 			select_lib: 'Select an image library',
 			select_lib: 'Select an image library',
@@ -22,37 +23,36 @@ svgEditor.addExtension("imagelib", function() {
 		}
 		}
 	});
 	});
 
 
-	var img_libs = [{
-			name: 'Local library (local)',
-			url: 'extensions/imagelib/index.php',
-			//description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
-			description: 'Course gallery'
-		},
-		{
-			name: 'Local library',
-			url: 'extensions/imagelib/groups.php',
-			//description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
-			description: 'Group gallery'
-		},
-		{
-			name: 'Local library',
-			url: 'extensions/imagelib/users.php',
-			//description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
-			description: 'Personal gallery'
-		},		
-		{
-			name: 'IAN Symbol Libraries',
-			url: 'http://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
-			description: 'Free library of illustrations'
-		}
+	var img_libs = [
+        {
+            name: 'Local library (local)',
+            url: 'extensions/imagelib/index.php',
+            //description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
+            description: 'Course gallery'
+        },
+        {
+            name: 'Local library',
+            url: 'extensions/imagelib/groups.php',
+            //description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
+            description: 'Group gallery'
+        },
+        {
+            name: 'Local library',
+            url: 'extensions/imagelib/users.php',
+            //description: 'Demonstration library for SVG-edit on this server'// Chamilo change this line by below
+            description: 'Personal gallery'
+        },
+        {
+            name: 'IAN Symbol Libraries',
+            url: 'http://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
+            description: 'Free library of illustrations'
+        }
 	];
 	];
-	
-	var xlinkns = "http://www.w3.org/1999/xlink";
 
 
 	function closeBrowser() {
 	function closeBrowser() {
 		$('#imgbrowse_holder').hide();
 		$('#imgbrowse_holder').hide();
 	}
 	}
-	
+
 	function importImage(url) {
 	function importImage(url) {
 		var newImage = svgCanvas.addSvgElementFromJson({
 		var newImage = svgCanvas.addSvgElementFromJson({
 			"element": "image",
 			"element": "image",
@@ -75,110 +75,115 @@ svgEditor.addExtension("imagelib", function() {
 	var cur_meta;
 	var cur_meta;
 	var tranfer_stopped = false;
 	var tranfer_stopped = false;
 	var pending = {};
 	var pending = {};
-	
-	//Juan Carlos Raña Trabado hack for Chamilo add window.top. on the bottom line to run into a frame
-	window.top.window.addEventListener("message", function(evt) {							 
-												 
+	var preview, submit;
+
+	window.addEventListener("message", function(evt) {
 		// Receive postMessage data
 		// Receive postMessage data
 		var response = evt.data;
 		var response = evt.data;
-		
-		if(!response) {
+
+		if (!response || typeof response !== "string") { // Todo: Should namespace postMessage API for this extension and filter out here
 			// Do nothing
 			// Do nothing
 			return;
 			return;
 		}
 		}
-		
+		try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed)
+			var res = JSON.parse(response);
+			if (res.namespace) { // Part of embedAPI communications
+				return;
+			}
+		}
+		catch (e) {}
+
 		var char1 = response.charAt(0);
 		var char1 = response.charAt(0);
-		
+		var id;
 		var svg_str;
 		var svg_str;
 		var img_str;
 		var img_str;
-		
-		if(char1 != "{" && tranfer_stopped) {
+
+		if (char1 != "{" && tranfer_stopped) {
 			tranfer_stopped = false;
 			tranfer_stopped = false;
 			return;
 			return;
 		}
 		}
-		
-		if(char1 == '|') {
+
+		if (char1 == '|') {
 			var secondpos = response.indexOf('|', 1);
 			var secondpos = response.indexOf('|', 1);
-			var id = response.substr(1, secondpos-1);
+			id = response.substr(1, secondpos-1);
 			response = response.substr(secondpos+1);
 			response = response.substr(secondpos+1);
 			char1 = response.charAt(0);
 			char1 = response.charAt(0);
-
 		}
 		}
-		
-		
+
+
 		// Hide possible transfer dialog box
 		// Hide possible transfer dialog box
 		$('#dialog_box').hide();
 		$('#dialog_box').hide();
-		
+		var entry, cur_meta;
 		switch (char1) {
 		switch (char1) {
 			case '{':
 			case '{':
 				// Metadata
 				// Metadata
 				tranfer_stopped = false;
 				tranfer_stopped = false;
-				var cur_meta = JSON.parse(response);
-				
+				cur_meta = JSON.parse(response);
+
 				pending[cur_meta.id] = cur_meta;
 				pending[cur_meta.id] = cur_meta;
-				
+
 				var name = (cur_meta.name || 'file');
 				var name = (cur_meta.name || 'file');
-				
+
 				var message = uiStrings.notification.retrieving.replace('%s', name);
 				var message = uiStrings.notification.retrieving.replace('%s', name);
-				
-				if(mode != 'm') {
+
+				if (mode != 'm') {
 					$.process_cancel(message, function() {
 					$.process_cancel(message, function() {
 						tranfer_stopped = true;
 						tranfer_stopped = true;
 						// Should a message be sent back to the frame?
 						// Should a message be sent back to the frame?
-						
+
 						$('#dialog_box').hide();
 						$('#dialog_box').hide();
 					});
 					});
 				} else {
 				} else {
-					var entry = $('<div>' + message + '</div>').data('id', cur_meta.id);
+					entry = $('<div>' + message + '</div>').data('id', cur_meta.id);
 					preview.append(entry);
 					preview.append(entry);
 					cur_meta.entry = entry;
 					cur_meta.entry = entry;
 				}
 				}
-				
+
 				return;
 				return;
 			case '<':
 			case '<':
 				svg_str = true;
 				svg_str = true;
 				break;
 				break;
 			case 'd':
 			case 'd':
-				if(response.indexOf('data:image/svg+xml') === 0) {
+				if (response.indexOf('data:image/svg+xml') === 0) {
 					var pre = 'data:image/svg+xml;base64,';
 					var pre = 'data:image/svg+xml;base64,';
 					var src = response.substring(pre.length);
 					var src = response.substring(pre.length);
-					response = svgCanvas.Utils.decode64(src);
+					response = svgedit.utilities.decode64(src);
 					svg_str = true;
 					svg_str = true;
 					break;
 					break;
-				} else if(response.indexOf('data:image/') === 0) {
+				} else if (response.indexOf('data:image/') === 0) {
 					img_str = true;
 					img_str = true;
 					break;
 					break;
 				}
 				}
 				// Else fall through
 				// Else fall through
 			default:
 			default:
 				// TODO: See if there's a way to base64 encode the binary data stream
 				// TODO: See if there's a way to base64 encode the binary data stream
-// 				var str = 'data:;base64,' + svgCanvas.Utils.encode64(response, true);
-			
+//				var str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
+
 				// Assume it's raw image data
 				// Assume it's raw image data
-// 				importImage(str);
-			
+//				importImage(str);
+
 				// Don't give warning as postMessage may have been used by something else
 				// Don't give warning as postMessage may have been used by something else
-				if(mode !== 'm') {
+				if (mode !== 'm') {
 					closeBrowser();
 					closeBrowser();
 				} else {
 				} else {
 					pending[id].entry.remove();
 					pending[id].entry.remove();
 				}
 				}
-// 				$.alert('Unexpected data was returned: ' + response, function() {
-// 					if(mode !== 'm') {
-// 						closeBrowser();
-// 					} else {
-// 						pending[id].entry.remove();
-// 					}
-// 				});
+//				$.alert('Unexpected data was returned: ' + response, function() {
+//					if (mode !== 'm') {
+//						closeBrowser();
+//					} else {
+//						pending[id].entry.remove();
+//					}
+//				});
 				return;
 				return;
 		}
 		}
-		
+
 		switch (mode) {
 		switch (mode) {
 			case 's':
 			case 's':
 				// Import one
 				// Import one
-				if(svg_str) {
+				if (svg_str) {
 					svgCanvas.importSvgString(response);
 					svgCanvas.importSvgString(response);
-				} else if(img_str) {
+				} else if (img_str) {
 					importImage(response);
 					importImage(response);
 				}
 				}
 				closeBrowser();
 				closeBrowser();
@@ -186,19 +191,20 @@ svgEditor.addExtension("imagelib", function() {
 			case 'm':
 			case 'm':
 				// Import multiple
 				// Import multiple
 				multi_arr.push([(svg_str ? 'svg' : 'img'), response]);
 				multi_arr.push([(svg_str ? 'svg' : 'img'), response]);
-				var cur_meta = pending[id];
-				if(svg_str) {
-					if(cur_meta && cur_meta.name) {
-						var title = cur_meta.name;
-					}  else {
+				var title;
+				cur_meta = pending[id];
+				if (svg_str) {
+					if (cur_meta && cur_meta.name) {
+						title = cur_meta.name;
+					} else {
 						// Try to find a title
 						// Try to find a title
 						var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
 						var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
-						var title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
+						title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
 					}
 					}
-					if(cur_meta) {
+					if (cur_meta) {
 						preview.children().each(function() {
 						preview.children().each(function() {
-							if($(this).data('id') == id) {
-								if(cur_meta.preview_url) {
+							if ($(this).data('id') == id) {
+								if (cur_meta.preview_url) {
 									$(this).html('<img src="' + cur_meta.preview_url + '">' + title);
 									$(this).html('<img src="' + cur_meta.preview_url + '">' + title);
 								} else {
 								} else {
 									$(this).text(title);
 									$(this).text(title);
@@ -211,18 +217,18 @@ svgEditor.addExtension("imagelib", function() {
 						submit.removeAttr('disabled');
 						submit.removeAttr('disabled');
 					}
 					}
 				} else {
 				} else {
-					if(cur_meta && cur_meta.preview_url) {
-						var title = cur_meta.name || '';
+					if (cur_meta && cur_meta.preview_url) {
+						title = cur_meta.name || '';
 					}
 					}
-					if(cur_meta && cur_meta.preview_url) {
-						var entry = '<img src="' + cur_meta.preview_url + '">' + title;
+					if (cur_meta && cur_meta.preview_url) {
+						entry = '<img src="' + cur_meta.preview_url + '">' + title;
 					} else {
 					} else {
-						var entry = '<img src="' + response + '">';
+						entry = '<img src="' + response + '">';
 					}
 					}
-				
-					if(cur_meta) {
+
+					if (cur_meta) {
 						preview.children().each(function() {
 						preview.children().each(function() {
-							if($(this).data('id') == id) {
+							if ($(this).data('id') == id) {
 								$(this).html(entry);
 								$(this).html(entry);
 								submit.removeAttr('disabled');
 								submit.removeAttr('disabled');
 							}
 							}
@@ -236,9 +242,9 @@ svgEditor.addExtension("imagelib", function() {
 				break;
 				break;
 			case 'o':
 			case 'o':
 				// Open
 				// Open
-				if(!svg_str) break;
+				if (!svg_str) {break;}
 				svgEditor.openPrep(function(ok) {
 				svgEditor.openPrep(function(ok) {
-					if(!ok) return;
+					if (!ok) {return;}
 					svgCanvas.clear();
 					svgCanvas.clear();
 					svgCanvas.setSvgString(response);
 					svgCanvas.setSvgString(response);
 					// updateCanvas();
 					// updateCanvas();
@@ -247,13 +253,11 @@ svgEditor.addExtension("imagelib", function() {
 				break;
 				break;
 		}
 		}
 	}, true);
 	}, true);
-	
-	var preview, submit;
 
 
 	function toggleMulti(show) {
 	function toggleMulti(show) {
-	
+
 		$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
 		$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
-		if(!preview) {
+		if (!preview) {
 			preview = $('<div id=imglib_preview>').css({
 			preview = $('<div id=imglib_preview>').css({
 				position: 'absolute',
 				position: 'absolute',
 				top: 45,
 				top: 45,
@@ -263,12 +267,14 @@ svgEditor.addExtension("imagelib", function() {
 				background: '#fff',
 				background: '#fff',
 				overflow: 'auto'
 				overflow: 'auto'
 			}).insertAfter('#lib_framewrap');
 			}).insertAfter('#lib_framewrap');
-			
-			submit = $('<button disabled>Import selected</button>').appendTo('#imgbrowse').click(function() {
+
+			submit = $('<button disabled>Import selected</button>')
+				.appendTo('#imgbrowse')
+				.on("click touchend", function() {
 				$.each(multi_arr, function(i) {
 				$.each(multi_arr, function(i) {
 					var type = this[0];
 					var type = this[0];
 					var data = this[1];
 					var data = this[1];
-					if(type == 'svg') {
+					if (type == 'svg') {
 						svgCanvas.importSvgString(data);
 						svgCanvas.importSvgString(data);
 					} else {
 					} else {
 						importImage(data);
 						importImage(data);
@@ -285,7 +291,7 @@ svgEditor.addExtension("imagelib", function() {
 			});
 			});
 
 
 		}
 		}
-		
+
 		preview.toggle(show);
 		preview.toggle(show);
 		submit.toggle(show);
 		submit.toggle(show);
 	}
 	}
@@ -293,7 +299,7 @@ svgEditor.addExtension("imagelib", function() {
 	function showBrowser() {
 	function showBrowser() {
 
 
 		var browser = $('#imgbrowse');
 		var browser = $('#imgbrowse');
-		if(!browser.length) {
+		if (!browser.length) {
 			$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>\
 			$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>\
 			</div></div>').insertAfter('#svg_docprops');
 			</div></div>').insertAfter('#svg_docprops');
 			browser = $('#imgbrowse');
 			browser = $('#imgbrowse');
@@ -302,25 +308,29 @@ svgEditor.addExtension("imagelib", function() {
 
 
 			var lib_opts = $('<ul id=imglib_opts>').appendTo(browser);
 			var lib_opts = $('<ul id=imglib_opts>').appendTo(browser);
 			var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
 			var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
-			
+
 			var header = $('<h1>').prependTo(browser).text(all_libs).css({
 			var header = $('<h1>').prependTo(browser).text(all_libs).css({
 				position: 'absolute',
 				position: 'absolute',
 				top: 0,
 				top: 0,
 				left: 0,
 				left: 0,
 				width: '100%'
 				width: '100%'
 			});
 			});
-			
-			var cancel = $('<button>' + uiStrings.common.cancel + '</button>').appendTo(browser).click(function() {
+
+			var cancel = $('<button>' + uiStrings.common.cancel + '</button>')
+				.appendTo(browser)
+				.on("click touchend", function() {
 				$('#imgbrowse_holder').hide();
 				$('#imgbrowse_holder').hide();
 			}).css({
 			}).css({
 				position: 'absolute',
 				position: 'absolute',
 				top: 5,
 				top: 5,
 				right: -10
 				right: -10
 			});
 			});
-			
+
 			var leftBlock = $('<span>').css({position:'absolute',top:5,left:10}).appendTo(browser);
 			var leftBlock = $('<span>').css({position:'absolute',top:5,left:10}).appendTo(browser);
-			
-			var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>').appendTo(leftBlock).click(function() {
+
+			var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
+				.appendTo(leftBlock)
+				.on("click touchend", function() {
 				frame.attr('src', 'about:blank').hide();
 				frame.attr('src', 'about:blank').hide();
 				lib_opts.show();
 				lib_opts.show();
 				header.text(all_libs);
 				header.text(all_libs);
@@ -328,8 +338,8 @@ svgEditor.addExtension("imagelib", function() {
 			}).css({
 			}).css({
 				'margin-right': 5
 				'margin-right': 5
 			}).hide();
 			}).hide();
-			
-			var type = $('<select><option value=s>' + 
+
+			var type = $('<select><option value=s>' +
 			uiStrings.imagelib.import_single + '</option><option value=m>' +
 			uiStrings.imagelib.import_single + '</option><option value=m>' +
 			uiStrings.imagelib.import_multi + '</option><option value=o>' +
 			uiStrings.imagelib.import_multi + '</option><option value=o>' +
 			uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function() {
 			uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function() {
@@ -339,34 +349,38 @@ svgEditor.addExtension("imagelib", function() {
 					case 'o':
 					case 'o':
 						toggleMulti(false);
 						toggleMulti(false);
 						break;
 						break;
-					
+
 					case 'm':
 					case 'm':
 						// Import multiple
 						// Import multiple
 						toggleMulti(true);
 						toggleMulti(true);
+						break;
 				}
 				}
 			}).css({
 			}).css({
 				'margin-top': 10
 				'margin-top': 10
 			});
 			});
-			
+
 			cancel.prepend($.getSvgIcon('cancel', true));
 			cancel.prepend($.getSvgIcon('cancel', true));
 			back.prepend($.getSvgIcon('tool_imagelib', true));
 			back.prepend($.getSvgIcon('tool_imagelib', true));
-			
+
 			$.each(img_libs, function(i, opts) {
 			$.each(img_libs, function(i, opts) {
-				$('<li>').appendTo(lib_opts).text(opts.name).click(function() {
+				$('<li>')
+					.appendTo(lib_opts)
+					.text(opts.name)
+					.on("click touchend", function() {
 					frame.attr('src', opts.url).show();
 					frame.attr('src', opts.url).show();
 					header.text(opts.name);
 					header.text(opts.name);
 					lib_opts.hide();
 					lib_opts.hide();
 					back.show();
 					back.show();
 				}).append('<span>' + opts.description + '</span>');
 				}).append('<span>' + opts.description + '</span>');
 			});
 			});
-			
+
 		} else {
 		} else {
 			$('#imgbrowse_holder').show();
 			$('#imgbrowse_holder').show();
 		}
 		}
 	}
 	}
-	
+
 	return {
 	return {
-		svgicons: "extensions/ext-imagelib.xml",
+		svgicons: svgEditor.curConfig.extPath + "ext-imagelib.xml",
 		buttons: [{
 		buttons: [{
 			id: "tool_imagelib",
 			id: "tool_imagelib",
 			type: "app_menu", // _flyout
 			type: "app_menu", // _flyout
@@ -377,7 +391,7 @@ svgEditor.addExtension("imagelib", function() {
 			}
 			}
 		}],
 		}],
 		callback: function() {
 		callback: function() {
-		
+
 			$('<style>').text('\
 			$('<style>').text('\
 				#imgbrowse_holder {\
 				#imgbrowse_holder {\
 					position: absolute;\
 					position: absolute;\
@@ -455,6 +469,6 @@ svgEditor.addExtension("imagelib", function() {
 				}\
 				}\
 			').appendTo('head');
 			').appendTo('head');
 		}
 		}
-	}
+	};
 });
 });
 
 

+ 147 - 140
main/inc/lib/svg-edit/extensions/ext-imagelib.xml

@@ -1,3 +1,5 @@
+/*globals svgEditor, svgCanvas, $*/
+/*jslint vars: true, eqeq: true, todo: true */
 /*
 /*
  * ext-markers.js
  * ext-markers.js
  *
  *
@@ -22,7 +24,7 @@
  *    text marker font, size, and attributes are fixed
  *    text marker font, size, and attributes are fixed
  *    an application specific attribute - se_type - is added to each marker element
  *    an application specific attribute - se_type - is added to each marker element
  *        to store the type of marker
  *        to store the type of marker
- *        
+ *
  * TODO:
  * TODO:
  *    remove some of the restrictions above
  *    remove some of the restrictions above
  *    add option for keeping text aligned to horizontal
  *    add option for keeping text aligned to horizontal
@@ -31,9 +33,9 @@
  */
  */
 
 
 svgEditor.addExtension("Markers", function(S) {
 svgEditor.addExtension("Markers", function(S) {
-	var svgcontent = S.svgcontent,
-	addElem = S.addSvgElementFromJson,
-	selElems;
+	var // svgcontent = S.svgcontent,
+		addElem = S.addSvgElementFromJson,
+		selElems;
 
 
 	var mtypes = ['start','mid','end'];
 	var mtypes = ['start','mid','end'];
 
 
@@ -69,8 +71,8 @@ svgEditor.addExtension("Markers", function(S) {
 		triangle:
 		triangle:
 			{element:'path', attr:{d:'M10,80 L50,20 L80,80 Z'}},
 			{element:'path', attr:{d:'M10,80 L50,20 L80,80 Z'}},
 		mcircle:
 		mcircle:
-			{element:'circle', attr:{r:30, cx:50, cy:50}},			
-	}
+			{element:'circle', attr:{r:30, cx:50, cy:50}}			
+	};
 	
 	
 	
 	
 	var lang_list = {
 	var lang_list = {
@@ -95,7 +97,7 @@ svgEditor.addExtension("Markers", function(S) {
 			{id: "box_o", title: "Open Box" },
 			{id: "box_o", title: "Open Box" },
 			{id: "star_o", title: "Open Star" },
 			{id: "star_o", title: "Open Star" },
 			{id: "triangle_o", title: "Open Triangle" },
 			{id: "triangle_o", title: "Open Triangle" },
-			{id: "mcircle_o", title: "Open Circle" },
+			{id: "mcircle_o", title: "Open Circle" }
 		]
 		]
 	};
 	};
 
 
@@ -110,7 +112,7 @@ svgEditor.addExtension("Markers", function(S) {
 	// returns the marker element that is linked to the graphic element
 	// returns the marker element that is linked to the graphic element
 	function getLinked(elem, attr) {
 	function getLinked(elem, attr) {
 		var str = elem.getAttribute(attr);
 		var str = elem.getAttribute(attr);
-		if(!str) return null;
+		if(!str) {return null;}
 		var m = str.match(/\(\#(.*)\)/);
 		var m = str.match(/\(\#(.*)\)/);
 		if(!m || m.length !== 2) {
 		if(!m || m.length !== 2) {
 			return null;
 			return null;
@@ -118,7 +120,14 @@ svgEditor.addExtension("Markers", function(S) {
 		return S.getElem(m[1]);
 		return S.getElem(m[1]);
 	}
 	}
 
 
-	//toggles context tool panel off/on
+	function setIcon(pos,id) {
+		if (id.substr(0,1) !== '\\') {id = '\\textmarker';}
+		var ci = '#'+id_prefix+pos+'_'+id.substr(1);
+		svgEditor.setIcon('#cur_' + pos +'_marker_list', $(ci).children());
+		$(ci).addClass('current').siblings().removeClass('current');
+	}
+
+	// toggles context tool panel off/on
 	//sets the controls with the selected element's settings
 	//sets the controls with the selected element's settings
 	function showPanel(on) {
 	function showPanel(on) {
 		$('#marker_panel').toggle(on);
 		$('#marker_panel').toggle(on);
@@ -129,26 +138,26 @@ svgEditor.addExtension("Markers", function(S) {
 			var ci;
 			var ci;
 
 
 			$.each(mtypes, function(i, pos) {
 			$.each(mtypes, function(i, pos) {
-				var m=getLinked(el,"marker-"+pos);
-				var txtbox = $('#'+pos+'_marker');
+				var m = getLinked(el, "marker-" + pos);
+				var txtbox = $('#' + pos + '_marker');
 				if (!m) {
 				if (!m) {
-					val='\\nomarker';
-					ci=val;
-					txtbox.hide() // hide text box
+					val = '\\nomarker';
+					ci = val;
+					txtbox.hide(); // hide text box
 				} else {
 				} else {
-					if (!m.attributes.se_type) return; // not created by this extension
-					val='\\'+m.attributes.se_type.textContent;
-					ci=val;
-					if (val=='\\textmarker') {
-						val=m.lastChild.textContent;
+					if (!m.attributes.se_type) {return;} // not created by this extension
+					val = '\\' + m.attributes.se_type.textContent;
+					ci = val;
+					if (val === '\\textmarker') {
+						val = m.lastChild.textContent;
 						//txtbox.show(); // show text box
 						//txtbox.show(); // show text box
 					} else {
 					} else {
-						txtbox.hide() // hide text box
+						txtbox.hide(); // hide text box
 					}
 					}
 				}
 				}
 				txtbox.val(val);				
 				txtbox.val(val);				
 				setIcon(pos,ci);
 				setIcon(pos,ci);
-			})
+			});
 		}
 		}
 	}	
 	}	
 
 
@@ -159,9 +168,9 @@ svgEditor.addExtension("Markers", function(S) {
 		
 		
 		var marker = S.getElem(id);
 		var marker = S.getElem(id);
 
 
-		if (marker) return;
+		if (marker) {return;}
 
 
-		if (val=='' || val=='\\nomarker') return;
+		if (val == '' || val == '\\nomarker') {return;}
 
 
 		var el = selElems[0];		 
 		var el = selElems[0];		 
 		var color = el.getAttribute('stroke');
 		var color = el.getAttribute('stroke');
@@ -174,12 +183,13 @@ svgEditor.addExtension("Markers", function(S) {
 		var markerWidth = 5;
 		var markerWidth = 5;
 		var markerHeight = 5;
 		var markerHeight = 5;
 		var strokeWidth = 10;
 		var strokeWidth = 10;
-		if (val.substr(0,1)=='\\') se_type=val.substr(1);
-		else se_type='textmarker';
+		var se_type;
+		if (val.substr(0,1) === '\\') {se_type = val.substr(1);}
+		else {se_type = 'textmarker';}
 
 
-		if (!marker_types[se_type]) return; // an unknown type!
+		if (!marker_types[se_type]) {return;} // an unknown type!
 		
 		
- 		// create a generic marker
+		// create a generic marker
 		marker = addElem({
 		marker = addElem({
 			"element": "marker",
 			"element": "marker",
 			"attr": {
 			"attr": {
@@ -191,21 +201,21 @@ svgEditor.addExtension("Markers", function(S) {
 		}
 		}
 		});
 		});
 
 
-		if (se_type!='textmarker') {
+		if (se_type != 'textmarker') {
 			var mel = addElem(marker_types[se_type]);
 			var mel = addElem(marker_types[se_type]);
 			var fillcolor = color;
 			var fillcolor = color;
-			if (se_type.substr(-2)=='_o') fillcolor='none';
-			mel.setAttribute('fill',fillcolor);
-			mel.setAttribute('stroke',color);
-			mel.setAttribute('stroke-width',strokeWidth);
+			if (se_type.substr(-2) === '_o') {fillcolor = 'none';}
+			mel.setAttribute('fill', fillcolor);
+			mel.setAttribute('stroke', color);
+			mel.setAttribute('stroke-width', strokeWidth);
 			marker.appendChild(mel);
 			marker.appendChild(mel);
 		} else {
 		} else {
 			var text = addElem(marker_types[se_type]);
 			var text = addElem(marker_types[se_type]);
 			// have to add text to get bounding box
 			// have to add text to get bounding box
 			text.textContent = val;
 			text.textContent = val;
-			var tb=text.getBBox();
+			var tb = text.getBBox();
 			//alert( tb.x + " " + tb.y + " " + tb.width + " " + tb.height);
 			//alert( tb.x + " " + tb.y + " " + tb.width + " " + tb.height);
-			var pad=1;
+			var pad = 1;
 			var bb = tb;
 			var bb = tb;
 			bb.x = 0;
 			bb.x = 0;
 			bb.y = 0;
 			bb.y = 0;
@@ -215,23 +225,23 @@ svgEditor.addExtension("Markers", function(S) {
 			text.setAttribute('x', pad);
 			text.setAttribute('x', pad);
 			text.setAttribute('y', bb.height - pad - tb.height/4); // kludge?
 			text.setAttribute('y', bb.height - pad - tb.height/4); // kludge?
 			text.setAttribute('fill',color);
 			text.setAttribute('fill',color);
-			refX = bb.width/2+pad;
-			refY = bb.height/2+pad;
+			refX = bb.width/2 + pad;
+			refY = bb.height/2 + pad;
 			viewBox = bb.x + " " + bb.y + " " + bb.width + " " + bb.height;
 			viewBox = bb.x + " " + bb.y + " " + bb.width + " " + bb.height;
-			markerWidth =bb.width/10;
+			markerWidth = bb.width/10;
 			markerHeight = bb.height/10;
 			markerHeight = bb.height/10;
 
 
 			var box = addElem({
 			var box = addElem({
 				"element": "rect",
 				"element": "rect",
 				"attr": {
 				"attr": {
-				"x": bb.x,
-				"y": bb.y,
-				"width": bb.width,
-				"height": bb.height,
-				"fill": txt_box_bg,
-				"stroke": txt_box_border,
-				"stroke-width": txt_box_stroke_width
-			}
+					"x": bb.x,
+					"y": bb.y,
+					"width": bb.width,
+					"height": bb.height,
+					"fill": txt_box_bg,
+					"stroke": txt_box_border,
+					"stroke-width": txt_box_stroke_width
+				}
 			});
 			});
 			marker.setAttribute("orient",0);
 			marker.setAttribute("orient",0);
 			marker.appendChild(box);
 			marker.appendChild(box);
@@ -248,59 +258,34 @@ svgEditor.addExtension("Markers", function(S) {
 		return marker;
 		return marker;
 	}
 	}
 
 
-
-	function setMarker() {
-		var poslist={'start_marker':'start','mid_marker':'mid','end_marker':'end'};
-		var pos = poslist[this.id];
-		var marker_name = 'marker-'+pos;
-		var val = this.value;
-		var el = selElems[0];
-		var marker = getLinked(el, marker_name);
-		if (marker) $(marker).remove();
-		el.removeAttribute(marker_name);
-		if (val=='') val='\\nomarker';
-		if (val=='\\nomarker') {
-			setIcon(pos,val);
-			S.call("changed", selElems);
-			return;
-		}
-		// Set marker on element
-		var id = marker_prefix + pos + '_' + el.id;
-		addMarker(id, val);
-		svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
-		if (el.tagName == "line" && pos=='mid') el=convertline(el);
-		S.call("changed", selElems);
-		setIcon(pos,val);
-	}
-
 	function convertline(elem) {
 	function convertline(elem) {
 		// this routine came from the connectors extension
 		// this routine came from the connectors extension
 		// it is needed because midpoint markers don't work with line elements
 		// it is needed because midpoint markers don't work with line elements
-		if (!(elem.tagName == "line")) return elem;
+		if (!(elem.tagName === 'line')) {return elem;}
 
 
 		// Convert to polyline to accept mid-arrow
 		// Convert to polyline to accept mid-arrow
 
 
-		var x1 = elem.getAttribute('x1')-0;
-		var x2 = elem.getAttribute('x2')-0;
-		var y1 = elem.getAttribute('y1')-0;
-		var y2 = elem.getAttribute('y2')-0;
+		var x1 = Number(elem.getAttribute('x1'));
+		var x2 = Number(elem.getAttribute('x2'));
+		var y1 = Number(elem.getAttribute('y1'));
+		var y2 = Number(elem.getAttribute('y2'));
 		var id = elem.id;
 		var id = elem.id;
 
 
 		var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' ');
 		var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' ');
 		var pline = addElem({
 		var pline = addElem({
 			"element": "polyline",
 			"element": "polyline",
 			"attr": {
 			"attr": {
-			"points": (x1+','+y1+ mid_pt +x2+','+y2),
-			"stroke": elem.getAttribute('stroke'),
-			"stroke-width": elem.getAttribute('stroke-width'),
-			"fill": "none",
-			"opacity": elem.getAttribute('opacity') || 1
-		}
+				"points": (x1+','+y1+ mid_pt +x2+','+y2),
+				"stroke": elem.getAttribute('stroke'),
+				"stroke-width": elem.getAttribute('stroke-width'),
+				"fill": "none",
+				"opacity": elem.getAttribute('opacity') || 1
+			}
 		});
 		});
 		$.each(mtypes, function(i, pos) { // get any existing marker definitions
 		$.each(mtypes, function(i, pos) { // get any existing marker definitions
 			var nam = 'marker-'+pos;
 			var nam = 'marker-'+pos;
 			var m = elem.getAttribute(nam);
 			var m = elem.getAttribute(nam);
-			if (m) pline.setAttribute(nam,elem.getAttribute(nam));
+			if (m) {pline.setAttribute(nam,elem.getAttribute(nam));}
 		});
 		});
 		
 		
 		var batchCmd = new S.BatchCommand();
 		var batchCmd = new S.BatchCommand();
@@ -315,6 +300,30 @@ svgEditor.addExtension("Markers", function(S) {
 		return pline;
 		return pline;
 	}
 	}
 
 
+	function setMarker() {
+		var poslist={'start_marker':'start','mid_marker':'mid','end_marker':'end'};
+		var pos = poslist[this.id];
+		var marker_name = 'marker-'+pos;
+		var val = this.value;
+		var el = selElems[0];
+		var marker = getLinked(el, marker_name);
+		if (marker) {$(marker).remove();}
+		el.removeAttribute(marker_name);
+		if (val == '') {val = '\\nomarker';}
+		if (val == '\\nomarker') {
+			setIcon(pos,val);
+			S.call("changed", selElems);
+			return;
+		}
+		// Set marker on element
+		var id = marker_prefix + pos + '_' + el.id;
+		addMarker(id, val);
+		svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
+		if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);}
+		S.call("changed", selElems);
+		setIcon(pos,val);
+	}
+
 	// called when the main system modifies an object
 	// called when the main system modifies an object
 	// this routine changes the associated markers to be the same color
 	// this routine changes the associated markers to be the same color
 	function colorChanged(elem) {
 	function colorChanged(elem) {
@@ -322,34 +331,34 @@ svgEditor.addExtension("Markers", function(S) {
 
 
 		$.each(mtypes, function(i, pos) {
 		$.each(mtypes, function(i, pos) {
 			var marker = getLinked(elem, 'marker-'+pos);
 			var marker = getLinked(elem, 'marker-'+pos);
-			if (!marker) return;
-			if (!marker.attributes.se_type) return; //not created by this extension
+			if (!marker) {return;}
+			if (!marker.attributes.se_type) {return;} // not created by this extension
 			var ch = marker.lastElementChild;
 			var ch = marker.lastElementChild;
-			if (!ch) return;
-			var curfill = ch.getAttribute("fill");
-			var curstroke = ch.getAttribute("stroke")
-			if (curfill && curfill!='none') ch.setAttribute("fill",color);
-			if (curstroke && curstroke!='none') ch.setAttribute("stroke",color);
+			if (!ch) {return;}
+			var curfill = ch.getAttribute('fill');
+			var curstroke = ch.getAttribute('stroke');
+			if (curfill && curfill != 'none') {ch.setAttribute('fill', color);}
+			if (curstroke && curstroke != 'none') {ch.setAttribute('stroke', color);}
 		});
 		});
 	}
 	}
 
 
 	// called when the main system creates or modifies an object
 	// called when the main system creates or modifies an object
 	// primary purpose is create new markers for cloned objects
 	// primary purpose is create new markers for cloned objects
 	function updateReferences(el) {
 	function updateReferences(el) {
-		$.each(mtypes, function (i,pos) {
+		$.each(mtypes, function (i, pos) {
 			var id = marker_prefix + pos + '_' + el.id;
 			var id = marker_prefix + pos + '_' + el.id;
 			var marker_name = 'marker-'+pos;
 			var marker_name = 'marker-'+pos;
 			var marker = getLinked(el, marker_name);
 			var marker = getLinked(el, marker_name);
-			if (!marker || !marker.attributes.se_type) return; //not created by this extension
+			if (!marker || !marker.attributes.se_type) {return;} // not created by this extension
 			var url = el.getAttribute(marker_name);
 			var url = el.getAttribute(marker_name);
 			if (url) {
 			if (url) {
 				var len = el.id.length;
 				var len = el.id.length;
-				var linkid = url.substr(-len-1,len);
+				var linkid = url.substr(-len-1, len);
 				if (el.id != linkid) {
 				if (el.id != linkid) {
-					var val = $('#'+pos+'_marker').attr('value');
+					var val = $('#'+pos + '_marker').attr('value');
 					addMarker(id, val);
 					addMarker(id, val);
 					svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
 					svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
-					if (el.tagName == "line" && pos=='mid') el=convertline(el);
+					if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);}
 					S.call("changed", selElems);
 					S.call("changed", selElems);
 				}
 				}
 			}
 			}
@@ -357,21 +366,23 @@ svgEditor.addExtension("Markers", function(S) {
 	}
 	}
 
 
 	// simulate a change event a text box that stores the current element's marker type
 	// simulate a change event a text box that stores the current element's marker type
-	function triggerTextEntry(pos,val) {
+	function triggerTextEntry(pos, val) {
 		$('#'+pos+'_marker').val(val);
 		$('#'+pos+'_marker').val(val);
 		$('#'+pos+'_marker').change();
 		$('#'+pos+'_marker').change();
-		var txtbox = $('#'+pos+'_marker');
-		//if (val.substr(0,1)=='\\') txtbox.hide();
-		//else txtbox.show();
+		// var txtbox = $('#'+pos+'_marker');
+		// if (val.substr(0,1)=='\\') {txtbox.hide();}
+		// else {txtbox.show();}
 	}
 	}
-	
-	function setIcon(pos,id) {
-		if (id.substr(0,1)!='\\') id='\\textmarker'
-		var ci = '#'+id_prefix+pos+'_'+id.substr(1);
-		svgEditor.setIcon('#cur_' + pos +'_marker_list', $(ci).children());
-		$(ci).addClass('current').siblings().removeClass('current');
+
+	function showTextPrompt(pos) {
+		var def = $('#'+pos+'_marker').val();
+		if (def.substr(0,1) === '\\') {def = '';}
+		$.prompt('Enter text for ' + pos + ' marker', def , function(txt) {
+			if (txt) {triggerTextEntry(pos, txt);}
+		});
 	}
 	}
-		
+
+	/*
 	function setMarkerSet(obj) {
 	function setMarkerSet(obj) {
 		var parts = this.id.split('_');
 		var parts = this.id.split('_');
 		var set = parts[2];
 		var set = parts[2];
@@ -393,32 +404,28 @@ svgEditor.addExtension("Markers", function(S) {
 			break;
 			break;
 		}
 		}
 	}
 	}
-		
-	function showTextPrompt(pos) {
-		var def = $('#'+pos+'_marker').val();
-		if (def.substr(0,1)=='\\') def='';
-		$.prompt('Enter text for ' + pos + ' marker', def , function(txt) { if (txt) triggerTextEntry(pos,txt); });
-	}
-	
+	*/
 	// callback function for a toolbar button click
 	// callback function for a toolbar button click
 	function setArrowFromButton(obj) {
 	function setArrowFromButton(obj) {
 		
 		
 		var parts = this.id.split('_');
 		var parts = this.id.split('_');
 		var pos = parts[1];
 		var pos = parts[1];
 		var val = parts[2];
 		var val = parts[2];
-		if (parts[3]) val+='_'+parts[3];
+		if (parts[3]) { val += '_' + parts[3];}
 		
 		
-		if (val!='textmarker') {
-			triggerTextEntry(pos,'\\'+val);
+		if (val != 'textmarker') {
+			triggerTextEntry(pos, '\\'+val);
 		} else {
 		} else {
 			showTextPrompt(pos);
 			showTextPrompt(pos);
 		}
 		}
 	}
 	}
 	
 	
-	function getTitle(lang,id) {
-		var list = lang_list[lang];
-		for (var i in list) {
-			if (list[i].id==id) return list[i].title;
+	function getTitle(lang, id) {
+		var i, list = lang_list[lang];
+		for (i in list) {
+			if (list.hasOwnProperty(i) && list[i].id == id) {
+				return list[i].title;
+			}
 		}
 		}
 		return id;
 		return id;
 	}
 	}
@@ -428,7 +435,7 @@ svgEditor.addExtension("Markers", function(S) {
 	// TODO: need to incorporate language specific titles
 	// TODO: need to incorporate language specific titles
 	function buildButtonList() {
 	function buildButtonList() {
 		var buttons=[];
 		var buttons=[];
-		var i=0;
+		// var i = 0;
 /*
 /*
 		buttons.push({
 		buttons.push({
 			id:id_prefix + 'markers_off',
 			id:id_prefix + 'markers_off',
@@ -452,30 +459,30 @@ svgEditor.addExtension("Markers", function(S) {
 			panel: 'marker_panel'
 			panel: 'marker_panel'
 		});
 		});
 */
 */
-		$.each(mtypes,function(k,pos) {
+		$.each(mtypes, function (k, pos) {
 			var listname = pos + "_marker_list";
 			var listname = pos + "_marker_list";
 			var def = true;
 			var def = true;
-		$.each(marker_types,function(id,v) {
-			var title = getTitle('en',id);
-			buttons.push({
-					id:id_prefix + pos + "_" + id,
-					svgicon:id,
-					title:title,
-					type:'context',
-					events: { 'click': setArrowFromButton },
-					panel:'marker_panel',
+			$.each(marker_types, function (id, v) {
+				var title = getTitle('en', id);
+				buttons.push({
+					id: id_prefix + pos + '_' + id,
+					svgicon: id,
+					title: title,
+					type: 'context',
+					events: {'click': setArrowFromButton},
+					panel: 'marker_panel',
 					list: listname,
 					list: listname,
 					isDefault: def
 					isDefault: def
+				});
+				def = false;
 			});
 			});
-			def = false;
-		});
 		});
 		});
 		return buttons;
 		return buttons;
 	}
 	}
 
 
 	return {
 	return {
 		name: "Markers",
 		name: "Markers",
-		svgicons: "extensions/markers-icons.xml",
+		svgicons: svgEditor.curConfig.extPath + "markers-icons.xml",
 		buttons: buildButtonList(),
 		buttons: buildButtonList(),
 		context_tools: [
 		context_tools: [
 		   {
 		   {
@@ -489,7 +496,7 @@ svgEditor.addExtension("Markers", function(S) {
 		},{
 		},{
 			type: "button-select",
 			type: "button-select",
 			panel: "marker_panel",
 			panel: "marker_panel",
-			title: getTitle('en','start_marker_list'),
+			title: getTitle('en', 'start_marker_list'),
 			id: "start_marker_list",
 			id: "start_marker_list",
 			colnum: 3,
 			colnum: 3,
 			events: { change: setArrowFromButton }
 			events: { change: setArrowFromButton }
@@ -505,7 +512,7 @@ svgEditor.addExtension("Markers", function(S) {
 		},{
 		},{
 			type: "button-select",
 			type: "button-select",
 			panel: "marker_panel",
 			panel: "marker_panel",
-			title: getTitle('en','mid_marker_list'),
+			title: getTitle('en', 'mid_marker_list'),
 			id: "mid_marker_list",
 			id: "mid_marker_list",
 			colnum: 3,
 			colnum: 3,
 			events: { change: setArrowFromButton }
 			events: { change: setArrowFromButton }
@@ -520,7 +527,7 @@ svgEditor.addExtension("Markers", function(S) {
 		},{
 		},{
 			type: "button-select",
 			type: "button-select",
 			panel: "marker_panel",
 			panel: "marker_panel",
-			title: getTitle('en','end_marker_list'),
+			title: getTitle('en', 'end_marker_list'),
 			id: "end_marker_list",
 			id: "end_marker_list",
 			colnum: 3,
 			colnum: 3,
 			events: { change: setArrowFromButton }
 			events: { change: setArrowFromButton }
@@ -543,8 +550,8 @@ svgEditor.addExtension("Markers", function(S) {
 
 
 		while(i--) {
 		while(i--) {
 			var elem = selElems[i];
 			var elem = selElems[i];
-			if(elem && $.inArray(elem.tagName, marker_elems) != -1) {
-				if(opts.selectedElement && !opts.multiselected) {
+			if(elem && $.inArray(elem.tagName, marker_elems) !== -1) {
+				if (opts.selectedElement && !opts.multiselected) {
 					showPanel(true);
 					showPanel(true);
 				} else {
 				} else {
 					showPanel(false);
 					showPanel(false);
@@ -558,7 +565,7 @@ svgEditor.addExtension("Markers", function(S) {
 	elementChanged: function(opts) {		
 	elementChanged: function(opts) {		
 		//console.log('elementChanged',opts);
 		//console.log('elementChanged',opts);
 		var elem = opts.elems[0];
 		var elem = opts.elems[0];
-		if(elem && (
+		if (elem && (
 				elem.getAttribute("marker-start") ||
 				elem.getAttribute("marker-start") ||
 				elem.getAttribute("marker-mid") ||
 				elem.getAttribute("marker-mid") ||
 				elem.getAttribute("marker-end")
 				elem.getAttribute("marker-end")
@@ -566,7 +573,7 @@ svgEditor.addExtension("Markers", function(S) {
 			colorChanged(elem);
 			colorChanged(elem);
 			updateReferences(elem);
 			updateReferences(elem);
 		}
 		}
-		changing_flag = false;
+		// changing_flag = false; // Not apparently in use
 	}
 	}
 	};
 	};
 });
 });

+ 273 - 0
main/inc/lib/svg-edit/extensions/ext-mathjax.js

@@ -0,0 +1,273 @@
+/*globals MathJax, svgEditor, svgCanvas, $*/
+/*jslint es5: true, todo: true, vars: true*/
+/*
+ * ext-mathjax.js
+ *
+ * Licensed under the Apache License
+ *
+ * Copyright(c) 2013 Jo Segaert
+ *
+ */
+
+svgEditor.addExtension("mathjax", function() {'use strict';
+  // Configuration of the MathJax extention.
+
+  // This will be added to the head tag before MathJax is loaded.
+  var /*mathjaxConfiguration = '<script type="text/x-mathjax-config">\
+        MathJax.Hub.Config({\
+          extensions: ["tex2jax.js"],\
+			    jax: ["input/TeX","output/SVG"],\
+          showProcessingMessages: true,\
+          showMathMenu: false,\
+          showMathMenuMSIE: false,\
+          errorSettings: {\
+            message: ["[Math Processing Error]"],\
+            style: {color: "#CC0000", "font-style":"italic"}\
+          },\
+          elements: [],\
+            tex2jax: {\
+            ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
+          },\
+          TeX: {\
+            extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
+          },\
+          "SVG": {\
+          }\
+      });\
+      </script>',*/
+    // mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
+    mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js',
+    math,
+    locationX,
+    locationY,
+    mathjaxLoaded = false,
+    uiStrings = svgEditor.uiStrings;
+
+  // TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
+  $.extend(uiStrings, {
+    mathjax: {
+      embed_svg: 'Save as mathematics',
+      embed_mathml: 'Save as figure',
+      svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ',
+      mathml_save_warning: 'Advised. The math will be saved as a figure.',
+      title: 'Mathematics code editor'
+    }
+  });
+
+
+  function saveMath() {
+    var code = $('#mathjax_code_textarea').val();
+    // displaystyle to force MathJax NOT to use the inline style. Because it is
+    // less fancy!
+    MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
+
+    /*
+     * The MathJax library doesn't want to bloat your webpage so it creates 
+     * every symbol (glymph) you need only once. These are saved in a <svg> on  
+     * the top of your html document, just under the body tag. Each glymph has
+     * its unique id and is saved as a <path> in the <defs> tag of the <svg>
+     * 
+     * Then when the symbols are needed in the rest of your html document they
+     * are refferd to by a <use> tag.
+     * Because of bug 1076 we can't just grab the defs tag on the top and add it 
+     * to your formula's <svg> and copy the lot. So we have to replace each 
+     * <use> tag by it's <path>.
+     */
+    MathJax.Hub.queue.Push(
+      function() {
+        var mathjaxMath = $('.MathJax_SVG');
+        var svg = $(mathjaxMath.html());
+        svg.find('use').each(function() {
+          var x, y, id, transform;
+
+          // TODO: find a less pragmatic and more elegant solution to this.
+          if ($(this).attr('href')) {
+            id = $(this).attr('href').slice(1); // Works in Chrome.
+          } else {
+            id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
+          }
+
+          var glymph = $('#' + id).clone().removeAttr('id');
+          x = $(this).attr('x');
+          y = $(this).attr('y');
+          transform = $(this).attr('transform');
+          if (transform && ( x || y )) {
+            glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
+          }
+          else if (transform) {
+            glymph.attr('transform', transform);
+          }
+          else if (x || y) {
+            glymph.attr('transform', 'translate(' + x + ',' + y + ')');
+          }
+          $(this).replaceWith(glymph);
+        });
+        // Remove the style tag because it interferes with SVG-Edit.
+        svg.removeAttr('style');
+        svg.attr('xmlns', 'http://www.w3.org/2000/svg');
+        svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true);
+        svgCanvas.ungroupSelectedElement();
+        // TODO: To undo the adding of the Formula you now have to undo twice.
+        // This should only be once!
+        svgCanvas.moveSelectedElements(locationX, locationY, true);
+      }
+    );
+  }
+
+  return {
+    name: "MatJax",
+    svgicons: svgEditor.curConfig.extPath + "mathjax-icons.xml",
+    buttons: [{
+        id: "tool_mathjax",
+        type: "mode",
+        title: "Add Mathematics",
+        events: {
+          'click': function() {
+            // Only load Mathjax when needed, we don't want to strain Svg-Edit any more. 
+            // From this point on it is very probable that it will be needed, so load it.
+            if (mathjaxLoaded === false) {
+
+              $('<div id="mathjax">\
+                <!-- Here is where MathJax creates the math -->\
+                  <div id="mathjax_creator" class="tex2jax_process" style="display:none">\
+                    $${}$$\
+                  </div>\
+                  <div id="mathjax_overlay"></div>\
+                  <div id="mathjax_container">\
+                    <div id="tool_mathjax_back" class="toolbar_button">\
+                      <button id="tool_mathjax_save">OK</button>\
+                      <button id="tool_mathjax_cancel">Cancel</button>\
+                    </div>\
+                    <fieldset>\
+                      <legend id="mathjax_legend">Mathematics Editor</legend>\
+                      <label>\
+                        <span id="mathjax_explication">Please type your mathematics in \
+                        <a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>\
+                      <textarea id="mathjax_code_textarea" spellcheck="false"></textarea>\
+                    </fieldset>\
+                  </div>\
+                </div>'
+                ).insertAfter('#svg_prefs').hide();
+
+              // Make the MathEditor draggable.
+              $('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
+
+              // Add functionality and picture to cancel button.
+              $('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
+                .on("click touched", function() {
+                $('#mathjax').hide();
+              });
+
+              // Add functionality and picture to the save button.
+              $('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
+                .on("click touched", function() {
+                saveMath();
+                $('#mathjax').hide();
+              });
+
+              // MathJax preprocessing has to ignore most of the page.
+              $('body').addClass('tex2jax_ignore');
+
+              // Now get (and run) the MathJax Library.
+              $.getScript(mathjaxSrcSecure)
+                .done(function(script, textStatus) {
+
+                // When MathJax is loaded get the div where the math will be rendered.
+                MathJax.Hub.queue.Push(function() {
+                  math = MathJax.Hub.getAllJax('#mathjax_creator')[0];
+                  console.log(math);
+                  mathjaxLoaded = true;
+                  console.log('MathJax Loaded');
+                });
+
+              })
+                // If it fails.
+                .fail(function() {
+                console.log("Failed loadeing MathJax.");
+                $.alert("Failed loading MathJax. You will not be able to change the mathematics.");
+              });
+            }
+            // Set the mode.
+            svgCanvas.setMode("mathjax");
+          }
+        }
+      }],
+    
+    mouseDown: function() {
+      if (svgCanvas.getMode() === "mathjax") {
+        return {started: true};
+      }
+    },
+    mouseUp: function(opts) {
+      if (svgCanvas.getMode() === "mathjax") {
+        // Get the coordinates from your mouse.
+        var zoom = svgCanvas.getZoom();
+        // Get the actual coordinate by dividing by the zoom value
+        locationX = opts.mouse_x / zoom;
+        locationY = opts.mouse_y / zoom;
+
+        $('#mathjax').show();
+        return {started: false}; // Otherwise the last selected object dissapears.
+      }
+    },
+    callback: function() {
+      $('<style>').text('\
+				#mathjax fieldset{\
+					padding: 5px;\
+					margin: 5px;\
+					border: 1px solid #DDD;\
+				}\
+				#mathjax label{\
+					display: block;\
+					margin: .5em;\
+				}\
+				#mathjax legend {\
+					max-width:195px;\
+				}\
+				#mathjax_overlay {\
+					position: absolute;\
+					top: 0;\
+					left: 0;\
+					right: 0;\
+					bottom: 0;\
+					background-color: black;\
+					opacity: 0.6;\
+					z-index: 20000;\
+				}\
+				\
+				#mathjax_container {\
+					position: absolute;\
+					top: 50px;\
+					padding: 10px;\
+					background-color: #B0B0B0;\
+					border: 1px outset #777;\
+					opacity: 1.0;\
+					font-family: Verdana, Helvetica, sans-serif;\
+					font-size: .8em;\
+					z-index: 20001;\
+				}\
+				\
+				#tool_mathjax_back {\
+					margin-left: 1em;\
+					overflow: auto;\
+				}\
+				\
+				#mathjax_legend{\
+					font-weight: bold;\
+					font-size:1.1em;\
+				}\
+				\
+				#mathjax_code_textarea {\\n\
+          margin: 5px .7em;\
+					overflow: hidden;\
+          width: 416px;\
+					display: block;\
+					height: 100px;\
+				}\
+			').appendTo('head');
+
+      // Add the MathJax configuration.
+      //$(mathjaxConfiguration).appendTo('head');
+    }
+  };
+});

+ 142 - 0
main/inc/lib/svg-edit/extensions/ext-overview_window.js

@@ -0,0 +1,142 @@
+/*globals svgEditor, svgedit, $ */
+/*jslint es5: true, vars: true*/
+/*
+ * ext-overview_window.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2013 James Sacksteder
+ *
+ */
+
+var overviewWindowGlobals = {};
+svgEditor.addExtension("overview_window", function() {	'use strict';
+	//define and insert the base html element
+	var propsWindowHtml= "\
+		<div id=\"overview_window_content_pane\" style=\" width:100%; word-wrap:break-word;  display:inline-block; margin-top:20px;\">\
+			<div id=\"overview_window_content\" style=\"position:relative; left:12px; top:0px;\">\
+				<div style=\"background-color:#A0A0A0; display:inline-block; overflow:visible;\">\
+					<svg id=\"overviewMiniView\" width=\"150\" height=\"100\" x=\"0\" y=\"0\" viewBox=\"0 0 4800 3600\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\
+						<use x=\"0\" y=\"0\" xlink:href=\"#svgroot\"> <\/use>\
+					 </svg>\
+					 <div id=\"overview_window_view_box\" style=\"min-width:50px; min-height:50px; position:absolute; top:30px; left:30px; z-index:5; background-color:rgba(255,0,102,0.3);\">\
+					 <\/div>\
+				 <\/div>\
+			<\/div>\
+		<\/div>";
+	$("#sidepanels").append(propsWindowHtml);
+
+	//define dynamic animation of the view box.
+	var updateViewBox = function(){
+		var portHeight=parseFloat($("#workarea").css("height"));
+		var portWidth=parseFloat($("#workarea").css("width"));
+		var portX=$("#workarea").scrollLeft();
+		var portY=$("#workarea").scrollTop();
+		var windowWidth=parseFloat($("#svgcanvas").css("width"));
+		var windowHeight=parseFloat($("#svgcanvas").css("height"));
+		var overviewWidth=$("#overviewMiniView").attr("width");
+		var overviewHeight=$("#overviewMiniView").attr("height");
+		
+		var viewBoxX=portX/windowWidth*overviewWidth;
+		var viewBoxY=portY/windowHeight*overviewHeight;
+		var viewBoxWidth=portWidth/windowWidth*overviewWidth;
+		var viewBoxHeight=portHeight/windowHeight*overviewHeight;
+		
+		$("#overview_window_view_box").css("min-width",viewBoxWidth+"px");
+		$("#overview_window_view_box").css("min-height",viewBoxHeight+"px");
+		$("#overview_window_view_box").css("top",viewBoxY+"px");
+		$("#overview_window_view_box").css("left",viewBoxX+"px");
+	};
+	$("#workarea").scroll(function(){
+		if(!(overviewWindowGlobals.viewBoxDragging)){
+			updateViewBox();
+		}
+	});
+	$("#workarea").resize(updateViewBox);
+	updateViewBox();
+	
+	//comphensate for changes in zoom and canvas size
+	var updateViewDimensions= function(){
+		var viewWidth=$("#svgroot").attr("width");
+		var viewHeight=$("#svgroot").attr("height");
+		var viewX=640;
+		var viewY=480;
+		
+		if(svgedit.browser.isIE())
+		{
+			//This has only been tested with Firefox 10 and IE 9 (without chrome frame).
+			//I am not sure if if is Firefox or IE that is being non compliant here.
+			//Either way the one that is noncompliant may become more compliant later.
+			//TAG:HACK  
+			//TAG:VERSION_DEPENDENT
+			//TAG:BROWSER_SNIFFING
+			viewX=0;
+			viewY=0;
+		}
+		
+		var svgWidth_old=$("#overviewMiniView").attr("width");
+		var svgHeight_new=viewHeight/viewWidth*svgWidth_old;
+		$("#overviewMiniView").attr("viewBox",viewX+" "+viewY+" "+viewWidth+" "+viewHeight);
+		$("#overviewMiniView").attr("height",svgHeight_new);
+		updateViewBox();
+	};
+	updateViewDimensions();
+	
+	//set up the overview window as a controller for the view port.
+	overviewWindowGlobals.viewBoxDragging=false;
+	var updateViewPortFromViewBox = function(){
+	
+		var windowWidth =parseFloat($("#svgcanvas").css("width" ));
+		var windowHeight=parseFloat($("#svgcanvas").css("height"));
+		var overviewWidth =$("#overviewMiniView").attr("width" );
+		var overviewHeight=$("#overviewMiniView").attr("height");
+		var viewBoxX=parseFloat($("#overview_window_view_box").css("left"));
+		var viewBoxY=parseFloat($("#overview_window_view_box").css("top" ));
+		
+		var portX=viewBoxX/overviewWidth *windowWidth;
+		var portY=viewBoxY/overviewHeight*windowHeight;
+
+		$("#workarea").scrollLeft(portX);
+		$("#workarea").scrollTop(portY);
+	};
+	$( "#overview_window_view_box" ).draggable({  containment: "parent"
+		,drag: updateViewPortFromViewBox
+		,start:function(){overviewWindowGlobals.viewBoxDragging=true; }
+		,stop :function(){overviewWindowGlobals.viewBoxDragging=false;}
+	});  
+	$("#overviewMiniView").click(function(evt){
+		//Firefox doesn't support evt.offsetX and evt.offsetY
+		var mouseX=(evt.offsetX || evt.originalEvent.layerX);
+		var mouseY=(evt.offsetY || evt.originalEvent.layerY);
+		var overviewWidth =$("#overviewMiniView").attr("width" );
+		var overviewHeight=$("#overviewMiniView").attr("height");
+		var viewBoxWidth =parseFloat($("#overview_window_view_box").css("min-width" ));
+		var viewBoxHeight=parseFloat($("#overview_window_view_box").css("min-height"));
+ 
+		var viewBoxX=mouseX - 0.5 * viewBoxWidth;
+		var viewBoxY=mouseY- 0.5 * viewBoxHeight;
+		//deal with constraints
+		if(viewBoxX<0){
+			viewBoxX=0;
+		}
+		if(viewBoxY<0){
+			viewBoxY=0;
+		}
+		if(viewBoxX+viewBoxWidth>overviewWidth){
+			viewBoxX=overviewWidth-viewBoxWidth;
+		}
+		if(viewBoxY+viewBoxHeight>overviewHeight){
+			viewBoxY=overviewHeight-viewBoxHeight;
+		}
+		
+		$("#overview_window_view_box").css("top",viewBoxY+"px");
+		$("#overview_window_view_box").css("left",viewBoxX+"px");
+		updateViewPortFromViewBox();
+	});
+	
+	return{
+		name: "overview window",
+		canvasUpdated:updateViewDimensions,
+		workareaResized:updateViewBox
+	};
+});

+ 46 - 0
main/inc/lib/svg-edit/extensions/ext-panning.js

@@ -0,0 +1,46 @@
+/*globals svgEditor, svgCanvas*/
+/*jslint eqeq: true*/
+/*
+ * ext-panning.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2013 Luis Aguirre
+ *
+ */
+ 
+/* 
+	This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem
+*/
+
+svgEditor.addExtension('ext-panning', function() {'use strict';
+	return {
+		name: 'Extension Panning',
+		svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
+		buttons: [{
+			id: 'ext-panning',
+			type: 'mode',
+			title: 'Panning',
+			events: {
+				click: function() {
+					svgCanvas.setMode('ext-panning');
+				}
+			}
+		}],
+		mouseDown: function() {
+			if (svgCanvas.getMode() == 'ext-panning') {
+				svgEditor.setPanning(true);
+				return {started: true};
+			}
+		},
+		mouseUp: function() {
+			if (svgCanvas.getMode() == 'ext-panning') {
+				svgEditor.setPanning(false);
+				return {
+					keep: false,
+					element: null
+				};
+			}
+		}
+	};
+});

+ 7 - 0
main/inc/lib/svg-edit/extensions/ext-panning.xml

@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+	<g id="ext-panning">
+	  <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
+                  <path fill="#7f0000" stroke="#000000" stroke-width="10" d="m1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z"></path>
+  	</svg>
+	</g>
+</svg>

+ 23 - 0
main/inc/lib/svg-edit/extensions/ext-php_savefile.js

@@ -0,0 +1,23 @@
+/*globals $, svgCanvas, svgEditor*/
+/*jslint regexp:true*/
+// TODO: Might add support for "exportImage" custom
+//   handler as in "ext-server_opensave.js" (and in savefile.php)
+
+svgEditor.addExtension("php_savefile", {
+	callback: function() {
+		'use strict';
+		function getFileNameFromTitle () {
+			var title = svgCanvas.getDocumentTitle();
+			return $.trim(title);
+		}
+		var save_svg_action = svgEditor.curConfig.extPath + 'savefile.php';
+		svgEditor.setCustomHandlers({
+			save: function(win, data) {
+				var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
+					filename = getFileNameFromTitle();
+
+				$.post(save_svg_action, {output_svg: svg, filename: filename});
+			}
+		});
+	}
+});

+ 34 - 0
main/inc/lib/svg-edit/extensions/ext-php_savefile_chamilo.js

@@ -0,0 +1,34 @@
+/*globals $, svgCanvas, svgEditor*/
+/*jslint regexp:true*/
+// TODO: Might add support for "exportImage" custom
+//   handler as in "ext-server_opensave.js" (and in savefile.php)
+
+svgEditor.addExtension("php_savefile_chamilo", {
+	callback: function() {
+		'use strict';
+		function getFileNameFromTitle () {
+			var title = svgCanvas.getDocumentTitle();
+			return $.trim(title);
+		}
+		var save_svg_action = svgEditor.curConfig.extPath + 'savefile.php';
+		svgEditor.setCustomHandlers({
+			save: function(win, data) {
+				var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
+					filename = getFileNameFromTitle();
+
+				$.post(
+                    save_svg_action,
+                    {output_svg: svg, filename: filename}
+                ).done(function(data) {
+                    var response = jQuery.parseJSON(data);
+                        console.log(response.message);
+                        alert(response.message);
+                        if (response.url != '') {
+                            window.top.location.href = response.url;
+                        }
+                    }
+                );
+			}
+		});
+	}
+});

+ 295 - 0
main/inc/lib/svg-edit/extensions/ext-polygon.js

@@ -0,0 +1,295 @@
+/*globals svgEditor, svgCanvas, svgedit, $*/
+/*jslint vars: true, eqeq: true, todo: true */
+/*
+ * ext-polygon.js
+ *
+ *
+ * Copyright(c) 2010 CloudCanvas, Inc.
+ * All rights reserved
+ *
+ */
+svgEditor.addExtension("polygon", function(S) {'use strict';
+
+    var // NS = svgedit.NS,
+		// svgcontent = S.svgcontent,
+		// addElem = S.addSvgElementFromJson,
+		selElems,
+		editingitex = false,
+		// svgdoc = S.svgroot.parentNode.ownerDocument,
+		// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
+		// edg = 0,
+		// undoCommand = "Not image";
+		started, newFO;
+    
+    // var ccZoom;
+    // var wEl, hEl;
+    // var wOffset, hOffset;
+    // var ccRBG;
+	var ccRgbEl;
+    // var ccOpacity;
+    // var brushW, brushH;
+	var shape;
+    
+    // var ccDebug = document.getElementById('debugpanel');
+    
+    /* var properlySourceSizeTextArea = function(){
+     // TODO: remove magic numbers here and get values from CSS
+     var height = $('#svg_source_container').height() - 80;
+     $('#svg_source_textarea').css('height', height);
+     }; */
+    function showPanel(on){
+        var fc_rules = $('#fc_rules');
+        if (!fc_rules.length) {
+            fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
+        }
+        fc_rules.text(!on ? "" : " #tool_topath { display: none !important; }");
+        $('#polygon_panel').toggle(on);
+    }
+    
+	/*
+    function toggleSourceButtons(on){
+        $('#tool_source_save, #tool_source_cancel').toggle(!on);
+        $('#polygon_save, #polygon_cancel').toggle(on);
+    }
+	*/
+    
+    function setAttr(attr, val){
+        svgCanvas.changeSelectedAttribute(attr, val);
+        S.call("changed", selElems);
+    }
+    
+    function cot(n){
+        return 1 / Math.tan(n);
+    }
+    
+    function sec(n){
+        return 1 / Math.cos(n);
+    }
+
+	/**
+	* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
+	* This function sets the content of of the currently-selected foreignObject element,
+	*   based on the itex contained in string.
+	* @param {string} tex The itex text.
+	* @returns This function returns false if the set was unsuccessful, true otherwise.
+	*/
+	/*
+	function setItexString(tex) {
+		var mathns = 'http://www.w3.org/1998/Math/MathML',
+			xmlnsns = 'http://www.w3.org/2000/xmlns/',
+			ajaxEndpoint = '../../itex';
+		var elt = selElems[0];
+		try {
+			var math = svgdoc.createElementNS(mathns, 'math');
+			math.setAttributeNS(xmlnsns, 'xmlns', mathns);
+			math.setAttribute('display', 'inline');
+			var semantics = document.createElementNS(mathns, 'semantics');
+			var annotation = document.createElementNS(mathns, 'annotation');
+			annotation.setAttribute('encoding', 'application/x-tex');
+			annotation.textContent = tex;
+			var mrow = document.createElementNS(mathns, 'mrow');
+			semantics.appendChild(mrow);
+			semantics.appendChild(annotation);
+			math.appendChild(semantics);
+			// make an AJAX request to the server, to get the MathML
+			$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){
+				var children = data.documentElement.childNodes;
+				while (children.length > 0) {
+				     mrow.appendChild(svgdoc.adoptNode(children[0], true));
+				}
+				S.sanitizeSvg(math);
+				S.call("changed", [elt]);
+			});
+			elt.replaceChild(math, elt.firstChild);
+			S.call("changed", [elt]);
+			svgCanvas.clearSelection();
+		} catch(e) {
+			console.log(e);
+			return false;
+		}
+
+		return true;
+	}
+	*/
+    return {
+        name: "polygon",
+        svgicons: svgEditor.curConfig.extPath + "polygon-icons.svg",
+        buttons: [{
+            id: "tool_polygon",
+            type: "mode",
+            title: "Polygon Tool",
+            position: 11,
+            events: {
+                'click': function(){
+                    svgCanvas.setMode('polygon');
+					showPanel(true);
+                }
+            }
+        }],
+        
+        context_tools: [{
+            type: "input",
+            panel: "polygon_panel",
+            title: "Number of Sides",
+            id: "polySides",
+            label: "sides",
+            size: 3,
+            defval: 5,
+            events: {
+                change: function(){
+                    setAttr('sides', this.value);
+					
+                }
+            }
+        }],
+        
+        callback: function(){
+        
+            $('#polygon_panel').hide();
+            
+            var endChanges = function(){
+            };
+            
+            // TODO: Needs to be done after orig icon loads
+            setTimeout(function(){
+                // Create source save/cancel buttons
+                var save = $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo("#tool_source_back").click(function(){
+                
+                    if (!editingitex) {
+						return;
+					}
+					// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
+                    if (!setItexString($('#svg_source_textarea').val())) {
+                        $.confirm("Errors found. Revert to original?", function(ok){
+                            if (!ok) {
+								return false;
+							}
+                            endChanges();
+                        });
+                    }
+                    else {
+                        endChanges();
+                    }
+                    // setSelectMode();	
+                });
+                
+                var cancel = $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo("#tool_source_back").click(function(){
+                    endChanges();
+                });
+                
+            }, 3000);
+        },
+        mouseDown: function(opts){
+            // var e = opts.event;
+            var rgb = svgCanvas.getColor("fill");
+            ccRgbEl = rgb.substring(1, rgb.length);
+            var sRgb = svgCanvas.getColor("stroke");
+            // ccSRgbEl = sRgb.substring(1, rgb.length);
+            var sWidth = svgCanvas.getStrokeWidth();
+            
+            if (svgCanvas.getMode() == "polygon") {
+                started = true;
+                
+                newFO = S.addSvgElementFromJson({
+                    "element": "polygon",
+                    "attr": {
+                        "cx": opts.start_x,
+                        "cy": opts.start_y,
+                        "id": S.getNextId(),
+                        "shape": "regularPoly",
+                        "sides": document.getElementById("polySides").value,
+                        "orient": "x",
+                        "edge": 0,
+                        "fill": rgb,
+                        "strokecolor": sRgb,
+                        "strokeWidth": sWidth
+                    }
+                });
+                
+                return {
+                    started: true
+                };
+            }
+        },
+        mouseMove: function(opts){
+            if (!started) {
+                return;
+			}
+            if (svgCanvas.getMode() == "polygon") {
+                // var e = opts.event;
+                var x = opts.mouse_x;
+                var y = opts.mouse_y;
+                var c = $(newFO).attr(["cx", "cy", "sides", "orient", "fill", "strokecolor", "strokeWidth"]);
+                var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides,
+					// orient = c.orient,
+					edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
+                newFO.setAttributeNS(null, "edge", edg);
+                
+                var inradius = (edg / 2) * cot(Math.PI / sides);
+                var circumradius = inradius * sec(Math.PI / sides);
+                var points = '';
+				var s;
+                for (s = 0; sides >= s; s++) {
+                    var angle = 2.0 * Math.PI * s / sides;
+                    x = (circumradius * Math.cos(angle)) + cx;
+                    y = (circumradius * Math.sin(angle)) + cy;
+                    
+                    points += x + ',' + y + ' ';
+                }
+                
+                //var poly = newFO.createElementNS(NS.SVG, 'polygon');
+                newFO.setAttributeNS(null, 'points', points);
+                newFO.setAttributeNS(null, 'fill', fill);
+                newFO.setAttributeNS(null, 'stroke', strokecolor);
+                newFO.setAttributeNS(null, 'stroke-width', strokewidth);
+				// newFO.setAttributeNS(null, 'transform', "rotate(-90)");
+                shape = newFO.getAttributeNS(null, 'shape');
+                //newFO.appendChild(poly);
+                //DrawPoly(cx, cy, sides, edg, orient);
+                return {
+                    started: true
+                };
+            }
+            
+        },
+        
+        mouseUp: function(opts){
+            if (svgCanvas.getMode() == "polygon") {
+                var attrs = $(newFO).attr("edge");
+                var keep = (attrs.edge != 0);
+               // svgCanvas.addToSelection([newFO], true);
+                return {
+                    keep: keep,
+                    element: newFO
+                };
+            }
+            
+        },
+        selectedChanged: function(opts){
+            // Use this to update the current selected elements
+            selElems = opts.elems;
+            
+            var i = selElems.length;
+            
+            while (i--) {
+                var elem = selElems[i];
+                if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
+                    if (opts.selectedElement && !opts.multiselected) {
+                        $('#polySides').val(elem.getAttribute("sides"));
+                        
+                        showPanel(true);
+                    }
+                    else {
+                        showPanel(false);
+                    }
+                }
+                else {
+                    showPanel(false);
+                }
+            }
+        },
+        elementChanged: function(opts){
+            // var elem = opts.elems[0];
+        }
+    };
+});

+ 23 - 19
main/inc/lib/svg-edit/extensions/ext-server_moinsave.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, svgedit, svgCanvas, canvg, $, top*/
+/*jslint vars: true*/
 /*
 /*
  * ext-server_moinsave.js
  * ext-server_moinsave.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *              2011 MoinMoin:ReimarBauer
  *              2011 MoinMoin:ReimarBauer
@@ -11,7 +13,7 @@
  */
  */
 
 
 svgEditor.addExtension("server_opensave", {
 svgEditor.addExtension("server_opensave", {
-	callback: function() {
+	callback: function() {'use strict';
 
 
 		var save_svg_action = '/+modify';
 		var save_svg_action = '/+modify';
 		
 		
@@ -31,25 +33,27 @@ svgEditor.addExtension("server_opensave", {
 				c.width = svgCanvas.contentW;
 				c.width = svgCanvas.contentW;
 				c.height = svgCanvas.contentH;
 				c.height = svgCanvas.contentH;
 				$.getScript('canvg/canvg.js', function() {
 				$.getScript('canvg/canvg.js', function() {
-				canvg(c, svg, {renderCallback: function() {
-					var datauri = c.toDataURL('image/png');
-					var uiStrings = svgEditor.uiStrings;
-					var png_data = svgedit.utilities.encode64(datauri);
-					var form = $('<form>').attr({
-					method: 'post',
-					action: save_svg_action + '/' + name,
-					target: 'output_frame'
-				})	.append('<input type="hidden" name="png_data" value="' + png_data + '">')
-					.append('<input type="hidden" name="filepath" value="' + svg_data + '">')
-					.append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
-					.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
-					.appendTo('body')
-					.submit().remove();
-					}})});
+					canvg(c, svg, {renderCallback: function() {
+						var datauri = c.toDataURL('image/png');
+						// var uiStrings = svgEditor.uiStrings;
+						var png_data = svgedit.utilities.encode64(datauri);
+						var form = $('<form>').attr({
+						method: 'post',
+						action: save_svg_action + '/' + name,
+						target: 'output_frame'
+					}).append('<input type="hidden" name="png_data" value="' + png_data + '">')
+						.append('<input type="hidden" name="filepath" value="' + svg_data + '">')
+						.append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
+						.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
+						.appendTo('body')
+						.submit().remove();
+					}});
+				});
 				alert("Saved! Return to Item View!");
 				alert("Saved! Return to Item View!");
 				top.window.location = '/'+name;
 				top.window.location = '/'+name;
-			},
+			}
 		});
 		});
 	
 	
 	}
 	}
-});
+});
+

+ 80 - 51
main/inc/lib/svg-edit/extensions/ext-server_opensave.js

@@ -1,7 +1,9 @@
+/*globals svgEditor, svgedit, svgCanvas, canvg, $*/
+/*jslint eqeq: true*/
 /*
 /*
  * ext-server_opensave.js
  * ext-server_opensave.js
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
@@ -9,48 +11,72 @@
 
 
 svgEditor.addExtension("server_opensave", {
 svgEditor.addExtension("server_opensave", {
 	callback: function() {
 	callback: function() {
-
-		var save_svg_action = 'extensions/filesave.php';
-		var save_png_action = 'extensions/filesave.php';
-	
-		// Create upload target (hidden iframe)
-		var target = $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
+		'use strict';
+		function getFileNameFromTitle () {
+			var title = svgCanvas.getDocumentTitle();
+			// We convert (to underscore) only those disallowed Win7 file name characters
+			return $.trim(title).replace(/[\/\\:*?"<>|]/g, '_');
+		}
+		function xhtmlEscape(str) {
+			return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways
+		}
+		function clientDownloadSupport (filename, suffix, uri) {
+			var a,
+				support = $('<a>')[0].download === '';
+			if (support) {
+				a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body');
+				a[0].click();
+				return true;
+			}
+		}
+		var open_svg_action, import_svg_action, import_img_action,
+			open_svg_form, import_svg_form, import_img_form,
+			save_svg_action = svgEditor.curConfig.extPath + 'filesave.php',
+			save_img_action = svgEditor.curConfig.extPath + 'filesave.php',
+			// Create upload target (hidden iframe)
+			cancelled = false;
 	
 	
+		$('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
 		svgEditor.setCustomHandlers({
 		svgEditor.setCustomHandlers({
 			save: function(win, data) {
 			save: function(win, data) {
-				var svg = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + data; // Chamilo add encoding="UTF-8"
+				var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
+					filename = getFileNameFromTitle();
+
+				if (clientDownloadSupport(filename, '.svg', 'data:image/svg+xml;charset=UTF-8;base64,' + svgedit.utilities.encode64(svg))) {
+					return;
+				}
 
 
-				var title = svgCanvas.getDocumentTitle();
-				//var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');//Chamilo replace by below  
-				var filename =title;//Chamilo TODO:check if the filter through filesave.php is enough				
-				var form = $('<form>').attr({
+				$('<form>').attr({
 					method: 'post',
 					method: 'post',
 					action: save_svg_action,
 					action: save_svg_action,
 					target: 'output_frame'
 					target: 'output_frame'
-				})	.append('<input type="hidden" name="output_svg" value="' + encodeURI(svg) + '">')
-					.append('<input type="hidden" name="filename" value="' + filename + '">')
+				}).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">')
+					.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
 					.appendTo('body')
 					.appendTo('body')
 					.submit().remove();
 					.submit().remove();
 			},
 			},
-			pngsave: function(win, data) {
-				var issues = data.issues;
+			exportImage: function(win, data) {
+				var c,
+					issues = data.issues,
+					mimeType = data.mimeType,
+					quality = data.quality;
 				
 				
 				if(!$('#export_canvas').length) {
 				if(!$('#export_canvas').length) {
 					$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
 					$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
 				}
 				}
-				var c = $('#export_canvas')[0];
+				c = $('#export_canvas')[0];
 				
 				
 				c.width = svgCanvas.contentW;
 				c.width = svgCanvas.contentW;
 				c.height = svgCanvas.contentH;
 				c.height = svgCanvas.contentH;
 				canvg(c, data.svg, {renderCallback: function() {
 				canvg(c, data.svg, {renderCallback: function() {
-					var datauri = c.toDataURL('image/png');
+					var pre, filename, suffix,
+						datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType),
+						// uiStrings = svgEditor.uiStrings,
+						note = '';
 					
 					
-					var uiStrings = svgEditor.uiStrings;
-					var note = '';
-					
-					// Check if there's issues
-					if(issues.length) {
-						var pre = "\n \u2022 ";
+					// Check if there are issues
+					if (issues.length) {
+						pre = "\n \u2022 ";
 						note += ("\n\n" + pre + issues.join(pre));
 						note += ("\n\n" + pre + issues.join(pre));
 					} 
 					} 
 					
 					
@@ -58,16 +84,20 @@ svgEditor.addExtension("server_opensave", {
 						alert(note);
 						alert(note);
 					}
 					}
 					
 					
-					var title = svgCanvas.getDocumentTitle();
-					//var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_');//Chamilo replace by below 
-					var filename =title;//Chamilo TODO:check if the filter through filesave.php is enough
+					filename = getFileNameFromTitle();
+					suffix = '.' + data.type.toLowerCase();
 					
 					
-					var form = $('<form>').attr({
+					if (clientDownloadSupport(filename, suffix, datauri)) {
+						return;
+					}
+
+					$('<form>').attr({
 						method: 'post',
 						method: 'post',
-						action: save_png_action,
+						action: save_img_action,
 						target: 'output_frame'
 						target: 'output_frame'
-					})	.append('<input type="hidden" name="output_png" value="' + datauri + '">')
-						.append('<input type="hidden" name="filename" value="' + filename + '">')
+					}).append('<input type="hidden" name="output_img" value="' + datauri + '">')
+						.append('<input type="hidden" name="mime" value="' + mimeType + '">')
+						.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
 						.appendTo('body')
 						.appendTo('body')
 						.submit().remove();
 						.submit().remove();
 				}});
 				}});
@@ -75,31 +105,30 @@ svgEditor.addExtension("server_opensave", {
 				
 				
 			}
 			}
 		});
 		});
-	
+
 		// Do nothing if client support is found
 		// Do nothing if client support is found
-		if(window.FileReader) return;
+		if (window.FileReader) {return;}
 		
 		
-		var cancelled = false;
-	
 		// Change these to appropriate script file
 		// Change these to appropriate script file
-		var open_svg_action = 'extensions/fileopen.php?type=load_svg';
-		var import_svg_action = 'extensions/fileopen.php?type=import_svg';
-		var import_img_action = 'extensions/fileopen.php?type=import_img';
+		open_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
+		import_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
+		import_img_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
 		
 		
 		// Set up function for PHP uploader to use
 		// Set up function for PHP uploader to use
 		svgEditor.processFile = function(str64, type) {
 		svgEditor.processFile = function(str64, type) {
-			if(cancelled) {
+			var xmlstr;
+			if (cancelled) {
 				cancelled = false;
 				cancelled = false;
 				return;
 				return;
 			}
 			}
 		
 		
 			$('#dialog_box').hide();
 			$('#dialog_box').hide();
-		
-			if(type != 'import_img') {
-				var xmlstr = svgCanvas.Utils.decode64(str64);
+
+			if (type !== 'import_img') {
+				xmlstr = svgedit.utilities.decode64(str64);
 			}
 			}
 			
 			
-			switch ( type ) {
+			switch (type) {
 				case 'load_svg':
 				case 'load_svg':
 					svgCanvas.clear();
 					svgCanvas.clear();
 					svgCanvas.setSvgString(xmlstr);
 					svgCanvas.setSvgString(xmlstr);
@@ -113,10 +142,10 @@ svgEditor.addExtension("server_opensave", {
 					svgCanvas.setGoodImage(str64);
 					svgCanvas.setGoodImage(str64);
 					break;
 					break;
 			}
 			}
-		}
+		};
 	
 	
 		// Create upload form
 		// Create upload form
-		var open_svg_form = $('<form>');
+		open_svg_form = $('<form>');
 		open_svg_form.attr({
 		open_svg_form.attr({
 			enctype: 'multipart/form-data',
 			enctype: 'multipart/form-data',
 			method: 'post',
 			method: 'post',
@@ -125,12 +154,12 @@ svgEditor.addExtension("server_opensave", {
 		});
 		});
 		
 		
 		// Create import form
 		// Create import form
-		var import_svg_form = open_svg_form.clone().attr('action', import_svg_action);
-		
+		import_svg_form = open_svg_form.clone().attr('action', import_svg_action);
+
 		// Create image form
 		// Create image form
-		var import_img_form = open_svg_form.clone().attr('action', import_img_action);
+		import_img_form = open_svg_form.clone().attr('action', import_img_action);
 		
 		
-		// It appears necessory to rebuild this input every time a file is 
+		// It appears necessary to rebuild this input every time a file is 
 		// selected so the same file can be picked and the change event can fire.
 		// selected so the same file can be picked and the change event can fire.
 		function rebuildInput(form) {
 		function rebuildInput(form) {
 			form.empty();
 			form.empty();
@@ -138,7 +167,7 @@ svgEditor.addExtension("server_opensave", {
 			
 			
 			
 			
 			function submit() {
 			function submit() {
-				// This submits the form, which returns the file data using svgEditor.uploadSVG
+				// This submits the form, which returns the file data using svgEditor.processFile()
 				form.submit();
 				form.submit();
 				
 				
 				rebuildInput(form);
 				rebuildInput(form);
@@ -161,7 +190,7 @@ svgEditor.addExtension("server_opensave", {
 				});
 				});
 			} else {
 			} else {
 				inp.change(function() {
 				inp.change(function() {
-					// This submits the form, which returns the file data using svgEditor.uploadSVG
+					// This submits the form, which returns the file data using svgEditor.processFile()
 					submit();
 					submit();
 				});
 				});
 			}
 			}

+ 357 - 387
main/inc/lib/svg-edit/extensions/ext-shapes.js

@@ -1,387 +1,357 @@
-/*
- * ext-shapes.js
- *
- * Licensed under the Apache License, Version 2
- *
- * Copyright(c) 2010 Christian Tzurcanu
- * Copyright(c) 2010 Alexis Deveria
- *
- */
-
-svgEditor.addExtension("shapes", function() {
-	
-
-	var current_d, cur_shape_id;
-	var canv = svgEditor.canvas;
-	var cur_shape;
-	var start_x, start_y;
-	var svgroot = canv.getRootElem();
-	var lastBBox = {};
-	
-	// This populates the category list
-	var categories = {
-		basic: 'Basic',
-		object: 'Objects',
-		symbol: 'Symbols',
-		arrow: 'Arrows',
-		flowchart: 'Flowchart',
-		animal: 'Animals',
-		game: 'Cards & Chess',
-		dialog_balloon: 'Dialog balloons',
-		electronics: 'Electronics',
-		math: 'Mathematical',
-		music: 'Music',
-		misc: 'Miscellaneous',
-		raphael_1: 'raphaeljs.com set 1',
-		raphael_2: 'raphaeljs.com set 2'
-	};
-	
-	var library = {
-		'basic': {
-			data: {
-				'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
-				'frame': 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
-				'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
-				"triangle": "m1,280.375l149,-260.75l149,260.75z",
-				"right_triangle": "m1,299l0,-298l298,298z",
-				"diamond": "m1,150l149,-149l149,149l-149,149l-149,-149z",
-				"pentagon": "m1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z",
-				"hexagon": "m1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z",
-				"septagon1": "m0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z",
-				"heptagon": "m1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z",
-				"decagon": "m1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z",
-				"dodecagon": "m1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z",
-				"star_points_5": "m1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z",
-				"trapezoid": "m1,299l55.875,-298l186.25001,0l55.87498,298z",
-				"arrow_up": "m1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z",
-				"vertical_scrool": "m37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875",
-				"smiley": "m68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z",
-				"left_braket": "m174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066",
-				"uml_actor": "m40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z",
-				"dialog_balloon_1": "m0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z",
-				"cloud": "m182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z",
-				"cylinder": "m299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z",
-				"arrow_u_turn": "m1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z",
-				"arrow_left_up": "m0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z",
-				"maximize": "m1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z",
-				"cross": "m0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z",
-				"plaque": "m-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z",
-				"page": "m249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234"
-
-			},
-			buttons: []
-		}
-	};
-	
-	var cur_lib = library.basic;
-	
-	var mode_id = 'shapelib';
-	
-	function loadIcons() {
-		$('#shape_buttons').empty();
-		
-		// Show lib ones
-		$('#shape_buttons').append(cur_lib.buttons);
-	}
-	
-	function loadLibrary(cat_id) {
-	
-		var lib = library[cat_id];
-		
-		if(!lib) {
-			$('#shape_buttons').html('Loading...');
-			$.getJSON('extensions/shapelib/' + cat_id + '.json', function(result, textStatus) {
-				cur_lib = library[cat_id] = {
-					data: result.data,
-					size: result.size,
-					fill: result.fill
-				}
-				makeButtons(cat_id, result);
-				loadIcons();
-			});
-			return;
-		}
-		
-		cur_lib = lib;
-		if(!lib.buttons.length)	makeButtons(cat_id, lib);
-		loadIcons();
-	}
-	
-	function makeButtons(cat, shapes) {
-		var size = cur_lib.size || 300;
-		var fill = cur_lib.fill || false;
-		var off = size * .05;
-		var vb = [-off, -off, size + off*2, size + off*2].join(' ');
-		var stroke = fill ? 0: (size/30);
-		
-		var shape_icon = new DOMParser().parseFromString(
-			'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="'+(fill?'#333':'none')+'" stroke="#000000" stroke-width="' + stroke + '" /><\/svg><\/svg>',
-			'text/xml');
-
-		var width = 24;
-		var height = 24;
-		shape_icon.documentElement.setAttribute('width', width);
-		shape_icon.documentElement.setAttribute('height', height);
-		var svg_elem = $(document.importNode(shape_icon.documentElement,true));
-	
-		var data = shapes.data;
-		
-		cur_lib.buttons = [];
-	
-		for(var id in data) {
-			var path_d = data[id];
-			var icon = svg_elem.clone();
-			icon.find('path').attr('d', path_d);
-			
-			var icon_btn = icon.wrap('<div class="tool_button">').parent().attr({
-				id: mode_id + '_' + id,
-				title: id
-			});
-			
-			
-			// Store for later use
-			cur_lib.buttons.push(icon_btn[0]);
-		}
-		
-	}
-
-	
-	return {
-		svgicons: "extensions/ext-shapes.xml",
-		buttons: [{
-			id: "tool_shapelib",
-			type: "mode_flyout", // _flyout
-			position: 6,
-			title: "Shape library",
-			events: {
-				"click": function() {
-					canv.setMode(mode_id);
-				}
-			}
-		}],
-		callback: function() {
-		
-			$('<style>').text('\
-			#shape_buttons {\
-				overflow: auto;\
-				width: 180px;\
-				max-height: 300px;\
-				display: table-cell;\
-				vertical-align: middle;\
-			}\
-			\
-			#shape_cats {\
-				min-width: 110px;\
-				display: table-cell;\
-				vertical-align: middle;\
-				height: 300px;\
-			}\
-			#shape_cats > div {\
-				line-height: 1em;\
-				padding: .5em;\
-				border:1px solid #B0B0B0;\
-				background: #E8E8E8;\
-				margin-bottom: -1px;\
-			}\
-			#shape_cats div:hover {\
-				background: #FFFFCC;\
-			}\
-			#shape_cats div.current {\
-				font-weight: bold;\
-			}').appendTo('head');
-
-		
-			var btn_div = $('<div id="shape_buttons">');
-			$('#tools_shapelib > *').wrapAll(btn_div);
-			
-			var shower = $('#tools_shapelib_show');
-
-			
-			loadLibrary('basic');
-			
-			// Do mouseup on parent element rather than each button
-			$('#shape_buttons').mouseup(function(evt) {
-				var btn = $(evt.target).closest('div.tool_button');
-				
-				if(!btn.length) return;
-				
-				var copy = btn.children().clone();
-				shower.children(':not(.flyout_arrow_horiz)').remove();
-				shower
-					.append(copy)
-					.attr('data-curopt', '#' + btn[0].id) // This sets the current mode
-					.mouseup();
-				canv.setMode(mode_id);
-				
-				cur_shape_id = btn[0].id.substr((mode_id+'_').length);
-				current_d = cur_lib.data[cur_shape_id];
-				
-				$('.tools_flyout').fadeOut();
-
-			});
-
-// 			
-			var shape_cats = $('<div id="shape_cats">');
-			
-			var cat_str = '';
-			
-			$.each(categories, function(id, label) {
-				cat_str += '<div data-cat=' + id + '>' + label + '</div>';
-			});
-			
-			shape_cats.html(cat_str).children().bind('mouseup', function() {
-				var catlink = $(this);
-				catlink.siblings().removeClass('current');
-				catlink.addClass('current');
-				
-				loadLibrary(catlink.attr('data-cat'));
-				// Get stuff
-				
-				return false;
-			});
-			
-			shape_cats.children().eq(0).addClass('current');
-			
-			$('#tools_shapelib').append(shape_cats);
-
-			shower.mouseup(function() {
-				canv.setMode(current_d ? mode_id : 'select');
-			});
-
-			
-			$('#tool_shapelib').remove();
-			
-			var h = $('#tools_shapelib').height();
-			$('#tools_shapelib').css({
-				'margin-top': -(h/2 - 15),
-				'margin-left': 3
-			});
-
-	
-		},
-		mouseDown: function(opts) {
-			var mode = canv.getMode();
-			if(mode !== mode_id) return;
-			
-			var e = opts.event;
-			var x = start_x = opts.start_x;
-			var y = start_y = opts.start_y;
-			var cur_style = canv.getStyle();
-
-			cur_shape = canv.addSvgElementFromJson({
-				"element": "path",
-				"curStyles": true,
-				"attr": {
-					"d": current_d,
-					"id": canv.getNextId(),
-					"opacity": cur_style.opacity / 2,
-					"style": "pointer-events:none"
-				}
-			});
-			
-			// Make sure shape uses absolute values
-			if(/[a-z]/.test(current_d)) {
-				current_d = cur_lib.data[cur_shape_id] = canv.pathActions.convertPath(cur_shape);
-				cur_shape.setAttribute('d', current_d);
-				canv.pathActions.fixEnd(cur_shape);
-			}
-	
-			cur_shape.setAttribute('transform', "translate(" + x + "," + y + ") scale(0.005) translate(" + -x + "," + -y + ")");
-			
-// 			console.time('b');
-			canv.recalculateDimensions(cur_shape);
-			
-			var tlist = canv.getTransformList(cur_shape);
-			
-			lastBBox = cur_shape.getBBox();
-			
-			return {
-				started: true
-			}
-			// current_d
-		},
-		mouseMove: function(opts) {
-			var mode = canv.getMode();
-			if(mode !== mode_id) return;
-			
-			var zoom = canv.getZoom();
-			var evt = opts.event
-			
-			var x = opts.mouse_x/zoom;
-			var y = opts.mouse_y/zoom;
-			
-			var tlist = canv.getTransformList(cur_shape),
-				box = cur_shape.getBBox(), 
-				left = box.x, top = box.y, width = box.width,
-				height = box.height;
-			var dx = (x-start_x), dy = (y-start_y);
-
-			var newbox = {
-				'x': Math.min(start_x,x),
-				'y': Math.min(start_y,y),
-				'width': Math.abs(x-start_x),
-				'height': Math.abs(y-start_y)
-			};
-
-			var ts = null,
-				tx = 0, ty = 0,
-				sy = height ? (height+dy)/height : 1, 
-				sx = width ? (width+dx)/width : 1;
-
-			var sx = newbox.width / lastBBox.width;
-			var sy = newbox.height / lastBBox.height;
-			
-			sx = sx || 1;
-			sy = sy || 1;
-			
-			// Not perfect, but mostly works...
-			if(x < start_x) {
-				tx = lastBBox.width;
-			}
-			if(y < start_y) ty = lastBBox.height;
-			
-			// update the transform list with translate,scale,translate
-			var translateOrigin = svgroot.createSVGTransform(),
-				scale = svgroot.createSVGTransform(),
-				translateBack = svgroot.createSVGTransform();
-				
-			translateOrigin.setTranslate(-(left+tx), -(top+ty));
-			if(!evt.shiftKey) {
-				var max = Math.min(Math.abs(sx), Math.abs(sy));
-
-				sx = max * (sx < 0 ? -1 : 1);
-				sy = max * (sy < 0 ? -1 : 1);
-			}
-			scale.setScale(sx,sy);
-			
-			translateBack.setTranslate(left+tx, top+ty);
-			var N = tlist.numberOfItems;
-			tlist.appendItem(translateBack);
-			tlist.appendItem(scale);
-			tlist.appendItem(translateOrigin);
-
-			canv.recalculateDimensions(cur_shape);
-			
-			lastBBox = cur_shape.getBBox();
-		},
-		mouseUp: function(opts) {
-			var mode = canv.getMode();
-			if(mode !== mode_id) return;
-			
-			if(opts.mouse_x == start_x && opts.mouse_y == start_y) {
-				return {
-					keep: false,
-					element: cur_shape,
-					started: false
-				}
-			}
-			
-			return {
-				keep: true,
-				element: cur_shape,
-				started: false
-			}
-		}		
-	}
-});
-
+/*globals svgEditor, $, DOMParser*/
+/*jslint es5: true, vars: true, eqeq: true*/
+/*
+ * ext-shapes.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2010 Christian Tzurcanu
+ * Copyright(c) 2010 Alexis Deveria
+ *
+ */
+
+svgEditor.addExtension('shapes', function() {'use strict';
+	var current_d, cur_shape_id;
+	var canv = svgEditor.canvas;
+	var cur_shape;
+	var start_x, start_y;
+	var svgroot = canv.getRootElem();
+	var lastBBox = {};
+
+	// This populates the category list
+	var categories = {
+		basic: 'Basic',
+		object: 'Objects',
+		symbol: 'Symbols',
+		arrow: 'Arrows',
+		flowchart: 'Flowchart',
+		animal: 'Animals',
+		game: 'Cards & Chess',
+		dialog_balloon: 'Dialog balloons',
+		electronics: 'Electronics',
+		math: 'Mathematical',
+		music: 'Music',
+		misc: 'Miscellaneous',
+		raphael_1: 'raphaeljs.com set 1',
+		raphael_2: 'raphaeljs.com set 2'
+	};
+
+	var library = {
+		basic: {
+			data: {
+				'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
+				'frame': 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
+				'donut': 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
+				'triangle': 'm1,280.375l149,-260.75l149,260.75z',
+				'right_triangle': 'm1,299l0,-298l298,298z',
+				'diamond': 'm1,150l149,-149l149,149l-149,149l-149,-149z',
+				'pentagon': 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z',
+				'hexagon': 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z',
+				'septagon1': 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z',
+				'heptagon': 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z',
+				'decagon': 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z',
+				'dodecagon': 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z',
+				'star_points_5': 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z',
+				'trapezoid': 'm1,299l55.875,-298l186.25001,0l55.87498,298z',
+				'arrow_up': 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z',
+				'vertical_scrool': 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875',
+				'smiley': 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z',
+				'left_braket': 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066',
+				'uml_actor': 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z',
+				'dialog_balloon_1': 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z',
+				'cloud': 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z',
+				'cylinder': 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z',
+				'arrow_u_turn': 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z',
+				'arrow_left_up': 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z',
+				'maximize': 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z',
+				'cross': 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z',
+				'plaque': 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z',
+				'page': 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234'
+
+			},
+			buttons: []
+		}
+	};
+
+	var cur_lib = library.basic;
+	var mode_id = 'shapelib';
+	var startClientPos = {};
+
+	function loadIcons() {
+		$('#shape_buttons').empty().append(cur_lib.buttons);
+	}
+
+	function makeButtons(cat, shapes) {
+		var size = cur_lib.size || 300;
+		var fill = cur_lib.fill || false;
+		var off = size * 0.05;
+		var vb = [-off, -off, size + off*2, size + off*2].join(' ');
+		var stroke = fill ? 0: (size/30);
+		var shape_icon = new DOMParser().parseFromString(
+			'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="'+(fill?'#333':'none')+'" stroke="#000" stroke-width="' + stroke + '" /><\/svg><\/svg>',
+			'text/xml');
+
+		var width = 24;
+		var height = 24;
+		shape_icon.documentElement.setAttribute('width', width);
+		shape_icon.documentElement.setAttribute('height', height);
+		var svg_elem = $(document.importNode(shape_icon.documentElement,true));
+
+		var data = shapes.data;
+
+		cur_lib.buttons = [];
+		var id;
+		for (id in data) {
+			var path_d = data[id];
+			var icon = svg_elem.clone();
+			icon.find('path').attr('d', path_d);
+
+			var icon_btn = icon.wrap('<div class="tool_button">').parent().attr({
+				id: mode_id + '_' + id,
+				title: id
+			});
+			// Store for later use
+			cur_lib.buttons.push(icon_btn[0]);
+		}
+	}
+
+	function loadLibrary(cat_id) {
+
+		var lib = library[cat_id];
+
+		if (!lib) {
+			$('#shape_buttons').html('Loading...');
+			$.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + cat_id + '.json', function(result) {
+				cur_lib = library[cat_id] = {
+					data: result.data,
+					size: result.size,
+					fill: result.fill
+				};
+				makeButtons(cat_id, result);
+				loadIcons();
+			});
+			return;
+		}
+		cur_lib = lib;
+		if (!lib.buttons.length) {makeButtons(cat_id, lib);}
+		loadIcons();
+	}
+
+	return {
+		svgicons: svgEditor.curConfig.extPath + 'ext-shapes.xml',
+		buttons: [{
+			id: 'tool_shapelib',
+			type: 'mode_flyout', // _flyout
+			position: 6,
+			title: 'Shape library',
+			events: {
+				click: function() {
+					canv.setMode(mode_id);
+				}
+			}
+		}],
+		callback: function() {
+			$('<style>').text('\
+			#shape_buttons {\
+				overflow: auto;\
+				width: 180px;\
+				max-height: 300px;\
+				display: table-cell;\
+				vertical-align: middle;\
+			}\
+			\
+			#shape_cats {\
+				min-width: 110px;\
+				display: table-cell;\
+				vertical-align: middle;\
+				height: 300px;\
+			}\
+			#shape_cats > div {\
+				line-height: 1em;\
+				padding: .5em;\
+				border:1px solid #B0B0B0;\
+				background: #E8E8E8;\
+				margin-bottom: -1px;\
+			}\
+			#shape_cats div:hover {\
+				background: #FFFFCC;\
+			}\
+			#shape_cats div.current {\
+				font-weight: bold;\
+			}').appendTo('head');
+
+			var btn_div = $('<div id="shape_buttons">');
+			$('#tools_shapelib > *').wrapAll(btn_div);
+
+			var shower = $('#tools_shapelib_show');
+
+			loadLibrary('basic');
+
+			// Do mouseup on parent element rather than each button
+			$('#shape_buttons').mouseup(function(evt) {
+				var btn = $(evt.target).closest('div.tool_button');
+
+				if (!btn.length) {return;}
+
+				var copy = btn.children().clone();
+				shower.children(':not(.flyout_arrow_horiz)').remove();
+				shower
+					.append(copy)
+					.attr('data-curopt', '#' + btn[0].id) // This sets the current mode
+					.mouseup();
+				canv.setMode(mode_id);
+
+				cur_shape_id = btn[0].id.substr((mode_id+'_').length);
+				current_d = cur_lib.data[cur_shape_id];
+
+				$('.tools_flyout').fadeOut();
+			});
+
+			var shape_cats = $('<div id="shape_cats">');
+			var cat_str = '';
+
+			$.each(categories, function(id, label) {
+				cat_str += '<div data-cat=' + id + '>' + label + '</div>';
+			});
+
+			shape_cats.html(cat_str).children().bind('mouseup', function() {
+				var catlink = $(this);
+				catlink.siblings().removeClass('current');
+				catlink.addClass('current');
+
+				loadLibrary(catlink.attr('data-cat'));
+				// Get stuff
+				return false;
+			});
+
+			shape_cats.children().eq(0).addClass('current');
+
+			$('#tools_shapelib').append(shape_cats);
+
+			shower.mouseup(function() {
+				canv.setMode(current_d ? mode_id : 'select');
+			});
+			$('#tool_shapelib').remove();
+
+			var h = $('#tools_shapelib').height();
+			$('#tools_shapelib').css({
+				'margin-top': -(h/2 - 15),
+				'margin-left': 3
+			});
+		},
+		mouseDown: function(opts) {
+			var mode = canv.getMode();
+			if (mode !== mode_id) {return;}
+
+			start_x = opts.start_x;
+			var x = start_x;
+			start_y = opts.start_y;
+			var y = start_y;
+			var cur_style = canv.getStyle();
+         
+			startClientPos.x = opts.event.clientX;
+			startClientPos.y = opts.event.clientY;
+
+			cur_shape = canv.addSvgElementFromJson({
+				'element': 'path',
+				'curStyles': true,
+				'attr': {
+					'd': current_d,
+					'id': canv.getNextId(),
+					'opacity': cur_style.opacity / 2,
+					'style': 'pointer-events:none'
+				}
+			});
+
+			// Make sure shape uses absolute values
+			if (/[a-z]/.test(current_d)) {
+				current_d = cur_lib.data[cur_shape_id] = canv.pathActions.convertPath(cur_shape);
+				cur_shape.setAttribute('d', current_d);
+				canv.pathActions.fixEnd(cur_shape);
+			}
+			cur_shape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
+
+			canv.recalculateDimensions(cur_shape);
+
+			var tlist = canv.getTransformList(cur_shape);
+
+			lastBBox = cur_shape.getBBox();
+
+			return {
+				started: true
+			};
+		},
+		mouseMove: function(opts) {
+			var mode = canv.getMode();
+			if (mode !== mode_id) {return;}
+
+			var zoom = canv.getZoom();
+			var evt = opts.event;
+
+			var x = opts.mouse_x/zoom;
+			var y = opts.mouse_y/zoom;
+
+			var tlist = canv.getTransformList(cur_shape),
+				box = cur_shape.getBBox(),
+				left = box.x, top = box.y, width = box.width,
+				height = box.height;
+			var dx = (x-start_x), dy = (y-start_y);
+
+			var newbox = {
+				'x': Math.min(start_x,x),
+				'y': Math.min(start_y,y),
+				'width': Math.abs(x-start_x),
+				'height': Math.abs(y-start_y)
+			};
+
+			var tx = 0, ty = 0,
+				sy = height ? (height+dy)/height : 1,
+				sx = width ? (width+dx)/width : 1;
+
+			sx = (newbox.width / lastBBox.width) || 1;
+			sy = (newbox.height / lastBBox.height) || 1;
+
+			// Not perfect, but mostly works...
+			if (x < start_x) {
+				tx = lastBBox.width;
+			}
+			if (y < start_y) {ty = lastBBox.height;}
+
+			// update the transform list with translate,scale,translate
+			var translateOrigin = svgroot.createSVGTransform(),
+				scale = svgroot.createSVGTransform(),
+				translateBack = svgroot.createSVGTransform();
+
+			translateOrigin.setTranslate(-(left+tx), -(top+ty));
+			if (!evt.shiftKey) {
+				var max = Math.min(Math.abs(sx), Math.abs(sy));
+
+				sx = max * (sx < 0 ? -1 : 1);
+				sy = max * (sy < 0 ? -1 : 1);
+			}
+			scale.setScale(sx,sy);
+
+			translateBack.setTranslate(left+tx, top+ty);
+			tlist.appendItem(translateBack);
+			tlist.appendItem(scale);
+			tlist.appendItem(translateOrigin);
+
+			canv.recalculateDimensions(cur_shape);
+
+			lastBBox = cur_shape.getBBox();
+		},
+		mouseUp: function(opts) {
+			var mode = canv.getMode();
+			if (mode !== mode_id) {return;}
+         
+      var keepObject = (opts.event.clientX != startClientPos.x && opts.event.clientY != startClientPos.y);
+
+			return {
+				keep: keepObject,
+				element: cur_shape,
+				started: false
+			};
+		}
+	};
+});
+

+ 236 - 0
main/inc/lib/svg-edit/extensions/ext-shapes.xml

@@ -0,0 +1,236 @@
+/*globals svgEditor, svgedit, svgCanvas, $*/
+/*jslint vars: true, eqeq: true*/
+/*
+ * ext-star.js
+ *
+ *
+ * Copyright(c) 2010 CloudCanvas, Inc.
+ * All rights reserved
+ *
+ */
+
+svgEditor.addExtension('star', function(S){'use strict';
+
+	var // NS = svgedit.NS,
+		// svgcontent = S.svgcontent,
+		selElems,
+		// editingitex = false,
+		// svgdoc = S.svgroot.parentNode.ownerDocument,
+		started,
+		newFO,
+		// edg = 0,
+		// newFOG, newFOGParent, newDef, newImageName, newMaskID,
+		// undoCommand = 'Not image',
+		// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH,
+		shape;
+
+	function showPanel(on){
+		var fc_rules = $('#fc_rules');
+		if (!fc_rules.length) {
+			fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head');
+		}
+		fc_rules.text(!on ? '' : ' #tool_topath { display: none !important; }');
+		$('#star_panel').toggle(on);
+	}
+
+	/*
+	function toggleSourceButtons(on){
+		$('#star_save, #star_cancel').toggle(on);
+	}
+	*/
+
+	function setAttr(attr, val){
+		svgCanvas.changeSelectedAttribute(attr, val);
+		S.call('changed', selElems);
+	}
+
+	/*
+	function cot(n){
+		return 1 / Math.tan(n);
+	}
+
+	function sec(n){
+		return 1 / Math.cos(n);
+	}
+	*/
+
+	return {
+		name: 'star',
+		svgicons: svgEditor.curConfig.extPath + 'star-icons.svg',
+		buttons: [{
+			id: 'tool_star',
+			type: 'mode',
+			title: 'Star Tool',
+			position: 12,
+			events: {
+				click: function(){
+					showPanel(true);
+					svgCanvas.setMode('star');
+				}
+			}
+		}],
+
+		context_tools: [{
+			type: 'input',
+			panel: 'star_panel',
+			title: 'Number of Sides',
+			id: 'starNumPoints',
+			label: 'points',
+			size: 3,
+			defval: 5,
+			events: {
+				change: function(){
+					setAttr('point', this.value);
+				}
+			}
+		}, {
+			type: 'input',
+			panel: 'star_panel',
+			title: 'Pointiness',
+			id: 'starRadiusMulitplier',
+			label: 'Pointiness',
+			size: 3,
+			defval: 2.5
+		}, {
+			type: 'input',
+			panel: 'star_panel',
+			title: 'Twists the star',
+			id: 'radialShift',
+			label: 'Radial Shift',
+			size: 3,
+			defval: 0,
+			events: {
+				change: function(){
+					setAttr('radialshift', this.value);
+				}
+			}
+		}],
+		callback: function(){
+			$('#star_panel').hide();
+			// var endChanges = function(){};
+		},
+		mouseDown: function(opts){
+			var rgb = svgCanvas.getColor('fill');
+			// var ccRgbEl = rgb.substring(1, rgb.length);
+			var sRgb = svgCanvas.getColor('stroke');
+			// var ccSRgbEl = sRgb.substring(1, rgb.length);
+			var sWidth = svgCanvas.getStrokeWidth();
+
+			if (svgCanvas.getMode() == 'star') {
+				started = true;
+
+				newFO = S.addSvgElementFromJson({
+					'element': 'polygon',
+					'attr': {
+						'cx': opts.start_x,
+						'cy': opts.start_y,
+						'id': S.getNextId(),
+						'shape': 'star',
+						'point': document.getElementById('starNumPoints').value,
+						'r': 0,
+						'radialshift': document.getElementById('radialShift').value,
+						'r2': 0,
+						'orient': 'point',
+						'fill': rgb,
+						'strokecolor': sRgb,
+						'strokeWidth': sWidth
+					}
+				});
+				return {
+					started: true
+				};
+			}
+		},
+		mouseMove: function(opts){
+			if (!started) {
+				return;
+			}
+			if (svgCanvas.getMode() == 'star') {
+				var x = opts.mouse_x;
+				var y = opts.mouse_y;
+				var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
+
+				var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, radialShift = c.radialshift, point = c.point, orient = c.orient, circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5, inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
+				newFO.setAttributeNS(null, 'r', circumradius);
+				newFO.setAttributeNS(null, 'r2', inradius);
+
+				var polyPoints = '';
+				var s;
+				for (s = 0; point >= s; s++) {
+					var angle = 2.0 * Math.PI * (s / point);
+					if ('point' == orient) {
+						angle -= (Math.PI / 2);
+					} else if ('edge' == orient) {
+						angle = (angle + (Math.PI / point)) - (Math.PI / 2);
+					}
+
+					x = (circumradius * Math.cos(angle)) + cx;
+					y = (circumradius * Math.sin(angle)) + cy;
+
+					polyPoints += x + ',' + y + ' ';
+
+					if (null != inradius) {
+						angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point);
+						if ('point' == orient) {
+							angle -= (Math.PI / 2);
+						} else if ('edge' == orient) {
+							angle = (angle + (Math.PI / point)) - (Math.PI / 2);
+						}
+						angle += radialShift;
+
+						x = (inradius * Math.cos(angle)) + cx;
+						y = (inradius * Math.sin(angle)) + cy;
+
+						polyPoints += x + ',' + y + ' ';
+					}
+				}
+				newFO.setAttributeNS(null, 'points', polyPoints);
+				newFO.setAttributeNS(null, 'fill', fill);
+				newFO.setAttributeNS(null, 'stroke', strokecolor);
+				newFO.setAttributeNS(null, 'stroke-width', strokewidth);
+				shape = newFO.getAttributeNS(null, 'shape');
+
+				return {
+					started: true
+				};
+			}
+
+		},
+		mouseUp: function(){
+			if (svgCanvas.getMode() == 'star') {
+				var attrs = $(newFO).attr(['r']);
+				// svgCanvas.addToSelection([newFO], true);
+				return {
+					keep: (attrs.r != 0),
+					element: newFO
+				};
+			}
+		},
+		selectedChanged: function(opts){
+			// Use this to update the current selected elements
+			selElems = opts.elems;
+
+			var i = selElems.length;
+
+			while (i--) {
+				var elem = selElems[i];
+				if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
+					if (opts.selectedElement && !opts.multiselected) {
+						// $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
+						$('#starNumPoints').val(elem.getAttribute('point'));
+						$('#radialShift').val(elem.getAttribute('radialshift'));
+						showPanel(true);
+					}
+					else {
+						showPanel(false);
+					}
+				} else {
+					showPanel(false);
+				}
+			}
+		},
+		elementChanged: function(opts){
+			// var elem = opts.elems[0];
+		}
+	};
+});

+ 230 - 0
main/inc/lib/svg-edit/extensions/ext-storage - Copy.js

@@ -0,0 +1,230 @@
+/*globals svgEditor, Editor, svgCanvas, $, widget*/
+/*jslint vars: true, eqeq: true, regexp: true, continue: true*/
+/*
+ * ext-storage.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2010 Brett Zamir
+ *
+ */
+/**
+* This extension allows automatic saving of the SVG canvas contents upon
+*  page unload and and automatic retrieval of the contents upon editor load.
+*  The functionality was originally part of the SVG Editor, but moved to a
+*  separate extension to make the behavior optional, and adapted to inform
+*  the user of its setting of local data.
+*/
+
+/*
+TODOS
+1. Revisit on whether to use $.pref over directly setting curConfig in all
+	extensions for a more public API (not only for extPath and imagePath,
+	but other currently used config in the extensions)
+*/
+svgEditor.addExtension('storage', function() { 'use strict';
+	// We could empty any already-set data for them, but it
+	// would be a risk for users who wanted to store but accidentally
+	// said "no"; instead, we'll let those who already set it, delete it themselves;
+	// to change, change the following line to true.
+	var emptyStorageOnDecline = false;
+
+	function replaceStoragePrompt (val) {
+		val = val ? 'storagePrompt=' + val : '';
+		if (window.location.href.indexOf('storagePrompt=') > -1) {
+			window.location.href = window.location.href.replace(/([&?])storagePrompt=[^&]*/, (val ? '$1' : '') + val);
+		}
+		else {
+			window.location.href += (window.location.href.indexOf('?') > -1 ? '&' : '?') + val;
+		}
+	}
+	function setSVGContentStorage (val) {
+		if (window.localStorage) {
+			var name = 'svgedit-' + svgEditor.curConfig.canvasName;
+			window.localStorage.setItem(name, val);
+		}
+	}
+	function emptyLocalStorage() {
+		document.cookie = 'store=';
+		setSVGContentStorage('');
+	}
+	
+	//emptyLocalStorage();
+
+	/**
+	* Listen for unloading: If and only if opted in by the user, set the content
+	*   document and preferences into storage:
+	* 1. Prevent save warnings (since we're automatically saving unsaved
+	*       content into storage)
+	* 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
+	* 3. Use localStorage (where available) or cookies to set preferences.
+	*/
+	function setupBeforeUnloadListener () {
+		window.addEventListener('beforeunload', function(e) {
+			// Don't save anything unless the user opted in to storage
+			if (!document.cookie.match(/store=(?:prefsAndContent|prefsOnly)/)) {
+				return;
+			}
+			var key;
+			setSVGContentStorage(svgCanvas.getSvgString());
+
+			svgEditor.showSaveWarning = false;
+
+			var curConfig = svgEditor.curConfig;
+			for (key in curConfig) {
+				if (curConfig.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
+					var d,
+						storage = svgEditor.storage,
+						val = curConfig[key],
+						store = (val != undefined);
+					key = 'svg-edit-' + key;
+					
+					if (!store) {
+						continue;
+					}
+					if (storage) {
+						storage.setItem(key, val);
+					}
+					else if (window.widget) {
+						widget.setPreferenceForKey(val, key);
+					}
+					else {
+						d = new Date();
+						d.setTime(d.getTime() + 31536000000);
+						val = encodeURIComponent(val);
+						document.cookie = key + '=' + val + '; expires=' + d.toUTCString();
+					}
+				}
+			}
+		}, false);
+	}
+
+	var userStoragePref = 'noPrefsOrContent';
+
+		/*
+		// We could add locales here instead (and also thereby avoid the need
+		// to keep our content within "langReady"), but this would be less
+		// convenient for translators.
+		$.extend(uiStrings, {confirmSetStorage: {
+			message: "By default and where supported, SVG-Edit can store your editor "+
+			"preferences and SVG content locally on your machine so you do not "+
+			"need to add these back each time you load SVG-Edit. If, for privacy "+
+			"reasons, you do not wish to store this information on your machine, "+
+			"you can change away from the default option below.",
+			storagePrefsAndContent: "Store preferences and SVG content locally",
+			storagePrefsOnly: "Only store preferences locally",
+			storagePrefs: "Store preferences locally",
+			storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
+			storageNoPrefs: "Do not store my preferences locally",
+			rememberLabel: "Remember this choice?",
+			rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
+		}});
+		*/
+	
+	return {
+		name: 'storage',
+		langReady: function (lang, uiStrings) {
+			var storagePrompt = $.deparam.querystring(true).storagePrompt;
+			if (
+				// If explicitly set to always prompt (e.g., so a user can alter
+				//   their settings)...
+				storagePrompt === true ||
+				// ...or...the user hasn't visited page preventing storage prompt (for
+				// users who don't want to set cookies at all but don't want
+				// continual prompts)...
+				(storagePrompt !== false &&
+					// ...and user hasn't already indicated a desire for storage
+					!document.cookie.match(/store=(?:prefsAndContent|prefsOnly)/)
+				)
+				// ...then show the storage prompt.
+			) {
+				var options = [];
+				if (window.localStorage) {
+					options.unshift(
+						{value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent},
+						{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
+						{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
+					);
+				}
+				else {
+					options.unshift(
+						{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
+						{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
+					);
+				}
+
+				// Hack to temporarily provide a wide and high enough dialog
+				var oldContainerWidth = $('#dialog_container')[0].style.width,
+					oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
+					oldContentHeight = $('#dialog_content')[0].style.height,
+					oldContainerHeight = $('#dialog_container')[0].style.height;
+				$('#dialog_content')[0].style.height = '120px';
+				$('#dialog_container')[0].style.height = '170px';
+				$('#dialog_container')[0].style.width = '800px';
+				$('#dialog_container')[0].style.marginLeft = '-400px';
+
+				// Open select-with-checkbox dialog
+				$.select(
+					uiStrings.confirmSetStorage.message,
+					options,
+					function (pref, checked) {
+						// If the URL was configured to always insist on a prompt, if
+						//    the user does indicate a wish to store their info, we
+						//    don't want ask them again upon page refresh so move
+						//    them instead to a URL which does not always prompt
+						if (storagePrompt === true && pref && pref !== 'noPrefsOrContent') {
+							replaceStoragePrompt();
+							return;
+						}
+						if (pref && pref !== 'noPrefsOrContent') {
+							// Regardless of whether the user opted
+							// to remember the choice (and move to a URL which won't
+							// ask them again), we have to assume the user
+							// doesn't even want to remember their not wanting
+							// storage, so we don't set the cookie or continue on with
+							//  setting storage on beforeunload
+							document.cookie = 'store=' + pref; // 'prefsAndContent' | 'prefsOnly'
+						}
+						else {
+							if (emptyStorageOnDecline) {
+								emptyLocalStorage();
+							}
+							if (checked) {
+								// Open a URL which won't set storage and won't prompt user about storage
+								replaceStoragePrompt('false');
+							}
+						}
+						
+						// Store the preference in memory (not currently in use)
+						userStoragePref = pref;
+						// Reset width/height of dialog (e.g., for use by Export)
+						$('#dialog_container')[0].style.width = oldContainerWidth;
+						$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;				
+						$('#dialog_content')[0].style.height = oldContentHeight;
+						$('#dialog_container')[0].style.height = oldContainerHeight;
+						
+						// It should be enough to (conditionally) add to storage on
+						//   beforeunload, but if we wished to update immediately,
+						//   we might wish to try setting:
+						//       Editor.preventStorageAccessOnLoad = true;
+						//   and then call:
+						//       Editor.loadContentAndPrefs();
+						setupBeforeUnloadListener();
+						
+						Editor.storagePromptClosed = true;
+					},
+					null,
+					null,
+					{
+						label: uiStrings.confirmSetStorage.rememberLabel,
+						checked: false,
+						tooltip: uiStrings.confirmSetStorage.rememberTooltip
+					}
+				);
+			}
+			else {
+				setupBeforeUnloadListener();
+			}
+		}
+	};
+});

+ 293 - 0
main/inc/lib/svg-edit/extensions/ext-storage.js

@@ -0,0 +1,293 @@
+/*globals svgEditor, svgCanvas, $, widget*/
+/*jslint vars: true, eqeq: true, regexp: true, continue: true*/
+/*
+ * ext-storage.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2010 Brett Zamir
+ *
+ */
+/**
+* This extension allows automatic saving of the SVG canvas contents upon
+*  page unload (which can later be automatically retrieved upon future
+*  editor loads).
+*
+*  The functionality was originally part of the SVG Editor, but moved to a
+*  separate extension to make the setting behavior optional, and adapted
+*  to inform the user of its setting of local data.
+*/
+
+/*
+TODOS
+1. Revisit on whether to use $.pref over directly setting curConfig in all
+	extensions for a more public API (not only for extPath and imagePath,
+	but other currently used config in the extensions)
+2. We might provide control of storage settings through the UI besides the
+    initial (or URL-forced) dialog.
+*/
+svgEditor.addExtension('storage', function() {
+	// We could empty any already-set data for users when they decline storage,
+	//  but it would be a risk for users who wanted to store but accidentally
+	// said "no"; instead, we'll let those who already set it, delete it themselves;
+	// to change, set the "emptyStorageOnDecline" config setting to true
+	// in config.js.
+	var emptyStorageOnDecline = svgEditor.curConfig.emptyStorageOnDecline,
+		// When the code in svg-editor.js prevents local storage on load per
+		//  user request, we also prevent storing on unload here so as to
+		//  avoid third-party sites making XSRF requests or providing links
+		// which would cause the user's local storage not to load and then
+		// upon page unload (such as the user closing the window), the storage
+		//  would thereby be set with an empty value, erasing any of the
+		// user's prior work. To change this behavior so that no use of storage
+		// or adding of new storage takes place regardless of settings, set
+		// the "noStorageOnLoad" config setting to true in config.js.
+		noStorageOnLoad = svgEditor.curConfig.noStorageOnLoad,
+		forceStorage = svgEditor.curConfig.forceStorage,
+		storage = svgEditor.storage;
+
+	function replaceStoragePrompt (val) {
+		val = val ? 'storagePrompt=' + val : '';
+		var loc = top.location; // Allow this to work with the embedded editor as well
+		if (loc.href.indexOf('storagePrompt=') > -1) {
+			loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
+				return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
+			});
+		}
+		else {
+			loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val;
+		}
+	}
+	function setSVGContentStorage (val) {
+		if (storage) {
+			var name = 'svgedit-' + svgEditor.curConfig.canvasName;
+			if (!val) {
+				storage.removeItem(name);
+			}
+			else {
+				storage.setItem(name, val);
+			}
+		}
+	}
+	
+	function expireCookie (cookie) {
+		document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
+	}
+	
+	function removeStoragePrefCookie () {
+		expireCookie('store');
+	}
+	
+	function emptyStorage() {
+		setSVGContentStorage('');
+		var name;
+		for (name in svgEditor.curPrefs) {
+			if (svgEditor.curPrefs.hasOwnProperty(name)) {
+				name = 'svg-edit-' + name;
+				if (storage) {
+					storage.removeItem(name);
+				}
+				expireCookie(name);
+			}
+		}
+	}
+	
+//	emptyStorage();
+
+	/**
+	* Listen for unloading: If and only if opted in by the user, set the content
+	*   document and preferences into storage:
+	* 1. Prevent save warnings (since we're automatically saving unsaved
+	*       content into storage)
+	* 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
+	* 3. Use localStorage (where available) or cookies to set preferences.
+	*/
+	function setupBeforeUnloadListener () {
+		window.addEventListener('beforeunload', function(e) {
+			// Don't save anything unless the user opted in to storage
+			if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
+				return;
+			}
+			var key;
+			if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
+				setSVGContentStorage(svgCanvas.getSvgString());			
+			}
+
+			svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
+			// svgEditor.showSaveWarning = false;
+
+			var curPrefs = svgEditor.curPrefs;
+
+			for (key in curPrefs) {
+				if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
+					var val = curPrefs[key],
+						store = (val != undefined);
+					key = 'svg-edit-' + key;
+					if (!store) {
+						continue;
+					}
+					if (storage) {
+						storage.setItem(key, val);
+					}
+					else if (window.widget) {
+						widget.setPreferenceForKey(val, key);
+					}
+					else {
+						val = encodeURIComponent(val);
+						document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
+					}
+				}
+			}
+		}, false);
+	}
+
+	/*
+	// We could add locales here instead (and also thereby avoid the need
+	// to keep our content within "langReady"), but this would be less
+	// convenient for translators.
+	$.extend(uiStrings, {confirmSetStorage: {
+		message: "By default and where supported, SVG-Edit can store your editor "+
+		"preferences and SVG content locally on your machine so you do not "+
+		"need to add these back each time you load SVG-Edit. If, for privacy "+
+		"reasons, you do not wish to store this information on your machine, "+
+		"you can change away from the default option below.",
+		storagePrefsAndContent: "Store preferences and SVG content locally",
+		storagePrefsOnly: "Only store preferences locally",
+		storagePrefs: "Store preferences locally",
+		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
+		storageNoPrefs: "Do not store my preferences locally",
+		rememberLabel: "Remember this choice?",
+		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
+	}});
+	*/
+	var loaded = false;
+	return {
+		name: 'storage',
+		langReady: function (data) {
+			var // lang = data.lang,
+				uiStrings = data.uiStrings, // No need to store as dialog should only run once
+				storagePrompt = $.deparam.querystring(true).storagePrompt;
+
+			// No need to run this one-time dialog again just because the user
+			//   changes the language
+			if (loaded) {
+				return;
+			}
+			loaded = true;
+
+			// Note that the following can load even if "noStorageOnLoad" is
+			//   set to false; to avoid any chance of storage, avoid this
+			//   extension! (and to avoid using any prior storage, set the
+			//   config option "noStorageOnLoad" to true).
+			if (!forceStorage && (
+				// If the URL has been explicitly set to always prompt the
+				//  user (e.g., so one can be pointed to a URL where one
+				// can alter one's settings, say to prevent future storage)...
+				storagePrompt === true ||
+				(
+					// ...or...if the URL at least doesn't explicitly prevent a
+					//  storage prompt (as we use for users who
+					// don't want to set cookies at all but who don't want
+					// continual prompts about it)...
+					storagePrompt !== false &&
+					// ...and this user hasn't previously indicated a desire for storage
+					!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)
+				)
+				// ...then show the storage prompt.
+			)) {
+
+				var options = [];
+				if (storage) {
+					options.unshift(
+						{value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent},
+						{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
+						{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
+					);
+				}
+				else {
+					options.unshift(
+						{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
+						{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
+					);
+				}
+
+				// Hack to temporarily provide a wide and high enough dialog
+				var oldContainerWidth = $('#dialog_container')[0].style.width,
+					oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
+					oldContentHeight = $('#dialog_content')[0].style.height,
+					oldContainerHeight = $('#dialog_container')[0].style.height;
+				$('#dialog_content')[0].style.height = '120px';
+				$('#dialog_container')[0].style.height = '170px';
+				$('#dialog_container')[0].style.width = '800px';
+				$('#dialog_container')[0].style.marginLeft = '-400px';
+
+				// Open select-with-checkbox dialog
+				$.select(
+					uiStrings.confirmSetStorage.message,
+					options,
+					function (pref, checked) {
+						if (pref && pref !== 'noPrefsOrContent') {
+							// Regardless of whether the user opted
+							// to remember the choice (and move to a URL which won't
+							// ask them again), we have to assume the user
+							// doesn't even want to remember their not wanting
+							// storage, so we don't set the cookie or continue on with
+							//  setting storage on beforeunload
+							document.cookie = 'store=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'
+							// If the URL was configured to always insist on a prompt, if
+							//    the user does indicate a wish to store their info, we
+							//    don't want ask them again upon page refresh so move
+							//    them instead to a URL which does not always prompt
+							if (storagePrompt === true && checked) {
+								replaceStoragePrompt();
+								return;
+							}
+						}
+						else { // The user does not wish storage (or cancelled, which we treat equivalently)
+							removeStoragePrefCookie();
+							if (pref && // If the user explicitly expresses wish for no storage
+								emptyStorageOnDecline
+							) {
+								emptyStorage();
+							}
+							if (pref && checked) {
+								// Open a URL which won't set storage and won't prompt user about storage
+								replaceStoragePrompt('false');
+								return;
+							}
+						}
+
+						// Reset width/height of dialog (e.g., for use by Export)
+						$('#dialog_container')[0].style.width = oldContainerWidth;
+						$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;				
+						$('#dialog_content')[0].style.height = oldContentHeight;
+						$('#dialog_container')[0].style.height = oldContainerHeight;
+						
+						// It should be enough to (conditionally) add to storage on
+						//   beforeunload, but if we wished to update immediately,
+						//   we might wish to try setting:
+						//       svgEditor.setConfig({noStorageOnLoad: true});
+						//   and then call:
+						//       svgEditor.loadContentAndPrefs();
+						
+						// We don't check for noStorageOnLoad here because
+						//   the prompt gives the user the option to store data
+						setupBeforeUnloadListener();
+						
+						svgEditor.storagePromptClosed = true;
+					},
+					null,
+					null,
+					{
+						label: uiStrings.confirmSetStorage.rememberLabel,
+						checked: false,
+						tooltip: uiStrings.confirmSetStorage.rememberTooltip
+					}
+				);
+			}
+			else if (!noStorageOnLoad || forceStorage) {
+				setupBeforeUnloadListener();
+			}
+		}
+	};
+});

+ 67 - 0
main/inc/lib/svg-edit/extensions/ext-webappfind.js

@@ -0,0 +1,67 @@
+/*globals svgEditor*/
+/*
+Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind
+
+Todos:
+1. See WebAppFind Readme for SVG-related todos
+*/
+(function () {'use strict';
+
+var pathID,
+    saveMessage = 'webapp-save',
+    readMessage = 'webapp-read',
+    excludedMessages = [readMessage, saveMessage];
+
+window.addEventListener('message', function(e) {
+    if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively)
+        (!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below
+    ) {
+        return;
+    }
+    var svgString,
+        messageType = e.data[0];
+    switch (messageType) {
+        case 'webapp-view':
+            // Populate the contents
+            pathID = e.data[1];
+            
+            svgString = e.data[2];
+            svgEditor.loadFromString(svgString);
+            
+            /*if ($('#tool_save_file')) {
+                $('#tool_save_file').disabled = false;
+            }*/
+            break;
+        case 'webapp-save-end':
+            alert('save complete for pathID ' + e.data[1] + '!');
+            break;
+        default:
+            throw 'Unexpected mode';
+    }
+}, false);
+
+window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on)
+
+svgEditor.addExtension('WebAppFind', function() {
+
+    return {
+        name: 'WebAppFind',
+        svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg',
+        buttons: [{
+            id: 'webappfind_save', // 
+            type: 'app_menu',
+            title: 'Save Image back to Disk',
+            position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
+            events: {
+                click: function () {
+                    if (!pathID) { // Not ready yet as haven't received first payload
+                        return;
+                    }
+                    window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin);
+                }
+            }
+        }]
+    };
+});
+
+}());

+ 42 - 0
main/inc/lib/svg-edit/extensions/ext-xdomain-messaging.js

@@ -0,0 +1,42 @@
+/**
+* Should not be needed for same domain control (just call via child frame),
+*  but an API common for cross-domain and same domain use can be found
+*  in embedapi.js with a demo at embedapi.html
+*/
+/*globals svgEditor, svgCanvas*/
+svgEditor.addExtension('xdomain-messaging', function() {'use strict';
+	try {
+		window.addEventListener('message', function(e) {
+			// We accept and post strings for the sake of IE9 support
+			if (typeof e.data !== 'string' || e.data.charAt() === '|') {
+				return;
+			}
+			var cbid, name, args, message, allowedOrigins, data = JSON.parse(e.data);
+			if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') {
+				return;
+			}
+			// The default is not to allow any origins, including even the same domain or if run on a file:// URL
+			//  See config-sample.js for an example of how to configure
+			allowedOrigins = svgEditor.curConfig.allowedOrigins;
+			if (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) {
+				return;
+			}
+			cbid = data.id;
+			name = data.name;
+			args = data.args;
+			message = {
+				namespace: 'svg-edit',
+				id: cbid
+			};
+			try {
+				message.result = svgCanvas[name].apply(svgCanvas, args);
+			} catch (err) {
+				message.error = err.message;
+			}
+			e.source.postMessage(JSON.stringify(message), '*');
+		}, false);
+	}
+	catch (err) {
+		console.log('Error with xdomain message listener: ' + err);
+	}
+});

+ 30 - 50
main/inc/lib/svg-edit/extensions/eyedropper-icon.xml

@@ -1,70 +1,50 @@
+<!DOCTYPE html>
 <?php
 <?php
+exit;
 /*
 /*
  * fileopen.php
  * fileopen.php
  * To be used with ext-server_opensave.js for SVG-edit
  * To be used with ext-server_opensave.js for SVG-edit
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
- * Integrate svg-edit with Chamilo
- * @author Juan Carlos Ra�a Trabado
- * @since 25/september/2010
-*/
-
-require_once '../../../../inc/global.inc.php';//hack for chamilo
-require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
-
-api_protect_course_script();
-api_block_anonymous_users();
-
-if(!isset($_FILES['svg_file']['tmp_name'])) {
-	api_not_allowed(false);//from Chamilo
-	die();
-}
-
-
-?>
-<!doctype html>
-<?php
+ */
 	// Very minimal PHP file, all we do is Base64 encode the uploaded file and
 	// Very minimal PHP file, all we do is Base64 encode the uploaded file and
 	// return it to the editor
 	// return it to the editor
-	
+
+	$type = $_REQUEST['type'];
+	if (!in_array($type, array('load_svg', 'import_svg', 'import_img'))) {
+		exit;
+	}
+	require('allowedMimeTypes.php');
+
 	$file = $_FILES['svg_file']['tmp_name'];
 	$file = $_FILES['svg_file']['tmp_name'];
-	
+
 	$output = file_get_contents($file);
 	$output = file_get_contents($file);
-	
-	$type = $_REQUEST['type'];
-	
+
 	$prefix = '';
 	$prefix = '';
-	
+
 	// Make Data URL prefix for import image
 	// Make Data URL prefix for import image
-	if($type == 'import_img') {
+	if ($type == 'import_img') {
 		$info = getimagesize($file);
 		$info = getimagesize($file);
+		if (!in_array($info['mime'], $allowedMimeTypesBySuffix)) {
+			exit;
+		}
 		$prefix = 'data:' . $info['mime'] . ';base64,';
 		$prefix = 'data:' . $info['mime'] . ';base64,';
 	}
 	}
-	
-//check the extension
-$extension = explode('.', $file);
-$extension = strtolower($extension[sizeof($extension) - 1]);	
+?>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta charset="utf-8" />
+<script>
 
 
-//a bit title security
-$filename = addslashes(trim($file));
-$filename = Security::remove_XSS($filename);
-$filename = replace_dangerous_char($filename, 'strict');
-$filename = disable_dangerous_file($filename);	
-	
-//a bit mime security
-$current_mime = $_FILES['svg_file']['type'];
-$mime_svg='image/svg+xml';
-$mime_xml='application/xml';//hack for svg-edit because original code return application/xml; charset=us-ascii.
-		
-if(strpos($current_mime, $mime_svg)===false && strpos($current_mime, $mime_xml)===false && $extension=='svg'){
-	// die();//File extension does not match its content disabled to check into chamilo dev campus TODO:enabled
-}
+top.svgEditor.processFile("<?php
 
 
-?>
+// This should be safe since SVG edit does its own filtering (e.g., if an SVG file contains scripts)
+echo $prefix . base64_encode($output);
 
 
-<script>
-window.top.window.svgEditor.processFile("<?php echo $prefix . base64_encode($output); ?>", "<?php echo $type ?>");
-</script>
+?>", "<?php echo $type; ?>");
+</script>
+</head><body></body>
+</html>

+ 34 - 127
main/inc/lib/svg-edit/extensions/filesave.php

@@ -3,151 +3,58 @@
  * filesave.php
  * filesave.php
  * To be used with ext-server_opensave.js for SVG-edit
  * To be used with ext-server_opensave.js for SVG-edit
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Alexis Deveria
  * Copyright(c) 2010 Alexis Deveria
  *
  *
- * Integrate svg-edit with Chamilo
- * @author Juan Carlos Raña Trabado
- * @since 25/september/2010
-*/
-
-$language_file = array('document');//Chamilo load lang var
+ */
+exit;
+function encodeRFC5987ValueChars ($str) {
+	// See http://tools.ietf.org/html/rfc5987#section-3.2.1
+	// For better readability within headers, add back the characters escaped by rawurlencode but still allowable
+	// Although RFC3986 reserves "!" (%21), RFC5987 does not
+	return preg_replace_callback('@%(2[1346B]|5E|60|7C)@', function ($matches) {
+		return chr('0x' . $matches[1]);
+	}, rawurlencode($str));
+}
 
 
-//Chamilo load libraries
-require_once '../../../../inc/global.inc.php';
-require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
-require_once api_get_path(LIBRARY_PATH).'document.lib.php';
+require('allowedMimeTypes.php');
 
 
-//Add security from Chamilo
-api_protect_course_script();
-api_block_anonymous_users();
+$mime = !isset($_POST['mime']) || !in_array($_POST['mime'], $allowedMimeTypesBySuffix) ? 'image/svg+xml;charset=UTF-8' : $_POST['mime'];
 
 
-if(!isset($_POST['output_svg']) && !isset($_POST['output_png'])) {
-	api_not_allowed();//from Chamilo
-	die();
+if (!isset($_POST['output_svg']) && !isset($_POST['output_img'])) {
+	die('post fail');
 }
 }
 
 
 $file = '';
 $file = '';
-$suffix = isset($_POST['output_svg'])?'svg':'png';
 
 
-if(isset($_POST['filename']) && strlen($_POST['filename']) > 0) {
-	$file = $_POST['filename'];	
+$suffix = '.' . array_search($mime, $allowedMimeTypesBySuffix);
+
+if (isset($_POST['filename']) && strlen($_POST['filename']) > 0) {
+	$file = $_POST['filename'] . $suffix;
 } else {
 } else {
-	$file = 'image';
+	$file = 'image' . $suffix;
 }
 }
 
 
-if($suffix == 'svg') {
-	$mime = 'image/svg+xml';
-	$contents = rawurldecode($_POST['output_svg']);
+if ($suffix == '.svg') {
+	$contents = $_POST['output_svg'];
 } else {
 } else {
-	$mime = 'image/png';
-	$contents = $_POST['output_png'];
+	$contents = $_POST['output_img'];
 	$pos = (strpos($contents, 'base64,') + 7);
 	$pos = (strpos($contents, 'base64,') + 7);
 	$contents = base64_decode(substr($contents, $pos));
 	$contents = base64_decode(substr($contents, $pos));
 }
 }
 
 
-//get SVG-Edit values
-$filename=$file;//from svg-edit
-$extension=$suffix;// from svg-edit
-$content=$contents;//from svg-edit
-
-$title = Database::escape_string(str_replace('_',' ',$filename));
-
-//get Chamilo variables 
-
-if(!isset($_SESSION['draw_dir']) && !isset($_SESSION['whereami'])) {
-	api_not_allowed();//from Chamilo
-	die();	
-}
-
-$current_session_id = api_get_session_id();
-$groupId    =  api_get_group_id();
-$relativeUrlPath=$_SESSION['draw_dir'];
-$currentTool=$_SESSION['whereami'];
-$dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
-$saveDir=$dirBaseDocuments.$_SESSION['draw_dir'];
-
-//a bit title security
-
-$filename = addslashes(trim($filename));
-$filename = Security::remove_XSS($filename);
-$filename = replace_dangerous_char($filename, 'strict');
-$filename = disable_dangerous_file($filename);
-
-// a bit extension
-if ($suffix!= 'svg' && $suffix!= 'png'){
-	die();
-}
-
-//a bit mime security
-//comment because finfo seems stopping the save process files in some php vers.
-/*
-if (phpversion() >= '5.3' && extension_loaded('fileinfo')) {
-	$finfo = new finfo(FILEINFO_MIME);
-	$current_mime=$finfo->buffer($contents);
-	finfo_close($finfo);
-	$mime_png='image/png';//svg-edit return image/png; charset=binary 
-	$mime_svg='image/svg+xml';
-	$mime_xml='application/xml';//hack for svg-edit because original code return application/xml; charset=us-ascii. See	  
-	if(strpos($current_mime, $mime_png)===false && $extension=='png') {
-		die();//File extension does not match its content
-	} elseif(strpos($current_mime, $mime_svg)===false && strpos($current_mime, $mime_xml)===false && $extension=='svg') {
-		die();//File extension does not match its content
-	}
-}
-*/
-
-//checks if the file exists, then rename the new
-if (file_exists($saveDir.'/'.$filename.$i.'.'.$extension) && $currentTool=='document/createdraw'){
-	echo '<script language="javascript" type="text/javascript">';
-	echo 'alert("'.get_lang('FileExistsChangeToSave').'");';
-	echo '</script>';
-	die();
-} else {
-	$drawFileName = $filename.'.'.$extension;
-	$title = $title.'.'.$extension;
-}
-$documentPath = $saveDir.'/'.$drawFileName;
-
-//add new document to disk
-file_put_contents( $documentPath, $contents );
-
-if ($currentTool=='document/createdraw') {
-	//add document to database
-	$doc_id = add_document($_course, $relativeUrlPath.'/'.$drawFileName, 'file', filesize($documentPath), $title);
-	api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id);
-
-} elseif($currentTool=='document/editdraw') {
+header("Cache-Control: public");
+header("Content-Description: File Transfer");
 
 
-	//check path
-	if (!isset($_SESSION['draw_file'])){
-		api_not_allowed();//from Chamilo
-		die();
-	}
-	if ($_SESSION['draw_file'] == $drawFileName ){
-		$document_id = DocumentManager::get_document_id($_course, $relativeUrlPath.'/'.$drawFileName);
-		update_existing_document($_course, $document_id, filesize($documentPath), null);
-		api_item_property_update($_course, TOOL_DOCUMENT, $document_id, 'DocumentUpdated', $_user['user_id'], $groupId, null, null, null, $current_session_id);
-	} else {
-		//add a new document
-		$doc_id = add_document($_course, $relativeUrlPath.'/'.$drawFileName, 'file', filesize($documentPath), $title);
-		api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id);
-	}	
-}
+// See http://tools.ietf.org/html/rfc6266#section-4.1
+header("Content-Disposition: attachment; filename*=UTF-8''" . encodeRFC5987ValueChars(
+	// preg_replace('@[\\\\/:*?"<>|]@', '', $file) // If we wanted to strip Windows-disallowed characters server-side (but not a security issue, so we can strip client-side instead)
+	$file
+));
+header("Content-Type: " .  $mime);
+header("Content-Transfer-Encoding: binary");
 
 
-//clean sessions and add messages and return to current document list
-unset($_SESSION['draw_dir']);
-unset($_SESSION['draw_file']);
-unset($_SESSION['whereami']);
+echo $contents;
 
 
-echo '<script language="javascript" type="text/javascript">';
-if ($suffix!= 'png'){	
-	if ($relativeUrlPath==''){$relativeUrlPath='/';};    
-	$interbreadcrumb=api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&curdirpath='.	urlencode($relativeUrlPath);
-	echo 'alert("'.get_lang('FileSavedAs').': '.$title.'");';	
-	echo 'window.top.location.href="'.$interbreadcrumb.'";';//return to current document list
-} else {
-	echo 'alert("'.get_lang('FileExportAs').': '.$title.'");';
-}
-echo '</script>';
+?>

+ 27 - 0
main/inc/lib/svg-edit/extensions/foreignobject-icons.xml

@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <meta charset="utf-8" />
+    <title></title>
+		<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
+</head>
+<body>
+<form action="filesave.php">
+<input type="hidden" value="" name="output_svg" />
+</form>
+<script>
+/*globals $*/
+function xhtmlEscape(str) {'use strict';
+		return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways
+	}
+$('<form>').attr({
+					method: 'post',
+					action: 'filesave.php',
+					target: 'output_frame'
+				}).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape('<svg width="640" height="480" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"><script>alert(document.cookie);<\/script><\/svg>') + '">')
+					.appendTo('body')
+					.submit().remove();
+</script>
+
+</body>
+</html>

+ 70 - 0
main/inc/lib/svg-edit/extensions/grid-icon.xml

@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta charset="utf-8" />
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+</head>
+<body>
+
+<h1>Select an image:</h1>
+<a href="smiley.svg">smiley.svg</a>
+<br>
+<a href="../../images/logo.png">logo.png</a>
+
+<script>
+/*globals $*/
+/*jslint vars: true*/
+$('a').click(function() {'use strict';
+	var meta_str;
+	var href = this.href;
+	var target = window.parent;
+	// Convert Non-SVG images to data URL first 
+	// (this could also have been done server-side by the library)
+	if (this.href.indexOf('.svg') === -1) {
+
+		meta_str = JSON.stringify({
+			name: $(this).text(),
+			id: href
+		});
+		target.postMessage(meta_str, '*');
+
+		var img = new Image();
+		img.onload = function() {
+			var canvas = document.createElement('canvas');
+			canvas.width = this.width;
+			canvas.height = this.height;
+			// load the raster image into the canvas
+			canvas.getContext('2d').drawImage(this, 0, 0);
+			// retrieve the data: URL
+			var dataurl;
+			try {
+				dataurl = canvas.toDataURL();
+			} catch(err) {
+				// This fails in Firefox with file:// URLs :(
+				alert("Data URL conversion failed: " + err);
+				dataurl = "";
+			}
+			target.postMessage('|' + href + '|' + dataurl, '*');
+		};
+		img.src = href;
+	} else {
+		// Send metadata (also indicates file is about to be sent)
+		meta_str = JSON.stringify({
+			name: $(this).text(),
+			id: href
+		});
+		target.postMessage(meta_str, '*');
+		// Do ajax request for image's href value
+		$.get(href, function(data) {
+			data = '|' + href + '|' + data;
+			// This is where the magic happens!
+			target.postMessage(data, '*');
+			
+		}, 'html'); // 'html' is necessary to keep returned data as a string
+	}
+	return false;
+});
+
+</script>
+</body>
+</html>

+ 0 - 6
main/inc/lib/svg-edit/extensions/imagelib/smiley.svg

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 11 - 0
main/inc/lib/svg-edit/extensions/markers-icons.xml

@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+  <g id="tool_mathjax">
+    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 43 43">
+      <g id="svg_20" stroke="black" fill="black" transform="matrix(0.0510725, 0, 0, -0.0510725, 0, 37.4108)">
+        <path id="svg_21" stroke-width="10" d="m20.45372,122.639297q0,57 19,104t49,78.000015t67,52t70,31t63.000015,9l3,0q45,0 78,-22t33,-65q0,-90.000015 -111,-118.000015q-49.000015,-13 -134.000015,-14q-37,0 -38,-2q0,-2 -6,-35t-7,-58q0,-46.999996 21,-73.999996t63,-28t93.000015,19t92,65.999996q9,10 12,10q4,0 13,-9t10,-13.999996t-9,-16t-30,-27t-46,-31t-63,-25t-76.000015,-10q-79,0 -122,53t-44,125.999996zm334.000015,185.000015q-6,52 -68,52q-33.000015,0 -61.000015,-14t-45,-34t-29,-41t-16,-36.000015t-5,-19q0,-1 20,-1q113.000015,0 158.000015,24t46,69.000015z"/>
+        <path id="svg_22" stroke-width="10" d="m489.156433,571.236389q4.949707,29.698486 38.183716,68.589355t82.024414,39.597961q24.748657,0 45.254761,-12.727905t30.40564,-31.819824q29.698486,44.547729 71.417847,44.547729q26.162842,0 45.254761,-15.556335t19.79895,-41.719299q0,-20.506104 -9.899414,-33.234009t-19.091919,-15.556396t-16.263428,-2.82843q-13.435059,0 -21.920288,7.778198t-8.485352,20.506104q0,32.526917 35.355347,44.547729q-7.778198,9.192383 -28.284302,9.192383q-9.192383,0 -13.434937,-1.414246q-26.870117,-11.31366 -39.598022,-46.669006q-42.426392,-156.270599 -42.426392,-182.433502q0,-19.799011 11.313721,-28.284302t24.748657,-8.485291q26.162964,0 51.618896,23.334534t34.648193,57.275635q2.121338,7.071106 4.242676,7.778198t11.313721,1.414185l2.828369,0q10.606567,0 10.606567,-5.65686q0,-0.707092 -1.414185,-7.778137q-11.313721,-40.305115 -43.840576,-71.417786t-75.6604,-31.112732q-49.497559,0 -74.953369,44.547729q-28.991333,-43.840576 -66.468018,-43.840576l-4.242676,0q-34.648193,0 -49.497437,18.384766t-15.556396,38.890869q0,22.62738 13.435059,36.769531t31.819824,14.142151q30.405518,0 30.405518,-29.698486q0,-14.142151 -8.485229,-24.748718t-16.263428,-14.142151t-9.192383,-3.535522l-2.121338,-0.707153q0,-0.707092 4.242676,-2.828369t11.313599,-4.949768t13.435059,-2.121338q25.455811,0 43.840698,31.819824q6.363892,11.313721 16.263428,48.083252t19.79895,76.367523t11.313721,46.669006q3.535522,19.091919 3.535522,27.577209q0,19.79895 -10.606567,28.284241t-24.041626,8.485291q-28.284302,0 -53.033081,-22.627441t-34.648193,-57.982727q-1.414185,-6.363953 -3.535522,-7.071106t-11.313721,-1.414185l-9.899536,0q-4.242554,4.242615 -4.242554,7.778198z"/>
+      </g>
+	  </svg>
+  </g>
+  <g id="svg_eof"/>
+</svg>

+ 14 - 0
main/inc/lib/svg-edit/extensions/polygon-icons.svg

@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+	<g id="tool_polygon">
+     <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-1 -2 25 24">
+     	<defs>
+		<linearGradient y2="1" x2="1" y1="0.10156" x1="0.36328" id="svg_i22">
+			<stop stop-opacity="1" stop-color="#ffffff" offset="0"/>
+			<stop stop-opacity="1" stop-color="#666666" offset="1"/>
+		</linearGradient>
+		</defs>
+		<polygon points="6.09251,19.6032 0.577744,10.0516 6.09251,0.5 17.1217,0.5 22.6365,10.0516 17.1217,19.6032" stroke="#000000" fill="url(#svg_i22)"/>	 </svg>
+	</g>
+	
+	<g id="svg_eof"/>
+</svg>

Diferenças do arquivo suprimidas por serem muito extensas
+ 5 - 0
main/inc/lib/svg-edit/extensions/saved.svg


+ 16 - 0
main/inc/lib/svg-edit/extensions/savefile.php

@@ -0,0 +1,16 @@
+<?php
+	// You must first create a file "savefile_config.php" in this extensions directory and do whatever
+	//   checking of user credentials, etc. that you wish; otherwise anyone will be able to post SVG
+	//   files to your server which may cause disk space or possibly security problems
+  require('savefile_config.php');
+  if (!isset($_POST['output_svg'])) {
+		print "You must supply output_svg";
+		exit;
+	}
+	$svg = $_POST['output_svg'];
+	$filename = (isset($_POST['filename']) && !empty($_POST['filename']) ? preg_replace('@[\\\\/:*?"<>|]@u', '_', $_POST['filename']) : 'saved') . '.svg'; // These characters are indicated as prohibited by Windows
+
+	$fh = fopen($filename, 'w') or die("Can't open file");
+	fwrite($fh, $svg);
+	fclose($fh);
+?>

+ 166 - 0
main/inc/lib/svg-edit/extensions/savefile_config.php

@@ -0,0 +1,166 @@
+<?php
+/*
+ * filesave.php
+ * To be used with ext-server_opensave.js for SVG-edit
+ *
+ * Licensed under the Apache License, Version 2
+ *
+ * Copyright(c) 2010 Alexis Deveria
+ *
+ * Integrate svg-edit with Chamilo
+ * @author Juan Carlos Raña Trabado
+ * @since 25/september/2010
+*/
+
+$language_file = array('document');//Chamilo load lang var
+
+//Chamilo load libraries
+require_once '../../../../inc/global.inc.php';
+require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
+require_once api_get_path(LIBRARY_PATH).'document.lib.php';
+
+//Add security from Chamilo
+api_protect_course_script();
+api_block_anonymous_users();
+
+if(!isset($_POST['output_svg']) && !isset($_POST['output_png'])) {
+    api_not_allowed();//from Chamilo
+    die();
+}
+
+$file = '';
+$suffix = isset($_POST['output_svg'])?'svg':'png';
+
+if(isset($_POST['filename']) && strlen($_POST['filename']) > 0) {
+    $file = $_POST['filename'];
+} else {
+    $file = 'image';
+}
+
+if($suffix == 'svg') {
+    $mime = 'image/svg+xml';
+    $contents = rawurldecode($_POST['output_svg']);
+} else {
+    $mime = 'image/png';
+    $contents = $_POST['output_png'];
+    $pos = (strpos($contents, 'base64,') + 7);
+    $contents = base64_decode(substr($contents, $pos));
+}
+
+//get SVG-Edit values
+$filename=$file;//from svg-edit
+$extension=$suffix;// from svg-edit
+$content=$contents;//from svg-edit
+
+$title = Database::escape_string(str_replace('_',' ',$filename));
+
+//get Chamilo variables
+
+if(!isset($_SESSION['draw_dir']) && !isset($_SESSION['whereami'])) {
+    api_not_allowed();//from Chamilo
+    die();
+}
+
+$current_session_id = api_get_session_id();
+$groupId    =  api_get_group_id();
+$relativeUrlPath=$_SESSION['draw_dir'];
+$currentTool=$_SESSION['whereami'];
+$dirBaseDocuments = api_get_path(SYS_COURSE_PATH).$_course['path'].'/document';
+$saveDir=$dirBaseDocuments.$_SESSION['draw_dir'];
+
+//a bit title security
+
+$filename = addslashes(trim($filename));
+$filename = Security::remove_XSS($filename);
+$filename = replace_dangerous_char($filename, 'strict');
+$filename = disable_dangerous_file($filename);
+
+// a bit extension
+if ($suffix != 'svg' && $suffix != 'png') {
+    die();
+}
+
+//a bit mime security
+//comment because finfo seems stopping the save process files in some php vers.
+/*
+if (phpversion() >= '5.3' && extension_loaded('fileinfo')) {
+	$finfo = new finfo(FILEINFO_MIME);
+	$current_mime=$finfo->buffer($contents);
+	finfo_close($finfo);
+	$mime_png='image/png';//svg-edit return image/png; charset=binary
+	$mime_svg='image/svg+xml';
+	$mime_xml='application/xml';//hack for svg-edit because original code return application/xml; charset=us-ascii. See
+	if(strpos($current_mime, $mime_png)===false && $extension=='png') {
+		die();//File extension does not match its content
+	} elseif(strpos($current_mime, $mime_svg)===false && strpos($current_mime, $mime_xml)===false && $extension=='svg') {
+		die();//File extension does not match its content
+	}
+}
+*/
+
+//checks if the file exists, then rename the new
+if (file_exists($saveDir.'/'.$filename.$i.'.'.$extension) && $currentTool=='document/createdraw') {
+    $message = get_lang('FileExistsChangeToSave');
+    $params = array(
+        'message' => $message,
+        'url' => ''
+    );
+    echo json_encode($params);
+    exit;
+} else {
+    $drawFileName = $filename.'.'.$extension;
+    $title = $title.'.'.$extension;
+}
+
+$documentPath = $saveDir.'/'.$drawFileName;
+
+//add new document to disk
+file_put_contents( $documentPath, $contents );
+
+if ($currentTool=='document/createdraw') {
+    //add document to database
+    $doc_id = add_document($_course, $relativeUrlPath.'/'.$drawFileName, 'file', filesize($documentPath), $title);
+    api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id);
+
+} elseif($currentTool=='document/editdraw') {
+
+    //check path
+    if (!isset($_SESSION['draw_file'])){
+        api_not_allowed();//from Chamilo
+        die();
+    }
+    if ($_SESSION['draw_file'] == $drawFileName ){
+        $document_id = DocumentManager::get_document_id($_course, $relativeUrlPath.'/'.$drawFileName);
+        update_existing_document($_course, $document_id, filesize($documentPath), null);
+        api_item_property_update($_course, TOOL_DOCUMENT, $document_id, 'DocumentUpdated', $_user['user_id'], $groupId, null, null, null, $current_session_id);
+    } else {
+        //add a new document
+        $doc_id = add_document($_course, $relativeUrlPath.'/'.$drawFileName, 'file', filesize($documentPath), $title);
+        api_item_property_update($_course, TOOL_DOCUMENT, $doc_id, 'DocumentAdded', $_user['user_id'], $groupId, null, null, null, $current_session_id);
+    }
+}
+
+//clean sessions and add messages and return to current document list
+unset($_SESSION['draw_dir']);
+unset($_SESSION['draw_file']);
+unset($_SESSION['whereami']);
+
+if ($suffix != 'png') {
+    if ($relativeUrlPath == '') {
+        $relativeUrlPath = '/';
+    };
+    $url = api_get_path(WEB_CODE_PATH).'document/document.php?'.api_get_cidreq().'&curdirpath='.urlencode($relativeUrlPath);
+    $message = get_lang('FileSavedAs').': '.$title;
+    //echo 'alert("'.get_lang('FileSavedAs').': '.$title.'");';
+    //echo 'window.top.location.href="'.$interbreadcrumb.'";';//return to current document list
+} else {
+    $url = '';
+    $message = get_lang('FileExportAs').': '.$title;
+}
+
+$params = array(
+    'message' => $message,
+    'url' => $url
+);
+echo json_encode($params);
+exit;

+ 0 - 6
main/inc/lib/svg-edit/extensions/shapelib/animal.json

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 0 - 1
main/inc/lib/svg-edit/extensions/shapelib/math.json

@@ -5,7 +5,6 @@
 	"car_smart": "m28.92024,238.37814c-20.54175,-8.15092 -27.36674,-32.3504 -27.6178,-52.52942c-2.7836,-14.94118 14.71887,-25.93048 8.95686,-41.2937c-2.18657,-22.71175 4.68564,-45.20703 14.9548,-65.22043c0.32475,-12.85873 10.87969,-17.84956 22.37955,-17.11762c37.15603,-4.71741 74.98359,-4.84966 112.15372,-0.39277c22.18198,4.11681 39.85953,19.32546 58.61859,30.81274c11.63586,8.63808 25.21985,14.32888 36.92355,22.63131c12.64026,10.62529 24.51556,22.47708 33.27448,36.57193c3.15143,14.09033 7.38165,28.09947 9.54742,42.2829c4.39661,13.27223 -4.6037,21.62047 -11.41214,30.84103c-10.34,12.57306 -29.90723,17.53416 -44.71561,10.78313c-10.28528,-3.75465 -14.07077,-19.70746 -25.7968,-18.60466c-44.20906,-0.65964 -88.41812,-1.31926 -132.62719,-1.97884c-10.24168,13.44736 -24.40165,28.14365 -42.91705,26.05086c-4.02312,-0.33679 -7.97831,-1.33774 -11.7224,-2.83646z",
 	"car_smart": "m28.92024,238.37814c-20.54175,-8.15092 -27.36674,-32.3504 -27.6178,-52.52942c-2.7836,-14.94118 14.71887,-25.93048 8.95686,-41.2937c-2.18657,-22.71175 4.68564,-45.20703 14.9548,-65.22043c0.32475,-12.85873 10.87969,-17.84956 22.37955,-17.11762c37.15603,-4.71741 74.98359,-4.84966 112.15372,-0.39277c22.18198,4.11681 39.85953,19.32546 58.61859,30.81274c11.63586,8.63808 25.21985,14.32888 36.92355,22.63131c12.64026,10.62529 24.51556,22.47708 33.27448,36.57193c3.15143,14.09033 7.38165,28.09947 9.54742,42.2829c4.39661,13.27223 -4.6037,21.62047 -11.41214,30.84103c-10.34,12.57306 -29.90723,17.53416 -44.71561,10.78313c-10.28528,-3.75465 -14.07077,-19.70746 -25.7968,-18.60466c-44.20906,-0.65964 -88.41812,-1.31926 -132.62719,-1.97884c-10.24168,13.44736 -24.40165,28.14365 -42.91705,26.05086c-4.02312,-0.33679 -7.97831,-1.33774 -11.7224,-2.83646z",
 	"car": "m26.77284,183.48201c-8.08779,-6.80998 -23.25337,0.56996 -25.08215,-11.86069c-3.52016,-11.04616 7.23365,-19.6761 14.38957,-26.36473c12.51913,-6.23676 26.95447,-6.99092 40.49323,-9.84883c16.2238,-2.35439 33.11552,-4.36668 47.10119,-13.71207c15.9294,-9.9651 33.67083,-18.25834 52.86141,-18.11141c26.44141,-0.91634 53.7986,-0.02856 78.2453,11.26058c15.36688,6.93465 31.87709,10.4591 48.27711,13.85143c13.95395,1.83385 10.70889,16.88237 15.35007,26.15973c3.54291,10.65329 -4.11594,21.25732 -15.32654,21.59605c-11.85318,2.69405 -25.72552,2.95921 -34.00009,13.30453c-8.47623,9.38277 -23.69647,9.05888 -32.32811,0.09547c-3.56866,-2.21568 -5.9512,-7.58008 -10.70335,-6.65411c-44.31184,0.24008 -88.64653,-0.63266 -132.93902,0.78894c-11.57394,-0.92139 -16.38131,13.44077 -28.69251,12.44249c-6.30352,0.19554 -12.27285,-9.98318 -17.64611,-12.94739z",
 	"car": "m26.77284,183.48201c-8.08779,-6.80998 -23.25337,0.56996 -25.08215,-11.86069c-3.52016,-11.04616 7.23365,-19.6761 14.38957,-26.36473c12.51913,-6.23676 26.95447,-6.99092 40.49323,-9.84883c16.2238,-2.35439 33.11552,-4.36668 47.10119,-13.71207c15.9294,-9.9651 33.67083,-18.25834 52.86141,-18.11141c26.44141,-0.91634 53.7986,-0.02856 78.2453,11.26058c15.36688,6.93465 31.87709,10.4591 48.27711,13.85143c13.95395,1.83385 10.70889,16.88237 15.35007,26.15973c3.54291,10.65329 -4.11594,21.25732 -15.32654,21.59605c-11.85318,2.69405 -25.72552,2.95921 -34.00009,13.30453c-8.47623,9.38277 -23.69647,9.05888 -32.32811,0.09547c-3.56866,-2.21568 -5.9512,-7.58008 -10.70335,-6.65411c-44.31184,0.24008 -88.64653,-0.63266 -132.93902,0.78894c-11.57394,-0.92139 -16.38131,13.44077 -28.69251,12.44249c-6.30352,0.19554 -12.27285,-9.98318 -17.64611,-12.94739z",
 	"coud": "m193.50864,67.27344c-28.56444,0 -53.08249,14.81322 -65.08365,36.1982c-4.7932,-2.67596 -10.08009,-4.29625 -15.72245,-4.29625c-17.06268,0 -31.26126,13.72618 -35.64974,32.35901c-7.49058,-2.96072 -16.20005,-4.7533 -25.50328,-4.7533c-27.90971,0 -50.54951,15.27039 -50.54951,34.09579c0,16.99312 18.56764,30.96303 42.68829,33.54732c-1.08106,1.83421 -1.91961,3.65059 -1.91961,5.57599c0,18.02431 49.38134,32.72462 110.23999,32.72462c60.85864,0 110.24005,-14.70032 110.23999,-32.72462c0,-1.21274 -0.75272,-2.29501 -1.18832,-3.47357c2.66562,0.6629 5.30496,1.37115 8.22687,1.37115c16.28061,0.00005 29.5253,-11.06223 29.5253,-24.6806c0,-13.61838 -13.24469,-24.68059 -29.5253,-24.68059c-1.99515,0 -3.69165,0.68915 -5.57599,1.00551c1.64767,-5.44531 2.74228,-11.00153 2.74228,-16.91078c0,-36.04859 -32.63087,-65.35786 -72.94485,-65.35786z",
 	"coud": "m193.50864,67.27344c-28.56444,0 -53.08249,14.81322 -65.08365,36.1982c-4.7932,-2.67596 -10.08009,-4.29625 -15.72245,-4.29625c-17.06268,0 -31.26126,13.72618 -35.64974,32.35901c-7.49058,-2.96072 -16.20005,-4.7533 -25.50328,-4.7533c-27.90971,0 -50.54951,15.27039 -50.54951,34.09579c0,16.99312 18.56764,30.96303 42.68829,33.54732c-1.08106,1.83421 -1.91961,3.65059 -1.91961,5.57599c0,18.02431 49.38134,32.72462 110.23999,32.72462c60.85864,0 110.24005,-14.70032 110.23999,-32.72462c0,-1.21274 -0.75272,-2.29501 -1.18832,-3.47357c2.66562,0.6629 5.30496,1.37115 8.22687,1.37115c16.28061,0.00005 29.5253,-11.06223 29.5253,-24.6806c0,-13.61838 -13.24469,-24.68059 -29.5253,-24.68059c-1.99515,0 -3.69165,0.68915 -5.57599,1.00551c1.64767,-5.44531 2.74228,-11.00153 2.74228,-16.91078c0,-36.04859 -32.63087,-65.35786 -72.94485,-65.35786z",
-	"drop": "m101.50413,119.73441c-169.70167,149.53423 29.55369,277.04852 105.31838,71.70643l58.26123,-190.46983l-163.57961,118.7634z",
 	"drop": "m115.15536,295.759c-42.01334,-15.78687 -72.12711,-65.94934 -65.28346,-108.74701c4.3154,-26.98718 95.35947,-190.81818 103.3105,-185.90417c2.59511,1.60386 25.68835,39.79974 51.31831,84.87975c41.0565,72.21342 46.5999,85.67899 46.5999,113.19665c0,55.77716 -44.6394,101.46498 -98.23825,100.54555c-15.6409,-0.26834 -32.60906,-2.05518 -37.707,-3.97076zm42.09262,-28.05386c1.39066,-7.22116 -1.85785,-10.74289 -9.90955,-10.74289c-18.35065,0 -43.80598,-23.24161 -49.49309,-45.18889c-6.0666,-23.41179 -22.15186,-26.19615 -24.52774,-4.24574c-4.57746,42.29059 76.21872,100.22086 83.93037,60.17752z",
 	"drop": "m115.15536,295.759c-42.01334,-15.78687 -72.12711,-65.94934 -65.28346,-108.74701c4.3154,-26.98718 95.35947,-190.81818 103.3105,-185.90417c2.59511,1.60386 25.68835,39.79974 51.31831,84.87975c41.0565,72.21342 46.5999,85.67899 46.5999,113.19665c0,55.77716 -44.6394,101.46498 -98.23825,100.54555c-15.6409,-0.26834 -32.60906,-2.05518 -37.707,-3.97076zm42.09262,-28.05386c1.39066,-7.22116 -1.85785,-10.74289 -9.90955,-10.74289c-18.35065,0 -43.80598,-23.24161 -49.49309,-45.18889c-6.0666,-23.41179 -22.15186,-26.19615 -24.52774,-4.24574c-4.57746,42.29059 76.21872,100.22086 83.93037,60.17752z",
 	"electric_guitar": "m168.96899,1.09303c-2.62799,0.19977 -5.017,2.04496 -6.96899,4.55579c0.009,13.46278 -11.116,25.03858 -14.875,34.35928c2.30499,1.8475 1.13,2.9332 -1.03101,4.4286c-0.17,2.5165 0.468,4.9685 2.468,7.3554c-2.591,41.8755 -6.024,92.17889 -8.718,134.4599c6.14801,0.138 12.354,1.117 18.81201,0.687c-0.007,-32.55499 2.539,-84.562 3.282,-116.00749c-0.101,-10.2094 -0.504,-24.029 13.12399,-28.8618c-6.94499,-14.7833 5.922,-35.70095 -5.562,-40.97666c-0.146,-0.00122 -0.293,-0.00885 -0.438,0c-0.03099,0.00187 -0.062,-0.00236 -0.093,0l0,-0.00001zm11.692,171.76396c-4.715,6.66701 -11.79199,10.17 -14.146,13.60501c-5.37599,8.46799 -14.379,-3.16701 -26.89,2.99599c0.065,-1.02399 0.153,-2.172 0.21899,-3.20599c-0.07199,-0.002 -0.14699,0.00101 -0.21899,0c-6.659,1.013 -12.157,-7.713 -12.594,-15.44901c5.55199,-11.89 -14.242,-18.006 -19.5,-5.82899c-3.943,13.605 -0.41,27.51199 4.78201,40.672c5.933,16.162 -8.871,30.179 -13.2192,45.17601c-4.1375,9.502 -4.2709,20.46999 2.68719,29.192c9.486,13.58398 29.413,18.62799 47.563,18.758c3.23401,0.224 6.44801,0.414 9.68701,0.58499c57.61699,3.284 34.35399,-35.13699 25.282,-68.41299c-5.82201,-21.66299 1.48199,-36.38 6.269,-42.614c2.659,-7.35001 6.02899,-23 -9.92101,-15.472l0,-0.00101zm-34.567,-128.4203c2.43501,-11.918 -8.10399,0.709 0,0z",
 	"electric_guitar": "m168.96899,1.09303c-2.62799,0.19977 -5.017,2.04496 -6.96899,4.55579c0.009,13.46278 -11.116,25.03858 -14.875,34.35928c2.30499,1.8475 1.13,2.9332 -1.03101,4.4286c-0.17,2.5165 0.468,4.9685 2.468,7.3554c-2.591,41.8755 -6.024,92.17889 -8.718,134.4599c6.14801,0.138 12.354,1.117 18.81201,0.687c-0.007,-32.55499 2.539,-84.562 3.282,-116.00749c-0.101,-10.2094 -0.504,-24.029 13.12399,-28.8618c-6.94499,-14.7833 5.922,-35.70095 -5.562,-40.97666c-0.146,-0.00122 -0.293,-0.00885 -0.438,0c-0.03099,0.00187 -0.062,-0.00236 -0.093,0l0,-0.00001zm11.692,171.76396c-4.715,6.66701 -11.79199,10.17 -14.146,13.60501c-5.37599,8.46799 -14.379,-3.16701 -26.89,2.99599c0.065,-1.02399 0.153,-2.172 0.21899,-3.20599c-0.07199,-0.002 -0.14699,0.00101 -0.21899,0c-6.659,1.013 -12.157,-7.713 -12.594,-15.44901c5.55199,-11.89 -14.242,-18.006 -19.5,-5.82899c-3.943,13.605 -0.41,27.51199 4.78201,40.672c5.933,16.162 -8.871,30.179 -13.2192,45.17601c-4.1375,9.502 -4.2709,20.46999 2.68719,29.192c9.486,13.58398 29.413,18.62799 47.563,18.758c3.23401,0.224 6.44801,0.414 9.68701,0.58499c57.61699,3.284 34.35399,-35.13699 25.282,-68.41299c-5.82201,-21.66299 1.48199,-36.38 6.269,-42.614c2.659,-7.35001 6.02899,-23 -9.92101,-15.472l0,-0.00101zm-34.567,-128.4203c2.43501,-11.918 -8.10399,0.709 0,0z",
 	"guitar": "m158.45264,1.00012c-0.96039,0.00612 -1.8884,0.06411 -2.73161,0.18457c-4.49716,0.64245 -8.99768,2.5655 -8.99768,2.5655c0,0 0.00569,8.99612 -0.63676,15.42064c-0.64244,6.42453 -3.21147,17.34015 -3.21147,17.34015l3.15611,6.32144l0.05536,-1.172l10.62189,1.86414l0.94128,0.05537c0,0 1.28059,-1.28413 2.56551,-3.21148c1.2849,-1.92736 3.85747,-3.21148 3.85747,-3.21148c0,0 0.63675,-9.63641 0.63675,-16.70339c0,-7.06698 2.57472,-18.63212 2.57472,-18.63212c0,0 -4.66991,-0.84783 -8.83156,-0.82133zm-1.74417,42.52442l-10.62189,-0.58139l-0.05536,-0.11074l-5.5278,113.65688c0.19376,0.03734 0.44296,0.08304 0.44296,0.08304c0.14801,2.18161 0.8121,3.84209 1.8549,5.14021l11.84926,5.41707c0.3562,0.09476 0.71249,0.18806 1.07048,0.28609l1.28276,-123.83578l-0.29532,-0.05537zm-0.98744,123.89115l0,0.20302l-1.07048,-0.48911c-4.80661,-1.27875 -9.3821,-2.34575 -11.84926,-5.41707l-2.5009,-1.14432l0.20303,-4.07893c-2.16553,-0.41753 -15.40038,-2.83867 -20.1179,-0.47989c-5.13962,2.56979 -8.99552,6.42279 -10.28043,14.77466c-1.2849,8.3519 2.57119,23.77351 1.92873,34.05275c-0.64246,10.27924 -7.71416,19.91469 -10.92641,28.26657c-3.21227,8.35188 -6.4202,17.99007 -2.5655,32.12404c3.85472,14.13391 17.99164,23.77151 25.70107,26.9838c7.70942,3.21225 23.7631,5.14023 23.7631,5.14023c0,0 15.42752,2.58041 25.06432,1.93796c20.23672,-3.64624 28.72404,-15.65756 29.98303,-30.66595c1.259,-15.00839 -4.71521,-33.01251 -13.40884,-48.65207c-9.50552,-17.10013 8.59656,-39.76326 -0.76596,-52.52802c-9.74182,-13.28188 -16.9409,8.64334 -23.78156,3.87593c-2.77655,-1.93504 -6.09895,-3.00655 -9.37605,-3.90359z",
 	"guitar": "m158.45264,1.00012c-0.96039,0.00612 -1.8884,0.06411 -2.73161,0.18457c-4.49716,0.64245 -8.99768,2.5655 -8.99768,2.5655c0,0 0.00569,8.99612 -0.63676,15.42064c-0.64244,6.42453 -3.21147,17.34015 -3.21147,17.34015l3.15611,6.32144l0.05536,-1.172l10.62189,1.86414l0.94128,0.05537c0,0 1.28059,-1.28413 2.56551,-3.21148c1.2849,-1.92736 3.85747,-3.21148 3.85747,-3.21148c0,0 0.63675,-9.63641 0.63675,-16.70339c0,-7.06698 2.57472,-18.63212 2.57472,-18.63212c0,0 -4.66991,-0.84783 -8.83156,-0.82133zm-1.74417,42.52442l-10.62189,-0.58139l-0.05536,-0.11074l-5.5278,113.65688c0.19376,0.03734 0.44296,0.08304 0.44296,0.08304c0.14801,2.18161 0.8121,3.84209 1.8549,5.14021l11.84926,5.41707c0.3562,0.09476 0.71249,0.18806 1.07048,0.28609l1.28276,-123.83578l-0.29532,-0.05537zm-0.98744,123.89115l0,0.20302l-1.07048,-0.48911c-4.80661,-1.27875 -9.3821,-2.34575 -11.84926,-5.41707l-2.5009,-1.14432l0.20303,-4.07893c-2.16553,-0.41753 -15.40038,-2.83867 -20.1179,-0.47989c-5.13962,2.56979 -8.99552,6.42279 -10.28043,14.77466c-1.2849,8.3519 2.57119,23.77351 1.92873,34.05275c-0.64246,10.27924 -7.71416,19.91469 -10.92641,28.26657c-3.21227,8.35188 -6.4202,17.99007 -2.5655,32.12404c3.85472,14.13391 17.99164,23.77151 25.70107,26.9838c7.70942,3.21225 23.7631,5.14023 23.7631,5.14023c0,0 15.42752,2.58041 25.06432,1.93796c20.23672,-3.64624 28.72404,-15.65756 29.98303,-30.66595c1.259,-15.00839 -4.71521,-33.01251 -13.40884,-48.65207c-9.50552,-17.10013 8.59656,-39.76326 -0.76596,-52.52802c-9.74182,-13.28188 -16.9409,8.64334 -23.78156,3.87593c-2.77655,-1.93504 -6.09895,-3.00655 -9.37605,-3.90359z",

Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 0
main/inc/lib/svg-edit/extensions/shapelib/raphael.txt


+ 14 - 0
main/inc/lib/svg-edit/extensions/shapelib/raphael_2.json

@@ -0,0 +1,14 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+	<g id="tool_star">
+     <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-1 -1 26 26">
+     	<defs>
+		<linearGradient y2="1" x2="1" y1="0.10156" x1="0.36328" id="svg_i22">
+			<stop stop-opacity="1" stop-color="#ffffff" offset="0"/>
+			<stop stop-opacity="1" stop-color="#666666" offset="1"/>
+		</linearGradient>
+		</defs>
+		<polygon points="12.4062,1.55891 15.0578,9.39339 23.3283,9.49422 16.6965,14.4371 19.1564,22.3338 12.4062,17.5543 5.65596,22.3338 8.11588,14.4371 1.48406,9.49422 9.75455,9.39339" stroke="#000000" fill="url(#svg_i22)"/>	 </svg>
+	</g>
+	
+	<g id="svg_eof"/>
+</svg>

+ 23 - 0
main/inc/lib/svg-edit/extensions/webappfind-icon.svg

@@ -0,0 +1,23 @@
+<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
+<!--
+Copied from /editor/images/svg_edit_icons.svg#save but with id renamed, first stop-color changed to red, and SVG namespaces moved to root
+-->
+<g id="webappfind_save">
+	<svg viewBox="0 0 24 24">
+	 <defs>
+	  <linearGradient y2="0" x2="1" y1="0" x1="0" id="svg_41">
+	   <stop stop-opacity="1" stop-color="red" offset="0"/>
+	   <stop stop-opacity="1" stop-color="#d6d6d6" offset="1"/>
+	  </linearGradient>
+	  <linearGradient y2="0.875" x2="0.21484" y1="0.00391" x1="0.04297" id="svg_46">
+	   <stop stop-opacity="1" stop-color="#81bbf4" offset="0"/>
+	   <stop stop-opacity="1" stop-color="#376eb7" offset="1"/>
+	  </linearGradient>
+	 </defs>
+	   <path stroke="#202020" fill="#e0e0e0" id="svg_21" d="m1.51669,22.3458l21.13245,-0.10111l0,-6.06673l-2.62892,-9.80789l-16.27907,0.10111l-2.32558,9.20121l0.10111,6.67341z"/>
+	   <rect stroke="#efefef" fill="url(#svg_41)" id="svg_32" height="4.75108" width="19.21031" y="16.58227" x="2.42667"/>
+	   <path stroke="#ffffff" fill="#c0c0c0" id="svg_42" d="m4.55005,11.12235l0.70779,-2.83114l13.04348,0l0.70779,3.13448c-0.70779,2.52781 -4.04479,3.84227 -7.17897,3.84227c-2.72977,0 -6.37007,-1.41557 -7.28008,-4.1456z"/>
+	  <path stroke="#285582" fill="url(#svg_46)" id="svg_45" d="m7.14286,9.74903l5.21236,5.79151l5.50193,-5.88803l-2.50965,-0.09653l0,-2.79923c0,-2.3166 -2.3166,-5.59846 -6.56371,-5.59846c-4.05405,0 -6.27413,3.37838 -6.56371,6.75676c0.48263,-1.5444 2.7027,-4.53668 4.44015,-4.44015c2.12355,-0.09653 2.79923,1.64093 2.79923,3.37838l0.09653,2.79923l-2.41313,0.09653z"/>
+	</svg>
+</g>
+</svg>

+ 92 - 80
main/inc/lib/svg-edit/history.js

@@ -1,7 +1,9 @@
+/*globals svgedit*/
+/*jslint vars: true, eqeq: true, continue: true, forin: true*/
 /**
 /**
  * Package: svedit.history
  * Package: svedit.history
  *
  *
- * Licensed under the Apache License, Version 2
+ * Licensed under the MIT License
  *
  *
  * Copyright(c) 2010 Jeff Schiller
  * Copyright(c) 2010 Jeff Schiller
  */
  */
@@ -11,17 +13,13 @@
 // 2) svgtransformlist.js
 // 2) svgtransformlist.js
 // 3) svgutils.js
 // 3) svgutils.js
 
 
-var svgedit = svgedit || {};
-
-(function() {
+(function() {'use strict';
 
 
 if (!svgedit.history) {
 if (!svgedit.history) {
 	svgedit.history = {};
 	svgedit.history = {};
 }
 }
 
 
 // Group: Undo/Redo history management
 // Group: Undo/Redo history management
-
-
 svgedit.history.HistoryEventTypes = {
 svgedit.history.HistoryEventTypes = {
 	BEFORE_APPLY: 'before_apply',
 	BEFORE_APPLY: 'before_apply',
 	AFTER_APPLY: 'after_apply',
 	AFTER_APPLY: 'after_apply',
@@ -32,10 +30,9 @@ svgedit.history.HistoryEventTypes = {
 var removedElements = {};
 var removedElements = {};
 
 
 /**
 /**
- * Interface: svgedit.history.HistoryCommand
  * An interface that all command objects must implement.
  * An interface that all command objects must implement.
- *
- * interface svgedit.history.HistoryCommand {
+ * @typedef svgedit.history.HistoryCommand
+ * @type {object}
  *   void apply(svgedit.history.HistoryEventHandler);
  *   void apply(svgedit.history.HistoryEventHandler);
  *   void unapply(svgedit.history.HistoryEventHandler);
  *   void unapply(svgedit.history.HistoryEventHandler);
  *   Element[] elements();
  *   Element[] elements();
@@ -55,15 +52,15 @@ var removedElements = {};
  * command is an object fulfilling the HistoryCommand interface.
  * command is an object fulfilling the HistoryCommand interface.
  */
  */
 
 
-// Class: svgedit.history.MoveElementCommand
-// implements svgedit.history.HistoryCommand
-// History command for an element that had its DOM position changed
-//
-// Parameters:
-// elem - The DOM element that was moved
-// oldNextSibling - The element's next sibling before it was moved
-// oldParent - The element's parent before it was moved
-// text - An optional string visible to user related to this change
+/**
+ * @class svgedit.history.MoveElementCommand
+ * @implements svgedit.history.HistoryCommand
+ * History command for an element that had its DOM position changed
+ * @param {Element} elem - The DOM element that was moved
+ * @param {Element} oldNextSibling - The element's next sibling before it was moved
+ * @param {Element} oldParent - The element's parent before it was moved
+ * @param {string} [text] - An optional string visible to user related to this change
+*/
 svgedit.history.MoveElementCommand = function(elem, oldNextSibling, oldParent, text) {
 svgedit.history.MoveElementCommand = function(elem, oldNextSibling, oldParent, text) {
 	this.elem = elem;
 	this.elem = elem;
 	this.text = text ? ("Move " + elem.tagName + " to " + text) : ("Move " + elem.tagName);
 	this.text = text ? ("Move " + elem.tagName + " to " + text) : ("Move " + elem.tagName);
@@ -72,16 +69,17 @@ svgedit.history.MoveElementCommand = function(elem, oldNextSibling, oldParent, t
 	this.newNextSibling = elem.nextSibling;
 	this.newNextSibling = elem.nextSibling;
 	this.newParent = elem.parentNode;
 	this.newParent = elem.parentNode;
 };
 };
-svgedit.history.MoveElementCommand.type = function() { return 'svgedit.history.MoveElementCommand'; }
+svgedit.history.MoveElementCommand.type = function() { return 'svgedit.history.MoveElementCommand'; };
 svgedit.history.MoveElementCommand.prototype.type = svgedit.history.MoveElementCommand.type;
 svgedit.history.MoveElementCommand.prototype.type = svgedit.history.MoveElementCommand.type;
 
 
-// Function: svgedit.history.MoveElementCommand.getText
 svgedit.history.MoveElementCommand.prototype.getText = function() {
 svgedit.history.MoveElementCommand.prototype.getText = function() {
 	return this.text;
 	return this.text;
 };
 };
 
 
-// Function: svgedit.history.MoveElementCommand.apply
-// Re-positions the element
+/**
+ * Re-positions the element
+ * @param {handleHistoryEvent: function}
+*/
 svgedit.history.MoveElementCommand.prototype.apply = function(handler) {
 svgedit.history.MoveElementCommand.prototype.apply = function(handler) {
 	// TODO(codedread): Refactor this common event code into a base HistoryCommand class.
 	// TODO(codedread): Refactor this common event code into a base HistoryCommand class.
 	if (handler) {
 	if (handler) {
@@ -95,13 +93,15 @@ svgedit.history.MoveElementCommand.prototype.apply = function(handler) {
 	}
 	}
 };
 };
 
 
-// Function: svgedit.history.MoveElementCommand.unapply
-// Positions the element back to its original location
+/**
+ * Positions the element back to its original location
+ * @param {handleHistoryEvent: function}
+*/
 svgedit.history.MoveElementCommand.prototype.unapply = function(handler) {
 svgedit.history.MoveElementCommand.prototype.unapply = function(handler) {
 	if (handler) {
 	if (handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 	}
 	}
-		
+
 	this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling);
 	this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling);
 
 
 	if (handler) {
 	if (handler) {
@@ -129,7 +129,7 @@ svgedit.history.InsertElementCommand = function(elem, text) {
 	this.parent = elem.parentNode;
 	this.parent = elem.parentNode;
 	this.nextSibling = this.elem.nextSibling;
 	this.nextSibling = this.elem.nextSibling;
 };
 };
-svgedit.history.InsertElementCommand.type = function() { return 'svgedit.history.InsertElementCommand'; }
+svgedit.history.InsertElementCommand.type = function() { return 'svgedit.history.InsertElementCommand'; };
 svgedit.history.InsertElementCommand.prototype.type = svgedit.history.InsertElementCommand.type;
 svgedit.history.InsertElementCommand.prototype.type = svgedit.history.InsertElementCommand.type;
 
 
 // Function: svgedit.history.InsertElementCommand.getText
 // Function: svgedit.history.InsertElementCommand.getText
@@ -139,12 +139,12 @@ svgedit.history.InsertElementCommand.prototype.getText = function() {
 
 
 // Function: svgedit.history.InsertElementCommand.apply
 // Function: svgedit.history.InsertElementCommand.apply
 // Re-Inserts the new element
 // Re-Inserts the new element
-svgedit.history.InsertElementCommand.prototype.apply = function(handler) { 
+svgedit.history.InsertElementCommand.prototype.apply = function(handler) {
 	if (handler) {
 	if (handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 	}
 	}
 
 
-	this.elem = this.parent.insertBefore(this.elem, this.nextSibling); 
+	this.elem = this.parent.insertBefore(this.elem, this.nextSibling);
 
 
 	if (handler) {
 	if (handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
@@ -191,7 +191,7 @@ svgedit.history.RemoveElementCommand = function(elem, oldNextSibling, oldParent,
 	// special hack for webkit: remove this element's entry in the svgTransformLists map
 	// special hack for webkit: remove this element's entry in the svgTransformLists map
 	svgedit.transformlist.removeElementFromListMap(elem);
 	svgedit.transformlist.removeElementFromListMap(elem);
 };
 };
-svgedit.history.RemoveElementCommand.type = function() { return 'svgedit.history.RemoveElementCommand'; }
+svgedit.history.RemoveElementCommand.type = function() { return 'svgedit.history.RemoveElementCommand'; };
 svgedit.history.RemoveElementCommand.prototype.type = svgedit.history.RemoveElementCommand.type;
 svgedit.history.RemoveElementCommand.prototype.type = svgedit.history.RemoveElementCommand.type;
 
 
 // Function: svgedit.history.RemoveElementCommand.getText
 // Function: svgedit.history.RemoveElementCommand.getText
@@ -201,7 +201,7 @@ svgedit.history.RemoveElementCommand.prototype.getText = function() {
 
 
 // Function: RemoveElementCommand.apply
 // Function: RemoveElementCommand.apply
 // Re-removes the new element
 // Re-removes the new element
-svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {	
+svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {
 	if (handler) {
 	if (handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 	}
 	}
@@ -217,14 +217,16 @@ svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {
 
 
 // Function: RemoveElementCommand.unapply
 // Function: RemoveElementCommand.unapply
 // Re-adds the new element
 // Re-adds the new element
-svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) { 
+svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
 	if (handler) {
 	if (handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 	}
 	}
 
 
 	svgedit.transformlist.removeElementFromListMap(this.elem);
 	svgedit.transformlist.removeElementFromListMap(this.elem);
-	if(this.nextSibling == null) {
-		if(window.console) console.log('Error: reference element was lost');
+	if (this.nextSibling == null) {
+		if (window.console) {
+            console.log('Error: reference element was lost');
+        }
 	}
 	}
 	this.parent.insertBefore(this.elem, this.nextSibling);
 	this.parent.insertBefore(this.elem, this.nextSibling);
 
 
@@ -243,7 +245,7 @@ svgedit.history.RemoveElementCommand.prototype.elements = function() {
 
 
 // Class: svgedit.history.ChangeElementCommand
 // Class: svgedit.history.ChangeElementCommand
 // implements svgedit.history.HistoryCommand
 // implements svgedit.history.HistoryCommand
-// History command to make a change to an element. 
+// History command to make a change to an element.
 // Usually an attribute change, but can also be textcontent.
 // Usually an attribute change, but can also be textcontent.
 //
 //
 // Parameters:
 // Parameters:
@@ -255,13 +257,14 @@ svgedit.history.ChangeElementCommand = function(elem, attrs, text) {
 	this.text = text ? ("Change " + elem.tagName + " " + text) : ("Change " + elem.tagName);
 	this.text = text ? ("Change " + elem.tagName + " " + text) : ("Change " + elem.tagName);
 	this.newValues = {};
 	this.newValues = {};
 	this.oldValues = attrs;
 	this.oldValues = attrs;
-	for (var attr in attrs) {
-		if (attr == "#text") this.newValues[attr] = elem.textContent;
-		else if (attr == "#href") this.newValues[attr] = svgedit.utilities.getHref(elem);
-		else this.newValues[attr] = elem.getAttribute(attr);
+	var attr;
+	for (attr in attrs) {
+		if (attr == "#text") {this.newValues[attr] = elem.textContent;}
+		else if (attr == "#href") {this.newValues[attr] = svgedit.utilities.getHref(elem);}
+		else {this.newValues[attr] = elem.getAttribute(attr);}
 	}
 	}
 };
 };
-svgedit.history.ChangeElementCommand.type = function() { return 'svgedit.history.ChangeElementCommand'; }
+svgedit.history.ChangeElementCommand.type = function() { return 'svgedit.history.ChangeElementCommand'; };
 svgedit.history.ChangeElementCommand.prototype.type = svgedit.history.ChangeElementCommand.type;
 svgedit.history.ChangeElementCommand.prototype.type = svgedit.history.ChangeElementCommand.type;
 
 
 // Function: svgedit.history.ChangeElementCommand.getText
 // Function: svgedit.history.ChangeElementCommand.getText
@@ -277,11 +280,12 @@ svgedit.history.ChangeElementCommand.prototype.apply = function(handler) {
 	}
 	}
 
 
 	var bChangedTransform = false;
 	var bChangedTransform = false;
-	for(var attr in this.newValues ) {
+	var attr;
+	for (attr in this.newValues ) {
 		if (this.newValues[attr]) {
 		if (this.newValues[attr]) {
-			if (attr == "#text") this.elem.textContent = this.newValues[attr];
-			else if (attr == "#href") svgedit.utilities.setHref(this.elem, this.newValues[attr])
-			else this.elem.setAttribute(attr, this.newValues[attr]);
+			if (attr == "#text") {this.elem.textContent = this.newValues[attr];}
+			else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.newValues[attr]);}
+			else {this.elem.setAttribute(attr, this.newValues[attr]);}
 		}
 		}
 		else {
 		else {
 			if (attr == "#text") {
 			if (attr == "#text") {
@@ -297,9 +301,11 @@ svgedit.history.ChangeElementCommand.prototype.apply = function(handler) {
 	}
 	}
 
 
 	// relocate rotational transform, if necessary
 	// relocate rotational transform, if necessary
-	if(!bChangedTransform) {
+	if (!bChangedTransform) {
 		var angle = svgedit.utilities.getRotationAngle(this.elem);
 		var angle = svgedit.utilities.getRotationAngle(this.elem);
 		if (angle) {
 		if (angle) {
+			// TODO: These instances of elem either need to be declared as global
+			//				(which would not be good for conflicts) or declare/use this.elem
 			var bbox = elem.getBBox();
 			var bbox = elem.getBBox();
 			var cx = bbox.x + bbox.width/2,
 			var cx = bbox.x + bbox.width/2,
 				cy = bbox.y + bbox.height/2;
 				cy = bbox.y + bbox.height/2;
@@ -325,22 +331,25 @@ svgedit.history.ChangeElementCommand.prototype.unapply = function(handler) {
 	}
 	}
 
 
 	var bChangedTransform = false;
 	var bChangedTransform = false;
-	for(var attr in this.oldValues ) {
+	var attr;
+	for (attr in this.oldValues ) {
 		if (this.oldValues[attr]) {
 		if (this.oldValues[attr]) {
-			if (attr == "#text") this.elem.textContent = this.oldValues[attr];
-			else if (attr == "#href") svgedit.utilities.setHref(this.elem, this.oldValues[attr]);
-			else this.elem.setAttribute(attr, this.oldValues[attr]);
+			if (attr == "#text") {this.elem.textContent = this.oldValues[attr];}
+			else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.oldValues[attr]);}
+			else {
+				this.elem.setAttribute(attr, this.oldValues[attr]);
+			}
 		}
 		}
 		else {
 		else {
 			if (attr == "#text") {
 			if (attr == "#text") {
 				this.elem.textContent = "";
 				this.elem.textContent = "";
 			}
 			}
-			else this.elem.removeAttribute(attr);
+			else {this.elem.removeAttribute(attr);}
 		}
 		}
 		if (attr == "transform") { bChangedTransform = true; }
 		if (attr == "transform") { bChangedTransform = true; }
 	}
 	}
 	// relocate rotational transform, if necessary
 	// relocate rotational transform, if necessary
-	if(!bChangedTransform) {
+	if (!bChangedTransform) {
 		var angle = svgedit.utilities.getRotationAngle(this.elem);
 		var angle = svgedit.utilities.getRotationAngle(this.elem);
 		if (angle) {
 		if (angle) {
 			var bbox = elem.getBBox();
 			var bbox = elem.getBBox();
@@ -385,7 +394,7 @@ svgedit.history.BatchCommand = function(text) {
 	this.text = text || "Batch Command";
 	this.text = text || "Batch Command";
 	this.stack = [];
 	this.stack = [];
 };
 };
-svgedit.history.BatchCommand.type = function() { return 'svgedit.history.BatchCommand'; }
+svgedit.history.BatchCommand.type = function() { return 'svgedit.history.BatchCommand'; };
 svgedit.history.BatchCommand.prototype.type = svgedit.history.BatchCommand.type;
 svgedit.history.BatchCommand.prototype.type = svgedit.history.BatchCommand.type;
 
 
 // Function: svgedit.history.BatchCommand.getText
 // Function: svgedit.history.BatchCommand.getText
@@ -400,8 +409,9 @@ svgedit.history.BatchCommand.prototype.apply = function(handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
 	}
 	}
 
 
-	var len = this.stack.length;
-	for (var i = 0; i < len; ++i) {
+	var i,
+		len = this.stack.length;
+	for (i = 0; i < len; ++i) {
 		this.stack[i].apply(handler);
 		this.stack[i].apply(handler);
 	}
 	}
 
 
@@ -417,7 +427,8 @@ svgedit.history.BatchCommand.prototype.unapply = function(handler) {
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 		handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
 	}
 	}
 
 
-	for (var i = this.stack.length-1; i >= 0; i--) {
+	var i;
+	for (i = this.stack.length-1; i >= 0; i--) {
 		this.stack[i].unapply(handler);
 		this.stack[i].unapply(handler);
 	}
 	}
 
 
@@ -435,7 +446,7 @@ svgedit.history.BatchCommand.prototype.elements = function() {
 		var thisElems = this.stack[cmd].elements();
 		var thisElems = this.stack[cmd].elements();
 		var elem = thisElems.length;
 		var elem = thisElems.length;
 		while (elem--) {
 		while (elem--) {
-			if (elems.indexOf(thisElems[elem]) == -1) elems.push(thisElems[elem]);
+			if (elems.indexOf(thisElems[elem]) == -1) {elems.push(thisElems[elem]);}
 		}
 		}
 	}
 	}
 	return elems;
 	return elems;
@@ -453,7 +464,7 @@ svgedit.history.BatchCommand.prototype.addSubCommand = function(cmd) {
 // Function: svgedit.history.BatchCommand.isEmpty
 // Function: svgedit.history.BatchCommand.isEmpty
 // Returns a boolean indicating whether or not the batch command is empty
 // Returns a boolean indicating whether or not the batch command is empty
 svgedit.history.BatchCommand.prototype.isEmpty = function() {
 svgedit.history.BatchCommand.prototype.isEmpty = function() {
-	return this.stack.length == 0;
+	return this.stack.length === 0;
 };
 };
 
 
 
 
@@ -471,7 +482,7 @@ svgedit.history.UndoManager = function(historyEventHandler) {
 	this.undoChangeStackPointer = -1;
 	this.undoChangeStackPointer = -1;
 	this.undoableChangeStack = [];
 	this.undoableChangeStack = [];
 };
 };
-	
+
 // Function: svgedit.history.UndoManager.resetUndoStack
 // Function: svgedit.history.UndoManager.resetUndoStack
 // Resets the undo stack, effectively clearing the undo/redo history
 // Resets the undo stack, effectively clearing the undo/redo history
 svgedit.history.UndoManager.prototype.resetUndoStack = function() {
 svgedit.history.UndoManager.prototype.resetUndoStack = function() {
@@ -480,30 +491,30 @@ svgedit.history.UndoManager.prototype.resetUndoStack = function() {
 };
 };
 
 
 // Function: svgedit.history.UndoManager.getUndoStackSize
 // Function: svgedit.history.UndoManager.getUndoStackSize
-// Returns: 
+// Returns:
 // Integer with the current size of the undo history stack
 // Integer with the current size of the undo history stack
 svgedit.history.UndoManager.prototype.getUndoStackSize = function() {
 svgedit.history.UndoManager.prototype.getUndoStackSize = function() {
 	return this.undoStackPointer;
 	return this.undoStackPointer;
 };
 };
 
 
 // Function: svgedit.history.UndoManager.getRedoStackSize
 // Function: svgedit.history.UndoManager.getRedoStackSize
-// Returns: 
+// Returns:
 // Integer with the current size of the redo history stack
 // Integer with the current size of the redo history stack
 svgedit.history.UndoManager.prototype.getRedoStackSize = function() {
 svgedit.history.UndoManager.prototype.getRedoStackSize = function() {
 	return this.undoStack.length - this.undoStackPointer;
 	return this.undoStack.length - this.undoStackPointer;
 };
 };
 
 
 // Function: svgedit.history.UndoManager.getNextUndoCommandText
 // Function: svgedit.history.UndoManager.getNextUndoCommandText
-// Returns: 
+// Returns:
 // String associated with the next undo command
 // String associated with the next undo command
-svgedit.history.UndoManager.prototype.getNextUndoCommandText = function() { 
+svgedit.history.UndoManager.prototype.getNextUndoCommandText = function() {
 	return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer-1].getText() : "";
 	return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer-1].getText() : "";
 };
 };
 
 
 // Function: svgedit.history.UndoManager.getNextRedoCommandText
 // Function: svgedit.history.UndoManager.getNextRedoCommandText
-// Returns: 
+// Returns:
 // String associated with the next redo command
 // String associated with the next redo command
-svgedit.history.UndoManager.prototype.getNextRedoCommandText = function() { 
+svgedit.history.UndoManager.prototype.getNextRedoCommandText = function() {
 	return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : "";
 	return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : "";
 };
 };
 
 
@@ -516,7 +527,7 @@ svgedit.history.UndoManager.prototype.undo = function() {
 	}
 	}
 };
 };
 
 
-// Function: svgedit.history.UndoManager.redo		
+// Function: svgedit.history.UndoManager.redo
 // Performs a redo step
 // Performs a redo step
 svgedit.history.UndoManager.prototype.redo = function() {
 svgedit.history.UndoManager.prototype.redo = function() {
 	if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
 	if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
@@ -524,18 +535,18 @@ svgedit.history.UndoManager.prototype.redo = function() {
 		cmd.apply(this.handler_);
 		cmd.apply(this.handler_);
 	}
 	}
 };
 };
-	
+
 // Function: svgedit.history.UndoManager.addCommandToHistory
 // Function: svgedit.history.UndoManager.addCommandToHistory
 // Adds a command object to the undo history stack
 // Adds a command object to the undo history stack
 //
 //
-// Parameters: 
+// Parameters:
 // cmd - The command object to add
 // cmd - The command object to add
 svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) {
 svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) {
 	// FIXME: we MUST compress consecutive text changes to the same element
 	// FIXME: we MUST compress consecutive text changes to the same element
 	// (right now each keystroke is saved as a separate command that includes the
 	// (right now each keystroke is saved as a separate command that includes the
 	// entire text contents of the text element)
 	// entire text contents of the text element)
 	// TODO: consider limiting the history that we store here (need to do some slicing)
 	// TODO: consider limiting the history that we store here (need to do some slicing)
-	
+
 	// if our stack pointer is not at the end, then we have to remove
 	// if our stack pointer is not at the end, then we have to remove
 	// all commands after the pointer and insert the new command
 	// all commands after the pointer and insert the new command
 	if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
 	if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
@@ -553,7 +564,7 @@ svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) {
 // pop the elements and old values off the stack, gets the current values
 // pop the elements and old values off the stack, gets the current values
 // from the DOM and uses all of these to construct the undo-able command.
 // from the DOM and uses all of these to construct the undo-able command.
 //
 //
-// Parameters: 
+// Parameters:
 // attrName - The name of the attribute being changed
 // attrName - The name of the attribute being changed
 // elems - Array of DOM elements being changed
 // elems - Array of DOM elements being changed
 svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, elems) {
 svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, elems) {
@@ -562,13 +573,15 @@ svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, e
 	var oldValues = new Array(i), elements = new Array(i);
 	var oldValues = new Array(i), elements = new Array(i);
 	while (i--) {
 	while (i--) {
 		var elem = elems[i];
 		var elem = elems[i];
-		if (elem == null) continue;
+		if (elem == null) {continue;}
 		elements[i] = elem;
 		elements[i] = elem;
 		oldValues[i] = elem.getAttribute(attrName);
 		oldValues[i] = elem.getAttribute(attrName);
 	}
 	}
-	this.undoableChangeStack[p] = {'attrName': attrName,
-							'oldValues': oldValues,
-							'elements': elements};
+	this.undoableChangeStack[p] = {
+		'attrName': attrName,
+		'oldValues': oldValues,
+		'elements': elements
+	};
 };
 };
 
 
 // Function: svgedit.history.UndoManager.finishUndoableChange
 // Function: svgedit.history.UndoManager.finishUndoableChange
@@ -576,19 +589,19 @@ svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, e
 // change since beginUndoableChange was called.  The command can then
 // change since beginUndoableChange was called.  The command can then
 // be added to the command history
 // be added to the command history
 //
 //
-// Returns: 
+// Returns:
 // Batch command object with resulting changes
 // Batch command object with resulting changes
 svgedit.history.UndoManager.prototype.finishUndoableChange = function() {
 svgedit.history.UndoManager.prototype.finishUndoableChange = function() {
 	var p = this.undoChangeStackPointer--;
 	var p = this.undoChangeStackPointer--;
 	var changeset = this.undoableChangeStack[p];
 	var changeset = this.undoableChangeStack[p];
-	var i = changeset['elements'].length;
-	var attrName = changeset['attrName'];
+	var i = changeset.elements.length;
+	var attrName = changeset.attrName;
 	var batchCmd = new svgedit.history.BatchCommand("Change " + attrName);
 	var batchCmd = new svgedit.history.BatchCommand("Change " + attrName);
 	while (i--) {
 	while (i--) {
-		var elem = changeset['elements'][i];
-		if (elem == null) continue;
+		var elem = changeset.elements[i];
+		if (elem == null) {continue;}
 		var changes = {};
 		var changes = {};
-		changes[attrName] = changeset['oldValues'][i];
+		changes[attrName] = changeset.oldValues[i];
 		if (changes[attrName] != elem.getAttribute(attrName)) {
 		if (changes[attrName] != elem.getAttribute(attrName)) {
 			batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName));
 			batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName));
 		}
 		}
@@ -597,5 +610,4 @@ svgedit.history.UndoManager.prototype.finishUndoableChange = function() {
 	return batchCmd;
 	return batchCmd;
 };
 };
 
 
-
-})();
+}());

+ 1 - 1
main/inc/lib/svg-edit/images/README.txt

@@ -49,7 +49,7 @@ rotate.png
 save.png
 save.png
 select.png
 select.png
 sep.png
 sep.png
-shape_group.png
+shape_group_elements.png
 shape_ungroup.png
 shape_ungroup.png
 source.png
 source.png
 square.png
 square.png

+ 0 - 6
main/inc/lib/svg-edit/images/align-bottom.png

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

BIN
main/inc/lib/svg-edit/images/italic.png


+ 0 - 0
main/inc/lib/svg-edit/images/move_bottom.png → main/inc/lib/svg-edit/images/move_bottom.png


+ 1 - 3
main/inc/lib/svg-edit/images/shape_ungroup.png


+ 0 - 6
main/inc/lib/svg-edit/images/svg_edit_icons.svgz

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 1 - 1
main/inc/lib/svg-edit/jgraduate/css/jPicker.css

@@ -7,7 +7,7 @@
  * Copyright (c) 2010 Alexis Deveria
  * Copyright (c) 2010 Alexis Deveria
  * http://a.deveria.com/
  * http://a.deveria.com/
  *
  *
- * Licensed under the Apache License Version 2
+ * Licensed under the MIT License
  */
  */
 
 
 h2.jGraduate_Title {
 h2.jGraduate_Title {

+ 0 - 6
main/inc/lib/svg-edit/jgraduate/images/AlphaBar.png

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 0 - 6
main/inc/lib/svg-edit/jgraduate/images/map-opacity.png

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

Diferenças do arquivo suprimidas por serem muito extensas
+ 1673 - 0
main/inc/lib/svg-edit/jgraduate/jpicker.js


+ 4 - 4
main/inc/lib/svg-edit/jgraduate/jpicker.min.js

@@ -228,7 +228,7 @@ jQuery.fn.jGraduate =
     	        		'<div class="jGraduate_Form_Section">' +
     	        		'<div class="jGraduate_Form_Section">' +
         	    			'<label>x:</label>' +
         	    			'<label>x:</label>' +
             				'<input type="text" id="' + id + '_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/>' +
             				'<input type="text" id="' + id + '_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/>' +
-            				'<label> y:</label>' +
+            				'<label>y:</label>' +
             				'<input type="text" id="' + id + '_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/>' +
             				'<input type="text" id="' + id + '_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/>' +
         	   			'</div>' +
         	   			'</div>' +
         	   		'</div>' +
         	   		'</div>' +
@@ -237,7 +237,7 @@ jQuery.fn.jGraduate =
     	        		'<div class="jGraduate_Form_Section">' +
     	        		'<div class="jGraduate_Form_Section">' +
 	    	        		'<label>x:</label>' +
 	    	        		'<label>x:</label>' +
 		    	        	'<input type="text" id="' + id + '_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/>' +
 		    	        	'<input type="text" id="' + id + '_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/>' +
-    		    	    	'<label> y:</label>' +
+    		    	    	'<label>y:</label>' +
         		    		'<input type="text" id="' + id + '_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/>' +
         		    		'<input type="text" id="' + id + '_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/>' +
     	    	    	'</div>' +
     	    	    	'</div>' +
     	    	    '</div>' +
     	    	    '</div>' +
@@ -248,7 +248,7 @@ jQuery.fn.jGraduate =
 						'<div class="jGraduate_Form_Section">' +
 						'<div class="jGraduate_Form_Section">' +
 							'<label>x:</label>' +
 							'<label>x:</label>' +
 							'<input type="text" id="' + id + '_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
 							'<input type="text" id="' + id + '_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
-							'<label> y:</label>' +
+							'<label>y:</label>' +
 							'<input type="text" id="' + id + '_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
 							'<input type="text" id="' + id + '_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
 						'</div>' +
 						'</div>' +
 					'</div>' +
 					'</div>' +
@@ -258,7 +258,7 @@ jQuery.fn.jGraduate =
 							'<label>Match center: <input type="checkbox" checked="checked" id="' + id + '_jGraduate_match_ctr"/></label><br/>' +
 							'<label>Match center: <input type="checkbox" checked="checked" id="' + id + '_jGraduate_match_ctr"/></label><br/>' +
 							'<label>x:</label>' +
 							'<label>x:</label>' +
 							'<input type="text" id="' + id + '_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
 							'<input type="text" id="' + id + '_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/>' +
-							'<label> y:</label>' +
+							'<label>y:</label>' +
 							'<input type="text" id="' + id + '_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
 							'<input type="text" id="' + id + '_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/>' +
 						'</div>' +
 						'</div>' +
 					'</div>' +
 					'</div>' +

+ 74 - 0
main/inc/lib/svg-edit/jgraduate/jquery.jgraduate.min.js

@@ -0,0 +1,74 @@
+/*globals $, jQuery */
+/*jslint vars: true */
+/**
+ * jQuery module to work with SVG.
+ *
+ * Licensed under the MIT License
+ *
+ */
+
+// Dependencies:
+// 1) jquery
+
+(function() {'use strict';
+
+  // This fixes $(...).attr() to work as expected with SVG elements.
+  // Does not currently use *AttributeNS() since we rarely need that.
+
+  // See http://api.jquery.com/attr/ for basic documentation of .attr()
+
+  // Additional functionality:
+  // - When getting attributes, a string that's a number is return as type number.
+  // - If an array is supplied as first parameter, multiple values are returned
+  // as an object with values for each given attributes
+
+  var proxied = jQuery.fn.attr,
+    // TODO use NS.SVG instead
+    svgns = "http://www.w3.org/2000/svg";
+  jQuery.fn.attr = function(key, value) {
+    var i, attr;
+	var len = this.length;
+    if (!len) {return proxied.apply(this, arguments);}
+    for (i = 0; i < len; ++i) {
+      var elem = this[i];
+      // set/get SVG attribute
+      if (elem.namespaceURI === svgns) {
+        // Setting attribute
+        if (value !== undefined) {
+          elem.setAttribute(key, value);
+        } else if ($.isArray(key)) {
+          // Getting attributes from array
+          var j = key.length, obj = {};
+
+          while (j--) {
+            var aname = key[j];
+            attr = elem.getAttribute(aname);
+            // This returns a number when appropriate
+            if (attr || attr === "0") {
+              attr = isNaN(attr) ? attr : (attr - 0);
+            }
+            obj[aname] = attr;
+          }
+          return obj;
+        }
+		if (typeof key === "object") {
+          // Setting attributes form object
+		  var v;
+          for (v in key) {
+            elem.setAttribute(v, key[v]);
+          }
+        // Getting attribute
+        } else {
+          attr = elem.getAttribute(key);
+          if (attr || attr === "0") {
+            attr = isNaN(attr) ? attr : (attr - 0);
+          }
+          return attr;
+        }
+      } else {
+        return proxied.apply(this, arguments);
+      }
+    }
+    return this;
+  };
+}());

+ 0 - 6
main/inc/lib/svg-edit/jquery-ui/index.html

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

Diferenças do arquivo suprimidas por serem muito extensas
+ 17 - 0
main/inc/lib/svg-edit/jquery-ui/jquery-ui-1.8.17.custom.min.js


+ 0 - 6
main/inc/lib/svg-edit/jquery.js

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 0 - 6
main/inc/lib/svg-edit/jquerybbq/jquery.bbq.min.js

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 1 - 0
main/inc/lib/svg-edit/js-hotkeys/jquery.hotkeys.min.js

@@ -13,5 +13,6 @@ Languages Already Translated By Humans:
   * lang.fr.js
   * lang.fr.js
   * lang.ja.js
   * lang.ja.js
   * lang.nl.js
   * lang.nl.js
+  * lang.pl.js
   * lang.ro.js
   * lang.ro.js
   * lang.sk.js
   * lang.sk.js

+ 0 - 6
main/inc/lib/svg-edit/locale/index.html

@@ -1,6 +0,0 @@
-<html>
-<head>
-</head>
-<body>
-</body>
-</html>

+ 19 - 3
main/inc/lib/svg-edit/locale/lang.af.js

@@ -1,3 +1,4 @@
+/*globals svgEditor */
 svgEditor.readLang({
 svgEditor.readLang({
 	lang: "af",
 	lang: "af",
 	dir : "ltr",
 	dir : "ltr",
@@ -84,7 +85,7 @@ svgEditor.readLang({
 		"smallest_object": "kleinste voorwerp",
 		"smallest_object": "kleinste voorwerp",
 		"new_doc": "Nuwe Beeld",
 		"new_doc": "Nuwe Beeld",
 		"open_doc": "Open Beeld",
 		"open_doc": "Open Beeld",
-		"export_png": "Export as PNG",
+		"export_img": "Export",
 		"save_doc": "Slaan Beeld",
 		"save_doc": "Slaan Beeld",
 		"import_doc": "Import SVG",
 		"import_doc": "Import SVG",
 		"align_to_page": "Align Element to Page",
 		"align_to_page": "Align Element to Page",
@@ -118,7 +119,7 @@ svgEditor.readLang({
 		"toggle_grid": "Show/Hide Grid",
 		"toggle_grid": "Show/Hide Grid",
 		"clone": "Clone Element(s)",
 		"clone": "Clone Element(s)",
 		"del": "Delete Element(s)",
 		"del": "Delete Element(s)",
-		"group": "Groep Elemente",
+		"group_elements": "Groep Elemente",
 		"make_link": "Make (hyper)link",
 		"make_link": "Make (hyper)link",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"to_path": "Convert to Path",
 		"to_path": "Convert to Path",
@@ -182,7 +183,8 @@ svgEditor.readLang({
 		"base_unit": "Base Unit:",
 		"base_unit": "Base Unit:",
 		"grid": "Grid",
 		"grid": "Grid",
 		"snapping_onoff": "Snapping on/off",
 		"snapping_onoff": "Snapping on/off",
-		"snapping_stepsize": "Snapping Step-Size:"
+		"snapping_stepsize": "Snapping Step-Size:",
+		"grid_color": "Grid color"
 	},
 	},
 	shape_cats: {
 	shape_cats: {
 		"basic": "Basic",
 		"basic": "Basic",
@@ -230,5 +232,19 @@ svgEditor.readLang({
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"URLloadFail": "Unable to load from URL",
 		"URLloadFail": "Unable to load from URL",
 		"retrieving": "Retrieving \"%s\"..."
 		"retrieving": "Retrieving \"%s\"..."
+	},
+	confirmSetStorage: {
+		message: "By default and where supported, SVG-Edit can store your editor "+
+		"preferences and SVG content locally on your machine so you do not "+
+		"need to add these back each time you load SVG-Edit. If, for privacy "+
+		"reasons, you do not wish to store this information on your machine, "+
+		"you can change away from the default option below.",
+		storagePrefsAndContent: "Store preferences and SVG content locally",
+		storagePrefsOnly: "Only store preferences locally",
+		storagePrefs: "Store preferences locally",
+		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
+		storageNoPrefs: "Do not store my preferences locally",
+		rememberLabel: "Remember this choice?",
+		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
 	}
 	}
 });
 });

+ 19 - 3
main/inc/lib/svg-edit/locale/lang.ar.js

@@ -1,3 +1,4 @@
+/*globals svgEditor */
 svgEditor.readLang({
 svgEditor.readLang({
 	lang: "ar",
 	lang: "ar",
 	dir : "ltr",
 	dir : "ltr",
@@ -84,7 +85,7 @@ svgEditor.readLang({
 		"smallest_object": "أصغر كائن",
 		"smallest_object": "أصغر كائن",
 		"new_doc": "صورة جديدة",
 		"new_doc": "صورة جديدة",
 		"open_doc": "فتح الصورة",
 		"open_doc": "فتح الصورة",
-		"export_png": "Export as PNG",
+		"export_img": "Export",
 		"save_doc": "حفظ صورة",
 		"save_doc": "حفظ صورة",
 		"import_doc": "Import SVG",
 		"import_doc": "Import SVG",
 		"align_to_page": "Align Element to Page",
 		"align_to_page": "Align Element to Page",
@@ -118,7 +119,7 @@ svgEditor.readLang({
 		"toggle_grid": "Show/Hide Grid",
 		"toggle_grid": "Show/Hide Grid",
 		"clone": "Clone Element(s)",
 		"clone": "Clone Element(s)",
 		"del": "Delete Element(s)",
 		"del": "Delete Element(s)",
-		"group": "مجموعة عناصر",
+		"group_elements": "مجموعة عناصر",
 		"make_link": "Make (hyper)link",
 		"make_link": "Make (hyper)link",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"to_path": "Convert to Path",
 		"to_path": "Convert to Path",
@@ -182,7 +183,8 @@ svgEditor.readLang({
 		"base_unit": "Base Unit:",
 		"base_unit": "Base Unit:",
 		"grid": "Grid",
 		"grid": "Grid",
 		"snapping_onoff": "Snapping on/off",
 		"snapping_onoff": "Snapping on/off",
-		"snapping_stepsize": "Snapping Step-Size:"
+		"snapping_stepsize": "Snapping Step-Size:",
+		"grid_color": "Grid color"
 	},
 	},
 	shape_cats: {
 	shape_cats: {
 		"basic": "Basic",
 		"basic": "Basic",
@@ -230,5 +232,19 @@ svgEditor.readLang({
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"URLloadFail": "Unable to load from URL",
 		"URLloadFail": "Unable to load from URL",
 		"retrieving": "Retrieving \"%s\"..."
 		"retrieving": "Retrieving \"%s\"..."
+	},
+	confirmSetStorage: {
+		message: "By default and where supported, SVG-Edit can store your editor "+
+		"preferences and SVG content locally on your machine so you do not "+
+		"need to add these back each time you load SVG-Edit. If, for privacy "+
+		"reasons, you do not wish to store this information on your machine, "+
+		"you can change away from the default option below.",
+		storagePrefsAndContent: "Store preferences and SVG content locally",
+		storagePrefsOnly: "Only store preferences locally",
+		storagePrefs: "Store preferences locally",
+		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
+		storageNoPrefs: "Do not store my preferences locally",
+		rememberLabel: "Remember this choice?",
+		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
 	}
 	}
 });
 });

+ 19 - 3
main/inc/lib/svg-edit/locale/lang.az.js

@@ -1,3 +1,4 @@
+/*globals svgEditor */
 svgEditor.readLang({
 svgEditor.readLang({
 	lang: "az",
 	lang: "az",
 	dir : "ltr",
 	dir : "ltr",
@@ -84,7 +85,7 @@ svgEditor.readLang({
 		"smallest_object": "smallest object",
 		"smallest_object": "smallest object",
 		"new_doc": "New Image",
 		"new_doc": "New Image",
 		"open_doc": "Open Image",
 		"open_doc": "Open Image",
-		"export_png": "Export as PNG",
+		"export_img": "Export",
 		"save_doc": "Save Image",
 		"save_doc": "Save Image",
 		"import_doc": "Import SVG",
 		"import_doc": "Import SVG",
 		"align_to_page": "Align Element to Page",
 		"align_to_page": "Align Element to Page",
@@ -118,7 +119,7 @@ svgEditor.readLang({
 		"toggle_grid": "Show/Hide Grid",
 		"toggle_grid": "Show/Hide Grid",
 		"clone": "Clone Element(s)",
 		"clone": "Clone Element(s)",
 		"del": "Delete Element(s)",
 		"del": "Delete Element(s)",
-		"group": "Group Elements",
+		"group_elements": "Group Elements",
 		"make_link": "Make (hyper)link",
 		"make_link": "Make (hyper)link",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"set_link_url": "Set link URL (leave empty to remove)",
 		"to_path": "Convert to Path",
 		"to_path": "Convert to Path",
@@ -182,7 +183,8 @@ svgEditor.readLang({
 		"base_unit": "Base Unit:",
 		"base_unit": "Base Unit:",
 		"grid": "Grid",
 		"grid": "Grid",
 		"snapping_onoff": "Snapping on/off",
 		"snapping_onoff": "Snapping on/off",
-		"snapping_stepsize": "Snapping Step-Size:"
+		"snapping_stepsize": "Snapping Step-Size:",
+		"grid_color": "Grid color"
 	},
 	},
 	shape_cats: {
 	shape_cats: {
 		"basic": "Basic",
 		"basic": "Basic",
@@ -230,5 +232,19 @@ svgEditor.readLang({
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"errorLoadingSVG": "Error: Unable to load SVG data",
 		"URLloadFail": "Unable to load from URL",
 		"URLloadFail": "Unable to load from URL",
 		"retrieving": "Retrieving \"%s\"..."
 		"retrieving": "Retrieving \"%s\"..."
+	},
+	confirmSetStorage: {
+		message: "By default and where supported, SVG-Edit can store your editor "+
+		"preferences and SVG content locally on your machine so you do not "+
+		"need to add these back each time you load SVG-Edit. If, for privacy "+
+		"reasons, you do not wish to store this information on your machine, "+
+		"you can change away from the default option below.",
+		storagePrefsAndContent: "Store preferences and SVG content locally",
+		storagePrefsOnly: "Only store preferences locally",
+		storagePrefs: "Store preferences locally",
+		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
+		storageNoPrefs: "Do not store my preferences locally",
+		rememberLabel: "Remember this choice?",
+		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
 	}
 	}
 });
 });

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff