--- /dev/null
+/*
+ * jsPlumb
+ *
+ * Title:jsPlumb 1.5.5
+ *
+ * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
+ * elements, or VML.
+ *
+ * This file contains the base functionality for DOM type adapters.
+ *
+ * Copyright (c) 2010 - 2013 Simon Porritt (http://jsplumb.org)
+ *
+ * http://jsplumb.org
+ * http://github.com/sporritt/jsplumb
+ * http://code.google.com/p/jsplumb
+ *
+ * Dual licensed under the MIT and GPL2 licenses.
+ */
+;(function() {
+
+ var canvasAvailable = !!document.createElement('canvas').getContext,
+ svgAvailable = !!window.SVGAngle || document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
+ // http://stackoverflow.com/questions/654112/how-do-you-detect-support-for-vml-or-svg-in-a-browser
+ vmlAvailable = function() {
+ if (vmlAvailable.vml === undefined) {
+ var a = document.body.appendChild(document.createElement('div'));
+ a.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
+ var b = a.firstChild;
+ if (b != null && b.style != null) {
+ b.style.behavior = "url(#default#VML)";
+ vmlAvailable.vml = b ? typeof b.adj == "object": true;
+ }
+ else
+ vmlAvailable.vml = false;
+ a.parentNode.removeChild(a);
+ }
+ return vmlAvailable.vml;
+ };
+
+ /**
+ Manages dragging for some instance of jsPlumb.
+ */
+ var DragManager = function(_currentInstance) {
+ var _draggables = {}, _dlist = [], _delements = {}, _elementsWithEndpoints = {},
+ // elementids mapped to the draggable to which they belong.
+ _draggablesForElements = {};
+
+ /**
+ register some element as draggable. right now the drag init stuff is done elsewhere, and it is
+ possible that will continue to be the case.
+ */
+ this.register = function(el) {
+ var jpcl = jsPlumb.CurrentLibrary,
+ _el = jpcl.getElementObject(el),
+ id = _currentInstance.getId(el),
+ parentOffset = jpcl.getOffset(_el);
+
+ if (!_draggables[id]) {
+ _draggables[id] = el;
+ _dlist.push(el);
+ _delements[id] = {};
+ }
+
+ // look for child elements that have endpoints and register them against this draggable.
+ var _oneLevel = function(p, startOffset) {
+ if (p) {
+ for (var i = 0; i < p.childNodes.length; i++) {
+ if (p.childNodes[i].nodeType != 3 && p.childNodes[i].nodeType != 8) {
+ var cEl = jpcl.getElementObject(p.childNodes[i]),
+ cid = _currentInstance.getId(p.childNodes[i], null, true);
+ if (cid && _elementsWithEndpoints[cid] && _elementsWithEndpoints[cid] > 0) {
+ var cOff = jpcl.getOffset(cEl);
+ _delements[id][cid] = {
+ id:cid,
+ offset:{
+ left:cOff.left - parentOffset.left,
+ top:cOff.top - parentOffset.top
+ }
+ };
+ _draggablesForElements[cid] = id;
+ }
+ _oneLevel(p.childNodes[i]);
+ }
+ }
+ }
+ };
+
+ _oneLevel(el);
+ };
+
+ // refresh the offsets for child elements of this element.
+ this.updateOffsets = function(elId) {
+ var jpcl = jsPlumb.CurrentLibrary,
+ el = jpcl.getElementObject(elId),
+ domEl = jpcl.getDOMElement(el),
+ id = _currentInstance.getId(domEl),
+ children = _delements[id],
+ parentOffset = jpcl.getOffset(el);
+
+ if (children) {
+ for (var i in children) {
+ var cel = jpcl.getElementObject(i),
+ cOff = jpcl.getOffset(cel);
+
+ _delements[id][i] = {
+ id:i,
+ offset:{
+ left:cOff.left - parentOffset.left,
+ top:cOff.top - parentOffset.top
+ }
+ };
+ _draggablesForElements[i] = id;
+ }
+ }
+ };
+
+ /**
+ notification that an endpoint was added to the given el. we go up from that el's parent
+ node, looking for a parent that has been registered as a draggable. if we find one, we add this
+ el to that parent's list of elements to update on drag (if it is not there already)
+ */
+ this.endpointAdded = function(el) {
+ var jpcl = jsPlumb.CurrentLibrary, b = document.body, id = _currentInstance.getId(el),
+ c = jpcl.getElementObject(el),
+ cLoc = jsPlumb.CurrentLibrary.getOffset(c),
+ p = el.parentNode, done = p == b;
+
+ _elementsWithEndpoints[id] = _elementsWithEndpoints[id] ? _elementsWithEndpoints[id] + 1 : 1;
+
+ while (p != null && p != b) {
+ var pid = _currentInstance.getId(p, null, true);
+ if (pid && _draggables[pid]) {
+ var idx = -1, pEl = jpcl.getElementObject(p), pLoc = jpcl.getOffset(pEl);
+
+ if (_delements[pid][id] == null) {
+ _delements[pid][id] = {
+ id:id,
+ offset:{
+ left:cLoc.left - pLoc.left,
+ top:cLoc.top - pLoc.top
+ }
+ };
+ _draggablesForElements[id] = pid;
+ }
+ break;
+ }
+ p = p.parentNode;
+ }
+ };
+
+ this.endpointDeleted = function(endpoint) {
+ if (_elementsWithEndpoints[endpoint.elementId]) {
+ _elementsWithEndpoints[endpoint.elementId]--;
+ if (_elementsWithEndpoints[endpoint.elementId] <= 0) {
+ for (var i in _delements) {
+ if (_delements[i]) {
+ delete _delements[i][endpoint.elementId];
+ delete _draggablesForElements[endpoint.elementId];
+ }
+ }
+ }
+ }
+ };
+
+ this.changeId = function(oldId, newId) {
+ _delements[newId] = _delements[oldId];
+ _delements[oldId] = {};
+ _draggablesForElements[newId] = _draggablesForElements[oldId];
+ _draggablesForElements[oldId] = null;
+ };
+
+ this.getElementsForDraggable = function(id) {
+ return _delements[id];
+ };
+
+ this.elementRemoved = function(elementId) {
+ var elId = _draggablesForElements[elementId];
+ if (elId) {
+ delete _delements[elId][elementId];
+ delete _draggablesForElements[elementId];
+ }
+ };
+
+ this.reset = function() {
+ _draggables = {};
+ _dlist = [];
+ _delements = {};
+ _elementsWithEndpoints = {};
+ };
+
+ //
+ // notification drag ended. from 1.5.5 we check automatically if need to update some
+ // ancestor's offsets.
+ //
+ this.dragEnded = function(el) {
+ var id = _currentInstance.getId(el),
+ ancestor = _draggablesForElements[id];
+
+ if (ancestor) this.updateOffsets(ancestor);
+ };
+
+ this.setParent = function(el, elId, p, pId) {
+ var current = _draggablesForElements[elId];
+ if (current) {
+ if (!_delements[pId])
+ _delements[pId] = {};
+ _delements[pId][elId] = _delements[current][elId];
+ delete _delements[current][elId];
+ var pLoc = jsPlumb.CurrentLibrary.getOffset(p),
+ cLoc = jsPlumb.CurrentLibrary.getOffset(el);
+ _delements[pId][elId].offset = {
+ left:cLoc.left - pLoc.left,
+ top:cLoc.top - pLoc.top
+ };
+ _draggablesForElements[elId] = pId;
+ }
+ };
+
+ };
+
+ // for those browsers that dont have it. they still don't have it! but at least they won't crash.
+ if (!window.console)
+ window.console = { time:function(){}, timeEnd:function(){}, group:function(){}, groupEnd:function(){}, log:function(){} };
+
+ window.jsPlumbAdapter = {
+
+ headless:false,
+
+ getAttribute:function(el, attName) {
+ return el.getAttribute(attName);
+ },
+
+ setAttribute:function(el, a, v) {
+ el.setAttribute(a, v);
+ },
+
+ appendToRoot : function(node) {
+ document.body.appendChild(node);
+ },
+ getRenderModes : function() {
+ return [ "canvas", "svg", "vml" ];
+ },
+ isRenderModeAvailable : function(m) {
+ return {
+ "canvas":canvasAvailable,
+ "svg":svgAvailable,
+ "vml":vmlAvailable()
+ }[m];
+ },
+ getDragManager : function(_jsPlumb) {
+ return new DragManager(_jsPlumb);
+ },
+ setRenderMode : function(mode) {
+ var renderMode;
+
+ if (mode) {
+ mode = mode.toLowerCase();
+
+ var canvasAvailable = this.isRenderModeAvailable("canvas"),
+ svgAvailable = this.isRenderModeAvailable("svg"),
+ vmlAvailable = this.isRenderModeAvailable("vml");
+
+ // now test we actually have the capability to do this.
+ if (mode === "svg") {
+ if (svgAvailable) renderMode = "svg";
+ else if (canvasAvailable) renderMode = "canvas";
+ else if (vmlAvailable) renderMode = "vml";
+ }
+ else if (mode === "canvas" && canvasAvailable) renderMode = "canvas";
+ else if (vmlAvailable) renderMode = "vml";
+ }
+
+ return renderMode;
+ }
+ };
+
+
+ /*
+
+ addClass:
+
+ add: function( elem, classNames ) {
+ jQuery.each((classNames || "").split(/\s+/), function(i, className){
+ if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+ elem.className += (elem.className ? " " : "") + className;
+ });
+ },
+ */
+
+ /*
+
+ removeClass:
+
+ elem.className = classNames !== undefined ?
+ jQuery.grep(elem.className.split(/\s+/), function(className){
+ return !jQuery.className.has( classNames, className );
+ }).join(" ") :
+
+*/
+
+})();
\ No newline at end of file