I'm writing a JS webapp client. User can edit list/tree of text items (say, a todo list or notes). I manipulate DOM with jQuery a lot.
User can navigate the list up and down using keyboard (similar to J/K keys in GMail), and perform several other operations. Many of these operations have mirror "up" / "down" functionality, e.g.
$.fn.moveItemUp = function() {
var prev = this.getPreviousItem();
prev && this.insertBefore(prev);
// there's a bit more code in here, but the idea is pretty simple,
// i.e. move the item up if there's a previous item in the list
}
$.fn.moveItemDown = function() {
var next = this.getNextItem();
next && this.insertAfter(next);
// ....
}
Now this pattern of having two almost identical functions is repeated in several places in my code because there are many operations on the list/tree of items that are pretty much symmetrical.
QUESTION: How do I refactor this elegantly to avoid code duplication?
The trivial way I came up with so far is to use .apply()...
$.fn.moveItem = function(direction) {
var up = direction === 'up',
sibling = up ? this.getPreviousItem() : this.getNextItem(),
func = up ? $.fn.insertBefore : $.fn.insertAfter;
// ...
if (! sibling) { return false; }
func.apply(this, [ sibling ]);
// ...
};
The benefit is easier maintenance when structure of other elements of the code requires changing moveUp/moveDown. I've already needed to slightly change the code multiple times, and I always need to keep in mind that I need to do it in two places...
But I'm not happy with the "unified" version, because:
- Implementation is more complicated than simple moveUp/moveDown, hence in the future it may NOT be so easy to maintain afterall. I like simple code. All these parameters, ternary operations, .apply() tricks in every function that's supposed to go "up" and "down"...
- Not sure if it's safe to refer to jQuery.fn.* functions explicitly (after all they're supposed to be used by applying them to jQuery object $('...').*)
How do you solve those "almost identical code" situations when working with DOM or similar structure?