| 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.7 2008/03/26 01:25:52 gage Exp $ |
4 | # $CVSHeader$ |
| 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. |
| … | |
… | |
| 21 | =head1 SYNPOSIS |
21 | =head1 SYNPOSIS |
| 22 | |
22 | |
| 23 | ################################### |
23 | ################################### |
| 24 | # Create link to applet |
24 | # Create link to applet |
| 25 | ################################### |
25 | ################################### |
| 26 | my $appletName = "LineThruPointsWW"; |
26 | $appletName = "PointGraph"; |
| 27 | $applet = new FlashApplet( |
27 | $applet = FlashApplet( |
| 28 | # can be replaced by $applet =FlashApplet() when using AppletObjects.pl |
|
|
| 29 | codebase => findAppletCodebase("$appletName.swf"), |
28 | codebase => findAppletCodebase("$appletName.swf"), |
| 30 | appletName => $appletName, |
29 | appletName => $appletName, |
| 31 | appletId => $appletName, |
30 | appletId => $appletName, |
| 32 | submitActionAlias => 'checkAnswer', |
31 | setStateAlias => 'setXML', |
| 33 | ); |
32 | getStateAlias => 'getXML', |
| 34 | |
33 | setConfigAlias => 'config', |
|
|
34 | answerBoxAlias => 'answerBox', |
|
|
35 | submitActionScript => qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, |
|
|
36 | ); |
|
|
37 | |
| 35 | ################################### |
38 | ################################### |
| 36 | # Configure applet |
39 | # Configure applet |
| 37 | ################################### |
40 | ################################### |
| 38 | |
41 | |
| 39 | #xml data to set up the problem-rac |
42 | #data to set up the equation |
| 40 | $applet->state(qq{<XML> |
43 | $applet->configuration(qq{<XML expr='(x - $a)^3 + $b/$a * x' />}); |
| 41 | <point xval='$xval_1' yval='$yval_1' /> |
44 | # initial points |
| 42 | <point xval='$xval_2' yval='$yval_2' /> |
45 | $applet->intialState(qq{<XML> </XML>}); |
| 43 | </XML>}); |
|
|
| 44 | |
|
|
| 45 | |
|
|
| 46 | ################################### |
46 | ################################### |
| 47 | # insert applet header material |
47 | #insert applet into body |
| 48 | ################################### |
48 | ################################### |
| 49 | HEADER_TEXT($applet->insertHeader ); |
49 | |
| 50 | |
|
|
| 51 | ################################### |
|
|
| 52 | # Text section |
|
|
| 53 | # |
|
|
| 54 | |
|
|
| 55 | ################################### |
|
|
| 56 | #insert applet into body |
|
|
| 57 | ################################### |
|
|
| 58 | TEXT( MODES(TeX=>'object code', HTML=>$applet->insertObject)); |
50 | TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll( |
|
|
51 | includeAnswerBox => 1 |
|
|
52 | debug=>0, |
|
|
53 | reinitialize_button=>1, |
|
|
54 | ))); |
| 59 | |
55 | |
| 60 | |
56 | |
| 61 | =head1 DESCRIPTION |
57 | =head1 DESCRIPTION |
| 62 | |
58 | |
| 63 | This file provides an object to store in one place |
59 | This file provides an object to store in one place |
| … | |
… | |
| 99 | use MIME::Base64 qw( encode_base64 decode_base64); |
95 | use MIME::Base64 qw( encode_base64 decode_base64); |
| 100 | |
96 | |
| 101 | |
97 | |
| 102 | =head2 Default javaScript functions placed in header |
98 | =head2 Default javaScript functions placed in header |
| 103 | |
99 | |
|
|
100 | =pod |
|
|
101 | |
| 104 | These functions are automatically defined for use for |
102 | These functions are automatically defined for use for |
| 105 | any javaScript placed in the text of a PG question. |
103 | any javaScript placed in the text of a PG question. |
| 106 | |
104 | |
| 107 | getApplet(appletName) -- finds the applet path in the DOM |
105 | getApplet(appletName) -- finds the applet path in the DOM |
| 108 | |
106 | |
| 109 | submitAction() -- calls the submit action of the applets |
107 | submitAction() -- calls the submit action of the applets |
| 110 | |
|
|
| 111 | |
108 | |
| 112 | initializeAction() -- calls the initialize action of the applets |
109 | initializeWWquestion() -- calls the initialize action of the applets |
| 113 | |
110 | |
| 114 | getQE(name) -- gets an HTML element of the question by name |
111 | getQE(name) -- gets an HTML element of the question by name |
| 115 | or by id. Be sure to keep all names and ids |
112 | or by id. Be sure to keep all names and ids |
| 116 | unique within a given PG question. |
113 | unique within a given PG question. |
| 117 | |
114 | |
| 118 | getQuestionElement(name) -- long form of getQE(name) |
115 | getQuestionElement(name) -- long form of getQE(name) |
| 119 | |
116 | |
| 120 | listQuestionElements() -- for discovering the names of inputs in the |
117 | listQuestionElements() -- for discovering the names of inputs in the |
| 121 | PG question. An alert dialog will list all |
118 | PG question. An alert dialog will list all |
| 122 | of the elements. |
119 | of the elements. |
|
|
120 | |
| 123 | Usage: Place this at the END of the question, |
121 | Usage: Place this at the END of the question, just before END_DOCUMENT(): |
| 124 | just before END_DOCUMENT(): |
|
|
| 125 | |
122 | |
| 126 | TEXT(qq!<script> listQuestionElements() </script>!); |
123 | TEXT(qq!<script> listQuestionElements() </script>!); |
| 127 | ENDDOCUMENT(); |
124 | ENDDOCUMENT(); |
|
|
125 | to obtain a list of all of the HTML elements in the question |
|
|
126 | |
|
|
127 | ---------------------------------------------------------------------------- |
|
|
128 | |
|
|
129 | |
|
|
130 | List of accessor methods made available by the FlashApplet class: |
|
|
131 | Usage: $current_value = $applet->method(new_value or empty) |
|
|
132 | These can also be set when creating the class -- for exampe: |
|
|
133 | $applet = new FlashApplet( |
|
|
134 | # can be replaced by $applet =FlashApplet() when using AppletObjects.pl |
|
|
135 | codebase => findAppletCodebase("$appletName.swf"), |
|
|
136 | appletName => $appletName, |
|
|
137 | appletId => $appletName, |
|
|
138 | submitActionAlias => 'checkAnswer', |
|
|
139 | ); |
| 128 | |
140 | |
| 129 | list of accessor methods format: current_value = $self->method(new_value or empty) |
|
|
| 130 | |
141 | |
| 131 | appletId for simplicity and reliability appletId and appletName are always the same |
142 | appletId for simplicity and reliability appletId and appletName are always the same |
| 132 | appletName |
143 | appletName |
|
|
144 | archive the name of the .jar file containing the applet code |
|
|
145 | code the name of the applet code in the .jar archive |
|
|
146 | codebase a prefix url used to find the archive and the applet itself |
|
|
147 | |
|
|
148 | params an anonymous array containing name/value pairs |
|
|
149 | to configure the applet [name =>'value, ...] |
|
|
150 | |
|
|
151 | width rectangle alloted in the html page for displaying the applet |
|
|
152 | height |
|
|
153 | |
|
|
154 | bgcolor background color of the applet rectangle |
| 133 | |
155 | |
| 134 | archive the name of the .jar file containing the applet code |
|
|
| 135 | 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 |
|
|
| 137 | |
|
|
| 138 | height rectangle alloted in the html page for displaying the applet |
|
|
| 139 | width |
|
|
| 140 | |
|
|
| 141 | params an anonymous array containing name/value pairs |
|
|
| 142 | to configure the applet [name =>'value, ...] |
|
|
| 143 | |
|
|
| 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 | |
| 148 | |
|
|
| 149 | config configuration are those customizable attributes of the applet which don't |
160 | configuration configuration contains those customizable attributes of the applet which don't |
| 150 | change as it is used. When stored in hidden answer fields |
161 | change as it is used. When stored in hidden answer fields |
| 151 | it is usually stored in base64 encoded format. |
162 | it is usually stored in base64 encoded format. |
| 152 | base64_config base64 encode version of the contents of config |
163 | initialState the state consists of those customizable attributes of the applet which change |
| 153 | |
164 | as the applet is used by the student. It is stored by the calling .pg question so that |
|
|
165 | when revisiting the question the applet will be restored to the same state it was |
|
|
166 | left in when the question was last viewed. |
|
|
167 | |
|
|
168 | getStateAlias (default: getState) alias for command called to read the current state of the applet. |
|
|
169 | The state is passed in plain text xml format with outer tags: <xml>....</xml> |
|
|
170 | setStateAlias (default: setState) alias for the command called to reset the state of the applet. |
|
|
171 | The state is passed in plain text in xml format with outer tags: <xml>....</xml> |
|
|
172 | |
|
|
173 | configAlias (deprecated) -- a synonym for configAlias |
|
|
174 | |
|
|
175 | getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used |
|
|
176 | mainly for debugging. In principal the configuration remains the same for a given instance |
|
|
177 | of the applet -- i.e. for the homework question for a single student. The state however |
|
|
178 | will change depending on the interactions between the student and the applet. |
| 154 | configAlias (default: config ) names the applet command called with the contents of $self->config |
179 | setConfigAlias (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> |
180 | to configure the applet. The parameters are passed to the applet in plain text using <xml> |
| 156 | The outer tags must be <xml> ..... </xml> |
181 | The outer tags must be <xml> ..... </xml> |
| 157 | state 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 |
|
|
| 159 | when revisiting the question the applet |
|
|
| 160 | will be restored to the same state it was left in when the question was last |
|
|
| 161 | viewed. |
|
|
| 162 | |
|
|
| 163 | 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> |
|
|
| 165 | 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> |
|
|
| 167 | |
182 | |
| 168 | base64_state returns the base64 encoded version of the state stored in the applet object. |
183 | |
| 169 | |
184 | initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called |
| 170 | initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState |
185 | to initialize the applet (some overlap with config/ and setState |
|
|
186 | maxInitializationAttempts -- (default: 5) number attempts to test applet to see if it is installed. |
|
|
187 | If isActive() exists then the WW question waits until the return value is 1 before |
|
|
188 | calling the applet's confguration commands. |
|
|
189 | Because some applets have isActive return 0 even when they are ready, |
|
|
190 | if isActive() exists but does not return 1 then the applet's configuration commands |
|
|
191 | are called after maxInitializationAttempts number of times. If none of the configuration commands |
|
|
192 | of the applet can be detected then the WW question gives up after maxInitializationAttempts. |
|
|
193 | |
| 171 | submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the |
194 | submitActionAlias -- (default: getXML) applet subroutine called when the submit button of the |
| 172 | .pg question is pressed. |
195 | .pg question is pressed. |
|
|
196 | submitActionScript -- (default: qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() }, |
|
|
197 | |
|
|
198 | answerBoxAlias -- name of answer box to return answer to: default defaultAnswerBox |
|
|
199 | returnFieldName -- (deprecated) synonmym for answerBoxAlias |
|
|
200 | |
|
|
201 | |
|
|
202 | debugMode (default: 0) for debugMode==1 the answerBox and the box preserving the applet state |
|
|
203 | between questions are made visible along with some buttons for manually getting the state of |
|
|
204 | the applet and setting the state of the applet. |
|
|
205 | |
|
|
206 | for debugMode==2, in addition to the answerBox and stateBox there are several alerts |
|
|
207 | which mark progress through the procedures of calling the applet. Useful for troubleshooting |
|
|
208 | where in the chain of command a communication failure occurs |
| 173 | |
209 | |
| 174 | returnFieldName |
210 | |
| 175 | |
211 | Methods: |
| 176 | |
212 | |
|
|
213 | insertHeader -- inserts text in header section of HTML page |
|
|
214 | insertObject -- inserts <object></object> or <applet></applet> tag in body of the HTML page |
|
|
215 | insertAll -- (defined in AppletObjects.pl) installs applet by inserting both header text and the object text |
|
|
216 | Usage: $applet->insertAll( |
|
|
217 | includeAnswerBox => 0, |
|
|
218 | debugMode => 0, |
|
|
219 | reinitialize_button =>0, |
|
|
220 | ); |
| 177 | |
221 | |
| 178 | |
|
|
| 179 | |
222 | |
| 180 | =cut |
223 | =cut |
| 181 | |
224 | |
|
|
225 | =head4 More details |
| 182 | |
226 | |
|
|
227 | There are three different "images" of the applet. The first is the java or flash applet itself. The object that actually does the work. |
|
|
228 | The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question |
|
|
229 | 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 |
|
|
230 | 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 |
|
|
231 | 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 |
|
|
232 | the PG rendering process. |
|
|
233 | |
|
|
234 | The perlApplet is initialized by $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in |
|
|
235 | ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object. So $newApplet->{appletName} |
|
|
236 | corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-(). |
|
|
237 | |
|
|
238 | 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 |
|
|
239 | to a base64 constant and then converted back to text form when it is read by a javaScript subroutine. |
|
|
240 | |
|
|
241 | The perlApplet has methods that help place the jsApplet code on the HTML page and create the link to the applet itself. |
|
|
242 | In particular instance variables such as "setStateAlias", "getStateAlias" connect the WW default of "setState" to subroutine |
|
|
243 | name chosen by the applet designer. The aim is to make it easier to connect to applets previously designed to work |
|
|
244 | with javaScript in an HTML page or other systems. |
|
|
245 | |
|
|
246 | |
|
|
247 | The jsApplet acts as an intermediary for commands directed at the applet. |
|
|
248 | It is not necessary for the minimal operations of |
|
|
249 | configuring the applet and maintaining |
|
|
250 | state from one viewing of the WW question to address the applet directly. |
|
|
251 | The methods such as "setState", "getState", "setConfig" which are part of the jsApplet |
|
|
252 | take care of the book keeping details. |
|
|
253 | It is also possible to make direct calls to the applet from handcrafted javaScript subroutines, |
|
|
254 | but it may be convenient to store these as additional methods in the |
|
|
255 | jsApplet. |
|
|
256 | |
|
|
257 | =cut |
|
|
258 | |
|
|
259 | =head4 Detecting that the applet is ready |
|
|
260 | |
|
|
261 | Timing issues are among the pitfalls awaiting when using flash or java applets in WW questions. It is important that the WW question |
|
|
262 | does not issue any commands to the applet until the applet is fully loaded, including the uploading of any additional configuration |
|
|
263 | information from XML files. This can be tricky since the timing issues usually don't arise when initiating the applet from an HTML page. |
|
|
264 | |
|
|
265 | The WW API performs the following actions to determine if the applet is loaded: |
|
|
266 | |
|
|
267 | check the ww_applet_list[appletName].isReady flag (1== applet is ready) |
|
|
268 | -- this caches the readiness information so that it doesn't |
|
|
269 | have to be repeated within a given viewing of a WW question |
|
|
270 | If this is 1 then the applet is ready. |
|
|
271 | determine whether the applet's isActive subroutine is defined AND returns 1 when called. |
|
|
272 | -- if the return value is 1 the applet is ready, if it is zero or no response then the applet is NOT ready |
|
|
273 | -- If the applet has an isActive() subroutine -- there is no alias for this -- |
|
|
274 | then it must return 1 as soon as the applet is ready. Otherwise |
|
|
275 | the applet will timeout. |
|
|
276 | determine whether the applet's setConfig subroutine is defined. |
|
|
277 | -- applet.{setConfigAlias}. |
|
|
278 | determine whether the applet's setState subroutine is defined. |
|
|
279 | determine whether the jsApplets ww_applet_list[appletName].reportsLoaded flag is set to 1 |
|
|
280 | -- this can be set by the applet if it calls the javaScript function |
|
|
281 | "applet_loaded(appletName, loaded_status). The loaded_status is 1 or 0 |
|
|
282 | |
|
|
283 | Logic for determining applet status: if any one of the above checks succeeds (or returns 1) then the applet is |
|
|
284 | consdered to be ready UNLESS the isActive() exists and the call returns a 0 or no response. In this case |
|
|
285 | the applet is assumed to be loading additional data and is not yet ready. |
|
|
286 | |
|
|
287 | For this reason if the isActive subroutine |
|
|
288 | is defined in the applet it must return a 1 once the applet is prepared to accept additional commands. |
|
|
289 | (Since there are some extent flashApplets with non-functioning isActive() subroutines a temporary workaround |
|
|
290 | assuems that after C<maxInitializationAttempts> -- 5 by default -- the applet is in fact ready but the |
|
|
291 | isActive() subroutine is non functioning. This can give rise to false "readiness" signals if the applet |
|
|
292 | takes a long time to load auxiliary files.) |
|
|
293 | |
|
|
294 | The applet itself can take measures to insure that the setConfig subroutine is prepared to respond immediately once the applet is loaded. |
|
|
295 | It can include timers that delay execution of the configuring actions until all of the auxiliary files needed by the applet are loaded. |
|
|
296 | |
|
|
297 | |
|
|
298 | =cut |
|
|
299 | |
|
|
300 | |
|
|
301 | |
|
|
302 | |
|
|
303 | =head4 Instance variables in the javaScript applet ww_applet_list[appletName] |
|
|
304 | |
|
|
305 | Most of the instance variables in the perl version of the applet are transferred to the javaScript applet |
|
|
306 | |
|
|
307 | =cut |
|
|
308 | |
|
|
309 | |
|
|
310 | =head4 Methods defined for the javaScript applet ww_applet_list[appletName] |
|
|
311 | |
|
|
312 | This is not a comprehensive list |
|
|
313 | |
|
|
314 | setConfig -- transmits the information for configuring the applet |
|
|
315 | |
|
|
316 | getConfig -- retrieves the configuration information -- this is used mainly for debugging and may not be defined in most applets |
|
|
317 | |
|
|
318 | |
|
|
319 | setState -- sets the current state (1) from the appletName_state HTML element if this contains an <xml>...</xml> string |
|
|
320 | -- if the value contains <xml>restart_applet</xml> then set the current state to ww_applet_list[appletName].initialState |
|
|
321 | -- if the value is a blank string set the current state to ww_applet_list[appletName].initialState |
|
|
322 | |
|
|
323 | |
|
|
324 | getState -- retrieves the current state and stores in the appletName_state HTML element. |
|
|
325 | |
|
|
326 | |
|
|
327 | =cut |
|
|
328 | |
|
|
329 | =head4 Requirements for applets |
|
|
330 | |
|
|
331 | The following methods are desirable in an applet that preserves state in a WW question. None of them are required. |
|
|
332 | |
|
|
333 | setState(str) (default: setXML) |
|
|
334 | -- set the current state of the applet from an xml string |
|
|
335 | -- should be able to accept an empty string or a string of |
|
|
336 | the form <XML>.....</XML> without creating errors |
|
|
337 | -- can be designed to receive other forms of input if it is |
|
|
338 | coordinated with the WW question. |
|
|
339 | getState() (default: getXML) |
|
|
340 | -- return the current state of the applet in an xml string. |
|
|
341 | -- an empty string or a string of the form <XML>.....</XML> |
|
|
342 | are the standard responses. |
|
|
343 | -- can be designed to return other strings if it is |
|
|
344 | coordinated with the WW question. |
|
|
345 | setConfig(str) (default: setConfig) |
|
|
346 | -- If the applet allows configuration this configures the applet |
|
|
347 | from an xml string |
|
|
348 | -- should be able to accept an empty string or a string of the |
|
|
349 | form <XML>.....</XML> without creating errors |
|
|
350 | -- can be designed to receive other forms of input if it is |
|
|
351 | coordinated with the WW question. |
|
|
352 | getConfig (default: getConfig) |
|
|
353 | -- This returns a string defining the configuration of the |
|
|
354 | applet in an xml string |
|
|
355 | -- an empty string or a string of the form <XML>.....</XML> |
|
|
356 | are the standard responses. |
|
|
357 | -- can be designed to return other strings if it is |
|
|
358 | coordinated with the WW question. |
|
|
359 | -- this method is used for debugging to ensure that |
|
|
360 | the configuration was set as expected. |
|
|
361 | getAnswer (default: getAnswer) |
|
|
362 | -- Returns a string (usually NOT xml) which is the |
|
|
363 | response that the student is effectvely submitting to answer |
|
|
364 | the WW question. |
|
|
365 | |
|
|
366 | |
|
|
367 | =cut |
|
|
368 | |
|
|
369 | =head4 Initialization sequence |
|
|
370 | |
|
|
371 | When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them |
|
|
372 | to initialize themselves. |
|
|
373 | |
|
|
374 | The applets initialization method is as follows: |
|
|
375 | |
|
|
376 | -- wait until the applet is loaded and the applet has loaded all of its auxiliary files. |
|
|
377 | -- set the debugMode in the applet |
|
|
378 | -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet |
|
|
379 | -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet |
|
|
380 | |
|
|
381 | =cut |
|
|
382 | |
|
|
383 | |
|
|
384 | =head Submit sequence |
|
|
385 | |
|
|
386 | When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks |
|
|
387 | each of the applets on the page to perform its submit action which consists of |
|
|
388 | |
|
|
389 | -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then |
|
|
390 | the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml> |
|
|
391 | to be interpreted by the next setState command |
|
|
392 | -- Otherwise getState() from the applet and save it to the HTML input element appletName_state |
|
|
393 | -- Perform the javaScript commands in .submitActionScript (default: '' ) |
|
|
394 | a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() ) |
|
|
395 | |
|
|
396 | =cut |
| 183 | |
397 | |
| 184 | |
398 | |
| 185 | sub new { |
399 | sub new { |
| 186 | my $class = shift; |
400 | my $class = shift; |
| 187 | my $self = { |
401 | my $self = { |
| 188 | appletName =>'', |
402 | appletName => '', |
| 189 | code=>'', |
|
|
| 190 | codebase=>'', |
|
|
| 191 | # appletId =>'', #always use identical applet Id's and applet Names |
403 | appletId => '', #always use identical applet Id's and applet Names |
|
|
404 | archive => '', |
|
|
405 | code => '', |
|
|
406 | codebase => '', |
| 192 | params =>undef, |
407 | params =>undef, |
| 193 | width => 550, |
408 | width => 550, |
| 194 | height => 400, |
409 | height => 400, |
| 195 | base64_state => '', |
410 | bgcolor => "#869ca7", |
| 196 | base64_config => '', |
411 | configuration => '', # configuration defining the applet |
|
|
412 | initialState => '', # initial state. |
| 197 | getStateAlias => 'getXML', |
413 | getStateAlias => 'getXML', |
| 198 | setStateAlias => 'setXML', |
414 | setStateAlias => 'setXML', |
|
|
415 | configAlias => '', # deprecated |
| 199 | configAlias => 'config', |
416 | getConfigAlias => 'getConfig', |
|
|
417 | setConfigAlias => 'setConfig', |
| 200 | initializeActionAlias => 'setXML', |
418 | initializeActionAlias => 'setXML', |
|
|
419 | maxInitializationAttempts => 5, # number of attempts to initialize applet |
| 201 | submitActionAlias => 'getXML', |
420 | submitActionAlias => 'getXML', |
| 202 | returnFieldName => 'receivedField', |
421 | submitActionScript => '', # script executed on submitting the WW question |
|
|
422 | answerBoxAlias => 'answerBox', |
|
|
423 | answerBox => '', # deprecated |
|
|
424 | returnFieldName => '', # deprecated |
| 203 | headerText => DEFAULT_HEADER_TEXT(), |
425 | headerText => DEFAULT_HEADER_TEXT(), |
| 204 | objectText => '', |
426 | objectText => '', |
| 205 | debug => 0, |
427 | debugMode => 0, |
| 206 | @_, |
428 | @_, |
| 207 | }; |
429 | }; |
| 208 | bless $self, $class; |
430 | bless $self, $class; |
|
|
431 | $self->initialState('<xml></xml>'); |
|
|
432 | if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility |
|
|
433 | warn "use answerBoxAlias instead of returnFieldName or answerBox"; |
|
|
434 | $self->{answerBox}=''; |
|
|
435 | $self->{returnFieldName}=''; |
|
|
436 | } |
|
|
437 | if ($self->{configAlias}) { # backward compatibility |
|
|
438 | warn "use setConfigAlias instead of configAlias"; |
|
|
439 | $self->{configAlias}=''; |
|
|
440 | } |
|
|
441 | $self->configuration('<xml></xml>'); |
| 209 | return $self; |
442 | return $self; |
| 210 | } |
443 | } |
| 211 | |
444 | sub appletId { |
| 212 | sub header { |
445 | appletName(@_); |
|
|
446 | } |
|
|
447 | sub appletName { |
| 213 | my $self = shift; |
448 | my $self = shift; |
| 214 | if ($_[0] eq "reset") { # $applet->header('reset'); erases default header text. |
449 | $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty |
| 215 | $self->{headerText}=''; |
450 | $self->{appletName}; |
| 216 | } else { |
451 | } |
| 217 | $self->{headerText} .= join("",@_); # $applet->header(new_text); concatenates new_text to existing header. |
452 | sub archive { |
| 218 | } |
453 | my $self = shift; |
|
|
454 | $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty |
|
|
455 | $self->{archive}; |
|
|
456 | } |
|
|
457 | sub code { |
|
|
458 | my $self = shift; |
|
|
459 | $self->{code} = shift ||$self->{code}; # replace the current code if non-empty |
| 219 | $self->{headerText}; |
460 | $self->{code}; |
| 220 | } |
461 | } |
| 221 | sub object { |
462 | sub codebase { |
| 222 | my $self = shift; |
463 | my $self = shift; |
| 223 | if ($_[0] eq "reset") { |
464 | $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty |
| 224 | $self->{objectText}=''; |
465 | $self->{codebase}; |
| 225 | } else { |
|
|
| 226 | $self->{objectText} .= join("",@_); |
|
|
| 227 | } |
|
|
| 228 | $self->{objectText}; |
|
|
| 229 | } |
466 | } |
| 230 | sub params { |
467 | sub params { |
| 231 | my $self = shift; |
468 | my $self = shift; |
| 232 | if (ref($_[0]) =~/HASH/) { |
469 | if (ref($_[0]) =~/HASH/) { |
| 233 | $self->{params} = shift; |
470 | $self->{params} = shift; |
| … | |
… | |
| 236 | } else { |
473 | } else { |
| 237 | warn "You must enter a reference to a hash for the parameter list"; |
474 | warn "You must enter a reference to a hash for the parameter list"; |
| 238 | } |
475 | } |
| 239 | $self->{params}; |
476 | $self->{params}; |
| 240 | } |
477 | } |
| 241 | |
478 | |
|
|
479 | sub width { |
|
|
480 | my $self = shift; |
|
|
481 | $self->{width} = shift ||$self->{width}; # replace the current width if non-empty |
|
|
482 | $self->{width}; |
|
|
483 | } |
|
|
484 | sub height { |
|
|
485 | my $self = shift; |
|
|
486 | $self->{height} = shift ||$self->{height}; # replace the current height if non-empty |
|
|
487 | $self->{height}; |
|
|
488 | } |
|
|
489 | sub bgcolor { |
|
|
490 | my $self = shift; |
|
|
491 | $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty |
|
|
492 | $self->{bgcolor}; |
|
|
493 | } |
|
|
494 | |
|
|
495 | sub header { |
|
|
496 | my $self = shift; |
|
|
497 | if ($_[0] eq "reset") { # $applet->header('reset'); erases default header text. |
|
|
498 | $self->{headerText}=''; |
|
|
499 | } else { |
|
|
500 | $self->{headerText} .= join("",@_); # $applet->header(new_text); concatenates new_text to existing header. |
|
|
501 | } |
|
|
502 | $self->{headerText}; |
|
|
503 | } |
|
|
504 | sub object { |
|
|
505 | my $self = shift; |
|
|
506 | if ($_[0] eq "reset") { |
|
|
507 | $self->{objectText}=''; |
|
|
508 | } else { |
|
|
509 | $self->{objectText} .= join("",@_); |
|
|
510 | } |
|
|
511 | $self->{objectText}; |
|
|
512 | } |
|
|
513 | sub configuration { |
|
|
514 | my $self = shift; |
|
|
515 | my $str = shift; |
|
|
516 | $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty |
|
|
517 | $self->{configuration} =~ s/\n//g; |
|
|
518 | $self->{configuration}; |
|
|
519 | } |
|
|
520 | |
|
|
521 | sub initialState { |
|
|
522 | my $self = shift; |
|
|
523 | my $str = shift; |
|
|
524 | $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty |
|
|
525 | $self->{initialState}; |
|
|
526 | } |
|
|
527 | |
|
|
528 | sub getStateAlias { |
|
|
529 | my $self = shift; |
|
|
530 | $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty |
|
|
531 | $self->{getStateAlias}; |
|
|
532 | } |
|
|
533 | |
|
|
534 | sub setStateAlias { |
|
|
535 | my $self = shift; |
|
|
536 | $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty |
|
|
537 | $self->{setStateAlias}; |
|
|
538 | } |
|
|
539 | |
|
|
540 | sub getConfigAlias { |
|
|
541 | my $self = shift; |
|
|
542 | $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty |
|
|
543 | $self->{getConfigAlias}; |
|
|
544 | } |
|
|
545 | sub setConfigAlias { |
|
|
546 | my $self = shift; |
|
|
547 | $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty |
|
|
548 | $self->{setConfigAlias}; |
|
|
549 | } |
|
|
550 | |
| 242 | sub initializeActionAlias { |
551 | sub initializeActionAlias { |
| 243 | my $self = shift; |
552 | my $self = shift; |
| 244 | $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty |
553 | $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty |
| 245 | $self->{initializeActionAlias}; |
554 | $self->{initializeActionAlias}; |
| 246 | } |
555 | } |
| 247 | |
556 | sub maxInitializationAttempts { |
|
|
557 | my $self = shift; |
|
|
558 | $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts}; |
|
|
559 | $self->{maxInitializationAttempts}; |
|
|
560 | } |
| 248 | sub submitActionAlias { |
561 | sub submitActionAlias { |
| 249 | my $self = shift; |
562 | my $self = shift; |
| 250 | $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty |
563 | $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty |
| 251 | $self->{submitActionAlias}; |
564 | $self->{submitActionAlias}; |
| 252 | } |
565 | } |
| 253 | sub getStateAlias { |
566 | sub submitActionScript { |
|
|
567 | my $self = shift; |
|
|
568 | $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty |
|
|
569 | $self->{submitActionScript}; |
|
|
570 | } |
|
|
571 | |
|
|
572 | sub answerBoxAlias { |
|
|
573 | my $self = shift; |
|
|
574 | $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty |
|
|
575 | $self->{answerBox}; |
|
|
576 | } |
|
|
577 | |
|
|
578 | sub debugMode { |
|
|
579 | my $self = shift; |
|
|
580 | my $new_flag = shift; |
|
|
581 | $self->{debugMode} = $new_flag if defined($new_flag); |
|
|
582 | $self->{debugMode}; |
|
|
583 | } |
|
|
584 | |
|
|
585 | |
|
|
586 | ####################### |
|
|
587 | # soon to be deprecated? |
|
|
588 | ####################### |
|
|
589 | |
|
|
590 | sub config { |
|
|
591 | my $self = shift; |
| 254 | my $self = shift; |
592 | my $str = shift; |
| 255 | $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty |
593 | warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded", join(' ', caller()); |
| 256 | $self->{getStateAlias}; |
594 | # $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty |
|
|
595 | # $self->{base64_config} =~ s/\n//g; |
|
|
596 | # decode_base64($self->{base64_config}); |
| 257 | } |
597 | } |
| 258 | |
598 | sub state { |
| 259 | sub setStateAlias { |
599 | my $self = shift; |
| 260 | my $self = shift; |
600 | my $str = shift; |
| 261 | $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty |
601 | warn "use $self->initialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); |
| 262 | $self->{setStateAlias}; |
602 | # $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty |
|
|
603 | # $self->{base64_state} =~ s/\n//g; |
|
|
604 | # decode_base64($self->{base64_state}); |
|
|
605 | } |
|
|
606 | sub base64_state{ |
|
|
607 | my $self = shift; |
|
|
608 | warn "use $self->InitialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller()); |
|
|
609 | |
|
|
610 | |
|
|
611 | } |
|
|
612 | |
|
|
613 | sub base64_config { |
|
|
614 | my $self = shift; |
|
|
615 | warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded"; |
|
|
616 | } |
|
|
617 | |
|
|
618 | sub returnFieldName { |
|
|
619 | my $self = shift; |
|
|
620 | warn "use answerBoxName instead of returnFieldName"; |
|
|
621 | } |
|
|
622 | sub answerBox { |
|
|
623 | my $self = shift; |
|
|
624 | warn "use answerBoxAlias instead of AnswerBox"; |
| 263 | } |
625 | } |
| 264 | sub configAlias { |
626 | sub configAlias { |
| 265 | my $self = shift; |
627 | my $self = shift; |
| 266 | $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty |
628 | warn "use setConfigAlias instead of configAlias"; |
| 267 | $self->{configAlias}; |
|
|
| 268 | } |
629 | } |
| 269 | sub returnFieldName { |
630 | ######################### |
| 270 | my $self = shift; |
|
|
| 271 | $self->{returnFieldName} = shift ||$self->{returnFieldName}; # replace the current contents if non-empty |
|
|
| 272 | $self->{returnFieldName}; |
|
|
| 273 | } |
|
|
| 274 | sub codebase { |
|
|
| 275 | my $self = shift; |
|
|
| 276 | $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty |
|
|
| 277 | $self->{codebase}; |
|
|
| 278 | } |
|
|
| 279 | sub code { |
|
|
| 280 | my $self = shift; |
|
|
| 281 | $self->{code} = shift ||$self->{code}; # replace the current code if non-empty |
|
|
| 282 | $self->{code}; |
|
|
| 283 | } |
|
|
| 284 | sub height { |
|
|
| 285 | my $self = shift; |
|
|
| 286 | $self->{height} = shift ||$self->{height}; # replace the current height if non-empty |
|
|
| 287 | $self->{height}; |
|
|
| 288 | } |
|
|
| 289 | sub width { |
|
|
| 290 | my $self = shift; |
|
|
| 291 | $self->{width} = shift ||$self->{width}; # replace the current width if non-empty |
|
|
| 292 | $self->{width}; |
|
|
| 293 | } |
|
|
| 294 | sub archive { |
|
|
| 295 | my $self = shift; |
|
|
| 296 | $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty |
|
|
| 297 | $self->{archive}; |
|
|
| 298 | } |
|
|
| 299 | sub appletName { |
|
|
| 300 | my $self = shift; |
|
|
| 301 | $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty |
|
|
| 302 | $self->{appletName}; |
|
|
| 303 | } |
|
|
| 304 | sub debug { |
|
|
| 305 | my $self = shift; |
|
|
| 306 | my $new_flag = shift; |
|
|
| 307 | $self->{debug} = $new_flag if defined($new_flag); |
|
|
| 308 | $self->{debug}; |
|
|
| 309 | } |
|
|
| 310 | sub appletId { |
|
|
| 311 | appletName(@_); |
|
|
| 312 | } |
|
|
| 313 | sub state { |
|
|
| 314 | my $self = shift; |
|
|
| 315 | my $str = shift; |
|
|
| 316 | $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty |
|
|
| 317 | $self->{base64_state} =~ s/\n//g; |
|
|
| 318 | decode_base64($self->{base64_state}); |
|
|
| 319 | } |
|
|
| 320 | |
|
|
| 321 | sub base64_state{ |
|
|
| 322 | my $self = shift; |
|
|
| 323 | $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty |
|
|
| 324 | $self->{base64_state}; |
|
|
| 325 | } |
|
|
| 326 | sub config { |
|
|
| 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 { |
|
|
| 334 | my $self = shift; |
|
|
| 335 | $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty |
|
|
| 336 | $self->{base64_config} =$self->{base64_config}; |
|
|
| 337 | $self->{base64_config}; |
|
|
| 338 | } |
|
|
| 339 | #FIXME |
631 | #FIXME |
| 340 | # need to be able to adjust header material |
632 | # need to be able to adjust header material |
| 341 | |
633 | |
| 342 | sub insertHeader { |
634 | sub insertHeader { |
| 343 | my $self = shift; |
635 | my $self = shift; |
|
|
636 | |
| 344 | my $codebase = $self->codebase; |
637 | my $codebase = $self->codebase; |
| 345 | my $appletId = $self->appletId; |
638 | my $appletId = $self->appletId; |
| 346 | my $appletName = $self->appletName; |
639 | my $appletName = $self->appletName; |
| 347 | my $base64_initialState = $self->base64_state; |
|
|
| 348 | my $initializeAction = $self->initializeActionAlias; |
640 | my $initializeActionAlias = $self->initializeActionAlias; |
| 349 | my $submitAction = $self->submitActionAlias; |
641 | my $submitActionScript = $self->submitActionScript; |
| 350 | my $setState = $self->setStateAlias; |
642 | my $setStateAlias = $self->setStateAlias; |
| 351 | my $getState = $self->getStateAlias; |
643 | my $getStateAlias = $self->getStateAlias; |
|
|
644 | |
| 352 | my $config = $self->configAlias; |
645 | my $setConfigAlias = $self->setConfigAlias; |
| 353 | my $base64_config = $self->base64_config; |
646 | my $getConfigAlias = $self->getConfigAlias; |
|
|
647 | my $maxInitializationAttempts = $self->maxInitializationAttempts; |
| 354 | my $debugMode = ($self->debug) ? "1": "0"; |
648 | my $debugMode = ($self->debugMode) ? "1": "0"; |
| 355 | my $returnFieldName = $self->{returnFieldName}; |
649 | my $answerBoxAlias = $self->{answerBoxAlias}; |
| 356 | # my $encodeStateQ = ($self->debug)?'' : "state = Base64.encode(state);"; # in debug mode base64 encoding is not used. |
|
|
| 357 | # my $decodeStateQ = "if (!state.match(/<XML>*/i) ) {state = Base64.decode(state)}"; # decode if <XML> is not present |
|
|
| 358 | my $headerText = $self->header(); |
650 | my $headerText = $self->header(); |
|
|
651 | |
|
|
652 | |
|
|
653 | #$submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript |
|
|
654 | # other variables should not have quotes. |
|
|
655 | |
|
|
656 | $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript |
|
|
657 | $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble |
|
|
658 | my $base64_submitActionScript = encode_base64($submitActionScript); |
|
|
659 | my $base64_configuration = encode_base64($self->configuration); |
|
|
660 | my $base64_initialState = encode_base64($self->initialState); |
|
|
661 | |
|
|
662 | $base64_submitActionScript =~s/\n//g; |
|
|
663 | $base64_initialState =~s/\n//g; # base64 encoded xml |
|
|
664 | $base64_configuration =~s/\n//g; # base64 encoded xml |
| 359 | |
665 | |
| 360 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
666 | $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook |
| 361 | |
667 | |
| 362 | return $headerText; |
668 | return $headerText; |
| 363 | |
669 | |
| 364 | |
670 | |
| 365 | } |
671 | } |
|
|
672 | |
|
|
673 | |
|
|
674 | ######################################################## |
|
|
675 | # HEADER material for one flash or java applet |
|
|
676 | ######################################################## |
|
|
677 | |
|
|
678 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
|
|
679 | <script src="/webwork2_files/js/Base64.js" language="javascript"> |
|
|
680 | </script> |
|
|
681 | <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> |
|
|
682 | //upload functions stored in /opt/webwork/webwork2/htdocs/js ... |
|
|
683 | |
|
|
684 | </script> |
|
|
685 | <script language="JavaScript"> |
|
|
686 | |
|
|
687 | function getApplet(appletName) { |
|
|
688 | var isIE = navigator.appName.indexOf("Microsoft") != -1; // ie8 uses this for java and firefox uses it for flash. |
|
|
689 | var obj = (isIE) ? window[appletName] : window.document[appletName]; |
|
|
690 | //return window.document[appletName]; |
|
|
691 | if (!obj) { obj = document.getElementById(appletName) } |
|
|
692 | if (obj ) { //RECENT FIX to == |
|
|
693 | return( obj ); |
|
|
694 | } else { |
|
|
695 | alert ("can't find applet " + appletName); |
|
|
696 | } |
|
|
697 | } |
|
|
698 | |
|
|
699 | ////////////////////////////////////////////////////////// |
|
|
700 | //TEST code |
|
|
701 | // |
|
|
702 | // |
|
|
703 | ////////////////////////////////////////////////////////// |
|
|
704 | |
|
|
705 | ww_applet_list["$appletName"] = new ww_applet("$appletName"); |
|
|
706 | |
|
|
707 | |
|
|
708 | ww_applet_list["$appletName"].code = "$code"; |
|
|
709 | ww_applet_list["$appletName"].codebase = "$codebase"; |
|
|
710 | ww_applet_list["$appletName"].appletID = "$appletID"; |
|
|
711 | ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; |
|
|
712 | ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState"); |
|
|
713 | ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");; |
|
|
714 | ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; |
|
|
715 | ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; |
|
|
716 | ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; |
|
|
717 | ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; |
|
|
718 | ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; |
|
|
719 | ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; |
|
|
720 | ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript"); |
|
|
721 | ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; |
|
|
722 | ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; |
|
|
723 | ww_applet_list["$appletName"].debugMode = "$debugMode"; |
|
|
724 | |
|
|
725 | </script> |
|
|
726 | |
|
|
727 | END_HEADER_SCRIPT |
|
|
728 | |
|
|
729 | |
| 366 | |
730 | |
| 367 | sub insertObject { |
731 | sub insertObject { |
| 368 | my $self = shift; |
732 | my $self = shift; |
| 369 | my $code = $self->{code}; |
733 | my $code = $self->{code}; |
| 370 | my $codebase = $self->{codebase}; |
734 | my $codebase = $self->{codebase}; |
| 371 | my $appletId = $self->{appletName}; |
735 | my $appletId = $self->{appletName}; |
| 372 | my $appletName = $self->{appletName}; |
736 | my $appletName = $self->{appletName}; |
| 373 | my $archive = $self->{archive}; |
737 | my $archive = $self->{archive}; |
| 374 | my $width = $self->{width}; |
738 | my $width = $self->{width}; |
| 375 | my $height = $self->{height}; |
739 | my $height = $self->{height}; |
|
|
740 | my $applet_bgcolor = $self->{bgcolor}; |
| 376 | my $javaParameters = ''; |
741 | my $javaParameters = ''; |
| 377 | my $flashParameters = ''; |
742 | my $flashParameters = ''; |
| 378 | my %param_hash = %{$self->params()}; |
743 | my %param_hash = %{$self->params()}; |
| 379 | foreach my $key (keys %param_hash) { |
744 | foreach my $key (keys %param_hash) { |
| 380 | $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; |
745 | $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!; |
| … | |
… | |
| 385 | |
750 | |
| 386 | $objectText = $self->{objectText}; |
751 | $objectText = $self->{objectText}; |
| 387 | $objectText =~ s/(\$\w+)/$1/gee; |
752 | $objectText =~ s/(\$\w+)/$1/gee; |
| 388 | return $objectText; |
753 | return $objectText; |
| 389 | } |
754 | } |
| 390 | sub initialize { |
|
|
| 391 | my $self = shift; |
|
|
| 392 | return q{ |
|
|
| 393 | <script> |
|
|
| 394 | initializeAction(); |
|
|
| 395 | // this should really be done in the <body> tag |
|
|
| 396 | </script> |
|
|
| 397 | }; |
|
|
| 398 | |
755 | |
| 399 | } |
|
|
| 400 | |
756 | |
| 401 | |
757 | ############################################################################################################### |
| 402 | use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
758 | # |
| 403 | |
759 | # FLASH APPLET PACKAGE |
| 404 | <script language="JavaScript"> |
760 | # |
| 405 | var debug = $debugMode; |
761 | ############################################################################################################### |
| 406 | // |
|
|
| 407 | //CONFIGURATIONS |
|
|
| 408 | // |
|
|
| 409 | // configurations are "permanent" |
|
|
| 410 | applet_config_list["$appletName"] = function() { |
|
|
| 411 | if (debug) { alert("configure $appletName . $config ( $base64_config )");} |
|
|
| 412 | try { |
|
|
| 413 | if (debug || !( typeof(getApplet("$appletName").$config) == "undefined" ) ) { |
|
|
| 414 | |
|
|
| 415 | getApplet("$appletName").$config(Base64.decode("$base64_config")); |
|
|
| 416 | } |
|
|
| 417 | } catch(e) { |
|
|
| 418 | alert("error executing configuration command $config for $appletName: " + e ); |
|
|
| 419 | } |
|
|
| 420 | } |
|
|
| 421 | // |
|
|
| 422 | //STATE |
|
|
| 423 | // |
|
|
| 424 | // state can vary as the applet is manipulated. |
|
|
| 425 | applet_setState_list["$appletName"] = function(state) { |
|
|
| 426 | if (debug) { alert("set state for $appletName to " + state);} |
|
|
| 427 | state = state || getQE("$appletName"+"_state").value |
|
|
| 428 | if (state.match(/<xml/i) || state.match(/<?xml/i) ) { // if state is not all white space |
|
|
| 429 | if ( base64Q(state) ) { |
|
|
| 430 | state=Base64.decode(state); |
|
|
| 431 | } |
|
|
| 432 | alert("set (decoded) state for $appletName to " + state); |
|
|
| 433 | try { |
|
|
| 434 | if (debug || !( typeof(getApplet("$appletName").$setState) =="undefined" ) ) { |
|
|
| 435 | getApplet("$appletName").$setState( state ); |
|
|
| 436 | } |
|
|
| 437 | } catch(e) { |
|
|
| 438 | alert("Error in setting state of $appletName using command $setState : " + e ); |
|
|
| 439 | } |
|
|
| 440 | } else if (debug) { |
|
|
| 441 | alert("new state was empty string or did not begin with <xml-- state was not reset"); |
|
|
| 442 | } |
|
|
| 443 | }; |
|
|
| 444 | applet_getState_list["$appletName"] = function () { |
|
|
| 445 | if (debug) { alert("getState for applet $appletName");} |
|
|
| 446 | try { |
|
|
| 447 | var applet = getApplet("$appletName"); |
|
|
| 448 | var state; |
|
|
| 449 | if (!( typeof(getApplet("$appletName").$getState) =="undefined" ) ) { |
|
|
| 450 | state = applet.$getState(); // get state in xml format |
|
|
| 451 | } |
|
|
| 452 | if (!debug) {state = Base64.encode(state) }; // replace state by encoded version |
|
|
| 453 | getQE("$appletName"+"_state").value = state; //place in state htmlItem (debug: textarea, otherwise hidden) |
|
|
| 454 | } catch (e) { |
|
|
| 455 | alert("Error in getting state for $appletName " + e ); |
|
|
| 456 | } |
|
|
| 457 | }; |
|
|
| 458 | // |
|
|
| 459 | //INITIALIZE |
|
|
| 460 | // |
|
|
| 461 | applet_initializeAction_list["$appletName"] = function () { |
|
|
| 462 | applet_setState_list["$appletName"](); |
|
|
| 463 | }; |
|
|
| 464 | |
|
|
| 465 | applet_submitAction_list["$appletName"] = function () { |
|
|
| 466 | applet_getState_list["$appletName"](); |
|
|
| 467 | getQE("$returnFieldName").value = getApplet("$appletName").sendData(); |
|
|
| 468 | }; |
|
|
| 469 | </script> |
|
|
| 470 | |
|
|
| 471 | END_HEADER_SCRIPT |
|
|
| 472 | |
762 | |
| 473 | package FlashApplet; |
763 | package FlashApplet; |
| 474 | @ISA = qw(Applet); |
764 | @ISA = qw(Applet); |
| 475 | |
765 | |
| 476 | |
766 | |
|
|
767 | =head2 Insertion HTML code for FlashApplet |
| 477 | |
768 | |
| 478 | =pod |
769 | =pod |
| 479 | |
770 | |
| 480 | The secret to making this applet work with IE in addition to normal browsers |
771 | The secret to making this applet work with IE in addition to normal browsers |
| 481 | is the addition of the C(<form></form>) construct just before the object. |
772 | is the addition of the C(<form></form>) construct just before the object. |
| … | |
… | |
| 494 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
785 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
| 495 | id="$appletName" width="500" height="375" |
786 | id="$appletName" width="500" height="375" |
| 496 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
787 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
| 497 | <param name="movie" value="$codebase/$appletName.swf" /> |
788 | <param name="movie" value="$codebase/$appletName.swf" /> |
| 498 | <param name="quality" value="high" /> |
789 | <param name="quality" value="high" /> |
| 499 | <param name="bgcolor" value="#869ca7" /> |
790 | <param name="bgcolor" value="$applet_bgcolor" /> |
| 500 | <param name="allowScriptAccess" value="sameDomain" /> |
791 | <param name="allowScriptAccess" value="sameDomain" /> |
| 501 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
792 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
| 502 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
793 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
| 503 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
794 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
| 504 | type="application/x-shockwave-flash" |
795 | type="application/x-shockwave-flash" |
| 505 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
796 | pluginspage="http://www.macromedia.com/go/getflashplayer"> |
| 506 | </embed> |
797 | </embed> |
| … | |
… | |
| 510 | |
801 | |
| 511 | |
802 | |
| 512 | =cut |
803 | =cut |
| 513 | |
804 | |
| 514 | use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
805 | use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
| 515 | <form></form> |
806 | |
| 516 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
807 | <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" |
| 517 | id="$appletName" width="500" height="375" |
808 | id="$appletName" width="500" height="375" |
| 518 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
809 | codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> |
| 519 | <param name="movie" value="$codebase/$appletName.swf" /> |
810 | <param name="movie" value="$codebase/$appletName.swf" /> |
| 520 | <param name="quality" value="high" /> |
811 | <param name="quality" value="high" /> |
| 521 | <param name="bgcolor" value="#869ca7" /> |
812 | <param name="bgcolor" value="$applet_bgcolor" /> |
| 522 | <param name="allowScriptAccess" value="sameDomain" /> |
813 | <param name="allowScriptAccess" value="sameDomain" /> |
| 523 | <param name="FlashVars" value="$flashParameters"/> |
814 | <param name="FlashVars" value="$flashParameters"/> |
| 524 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="#869ca7" |
815 | <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor" |
| 525 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
816 | width="$width" height="$height" name="$appletName" align="middle" id="$appletName" |
| 526 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
817 | play="true" loop="false" quality="high" allowScriptAccess="sameDomain" |
| 527 | type="application/x-shockwave-flash" |
818 | type="application/x-shockwave-flash" |
| 528 | pluginspage="http://www.macromedia.com/go/getflashplayer" |
819 | pluginspage="http://www.macromedia.com/go/getflashplayer" |
| 529 | FlashVars="$flashParameters"> |
820 | FlashVars="$flashParameters"> |
| … | |
… | |
| 538 | @_ |
829 | @_ |
| 539 | ); |
830 | ); |
| 540 | |
831 | |
| 541 | } |
832 | } |
| 542 | |
833 | |
|
|
834 | ############################################################################################################### |
|
|
835 | # |
|
|
836 | # JAVA APPLET PACKAGE |
|
|
837 | # |
|
|
838 | ############################################################################################################### |
| 543 | |
839 | |
| 544 | package JavaApplet; |
840 | package JavaApplet; |
| 545 | @ISA = qw(Applet); |
841 | @ISA = qw(Applet); |
| 546 | |
842 | |
| 547 | |
843 | =head2 Insertion HTML code for JavaApplet |
| 548 | |
844 | |
| 549 | =pod |
845 | =pod |
| 550 | |
846 | |
| 551 | The secret to making this applet work with IE in addition to normal browsers |
847 | The secret to making this applet work with IE in addition to normal browsers |
| 552 | is the addition of the C(<form></form>) construct just before the object. |
848 | is the addition of the C(<form></form>) construct just before the object. |
| … | |
… | |
| 577 | END_OBJECT_TEXT |
873 | END_OBJECT_TEXT |
| 578 | |
874 | |
| 579 | =cut |
875 | =cut |
| 580 | |
876 | |
| 581 | use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
877 | use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
| 582 | <form></form> |
878 | |
| 583 | <applet |
879 | <applet |
| 584 | code = "$code" |
880 | code = "$code" |
| 585 | codebase = "$codebase" |
881 | codebase = "$codebase" |
| 586 | archive = "$archive" |
882 | archive = "$archive" |
| 587 | name = "$appletName" |
883 | name = "$appletName" |
| 588 | id = "$appletName" |
884 | id = "$appletName" |
| 589 | width = "$width" |
885 | width = "$width" |
| 590 | height = "$height" |
886 | height = "$height" |
|
|
887 | bgcolor = "$applet_bgcolor" |
| 591 | MAYSCRIPT |
888 | MAYSCRIPT |
| 592 | > |
889 | > |
| 593 | $javaParameters |
890 | $javaParameters |
|
|
891 | |
|
|
892 | Sorry, the Applet could not be started. Please make sure that |
|
|
893 | Java 1.4.2 (or later) is installed and activated. |
|
|
894 | (<a href="http://java.sun.com/getjava">click here to install Java now</a>) |
| 594 | </applet> |
895 | </applet> |
| 595 | END_OBJECT_TEXT |
896 | END_OBJECT_TEXT |
| 596 | |
897 | |
| 597 | sub new { |
898 | sub new { |
| 598 | my $class = shift; |
899 | my $class = shift; |
| … | |
… | |
| 600 | @_ |
901 | @_ |
| 601 | ); |
902 | ); |
| 602 | |
903 | |
| 603 | } |
904 | } |
| 604 | |
905 | |
|
|
906 | ############################################################################################################### |
|
|
907 | # |
|
|
908 | # CANVAS APPLET PACKAGE |
|
|
909 | # |
|
|
910 | ############################################################################################################### |
|
|
911 | |
|
|
912 | package CanvasApplet; |
|
|
913 | @ISA = qw(Applet); |
|
|
914 | |
|
|
915 | |
|
|
916 | =head2 Insertion HTML code for CanvasApplet |
|
|
917 | |
|
|
918 | =pod |
|
|
919 | |
|
|
920 | The secret to making this applet work with IE in addition to normal browsers |
|
|
921 | is the addition of the C(<form></form>) construct just before the object. |
|
|
922 | |
|
|
923 | For some reason IE has trouble locating a flash object which is contained |
|
|
924 | within a form. Adding this second blank form with the larger problemMainForm |
|
|
925 | seems to solve the problem. |
|
|
926 | |
|
|
927 | This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2) |
|
|
928 | Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated: |
|
|
929 | http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js |
|
|
930 | http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933 |
|
|
931 | |
|
|
932 | use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
|
|
933 | <form></form> |
|
|
934 | <script> var width = 200; var height = 200;</script> |
|
|
935 | <canvas name="cv" id="cv" data-src="http://localhost/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="400" height="400"></canvas> |
|
|
936 | END_OBJECT_TEXT |
|
|
937 | |
|
|
938 | |
|
|
939 | |
|
|
940 | =cut |
|
|
941 | |
|
|
942 | |
|
|
943 | use constant CANVAS_OBJECT_HEADER_TEXT =><<'END_HEADER_SCRIPT'; |
|
|
944 | <script src="/webwork2_files/js/Base64.js" language="javascript"> |
|
|
945 | </script> |
|
|
946 | <script src="/webwork2_files/js/ww_applet_support.js" language="javascript"> |
|
|
947 | //upload functions stored in /opt/webwork/webwork2/htdocs/js ... |
|
|
948 | |
|
|
949 | </script> |
|
|
950 | <script language="JavaScript"> |
|
|
951 | |
|
|
952 | |
|
|
953 | |
|
|
954 | ////////////////////////////////////////////////////////// |
|
|
955 | //CANVAS OBJECT HEADER CODE |
|
|
956 | // |
|
|
957 | ////////////////////////////////////////////////////////// |
|
|
958 | |
|
|
959 | ww_applet_list["$appletName"] = new ww_applet("$appletName"); |
|
|
960 | |
|
|
961 | |
|
|
962 | ww_applet_list["$appletName"].code = "$code"; |
|
|
963 | ww_applet_list["$appletName"].codebase = "$codebase"; |
|
|
964 | ww_applet_list["$appletName"].appletID = "$appletID"; |
|
|
965 | ww_applet_list["$appletName"].base64_state = "$base64_initializationState"; |
|
|
966 | ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState"); |
|
|
967 | ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");; |
|
|
968 | ww_applet_list["$appletName"].getStateAlias = "$getStateAlias"; |
|
|
969 | ww_applet_list["$appletName"].setStateAlias = "$setStateAlias"; |
|
|
970 | ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias"; |
|
|
971 | ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias"; |
|
|
972 | ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias"; |
|
|
973 | ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias"; |
|
|
974 | ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript"); |
|
|
975 | ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias"; |
|
|
976 | ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts; |
|
|
977 | ww_applet_list["$appletName"].debugMode = "$debugMode"; |
|
|
978 | |
|
|
979 | |
|
|
980 | ww_applet_list["$appletName"].reportsLoaded = 1; |
|
|
981 | ww_applet_list["$appletName"].object = $appletName; |
|
|
982 | |
|
|
983 | function getApplet(appletName) { |
|
|
984 | //var isIE = navigator.appName.indexOf("Microsoft") != -1; |
|
|
985 | //var obj = (isIE) ? window[appletName] : window.document[appletName]; |
|
|
986 | //return window.document[appletName]; |
|
|
987 | var obj = ww_applet_list[appletName].object; // define fake applet for this object |
|
|
988 | if (obj && (obj.name == appletName)) { //RECENT FIX to == |
|
|
989 | //alert("getting fake applet " + obj.name); |
|
|
990 | return( obj ); |
|
|
991 | } else { |
|
|
992 | alert ("can't find fake applet " + appletName + " in object "+obj.name); |
|
|
993 | } |
|
|
994 | } |
|
|
995 | </script> |
|
|
996 | |
|
|
997 | END_HEADER_SCRIPT |
|
|
998 | |
|
|
999 | |
|
|
1000 | #FIXME need to get rid of hardcoded url |
|
|
1001 | |
|
|
1002 | |
|
|
1003 | use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT'; |
|
|
1004 | |
|
|
1005 | <canvas name="cv" id="cv" data-src="/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="$width" height="$height"></canvas> |
|
|
1006 | END_OBJECT_TEXT |
|
|
1007 | |
|
|
1008 | sub new { |
|
|
1009 | my $class = shift; |
|
|
1010 | $class -> SUPER::new( objectText => CANVAS_OBJECT_TEXT(), |
|
|
1011 | headerText => CANVAS_OBJECT_HEADER_TEXT(), |
|
|
1012 | @_ |
|
|
1013 | ); |
|
|
1014 | |
|
|
1015 | } |
| 605 | |
1016 | |
| 606 | |
1017 | |
| 607 | 1; |
1018 | 1; |