mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
@@ -361,15 +361,25 @@ Spark._Patcher._copyAttributes = function(tgt, src) {
|
||||
tgt.style.cssText = '';
|
||||
|
||||
var isRadio = false;
|
||||
var finalChecked = null;
|
||||
if (tgt.nodeName === "INPUT") {
|
||||
// Record for later whether this is a radio button.
|
||||
isRadio = (tgt.type === 'radio');
|
||||
// Clearing the attributes of a checkbox won't necessarily
|
||||
// uncheck it, eg in FF12, so we uncheck explicitly
|
||||
// (if necessary; we don't want to generate spurious
|
||||
// propertychange events in old IE).
|
||||
if (tgt.checked === true && src.checked === false) {
|
||||
tgt.checked = false;
|
||||
|
||||
// Figure out whether this should be checked or not. If the re-rendering
|
||||
// changed its idea of checkedness, go with that; otherwsie go with whatever
|
||||
// the control's current setting is.
|
||||
if (isRadio || tgt.type === 'checkbox') {
|
||||
var tgtOriginalChecked = !!tgt._sparkOriginalRenderedChecked &&
|
||||
tgt._sparkOriginalRenderedChecked[0];
|
||||
var srcOriginalChecked = !!src._sparkOriginalRenderedChecked &&
|
||||
src._sparkOriginalRenderedChecked[0];
|
||||
if (tgtOriginalChecked === srcOriginalChecked) {
|
||||
finalChecked = !!tgt.checked;
|
||||
} else {
|
||||
finalChecked = !!srcOriginalChecked;
|
||||
tgt._sparkOriginalRenderedChecked = [finalChecked];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,9 +456,6 @@ Spark._Patcher._copyAttributes = function(tgt, src) {
|
||||
if (srcExpando)
|
||||
src._sparkOriginalRenderedValue = srcExpando;
|
||||
|
||||
if (typeof tgt.checked !== "undefined" && src.checked)
|
||||
tgt.checked = src.checked;
|
||||
|
||||
if (src.name)
|
||||
tgt.name = src.name;
|
||||
|
||||
@@ -463,8 +470,7 @@ Spark._Patcher._copyAttributes = function(tgt, src) {
|
||||
if (name === "type") {
|
||||
// can't change type of INPUT in IE; don't support it
|
||||
} else if (name === "checked") {
|
||||
tgt.checked = tgt.defaultChecked = (value && value !== "false");
|
||||
tgt.setAttribute("checked", "checked");
|
||||
// handled specially below
|
||||
} else if (name === "style") {
|
||||
tgt.style.cssText = src.style.cssText;
|
||||
} else if (name === "class") {
|
||||
@@ -544,4 +550,19 @@ Spark._Patcher._copyAttributes = function(tgt, src) {
|
||||
// around we'll be comparing to this rendered value instead of the old one.
|
||||
tgt._sparkOriginalRenderedValue = [srcOriginalRenderedValue];
|
||||
}
|
||||
|
||||
// Deal with checkboxes and radios.
|
||||
if (finalChecked !== null) {
|
||||
// Don't do a no-op write to 'checked', since in some browsers that triggers
|
||||
// events.
|
||||
if (tgt.checked !== finalChecked)
|
||||
tgt.checked = finalChecked;
|
||||
|
||||
// Set various other fields related to checkedness.
|
||||
tgt.defaultChecked = finalChecked;
|
||||
if (finalChecked)
|
||||
tgt.setAttribute("checked", "checked");
|
||||
else
|
||||
tgt.removeAttribute("checked");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -138,6 +138,7 @@ Tinytest.add("spark - patch - copyAttributes", function(test) {
|
||||
var nodeHtml = buf.join('');
|
||||
var frag = DomUtils.htmlToFragment(nodeHtml);
|
||||
var n = frag.firstChild;
|
||||
n._sparkOriginalRenderedChecked = [n.checked];
|
||||
if (! node) {
|
||||
node = n;
|
||||
} else {
|
||||
|
||||
@@ -311,9 +311,15 @@ _.extend(Spark._Renderer.prototype, {
|
||||
// We save it in a one-element array expando. We use the array because IE8
|
||||
// gets confused by expando properties with scalar values and exposes them
|
||||
// as HTML attributes.
|
||||
//
|
||||
// We also save the values of CHECKED for radio and checkboxes.
|
||||
_.each(DomUtils.findAll(ret, '[value], textarea, select'), function (node) {
|
||||
node._sparkOriginalRenderedValue = [DomUtils.getElementValue(node)];
|
||||
});
|
||||
_.each(DomUtils.findAll(ret, 'input[type=checkbox], input[type=radio]'),
|
||||
function (node) {
|
||||
node._sparkOriginalRenderedChecked = [node.checked];
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2712,6 +2712,74 @@ Tinytest.add("spark - controls - radio", function(test) {
|
||||
div.kill();
|
||||
});
|
||||
|
||||
Tinytest.add("spark - controls - checkbox", function(test) {
|
||||
var labels = ["Foo", "Bar", "Baz"];
|
||||
var Rs = {};
|
||||
_.each(labels, function (label) {
|
||||
Rs[label] = ReactiveVar(false);
|
||||
});
|
||||
var changeBuf = [];
|
||||
var div = OnscreenDiv(renderWithPreservation(function() {
|
||||
var buf = [];
|
||||
_.each(labels, function (label) {
|
||||
var checked = Rs[label].get() ? 'checked="checked"' : '';
|
||||
buf.push('<input type="checkbox" name="checky" '+
|
||||
'value="'+label+'" '+checked+'/>');
|
||||
});
|
||||
return buf.join('');
|
||||
}));
|
||||
|
||||
Meteor.flush();
|
||||
|
||||
// get the three boxes; they should be considered 'labeled' by the patcher and
|
||||
// not change identities!
|
||||
var boxes = nodesToArray(div.node().getElementsByTagName("INPUT"));
|
||||
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, false, false]);
|
||||
|
||||
// Re-render with first one checked.
|
||||
Rs.Foo.set(true);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [true, false, false]);
|
||||
|
||||
// Re-render with first one unchecked again.
|
||||
Rs.Foo.set(false);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, false, false]);
|
||||
|
||||
// User clicks the second one.
|
||||
clickElement(boxes[1]);
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, true, false]);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, true, false]);
|
||||
|
||||
// Re-render with third one checked. Second one should stay checked because
|
||||
// it's a user update!
|
||||
Rs.Baz.set(true);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, true, true]);
|
||||
|
||||
// User turns second and third off.
|
||||
clickElement(boxes[1]);
|
||||
clickElement(boxes[2]);
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, false, false]);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, false, false]);
|
||||
|
||||
// Re-render with first one checked. Third should stay off because it's a user
|
||||
// update!
|
||||
Rs.Foo.set(true);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [true, false, false]);
|
||||
|
||||
// Re-render with first one unchecked. Third should still stay off.
|
||||
Rs.Foo.set(false);
|
||||
Meteor.flush();
|
||||
test.equal(_.pluck(boxes, 'checked'), [false, false, false]);
|
||||
|
||||
div.kill();
|
||||
});
|
||||
|
||||
_.each(['textarea', 'text', 'password', 'submit', 'button',
|
||||
'reset', 'select', 'hidden'], function (type) {
|
||||
Tinytest.add("spark - controls - " + type, function(test) {
|
||||
|
||||
Reference in New Issue
Block a user