소스 검색

Merge branch 'improveLog' of ssh://git.lcalion.com:2245/LInE/ivprog into improveLog

Lucas de Souza 5 년 전
부모
커밋
e5b1140544
8개의 변경된 파일459개의 추가작업 그리고 114개의 파일을 삭제
  1. 25 17
      js/iassign-integration-functions.js
  2. 8 1
      js/main.js
  3. 105 0
      js/services/userLog.js
  4. 80 7
      js/visualUI/commands.js
  5. 57 46
      js/visualUI/functions.js
  6. 71 11
      js/visualUI/globals.js
  7. 112 31
      js/visualUI/variables.js
  8. 1 1
      package-lock.json

+ 25 - 17
js/iassign-integration-functions.js

@@ -239,19 +239,26 @@ function prepareActivityToStudent (ilm_cont) {
 // Função para organizar se para criação, visualização ou resolução de atividade
 function prepareEnvironment () {
 
+  $('.div_to_body').click(function(e) {
+    // trackingMatrix.push(adCoords(e, 1));
+    console.log("Log click");
+    ivprogCore.registerClick(e.pageX, e.pageY, e.target.classList['value']);
+  });
+
   // Se iLM_PARAM_SendAnswer for false, então trata-se de resolução de atividade,
   // portanto, a "DIV" de resolução é liberada
   if (iLMparameters.iLM_PARAM_SendAnswer == 'false') {
     //$('.resolucao').css("display","block");
     getiLMContent();
 
-    $('.div_to_body').mousemove(function(e) {
-        trackingMatrix.push(adCoords(e, 0));
-    });
+    // $('.div_to_body').mousemove(function(e) {
+    //     trackingMatrix.push(adCoords(e, 0));
+    // });
 
-    $('.div_to_body').click(function(e) {
-        trackingMatrix.push(adCoords(e, 1));                    
-    });
+    // $('.div_to_body').click(function(e) {
+    //   // trackingMatrix.push(adCoords(e, 1));
+    //   ivprogCore.registerClick(e.pageX, e.pageY, e.target.classList['value']);
+    // });
   } else if (iLMparameters.iLM_PARAM_Assignment) {
     // Caso não esteja em modo de resolução de atividade, a visualização no momento
     // é para a elaboração de atividade:
@@ -436,20 +443,21 @@ function prepareTableSettings (div_el) {
 }
 
 function getTrackingLogs () {
-  var ret = "";
-  for (var i = 0; i < trackingMatrix.length; ++i) {
-    ret += "\n" + trackingMatrix[i][0] + "," + trackingMatrix[i][1] + "," + trackingMatrix[i][2];
-    if (trackingMatrix[i][3] === 1) {
-      ret += ',' + trackingMatrix[i][3] + ',"' + trackingMatrix[i][4] + '"';
-    }
-  }
-  return ret;
+  return ivprogCore.getLogsAsString();
+  // var ret = "";
+  // for (var i = 0; i < trackingMatrix.length; ++i) {
+  //   ret += "\n" + trackingMatrix[i][0] + "," + trackingMatrix[i][1] + "," + trackingMatrix[i][2];
+  //   if (trackingMatrix[i][3] === 1) {
+  //     ret += ',' + trackingMatrix[i][3] + ',"' + trackingMatrix[i][4] + '"';
+  //   }
+  // }
+  // return ret;
 }
 
 // Tracking mouse movements
-var trackingMatrix = [];
+// var trackingMatrix = [];
 
-function adCoords(e, code){
+/* function adCoords(e, code){
   var x = e.pageX; 
   var y = e.pageY;
   if (code === 1) {
@@ -457,7 +465,7 @@ function adCoords(e, code){
   } else {
     return [x, y, code];
   }
-}
+} */
 
 // $( document ).ready(function() {
 

+ 8 - 1
js/main.js

@@ -4,6 +4,7 @@ import { initVisualUI, addFunctionChangeListener,
   removeGlobalListener, getTestCases } from './visualUI/functions';
 import * as LocalizedStringsService from './services/localizedStringsService';
 import { i18nHelper } from "./services/i18nHelper";
+import { ActionTypes, getLogs, getLogsAsString, registerClick, registerUserEvent, parseLogs } from "./services/userLog";
 import { prepareActivityToStudentHelper, autoEval } from "./util/iassignHelpers";
 
 const i18n = i18nHelper.i18n
@@ -20,5 +21,11 @@ export {
   autoEval,
   prepareActivityToStudentHelper,
   LocalizedStrings,
-  i18n
+  i18n,
+  getLogs,
+  getLogsAsString,
+  registerClick,
+  registerUserEvent,
+  parseLogs,
+  ActionTypes
 }

+ 105 - 0
js/services/userLog.js

@@ -0,0 +1,105 @@
+let clicks = [];
+let inRebuildMode = false;
+
+export const ActionTypes = Object.freeze({
+  // registerUserEvent payload:
+  // (function_name, insert action)
+  INSERT_FUNCTION:"INSERT_FUNCTION",
+  // (function_name, remove action)
+  REMOVE_FUNCTION:"REMOVE_FUNCTION",
+  // (var_name,insert action, type, dim)
+  INSERT_GLOBAL_VAR:"INSERT_GLOBAL_VAR",
+  // (var name, remove action)
+  REMOVE_GLOBAL_VAR:"REMOVE_GLOBAL_VAR",
+  // (old function name, rename action, new function name)
+  RENAME_FUNCTION:"RENAME_FUNCTION",
+  // (old var name, rename action. new var name)
+  RENAME_GLOBAL_VAR:"RENAME_GLOBAL_VAR",
+  // (var name, set const action)
+  SET_GLOBAL_CONST:"SET_GLOBAL_CONST",
+  // (function name, change return action, type, dim)
+  CHANGE_FUNCTION_RETURN:"CHANGE_FUNCTION_RETURN",
+  // (var name, change type action, type, dim, rows?, columns?)
+  CHANGE_GLOBAL_TYPE:"CHANGE_GLOBAL_TYPE",
+  // (var name, change value action, value)
+  CHANGE_GLOBAL_VALUE:"CHANGE_GLOBAL_VALUE",
+  // (function name, insert param action, param varname, type, dim)
+  INSERT_FUNCTION_PARAM:"INSERT_FUNCTION_PARAM",
+  // (function name, remove param action, param varname)
+  REMOVE_FUNCTION_PARAM:"REMOVE_FUNCTION_PARAM",
+  // (function name, change param type action, type, dim)
+  CHANGE_PARAM_TYPE:"CHANGE_PARAM_TYPE",
+  // (function name, rename param action, old param name, new param name)
+  RENAME_FUNCTION_PARAM:"RENAME_FUNCTION_PARAM",
+  // (function name, insert var action, var name, type, dim)
+  INSERT_FUNCTION_VAR:"INSERT_FUCNTION_VAR",
+  // (function name, remove var action, var name)
+  REMOVE_FUNCTION_VAR:"REMOVE_FUNCTION_VAR",
+  // (function name, rename var action, old var name, new var name)
+  RENAME_FUNCTION_VAR:"RENAME_FUNCTION_VAR",
+  // (function name, change var type action, var name, type, dim, rows?, columns?)
+  CHANGE_VAR_TYPE:"CHANGE_VAR_TYPE",
+  // (function name, change var value action, var name, value)
+  CHANGE_VAR_VALUE:"CHANGE_VAR_VALUE",
+  // (function name, insert command action, command, path)
+  INSERT_COMMAND:"INSERT_COMMAND",
+  // (function name, remove command action, path)
+  REMOVE_COMMAND:"REMOVE_COMMAND",
+  // (function name, change command exp action, path, exp)
+  CHANGE_COMMAND_EXP:"CHANGE_COMMAND_EXP",
+  // (function name, change attrib exp action, path, exp)
+  CHANGE_ATTRIB_EXP:"CHANGE_ATTRIB_EXP",
+  // (function name, change attrib var action, path, var name, row_exp?, column_exp?)
+  CHANGE_ATTRIB_VAR:"CHANGE_ATTRIB_VAR",
+  // (function name, move command action, old path, new path)
+  MOVE_COMMAND:"MOVE_COMMAND",
+  // (function name, enter change name action, var name)
+  ENTER_CHANGE_VAR_NAME:'ENTER_CHANGE_VAR_NAME',
+  // (function name, enter change value action, var name)
+  ENTER_CHANGE_VAR_VALUE:'ENTER_CHANGE_VAR_VALUE',
+  // (var name, enter change name action)
+  ENTER_CHANGE_GLOBAL_NAME:'ENTER_CHANGE_GLOBAL_NAME',
+  // (var name, enter change value action)
+  ENTER_CHANGE_GLOBAL_VALUE:'ENTER_CHANGE_GLOBAL_VALUE',
+  // (function name, enter change name action, param name)
+  ENTER_CHANGE_PARAM_NAME:'ENTER_CHANGE_PARAM_NAME',
+});
+
+export function registerClick (x, y, details) {
+  if (inRebuildMode) {
+    return;
+  }
+  clicks.push([x, y, Date.now(), details]);
+}
+
+export function registerUserEvent (command, action, ...params) {
+  registerEvent('user_event', command, action, params);
+}
+
+export function registerSystemEvent (command, action, ...params) {
+  registerEvent('system_event', command, action, params);
+}
+
+function registerEvent (tag, command, action, params) {
+  if (inRebuildMode) {
+    return;
+  }
+  const event = {context: command, action: action, params:params};
+  clicks.push([tag, Date.now(), event]);
+}
+
+export function getLogs () {
+  return clicks;
+}
+
+export function setRebuildMode (flag) {
+  inRebuildMode = flag;
+}
+
+export function getLogsAsString () {
+  return JSON.stringify(clicks);
+}
+
+export function parseLogs (logData) {
+  clicks = JSON.parse(logData);
+}

+ 80 - 7
js/visualUI/commands.js

@@ -13,6 +13,7 @@ import * as FunctioncallsManagement from './commands/functioncall';
 import * as VariableValueMenuManagement from './commands/variable_value_menu';
 import * as BreaksManagement from './commands/break';
 import * as ReturnsManagement from './commands/return';
+import { registerUserEvent, ActionTypes } from "./../services/userLog";
 
 // let has_element_created_draged = false;
 // let which_element_is_draged = null;
@@ -319,12 +320,8 @@ function addGhostToFunctionArea (undermouse, evt) {
 
 function addGhostDiv (evt) {
 
-	console.log('a');
-
 	var undermouse = $(evt.target);
 
-	console.log('undermouse', undermouse);
-
 	if (undermouse.hasClass('ghost_div')) {
 		return;
 	} else if (undermouse.hasClass('commands_list_div')) {
@@ -524,6 +521,64 @@ function dragTrash (event) {
     });
 }
 
+function findSingleElement (searching, query) {
+
+	if (!searching || !query) {
+		return '';
+	}
+
+	if (searching.type == Models.COMMAND_TYPES.repeatNtimes || 
+		searching.type == Models.COMMAND_TYPES.whiletrue ||
+		searching.type == Models.COMMAND_TYPES.dowhiletrue) {
+
+		if (searching.commands_block) {
+			return '' + searching.commands_block.indexOf(query);
+		} else {
+			return '0';
+		}
+
+	} else if (searching.type == Models.COMMAND_TYPES.iftrue) {
+
+		if (searching.commands_block == null) {
+			searching.commands_block = [];
+		}
+		if (searching.commands_else == null) {
+			searching.commands_else = [];
+		}
+
+		console.log('\n\nveja onde: ', searching.commands_block, ' \n\nquery: ', query);
+
+		if (searching.commands_block.indexOf(query) >= 0) {
+			return 'if[' + searching.commands_block.indexOf(query) + ']';
+		} else {
+			return 'else[' + searching.commands_else.indexOf(query) + ']';
+		}
+
+	} else if (searching.type == Models.COMMAND_TYPES.switch) {
+
+		for (var i = 0; i < searching.cases.length; i++) {
+			if (searching.cases[i].commands_block.indexOf(query) >= 0) {
+				return 'case[' + searching.cases[i].commands_block.indexOf(query) + ']';
+			}
+		}
+
+	}
+
+}
+
+function findPathRecursive (starter_index, hierarquia_bottom_up, function_obj, index_command = -1, actual = null) {
+	var full_path = '';
+	
+	for (var i = 0; i <= hierarquia_bottom_up.length; i ++) {
+
+		console.log('\n\n:: ', i, ':\n', hierarquia_bottom_up[i]);
+
+		full_path += findSingleElement(hierarquia_bottom_up[i], hierarquia_bottom_up[i + 1]) + '-';
+	}
+
+	return full_path;
+}
+
 function manageCommand (function_obj, function_container, event, command_type) {
 
 	$( ".created_element" ).each(function( index ) { 
@@ -582,9 +637,9 @@ function manageCommand (function_obj, function_container, event, command_type) {
 			return;
 		}
 	}
-
+	var hierarquia_bottom_up = null;
 	// Agora é descobrir qual o escopo para adicionar o comando:
-
+	console.log('ev0');
 	// Se o elemento clicado possuir o atributo "fun", então, é direto na div dos comandos:
 	if (typeof el.data('fun') !== 'undefined') {
 
@@ -595,6 +650,7 @@ function manageCommand (function_obj, function_container, event, command_type) {
 				el.data('fun').commands = [];
 
 				var new_cmd = genericCreateCommand(command_type);
+				registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/', 0);
 
 				el.data('fun').commands.push(new_cmd);
 
@@ -609,7 +665,7 @@ function manageCommand (function_obj, function_container, event, command_type) {
 		console.log("soltou em um comando");
 		// descobrir em qual comando ele soltou: 
 		var hier_find = el.parentsUntil(".commands_list_div");
-		var hierarquia_bottom_up = [];
+		hierarquia_bottom_up = [];
 		if (typeof el.data('command') !== 'undefined') {
 			hierarquia_bottom_up.push(el.data('command'));
 		}
@@ -688,6 +744,16 @@ function manageCommand (function_obj, function_container, event, command_type) {
 	// has_element_created_draged = false;
 	// which_element_is_draged = null;
 
+	if (hierarquia_bottom_up) {
+		console.log('\n\n:::índices::\n\n');
+		var i = hierarquia_bottom_up.length - 1;
+		var starter_index = window.program_obj.functions[window.program_obj.functions.indexOf(function_obj)].commands.indexOf(hierarquia_bottom_up[i]);
+		var all_str_path = starter_index + '-' + findPathRecursive(starter_index, hierarquia_bottom_up, function_obj);
+		registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/' , all_str_path);
+		console.log('\n\nfull path: \n\n', all_str_path);
+		console.log('fim dos índices');
+	}
+
 	renderAlgorithm();
 }
 
@@ -714,6 +780,7 @@ function insertCommandInBlockHierar (el, event, function_obj, command_type, hier
 
 				var recentComand = genericCreateCommand(command_type);
 				command_parent.commands_block.push(recentComand);
+				registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/' + el_jq.data('command').type, 0);
 
 				renderCommand(recentComand, el_jq.find('.block_commands'), 3, function_obj);
 			} else { // Se já tem algum comando no bloco:
@@ -734,6 +801,8 @@ function insertCommandInBlockHierar (el, event, function_obj, command_type, hier
 
 function findNearbyCommandToAddInBlockScope (el, event, node_list_commands, function_obj, command_type, command_parent) {
 
+	console.log("\n\n\n::COMANDOS:\n\n", el, event, node_list_commands, function_obj, command_type, command_parent);
+
 	var all_sub = $(node_list_commands).find('div.command_container');
 
 	var menor_distancia = 999999999;
@@ -1268,6 +1337,7 @@ function findBeforeOrAfterCommandToAdd (el, event, function_obj, command_type) {
 		}
 
 		renderCommand(recentComand, el, 1, function_obj);
+		registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/', index);
 
 	} else {
 		var recentComand = genericCreateCommand(command_type);
@@ -1279,6 +1349,7 @@ function findBeforeOrAfterCommandToAdd (el, event, function_obj, command_type) {
 		}
 
 		renderCommand(recentComand, el, 2, function_obj);
+		registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/', index);
 	}
 }
 
@@ -1314,6 +1385,7 @@ function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, f
 		function_obj.commands.push(recentComand);
 		//
 		renderCommand(recentComand, node_list_commands, 3, function_obj);
+		registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/', function_obj.commands.length - 1);
 
 	} else {
 
@@ -1326,5 +1398,6 @@ function findNearbyCommandToAddInFunctionScope (el, event, node_list_commands, f
 		}
 
 		renderCommand(recentComand, elemento_menor_distancia, 1, function_obj);
+		registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, command_type, '/', index);
 	}
 }

+ 57 - 46
js/visualUI/functions.js

@@ -13,6 +13,7 @@ import { SemanticAnalyser } from '../processor/semantic/semanticAnalyser';
 import { IVProgAssessment } from '../assessment/ivprogAssessment';
 import * as AlgorithmManagement from './algorithm';
 import * as Utils from './utils';
+import { registerUserEvent, ActionTypes } from "./../services/userLog";
 import VersionInfo from './../../.ima_version.json';
 
 var counter_new_functions = 0;
@@ -128,36 +129,38 @@ WatchJS.watch(window.program_obj.functions, function(){
 
 function addFunctionHandler () {
 
-	var new_function = new Models.Function(LocalizedStrings.getUI("new_function") + "_" + counter_new_functions, Types.VOID, 0, [], false, false, [], new Models.Comment(LocalizedStrings.getUI('text_comment_start')));
+	const new_function = new Models.Function(LocalizedStrings.getUI("new_function") + "_" + counter_new_functions, Types.VOID, 0, [], false, false, [], new Models.Comment(LocalizedStrings.getUI('text_comment_start')));
 	program.addFunction(new_function);
 
 	counter_new_functions ++;
 
   window.insertContext = true;
+  registerUserEvent(new_function.name, ActionTypes.INSERT_FUNCTION);
 
-  var newe = renderFunction(new_function);
-
+  // var newe = renderFunction(new_function);
+  renderFunction(new_function);
   /*newe.css('display', 'none');
   newe.fadeIn();*/
 }
 
-function addParameter (function_obj, function_container, is_from_click = false) {
+function addParameter (function_obj, function_container/*, is_from_click = false*/) {
   if (function_obj.parameters_list == null) {
     function_obj.parameters_list = [];
   }
-  var new_parameter = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI("new_parameter") + "_" + counter_new_parameters);
+  const new_parameter = new Models.Variable(Types.INTEGER, LocalizedStrings.getUI("new_parameter") + "_" + counter_new_parameters);
   function_obj.parameters_list.push(new_parameter);
   counter_new_parameters ++;
-
-  var newe = renderParameter(function_obj, new_parameter, function_container);
-
-  if (is_from_click) {
-    /*newe.css('display', 'none');
-    newe.fadeIn();*/
-  }
+  registerUserEvent(function_obj.name, ActionTypes.INSERT_FUNCTION_PARAM, new_parameter.name, Types.INTEGER, 0);
+  //var newe = renderParameter(function_obj, new_parameter, function_container);
+  renderParameter(function_obj, new_parameter, function_container);
+  // if (is_from_click) {
+  //   newe.css('display', 'none');
+  //   newe.fadeIn();
+  // }
 }
 
 function updateReturnType (function_obj, new_type, new_dimensions = 0) {
+  registerUserEvent(function_obj.name, ActionTypes.CHANGE_FUNCTION_RETURN, new_type, new_dimensions);
   function_obj.return_type = new_type;
   function_obj.return_dimensions = new_dimensions;
 }
@@ -165,6 +168,7 @@ function updateReturnType (function_obj, new_type, new_dimensions = 0) {
 function removeFunction (function_obj) {
   var index = program.functions.indexOf(function_obj);
   if (index > -1) {
+    registerUserEvent(function_obj.name, ActionTypes.REMOVE_FUNCTION);
     program.functions.splice(index, 1);
   }
 }
@@ -206,6 +210,7 @@ function addHandlers (function_obj, function_container) {
       function_obj.commands.push(new_cmd);
 
       CommandsManagement.renderCommand(new_cmd, function_container.find('.commands_list_div'), 3, function_obj);
+      registerUserEvent(function_obj.name, ActionTypes.INSERT_COMMAND, $(this).data('command'), '/', 0);
     } else {
       CommandsManagement.createFloatingCommand(function_obj, function_container, $(this).data('command'), evt);
     }
@@ -452,22 +457,23 @@ function isVisible (element, container) {
 window.evento_drag;
 
 function updateProgramObjDrag () {
-  var nodes = Array.prototype.slice.call( $('.all_functions').children() );
-  var function_index;
-  var start_index;
-  var function_obj;
+  const nodes = Array.prototype.slice.call( $('.all_functions').children() );
+  let function_index;
+  // var start_index;
+  let function_obj;
   $(evento_drag.item).parentsUntil(".all_functions").each(function (index) {
-    if ($(this).hasClass('function_div')) {
+    const ref = $(this);
+    if (ref.hasClass('function_div')) {
       function_index = nodes.indexOf(this);
       start_index = index;
-      function_obj = $(this);
+      function_obj = ref;
     }
   });
 
   console.log(function_index);
 
-  var path_target = [];
-  $(evento_drag.item).parentsUntil(".all_functions").each(function (index) {
+  const path_target = [];
+  $(evento_drag.item).parentsUntil(".all_functions").each(function () {
     if ($(this).hasClass('command_container')) {
       path_target.push(this);
     }
@@ -510,16 +516,16 @@ function updateProgramObjDrag () {
       }
     }
   }
-  var index_in_block = -1;
-  var is_in_else = $(evento_drag.item).parent().hasClass('commands_else');
+  // var index_in_block = -1;
+  const is_in_else = $(evento_drag.item).parent().hasClass('commands_else');
 
-  index_in_block = $(evento_drag.item).parent().find('.command_container').index(evento_drag.item);
+  // index_in_block = $(evento_drag.item).parent().find('.command_container').index(evento_drag.item);
 
-  var is_in_case_switch = $(evento_drag.item).parent().hasClass('case_commands_block');
-  var index_case_of_switch = -1;
-  if (is_in_case_switch) {
-    index_case_of_switch = $(evento_drag.item).parent().parent().parent().find('.case_div').index($(evento_drag.item).parent().parent());
-  }
+  const is_in_case_switch = $(evento_drag.item).parent().hasClass('case_commands_block');
+  // var index_case_of_switch = -1;
+  // if (is_in_case_switch) {
+  //   index_case_of_switch = $(evento_drag.item).parent().parent().parent().find('.case_div').index($(evento_drag.item).parent().parent());
+  // }
 
   /*console.log('path_relative:');
   console.log(path_relative);
@@ -933,17 +939,17 @@ function toggleConsole (is_running) {
   }
 }
 
-function waitToCloseConsole () {
-  domConsole.info("Aperte qualquer tecla para fechar...");
-  const p = new Promise((resolve, _) => {
-    domConsole.requestInput(resolve, true);
-  });
-  p.then( _ => {
-    domConsole.dispose();
-    domConsole = null;
-    $("#ivprog-term").hide();
-  })
-}
+// function waitToCloseConsole () {
+//   domConsole.info("Aperte qualquer tecla para fechar...");
+//   const p = new Promise((resolve, _) => {
+//     domConsole.requestInput(resolve, true);
+//   });
+//   p.then( _ => {
+//     domConsole.dispose();
+//     domConsole = null;
+//     $("#ivprog-term").hide();
+//   })
+// }
 
 function toggleTextualCoding () {
   var code = CodeManagement.generate();
@@ -971,6 +977,7 @@ function toggleVisualCoding () {
 }
 
 function removeParameter (function_obj, parameter_obj, parameter_container) {
+  registerUserEvent(parameter_obj.name, ActionTypes.REMOVE_FUNCTION_PARAM, function_obj.name);
   var index = function_obj.parameters_list.indexOf(parameter_obj);
   if (index > -1) {
     window.insertContext = true;
@@ -979,7 +986,8 @@ function removeParameter (function_obj, parameter_obj, parameter_container) {
   $(parameter_container).fadeOut();
 }
 
-function updateParameterType (parameter_obj, new_type, new_dimensions = 0) {
+function updateParameterType (parameter_obj, new_type, function_name, new_dimensions = 0) {
+  registerUserEvent(parameter_obj.name, ActionTypes.CHANGE_PARAM_TYPE, function_name, new_type, new_dimensions);
   parameter_obj.type = new_type;
   parameter_obj.dimensions = new_dimensions;
 
@@ -991,7 +999,7 @@ function updateParameterType (parameter_obj, new_type, new_dimensions = 0) {
 }
 
 function renderParameter (function_obj, parameter_obj, function_container) {
-  var ret = "";
+  let ret = "";
 
   ret += '<div class="ui label function_name_parameter pink"><i class="ui icon ellipsis vertical inverted"></i>';
 
@@ -1012,14 +1020,14 @@ function renderParameter (function_obj, parameter_obj, function_container) {
   ret += '<div class="menu">';
 
   
-  for (var tm in Types) {
+  for (const tm in Types) {
       if (tm == Types.VOID.toUpperCase()) {
         continue;
       }
       ret += '<div class="item ' + (parameter_obj.type == tm.toLowerCase() ? ' selected ' : '') + '" data-type="'+tm+'" >'+LocalizedStrings.getUI(tm.toLowerCase())+'</div>';
   }
 
-  for (var tm in Types) {
+  for (const tm in Types) {
     if (tm == Types.VOID.toUpperCase()) {
       continue;
     }
@@ -1048,17 +1056,18 @@ function renderParameter (function_obj, parameter_obj, function_container) {
   });
   
   ret.find('.ui.dropdown.parameter_type').dropdown({
-    onChange: function(value, text, $selectedItem) {
+    onChange: function(_, __, $selectedItem) {
       if ($selectedItem.data('dimensions')) {
-        updateParameterType(parameter_obj, Types[$selectedItem.data('type')], $selectedItem.data('dimensions'));
+        updateParameterType(parameter_obj, Types[$selectedItem.data('type')], function_obj.name, $selectedItem.data('dimensions'));
       } else {
-        updateParameterType(parameter_obj, Types[$selectedItem.data('type')]);
+        updateParameterType(parameter_obj, Types[$selectedItem.data('type')], function_obj.name);
       }
     },
     selectOnKeydown: false
   });
 
   ret.find('.label_enable_name_parameter').on('click', function(e){
+    registerUserEvent(function_obj.name, ActionTypes.ENTER_CHANGE_PARAM_NAME, parameter_obj.name);
     enableNameParameterUpdate(parameter_obj, ret, function_obj);
   });
 
@@ -1075,6 +1084,7 @@ function updateParameterName (parameter_var, new_name, parameter_obj_dom, functi
     if (variableNameAlreadyExists(new_name, function_obj)) {
       Utils.renderErrorMessage(parameter_obj_dom.find('.parameter_div_edit'), LocalizedStrings.getUI('inform_valid_variable_duplicated'));
     } else {
+      registerUserEvent(parameter_var.name, ActionTypes.RENAME_FUNCTION_PARAM, function_obj.name, new_name);
       parameter_var.name = new_name;
     }
   } else {
@@ -1113,6 +1123,7 @@ function updateFunctionName (function_var, new_name, function_obj_dom) {
     if (functionNameAlreadyExists(new_name)) {
       Utils.renderErrorMessage(function_obj_dom.find('.function_name_div'), LocalizedStrings.getUI('inform_valid_name_duplicated'));
     } else {
+      registerUserEvent(function_var.name, ActionTypes.RENAME_FUNCTION, new_name);
       function_var.name = new_name;
     }
   } else {

+ 71 - 11
js/visualUI/globals.js

@@ -2,6 +2,7 @@ import { Types } from './types';
 import * as Models from './ivprog_elements';
 import { LocalizedStrings } from './../services/localizedStringsService';
 import * as Utils from './utils';
+import { registerUserEvent, registerSystemEvent, ActionTypes } from "./../services/userLog";
 
 var counter_new_globals = 0;
 
@@ -12,6 +13,7 @@ export function addGlobal (program, is_from_click = false) {
 
 	program.addGlobal(new_global);
 
+	registerUserEvent(new_global.name, ActionTypes.INSERT_GLOBAL_VAR);
 	var newe = renderGlobal(new_global);
 
 	if (is_from_click) {
@@ -23,6 +25,7 @@ export function addGlobal (program, is_from_click = false) {
 
 function toggleConstant (global_var) {
 	global_var.is_constant = !global_var.is_constant;
+	registerUserEvent(global_var.name, ActionTypes.SET_GLOBAL_CONST);
 }
 
 function updateName (global_var, new_name, global_obj_dom) {
@@ -35,6 +38,7 @@ function updateName (global_var, new_name, global_obj_dom) {
 		if (globalNameAlreadyExists(new_name)) {
 			Utils.renderErrorMessage(global_obj_dom.find('.editing_name_var'), LocalizedStrings.getUI('inform_valid_global_duplicated'));
 		} else {
+			registerUserEvent(global_var.name, ActionTypes.RENAME_GLOBAL_VAR, new_name);
 			global_var.name = new_name;
 		}
 	} else {
@@ -63,7 +67,8 @@ function updateType (global_var, new_type, new_dimensions = 0) {
 		global_var.rows = new_dimensions;
 		global_var.columns = 2;
 	}
-
+	registerUserEvent(global_var.name, ActionTypes.CHANGE_VAR_TYPE, new_type,
+		new_dimensions, global_var.rows, global_var.columns);
 	updateInitialValues(global_var);
 }
 
@@ -73,6 +78,7 @@ function removeGlobal (global_var, global_container) {
 		window.insertContext = true;
 	  window.program_obj.globals.splice(index, 1);
 	}
+	registerUserEvent(global_var.name, ActionTypes.REMOVE_GLOBAL_VAR);
 	global_container.children().off();
 	global_container.off();
 	global_container.fadeOut();
@@ -127,6 +133,8 @@ function updateInitialValues (global_var) {
 			global_var.value = [[true, true], [true, true]];
 		}
 	}
+	registerSystemEvent(function_name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.name,
+		global_var.value);
 }
 
 function alternateBooleanGlobalValue (global_var, value_container) {
@@ -335,51 +343,75 @@ function renderValues (global_var, global_container) {
 
 	ret.find( ".boolean_simple_type" ).on('click', function(e){
 		alternateBooleanGlobalValue(global_var, this.parentNode);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 	});
 	ret.find( ".simple_var" ).on('click', function(e){
+		registerUserEvent(global_var.name, ActionTypes.ENTER_CHANGE_GLOBAL_VALUE);
 		enableGlobalValueUpdate(global_var, this.parentNode);
 	});
 
 	ret.find( ".boolean_vector_var" ).on('click', function(e){
 		alternateBooleanGlobalVectorValue(global_var, $(this).data('index'), this.parentNode);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 	});
 	ret.find( ".vector_var" ).on('click', function(e){
+		registerUserEvent(global_var.name, ActionTypes.ENTER_CHANGE_GLOBAL_VALUE);
 		enableGlobalVectorValueUpdate(global_var, $(this).data('index'), this.parentNode);
 	});
 	ret.find( ".remove_global_vector_column" ).on('click', function(e){
 		removeGlobalColumnVector(global_var);
 		global_container.find( ".div_valor_var" ).html('');
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".add_global_vector_column" ).on('click', function(e){
 		addGlobalColumnVector(global_var);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		global_container.find( ".div_valor_var" ).html('');
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".remove_global_matrix_column" ).on('click', function(e){
 		removeColumnGlobalMatrix(global_var);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		global_container.find( ".div_valor_var" ).html('');
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".add_global_matrix_column" ).on('click', function(e){
 		addColumnGlobalMatrix(global_var);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		global_container.find( ".div_valor_var" ).html('');
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".remove_global_matrix_line" ).on('click', function(e){
 		removeLineGlobalMatrix(global_var);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		global_container.find( ".div_valor_var" ).html('');
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".add_global_matrix_line" ).on('click', function(e){
 		addLineGlobalMatrix(global_var);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_TYPE,
+			global_var.type, global_var.dimensions, global_var.rows, global_var.columns);
+		registerSystemEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		global_container.find( ".div_valor_var" ).html('');
 		renderValues(global_var, global_container);
 	});
 	ret.find( ".boolean_matrix_var" ).on('click', function(e){
 		alternateBooleanGlobalMatrixValue(global_var, $(this).data('row'), $(this).data('index'), this.parentNode);
+		registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 	});
 	ret.find( ".matrix_var" ).on('click', function(e){
+		registerUserEvent(global_var.name, ActionTypes.ENTER_CHANGE_GLOBAL_VALUE);
 		enableGlobalMatrixValueUpdate(global_var, $(this).data('row'), $(this).data('index'), this.parentNode);
 	});
 	global_container.find( ".div_valor_var" ).append(ret);
@@ -405,12 +437,13 @@ function addHandlers (global_container) {
 
 	// Manage global name: 
 	global_container.find( ".enable_edit_name_parameter" ).on('click', function(e){
+		registerUserEvent(global_var.name, ActionTypes.ENTER_CHANGE_GLOBAL_NAME);
 		enableNameUpdate(global_container);
 	});
 
 	// Menu to change type:
 	global_container.find('.ui.dropdown.global_type').dropdown({
-	    onChange: function(value, text, $selectedItem) {
+	    onChange: function(_, __, $selectedItem) {
 	    	if ($selectedItem.data('dimensions')) {
 	    		updateType(global_var, Types[$selectedItem.data('type')], $selectedItem.data('dimensions'));
 	    	} else {
@@ -564,6 +597,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 				}
 				parent_node.find('.span_value_variable').text(global_var.value[row][index]);
 			}
+			registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 		} else {
 			if (global_var.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
@@ -599,6 +633,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 					}
 					parent_node.find('.span_value_variable').text(global_var.value[row][index]);
 				}
+				registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 			} else {
 				if (global_var.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(global_var.value[row][index].toFixed(1));
@@ -608,6 +643,7 @@ function enableGlobalMatrixValueUpdate (global_var, row, index, parent_node) {
 			}
 			if (global_var.type == Types.TEXT) {
 				global_var.value[row][index] = input_field.val();
+				registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
 				parent_node.find('.span_value_variable').text(global_var.value[row][index]);
 			}
 			input_field.off();
@@ -659,20 +695,21 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 	}
 
 	input_field.on('input', function() {
-	    var inputWidth = input_field.textWidth()+10;
-	    opened_input_value_global_ar = input_field;
-	    input_field.focus();
+		var inputWidth = input_field.textWidth()+10;
+		opened_input_value_global_ar = input_field;
+		input_field.focus();
 
-	    var tmpStr = input_field.val();
+	  var tmpStr = input_field.val();
 		input_field.val('');
 		input_field.val(tmpStr);
 
-	    input_field.css({
-	        width: inputWidth
-	    })
+		input_field.css({
+				width: inputWidth
+		})
 	}).trigger('input');
 
 	input_field.focusout(function() {
+		let changed = false;
 		/// update array:
 		if (input_field.val().trim()) {
 			if (global_var.type == Types.REAL) {
@@ -687,6 +724,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 				parent_node.find('.span_value_variable').text(global_var.value);
 				
 			}
+			changed = true;
 		} else {
 			if (global_var.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
@@ -696,8 +734,12 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 		}
 		if (global_var.type == Types.TEXT) {
 			global_var.value = input_field.val();
+			changed = true;
 			parent_node.find('.span_value_variable').text(global_var.value);
 		}
+		if (changed) {
+			registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
+		}
 		input_field.off();
 		input_field.remove();
 
@@ -708,7 +750,8 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 	});
 
 	input_field.on('keydown', function(e) {
-		var code = e.keyCode || e.which;
+		const code = e.keyCode || e.which;
+		let changed = true;
 		if(code == 13) {
 			if (input_field.val().trim()) {
 				if (global_var.type == Types.REAL) {
@@ -722,6 +765,7 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 					}
 					parent_node.find('.span_value_variable').text(global_var.value);
 				}
+				changed = true;
 			} else {
 				if (global_var.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(global_var.value.toFixed(1));
@@ -731,8 +775,12 @@ function enableGlobalValueUpdate (global_var, parent_node) {
 			}
 			if (global_var.type == Types.TEXT) {
 				global_var.value = input_field.val();
+				changed = true;
 				parent_node.find('.span_value_variable').text(global_var.value);
 			}
+			if (changed) {
+				registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
+			}
 			input_field.off();
 			input_field.remove();
 
@@ -874,6 +922,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 	}).trigger('input');
 
 	input_field.focusout(function() {
+		let changed = false;
 		/// update array:
 		if (input_field.val().trim()) {
 			if (global_var.type == Types.REAL) {
@@ -891,6 +940,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 				parent_node.find('.span_value_variable').text(global_var.value[index]);
 
 			}
+			changed = true;
 		} else {
 			if (global_var.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
@@ -900,8 +950,12 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 		}
 		if (global_var.type == Types.TEXT) {
 			global_var.value[index] = input_field.val();
+			changed = true;
 			parent_node.find('.span_value_variable').text(global_var.value[index]);
 		}
+		if (changed) {
+			registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
+		}
 		input_field.off();
 		input_field.remove();
 
@@ -911,7 +965,8 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 	});
 
 	input_field.on('keydown', function(e) {
-		var code = e.keyCode || e.which;
+		const code = e.keyCode || e.which;
+		let changed = false;
 		if(code == 13) {
 			if (input_field.val().trim()) {
 				if (global_var.type == Types.REAL) {
@@ -929,6 +984,7 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 					parent_node.find('.span_value_variable').text(global_var.value[index]);
 
 				}
+				changed = true;
 			} else {
 				if (global_var.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(global_var.value[index].toFixed(1));
@@ -938,8 +994,12 @@ function enableGlobalVectorValueUpdate (global_var, index, parent_node) {
 			}
 			if (global_var.type == Types.TEXT) {
 				global_var.value[index] = input_field.val();
+				changed = true;
 				parent_node.find('.span_value_variable').text(global_var.value[index]);
 			}
+			if (changed) {
+				registerUserEvent(global_var.name, ActionTypes.CHANGE_GLOBAL_VALUE, global_var.value);
+			}
 			input_field.off();
 			input_field.remove();
 

+ 112 - 31
js/visualUI/variables.js

@@ -2,6 +2,7 @@ import { Types } from './types';
 import * as Models from './ivprog_elements';
 import { LocalizedStrings } from './../services/localizedStringsService';
 import * as Utils from './utils';
+import { registerUserEvent, registerSystemEvent, ActionTypes } from "./../services/userLog";
 
 var counter_new_variables = 0;
 
@@ -14,6 +15,7 @@ export function addVariable (function_obj, function_container, is_in_click = fal
 
 	counter_new_variables ++;
 
+	registerUserEvent(function_obj.name, ActionTypes.INSERT_FUNCTION_VAR, new_var.name, Types.INTEGER, 0);
 	var newe = renderVariable(function_container, new_var, function_obj);
 
 	if (is_in_click) {
@@ -32,6 +34,7 @@ function updateName (variable_obj, new_name, variable_obj_dom, function_obj) {
 		if (variableNameAlreadyExists(new_name, function_obj)) {
 			Utils.renderErrorMessage(variable_obj_dom.find('.editing_name_var'), LocalizedStrings.getUI('inform_valid_variable_duplicated'));
 		} else {
+			registerUserEvent(function_obj.name, ActionTypes.REMOVE_FUNCTION_VAR, variable_obj.name, new_name);
 			variable_obj.name = new_name;
 		}
 	} else {
@@ -64,8 +67,9 @@ function isValidIdentifier (identifier_str) {
 	return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(identifier_str);
 }
 
-function removeVariable (variable_obj, variable_container) {
+function removeVariable (variable_obj, variable_container, function_name) {
 	var function_associated = variable_container.data('associatedFunction');
+	registerUserEvent(function_name, ActionTypes.REMOVE_FUNCTION_VAR, variable_obj.name);
 
 	var index = function_associated.variables_list.indexOf(variable_obj);
 	if (index > -1) {
@@ -78,42 +82,45 @@ function removeVariable (variable_obj, variable_container) {
 	variable_container.fadeOut();
 }
 
-function updateType (variable_obj, new_type, new_dimensions = 0) {
-	variable_obj.type = new_type;
+function updateType (variable_obj, new_type, function_name, new_dimensions = 0) {
+	variable_obj.type = new_type;		
 	variable_obj.dimensions = new_dimensions;
 
 	if (new_dimensions > 0) {
 		variable_obj.rows = new_dimensions;
 		variable_obj.columns = 2;
 	}
+	registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, variable_obj.name,
+		new_type, new_dimensions, variable_obj.rows, variable_obj.columns);
 
-	updateInitialValues(variable_obj);
+	updateInitialValues(variable_obj, function_name);
 }
 
 function addHandlers (variable_obj, variable_container, function_obj) {
 
 	// Manage variable name: 
 	variable_container.find( ".enable_edit_name_variable" ).on('click', function(e){
+		registerUserEvent(function_obj.name, ActionTypes.ENTER_CHANGE_VAR_NAME, variable_obj.name);
 		enableNameUpdate(variable_obj, variable_container, function_obj);
 	});
 
 	// Menu to change type:
 	variable_container.find('.ui.dropdown.variable_type').dropdown({
-	    onChange: function(value, text, $selectedItem) {
+	    onChange: function(_, __, $selectedItem) {
 	    	if ($selectedItem.data('dimensions')) {
-	    		updateType(variable_obj, Types[$selectedItem.data('type')], $selectedItem.data('dimensions'));
+	    		updateType(variable_obj, Types[$selectedItem.data('type')], function_obj.name, $selectedItem.data('dimensions'));
 	    	} else {
-	    		updateType(variable_obj, Types[$selectedItem.data('type')]);
+	    		updateType(variable_obj, Types[$selectedItem.data('type')], function_obj.name);
 	    	}
 
-	    	renderValues(variable_obj, variable_container);
+	    	renderValues(variable_obj, variable_container, function_obj.name);
 	    },
 	    selectOnKeydown: false
 	});
 
 	// Remove variable: 
 	variable_container.find( ".remove_variable" ).on('click', function(e){
-		removeVariable(variable_obj, variable_container);
+		removeVariable(variable_obj, variable_container, function_obj.name);
 	});
 
 }
@@ -173,7 +180,7 @@ export function renderVariable (function_container, new_var, function_obj) {
 
 	addHandlers(new_var, element, function_obj);
 
-	renderValues(new_var, element);
+	renderValues(new_var, element, function_obj.name);
 
 	return element;
 }
@@ -192,11 +199,11 @@ function updateColumnsAndRowsText (variable_container, variable_var) {
 	}
 }
 
-function renderValues (new_var, variable_container) {
+function renderValues (new_var, variable_container, function_name) {
 
 	var ret = "";
 	var j = 0;
-
+		
 	if (new_var.dimensions == 0) {
 		if (new_var.type == Types.REAL) {
 			ret += '<div class="created_div_valor_var"><span class="span_value_variable simple_var">'+new_var.value.toFixed(1)+'</span> </div> ';
@@ -272,56 +279,87 @@ function renderValues (new_var, variable_container) {
 
 	ret = $(ret);
 
-	$(ret).find('.span_value_variable').data('associatedOject', new_var);
+	$(ret).find('.span_value_variable').		data('associatedOject', new_var);
 
 	$( ret ).find( ".boolean_simple_type" ).on('click', function(e){
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name, new_var.value);
 		alternateBooleanValue(new_var, this.parentNode);
 	});
 	$( ret ).find( ".simple_var" ).on('click', function(e){
-		enableValueUpdate(new_var, this.parentNode);
+		registerUserEvent(function_name, ActionTypes.ENTER_CHANGE_VAR_VALUE, new_var.name);
+		enableValueUpdate(new_var, this.parentNode, function_name);
 	});
 
 	$( ret ).find( ".boolean_vector_var" ).on('click', function(e){
 		alternateBooleanVectorValue(new_var, $(this).data('index'), this.parentNode);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 	});
 	$( ret ).find( ".vector_var" ).on('click', function(e){
-		enableVectorValueUpdate(new_var, $(this).data('index'), this.parentNode);
+		enableVectorValueUpdate(new_var, $(this).data('index'), this.parentNode, function_name);
 	});
 	$( ret ).find( ".remove_global_vector_column" ).on('click', function(e){
 		removeColumnVector(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".add_global_vector_column" ).on('click', function(e){
 		addColumnVector(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".remove_global_matrix_column" ).on('click', function(e){
 		removeColumnMatrix(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".add_global_matrix_column" ).on('click', function(e){
 		addColumnMatrix(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".remove_global_matrix_line" ).on('click', function(e){
 		removeLineMatrix(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".add_global_matrix_line" ).on('click', function(e){
 		addLineMatrix(new_var);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_TYPE, new_var.name,
+			new_var.type, new_var.dimensions, new_var.rows, new_var.columns);
+		registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 		$( variable_container ).find( ".div_valor_var" ).html('');
-		renderValues(new_var, variable_container);
+		renderValues(new_var, variable_container, function_name);
 	});
 	$( ret ).find( ".boolean_matrix_var" ).on('click', function(e){
 		alternateBooleanMatrixValue(new_var, $(this).data('row'), $(this).data('index'), this.parentNode);
+		registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, new_var.name,
+			new_var.value);
 	});
 	$( ret ).find( ".matrix_var" ).on('click', function(e){
-		enableMatrixValueUpdate(new_var, $(this).data('row'), $(this).data('index'), this.parentNode);
+		registerUserEvent(function_name, ActionTypes.ENTER_CHANGE_VAR_VALUE, new_var.name);
+		enableMatrixValueUpdate(new_var, $(this).data('row'), $(this).data('index'), this.parentNode, function_name);
 	});
 	$( variable_container ).find( ".div_valor_var" ).append(ret);
 
@@ -451,7 +489,7 @@ function alternateBooleanVectorValue (var_obj, index, value_container) {
 	$(value_container).find('.span_value_variable').text(LocalizedStrings.getUI(var_obj.value[index]));
 }
 
-function updateInitialValues (variable_obj) {
+function updateInitialValues (variable_obj, function_name) {
 	if (variable_obj.type == Types.INTEGER) {
 		if (variable_obj.dimensions == 0) {
 			variable_obj.value = 1;
@@ -500,11 +538,12 @@ function updateInitialValues (variable_obj) {
 			variable_obj.value = [[true, true], [true, true]];
 		}
 	}
+	registerSystemEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, variable_obj.name, variable_obj.value);
 }
 
 var opened_name_value_vector_global_ = false;
 var opened_input_value_vector_global_ = null;
-function enableVectorValueUpdate (var_obj, index, parent_node) {
+function enableVectorValueUpdate (var_obj, index, parent_node, function_name) {
 	if (opened_name_value_vector_global_) {
 		opened_input_value_vector_global_.focus();
 		return;
@@ -541,6 +580,7 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 	}).trigger('input');
 
 	input_field.focusout(function() {
+		let changed = false;
 		/// update array:
 		if (input_field.val().trim()) {
 			if (var_obj.type == Types.REAL) {
@@ -558,6 +598,7 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 				parent_node.find('.span_value_variable').text(var_obj.value[index]);
 
 			}
+			changed = true;
 		} else {
 			if (var_obj.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(var_obj.value[index].toFixed(1));
@@ -567,8 +608,13 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 		}
 		if (var_obj.type == Types.TEXT) {
 			var_obj.value[index] = input_field.val();
+			changed = true;
 			parent_node.find('.span_value_variable').text(var_obj.value[index]);
 		}
+		if (changed) {
+			registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+				var_obj.value);
+		}
 		input_field.off();
 		input_field.remove();
 
@@ -578,7 +624,8 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 	});
 
 	input_field.on('keydown', function(e) {
-		var code = e.keyCode || e.which;
+		const code = e.keyCode || e.which;
+		let changed = false;
 		if(code == 13) {
 			if (input_field.val().trim()) {
 				if (var_obj.type == Types.REAL) {
@@ -596,6 +643,7 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 					parent_node.find('.span_value_variable').text(var_obj.value[index]);
 
 				}
+				changed = true;
 			} else {
 				if (var_obj.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(var_obj.value[index].toFixed(1));
@@ -605,8 +653,13 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 			}
 			if (var_obj.type == Types.TEXT) {
 				var_obj.value[index] = input_field.val();
+				changed = true;
 				parent_node.find('.span_value_variable').text(var_obj.value[index]);
 			}
+			if (changed) {
+				registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+					var_obj.value);
+			}
 			input_field.off();
 			input_field.remove();
 
@@ -634,7 +687,7 @@ function enableVectorValueUpdate (var_obj, index, parent_node) {
 
 var opened_name_value_global_var = false;
 var opened_input_value_global_ar = null;
-function enableValueUpdate (var_obj, parent_node) {
+function enableValueUpdate (var_obj, parent_node, function_name) {
 	if (opened_name_value_global_var) {
 		opened_input_value_global_ar.focus();
 		return;
@@ -671,6 +724,7 @@ function enableValueUpdate (var_obj, parent_node) {
 
 	input_field.focusout(function() {
 		/// update array:
+		let changed = false;
 		if (input_field.val().trim()) {
 			if (var_obj.type == Types.REAL) {
 				var_obj.value = parseFloat(input_field.val().trim());
@@ -684,6 +738,7 @@ function enableValueUpdate (var_obj, parent_node) {
 				parent_node.find('.span_value_variable').text(var_obj.value);
 				
 			}
+			changed = true;
 		} else {
 			if (var_obj.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(var_obj.value.toFixed(1));
@@ -693,8 +748,13 @@ function enableValueUpdate (var_obj, parent_node) {
 		}
 		if (var_obj.type == Types.TEXT) {
 			var_obj.value = input_field.val();
+			changed = true;
 			parent_node.find('.span_value_variable').text(var_obj.value);
 		}
+		if (changed) {
+			registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+				var_obj.value);
+		}
 		input_field.off();
 		input_field.remove();
 
@@ -705,7 +765,8 @@ function enableValueUpdate (var_obj, parent_node) {
 	});
 
 	input_field.on('keydown', function(e) {
-		var code = e.keyCode || e.which;
+		const code = e.keyCode || e.which;
+		let changed = false;
 		if(code == 13) {
 			if (input_field.val().trim()) {
 				if (var_obj.type == Types.REAL) {
@@ -719,6 +780,7 @@ function enableValueUpdate (var_obj, parent_node) {
 					}
 					parent_node.find('.span_value_variable').text(var_obj.value);
 				}
+				changed = true;
 			} else {
 				if (var_obj.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(var_obj.value.toFixed(1));
@@ -728,8 +790,13 @@ function enableValueUpdate (var_obj, parent_node) {
 			}
 			if (var_obj.type == Types.TEXT) {
 				var_obj.value = input_field.val();
+				changed = true;
 				parent_node.find('.span_value_variable').text(var_obj.value);
 			}
+			if (changed) {
+				registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+					var_obj.value);
+			}
 			input_field.off();
 			input_field.remove();
 
@@ -776,7 +843,7 @@ function enableNameUpdate (variable_obj, variable_container, function_obj) {
 	input_name.on('input', function() {
 	    var inputWidth = input_name.textWidth()+10;
 	    opened_input_global = input_name;
-	    input_name.focus();
+	    input_name.focus();					
 
 	    var tmpStr = input_name.val();
 		input_name.val('');
@@ -838,7 +905,7 @@ function enableNameUpdate (variable_obj, variable_container, function_obj) {
 
 var opened_name_value_matrix_global_v = false;
 var opened_input_value_matrix_global_v = null;
-function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
+function enableMatrixValueUpdate (var_obj, row, index, parent_node, function_name) {
 	if (opened_name_value_matrix_global_v) {
 		opened_input_value_matrix_global_v.focus();
 		return;
@@ -875,13 +942,14 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 	}).trigger('input');
 
 	input_field.focusout(function() {
+		let changed = false;
 		/// update array:
 		if (input_field.val().trim()) {
 			if (var_obj.type == Types.REAL) {
 				var_obj.value[row][index] = parseFloat(input_field.val().trim());
 
 				parent_node.find('.span_value_variable').text(var_obj.value[row][index].toFixed(1));
-			} else {
+			} else {					
 				if (var_obj.type == Types.INTEGER) {
 					var_obj.value[row][index] = parseInt(input_field.val().trim());
 				} else {
@@ -889,6 +957,7 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 				}
 				parent_node.find('.span_value_variable').text(var_obj.value[row][index]);
 			}
+			changed = true;
 		} else {
 			if (var_obj.type == Types.REAL) {
 				parent_node.find('.span_value_variable').text(var_obj.value[row][index].toFixed(1));
@@ -898,8 +967,13 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 		}
 		if (var_obj.type == Types.TEXT) {
 			var_obj.value[row][index] = input_field.val();
+			changed = true;
 			parent_node.find('.span_value_variable').text(var_obj.value[row][index]);
 		}
+		if (changed) {
+			registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+				var_obj.value);
+		}
 		input_field.off();
 		input_field.remove();
 
@@ -909,7 +983,8 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 	});
 
 	input_field.on('keydown', function(e) {
-		var code = e.keyCode || e.which;
+		const code = e.keyCode || e.which;
+		let changed = false;
 		if(code == 13) {
 			if (input_field.val().trim()) {
 				if (var_obj.type == Types.REAL) {
@@ -924,6 +999,7 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 					}
 					parent_node.find('.span_value_variable').text(var_obj.value[row][index]);
 				}
+				changed = true;
 			} else {
 				if (var_obj.type == Types.REAL) {
 					parent_node.find('.span_value_variable').text(var_obj.value[row][index].toFixed(1));
@@ -933,8 +1009,13 @@ function enableMatrixValueUpdate (var_obj, row, index, parent_node) {
 			}
 			if (var_obj.type == Types.TEXT) {
 				var_obj.value[row][index] = input_field.val();
+				changed = true;
 				parent_node.find('.span_value_variable').text(var_obj.value[row][index]);
 			}
+			if (changed) {
+				registerUserEvent(function_name, ActionTypes.CHANGE_VAR_VALUE, var_obj.name,
+					var_obj.value);
+			}
 			input_field.off();
 			input_field.remove();
 

+ 1 - 1
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "ivprog",
-  "version": "0.1.0",
+  "version": "1.1.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {