[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 6058 - (download) (as text) (annotate)
Thu Jun 25 23:28:44 2009 UTC (10 years, 7 months ago) by gage
File size: 36633 byte(s)
syncing pg HEAD with pg2.4.7 on 6/25/2009

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader$
    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  $appletName = "PointGraph";
   27 $applet =  FlashApplet(
   28    codebase              => findAppletCodebase("$appletName.swf"),
   29    appletName            => $appletName,
   30    appletId              => $appletName,
   31    setStateAlias         => 'setXML',
   32    getStateAlias         => 'getXML',
   33    setConfigAlias        => 'config',
   34    answerBoxAlias        => 'answerBox',
   35    submitActionScript    => qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() },
   36 );
   37 
   38 ###################################
   39 # Configure applet
   40 ###################################
   41 
   42 #data to set up the equation
   43 $applet->configuration(qq{<XML expr='(x - $a)^3 + $b/$a * x' />});
   44 # initial points
   45 $applet->intialState(qq{<XML> </XML>});
   46 ###################################
   47 #insert applet into body
   48 ###################################
   49 
   50 TEXT( MODES(TeX=>'object code', HTML=>$applet->insertAll(
   51   includeAnswerBox => 1
   52   debug=>0,
   53   reinitialize_button=>1,
   54  )));
   55 
   56 
   57 =head1 DESCRIPTION
   58 
   59 This file provides an object to store in one place
   60 all of the information needed to call an applet.
   61 
   62 The object FlashApplet has defaults for inserting flash applets.
   63 
   64 =over
   65 
   66 =item *
   67 
   68 =item *
   69 
   70 =back
   71 
   72 (not yet completed)
   73 
   74 The module JavaApplet has defaults for inserting java applets.
   75 
   76 The module Applet stores common code for the two types of applet.
   77 
   78 =head1 USAGE
   79 
   80 These modules are activate by listing it in the modules section of global.conf and rebooting the server.
   81 The companion file to this one is macros/AppletObjects.pl
   82 
   83 qw(Applet FlashApplet JavaApplet)
   84 
   85 =cut
   86 
   87 
   88 
   89 package Applet;
   90 
   91 use URI::Escape;
   92 
   93 
   94 
   95 use MIME::Base64 qw( encode_base64 decode_base64);
   96 
   97 
   98 =head2 Default javaScript functions placed in header
   99 
  100 =pod
  101 
  102 These functions are automatically defined for use for
  103 any javaScript placed in the text of a PG question.
  104 
  105     getApplet(appletName)     -- finds the applet path in the DOM
  106 
  107     submitAction()            -- calls the submit action of the applets
  108 
  109     initializeWWquestion()    -- calls the initialize action of the applets
  110 
  111     getQE(name)               -- gets an HTML element of the question by name
  112                                  or by id.  Be sure to keep all names and ids
  113                                  unique within a given PG question.
  114 
  115     getQuestionElement(name)  -- long form of getQE(name)
  116 
  117     listQuestionElements()    -- for discovering the names of inputs in the
  118                                  PG question.  An alert dialog will list all
  119                                  of the elements.
  120 
  121         Usage: Place this at the END of the question, just before END_DOCUMENT():
  122 
  123                 TEXT(qq!<script> listQuestionElements() </script>!);
  124                 ENDDOCUMENT();
  125              to obtain a list of all of the HTML elements in the question
  126 
  127     ----------------------------------------------------------------------------
  128 
  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         params       an anonymous array containing name/value pairs
  149                      to configure the applet [name =>'value, ...]
  150 
  151         width        rectangle alloted in the html page for displaying the applet
  152         height
  153 
  154     bgcolor      background color of the applet rectangle
  155 
  156         header       stores the text to be added to the header section of the html page
  157         object       stores the text which places the applet on the html page
  158 
  159 
  160         configuration  configuration contains those customizable attributes of the applet which don't
  161                      change as it is used.  When stored in hidden answer fields
  162                      it is usually stored in base64 encoded format.
  163         initialState  the state consists of those customizable attributes of the applet which change
  164                      as the applet is used by the student.  It is stored by the calling .pg question so that
  165                      when revisiting the question the applet will be restored to the same state it was
  166                      left in when the question was last viewed.
  167 
  168         getStateAlias  (default: getState) alias for command called to read the current state of the applet.
  169                        The state is passed in plain text xml format with outer tags: <xml>....</xml>
  170         setStateAlias  (default: setState) alias for the command called to reset the  state of the applet.
  171                        The state is passed in plain text in xml format with outer tags: <xml>....</xml>
  172 
  173         configAlias   (deprecated) -- a synonym for configAlias
  174 
  175         getConfigAlias (default: getConfig) -- retrieves the configuration from the applet.  This is used
  176                      mainly for debugging.  In principal the configuration remains the same for a given instance
  177                      of the applet -- i.e. for the homework question for a single student.  The state however
  178                      will change depending on the interactions between the student and the applet.
  179         setConfigAlias (default: setConfig ) names the applet command called with the contents of $self->config
  180                      to configure the applet.  The parameters are passed to the applet in plain text using <xml>
  181                      The outer tags must be   <xml> .....   </xml>
  182 
  183 
  184         initializeActionAlias  -- (default: initializeAction) the name of the javaScript subroutine called
  185                                   to initialize the applet (some overlap with config/ and setState
  186         maxInitializationAttempts -- (default: 5) number attempts to test applet to see if it is installed.
  187                                      If isActive() exists then the WW question waits until the return value is 1 before
  188                                      calling the applet's confguration commands.
  189                                      Because some applets have isActive return 0 even when they are ready,
  190                                      if isActive() exists but does not return 1 then the applet's configuration commands
  191                                      are called after maxInitializationAttempts number of times.  If none of the configuration commands
  192                                      of the applet can be detected then the WW question gives up after maxInitializationAttempts.
  193 
  194         submitActionAlias      -- (default: getXML) applet subroutine called when the submit button of the
  195                                   .pg question is pressed.
  196         submitActionScript     -- (default: qq{ getQE('answerBox').value = getApplet("$appletName").getAnswer() },
  197 
  198         answerBoxAlias         -- name of answer box to return answer to: default defaultAnswerBox
  199         returnFieldName        -- (deprecated) synonmym for answerBoxAlias
  200 
  201 
  202         debugMode              (default: 0) for debugMode==1 the answerBox and the box preserving the applet state
  203                                between questions are made visible along with some buttons for manually getting the state of
  204                                the applet and setting the state of the applet.
  205 
  206                                for debugMode==2, in addition to the answerBox and stateBox there are several alerts
  207                                which mark progress through the procedures of calling the applet.  Useful for troubleshooting
  208                                where in the chain of command a communication failure occurs
  209 
  210 
  211    Methods:
  212 
  213         insertHeader          -- inserts text in header section of HTML page
  214         insertObject          -- inserts <object></object> or <applet></applet>  tag in body of the HTML page
  215         insertAll             -- (defined in AppletObjects.pl) installs applet by inserting both header text and the object text
  216             Usage:    $applet->insertAll(
  217                               includeAnswerBox     => 0,
  218                               debugMode            => 0,
  219                               reinitialize_button  =>0,
  220                       );
  221 
  222 
  223 =cut
  224 
  225 =head4 More details
  226 
  227 There are three different "images" of the applet.  The first is the java or flash applet itself.  The object that actually does the work.
  228 The second is a perl image of the applet -- henceforth the perlApplet -- which is configured in the .pg file and allows a WeBWorK question
  229 to communicate with the applet.  The third image is a javaScript image of the applet -- henceforth the jsApplet which is a mirror of the perlApplet
  230 but is available to the javaScript code setup and executed in the virtual HTML page defined by the .pg file of the WeBWorK question. One can think of
  231 the jsApplet as a runtime version of the perlApplet since it can be accessed and modified after the virtual HTML page has been created by
  232 the PG rendering process.
  233 
  234 The perlApplet is initialized by   $newApplet = new flashApplet( appletName=>'myApplet',..... ); The jsApplet is automatically defined in
  235 ww_applet_list["myApplet"] by copying the instance variables of $newApplet to a corresponding javaScript object.  So  $newApplet->{appletName}
  236 corresponds to ww_applet_list["myApplet"].appletName.  (This paragraph is not yet fully implemented :-().
  237 
  238 Currently all messages read by the applet are xml text.  If some of the code needs to be printed in the HTML header than it is converted
  239 to a base64 constant and then converted back to text form when it is read by a javaScript subroutine.
  240 
  241 The perlApplet has  methods that help place the jsApplet code on the HTML page and create the link to the applet itself.
  242 In particular instance variables such as "setStateAlias", "getStateAlias" connect the WW default of "setState" to subroutine
  243 name chosen by the applet designer.  The aim is to make it easier to connect to applets previously designed to work
  244 with javaScript in an HTML page or other  systems.
  245 
  246 
  247 The jsApplet acts as an intermediary for commands directed at the applet.
  248 It is not necessary for the minimal operations of
  249 configuring the applet and maintaining
  250 state from one viewing of the WW question to address the applet directly.
  251 The methods such as "setState", "getState", "setConfig" which are part of the jsApplet
  252 take care of the book keeping details.
  253 It is also possible to make direct calls to the applet from handcrafted javaScript subroutines,
  254 but it may be convenient to store these as additional methods in the
  255 jsApplet.
  256 
  257 =cut
  258 
  259 =head4 Detecting that the applet is ready
  260 
  261 Timing issues are among the pitfalls awaiting when using flash or java applets in WW questions.  It is important that the WW question
  262 does not issue any commands to the applet until the applet is fully loaded, including the uploading of any additional configuration
  263 information from XML files.  This can be tricky since the timing issues usually don't arise when initiating the applet from an HTML page.
  264 
  265 The WW API performs the following actions to determine if the applet is loaded:
  266 
  267   check the ww_applet_list[appletName].isReady flag (1== applet is ready)
  268                       -- this caches the readiness information so that it doesn't
  269                          have to be repeated within a given viewing of a WW question
  270                          If this is 1 then the applet is ready.
  271   determine whether the applet's isActive subroutine is defined AND returns 1 when called.
  272                       -- if the return value is 1 the applet is ready, if it is zero or no response then the applet is NOT ready
  273                       -- If the applet has an isActive() subroutine -- there is no alias for this --
  274                          then it must return 1 as soon as the applet is ready.  Otherwise
  275                          the applet will timeout.
  276   determine whether the applet's setConfig subroutine is defined.
  277                       -- applet.{setConfigAlias}.
  278   determine whether the applet's setState subroutine is defined.
  279   determine whether the  jsApplets ww_applet_list[appletName].reportsLoaded flag is set to 1
  280                       -- this can be set by the applet if it calls the javaScript function
  281                          "applet_loaded(appletName, loaded_status).  The loaded_status is 1 or 0
  282 
  283   Logic for determining applet status: if any one of the above checks succeeds (or returns 1) then the applet is
  284                         consdered to be ready  UNLESS the isActive() exists and the call returns a 0 or no response. In this case
  285                         the applet is assumed to be loading additional data and is not yet ready.
  286 
  287                         For this reason if the isActive subroutine
  288                         is defined in the applet it must return a 1 once the applet is prepared to accept additional commands.
  289                         (Since there are some extent flashApplets with non-functioning isActive() subroutines a temporary workaround
  290                          assuems that after C<maxInitializationAttempts> -- 5 by default -- the applet is in fact ready but the
  291                          isActive() subroutine is non functioning.  This can give rise to false "readiness" signals if the applet
  292                          takes a long time to load auxiliary files.)
  293 
  294 The applet itself can take measures to insure that the setConfig subroutine is prepared to respond immediately once the applet is loaded.
  295 It can include timers that delay execution of the configuring actions until all of the auxiliary files needed by the applet are loaded.
  296 
  297 
  298 =cut
  299 
  300 
  301 
  302 
  303 =head4 Instance variables in the javaScript applet   ww_applet_list[appletName]
  304 
  305        Most of the instance variables in the perl version of the applet are transferred to the javaScript applet
  306 
  307 =cut
  308 
  309 
  310 =head4 Methods defined for the javaScript applet   ww_applet_list[appletName]
  311 
  312 This is not a comprehensive list
  313 
  314   setConfig         -- transmits the information for configuring the applet
  315 
  316   getConfig         -- retrieves the configuration information -- this is used mainly for debugging and may not be defined in most applets
  317 
  318 
  319   setState          -- sets the current state (1) from the appletName_state HTML element if this contains an <xml>...</xml> string
  320                     -- if the value contains <xml>restart_applet</xml> then set the current state to ww_applet_list[appletName].initialState
  321                     -- if the value is a blank string set the current state to ww_applet_list[appletName].initialState
  322 
  323 
  324   getState          -- retrieves the current state and stores in the appletName_state HTML element.
  325 
  326 
  327 =cut
  328 
  329 =head4 Requirements for applets
  330 
  331 The following methods are desirable in an applet that preserves state in a WW question.  None of them are required.
  332 
  333   setState(str)   (default: setXML)
  334                      -- set the current state of the applet from an xml string
  335                      -- should be able to accept an empty string or a string of
  336                         the form <XML>.....</XML> without creating errors
  337                      -- can be designed to receive other forms of input if it is
  338                         coordinated with the WW question.
  339   getState()      (default: getXML)
  340                    -- return the current state of the applet in an xml string.
  341                      -- an empty string or a string of the form <XML>.....</XML>
  342                         are the standard responses.
  343                      -- can be designed to return other strings if it is
  344                         coordinated with the WW question.
  345   setConfig(str) (default: setConfig)
  346                      -- If the applet allows configuration this configures the applet
  347                         from an xml string
  348                        -- should be able to accept an empty string or a string of the
  349                           form <XML>.....</XML> without creating errors
  350                      -- can be designed to receive other forms of input if it is
  351                         coordinated with the WW question.
  352     getConfig      (default: getConfig)
  353                      -- This returns a string defining the configuration of the
  354                         applet in an xml string
  355                        -- an empty string or a string of the form <XML>.....</XML>
  356                           are the standard responses.
  357                      -- can be designed to return other strings if it is
  358                         coordinated with the WW question.
  359                      -- this method is used for debugging to ensure that
  360                         the configuration was set as expected.
  361   getAnswer      (default: getAnswer)
  362                      -- Returns a string (usually NOT xml) which is the
  363                         response that the student is effectvely submitting to answer
  364                         the WW question.
  365 
  366 
  367 =cut
  368 
  369 =head4 Initialization sequence
  370 
  371 When the WW question is loaded the C<initializeWWquestion> javaScript subroutine calls each of the applets used in the question asking them
  372 to initialize themselves.
  373 
  374 The applets initialization method is as follows:
  375 
  376                        -- wait until the applet is loaded and the applet has loaded all of its auxiliary files.
  377                        -- set the debugMode in the applet
  378                        -- call the setConfig  method in the javaScript applet  -- (configuration parameters are "permanent" for the life of the applet
  379                        -- call the setInitialization method in the javaScript applet -- this often calls the setState method in the applet
  380 
  381 =cut
  382 
  383 
  384 =head Submit sequence
  385 
  386 When the WW question submit button is pressed the form containing the WW question calles the javaScript "submitAction()" which then asks
  387 each of the applets on the page to perform its submit action which consists of
  388 
  389   -- if the applet is to be reinitialized (appletName_state contains <xml>restart_applet</xml>) then
  390      the HTML elements appletName_state and previous_appletName_state are set to <xml>restart_applet</xml>
  391      to be interpreted by the next setState command
  392   -- Otherwise getState() from the applet and save it to the  HTML input element appletName_state
  393   -- Perform the javaScript commands in .submitActionScript (default: '' )
  394      a typical submitActionScript looks like getQE(this.answerBox).value = getApplet(appletName).getAnswer()  )
  395 
  396 =cut
  397 
  398 
  399 sub new {
  400    my $class = shift;
  401    my $self = {
  402     appletName  => '',
  403 #   appletId    => '',   #always use identical applet Id's and applet Names
  404         archive     => '',
  405     code        => '',
  406     codebase    => '',
  407     params    =>undef,
  408     width     => 550,
  409     height    => 400,
  410     bgcolor   => "#869ca7",
  411     configuration      => '',         # configuration defining the applet
  412     initialState       => '',         # initial state.
  413     getStateAlias      =>  'getXML',
  414     setStateAlias      =>  'setXML',
  415     configAlias        =>  '',        # deprecated
  416     getConfigAlias     =>  'getConfig',
  417     setConfigAlias     =>  'setConfig',
  418     initializeActionAlias => 'setXML',
  419     maxInitializationAttempts => 5,   # number of attempts to initialize applet
  420     submitActionAlias  =>  'getXML',
  421     submitActionScript  => '',        # script executed on submitting the WW question
  422     answerBoxAlias     =>  'answerBox',
  423     answerBox          =>  '',        # deprecated
  424     returnFieldName    => '',         # deprecated
  425     headerText         =>  DEFAULT_HEADER_TEXT(),
  426     objectText         => '',
  427     debugMode          => 0,
  428     @_,
  429   };
  430   bless $self, $class;
  431   $self->initialState('<xml></xml>');
  432   if ($self->{returnFieldName} or $self->{answerBox} ) { # backward compatibility
  433     warn "use answerBoxAlias instead of returnFieldName or answerBox";
  434     $self->{answerBox}='';
  435     $self->{returnFieldName}='';
  436   }
  437   if ($self->{configAlias}) { # backward compatibility
  438     warn "use setConfigAlias instead of configAlias";
  439     $self->{configAlias}='';
  440   }
  441   $self->configuration('<xml></xml>');
  442   return $self;
  443 }
  444 sub appletId {
  445   appletName(@_);
  446 }
  447 sub appletName {
  448   my $self = shift;
  449   $self->{appletName} = shift ||$self->{appletName}; # replace the current appletName if non-empty
  450     $self->{appletName};
  451 }
  452 sub archive {
  453   my $self = shift;
  454   $self->{archive} = shift ||$self->{archive}; # replace the current archive if non-empty
  455     $self->{archive};
  456 }
  457 sub code {
  458   my $self = shift;
  459   $self->{code} = shift ||$self->{code}; # replace the current code if non-empty
  460     $self->{code};
  461 }
  462 sub codebase {
  463   my $self = shift;
  464   $self->{codebase} = shift ||$self->{codebase}; # replace the current codebase if non-empty
  465     $self->{codebase};
  466 }
  467 sub params {
  468   my $self = shift;
  469   if (ref($_[0]) =~/HASH/) {
  470     $self->{params} = shift;
  471   } elsif ( !defined($_[0]) or $_[0] =~ '') {
  472     # do nothing (read)
  473   } else {
  474     warn "You must enter a reference to a hash for the parameter list";
  475   }
  476   $self->{params};
  477 }
  478 
  479 sub width {
  480   my $self = shift;
  481   $self->{width} = shift ||$self->{width}; # replace the current width if non-empty
  482     $self->{width};
  483 }
  484 sub height {
  485   my $self = shift;
  486   $self->{height} = shift ||$self->{height}; # replace the current height if non-empty
  487     $self->{height};
  488 }
  489 sub bgcolor {
  490   my $self = shift;
  491   $self->{bgcolor} = shift ||$self->{bgcolor}; # replace the current background color if non-empty
  492     $self->{bgcolor};
  493 }
  494 
  495 sub  header {
  496   my $self = shift;
  497   if ($_[0] eq "reset") {  # $applet->header('reset');  erases default header text.
  498     $self->{headerText}='';
  499   } else {
  500     $self->{headerText} .= join("",@_);  # $applet->header(new_text); concatenates new_text to existing header.
  501   }
  502     $self->{headerText};
  503 }
  504 sub  object {
  505   my $self = shift;
  506   if ($_[0] eq "reset") {
  507     $self->{objectText}='';
  508   } else {
  509     $self->{objectText} .= join("",@_);
  510   }
  511     $self->{objectText};
  512 }
  513 sub configuration {
  514   my $self = shift;
  515   my $str = shift;
  516   $self->{configuration} =  $str   || $self->{configuration}; # replace the current string if non-empty
  517   $self->{configuration} =~ s/\n//g;
  518     $self->{configuration};
  519 }
  520 
  521 sub initialState {
  522   my $self = shift;
  523   my $str = shift;
  524   $self->{initialState} = $str   ||$self->{initialState}; # replace the current string if non-empty
  525     $self->{initialState};
  526 }
  527 
  528 sub getStateAlias {
  529   my $self = shift;
  530   $self->{getStateAlias} = shift ||$self->{getStateAlias}; # replace the current contents if non-empty
  531     $self->{getStateAlias};
  532 }
  533 
  534 sub setStateAlias {
  535   my $self = shift;
  536   $self->{setStateAlias} = shift ||$self->{setStateAlias}; # replace the current contents if non-empty
  537     $self->{setStateAlias};
  538 }
  539 
  540 sub getConfigAlias {
  541   my $self = shift;
  542   $self->{getConfigAlias} = shift ||$self->{getConfigAlias}; # replace the current contents if non-empty
  543     $self->{getConfigAlias};
  544 }
  545 sub setConfigAlias {
  546   my $self = shift;
  547   $self->{setConfigAlias} = shift ||$self->{setConfigAlias}; # replace the current contents if non-empty
  548     $self->{setConfigAlias};
  549 }
  550 
  551 sub initializeActionAlias {
  552   my $self = shift;
  553   $self->{initializeActionAlias} = shift ||$self->{initializeActionAlias}; # replace the current contents if non-empty
  554     $self->{initializeActionAlias};
  555 }
  556 sub maxInitializationAttempts {
  557   my $self = shift;
  558   $self->{maxInitializationAttempts} = shift || $self->{maxInitializationAttempts};
  559   $self->{maxInitializationAttempts};
  560 }
  561 sub submitActionAlias {
  562   my $self = shift;
  563   $self->{submitActionAlias} = shift ||$self->{submitActionAlias}; # replace the current contents if non-empty
  564     $self->{submitActionAlias};
  565 }
  566 sub submitActionScript {
  567   my $self = shift;
  568   $self->{submitActionScript} = shift ||$self->{submitActionScript}; # replace the current contents if non-empty
  569     $self->{submitActionScript};
  570 }
  571 
  572 sub answerBoxAlias {
  573   my $self = shift;
  574   $self->{answerBox} = shift ||$self->{answerBox}; # replace the current contents if non-empty
  575     $self->{answerBox};
  576 }
  577 
  578 sub debugMode {
  579   my $self = shift;
  580   my $new_flag = shift;
  581   $self->{debugMode} = $new_flag if defined($new_flag);
  582   $self->{debugMode};
  583 }
  584 
  585 
  586 #######################
  587 # soon to be deprecated?
  588 #######################
  589 
  590 sub config {
  591   my $self = shift;
  592   my $str = shift;
  593   warn "use $self->configuration instead of $self->config.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  594 #   $self->{base64_config} =  encode_base64($str)   || $self->{base64_config}; # replace the current string if non-empty
  595 #   $self->{base64_config} =~ s/\n//g;
  596 #     decode_base64($self->{base64_config});
  597 }
  598 sub state {
  599   my $self = shift;
  600   my $str = shift;
  601   warn "use $self->initialState instead of $self->state.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  602 #   $self->{base64_state} =  encode_base64($str)   ||$self->{base64_state}; # replace the current string if non-empty
  603 #   $self->{base64_state} =~ s/\n//g;
  604 #     decode_base64($self->{base64_state});
  605 }
  606 sub base64_state{
  607   my $self = shift;
  608   warn "use $self->InitialState instead of $self->state.  Internally this string is ascii, not base64 encoded", join(' ', caller());
  609 
  610 
  611 }
  612 
  613 sub base64_config {
  614   my $self = shift;
  615   warn "use $self->configuration instead of $self->config.  Internally this string is ascii, not base64 encoded";
  616 }
  617 
  618 sub returnFieldName {
  619   my $self = shift;
  620     warn "use  answerBoxName  instead of returnFieldName";
  621 }
  622 sub answerBox {
  623   my $self = shift;
  624     warn "use  answerBoxAlias  instead of AnswerBox";
  625 }
  626 sub configAlias {
  627   my $self = shift;
  628     warn "use setConfigAlias instead of configAlias";
  629 }
  630 #########################
  631 #FIXME
  632 # need to be able to adjust header material
  633 
  634 sub insertHeader {
  635     my $self = shift;
  636 
  637     my $codebase              =  $self->codebase;
  638     my $appletId              =  $self->appletId;
  639     my $appletName            =  $self->appletName;
  640     my $initializeActionAlias =  $self->initializeActionAlias;
  641     my $submitActionScript    =  $self->submitActionScript;
  642     my $setStateAlias         =  $self->setStateAlias;
  643     my $getStateAlias         =  $self->getStateAlias;
  644 
  645     my $setConfigAlias        =  $self->setConfigAlias;
  646     my $getConfigAlias        =  $self->getConfigAlias;
  647     my $maxInitializationAttempts = $self->maxInitializationAttempts;
  648     my $debugMode             =  ($self->debugMode) ? "1": "0";
  649     my $answerBoxAlias        =  $self->{answerBoxAlias};
  650     my $headerText            =  $self->header();
  651 
  652 
  653     #$submitActionScript =~ s/"/\\"/g;    # escape quotes for ActionScript
  654                                          # other variables should not have quotes.
  655 
  656     $submitActionScript =~ s/\n/ /g;     # replace returns with spaces -- returns in the wrong spot can cause trouble with javaScript
  657     $submitActionScript =~ s/\r/ /g;     # replace returns with spaces -- returns can cause trouble
  658     my  $base64_submitActionScript =     encode_base64($submitActionScript);
  659     my $base64_configuration  =  encode_base64($self->configuration);
  660     my $base64_initialState   =  encode_base64($self->initialState);
  661 
  662     $base64_submitActionScript =~s/\n//g;
  663     $base64_initialState  =~s/\n//g;  # base64 encoded xml
  664     $base64_configuration =~s/\n//g;  # base64 encoded xml
  665 
  666     $headerText =~ s/(\$\w+)/$1/gee;   # interpolate variables p17 of Cookbook
  667 
  668     return $headerText;
  669 
  670 
  671 }
  672 
  673 
  674 ########################################################
  675 # HEADER material for one flash or java applet
  676 ########################################################
  677 
  678 use constant DEFAULT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
  679     <script src="/webwork2_files/js/Base64.js" language="javascript">
  680     </script>
  681     <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
  682         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
  683 
  684      </script>
  685   <script language="JavaScript">
  686 
  687 
  688 
  689     //////////////////////////////////////////////////////////
  690   //TEST code
  691   //
  692     //
  693     //////////////////////////////////////////////////////////
  694 
  695     ww_applet_list["$appletName"] = new ww_applet("$appletName");
  696 
  697 
  698   ww_applet_list["$appletName"].code = "$code";
  699   ww_applet_list["$appletName"].codebase         = "$codebase";
  700     ww_applet_list["$appletName"].appletID         = "$appletID";
  701   ww_applet_list["$appletName"].base64_state     = "$base64_initializationState";
  702   ww_applet_list["$appletName"].initialState     =  Base64.decode("$base64_initialState");
  703   ww_applet_list["$appletName"].configuration    = Base64.decode("$base64_configuration");;
  704   ww_applet_list["$appletName"].getStateAlias    = "$getStateAlias";
  705   ww_applet_list["$appletName"].setStateAlias    = "$setStateAlias";
  706   ww_applet_list["$appletName"].setConfigAlias   = "$setConfigAlias";
  707   ww_applet_list["$appletName"].getConfigAlias   = "$getConfigAlias";
  708   ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
  709   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
  710   ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
  711   ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias";
  712   ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
  713   ww_applet_list["$appletName"].debugMode = "$debugMode";
  714 
  715     </script>
  716 
  717 END_HEADER_SCRIPT
  718 
  719 
  720 
  721 sub insertObject {
  722     my $self       = shift;
  723     my $code       = $self->{code};
  724     my $codebase   = $self->{codebase};
  725     my $appletId   = $self->{appletName};
  726     my $appletName = $self->{appletName};
  727     my $archive    = $self->{archive};
  728     my $width      = $self->{width};
  729     my $height     = $self->{height};
  730     my $applet_bgcolor = $self->{bgcolor};
  731     my $javaParameters = '';
  732     my $flashParameters = '';
  733     my %param_hash = %{$self->params()};
  734     foreach my $key (keys %param_hash) {
  735       $javaParameters .= qq!<param name ="$key"  value = "$param_hash{$key}">\n!;
  736       $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&';
  737     }
  738     $flashParameters =~ s/\&$//;    # trim last &
  739 
  740 
  741     $objectText = $self->{objectText};
  742     $objectText =~ s/(\$\w+)/$1/gee;
  743     return $objectText;
  744 }
  745 
  746 package FlashApplet;
  747 @ISA = qw(Applet);
  748 
  749 
  750 =head2 Insertion HTML code for FlashApplet
  751 
  752 =pod
  753 
  754 The secret to making this applet work with IE in addition to normal browsers
  755 is the addition of the C(<form></form>) construct just before the object.
  756 
  757 For some reason IE has trouble locating a flash object which is contained
  758 within a form.  Adding this second blank form with the larger problemMainForm
  759 seems to solve the problem.
  760 
  761 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  762 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  763 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  764 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  765 
  766     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  767       <form></form>
  768       <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  769            id="$appletName" width="500" height="375"
  770            codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  771          <param name="movie" value="$codebase/$appletName.swf" />
  772          <param name="quality" value="high" />
  773          <param name="bgcolor" value="$applet_bgcolor" />
  774          <param name="allowScriptAccess" value="sameDomain" />
  775          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  776            width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  777            play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  778            type="application/x-shockwave-flash"
  779            pluginspage="http://www.macromedia.com/go/getflashplayer">
  780          </embed>
  781 
  782        </object>
  783     END_OBJECT_TEXT
  784 
  785 
  786 =cut
  787 
  788 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  789   <form></form>
  790   <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  791              id="$appletName" width="500" height="375"
  792              codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  793          <param name="movie" value="$codebase/$appletName.swf" />
  794          <param name="quality" value="high" />
  795          <param name="bgcolor" value="$applet_bgcolor" />
  796          <param name="allowScriptAccess" value="sameDomain" />
  797          <param name="FlashVars" value="$flashParameters"/>
  798          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  799              width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  800              play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  801              type="application/x-shockwave-flash"
  802              pluginspage="http://www.macromedia.com/go/getflashplayer"
  803              FlashVars="$flashParameters">
  804          </embed>
  805 
  806      </object>
  807 END_OBJECT_TEXT
  808 
  809 sub new {
  810     my $class = shift;
  811   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  812                   @_
  813   );
  814 
  815 }
  816 
  817 
  818 package JavaApplet;
  819 @ISA = qw(Applet);
  820 
  821 =head2 Insertion HTML code for JavaApplet
  822 
  823 =pod
  824 
  825 The secret to making this applet work with IE in addition to normal browsers
  826 is the addition of the C(<form></form>) construct just before the object.
  827 
  828 For some reason IE has trouble locating a flash object which is contained
  829 within a form.  Adding this second blank form with the larger problemMainForm
  830 seems to solve the problem.
  831 
  832 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  833 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  834 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  835 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  836 
  837     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  838       <form></form>
  839      <applet
  840       code     = "$code"
  841       codebase = "$codebase"
  842       archive  = "$archive"
  843       name     = "$appletName"
  844       id       = "$appletName"
  845       width    = "$width"
  846       height   = "$height"
  847       MAYSCRIPT
  848      >
  849       $javaParameters
  850      </applet>
  851     END_OBJECT_TEXT
  852 
  853 =cut
  854 
  855 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  856   <form></form>
  857  <applet
  858   code     = "$code"
  859   codebase = "$codebase"
  860   archive  = "$archive"
  861   name     = "$appletName"
  862     id       = "$appletName"
  863     width    = "$width"
  864     height   = "$height"
  865     bgcolor  = "$applet_bgcolor"
  866     MAYSCRIPT
  867  >
  868   $javaParameters
  869 
  870   Sorry, the Applet could not be started. Please make sure that
  871 Java 1.4.2 (or later) is installed and activated.
  872 (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
  873  </applet>
  874 END_OBJECT_TEXT
  875 
  876 sub new {
  877     my $class = shift;
  878   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  879                   @_
  880   );
  881 
  882 }
  883 
  884 
  885 
  886 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9