[system] / trunk / pg / lib / Applet.pm Repository:
ViewVC logotype

Annotation of /trunk/pg/lib/Applet.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6030 - (view) (download) (as text)

1 : gage 5574 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 :     # Copyright 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 6030 # $CVSHeader: pg/lib/Applet.pm,v 1.21 2009/03/15 19:25:03 gage Exp $
5 : gage 5574 #
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
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.
10 :     #
11 :     # This program is distributed in the hope that it will be useful, but WITHOUT
12 :     # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 :     # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14 :     # Artistic License for more details.
15 :     ################################################################################
16 :    
17 :     =head1 NAME
18 :    
19 :     Applet.pl - Provides code for inserting FlashApplets and JavaApplets into webwork problems
20 :    
21 :     =head1 SYNPOSIS
22 :    
23 :     ###################################
24 :     # Create link to applet
25 :     ###################################
26 : gage 6026 $appletName = "PointGraph";
27 :     $applet = FlashApplet(
28 :     codebase => findAppletCodebase("$appletName.swf"),
29 :     appletName => $appletName,
30 :     appletId => $appletName,
31 :     setStateAlias => 'setXML',
32 :     getStateAlias => 'getXML',
33 :     setConfigAlias => 'config',
34 : gage 6030 answerBoxAlias => 'answerBox',
35 :     submitActionScript => qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() },
36 : gage 6026 );
37 : gage 5574
38 : gage 6026 ###################################
39 :     # Configure applet
40 :     ###################################
41 : gage 5574
42 : gage 6026 #data to set up the equation
43 :     $applet->config(qq{<XML expr='(x - $a)^3 + $b/$a * x' />});
44 :     # initial points
45 :     $applet->state(qq{<XML>
46 :     </XML>});
47 :     ###################################
48 :     #insert applet into body
49 :     ###################################
50 :    
51 :     TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll(
52 : gage 6030 includeAnswerBox => 1
53 : gage 6026 debug=>0,
54 : gage 6030 reinitialize_button=>1,
55 : gage 6026 )));
56 :    
57 :    
58 : gage 5574 =head1 DESCRIPTION
59 :    
60 :     This file provides an object to store in one place
61 :     all of the information needed to call an applet.
62 :    
63 :     The object FlashApplet has defaults for inserting flash applets.
64 :    
65 :     =over
66 :    
67 :     =item *
68 :    
69 :     =item *
70 :    
71 :     =back
72 :    
73 :     (not yet completed)
74 :    
75 :     The module JavaApplet has defaults for inserting java applets.
76 :    
77 : gage 5619 The module Applet stores common code for the two types of applet.
78 : gage 5574
79 :     =head1 USAGE
80 :    
81 : gage 5619 These modules are activate by listing it in the modules section of global.conf and rebooting the server.
82 :     The companion file to this one is macros/AppletObjects.pl
83 : gage 5574
84 : gage 5619 qw(Applet FlashApplet JavaApplet)
85 :    
86 : gage 5574 =cut
87 :    
88 :    
89 :    
90 :     package Applet;
91 :    
92 : gage 5624 use URI::Escape;
93 : gage 5574
94 :    
95 :    
96 :     use MIME::Base64 qw( encode_base64 decode_base64);
97 :    
98 : gage 5594
99 :     =head2 Default javaScript functions placed in header
100 :    
101 : gage 5944 =pod
102 :    
103 : gage 5594 These functions are automatically defined for use for
104 :     any javaScript placed in the text of a PG question.
105 :    
106 : gage 5944 getApplet(appletName) -- finds the applet path in the DOM
107 : gage 5594
108 : gage 5944 submitAction() -- calls the submit action of the applets
109 :    
110 : gage 6021 initializeWWquestion() -- calls the initialize action of the applets
111 : gage 5594
112 :     getQE(name) -- gets an HTML element of the question by name
113 :     or by id. Be sure to keep all names and ids
114 :     unique within a given PG question.
115 : gage 5944
116 : gage 5594 getQuestionElement(name) -- long form of getQE(name)
117 : gage 5944
118 : gage 5594 listQuestionElements() -- for discovering the names of inputs in the
119 :     PG question. An alert dialog will list all
120 :     of the elements.
121 : gage 5944 Usage: Place this at the END of the question, just before END_DOCUMENT():
122 : gage 5594
123 : gage 5944 TEXT(qq!<script> listQuestionElements() </script>!);
124 :     ENDDOCUMENT();
125 :     to obtain a list of all of the HTML elements in the question
126 : gage 6021
127 :     ----------------------------------------------------------------------------
128 :    
129 :    
130 : gage 5944 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 :     );
140 : gage 5594
141 :    
142 : gage 5944 appletId for simplicity and reliability appletId and appletName are always the same
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 :     height rectangle alloted in the html page for displaying the applet
149 :    
150 :     params an anonymous array containing name/value pairs
151 :     to configure the applet [name =>'value, ...]
152 :    
153 :     header stores the text to be added to the header section of the html page
154 : gage 5619 object stores the text which places the applet on the html page
155 : gage 5594
156 : gage 6030 debugMode in debug mode several alerts mark progress through the procedure of calling the applet
157 : gage 5944
158 : gage 6030 configuration configuration contains those customizable attributes of the applet which don't
159 : gage 5944 change as it is used. When stored in hidden answer fields
160 :     it is usually stored in base64 encoded format.
161 : gage 6030
162 : gage 6021 configAlias (default: setConfig ) names the applet command called with the contents of $self->config
163 : gage 5944 to configure the applet. The parameters are passed to the applet in plain text using <xml>
164 :     The outer tags must be <xml> ..... </xml>
165 : gage 6021 setConfigAlias (default: setConfig) -- a synonym for configAlias
166 :     getConfigAlias (default: getConfig) -- retrieves the configuration from the applet. This is used
167 :     mainly for debugging. In principal the configuration remains the same for a given instance
168 :     of the applet -- i.e. for the homework question for a single student. The state however
169 :     will change depending on the interactions between the student and the applet.
170 :     initialState the state consists of those customizable attributes of the applet which change
171 :     as the applet is used by the student. It is stored by the calling .pg question so that
172 :     when revisiting the question the applet will be restored to the same state it was left in when the question was last
173 : gage 5944 viewed.
174 :    
175 :     getStateAlias (default: getState) alias for command called to read the current state of the applet.
176 :     The state is passed in plain text xml format with outer tags: <xml>....</xml>
177 :     setStateAlias (default: setState) alias for the command called to reset the state of the applet.
178 :     The state is passed in plain text in xml format with outer tags: <xml>....</xml>
179 :    
180 :     initializeActionAlias -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState
181 : gage 5619 submitActionAlias -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the
182 :     .pg question is pressed.
183 : gage 6026 answerBoxAlias -- name of answer box to return answer to: default defaultAnswerBox
184 : gage 5994 getAnswer -- (formerly sendData) get student answer from applet and place in answerBox
185 : gage 6026 returnFieldName -- (deprecated) synonmym for answerBoxAlias
186 : gage 5594
187 : gage 5578
188 : gage 5583 =cut
189 :    
190 : gage 6021 =head4 More details
191 : gage 5574
192 : gage 6021 There are three different "images" of the applet. The first is the java or flash applet itself. The object that actually does the work.
193 :     The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question
194 :     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
195 :     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
196 :     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
197 :     the PG rendering process.
198 : gage 5574
199 : gage 6021 The perlApplet is initialized by $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in
200 :     ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object. So $newApplet->{appletName}
201 :     corresponds to ww_applet_list["myApplet"].appletName. (This paragraph is not yet fully implemented :-().
202 : gage 5574
203 : gage 6021 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
204 : gage 6026 to a base64 constant and then converted back to text form when it is read by a javaScript subroutine.
205 : gage 6021
206 : gage 6026 The perlApplet has methods that help place the jsApplet code on the HTML page and create the link to the applet itself.
207 :     In particular instance variables such as "setStateAlias", "getStateAlias" connect the WW default of "setState" to subroutine
208 :     name chosen by the applet designer. The aim is to make it easier to connect to applets previously designed to work
209 :     with javaScript in an HTML page or other systems.
210 :    
211 :    
212 :     The jsApplet acts as an intermediary for commands directed at the applet.
213 :     It is not necessary for the minimal operations of
214 :     configuring the applet and maintaining
215 :     state from one viewing of the WW question to address the applet directly.
216 :     The methods such as "setState", "getState", "setConfig" which are part of the jsApplet
217 :     take care of the book keeping details.
218 :     It is also possible to make direct calls to the applet from handcrafted javaScript subroutines,
219 :     but it may be convenient to store these as additional methods in the
220 :     jsApplet.
221 :    
222 : gage 6021 =cut
223 :    
224 : gage 6026 =head4 Detecting that the applet is ready
225 :    
226 :     Timing issues are among the pitfalls awaiting when using flash or java applets in WW questions. It is important that the WW question
227 :     does not issue any commands to the applet until the applet is fully loaded, including the uploading of any additional configuration
228 :     information from XML files. This can be tricky since the timing issues usually don't arise when initiating the applet from an HTML page.
229 :    
230 :     The WW API performs the following actions to determine if the applet is loaded:
231 :    
232 :     check the ww_applet_list[appletName].isReady flag (1== applet is ready)
233 :     -- this caches the readiness information so that it doesn't
234 :     have to be repeated within a given viewing of a WW question
235 :     If this is 1 then the applet is ready.
236 :     determine whether the applet's isActive subroutine is defined AND returns 1 when called.
237 :     -- if the return value is 1 the applet is ready, if it is zero or no response then the applet is NOT ready
238 :     -- If the applet has an isActive() subroutine -- there is no alias for this --
239 :     then it must return 1 as soon as the applet is ready. Otherwise
240 :     the applet will timeout.
241 :     determine whether the applet's setConfig subroutine is defined.
242 :     -- applet.{setConfigAlias}.
243 :     determine whether the applet's setState subroutine is defined.
244 :     determine whether the jsApplets ww_applet_list[appletName].reportsLoaded flag is set to 1
245 :     -- this can be set by the applet if it calls the javaScript function
246 :     "applet_loaded(appletName, loaded_status). The loaded_status is 1 or 0
247 :    
248 :     Logic for determining applet status: if any one of the above checks succeeds (or returns 1) then the applet is
249 :     consdered to be ready UNLESS the isActive() exists and the call returns a 0 or no response. In this case
250 :     the applet is assumed to be loading additional data and is not yet ready.
251 :    
252 :     For this reason if the isActive subroutine
253 :     is defined in the applet it must return a 1 once the applet is prepared to accept additional commands.
254 :     (Since there are some extent flashApplets with non-functioning isActive() subroutines a temporary workaround
255 :     assuems that after C<maxInitializationAttempts> -- 5 by default -- the applet is in fact ready but the
256 :     isActive() subroutine is non functioning. This can give rise to false "readiness" signals if the applet
257 :     takes a long time to load auxiliary files.)
258 :    
259 :     The applet itself can take measures to insure that the setConfig subroutine is prepared to respond immediately once the applet is loaded.
260 :     It can include timers that delay execution of the configuring actions until all of the auxiliary files needed by the applet are loaded.
261 :    
262 :    
263 :     =cut
264 :    
265 :    
266 :     =head4 Initialization sequence
267 :    
268 :     When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them
269 :     to initialize themselves.
270 :    
271 :     The applets initialization method is as follows:
272 :    
273 :     -- wait until the applet is loaded and the applet has loaded all of its auxiliary files.
274 :     -- set the debugMode in the applet
275 :     -- call the setConfig method in the javaScript applet -- (configuration parameters are "permanent" for the life of the applet
276 :     -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet
277 :    
278 :     =cut
279 :    
280 :     =head Methods defined for the javaScript applet ww_applet_list[appletName]
281 :    
282 :     This is not a comprehensive list
283 :    
284 :     setConfig -- transmits the information for configuring the applet
285 :    
286 :     getConfig -- retrieves the configuration information -- this is used mainly for debugging and may not be defined in most applets
287 :    
288 :    
289 :     setState -- sets the current state (1) from the appletName_state HTML element if this contains an <xml>...</xml> string
290 :     -- if the value contains <xml>restart_applet</xml> then set the current state to ww_applet_list[appletName].initialState
291 :     -- if the value is a blank string set the current state to ww_applet_list[appletName].initialState
292 :    
293 :    
294 :     getState -- retrieves the current state and stores in the appletName_state HTML element.
295 :    
296 :    
297 :    
298 :    
299 :    
300 :    
301 :    
302 :     =head Submit sequence
303 :    
304 :     When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks
305 :     each of the applets on the page to perform its submit action which consists of
306 :    
307 :     -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then
308 :     the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml>
309 :     to be interpreted by the next setState command
310 :     -- Otherwise getState() from the applet and save it to the HTML input element appletName_state
311 :     -- Perform the javaScript commands in .submitActionScript (default: '' )
312 :     a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer() )
313 :    
314 : gage 6021 =head4 Requirements for applets
315 :    
316 :     The following methods are desirable in an applet that preserves state in a WW question. None of them are required.
317 :    
318 :     setState(str) (default: setXML)
319 :     -- set the current state of the applet from an xml string
320 :     -- should be able to accept an empty string or a string of
321 :     the form <XML>.....</XML> without creating errors
322 :     -- can be designed to receive other forms of input if it is
323 :     coordinated with the WW question.
324 :     getState() (default: getXML)
325 :     -- return the current state of the applet in an xml string.
326 :     -- an empty string or a string of the form <XML>.....</XML>
327 :     are the standard responses.
328 :     -- can be designed to return other strings if it is
329 :     coordinated with the WW question.
330 :     setConfig(str) (default: setConfig)
331 :     -- If the applet allows configuration this configures the applet
332 :     from an xml string
333 :     -- should be able to accept an empty string or a string of the
334 :     form <XML>.....</XML> without creating errors
335 :     -- can be designed to receive other forms of input if it is
336 :     coordinated with the WW question.
337 :     getConfig (default: getConfig)
338 :     -- This returns a string defining the configuration of the
339 :     applet in an xml string
340 :     -- an empty string or a string of the form <XML>.....</XML>
341 :     are the standard responses.
342 :     -- can be designed to return other strings if it is
343 :     coordinated with the WW question.
344 :     -- this method is used for debugging to ensure that
345 :     the configuration was set as expected.
346 :     getAnswer (default: getAnswer)
347 :     -- Returns a string (usually NOT xml) which is the
348 : gage 6026 response that the student is effectvely submitting to answer
349 : gage 6021 the WW question.
350 :    
351 :    
352 :     =cut
353 :    
354 : gage 5574 sub new {
355 :     my $class = shift;
356 :     my $self = {
357 :     appletName =>'',
358 : gage 5619 code=>'',
359 : gage 5574 codebase=>'',
360 : gage 5619 # appletId =>'', #always use identical applet Id's and applet Names
361 : gage 5574 params =>undef,
362 : gage 5619 width => 550,
363 :     height => 400,
364 : gage 6009 bgcolor => "#869ca7",
365 : gage 6030 # base64_state => undef, # this is a state to use for initializing the first occurence of the question.
366 :     # base64_config => undef, # this is the initial (and final?) configuration
367 :     configuration => '', # configuration defining the applet
368 :     initialState => '', # initial state.
369 : gage 5619 getStateAlias => 'getXML',
370 : gage 5625 setStateAlias => 'setXML',
371 : gage 6023 configAlias => '', # deprecated
372 : gage 6021 getConfigAlias => 'getConfig',
373 :     setConfigAlias => 'setConfig',
374 : gage 5619 initializeActionAlias => 'setXML',
375 : gage 6026 maxInitializationAttempts => 5, # number of attempts to initialize applet
376 : gage 5619 submitActionAlias => 'getXML',
377 : gage 6023 submitActionScript => '', # script executed on submitting the WW question
378 :     answerBoxAlias => 'answerBox',
379 :     answerBox => '', # deprecated
380 :     returnFieldName => '', # deprecated
381 : gage 5619 headerText => DEFAULT_HEADER_TEXT(),
382 :     objectText => '',
383 : gage 6026 debugMode => 0,
384 : gage 5574 @_,
385 :     };
386 :     bless $self, $class;
387 : gage 6021 $self->initialState('<xml></xml>');
388 : gage 6025 if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility
389 : gage 6023 warn "use answerBoxAlias instead of returnFieldName or answerBox";
390 :     $self->{answerBox}='';
391 :     $self->{returnFieldName}='';
392 :     }
393 : gage 6021 if ($self->{configAlias}) { # backward compatibility
394 :     warn "use setConfigAlias instead of configAlias";
395 :     $self->{configAlias}='';
396 :     }
397 : gage 6030 $self->configuration('<xml></xml>');
398 : gage 5574 return $self;
399 :     }
400 :    
401 :     sub header {
402 :     my $self = shift;
403 :     if ($_[0] eq "reset") { # $applet->header('reset'); erases default header text.
404 :     $self->{headerText}='';
405 :     } else {
406 :     $self->{headerText} .= join("",@_); # $applet->header(new_text); concatenates new_text to existing header.
407 :     }
408 :     $self->{headerText};
409 :     }
410 :     sub object {
411 :     my $self = shift;
412 :     if ($_[0] eq "reset") {
413 :     $self->{objectText}='';
414 :     } else {
415 :     $self->{objectText} .= join("",@_);
416 :     }
417 :     $self->{objectText};
418 :     }
419 :     sub params {
420 :     my $self = shift;
421 :     if (ref($_[0]) =~/HASH/) {
422 :     $self->{params} = shift;
423 : gage 5619 } elsif ( !defined($_[0]) or $_[0] =~ '') {
424 : gage 5574 # do nothing (read)
425 :     } else {
426 :     warn "You must enter a reference to a hash for the parameter list";
427 :     }
428 :     $self->{params};
429 :     }
430 :    
431 :     sub initializeActionAlias {
432 :     my $self = shift;
433 :     $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty
434 :     $self->{initializeActionAlias};
435 :     }
436 :    
437 :     sub submitActionAlias {
438 :     my $self = shift;
439 :     $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty
440 :     $self->{submitActionAlias};
441 :     }
442 : gage 5984 sub submitActionScript {
443 :     my $self = shift;
444 :     $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty
445 :     $self->{submitActionScript};
446 :     }
447 : gage 5619 sub getStateAlias {
448 :     my $self = shift;
449 :     $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty
450 :     $self->{getStateAlias};
451 :     }
452 :    
453 :     sub setStateAlias {
454 :     my $self = shift;
455 :     $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty
456 :     $self->{setStateAlias};
457 :     }
458 :     sub configAlias {
459 :     my $self = shift;
460 : gage 6021 $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty
461 :     $self->{setConfigAlias};
462 : gage 5619 }
463 : gage 6021 sub setConfigAlias {
464 : gage 5574 my $self = shift;
465 : gage 6021 $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty
466 :     $self->{setConfigAlias};
467 : gage 5574 }
468 : gage 6021 sub getConfigAlias {
469 : gage 5994 my $self = shift;
470 : gage 6021 $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty
471 :     $self->{getConfigAlias};
472 :     }
473 :    
474 :     sub answerBoxName {
475 :     my $self = shift;
476 : gage 5994 $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty
477 :     $self->{answerBox};
478 :     }
479 : gage 5574 sub codebase {
480 :     my $self = shift;
481 :     $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty
482 :     $self->{codebase};
483 :     }
484 : gage 5619 sub code {
485 :     my $self = shift;
486 :     $self->{code} = shift ||$self->{code}; # replace the current code if non-empty
487 :     $self->{code};
488 :     }
489 :     sub height {
490 :     my $self = shift;
491 :     $self->{height} = shift ||$self->{height}; # replace the current height if non-empty
492 :     $self->{height};
493 :     }
494 :     sub width {
495 :     my $self = shift;
496 :     $self->{width} = shift ||$self->{width}; # replace the current width if non-empty
497 :     $self->{width};
498 :     }
499 : gage 6009 sub bgcolor {
500 :     my $self = shift;
501 :     $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty
502 :     $self->{bgcolor};
503 :     }
504 : gage 5619 sub archive {
505 :     my $self = shift;
506 :     $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty
507 :     $self->{archive};
508 :     }
509 : gage 5574 sub appletName {
510 :     my $self = shift;
511 :     $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty
512 :     $self->{appletName};
513 :     }
514 : gage 6026 sub debugMode {
515 : gage 5574 my $self = shift;
516 : gage 5619 my $new_flag = shift;
517 : gage 6026 $self->{debugMode} = $new_flag if defined($new_flag);
518 :     $self->{debugMode};
519 : gage 5574 }
520 : gage 5619 sub appletId {
521 :     appletName(@_);
522 :     }
523 : gage 6026 sub maxInitializationAttempts {
524 :     my $self = shift;
525 :     $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts};
526 :     $self->{maxInitializationAttempts};
527 :     }
528 : gage 6021 sub initialState {
529 :     my $self = shift;
530 :     my $str = shift;
531 :     $self->{initialState} = $str ||$self->{initialState}; # replace the current string if non-empty
532 :     $self->{initialState};
533 :     }
534 : gage 6030 sub configuration {
535 : gage 6021 my $self = shift;
536 :     my $str = shift;
537 : gage 6030 $self->{configuration} = $str || $self->{configuration}; # replace the current string if non-empty
538 :     $self->{configuration} =~ s/\n//g;
539 :     $self->{configuration};
540 : gage 6021 }
541 : gage 6030
542 : gage 6021 #######################
543 :     # soon to be deprecated?
544 :     #######################
545 : gage 6030
546 :     sub config {
547 :     my $self = shift;
548 :     my $str = shift;
549 :     warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded", join(' ', caller());
550 :     # $self->{base64_config} = encode_base64($str) || $self->{base64_config}; # replace the current string if non-empty
551 :     # $self->{base64_config} =~ s/\n//g;
552 :     # decode_base64($self->{base64_config});
553 :     }
554 : gage 5619 sub state {
555 : gage 5574 my $self = shift;
556 :     my $str = shift;
557 : gage 6030 warn "use $self->initialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller());
558 :     # $self->{base64_state} = encode_base64($str) ||$self->{base64_state}; # replace the current string if non-empty
559 :     # $self->{base64_state} =~ s/\n//g;
560 :     # decode_base64($self->{base64_state});
561 : gage 5574 }
562 : gage 5619 sub base64_state{
563 : gage 5574 my $self = shift;
564 : gage 6030 warn "use $self->InitialState instead of $self->state. Internally this string is ascii, not base64 encoded", join(' ', caller());
565 :    
566 :    
567 : gage 5574 }
568 : gage 6021
569 : gage 5619 sub base64_config {
570 :     my $self = shift;
571 : gage 6030 warn "use $self->configuration instead of $self->config. Internally this string is ascii, not base64 encoded";
572 : gage 5619 }
573 : gage 6021
574 :     sub returnFieldName {
575 :     my $self = shift;
576 :     warn "use answerBoxName instead of returnFieldName";
577 :     }
578 :     sub answerBox {
579 :     my $self = shift;
580 : gage 6026 warn "use answerBoxAlias instead of AnswerBox";
581 : gage 6021 }
582 :     #########################
583 : gage 5574 #FIXME
584 :     # need to be able to adjust header material
585 :    
586 :     sub insertHeader {
587 :     my $self = shift;
588 : gage 6013
589 : gage 6009 my $codebase = $self->codebase;
590 :     my $appletId = $self->appletId;
591 :     my $appletName = $self->appletName;
592 : gage 6026 my $initializeActionAlias = $self->initializeActionAlias;
593 :     my $submitActionScript = $self->submitActionScript;
594 : gage 6009 my $setStateAlias = $self->setStateAlias;
595 :     my $getStateAlias = $self->getStateAlias;
596 : gage 6021
597 :     my $setConfigAlias = $self->setConfigAlias;
598 :     my $getConfigAlias = $self->getConfigAlias;
599 : gage 6026 my $maxInitializationAttempts = $self->maxInitializationAttempts;
600 :     my $debugMode = ($self->debugMode) ? "1": "0";
601 :     my $answerBoxAlias = $self->{answerBoxAlias};
602 : gage 6009 my $headerText = $self->header();
603 : gage 5622
604 : gage 6009
605 : gage 6030 #$submitActionScript =~ s/"/\\"/g; # escape quotes for ActionScript
606 : gage 6009 # other variables should not have quotes.
607 :    
608 :     $submitActionScript =~ s/\n/ /g; # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript
609 :     $submitActionScript =~ s/\r/ /g; # replace returns with spaces -- returns can cause trouble
610 : gage 6026 my $base64_submitActionScript = encode_base64($submitActionScript);
611 : gage 6030 my $base64_configuration = encode_base64($self->configuration);
612 :     my $base64_initialState = encode_base64($self->initialState);
613 :    
614 : gage 6026 $base64_submitActionScript =~s/\n//g;
615 : gage 6030 $base64_initialState =~s/\n//g; # base64 encoded xml
616 :     $base64_configuration =~s/\n//g; # base64 encoded xml
617 : gage 6009
618 : gage 5574 $headerText =~ s/(\$\w+)/$1/gee; # interpolate variables p17 of Cookbook
619 :    
620 :     return $headerText;
621 :    
622 :    
623 :     }
624 :    
625 :     sub insertObject {
626 : gage 5619 my $self = shift;
627 :     my $code = $self->{code};
628 :     my $codebase = $self->{codebase};
629 :     my $appletId = $self->{appletName};
630 : gage 5574 my $appletName = $self->{appletName};
631 : gage 5619 my $archive = $self->{archive};
632 :     my $width = $self->{width};
633 :     my $height = $self->{height};
634 : gage 6009 my $applet_bgcolor = $self->{bgcolor};
635 : gage 5624 my $javaParameters = '';
636 :     my $flashParameters = '';
637 : gage 5619 my %param_hash = %{$self->params()};
638 :     foreach my $key (keys %param_hash) {
639 : gage 5624 $javaParameters .= qq!<param name ="$key" value = "$param_hash{$key}">\n!;
640 :     $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&';
641 : gage 5619 }
642 : gage 5624 $flashParameters =~ s/\&$//; # trim last &
643 : gage 5619
644 : gage 5624
645 : gage 5574 $objectText = $self->{objectText};
646 :     $objectText =~ s/(\$\w+)/$1/gee;
647 :     return $objectText;
648 :     }
649 : gage 5994 # sub initialize {
650 :     # my $self = shift;
651 :     # return q{
652 :     # <script>
653 :     # initializeAllApplets();
654 :     # // this should really be done in the <body> tag
655 :     # </script>
656 :     # };
657 :     #
658 :     # }
659 : gage 5661 ########################################################
660 :     # HEADER material for one flash or java applet
661 :     ########################################################
662 : gage 5574
663 : gage 5619 use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
664 : gage 5994 <script src="/webwork2_files/js/Base64.js" language="javascript">
665 :     </script>
666 : gage 6009 <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
667 : gage 5994 //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
668 : gage 6021
669 : gage 5994 </script>
670 : gage 5619 <script language="JavaScript">
671 : gage 5661
672 : gage 6026
673 : gage 5994
674 :     //////////////////////////////////////////////////////////
675 :     //TEST code
676 :     //
677 :     //
678 :     //////////////////////////////////////////////////////////
679 :    
680 :     ww_applet_list["$appletName"] = new ww_applet("$appletName");
681 :    
682 :    
683 :     ww_applet_list["$appletName"].code = "$code";
684 : gage 6026 ww_applet_list["$appletName"].codebase = "$codebase";
685 :     ww_applet_list["$appletName"].appletID = "$appletID";
686 :     ww_applet_list["$appletName"].base64_state = "$base64_initializationState";
687 : gage 6030 ww_applet_list["$appletName"].initialState = Base64.decode("$base64_initialState");
688 :     ww_applet_list["$appletName"].configuration = Base64.decode("$base64_configuration");;
689 : gage 6026 ww_applet_list["$appletName"].getStateAlias = "$getStateAlias";
690 :     ww_applet_list["$appletName"].setStateAlias = "$setStateAlias";
691 : gage 6021 ww_applet_list["$appletName"].setConfigAlias = "$setConfigAlias";
692 :     ww_applet_list["$appletName"].getConfigAlias = "$getConfigAlias";
693 : gage 6026 ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
694 : gage 6009 ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
695 : gage 6030 ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
696 : gage 6026 ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias";
697 :     ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
698 :     ww_applet_list["$appletName"].debugMode = "$debugMode";
699 : gage 5994
700 : gage 5619 </script>
701 :    
702 :     END_HEADER_SCRIPT
703 :    
704 :     package FlashApplet;
705 :     @ISA = qw(Applet);
706 :    
707 :    
708 : gage 5944 =head2 Insertion HTML code for FlashApplet
709 : gage 5619
710 :     =pod
711 :    
712 :     The secret to making this applet work with IE in addition to normal browsers
713 :     is the addition of the C(<form></form>) construct just before the object.
714 :    
715 :     For some reason IE has trouble locating a flash object which is contained
716 :     within a form. Adding this second blank form with the larger problemMainForm
717 :     seems to solve the problem.
718 :    
719 :     This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
720 :     Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
721 :     http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
722 :     http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
723 :    
724 :     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
725 :     <form></form>
726 :     <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
727 :     id="$appletName" width="500" height="375"
728 :     codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
729 :     <param name="movie" value="$codebase/$appletName.swf" />
730 :     <param name="quality" value="high" />
731 : gage 6009 <param name="bgcolor" value="$applet_bgcolor" />
732 : gage 5619 <param name="allowScriptAccess" value="sameDomain" />
733 : gage 6009 <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
734 : gage 5619 width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
735 :     play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
736 :     type="application/x-shockwave-flash"
737 :     pluginspage="http://www.macromedia.com/go/getflashplayer">
738 :     </embed>
739 :    
740 :     </object>
741 :     END_OBJECT_TEXT
742 :    
743 :    
744 :     =cut
745 :    
746 :     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
747 :     <form></form>
748 :     <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
749 :     id="$appletName" width="500" height="375"
750 :     codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
751 :     <param name="movie" value="$codebase/$appletName.swf" />
752 :     <param name="quality" value="high" />
753 : gage 6009 <param name="bgcolor" value="$applet_bgcolor" />
754 : gage 5619 <param name="allowScriptAccess" value="sameDomain" />
755 : gage 5624 <param name="FlashVars" value="$flashParameters"/>
756 : gage 6009 <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
757 : gage 5619 width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
758 :     play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
759 :     type="application/x-shockwave-flash"
760 : gage 5624 pluginspage="http://www.macromedia.com/go/getflashplayer"
761 :     FlashVars="$flashParameters">
762 : gage 5619 </embed>
763 :    
764 :     </object>
765 :     END_OBJECT_TEXT
766 :    
767 :     sub new {
768 :     my $class = shift;
769 :     $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(),
770 :     @_
771 :     );
772 :    
773 :     }
774 :    
775 :    
776 :     package JavaApplet;
777 :     @ISA = qw(Applet);
778 :    
779 : gage 5944 =head2 Insertion HTML code for JavaApplet
780 : gage 5619
781 :     =pod
782 :    
783 :     The secret to making this applet work with IE in addition to normal browsers
784 :     is the addition of the C(<form></form>) construct just before the object.
785 :    
786 :     For some reason IE has trouble locating a flash object which is contained
787 :     within a form. Adding this second blank form with the larger problemMainForm
788 :     seems to solve the problem.
789 :    
790 :     This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
791 :     Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
792 :     http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
793 :     http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
794 :    
795 :     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
796 :     <form></form>
797 :     <applet
798 :     code = "$code"
799 :     codebase = "$codebase"
800 :     archive = "$archive"
801 :     name = "$appletName"
802 :     id = "$appletName"
803 :     width = "$width"
804 :     height = "$height"
805 :     MAYSCRIPT
806 :     >
807 : gage 5624 $javaParameters
808 : gage 5619 </applet>
809 :     END_OBJECT_TEXT
810 :    
811 :     =cut
812 :    
813 :     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
814 :     <form></form>
815 :     <applet
816 :     code = "$code"
817 :     codebase = "$codebase"
818 :     archive = "$archive"
819 :     name = "$appletName"
820 :     id = "$appletName"
821 :     width = "$width"
822 :     height = "$height"
823 : gage 6009 bgcolor = "$applet_bgcolor"
824 : gage 5619 MAYSCRIPT
825 :     >
826 : gage 5624 $javaParameters
827 : gage 5667
828 :     Sorry, the Applet could not be started. Please make sure that
829 :     Java 1.4.2 (or later) is installed and activated.
830 :     (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
831 : gage 5619 </applet>
832 :     END_OBJECT_TEXT
833 :    
834 :     sub new {
835 :     my $class = shift;
836 :     $class -> SUPER::new( objectText => DEFAULT_OBJECT_TEXT(),
837 :     @_
838 :     );
839 :    
840 :     }
841 :    
842 :    
843 :    
844 : gage 5574 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9