[system] / trunk / pg / lib / Applet.pm Repository:
ViewVC logotype

View of /trunk/pg/lib/Applet.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6013 - (download) (as text) (annotate)
Thu Feb 19 16:35:26 2009 UTC (10 years, 9 months ago) by gage
File size: 21626 byte(s)
Cleaning up duplicated lines

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/lib/Applet.pm,v 1.16 2009/02/19 03:04:22 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 Applet.pl - Provides code for inserting FlashApplets and JavaApplets into webwork problems
   20 
   21 =head1 SYNPOSIS
   22 
   23   ###################################
   24   # Create  link to applet
   25   ###################################
   26   my $appletName = "LineThruPointsWW";
   27   $applet = new FlashApplet(
   28      # can be replaced by $applet =FlashApplet() when using AppletObjects.pl
   29      codebase   => findAppletCodebase("$appletName.swf"),
   30      appletName => $appletName,
   31      appletId   => $appletName,
   32      submitActionAlias => 'checkAnswer',
   33   );
   34 
   35   ###################################
   36   # Configure applet
   37   ###################################
   38 
   39   #xml data to set up the problem-rac
   40   $applet->config(qq{<XML>
   41   <point xval='$xval_1' yval='$yval_1' />
   42   <point xval='$xval_2' yval='$yval_2' />
   43   </XML>});
   44 
   45 
   46   ###################################
   47   # insert applet header material
   48   ###################################
   49   HEADER_TEXT($applet->insertHeader );
   50 
   51   ###################################
   52   # Text section
   53   #
   54 
   55   ###################################
   56   #insert applet into body
   57   ###################################
   58   TEXT( MODES(TeX=>'object code', HTML=>$applet->insertObject));
   59 
   60 
   61 =head1 DESCRIPTION
   62 
   63 This file provides an object to store in one place
   64 all of the information needed to call an applet.
   65 
   66 The object FlashApplet has defaults for inserting flash applets.
   67 
   68 =over
   69 
   70 =item *
   71 
   72 =item *
   73 
   74 =back
   75 
   76 (not yet completed)
   77 
   78 The module JavaApplet has defaults for inserting java applets.
   79 
   80 The module Applet stores common code for the two types of applet.
   81 
   82 =head1 USAGE
   83 
   84 These modules are activate by listing it in the modules section of global.conf and rebooting the server.
   85 The companion file to this one is macros/AppletObjects.pl
   86 
   87 qw(Applet FlashApplet JavaApplet)
   88 
   89 =cut
   90 
   91 
   92 
   93 package Applet;
   94 
   95 use URI::Escape;
   96 
   97 
   98 
   99 use MIME::Base64 qw( encode_base64 decode_base64);
  100 
  101 
  102 =head2 Default javaScript functions placed in header
  103 
  104 =pod
  105 
  106 These functions are automatically defined for use for
  107 any javaScript placed in the text of a PG question.
  108 
  109     getApplet(appletName)  -- finds the applet path in the DOM
  110 
  111     submitAction()            -- calls the submit action of the applets
  112 
  113     initializeWWquestion()        -- calls the initialize action of the applets
  114 
  115     getQE(name)               -- gets an HTML element of the question by name
  116                                  or by id.  Be sure to keep all names and ids
  117                                  unique within a given PG question.
  118 
  119     getQuestionElement(name)  -- long form of getQE(name)
  120 
  121     listQuestionElements()    -- for discovering the names of inputs in the
  122                                  PG question.  An alert dialog will list all
  123                                  of the elements.
  124       Usage: Place this at the END of the question, just before END_DOCUMENT():
  125 
  126                 TEXT(qq!<script> listQuestionElements() </script>!);
  127                 ENDDOCUMENT();
  128              to obtain a list of all of the HTML elements in the question
  129 
  130     List of  accessor methods made available by the FlashApplet class:
  131         Usage:  $current_value = $applet->method(new_value or empty)
  132         These can also be set when creating the class -- for exampe:
  133              $applet = new FlashApplet(
  134                        # can be replaced by $applet =FlashApplet() when using AppletObjects.pl
  135                        codebase   => findAppletCodebase("$appletName.swf"),
  136                        appletName => $appletName,
  137                        appletId   => $appletName,
  138                        submitActionAlias => 'checkAnswer',
  139             );
  140 
  141 
  142         appletId         for simplicity and reliability appletId and appletName are always the same
  143         appletName
  144         archive      the name of the .jar file containing the applet code
  145         code         the name of the applet code in the .jar archive
  146         codebase     a prefix url used to find the archive and the applet itself
  147 
  148         height       rectangle alloted in the html page for displaying the applet
  149 
  150         params       an anonymous array containing name/value pairs
  151                      to configure the applet [name =>'value, ...]
  152 
  153         header       stores the text to be added to the header section of the html page
  154         object       stores the text which places the applet on the html page
  155 
  156         debug        in debug mode several alerts mark progress through the procedure of calling the applet
  157 
  158         config       configuration are those customizable attributes of the applet which don't
  159                      change as it is used.  When stored in hidden answer fields
  160                      it is usually stored in base64 encoded format.
  161         base64_config base64 encode version of the contents of config
  162 
  163         configAlias  (default: config ) names the applet command called with the contents of $self->config
  164                      to configure the applet.  The parameters are passed to the applet in plain text using <xml>
  165                      The outer tags must be   <xml> .....   </xml>
  166         state        state consists of those customizable attributes of the applet which change
  167                      as the applet is used.  It is stored by the calling .pg question so that
  168                      when revisiting the question the applet
  169                      will be restored to the same state it was left in when the question was last
  170                      viewed.
  171 
  172         getStateAlias  (default: getState) alias for command called to read the current state of the applet.
  173                        The state is passed in plain text xml format with outer tags: <xml>....</xml>
  174         setStateAlias  (default: setState) alias for the command called to reset the  state of the applet.
  175                        The state is passed in plain text in xml format with outer tags: <xml>....</xml>
  176 
  177         base64_state   returns the base64 encoded version of the state stored in the applet object.
  178 
  179         initializeActionAlias  -- (default: initializeAction) the name of the javaScript subroutine called to initialize the applet (some overlap with config/ and setState
  180         submitActionAlias      -- (default: submitAction)the name of the javaScript subroutine called when the submit button of the
  181                                   .pg question is pressed.
  182         answerBox              -- name of answer box to return answer to: default defaultAnswerBox
  183         getAnswer              -- (formerly sendData) get student answer from applet and place in answerBox
  184         returnFieldName        -- (deprecated) synonmym for answerBox
  185 
  186 
  187 =cut
  188 
  189 
  190 
  191 
  192 sub new {
  193    my $class = shift;
  194    my $self = {
  195     appletName =>'',
  196     code=>'',
  197     codebase=>'',
  198 #   appletId  =>'',   #always use identical applet Id's and applet Names
  199     params    =>undef,
  200     width     => 550,
  201     height    => 400,
  202     bgcolor   => "#869ca7",
  203     base64_state       =>  undef,     # this is an state to use for initializing the first occurence of the question.
  204     base64_config      =>  undef,     # this is the initial (and final?) configuration
  205     getStateAlias      =>  'getXML',
  206     setStateAlias      =>  'setXML',
  207     configAlias        =>  'config',
  208     initializeActionAlias => 'setXML',
  209     submitActionAlias  =>  'getXML',
  210     submitActionScript  =>  '',        # script executed on submitting the WW question
  211     answerBox          =>  'answerBox',
  212     headerText         =>  DEFAULT_HEADER_TEXT(),
  213     objectText         => '',
  214     debug              => 0,
  215     @_,
  216   };
  217   bless $self, $class;
  218   $self->state('<xml></xml>');
  219   $self->config('<xml></xml>');
  220   return $self;
  221 }
  222 
  223 sub  header {
  224   my $self = shift;
  225   if ($_[0] eq "reset") {  # $applet->header('reset');  erases default header text.
  226     $self->{headerText}='';
  227   } else {
  228     $self->{headerText} .= join("",@_);  # $applet->header(new_text); concatenates new_text to existing header.
  229   }
  230     $self->{headerText};
  231 }
  232 sub  object {
  233   my $self = shift;
  234   if ($_[0] eq "reset") {
  235     $self->{objectText}='';
  236   } else {
  237     $self->{objectText} .= join("",@_);
  238   }
  239     $self->{objectText};
  240 }
  241 sub params {
  242   my $self = shift;
  243   if (ref($_[0]) =~/HASH/) {
  244     $self->{params} = shift;
  245   } elsif ( !defined($_[0]) or $_[0] =~ '') {
  246     # do nothing (read)
  247   } else {
  248     warn "You must enter a reference to a hash for the parameter list";
  249   }
  250   $self->{params};
  251 }
  252 
  253 sub initializeActionAlias {
  254   my $self = shift;
  255   $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty
  256     $self->{initializeActionAlias};
  257 }
  258 
  259 sub submitActionAlias {
  260   my $self = shift;
  261   $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty
  262     $self->{submitActionAlias};
  263 }
  264 sub submitActionScript {
  265   my $self = shift;
  266   $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty
  267     $self->{submitActionScript};
  268 }
  269 sub getStateAlias {
  270   my $self = shift;
  271   $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty
  272     $self->{getStateAlias};
  273 }
  274 
  275 sub setStateAlias {
  276   my $self = shift;
  277   $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty
  278     $self->{setStateAlias};
  279 }
  280 sub configAlias {
  281   my $self = shift;
  282   $self->{configAlias} = shift ||$self->{configAlias}; # replace the current contents if non-empty
  283     $self->{configAlias};
  284 }
  285 sub returnFieldName {
  286   my $self = shift;
  287   $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty
  288     $self->{answerBox};
  289 }
  290 sub answerBox {
  291   my $self = shift;
  292   $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty
  293     $self->{answerBox};
  294 }
  295 sub codebase {
  296   my $self = shift;
  297   $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty
  298     $self->{codebase};
  299 }
  300 sub code {
  301   my $self = shift;
  302   $self->{code} = shift ||$self->{code}; # replace the current code if non-empty
  303     $self->{code};
  304 }
  305 sub height {
  306   my $self = shift;
  307   $self->{height} = shift ||$self->{height}; # replace the current height if non-empty
  308     $self->{height};
  309 }
  310 sub width {
  311   my $self = shift;
  312   $self->{width} = shift ||$self->{width}; # replace the current width if non-empty
  313     $self->{width};
  314 }
  315 sub bgcolor {
  316   my $self = shift;
  317   $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty
  318     $self->{bgcolor};
  319 }
  320 sub archive {
  321   my $self = shift;
  322   $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty
  323     $self->{archive};
  324 }
  325 sub appletName {
  326   my $self = shift;
  327   $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty
  328     $self->{appletName};
  329 }
  330 sub debug {
  331   my $self = shift;
  332   my $new_flag = shift;
  333   $self->{debug} = $new_flag if defined($new_flag);
  334   $self->{debug};
  335 }
  336 sub appletId {
  337   appletName(@_);
  338 }
  339 sub state {
  340   my $self = shift;
  341   my $str = shift;
  342   $self->{base64_state} =  encode_base64($str)   ||$self->{base64_state}; # replace the current string if non-empty
  343   $self->{base64_state} =~ s/\n//g;
  344     decode_base64($self->{base64_state});
  345 }
  346 
  347 sub base64_state{
  348   my $self = shift;
  349   $self->{base64_state} = shift ||$self->{base64_state}; # replace the current string if non-empty
  350     $self->{base64_state};
  351 }
  352 sub config {
  353   my $self = shift;
  354   my $str = shift;
  355   $self->{base64_config} =  encode_base64($str)   || $self->{base64_config}; # replace the current string if non-empty
  356   $self->{base64_config} =~ s/\n//g;
  357     decode_base64($self->{base64_config});
  358 }
  359 sub base64_config {
  360   my $self = shift;
  361   $self->{base64_config} = shift ||$self->{base64_config}; # replace the current string if non-empty
  362   $self->{base64_config} =$self->{base64_config};
  363     $self->{base64_config};
  364 }
  365 #FIXME
  366 # need to be able to adjust header material
  367 
  368 sub insertHeader {
  369     my $self = shift;
  370 
  371     my $codebase              =  $self->codebase;
  372     my $appletId              =  $self->appletId;
  373     my $appletName            =  $self->appletName;
  374     my $base64_initialState   = $self->base64_state;
  375     my $initializeAction      =  $self->initializeActionAlias;
  376     my $submitActionAlias     =  $self->submitActionAlias;
  377     my $submitActionScript    = $self->submitActionScript;
  378     my $setStateAlias         =  $self->setStateAlias;
  379     my $getStateAlias         =  $self->getStateAlias;
  380     my $configAlias           =  $self->configAlias;
  381     my $base64_config         =  $self->base64_config;
  382     my $debugMode             =  ($self->debug) ? "1": "0";
  383     my $returnFieldName       =  $self->{returnFieldName};
  384     my $answerBox             =  $self->{answerBox};
  385     my $headerText            =  $self->header();
  386 
  387 
  388     $submitActionScript =~ s/"/\\"/g;    # escape quotes for ActionScript
  389                                          # other variables should not have quotes.
  390 
  391     $submitActionScript =~ s/\n/ /g;     # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript
  392     $submitActionScript =~ s/\r/ /g;     # replace returns with spaces -- returns can cause trouble
  393 
  394     $headerText =~ s/(\$\w+)/$1/gee;   # interpolate variables p17 of Cookbook
  395 
  396     return $headerText;
  397 
  398 
  399 }
  400 
  401 sub insertObject {
  402     my $self       = shift;
  403     my $code       = $self->{code};
  404     my $codebase   = $self->{codebase};
  405     my $appletId   = $self->{appletName};
  406     my $appletName = $self->{appletName};
  407     my $archive    = $self->{archive};
  408     my $width      = $self->{width};
  409     my $height     = $self->{height};
  410     my $applet_bgcolor = $self->{bgcolor};
  411     my $javaParameters = '';
  412     my $flashParameters = '';
  413     my %param_hash = %{$self->params()};
  414     foreach my $key (keys %param_hash) {
  415       $javaParameters .= qq!<param name ="$key"  value = "$param_hash{$key}">\n!;
  416       $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&';
  417     }
  418     $flashParameters =~ s/\&$//;    # trim last &
  419 
  420 
  421     $objectText = $self->{objectText};
  422     $objectText =~ s/(\$\w+)/$1/gee;
  423     return $objectText;
  424 }
  425 # sub initialize  {
  426 #     my $self = shift;
  427 #   return q{
  428 #     <script>
  429 #       initializeAllApplets();
  430 #       // this should really be done in the <body> tag
  431 #     </script>
  432 #   };
  433 #
  434 # }
  435 ########################################################
  436 # HEADER material for one flash or java applet
  437 ########################################################
  438 
  439 use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
  440     <script src="/webwork2_files/js/Base64.js" language="javascript">
  441     </script>
  442     <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
  443         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
  444      </script>
  445   <script language="JavaScript">
  446 
  447   // set debug mode for this applet
  448     set_debug($debugMode);
  449 
  450     //////////////////////////////////////////////////////////
  451   //TEST code
  452   //
  453     //
  454     //////////////////////////////////////////////////////////
  455 
  456     ww_applet_list["$appletName"] = new ww_applet("$appletName");
  457 
  458 
  459   ww_applet_list["$appletName"].code = "$code";
  460   ww_applet_list["$appletName"].codebase = "$codebase";
  461     ww_applet_list["$appletName"].appletID = "$appletID";
  462   ww_applet_list["$appletName"].base64_state = "$base64_initializationState";
  463   ww_applet_list["$appletName"].base64_config = "$base64_config";
  464   ww_applet_list["$appletName"].getStateAlias = "$getStateAlias";
  465   ww_applet_list["$appletName"].setStateAlias = "$setStateAlias";
  466   ww_applet_list["$appletName"].configAlias   = "$configAlias";
  467   ww_applet_list["$appletName"].initializeActionAlias = "$initializeAction";
  468   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
  469   ww_applet_list["$appletName"].submitActionScript = "$submitActionScript";
  470   ww_applet_list["$appletName"].answerBox = "$answerBox";
  471   ww_applet_list["$appletName"].debug = "$debugMode";
  472 
  473     </script>
  474 
  475 END_HEADER_SCRIPT
  476 
  477 package FlashApplet;
  478 @ISA = qw(Applet);
  479 
  480 
  481 =head2 Insertion HTML code for FlashApplet
  482 
  483 =pod
  484 
  485 The secret to making this applet work with IE in addition to normal browsers
  486 is the addition of the C(<form></form>) construct just before the object.
  487 
  488 For some reason IE has trouble locating a flash object which is contained
  489 within a form.  Adding this second blank form with the larger problemMainForm
  490 seems to solve the problem.
  491 
  492 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  493 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  494 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  495 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  496 
  497     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  498       <form></form>
  499       <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  500            id="$appletName" width="500" height="375"
  501            codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  502          <param name="movie" value="$codebase/$appletName.swf" />
  503          <param name="quality" value="high" />
  504          <param name="bgcolor" value="$applet_bgcolor" />
  505          <param name="allowScriptAccess" value="sameDomain" />
  506          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  507            width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  508            play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  509            type="application/x-shockwave-flash"
  510            pluginspage="http://www.macromedia.com/go/getflashplayer">
  511          </embed>
  512 
  513        </object>
  514     END_OBJECT_TEXT
  515 
  516 
  517 =cut
  518 
  519 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  520   <form></form>
  521   <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  522              id="$appletName" width="500" height="375"
  523              codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  524          <param name="movie" value="$codebase/$appletName.swf" />
  525          <param name="quality" value="high" />
  526          <param name="bgcolor" value="$applet_bgcolor" />
  527          <param name="allowScriptAccess" value="sameDomain" />
  528          <param name="FlashVars" value="$flashParameters"/>
  529          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  530              width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  531              play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  532              type="application/x-shockwave-flash"
  533              pluginspage="http://www.macromedia.com/go/getflashplayer"
  534              FlashVars="$flashParameters">
  535          </embed>
  536 
  537      </object>
  538 END_OBJECT_TEXT
  539 
  540 sub new {
  541     my $class = shift;
  542   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  543                   @_
  544   );
  545 
  546 }
  547 
  548 
  549 package JavaApplet;
  550 @ISA = qw(Applet);
  551 
  552 =head2 Insertion HTML code for JavaApplet
  553 
  554 =pod
  555 
  556 The secret to making this applet work with IE in addition to normal browsers
  557 is the addition of the C(<form></form>) construct just before the object.
  558 
  559 For some reason IE has trouble locating a flash object which is contained
  560 within a form.  Adding this second blank form with the larger problemMainForm
  561 seems to solve the problem.
  562 
  563 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  564 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  565 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  566 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  567 
  568     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  569       <form></form>
  570      <applet
  571       code     = "$code"
  572       codebase = "$codebase"
  573       archive  = "$archive"
  574       name     = "$appletName"
  575       id       = "$appletName"
  576       width    = "$width"
  577       height   = "$height"
  578       MAYSCRIPT
  579      >
  580       $javaParameters
  581      </applet>
  582     END_OBJECT_TEXT
  583 
  584 =cut
  585 
  586 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  587   <form></form>
  588  <applet
  589   code     = "$code"
  590   codebase = "$codebase"
  591   archive  = "$archive"
  592   name     = "$appletName"
  593     id       = "$appletName"
  594     width    = "$width"
  595     height   = "$height"
  596     bgcolor  = "$applet_bgcolor"
  597     MAYSCRIPT
  598  >
  599   $javaParameters
  600 
  601   Sorry, the Applet could not be started. Please make sure that
  602 Java 1.4.2 (or later) is installed and activated.
  603 (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
  604  </applet>
  605 END_OBJECT_TEXT
  606 
  607 sub new {
  608     my $class = shift;
  609   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  610                   @_
  611   );
  612 
  613 }
  614 
  615 
  616 
  617 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9