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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9