playback: separate out style-dependent methods
cleanups in PlaybackController
Use just CSS to center playback controls
implement CODAP playback button style

[#79814268]
cleanups in ExportController
Remove the never-used builtin Analyze Data button

[#79814268]
dispatch event when CODAP export becomes available

[#79814268]
Use CODAP button style; move exporter setup

[#79814268]

Exporter setup now needs access to the model's properties on initialization, so it was moved. The MD2D metadata fix also assures that setting controlButtonStyle doesn't cause breakage by triggering a property invalidation before the model is really ready.
fix broken mock, & test new ExportController event

[#79814268]
Don’t throw (harmless) error if no CODAP callback
delay dgExporter init until interactive load

[#79814268]

Previously, redirected interactives to fail to connect to CODAP because dgExporter was inited in the initial load of the interactive (which doesn’t initialize an interactive but just reloads the page), swallowing the codap-present message. Now we only init when the interactive
no point in dispatching event from constructor…

[#79814268]
don’t show new run button if no start/stop

[#79814268]
rm previous playback buttons before adding new ones

[#79814268]
Correctly notify of CODAP detection

[#79814268]
and fix exporter test

[#79814268]
Fix parentMessageAPI vs. codapPhone race

[#79814268]

Unfortunately, the current design of iframePhone doesn’t provide builtin namespacing, or a way for an iframePhone endpoint to find and “join” a previously-instantiated iframePhone endpoint in the same page. This means that if the parentMessageAPI (used to communicate with e.g., interactives.html on lab.concord.org) is instantiated in before the exportController/dgExporter is initialized, then the ‘hello’ message sent by the parentMessageAPI is received by CODAP, which responds with the queued codap-present message. If dgExporter starts listening *after* the message is processed by the parentMessageAPI, then it never hears the codap-present message.

This is a race in the current setup because, at least in Chrome and Firefox, the dgExporter *usually* started listening before the ‘codap-present’ message was actually dispatched to the iframe. But this was not guaranteed as the message was definitely *sent* before the dgExporter started listening.
Make disabling of playback buttons more prominent

[#79814468]
playback: update button states when style changes

[#79814268]
playback: don’t enable new run until model stops

[#79814268]