6 * Provides a way to visually connect elements on an HTML page, using either SVG, Canvas
9 * This file contains the basic adapter that does not require any support library such as jquery, yui or mootools.
11 but it's not yet there. currently this is a copy of the jquery adapter.
14 * Copyright (c) 2010 - 2013 Simon Porritt (http://jsplumb.org)
17 * http://github.com/sporritt/jsplumb
18 * http://code.google.com/p/jsplumb
20 * Dual licensed under the MIT and GPL2 licenses.
23 * the library specific functions, such as find offset, get id, get attribute, extend etc.
26 * addClass adds a class to the given element
27 * animate calls the underlying library's animate functionality
28 * appendElement appends a child element to a parent element.
29 * bind binds some event to an element
30 * dragEvents a dictionary of event names
31 * extend extend some js object with another. probably not overly necessary; jsPlumb could just do this internally.
32 * getAttribute gets some attribute from an element
33 * getDragObject gets the object that is being dragged, by extracting it from the arguments passed to a drag callback
34 * getDragScope gets the drag scope for a given element.
35 * getDropScope gets the drop scope for a given element.
36 * getElementObject turns an id or dom element into an element object of the underlying library's type.
37 * getOffset gets an element's offset
38 * getOriginalEvent gets the original browser event from some wrapper event
39 * getPageXY gets the page event's xy location.
40 * getParent gets the parent of some element.
41 * getScrollLeft gets an element's scroll left. TODO: is this actually used? will it be?
42 * getScrollTop gets an element's scroll top. TODO: is this actually used? will it be?
43 * getSize gets an element's size.
44 * getUIPosition gets the position of some element that is currently being dragged, by extracting it from the arguments passed to a drag callback.
45 * hasClass returns whether or not the given element has the given class.
46 * initDraggable initializes an element to be draggable
47 * initDroppable initializes an element to be droppable
48 * isDragSupported returns whether or not drag is supported for some element.
49 * isDropSupported returns whether or not drop is supported for some element.
50 * removeClass removes a class from a given element.
51 * removeElement removes some element completely from the DOM.
52 * setAttribute sets an attribute on some element.
53 * setDraggable sets whether or not some element should be draggable.
54 * setDragScope sets the drag scope for a given element.
55 * setOffset sets the offset of some element.
56 * trigger triggers some event on an element.
57 * unbind unbinds some listener from some element.
61 //var getBoundingClientRectSupported = "getBoundingClientRect" in document.documentElement;
65 METHODS TO USE/INVESTIGATE:
69 document.querySelector/querySelectorAll
70 element.classList (has add and remove methods)
75 var _setClassName = function(el, val) {
76 if (el.className.baseVal)
77 el.className.baseVal = val;
81 _getClassName = function(el) {
82 return el.className.baseVal != null ? el.className.baseVal : el.className;
84 _classManip = function(el, add, clazz) {
85 var classesToAddOrRemove = clazz.split(" "),
86 curClasses = _getClassName(el).split(" ");
88 for (var i = 0; i < classesToAddOrRemove.length; i++) {
90 if (curClasses.indexOf(classesToAddOrRemove[i]) == -1)
91 curClasses.push(classesToAddOrRemove[i]);
94 var idx = curClasses.indexOf(classesToAddOrRemove[i]);
96 curClasses.splice(idx, 1);
100 _setClassName(el, curClasses.join(" "));
102 _addClass = function(el, clazz) {
103 _classManip(el, true, clazz);
105 _removeClass = function(el, clazz) {
106 _classManip(el, false, clazz);
110 jsPlumb.CurrentLibrary = {
113 * adds the given class to the element object.
115 addClass : function(el, clazz) {
116 el = jsPlumb.CurrentLibrary.getElementObject(el);
118 if (el[0].className.constructor == SVGAnimatedString) {
119 jsPlumbUtil.svg.addClass(el[0], clazz);
123 // SVGAnimatedString not supported; no problem.
129 // you probably have jQuery 1.9 and Firefox.
134 * animates the given element.
136 animate : function(el, properties, options) {
137 el.animate(properties, options);
141 * appends the given child to the given parent.
143 appendElement : function(child, parent) {
144 jsPlumb.CurrentLibrary.getElementObject(parent).append(child);
148 * executes an ajax call.
150 ajax : function(params) {
151 params = params || {};
152 params.type = params.type || "get";
157 * event binding wrapper. it just so happens that jQuery uses 'bind' also. yui3, for example,
160 bind : function(el, event, callback) {
161 el = jsPlumb.CurrentLibrary.getElementObject(el);
162 el.bind(event, callback);
166 * mapping of drag events for jQuery
169 'start':'start', 'stop':'stop', 'drag':'drag', 'step':'step',
170 'over':'over', 'out':'out', 'drop':'drop', 'complete':'complete'
174 * wrapper around the library's 'extend' functionality (which it hopefully has.
175 * otherwise you'll have to do it yourself). perhaps jsPlumb could do this for you
176 * instead. it's not like its hard.
178 extend : function(o1, o2) {
179 return $.extend(o1, o2);
183 * gets the named attribute from the given element object.
185 getAttribute : function(el, attName) {
186 return el.attr(attName);
189 getClientXY : function(eventObject) {
190 return [eventObject.clientX, eventObject.clientY];
194 * takes the args passed to an event function and returns you an object representing that which is being dragged.
196 getDragObject : function(eventArgs) {
197 return eventArgs[1].draggable || eventArgs[1].helper;
200 getDragScope : function(el) {
201 return el.draggable("option", "scope");
204 getDropEvent : function(args) {
208 getDropScope : function(el) {
209 return el.droppable("option", "scope");
213 * gets a DOM element from the given input, which might be a string (in which case we just do document.getElementById),
214 * 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
215 * two cases). this is the opposite of getElementObject below.
217 getDOMElement : function(el) {
218 if (typeof(el) == "string") return document.getElementById(el);
219 else if (el.context || el.length != null) return el[0];
224 * gets an "element object" from the given input. this means an object that is used by the
225 * underlying library on which jsPlumb is running. 'el' may already be one of these objects,
226 * in which case it is returned as-is. otherwise, 'el' is a String, the library's lookup
227 * function is used to find the element, using the given String as the element's id.
230 getElementObject : function(el) {
231 return typeof(el) == "string" ? $("#" + el) : $(el);
235 * gets the offset for the element object. this should return a js object like this:
237 * { left:xxx, top: xxx }
239 getOffset : function(el) {
243 getOriginalEvent : function(e) {
244 return e.originalEvent;
247 getPageXY : function(eventObject) {
248 return [eventObject.pageX, eventObject.pageY];
251 getParent : function(el) {
252 return jsPlumb.CurrentLibrary.getElementObject(el).parent();
255 getScrollLeft : function(el) {
256 return el.scrollLeft();
259 getScrollTop : function(el) {
260 return el.scrollTop();
263 getSelector : function(context, spec) {
264 if (arguments.length == 2)
265 return jsPlumb.CurrentLibrary.getElementObject(context).find(spec);
271 * gets the size for the element object, in an array : [ width, height ].
273 getSize : function(el) {
274 return [el.outerWidth(), el.outerHeight()];
277 getTagName : function(el) {
278 var e = jsPlumb.CurrentLibrary.getElementObject(el);
279 return e.length > 0 ? e[0].tagName : null;
283 * takes the args passed to an event function and returns you an object that gives the
284 * position of the object being moved, as a js object with the same params as the result of
285 * getOffset, ie: { left: xxx, top: xxx }.
287 * different libraries have different signatures for their event callbacks.
288 * see getDragObject as well
290 getUIPosition : function(eventArgs, zoom) {
293 // this code is a workaround for the case that the element being dragged has a margin set on it. jquery UI passes
294 // in the wrong offset if the element has a margin (it doesn't take the margin into account). the getBoundingClientRect
295 // method, which is in pretty much all browsers now, reports the right numbers. but it introduces a noticeable lag, which
298 /*if ( getBoundingClientRectSupported ) {
299 var r = eventArgs[1].helper[0].getBoundingClientRect();
300 return { left : r.left, top: r.top };
302 if (eventArgs.length == 1) {
303 ret = { left: eventArgs[0].pageX, top:eventArgs[0].pageY };
306 var ui = eventArgs[1],
309 ret = _offset || ui.absolutePosition;
311 // adjust ui position to account for zoom, because jquery ui does not do this.
312 ui.position.left /= zoom;
313 ui.position.top /= zoom;
315 return { left:ret.left / zoom, top: ret.top / zoom };
318 hasClass : function(el, clazz) {
319 return el.hasClass(clazz);
323 * initialises the given element to be draggable.
325 initDraggable : function(el, options, isPlumbedComponent) {
326 options = options || {};
327 // remove helper directive if present and no override
328 if (!options.doNotRemoveHelper)
329 options.helper = null;
330 if (isPlumbedComponent)
331 options['scope'] = options['scope'] || jsPlumb.Defaults.Scope;
332 el.draggable(options);
336 * initialises the given element to be droppable.
338 initDroppable : function(el, options) {
339 options['scope'] = options['scope'] || jsPlumb.Defaults.Scope;
340 el.droppable(options);
343 isAlreadyDraggable : function(el) {
344 el = jsPlumb.CurrentLibrary.getElementObject(el);
345 return el.hasClass("ui-draggable");
349 * returns whether or not drag is supported (by the library, not whether or not it is disabled) for the given element.
351 isDragSupported : function(el, options) {
356 * returns whether or not drop is supported (by the library, not whether or not it is disabled) for the given element.
358 isDropSupported : function(el, options) {
363 * removes the given class from the element object.
365 removeClass : function(el, clazz) {
366 el = jsPlumb.CurrentLibrary.getElementObject(el);
368 if (el[0].className.constructor == SVGAnimatedString) {
369 jsPlumbUtil.svg.removeClass(el[0], clazz);
374 // SVGAnimatedString not supported; no problem.
376 el.removeClass(clazz);
379 removeElement : function(element) {
380 jsPlumb.CurrentLibrary.getElementObject(element).remove();
384 * sets the named attribute on the given element object.
386 setAttribute : function(el, attName, attValue) {
387 el.attr(attName, attValue);
391 * sets the draggable state for the given element
393 setDraggable : function(el, draggable) {
394 el.draggable("option", "disabled", !draggable);
398 * sets the drag scope. probably time for a setDragOption method (roll this and the one above together)
402 setDragScope : function(el, scope) {
403 el.draggable("option", "scope", scope);
406 setOffset : function(el, o) {
407 jsPlumb.CurrentLibrary.getElementObject(el).offset(o);
411 * note that jquery ignores the name of the event you wanted to trigger, and figures it out for itself.
412 * the other libraries do not. yui, in fact, cannot even pass an original event. we have to pull out stuff
413 * from the originalEvent to put in an options object for YUI.
416 * @param originalEvent
418 trigger : function(el, event, originalEvent) {
419 //originalEvent.stopPropagation();
420 //jsPlumb.CurrentLibrary.getElementObject(el).trigger(originalEvent);
421 var h = jQuery._data(jsPlumb.CurrentLibrary.getElementObject(el)[0], "handle");
423 //originalEvent.stopPropagation();
427 * event unbinding wrapper. it just so happens that jQuery uses 'unbind' also. yui3, for example,
428 * uses..something else.
430 unbind : function(el, event, callback) {
431 el = jsPlumb.CurrentLibrary.getElementObject(el);
432 el.unbind(event, callback);
436 $(document).ready(jsPlumb.init);