123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- /*
- * jsPlumb
- *
- * Title:jsPlumb 1.3.6
- *
- * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
- * elements, or VML.
- *
- * This file contains the MooTools adapter.
- *
- * Copyright (c) 2010 - 2012 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() {
-
- /*
- * overrides the FX class to inject 'step' functionality, which MooTools does not
- * offer, and which makes me sad. they don't seem keen to add it, either, despite
- * the fact that it could be useful:
- *
- * https://mootools.lighthouseapp.com/projects/2706/tickets/668
- *
- */
- var jsPlumbMorph = new Class({
- Extends:Fx.Morph,
- onStep : null,
- initialize : function(el, options) {
- this.parent(el, options);
- if (options['onStep']) {
- this.onStep = options['onStep'];
- }
- },
- step : function(now) {
- this.parent(now);
- if (this.onStep) {
- try { this.onStep(); }
- catch(e) { }
- }
- }
- });
-
- var _droppables = {},
- _droppableOptions = {},
- _draggablesByScope = {},
- _draggablesById = {},
- _droppableScopesById = {};
- /*
- *
- */
- var _executeDroppableOption = function(el, dr, event) {
- if (dr) {
- var id = dr.get("id");
- if (id) {
- var options = _droppableOptions[id];
- if (options) {
- if (options[event]) {
- options[event](el, dr);
- }
- }
- }
- }
- };
-
- var _checkHover = function(el, entering) {
- if (el) {
- var id = el.get("id");
- if (id) {
- var options = _droppableOptions[id];
- if (options) {
- if (options['hoverClass']) {
- if (entering) el.addClass(options['hoverClass']);
- else el.removeClass(options['hoverClass']);
- }
- }
- }
- }
- };
- /**
- * adds the given value to the given list, with the given scope. creates the scoped list
- * if necessary.
- * used by initDraggable and initDroppable.
- */
- var _add = function(list, _scope, value) {
- var l = list[_scope];
- if (!l) {
- l = [];
- list[_scope] = l;
- }
- l.push(value);
- };
-
- /*
- * gets an "element object" from the given input. this means an object that is used by the
- * underlying library on which jsPlumb is running. 'el' may already be one of these objects,
- * in which case it is returned as-is. otherwise, 'el' is a String, the library's lookup
- * function is used to find the element, using the given String as the element's id.
- */
- var _getElementObject = function(el) {
- return $(el);
- },
- _removeNonPermanentDroppables = function(drag) {
- /*
- // remove non-permanent droppables from all arrays
- var dbs = _droppables[drag.scope], d = [];
- if (dbs) {
- var d = [];
- for (var i=0; i < dbs.length; i++) {
- var isPermanent = dbs[i].getAttribute("_isPermanentDroppable");
- if (isPermanent === "true") d.push(dbs[i]);
- }
- dbs.splice(0, dbs.length);
- _droppables[drag.scope] = d;
- }
- d = [];
- // clear out transient droppables from the drag itself
- for(var i = 0; i < drag.droppables.length; i++) {
- var isPermanent = drag.droppables[i].getAttribute("_isPermanentDroppable");
- if (isPermanent === "true") d.push(drag.droppables[i]);
- }
- drag.droppables.splice(0, drag.droppables.length); // release old ones
- drag.droppables = d;
- //*/
- };
-
- jsPlumb.CurrentLibrary = {
-
- /**
- * adds the given class to the element object.
- */
- addClass : function(el, clazz) {
- el = jsPlumb.CurrentLibrary.getElementObject(el)
- try {
- if (el.className.constructor == SVGAnimatedString) {
- jsPlumb.util.svg.addClass(el, clazz);
- }
- else el.addClass(clazz);
- }
- catch (e) {
- // SVGAnimatedString not supported; no problem.
- el.addClass(clazz);
- }
- },
-
- animate : function(el, properties, options) {
- var m = new jsPlumbMorph(el, options);
- m.start(properties);
- },
-
- appendElement : function(child, parent) {
- _getElementObject(parent).grab(child);
- },
-
- bind : function(el, event, callback) {
- el = _getElementObject(el);
- el.addEvent(event, callback);
- },
-
- dragEvents : {
- 'start':'onStart', 'stop':'onComplete', 'drag':'onDrag', 'step':'onStep',
- 'over':'onEnter', 'out':'onLeave','drop':'onDrop', 'complete':'onComplete'
- },
- /*
- * wrapper around the library's 'extend' functionality (which it hopefully has.
- * otherwise you'll have to do it yourself). perhaps jsPlumb could do this for you
- * instead. it's not like its hard.
- */
- extend : function(o1, o2) {
- return $extend(o1, o2);
- },
-
- /**
- * gets the named attribute from the given element object.
- */
- getAttribute : function(el, attName) {
- return el.get(attName);
- },
-
- getClientXY : function(eventObject) {
- return [eventObject.event.clientX, eventObject.event.clientY];
- },
-
- getDragObject : function(eventArgs) {
- return eventArgs[0];
- },
-
- getDragScope : function(el) {
- var id = jsPlumb.getId(el),
- drags = _draggablesById[id];
- return drags[0].scope;
- },
-
- getDropScope : function(el) {
- var id = jsPlumb.getId(el);
- return _droppableScopesById[id];
- },
-
- getDOMElement : function(el) {
- // MooTools just decorates the DOM elements. so we have either an ID or an Element here.
- return typeof(el) == "String" ? document.getElementById(el) : el;
- },
-
- getElementObject : _getElementObject,
-
- /*
- gets the offset for the element object. this should return a js object like this:
-
- { left:xxx, top: xxx}
- */
- getOffset : function(el) {
- var p = el.getPosition();
- return { left:p.x, top:p.y };
- },
-
- getPageXY : function(eventObject) {
- return [eventObject.event.pageX, eventObject.event.pageY];
- },
-
- getParent : function(el) {
- return jsPlumb.CurrentLibrary.getElementObject(el).getParent();
- },
-
- getScrollLeft : function(el) {
- return null;
- },
-
- getScrollTop : function(el) {
- return null;
- },
-
- getSelector : function(spec) {
- return $$(spec);
- },
-
- getSize : function(el) {
- var s = el.getSize();
- return [s.x, s.y];
- },
- getTagName : function(el) {
- var e = jsPlumb.CurrentLibrary.getElementObject(el);
- return e != null ? e.tagName : null;
- },
-
- /*
- * takes the args passed to an event function and returns you an object that gives the
- * position of the object being moved, as a js object with the same params as the result of
- * getOffset, ie: { left: xxx, top: xxx }.
- */
- getUIPosition : function(eventArgs) {
- var ui = eventArgs[0],
- p = jsPlumb.CurrentLibrary.getElementObject(ui).getPosition();
- return { left:p.x, top:p.y };
- },
-
- hasClass : function(el, clazz) {
- return el.hasClass(clazz);
- },
-
- initDraggable : function(el, options, isPlumbedComponent) {
- var id = jsPlumb.getId(el);
- var drag = _draggablesById[id];
- if (!drag) {
- var originalZIndex = 0,
- originalCursor = null,
- dragZIndex = jsPlumb.Defaults.DragOptions.zIndex || 2000;
-
- options['onStart'] = jsPlumb.wrap(options['onStart'], function() {
- originalZIndex = this.element.getStyle('z-index');
- this.element.setStyle('z-index', dragZIndex);
- drag.originalZIndex = originalZIndex;
- if (jsPlumb.Defaults.DragOptions.cursor) {
- originalCursor = this.element.getStyle('cursor');
- this.element.setStyle('cursor', jsPlumb.Defaults.DragOptions.cursor);
- }
- });
-
- options['onComplete'] = jsPlumb.wrap(options['onComplete'], function() {
- this.element.setStyle('z-index', originalZIndex);
- if (originalCursor) {
- this.element.setStyle('cursor', originalCursor);
- }
- _removeNonPermanentDroppables(drag);
- });
-
- // DROPPABLES - only relevant if this is a plumbed component, ie. not just the result of the user making some DOM element
- // draggable. this is the only library adapter that has to care about this parameter.
- var scope = "" + (options["scope"] || jsPlumb.Defaults.Scope),
- filterFunc = function(entry) {
- return entry.get("id") != el.get("id");
- },
- droppables = _droppables[scope] ? _droppables[scope].filter(filterFunc) : [];
- if (isPlumbedComponent) {
- options['droppables'] = droppables;
- options['onLeave'] = jsPlumb.wrap(options['onLeave'], function(el, dr) {
- if (dr) {
- _checkHover(dr, false);
- _executeDroppableOption(el, dr, 'onLeave');
- }
- });
- options['onEnter'] = jsPlumb.wrap(options['onEnter'], function(el, dr) {
- if (dr) {
- _checkHover(dr, true);
- _executeDroppableOption(el, dr, 'onEnter');
- }
- });
- options['onDrop'] = function(el, dr) {
- if (dr) {
- _checkHover(dr, false);
- _executeDroppableOption(el, dr, 'onDrop');
- }
- };
- }
- else
- options["droppables"] = [];
-
- drag = new Drag.Move(el, options);
- drag.scope = scope;
- drag.originalZIndex = originalZIndex;
- _add(_draggablesById, el.get("id"), drag);
- // again, only keep a record of this for scope stuff if this is a plumbed component (an endpoint)
- if (isPlumbedComponent) {
- _add(_draggablesByScope, scope, drag);
- }
- // test for disabled.
- if (options.disabled) drag.detach();
- }
- return drag;
- },
-
- initDroppable : function(el, options, isPlumbedComponent, isPermanent) {
- var scope = options["scope"];
- _add(_droppables, scope, el);
- var id = jsPlumb.getId(el);
- el.setAttribute("_isPermanentDroppable", isPermanent); // we use this to clear out droppables on drag complete.
- _droppableOptions[id] = options;
- _droppableScopesById[id] = scope;
- var filterFunc = function(entry) { return entry.element != el; },
- draggables = _draggablesByScope[scope] ? _draggablesByScope[scope].filter(filterFunc) : [];
- for (var i = 0; i < draggables.length; i++) {
- draggables[i].droppables.push(el);
- }
- },
-
- isAlreadyDraggable : function(el) {
- return _draggablesById[jsPlumb.getId(el)] != null;
- },
-
- isDragSupported : function(el, options) {
- return typeof Drag != 'undefined' ;
- },
-
- /*
- * you need Drag.Move imported to make drop work.
- */
- isDropSupported : function(el, options) {
- return (typeof Drag != undefined && typeof Drag.Move != undefined);
- },
-
- /**
- * removes the given class from the element object.
- */
- removeClass : function(el, clazz) {
- el = jsPlumb.CurrentLibrary.getElementObject(el);
- try {
- if (el.className.constructor == SVGAnimatedString) {
- jsPlumb.util.svg.removeClass(el, clazz);
- }
- else el.removeClass(clazz);
- }
- catch (e) {
- // SVGAnimatedString not supported; no problem.
- el.removeClass(clazz);
- }
- },
-
- removeElement : function(element, parent) {
- var el = _getElementObject(element);
- if (el) el.dispose(); // ??
- },
-
- /**
- * sets the named attribute on the given element object.
- */
- setAttribute : function(el, attName, attValue) {
- el.set(attName, attValue);
- },
-
- setDraggable : function(el, draggable) {
- var draggables = _draggablesById[el.get("id")];
- if (draggables) {
- draggables.each(function(d) {
- if (draggable) d.attach(); else d.detach();
- });
- }
- },
-
- setDragScope : function(el, scope) {
- var drag = _draggablesById[el.get("id")];
- var filterFunc = function(entry) {
- return entry.get("id") != el.get("id");
- };
- var droppables = _droppables[scope] ? _droppables[scope].filter(filterFunc) : [];
- drag[0].droppables = droppables;
- },
-
- setOffset : function(el, o) {
- _getElementObject(el).setPosition({x:o.left, y:o.top});
- },
- stopDrag : function() {
- for (var i in _draggablesById) {
- for (var j = 0; j < _draggablesById[i].length; j++) {
- var d = _draggablesById[i][j];
- d.stop();
- if (d.originalZIndex != 0)
- d.element.setStyle("z-index", d.originalZIndex);
- }
- }
- },
-
- /**
- * note that jquery ignores the name of the event you wanted to trigger, and figures it out for itself.
- * the other libraries do not. yui, in fact, cannot even pass an original event. we have to pull out stuff
- * from the originalEvent to put in an options object for YUI.
- * @param el
- * @param event
- * @param originalEvent
- */
- trigger : function(el, event, originalEvent) {
- originalEvent.stopPropagation();
- _getElementObject(el).fireEvent(event, originalEvent);
- },
-
- unbind : function(el, event, callback) {
- el = _getElementObject(el);
- el.removeEvent(event, callback);
- }
- };
-
- window.addEvent('domready', jsPlumb.init);
- })();
|