/** * 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 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' };