[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 6030 - (download) (as text) (annotate)
Sun Mar 22 18:33:06 2009 UTC (10 years, 7 months ago) by gage
File size: 34659 byte(s)
minor changes to refine the applet interface and to make
it work smoothly in both debuMode and non-debugMode

Also changed the name of the reset_button to the reinitialize_button
and the title the button carries

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9