All Downloads are FREE. Search and download functionalities are using the official Maven repository.

static.script.js Maven / Gradle / Ivy

There is a newer version: 4.3.2
Show newest version

// Hash array that holds all graphs/models.
var graphs = [];
var currentModelId;
var pauseExecution = false;
var stepExecution = false;
var isTestRunning = false;
var keys = {};
var issues;
var currentElement;
var currentExecutingElementId;
var mouseoverElement;
var rightClickedElement;
var rightClickedRenderedPosition;
var breakPoints = [];
$('#location').val('ws://localhost:9999');

function onConnect() {
  console.log('onConnect');

  onDisconnect();

  var wsUri = $.trim($('#location').val());
  try {
    testWebSocket(wsUri);
  } catch (err) {
    document.getElementById('issues').innerHTML = err.message;
  }
}

function onDisconnect() {
  console.log('onDisconnect');
  if (websocket) {
    // http://stackoverflow.com/questions/25779831/how-to-catch-websocket-connection-to-ws-xxxnn-failed-connection-closed-be
    // https://jsfiddle.net/lamarant/ry0ty52n/
    websocket.close(3001);
  }
}

function onNewTest() {
  console.log('onNewTest');
  removeTest();
  emptyInitialControlStates();
  defaultUI();
}

function onLoadTest() {
  console.log('onLoadTest');

  removeTest();

  $('')
    .appendTo('body')
    .focus()
    .trigger('click')
    .remove()
    .change(function(evt) {
      var files = evt.target.files; // FileList object


      // files is a FileList of File objects. List some properties.
      for (var i = 0, f; f = files[i]; i++) {
        var fileExt = f.name.split('.').pop();

        switch (fileExt) {
          case 'graphml':
            var fr = new FileReader();
            fr.onload = function(e) {
              var convertGraphml = {
                command: 'convertGraphml',
                graphml: e.target.result
              };
              doSend(JSON.stringify(convertGraphml));
            };
            fr.readAsText(f);
            break;

          case 'json':
            var fr = new FileReader();
            fr.onload = function(e) {
              readGraphFromJSON(JSON.parse(e.target.result));
              var tabs = $('#tabs');
              tabs.show();
              for (var modelId in graphs) {
                if (!graphs.hasOwnProperty(modelId)) {
                  continue;
                }
                var index = $('#tabs').find('a[href="#A-' + modelId + '"]').parent().index();
                tabs.tabs('option', 'active', index);
                graphs[modelId].resize();
                graphs[modelId].fit();
              }
              defaultUI();
            };
            fr.readAsText(f);
            break;

          default:
            console.error('Unsupported file extension/format: ' + fileExt);
        }
      }
    });
}

function onSaveTest() {
  console.log('onSaveTest');
  var link = document.createElement('a');
  link.setAttribute('download', graphs.name + '.json');
  link.href = makeJsonGraphFile();
  document.body.appendChild(link);

  // wait for the link to be added to the document
  window.requestAnimationFrame(function() {
    var event = new MouseEvent('click');
    link.dispatchEvent(event);
    document.body.removeChild(link);
  });
}

function removeTest() {
  console.log('removeTest');

  $('#tabs > ul > li').each(function() {
    $(this).remove();
  });

  $('#tabs > div').each(function() {
    var id = $(this).attr('id').substr(2);
    $(this).remove();
    $('#A-' + id).remove();
    removeModel(id);
  });

  var tabs = $('#tabs');
  tabs.tabs('refresh');
  tabs.hide();
}

function makeJsonGraphFile() {
  console.log('makeJsonGraphFile');
  var jsonFile = null;
  var data = new Blob([JSON.stringify(generateJsonGraph())], {
    type: 'text/plain'
  });

  // If we are replacing a previously generated file we need to
  // manually revoke the object URL to avoid memory leaks.
  if (jsonFile !== null) {
    window.URL.revokeObjectURL(jsonFile);
  }

  jsonFile = window.URL.createObjectURL(data);

  return jsonFile;
}

function generateJsonGraph() {
  var jsonGraphs = {
    name: graphs.name,
    models: []
  };
  for (var modelId in graphs) {
    if (!graphs.hasOwnProperty(modelId)) {
      continue;
    }

    var actions = [];
    if (graphs[modelId].actions) {
      actions.push(graphs[modelId].actions);
    }
    var requirements = [];
    if (graphs[modelId].requirements) {
      requirements = graphs[modelId].requirements.split(',');
    }

    var model = {
      name: graphs[modelId].name,
      id: modelId,
      generator: graphs[modelId].generator,
      actions: actions,
      vertices: [],
      edges: []
    };

    if (graphs[modelId].startElementId !== undefined) {
      model.startElementId = graphs[modelId].startElementId;
    }


    /**
     * Iterate ove all nodes in the graph, and create a json
     * representation of the vertex
     */
    graphs[modelId].nodes().each(function(index, node) {

      if (node.data().startVertex === true) {
        return true;
      }

      var actions = [];
      if (node.data().actions) {
        actions.push(node.data().actions);
      }

      var requirements = [];
      if (node.data().requirements) {
        requirements = node.data().requirements.split(',');
      }

      var properties = {};
      if (node.data().properties) {
        properties = node.data().properties;
      }
      properties['x'] = node.position().x;
      properties['y'] = node.position().y;

      var vertex = {
        id: node.data().id,
        name: node.data().label,
        sharedState: node.data().sharedState,
        actions: actions,
        requirements: requirements,
        properties: properties
      };
      model.vertices.push(vertex);
    });


    /**
     * Iterate over all edges in the graph, and create a json
     * representation of the edge
     */
    graphs[modelId].edges().each(function(index, edge) {

      if (edge.data().source === 'Start') {
        edge.data().source = null;
      }

      var actions = [];
      if (edge.data().actions) {
        actions.push(edge.data().actions);
      }

      var requirements = [];
      if (edge.data().requirements) {
        requirements = edge.data().requirements.split(',');
      }

      var properties = [];
      if (edge.data().properties) {
        properties = edge.data().properties;
      }

      var newEdge = {
        id: edge.data().id,
        name: edge.data().label,
        guard: edge.data().guard,
        weight: edge.data().weight,
        actions: actions,
        requirements: requirements,
        properties: properties,
        sourceVertexId: edge.data().source,
        targetVertexId: edge.data().target
      };
      model.edges.push(newEdge);

    });

    jsonGraphs.models.push(model);
  }

  return jsonGraphs;
}

function onPausePlayExecution(element) {
  console.log('pausePlayExecution: pauseExecution: ' + pauseExecution + ', clicked: ' + currentModelId);
  stepExecution = false;

  if (pauseExecution) {
    document.getElementById('runTest').disabled = true;
    document.getElementById('resetTest').disabled = true;
    document.getElementById('pausePlayExecution').disabled = false;
    document.getElementById('stepExecution').disabled = true;
    document.getElementById('pausePlayExecution').innerHTML = 'Pause';
    pauseExecution = false;

    var hasNext = {
      command: 'hasNext'
    };
    doSend(JSON.stringify(hasNext));
  } else {
    document.getElementById('runTest').disabled = true;
    document.getElementById('resetTest').disabled = false;
    document.getElementById('pausePlayExecution').disabled = false;
    document.getElementById('stepExecution').disabled = false;
    document.getElementById('pausePlayExecution').innerHTML = 'Run';
    pauseExecution = true;
  }
}

function onStepExecution() {
  console.log('onStepExecution: ' + currentModelId);
  document.getElementById('runTest').disabled = true;
  document.getElementById('resetTest').disabled = false;
  document.getElementById('pausePlayExecution').disabled = false;
  document.getElementById('stepExecution').disabled = false;
  stepExecution = true;

  var hasNext = {
    command: 'hasNext'
  };
  doSend(JSON.stringify(hasNext));
}

// Run the execution of the state machine
function onRunTest() {
  console.log('onRunTest: ' + currentModelId);

  // Reset any previous runs
  onResetTest();
  isTestRunning = true;

  $('.ui-panel').panel('close');

  document.getElementById('runTest').disabled = true;
  document.getElementById('resetTest').disabled = true;
  document.getElementById('pausePlayExecution').disabled = false;
  document.getElementById('stepExecution').disabled = true;
  document.getElementById('addModel').disabled = true;
  stepExecution = false;
  pauseExecution = false;

  var start = {
    command: 'start',
  };

  start.gw = generateJsonGraph();
  doSend(JSON.stringify(start));
}

// Reset the state machine to it's initial state
function onResetTest() {
  console.log('onResetTest: ' + currentModelId);
  isTestRunning = false;
  defaultUI();

  document.getElementById('issues').innerHTML = 'Ready';

  for (var modelId in graphs) {
    if (!graphs.hasOwnProperty(modelId)) {
      continue;
    }

    graphs[modelId].nodes().unselect();
    graphs[modelId].edges().unselect();
  }
  setElementsColor();
}

function onAddModel() {
  console.log('onAddModel');
  enableModelControls();

  var id = generateUUID();
  var graph = createTab(id, 'New model');
  graph.name = 'New model';
  var tabs = $('#tabs');
  var index = tabs.find('a[href="#A-' + id + '"]').parent().index();
  tabs.show().tabs('option', 'active', index);
}

function onDoLayout() {
  console.log('onDoLayout');
  if (graphs[currentModelId] !== undefined) {
    graphs[currentModelId].layout().stop();
    var layout = graphs[currentModelId].makeLayout({
      name: 'dagre',
      animate: true,
      edgeSep: 4,
      minLen: function() {
        return 2;
      }
    });
    layout.run();
  }
}


window.graphwalker = {
  onConnect: onConnect,
  onDisconnect: onDisconnect,
  onNewTest: onNewTest,
  onLoadTest: onLoadTest,
  onSaveTest: onSaveTest,
  removeTest: removeTest,
  makeJsonGraphFile: makeJsonGraphFile,
  generateJsonGraph: generateJsonGraph,
  onPausePlayExecution: onPausePlayExecution,
  onStepExecution: onStepExecution,
  onRunTest: onRunTest,
  onResetTest: onResetTest,
  onAddModel: onAddModel,
  onDoLayout: onDoLayout
}

  window.onConnect = onConnect;
  window.onDisconnect = onDisconnect;
  window.onNewTest = onNewTest;
  window.onLoadTest = onLoadTest;
  window.onSaveTest = onSaveTest;
  window.removeTest = removeTest;
  window.makeJsonGraphFile = makeJsonGraphFile;
  window.generateJsonGraph = generateJsonGraph;
  window.onPausePlayExecution = onPausePlayExecution;
  window.onStepExecution = onStepExecution;
  window.onRunTest = onRunTest;
  window.onResetTest = onResetTest;
  window.onAddModel = onAddModel;
  window.onDoLayout = onDoLayout;

/*
 ************************************************************************
 * CREATE SOME CUSTOM EVENTS THAT HANDLES MODEL EXECUTION
 ************************************************************************
 */
var playbackEvent = new CustomEvent('playbackEvent', {});
document.addEventListener('playbackEvent', function() {
  console.log('playbackEvent');

  var getModel = {
    command: 'getModel'
  };
  doSend(JSON.stringify(getModel));
});

var startEvent = new CustomEvent('startEvent', {});
document.addEventListener('startEvent', function() {
  console.log('startEvent: ' + currentModelId);

  // Change some UI elements
  document.getElementById('runTest').disabled = true;
  document.getElementById('resetTest').disabled = true;
  document.getElementById('pausePlayExecution').disabled = false;
  document.getElementById('stepExecution').disabled = true;

  var hasNext = {
    command: 'hasNext'
  };
  doSend(JSON.stringify(hasNext));
});

var hasNextEvent = new CustomEvent('hasNextEvent', {});
document.addEventListener('hasNextEvent', function() {
  console.log('hasNextEvent: pauseExecution: ' + pauseExecution +
    ', stepExecution: ' + stepExecution + ' : modelId ' + currentModelId);
  if (pauseExecution) {
    if (!stepExecution) {
      return;
    }
  }
  var getNext = {
    command: 'getNext'
  };
  doSend(JSON.stringify(getNext));
});

var getNextEvent = new CustomEvent('getNextEvent', {
  "modelId": "",
  "elementId": "",
  "name": ""
});
document.addEventListener('getNextEvent', function(e) {
  console.log('getNextEvent: ' + e.id + ': ' + e.name + 'pauseExecution: ' + pauseExecution +
    ', stepExecution: ' + stepExecution + ' : modelId ' + currentModelId);

  if (breakPoints.some(function(e) {
      return e.data().id === currentExecutingElementId
    })) {
    onPausePlayExecution(currentExecutingElementId);
    return;
  }

  if (stepExecution) {
    stepExecution = false;
    return;
  }

  var hasNext = {
    command: 'hasNext'
  };
  setTimeout(function() {
    doSend(JSON.stringify(hasNext));
  }, $.trim($('#executionSpeedSlider').val()));
});

var getModelEvent = new CustomEvent('getModelEvent', {});
document.addEventListener('getModelEvent', function(e) {
  console.log('getModelEvent');

  var updateAllElements = {
    command: 'updateAllElements'
  };
  doSend(JSON.stringify(updateAllElements));
});

function removeModel(modelId) {
  console.log('Remove model with id: ' + modelId);
  delete graphs[modelId];
}


document.addEventListener('DOMContentLoaded', function() {
  var tabs = $('#tabs');
  var modelRequirements = $('#modelRequirements');
  var modelActions = $('#modelActions');
  var modelName = $('#modelName');
  var generator = $('#generator');

  tabs.delegate('span.ui-icon-close', 'click', function() {
    var id = $(this).closest('li').remove().attr('aria-controls').substr(2);
    $('#A-' + id).remove();
    tabs.tabs('refresh');
    if (tabs.find('li').length < 1) {
      tabs.hide();
    }
    removeModel(id);
  });

  tabs.tabs({
    activate: function(event, ui) {
      currentModelId = ui.newPanel.attr('id').substr(2);
      console.log('tabs activate: ' + currentModelId);
      graphs[currentModelId].resize();
      modelName.val(graphs[currentModelId].name);
      generator.val(graphs[currentModelId].generator);
      modelActions.val(graphs[currentModelId].actions);
      modelRequirements.val(graphs[currentModelId].requirements);
    }
  });

  // Hide the tab component. It will get visible when the graphs are loaded.
  tabs.hide();

  $(document).keyup(function(e) {
    console.log('key up: ' + e.which);
    delete keys[e.which];
  });

  $(document).keydown(function(e) {
    console.log('key down: ' + e.which);
    keys[e.which] = true;

    if (keys[46]) { // Delete key is pressed
      if (graphs[currentModelId] !== undefined) {
        graphs[currentModelId].remove(':selected');
      }
    }
  });

  modelName.on('input', function() {
    if (graphs[currentModelId]) {
      graphs[currentModelId].name = $.trim(modelName.val());
      var tabs = $('#tabs');
      var selectedTab = tabs.tabs('option', 'selected');
      tabs.find('ul li a').eq(selectedTab).text($.trim(modelName.val()));
    }
  });

  generator.on('input', function() {
    if (graphs[currentModelId]) {
      graphs[currentModelId].generator = $.trim(generator.val());
    }
  });

  modelActions.on('input', function() {
    if (graphs[currentModelId]) {
      graphs[currentModelId].actions = $.trim(modelActions.val());
    }
  });

  modelRequirements.on('input', function() {
    if (graphs[currentModelId]) {
      graphs[currentModelId].requirements = $.trim(modelRequirements.val());
    }
  });
});


function createTab(modelId, modelName) {
  console.log('createTab: ' + modelId + ', ' + modelName);
  enableModelControls();

  var tabs = $('#tabs').tabs();
  var ul = tabs.find('ul');

  // ID tokens must begin with a letter ([A-Za-z])
  // https://www.w3.org/TR/html401/types.html#type-name
  var href = '#A-' + modelId;
  $('
  • ' + modelName + '
  • ').appendTo(ul); $('
    ').appendTo(tabs); tabs.tabs('refresh'); $('