-
Notifications
You must be signed in to change notification settings - Fork 481
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 CdoFieldDropdown bug #51879
Fix CdoFieldDropdown bug #51879
Conversation
@@ -32,6 +32,16 @@ export default class CdoFieldDropdown extends GoogleBlockly.FieldDropdown { | |||
} | |||
} | |||
|
|||
loadState(state) { |
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.
Overridden from mainline Blockly.
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.
Not very familiar with this code, but confirmed it at least seems to fix Music Lab.
* For music lab, `state` is the value of the field. | ||
* For other labs, `state` is stringified xml. |
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.
In the future, will this only be a difference between Music Lab and all other labs? Or could other labs that use Blockly in the same way as Music Lab also fall into the former case?
(The underlying question here is whether Music Lab is doing something it shouldn't, or is it actually doing things as expected?)
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.
I think this is more of a question of whether the source for the block is XML or JSON, but both are supported. From the documentation:
saveState
andloadState
are serialization hooks that work with the new JSON serialization system.In some cases you do not need to provide these, because the default implementations will work. If (1) your field is a direct subclass of the base
Blockly.Field
class, (2) your value is a JSON serializable type, and (3) you only need to serialize the value, then the default implementation will work just fine!Otherwise, your
saveState
function should return a JSON serializable object/value which represents the state of the field. And your loadState function should accept the same JSON serializable object/value, and apply it to the field.
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.
Also, I believe it's fine for state to be stringified xml i this case and that it's actually an intentional part of mainline's backwards compatibility with XML..
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.
Thanks Mike! Music lab is doing what the Blockly team now recommends (using json) and Blocky's implementation of the fields is to support both json and xml. But they didn't anticipate this scenario where sometimes state is xml and sometimes it's stored in json as it is in our code base.
I think this was a super useful bug since we're migrating to using json, but from my understanding, we'll always have to support xml to some degree (levelbuilder, student projects).
This reverts commit 6eeb05e.
…to alice/fix-dropdown-bug
if (field) { | ||
this.setValue(field.textContent); | ||
} else { | ||
this.setValue(state); // music lab |
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.
This line actually looks closest to the standard implementation in the documentation, which makes me wonder if our code should treat it as the general rule rather than the exception. Either way, I'm wondering if it makes sense to do all the xml parsing above if state
is just the value. Is there a way we could check at the top of this function which type of state
we have and only parse the xml if necessary?
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.
Sure. I can first check to see if state
is not a stringified xml (checking first character). How does that sound?
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.
Discussed in Slack - using regex.
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.
This looks good, Alice!
* | ||
* @param state The state we want to apply to the field. | ||
* @override because different labs store `state` in different ways. | ||
* For music lab, `state` is the value of the field. |
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.
nit: Can we update this to clarify that this isn't a "music lab" thing so much as it is a JSON serialization thing?
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.
Sure - pushed the update!
if (this.config) { | ||
element.setAttribute('config', this.config); | ||
} | ||
super.toXml(element); |
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.
Can you explain why we wanted to move this down?
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.
Sure!
Short answer: to be consistent with fromXml
.
Long answer: super.toXml
assigns to the element (textContent
) the value of the field. We override to support the config
attribute if it exists and the placement of the call to super
doesn't matter in this function.
But the order does matter in fromXml
above. The call to super.fromXml
must happen after we check the config
. So I moved this line just to be consistent with fromXml
.
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.
Perfect, thanks!
if (this.isOptionListDynamic()) { | ||
this.getOptions(false); | ||
} | ||
// TODO: handle config if stored in json |
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.
At this point, when state
is stored as json. it is assigned only the value. At some point, we may choose support config
in json so leaving comment here.
// Check if state is not stringified xml, i.e., value from json. | ||
const fieldTagRegEx = /<field/; | ||
if (!fieldTagRegEx.test(state)) { | ||
if (this.isOptionListDynamic()) { |
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.
Although we currently don't generate options using a function, we may choose to do so in the future.
Re-wrote comment explaining current state - that we only support config in xml and not in json.
return; | ||
} | ||
const field = GoogleBlockly.utils.xml.textToDom(state); | ||
this.fromXml(field); |
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.
Handles state
when state
is stored as xml.
Fix CdoFieldDropdown bug
This PR fixes a bug that resulted in the recently refactored
CdoFieldDropdown
from this PR.The bug showed up in Project Beats - the toolbox flyout was not working properly. See video below
Before update:
before-update-toolbox.mp4
Here is the error message in the dev console:
I saw that there were calls to
loadLegacyState
andloadState
so I hopped over tofield_dropdown.ts
from mainline Blockly.loadState
is defined as:Initially, I overrode this function in
cdoFieldDropdown.js
so that the first parameter forloadLegacyState
isCdoFieldDropdown
instead ofFieldDropdown
. This fixed the problem in music lab, but caused a regression back in Dance Lab with the field that contained aconfig
attribute. Once the block was dropped in the workspace, the dropdown options went back to the original state listing all 12 options instead of just 'cat' and 'sloth'. See video below:may15.mp4
In
loadState
,loadLegacyState
is called. This function is where the music lab error occurs. BecausefromXml
was overridden by the PR that provides support for theconfig
attribute, the following condition is now set totrue
.When
this.fromXml(utilsXml.textToDom(state)
is called, an error is thrown becausestate
in music lab is assigned the value of the dropdown field, e.g.,1
, and not a stringified xml element.Thus, I override the
loadState
function to accommodate for the differences in whatstate
stores in Google Blockly labs.Links
Testing story
Deployment strategy
Follow-up work
Privacy
Security
Caching
PR Checklist: