[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 5677 - (download) (as text) (annotate)
Thu May 22 19:17:10 2008 UTC (11 years, 4 months ago) by gage
File size: 14763 byte(s)
minor changes to help with debugging

    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.10 2008/05/12 00:50:24 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 later 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 
   45 main::HEADER_TEXT(<<'END_HEADER_TEXT');
   46   <script language="javascript">AC_FL_RunContent = 0;</script>
   47     <script src="/webwork2_files/applets/AC_RunActiveContent.js" language="javascript">
   48     </script>
   49     <script src="/webwork2_files/js/Base64.js" language="javascript">
   50     </script>
   51 
   52 <script language="JavaScript">
   53 
   54 //////////////////////////////////////////////////////////
   55 // applet lists
   56 //////////////////////////////////////////////////////////
   57 
   58     var  applet_initializeAction_list = new Object;  // functions for initializing question with an applet
   59     var  applet_submitAction_list     = new Object;  // functions for submitting question with applet
   60     var  applet_setState_list         = new Object;  // functions for setting state (XML) from applets
   61     var  applet_getState_list         = new Object;  // functions for getting state (XML) from applets
   62     var  applet_config_list           = new Object;  // functions for  configuring on applets
   63   var  applet_checkLoaded_list      = new Object;  // functions for probing the applet to see if it is loaded
   64   var  applet_reportsLoaded_list    = new Object;  // flag set by applet
   65   var  applet_isReady_list          = new Object;  // flag set by javaScript in checkLoaded
   66 
   67 //////////////////////////////////////////////////////////
   68 // DEBUGGING tools
   69 //////////////////////////////////////////////////////////
   70   var debug;
   71   var debugText = "";
   72   function set_debug(num) { // setting debug for any applet sets it for all of them
   73     if (num) {
   74       debug =1;
   75     }
   76   }
   77   function debug_add(str) {
   78     if (debug) {
   79       debugText = debugText + "\n\n" +str;
   80     }
   81   }
   82 
   83 //////////////////////////////////////////////////////////
   84 // INITIALIZE and SUBMIT actions
   85 //////////////////////////////////////////////////////////
   86 
   87     function submitAction()  {
   88 
   89         if (debug) {
   90           debugText = " Begin looping through applet_submitAction_list\n";
   91         }
   92     for (var applet in applet_submitAction_list)  {
   93 
   94        applet_submitAction_list[applet]();
   95     }
   96     if (debug) {
   97       alert(debugText); debugText="";
   98     };
   99     }
  100     function initializeAction() {
  101         var iMax = 10;
  102         debugText="start intializeAction() with up to " +iMax + " attempts\n";
  103       for (var appletName in applet_initializeAction_list)  {
  104       safe_applet_initialize(appletName, iMax);
  105       }
  106 
  107     }
  108 
  109     // applet can set isReady flag by calling applet_loaded(appletName, loaded);
  110     function applet_loaded(appletName,loaded) {
  111         applet_reportsLoaded_list[appletName] = loaded; // 0 means not loaded
  112       debug_add("applet reporting that it has been loaded = " + loaded );
  113     }
  114 
  115     // insures that applet is loaded before initializing it
  116   function safe_applet_initialize(appletName, i) {
  117     debug_add("Iteration " + i + " of safe_applet_initialize with applet " + appletName );
  118 
  119     i--;
  120     var applet_loaded = applet_checkLoaded_list[appletName]();
  121     debug_add("applet is ready = " + applet_loaded  );
  122 
  123     if ( 0 < i && !applet_loaded ) { // wait until applet is loaded
  124       debug_add("applet " + appletName + "not ready try again");
  125       window.setTimeout( "safe_applet_initialize(\"" + appletName + "\"," + i +  ")",1);
  126     } else if( 0 < i ){  // now that applet is loaded configure it and initialize it with saved data.
  127       debug_add(" Ready to initialize applet " + appletName + " with " + i +  " iterations left. ");
  128 
  129       // in-line handler -- configure and initialize
  130       try{
  131         if (debug && typeof(getApplet(appletName).debug) == "function" ) {
  132           getApplet(appletName).debug(1);  // turn the applet's debug functions on.
  133         }
  134       } catch(e) {
  135         alert("Unable to set debug mode for applet " + appletName);
  136       }
  137       try{
  138         applet_config_list[appletName]();
  139       } catch(e) {
  140         alert("Unable to configure " + appletName + " \n " +e );
  141       }
  142       try{
  143         applet_initializeAction_list[appletName]();
  144       } catch(e) {
  145         alert("unable to initialize " + appletName + " \n " +e );
  146       }
  147 
  148     } else {
  149       if (debug) {alert("Error: timed out waiting for applet " +appletName + " to load");}
  150     }
  151     if (debug) {alert(debugText); debugText="";};
  152   }
  153 
  154 ///////////////////////////////////////////////////////
  155 // Utility functions
  156 ///////////////////////////////////////////////////////
  157 
  158 
  159   function getApplet(appletName) {
  160       var isIE = navigator.appName.indexOf("Microsoft") != -1;
  161       var obj = (isIE) ? window[appletName] : window.document[appletName];
  162       //return window.document[appletName];
  163       if (obj && (obj.name = appletName)) {
  164         return( obj );
  165       } else {
  166        // alert ("can't find applet " + appletName);
  167       }
  168    }
  169 
  170   function listQuestionElements() { // list all HTML input and textarea elements in main problem form
  171      var isIE = navigator.appName.indexOf("Microsoft") != -1;
  172      var elementList = (isIE) ?  document.getElementsByTagName("input") : document.problemMainForm.getElementsByTagName("input");
  173      var str=elementList.length +" Question Elements\n type | name = value  < id > \n";
  174      for( var i=0; i< elementList.length; i++) {
  175        str = str + " "+i+" " + elementList[i].type
  176                + " | " + elementList[i].name
  177                + "= " + elementList[i].value +
  178                " <" + elementList[i].id + ">\n";
  179      }
  180      elementList = (isIE) ?  document.getElementsByTagName("textarea") : document.problemMainForm.getElementsByTagName("textarea");
  181      for( var i=0; i< elementList.length; i++) {
  182        str = str + " "+i+" " + elementList[i].type
  183                + " | " + elementList[i].name
  184                + "= " + elementList[i].value +
  185                " <" + elementList[i].id + ">\n";
  186      }
  187      alert(str +"\n Place listQuestionElements() at end of document in order to get all form elements!");
  188   }
  189 
  190   function base64Q(str) {
  191     return ( !str.match(/<XML/i) && !str.match(/<?xml/i));
  192   }
  193   function setEmptyState(appletName){
  194     var newState = "<xml></xml>";
  195     applet_setState_list[appletName](newState);
  196     var applet = getApplet(appletName);
  197     getQE(appletName+"_state").value = newState;
  198     getQE("previous_" + appletName + "_state").value = newState
  199   }
  200 
  201   function getQE(name1) { // get Question Element in problemMainForm by name
  202     var isIE = navigator.appName.indexOf("Microsoft") != -1;
  203     var obj = (isIE) ? document.getElementById(name1)
  204               :document.problemMainForm[name1];
  205     // needed for IE -- searches id and name space so it can be unreliable if names are not unique
  206     if (!obj || obj.name != name1) {
  207       alert("Can't find element " + name1);
  208       listQuestionElements();
  209     } else {
  210       return( obj );
  211     }
  212 
  213   }
  214   function getQuestionElement(name1) {
  215     return getQE(name1);
  216   }
  217 
  218  </script>
  219 
  220 END_HEADER_TEXT
  221 
  222 };
  223 
  224 =head3
  225   FlashApplet
  226 
  227   Useage:    $applet = FlashApplet();
  228 
  229 =cut
  230 
  231 sub FlashApplet {
  232   return new FlashApplet(@_);
  233 
  234 }
  235 
  236 sub JavaApplet {
  237   return new JavaApplet(@_);
  238 
  239 }
  240 
  241 package Applet;
  242 
  243 
  244 
  245 =head2 Methods
  246 
  247 =cut
  248 
  249 ## this method is defined in this file
  250 ## because the main subroutines HEADER_TEXT and MODES are
  251 ## not available to the module FlashApplet when that file
  252 ## is compiled (at the time the apache child process is first initialized)
  253 
  254 =head3  insertAll
  255 
  256   Useage:   TEXT( $applet->insertAll() );
  257             \{ $applet->insertAll() \}     (used within BEGIN_TEXT/END_TEXT blocks)
  258 
  259 =cut
  260 
  261 =pod
  262 
  263 Inserts applet at this point in the HTML code.  (In TeX mode a message "Applet" is written.)  This method
  264 also adds the applets header material into the header portion of the HTML page. It effectively inserts
  265 the outputs of both C<$applet-E<gt>insertHeader> and C<$applet-E<gt>insertObject> (defined in L<Applet.pm> )
  266 in the appropriate places.
  267 
  268 Note: This method is defined here rather than in Applet.pl because it
  269       requires access to the RECORD_FORM_LABEL subroutine
  270       and to the routine accessing the stored values of the answers.  These are defined in main::.
  271 
  272 =cut
  273 
  274 sub insertAll {  ## inserts both header text and object text
  275   my $self = shift;
  276   my %options = @_;
  277   $self->debug( (defined($options{debug}) and $options{debug}==1) ? 1 : 0 );
  278   my $reset_button = $options{reset_button} || 0;
  279   # prepare html code for storing state
  280   my $appletName      = $self->appletName;
  281   my $appletStateName = "${appletName}_state";
  282   my $getState        = $self->getStateAlias;
  283   my $setState        = $self->setStateAlias;
  284   my $base64_initialState     = $self->base64_state;
  285   main::RECORD_FORM_LABEL($appletStateName);            #this insures that they'll be saved from one invocation to the next
  286   #main::RECORD_FORM_LABEL("previous_$appletStateName");
  287     my $answer_value = '';
  288   $answer_value = ${$main::inputs_ref}{$appletStateName} if defined(${$main::inputs_ref}{$appletStateName});
  289 
  290   if ( defined( $main::rh_sticky_answers->{$appletStateName} ) ) {
  291     $answer_value = shift( @{ $main::rh_sticky_answers->{$appletStateName} });
  292     $answer_value = '' unless defined($answer_value);
  293   }
  294   $answer_value =~ tr/\\$@`//d;   #`## make sure student answers can not be interpolated by e.g. EV3
  295   $answer_value =~ s/\s+/ /g;     ## remove excessive whitespace from student answer
  296 
  297   #######
  298   # insert a hidden variable to hold the applet's state (debug =>1 makes it visible for debugging and provides debugging buttons)
  299   #######
  300   my $base_64_encoded_answer_value = ($answer_value =~/<XML|<?xml/i)? encode_base64($answer_value) : $answer_value;
  301   $base_64_encoded_answer_value =~ s/\r|\n//g;    # get rid of line returns
  302   my $decoded_answer_value         = ($answer_value =~/<XML|<?xml/i) ? $answer_value : decode_base64($answer_value);
  303     my $debug_input_element  = qq!\n<textarea  rows="4" cols="80"
  304      name = "$appletStateName">$decoded_answer_value</textarea><br/>
  305           <input type="button"  value="$getState"
  306                  onClick="applet_getState_list['$appletName']()"
  307           >
  308           <input type="button"  value="$setState"
  309                  onClick="var tmp = getQE('$appletStateName').value;
  310                           applet_setState_list['$appletName'](tmp);"
  311           >
  312     !;
  313   my $state_input_element = ($self->debug == 1) ? $debug_input_element :
  314         qq!\n<input type="hidden" name = "$appletStateName" value ="$base_64_encoded_answer_value">!;
  315     my $reset_button_str = ($reset_button) ?
  316             qq!<br/><input type='button' value='set applet state empty' onClick="setEmptyState('$appletName')">
  317                     <input type="button" value="reinitialize applet" onClick="getQE('$appletStateName').value='$base64_initialState'"/>!
  318             : ''
  319     ;
  320   # always base64 encode the hidden answer value to prevent problems with quotes.
  321     #
  322   $state_storage_html_code =
  323                       $reset_button_str.
  324                       $state_input_element.
  325                         qq!<input type="hidden"  name="previous_$appletStateName" value = "$base_64_encoded_answer_value">!;
  326     #######
  327     # insert header material
  328     #######
  329   main::HEADER_TEXT($self->insertHeader());
  330     return main::MODES(TeX=>' {\bf  applet } ', HTML=>$self->insertObject.$main::BR.$state_storage_html_code);
  331 }
  332 
  333 =head3 Example problem
  334 
  335 
  336 =cut
  337 
  338 
  339 
  340 =pod
  341 
  342 
  343   DOCUMENT();
  344 
  345   # Load whatever macros you need for the problem
  346   loadMacros("PG.pl",
  347          "PGbasicmacros.pl",
  348          "PGchoicemacros.pl",
  349          "PGanswermacros.pl",
  350          "AppletObjects.pl",
  351          "MathObjects.pl",
  352          "source.pl"
  353         );
  354 
  355   ## Do NOT show partial correct answers
  356   $showPartialCorrectAnswers = 0;
  357 
  358 
  359 
  360   ###################################
  361   # Create  link to applet
  362   ###################################
  363 
  364   $applet = FlashApplet();
  365   my $appletName = "ExternalInterface";
  366   $applet->codebase(findAppletCodebase("$appletName.swf"));
  367   $applet->appletName($appletName);
  368   $applet->appletId($appletName);
  369 
  370   # findAppletCodebase looks for the applet in a list
  371   # of locations specified in global.conf
  372 
  373   ###################################
  374   # Add additional javaScript functions to header section of HTML to
  375   # communicate with the "ExternalInterface" applet.
  376   ###################################
  377 
  378   $applet->header(<<'END_HEADER');
  379   <script type="text/javascript" src="https://devel.webwork.rochester.edu:8002/webwork2_files/js/BrowserSniffer.js">
  380   </script>
  381 
  382 
  383   <script language="JavaScript">
  384     function getBrowser() {
  385         //alert("look for sniffer");
  386       var sniffer = new BrowserSniffer();
  387       //alert("found sniffer" +sniffer);
  388       return sniffer;
  389     }
  390 
  391     function updateStatus(sMessage) {
  392         getQE("playbackStatus").value = sMessage;
  393     }
  394 
  395     function newColor() {
  396 
  397       getApplet("ExternalInterface").updateColor(Math.round(Math.random() * 0xFFFFFF));
  398     }
  399 
  400   </script>
  401   END_HEADER
  402 
  403   ###################################
  404   # Configure applet
  405   ###################################
  406 
  407   # not used here.  Allows for uploading an xml string for the applet
  408 
  409 
  410 
  411 
  412   ###################################
  413   # write the text for the problem
  414   ###################################
  415 
  416   TEXT(beginproblem());
  417 
  418 
  419 
  420   BEGIN_TEXT
  421   \{ $applet->insertAll() \}
  422     $PAR
  423 
  424     The Flash object operates above this line.  The box and button below this line are part of
  425     the WeBWorK problem.  They communicate with the Flash object.
  426     $HR
  427     Status <input type="text" id="playbackStatus" value="started" /><br />
  428     Color <input type="button" value="new color" name="newColorButton" onClick="newColor()" />
  429      $PAR $HR
  430      This flash applet was created by Barbara Kaskosz.
  431 
  432   END_TEXT
  433 
  434   ENDDOCUMENT();
  435 
  436 
  437 
  438 
  439 =cut

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9