@@ -61,7 +61,7 @@ var domain = "http://pythontutor.com/"; // for deployment
6161var isExecutingCode = false ; // nasty, nasty global
6262
6363
64- var appMode = 'edit' ; // 'edit', 'display', or 'display_no_frills' also support
64+ var appMode = 'edit' ; // 'edit', 'display', 'display_no_frills'. also support
6565 // 'visualize' for backward compatibility (same as 'display')
6666
6767var preseededCurInstr = null ; // if you passed in a 'curInstr=<number>' in the URL, then set this var
@@ -91,11 +91,49 @@ function guid() {
9191
9292var myVisualizer = null ; // singleton ExecutionVisualizer instance
9393
94-
9594var rawInputLst = [ ] ; // a list of strings inputted by the user in response to raw_input or mouse_input events
9695
96+
97+ function redrawConnectors ( ) {
98+ if ( appMode == 'display' || appMode == 'visualize' /* deprecated */ ) {
99+ if ( myVisualizer ) {
100+ myVisualizer . redrawConnectors ( ) ;
101+ }
102+ }
103+ }
104+
105+
97106function genericOptFrontendReady ( ) {
98- // log a generic AJAX error handler
107+ var queryStrOptions = getQueryStringOptions ( ) ;
108+ setToggleOptions ( queryStrOptions ) ;
109+
110+ if ( queryStrOptions . preseededCode ) {
111+ setCodeMirrorVal ( queryStrOptions . preseededCode ) ;
112+ }
113+
114+ // ugh tricky -- always start in edit mode by default, and then
115+ // simulate a click to get it to switch to display mode ONLY after the
116+ // code successfully executes
117+ appMode = 'edit' ;
118+ if ( ( queryStrOptions . appMode == 'display' ||
119+ queryStrOptions . appMode == 'visualize' /* 'visualize' is deprecated */ ) &&
120+ queryStrOptions . preseededCode /* jump to display only with pre-seeded code */ ) {
121+ console . log ( 'seeded in display mode' ) ;
122+ preseededCurInstr = queryStrOptions . preseededCurInstr ; // ugly global
123+ $ ( "#executeBtn" ) . trigger ( 'click' ) ;
124+ }
125+ $ . bbq . removeState ( ) ; // clean up the URL no matter what
126+
127+ $ ( window ) . resize ( redrawConnectors ) ;
128+
129+ $ ( '#genUrlBtn' ) . bind ( 'click' , function ( ) {
130+ var myArgs = getAppState ( ) ;
131+ var urlStr = $ . param . fragment ( window . location . href , myArgs , 2 /* clobber all */ ) ;
132+ $ ( '#urlOutput' ) . val ( urlStr ) ;
133+ } ) ;
134+
135+
136+ // register a generic AJAX error handler
99137 $ ( document ) . ajaxError ( function ( evt , jqxhr , settings , exception ) {
100138 // ignore errors related to togetherjs stuff:
101139 if ( settings . url . indexOf ( 'togetherjs' ) > - 1 ) {
@@ -150,15 +188,33 @@ function setToggleOptions(dat) {
150188
151189// get the ENTIRE current state of the app
152190function getAppState ( ) {
153- return { code : pyInputCodeMirror . getValue ( ) ,
154- mode : appMode ,
155- cumulative : $ ( '#cumulativeModeSelector' ) . val ( ) ,
156- heapPrimitives : $ ( '#heapPrimitivesSelector' ) . val ( ) ,
157- drawParentPointers : $ ( '#drawParentPointerSelector' ) . val ( ) ,
158- textReferences : $ ( '#textualMemoryLabelsSelector' ) . val ( ) ,
159- showOnlyOutputs : $ ( '#showOnlyOutputsSelector' ) . val ( ) ,
160- py : $ ( '#pythonVersionSelector' ) . val ( ) ,
161- curInstr : myVisualizer ? myVisualizer . curInstr : undefined } ;
191+ var ret = { code : pyInputCodeMirror . getValue ( ) ,
192+ mode : appMode ,
193+ cumulative : $ ( '#cumulativeModeSelector' ) . val ( ) ,
194+ heapPrimitives : $ ( '#heapPrimitivesSelector' ) . val ( ) ,
195+ drawParentPointers : $ ( '#drawParentPointerSelector' ) . val ( ) ,
196+ textReferences : $ ( '#textualMemoryLabelsSelector' ) . val ( ) ,
197+ showOnlyOutputs : $ ( '#showOnlyOutputsSelector' ) . val ( ) ,
198+ py : $ ( '#pythonVersionSelector' ) . val ( ) ,
199+ curInstr : myVisualizer ? myVisualizer . curInstr : undefined } ;
200+
201+ // keep this really clean by avoiding undefined values
202+ if ( ret . cumulative === undefined )
203+ delete ret . cumulative ;
204+ if ( ret . heapPrimitives === undefined )
205+ delete ret . heapPrimitives ;
206+ if ( ret . drawParentPointers === undefined )
207+ delete ret . drawParentPointers ;
208+ if ( ret . textReferences === undefined )
209+ delete ret . textReferences ;
210+ if ( ret . showOnlyOutputs === undefined )
211+ delete ret . showOnlyOutputs ;
212+ if ( ret . py === undefined )
213+ delete ret . py ;
214+ if ( ret . curInstr === undefined )
215+ delete ret . curInstr ;
216+
217+ return ret ;
162218}
163219
164220// return whether two states match, except don't worry about curInstr
@@ -186,10 +242,20 @@ function setVisibleAppState(appState) {
186242}
187243
188244
189- // update the app display based on current state of the appMode global
190- // TODO: refactor all frontend clients to call this unified function
191- function updateAppDisplay ( ) {
192- if ( appMode === undefined || appMode == 'edit' ) {
245+ // sets the global appMode variable if relevant and also the URL hash to
246+ // support some amount of Web browser back button goodness
247+ function updateAppDisplay ( newAppMode ) {
248+ // idempotence is VERY important here
249+ if ( newAppMode == appMode ) {
250+ return ;
251+ }
252+
253+ appMode = newAppMode ; // global!
254+
255+ if ( appMode === undefined || appMode == 'edit' ||
256+ ! myVisualizer /* subtle -- if no visualizer, default to edit mode */ ) {
257+ appMode = 'edit' ; // canonicalize
258+
193259 $ ( "#pyInputPane" ) . show ( ) ;
194260 $ ( "#pyOutputPane,#surveyHeader" ) . hide ( ) ;
195261 $ ( "#embedLinkDiv" ) . hide ( ) ;
@@ -208,39 +274,48 @@ function updateAppDisplay() {
208274 $ ( "#pyOutputPane" ) . empty ( ) ;
209275 myVisualizer = null ;
210276 $ ( document ) . unbind ( 'keydown' ) ; // also kill kb bindings to avoid staleness
277+
278+ $ ( document ) . scrollTop ( 0 ) ; // scroll to top to make UX better on small monitors
279+
280+ $ . bbq . pushState ( { mode : 'edit' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
211281 }
212282 else if ( appMode == 'display' || appMode == 'visualize' /* 'visualize' is deprecated */ ) {
213- if ( ! myVisualizer ) {
214- enterEditMode ( ) ; // if there's no visualizer, switch back to edit mode
215- }
216- else {
217- $ ( "#pyInputPane" ) . hide ( ) ;
218- $ ( "#pyOutputPane,#surveyHeader" ) . show ( ) ;
219- $ ( "#embedLinkDiv" ) . show ( ) ;
220-
221- doneExecutingCode ( ) ;
222-
223- // do this AFTER making #pyOutputPane visible, or else
224- // jsPlumb connectors won't render properly
225- myVisualizer . updateOutput ( ) ;
226-
227- // customize edit button click functionality AFTER rendering (NB: awkward!)
228- $ ( '#pyOutputPane #editCodeLinkDiv' ) . show ( ) ;
229- $ ( '#pyOutputPane #editBtn' ) . click ( function ( ) {
230- enterEditMode ( ) ;
231- } ) ;
232- }
233- }
234- else if ( appMode == 'display_no_frills' ) {
283+ assert ( myVisualizer ) ;
284+ appMode = 'display' ; // canonicalize
285+
235286 $ ( "#pyInputPane" ) . hide ( ) ;
236287 $ ( "#pyOutputPane,#surveyHeader" ) . show ( ) ;
237288 $ ( "#embedLinkDiv" ) . show ( ) ;
289+
290+ doneExecutingCode ( ) ;
291+
292+ // do this AFTER making #pyOutputPane visible, or else
293+ // jsPlumb connectors won't render properly
294+ myVisualizer . updateOutput ( ) ;
295+
296+ // customize edit button click functionality AFTER rendering (NB: awkward!)
297+ $ ( '#pyOutputPane #editCodeLinkDiv' ) . show ( ) ;
298+ $ ( '#pyOutputPane #editBtn' ) . click ( function ( ) {
299+ enterEditMode ( ) ;
300+ } ) ;
301+
302+ $ ( document ) . scrollTop ( 0 ) ; // scroll to top to make UX better on small monitors
303+
304+ $ . bbq . pushState ( { mode : 'display' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
238305 }
239306 else {
240- assert ( false ) ;
307+ assert ( appMode == 'display_no_frills' ) ;
308+ assert ( myVisualizer ) ;
309+
310+ $ ( "#pyInputPane" ) . hide ( ) ;
311+ $ ( "#pyOutputPane,#surveyHeader" ) . show ( ) ;
312+ $ ( "#embedLinkDiv" ) . show ( ) ;
313+ $ . bbq . pushState ( { mode : 'display_no_frills' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
241314 }
242315
243316 $ ( '#urlOutput,#embedCodeOutput' ) . val ( '' ) ; // clear to avoid stale values
317+
318+ console . log ( 'END updateAppDisplay' , appMode ) ;
244319}
245320
246321
@@ -270,18 +345,20 @@ function doneExecutingCode() {
270345 isExecutingCode = false ; // nasty global
271346}
272347
348+
273349function enterDisplayMode ( ) {
274- $ ( document ) . scrollTop ( 0 ) ; // scroll to top to make UX better on small monitors
275- $ . bbq . pushState ( { mode : 'display' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
350+ console . log ( 'enterDisplayMode' ) ;
351+ updateAppDisplay ( 'display' ) ;
276352}
277353
278354function enterEditMode ( ) {
279- $ ( document ) . scrollTop ( 0 ) ; // scroll to top to make UX better on small monitors
280- $ . bbq . pushState ( { mode : 'edit' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
355+ console . log ( 'enterEditMode' ) ;
356+ updateAppDisplay ( 'edit' ) ;
281357}
282358
283359function enterDisplayNoFrillsMode ( ) {
284- $ . bbq . pushState ( { mode : 'display_no_frills' } , 2 /* completely override other hash strings to keep URL clean */ ) ;
360+ console . log ( 'enterDisplayNoFrillsMode' ) ;
361+ updateAppDisplay ( 'display_no_frills' ) ;
285362}
286363
287364
0 commit comments