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.5 2008/03/16 14:39:39 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. |
… | |
… | |
35 | ################################### |
35 | ################################### |
36 | # Configure applet |
36 | # Configure applet |
37 | ################################### |
37 | ################################### |
38 | |
38 | |
39 | #xml data to set up the problem-rac |
39 | #xml data to set up the problem-rac |
40 | $applet->state(qq{<XML> |
40 | $applet->config(qq{<XML> |
41 | <point xval='$xval_1' yval='$yval_1' /> |
41 | <point xval='$xval_1' yval='$yval_1' /> |
42 | <point xval='$xval_2' yval='$yval_2' /> |
42 | <point xval='$xval_2' yval='$yval_2' /> |
43 | </XML>}); |
43 | </XML>}); |
44 | |
44 | |
45 | |
45 | |
… | |
… | |
90 | |
90 | |
91 | |
91 | |
92 | |
92 | |
93 | package Applet; |
93 | package Applet; |
94 | |
94 | |
95 | |
95 | use URI::Escape; |
96 | |
96 | |
97 | |
97 | |
98 | |
98 | |
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 | |
|
|
104 | =pod |
103 | |
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, |
195 | base64_state => '', |
264 | bgcolor => "#869ca7", |
196 | base64_config => '', |
265 | base64_state => undef, # this is a state to use for initializing the first occurence of the question. |
|
|
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 => 'setState', |
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; |
|
|
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 | } |
|
|
296 | $self->config('<xml></xml>'); |
209 | return $self; |
297 | return $self; |
210 | } |
298 | } |
211 | |
299 | |
212 | sub header { |
300 | sub header { |
213 | my $self = shift; |
301 | my $self = shift; |
… | |
… | |
248 | sub submitActionAlias { |
336 | sub submitActionAlias { |
249 | my $self = shift; |
337 | my $self = shift; |
250 | $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 |
251 | $self->{submitActionAlias}; |
339 | $self->{submitActionAlias}; |
252 | } |
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 | } |
253 | sub getStateAlias { |
346 | sub getStateAlias { |
254 | my $self = shift; |
347 | my $self = shift; |
255 | $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 |
256 | $self->{getStateAlias}; |
349 | $self->{getStateAlias}; |
257 | } |
350 | } |
… | |
… | |
261 | $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 |
262 | $self->{setStateAlias}; |
355 | $self->{setStateAlias}; |
263 | } |
356 | } |
264 | sub configAlias { |
357 | sub configAlias { |
265 | my $self = shift; |
358 | my $self = shift; |
266 | $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 |
267 | $self->{configAlias}; |
360 | $self->{setConfigAlias}; |
268 | } |
361 | } |
269 | sub returnFieldName { |
362 | sub setConfigAlias { |
270 | my $self = shift; |
363 | my $self = shift; |
271 | $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 |
272 | $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}; |
273 | } |
377 | } |
274 | sub codebase { |
378 | sub codebase { |
275 | my $self = shift; |
379 | my $self = shift; |
276 | $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 |
277 | $self->{codebase}; |
381 | $self->{codebase}; |
… | |
… | |
288 | } |
392 | } |
289 | sub width { |
393 | sub width { |
290 | my $self = shift; |
394 | my $self = shift; |
291 | $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 |
292 | $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}; |
293 | } |
402 | } |
294 | sub archive { |
403 | sub archive { |
295 | my $self = shift; |
404 | my $self = shift; |
296 | $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 |
297 | $self->{archive}; |
406 | $self->{archive}; |
… | |
… | |
308 | $self->{debug}; |
417 | $self->{debug}; |
309 | } |
418 | } |
310 | sub appletId { |
419 | sub appletId { |
311 | appletName(@_); |
420 | appletName(@_); |
312 | } |
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 | ####################### |
313 | sub state { |
440 | sub state { |
314 | my $self = shift; |
441 | my $self = shift; |
315 | my $str = shift; |
442 | my $str = shift; |
316 | $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 |
317 | $self->{base64_state} =~ s/\n//g; |
444 | $self->{base64_state} =~ s/\n//g; |
318 | decode_base64($self->{base64_state}); |
445 | decode_base64($self->{base64_state}); |
319 | } |
446 | } |
320 | |
|
|
321 | sub base64_state{ |
447 | sub base64_state{ |
322 | my $self = shift; |
448 | my $self = shift; |
323 | $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 |
324 | $self->{base64_state}; |
450 | $self->{base64_state}; |
325 | } |
451 | } |
326 | sub config { |
452 | |
327 | my $self = shift; |
|
|
328 | my $str = shift; |
|
|
329 | $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty |
|
|
330 | $self->{base64_config} =~ s/\n//g; |
|
|
331 | decode_base64($self->{base64_config}); |
|
|
332 | } |
|
|
333 | sub base64_config { |
453 | sub base64_config { |
334 | my $self = shift; |
454 | my $self = shift; |
335 | $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 |
336 | $self->{base64_config} =$self->{base64_config}; |
456 | $self->{base64_config} =$self->{base64_config}; |
337 | $self->{base64_config}; |
457 | $self->{base64_config}; |
338 | } |
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 | ######################### |
339 | #FIXME |
469 | #FIXME |
340 | # need to be able to adjust header material |
470 | # need to be able to adjust header material |
341 | |
471 | |
342 | sub insertHeader { |
472 | sub insertHeader { |
343 | my $self = shift; |
473 | my $self = shift; |
|
|
474 | |
344 | my $codebase = $self->codebase; |
475 | my $codebase = $self->codebase; |
345 | my $appletId = $self->appletId; |
476 | my $appletId = $self->appletId; |
346 | my $appletName = $self->appletName; |
477 | my $appletName = $self->appletName; |
347 | my $base64_initialState = $self->base64_state; |
478 | my $base64_initialState = $self->base64_state; |
348 | my $initializeAction = $self->initializeActionAlias; |
479 | my $initializeAction = $self->initializeActionAlias; |
349 | my $submitAction = $self->submitActionAlias; |
480 | my $submitActionAlias = $self->submitActionAlias; |
|
|
481 | my $submitActionScript = $self->submitActionScript; |
350 | my $setState = $self->setStateAlias; |
482 | my $setStateAlias = $self->setStateAlias; |
351 | my $getState = $self->getStateAlias; |
483 | my $getStateAlias = $self->getStateAlias; |
|
|
484 | |
352 | my $config = $self->configAlias; |
485 | my $setConfigAlias = $self->setConfigAlias; |
|
|
486 | my $getConfigAlias = $self->getConfigAlias; |
353 | my $base64_config = $self->base64_config; |
487 | my $base64_config = $self->base64_config; |
354 | my $debugMode = ($self->debug) ? "1": "0"; |
488 | my $debugMode = ($self->debug) ? "1": "0"; |
355 | my $returnFieldName = $self->{returnFieldName}; |
489 | my $returnFieldName = $self->{returnFieldName}; |
356 | # my $encodeStateQ = ($self->debug)?'' : "state = Base64.encode(state);"; # in debug mode base64 encoding is not used. |
490 | my $answerBox = $self->{answerBox}; |
357 | # my $decodeStateQ = "if (!state.match(/<XML>*/i) ) {state = Base64.decode(state)}"; # decode if <XML> is not present |
|
|
358 | 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 |
359 | |
499 | |
360 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
500 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
361 | |
501 | |
362 | return $headerText; |
502 | return $headerText; |
363 | |
503 | |
… | |
… | |
371 | my $appletId = $self->{appletName}; |
511 | my $appletId = $self->{appletName}; |
372 | my $appletName = $self->{appletName}; |
512 | my $appletName = $self->{appletName}; |
373 | my $archive = $self->{archive}; |
513 | my $archive = $self->{archive}; |
374 | my $width = $self->{width}; |
514 | my $width = $self->{width}; |
375 | my $height = $self->{height}; |
515 | my $height = $self->{height}; |
|
|
516 | my $applet_bgcolor = $self->{bgcolor}; |
376 | my $parameters = ''; |
517 | my $javaParameters = ''; |
377 | my $parameters = ''; |
518 | my $flashParameters = ''; |
378 | my %param_hash = %{$self->params()}; |
519 | my %param_hash = %{$self->params()}; |
379 | foreach my $key (keys %param_hash) { |
520 | foreach my $key (keys %param_hash) { |
380 | $parameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n! |
521 | $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; |
|
|
522 | $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&'; |
381 | } |
523 | } |
|
|
524 | $flashParameters =~ s/\&$//; # trim last & |
382 | |
525 | |
|
|
526 | |
383 | $objectText = $self->{objectText}; |
527 | $objectText = $self->{objectText}; |
384 | $objectText =~ s/(\$\w+)/$1/gee; |
528 | $objectText =~ s/(\$\w+)/$1/gee; |
385 | return $objectText; |
529 | return $objectText; |
386 | } |
530 | } |
387 | sub initialize { |
531 | # sub initialize { |
388 | my $self = shift; |
532 | # my $self = shift; |
389 | return q{ |
533 | # return q{ |
390 | <script> |
534 | # <script> |
391 | initializeAction(); |
535 | # initializeAllApplets(); |
392 | // this should really be done in the <body> tag |
536 | # // this should really be done in the <body> tag |
393 | </script> |
537 | # </script> |
394 | }; |
538 | # }; |
395 | |
539 | # |
396 | } |
540 | # } |
397 | |
541 | ######################################################## |
|
|
542 | # HEADER material for one flash or java applet |
|
|
543 | ######################################################## |
398 | |
544 | |
399 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
545 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
400 | |
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> |
401 | <script language="JavaScript"> |
552 | <script language="JavaScript"> |
402 | var debug = $debugMode; |
553 | |
|
|
554 | // set debug mode for this applet |
|
|
555 | set_debug($debugMode); |
|
|
556 | |
|
|
557 | ////////////////////////////////////////////////////////// |
|
|
558 | //TEST code |
403 | // |
559 | // |
404 | //CONFIGURATIONS |
|
|
405 | // |
|
|
406 | // configurations are "permanent" |
|
|
407 | applet_config_list["$appletName"] = function() { |
|
|
408 | if (debug) { alert("configure $appletName . $config ( $base64_config )");} |
|
|
409 | try { |
|
|
410 | if (debug || !( typeof(getApplet("$appletName").$config) == "undefined" ) ) { |
|
|
411 | |
|
|
412 | getApplet("$appletName").$config(Base64.decode("$base64_config")); |
|
|
413 | } |
|
|
414 | } catch(e) { |
|
|
415 | alert("error executing configuration command $config for $appletName: " + e ); |
|
|
416 | } |
|
|
417 | } |
|
|
418 | // |
560 | // |
419 | //STATE |
561 | ////////////////////////////////////////////////////////// |
|
|
562 | |
|
|
563 | ww_applet_list["$appletName"] = new ww_applet("$appletName"); |
420 | // |
564 | |
421 | // state can vary as the applet is manipulated. |
|
|
422 | applet_setState_list["$appletName"] = function(state) { |
|
|
423 | state = state || getQE("$appletName"+"_state").value |
|
|
424 | if (state.match("\S") ) { // if state is not all white space |
|
|
425 | if ( base64Q(state) ) { |
|
|
426 | state=Base64.decode(state); |
|
|
427 | } |
|
|
428 | if (debug) { alert("set state for $appletName to " + state);} |
|
|
429 | try { |
|
|
430 | if (debug || !( typeof(getApplet("$appletName").$setState) =="undefined" ) ) { |
|
|
431 | getApplet("$appletName").$setState( state ); |
|
|
432 | } |
|
|
433 | } catch(e) { |
|
|
434 | alert("Error in setting state of $appletName using command $setState : " + e ); |
|
|
435 | } |
|
|
436 | } |
|
|
437 | }; |
|
|
438 | applet_getState_list["$appletName"] = function () { |
|
|
439 | if (debug) { alert("getState for applet $appletName");} |
|
|
440 | try { |
|
|
441 | var applet = getApplet("$appletName"); |
|
|
442 | var state; |
|
|
443 | if (!( typeof(getApplet("$appletName").$getState) =="undefined" ) ) { |
|
|
444 | state = applet.$getState(); // get state in xml format |
|
|
445 | } |
|
|
446 | if (!debug) {state = Base64.encode(state) }; // replace state by encoded version |
|
|
447 | getQE("$appletName"+"_state").value = state; //place in state htmlItem (debug: textarea, otherwise hidden) |
|
|
448 | } catch (e) { |
|
|
449 | alert("Error in getting state for $appletName " + e ); |
|
|
450 | } |
|
|
451 | }; |
565 | |
452 | // |
566 | ww_applet_list["$appletName"].code = "$code"; |
453 | //INITIALIZE |
567 | ww_applet_list["$appletName"].codebase = "$codebase"; |
454 | // |
568 | ww_applet_list["$appletName"].appletID = "$appletID"; |
455 | applet_initializeAction_list["$appletName"] = function () { |
569 | ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; |
456 | applet_setState_list["$appletName"](); |
570 | ww_applet_list["$appletName"].base64_config = "$base64_config"; |
457 | }; |
571 | ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; |
458 | |
572 | ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; |
459 | applet_submitAction_list["$appletName"] = function () { |
573 | ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; |
460 | applet_getState_list["$appletName"](); |
574 | ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; |
461 | getQE("$returnFieldName").value = getApplet("$appletName").sendData(); |
575 | ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction"; |
462 | }; |
576 | ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; |
|
|
577 | ww_applet_list["$appletName"].submitActionScript = "$submitActionScript"; |
|
|
578 | ww_applet_list["$appletName"].answerBox = "$answerBox"; |
|
|
579 | ww_applet_list["$appletName"].debug = "$debugMode"; |
|
|
580 | |
463 | </script> |
581 | </script> |
464 | |
582 | |
465 | END_HEADER_SCRIPT |
583 | END_HEADER_SCRIPT |
466 | |
584 | |
467 | package FlashApplet; |
585 | package FlashApplet; |
468 | @ISA = qw(Applet); |
586 | @ISA = qw(Applet); |
469 | |
587 | |
470 | |
588 | |
|
|
589 | =head2 Insertion HTML code for FlashApplet |
471 | |
590 | |
472 | =pod |
591 | =pod |
473 | |
592 | |
474 | 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 |
475 | 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. |
… | |
… | |
488 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
607 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
489 | id="$appletName" width="500" height="375" |
608 | id="$appletName" width="500" height="375" |
490 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
609 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
491 | <param name="movie" value="$codebase/$appletName.swf" /> |
610 | <param name="movie" value="$codebase/$appletName.swf" /> |
492 | <param name="quality" value="high" /> |
611 | <param name="quality" value="high" /> |
493 | <param name="bgcolor" value="#869ca7" /> |
612 | <param name="bgcolor" value="$applet_bgcolor" /> |
494 | <param name="allowScriptAccess" value="sameDomain" /> |
613 | <param name="allowScriptAccess" value="sameDomain" /> |
495 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
614 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
496 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
615 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
497 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
616 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
498 | type="application/x-shockwave-flash" |
617 | type="application/x-shockwave-flash" |
499 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
618 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
500 | </embed> |
619 | </embed> |
… | |
… | |
510 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
629 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
511 | id="$appletName" width="500" height="375" |
630 | id="$appletName" width="500" height="375" |
512 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
631 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
513 | <param name="movie" value="$codebase/$appletName.swf" /> |
632 | <param name="movie" value="$codebase/$appletName.swf" /> |
514 | <param name="quality" value="high" /> |
633 | <param name="quality" value="high" /> |
515 | <param name="bgcolor" value="#869ca7" /> |
634 | <param name="bgcolor" value="$applet_bgcolor" /> |
516 | <param name="allowScriptAccess" value="sameDomain" /> |
635 | <param name="allowScriptAccess" value="sameDomain" /> |
|
|
636 | <param name="FlashVars" value="$flashParameters"/> |
517 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
637 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
518 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
638 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
519 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
639 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
520 | type="application/x-shockwave-flash" |
640 | type="application/x-shockwave-flash" |
521 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
641 | pluginspage="http://www.macromedia.com/go/getflashplayer" |
|
|
642 | FlashVars="$flashParameters"> |
522 | </embed> |
643 | </embed> |
523 | |
644 | |
524 | </object> |
645 | </object> |
525 | END_OBJECT_TEXT |
646 | END_OBJECT_TEXT |
526 | |
647 | |
… | |
… | |
534 | |
655 | |
535 | |
656 | |
536 | package JavaApplet; |
657 | package JavaApplet; |
537 | @ISA = qw(Applet); |
658 | @ISA = qw(Applet); |
538 | |
659 | |
539 | |
660 | =head2 Insertion HTML code for JavaApplet |
540 | |
661 | |
541 | =pod |
662 | =pod |
542 | |
663 | |
543 | 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 |
544 | 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. |
… | |
… | |
562 | id = "$appletName" |
683 | id = "$appletName" |
563 | width = "$width" |
684 | width = "$width" |
564 | height = "$height" |
685 | height = "$height" |
565 | MAYSCRIPT |
686 | MAYSCRIPT |
566 | > |
687 | > |
567 | $parameters |
688 | $javaParameters |
568 | </applet> |
689 | </applet> |
569 | END_OBJECT_TEXT |
690 | END_OBJECT_TEXT |
570 | |
691 | |
571 | =cut |
692 | =cut |
572 | |
693 | |
… | |
… | |
578 | archive = "$archive" |
699 | archive = "$archive" |
579 | name = "$appletName" |
700 | name = "$appletName" |
580 | id = "$appletName" |
701 | id = "$appletName" |
581 | width = "$width" |
702 | width = "$width" |
582 | height = "$height" |
703 | height = "$height" |
|
|
704 | bgcolor = "$applet_bgcolor" |
583 | MAYSCRIPT |
705 | MAYSCRIPT |
584 | > |
706 | > |
585 | $parameters |
707 | $javaParameters |
|
|
708 | |
|
|
709 | Sorry, the Applet could not be started. Please make sure that |
|
|
710 | Java 1.4.2 (or later) is installed and activated. |
|
|
711 | (<a href="http://java.sun.com/getjava">click here to install Java now</a>) |
586 | </applet> |
712 | </applet> |
587 | END_OBJECT_TEXT |
713 | END_OBJECT_TEXT |
588 | |
714 | |
589 | sub new { |
715 | sub new { |
590 | my $class = shift; |
716 | my $class = shift; |