/*
* This file is part of Toolkit.
*
* Toolkit is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* Toolkit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General
* Public License along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
"use strict";
(function(w, TK){
function extract_matrix (t) {
var a = t.indexOf("matrix(");
if (a < 0) return;
t = t.substr(a+7);
return (t.split(")"))[0].split(",").map(function(v){return parseInt(v.trim())});
}
function xy_from_transform (t) {
var mx = extract_matrix(t);
return (!mx || !mx.length) ? [0, 0] : [mx[4], mx[5]];
}
function startdrag(e, drag) {
this._dragged = 0;
var O = this.options;
if (!O.active) return;
if (e.button !== void(0) && e.button > 0) return;
this._xstart = this._xlast = e.pageX;
this._ystart = this._ylast = e.pageY;
if (O.transform) {
var xy = xy_from_transform(this._style.transform);
this._xpos = xy[0];
this._ypos = xy[1];
} else {
this._xpos = O.node.offsetLeft;
this._ypos = O.node.offsetTop;
}
TK.add_class(O.node, "toolkit-dragging");
}
function stopdrag(e, drag) {
if (!this.options.active) return;
if (e.button !== void(0) && e.button > 0) return;
TK.remove_class(this.options.node, "toolkit-dragging");
}
function dragging(e, drag) {
var O = this.options;
if (!O.active) return;
if (e.button !== void(0) && e.button > 0) return;
this._dragged += (Math.abs(e.pageX - this._xlast)
+ Math.abs(e.pageY - this._ylast)) / 2;
if (this._dragged < O.initial) return;
this._xlast = e.pageX;
this._ylast = e.pageY;
var x = this._xpos + e.pageX - this._xstart;
var y = this._ypos + e.pageY - this._ystart;
if (O.min.x !== false) x = Math.max(O.min.x, x);
if (O.max.x !== false) x = Math.min(O.max.x, x);
if (O.min.y !== false) y = Math.max(O.min.y, y);
if (O.max.y !== false) y = Math.min(O.max.y, y);
if (O.transform) {
var t = this._style.transform;
var mx = extract_matrix(t);
mx[4] = x;
mx[5] = y;
var nt = t.replace(/matrix\([0-9 \,]*\)/, "matrix(" + mx.join(",") + ")");
O.node.style.transform = nt;
} else {
O.node.style.top = y + "px";
O.node.style.left = x + "px";
}
}
function set_handle() {
var h = this.options.handle;
if (this.drag)
this.drag.destroy();
var range = new TK.Range({});
this.drag = new TK.DragValue(this, {
node: h,
range: function () { return range; },
get: function() { return 0; },
set: function(v) { return; },
});
}
/**
* TK.Drag enables dragging of elements on the screen positioned absolutely or by CSS transformation.
*
* @param {Object} [options={ }] - An object containing initial options.
*
* @property {HTMLElement|SVGElement} options.node - The element to drag.
* @property {HTMLElement|SVGElement} [options.handle] A DOM node to be used as a handle. If not set, <code>options.node</code> is used.
* @property {Boolean} [options.active=true] - Enable or disable dragging
* @property {Object|Boolean} [options.min={x: false, y: false}] - Object containing the minimum positions for x and y. A value of <code>false</code> is interpreted as no minimum.
* @property {Object|Boolean} [options.max={x: false, y: false}] - Object containing the maximum positions for x and y. A value of <code>false</code> is interpreted as no maximum.
* @property {Number} [options.initial=2] - Number of pixels the user has to move until dragging starts.
* @property {Boolean} [options.transform=false] - Use CSS transformations instead of absolute positioning.
*
* @extends TK.Base
*
* @class TK.Drag
*/
TK.Drag = TK.class({
_class: "Drag",
Extends: TK.Base,
_options: {
node : "object",
handle : "object",
active : "boolean",
min : "object",
max : "object",
initial : "number",
transform : "boolean",
},
options: {
node : null,
handle : null,
active : true,
min : {x: false, y: false},
max : {x: false, y: false},
initial : 2,
transform : false,
},
/**
* The user is dragging this item.
*
* @event TK.Drag#dragging
*
* @param {DOMEvent} event - The native DOM event.
*/
/**
* The user started dragging this item.
*
* @event TK.Drag#startdrag
*
* @param {DOMEvent} event - The native DOM event.
*/
/**
* The user stopped dragging this item.
*
* @event TK.Drag#stopdrag
*
* @param {DOMEvent} event - The native DOM event.
*/
static_events: {
startdrag: startdrag,
dragging: dragging,
stopdrag: stopdrag,
},
initialize: function (options) {
TK.Base.prototype.initialize.call(this, options);
this.set("handle", this.options.handle);
this.set("node", this.options.node);
},
// GETTERS & SETTERS
set: function (key, value) {
if (key === "node")
this._style = window.getComputedStyle(value);
if (key === "handle" && !value)
value = this.options.node;
TK.Base.prototype.set.call(this, key, value);
if (key === "handle")
set_handle.call(this);
if (key === "initial" && this.drag)
this.drag.set("initial", value);
}
});
})(this, this.TK);