websch/method-draw/jquery-draginput.js

203 lines
6.5 KiB
JavaScript

// Mark MacKay http://method.ac MIT License
$.fn.dragInput = function(cfg){
return this.each(function(){
this.repeating = false;
// Apply specified options or defaults:
// (Ought to refactor this some day to use $.extend() instead)
this.dragCfg = {
min: cfg && !isNaN(parseFloat(cfg.min)) ? Number(cfg.min) : null, // Fixes bug with min:0
max: cfg && !isNaN(parseFloat(cfg.max)) ? Number(cfg.max) : null,
step: cfg && cfg.step ? Number(cfg.step) : 1,
stepfunc: cfg && cfg.stepfunc ? cfg.stepfunc : false,
page: cfg && cfg.page ? Number(cfg.page) : 10,
reset: cfg && cfg.reset ? cfg.reset : this.value,
delay: cfg && cfg.delay ? Number(cfg.delay) : 500,
interval: cfg && cfg.interval ? Number(cfg.interval) : 100,
height: 70,
cursor: cfg && cfg.cursor ? Boolean(cfg.cursor) : false,
start: cfg && cfg.start ? Number(cfg.start) : 0,
_btn_width: 20,
_direction: null,
_delay: null,
_repeat: null,
callback: cfg && cfg.callback ? cfg.callback : null
};
// if a smallStep isn't supplied, use half the regular step
this.dragCfg.smallStep = cfg && cfg.smallStep ? cfg.smallStep : this.dragCfg.step/2;
var $label = $(this).parent();
var $input = $(this);
var cursorHeight = this.dragCfg.height;
var min = this.dragCfg.min;
var max = this.dragCfg.max
var step = this.dragCfg.step
var area = (max - min > 0) ? (max - min) / step : 200;
var scale = area/cursorHeight * step;
var lastY = 0;
var attr = this.getAttribute("data-attr");
var canvas = svgEditor.canvas
var selectedElems = canvas.getSelectedElems();
var isTouch = svgedit.browser.isTouch();
var $cursor = (area && this.dragCfg.cursor)
? $("<div class='draginput_cursor' />").appendTo($label)
: false
if ($cursor && this.dragCfg.start) $cursor.css("top", (this.dragCfg.start*-1)/scale+cursorHeight)
//this is where all the magic happens
this.adjustValue = function(i, noUndo){
var v;
if(isNaN(this.value)) {
v = this.dragCfg.reset;
} else if($.isFunction(this.dragCfg.stepfunc)) {
v = this.dragCfg.stepfunc(this, i);
} else {
// weirdest javascript bug ever: 5.1 + 0.1 = 5.199999999
v = Number((Number(this.value) + Number(i)).toFixed(5));
}
if (max !== null) v = Math.min(v, max);
if (min !== null) v = Math.max(v, min);
if ($cursor) this.updateCursor(v);
this.value = v;
$label.attr("data-value", v)
if ($.isFunction(this.dragCfg.callback)) this.dragCfg.callback(this, noUndo)
};
$label.toggleClass("draginput", $label.is("label"))
// when the mouse is down and moving
this.move = function(e, oy, val) {
if (isTouch) {
e = e.originalEvent.touches[0]
}
// just got started let's save for undo purposes
if (lastY === 0) {
lastY = oy;
}
var deltaY = (e.pageY - lastY) *-1
lastY = e.pageY;
val = deltaY * scale
var fixed = (step < 1) ? 1 : 0
this.adjustValue(val.toFixed(fixed)) //no undo true
};
//when the mouse is released
this.stop = function() {
$('body').removeClass('dragging');
$label.removeClass("active")
$(window).unbind("mousemove.draginput touchmove.draginput mouseup.draginput touchend.draginput");
lastY = 0;
if (selectedElems[0]) {
var batchCmd = canvas.undoMgr.finishUndoableChange();
if (!batchCmd.isEmpty()) canvas.undoMgr.addCommandToHistory(batchCmd);
}
this.adjustValue(0)
}
this.updateCursor = function(){
var value = parseFloat(this.value)
var pos = (value*-1)/scale+cursorHeight
$(this).next(".draginput_cursor").css("top", pos)
}
this.start = function(e) {
if (isTouch) e = e.originalEvent.touches[0]
var oy = e.pageY;
var val = this.value;
var el = this;
canvas.undoMgr.beginUndoableChange(attr, selectedElems)
$('body').addClass('dragging');
$label.addClass('active');
$(window).bind("mousemove.draginput touchmove.draginput", function(e){el.move(e, oy, parseFloat(val))})
$(window).bind("mouseup.draginput touchend.draginput", function(e){el.stop()})
}
$(this)
.attr("readonly", "readonly")
.attr("data-scale", scale)
.attr("data-domain", cursorHeight)
.attr("data-cursor", ($cursor != false))
.bind("mousedown touchstart", function(e){this.start(e);})
.bind("dblclick taphold", function(e) {
this.removeAttribute("readonly", "readonly");
this.focus();
this.select();
})
.blur(function(e){
this.setAttribute("readonly", "readonly");
this.adjustValue(0)
})
.keydown(function(e){
// Respond to up/down arrow keys.
switch(e.keyCode){
case 13: this.blur(); break; // Enter
case 38: this.adjustValue(this.dragCfg.step); break; // Up
case 40: this.adjustValue(-this.dragCfg.step); break; // Down
case 33: this.adjustValue(this.dragCfg.page); break; // PageUp
case 34: this.adjustValue(-this.dragCfg.page); break; // PageDown
}
})
/*
http://unixpapa.com/js/key.html describes the current state-of-affairs for
key repeat events:
- Safari 3.1 changed their model so that keydown is reliably repeated going forward
- Firefox and Opera still only repeat the keypress event, not the keydown
*/
.keypress(function(e){
if (this.repeating) {
// Respond to up/down arrow keys.
switch(e.keyCode){
case 38: this.adjustValue(this.dragCfg.step); break; // Up
case 40: this.adjustValue(-this.dragCfg.step); break; // Down
case 33: this.adjustValue(this.dragCfg.page); break; // PageUp
case 34: this.adjustValue(-this.dragCfg.page); break; // PageDown
}
}
// we always ignore the first keypress event (use the keydown instead)
else {
this.repeating = true;
}
})
// clear the 'repeating' flag
.keyup(function(e) {
this.repeating = false;
switch(e.keyCode){
case 38: // Up
case 40: // Down
case 33: // PageUp
case 34: // PageDown
case 13: this.adjustValue(0); break; // Enter/Return
}
})
.bind("mousewheel", function(e, delta, deltaX, deltaY){
if (deltaY > 0)
this.adjustValue(this.dragCfg.step, true);
else if (deltaY < 0)
this.adjustValue(-this.dragCfg.step, true);
e.preventDefault();
})
});
};
// public function
$.fn.dragInput.updateCursor = function(el){
var value = parseFloat(el.value);
var scale = parseFloat(el.getAttribute("data-scale"));
var domain = parseFloat(el.getAttribute("data-domain"));
var pos = ((value*-1)/scale+domain) + "px";
var cursor = el.nextElementSibling
if (cursor) cursor.style.top = pos;
}