Skip to content

Instantly share code, notes, and snippets.

@ympbyc
Last active November 28, 2016 01:58
Show Gist options
  • Save ympbyc/fb37d8728f1272b27846 to your computer and use it in GitHub Desktop.
Save ympbyc/fb37d8728f1272b27846 to your computer and use it in GitHub Desktop.
コレクションの差分取ってよしなにやってくれる偉いヤツ
(function (K) {
K.util = {};
K.util.dom = {};
//[a] * [a] * (a->HTMLElement) * HTMLElement * $ -> ()
//collとold_collの差分を計算してelに反映させる
K.util.dom.render_collection_change = function (coll, old_coll, f, el, $) {
var $el = $(el);
var $children = $(el).children();
var children = $children.get();
if (children.length !== old_coll.length) {
console.warn("DOM state and app state appears to be inconsistent. Re-rendering everything in the element");
$el.html("");
coll.forEach(function (item) {
$(f(item)).appendTo($el);
});
return;
}
var diff = K.util.difference(coll, old_coll);
console.info("Rendering "
+ (diff.inserted.length + diff.removed.length)
+ " items based on calculated diff: " + JSON.stringify(diff));
var applied = K.util.apply_difference(diff, old_coll, {
inserted: function (d) {
var $new = f(d.item);
if (children[d.at])
$(children[d.at]).before($new);
else
children[d.at] = $new.appendTo($el);
},
removed: function (d) {
$(children[d.from]).remove();
children[d.from] = undefined;
},
compact: function () {
children = _.compact(children);
}
});
setTimeout(function () {
if ( ! _.isEqual(applied, coll))
throw new Error(
"BUG(K.util.render_collection_change) Please report to ---- team : "
+ JSON.stringify([applied, coll, old_coll], null, " ")
);
}, 0);
};
//[a] * [a] -> {inserted: [{at: Number, item: a}], removed: [{from: Number, item: a}]}
K.util.difference = function (xs, ys) {
var ws = xs;
var diff = {
inserted: [],
removed: []
};
if (xs.length < ys.length)
ws = xs.concat(_.range(0, ys.length - xs.length).map(function () {
return undefined;
}));
ws.forEach(function (x, i) {
if (x !== ys[i]) {
if (ys[i]) diff.removed.push({from: i, item: ys[i]});
if (x) diff.inserted.push({at: i, item: x});
}
});
return diff;
};
//{inserted: [{at: Number, item: a}], removed: [{from: Number, item: a}]} * [a] * {} -> [a]
K.util.apply_difference = function (diff, xs, actions) {
actions = actions || {};
var zs = _.clone(xs);
diff.removed.forEach(function (d) {
zs[d.from] = undefined;
if (actions.removed)
actions.removed(d);
});
if (actions.compact) actions.compact();
diff.inserted.forEach(function (d) {
zs[d.at] = d.item;
if (actions.inserted)
actions.inserted(d);
});
return _.compact(zs);
};
}(window.kakahiaka));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment