540 lines
17 KiB
JavaScript
540 lines
17 KiB
JavaScript
|
Savage.plugin(function (Savage, Element, Paper, glob) {
|
||
|
var elproto = Element.prototype,
|
||
|
has = "hasOwnProperty",
|
||
|
supportsTouch = "createTouch" in glob.doc,
|
||
|
events = [
|
||
|
"click", "dblclick", "mousedown", "mousemove", "mouseout",
|
||
|
"mouseover", "mouseup", "touchstart", "touchmove", "touchend",
|
||
|
"touchcancel"
|
||
|
],
|
||
|
touchMap = {
|
||
|
mousedown: "touchstart",
|
||
|
mousemove: "touchmove",
|
||
|
mouseup: "touchend"
|
||
|
},
|
||
|
getScroll = function (xy) {
|
||
|
var name = xy == "y" ? "scrollTop" : "scrollLeft";
|
||
|
return glob.doc.documentElement[name] || glob.doc.body[name];
|
||
|
},
|
||
|
preventDefault = function () {
|
||
|
this.returnValue = false;
|
||
|
},
|
||
|
preventTouch = function () {
|
||
|
return this.originalEvent.preventDefault();
|
||
|
},
|
||
|
stopPropagation = function () {
|
||
|
this.cancelBubble = true;
|
||
|
},
|
||
|
stopTouch = function () {
|
||
|
return this.originalEvent.stopPropagation();
|
||
|
},
|
||
|
addEvent = (function () {
|
||
|
if (glob.doc.addEventListener) {
|
||
|
return function (obj, type, fn, element) {
|
||
|
var realName = supportsTouch && touchMap[type] ? touchMap[type] : type,
|
||
|
f = function (e) {
|
||
|
var scrollY = getScroll("y"),
|
||
|
scrollX = getScroll("x"),
|
||
|
x = e.clientX + scrollX,
|
||
|
y = e.clientY + scrollY;
|
||
|
if (supportsTouch && touchMap[has](type)) {
|
||
|
for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
|
||
|
if (e.targetTouches[i].target == obj) {
|
||
|
var olde = e;
|
||
|
e = e.targetTouches[i];
|
||
|
e.originalEvent = olde;
|
||
|
e.preventDefault = preventTouch;
|
||
|
e.stopPropagation = stopTouch;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return fn.call(element, e, x, y);
|
||
|
};
|
||
|
obj.addEventListener(realName, f, false);
|
||
|
return function () {
|
||
|
obj.removeEventListener(realName, f, false);
|
||
|
return true;
|
||
|
};
|
||
|
};
|
||
|
} else if (glob.doc.attachEvent) {
|
||
|
return function (obj, type, fn, element) {
|
||
|
var f = function (e) {
|
||
|
e = e || glob.win.event;
|
||
|
var scrollY = getScroll("y"),
|
||
|
scrollX = getScroll("x"),
|
||
|
x = e.clientX + scrollX,
|
||
|
y = e.clientY + scrollY;
|
||
|
e.preventDefault = e.preventDefault || preventDefault;
|
||
|
e.stopPropagation = e.stopPropagation || stopPropagation;
|
||
|
return fn.call(element, e, x, y);
|
||
|
};
|
||
|
obj.attachEvent("on" + type, f);
|
||
|
var detacher = function () {
|
||
|
obj.detachEvent("on" + type, f);
|
||
|
return true;
|
||
|
};
|
||
|
return detacher;
|
||
|
};
|
||
|
}
|
||
|
})(),
|
||
|
drag = [],
|
||
|
dragMove = function (e) {
|
||
|
var x = e.clientX,
|
||
|
y = e.clientY,
|
||
|
scrollY = getScroll("y"),
|
||
|
scrollX = getScroll("x"),
|
||
|
dragi,
|
||
|
j = drag.length;
|
||
|
while (j--) {
|
||
|
dragi = drag[j];
|
||
|
if (supportsTouch) {
|
||
|
var i = e.touches.length,
|
||
|
touch;
|
||
|
while (i--) {
|
||
|
touch = e.touches[i];
|
||
|
if (touch.identifier == dragi.el._drag.id) {
|
||
|
x = touch.clientX;
|
||
|
y = touch.clientY;
|
||
|
(e.originalEvent ? e.originalEvent : e).preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
var node = dragi.el.node,
|
||
|
o,
|
||
|
next = node.nextSibling,
|
||
|
parent = node.parentNode,
|
||
|
display = node.style.display;
|
||
|
// glob.win.opera && parent.removeChild(node);
|
||
|
// node.style.display = "none";
|
||
|
// o = dragi.el.paper.getElementByPoint(x, y);
|
||
|
// node.style.display = display;
|
||
|
// glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node));
|
||
|
// o && eve("savage.drag.over." + dragi.el.id, dragi.el, o);
|
||
|
x += scrollX;
|
||
|
y += scrollY;
|
||
|
eve("savage.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e);
|
||
|
}
|
||
|
},
|
||
|
dragUp = function (e) {
|
||
|
Savage.unmousemove(dragMove).unmouseup(dragUp);
|
||
|
var i = drag.length,
|
||
|
dragi;
|
||
|
while (i--) {
|
||
|
dragi = drag[i];
|
||
|
dragi.el._drag = {};
|
||
|
eve("savage.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e);
|
||
|
}
|
||
|
drag = [];
|
||
|
};
|
||
|
/*\
|
||
|
* Element.click
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for click for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unclick
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for click for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.dblclick
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for double click for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.undblclick
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for double click for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.mousedown
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for mousedown for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unmousedown
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for mousedown for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.mousemove
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for mousemove for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unmousemove
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for mousemove for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.mouseout
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for mouseout for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unmouseout
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for mouseout for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.mouseover
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for mouseover for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unmouseover
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for mouseover for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.mouseup
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for mouseup for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.unmouseup
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for mouseup for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.touchstart
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for touchstart for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.untouchstart
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for touchstart for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.touchmove
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for touchmove for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.untouchmove
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for touchmove for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.touchend
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for touchend for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.untouchend
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for touchend for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
|
||
|
/*\
|
||
|
* Element.touchcancel
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handler for touchcancel for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
/*\
|
||
|
* Element.untouchcancel
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handler for touchcancel for the element.
|
||
|
> Parameters
|
||
|
- handler (function) handler for the event
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
for (var i = events.length; i--;) {
|
||
|
(function (eventName) {
|
||
|
Savage[eventName] = elproto[eventName] = function (fn, scope) {
|
||
|
if (Savage.is(fn, "function")) {
|
||
|
this.events = this.events || [];
|
||
|
this.events.push({
|
||
|
name: eventName,
|
||
|
f: fn,
|
||
|
unbind: addEvent(this.shape || this.node || glob.doc, eventName, fn, scope || this)
|
||
|
});
|
||
|
}
|
||
|
return this;
|
||
|
};
|
||
|
Savage["un" + eventName] = elproto["un" + eventName] = function (fn) {
|
||
|
var events = this.events || [],
|
||
|
l = events.length;
|
||
|
while (l--) if (events[l].name == eventName && events[l].f == fn) {
|
||
|
events[l].unbind();
|
||
|
events.splice(l, 1);
|
||
|
!events.length && delete this.events;
|
||
|
return this;
|
||
|
}
|
||
|
return this;
|
||
|
};
|
||
|
})(events[i]);
|
||
|
}
|
||
|
|
||
|
/*\
|
||
|
* Element.data
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds or retrieves given value asociated with given key.
|
||
|
**
|
||
|
* See also @Element.removeData
|
||
|
> Parameters
|
||
|
- key (string) key to store data
|
||
|
- value (any) #optional value to store
|
||
|
= (object) @Element
|
||
|
* or, if value is not specified:
|
||
|
= (any) value
|
||
|
> Usage
|
||
|
| for (var i = 0, i < 5, i++) {
|
||
|
| paper.circle(10 + 15 * i, 10, 10)
|
||
|
| .attr({fill: "#000"})
|
||
|
| .data("i", i)
|
||
|
| .click(function () {
|
||
|
| alert(this.data("i"));
|
||
|
| });
|
||
|
| }
|
||
|
\*/
|
||
|
elproto.data = function (key, value) {
|
||
|
var data = eldata[this.id] = eldata[this.id] || {};
|
||
|
if (arguments.length == 1) {
|
||
|
if (Savage.is(key, "object")) {
|
||
|
for (var i in key) if (key[has](i)) {
|
||
|
this.data(i, key[i]);
|
||
|
}
|
||
|
return this;
|
||
|
}
|
||
|
eve("savage.data.get." + this.id, this, data[key], key);
|
||
|
return data[key];
|
||
|
}
|
||
|
data[key] = value;
|
||
|
eve("savage.data.set." + this.id, this, value, key);
|
||
|
return this;
|
||
|
};
|
||
|
/*\
|
||
|
* Element.removeData
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes value associated with an element by given key.
|
||
|
* If key is not provided, removes all the data of the element.
|
||
|
> Parameters
|
||
|
- key (string) #optional key
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
elproto.removeData = function (key) {
|
||
|
if (key == null) {
|
||
|
eldata[this.id] = {};
|
||
|
} else {
|
||
|
eldata[this.id] && delete eldata[this.id][key];
|
||
|
}
|
||
|
return this;
|
||
|
};
|
||
|
/*\
|
||
|
* Element.hover
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handlers for hover for the element.
|
||
|
> Parameters
|
||
|
- f_in (function) handler for hover in
|
||
|
- f_out (function) handler for hover out
|
||
|
- icontext (object) #optional context for hover in handler
|
||
|
- ocontext (object) #optional context for hover out handler
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
elproto.hover = function (f_in, f_out, scope_in, scope_out) {
|
||
|
return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in);
|
||
|
};
|
||
|
/*\
|
||
|
* Element.unhover
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes event handlers for hover for the element.
|
||
|
> Parameters
|
||
|
- f_in (function) handler for hover in
|
||
|
- f_out (function) handler for hover out
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
elproto.unhover = function (f_in, f_out) {
|
||
|
return this.unmouseover(f_in).unmouseout(f_out);
|
||
|
};
|
||
|
var draggable = [];
|
||
|
/*\
|
||
|
* Element.drag
|
||
|
[ method ]
|
||
|
**
|
||
|
* Adds event handlers for drag of the element.
|
||
|
> Parameters
|
||
|
- onmove (function) handler for moving
|
||
|
- onstart (function) handler for drag start
|
||
|
- onend (function) handler for drag end
|
||
|
- mcontext (object) #optional context for moving handler
|
||
|
- scontext (object) #optional context for drag start handler
|
||
|
- econtext (object) #optional context for drag end handler
|
||
|
* Additionaly following `drag` events will be triggered: `drag.start.<id>` on start,
|
||
|
* `drag.end.<id>` on end and `drag.move.<id>` on every move. When element will be dragged over another element
|
||
|
* `drag.over.<id>` will be fired as well.
|
||
|
*
|
||
|
* Start event and start handler will be called in specified context or in context of the element with following parameters:
|
||
|
o x (number) x position of the mouse
|
||
|
o y (number) y position of the mouse
|
||
|
o event (object) DOM event object
|
||
|
* Move event and move handler will be called in specified context or in context of the element with following parameters:
|
||
|
o dx (number) shift by x from the start point
|
||
|
o dy (number) shift by y from the start point
|
||
|
o x (number) x position of the mouse
|
||
|
o y (number) y position of the mouse
|
||
|
o event (object) DOM event object
|
||
|
* End event and end handler will be called in specified context or in context of the element with following parameters:
|
||
|
o event (object) DOM event object
|
||
|
= (object) @Element
|
||
|
\*/
|
||
|
elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) {
|
||
|
if (!arguments.length) {
|
||
|
var origTransform;
|
||
|
return this.drag(function (dx, dy) {
|
||
|
this.attr({
|
||
|
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
|
||
|
});
|
||
|
}, function () {
|
||
|
origTransform = this.transform().local;
|
||
|
});
|
||
|
}
|
||
|
function start(e) {
|
||
|
(e.originalEvent || e).preventDefault();
|
||
|
var scrollY = getScroll("y"),
|
||
|
scrollX = getScroll("x");
|
||
|
this._drag.x = e.clientX + scrollX;
|
||
|
this._drag.y = e.clientY + scrollY;
|
||
|
this._drag.id = e.identifier;
|
||
|
!drag.length && Savage.mousemove(dragMove).mouseup(dragUp);
|
||
|
drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope});
|
||
|
onstart && eve.on("savage.drag.start." + this.id, onstart);
|
||
|
onmove && eve.on("savage.drag.move." + this.id, onmove);
|
||
|
onend && eve.on("savage.drag.end." + this.id, onend);
|
||
|
eve("savage.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e);
|
||
|
}
|
||
|
this._drag = {};
|
||
|
draggable.push({el: this, start: start});
|
||
|
this.mousedown(start);
|
||
|
return this;
|
||
|
};
|
||
|
/*\
|
||
|
* Element.onDragOver
|
||
|
[ method ]
|
||
|
**
|
||
|
* Shortcut for assigning event handler for `drag.over.<id>` event, where id is id of the element (see @Element.id).
|
||
|
> Parameters
|
||
|
- f (function) handler for event, first argument would be the element you are dragging over
|
||
|
\*/
|
||
|
elproto.onDragOver = function (f) {
|
||
|
f ? eve.on("savage.drag.over." + this.id, f) : eve.unbind("savage.drag.over." + this.id);
|
||
|
};
|
||
|
/*\
|
||
|
* Element.undrag
|
||
|
[ method ]
|
||
|
**
|
||
|
* Removes all drag event handlers from given element.
|
||
|
\*/
|
||
|
elproto.undrag = function () {
|
||
|
var i = draggable.length;
|
||
|
while (i--) if (draggable[i].el == this) {
|
||
|
this.unmousedown(draggable[i].start);
|
||
|
draggable.splice(i, 1);
|
||
|
eve.unbind("savage.drag.*." + this.id);
|
||
|
}
|
||
|
!draggable.length && Savage.unmousemove(dragMove).unmouseup(dragUp);
|
||
|
};
|
||
|
});
|