6 * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
9 * This file contains the jQuery adapter.
11 * Copyright (c) 2010 - 2013 Simon Porritt (http://jsplumb.org)
14 * http://github.com/sporritt/jsplumb
15 * http://code.google.com/p/jsplumb
17 * Dual licensed under the MIT and GPL2 licenses.
20 * the library specific functions, such as find offset, get id, get attribute, extend etc.
23 * addClass adds a class to the given element
24 * animate calls the underlying library's animate functionality
25 * appendElement appends a child element to a parent element.
26 * bind binds some event to an element
27 * dragEvents a dictionary of event names
28 * extend extend some js object with another. probably not overly necessary; jsPlumb could just do this internally.
29 * getDragObject gets the object that is being dragged, by extracting it from the arguments passed to a drag callback
30 * getDragScope gets the drag scope for a given element.
31 * getDropScope gets the drop scope for a given element.
32 * getElementObject turns an id or dom element into an element object of the underlying library's type.
33 * getOffset gets an element's offset
34 * getOriginalEvent gets the original browser event from some wrapper event
35 * getPageXY gets the page event's xy location.
36 * getParent gets the parent of some element.
37 * getScrollLeft gets an element's scroll left. TODO: is this actually used? will it be?
38 * getScrollTop gets an element's scroll top. TODO: is this actually used? will it be?
39 * getSize gets an element's size.
40 * getUIPosition gets the position of some element that is currently being dragged, by extracting it from the arguments passed to a drag callback.
41 * hasClass returns whether or not the given element has the given class.
42 * initDraggable initializes an element to be draggable
43 * initDroppable initializes an element to be droppable
44 * isDragSupported returns whether or not drag is supported for some element.
45 * isDropSupported returns whether or not drop is supported for some element.
46 * removeClass removes a class from a given element.
47 * removeElement removes some element completely from the DOM.
48 * setDragFilter sets a filter for some element that indicates areas of the element that should not respond to dragging.
49 * setDraggable sets whether or not some element should be draggable.
50 * setDragScope sets the drag scope for a given element.
51 * setOffset sets the offset of some element.
52 * trigger triggers some event on an element.
53 * unbind unbinds some listener from some element.
57 //var getBoundingClientRectSupported = "getBoundingClientRect" in document.documentElement;
59 var _getElementObject = function(el) {
60 return typeof(el) == "string" ? $("#" + el) : $(el);
63 jsPlumb.CurrentLibrary = {
66 * adds the given class to the element object.
68 addClass : function(el, clazz) {
69 el = _getElementObject(el);
71 if (el[0].className.constructor == SVGAnimatedString) {
72 jsPlumbUtil.svg.addClass(el[0], clazz);
76 // SVGAnimatedString not supported; no problem.
82 // you probably have jQuery 1.9 and Firefox.
87 * animates the given element.
89 animate : function(el, properties, options) {
90 el.animate(properties, options);
94 * appends the given child to the given parent.
99 appendElement : function(child, parent) {
100 _getElementObject(parent).append(child);
104 * executes an ajax call.
106 ajax : function(params) {
107 params = params || {};
108 params.type = params.type || "get";
113 * event binding wrapper. it just so happens that jQuery uses 'bind' also. yui3, for example,
116 bind : function(el, event, callback) {
117 el = _getElementObject(el);
118 el.bind(event, callback);
121 destroyDraggable : function(el) {
122 if ($(el).data("draggable"))
123 $(el).draggable("destroy");
126 destroyDroppable : function(el) {
127 if ($(el).data("droppable"))
128 $(el).droppable("destroy");
132 * mapping of drag events for jQuery
135 'start':'start', 'stop':'stop', 'drag':'drag', 'step':'step',
136 'over':'over', 'out':'out', 'drop':'drop', 'complete':'complete'
140 * wrapper around the library's 'extend' functionality (which it hopefully has.
141 * otherwise you'll have to do it yourself). perhaps jsPlumb could do this for you
142 * instead. it's not like its hard.
144 extend : function(o1, o2) {
145 return $.extend(o1, o2);
148 getClientXY : function(eventObject) {
149 return [eventObject.clientX, eventObject.clientY];
153 * takes the args passed to an event function and returns you an object representing that which is being dragged.
155 getDragObject : function(eventArgs) {
156 return eventArgs[1].draggable || eventArgs[1].helper;
159 getDragScope : function(el) {
160 return $(el).draggable("option", "scope");
163 getDropEvent : function(args) {
167 getDropScope : function(el) {
168 return $(el).droppable("option", "scope");
172 * gets a DOM element from the given input, which might be a string (in which case we just do document.getElementById),
173 * a selector (in which case we return el[0]), or a DOM element already (we assume this if it's not either of the other
174 * two cases). this is the opposite of getElementObject below.
176 getDOMElement : function(el) {
177 if (el == null) return null;
178 if (typeof(el) == "string") return document.getElementById(el);
179 else if (el.context || el.length != null) return el[0];
184 * gets an "element object" from the given input. this means an object that is used by the
185 * underlying library on which jsPlumb is running. 'el' may already be one of these objects,
186 * in which case it is returned as-is. otherwise, 'el' is a String, the library's lookup
187 * function is used to find the element, using the given String as the element's id.
190 getElementObject : _getElementObject,
193 * gets the offset for the element object. this should return a js object like this:
195 * { left:xxx, top: xxx }
197 getOffset : function(el) {
201 getOriginalEvent : function(e) {
202 return e.originalEvent;
205 getPageXY : function(eventObject) {
206 return [eventObject.pageX, eventObject.pageY];
209 getParent : function(el) {
210 return _getElementObject(el).parent();
213 getScrollLeft : function(el) {
214 return el.scrollLeft();
217 getScrollTop : function(el) {
218 return el.scrollTop();
221 getSelector : function(context, spec) {
222 if (arguments.length == 2)
223 return _getElementObject(context).find(spec);
229 * gets the size for the element object, in an array : [ width, height ].
231 getSize : function(el) {
233 return [el.outerWidth(), el.outerHeight()];
236 getTagName : function(el) {
237 var e = _getElementObject(el);
238 return e.length > 0 ? e[0].tagName : null;
242 * takes the args passed to an event function and returns you an object that gives the
243 * position of the object being moved, as a js object with the same params as the result of
244 * getOffset, ie: { left: xxx, top: xxx }.
246 * different libraries have different signatures for their event callbacks.
247 * see getDragObject as well
249 getUIPosition : function(eventArgs, zoom) {
252 // this code is a workaround for the case that the element being dragged has a margin set on it. jquery UI passes
253 // in the wrong offset if the element has a margin (it doesn't take the margin into account). the getBoundingClientRect
254 // method, which is in pretty much all browsers now, reports the right numbers. but it introduces a noticeable lag, which
257 /*if ( getBoundingClientRectSupported ) {
258 var r = eventArgs[1].helper[0].getBoundingClientRect();
259 return { left : r.left, top: r.top };
261 if (eventArgs.length == 1) {
262 ret = { left: eventArgs[0].pageX, top:eventArgs[0].pageY };
265 var ui = eventArgs[1],
268 ret = _offset || ui.absolutePosition;
270 // adjust ui position to account for zoom, because jquery ui does not do this.
271 ui.position.left /= zoom;
272 ui.position.top /= zoom;
274 return { left:ret.left / zoom, top: ret.top / zoom };
277 hasClass : function(el, clazz) {
278 return el.hasClass(clazz);
282 * initialises the given element to be draggable.
284 initDraggable : function(el, options, isPlumbedComponent, _jsPlumb) {
285 options = options || {};
288 options.start = jsPlumbUtil.wrap(options.start, function() {
289 $("body").addClass(_jsPlumb.dragSelectClass);
292 options.stop = jsPlumbUtil.wrap(options.stop, function() {
293 $("body").removeClass(_jsPlumb.dragSelectClass);
296 // remove helper directive if present and no override
297 if (!options.doNotRemoveHelper)
298 options.helper = null;
299 if (isPlumbedComponent)
300 options.scope = options.scope || jsPlumb.Defaults.Scope;
301 el.draggable(options);
305 * initialises the given element to be droppable.
307 initDroppable : function(el, options) {
308 options.scope = options.scope || jsPlumb.Defaults.Scope;
309 $(el).droppable(options);
312 isAlreadyDraggable : function(el) {
313 return $(el).hasClass("ui-draggable");
317 * returns whether or not drag is supported (by the library, not whether or not it is disabled) for the given element.
319 isDragSupported : function(el, options) {
320 return $(el).draggable;
324 * returns whether or not drop is supported (by the library, not whether or not it is disabled) for the given element.
326 isDropSupported : function(el, options) {
327 return $(el).droppable;
331 * removes the given class from the element object.
333 removeClass : function(el, clazz) {
334 el = _getElementObject(el);
336 if (el[0].className.constructor == SVGAnimatedString) {
337 jsPlumbUtil.svg.removeClass(el[0], clazz);
342 // SVGAnimatedString not supported; no problem.
344 el.removeClass(clazz);
347 removeElement : function(element) {
348 _getElementObject(element).remove();
351 setDragFilter : function(el, filter) {
352 if (jsPlumb.CurrentLibrary.isAlreadyDraggable(el))
353 el.draggable("option", "cancel", filter);
356 setDraggable : function(el, draggable) {
357 el.draggable("option", "disabled", !draggable);
360 setDragScope : function(el, scope) {
361 el.draggable("option", "scope", scope);
364 setOffset : function(el, o) {
365 _getElementObject(el).offset(o);
369 * note that jquery ignores the name of the event you wanted to trigger, and figures it out for itself.
370 * the other libraries do not. yui, in fact, cannot even pass an original event. we have to pull out stuff
371 * from the originalEvent to put in an options object for YUI.
374 * @param originalEvent
376 trigger : function(el, event, originalEvent) {
377 var h = jQuery._data(_getElementObject(el)[0], "handle");
381 unbind : function(el, event, callback) {
382 el = _getElementObject(el);
383 el.unbind(event, callback);
387 $(document).ready(jsPlumb.init);