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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6297 - (download) (as text) (annotate)
Mon Jun 21 21:04:12 2010 UTC (9 years, 2 months ago) by gage
File size: 14677 byte(s)
added comments 

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/macros/AppletObjects.pl,v 1.24 2010/01/03 17:13:46 gage Exp $
    5 #
    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 AppletObjects.pl - Macro-based front end for the Applet.pm module.
   20 
   21 
   22 =head1 DESCRIPTION
   23 
   24 This subroutines in this
   25 file provide mechanisms to insert Flash applets (and  Java applets)
   26 into a WeBWorK problem.
   27 
   28 
   29 =head1 SEE ALSO
   30 
   31 L<Applets.pm>.
   32 
   33 =cut
   34 
   35 #########################################################################
   36 #
   37 # Add basic functionality to the header of the question
   38 #
   39 # don't reload this file
   40 #########################################################################
   41 
   42 sub _AppletObjects_init{
   43 
   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     </script>
   50     <script src="/webwork2_files/js/ww_applet_support.js">
   51         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
   52     </script>
   53 END_HEADER_TEXT
   54 
   55 };
   56 
   57 =head3
   58   FlashApplet
   59 
   60   Useage:    $applet = FlashApplet();
   61 
   62 =cut
   63 
   64 sub FlashApplet {
   65   return new FlashApplet(@_);
   66 
   67 }
   68 
   69 sub JavaApplet {
   70   return new JavaApplet(@_);
   71 
   72 }
   73 
   74 sub CanvasApplet {
   75   return new CanvasApplet(@_);
   76 }
   77 package Applet;
   78 
   79 
   80 
   81 =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 =head3  insertAll
   91 
   92   Useage:   TEXT( $applet->insertAll() );
   93             \{ $applet->insertAll() \}     (used within BEGIN_TEXT/END_TEXT blocks)
   94 
   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 the outputs of both C<$applet-E<gt>insertHeader> and C<$applet-E<gt>insertObject> (defined in L<Applet.pm> )
  102 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 
  105 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       FIXME -- with the creation of the PGcore object this can now be rewritten
  109 
  110 =cut
  111 
  112 sub insertAll {  ## inserts both header text and object text
  113   my $self = shift;
  114   my %options = @_;
  115 
  116 
  117   ##########################
  118   # determine debug mode
  119   # debugMode can be turned on by setting it to 1 in either the applet definition or at insertAll time
  120   ##########################
  121 
  122   my $debugMode = (defined($options{debug}) and $options{debug}>0) ? $options{debug} : 0;
  123   my $includeAnswerBox = (defined($options{includeAnswerBox}) and $options{includeAnswerBox}==1) ? 1 : 0;
  124   $debugMode = $debugMode || $self->debugMode;
  125     $self->debugMode( $debugMode);
  126 
  127 
  128   my $reset_button = $options{reinitialize_button} || 0;
  129   warn qq! please change  "reset_button=>1" to "reinitialize_button=>1" in the applet->installAll() command \n! if defined($options{reset_button});
  130 
  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   # prepare html code for storing state
  142   my $appletName      = $self->appletName;
  143   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   my $setState        = $self->setStateAlias;
  146   my $getConfig       = $self->getConfigAlias;
  147   my $setConfig       = $self->setConfigAlias;
  148 
  149   my $base64_initialState     = encode_base64($self->initialState);
  150   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     my $answer_value = '';
  153 
  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     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     $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 
  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   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   }
  197   $base_64_encoded_answer_value =~ s/\r|\n//g;    # get rid of line returns
  198 
  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     my $debug_input_element  = qq!\n<textarea  rows="4" cols="80"
  211      name = "$appletStateName" id = "$appletStateName">$decoded_answer_value</textarea><br/>!;
  212   if ($getState=~/\S/) {   # if getStateAlias is not an empty string
  213     $debug_input_element .= qq!
  214           <input type="button"  value="$getState"
  215                  onClick=" debugText='';
  216                            ww_applet_list['$appletName'].getState() ;
  217                           if (debugText) {alert(debugText)};"
  218           >!;
  219   }
  220   if ($setState=~/\S/) {   # if setStateAlias is not an empty string
  221     $debug_input_element .= qq!
  222           <input type="button"  value="$setState"
  223                  onClick="debugText='';
  224                           ww_applet_list['$appletName'].setState();
  225                           if (debugText) {alert(debugText)};"
  226           >!;
  227   }
  228   if ($getConfig=~/\S/) {   # if getConfigAlias is not an empty string
  229     $debug_input_element .= qq!
  230           <input type="button"  value="$getConfig"
  231                  onClick="debugText='';
  232                           ww_applet_list['$appletName'].getConfig();
  233                           if (debugText) {alert(debugText)};"
  234           >!;
  235   }
  236   if ($setConfig=~/\S/) {   # if setConfigAlias is not an empty string
  237     $debug_input_element .= qq!
  238         <input type="button"  value="$setConfig"
  239                  onClick="debugText='';
  240                           ww_applet_list['$appletName'].setConfig();
  241                           if (debugText) {alert(debugText)};"
  242             >!;
  243     }
  244 
  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 
  253   my $state_input_element = ($debugMode) ? $debug_input_element :
  254         qq!\n<input type="hidden" name = "$appletStateName" id = "$appletStateName"  value ="$base_64_encoded_answer_value">!;
  255 
  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     my $reset_button_str = ($reset_button) ?
  262             qq!<input type='submit' name='previewAnswers' id ='previewAnswers' value='return this question to its initial state'
  263                  onClick="setAppletStateToRestart('$appletName')"><br/>!
  264             : ''  ;
  265 
  266   ##########################
  267   # Combine the state_input_button and the reset button into one string
  268   # $state_storage_html_code
  269   ##########################
  270 
  271 
  272     $state_storage_html_code = qq!<input type="hidden"  name="previous_$appletStateName" id = "previous_$appletStateName"  value = "$base_64_encoded_answer_value">!
  273                               . $state_input_element. $reset_button_str
  274                              ;
  275   ##########################
  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     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 
  297   ##########################
  298     # insert header material
  299   ##########################
  300   main::HEADER_TEXT($self->insertHeader());
  301   # update the debug mode for this applet.
  302     main::HEADER_TEXT(qq!<script> ww_applet_list["$appletName"].debugMode = $debugMode;\n</script>!);
  303 
  304   ##########################
  305     # Return HTML or TeX strings to be included in the body of the page
  306   ##########################
  307 
  308     return main::MODES(TeX=>' {\bf  applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code.$answerBox_code);
  309 }
  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   # Add additional javaScript functions to header section of HTML to
  353   # communicate with the "ExternalInterface" applet.
  354   ###################################
  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         getQE("playbackStatus").value = sMessage;
  371     }
  372 
  373     function newColor() {
  374 
  375       getApplet("ExternalInterface").updateColor(Math.round(Math.random() * 0xFFFFFF));
  376     }
  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   \{ $applet->insertAll() \}
  400     $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