[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 6316 - (download) (as text) (annotate)
Thu Jul 1 21:47:45 2010 UTC (9 years, 7 months ago) by gage
File size: 41900 byte(s)
This revision works for ie8 and firefox most of the time for both java and flash applets.  Sometimes there will be a failure for the applet to load, followed by a successful load -- there is apparently still a race condition in determining whether an applet - particularly a flash applet -- is ready

    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      function getApplet(appletName) {
  688       var isIE = navigator.appName.indexOf("Microsoft") != -1;  // ie8 uses this for java and firefox uses it for flash.
  689       var obj = (isIE) ? window[appletName] : window.document[appletName];
  690       //return window.document[appletName];
  691       if (!obj) { obj = document.getElementById(appletName) }
  692       if (obj ) {   //RECENT FIX to ==
  693         return( obj );
  694       } else {
  695         alert ("can't find applet " + appletName);
  696       }
  697     }
  698 
  699     //////////////////////////////////////////////////////////
  700   //TEST code
  701   //
  702     //
  703     //////////////////////////////////////////////////////////
  704 
  705     ww_applet_list["$appletName"] = new ww_applet("$appletName");
  706 
  707 
  708   ww_applet_list["$appletName"].code = "$code";
  709   ww_applet_list["$appletName"].codebase         = "$codebase";
  710     ww_applet_list["$appletName"].appletID         = "$appletID";
  711   ww_applet_list["$appletName"].base64_state     = "$base64_initializationState";
  712   ww_applet_list["$appletName"].initialState     = Base64.decode("$base64_initialState");
  713   ww_applet_list["$appletName"].configuration    = Base64.decode("$base64_configuration");;
  714   ww_applet_list["$appletName"].getStateAlias    = "$getStateAlias";
  715   ww_applet_list["$appletName"].setStateAlias    = "$setStateAlias";
  716   ww_applet_list["$appletName"].setConfigAlias   = "$setConfigAlias";
  717   ww_applet_list["$appletName"].getConfigAlias   = "$getConfigAlias";
  718   ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
  719   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
  720   ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
  721   ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias";
  722   ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
  723   ww_applet_list["$appletName"].debugMode = "$debugMode";
  724 
  725     </script>
  726 
  727 END_HEADER_SCRIPT
  728 
  729 
  730 
  731 sub insertObject {
  732     my $self       = shift;
  733     my $code       = $self->{code};
  734     my $codebase   = $self->{codebase};
  735     my $appletId   = $self->{appletName};
  736     my $appletName = $self->{appletName};
  737     my $archive    = $self->{archive};
  738     my $width      = $self->{width};
  739     my $height     = $self->{height};
  740     my $applet_bgcolor = $self->{bgcolor};
  741     my $javaParameters = '';
  742     my $flashParameters = '';
  743     my %param_hash = %{$self->params()};
  744     foreach my $key (keys %param_hash) {
  745       $javaParameters .= qq!<param name ="$key"  value = "$param_hash{$key}">\n!;
  746       $flashParameters .= uri_escape($key).'='.uri_escape($param_hash{$key}).'&';
  747     }
  748     $flashParameters =~ s/\&$//;    # trim last &
  749 
  750 
  751     $objectText = $self->{objectText};
  752     $objectText =~ s/(\$\w+)/$1/gee;
  753     return $objectText;
  754 }
  755 
  756 
  757 ###############################################################################################################
  758 #
  759 # FLASH APPLET  PACKAGE
  760 #
  761 ###############################################################################################################
  762 
  763 package FlashApplet;
  764 @ISA = qw(Applet);
  765 
  766 
  767 =head2 Insertion HTML code for FlashApplet
  768 
  769 =pod
  770 
  771 The secret to making this applet work with IE in addition to normal browsers
  772 is the addition of the C(<form></form>) construct just before the object.
  773 
  774 For some reason IE has trouble locating a flash object which is contained
  775 within a form.  Adding this second blank form with the larger problemMainForm
  776 seems to solve the problem.
  777 
  778 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  779 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  780 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  781 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  782 
  783     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  784       <form></form>
  785       <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  786            id="$appletName" width="500" height="375"
  787            codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  788          <param name="movie" value="$codebase/$appletName.swf" />
  789          <param name="quality" value="high" />
  790          <param name="bgcolor" value="$applet_bgcolor" />
  791          <param name="allowScriptAccess" value="sameDomain" />
  792          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  793            width="$width" height="$height" name="$appletName" align="middle" id="$appletName"
  794            play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  795            type="application/x-shockwave-flash"
  796            pluginspage="http://www.macromedia.com/go/getflashplayer">
  797          </embed>
  798 
  799        </object>
  800     END_OBJECT_TEXT
  801 
  802 
  803 =cut
  804 
  805 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  806 
  807   <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  808              id="$appletName"  width="500" height="375"
  809              codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
  810          <param name="movie" value="$codebase/$appletName.swf" />
  811          <param name="quality" value="high" />
  812          <param name="bgcolor" value="$applet_bgcolor" />
  813          <param name="allowScriptAccess" value="sameDomain" />
  814          <param name="FlashVars" value="$flashParameters"/>
  815          <embed src="$codebase/$appletName.swf" quality="high" bgcolor="$applet_bgcolor"
  816              width="$width" height="$height" name="$appletName"  align="middle" id="$appletName"
  817              play="true" loop="false" quality="high" allowScriptAccess="sameDomain"
  818              type="application/x-shockwave-flash"
  819              pluginspage="http://www.macromedia.com/go/getflashplayer"
  820              FlashVars="$flashParameters">
  821          </embed>
  822 
  823      </object>
  824 END_OBJECT_TEXT
  825 
  826 sub new {
  827     my $class = shift;
  828   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  829                   @_
  830   );
  831 
  832 }
  833 
  834 ###############################################################################################################
  835 #
  836 # JAVA APPLET  PACKAGE
  837 #
  838 ###############################################################################################################
  839 
  840 package JavaApplet;
  841 @ISA = qw(Applet);
  842 
  843 =head2 Insertion HTML code for JavaApplet
  844 
  845 =pod
  846 
  847 The secret to making this applet work with IE in addition to normal browsers
  848 is the addition of the C(<form></form>) construct just before the object.
  849 
  850 For some reason IE has trouble locating a flash object which is contained
  851 within a form.  Adding this second blank form with the larger problemMainForm
  852 seems to solve the problem.
  853 
  854 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  855 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  856 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  857 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  858 
  859     use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  860       <form></form>
  861      <applet
  862       code     = "$code"
  863       codebase = "$codebase"
  864       archive  = "$archive"
  865       name     = "$appletName"
  866       id       = "$appletName"
  867       width    = "$width"
  868       height   = "$height"
  869       MAYSCRIPT
  870      >
  871       $javaParameters
  872      </applet>
  873     END_OBJECT_TEXT
  874 
  875 =cut
  876 
  877 use constant DEFAULT_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  878 
  879  <applet
  880   code     = "$code"
  881   codebase = "$codebase"
  882   archive  = "$archive"
  883   name     = "$appletName"
  884     id       = "$appletName"
  885     width    = "$width"
  886     height   = "$height"
  887     bgcolor  = "$applet_bgcolor"
  888     MAYSCRIPT
  889  >
  890   $javaParameters
  891 
  892   Sorry, the Applet could not be started. Please make sure that
  893 Java 1.4.2 (or later) is installed and activated.
  894 (<a href="http://java.sun.com/getjava">click here to install Java now</a>)
  895  </applet>
  896 END_OBJECT_TEXT
  897 
  898 sub new {
  899     my $class = shift;
  900   $class -> SUPER::new( objectText   => DEFAULT_OBJECT_TEXT(),
  901                   @_
  902   );
  903 
  904 }
  905 
  906 ###############################################################################################################
  907 #
  908 # CANVAS APPLET  PACKAGE
  909 #
  910 ###############################################################################################################
  911 
  912 package CanvasApplet;
  913 @ISA = qw(Applet);
  914 
  915 
  916 =head2 Insertion HTML code for CanvasApplet
  917 
  918 =pod
  919 
  920 The secret to making this applet work with IE in addition to normal browsers
  921 is the addition of the C(<form></form>) construct just before the object.
  922 
  923 For some reason IE has trouble locating a flash object which is contained
  924 within a form.  Adding this second blank form with the larger problemMainForm
  925 seems to solve the problem.
  926 
  927 This follows method2 of the advice given in url(http://kb.adobe.com/selfservice/viewContent.do?externalId=kb400730&sliceId=2)
  928 Method1 and methods involving SWFObject(Geoff Stearns) and SWFFormFix (Steve Kamerman) have yet to be fully investigated:
  929 http://devel.teratechnologies.net/swfformfix/swfobject_swfformfix_source.js
  930 http://www.teratechnologies.net/stevekamerman/index.php?m=01&y=07&entry=entry070101-033933
  931 
  932 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT';
  933   <form></form>
  934   <script> var width = 200; var height = 200;</script>
  935   <canvas name="cv" id="cv" data-src="http://localhost/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="400" height="400"></canvas>
  936 END_OBJECT_TEXT
  937 
  938 
  939 
  940 =cut
  941 
  942 
  943 use constant CANVAS_OBJECT_HEADER_TEXT =><<'END_HEADER_SCRIPT';
  944     <script src="/webwork2_files/js/Base64.js" language="javascript">
  945     </script>
  946     <script src="/webwork2_files/js/ww_applet_support.js" language="javascript">
  947         //upload functions stored in /opt/webwork/webwork2/htdocs/js ...
  948 
  949      </script>
  950   <script language="JavaScript">
  951 
  952 
  953 
  954     //////////////////////////////////////////////////////////
  955   //CANVAS OBJECT HEADER CODE
  956     //
  957     //////////////////////////////////////////////////////////
  958 
  959     ww_applet_list["$appletName"] = new ww_applet("$appletName");
  960 
  961 
  962   ww_applet_list["$appletName"].code = "$code";
  963   ww_applet_list["$appletName"].codebase         = "$codebase";
  964     ww_applet_list["$appletName"].appletID         = "$appletID";
  965   ww_applet_list["$appletName"].base64_state     = "$base64_initializationState";
  966   ww_applet_list["$appletName"].initialState     = Base64.decode("$base64_initialState");
  967   ww_applet_list["$appletName"].configuration    = Base64.decode("$base64_configuration");;
  968   ww_applet_list["$appletName"].getStateAlias    = "$getStateAlias";
  969   ww_applet_list["$appletName"].setStateAlias    = "$setStateAlias";
  970   ww_applet_list["$appletName"].setConfigAlias   = "$setConfigAlias";
  971   ww_applet_list["$appletName"].getConfigAlias   = "$getConfigAlias";
  972   ww_applet_list["$appletName"].initializeActionAlias = "$initializeActionAlias";
  973   ww_applet_list["$appletName"].submitActionAlias = "$submitActionAlias";
  974   ww_applet_list["$appletName"].submitActionScript = Base64.decode("$base64_submitActionScript");
  975   ww_applet_list["$appletName"].answerBoxAlias = "$answerBoxAlias";
  976   ww_applet_list["$appletName"].maxInitializationAttempts = $maxInitializationAttempts;
  977   ww_applet_list["$appletName"].debugMode = "$debugMode";
  978 
  979 
  980     ww_applet_list["$appletName"].reportsLoaded = 1;
  981     ww_applet_list["$appletName"].object = $appletName;
  982 
  983     function getApplet(appletName) {
  984       //var isIE = navigator.appName.indexOf("Microsoft") != -1;
  985       //var obj = (isIE) ? window[appletName] : window.document[appletName];
  986       //return window.document[appletName];
  987       var obj = ww_applet_list[appletName].object;   // define fake applet for this object
  988       if (obj && (obj.name == appletName)) {   //RECENT FIX to ==
  989           //alert("getting fake applet " + obj.name);
  990         return( obj );
  991       } else {
  992         alert ("can't find fake applet " + appletName + " in object "+obj.name);
  993       }
  994     }
  995     </script>
  996 
  997 END_HEADER_SCRIPT
  998 
  999 
 1000 #FIXME   need to get rid of hardcoded url
 1001 
 1002 
 1003 use constant CANVAS_OBJECT_TEXT =><<'END_OBJECT_TEXT';
 1004 
 1005   <canvas name="cv" id="cv" data-src="/webwork2_files/js/sketchgraphhtml5b/SketchGraph.pjs" width="$width" height="$height"></canvas>
 1006 END_OBJECT_TEXT
 1007 
 1008 sub new {
 1009     my $class = shift;
 1010   $class -> SUPER::new( objectText   => CANVAS_OBJECT_TEXT(),
 1011                       headerText   => CANVAS_OBJECT_HEADER_TEXT(),
 1012                   @_
 1013   );
 1014 
 1015 }
 1016 
 1017 
 1018 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9