-
Notifications
You must be signed in to change notification settings - Fork 3
/
incrementable.js
94 lines (77 loc) · 2.71 KB
/
incrementable.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
* Script for making multiple numbers in a textfield incrementable/decrementable (like Firebug's CSS values)
* @author Lea Verou
* @version 1.0
*/
/**
* Constructor
* @param textField {HTMLElement} An input or textarea element
* @param modifiers {Object} An object with params ctrlKey, altKey and/or shiftKey. The key combination must have a sum of >= 3.
* For example, {altKey: 1, ctrlKey: 3, shiftKey: 2} means that either Ctrl has to be pressed with the arrows, or alt+shift, or alt+ctrl, or all three.
* The default is 0, which means no modifiers needed.
*/
function Incrementable(textField, modifiers, units) {
var me = this;
this.textField = textField;
this.step = +textField.getAttribute('step') ||
+textField.getAttribute('data-step') || 1;
modifiers = modifiers || {};
this.modifiers = {
ctrlKey: modifiers.ctrlKey || 0,
altKey: modifiers.altKey || 0,
shiftKey: modifiers.shiftKey || 0
};
if(units) {
this.units = units;
}
this.changed = false;
this.textField.addEventListener('keydown', function(evt) {
if(me.checkModifiers(evt) && (evt.keyCode == 38 || evt.keyCode == 40)) {
me.changed = false;
// Up or down arrow pressed, check if there's something
// increment/decrement-able where the caret is
var caret = this.selectionStart, text = this.value,
regex = new RegExp('^([\\s\\S]{0,' + caret + '}[^-0-9\\.])(-?[0-9]*(?:\\.?[0-9]+)(?:' + me.units + '))\\b', 'i');
this.value = this.value.replace(regex, function($0, $1, $2) {
if($1.length <= caret && $1.length + $2.length >= caret) {
me.changed = true;
return $1 + me.stepValue($2, evt.keyCode == 40, evt.shiftKey);
}
else {
return $1 + $2;
}
});
if(me.changed) {
this.selectionEnd = this.selectionStart = caret;
evt.preventDefault();
evt.stopPropagation();
}
}
}, false);
this.textField.addEventListener('keypress', function(evt) {
if(me.changed && me.checkModifiers(evt)
&& (evt.keyCode == 38 || evt.keyCode == 40))
evt.preventDefault();
evt.stopPropagation();
me.changed = false;
}, false);
}
Incrementable.prototype = {
checkModifiers: function(evt) {
var m = this.modifiers;
return m.ctrlKey * evt.ctrlKey + m.altKey * evt.altKey + m.shiftKey * evt.shiftKey >= 3
|| (m.ctrlKey + m.altKey + m.shiftKey == 0);
},
/**
* Gets a <length> and increments or decrements it
*/
stepValue: function(length, decrement, byChunk) {
var val = parseFloat(length) + (decrement? -1 : 1) * (byChunk? 10 : 1) * this.step;
// Prevent rounding errors
if(this.step % 1) {
val = (parseFloat(val.toPrecision(12)));
}
return val + length.replace(/^-|[0-9]+|\./g, '');
},
units: '|%|deg|px|r?em|ex|ch|in|cm|mm|pt|pc|vm|vw|vh|gd|m?s'
};