-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Fix setting tickwidth, tickcolor, ticklen, linecolor and possibly more attributes via template #4904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix setting tickwidth, tickcolor, ticklen, linecolor and possibly more attributes via template #4904
Changes from 13 commits
bddaafa
11fd23c
756a0ee
a2c1c93
8d0b4cb
5c3be81
642bf28
57cec14
1d9cc4a
cf7c061
21b86cd
2b911d1
adc36cd
24d1da9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -361,58 +361,81 @@ exports.valObjectMeta = { | |||||||||||
* as a convenience, returns the value it finally set | ||||||||||||
*/ | ||||||||||||
exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt) { | ||||||||||||
var opts = nestedProperty(attributes, attribute).get(); | ||||||||||||
return _coerce(containerIn, containerOut, attributes, attribute, dflt).val; | ||||||||||||
}; | ||||||||||||
|
||||||||||||
function _coerce(containerIn, containerOut, attributes, attribute, dflt, opts) { | ||||||||||||
var shouldValidate = (opts || {}).shouldValidate; | ||||||||||||
|
||||||||||||
var attr = nestedProperty(attributes, attribute).get(); | ||||||||||||
if(dflt === undefined) dflt = attr.dflt; | ||||||||||||
var src = ''; // i.e. default | ||||||||||||
|
||||||||||||
var propIn = nestedProperty(containerIn, attribute); | ||||||||||||
var propOut = nestedProperty(containerOut, attribute); | ||||||||||||
var v = propIn.get(); | ||||||||||||
var valIn = propIn.get(); | ||||||||||||
|
||||||||||||
var template = containerOut._template; | ||||||||||||
if(v === undefined && template) { | ||||||||||||
v = nestedProperty(template, attribute).get(); | ||||||||||||
if(valIn === undefined && template) { | ||||||||||||
valIn = nestedProperty(template, attribute).get(); | ||||||||||||
if(valIn !== undefined && shouldValidate && validate(valIn, attr)) src = 't'; // template | ||||||||||||
|
||||||||||||
// already used the template value, so short-circuit the second check | ||||||||||||
template = 0; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if(dflt === undefined) dflt = opts.dflt; | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* arrayOk: value MAY be an array, then we do no value checking | ||||||||||||
* at this point, because it can be more complicated than the | ||||||||||||
* individual form (eg. some array vals can be numbers, even if the | ||||||||||||
* single values must be color strings) | ||||||||||||
*/ | ||||||||||||
if(opts.arrayOk && isArrayOrTypedArray(v)) { | ||||||||||||
propOut.set(v); | ||||||||||||
return v; | ||||||||||||
if(attr.arrayOk && isArrayOrTypedArray(valIn)) { | ||||||||||||
propOut.set(valIn); | ||||||||||||
return { | ||||||||||||
inp: valIn, | ||||||||||||
val: valIn, | ||||||||||||
src: 'c' // container | ||||||||||||
}; | ||||||||||||
} | ||||||||||||
|
||||||||||||
var coerceFunction = exports.valObjectMeta[opts.valType].coerceFunction; | ||||||||||||
coerceFunction(v, propOut, dflt, opts); | ||||||||||||
var coerceFunction = exports.valObjectMeta[attr.valType].coerceFunction; | ||||||||||||
coerceFunction(valIn, propOut, dflt, attr); | ||||||||||||
|
||||||||||||
var valOut = propOut.get(); | ||||||||||||
if(valOut !== undefined && shouldValidate && validate(valIn, attr)) src = 'c'; // container | ||||||||||||
|
||||||||||||
var out = propOut.get(); | ||||||||||||
// in case v was provided but invalid, try the template again so it still | ||||||||||||
// overrides the regular default | ||||||||||||
if(template && out === dflt && !validate(v, opts)) { | ||||||||||||
v = nestedProperty(template, attribute).get(); | ||||||||||||
coerceFunction(v, propOut, dflt, opts); | ||||||||||||
out = propOut.get(); | ||||||||||||
if(template && valOut === dflt && !validate(valIn, attr)) { | ||||||||||||
valIn = nestedProperty(template, attribute).get(); | ||||||||||||
coerceFunction(valIn, propOut, dflt, attr); | ||||||||||||
valOut = propOut.get(); | ||||||||||||
|
||||||||||||
if(valOut !== undefined && shouldValidate && validate(valIn, attr)) src = 't'; // template | ||||||||||||
} | ||||||||||||
return out; | ||||||||||||
}; | ||||||||||||
|
||||||||||||
return { | ||||||||||||
inp: valIn, | ||||||||||||
val: valOut, | ||||||||||||
src: src | ||||||||||||
}; | ||||||||||||
} | ||||||||||||
|
||||||||||||
/** | ||||||||||||
* Variation on coerce | ||||||||||||
* useful when setting an attribute to a valid value | ||||||||||||
* can change the default for another attribute. | ||||||||||||
* | ||||||||||||
* Uses coerce to get attribute value if user input is valid, | ||||||||||||
* returns attribute default if user input it not valid or | ||||||||||||
* returns false if there is no user input. | ||||||||||||
*/ | ||||||||||||
exports.coerce2 = function(containerIn, containerOut, attributes, attribute, dflt) { | ||||||||||||
var propIn = nestedProperty(containerIn, attribute); | ||||||||||||
var propOut = exports.coerce(containerIn, containerOut, attributes, attribute, dflt); | ||||||||||||
var valIn = propIn.get(); | ||||||||||||
|
||||||||||||
return (valIn !== undefined && valIn !== null) ? propOut : false; | ||||||||||||
var out = _coerce(containerIn, containerOut, attributes, attribute, dflt, { | ||||||||||||
shouldValidate: true | ||||||||||||
}); | ||||||||||||
return (out.src && out.inp !== undefined) ? out.val : false; | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I'm not sure about this, but at this point I think the best way to handle it will be extensive jasmine testing. I see we actually do have a test that contradicts one thing I was hoping to "fix": plotly.js/test/jasmine/tests/lib_test.js Line 781 in be70865
Do we have a good reason for that behavior? It seems contrary to what we do with templates, as well as contrary to what I think the purpose of
@archmoj do you see any issue if we make such a change? I feel like that test is locking down a bug rather than useful behavior. (while we're at it there's a piece of copypasta in that test plotly.js/test/jasmine/tests/lib_test.js Lines 795 to 798 in be70865
colOut lines and 2 sizeOut lines)
So what I'd like to see is a test covering each of the valTypes used by
I suspect getting this to work for all valTypes may not be worthwhile - especially since there are things like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson thanks for the review. Please see cf7c061 and 21b86cd. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson wondering what should be the result of this test? expect(yaxis.ticklen).toBe(undefined);
expect(yaxis.tickwidth).toBe(undefined);
expect(yaxis.tickcolor).toBe(undefined);
expect(yaxis.ticks).toBe(''); ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alexcjohnson this PR is ready for another review. |
||||||||||||
}; | ||||||||||||
|
||||||||||||
/* | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see -
shouldValidate
is really just used to improve performance for regularcoerce
by skipping these extra validation steps. Very nice.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, is this particular line actually necessary? Since this step is overwriting
valIn
, after this we're going to treat it as though it came from the container, so on line 406 (or 398) we'll reset it to'c'
. In practice we don't care about this for now - given thecoerce2
logic all we care about is truthy (specified) or falsy (default), but in case that ever changes, seems like we should either:src
so future users don't think'c'
vs't'
is accurate't'
, something like:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. Revised in 24d1da9.