1 | ################################################################################ |
1 | ################################################################################ |
2 | # WeBWorK Online Homework Delivery System |
2 | # WeBWorK Online Homework Delivery System |
3 | # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ |
3 | # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ |
4 | # $CVSHeader: pg/lib/Applet.pm,v 1.10 2008/05/05 17:24:31 gage Exp $ |
4 | # $CVSHeader: pg/lib/Applet.pm,v 1.18 2009/03/10 12:10:36 gage Exp $ |
5 | # |
5 | # |
6 | # This program is free software; you can redistribute it and/or modify it under |
6 | # This program is free software; you can redistribute it and/or modify it under |
7 | # the terms of either: (a) the GNU General Public License as published by the |
7 | # the terms of either: (a) the GNU General Public License as published by the |
8 | # Free Software Foundation; either version 2, or (at your option) any later |
8 | # Free Software Foundation; either version 2, or (at your option) any later |
9 | # version, or (b) the "Artistic License" which comes with this package. |
9 | # version, or (b) the "Artistic License" which comes with this package. |
… | |
… | |
99 | use MIME::Base64 qw( encode_base64 decode_base64); |
99 | use MIME::Base64 qw( encode_base64 decode_base64); |
100 | |
100 | |
101 | |
101 | |
102 | =head2 Default javaScript functions placed in header |
102 | =head2 Default javaScript functions placed in header |
103 | |
103 | |
|
|
104 | =pod |
|
|
105 | |
104 | These functions are automatically defined for use for |
106 | These functions are automatically defined for use for |
105 | any javaScript placed in the text of a PG question. |
107 | any javaScript placed in the text of a PG question. |
106 | |
108 | |
107 | getApplet(appletName) -- finds the applet path in the DOM |
109 | getApplet(appletName) -- finds the applet path in the DOM |
108 | |
110 | |
109 | submitAction() -- calls the submit action of the applets |
111 | submitAction() -- calls the submit action of the applets |
110 | |
|
|
111 | |
112 | |
112 | initializeAction() -- calls the initialize action of the applets |
113 | initializeWWquestion() -- calls the initialize action of the applets |
113 | |
114 | |
114 | getQE(name) -- gets an HTML element of the question by name |
115 | getQE(name) -- gets an HTML element of the question by name |
115 | or by id. Be sure to keep all names and ids |
116 | or by id. Be sure to keep all names and ids |
116 | unique within a given PG question. |
117 | unique within a given PG question. |
117 | |
118 | |
118 | getQuestionElement(name) -- long form of getQE(name) |
119 | getQuestionElement(name) -- long form of getQE(name) |
119 | |
120 | |
120 | listQuestionElements() -- for discovering the names of inputs in the |
121 | listQuestionElements() -- for discovering the names of inputs in the |
121 | PG question. An alert dialog will list all |
122 | PG question. An alert dialog will list all |
122 | of the elements. |
123 | of the elements. |
123 | Usage: Place this at the END of the question, |
124 | Usage: Place this at the END of the question, just before END_DOCUMENT(): |
124 | just before END_DOCUMENT(): |
|
|
125 | |
125 | |
126 | TEXT(qq!<script> listQuestionElements() </script>!); |
126 | TEXT(qq!<script> listQuestionElements() </script>!); |
127 | ENDDOCUMENT(); |
127 | ENDDOCUMENT(); |
|
|
128 | to obtain a list of all of the HTML elements in the question |
|
|
129 | |
|
|
130 | ---------------------------------------------------------------------------- |
|
|
131 | |
|
|
132 | |
|
|
133 | List of accessor methods made available by the FlashApplet class: |
|
|
134 | Usage: $current_value = $applet->method(new_value or empty) |
|
|
135 | These can also be set when creating the class -- for exampe: |
|
|
136 | $applet = new FlashApplet( |
|
|
137 | # can be replaced by $applet =FlashApplet() when using AppletObjects.pl |
|
|
138 | codebase => findAppletCodebase("$appletName.swf"), |
|
|
139 | appletName => $appletName, |
|
|
140 | appletId => $appletName, |
|
|
141 | submitActionAlias => 'checkAnswer', |
|
|
142 | ); |
128 | |
143 | |
129 | list of accessor methods format: current_value = $self->method(new_value or empty) |
|
|
130 | |
144 | |
131 | appletId for simplicity and reliability appletId and appletName are always the same |
145 | appletId for simplicity and reliability appletId and appletName are always the same |
132 | appletName |
146 | appletName |
133 | |
|
|
134 | archive the name of the .jar file containing the applet code |
147 | archive the name of the .jar file containing the applet code |
135 | code the name of the applet code in the .jar archive |
148 | code the name of the applet code in the .jar archive |
136 | codebase a prefix url used to find the archive and the applet itself |
149 | codebase a prefix url used to find the archive and the applet itself |
137 | |
150 | |
138 | height rectangle alloted in the html page for displaying the applet |
151 | height rectangle alloted in the html page for displaying the applet |
139 | width |
152 | |
140 | |
|
|
141 | params an anonymous array containing name/value pairs |
153 | params an anonymous array containing name/value pairs |
142 | to configure the applet [name =>'value, ...] |
154 | to configure the applet [name =>'value, ...] |
143 | |
155 | |
144 | header stores the text to be added to the header section of the html page |
156 | header stores the text to be added to the header section of the html page |
145 | object stores the text which places the applet on the html page |
157 | object stores the text which places the applet on the html page |
146 | |
158 | |
147 | debug in debug mode several alerts mark progress through the procedure of calling the applet |
159 | debug in debug mode several alerts mark progress through the procedure of calling the applet |
148 | |
160 | |
149 | config configuration are those customizable attributes of the applet which don't |
161 | config configuration are those customizable attributes of the applet which don't |
150 | change as it is used. When stored in hidden answer fields |
162 | change as it is used. When stored in hidden answer fields |
151 | it is usually stored in base64 encoded format. |
163 | it is usually stored in base64 encoded format. |
152 | base64_config base64 encode version of the contents of config |
164 | base64_config base64 encode version of the contents of config |
153 | |
165 | |
154 | configAlias (default: config ) names the applet command called with the contents of $self->config |
166 | configAlias (default: setConfig ) names the applet command called with the contents of $self->config |
155 | to configure the applet. The parameters are passed to the applet in plain text using <xml> |
167 | to configure the applet. The parameters are passed to the applet in plain text using <xml> |
156 | The outer tags must be <xml> ..... </xml> |
168 | The outer tags must be <xml> ..... </xml> |
|
|
169 | setConfigAlias (default: setConfig) -- a synonym for configAlias |
|
|
170 | getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used |
|
|
171 | mainly for debugging. In principal the configuration remains the same for a given instance |
|
|
172 | of the applet -- i.e. for the homework question for a single student. The state however |
|
|
173 | will change depending on the interactions between the student and the applet. |
157 | state state consists of those customizable attributes of the applet which change |
174 | initialState the state consists of those customizable attributes of the applet which change |
158 | as the applet is used. It is stored by the calling .pg question so that |
175 | as the applet is used by the student. It is stored by the calling .pg question so that |
159 | when revisiting the question the applet |
176 | when revisiting the question the applet will be restored to the same state it was left in when the question was last |
160 | will be restored to the same state it was left in when the question was last |
|
|
161 | viewed. |
177 | viewed. |
162 | |
178 | |
163 | getStateAlias (default: getState) alias for command called to read the current state of the applet. |
179 | getStateAlias (default: getState) alias for command called to read the current state of the applet. |
164 | The state is passed in plain text xml format with outer tags: <xml>....</xml> |
180 | The state is passed in plain text xml format with outer tags: <xml>....</xml> |
165 | setStateAlias (default: setState) alias for the command called to reset the state of the applet. |
181 | setStateAlias (default: setState) alias for the command called to reset the state of the applet. |
166 | The state is passed in plain text in xml format with outer tags: <xml>....</xml> |
182 | The state is passed in plain text in xml format with outer tags: <xml>....</xml> |
167 | |
183 | |
168 | base64_state returns the base64 encoded version of the state stored in the applet object. |
184 | base64_state returns the base64 encoded version of the state stored in the applet object. |
169 | |
185 | |
170 | initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState |
186 | initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState |
171 | submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the |
187 | submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the |
172 | .pg question is pressed. |
188 | .pg question is pressed. |
|
|
189 | answerBox -- name of answer box to return answer to: default defaultAnswerBox |
|
|
190 | getAnswer -- (formerly sendData) get student answer from applet and place in answerBox |
|
|
191 | returnFieldName -- (deprecated) synonmym for answerBox |
173 | |
192 | |
174 | returnFieldName |
|
|
175 | |
|
|
176 | |
|
|
177 | |
|
|
178 | |
|
|
179 | |
193 | |
180 | =cut |
194 | =cut |
181 | |
195 | |
|
|
196 | =head4 More details |
182 | |
197 | |
|
|
198 | There are three different "images" of the applet. The first is the java or flash applet itself. The object that actually does the work. |
|
|
199 | The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question |
|
|
200 | to communicate with the applet. The third image is a javaScript image of the applet -- henceforth the jsApplet which is a mirror of the perlApplet |
|
|
201 | but is available to the javaScript code setup and executed in the virtual HTML page defined by the .pg file of the WeBWorK question. One can think of |
|
|
202 | the jsApplet as a runtime version of the perlApplet since it can be accessed and modified after the virtual HTML page has been created by |
|
|
203 | the PG rendering process. |
183 | |
204 | |
|
|
205 | The perlApplet is initialized by $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in |
|
|
206 | ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object. So $newApplet->{appletName} |
|
|
207 | corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-(). |
|
|
208 | |
|
|
209 | Currently all messages read by the applet are xml text. If some of the code needs to be printed in the HTML header than it is converted |
|
|
210 | to a base64 constant and then converted back to text form when it is read by an javaScript subroutine. |
|
|
211 | |
|
|
212 | =cut |
|
|
213 | |
|
|
214 | =head4 Requirements for applets |
|
|
215 | |
|
|
216 | The following methods are desirable in an applet that preserves state in a WW question. None of them are required. |
|
|
217 | |
|
|
218 | setState(str) (default: setXML) |
|
|
219 | -- set the current state of the applet from an xml string |
|
|
220 | -- should be able to accept an empty string or a string of |
|
|
221 | the form <XML>.....</XML> without creating errors |
|
|
222 | -- can be designed to receive other forms of input if it is |
|
|
223 | coordinated with the WW question. |
|
|
224 | getState() (default: getXML) |
|
|
225 | -- return the current state of the applet in an xml string. |
|
|
226 | -- an empty string or a string of the form <XML>.....</XML> |
|
|
227 | are the standard responses. |
|
|
228 | -- can be designed to return other strings if it is |
|
|
229 | coordinated with the WW question. |
|
|
230 | setConfig(str) (default: setConfig) |
|
|
231 | -- If the applet allows configuration this configures the applet |
|
|
232 | from an xml string |
|
|
233 | -- should be able to accept an empty string or a string of the |
|
|
234 | form <XML>.....</XML> without creating errors |
|
|
235 | -- can be designed to receive other forms of input if it is |
|
|
236 | coordinated with the WW question. |
|
|
237 | getConfig (default: getConfig) |
|
|
238 | -- This returns a string defining the configuration of the |
|
|
239 | applet in an xml string |
|
|
240 | -- an empty string or a string of the form <XML>.....</XML> |
|
|
241 | are the standard responses. |
|
|
242 | -- can be designed to return other strings if it is |
|
|
243 | coordinated with the WW question. |
|
|
244 | -- this method is used for debugging to ensure that |
|
|
245 | the configuration was set as expected. |
|
|
246 | getAnswer (default: getAnswer) |
|
|
247 | -- Returns a string (usually NOT xml) which is the |
|
|
248 | response that the student is submitting to answer |
|
|
249 | the WW question. |
|
|
250 | |
|
|
251 | |
|
|
252 | =cut |
184 | |
253 | |
185 | sub new { |
254 | sub new { |
186 | my $class = shift; |
255 | my $class = shift; |
187 | my $self = { |
256 | my $self = { |
188 | appletName =>'', |
257 | appletName =>'', |
… | |
… | |
190 | codebase=>'', |
259 | codebase=>'', |
191 | # appletId =>'', #always use identical applet Id's and applet Names |
260 | # appletId =>'', #always use identical applet Id's and applet Names |
192 | params =>undef, |
261 | params =>undef, |
193 | width => 550, |
262 | width => 550, |
194 | height => 400, |
263 | height => 400, |
|
|
264 | bgcolor => "#869ca7", |
195 | base64_state => undef, # this is an state to use for initializing the first occurence of the question. |
265 | base64_state => undef, # this is a state to use for initializing the first occurence of the question. |
196 | base64_config => undef, # this is the initial (and final?) configuration |
266 | base64_config => undef, # this is the initial (and final?) configuration |
|
|
267 | # configuration => '', # configuration defining the applet |
|
|
268 | initialState => '', # initial state. (I'm considering storing everything as ascii and converting on the fly to base64 when needed.) |
197 | getStateAlias => 'getXML', |
269 | getStateAlias => 'getXML', |
198 | setStateAlias => 'setXML', |
270 | setStateAlias => 'setXML', |
|
|
271 | configAlias => '', # deprecated |
199 | configAlias => 'config', |
272 | getConfigAlias => 'getConfig', |
|
|
273 | setConfigAlias => 'setConfig', |
200 | initializeActionAlias => 'setXML', |
274 | initializeActionAlias => 'setXML', |
201 | submitActionAlias => 'getXML', |
275 | submitActionAlias => 'getXML', |
202 | returnFieldName => 'receivedField', |
276 | submitActionScript => '', # script executed on submitting the WW question |
|
|
277 | answerBoxAlias => 'answerBox', |
|
|
278 | answerBox => '', # deprecated |
|
|
279 | returnFieldName => '', # deprecated |
203 | headerText => DEFAULT_HEADER_TEXT(), |
280 | headerText => DEFAULT_HEADER_TEXT(), |
204 | objectText => '', |
281 | objectText => '', |
205 | debug => 0, |
282 | debug => 0, |
206 | @_, |
283 | @_, |
207 | }; |
284 | }; |
208 | bless $self, $class; |
285 | bless $self, $class; |
209 | $self->state('<xml></xml>'); |
286 | $self->initialState('<xml></xml>'); |
|
|
287 | if ($self->{returnFieldName}) or $self->{answerBox} ) { # backward compatibility |
|
|
288 | warn "use answerBoxAlias instead of returnFieldName or answerBox"; |
|
|
289 | $self->{answerBox}=''; |
|
|
290 | $self->{returnFieldName}=''; |
|
|
291 | } |
|
|
292 | if ($self->{configAlias}) { # backward compatibility |
|
|
293 | warn "use setConfigAlias instead of configAlias"; |
|
|
294 | $self->{configAlias}=''; |
|
|
295 | } |
210 | $self->config('<xml></xml>'); |
296 | $self->config('<xml></xml>'); |
211 | return $self; |
297 | return $self; |
212 | } |
298 | } |
213 | |
299 | |
214 | sub header { |
300 | sub header { |
… | |
… | |
250 | sub submitActionAlias { |
336 | sub submitActionAlias { |
251 | my $self = shift; |
337 | my $self = shift; |
252 | $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty |
338 | $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty |
253 | $self->{submitActionAlias}; |
339 | $self->{submitActionAlias}; |
254 | } |
340 | } |
|
|
341 | sub submitActionScript { |
|
|
342 | my $self = shift; |
|
|
343 | $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty |
|
|
344 | $self->{submitActionScript}; |
|
|
345 | } |
255 | sub getStateAlias { |
346 | sub getStateAlias { |
256 | my $self = shift; |
347 | my $self = shift; |
257 | $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty |
348 | $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty |
258 | $self->{getStateAlias}; |
349 | $self->{getStateAlias}; |
259 | } |
350 | } |
… | |
… | |
263 | $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty |
354 | $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty |
264 | $self->{setStateAlias}; |
355 | $self->{setStateAlias}; |
265 | } |
356 | } |
266 | sub configAlias { |
357 | sub configAlias { |
267 | my $self = shift; |
358 | my $self = shift; |
268 | $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty |
359 | $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty |
269 | $self->{configAlias}; |
360 | $self->{setConfigAlias}; |
270 | } |
361 | } |
271 | sub returnFieldName { |
362 | sub setConfigAlias { |
272 | my $self = shift; |
363 | my $self = shift; |
273 | $self->{returnFieldName} = shift ||$self->{returnFieldName}; # replace the current contents if non-empty |
364 | $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty |
274 | $self->{returnFieldName}; |
365 | $self->{setConfigAlias}; |
|
|
366 | } |
|
|
367 | sub getConfigAlias { |
|
|
368 | my $self = shift; |
|
|
369 | $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty |
|
|
370 | $self->{getConfigAlias}; |
|
|
371 | } |
|
|
372 | |
|
|
373 | sub answerBoxName { |
|
|
374 | my $self = shift; |
|
|
375 | $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty |
|
|
376 | $self->{answerBox}; |
275 | } |
377 | } |
276 | sub codebase { |
378 | sub codebase { |
277 | my $self = shift; |
379 | my $self = shift; |
278 | $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty |
380 | $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty |
279 | $self->{codebase}; |
381 | $self->{codebase}; |
… | |
… | |
290 | } |
392 | } |
291 | sub width { |
393 | sub width { |
292 | my $self = shift; |
394 | my $self = shift; |
293 | $self->{width} = shift ||$self->{width}; # replace the current width if non-empty |
395 | $self->{width} = shift ||$self->{width}; # replace the current width if non-empty |
294 | $self->{width}; |
396 | $self->{width}; |
|
|
397 | } |
|
|
398 | sub bgcolor { |
|
|
399 | my $self = shift; |
|
|
400 | $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty |
|
|
401 | $self->{bgcolor}; |
295 | } |
402 | } |
296 | sub archive { |
403 | sub archive { |
297 | my $self = shift; |
404 | my $self = shift; |
298 | $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty |
405 | $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty |
299 | $self->{archive}; |
406 | $self->{archive}; |
… | |
… | |
310 | $self->{debug}; |
417 | $self->{debug}; |
311 | } |
418 | } |
312 | sub appletId { |
419 | sub appletId { |
313 | appletName(@_); |
420 | appletName(@_); |
314 | } |
421 | } |
|
|
422 | |
|
|
423 | sub initialState { |
|
|
424 | my $self = shift; |
|
|
425 | my $str = shift; |
|
|
426 | $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty |
|
|
427 | $self->{initialState}; |
|
|
428 | } |
|
|
429 | |
|
|
430 | sub config { |
|
|
431 | my $self = shift; |
|
|
432 | my $str = shift; |
|
|
433 | $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty |
|
|
434 | $self->{base64_config} =~ s/\n//g; |
|
|
435 | decode_base64($self->{base64_config}); |
|
|
436 | } |
|
|
437 | ####################### |
|
|
438 | # soon to be deprecated? |
|
|
439 | ####################### |
315 | sub state { |
440 | sub state { |
316 | my $self = shift; |
441 | my $self = shift; |
317 | my $str = shift; |
442 | my $str = shift; |
318 | $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty |
443 | $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty |
319 | $self->{base64_state} =~ s/\n//g; |
444 | $self->{base64_state} =~ s/\n//g; |
320 | decode_base64($self->{base64_state}); |
445 | decode_base64($self->{base64_state}); |
321 | } |
446 | } |
322 | |
|
|
323 | sub base64_state{ |
447 | sub base64_state{ |
324 | my $self = shift; |
448 | my $self = shift; |
325 | $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty |
449 | $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty |
326 | $self->{base64_state}; |
450 | $self->{base64_state}; |
327 | } |
451 | } |
328 | sub config { |
452 | |
329 | my $self = shift; |
|
|
330 | my $str = shift; |
|
|
331 | $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty |
|
|
332 | $self->{base64_config} =~ s/\n//g; |
|
|
333 | decode_base64($self->{base64_config}); |
|
|
334 | } |
|
|
335 | sub base64_config { |
453 | sub base64_config { |
336 | my $self = shift; |
454 | my $self = shift; |
337 | $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty |
455 | $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty |
338 | $self->{base64_config} =$self->{base64_config}; |
456 | $self->{base64_config} =$self->{base64_config}; |
339 | $self->{base64_config}; |
457 | $self->{base64_config}; |
340 | } |
458 | } |
|
|
459 | |
|
|
460 | sub returnFieldName { |
|
|
461 | my $self = shift; |
|
|
462 | warn "use answerBoxName instead of returnFieldName"; |
|
|
463 | } |
|
|
464 | sub answerBox { |
|
|
465 | my $self = shift; |
|
|
466 | warn "use answerBoxName instead of AnswerBox"; |
|
|
467 | } |
|
|
468 | ######################### |
341 | #FIXME |
469 | #FIXME |
342 | # need to be able to adjust header material |
470 | # need to be able to adjust header material |
343 | |
471 | |
344 | sub insertHeader { |
472 | sub insertHeader { |
345 | my $self = shift; |
473 | my $self = shift; |
|
|
474 | |
346 | my $codebase = $self->codebase; |
475 | my $codebase = $self->codebase; |
347 | my $appletId = $self->appletId; |
476 | my $appletId = $self->appletId; |
348 | my $appletName = $self->appletName; |
477 | my $appletName = $self->appletName; |
349 | my $base64_initialState = $self->base64_state; |
478 | my $base64_initialState = $self->base64_state; |
350 | my $initializeAction = $self->initializeActionAlias; |
479 | my $initializeAction = $self->initializeActionAlias; |
351 | my $submitAction = $self->submitActionAlias; |
480 | my $submitActionAlias = $self->submitActionAlias; |
|
|
481 | my $submitActionScript = $self->submitActionScript; |
352 | my $setState = $self->setStateAlias; |
482 | my $setStateAlias = $self->setStateAlias; |
353 | my $getState = $self->getStateAlias; |
483 | my $getStateAlias = $self->getStateAlias; |
|
|
484 | |
354 | my $config = $self->configAlias; |
485 | my $setConfigAlias = $self->setConfigAlias; |
|
|
486 | my $getConfigAlias = $self->getConfigAlias; |
355 | my $base64_config = $self->base64_config; |
487 | my $base64_config = $self->base64_config; |
356 | my $debugMode = ($self->debug) ? "1": "0"; |
488 | my $debugMode = ($self->debug) ? "1": "0"; |
357 | my $returnFieldName = $self->{returnFieldName}; |
489 | my $returnFieldName = $self->{returnFieldName}; |
358 | # my $encodeStateQ = ($self->debug)?'' : "state = Base64.encode(state);"; # in debug mode base64 encoding is not used. |
490 | my $answerBox = $self->{answerBox}; |
359 | # my $decodeStateQ = "if (!state.match(/<XML>*/i) ) {state = Base64.decode(state)}"; # decode if <XML> is not present |
|
|
360 | my $headerText = $self->header(); |
491 | my $headerText = $self->header(); |
|
|
492 | |
|
|
493 | |
|
|
494 | $submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript |
|
|
495 | # other variables should not have quotes. |
|
|
496 | |
|
|
497 | $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript |
|
|
498 | $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble |
361 | |
499 | |
362 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
500 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
363 | |
501 | |
364 | return $headerText; |
502 | return $headerText; |
365 | |
503 | |
… | |
… | |
373 | my $appletId = $self->{appletName}; |
511 | my $appletId = $self->{appletName}; |
374 | my $appletName = $self->{appletName}; |
512 | my $appletName = $self->{appletName}; |
375 | my $archive = $self->{archive}; |
513 | my $archive = $self->{archive}; |
376 | my $width = $self->{width}; |
514 | my $width = $self->{width}; |
377 | my $height = $self->{height}; |
515 | my $height = $self->{height}; |
|
|
516 | my $applet_bgcolor = $self->{bgcolor}; |
378 | my $javaParameters = ''; |
517 | my $javaParameters = ''; |
379 | my $flashParameters = ''; |
518 | my $flashParameters = ''; |
380 | my %param_hash = %{$self->params()}; |
519 | my %param_hash = %{$self->params()}; |
381 | foreach my $key (keys %param_hash) { |
520 | foreach my $key (keys %param_hash) { |
382 | $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; |
521 | $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; |
… | |
… | |
387 | |
526 | |
388 | $objectText = $self->{objectText}; |
527 | $objectText = $self->{objectText}; |
389 | $objectText =~ s/(\$\w+)/$1/gee; |
528 | $objectText =~ s/(\$\w+)/$1/gee; |
390 | return $objectText; |
529 | return $objectText; |
391 | } |
530 | } |
392 | sub initialize { |
531 | # sub initialize { |
393 | my $self = shift; |
532 | # my $self = shift; |
394 | return q{ |
533 | # return q{ |
395 | <script> |
534 | # <script> |
396 | initializeAction(); |
535 | # initializeAllApplets(); |
397 | // this should really be done in the <body> tag |
536 | # // this should really be done in the <body> tag |
398 | </script> |
537 | # </script> |
399 | }; |
538 | # }; |
400 | |
539 | # |
401 | } |
540 | # } |
402 | ######################################################## |
541 | ######################################################## |
403 | # HEADER material for one flash or java applet |
542 | # HEADER material for one flash or java applet |
404 | ######################################################## |
543 | ######################################################## |
405 | |
544 | |
406 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
545 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
407 | |
546 | <script src="/webwork2_files/js/Base64.js" language="javascript"> |
|
|
547 | </script> |
|
|
548 | <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> |
|
|
549 | //upload functions stored in /opt/webwork/webwork2/htdocs/js ... |
|
|
550 | |
|
|
551 | </script> |
408 | <script language="JavaScript"> |
552 | <script language="JavaScript"> |
409 | |
553 | |
410 | // set debug mode for this applet |
554 | // set debug mode for this applet |
411 | set_debug($debugMode); |
555 | set_debug($debugMode); |
412 | |
556 | |
413 | ////////////////////////////////////////////////////////// |
557 | ////////////////////////////////////////////////////////// |
414 | //CONFIGURATIONS |
558 | //TEST code |
415 | // |
559 | // |
416 | // configurations are "permanent" |
560 | // |
417 | ////////////////////////////////////////////////////////// |
561 | ////////////////////////////////////////////////////////// |
|
|
562 | |
|
|
563 | ww_applet_list["$appletName"] = new ww_applet("$appletName"); |
418 | |
564 | |
419 | applet_config_list["$appletName"] = function() { |
|
|
420 | debug_add("applet_config_list:\n attempt to configure $appletName . $config ( $base64_config ) if config function is defined: " |
|
|
421 | ); |
|
|
422 | try { |
|
|
423 | if (( typeof(getApplet("$appletName").$config) == "function" ) ) { |
|
|
424 | debug_add("CONFIGURE $appletName"); |
|
|
425 | getApplet("$appletName").$config(Base64.decode("$base64_config")); |
|
|
426 | } |
|
|
427 | } catch(e) { |
|
|
428 | alert("Error executing configuration command $config for $appletName: " + e ); |
|
|
429 | } |
|
|
430 | } |
|
|
431 | //////////////////////////////////////////////////////////// |
|
|
432 | // |
|
|
433 | //STATE: |
|
|
434 | // state can vary as the applet is manipulated -- it is reset from the questions _state values |
|
|
435 | // |
|
|
436 | ////////////////////////////////////////////////////////// |
|
|
437 | |
565 | |
438 | applet_setState_list["$appletName"] = function(state) { |
566 | ww_applet_list["$appletName"].code = "$code"; |
439 | debug_add("Begin setState for applet $appletName"); |
567 | ww_applet_list["$appletName"].codebase = "$codebase"; |
440 | debug_add("Obtain state from $appletName"+"_state"); |
568 | ww_applet_list["$appletName"].appletID = "$appletID"; |
441 | state = state || getQE("$appletName"+"_state").value; |
569 | ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; |
442 | if ( base64Q(state) ) { |
570 | ww_applet_list["$appletName"].base64_config = "$base64_config"; |
443 | state=Base64.decode(state); |
571 | ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; |
444 | } |
572 | ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; |
445 | if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state starts with <?xml |
573 | ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; |
446 | |
574 | ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; |
447 | debug_add("applet_setState_list: \n set (decoded) state for $appletName to " + |
575 | ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction"; |
448 | state +"\nfunction type is " +typeof(getApplet("$appletName").$setState) |
576 | ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; |
449 | ); |
577 | ww_applet_list["$appletName"].submitActionScript = "$submitActionScript"; |
450 | try { |
578 | ww_applet_list["$appletName"].answerBox = "$answerBox"; |
451 | if (( typeof(getApplet("$appletName").$setState) =="function" ) ) { |
579 | ww_applet_list["$appletName"].debug = "$debugMode"; |
452 | debug_add("setState for $appletName"); |
|
|
453 | getApplet("$appletName").$setState( state ); |
|
|
454 | } |
|
|
455 | } catch(e) { |
|
|
456 | alert("Error in setting state of $appletName using command $setState : " + e ); |
|
|
457 | } |
|
|
458 | } else if (debug) { |
|
|
459 | alert("new state was empty string or did not begin with <xml-- state was not reset"); |
|
|
460 | } |
|
|
461 | }; |
|
|
462 | applet_getState_list["$appletName"] = function () { |
|
|
463 | debug_add("get current state for applet $appletName and store it in $appletName"+"_state"); |
|
|
464 | var applet = getApplet("$appletName"); |
|
|
465 | try { |
|
|
466 | if (( typeof(applet.$getState) == "function" ) ) { // there may be no state function |
|
|
467 | state = applet.$getState(); // get state in xml format |
|
|
468 | } |
|
|
469 | |
|
|
470 | if (!debug) {state = Base64.encode(state) }; // replace state by encoded version unless in debug mode |
|
|
471 | debug_add("state is "+state); // this should still be in plain text |
|
|
472 | getQE("$appletName"+"_state").value = state; //place state in input item (debug: textarea, otherwise: hidden) |
|
|
473 | } catch (e) { |
|
|
474 | alert("Error in getting state for $appletName " + e ); |
|
|
475 | } |
|
|
476 | }; |
|
|
477 | |
|
|
478 | //////////////////////////////////////////////////////////// |
|
|
479 | // |
|
|
480 | //INITIALIZE |
|
|
481 | // |
|
|
482 | //////////////////////////////////////////////////////////// |
|
|
483 | |
|
|
484 | |
580 | |
485 | applet_checkLoaded_list["$appletName"] = function() { // this function returns 0 unless: |
|
|
486 | // applet has already been flagged as ready in applet_isReady_list |
|
|
487 | // applet.config is defined (or alias for .config) |
|
|
488 | // applet.setState is defined |
|
|
489 | // applet.isActive is defined |
|
|
490 | // applet reported that it is loaded by calling loadQ() |
|
|
491 | var ready = 0; |
|
|
492 | var applet = getApplet("$appletName"); |
|
|
493 | if (!debug && applet_isReady_list["$appletName"]) {return(1)}; // memorize readiness in non-debug mode |
|
|
494 | if ( typeof(applet.$config) == "function") { |
|
|
495 | debug_add( "applet.config is " + typeof(applet.$config) ); |
|
|
496 | ready = 1; |
|
|
497 | } |
|
|
498 | if( typeof(applet.$getState) == "function") { |
|
|
499 | debug_add( "applet.getState is " + typeof(applet.$getState) ); |
|
|
500 | ready =1; |
|
|
501 | } |
|
|
502 | if (typeof(applet.isActive) == "function" && applet.isActive ) { |
|
|
503 | debug_add( "applet.isActive is " + typeof(applet.isActive) ); |
|
|
504 | ready =1; |
|
|
505 | } |
|
|
506 | if (typeof(applet_reportsLoaded_list["$appletName"]) !="undefined" && applet_reportsLoaded_list["$appletName"] != 0 ) { |
|
|
507 | debug_add( "applet reports that it is loaded " + applet_reportsLoaded_list["$appletName"] ); |
|
|
508 | ready =1; |
|
|
509 | } |
|
|
510 | applet_isReady_list["$appletName"]= ready; |
|
|
511 | return(ready); |
|
|
512 | } |
|
|
513 | |
|
|
514 | applet_initializeAction_list["$appletName"] = function (state) { |
|
|
515 | applet_setState_list["$appletName"](state); |
|
|
516 | }; |
|
|
517 | |
|
|
518 | applet_submitAction_list["$appletName"] = function () { |
|
|
519 | if (! applet_isReady_list["$appletName"] ) { |
|
|
520 | alert("$appletName is not ready"); |
|
|
521 | } |
|
|
522 | applet_getState_list["$appletName"](); |
|
|
523 | //getQE("$returnFieldName").value = getApplet("$appletName").sendData(); //FIXME -- not needed in general? |
|
|
524 | }; |
|
|
525 | </script> |
581 | </script> |
526 | |
582 | |
527 | END_HEADER_SCRIPT |
583 | END_HEADER_SCRIPT |
528 | |
584 | |
529 | package FlashApplet; |
585 | package FlashApplet; |
530 | @ISA = qw(Applet); |
586 | @ISA = qw(Applet); |
531 | |
587 | |
532 | |
588 | |
|
|
589 | =head2 Insertion HTML code for FlashApplet |
533 | |
590 | |
534 | =pod |
591 | =pod |
535 | |
592 | |
536 | The secret to making this applet work with IE in addition to normal browsers |
593 | The secret to making this applet work with IE in addition to normal browsers |
537 | is the addition of the C(<form></form>) construct just before the object. |
594 | is the addition of the C(<form></form>) construct just before the object. |
… | |
… | |
550 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
607 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
551 | id="$appletName" width="500" height="375" |
608 | id="$appletName" width="500" height="375" |
552 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
609 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
553 | <param name="movie" value="$codebase/$appletName.swf" /> |
610 | <param name="movie" value="$codebase/$appletName.swf" /> |
554 | <param name="quality" value="high" /> |
611 | <param name="quality" value="high" /> |
555 | <param name="bgcolor" value="#869ca7" /> |
612 | <param name="bgcolor" value="$applet_bgcolor" /> |
556 | <param name="allowScriptAccess" value="sameDomain" /> |
613 | <param name="allowScriptAccess" value="sameDomain" /> |
557 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
614 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
558 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
615 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
559 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
616 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
560 | type="application/x-shockwave-flash" |
617 | type="application/x-shockwave-flash" |
561 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
618 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
562 | </embed> |
619 | </embed> |
… | |
… | |
572 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
629 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
573 | id="$appletName" width="500" height="375" |
630 | id="$appletName" width="500" height="375" |
574 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
631 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
575 | <param name="movie" value="$codebase/$appletName.swf" /> |
632 | <param name="movie" value="$codebase/$appletName.swf" /> |
576 | <param name="quality" value="high" /> |
633 | <param name="quality" value="high" /> |
577 | <param name="bgcolor" value="#869ca7" /> |
634 | <param name="bgcolor" value="$applet_bgcolor" /> |
578 | <param name="allowScriptAccess" value="sameDomain" /> |
635 | <param name="allowScriptAccess" value="sameDomain" /> |
579 | <param name="FlashVars" value="$flashParameters"/> |
636 | <param name="FlashVars" value="$flashParameters"/> |
580 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
637 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
581 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
638 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
582 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
639 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
583 | type="application/x-shockwave-flash" |
640 | type="application/x-shockwave-flash" |
584 | pluginspage="http://www.macromedia.com/go/getflashplayer" |
641 | pluginspage="http://www.macromedia.com/go/getflashplayer" |
585 | FlashVars="$flashParameters"> |
642 | FlashVars="$flashParameters"> |
… | |
… | |
598 | |
655 | |
599 | |
656 | |
600 | package JavaApplet; |
657 | package JavaApplet; |
601 | @ISA = qw(Applet); |
658 | @ISA = qw(Applet); |
602 | |
659 | |
603 | |
660 | =head2 Insertion HTML code for JavaApplet |
604 | |
661 | |
605 | =pod |
662 | =pod |
606 | |
663 | |
607 | The secret to making this applet work with IE in addition to normal browsers |
664 | The secret to making this applet work with IE in addition to normal browsers |
608 | is the addition of the C(<form></form>) construct just before the object. |
665 | is the addition of the C(<form></form>) construct just before the object. |
… | |
… | |
642 | archive = "$archive" |
699 | archive = "$archive" |
643 | name = "$appletName" |
700 | name = "$appletName" |
644 | id = "$appletName" |
701 | id = "$appletName" |
645 | width = "$width" |
702 | width = "$width" |
646 | height = "$height" |
703 | height = "$height" |
|
|
704 | bgcolor = "$applet_bgcolor" |
647 | MAYSCRIPT |
705 | MAYSCRIPT |
648 | > |
706 | > |
649 | $javaParameters |
707 | $javaParameters |
650 | |
708 | |
651 | Sorry, the Applet could not be started. Please make sure that |
709 | Sorry, the Applet could not be started. Please make sure that |