[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 6372 - (download) (as text) (annotate)
Thu Jul 15 03:28:21 2010 UTC (9 years, 4 months ago) by gage
File size: 15026 byte(s)
back ported suppor for geogebra applets


    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" language="javascript">
   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 #  conversion to base64 is now being done in the setState module
  213 #  when submitting we want everything to be in the base64 mode for safety
  214     my $debug_input_element  = qq!\n<textarea  rows="4" cols="80"
  215      name = "$appletStateName" id = "$appletStateName">$answer_value</textarea><br/>!;
  216 
  217   if ($getState=~/\S/) {   # if getStateAlias is not an empty string
  218     $debug_input_element .= qq!
  219           <input type="button"  value="$getState"
  220                  onClick=" debugText='';
  221                            ww_applet_list['$appletName'].getState() ;
  222                           if (debugText) {alert(debugText)};"
  223           />!;
  224   }
  225   if ($setState=~/\S/) {   # if setStateAlias is not an empty string
  226     $debug_input_element .= qq!
  227           <input type="button"  value="$setState"
  228                  onClick="debugText='';
  229                           ww_applet_list['$appletName'].setState();
  230                           if (debugText) {alert(debugText)};"
  231           />!;
  232   }
  233   if ($getConfig=~/\S/) {   # if getConfigAlias is not an empty string
  234     $debug_input_element .= qq!
  235           <input type="button"  value="$getConfig"
  236                  onClick="debugText='';
  237                           ww_applet_list['$appletName'].getConfig();
  238                           if (debugText) {alert(debugText)};"
  239           />!;
  240   }
  241   if ($setConfig=~/\S/) {   # if setConfigAlias is not an empty string
  242     $debug_input_element .= qq!
  243         <input type="button"  value="$setConfig"
  244                  onClick="debugText='';
  245                           ww_applet_list['$appletName'].setConfig();
  246                           if (debugText) {alert(debugText)};"
  247             />!;
  248     }
  249 
  250   ##########################
  251     # Construct answerblank for storing state
  252     # using either the debug version (defined above) or the non-debug version
  253     # where the state variable is hidden and the definition is very simple
  254     # stored in
  255     # $state_input_element
  256   ##########################
  257 
  258   my $state_input_element = ($debugMode) ? $debug_input_element :
  259         qq!\n<input type="hidden" name = "$appletStateName" id = "$appletStateName"  value ="$base_64_encoded_answer_value">!;
  260 
  261   ##########################
  262     # Construct the reset button string (this is blank if the button is not to be displayed
  263     # $reset_button_str
  264   ##########################
  265 
  266     my $reset_button_str = ($reset_button) ?
  267             qq!<input type='submit' name='previewAnswers' id ='previewAnswers' value='return this question to its initial state'
  268                  onClick="setHTMLAppletStateToRestart('$appletName')"><br/>!
  269             : ''  ;
  270 
  271   ##########################
  272   # Combine the state_input_button and the reset button into one string
  273   # $state_storage_html_code
  274   ##########################
  275 
  276 
  277     $state_storage_html_code = qq!<input type="hidden"  name="previous_$appletStateName" id = "previous_$appletStateName"  value = "$base_64_encoded_answer_value">!
  278                               . $state_input_element. $reset_button_str
  279                              ;
  280   ##########################
  281   # Construct the answerBox (if it is requested).  This is a default input box for interacting
  282   # with the applet.  It is separate from maintaining state but it often contains similar data.
  283   # Additional answer boxes or buttons can be defined but they must be explicitly connected to
  284   # the applet with additional javaScript commands.
  285   # Result: $answerBox_code
  286   ##########################
  287 
  288     my $answerBox_code ='';
  289     if ($includeAnswerBox) {
  290     if ($debugMode) {
  291 
  292       $answerBox_code = $main::BR . main::NAMED_ANS_RULE('answerBox', 50 );
  293       $answerBox_code .= qq!
  294                <br/><input type="button" value="get Answer from applet" onClick="eval(ww_applet_list['$appletName'].submitActionScript )"/>
  295                <br/>
  296               !;
  297     } else {
  298       $answerBox_code = main::NAMED_HIDDEN_ANS_RULE('answerBox', 50 );
  299     }
  300   }
  301 
  302   ##########################
  303     # insert header material
  304   ##########################
  305   main::HEADER_TEXT($self->insertHeader());
  306   # update the debug mode for this applet.
  307     main::HEADER_TEXT(qq!<script language="javascript"> ww_applet_list["$appletName"].debugMode = $debugMode;\n</script>!);
  308 
  309   ##########################
  310     # Return HTML or TeX strings to be included in the body of the page
  311   ##########################
  312 
  313     return main::MODES(TeX=>' {\bf  applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code.$answerBox_code);
  314 }
  315 
  316 =head3 Example problem
  317 
  318 
  319 =cut
  320 
  321 
  322 
  323 =pod
  324 
  325 
  326   DOCUMENT();
  327 
  328   # Load whatever macros you need for the problem
  329   loadMacros("PG.pl",
  330          "PGbasicmacros.pl",
  331          "PGchoicemacros.pl",
  332          "PGanswermacros.pl",
  333          "AppletObjects.pl",
  334          "MathObjects.pl",
  335          "source.pl"
  336         );
  337 
  338   ## Do NOT show partial correct answers
  339   $showPartialCorrectAnswers = 0;
  340 
  341 
  342 
  343   ###################################
  344   # Create  link to applet
  345   ###################################
  346 
  347   $applet = FlashApplet();
  348   my $appletName = "ExternalInterface";
  349   $applet->codebase(findAppletCodebase("$appletName.swf"));
  350   $applet->appletName($appletName);
  351   $applet->appletId($appletName);
  352 
  353   # findAppletCodebase looks for the applet in a list
  354   # of locations specified in global.conf
  355 
  356   ###################################
  357   # Add additional javaScript functions to header section of HTML to
  358   # communicate with the "ExternalInterface" applet.
  359   ###################################
  360 
  361   $applet->header(<<'END_HEADER');
  362   <script language="javascript" src="https://devel.webwork.rochester.edu:8002/webwork2_files/js/BrowserSniffer.js">
  363   </script>
  364 
  365 
  366   <script language="JavaScript">
  367     function getBrowser() {
  368         //alert("look for sniffer");
  369       var sniffer = new BrowserSniffer();
  370       //alert("found sniffer" +sniffer);
  371       return sniffer;
  372     }
  373 
  374     function updateStatus(sMessage) {
  375         getQE("playbackStatus").value = sMessage;
  376     }
  377 
  378     function newColor() {
  379 
  380       getApplet("ExternalInterface").updateColor(Math.round(Math.random() * 0xFFFFFF));
  381     }
  382 
  383   </script>
  384   END_HEADER
  385 
  386   ###################################
  387   # Configure applet
  388   ###################################
  389 
  390   # not used here.  Allows for uploading an xml string for the applet
  391 
  392 
  393 
  394 
  395   ###################################
  396   # write the text for the problem
  397   ###################################
  398 
  399   TEXT(beginproblem());
  400 
  401 
  402 
  403   BEGIN_TEXT
  404   \{ $applet->insertAll() \}
  405     $PAR
  406 
  407     The Flash object operates above this line.  The box and button below this line are part of
  408     the WeBWorK problem.  They communicate with the Flash object.
  409     $HR
  410     Status <input type="text" id="playbackStatus" value="started" /><br />
  411     Color <input type="button" value="new color" name="newColorButton" onClick="newColor()" />
  412      $PAR $HR
  413      This flash applet was created by Barbara Kaskosz.
  414 
  415   END_TEXT
  416 
  417   ENDDOCUMENT();
  418 
  419 
  420 
  421 
  422 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9