summaryrefslogtreecommitdiff
path: root/src/js/util/mxSession.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/util/mxSession.js')
-rw-r--r--src/js/util/mxSession.js674
1 files changed, 0 insertions, 674 deletions
diff --git a/src/js/util/mxSession.js b/src/js/util/mxSession.js
deleted file mode 100644
index 4c2a70c..0000000
--- a/src/js/util/mxSession.js
+++ /dev/null
@@ -1,674 +0,0 @@
-/**
- * $Id: mxSession.js,v 1.46 2012-08-22 15:30:49 gaudenz Exp $
- * Copyright (c) 2006-2010, JGraph Ltd
- */
-/**
- * Class: mxSession
- *
- * Session for sharing an <mxGraphModel> with other parties
- * via a backend that acts as a multicaster for all changes.
- *
- * Diagram Sharing:
- *
- * The diagram sharing is a mechanism where each atomic change of the model is
- * encoded into XML using <mxCodec> and then transmitted to the server by the
- * <mxSession> object. On the server, the XML data is dispatched to each
- * listener on the same diagram (except the sender), and the XML is decoded
- * back into atomic changes on the client side, which are then executed on the
- * model and stored in the command history.
- *
- * The <mxSession.significantRemoteChanges> specifies how these changes are
- * treated with respect to undo: The default value (true) will undo the last
- * change regardless of whether it was a remote or a local change. If the
- * switch is false, then an undo will go back until the last local change,
- * silently undoing all remote changes up to that point. Note that these
- * changes will be added as new remote changes to the history of the other
- * clients.
- *
- * Event: mxEvent.CONNECT
- *
- * Fires after the session has been started, that is, after the response to the
- * initial request was received and the session goes into polling mode. This
- * event has no properties.
- *
- * Event: mxEvent.SUSPEND
- *
- * Fires after <suspend> was called an the session was not already in suspended
- * state. This event has no properties.
- *
- * Event: mxEvent.RESUME
- *
- * Fires after the session was resumed in <resume>. This event has no
- * properties.
- *
- * Event: mxEvent.DISCONNECT
- *
- * Fires after the session was stopped in <stop>. The <code>reason</code>
- * property contains the optional exception that was passed to the stop method.
- *
- * Event: mxEvent.NOTIFY
- *
- * Fires after a notification was sent in <notify>. The <code>url</code>
- * property contains the URL and the <code>xml</code> property contains the XML
- * data of the request.
- *
- * Event: mxEvent.GET
- *
- * Fires after a response was received in <get>. The <code>url</code> property
- * contains the URL and the <code>request</code> is the <mxXmlRequest> that
- * contains the response.
- *
- * Event: mxEvent.FIRED
- *
- * Fires after an array of edits has been executed on the model. The
- * <code>changes</code> property contains the array of changes.
- *
- * Event: mxEvent.RECEIVE
- *
- * Fires after an XML node was received in <receive>. The <code>node</code>
- * property contains the node that was received.
- *
- * Constructor: mxSession
- *
- * Constructs a new session using the given <mxGraphModel> and URLs to
- * communicate with the backend.
- *
- * Parameters:
- *
- * model - <mxGraphModel> that contains the data.
- * urlInit - URL to be used for initializing the session.
- * urlPoll - URL to be used for polling the backend.
- * urlNotify - URL to be used for sending changes to the backend.
- */
-function mxSession(model, urlInit, urlPoll, urlNotify)
-{
- this.model = model;
- this.urlInit = urlInit;
- this.urlPoll = urlPoll;
- this.urlNotify = urlNotify;
-
- // Resolves cells by id using the model
- if (model != null)
- {
- this.codec = new mxCodec();
-
- this.codec.lookup = function(id)
- {
- return model.getCell(id);
- };
- }
-
- // Adds the listener for notifying the backend of any
- // changes in the model
- model.addListener(mxEvent.NOTIFY, mxUtils.bind(this, function(sender, evt)
- {
- var edit = evt.getProperty('edit');
-
- if (edit != null && this.debug || (this.connected && !this.suspended))
- {
- this.notify('<edit>'+this.encodeChanges(edit.changes, edit.undone)+'</edit>');
- }
- }));
-};
-
-/**
- * Extends mxEventSource.
- */
-mxSession.prototype = new mxEventSource();
-mxSession.prototype.constructor = mxSession;
-
-/**
- * Variable: model
- *
- * Reference to the enclosing <mxGraphModel>.
- */
-mxSession.prototype.model = null;
-
-/**
- * Variable: urlInit
- *
- * URL to initialize the session.
- */
-mxSession.prototype.urlInit = null;
-
-/**
- * Variable: urlPoll
- *
- * URL for polling the backend.
- */
-mxSession.prototype.urlPoll = null;
-
-/**
- * Variable: urlNotify
- *
- * URL to send changes to the backend.
- */
-mxSession.prototype.urlNotify = null;
-
-/**
- * Variable: codec
- *
- * Reference to the <mxCodec> used to encoding and decoding changes.
- */
-mxSession.prototype.codec = null;
-
-/**
- * Variable: linefeed
- *
- * Used for encoding linefeeds. Default is '&#xa;'.
- */
-mxSession.prototype.linefeed = '&#xa;';
-
-/**
- * Variable: escapePostData
- *
- * Specifies if the data in the post request sent in <notify>
- * should be converted using encodeURIComponent. Default is true.
- */
-mxSession.prototype.escapePostData = true;
-
-/**
- * Variable: significantRemoteChanges
- *
- * Whether remote changes should be significant in the
- * local command history. Default is true.
- */
-mxSession.prototype.significantRemoteChanges = true;
-
-/**
- * Variable: sent
- *
- * Total number of sent bytes.
- */
-mxSession.prototype.sent = 0;
-
-/**
- * Variable: received
- *
- * Total number of received bytes.
- */
-mxSession.prototype.received = 0;
-
-/**
- * Variable: debug
- *
- * Specifies if the session should run in debug mode. In this mode, no
- * connection is established. The data is written to the console instead.
- * Default is false.
- */
-mxSession.prototype.debug = false;
-
-/**
- * Variable: connected
- */
-mxSession.prototype.connected = false;
-
-/**
- * Variable: send
- */
-mxSession.prototype.suspended = false;
-
-/**
- * Variable: polling
- */
-mxSession.prototype.polling = false;
-
-/**
- * Function: start
- */
-mxSession.prototype.start = function()
-{
- if (this.debug)
- {
- this.connected = true;
- this.fireEvent(new mxEventObject(mxEvent.CONNECT));
- }
- else if (!this.connected)
- {
- this.get(this.urlInit, mxUtils.bind(this, function(req)
- {
- this.connected = true;
- this.fireEvent(new mxEventObject(mxEvent.CONNECT));
- this.poll();
- }));
- }
-};
-
-/**
- * Function: suspend
- *
- * Suspends the polling. Use <resume> to reactive the session. Fires a
- * suspend event.
- */
-mxSession.prototype.suspend = function()
-{
- if (this.connected && !this.suspended)
- {
- this.suspended = true;
- this.fireEvent(new mxEventObject(mxEvent.SUSPEND));
- }
-};
-
-/**
- * Function: resume
- *
- * Resumes the session if it has been suspended. Fires a resume-event
- * before starting the polling.
- */
-mxSession.prototype.resume = function(type, attr, value)
-{
- if (this.connected &&
- this.suspended)
- {
- this.suspended = false;
- this.fireEvent(new mxEventObject(mxEvent.RESUME));
-
- if (!this.polling)
- {
- this.poll();
- }
- }
-};
-
-/**
- * Function: stop
- *
- * Stops the session and fires a disconnect event. The given reason is
- * passed to the disconnect event listener as the second argument.
- */
-mxSession.prototype.stop = function(reason)
-{
- if (this.connected)
- {
- this.connected = false;
- }
-
- this.fireEvent(new mxEventObject(mxEvent.DISCONNECT,
- 'reason', reason));
-};
-
-/**
- * Function: poll
- *
- * Sends an asynchronous GET request to <urlPoll>.
- */
-mxSession.prototype.poll = function()
-{
- if (this.connected &&
- !this.suspended &&
- this.urlPoll != null)
- {
- this.polling = true;
-
- this.get(this.urlPoll, mxUtils.bind(this, function()
- {
- this.poll();
- }));
- }
- else
- {
- this.polling = false;
- }
-};
-
-/**
- * Function: notify
- *
- * Sends out the specified XML to <urlNotify> and fires a <notify> event.
- */
-mxSession.prototype.notify = function(xml, onLoad, onError)
-{
- if (xml != null &&
- xml.length > 0)
- {
- if (this.urlNotify != null)
- {
- if (this.debug)
- {
- mxLog.show();
- mxLog.debug('mxSession.notify: '+this.urlNotify+' xml='+xml);
- }
- else
- {
- xml = '<message><delta>'+xml+'</delta></message>';
-
- if (this.escapePostData)
- {
- xml = encodeURIComponent(xml);
- }
-
- mxUtils.post(this.urlNotify, 'xml='+xml, onLoad, onError);
- }
- }
-
- this.sent += xml.length;
- this.fireEvent(new mxEventObject(mxEvent.NOTIFY,
- 'url', this.urlNotify, 'xml', xml));
- }
-};
-
-/**
- * Function: get
- *
- * Sends an asynchronous get request to the given URL, fires a <get> event
- * and invokes the given onLoad function when a response is received.
- */
-mxSession.prototype.get = function(url, onLoad, onError)
-{
- // Response after browser refresh has no global scope
- // defined. This response is ignored and the session
- // stops implicitely.
- if (typeof(mxUtils) != 'undefined')
- {
- var onErrorWrapper = mxUtils.bind(this, function(ex)
- {
- if (onError != null)
- {
- onError(ex);
- }
- else
- {
- this.stop(ex);
- }
- });
-
- // Handles a successful response for
- // the above request.
- mxUtils.get(url, mxUtils.bind(this, function(req)
- {
- if (typeof(mxUtils) != 'undefined')
- {
- if (req.isReady() && req.getStatus() != 404)
- {
- this.received += req.getText().length;
- this.fireEvent(new mxEventObject(mxEvent.GET, 'url', url, 'request', req));
-
- if (this.isValidResponse(req))
- {
- if (req.getText().length > 0)
- {
- var node = req.getDocumentElement();
-
- if (node == null)
- {
- onErrorWrapper('Invalid response: '+req.getText());
- }
- else
- {
- this.receive(node);
- }
- }
-
- if (onLoad != null)
- {
- onLoad(req);
- }
- }
- }
- else
- {
- onErrorWrapper('Response not ready');
- }
- }
- }),
- // Handles a transmission error for the
- // above request
- function(req)
- {
- onErrorWrapper('Transmission error');
- });
- }
-};
-
-/**
- * Function: isValidResponse
- *
- * Returns true if the response data in the given <mxXmlRequest> is valid.
- */
-mxSession.prototype.isValidResponse = function(req)
-{
- // TODO: Find condition to check if response
- // contains valid XML (not eg. the PHP code).
- return req.getText().indexOf('<?php') < 0;
-};
-
-/**
- * Function: encodeChanges
- *
- * Returns the XML representation for the given array of changes.
- */
-mxSession.prototype.encodeChanges = function(changes, invert)
-{
- // TODO: Use array for string concatenation
- var xml = '';
- var step = (invert) ? -1 : 1;
- var i0 = (invert) ? changes.length - 1 : 0;
-
- for (var i = i0; i >= 0 && i < changes.length; i += step)
- {
- // Newlines must be kept, they will be converted
- // to &#xa; when the server sends data to the
- // client
- var node = this.codec.encode(changes[i]);
- xml += mxUtils.getXml(node, this.linefeed);
- }
-
- return xml;
-};
-
-/**
- * Function: receive
- *
- * Processes the given node by applying the changes to the model. If the nodename
- * is state, then the namespace is used as a prefix for creating Ids in the model,
- * and the child nodes are visited recursively. If the nodename is delta, then the
- * changes encoded in the child nodes are applied to the model. Each call to the
- * receive function fires a <receive> event with the given node as the second argument
- * after processing. If changes are processed, then the function additionally fires
- * a <mxEvent.FIRED> event before the <mxEvent.RECEIVE> event.
- */
-mxSession.prototype.receive = function(node)
-{
- if (node != null && node.nodeType == mxConstants.NODETYPE_ELEMENT)
- {
- // Uses the namespace in the model
- var ns = node.getAttribute('namespace');
-
- if (ns != null)
- {
- this.model.prefix = ns + '-';
- }
-
- var child = node.firstChild;
-
- while (child != null)
- {
- var name = child.nodeName.toLowerCase();
-
- if (name == 'state')
- {
- this.processState(child);
- }
- else if (name == 'delta')
- {
- this.processDelta(child);
- }
-
- child = child.nextSibling;
- }
-
- // Fires receive event
- this.fireEvent(new mxEventObject(mxEvent.RECEIVE, 'node', node));
- }
-};
-
-/**
- * Function: processState
- *
- * Processes the given state node which contains the current state of the
- * remote model.
- */
-mxSession.prototype.processState = function(node)
-{
- var dec = new mxCodec(node.ownerDocument);
- dec.decode(node.firstChild, this.model);
-};
-
-/**
- * Function: processDelta
- *
- * Processes the given delta node which contains a sequence of edits which in
- * turn map to one transaction on the remote model each.
- */
-mxSession.prototype.processDelta = function(node)
-{
- var edit = node.firstChild;
-
- while (edit != null)
- {
- if (edit.nodeName == 'edit')
- {
- this.processEdit(edit);
- }
-
- edit = edit.nextSibling;
- }
-};
-
-/**
- * Function: processEdit
- *
- * Processes the given edit by executing its changes and firing the required
- * events via the model.
- */
-mxSession.prototype.processEdit = function(node)
-{
- var changes = this.decodeChanges(node);
-
- if (changes.length > 0)
- {
- var edit = this.createUndoableEdit(changes);
-
- // No notify event here to avoid the edit from being encoded and transmitted
- // LATER: Remove changes property (deprecated)
- this.model.fireEvent(new mxEventObject(mxEvent.CHANGE,
- 'edit', edit, 'changes', changes));
- this.model.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
- this.fireEvent(new mxEventObject(mxEvent.FIRED, 'edit', edit));
- }
-};
-
-/**
- * Function: createUndoableEdit
- *
- * Creates a new <mxUndoableEdit> that implements the notify function to fire a
- * <change> and <notify> event via the model.
- */
-mxSession.prototype.createUndoableEdit = function(changes)
-{
- var edit = new mxUndoableEdit(this.model, this.significantRemoteChanges);
- edit.changes = changes;
-
- edit.notify = function()
- {
- // LATER: Remove changes property (deprecated)
- edit.source.fireEvent(new mxEventObject(mxEvent.CHANGE,
- 'edit', edit, 'changes', edit.changes));
- edit.source.fireEvent(new mxEventObject(mxEvent.NOTIFY,
- 'edit', edit, 'changes', edit.changes));
- };
-
- return edit;
-};
-
-/**
- * Function: decodeChanges
- *
- * Decodes and executes the changes represented by the children in the
- * given node. Returns an array that contains all changes.
- */
-mxSession.prototype.decodeChanges = function(node)
-{
- // Updates the document in the existing codec
- this.codec.document = node.ownerDocument;
-
- // Parses and executes the changes on the model
- var changes = [];
- node = node.firstChild;
-
- while (node != null)
- {
- var change = this.decodeChange(node);
-
- if (change != null)
- {
- changes.push(change);
- }
-
- node = node.nextSibling;
- }
-
- return changes;
-};
-
-/**
- * Function: decodeChange
- *
- * Decodes, executes and returns the change object represented by the given
- * XML node.
- */
-mxSession.prototype.decodeChange = function(node)
-{
- var change = null;
-
- if (node.nodeType == mxConstants.NODETYPE_ELEMENT)
- {
- if (node.nodeName == 'mxRootChange')
- {
- // Handles the special case were no ids should be
- // resolved in the existing model. This change will
- // replace all registered ids and cells from the
- // model and insert a new cell hierarchy instead.
- var tmp = new mxCodec(node.ownerDocument);
- change = tmp.decode(node);
- }
- else
- {
- change = this.codec.decode(node);
- }
-
- if (change != null)
- {
- change.model = this.model;
- change.execute();
-
- // Workaround for references not being resolved if cells have
- // been removed from the model prior to being referenced. This
- // adds removed cells in the codec object lookup table.
- if (node.nodeName == 'mxChildChange' && change.parent == null)
- {
- this.cellRemoved(change.child);
- }
- }
- }
-
- return change;
-};
-
-/**
- * Function: cellRemoved
- *
- * Adds removed cells to the codec object lookup for references to the removed
- * cells after this point in time.
- */
-mxSession.prototype.cellRemoved = function(cell, codec)
-{
- this.codec.putObject(cell.getId(), cell);
-
- var childCount = this.model.getChildCount(cell);
-
- for (var i = 0; i < childCount; i++)
- {
- this.cellRemoved(this.model.getChildAt(cell, i));
- }
-};