[system] / trunk / pg / macros / AppletObjects.pl Repository:
ViewVC logotype

Annotation of /trunk/pg/macros/AppletObjects.pl

Parent Directory Parent Directory | Revision Log Revision Log


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

1 : gage 5582 ################################################################################
2 :     # WeBWorK Online Homework Delivery System
3 :     # Copyright 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
4 : gage 6210 # $CVSHeader: pg/macros/AppletObjects.pl,v 1.24 2010/01/03 17:13:46 gage Exp $
5 : gage 5582 #
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 : gage 5618 AppletObjects.pl - Macro-based front end for the Applet.pm module.
20 : gage 5582
21 :    
22 :     =head1 DESCRIPTION
23 :    
24 :     This subroutines in this
25 : gage 5971 file provide mechanisms to insert Flash applets (and Java applets)
26 : gage 5582 into a WeBWorK problem.
27 :    
28 :    
29 : gage 6546 See also L<http://webwork.maa.org/pod/pg_TRUNK/lib/Applet.html>.
30 : gage 5582
31 :     =cut
32 :    
33 : gage 5667 #########################################################################
34 :     #
35 :     # Add basic functionality to the header of the question
36 :     #
37 :     # don't reload this file
38 :     #########################################################################
39 : gage 5582
40 : gage 6026 sub _AppletObjects_init{
41 : gage 5618
42 :     main::HEADER_TEXT(<<'END_HEADER_TEXT');
43 :     <script language="javascript">AC_FL_RunContent = 0;</script>
44 :     <script src="/webwork2_files/applets/AC_RunActiveContent.js" language="javascript">
45 :     </script>
46 :     <script src="/webwork2_files/js/Base64.js" language="javascript">
47 : gage 5993 </script>
48 : gage 6316 <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
49 : gage 5993 //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
50 : gage 5996 </script>
51 : gage 5618 END_HEADER_TEXT
52 :    
53 : gage 5667 };
54 : gage 5618
55 : gage 6546 =head3 FlashApplet
56 : gage 5582
57 :     Useage: $applet = FlashApplet();
58 :    
59 :     =cut
60 :    
61 :     sub FlashApplet {
62 : gage 5597 return new FlashApplet(@_);
63 : gage 5582
64 :     }
65 :    
66 : gage 6546 =head3 JavaApplet
67 :    
68 :     Useage: $applet = JavaApplet(
69 :    
70 :    
71 :     );
72 :    
73 :     =cut
74 :    
75 : gage 5618 sub JavaApplet {
76 :     return new JavaApplet(@_);
77 : gage 5582
78 : gage 5618 }
79 :    
80 : gage 6546 =head3 CanvasApplet
81 :    
82 :     Useage: $applet = CanvasApplet(
83 :    
84 :    
85 :     );
86 :    
87 :     =cut
88 :    
89 : gage 6297 sub CanvasApplet {
90 :     return new CanvasApplet(@_);
91 :     }
92 : gage 5618 package Applet;
93 :    
94 :    
95 : gage 5582
96 : gage 6546 =head1 Methods
97 :    
98 : gage 5582 =cut
99 :    
100 :     ## this method is defined in this file
101 :     ## because the main subroutines HEADER_TEXT and MODES are
102 :     ## not available to the module FlashApplet when that file
103 :     ## is compiled (at the time the apache child process is first initialized)
104 :    
105 : gage 5618 =head3 insertAll
106 : gage 5582
107 : gage 5618 Useage: TEXT( $applet->insertAll() );
108 :     \{ $applet->insertAll() \} (used within BEGIN_TEXT/END_TEXT blocks)
109 : gage 5582
110 :     =cut
111 :    
112 :     =pod
113 :    
114 :     Inserts applet at this point in the HTML code. (In TeX mode a message "Applet" is written.) This method
115 :     also adds the applets header material into the header portion of the HTML page. It effectively inserts
116 : gage 5618 the outputs of both C<$applet-E<gt>insertHeader> and C<$applet-E<gt>insertObject> (defined in L<Applet.pm> )
117 : gage 6297 in the appropriate places. In addition it creates a hidden answer blank for storing the state of the applet
118 :     and provides mechanisms for revealing the state while debugging the applet.
119 : gage 5582
120 : gage 5618 Note: This method is defined here rather than in Applet.pl because it
121 :     requires access to the RECORD_FORM_LABEL subroutine
122 :     and to the routine accessing the stored values of the answers. These are defined in main::.
123 : gage 6297 FIXME -- with the creation of the PGcore object this can now be rewritten
124 : gage 5618
125 : gage 5582 =cut
126 :    
127 : gage 5618 sub insertAll { ## inserts both header text and object text
128 : gage 5582 my $self = shift;
129 : gage 5618 my %options = @_;
130 : gage 6026
131 : gage 6297
132 :     ##########################
133 :     # determine debug mode
134 : gage 6026 # debugMode can be turned on by setting it to 1 in either the applet definition or at insertAll time
135 : gage 6297 ##########################
136 :    
137 : gage 6178 my $debugMode = (defined($options{debug}) and $options{debug}>0) ? $options{debug} : 0;
138 : gage 6030 my $includeAnswerBox = (defined($options{includeAnswerBox}) and $options{includeAnswerBox}==1) ? 1 : 0;
139 : gage 6026 $debugMode = $debugMode || $self->debugMode;
140 :     $self->debugMode( $debugMode);
141 :    
142 :    
143 : gage 6030 my $reset_button = $options{reinitialize_button} || 0;
144 : gage 6178 warn qq! please change "reset_button=>1" to "reinitialize_button=>1" in the applet->installAll() command \n! if defined($options{reset_button});
145 : gage 6297
146 :     ##########################
147 :     # Get data to be interpolated into the HTML code defined in this subroutine
148 :     #
149 :     # This consists of the name of the applet and the names of the routines
150 :     # to get and set State of the applet (which is done every time the question page is refreshed
151 :     # and to get and set Config which is the initial configuration the applet is placed in
152 :     # when the question is first viewed. It is also the state which is returned to when the
153 :     # reset button is pressed.
154 :     ##########################
155 :    
156 : gage 5618 # prepare html code for storing state
157 :     my $appletName = $self->appletName;
158 : gage 6297 my $appletStateName = "${appletName}_state"; # the name of the hidden "answer" blank storing state FIXME -- use persistent data instead
159 :     my $getState = $self->getStateAlias; # names of routines for this applet
160 : gage 5618 my $setState = $self->setStateAlias;
161 : gage 6019 my $getConfig = $self->getConfigAlias;
162 :     my $setConfig = $self->setConfigAlias;
163 :    
164 : gage 6030 my $base64_initialState = encode_base64($self->initialState);
165 : gage 6297 main::RECORD_FORM_LABEL($appletStateName); #this insures that the state will be saved from one invocation to the next
166 :     # FIXME -- with PGcore the persistant data mechanism can be used instead
167 : gage 5618 my $answer_value = '';
168 : gage 6297
169 :     ##########################
170 :     # implement the sticky answer mechanism for maintaining the applet state when the question page is refreshed
171 :     # This is important for guest users for whom no permanent record of answers is recorded.
172 :     ##########################
173 :    
174 : gage 5993 if ( defined( ${$main::inputs_ref}{$appletStateName} ) and ${$main::inputs_ref}{$appletStateName} =~ /\S/ ) {
175 :     $answer_value = ${$main::inputs_ref}{$appletStateName};
176 :     } elsif ( defined( $main::rh_sticky_answers->{$appletStateName} ) ) {
177 :     warn "type of sticky answers is ", ref( $main::rh_sticky_answers->{$appletStateName} );
178 : gage 5618 $answer_value = shift( @{ $main::rh_sticky_answers->{$appletStateName} });
179 :     }
180 :     $answer_value =~ tr/\\$@`//d; #`## make sure student answers can not be interpolated by e.g. EV3
181 :     $answer_value =~ s/\s+/ /g; ## remove excessive whitespace from student answer
182 : gage 6297
183 :     ##########################
184 :     # insert a hidden answer blank to hold the applet's state
185 :     # (debug =>1 makes it visible for debugging and provides debugging buttons)
186 :     ##########################
187 :    
188 :    
189 :     ##########################
190 :     # Regularize the applet's state -- which could be in either XML format or in XML format encoded by base64
191 :     # In rare cases it might be simple string -- protect against that by putting xml tags around the state
192 :     # The result:
193 :     # $base_64_encoded_answer_value -- a base64 encoded xml string
194 :     # $decoded_answer_value -- and xml string
195 :     ##########################
196 :    
197 : gage 5993 my $base_64_encoded_answer_value;
198 :     my $decoded_answer_value;
199 :     if ( $answer_value =~/<XML|<?xml/i) {
200 :     $base_64_encoded_answer_value = encode_base64($answer_value);
201 :     $decoded_answer_value = $answer_value;
202 :     } else {
203 :     $decoded_answer_value = decode_base64($answer_value);
204 :     if ( $decoded_answer_value =~/<XML|<?xml/i) { # great, we've decoded the answer to obtain an xml string
205 :     $base_64_encoded_answer_value = $answer_value;
206 :     } else { #WTF?? apparently we don't have XML tags
207 :     $answer_value = "<xml>$answer_value</xml>";
208 :     $base_64_encoded_answer_value = encode_base64($answer_value);
209 :     $decoded_answer_value = $answer_value;
210 :     }
211 : gage 6297 }
212 : gage 5677 $base_64_encoded_answer_value =~ s/\r|\n//g; # get rid of line returns
213 : gage 6297
214 :     ##########################
215 :     # Construct answer blank for storing state -- in both regular (answer blank hidden)
216 :     # and debug (answer blank displayed) modes.
217 :     ##########################
218 :    
219 :     ##########################
220 :     # debug version of the applet state answerBox and controls (all displayed)
221 :     # stored in
222 :     # $debug_input_element
223 :     ##########################
224 :    
225 : gage 6368 # my $debug_input_element = qq!\n<textarea rows="4" cols="80"
226 :     # name = "$appletStateName" id = "$appletStateName">$decoded_answer_value</textarea><br/>!;
227 :     # conversion to base64 is now being done in the setState module
228 :     # when submitting we want everything to be in the base64 mode for safety
229 : gage 5618 my $debug_input_element = qq!\n<textarea rows="4" cols="80"
230 : gage 6372 name = "$appletStateName" id = "$appletStateName">$answer_value</textarea><br/>!;
231 : gage 6368
232 : gage 6178 if ($getState=~/\S/) { # if getStateAlias is not an empty string
233 :     $debug_input_element .= qq!
234 : gage 5623 <input type="button" value="$getState"
235 : gage 6297 onClick=" debugText='';
236 :     ww_applet_list['$appletName'].getState() ;
237 : gage 6079 if (debugText) {alert(debugText)};"
238 : gage 6316 />!;
239 : gage 6178 }
240 :     if ($setState=~/\S/) { # if setStateAlias is not an empty string
241 :     $debug_input_element .= qq!
242 : gage 5623 <input type="button" value="$setState"
243 : gage 5993 onClick="debugText='';
244 :     ww_applet_list['$appletName'].setState();
245 : gage 6079 if (debugText) {alert(debugText)};"
246 : gage 6316 />!;
247 : gage 6178 }
248 :     if ($getConfig=~/\S/) { # if getConfigAlias is not an empty string
249 :     $debug_input_element .= qq!
250 : gage 6019 <input type="button" value="$getConfig"
251 :     onClick="debugText='';
252 : gage 6079 ww_applet_list['$appletName'].getConfig();
253 :     if (debugText) {alert(debugText)};"
254 : gage 6316 />!;
255 : gage 6178 }
256 :     if ($setConfig=~/\S/) { # if setConfigAlias is not an empty string
257 :     $debug_input_element .= qq!
258 : gage 6019 <input type="button" value="$setConfig"
259 :     onClick="debugText='';
260 : gage 6026 ww_applet_list['$appletName'].setConfig();
261 : gage 6079 if (debugText) {alert(debugText)};"
262 : gage 6316 />!;
263 : gage 6178 }
264 : gage 6297
265 :     ##########################
266 :     # Construct answerblank for storing state
267 :     # using either the debug version (defined above) or the non-debug version
268 :     # where the state variable is hidden and the definition is very simple
269 :     # stored in
270 :     # $state_input_element
271 :     ##########################
272 : gage 6019
273 : gage 6026 my $state_input_element = ($debugMode) ? $debug_input_element :
274 : gage 6210 qq!\n<input type="hidden" name = "$appletStateName" id = "$appletStateName" value ="$base_64_encoded_answer_value">!;
275 : gage 6297
276 :     ##########################
277 :     # Construct the reset button string (this is blank if the button is not to be displayed
278 :     # $reset_button_str
279 :     ##########################
280 :    
281 : gage 5618 my $reset_button_str = ($reset_button) ?
282 : gage 6297 qq!<input type='submit' name='previewAnswers' id ='previewAnswers' value='return this question to its initial state'
283 : gage 6368 onClick="setHTMLAppletStateToRestart('$appletName')"><br/>!
284 : gage 6030 : '' ;
285 : gage 6297
286 :     ##########################
287 :     # Combine the state_input_button and the reset button into one string
288 :     # $state_storage_html_code
289 :     ##########################
290 :    
291 :    
292 : gage 6210 $state_storage_html_code = qq!<input type="hidden" name="previous_$appletStateName" id = "previous_$appletStateName" value = "$base_64_encoded_answer_value">!
293 : gage 6030 . $state_input_element. $reset_button_str
294 : gage 5993 ;
295 : gage 6297 ##########################
296 :     # Construct the answerBox (if it is requested). This is a default input box for interacting
297 :     # with the applet. It is separate from maintaining state but it often contains similar data.
298 :     # Additional answer boxes or buttons can be defined but they must be explicitly connected to
299 :     # the applet with additional javaScript commands.
300 :     # Result: $answerBox_code
301 :     ##########################
302 :    
303 : gage 6030 my $answerBox_code ='';
304 :     if ($includeAnswerBox) {
305 :     if ($debugMode) {
306 :    
307 :     $answerBox_code = $main::BR . main::NAMED_ANS_RULE('answerBox', 50 );
308 :     $answerBox_code .= qq!
309 :     <br/><input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/>
310 :     <br/>
311 :     !;
312 :     } else {
313 :     $answerBox_code = main::NAMED_HIDDEN_ANS_RULE('answerBox', 50 );
314 :     }
315 :     }
316 : gage 6297
317 :     ##########################
318 : gage 5618 # insert header material
319 : gage 6297 ##########################
320 : gage 5582 main::HEADER_TEXT($self->insertHeader());
321 : gage 6026 # update the debug mode for this applet.
322 : gage 6316 main::HEADER_TEXT(qq!<script language="javascript"> ww_applet_list["$appletName"].debugMode = $debugMode;\n</script>!);
323 : gage 6297
324 :     ##########################
325 :     # Return HTML or TeX strings to be included in the body of the page
326 :     ##########################
327 :    
328 : gage 6010 return main::MODES(TeX=>' {\bf applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code.$answerBox_code);
329 : gage 5582 }
330 :    
331 :     =head3 Example problem
332 :    
333 :    
334 :     =cut
335 :    
336 :    
337 :    
338 :     =pod
339 :    
340 :    
341 :     DOCUMENT();
342 :    
343 :     # Load whatever macros you need for the problem
344 :     loadMacros("PG.pl",
345 :     "PGbasicmacros.pl",
346 :     "PGchoicemacros.pl",
347 :     "PGanswermacros.pl",
348 :     "AppletObjects.pl",
349 :     "MathObjects.pl",
350 :     "source.pl"
351 :     );
352 :    
353 :     ## Do NOT show partial correct answers
354 :     $showPartialCorrectAnswers = 0;
355 :    
356 :    
357 :    
358 :     ###################################
359 :     # Create link to applet
360 :     ###################################
361 :    
362 :     $applet = FlashApplet();
363 :     my $appletName = "ExternalInterface";
364 :     $applet->codebase(findAppletCodebase("$appletName.swf"));
365 :     $applet->appletName($appletName);
366 :     $applet->appletId($appletName);
367 :    
368 :     # findAppletCodebase looks for the applet in a list
369 :     # of locations specified in global.conf
370 :    
371 :     ###################################
372 : gage 5618 # Add additional javaScript functions to header section of HTML to
373 : gage 5593 # communicate with the "ExternalInterface" applet.
374 : gage 5582 ###################################
375 :    
376 :     $applet->header(<<'END_HEADER');
377 : gage 6316 <script language="javascript" src="https://devel.webwork.rochester.edu:8002/webwork2_files/js/BrowserSniffer.js">
378 : gage 5582 </script>
379 :    
380 :    
381 :     <script language="JavaScript">
382 :     function getBrowser() {
383 :     //alert("look for sniffer");
384 :     var sniffer = new BrowserSniffer();
385 :     //alert("found sniffer" +sniffer);
386 :     return sniffer;
387 :     }
388 :    
389 :     function updateStatus(sMessage) {
390 : gage 5618 getQE("playbackStatus").value = sMessage;
391 : gage 5582 }
392 :    
393 :     function newColor() {
394 : gage 5618
395 :     getApplet("ExternalInterface").updateColor(Math.round(Math.random() * 0xFFFFFF));
396 : gage 5582 }
397 :    
398 :     </script>
399 :     END_HEADER
400 :    
401 :     ###################################
402 :     # Configure applet
403 :     ###################################
404 :    
405 :     # not used here. Allows for uploading an xml string for the applet
406 :    
407 :    
408 :    
409 :    
410 :     ###################################
411 :     # write the text for the problem
412 :     ###################################
413 :    
414 :     TEXT(beginproblem());
415 :    
416 :    
417 :    
418 :     BEGIN_TEXT
419 : gage 5618 \{ $applet->insertAll() \}
420 : gage 5582 $PAR
421 :    
422 :     The Flash object operates above this line. The box and button below this line are part of
423 :     the WeBWorK problem. They communicate with the Flash object.
424 :     $HR
425 :     Status <input type="text" id="playbackStatus" value="started" /><br />
426 :     Color <input type="button" value="new color" name="newColorButton" onClick="newColor()" />
427 :     $PAR $HR
428 :     This flash applet was created by Barbara Kaskosz.
429 :    
430 :     END_TEXT
431 :    
432 :     ENDDOCUMENT();
433 :    
434 :    
435 :    
436 :    
437 : gage 6372 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9